Decompiled source of CultOfTheLambMultiplayer v1.0.0

COTLMP/COTLMP.dll

Decompiled 3 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Logging;
using DG.Tweening;
using DG.Tweening.Core;
using HarmonyLib;
using Lamb.UI;
using Lamb.UI.DeathScreen;
using Lamb.UI.PauseMenu;
using MMBiomeGeneration;
using MMTools;
using Rewired;
using Spine;
using Spine.Unity;
using TMPro;
using Unify;
using Unify.Input;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("ClassLibrary1")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("ClassLibrary1")]
[assembly: AssemblyCopyright("Copyright ©  2026")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("b05729a9-afdc-413c-b90e-c3a9f2cd0a2c")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace COTLMultiplayerExpansion;

[BepInPlugin("com.cotlmp.multiplayerexpansion", "COTL Multiplayer Expansion", "2.20.14")]
public class Plugin : BaseUnityPlugin
{
	public static ManualLogSource Log;

	public const int MAX_PLAYERS = 4;

	public static readonly Color[] GoatColors = (Color[])(object)new Color[4]
	{
		Color.white,
		Color.white,
		new Color(0.4f, 0.7f, 1f, 1f),
		new Color(1f, 0.4f, 0.4f, 1f)
	};

	public static readonly Color[] IndicatorColors = (Color[])(object)new Color[4]
	{
		new Color(0.9f, 0.2f, 0.2f, 1f),
		new Color(0.6f, 0.3f, 0.9f, 1f),
		new Color(1f, 0.6f, 0.1f, 1f),
		new Color(0.4f, 0.7f, 1f, 1f)
	};

	private void Awake()
	{
		//IL_001f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0025: Expected O, but got Unknown
		//IL_004d: Unknown result type (might be due to invalid IL or missing references)
		//IL_005a: Expected O, but got Unknown
		//IL_0083: Unknown result type (might be due to invalid IL or missing references)
		//IL_0090: Expected O, but got Unknown
		//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c6: Expected O, but got Unknown
		//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fc: Expected O, but got Unknown
		//IL_0124: Unknown result type (might be due to invalid IL or missing references)
		//IL_0132: Expected O, but got Unknown
		//IL_015a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0168: Expected O, but got Unknown
		//IL_0191: Unknown result type (might be due to invalid IL or missing references)
		//IL_019e: Expected O, but got Unknown
		//IL_01d9: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e6: Expected O, but got Unknown
		//IL_020e: Unknown result type (might be due to invalid IL or missing references)
		//IL_021c: Expected O, but got Unknown
		//IL_0245: Unknown result type (might be due to invalid IL or missing references)
		//IL_0252: Expected O, but got Unknown
		//IL_027b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0288: Expected O, but got Unknown
		//IL_02b1: Unknown result type (might be due to invalid IL or missing references)
		//IL_02be: Expected O, but got Unknown
		//IL_02e7: Unknown result type (might be due to invalid IL or missing references)
		//IL_02f4: Expected O, but got Unknown
		//IL_031d: Unknown result type (might be due to invalid IL or missing references)
		//IL_032a: Expected O, but got Unknown
		//IL_0364: Unknown result type (might be due to invalid IL or missing references)
		//IL_0372: Expected O, but got Unknown
		//IL_039b: Unknown result type (might be due to invalid IL or missing references)
		//IL_03a8: Expected O, but got Unknown
		//IL_03d3: Unknown result type (might be due to invalid IL or missing references)
		//IL_03de: Expected O, but got Unknown
		//IL_0409: Unknown result type (might be due to invalid IL or missing references)
		//IL_0414: Expected O, but got Unknown
		//IL_043f: Unknown result type (might be due to invalid IL or missing references)
		//IL_044a: Expected O, but got Unknown
		//IL_0534: Unknown result type (might be due to invalid IL or missing references)
		//IL_0542: Expected O, but got Unknown
		//IL_0589: Unknown result type (might be due to invalid IL or missing references)
		//IL_0597: Expected O, but got Unknown
		//IL_05bf: Unknown result type (might be due to invalid IL or missing references)
		//IL_05cd: Expected O, but got Unknown
		//IL_05f6: Unknown result type (might be due to invalid IL or missing references)
		//IL_0603: Expected O, but got Unknown
		//IL_063e: Unknown result type (might be due to invalid IL or missing references)
		//IL_064b: Expected O, but got Unknown
		//IL_0678: Unknown result type (might be due to invalid IL or missing references)
		//IL_0685: Expected O, but got Unknown
		//IL_06f4: Unknown result type (might be due to invalid IL or missing references)
		//IL_0701: Expected O, but got Unknown
		//IL_04dd: Unknown result type (might be due to invalid IL or missing references)
		//IL_04f2: Unknown result type (might be due to invalid IL or missing references)
		//IL_04fd: Expected O, but got Unknown
		//IL_04fd: Expected O, but got Unknown
		//IL_048e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0499: Expected O, but got Unknown
		//IL_0757: Unknown result type (might be due to invalid IL or missing references)
		//IL_0764: Expected O, but got Unknown
		//IL_07b0: Unknown result type (might be due to invalid IL or missing references)
		//IL_07bd: Expected O, but got Unknown
		//IL_07f8: Unknown result type (might be due to invalid IL or missing references)
		//IL_0805: Expected O, but got Unknown
		//IL_0832: Unknown result type (might be due to invalid IL or missing references)
		//IL_083f: Expected O, but got Unknown
		//IL_0879: Unknown result type (might be due to invalid IL or missing references)
		//IL_088e: Unknown result type (might be due to invalid IL or missing references)
		//IL_089b: Expected O, but got Unknown
		//IL_089b: Expected O, but got Unknown
		//IL_08c4: Unknown result type (might be due to invalid IL or missing references)
		//IL_08d1: Expected O, but got Unknown
		//IL_08f9: Unknown result type (might be due to invalid IL or missing references)
		//IL_0907: Expected O, but got Unknown
		//IL_092f: Unknown result type (might be due to invalid IL or missing references)
		//IL_093d: Expected O, but got Unknown
		//IL_0965: Unknown result type (might be due to invalid IL or missing references)
		//IL_0973: Expected O, but got Unknown
		//IL_09ad: Unknown result type (might be due to invalid IL or missing references)
		//IL_09bb: Expected O, but got Unknown
		//IL_09f5: Unknown result type (might be due to invalid IL or missing references)
		//IL_0a03: Expected O, but got Unknown
		//IL_0a2b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0a39: Expected O, but got Unknown
		//IL_0a8d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0a9b: Expected O, but got Unknown
		//IL_0ae2: Unknown result type (might be due to invalid IL or missing references)
		//IL_0af0: Expected O, but got Unknown
		//IL_0b18: Unknown result type (might be due to invalid IL or missing references)
		//IL_0b26: Expected O, but got Unknown
		//IL_0b6d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0b7b: Expected O, but got Unknown
		//IL_0bc2: Unknown result type (might be due to invalid IL or missing references)
		//IL_0bd7: Unknown result type (might be due to invalid IL or missing references)
		//IL_0be4: Expected O, but got Unknown
		//IL_0be4: Expected O, but got Unknown
		//IL_0c1e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0c35: Unknown result type (might be due to invalid IL or missing references)
		//IL_0c40: Expected O, but got Unknown
		//IL_0c40: Expected O, but got Unknown
		//IL_0c7a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0c91: Unknown result type (might be due to invalid IL or missing references)
		//IL_0c9c: Expected O, but got Unknown
		//IL_0c9c: Expected O, but got Unknown
		Log = ((BaseUnityPlugin)this).Logger;
		Log.LogInfo((object)"COTL Multiplayer Expansion loading...");
		Harmony val = new Harmony("com.cotlmp.multiplayerexpansion");
		val.Patch((MethodBase)AccessTools.Method(typeof(CoopManager), "Awake", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(Patches), "CoopManager_Awake", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		val.Patch((MethodBase)AccessTools.Method(typeof(CoopManager), "OnControllerConnected", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(Patches), "OnControllerConnected", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		val.Patch((MethodBase)AccessTools.Method(typeof(CoopManager), "AddPlayerFromMenu", (Type[])null, (Type[])null), new HarmonyMethod(typeof(Patches), "AddPlayerFromMenu", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		val.Patch((MethodBase)AccessTools.Method(typeof(UICoopAssignController), "ConfirmSpawnButtonPress", (Type[])null, (Type[])null), new HarmonyMethod(typeof(Patches), "ConfirmSpawnButtonPress", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		val.Patch((MethodBase)AccessTools.Method(typeof(CoopManager), "RemovePlayerFromMenu", (Type[])null, (Type[])null), new HarmonyMethod(typeof(Patches), "RemovePlayerFromMenu", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		val.Patch((MethodBase)AccessTools.Method(typeof(PlayerFarming), "OnEnable", (Type[])null, (Type[])null), new HarmonyMethod(typeof(Patches), "PlayerFarming_OnEnable_Prefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		val.Patch((MethodBase)AccessTools.Method(typeof(CoopManager), "SpawnCoopPlayer", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(Patches), "SpawnCoopPlayer_Postfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		val.Patch((MethodBase)AccessTools.Method(typeof(PlayerFarming), "SetSkin", new Type[1] { typeof(bool) }, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(Patches), "SetSkin_Recolor", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		val.Patch((MethodBase)AccessTools.Method(typeof(UIPauseMenuController), "OnCoopButtonPressed", (Type[])null, (Type[])null), new HarmonyMethod(typeof(Patches), "OnCoopButtonPressed", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		val.Patch((MethodBase)AccessTools.Method(typeof(UIPauseMenuController), "RefreshCoopText", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(Patches), "RefreshCoopText", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		val.Patch((MethodBase)AccessTools.Method(typeof(HUD_Manager), "Update", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(Patches), "HUD_Update", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		val.Patch((MethodBase)AccessTools.Method(typeof(CoopManager), "RefreshCoopPlayerRewired", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(Patches), "RefreshCoopPlayerRewired", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		val.Patch((MethodBase)AccessTools.Method(typeof(PlayerFarming), "RefreshPlayersCount", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(Patches), "RefreshPlayersCount_Postfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		val.Patch((MethodBase)AccessTools.Method(typeof(CoopIndicatorIcon), "SetUsername", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(Patches), "SetUsername_Postfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		val.Patch((MethodBase)AccessTools.Method(typeof(CoopIndicatorIcon), "AnimateDamageOnIcons", new Type[1] { typeof(PlayerFarming) }, (Type[])null), new HarmonyMethod(typeof(Patches), "CoopIndicatorIcon_AnimateDamageOnIcons_Prefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		val.Patch((MethodBase)AccessTools.Method(typeof(PlayerFarming), "Update", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(Patches), "PlayerFarming_Update_Camera", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		val.Patch((MethodBase)AccessTools.Method(typeof(Interaction_DLCShrine), "Update", (Type[])null, (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(Patches), "SilentFinalizer", (Type[])null), (HarmonyMethod)null);
		val.Patch((MethodBase)AccessTools.Method(typeof(Interaction_DLCShrine), "OnDisable", (Type[])null, (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(Patches), "SilentFinalizer", (Type[])null), (HarmonyMethod)null);
		val.Patch((MethodBase)AccessTools.Method(typeof(CoopManager), "Update", (Type[])null, (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(Patches), "SilentFinalizer", (Type[])null), (HarmonyMethod)null);
		Type type = AccessTools.TypeByName("SkeletonAnimationLODGlobalManager");
		if (type != null)
		{
			MethodInfo methodInfo = AccessTools.Method(type, "Update", (Type[])null, (Type[])null);
			if (methodInfo != null)
			{
				val.Patch((MethodBase)methodInfo, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(Patches), "SilentFinalizer", (Type[])null), (HarmonyMethod)null);
				Log.LogInfo((object)"[MP] Patched SkeletonAnimationLODGlobalManager.Update finalizer");
			}
		}
		MethodInfo methodInfo2 = AccessTools.Method(typeof(BiomeConstants), "BiomeGenerator_OnBiomeChangeRoom", (Type[])null, (Type[])null);
		if (methodInfo2 != null)
		{
			val.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(Patches), "BiomeConstants_BiomeGenerator_OnBiomeChangeRoom_Transpiler", (Type[])null), new HarmonyMethod(typeof(Patches), "SilentFinalizer", (Type[])null), (HarmonyMethod)null);
			Log.LogInfo((object)"[MP] Patched BiomeConstants.BiomeGenerator_OnBiomeChangeRoom (safe particle-clear transpiler)");
		}
		val.Patch((MethodBase)AccessTools.Method(typeof(Interaction_BaseTeleporter), "HandleAnimationStateEvent", (Type[])null, (Type[])null), new HarmonyMethod(typeof(Patches), "TeleporterAnimEvent_Prefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		val.Patch((MethodBase)AccessTools.Method(typeof(Interaction_BaseTeleporter), "SpawnPlayerIE", new Type[2]
		{
			typeof(PlayerFarming),
			typeof(Vector3)
		}, (Type[])null), new HarmonyMethod(typeof(Patches), "SpawnPlayerIE_Prefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		val.Patch((MethodBase)AccessTools.Method(typeof(GameManager), "NewRun", (Type[])null, (Type[])null), new HarmonyMethod(typeof(Patches), "NewRun_Prefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		val.Patch((MethodBase)AccessTools.Method(typeof(CoopManager), "Start", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(Patches), "CoopManager_Start_Postfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		val.Patch((MethodBase)AccessTools.Method(typeof(CoopManager), "WakeAllKnockedOutPlayersWithHealth", new Type[1] { typeof(float) }, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(Patches), "CoopManager_WakeAllKnockedOutPlayersWithHealth_Postfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		val.Patch((MethodBase)AccessTools.Method(typeof(CoopManager), "WakeAllKnockedOutPlayers", Type.EmptyTypes, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(Patches), "CoopManager_WakeAllKnockedOutPlayers_Postfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		val.Patch((MethodBase)AccessTools.Method(typeof(CoopManager), "WakeKnockedOutPlayer", new Type[5]
		{
			typeof(PlayerFarming),
			typeof(float),
			typeof(PlayerFarming),
			typeof(HeartPickupType),
			typeof(bool)
		}, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(Patches), "CoopManager_WakeKnockedOutPlayer_Postfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		MethodInfo method = typeof(CoopManager).GetMethod("ResetMainPlayerOnConversationEnd", BindingFlags.Instance | BindingFlags.NonPublic, null, new Type[2]
		{
			typeof(bool),
			typeof(bool)
		}, null);
		if (method != null)
		{
			val.Patch((MethodBase)method, (HarmonyMethod)null, new HarmonyMethod(typeof(Patches), "CoopManager_ResetMainPlayerOnConversationEnd_Postfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		}
		else
		{
			Log.LogWarning((object)"[MP] Skipped patch: CoopManager.ResetMainPlayerOnConversationEnd(bool,bool) not found");
		}
		val.Patch((MethodBase)AccessTools.Method(typeof(Interaction_WeaponSelectionPodium), "SetWeapon", new Type[1] { typeof(int) }, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(Patches), "WeaponPodium_SetWeapon_Postfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		val.Patch((MethodBase)AccessTools.Method(typeof(Interaction_WeaponSelectionPodium), "SetCurse", new Type[1] { typeof(int) }, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(Patches), "WeaponPodium_SetCurse_Postfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		val.Patch((MethodBase)AccessTools.Method(typeof(Interaction_WeaponSelectionPodium), "OnEnable", Type.EmptyTypes, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(Patches), "WeaponPodium_OnEnable_Postfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		val.Patch((MethodBase)AccessTools.Method(typeof(Interaction_WeaponSelectionPodium), "OnInteract", new Type[1] { typeof(StateMachine) }, (Type[])null), new HarmonyMethod(typeof(Patches), "WeaponPodium_OnInteract_Prefix", (Type[])null), new HarmonyMethod(typeof(Patches), "WeaponPodium_OnInteract_Postfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		val.Patch((MethodBase)typeof(UICoopAssignController).GetMethod("OnShowStarted", BindingFlags.Instance | BindingFlags.NonPublic), (HarmonyMethod)null, new HarmonyMethod(typeof(Patches), "CoopAssign_OnShowStarted", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		val.Patch((MethodBase)AccessTools.Method(typeof(Health_Manager), "Init", (Type[])null, (Type[])null), new HarmonyMethod(typeof(Patches), "HealthManager_Init", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		val.Patch((MethodBase)AccessTools.Method(typeof(HUD_Hearts), "SetWeapon", (Type[])null, (Type[])null), new HarmonyMethod(typeof(Patches), "HUDHearts_SetWeapon_Prefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		val.Patch((MethodBase)AccessTools.Method(typeof(HUD_Hearts), "SetCurse", (Type[])null, (Type[])null), new HarmonyMethod(typeof(Patches), "HUDHearts_SetCurse_Prefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		val.Patch((MethodBase)AccessTools.Method(typeof(HUD_Hearts), "OnHPUpdated", new Type[1] { typeof(HealthPlayer) }, (Type[])null), new HarmonyMethod(typeof(Patches), "HUDHearts_OnHPUpdated_Prefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		val.Patch((MethodBase)AccessTools.Method(typeof(HUD_Hearts), "OnTotalHPUpdated", new Type[1] { typeof(HealthPlayer) }, (Type[])null), new HarmonyMethod(typeof(Patches), "HUDHearts_OnTotalHPUpdated_Prefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		val.Patch((MethodBase)AccessTools.Method(typeof(HUD_Hearts), "OnEnable", (Type[])null, (Type[])null), new HarmonyMethod(typeof(Patches), "HUDHearts_OnEnable_Prefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		val.Patch((MethodBase)AccessTools.Method(typeof(HUD_Heart), "SetSprite", new Type[3]
		{
			typeof(HeartState),
			typeof(bool),
			typeof(HeartType)
		}, (Type[])null), new HarmonyMethod(typeof(Patches), "HUDHeart_SetSprite_Prefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		val.Patch((MethodBase)AccessTools.Method(typeof(HUD_Heart), "Activate", new Type[2]
		{
			typeof(bool),
			typeof(bool)
		}, (Type[])null), new HarmonyMethod(typeof(Patches), "HUDHeart_Activate_Prefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		val.Patch((MethodBase)AccessTools.Method(typeof(FaithAmmo), "OnEnable", (Type[])null, (Type[])null), new HarmonyMethod(typeof(Patches), "FaithAmmo_OnEnable_Prefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		val.Patch((MethodBase)AccessTools.Method(typeof(FaithAmmo), "OnGetSoul", new Type[2]
		{
			typeof(int),
			typeof(PlayerFarming)
		}, (Type[])null), new HarmonyMethod(typeof(Patches), "FaithAmmo_OnGetSoul_Prefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		val.Patch((MethodBase)AccessTools.Method(typeof(FaithAmmo), "UseAmmo", new Type[2]
		{
			typeof(float),
			typeof(bool)
		}, (Type[])null), new HarmonyMethod(typeof(Patches), "FaithAmmo_UseAmmo_Prefix", (Type[])null), new HarmonyMethod(typeof(Patches), "FaithAmmo_UseAmmo_Postfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		val.Patch((MethodBase)AccessTools.Method(typeof(HUD_ActiveTrinketsCoOp), "OnTrinketsChanged", new Type[1] { typeof(PlayerFarming) }, (Type[])null), new HarmonyMethod(typeof(Patches), "HUDActiveTrinketsCoOp_OnTrinketsChanged_Prefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(Patches), "SilentFinalizer", (Type[])null), (HarmonyMethod)null);
		val.Patch((MethodBase)AccessTools.Method(typeof(HUD_ActiveTrinketsCoOp), "OnRomanNumeralSettingChanged", new Type[1] { typeof(bool) }, (Type[])null), new HarmonyMethod(typeof(Patches), "HUDActiveTrinketsCoOp_OnRomanNumeralSettingChanged_Prefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(Patches), "SilentFinalizer", (Type[])null), (HarmonyMethod)null);
		Log.LogInfo((object)("All patches applied. MAX_PLAYERS = " + 4));
	}
}
public static class Patches
{
	[CompilerGenerated]
	private sealed class <ApplyVisualDelayed>d__64 : IEnumerator<object>, IDisposable, IEnumerator
	{
		private int <>1__state;

		private object <>2__current;

		public int slot;

		private PlayerFarming <player>5__2;

		private float <waited>5__3;

		private bool <useAnimatedSpawn>5__4;

		private bool <inDungeon>5__5;

		private MeshRenderer <meshR>5__6;

		private float <waitLimit>5__7;

		private float <w>5__8;

		object IEnumerator<object>.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		object IEnumerator.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		[DebuggerHidden]
		public <ApplyVisualDelayed>d__64(int <>1__state)
		{
			this.<>1__state = <>1__state;
		}

		[DebuggerHidden]
		void IDisposable.Dispose()
		{
			<player>5__2 = null;
			<meshR>5__6 = null;
			<>1__state = -2;
		}

		private bool MoveNext()
		{
			//IL_047e: Unknown result type (might be due to invalid IL or missing references)
			//IL_048e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0493: Unknown result type (might be due to invalid IL or missing references)
			//IL_0193: Unknown result type (might be due to invalid IL or missing references)
			//IL_0394: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_03cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d5: Expected O, but got Unknown
			//IL_02a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b3: Expected O, but got Unknown
			//IL_0313: Unknown result type (might be due to invalid IL or missing references)
			//IL_031a: Invalid comparison between Unknown and I4
			//IL_042d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0434: Invalid comparison between Unknown and I4
			//IL_0327: Unknown result type (might be due to invalid IL or missing references)
			//IL_032e: Invalid comparison between Unknown and I4
			//IL_0254: Unknown result type (might be due to invalid IL or missing references)
			//IL_0264: Unknown result type (might be due to invalid IL or missing references)
			//IL_0269: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Expected O, but got Unknown
			switch (<>1__state)
			{
			default:
				return false;
			case 0:
				<>1__state = -1;
				if (slot < 2)
				{
					_pendingSpawnSlots.Remove(slot);
					_pendingSpawnUseAnimation.Remove(slot);
					return false;
				}
				<player>5__2 = null;
				<waited>5__3 = 0f;
				goto IL_0105;
			case 1:
				<>1__state = -1;
				<waited>5__3 += 0.2f;
				goto IL_0105;
			case 2:
				<>1__state = -1;
				<w>5__8 += 0.1f;
				goto IL_02d5;
			case 3:
				<>1__state = -1;
				if ((!<useAnimatedSpawn>5__4 || !<inDungeon>5__5) && (Object)(object)PlayerFarming.Instance != (Object)null && slot < SpawnOffsets.Length)
				{
					((Component)<player>5__2).transform.position = ((Component)PlayerFarming.Instance).transform.position + SpawnOffsets[slot];
				}
				break;
			case 4:
				<>1__state = -1;
				<w>5__8 += 0.1f;
				goto IL_03f7;
			case 5:
				{
					<>1__state = -1;
					if (slot < SpawnOffsets.Length && (Object)(object)PlayerFarming.Instance != (Object)null)
					{
						((Component)<player>5__2).transform.position = ((Component)PlayerFarming.Instance).transform.position + SpawnOffsets[slot];
					}
					break;
				}
				IL_02d5:
				if (<w>5__8 < <waitLimit>5__7 && (Object)(object)<player>5__2.state != (Object)null && (<player>5__2.state.LockStateChanges || (int)<player>5__2.state.CURRENT_STATE == 13 || (int)<player>5__2.state.CURRENT_STATE == 49))
				{
					<>2__current = (object)new WaitForSeconds(0.1f);
					<>1__state = 2;
					return true;
				}
				<>2__current = null;
				<>1__state = 3;
				return true;
				IL_03f7:
				if (<w>5__8 < 2f && ((Object)(object)PlayerFarming.Instance == (Object)null || (Object)(object)PlayerFarming.Instance.state == (Object)null || (int)PlayerFarming.Instance.state.CURRENT_STATE == 13))
				{
					<>2__current = (object)new WaitForSeconds(0.1f);
					<>1__state = 4;
					return true;
				}
				<>2__current = null;
				<>1__state = 5;
				return true;
				IL_0105:
				while ((Object)(object)<player>5__2 == (Object)null && <waited>5__3 < 10f)
				{
					foreach (PlayerFarming player in PlayerFarming.players)
					{
						if ((Object)(object)player != (Object)null && player.playerID == slot)
						{
							<player>5__2 = player;
							break;
						}
					}
					if ((Object)(object)<player>5__2 == (Object)null)
					{
						<>2__current = (object)new WaitForSeconds(0.2f);
						<>1__state = 1;
						return true;
					}
				}
				if ((Object)(object)<player>5__2 == (Object)null)
				{
					Plugin.Log.LogWarning((object)$"ApplyVisualDelayed: gave up waiting for playerID={slot}");
					_pendingSpawnSlots.Remove(slot);
					_pendingSpawnUseAnimation.Remove(slot);
					return false;
				}
				<useAnimatedSpawn>5__4 = false;
				_pendingSpawnUseAnimation.TryGetValue(slot, out <useAnimatedSpawn>5__4);
				<inDungeon>5__5 = GameManager.IsDungeon(PlayerFarming.Location);
				<meshR>5__6 = null;
				if (slot >= 2 && (Object)(object)<player>5__2.Spine != (Object)null)
				{
					<meshR>5__6 = ((Component)<player>5__2.Spine).GetComponent<MeshRenderer>();
					if (!<useAnimatedSpawn>5__4 && (Object)(object)<meshR>5__6 != (Object)null && ((Renderer)<meshR>5__6).enabled)
					{
						((Renderer)<meshR>5__6).enabled = false;
					}
				}
				if (slot >= 2 && (Object)(object)PlayerFarming.Instance != (Object)null && slot < SpawnOffsets.Length && (!<useAnimatedSpawn>5__4 || !<inDungeon>5__5))
				{
					((Component)<player>5__2).transform.position = ((Component)PlayerFarming.Instance).transform.position + SpawnOffsets[slot];
				}
				if ((slot >= 2) & <inDungeon>5__5)
				{
					<waitLimit>5__7 = 8f;
					<w>5__8 = 0f;
					goto IL_02d5;
				}
				<w>5__8 = 0f;
				goto IL_03f7;
			}
			if (slot >= 2 && (Object)(object)<meshR>5__6 != (Object)null && !((Renderer)<meshR>5__6).enabled)
			{
				((Renderer)<meshR>5__6).enabled = true;
			}
			if (slot < Plugin.GoatColors.Length && (Object)(object)<player>5__2.Spine != (Object)null && ((SkeletonRenderer)<player>5__2.Spine).skeleton != null)
			{
				((SkeletonRenderer)<player>5__2.Spine).skeleton.R = Plugin.GoatColors[slot].r;
				((SkeletonRenderer)<player>5__2.Spine).skeleton.G = Plugin.GoatColors[slot].g;
				((SkeletonRenderer)<player>5__2.Spine).skeleton.B = Plugin.GoatColors[slot].b;
				((SkeletonRenderer)<player>5__2.Spine).skeleton.A = Plugin.GoatColors[slot].a;
			}
			if ((Object)(object)GameManager.GetInstance() != (Object)null)
			{
				GameManager.GetInstance().AddToCamera(<player>5__2.CameraBone, 0.1f);
			}
			EnsurePlayerAwakeAfterRespawn(<player>5__2, $"ApplyVisualDelayed(slot={slot})");
			if (slot >= 2)
			{
				EnsureExtraSpawnStateUnlocked(<player>5__2, $"ApplyVisualDelayed(slot={slot})");
				SnapSpawnedPlayerToAwakeIdle(<player>5__2, $"ApplyVisualDelayed(slot={slot})");
			}
			if (_podiumClones.TryGetValue(slot, out var value))
			{
				foreach (Interaction_WeaponSelectionPodium item in value)
				{
					if ((Object)(object)item != (Object)null)
					{
						EnsurePodiumCloneOwner(item, slot, <player>5__2, forceInteractable: true);
						Plugin.Log.LogInfo((object)$"[MP] Refreshed podium clone state for slot {slot} on {((Object)item).name}");
					}
				}
			}
			HUD_Hearts val = <player>5__2.hudHearts;
			if ((Object)(object)val != (Object)null && (Object)(object)val.playerFarming != (Object)(object)<player>5__2)
			{
				Plugin.Log.LogWarning((object)$"[MP] ApplyVisualDelayed: stale hudHearts owner for slot {slot}, skipping direct faithAmmo init");
				val = null;
			}
			if ((Object)(object)val == (Object)null && _extraHeartBars.TryGetValue(slot, out var value2) && (Object)(object)value2 != (Object)null)
			{
				HUD_Hearts component = value2.GetComponent<HUD_Hearts>();
				if ((Object)(object)component != (Object)null && (Object)(object)component.playerFarming == (Object)(object)<player>5__2)
				{
					val = component;
					<player>5__2.hudHearts = component;
				}
			}
			if (slot >= 2 && (Object)(object)val != (Object)null)
			{
				SyncFaithAmmoForOwner(<player>5__2, val, $"ApplyVisualDelayed(slot={slot})", forceReinit: true);
			}
			_pendingSpawnSlots.Remove(slot);
			_pendingSpawnUseAnimation.Remove(slot);
			Plugin.Log.LogInfo((object)$"ApplyVisualDelayed done for slot {slot}");
			return false;
		}

		bool IEnumerator.MoveNext()
		{
			//ILSpy generated this explicit interface implementation from .override directive in MoveNext
			return this.MoveNext();
		}

		[DebuggerHidden]
		void IEnumerator.Reset()
		{
			throw new NotSupportedException();
		}
	}

	[CompilerGenerated]
	private sealed class <AutoRespawnMissingSlotsRoutine>d__153 : IEnumerator<object>, IDisposable, IEnumerator
	{
		private int <>1__state;

		private object <>2__current;

		public string reason;

		public List<int> missingSlots;

		private bool <allowDuringReviveFlow>5__2;

		private float <interSpawnDelay>5__3;

		private List<int>.Enumerator <>7__wrap3;

		private int <slot>5__5;

		private float <spawnWait>5__6;

		object IEnumerator<object>.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		object IEnumerator.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		[DebuggerHidden]
		public <AutoRespawnMissingSlotsRoutine>d__153(int <>1__state)
		{
			this.<>1__state = <>1__state;
		}

		[DebuggerHidden]
		void IDisposable.Dispose()
		{
			int num = <>1__state;
			if (num == -3 || (uint)(num - 2) <= 1u)
			{
				try
				{
				}
				finally
				{
					<>m__Finally1();
				}
			}
			<>7__wrap3 = default(List<int>.Enumerator);
			<>1__state = -2;
		}

		private bool MoveNext()
		{
			//IL_02fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0305: Expected O, but got Unknown
			//IL_01a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01aa: Expected O, but got Unknown
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Expected O, but got Unknown
			try
			{
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					_autoRespawnRoutineRunning = true;
					<allowDuringReviveFlow>5__2 = IsWakeAllRespawnReason(reason) || IsSacrificialReviveFlowReason(reason);
					<interSpawnDelay>5__3 = (<allowDuringReviveFlow>5__2 ? 0.15f : 0.75f);
					<>2__current = (object)new WaitForSeconds(0.35f);
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					<>7__wrap3 = missingSlots.GetEnumerator();
					<>1__state = -3;
					goto IL_0318;
				case 2:
					<>1__state = -3;
					<spawnWait>5__6 += 0.1f;
					goto IL_01d2;
				case 3:
					{
						<>1__state = -3;
						goto IL_0318;
					}
					IL_0318:
					while (true)
					{
						if (<>7__wrap3.MoveNext())
						{
							<slot>5__5 = <>7__wrap3.Current;
							if (!((Object)(object)CoopManager.Instance == (Object)null) && CoopManager.CoopActive)
							{
								if (!_pendingSpawnSlots.Contains(<slot>5__5) && !((Object)(object)FindActivePlayerBySlot(<slot>5__5) != (Object)null))
								{
									Player player = RewiredInputManager.GetPlayer(<slot>5__5);
									if (((player != null && player.controllers != null && player.controllers.Joysticks != null && player.controllers.Joysticks.Count > 0) || _desiredExtraSlots.Contains(<slot>5__5)) && !((Object)(object)PlayerFarming.Instance == (Object)null) && !((Object)(object)PlayerFarming.Instance.state == (Object)null) && (!IsReviveOrCutsceneFlowActive() || <allowDuringReviveFlow>5__2))
									{
										break;
									}
								}
								continue;
							}
						}
						<>m__Finally1();
						<>7__wrap3 = default(List<int>.Enumerator);
						_autoRespawnRoutineRunning = false;
						_nextAutoRespawnAttemptAt = Time.unscaledTime + 1.5f;
						return false;
					}
					<spawnWait>5__6 = 0f;
					goto IL_01d2;
					IL_01d2:
					if (CoopManager.Instance.IsSpawningOrRemovingPlayer && <spawnWait>5__6 < 10f)
					{
						<>2__current = (object)new WaitForSeconds(0.1f);
						<>1__state = 2;
						return true;
					}
					if (!_pendingSpawnSlots.Contains(<slot>5__5) && !((Object)(object)FindActivePlayerBySlot(<slot>5__5) != (Object)null))
					{
						Plugin.Log.LogInfo((object)$"[MP] Auto-respawn ({reason}): spawning missing slot {<slot>5__5}");
						_pendingSpawnSlots.Add(<slot>5__5);
						bool flag = false;
						Plugin.Log.LogInfo((object)$"[MP] Auto-respawn spawn mode slot {<slot>5__5}: animated={flag}");
						_pendingSpawnUseAnimation[<slot>5__5] = flag;
						try
						{
							CoopManager.Instance.SpawnCoopPlayer(<slot>5__5, flag, -1f);
						}
						catch (Exception ex)
						{
							_pendingSpawnSlots.Remove(<slot>5__5);
							_pendingSpawnUseAnimation.Remove(<slot>5__5);
							Plugin.Log.LogWarning((object)$"[MP] Auto-respawn failed for slot {<slot>5__5}: {ex.GetType().Name}: {ex.Message}");
						}
						<>2__current = (object)new WaitForSeconds(<interSpawnDelay>5__3);
						<>1__state = 3;
						return true;
					}
					goto IL_0318;
				}
			}
			catch
			{
				//try-fault
				((IDisposable)this).Dispose();
				throw;
			}
		}

		bool IEnumerator.MoveNext()
		{
			//ILSpy generated this explicit interface implementation from .override directive in MoveNext
			return this.MoveNext();
		}

		private void <>m__Finally1()
		{
			<>1__state = -1;
			((IDisposable)<>7__wrap3).Dispose();
		}

		[DebuggerHidden]
		void IEnumerator.Reset()
		{
			throw new NotSupportedException();
		}
	}

	[CompilerGenerated]
	private sealed class <BiomeConstants_BiomeGenerator_OnBiomeChangeRoom_Transpiler>d__230 : IEnumerable<CodeInstruction>, IEnumerable, IEnumerator<CodeInstruction>, IDisposable, IEnumerator
	{
		private int <>1__state;

		private CodeInstruction <>2__current;

		private int <>l__initialThreadId;

		private IEnumerable<CodeInstruction> instructions;

		public IEnumerable<CodeInstruction> <>3__instructions;

		private MethodInfo <clearNoArgs>5__2;

		private MethodInfo <clearWithChildren>5__3;

		private MethodInfo <safeNoArgs>5__4;

		private MethodInfo <safeWithChildren>5__5;

		private int <replacedNoArgs>5__6;

		private int <replacedWithChildren>5__7;

		private IEnumerator<CodeInstruction> <>7__wrap7;

		CodeInstruction IEnumerator<CodeInstruction>.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		object IEnumerator.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		[DebuggerHidden]
		public <BiomeConstants_BiomeGenerator_OnBiomeChangeRoom_Transpiler>d__230(int <>1__state)
		{
			this.<>1__state = <>1__state;
			<>l__initialThreadId = Environment.CurrentManagedThreadId;
		}

		[DebuggerHidden]
		void IDisposable.Dispose()
		{
			int num = <>1__state;
			if (num == -3 || num == 1)
			{
				try
				{
				}
				finally
				{
					<>m__Finally1();
				}
			}
			<clearNoArgs>5__2 = null;
			<clearWithChildren>5__3 = null;
			<safeNoArgs>5__4 = null;
			<safeWithChildren>5__5 = null;
			<>7__wrap7 = null;
			<>1__state = -2;
		}

		private bool MoveNext()
		{
			try
			{
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<clearNoArgs>5__2 = AccessTools.Method(typeof(ParticleSystem), "Clear", Type.EmptyTypes, (Type[])null);
					<clearWithChildren>5__3 = AccessTools.Method(typeof(ParticleSystem), "Clear", new Type[1] { typeof(bool) }, (Type[])null);
					<safeNoArgs>5__4 = AccessTools.Method(typeof(Patches), "SafeParticleClear_NoArgs", (Type[])null, (Type[])null);
					<safeWithChildren>5__5 = AccessTools.Method(typeof(Patches), "SafeParticleClear_WithChildren", (Type[])null, (Type[])null);
					<replacedNoArgs>5__6 = 0;
					<replacedWithChildren>5__7 = 0;
					<>7__wrap7 = instructions.GetEnumerator();
					<>1__state = -3;
					break;
				case 1:
					<>1__state = -3;
					break;
				}
				if (<>7__wrap7.MoveNext())
				{
					CodeInstruction current = <>7__wrap7.Current;
					if (<clearNoArgs>5__2 != null && CodeInstructionExtensions.Calls(current, <clearNoArgs>5__2))
					{
						<replacedNoArgs>5__6++;
						current.opcode = OpCodes.Call;
						current.operand = <safeNoArgs>5__4;
					}
					else if (<clearWithChildren>5__3 != null && CodeInstructionExtensions.Calls(current, <clearWithChildren>5__3))
					{
						<replacedWithChildren>5__7++;
						current.opcode = OpCodes.Call;
						current.operand = <safeWithChildren>5__5;
					}
					<>2__current = current;
					<>1__state = 1;
					return true;
				}
				<>m__Finally1();
				<>7__wrap7 = null;
				int num = <replacedNoArgs>5__6 + <replacedWithChildren>5__7;
				if (_safeBiomeClearPatchCountLog != num)
				{
					_safeBiomeClearPatchCountLog = num;
					Plugin.Log.LogInfo((object)($"[MP] Safe biome particle-clear transpiler replaced {num} ParticleSystem.Clear call(s) " + $"(noArgs={<replacedNoArgs>5__6}, withChildren={<replacedWithChildren>5__7})"));
				}
				return false;
			}
			catch
			{
				//try-fault
				((IDisposable)this).Dispose();
				throw;
			}
		}

		bool IEnumerator.MoveNext()
		{
			//ILSpy generated this explicit interface implementation from .override directive in MoveNext
			return this.MoveNext();
		}

		private void <>m__Finally1()
		{
			<>1__state = -1;
			if (<>7__wrap7 != null)
			{
				<>7__wrap7.Dispose();
			}
		}

		[DebuggerHidden]
		void IEnumerator.Reset()
		{
			throw new NotSupportedException();
		}

		[DebuggerHidden]
		IEnumerator<CodeInstruction> IEnumerable<CodeInstruction>.GetEnumerator()
		{
			<BiomeConstants_BiomeGenerator_OnBiomeChangeRoom_Transpiler>d__230 <BiomeConstants_BiomeGenerator_OnBiomeChangeRoom_Transpiler>d__;
			if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId)
			{
				<>1__state = 0;
				<BiomeConstants_BiomeGenerator_OnBiomeChangeRoom_Transpiler>d__ = this;
			}
			else
			{
				<BiomeConstants_BiomeGenerator_OnBiomeChangeRoom_Transpiler>d__ = new <BiomeConstants_BiomeGenerator_OnBiomeChangeRoom_Transpiler>d__230(0);
			}
			<BiomeConstants_BiomeGenerator_OnBiomeChangeRoom_Transpiler>d__.instructions = <>3__instructions;
			return <BiomeConstants_BiomeGenerator_OnBiomeChangeRoom_Transpiler>d__;
		}

		[DebuggerHidden]
		IEnumerator IEnumerable.GetEnumerator()
		{
			return ((IEnumerable<CodeInstruction>)this).GetEnumerator();
		}
	}

	[CompilerGenerated]
	private sealed class <DeferredEnsurePodiumOwner>d__178 : IEnumerator<object>, IDisposable, IEnumerator
	{
		private int <>1__state;

		private object <>2__current;

		public Interaction_WeaponSelectionPodium podium;

		public int slot;

		private float <waited>5__2;

		object IEnumerator<object>.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		object IEnumerator.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		[DebuggerHidden]
		public <DeferredEnsurePodiumOwner>d__178(int <>1__state)
		{
			this.<>1__state = <>1__state;
		}

		[DebuggerHidden]
		void IDisposable.Dispose()
		{
			<>1__state = -2;
		}

		private bool MoveNext()
		{
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Expected O, but got Unknown
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Expected O, but got Unknown
			switch (<>1__state)
			{
			default:
				return false;
			case 0:
				<>1__state = -1;
				<waited>5__2 = 0f;
				break;
			case 1:
				<>1__state = -1;
				<waited>5__2 += 0.1f;
				break;
			case 2:
				<>1__state = -1;
				<waited>5__2 += 0.1f;
				break;
			}
			if (<waited>5__2 < 3f)
			{
				if ((Object)(object)podium == (Object)null)
				{
					return false;
				}
				if (!((Component)podium).gameObject.activeInHierarchy)
				{
					<>2__current = (object)new WaitForSeconds(0.1f);
					<>1__state = 1;
					return true;
				}
				PlayerFarming val = FindActivePlayerBySlot(slot);
				EnsurePodiumCloneOwner(podium, slot, val, forceInteractable: true);
				if ((Object)(object)val != (Object)null)
				{
					return false;
				}
				<>2__current = (object)new WaitForSeconds(0.1f);
				<>1__state = 2;
				return true;
			}
			return false;
		}

		bool IEnumerator.MoveNext()
		{
			//ILSpy generated this explicit interface implementation from .override directive in MoveNext
			return this.MoveNext();
		}

		[DebuggerHidden]
		void IEnumerator.Reset()
		{
			throw new NotSupportedException();
		}
	}

	[CompilerGenerated]
	private sealed class <DeferredPositionAllPlayers>d__188 : IEnumerator<object>, IDisposable, IEnumerator
	{
		private int <>1__state;

		private object <>2__current;

		public int expectedTotal;

		public Vector3 pos;

		public bool increment;

		private float <waited>5__2;

		object IEnumerator<object>.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		object IEnumerator.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		[DebuggerHidden]
		public <DeferredPositionAllPlayers>d__188(int <>1__state)
		{
			this.<>1__state = <>1__state;
		}

		[DebuggerHidden]
		void IDisposable.Dispose()
		{
			<>1__state = -2;
		}

		private bool MoveNext()
		{
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Expected O, but got Unknown
			switch (<>1__state)
			{
			default:
				return false;
			case 0:
				<>1__state = -1;
				<waited>5__2 = 0f;
				break;
			case 1:
				<>1__state = -1;
				<waited>5__2 += 0.25f;
				break;
			}
			if (PlayerFarming.playersCount < expectedTotal && <waited>5__2 < 15f)
			{
				<>2__current = (object)new WaitForSeconds(0.25f);
				<>1__state = 1;
				return true;
			}
			Plugin.Log.LogInfo((object)$"DeferredPositionAllPlayers: proceeding with {PlayerFarming.playersCount} players after {<waited>5__2:F1}s");
			_positioningDeferred = false;
			PlayerFarming.PositionAllPlayers(pos, increment);
			return false;
		}

		bool IEnumerator.MoveNext()
		{
			//ILSpy generated this explicit interface implementation from .override directive in MoveNext
			return this.MoveNext();
		}

		[DebuggerHidden]
		void IEnumerator.Reset()
		{
			throw new NotSupportedException();
		}
	}

	[CompilerGenerated]
	private sealed class <DelayedRespawnAfterReviveRoutine>d__140 : IEnumerator<object>, IDisposable, IEnumerator
	{
		private int <>1__state;

		private object <>2__current;

		public string reason;

		private bool <allowDuringReviveFlow>5__2;

		private float <deadline>5__3;

		private int <attempts>5__4;

		private int <i>5__5;

		object IEnumerator<object>.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		object IEnumerator.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		[DebuggerHidden]
		public <DelayedRespawnAfterReviveRoutine>d__140(int <>1__state)
		{
			this.<>1__state = <>1__state;
		}

		[DebuggerHidden]
		void IDisposable.Dispose()
		{
			int num = <>1__state;
			if (num == -3 || (uint)(num - 1) <= 2u)
			{
				try
				{
				}
				finally
				{
					<>m__Finally1();
				}
			}
			<>1__state = -2;
		}

		private bool MoveNext()
		{
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Expected O, but got Unknown
			//IL_0345: Unknown result type (might be due to invalid IL or missing references)
			//IL_034f: Expected O, but got Unknown
			//IL_0261: Unknown result type (might be due to invalid IL or missing references)
			//IL_026b: Expected O, but got Unknown
			bool result;
			try
			{
				List<int> missingSpawnableExtraSlots;
				bool flag;
				bool isSpawningOrRemovingPlayer;
				bool flag2;
				switch (<>1__state)
				{
				default:
					result = false;
					goto end_IL_0000;
				case 0:
				{
					<>1__state = -1;
					<>1__state = -3;
					if ((Object)(object)CoopManager.Instance == (Object)null)
					{
						result = false;
						break;
					}
					<allowDuringReviveFlow>5__2 = IsWakeAllRespawnReason(reason) || IsSacrificialReviveFlowReason(reason);
					float num = (<allowDuringReviveFlow>5__2 ? 0.05f : 0.35f);
					<>2__current = (object)new WaitForSeconds(num);
					<>1__state = 1;
					result = true;
					goto end_IL_0000;
				}
				case 1:
					<>1__state = -3;
					<deadline>5__3 = Time.unscaledTime + 15f;
					<attempts>5__4 = 0;
					goto IL_0281;
				case 2:
					<>1__state = -3;
					goto IL_0281;
				case 3:
					{
						<>1__state = -3;
						if (AnyNonLambPlayerNeedsWakeRecovery())
						{
							EnsureAllPlayersAwake(reason + ".DelayedRespawnAfterReviveRoutine.stabilize");
							EnsureAllExtraPlayersUnlocked(reason + ".DelayedRespawnAfterReviveRoutine.stabilize");
							QueuePostReviveHardResetForAll(reason + ".DelayedRespawnAfterReviveRoutine.stabilize");
						}
						<i>5__5++;
						goto IL_03bd;
					}
					IL_03bd:
					if (<i>5__5 >= 8 || (Object)(object)CoopManager.Instance == (Object)null || !CoopManager.CoopActive)
					{
						goto IL_03c9;
					}
					<>2__current = (object)new WaitForSeconds(0.25f);
					<>1__state = 3;
					result = true;
					goto end_IL_0000;
					IL_0281:
					if (!(Time.unscaledTime < <deadline>5__3))
					{
						goto IL_0291;
					}
					if ((Object)(object)CoopManager.Instance == (Object)null || !CoopManager.CoopActive)
					{
						result = false;
						break;
					}
					_nextAutoRespawnAttemptAt = 0f;
					TryAutoRespawnMissingExtraSlots($"{reason}.poll{<attempts>5__4}");
					if ((reason.StartsWith("WakeAllKnockedOutPlayers", StringComparison.Ordinal) || IsSacrificialReviveFlowReason(reason)) && AnyNonLambPlayerNeedsWakeRecovery())
					{
						EnsureAllPlayersAwake(reason + ".DelayedRespawnAfterReviveRoutine");
						EnsureAllExtraPlayersUnlocked(reason + ".DelayedRespawnAfterReviveRoutine");
						QueuePostReviveHardResetForAll(reason + ".DelayedRespawnAfterReviveRoutine");
					}
					PrunePendingSpawnSlots();
					missingSpawnableExtraSlots = GetMissingSpawnableExtraSlots();
					flag = _pendingSpawnSlots.Count > 0;
					isSpawningOrRemovingPlayer = CoopManager.Instance.IsSpawningOrRemovingPlayer;
					flag2 = IsReviveOrCutsceneFlowActive();
					if (missingSpawnableExtraSlots.Count == 0 && !flag && !isSpawningOrRemovingPlayer && (!flag2 | <allowDuringReviveFlow>5__2))
					{
						if (<attempts>5__4 > 0)
						{
							Plugin.Log.LogInfo((object)$"[MP] Delayed revive respawn settled after {<attempts>5__4} poll(s) ({reason})");
						}
						goto IL_0291;
					}
					if (<attempts>5__4 % 8 == 0)
					{
						Plugin.Log.LogInfo((object)$"[MP] Delayed revive respawn polling ({reason}): missing={missingSpawnableExtraSlots.Count}, pending={_pendingSpawnSlots.Count}, blocked={flag2}, spawning={isSpawningOrRemovingPlayer}");
					}
					<attempts>5__4++;
					<>2__current = (object)new WaitForSeconds(0.2f);
					<>1__state = 2;
					result = true;
					goto end_IL_0000;
					IL_0291:
					_nextAutoRespawnAttemptAt = 0f;
					TryAutoRespawnMissingExtraSlots(reason + ".final");
					if (reason.StartsWith("WakeAllKnockedOutPlayers", StringComparison.Ordinal) || IsSacrificialReviveFlowReason(reason))
					{
						if (AnyNonLambPlayerNeedsWakeRecovery())
						{
							EnsureAllPlayersAwake(reason + ".DelayedRespawnAfterReviveRoutine.final");
							EnsureAllExtraPlayersUnlocked(reason + ".DelayedRespawnAfterReviveRoutine.final");
							QueuePostReviveHardResetForAll(reason + ".DelayedRespawnAfterReviveRoutine.final");
						}
						<i>5__5 = 0;
						goto IL_03bd;
					}
					goto IL_03c9;
					IL_03c9:
					<>m__Finally1();
					result = false;
					goto end_IL_0000;
				}
				<>m__Finally1();
				end_IL_0000:;
			}
			catch
			{
				//try-fault
				((IDisposable)this).Dispose();
				throw;
			}
			return result;
		}

		bool IEnumerator.MoveNext()
		{
			//ILSpy generated this explicit interface implementation from .override directive in MoveNext
			return this.MoveNext();
		}

		private void <>m__Finally1()
		{
			<>1__state = -1;
			_delayedRespawnAfterReviveQueued = false;
		}

		[DebuggerHidden]
		void IEnumerator.Reset()
		{
			throw new NotSupportedException();
		}
	}

	[CompilerGenerated]
	private sealed class <DungeonRoomTransitionStabilizeRoutine>d__195 : IEnumerator<object>, IDisposable, IEnumerator
	{
		private int <>1__state;

		private object <>2__current;

		public int roomId;

		public string reason;

		private int <i>5__2;

		object IEnumerator<object>.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		object IEnumerator.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		[DebuggerHidden]
		public <DungeonRoomTransitionStabilizeRoutine>d__195(int <>1__state)
		{
			this.<>1__state = <>1__state;
		}

		[DebuggerHidden]
		void IDisposable.Dispose()
		{
			int num = <>1__state;
			if (num == -3 || (uint)(num - 1) <= 1u)
			{
				try
				{
				}
				finally
				{
					<>m__Finally1();
				}
			}
			<>1__state = -2;
		}

		private bool MoveNext()
		{
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Expected O, but got Unknown
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_017d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0187: Expected O, but got Unknown
			bool result;
			try
			{
				switch (<>1__state)
				{
				default:
					result = false;
					goto end_IL_0000;
				case 0:
					<>1__state = -1;
					if (_dungeonRoomStabilizeRunning)
					{
						result = false;
					}
					else
					{
						_dungeonRoomStabilizeRunning = true;
						<>1__state = -3;
						<>2__current = (object)new WaitForSeconds(0.2f);
						<>1__state = 1;
						result = true;
					}
					goto end_IL_0000;
				case 1:
					<>1__state = -3;
					<i>5__2 = 0;
					break;
				case 2:
					<>1__state = -3;
					<i>5__2++;
					break;
				}
				if (<i>5__2 < 18)
				{
					if ((Object)(object)CoopManager.Instance == (Object)null || !CoopManager.CoopActive)
					{
						result = false;
						goto IL_01bf;
					}
					if (!GameManager.IsDungeon(PlayerFarming.Location))
					{
						result = false;
						goto IL_01bf;
					}
					int currentDungeonRoomInstanceIdSafe = GetCurrentDungeonRoomInstanceIdSafe();
					if (currentDungeonRoomInstanceIdSafe != int.MinValue && currentDungeonRoomInstanceIdSafe != roomId)
					{
						result = false;
						goto IL_01bf;
					}
					ClearFalseKnockedOutStatesForAll("RoomStabilize:" + reason);
					EnsureAllExtraPlayersUnlocked("RoomStabilize:" + reason);
					if (<i>5__2 <= 4)
					{
						StabilizeGoatRoomEntryState($"{reason}.tick{<i>5__2}");
					}
					if (<i>5__2 == 0 || <i>5__2 == 2 || <i>5__2 == 6 || <i>5__2 == 12)
					{
						AggressiveControllerOwnershipHeartbeat("RoomStabilize:" + reason);
						_nextAutoRespawnAttemptAt = 0f;
						TryAutoRespawnMissingExtraSlots($"RoomStabilize:{reason}.tick{<i>5__2}");
					}
					<>2__current = (object)new WaitForSeconds(0.2f);
					<>1__state = 2;
					result = true;
				}
				else
				{
					<>m__Finally1();
					result = false;
				}
				goto end_IL_0000;
				IL_01bf:
				<>m__Finally1();
				end_IL_0000:;
			}
			catch
			{
				//try-fault
				((IDisposable)this).Dispose();
				throw;
			}
			return result;
		}

		bool IEnumerator.MoveNext()
		{
			//ILSpy generated this explicit interface implementation from .override directive in MoveNext
			return this.MoveNext();
		}

		private void <>m__Finally1()
		{
			<>1__state = -1;
			_dungeonRoomStabilizeRunning = false;
		}

		[DebuggerHidden]
		void IEnumerator.Reset()
		{
			throw new NotSupportedException();
		}
	}

	[CompilerGenerated]
	private sealed class <EnsureP2DungeonEntranceNotStuckRoutine>d__172 : IEnumerator<object>, IDisposable, IEnumerator
	{
		private int <>1__state;

		private object <>2__current;

		private float <waited>5__2;

		object IEnumerator<object>.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		object IEnumerator.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		[DebuggerHidden]
		public <EnsureP2DungeonEntranceNotStuckRoutine>d__172(int <>1__state)
		{
			this.<>1__state = <>1__state;
		}

		[DebuggerHidden]
		void IDisposable.Dispose()
		{
			int num = <>1__state;
			if (num == -3 || (uint)(num - 1) <= 1u)
			{
				try
				{
				}
				finally
				{
					<>m__Finally1();
				}
			}
			<>1__state = -2;
		}

		private bool MoveNext()
		{
			//IL_026e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b7: Expected O, but got Unknown
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Expected O, but got Unknown
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01db: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_013a: Unknown result type (might be due to invalid IL or missing references)
			//IL_017a: Unknown result type (might be due to invalid IL or missing references)
			//IL_017f: Unknown result type (might be due to invalid IL or missing references)
			//IL_018e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0192: Invalid comparison between Unknown and I4
			//IL_0194: Unknown result type (might be due to invalid IL or missing references)
			//IL_0198: Invalid comparison between Unknown and I4
			//IL_019a: Unknown result type (might be due to invalid IL or missing references)
			//IL_019e: Invalid comparison between Unknown and I4
			//IL_01a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a4: Invalid comparison between Unknown and I4
			bool result;
			try
			{
				switch (<>1__state)
				{
				default:
					result = false;
					goto end_IL_0000;
				case 0:
					<>1__state = -1;
					if (_p2EntranceGuardRunning)
					{
						result = false;
					}
					else
					{
						_p2EntranceGuardRunning = true;
						<>1__state = -3;
						if (!GameManager.IsDungeon(PlayerFarming.Location))
						{
							result = false;
							break;
						}
						<>2__current = (object)new WaitForSeconds(1.8f);
						<>1__state = 1;
						result = true;
					}
					goto end_IL_0000;
				case 1:
					<>1__state = -3;
					<waited>5__2 = 0f;
					goto IL_02dc;
				case 2:
					{
						<>1__state = -3;
						<waited>5__2 += 0.2f;
						goto IL_02dc;
					}
					IL_02dc:
					if (<waited>5__2 < 3f)
					{
						if (!GameManager.IsDungeon(PlayerFarming.Location))
						{
							result = false;
							break;
						}
						PlayerFarming instance = PlayerFarming.Instance;
						PlayerFarming val = FindActivePlayerBySlot(1);
						if ((Object)(object)instance != (Object)null && (Object)(object)val != (Object)null && (Object)(object)((Component)instance).gameObject != (Object)null && (Object)(object)((Component)val).gameObject != (Object)null && ((Component)instance).gameObject.activeInHierarchy && ((Component)val).gameObject.activeInHierarchy)
						{
							Vector3 val2 = ((Component)val).transform.position - ((Component)instance).transform.position;
							float magnitude = ((Vector3)(ref val2)).magnitude;
							bool flag = val2.y < -2.8f && Mathf.Abs(val2.x) < 4.5f && magnitude > 3.2f;
							bool flag2 = false;
							bool flag3 = IsFalseKnockedOutState(val);
							try
							{
								if ((Object)(object)val.state != (Object)null)
								{
									State cURRENT_STATE = val.state.CURRENT_STATE;
									flag2 = val.state.LockStateChanges || (int)cURRENT_STATE == 13 || (int)cURRENT_STATE == 49 || (int)cURRENT_STATE == 24 || (int)cURRENT_STATE == 16;
								}
							}
							catch
							{
							}
							if (flag && (flag2 || flag3))
							{
								Vector3 position = ((Component)instance).transform.position + new Vector3(1.25f, -0.1f, 0f);
								((Component)val).transform.position = position;
								try
								{
									if ((Object)(object)val.state != (Object)null)
									{
										val.state.LockStateChanges = false;
										val.state.CURRENT_STATE = (State)0;
									}
								}
								catch
								{
								}
								try
								{
									if ((Object)(object)val.health != (Object)null && ((Health)val.health).CurrentHP <= 0f)
									{
										((Health)val.health).HP = 2f;
									}
								}
								catch
								{
								}
								val.IsKnockedOut = false;
								Plugin.Log.LogWarning((object)$"[MP] P2 entrance unstuck applied (dy={val2.y:0.00}, dist={magnitude:0.00}, stateLocked={flag2}, falseDowned={flag3})");
								result = false;
								break;
							}
						}
						<>2__current = (object)new WaitForSeconds(0.2f);
						<>1__state = 2;
						result = true;
					}
					else
					{
						<>m__Finally1();
						result = false;
					}
					goto end_IL_0000;
				}
				<>m__Finally1();
				end_IL_0000:;
			}
			catch
			{
				//try-fault
				((IDisposable)this).Dispose();
				throw;
			}
			return result;
		}

		bool IEnumerator.MoveNext()
		{
			//ILSpy generated this explicit interface implementation from .override directive in MoveNext
			return this.MoveNext();
		}

		private void <>m__Finally1()
		{
			<>1__state = -1;
			_p2EntranceGuardRunning = false;
		}

		[DebuggerHidden]
		void IEnumerator.Reset()
		{
			throw new NotSupportedException();
		}
	}

	[CompilerGenerated]
	private sealed class <PostReviveHardResetRoutine>d__110 : IEnumerator<object>, IDisposable, IEnumerator
	{
		private int <>1__state;

		private object <>2__current;

		public int slot;

		public string reason;

		private int <settledTicks>5__2;

		private int <i>5__3;

		object IEnumerator<object>.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		object IEnumerator.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		[DebuggerHidden]
		public <PostReviveHardResetRoutine>d__110(int <>1__state)
		{
			this.<>1__state = <>1__state;
		}

		[DebuggerHidden]
		void IDisposable.Dispose()
		{
			int num = <>1__state;
			if (num == -3 || (uint)(num - 1) <= 1u)
			{
				try
				{
				}
				finally
				{
					<>m__Finally1();
				}
			}
			<>1__state = -2;
		}

		private bool MoveNext()
		{
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Expected O, but got Unknown
			//IL_0139: Unknown result type (might be due to invalid IL or missing references)
			//IL_0143: Expected O, but got Unknown
			bool result;
			try
			{
				switch (<>1__state)
				{
				default:
					result = false;
					goto end_IL_0000;
				case 0:
					<>1__state = -1;
					<>1__state = -3;
					<settledTicks>5__2 = 0;
					<i>5__3 = 0;
					break;
				case 1:
					<>1__state = -3;
					goto IL_0156;
				case 2:
					{
						<>1__state = -3;
						goto IL_0156;
					}
					IL_0156:
					<i>5__3++;
					break;
				}
				PlayerFarming val;
				int num;
				int num2;
				if (<i>5__3 < 18)
				{
					if ((Object)(object)CoopManager.Instance == (Object)null || !CoopManager.CoopActive)
					{
						result = false;
						goto IL_017d;
					}
					val = FindActivePlayerBySlot(slot);
					if (!((Object)(object)val == (Object)null))
					{
						if (!NeedsWakeRecovery(val))
						{
							num = (IsFalseKnockedOutState(val) ? 1 : 0);
							if (num == 0)
							{
								num2 = ((<i>5__3 < 6) ? 1 : 0);
								goto IL_00bd;
							}
						}
						else
						{
							num = 1;
						}
						num2 = 0;
						goto IL_00bd;
					}
					<>2__current = (object)new WaitForSeconds(0.1f);
					<>1__state = 1;
					result = true;
				}
				else
				{
					<>m__Finally1();
					result = false;
				}
				goto end_IL_0000;
				IL_00bd:
				bool flag = (byte)num2 != 0;
				if (num != 0 || <i>5__3 < 2 || flag)
				{
					ForceReviveVisualState(val, $"PostRevive:{reason}.tick{<i>5__3}");
				}
				if (num == 0)
				{
					<settledTicks>5__2++;
					if (<settledTicks>5__2 >= 6 && <i>5__3 >= 8)
					{
						result = false;
						goto IL_017d;
					}
				}
				else
				{
					<settledTicks>5__2 = 0;
				}
				<>2__current = (object)new WaitForSeconds((<i>5__3 < 6) ? 0.12f : 0.18f);
				<>1__state = 2;
				result = true;
				goto end_IL_0000;
				IL_017d:
				<>m__Finally1();
				end_IL_0000:;
			}
			catch
			{
				//try-fault
				((IDisposable)this).Dispose();
				throw;
			}
			return result;
		}

		bool IEnumerator.MoveNext()
		{
			//ILSpy generated this explicit interface implementation from .override directive in MoveNext
			return this.MoveNext();
		}

		private void <>m__Finally1()
		{
			<>1__state = -1;
			_postReviveHardResetSlots.Remove(slot);
		}

		[DebuggerHidden]
		void IEnumerator.Reset()
		{
			throw new NotSupportedException();
		}
	}

	[CompilerGenerated]
	private sealed class <ReassignHudHeartsNextFrame>d__207 : IEnumerator<object>, IDisposable, IEnumerator
	{
		private int <>1__state;

		private object <>2__current;

		public PlayerFarming p;

		public HUD_Hearts hearts;

		object IEnumerator<object>.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		object IEnumerator.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		[DebuggerHidden]
		public <ReassignHudHeartsNextFrame>d__207(int <>1__state)
		{
			this.<>1__state = <>1__state;
		}

		[DebuggerHidden]
		void IDisposable.Dispose()
		{
			<>1__state = -2;
		}

		private bool MoveNext()
		{
			switch (<>1__state)
			{
			default:
				return false;
			case 0:
				<>1__state = -1;
				<>2__current = null;
				<>1__state = 1;
				return true;
			case 1:
				<>1__state = -1;
				if ((Object)(object)p != (Object)null && (Object)(object)hearts != (Object)null)
				{
					if ((Object)(object)hearts.playerFarming != (Object)(object)p)
					{
						hearts.playerFarming = p;
					}
					if ((Object)(object)p.hudHearts != (Object)(object)hearts)
					{
						p.hudHearts = hearts;
						Plugin.Log.LogInfo((object)$"[MP] Re-assigned hudHearts for playerID={p.playerID} after frame delay");
					}
				}
				<>2__current = null;
				<>1__state = 2;
				return true;
			case 2:
				<>1__state = -1;
				SyncFaithAmmoForOwner(p, hearts, "ReassignHudHeartsNextFrame", forceReinit: true);
				return false;
			}
		}

		bool IEnumerator.MoveNext()
		{
			//ILSpy generated this explicit interface implementation from .override directive in MoveNext
			return this.MoveNext();
		}

		[DebuggerHidden]
		void IEnumerator.Reset()
		{
			throw new NotSupportedException();
		}
	}

	[CompilerGenerated]
	private sealed class <RespawnExtraSlots>d__58 : IEnumerator<object>, IDisposable, IEnumerator
	{
		private int <>1__state;

		private object <>2__current;

		public int count;

		private bool <inDungeon>5__2;

		private float <timeout>5__3;

		private float <waited>5__4;

		private int <s>5__5;

		private float <spawnWait>5__6;

		object IEnumerator<object>.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		object IEnumerator.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		[DebuggerHidden]
		public <RespawnExtraSlots>d__58(int <>1__state)
		{
			this.<>1__state = <>1__state;
		}

		[DebuggerHidden]
		void IDisposable.Dispose()
		{
			int num = <>1__state;
			if (num == -3 || (uint)(num - 1) <= 3u)
			{
				try
				{
				}
				finally
				{
					<>m__Finally1();
				}
			}
			<>1__state = -2;
		}

		private bool MoveNext()
		{
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_045c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0466: Expected O, but got Unknown
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Expected O, but got Unknown
			//IL_014c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0156: Expected O, but got Unknown
			//IL_02d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e2: Expected O, but got Unknown
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Invalid comparison between Unknown and I4
			bool result;
			try
			{
				switch (<>1__state)
				{
				default:
					result = false;
					goto end_IL_0000;
				case 0:
					<>1__state = -1;
					_startupExtraRespawnDepth++;
					<>1__state = -3;
					<inDungeon>5__2 = GameManager.IsDungeon(PlayerFarming.Location);
					<timeout>5__3 = 30f;
					<waited>5__4 = 0f;
					goto IL_00f9;
				case 1:
					<>1__state = -3;
					<waited>5__4 += 0.25f;
					goto IL_00f9;
				case 2:
					<>1__state = -3;
					<s>5__5 = 2;
					goto IL_048b;
				case 3:
					<>1__state = -3;
					<spawnWait>5__6 += 0.1f;
					goto IL_030a;
				case 4:
					{
						<>1__state = -3;
						goto IL_0479;
					}
					IL_048b:
					if (<s>5__5 >= 2 + count || <s>5__5 >= 4)
					{
						break;
					}
					if (_pendingSpawnSlots.Contains(<s>5__5))
					{
						Plugin.Log.LogInfo((object)$"RespawnExtraSlots: slot {<s>5__5} already pending, skipping duplicate startup spawn");
					}
					else if ((Object)(object)FindActivePlayerBySlot(<s>5__5) != (Object)null)
					{
						Plugin.Log.LogInfo((object)$"RespawnExtraSlots: slot {<s>5__5} already active, skipping startup spawn");
					}
					else if (CoopManager.AllPlayerGameObjects != null && <s>5__5 < CoopManager.AllPlayerGameObjects.Length && (Object)(object)CoopManager.AllPlayerGameObjects[<s>5__5] != (Object)null && CoopManager.AllPlayerGameObjects[<s>5__5].activeInHierarchy)
					{
						Plugin.Log.LogInfo((object)$"RespawnExtraSlots: slot {<s>5__5} already has active gameobject, skipping startup spawn");
					}
					else
					{
						Player player = RewiredInputManager.GetPlayer(<s>5__5);
						if (player != null && player.controllers != null && player.controllers.Joysticks != null && player.controllers.Joysticks.Count > 0)
						{
							Plugin.Log.LogInfo((object)$"RespawnExtraSlots: spawning slot {<s>5__5}");
							<spawnWait>5__6 = 0f;
							goto IL_030a;
						}
						Plugin.Log.LogWarning((object)$"RespawnExtraSlots: slot {<s>5__5} has no joystick, skipping");
					}
					goto IL_0479;
					IL_0479:
					<s>5__5++;
					goto IL_048b;
					IL_030a:
					if ((Object)(object)CoopManager.Instance != (Object)null && CoopManager.Instance.IsSpawningOrRemovingPlayer && <spawnWait>5__6 < 10f)
					{
						<>2__current = (object)new WaitForSeconds(0.1f);
						<>1__state = 3;
						result = true;
					}
					else
					{
						if (_pendingSpawnSlots.Contains(<s>5__5))
						{
							Plugin.Log.LogInfo((object)$"RespawnExtraSlots: slot {<s>5__5} became pending during wait, skipping duplicate startup spawn");
							goto IL_0479;
						}
						if ((Object)(object)FindActivePlayerBySlot(<s>5__5) != (Object)null)
						{
							Plugin.Log.LogInfo((object)$"RespawnExtraSlots: slot {<s>5__5} became active during wait, skipping duplicate startup spawn");
							goto IL_0479;
						}
						_pendingSpawnSlots.Add(<s>5__5);
						bool flag = false;
						_pendingSpawnUseAnimation[<s>5__5] = flag;
						Plugin.Log.LogInfo((object)$"RespawnExtraSlots: slot {<s>5__5} spawn mode animated={flag}");
						try
						{
							CoopManager.Instance.SpawnCoopPlayer(<s>5__5, flag, -1f);
						}
						catch (Exception ex)
						{
							_pendingSpawnSlots.Remove(<s>5__5);
							_pendingSpawnUseAnimation.Remove(<s>5__5);
							Plugin.Log.LogWarning((object)$"RespawnExtraSlots: failed spawning slot {<s>5__5}: {ex.GetType().Name}: {ex.Message}");
						}
						<>2__current = (object)new WaitForSeconds(1f);
						<>1__state = 4;
						result = true;
					}
					goto end_IL_0000;
					IL_00f9:
					if (<waited>5__4 < <timeout>5__3 && (!((Object)(object)PlayerFarming.Instance != (Object)null) || !((Component)PlayerFarming.Instance).gameObject.activeSelf || PlayerFarming.playersCount < 1 || !((Object)(object)PlayerFarming.Instance.state != (Object)null) || (!<inDungeon>5__2 && (int)PlayerFarming.Instance.state.CURRENT_STATE == 13)))
					{
						<>2__current = (object)new WaitForSeconds(0.25f);
						<>1__state = 1;
						result = true;
					}
					else if (<waited>5__4 >= <timeout>5__3)
					{
						Plugin.Log.LogWarning((object)"RespawnExtraSlots: timed out waiting for PlayerFarming.Instance");
						result = false;
						<>m__Finally1();
					}
					else
					{
						if (<inDungeon>5__2)
						{
							_dungeonIntroProtectUntil = Time.unscaledTime + 8f;
						}
						<>2__current = (object)new WaitForSeconds(1f);
						<>1__state = 2;
						result = true;
					}
					goto end_IL_0000;
				}
				<>m__Finally1();
				result = false;
				end_IL_0000:;
			}
			catch
			{
				//try-fault
				((IDisposable)this).Dispose();
				throw;
			}
			return result;
		}

		bool IEnumerator.MoveNext()
		{
			//ILSpy generated this explicit interface implementation from .override directive in MoveNext
			return this.MoveNext();
		}

		private void <>m__Finally1()
		{
			<>1__state = -1;
			_startupExtraRespawnDepth = Math.Max(0, _startupExtraRespawnDepth - 1);
		}

		[DebuggerHidden]
		void IEnumerator.Reset()
		{
			throw new NotSupportedException();
		}
	}

	private static bool _removingPlayer = false;

	private static bool _manualRemoveRequested = false;

	private static float _autoRemoveSuppressedUntil = 0f;

	private const float AutoRemoveSuppressSeconds = 8f;

	private static int _savedExtraSlotCount = 0;

	private static bool _autoRespawnRoutineRunning = false;

	private static float _nextAutoRespawnAttemptAt = 0f;

	private static float _nextAutoRespawnHeartbeatAt = 0f;

	private static float _nextControllerHealHeartbeatAt = 0f;

	private static float _nextRumbleCleanupAt = 0f;

	private static readonly HashSet<int> _pendingSpawnSlots = new HashSet<int>();

	private static readonly Dictionary<int, bool> _pendingSpawnUseAnimation = new Dictionary<int, bool>();

	private static readonly Dictionary<int, float> _pendingSpawnFirstSeenAt = new Dictionary<int, float>();

	private static readonly HashSet<int> _desiredExtraSlots = new HashSet<int>();

	private static int _startupExtraRespawnDepth = 0;

	private static float _dungeonIntroProtectUntil = 0f;

	private static float _nextPendingBlockLogAt = 0f;

	private static string _lastLoggedDungeonRoomPath = null;

	private static bool _p2EntranceGuardRunning = false;

	private static bool _dungeonRoomStabilizeRunning = false;

	private static int _lastStabilizedDungeonRoomId = int.MinValue;

	private static float _nextDungeonRoomStabilizeCheckAt = 0f;

	private static float _roomEntryDistanceRepositionGraceUntil = 0f;

	private static readonly HashSet<int> _warnedOrphanSlotObjects = new HashSet<int>();

	private static readonly HashSet<int> _postReviveHardResetSlots = new HashSet<int>();

	private static float _lastObservedWakeHealth = 2f;

	private static float _lastObservedSacrificialWakeHealth = 2f;

	private static float _sacrificialReviveWindowUntil = 0f;

	private const float SacrificialReviveWindowSeconds = 7f;

	private const float BoostedWakeHealthThreshold = 2.01f;

	private static readonly Dictionary<int, float> _nextExtraFalseDownedWatchdogAt = new Dictionary<int, float>();

	private static readonly Dictionary<int, float> _postReviveRaceGuardUntil = new Dictionary<int, float>();

	private static readonly Dictionary<int, float> _nextPostReviveForceApplyAt = new Dictionary<int, float>();

	private static float _nextPostReviveRaceGuardHeartbeatAt = 0f;

	private const float PostReviveRaceGuardSeconds = 4f;

	private const float PostReviveRaceGuardPollInterval = 0.18f;

	private static Image _p2Widget;

	private static Image _p3Widget;

	private static Image _p4Widget;

	private static RectTransform _p2Arrow;

	private static RectTransform _p3Arrow;

	private static RectTransform _p4Arrow;

	private static readonly Dictionary<int, Sprite> _cachedSprites = new Dictionary<int, Sprite>();

	private static readonly Dictionary<int, Image> _cachedTextImages = new Dictionary<int, Image>();

	private static readonly Dictionary<int, SpriteRenderer> _cachedHaloSR = new Dictionary<int, SpriteRenderer>();

	private static readonly HashSet<int> _haloLogged = new HashSet<int>();

	private static readonly Dictionary<int, Sprite> _cachedHaloSprites = new Dictionary<int, Sprite>();

	private static readonly Dictionary<int, string> _haloSpriteNames = new Dictionary<int, string>
	{
		{ 2, "halo_orange.png" },
		{ 3, "halo_blue.png" }
	};

	private static int _podiumExtraCount = 0;

	private static readonly Vector3[] SpawnOffsets = (Vector3[])(object)new Vector3[4]
	{
		Vector3.zero,
		new Vector3(1.5f, 0f, 0f),
		new Vector3(0f, 1.5f, 0f),
		new Vector3(0f, -1.5f, 0f)
	};

	private static readonly FieldInfo _playerControllerUntouchableTimerField = AccessTools.Field(typeof(PlayerController), "untouchableTimer");

	private static readonly FieldInfo _playerControllerInvincibleTimerField = AccessTools.Field(typeof(PlayerController), "invincibleTimer");

	private static readonly FieldInfo _playerControllerImmuneToProjectilesTimerField = AccessTools.Field(typeof(PlayerController), "immuneToProjectilesTimer");

	private static readonly FieldInfo _playerControllerUntouchableTimerFlashField = AccessTools.Field(typeof(PlayerController), "untouchableTimerFlash");

	private static Type _cachedHealthReflectionType;

	private static FieldInfo _healthInvincibleField;

	private static FieldInfo _healthUntouchableField;

	private static FieldInfo _healthIgnoreProjectilesField;

	private static FieldInfo _healthMaxHpField;

	private static FieldInfo _healthTotalHpField;

	private static PropertyInfo _healthIgnoreProjectilesProperty;

	private static PropertyInfo _healthMaxHpProperty;

	private static PropertyInfo _healthTotalHpProperty;

	private static MethodInfo _healthClearAllStasisEffectsMethod;

	private static bool _faithAmmoDumped = false;

	private static bool _delayedRespawnAfterReviveQueued = false;

	private const float DelayedReviveRespawnInitialDelay = 0.35f;

	private const float DelayedReviveRespawnPollInterval = 0.2f;

	private const float DelayedReviveRespawnMaxDuration = 15f;

	private static readonly Vector3[] _teleporterOffsets = (Vector3[])(object)new Vector3[4]
	{
		new Vector3(-0.75f, 0f, 0f),
		new Vector3(0.75f, 0f, 0f),
		new Vector3(-1.5f, 0f, 0f),
		new Vector3(1.5f, 0f, 0f)
	};

	private static bool _spawnedExtraWeaponPodiums = false;

	private static bool _spawnedExtraSpellPodiums = false;

	private static readonly FieldInfo _twinPodiumField = typeof(Interaction_WeaponSelectionPodium).GetField("TwinPodium", BindingFlags.Instance | BindingFlags.NonPublic);

	private static readonly Dictionary<int, List<Interaction_WeaponSelectionPodium>> _podiumClones = new Dictionary<int, List<Interaction_WeaponSelectionPodium>>();

	private static readonly Dictionary<int, int> _podiumOwnerSlotByInstanceId = new Dictionary<int, int>();

	private static bool _positioningDeferred = false;

	private static readonly Dictionary<int, GameObject> _extraHeartBars = new Dictionary<int, GameObject>();

	private static readonly HashSet<int> _suppressedHeartEffectLogs = new HashSet<int>();

	private static readonly HashSet<int> _suppressedFaithAmmoLogs = new HashSet<int>();

	private static readonly HashSet<int> _suppressedTrinketHudLogs = new HashSet<int>();

	private static readonly HashSet<int> _missingDamageIconLogs = new HashSet<int>();

	private static readonly MethodInfo _hudHeartsClearHealthEvents = typeof(HUD_Hearts).GetMethod("ClearHealthEvents", BindingFlags.Instance | BindingFlags.NonPublic);

	private static readonly MethodInfo _faithAmmoUpdateBar = typeof(FaithAmmo).GetMethod("UpdateBar", BindingFlags.Instance | BindingFlags.NonPublic);

	private static readonly FieldInfo _coopIndicatorAnimateOnDamagedField = typeof(CoopIndicatorIcon).GetField("animateIconOnDamaged", BindingFlags.Instance | BindingFlags.NonPublic);

	private static bool _reroutingFaithAmmoUse = false;

	private static int _safeBiomeClearPatchCountLog = -1;

	private static readonly Dictionary<char, int[]> _digitBitmaps = new Dictionary<char, int[]>
	{
		{
			'1',
			new int[35]
			{
				0, 1, 1, 0, 0, 1, 1, 1, 0, 0,
				0, 1, 1, 0, 0, 0, 1, 1, 0, 0,
				0, 1, 1, 0, 0, 0, 1, 1, 0, 0,
				1, 1, 1, 1, 0
			}
		},
		{
			'2',
			new int[35]
			{
				1, 1, 1, 1, 0, 1, 0, 0, 1, 1,
				0, 0, 0, 1, 1, 0, 1, 1, 1, 0,
				1, 1, 0, 0, 0, 1, 1, 0, 0, 0,
				1, 1, 1, 1, 1
			}
		},
		{
			'3',
			new int[35]
			{
				1, 1, 1, 1, 0, 1, 0, 0, 1, 1,
				0, 0, 0, 1, 1, 0, 1, 1, 1, 0,
				0, 0, 0, 1, 1, 1, 0, 0, 1, 1,
				1, 1, 1, 1, 0
			}
		},
		{
			'4',
			new int[35]
			{
				0, 0, 1, 1, 0, 0, 1, 1, 1, 0,
				1, 1, 0, 1, 0, 1, 0, 0, 1, 0,
				1, 1, 1, 1, 1, 0, 0, 0, 1, 0,
				0, 0, 1, 1, 0
			}
		}
	};

	public static void CoopManager_Awake()
	{
		GameObject[] allPlayerGameObjects = CoopManager.AllPlayerGameObjects;
		if (allPlayerGameObjects.Length < 4)
		{
			GameObject[] array = (GameObject[])(object)new GameObject[4];
			for (int i = 0; i < allPlayerGameObjects.Length; i++)
			{
				array[i] = allPlayerGameObjects[i];
			}
			typeof(CoopManager).GetField("AllPlayerGameObjects", BindingFlags.Static | BindingFlags.Public).SetValue(null, array);
			Plugin.Log.LogInfo((object)$"AllPlayerGameObjects expanded to {4}");
		}
	}

	public static void OnControllerConnected(ControllerStatusChangedEventArgs args)
	{
		if (!CoopManager.CoopActive || PlayerFarming.playersCount >= 4 || (Object)(object)CoopManager.Instance == (Object)null || CoopManager.Instance.IsSpawningOrRemovingPlayer)
		{
			return;
		}
		Joystick val = null;
		foreach (Joystick joystick in ReInput.controllers.Joysticks)
		{
			if (((Controller)joystick).id == args.controllerId)
			{
				val = joystick;
				break;
			}
		}
		if (val == null)
		{
			return;
		}
		for (int i = 0; i < 4; i++)
		{
			Player player = RewiredInputManager.GetPlayer(i);
			if (player != null && player.controllers.ContainsController((Controller)(object)val))
			{
				Plugin.Log.LogInfo((object)$"OnControllerConnected: already assigned to slot {i}, skipping");
				return;
			}
		}
		int playersCount = PlayerFarming.playersCount;
		Plugin.Log.LogInfo((object)$"OnControllerConnected: auto-assigning to slot {playersCount}");
		for (int j = 0; j < 4; j++)
		{
			RewiredInputManager.GetPlayer(j).controllers.RemoveController((Controller)(object)val);
		}
		RewiredInputManager.GetPlayer(playersCount).controllers.AddController((Controller)(object)val, true);
		MarkDesiredExtraSlot(playersCount, desired: true);
		if (playersCount >= 2)
		{
			_pendingSpawnSlots.Add(playersCount);
		}
		CoopManager.Instance.SpawnCoopPlayer(playersCount, true, -1f);
		CoopManager.CoopActive = true;
		CoopManager.RefreshCoopPlayerRewired();
		TryStopAllRumble("OnControllerConnected");
		Plugin.Log.LogInfo((object)$"Auto-spawned goat at slot {playersCount}");
	}

	public static bool AddPlayerFromMenu()
	{
		if (PlayerFarming.playersCount < 4)
		{
			Plugin.Log.LogInfo((object)$"AddPlayerFromMenu: players={PlayerFarming.playersCount}, opening assign menu");
			UICoopAssignController obj = MonoSingleton<UIManager>.Instance.ShowCoopAssignMenu();
			((UIMenuBase)obj).OnHidden = (Action)Delegate.Combine(((UIMenuBase)obj).OnHidden, (Action)delegate
			{
				if (CoopManager.CoopActive)
				{
					CoopManager.AddtionalUser = UserHelper.GetPlayer(1);
				}
			});
		}
		return false;
	}

	public static bool OnCoopButtonPressed(UIPauseMenuController __instance)
	{
		Plugin.Log.LogInfo((object)$"OnCoopButtonPressed: players={PlayerFarming.playersCount}, coopActive={CoopManager.CoopActive}");
		if (PlayerFarming.playersCount < 4)
		{
			((UIMenuBase)__instance).Hide(true);
			CoopManager.AddPlayerFromMenu();
			return false;
		}
		if (CoopManager.CoopActive)
		{
			((UIMenuBase)__instance).Hide(false);
			_manualRemoveRequested = true;
			CoopManager.RemovePlayerFromMenu();
			return false;
		}
		return true;
	}

	public static void RefreshCoopText(UIPauseMenuController __instance)
	{
		FieldInfo field = typeof(UIPauseMenuController).GetField("_coopButtonText", BindingFlags.Instance | BindingFlags.NonPublic);
		FieldInfo field2 = typeof(UIPauseMenuController).GetField("_coopButton", BindingFlags.Instance | BindingFlags.NonPublic);
		FieldInfo field3 = typeof(UIPauseMenuController).GetField("DenyCoop", BindingFlags.Instance | BindingFlags.NonPublic);
		if (field == null || field2 == null)
		{
			return;
		}
		object? value = field.GetValue(__instance);
		TextMeshProUGUI val = (TextMeshProUGUI)((value is TextMeshProUGUI) ? value : null);
		object? value2 = field2.GetValue(__instance);
		MMButton val2 = (MMButton)((value2 is MMButton) ? value2 : null);
		bool flag = field3 != null && (bool)field3.GetValue(__instance);
		if (!((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null || flag))
		{
			if (PlayerFarming.playersCount < 4)
			{
				((TMP_Text)val).text = $"Add Player ({PlayerFarming.playersCount}/{4})";
				val2.Interactable = true;
			}
			else
			{
				((TMP_Text)val).text = $"Remove Player ({PlayerFarming.playersCount}/{4})";
				val2.Interactable = true;
			}
		}
	}

	public static bool ConfirmSpawnButtonPress(UICoopAssignController __instance)
	{
		FieldInfo field = typeof(UICoopAssignController).GetField("displayedConnectedGamepads", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		FieldInfo field2 = typeof(UICoopAssignController).GetField("keyboardInputOption", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		FieldInfo field3 = typeof(UICoopAssignController).GetField("preventSpawnBufferTime", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		FieldInfo field4 = typeof(UICoopAssignController).GetField("confirmLock", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		if (field == null || field2 == null)
		{
			Plugin.Log.LogError((object)"Reflection failed");
			return true;
		}
		if (field3 != null)
		{
			float num = (float)field3.GetValue(__instance);
			if (Time.realtimeSinceStartup < num + 0.25f)
			{
				return false;
			}
		}
		if (field4 != null)
		{
			if ((bool)field4.GetValue(__instance))
			{
				return false;
			}
			field4.SetValue(__instance, true);
		}
		if (!(field.GetValue(__instance) is CoopAssignInputOption[] array))
		{
			return true;
		}
		int num2 = PlayerFarming.playersCount;
		if (num2 < 1)
		{
			num2 = 1;
		}
		Plugin.Log.LogInfo((object)$"ConfirmSpawnButtonPress: nextSlot={num2}, players={PlayerFarming.playersCount}");
		EnforceKeyboardOwnership();
		List<Joystick> list = new List<Joystick>(ReInput.controllers.Joysticks);
		for (int i = 0; i < array.Length && i < list.Count; i++)
		{
			CoopAssignInputOption val = array[i];
			if ((Object)(object)val == (Object)null || !((Component)val).gameObject.activeSelf || val.selection != -1)
			{
				continue;
			}
			Joystick val2 = list[i];
			if (val2 == null)
			{
				continue;
			}
			for (int j = 1; j < 4; j++)
			{
				if (!RewiredInputManager.GetPlayer(j).controllers.ContainsController((Controller)(object)val2))
				{
					continue;
				}
				PlayerFarming val3 = null;
				foreach (PlayerFarming player2 in PlayerFarming.players)
				{
					if (!player2.isLamb && player2.playerID == j && ((Component)player2).gameObject.activeSelf)
					{
						val3 = player2;
						break;
					}
				}
				if ((Object)(object)val3 == (Object)null)
				{
					continue;
				}
				Plugin.Log.LogInfo((object)$"Joystick [{i}] moved to Lamb side — removing goat slot {j} (dropout)");
				int playerID = val3.playerID;
				MarkDesiredExtraSlot(playerID, desired: false);
				_pendingSpawnSlots.Remove(playerID);
				_pendingSpawnUseAnimation.Remove(playerID);
				if (_cachedSprites.ContainsKey(playerID))
				{
					_cachedSprites.Remove(playerID);
				}
				if (_cachedTextImages.ContainsKey(playerID))
				{
					_cachedTextImages.Remove(playerID);
				}
				if (_cachedHaloSR.ContainsKey(playerID))
				{
					_cachedHaloSR.Remove(playerID);
				}
				if (_cachedHaloSprites.ContainsKey(playerID))
				{
					_cachedHaloSprites.Remove(playerID);
				}
				_haloLogged.Remove(playerID);
				_removingPlayer = true;
				CoopManager.AddtionalUser = null;
				UnhookVanillaCoopDelegates();
				CoopManager.Instance.RemoveCoopPlayer(val3, true, false, true);
				if (_extraHeartBars.TryGetValue(playerID, out var value) && (Object)(object)value != (Object)null)
				{
					Object.Destroy((Object)(object)value);
				}
				_extraHeartBars.Remove(playerID);
				if (PlayerFarming.playersCount > 1 && (Object)(object)HUD_Manager.Instance != (Object)null)
				{
					foreach (PlayerFarming player3 in PlayerFarming.players)
					{
						if (!player3.isLamb)
						{
							HUD_Manager.Instance.healthManager.Init(player3);
						}
					}
				}
				int num3 = 0;
				foreach (PlayerFarming player4 in PlayerFarming.players)
				{
					if (!player4.isLamb)
					{
						num3++;
					}
				}
				if (num3 <= 0)
				{
					UICoopAssignController.SetInputForSoloPlay();
					UserHelper.DisengagePlayer(1);
					CoopManager.CoopActive = false;
					CoopManager.EnableCoopBlockers(false, true);
					DifficultyManager.LoadCurrentDifficulty();
				}
				else
				{
					Player player = RewiredInputManager.GetPlayer(playerID);
					if (player != null)
					{
						foreach (Joystick item in new List<Joystick>(player.controllers.Joysticks))
						{
							player.controllers.RemoveController((Controller)(object)item);
						}
					}
					EnforceKeyboardOwnership();
					CoopManager.RefreshCoopPlayerRewired();
				}
				GameManager.GetInstance().WaitForSeconds(2f, (Action)delegate
				{
					_removingPlayer = false;
					Plugin.Log.LogInfo((object)"Dropout remove guard released");
				});
				break;
			}
			bool flag = false;
			for (int k = 1; k < 4; k++)
			{
				if (RewiredInputManager.GetPlayer(k).controllers.ContainsController((Controller)(object)val2))
				{
					flag = true;
					break;
				}
			}
			if (!flag)
			{
				for (int l = 1; l < 4; l++)
				{
					RewiredInputManager.GetPlayer(l).controllers.RemoveController((Controller)(object)val2);
				}
				if (!RewiredInputManager.GetPlayer(0).controllers.ContainsController((Controller)(object)val2))
				{
					RewiredInputManager.GetPlayer(0).controllers.AddController((Controller)(object)val2, true);
				}
				Plugin.Log.LogInfo((object)$"Joystick [{i}] assigned to Lamb (slot 0)");
			}
		}
		num2 = PlayerFarming.playersCount;
		if (num2 < 1)
		{
			num2 = 1;
		}
		for (int m = 0; m < array.Length && m < list.Count; m++)
		{
			if (num2 >= 4)
			{
				break;
			}
			CoopAssignInputOption val4 = array[m];
			if ((Object)(object)val4 == (Object)null || !((Component)val4).gameObject.activeSelf || val4.selection != 1)
			{
				continue;
			}
			val4.inputLock = false;
			Joystick val5 = list[m];
			if (val5 == null)
			{
				continue;
			}
			bool flag2 = false;
			for (int n = 1; n < 4; n++)
			{
				if (!RewiredInputManager.GetPlayer(n).controllers.ContainsController((Controller)(object)val5))
				{
					continue;
				}
				PlayerFarming val6 = null;
				foreach (PlayerFarming player5 in PlayerFarming.players)
				{
					if (!player5.isLamb && player5.playerID == n && ((Component)player5).gameObject.activeSelf)
					{
						val6 = player5;
						break;
					}
				}
				if ((Object)(object)val6 != (Object)null)
				{
					flag2 = true;
					Plugin.Log.LogInfo((object)$"Joystick [{m}] already active goat slot {n}, skipping");
					break;
				}
			}
			if (!flag2)
			{
				for (int num4 = 0; num4 < 4; num4++)
				{
					RewiredInputManager.GetPlayer(num4).controllers.RemoveController((Controller)(object)val5);
				}
				RewiredInputManager.GetPlayer(num2).controllers.AddController((Controller)(object)val5, true);
				Plugin.Log.LogInfo((object)$"Joystick [{m}] -> new goat slot {num2}");
				MarkDesiredExtraSlot(num2, desired: true);
				if (num2 >= 2)
				{
					_pendingSpawnSlots.Add(num2);
				}
				CoopManager.Instance.SpawnCoopPlayer(num2, true, -1f);
				CoopManager.CoopActive = true;
				num2++;
			}
		}
		Plugin.Log.LogInfo((object)"Spawn complete");
		((UIMenuBase)__instance).Hide(false);
		return false;
	}

	public static void CoopAssign_OnShowStarted(UICoopAssignController __instance)
	{
		if (!CoopManager.CoopActive)
		{
			return;
		}
		FieldInfo field = typeof(UICoopAssignController).GetField("displayedConnectedGamepads", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		FieldInfo field2 = typeof(UICoopAssignController).GetField("keyboardInputOption", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		if (field == null || field2 == null)
		{
			return;
		}
		CoopAssignInputOption[] array = field.GetValue(__instance) as CoopAssignInputOption[];
		object? value = field2.GetValue(__instance);
		CoopAssignInputOption val = (CoopAssignInputOption)((value is CoopAssignInputOption) ? value : null);
		if (array == null)
		{
			return;
		}
		FieldInfo field3 = typeof(UICoopAssignController).GetField("keyboardInputOptionPreviousSelection", BindingFlags.Static | BindingFlags.NonPublic);
		if ((Object)(object)val != (Object)null)
		{
			int num = ((!RewiredInputManager.GetPlayer(0).controllers.hasKeyboard) ? 1 : (-1));
			field3?.SetValue(null, num);
			val.SetSelection(num, true);
		}
		List<Joystick> list = new List<Joystick>(ReInput.controllers.Joysticks);
		for (int i = 0; i < array.Length && i < list.Count; i++)
		{
			Joystick val2 = list[i];
			int num2 = -1;
			for (int j = 0; j < 4; j++)
			{
				Player player = RewiredInputManager.GetPlayer(j);
				if (player != null && player.controllers.ContainsController((Controller)(object)val2))
				{
					num2 = j;
					break;
				}
			}
			int num3 = ((num2 != 0) ? 1 : (-1));
			UICoopAssignController.displayedConnectedGamepadsPreviousSelection[i] = num3;
			array[i].SetSelection(num3, true);
			Plugin.Log.LogInfo((object)$"CoopAssign_OnShowStarted: joystick[{i}] ownerSlot={num2} → selection={num3}");
		}
	}

	public static bool RemovePlayerFromMenu()
	{
		if (_removingPlayer)
		{
			Plugin.Log.LogInfo((object)"Remove guard active, skipping");
			return false;
		}
		if (PlayerFarming.playersCount > 1 && CoopManager.CoopActive)
		{
			bool manualRemoveRequested = _manualRemoveRequested;
			_manualRemoveRequested = false;
			if (!manualRemoveRequested && Time.unscaledTime < _autoRemoveSuppressedUntil)
			{
				float num = Math.Max(0f, _autoRemoveSuppressedUntil - Time.unscaledTime);
				Plugin.Log.LogInfo((object)$"Auto remove suppressed ({num:0.00}s left)");
				return false;
			}
			PlayerFarming val = null;
			for (int num2 = PlayerFarming.players.Count - 1; num2 >= 0; num2--)
			{
				PlayerFarming val2 = PlayerFarming.players[num2];
				if (!((Object)(object)val2 == (Object)null) && !val2.isLamb && !((Object)(object)((Component)val2).gameObject == (Object)null) && ((Component)val2).gameObject.activeSelf)
				{
					if (manualRemoveRequested)
					{
						val = val2;
						break;
					}
					int playerID = val2.playerID;
					if (playerID > 0 && playerID < 4 && !SlotHasJoystick(playerID))
					{
						val = val2;
						break;
					}
				}
			}
			if ((Object)(object)val == (Object)null)
			{
				if (!manualRemoveRequested)
				{
					Plugin.Log.LogInfo((object)"Auto remove ignored: no goat slot lost joystick ownership");
				}
				else
				{
					Plugin.Log.LogWarning((object)"No Goat found to remove");
				}
				return false;
			}
			_removingPlayer = true;
			CoopManager.AddtionalUser = null;
			int playerID2 = val.playerID;
			MarkDesiredExtraSlot(playerID2, desired: false);
			_pendingSpawnSlots.Remove(playerID2);
			_pendingSpawnUseAnimation.Remove(playerID2);
			if (_cachedSprites.ContainsKey(playerID2))
			{
				_cachedSprites.Remove(playerID2);
			}
			if (_cachedTextImages.ContainsKey(playerID2))
			{
				_cachedTextImages.Remove(playerID2);
			}
			if (_cachedHaloSR.ContainsKey(playerID2))
			{
				_cachedHaloSR.Remove(playerID2);
			}
			if (_cachedHaloSprites.ContainsKey(playerID2))
			{
				_cachedHaloSprites.Remove(playerID2);
			}
			_haloLogged.Remove(playerID2);
			Plugin.Log.LogInfo((object)string.Format("Removing playerID {0} ({1})", playerID2, manualRemoveRequested ? "manual" : "auto-disconnect"));
			UnhookVanillaCoopDelegates();
			CoopManager.Instance.RemoveCoopPlayer(val, true, false, true);
			if (_extraHeartBars.TryGetValue(playerID2, out var value) && (Object)(object)value != (Object)null)
			{
				Object.Destroy((Object)(object)value);
			}
			_extraHeartBars.Remove(playerID2);
			int num3 = 0;
			foreach (PlayerFarming player2 in PlayerFarming.players)
			{
				if (!player2.isLamb)
				{
					num3++;
				}
			}
			if (num3 <= 0)
			{
				_desiredExtraSlots.Clear();
				UICoopAssignController.SetInputForSoloPlay();
				UserHelper.DisengagePlayer(1);
			}
			else
			{
				Player player = RewiredInputManager.GetPlayer(playerID2);
				if (player != null)
				{
					foreach (Joystick item in new List<Joystick>(player.controllers.Joysticks))
					{
						player.controllers.RemoveController((Controller)(object)item);
					}
				}
				EnforceKeyboardOwnership();
				CoopManager.RefreshCoopPlayerRewired();
			}
			if (PlayerFarming.playersCount <= 1)
			{
				CoopManager.CoopActive = false;
				CoopManager.EnableCoopBlockers(false, true);
				DifficultyManager.LoadCurrentDifficulty();
			}
			TryStopAllRumble($"RemovePlayerFromMenu(slot={playerID2})");
			if (!manualRemoveRequested)
			{
				_autoRemoveSuppressedUntil = Time.unscaledTime + 8f;
				Plugin.Log.LogInfo((object)$"Auto remove cooldown armed for {8f:0.0}s");
			}
			GameManager.GetInstance().WaitForSeconds(2f, (Action)delegate
			{
				_removingPlayer = false;
				Plugin.Log.LogInfo((object)"Remove guard released");
			});
		}
		return false;
	}

	public static void PlayerFarming_OnEnable_Prefix(PlayerFarming __instance)
	{
		//IL_001b: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)__instance == (Object)null || __instance.isLamb || __instance.playerID <= 1 || !GameManager.IsDungeon(PlayerFarming.Location) || (Object)(object)__instance.Spine == (Object)null)
		{
			return;
		}
		int num = __instance.playerID;
		if (num < 2 || num >= 4)
		{
			for (int i = 2; i < 4; i++)
			{
				if (CoopManager.AllPlayerGameObjects != null && i < CoopManager.AllPlayerGameObjects.Length && (Object)(object)CoopManager.AllPlayerGameObjects[i] == (Object)(object)((Component)__instance).gameObject)
				{
					num = i;
					break;
				}
			}
		}
		if (num < 2 || num >= 4)
		{
			return;
		}
		bool value = false;
		_pendingSpawnUseAnimation.TryGetValue(num, out value);
		if (value)
		{
			Plugin.Log.LogInfo((object)$"[MP] PlayerFarming_OnEnable_Prefix: keeping mesh visible for animated spawn slot {num}");
			return;
		}
		MeshRenderer component = ((Component)__instance.Spine).GetComponent<MeshRenderer>();
		if ((Object)(object)component != (Object)null)
		{
			((Renderer)component).enabled = false;
		}
		Plugin.Log.LogInfo((object)$"[MP] PlayerFarming_OnEnable_Prefix: hid mesh for slot {num}");
	}

	public static void SpawnCoopPlayer_Postfix(int slot)
	{
		if (slot < 2)
		{
			_pendingSpawnSlots.Remove(slot);
			_pendingSpawnUseAnimation.Remove(slot);
		}
		else
		{
			MarkDesiredExtraSlot(slot, desired: true);
			((MonoBehaviour)CoopManager.Instance).StartCoroutine(ApplyVisualDelayed(slot));
		}
	}

	[IteratorStateMachine(typeof(<RespawnExtraSlots>d__58))]
	private static IEnumerator RespawnExtraSlots(int count)
	{
		//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
		return new <RespawnExtraSlots>d__58(0)
		{
			count = count
		};
	}

	public static void NewRun_Prefix()
	{
		_spawnedExtraWeaponPodiums = false;
		_spawnedExtraSpellPodiums = false;
		_podiumClones.Clear();
		_podiumOwnerSlotByInstanceId.Clear();
		int num = 0;
		foreach (PlayerFarming player in PlayerFarming.players)
		{
			if (!player.isLamb && player.playerID >= 2)
			{
				num++;
			}
		}
		if (num > 0)
		{
			_savedExtraSlotCount = num;
			Plugin.Log.LogInfo((object)$"NewRun_Prefix: saved {num} extra slot(s) for dungeon respawn");
		}
		_cachedHaloSR.Clear();
		_cachedHaloSprites.Clear();
		_cachedTextImages.Clear();
		_cachedSprites.Clear();
		_haloLogged.Clear();
		foreach (KeyValuePair<int, GameObject> extraHeartBar in _extraHeartBars)
		{
			if ((Object)(object)extraHeartBar.Value != (Object)null)
			{
				Object.Destroy((Object)(object)extraHeartBar.Value);
			}
		}
		_extraHeartBars.Clear();
		_positioningDeferred = false;
		_podiumExtraCount = 0;
		_autoRespawnRoutineRunning = false;
		_nextAutoRespawnAttemptAt = 0f;
		_nextAutoRespawnHeartbeatAt = 0f;
		_pendingSpawnSlots.Clear();
		_pendingSpawnUseAnimation.Clear();
		_pendingSpawnFirstSeenAt.Clear();
		_nextPendingBlockLogAt = 0f;
		_delayedRespawnAfterReviveQueued = false;
		_lastObservedWakeHealth = 2f;
		_lastObservedSacrificialWakeHealth = 2f;
		_sacrificialReviveWindowUntil = 0f;
		_nextExtraFalseDownedWatchdogAt.Clear();
		_postReviveRaceGuardUntil.Clear();
		_nextPostReviveForceApplyAt.Clear();
		_nextPostReviveRaceGuardHeartbeatAt = 0f;
		_lastLoggedDungeonRoomPath = null;
		_p2EntranceGuardRunning = false;
		_dungeonRoomStabilizeRunning = false;
		_lastStabilizedDungeonRoomId = int.MinValue;
		_nextDungeonRoomStabilizeCheckAt = 0f;
		_ro

COTLMP/DungeonRoomSizeScaler.dll

Decompiled 3 weeks ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using MMBiomeGeneration;
using MMRoomGeneration;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("ClassLibrary4")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("ClassLibrary4")]
[assembly: AssemblyCopyright("Copyright ©  2026")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("d7f3cd4f-957c-4fa6-a4ae-1b1904889467")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace COTLMultiplayerRoomSizeScaling;

[BepInPlugin("com.cotlmp.roomsizescaling", "COTL Multiplayer Room Size Scaling", "0.1.1")]
public sealed class RoomSizeScalingPlugin : BaseUnityPlugin
{
	public const string PluginGuid = "com.cotlmp.roomsizescaling";

	public const string PluginName = "COTL Multiplayer Room Size Scaling";

	public const string PluginVersion = "0.1.1";

	internal ConfigEntry<bool> Enabled;

	internal ConfigEntry<float> BiasStrength;

	internal ConfigEntry<float> KeepVanillaChance;

	internal ConfigEntry<float> BiasStrength3P;

	internal ConfigEntry<float> KeepVanillaChance3P;

	internal ConfigEntry<float> BiasStrength4P;

	internal ConfigEntry<float> KeepVanillaChance4P;

	internal ConfigEntry<float> MinAreaGainPct;

	internal ConfigEntry<bool> DebugLogging;

	private Harmony _harmony;

	internal static RoomSizeScalingPlugin Instance { get; private set; }

	internal static ManualLogSource Log => ((BaseUnityPlugin)Instance).Logger;

	private void Awake()
	{
		//IL_0056: Unknown result type (might be due to invalid IL or missing references)
		//IL_0060: 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
		//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00dc: Expected O, but got Unknown
		//IL_0110: Unknown result type (might be due to invalid IL or missing references)
		//IL_011a: Expected O, but got Unknown
		//IL_014e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0158: Expected O, but got Unknown
		//IL_018c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0196: Expected O, but got Unknown
		//IL_01ca: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d4: Expected O, but got Unknown
		//IL_0200: Unknown result type (might be due to invalid IL or missing references)
		//IL_020a: Expected O, but got Unknown
		Instance = this;
		Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Enable generated room size scaling.");
		BiasStrength = ((BaseUnityPlugin)this).Config.Bind<float>("General", "BiasStrength", 0.7f, new ConfigDescription("Chance to attempt an upsize roll each generated room (0..1).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
		KeepVanillaChance = ((BaseUnityPlugin)this).Config.Bind<float>("General", "KeepVanillaChance", 0.35f, new ConfigDescription("Chance to keep vanilla selection for room-flow variety (0..1).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
		BiasStrength3P = ((BaseUnityPlugin)this).Config.Bind<float>("Multiplayer", "BiasStrength3P", 0.85f, new ConfigDescription("Upsize roll chance when 3 players are active.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
		KeepVanillaChance3P = ((BaseUnityPlugin)this).Config.Bind<float>("Multiplayer", "KeepVanillaChance3P", 0.25f, new ConfigDescription("Chance to keep vanilla room size when 3 players are active.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
		BiasStrength4P = ((BaseUnityPlugin)this).Config.Bind<float>("Multiplayer", "BiasStrength4P", 0.9f, new ConfigDescription("Upsize roll chance when 4+ players are active.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
		KeepVanillaChance4P = ((BaseUnityPlugin)this).Config.Bind<float>("Multiplayer", "KeepVanillaChance4P", 0.12f, new ConfigDescription("Chance to keep vanilla room size when 4+ players are active.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
		MinAreaGainPct = ((BaseUnityPlugin)this).Config.Bind<float>("General", "MinAreaGainPct", 0.15f, new ConfigDescription("Minimum area gain required to swap to a larger generated room piece.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 2f), Array.Empty<object>()));
		DebugLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "DebugLogging", false, "Verbose room-size selection logs.");
		_harmony = new Harmony("com.cotlmp.roomsizescaling");
		_harmony.PatchAll(Assembly.GetExecutingAssembly());
		((BaseUnityPlugin)this).Logger.LogInfo((object)"COTL Multiplayer Room Size Scaling v0.1.1 loaded.");
	}

	private void OnDestroy()
	{
		Harmony harmony = _harmony;
		if (harmony != null)
		{
			harmony.UnpatchSelf();
		}
	}
}
[HarmonyPatch]
internal static class GenerateRoomGetRandomEncounterIslandPatch
{
	private static MethodBase TargetMethod()
	{
		return AccessTools.Method(typeof(GenerateRoom), "GetRandomEncounterIsland", (Type[])null, (Type[])null);
	}

	private static void Postfix(GenerateRoom __instance, ref IslandPiece __result)
	{
		RoomSizeScalingPlugin instance = RoomSizeScalingPlugin.Instance;
		if ((Object)(object)instance == (Object)null || !instance.Enabled.Value || (Object)(object)__instance == (Object)null || (Object)(object)__result == (Object)null)
		{
			return;
		}
		BiomeRoom val = (((Object)(object)BiomeGenerator.Instance != (Object)null) ? BiomeGenerator.Instance.CurrentRoom : null);
		if (val != null && !string.IsNullOrEmpty(val.GameObjectPath))
		{
			return;
		}
		List<IslandPiece> startPieces = __instance.StartPieces;
		if (startPieces == null || startPieces.Count == 0)
		{
			return;
		}
		int num = Mathf.Max(1, PlayerFarming.playersCount);
		float value = instance.KeepVanillaChance.Value;
		float value2 = instance.BiasStrength.Value;
		if (num >= 4)
		{
			value = instance.KeepVanillaChance4P.Value;
			value2 = instance.BiasStrength4P.Value;
		}
		else if (num >= 3)
		{
			value = instance.KeepVanillaChance3P.Value;
			value2 = instance.BiasStrength3P.Value;
		}
		if (Random.value < value || Random.value > value2)
		{
			return;
		}
		List<IslandPiece> list = CollectAvailableCandidates(startPieces);
		if (list.Count == 0)
		{
			return;
		}
		float area = GetArea(__result);
		IslandPiece val2 = __result;
		float num2 = area;
		for (int i = 0; i < list.Count; i++)
		{
			IslandPiece val3 = list[i];
			float area2 = GetArea(val3);
			if (area2 > num2)
			{
				num2 = area2;
				val2 = val3;
			}
		}
		if ((Object)(object)val2 == (Object)null || val2 == __result)
		{
			return;
		}
		float num3 = area * (1f + instance.MinAreaGainPct.Value);
		if (!(num2 < num3))
		{
			if (instance.DebugLogging.Value)
			{
				RoomSizeScalingPlugin.Log.LogInfo((object)$"[RoomSizeScale] Up-sized generated room piece area {area:0.00} -> {num2:0.00} (players={num}, keep={value:0.00}, bias={value2:0.00})");
			}
			__result = val2;
		}
	}

	private static List<IslandPiece> CollectAvailableCandidates(List<IslandPiece> source)
	{
		List<IslandPiece> list = new List<IslandPiece>();
		for (int i = 0; i < source.Count; i++)
		{
			IslandPiece val = source[i];
			if ((Object)(object)val == (Object)null || val.Encounters == null || val.Encounters.ObjectList == null)
			{
				continue;
			}
			int num = 0;
			int num2 = 0;
			for (int j = 0; j < val.Encounters.ObjectList.Count; j++)
			{
				GameObjectAndProbability val2 = val.Encounters.ObjectList[j];
				if (val2 != null && IsAvailableOnCurrentLayer(val2))
				{
					num++;
					if (!string.IsNullOrEmpty(val2.GameObjectPath) && BiomeGenerator.EncounterAlreadyUsed(val2.GameObjectPath))
					{
						num2++;
					}
				}
			}
			if (num > 0 && num2 < num)
			{
				list.Add(val);
			}
		}
		if (list.Count == 0)
		{
			for (int k = 0; k < source.Count; k++)
			{
				if ((Object)(object)source[k] != (Object)null)
				{
					list.Add(source[k]);
				}
			}
		}
		return list;
	}

	private static float GetArea(IslandPiece piece)
	{
		//IL_0036: Unknown result type (might be due to invalid IL or missing references)
		//IL_003b: Unknown result type (might be due to invalid IL or missing references)
		//IL_003f: Unknown result type (might be due to invalid IL or missing references)
		//IL_004a: Unknown result type (might be due to invalid IL or missing references)
		//IL_004f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0053: Unknown result type (might be due to invalid IL or missing references)
		//IL_0071: Unknown result type (might be due to invalid IL or missing references)
		//IL_0076: Unknown result type (might be due to invalid IL or missing references)
		//IL_0081: Unknown result type (might be due to invalid IL or missing references)
		//IL_0086: Unknown result type (might be due to invalid IL or missing references)
		//IL_0089: Unknown result type (might be due to invalid IL or missing references)
		//IL_0090: Unknown result type (might be due to invalid IL or missing references)
		//IL_0098: Unknown result type (might be due to invalid IL or missing references)
		//IL_009f: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)piece == (Object)null)
		{
			return 0f;
		}
		PolygonCollider2D collider = piece.Collider;
		if ((Object)(object)collider == (Object)null)
		{
			return 0f;
		}
		Vector2[] points = collider.points;
		Bounds bounds;
		if (points == null || points.Length < 3)
		{
			bounds = ((Collider2D)collider).bounds;
			float x = ((Bounds)(ref bounds)).size.x;
			bounds = ((Collider2D)collider).bounds;
			return x * ((Bounds)(ref bounds)).size.y;
		}
		double num = 0.0;
		for (int i = 0; i < points.Length; i++)
		{
			Vector2 val = points[i];
			Vector2 val2 = points[(i + 1) % points.Length];
			num += (double)(val.x * val2.y - val2.x * val.y);
		}
		float num2 = Mathf.Abs((float)(num * 0.5));
		if (!(num2 > 0f))
		{
			bounds = ((Collider2D)collider).bounds;
			float x2 = ((Bounds)(ref bounds)).size.x;
			bounds = ((Collider2D)collider).bounds;
			return x2 * ((Bounds)(ref bounds)).size.y;
		}
		return num2;
	}

	private static bool IsAvailableOnCurrentLayer(GameObjectAndProbability encounter)
	{
		if (GameManager.DungeonUseAllLayers)
		{
			return true;
		}
		return GameManager.CurrentDungeonLayer switch
		{
			1 => encounter.LayerOne, 
			2 => encounter.LayerTwo, 
			3 => encounter.LayerThree, 
			4 => encounter.LayerFour, 
			_ => false, 
		};
	}
}

COTLMP/EnemySpawnScaler.dll

Decompiled 3 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("ClassLibrary3")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("ClassLibrary3")]
[assembly: AssemblyCopyright("Copyright ©  2026")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("b9a6c547-5fae-4c80-847d-8da4b933a5dd")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace COTLMultiplayerEnemySpawnScaling;

[BepInPlugin("com.cotlmp.enemyspawnscaling", "COTL Multiplayer Enemy Spawn Scaling", "0.2.9")]
public sealed class EnemySpawnScalingPlugin : BaseUnityPlugin
{
	internal static ManualLogSource Log;

	internal static EnemySpawnScalingPlugin Instance;

	internal static ConfigEntry<bool> DuplicateMiniBosses;

	private Harmony _harmony;

	private bool _heartbeatLogged;

	private void Awake()
	{
		//IL_0037: Unknown result type (might be due to invalid IL or missing references)
		//IL_0041: Expected O, but got Unknown
		Instance = this;
		Log = ((BaseUnityPlugin)this).Logger;
		DuplicateMiniBosses = ((BaseUnityPlugin)this).Config.Bind<bool>("Scaling", "DuplicateMiniBosses", false, "If true, mini-boss enemies can be duplicated instead of health-scaled. Can cause instability/softlocks for some encounters.");
		_harmony = new Harmony("com.cotlmp.enemyspawnscaling");
		PatchIfFound(AccessTools.Method(typeof(EnemySpawner), "Create", new Type[3]
		{
			typeof(Vector3),
			typeof(Transform),
			typeof(GameObject)
		}, (Type[])null), null, "EnemySpawner_Create_Postfix", "EnemySpawner.Create(Vector3,Transform,GameObject)");
		PatchIfFound(AccessTools.Method(typeof(EnemySpawner), "CreateWithAndInitInstantiatedEnemy", new Type[3]
		{
			typeof(Vector3),
			typeof(Transform),
			typeof(GameObject)
		}, (Type[])null), null, "EnemySpawner_CreateWithAndInit_Postfix", "EnemySpawner.CreateWithAndInitInstantiatedEnemy(Vector3,Transform,GameObject)");
		PatchIfFound(AccessTools.Method(typeof(EnemySpawner), "InitAndInstantiate", new Type[1] { typeof(GameObject) }, (Type[])null), null, "EnemySpawner_InitAndInstantiate_Postfix", "EnemySpawner.InitAndInstantiate(GameObject)");
		PatchIfFound(AccessTools.Method(typeof(EnemySpawner), "Init", new Type[1] { typeof(GameObject) }, (Type[])null), null, "EnemySpawner_Init_Postfix", "EnemySpawner.Init(GameObject)");
		PatchIfFound(AccessTools.Method(typeof(EnemyRoundsBase), "RoundStarted", new Type[2]
		{
			typeof(int),
			typeof(int)
		}, (Type[])null), "EnemyRoundsBase_RoundStarted_Prefix", null, "EnemyRoundsBase.RoundStarted(int,int)");
		PatchIfFound(AccessTools.Method(typeof(EnemyRoundsBase), "AddEnemyToRound", new Type[1] { typeof(Health) }, (Type[])null), null, "EnemyRoundsBase_AddEnemyToRound_Postfix", "EnemyRoundsBase.AddEnemyToRound(Health)");
		PatchIfFound(AccessTools.Method(typeof(EnemyEncounterChanceEvents), "AssignShieldsAndGroups", new Type[0], (Type[])null), null, "EnemyEncounterChanceEvents_AssignShieldsAndGroups_Postfix", "EnemyEncounterChanceEvents.AssignShieldsAndGroups()");
		PatchIfFound(AccessTools.Method(typeof(RoomLockController), "RoomCompleted", new Type[2]
		{
			typeof(bool),
			typeof(bool)
		}, (Type[])null), "RoomLockController_RoomCompleted_Prefix", "RoomLockController_RoomCompleted_Postfix", "RoomLockController.RoomCompleted(bool,bool)");
		Log.LogInfo((object)"Enemy spawn scaling addon loaded.");
		Log.LogInfo((object)"[SpawnScale] Ready v0.2.9");
		Log.LogInfo((object)("[SpawnScale] Config DuplicateMiniBosses=" + DuplicateMiniBosses.Value));
		Log.LogWarning((object)"[SPAWNSCALE_BOOT_017]");
		Debug.Log((object)"[SPAWNSCALE_BOOT_017]");
	}

	private void Update()
	{
		if (!_heartbeatLogged)
		{
			_heartbeatLogged = true;
			Log.LogWarning((object)"[SPAWNSCALE_HEARTBEAT_017]");
			Debug.Log((object)"[SPAWNSCALE_HEARTBEAT_017]");
		}
	}

	private void PatchIfFound(MethodInfo original, string prefix = null, string postfix = null, string label = null)
	{
		//IL_0041: Unknown result type (might be due to invalid IL or missing references)
		//IL_0047: Expected O, but got Unknown
		//IL_005b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0061: Expected O, but got Unknown
		if (original == null)
		{
			Log.LogWarning((object)("[SpawnScale] Skipped patch (missing): " + (label ?? "unknown")));
			return;
		}
		HarmonyMethod val = null;
		HarmonyMethod val2 = null;
		if (!string.IsNullOrEmpty(prefix))
		{
			val = new HarmonyMethod(typeof(EnemySpawnPatches), prefix, (Type[])null);
		}
		if (!string.IsNullOrEmpty(postfix))
		{
			val2 = new HarmonyMethod(typeof(EnemySpawnPatches), postfix, (Type[])null);
		}
		_harmony.Patch((MethodBase)original, val, val2, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		Log.LogInfo((object)("[SpawnScale] Patched: " + (label ?? original.Name)));
	}
}
internal static class EnemySpawnPatches
{
	private sealed class SpawnScaleCloneMarker : MonoBehaviour
	{
		public int RoomToken;
	}

	[CompilerGenerated]
	private sealed class <DeferredRoomCompletionRoutine>d__43 : IEnumerator<object>, IDisposable, IEnumerator
	{
		private int <>1__state;

		private object <>2__current;

		private float <deadline>5__2;

		object IEnumerator<object>.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		object IEnumerator.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		[DebuggerHidden]
		public <DeferredRoomCompletionRoutine>d__43(int <>1__state)
		{
			this.<>1__state = <>1__state;
		}

		[DebuggerHidden]
		void IDisposable.Dispose()
		{
			<>1__state = -2;
		}

		private bool MoveNext()
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Expected O, but got Unknown
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			switch (<>1__state)
			{
			default:
				return false;
			case 0:
				<>1__state = -1;
				<deadline>5__2 = Time.unscaledTime + 25f;
				break;
			case 1:
				<>1__state = -1;
				break;
			}
			if (Time.unscaledTime < <deadline>5__2 && CountAliveTrackedScaledClones() > 0)
			{
				<>2__current = (object)new WaitForSecondsRealtime(0.2f);
				<>1__state = 1;
				return true;
			}
			int num = CountAliveTrackedScaledClones();
			if (num > 0)
			{
				EnemySpawnScalingPlugin.Log.LogWarning((object)$"[SpawnScale] deferred completion timeout pendingScaled={num}; allowing completion to prevent softlock.");
			}
			_deferredRoomCompletionQueued = false;
			_allowRoomCompletePassThrough = true;
			try
			{
				if (!GameManager.IsDungeon(PlayerFarming.Location))
				{
					EnemySpawnScalingPlugin.Log.LogInfo((object)$"[SpawnScale] deferred completion canceled (left dungeon, loc={PlayerFarming.Location})");
					return false;
				}
				RoomLockController.RoomCompleted(true, _deferredDoorsDown);
			}
			catch (Exception ex)
			{
				EnemySpawnScalingPlugin.Log.LogWarning((object)("[SpawnScale] deferred completion failed: " + ex.Message));
			}
			finally
			{
				_allowRoomCompletePassThrough = false;
			}
			return false;
		}

		bool IEnumerator.MoveNext()
		{
			//ILSpy generated this explicit interface implementation from .override directive in MoveNext
			return this.MoveNext();
		}

		[DebuggerHidden]
		void IEnumerator.Reset()
		{
			throw new NotSupportedException();
		}
	}

	private static bool _spawningScaledCopy = false;

	private static bool _allowRoomCompletePassThrough = false;

	private static bool _deferredRoomCompletionQueued = false;

	private static bool _deferredDoorsDown = true;

	private static float _extraSpawnCarry = 0f;

	private static float _nextSkipLogAt = 0f;

	private static float _nextHookLogAt = 0f;

	private static float _nextRejectLogAt = 0f;

	private static int _roomToken = 0;

	private static readonly HashSet<int> _scaledEncounterInstanceIds = new HashSet<int>();

	private static readonly HashSet<int> _scaledSpawnInstanceIds = new HashSet<int>();

	private static readonly HashSet<int> _scaledBossHealthIds = new HashSet<int>();

	private static readonly HashSet<SpawnScaleCloneMarker> _trackedScaledClones = new HashSet<SpawnScaleCloneMarker>();

	private static readonly List<SpawnScaleCloneMarker> _cloneSweep = new List<SpawnScaleCloneMarker>();

	private static readonly Type DungeonLeaderMechanicsType = AccessTools.TypeByName("DungeonLeaderMechanics");

	private static readonly Type DemonType = AccessTools.TypeByName("Demon");

	private static readonly Type FriendlyEnemyType = AccessTools.TypeByName("FriendlyEnemy");

	public static void EnemyRoundsBase_RoundStarted_Prefix(int round, int totalRounds)
	{
		//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
		bool flag = round <= 1 || _roomToken == 0;
		if (flag)
		{
			_roomToken++;
			_trackedScaledClones.Clear();
			_scaledEncounterInstanceIds.Clear();
			_scaledSpawnInstanceIds.Clear();
			_scaledBossHealthIds.Clear();
		}
		_extraSpawnCarry = 0f;
		_deferredRoomCompletionQueued = false;
		_allowRoomCompletePassThrough = false;
		EnemySpawnScalingPlugin.Log.LogInfo((object)$"[SpawnScale] round start {round}/{totalRounds} token={_roomToken} newRoomToken={flag} (players={PlayerFarming.playersCount}, coop={GetCoopStateForLog()}, loc={PlayerFarming.Location})");
	}

	public static bool RoomLockController_RoomCompleted_Prefix(bool wasCombatRoom, bool doorsDown)
	{
		//IL_0018: Unknown result type (might be due to invalid IL or missing references)
		//IL_007c: Unknown result type (might be due to invalid IL or missing references)
		if (!wasCombatRoom)
		{
			return true;
		}
		if (_allowRoomCompletePassThrough)
		{
			return true;
		}
		if (PlayerFarming.playersCount <= 2)
		{
			return true;
		}
		if (!GameManager.IsDungeon(PlayerFarming.Location))
		{
			return true;
		}
		int num = CountAliveTrackedScaledClones();
		if (num <= 0)
		{
			return true;
		}
		if (!_deferredRoomCompletionQueued && (Object)(object)EnemySpawnScalingPlugin.Instance != (Object)null)
		{
			_deferredRoomCompletionQueued = true;
			_deferredDoorsDown = doorsDown;
			((MonoBehaviour)EnemySpawnScalingPlugin.Instance).StartCoroutine(DeferredRoomCompletionRoutine());
		}
		EnemySpawnScalingPlugin.Log.LogInfo((object)$"[SpawnScale] delaying room completion pendingScaled={num} (players={PlayerFarming.playersCount}, loc={PlayerFarming.Location})");
		return false;
	}

	public static void RoomLockController_RoomCompleted_Postfix(bool wasCombatRoom, bool doorsDown)
	{
		//IL_0068: Unknown result type (might be due to invalid IL or missing references)
		if (wasCombatRoom)
		{
			_extraSpawnCarry = 0f;
			_deferredRoomCompletionQueued = false;
			_allowRoomCompletePassThrough = false;
			_trackedScaledClones.Clear();
			_scaledEncounterInstanceIds.Clear();
			_scaledBossHealthIds.Clear();
			EnemySpawnScalingPlugin.Log.LogInfo((object)$"[SpawnScale] combat room completed reset carry (doorsDown={doorsDown}, players={PlayerFarming.playersCount}, coop={GetCoopStateForLog()}, loc={PlayerFarming.Location})");
		}
	}

	public static void EnemySpawner_Create_Postfix(Vector3 Position, Transform Parent, GameObject Spawn)
	{
		LogHookSeen("Create");
		Debug.Log((object)"[SPAWNSCALE_HOOK_017] Create");
	}

	public static void EnemySpawner_CreateWithAndInit_Postfix(Vector3 Position, Transform Parent, GameObject Spawn)
	{
		LogHookSeen("CreateWithInit");
		Debug.Log((object)"[SPAWNSCALE_HOOK_017] CreateWithInit");
	}

	public static void EnemySpawner_InitAndInstantiate_Postfix(EnemySpawner __instance, GameObject __0)
	{
		LogHookSeen("InitAndInstantiate");
		Debug.Log((object)"[SPAWNSCALE_HOOK_017] InitAndInstantiate");
	}

	public static void EnemySpawner_Init_Postfix(EnemySpawner __instance, GameObject __0)
	{
		LogHookSeen("Init");
		Debug.Log((object)"[SPAWNSCALE_HOOK_017] Init");
	}

	public static void EnemyRoundsBase_AddEnemyToRound_Postfix(Health e)
	{
		if (!((Object)(object)e == (Object)null))
		{
			LogHookSeen("AddEnemyToRound");
		}
	}

	public static void EnemyEncounterChanceEvents_AssignShieldsAndGroups_Postfix(EnemyEncounterChanceEvents __instance)
	{
		//IL_02cd: Unknown result type (might be due to invalid IL or missing references)
		//IL_0228: Unknown result type (might be due to invalid IL or missing references)
		//IL_022f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0248: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ba: Invalid comparison between Unknown and I4
		if ((Object)(object)__instance == (Object)null)
		{
			return;
		}
		if (!ShouldScaleDungeonSpawns(out var blockedReason))
		{
			LogSkip("encounter_gate=" + blockedReason);
			return;
		}
		int instanceID = ((Object)((Component)__instance).gameObject).GetInstanceID();
		if (!_scaledEncounterInstanceIds.Add(instanceID))
		{
			return;
		}
		UnitObject[] componentsInChildren;
		try
		{
			componentsInChildren = ((Component)__instance).GetComponentsInChildren<UnitObject>(true);
		}
		catch
		{
			return;
		}
		if (componentsInChildren == null || componentsInChildren.Length == 0)
		{
			return;
		}
		List<UnitObject> list = new List<UnitObject>();
		foreach (UnitObject val in componentsInChildren)
		{
			if (!((Object)(object)val == (Object)null) && !((Object)(object)((Component)val).gameObject == (Object)null) && ((Component)val).gameObject.activeInHierarchy && !((Object)(object)val.health == (Object)null) && (int)val.health.team == 2 && !((Object)(object)((Component)val).GetComponent<SpawnScaleCloneMarker>() != (Object)null) && !TryScaleBossLikeHealth(((Component)val).gameObject, "RoomEncounter") && !((Object)(object)((Component)val).GetComponent<MinionProtector>() != (Object)null) && !((Object)(object)((Component)val).GetComponent<LineRenderer>() != (Object)null) && !HasComponentInChildren(((Component)val).gameObject, DungeonLeaderMechanicsType) && !HasComponentInChildren(((Component)val).gameObject, DemonType) && !HasComponentInChildren(((Component)val).gameObject, FriendlyEnemyType))
			{
				list.Add(val);
			}
		}
		if (list.Count == 0)
		{
			return;
		}
		int roomExtraCount = GetRoomExtraCount(list.Count);
		if (roomExtraCount <= 0)
		{
			return;
		}
		int num = 0;
		for (int j = 0; j < roomExtraCount; j++)
		{
			UnitObject val2 = list[j % list.Count];
			if (!((Object)(object)val2 == (Object)null) && !((Object)(object)((Component)val2).gameObject == (Object)null))
			{
				try
				{
					GameObject val3 = Object.Instantiate<GameObject>(((Component)val2).gameObject, ((Component)val2).transform.parent);
					((Object)val3).name = ((Object)((Component)val2).gameObject).name + "_SpawnScale";
					SpawnScaleCloneMarker spawnScaleCloneMarker = val3.AddComponent<SpawnScaleCloneMarker>();
					spawnScaleCloneMarker.RoomToken = _roomToken;
					_trackedScaledClones.Add(spawnScaleCloneMarker);
					SanitizeClone(val3);
					_scaledSpawnInstanceIds.Add(((Object)val3).GetInstanceID());
					val3.transform.position = GetNearbySpawnPoint(((Component)val2).transform.position, j);
					val3.SetActive(false);
					EnemySpawner.CreateWithAndInitInstantiatedEnemy(val3.transform.position, val3.transform.parent, val3);
					num++;
				}
				catch (Exception ex)
				{
					EnemySpawnScalingPlugin.Log.LogWarning((object)("[SpawnScale] room clone failed: " + ex.Message));
				}
			}
		}
		EnemySpawnScalingPlugin.Log.LogInfo((object)$"[SpawnScale] room-scale eligible={list.Count} spawnedExtra={num} players={PlayerFarming.playersCount} loc={PlayerFarming.Location}");
	}

	private static void TrySpawnScaledCopies(Vector3 position, Transform parent, GameObject spawnPrefab, string source)
	{
		//IL_0074: Unknown result type (might be due to invalid IL or missing references)
		//IL_0076: Unknown result type (might be due to invalid IL or missing references)
		if (_spawningScaledCopy || (Object)(object)spawnPrefab == (Object)null)
		{
			return;
		}
		int instanceID = ((Object)spawnPrefab).GetInstanceID();
		if (_scaledSpawnInstanceIds.Remove(instanceID))
		{
			LogReject("scaled_copy_source");
		}
		else
		{
			if (TryScaleBossLikeHealth(spawnPrefab, source))
			{
				return;
			}
			if (!ShouldScaleDungeonSpawns(out var blockedReason))
			{
				LogSkip("gate=" + blockedReason);
			}
			else
			{
				if (!IsEligibleEnemyPrefab(spawnPrefab))
				{
					return;
				}
				int extraSpawnsForThisEnemy = GetExtraSpawnsForThisEnemy();
				if (extraSpawnsForThisEnemy <= 0)
				{
					return;
				}
				try
				{
					_spawningScaledCopy = true;
					for (int i = 0; i < extraSpawnsForThisEnemy; i++)
					{
						Vector3 nearbySpawnPoint = GetNearbySpawnPoint(position, i);
						GameObject val = Object.Instantiate<GameObject>(spawnPrefab, parent);
						SpawnScaleCloneMarker spawnScaleCloneMarker = val.AddComponent<SpawnScaleCloneMarker>();
						spawnScaleCloneMarker.RoomToken = _roomToken;
						_trackedScaledClones.Add(spawnScaleCloneMarker);
						_scaledSpawnInstanceIds.Add(((Object)val).GetInstanceID());
						val.SetActive(false);
						EnemySpawner.CreateWithAndInitInstantiatedEnemy(nearbySpawnPoint, parent, val);
					}
					EnemySpawnScalingPlugin.Log.LogInfo((object)$"[SpawnScale] source={source} players={PlayerFarming.playersCount} spawnedExtra={extraSpawnsForThisEnemy} carry={_extraSpawnCarry:0.00}");
				}
				catch (Exception ex)
				{
					EnemySpawnScalingPlugin.Log.LogWarning((object)("[SpawnScale] Failed to spawn scaled enemy copy: " + ex.Message));
				}
				finally
				{
					_spawningScaledCopy = false;
				}
			}
		}
	}

	private static bool ShouldScaleDungeonSpawns(out string blockedReason)
	{
		//IL_0018: Unknown result type (might be due to invalid IL or missing references)
		blockedReason = string.Empty;
		if (PlayerFarming.playersCount <= 2)
		{
			blockedReason = "players_le_2";
			return false;
		}
		if (!GameManager.IsDungeon(PlayerFarming.Location))
		{
			blockedReason = "not_dungeon";
			return false;
		}
		if ((Object)(object)EnemyRoundsBase.Instance != (Object)null && EnemyRoundsBase.Instance.Completed)
		{
			blockedReason = "rounds_completed";
			return false;
		}
		return true;
	}

	private static bool IsEligibleEnemyPrefab(GameObject spawnPrefab)
	{
		//IL_001d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0023: Invalid comparison between Unknown and I4
		Health component = spawnPrefab.GetComponent<Health>();
		if ((Object)(object)component == (Object)null)
		{
			LogReject("no_health");
			return false;
		}
		if ((int)component.team != 2)
		{
			LogReject("team_" + ((object)(Team)(ref component.team)).ToString());
			return false;
		}
		if (HasComponentInChildren(spawnPrefab, DungeonLeaderMechanicsType))
		{
			LogReject("dungeon_leader");
			return false;
		}
		if (HasComponentInChildren(spawnPrefab, DemonType))
		{
			LogReject("demon");
			return false;
		}
		if (HasComponentInChildren(spawnPrefab, FriendlyEnemyType))
		{
			LogReject("friendly_enemy");
			return false;
		}
		return true;
	}

	private static bool TryScaleBossLikeHealth(GameObject go, string source)
	{
		if ((Object)(object)go == (Object)null)
		{
			return false;
		}
		if (!IsHealthScaleOnlyEnemy(go))
		{
			return false;
		}
		Health component = go.GetComponent<Health>();
		if ((Object)(object)component == (Object)null)
		{
			return false;
		}
		int instanceID = ((Object)go).GetInstanceID();
		if (!_scaledBossHealthIds.Add(instanceID))
		{
			return true;
		}
		float num = 1f;
		if (PlayerFarming.playersCount >= 4)
		{
			num = 2f;
		}
		else if (PlayerFarming.playersCount == 3)
		{
			num = 1.5f;
		}
		if (num <= 1f)
		{
			return true;
		}
		component.totalHP *= num;
		component.HP *= num;
		EnemySpawnScalingPlugin.Log.LogInfo((object)$"[SpawnScale] boss-health source={source} enemy={GetEnemyName(go)} mult={num:0.00} players={PlayerFarming.playersCount}");
		return true;
	}

	private static bool IsHealthScaleOnlyEnemy(GameObject go)
	{
		//IL_002d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0032: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)go == (Object)null)
		{
			return false;
		}
		if (HasComponentInChildren(go, DungeonLeaderMechanicsType))
		{
			return true;
		}
		UnitObject component = go.GetComponent<UnitObject>();
		if ((Object)(object)component == (Object)null)
		{
			return false;
		}
		Enemy enemyType = component.EnemyType;
		string text = ((object)(Enemy)(ref enemyType)).ToString();
		if (string.IsNullOrEmpty(text))
		{
			return false;
		}
		if ((text.IndexOf("MiniBoss", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("Miniboss", StringComparison.OrdinalIgnoreCase) >= 0) && EnemySpawnScalingPlugin.DuplicateMiniBosses != null && EnemySpawnScalingPlugin.DuplicateMiniBosses.Value)
		{
			return false;
		}
		if (text.IndexOf("Boss", StringComparison.OrdinalIgnoreCase) >= 0)
		{
			return true;
		}
		return false;
	}

	private static string GetEnemyName(GameObject go)
	{
		//IL_0023: Unknown result type (might be due to invalid IL or missing references)
		//IL_0028: Unknown result type (might be due to invalid IL or missing references)
		UnitObject val = (((Object)(object)go != (Object)null) ? go.GetComponent<UnitObject>() : null);
		if (!((Object)(object)val != (Object)null))
		{
			return "Unknown";
		}
		Enemy enemyType = val.EnemyType;
		return ((object)(Enemy)(ref enemyType)).ToString();
	}

	private static void LogSkip(string reason)
	{
		//IL_0046: Unknown result type (might be due to invalid IL or missing references)
		float unscaledTime = Time.unscaledTime;
		if (!(unscaledTime < _nextSkipLogAt))
		{
			_nextSkipLogAt = unscaledTime + 2f;
			EnemySpawnScalingPlugin.Log.LogInfo((object)$"[SpawnScale] skip {reason} (players={PlayerFarming.playersCount}, coop={GetCoopStateForLog()}, loc={PlayerFarming.Location})");
		}
	}

	private static void LogHookSeen(string hook)
	{
		//IL_0046: Unknown result type (might be due to invalid IL or missing references)
		float unscaledTime = Time.unscaledTime;
		if (!(unscaledTime < _nextHookLogAt))
		{
			_nextHookLogAt = unscaledTime + 1.5f;
			EnemySpawnScalingPlugin.Log.LogInfo((object)$"[SpawnScale] hook={hook} seen (players={PlayerFarming.playersCount}, coop={GetCoopStateForLog()}, loc={PlayerFarming.Location})");
		}
	}

	private static void LogReject(string reason)
	{
		//IL_0046: Unknown result type (might be due to invalid IL or missing references)
		float unscaledTime = Time.unscaledTime;
		if (!(unscaledTime < _nextRejectLogAt))
		{
			_nextRejectLogAt = unscaledTime + 2f;
			EnemySpawnScalingPlugin.Log.LogInfo((object)$"[SpawnScale] reject {reason} (players={PlayerFarming.playersCount}, coop={GetCoopStateForLog()}, loc={PlayerFarming.Location})");
		}
	}

	private static string GetCoopStateForLog()
	{
		if ((Object)(object)CoopManager.Instance == (Object)null)
		{
			return "null";
		}
		if (!CoopManager.CoopActive)
		{
			return "inactive";
		}
		return "active";
	}

	private static bool HasComponentInChildren(GameObject go, Type componentType)
	{
		if ((Object)(object)go == (Object)null || componentType == null)
		{
			return false;
		}
		try
		{
			return (Object)(object)go.GetComponentInChildren(componentType, true) != (Object)null;
		}
		catch
		{
			return false;
		}
	}

	private static int GetExtraSpawnsForThisEnemy()
	{
		float num;
		if (PlayerFarming.playersCount >= 4)
		{
			num = 1f;
		}
		else
		{
			if (PlayerFarming.playersCount != 3)
			{
				return 0;
			}
			num = 0.5f;
		}
		_extraSpawnCarry += num;
		int num2 = Mathf.FloorToInt(_extraSpawnCarry + 0.0001f);
		if (num2 > 0)
		{
			_extraSpawnCarry -= num2;
		}
		return Mathf.Clamp(num2, 0, 3);
	}

	private static int GetRoomExtraCount(int baseCount)
	{
		if (baseCount <= 0)
		{
			return 0;
		}
		if (PlayerFarming.playersCount >= 4)
		{
			return Mathf.Clamp(Mathf.Max(4, Mathf.CeilToInt((float)baseCount * 2.25f)) - baseCount, 0, 12);
		}
		if (PlayerFarming.playersCount == 3)
		{
			return Mathf.Clamp(Mathf.Max(3, Mathf.CeilToInt((float)baseCount * 1.75f)) - baseCount, 0, 8);
		}
		return 0;
	}

	private static Vector3 GetNearbySpawnPoint(Vector3 origin, int index)
	{
		//IL_001b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0039: Unknown result type (might be due to invalid IL or missing references)
		//IL_003e: Unknown result type (might be due to invalid IL or missing references)
		float num = (float)(Time.frameCount * 37 + index * 113) % 360f * ((float)Math.PI / 180f);
		return origin + new Vector3(Mathf.Cos(num) * 0.75f, Mathf.Sin(num) * 0.75f, 0f);
	}

	private static void SanitizeClone(GameObject clone)
	{
		if (!((Object)(object)clone == (Object)null))
		{
			MinionProtector component = clone.GetComponent<MinionProtector>();
			if ((Object)(object)component != (Object)null)
			{
				Object.Destroy((Object)(object)component);
			}
			LineRenderer component2 = clone.GetComponent<LineRenderer>();
			if ((Object)(object)component2 != (Object)null)
			{
				Object.Destroy((Object)(object)component2);
			}
			UnitObject component3 = clone.GetComponent<UnitObject>();
			if ((Object)(object)component3 != (Object)null)
			{
				component3.orderIndicator = null;
				component3.RemoveModifier();
				component3.CanHaveModifier = false;
			}
		}
	}

	private static int CountAliveTrackedScaledClones()
	{
		//IL_00da: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e0: Invalid comparison between Unknown and I4
		try
		{
			SpawnScaleCloneMarker[] array = Object.FindObjectsOfType<SpawnScaleCloneMarker>(true);
			foreach (SpawnScaleCloneMarker spawnScaleCloneMarker in array)
			{
				if (!((Object)(object)spawnScaleCloneMarker == (Object)null) && !((Object)(object)((Component)spawnScaleCloneMarker).gameObject == (Object)null) && spawnScaleCloneMarker.RoomToken == _roomToken)
				{
					_trackedScaledClones.Add(spawnScaleCloneMarker);
				}
			}
		}
		catch
		{
		}
		_cloneSweep.Clear();
		int num = 0;
		foreach (SpawnScaleCloneMarker trackedScaledClone in _trackedScaledClones)
		{
			if ((Object)(object)trackedScaledClone == (Object)null || (Object)(object)((Component)trackedScaledClone).gameObject == (Object)null)
			{
				_cloneSweep.Add(trackedScaledClone);
				continue;
			}
			if (trackedScaledClone.RoomToken != _roomToken)
			{
				_cloneSweep.Add(trackedScaledClone);
				continue;
			}
			Health component = ((Component)trackedScaledClone).GetComponent<Health>();
			if ((Object)(object)component == (Object)null)
			{
				_cloneSweep.Add(trackedScaledClone);
			}
			else if ((int)component.team != 2 || component.HP <= 0f)
			{
				_cloneSweep.Add(trackedScaledClone);
			}
			else
			{
				num++;
			}
		}
		for (int j = 0; j < _cloneSweep.Count; j++)
		{
			_trackedScaledClones.Remove(_cloneSweep[j]);
		}
		return num;
	}

	[IteratorStateMachine(typeof(<DeferredRoomCompletionRoutine>d__43))]
	private static IEnumerator DeferredRoomCompletionRoutine()
	{
		//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
		return new <DeferredRoomCompletionRoutine>d__43(0);
	}
}

COTLMP/TarotPatch.dll

Decompiled 3 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using MMBiomeGeneration;
using Rewired;
using Unify.Input;
using UnityEngine;
using src.UINavigator;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("ClassLibrary2")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("ClassLibrary2")]
[assembly: AssemblyCopyright("Copyright ©  2026")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("528f5a23-6efd-4f6b-85e8-1d3d74dfddd6")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace COTLMultiplayerTarotAddon;

[BepInPlugin("com.cotlmp.tarotaddon", "COTL Multiplayer Tarot Addon", "0.1.0")]
public sealed class TarotAddonPlugin : BaseUnityPlugin
{
	internal static ManualLogSource Log;

	private Harmony _harmony;

	private void Awake()
	{
		//IL_0011: Unknown result type (might be due to invalid IL or missing references)
		//IL_001b: Expected O, but got Unknown
		Log = ((BaseUnityPlugin)this).Logger;
		_harmony = new Harmony("com.cotlmp.tarotaddon");
		TarotPatches.EnsureClauneckTarotRoomsOnly(null, "Awake");
		PatchIfFound(AccessTools.Method(typeof(Interaction_Tarot), "OnInteract", new Type[1] { typeof(StateMachine) }, (Type[])null), "InteractionTarot_OnInteract_Prefix", null, "Interaction_Tarot.OnInteract(StateMachine)");
		PatchIfFound(AccessTools.Method(typeof(Interaction_Tarot), "DelayEffectsRoutine", new Type[3]
		{
			typeof(TarotCard),
			typeof(float),
			typeof(PlayerFarming)
		}, (Type[])null), "InteractionTarot_DelayEffectsRoutine_Prefix", "InteractionTarot_DelayEffectsRoutine_Postfix", "Interaction_Tarot.DelayEffectsRoutine");
		PatchIfFound(AccessTools.Method(typeof(Interaction_Tarot), "OnDisable", (Type[])null, (Type[])null), null, "InteractionTarot_OnDisable_Postfix", "Interaction_Tarot.OnDisable");
		PatchIfFound(AccessTools.Method(typeof(Interaction_Tarot), "DoRoutine", (Type[])null, (Type[])null), "InteractionTarot_DoRoutine_Prefix", null, "Interaction_Tarot.DoRoutine()");
		PatchIfFound(AccessTools.Method(typeof(Interaction_TarotCard), "OnInteract", new Type[1] { typeof(StateMachine) }, (Type[])null), "InteractionTarotCard_OnInteract_Prefix", null, "Interaction_TarotCard.OnInteract(StateMachine)");
		PatchIfFound(AccessTools.Method(typeof(Interaction_TarotCard), "DoRoutine", (Type[])null, (Type[])null), "InteractionTarotCard_DoRoutine_Prefix", null, "Interaction_TarotCard.DoRoutine()");
		PatchIfFound(AccessTools.Method(typeof(Interaction_TarotCard), "DelayEffectsRoutine", new Type[1] { typeof(PlayerFarming) }, (Type[])null), "InteractionTarotCard_DelayEffectsRoutine_Prefix", null, "Interaction_TarotCard.DelayEffectsRoutine(PlayerFarming)");
		PatchIfFound(AccessTools.Method(typeof(Interaction_TarotCard), "OnDisable", (Type[])null, (Type[])null), null, "InteractionTarotCard_OnDisable_Postfix", "Interaction_TarotCard.OnDisable");
		PatchIfFound(AccessTools.Method(typeof(Interaction_Chest), "SelectReward", (Type[])null, (Type[])null), null, "InteractionChest_SelectReward_Postfix", "Interaction_Chest.SelectReward()");
		PatchIfFound(AccessTools.Method(typeof(Interaction_Chest), "OnDisableInteraction", Type.EmptyTypes, (Type[])null), null, "InteractionChest_OnDisableInteraction_Postfix", "Interaction_Chest.OnDisableInteraction()");
		PatchIfFound(AccessTools.Method(typeof(InventoryItem), "Spawn", new Type[5]
		{
			typeof(ITEM_TYPE),
			typeof(int),
			typeof(Vector3),
			typeof(float),
			typeof(Action<PickUp>)
		}, (Type[])null), "InventoryItem_Spawn_Prefix", null, "InventoryItem.Spawn(ITEM_TYPE,int,Vector3,float,Action<PickUp>)");
		PatchIfFound(AccessTools.Method(typeof(BiomeGenerator), "Generate", Type.EmptyTypes, (Type[])null), "BiomeGenerator_Generate_Prefix", null, "BiomeGenerator.Generate()");
		PatchIfFound(AccessTools.Method(typeof(Shrines), "OnInteract", new Type[1] { typeof(StateMachine) }, (Type[])null), "Shrines_OnInteract_Prefix", null, "Shrines.OnInteract(StateMachine)");
		PatchIfFound(AccessTools.Method(typeof(Shrines), "DrawCardRoutine", new Type[1] { typeof(PlayerFarming) }, (Type[])null), "Shrines_DrawCardRoutine_Prefix", null, "Shrines.DrawCardRoutine(PlayerFarming)");
		PatchIfFound(AccessTools.Method(typeof(Shrines), "DelayEffectsRoutine", new Type[3]
		{
			typeof(TarotCard),
			typeof(float),
			typeof(PlayerFarming)
		}, (Type[])null), "Shrines_DelayEffectsRoutine_Prefix", "Shrines_DelayEffectsRoutine_Postfix", "Shrines.DelayEffectsRoutine(TarotCard,float,PlayerFarming)");
		PatchIfFound(AccessTools.Method(typeof(Shrines), "OnDisable", Type.EmptyTypes, (Type[])null), null, "Shrines_OnDisable_Postfix", "Shrines.OnDisable()");
		Log.LogInfo((object)"Tarot addon loaded.");
	}

	private void PatchIfFound(MethodInfo original, string prefix = null, string postfix = null, string originalLabel = null)
	{
		//IL_0041: Unknown result type (might be due to invalid IL or missing references)
		//IL_0047: Expected O, but got Unknown
		//IL_005b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0061: Expected O, but got Unknown
		if (original == null)
		{
			Log.LogWarning((object)("[Tarot] Skipped patch (method missing): " + (originalLabel ?? "unknown")));
			return;
		}
		HarmonyMethod val = null;
		HarmonyMethod val2 = null;
		if (!string.IsNullOrEmpty(prefix))
		{
			val = new HarmonyMethod(typeof(TarotPatches), prefix, (Type[])null);
		}
		if (!string.IsNullOrEmpty(postfix))
		{
			val2 = new HarmonyMethod(typeof(TarotPatches), postfix, (Type[])null);
		}
		_harmony.Patch((MethodBase)original, val, val2, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
	}
}
internal static class TarotPatches
{
	[CompilerGenerated]
	private sealed class <SuppressedDelayRoutine>d__68 : IEnumerator<object>, IDisposable, IEnumerator
	{
		private int <>1__state;

		private object <>2__current;

		public float delay;

		object IEnumerator<object>.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		object IEnumerator.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		[DebuggerHidden]
		public <SuppressedDelayRoutine>d__68(int <>1__state)
		{
			this.<>1__state = <>1__state;
		}

		[DebuggerHidden]
		void IDisposable.Dispose()
		{
			<>1__state = -2;
		}

		private bool MoveNext()
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Expected O, but got Unknown
			switch (<>1__state)
			{
			default:
				return false;
			case 0:
				<>1__state = -1;
				<>2__current = (object)new WaitForSeconds(0.2f + delay);
				<>1__state = 1;
				return true;
			case 1:
				<>1__state = -1;
				return false;
			}
		}

		bool IEnumerator.MoveNext()
		{
			//ILSpy generated this explicit interface implementation from .override directive in MoveNext
			return this.MoveNext();
		}

		[DebuggerHidden]
		void IEnumerator.Reset()
		{
			throw new NotSupportedException();
		}
	}

	[CompilerGenerated]
	private sealed class <WrapAndAdvanceShrineTarotQueue>d__56 : IEnumerator<object>, IDisposable, IEnumerator
	{
		private int <>1__state;

		private object <>2__current;

		public IEnumerator original;

		public Shrines shrine;

		public PlayerFarming owner;

		private int <id>5__2;

		private Queue<int> <queue>5__3;

		object IEnumerator<object>.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		object IEnumerator.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		[DebuggerHidden]
		public <WrapAndAdvanceShrineTarotQueue>d__56(int <>1__state)
		{
			this.<>1__state = <>1__state;
		}

		[DebuggerHidden]
		void IDisposable.Dispose()
		{
			<queue>5__3 = null;
			<>1__state = -2;
		}

		private bool MoveNext()
		{
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Expected O, but got Unknown
			switch (<>1__state)
			{
			default:
				return false;
			case 0:
				<>1__state = -1;
				goto IL_0045;
			case 1:
				<>1__state = -1;
				goto IL_0045;
			case 2:
				{
					<>1__state = -1;
					while (<queue>5__3.Count > 0)
					{
						PlayerFarming activePlayerBySlot = GetActivePlayerBySlot(<queue>5__3.Dequeue());
						if (!((Object)(object)activePlayerBySlot == (Object)null) && (!((Object)(object)owner != (Object)null) || !((Object)(object)activePlayerBySlot == (Object)(object)owner)))
						{
							if (!((Behaviour)shrine).isActiveAndEnabled)
							{
								CleanupShrineTarotState(<id>5__2);
								return false;
							}
							TriggerNextShrineTarotInteraction(shrine, activePlayerBySlot);
							return false;
						}
					}
					CleanupShrineTarotState(<id>5__2);
					return false;
				}
				IL_0045:
				if (SafeMoveNext(original))
				{
					<>2__current = original.Current;
					<>1__state = 1;
					return true;
				}
				if ((Object)(object)shrine == (Object)null)
				{
					return false;
				}
				<id>5__2 = ((Object)shrine).GetInstanceID();
				if (!PendingShrineTarotQueueByInstance.TryGetValue(<id>5__2, out <queue>5__3) || <queue>5__3 == null || <queue>5__3.Count == 0)
				{
					CleanupShrineTarotState(<id>5__2);
					return false;
				}
				<>2__current = (object)new WaitForSeconds(0.05f);
				<>1__state = 2;
				return true;
			}
		}

		bool IEnumerator.MoveNext()
		{
			//ILSpy generated this explicit interface implementation from .override directive in MoveNext
			return this.MoveNext();
		}

		[DebuggerHidden]
		void IEnumerator.Reset()
		{
			throw new NotSupportedException();
		}
	}

	[CompilerGenerated]
	private sealed class <WrapAndAdvanceTarotQueue>d__54 : IEnumerator<object>, IDisposable, IEnumerator
	{
		private int <>1__state;

		private object <>2__current;

		public IEnumerator original;

		public Interaction_Tarot interaction;

		public PlayerFarming owner;

		private int <id>5__2;

		private Queue<int> <queue>5__3;

		object IEnumerator<object>.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		object IEnumerator.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		[DebuggerHidden]
		public <WrapAndAdvanceTarotQueue>d__54(int <>1__state)
		{
			this.<>1__state = <>1__state;
		}

		[DebuggerHidden]
		void IDisposable.Dispose()
		{
			<queue>5__3 = null;
			<>1__state = -2;
		}

		private bool MoveNext()
		{
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Expected O, but got Unknown
			switch (<>1__state)
			{
			default:
				return false;
			case 0:
				<>1__state = -1;
				goto IL_0045;
			case 1:
				<>1__state = -1;
				goto IL_0045;
			case 2:
				{
					<>1__state = -1;
					while (<queue>5__3.Count > 0)
					{
						PlayerFarming activePlayerBySlot = GetActivePlayerBySlot(<queue>5__3.Dequeue());
						if (!((Object)(object)activePlayerBySlot == (Object)null) && (!((Object)(object)owner != (Object)null) || !((Object)(object)activePlayerBySlot == (Object)(object)owner)))
						{
							if (!((Behaviour)interaction).isActiveAndEnabled)
							{
								CleanupInteractionState(<id>5__2);
								return false;
							}
							TriggerNextTarotInteraction(interaction, activePlayerBySlot);
							return false;
						}
					}
					CleanupInteractionState(<id>5__2);
					return false;
				}
				IL_0045:
				if (SafeMoveNext(original))
				{
					<>2__current = original.Current;
					<>1__state = 1;
					return true;
				}
				if ((Object)(object)interaction == (Object)null)
				{
					return false;
				}
				<id>5__2 = ((Object)interaction).GetInstanceID();
				if (!PendingTarotQueueByInstance.TryGetValue(<id>5__2, out <queue>5__3) || <queue>5__3 == null || <queue>5__3.Count == 0)
				{
					CleanupInteractionState(<id>5__2);
					return false;
				}
				<>2__current = (object)new WaitForSeconds(0.05f);
				<>1__state = 2;
				return true;
			}
		}

		bool IEnumerator.MoveNext()
		{
			//ILSpy generated this explicit interface implementation from .override directive in MoveNext
			return this.MoveNext();
		}

		[DebuggerHidden]
		void IEnumerator.Reset()
		{
			throw new NotSupportedException();
		}
	}

	private static bool VERBOSE_LOGS = false;

	private const string ClauneckTarotRoomPath = "Assets/_Rooms/Reward Room Tarot.prefab";

	private const string CardsOnlyTarotRoomPath = "Assets/_Rooms/Special Free Tarot Cards.prefab";

	private static bool _loggedTarotRoomPolicy = false;

	private static readonly Dictionary<int, PlayerFarming> TarotOwnerByInstance = new Dictionary<int, PlayerFarming>();

	private static readonly Dictionary<int, Queue<int>> PendingTarotQueueByInstance = new Dictionary<int, Queue<int>>();

	private static readonly HashSet<int> WarnedSuppressedDiscardByInstance = new HashSet<int>();

	private static readonly Dictionary<int, PlayerFarming> TarotCardOwnerByInstance = new Dictionary<int, PlayerFarming>();

	private static readonly Dictionary<int, PlayerFarming> ShrineTarotOwnerByInstance = new Dictionary<int, PlayerFarming>();

	private static readonly Dictionary<int, Queue<int>> PendingShrineTarotQueueByInstance = new Dictionary<int, Queue<int>>();

	private static readonly HashSet<int> WarnedSuppressedShrineDiscardByInstance = new HashSet<int>();

	private static readonly Dictionary<int, int> PendingChestTarotExtraByChest = new Dictionary<int, int>();

	private static readonly Dictionary<int, float> PendingChestTarotExpiryByChest = new Dictionary<int, float>();

	private static int PendingChestTarotExtraAny = 0;

	private static float PendingChestTarotAnyExpiry = -1f;

	private static int PendingChestTarotSourceChestId = 0;

	private static readonly Dictionary<int, float> RecentChestRewardWindowByChest = new Dictionary<int, float>();

	private static readonly Dictionary<int, Vector3> RecentChestRewardPositionByChest = new Dictionary<int, Vector3>();

	private static int RecentChestRewardSourceChestId = 0;

	private static float RecentChestRewardAnyExpiry = -1f;

	private const float RecentChestRewardWindowSeconds = 8f;

	private const float ChestTarotFallbackRadius = 6f;

	private static readonly FieldInfo InteractionChestRewardField = typeof(Interaction_Chest).GetField("Reward", BindingFlags.Instance | BindingFlags.NonPublic);

	private static bool IsSpawningExtraChestTarot = false;

	public static void BiomeGenerator_Generate_Prefix(BiomeGenerator __instance)
	{
		EnsureClauneckTarotRoomsOnly(__instance, "BiomeGenerator.Generate");
	}

	internal static void EnsureClauneckTarotRoomsOnly(BiomeGenerator biomeGenerator, string reason)
	{
		try
		{
			if (!_loggedTarotRoomPolicy)
			{
				_loggedTarotRoomPolicy = true;
				TarotAddonPlugin.Log.LogInfo((object)"[TarotRoom] Vanilla tarot-room behavior preserved (no tarot room path filtering).");
			}
		}
		catch (Exception ex)
		{
			TarotAddonPlugin.Log.LogWarning((object)("[TarotRoom] Failed to enforce tarot room policy during " + reason + ": " + ex.Message));
		}
	}

	private static int RemoveDisallowedTarotRoomPaths(List<string> roomPaths)
	{
		return 0;
	}

	private static bool IsDisallowedTarotRoomPath(string candidate)
	{
		if (string.IsNullOrEmpty(candidate))
		{
			return false;
		}
		string text = NormalizeRoomPath(candidate);
		if (string.Equals(text, NormalizeRoomPath("Assets/_Rooms/Reward Room Tarot.prefab"), StringComparison.OrdinalIgnoreCase))
		{
			return false;
		}
		return text.IndexOf("tarot", StringComparison.OrdinalIgnoreCase) >= 0;
	}

	private static string NormalizeRoomPath(string path)
	{
		if (string.IsNullOrEmpty(path))
		{
			return string.Empty;
		}
		return path.Replace('\\', '/').Trim();
	}

	public static void InteractionTarot_OnInteract_Prefix(Interaction_Tarot __instance, StateMachine state)
	{
		if ((Object)(object)__instance == (Object)null || (Object)(object)state == (Object)null)
		{
			return;
		}
		PlayerFarming val = ResolvePlayerFromState(state);
		if ((Object)(object)val == (Object)null)
		{
			return;
		}
		TrySetAllowedInputPlayer(val);
		SetInteractionContext(__instance, val, state);
		int instanceID = ((Object)__instance).GetInstanceID();
		if (PendingTarotQueueByInstance.ContainsKey(instanceID) || __instance.Activated)
		{
			return;
		}
		Queue<int> queue = BuildTarotQueue(val);
		if (queue.Count > 0)
		{
			PendingTarotQueueByInstance[instanceID] = queue;
			if (VERBOSE_LOGS)
			{
				TarotAddonPlugin.Log.LogInfo((object)("[Tarot] Queue created for instance " + instanceID + "."));
			}
		}
	}

	public static bool InteractionTarot_DelayEffectsRoutine_Prefix(Interaction_Tarot __instance, TarotCard card, float delay, ref PlayerFarming playerFarming, ref IEnumerator __result)
	{
		if ((Object)(object)__instance == (Object)null)
		{
			return true;
		}
		PlayerFarming trackedTarotOwner = GetTrackedTarotOwner(__instance);
		if ((Object)(object)trackedTarotOwner == (Object)null)
		{
			return true;
		}
		if (trackedTarotOwner.playerID >= 2 && (Object)(object)playerFarming != (Object)(object)trackedTarotOwner)
		{
			int instanceID = ((Object)__instance).GetInstanceID();
			if (WarnedSuppressedDiscardByInstance.Add(instanceID))
			{
				TarotAddonPlugin.Log.LogInfo((object)("[Tarot] Suppressed extra discard grant from P" + (trackedTarotOwner.playerID + 1) + "."));
			}
			__result = SuppressedDelayRoutine(delay);
			return false;
		}
		if ((Object)(object)playerFarming == (Object)null)
		{
			playerFarming = trackedTarotOwner;
		}
		return true;
	}

	public static void InteractionTarot_DelayEffectsRoutine_Postfix(Interaction_Tarot __instance, TarotCard card, float delay, PlayerFarming playerFarming, ref IEnumerator __result)
	{
		if (!((Object)(object)__instance == (Object)null) && __result != null)
		{
			PlayerFarming trackedTarotOwner = GetTrackedTarotOwner(__instance);
			if (!((Object)(object)trackedTarotOwner == (Object)null) && !((Object)(object)playerFarming != (Object)(object)trackedTarotOwner))
			{
				__result = WrapAndAdvanceTarotQueue(__result, __instance, trackedTarotOwner);
			}
		}
	}

	public static void InteractionTarot_OnDisable_Postfix(Interaction_Tarot __instance)
	{
		if (!((Object)(object)__instance == (Object)null))
		{
			int instanceID = ((Object)__instance).GetInstanceID();
			TarotOwnerByInstance.Remove(instanceID);
			PendingTarotQueueByInstance.Remove(instanceID);
			WarnedSuppressedDiscardByInstance.Remove(instanceID);
		}
	}

	public static void InteractionTarot_DoRoutine_Prefix(Interaction_Tarot __instance)
	{
		if ((Object)(object)__instance == (Object)null)
		{
			return;
		}
		int instanceID = ((Object)__instance).GetInstanceID();
		PlayerFarming trackedTarotOwner = GetTrackedTarotOwner(__instance);
		if ((Object)(object)trackedTarotOwner == (Object)null)
		{
			return;
		}
		StateMachine val = TryResolveInteractionState(__instance);
		if ((Object)(object)val == (Object)null && (Object)(object)trackedTarotOwner != (Object)null)
		{
			val = trackedTarotOwner.state;
		}
		TrySetAllowedInputPlayer(trackedTarotOwner);
		SetInteractionContext(__instance, trackedTarotOwner, val);
		if (!PendingTarotQueueByInstance.ContainsKey(instanceID))
		{
			Queue<int> queue = BuildTarotQueue(trackedTarotOwner);
			if (queue.Count > 0)
			{
				PendingTarotQueueByInstance[instanceID] = queue;
				TarotAddonPlugin.Log.LogInfo((object)("[Tarot] Bootstrapped chained queue for P" + (trackedTarotOwner.playerID + 1) + "."));
			}
		}
	}

	public static void Shrines_OnInteract_Prefix(Shrines __instance, StateMachine state)
	{
		//IL_0014: Unknown result type (might be due to invalid IL or missing references)
		//IL_001a: Invalid comparison between Unknown and I4
		if ((Object)(object)__instance == (Object)null || (Object)(object)state == (Object)null || (int)__instance.TypeOfShrine != 7)
		{
			return;
		}
		PlayerFarming val = ResolvePlayerFromState(state);
		if ((Object)(object)val == (Object)null)
		{
			return;
		}
		TrySetAllowedInputPlayer(val);
		SetInteractionContext(__instance, val, state);
		int instanceID = ((Object)__instance).GetInstanceID();
		ShrineTarotOwnerByInstance[instanceID] = val;
		if (!PendingShrineTarotQueueByInstance.ContainsKey(instanceID))
		{
			Queue<int> queue = BuildTarotQueue(val);
			if (queue.Count > 0)
			{
				PendingShrineTarotQueueByInstance[instanceID] = queue;
				TarotAddonPlugin.Log.LogInfo((object)("[ShrineTarot] Queue created for instance " + instanceID + "."));
			}
		}
	}

	public static void Shrines_DrawCardRoutine_Prefix(Shrines __instance, ref PlayerFarming playerFarming)
	{
		//IL_000b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0011: Invalid comparison between Unknown and I4
		if ((Object)(object)__instance == (Object)null || (int)__instance.TypeOfShrine != 7)
		{
			return;
		}
		PlayerFarming val = playerFarming;
		if ((Object)(object)val == (Object)null)
		{
			val = GetTrackedShrineTarotOwner(__instance);
		}
		if ((Object)(object)val == (Object)null)
		{
			val = TryResolveInteractionPlayer(__instance);
		}
		if ((Object)(object)val == (Object)null)
		{
			return;
		}
		playerFarming = val;
		TrySetAllowedInputPlayer(val);
		SetInteractionContext(__instance, val, val.state);
		int instanceID = ((Object)__instance).GetInstanceID();
		ShrineTarotOwnerByInstance[instanceID] = val;
		if (!PendingShrineTarotQueueByInstance.ContainsKey(instanceID))
		{
			Queue<int> queue = BuildTarotQueue(val);
			if (queue.Count > 0)
			{
				PendingShrineTarotQueueByInstance[instanceID] = queue;
				TarotAddonPlugin.Log.LogInfo((object)("[ShrineTarot] Bootstrapped queue for P" + (val.playerID + 1) + "."));
			}
		}
	}

	public static bool Shrines_DelayEffectsRoutine_Prefix(Shrines __instance, TarotCard card, float delay, ref PlayerFarming playerFarming, ref IEnumerator __result)
	{
		//IL_000c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0012: Invalid comparison between Unknown and I4
		if ((Object)(object)__instance == (Object)null)
		{
			return true;
		}
		if ((int)__instance.TypeOfShrine != 7)
		{
			return true;
		}
		PlayerFarming trackedShrineTarotOwner = GetTrackedShrineTarotOwner(__instance);
		if ((Object)(object)trackedShrineTarotOwner == (Object)null)
		{
			return true;
		}
		if (trackedShrineTarotOwner.playerID >= 2 && (Object)(object)playerFarming != (Object)(object)trackedShrineTarotOwner)
		{
			int instanceID = ((Object)__instance).GetInstanceID();
			if (WarnedSuppressedShrineDiscardByInstance.Add(instanceID))
			{
				TarotAddonPlugin.Log.LogInfo((object)("[ShrineTarot] Suppressed extra discard grant from P" + (trackedShrineTarotOwner.playerID + 1) + "."));
			}
			__result = SuppressedDelayRoutine(delay);
			return false;
		}
		if ((Object)(object)playerFarming == (Object)null)
		{
			playerFarming = trackedShrineTarotOwner;
		}
		return true;
	}

	public static void Shrines_DelayEffectsRoutine_Postfix(Shrines __instance, TarotCard card, float delay, PlayerFarming playerFarming, ref IEnumerator __result)
	{
		//IL_0010: Unknown result type (might be due to invalid IL or missing references)
		//IL_0016: Invalid comparison between Unknown and I4
		if (!((Object)(object)__instance == (Object)null) && __result != null && (int)__instance.TypeOfShrine == 7)
		{
			PlayerFarming trackedShrineTarotOwner = GetTrackedShrineTarotOwner(__instance);
			if (!((Object)(object)trackedShrineTarotOwner == (Object)null) && !((Object)(object)playerFarming != (Object)(object)trackedShrineTarotOwner))
			{
				__result = WrapAndAdvanceShrineTarotQueue(__result, __instance, trackedShrineTarotOwner);
			}
		}
	}

	public static void Shrines_OnDisable_Postfix(Shrines __instance)
	{
		if (!((Object)(object)__instance == (Object)null))
		{
			CleanupShrineTarotState(((Object)__instance).GetInstanceID());
		}
	}

	public static void InteractionTarotCard_OnInteract_Prefix(Interaction_TarotCard __instance, StateMachine state)
	{
		if (!((Object)(object)__instance == (Object)null) && !((Object)(object)state == (Object)null))
		{
			PlayerFarming val = ResolvePlayerFromState(state);
			if (!((Object)(object)val == (Object)null))
			{
				TrySetAllowedInputPlayer(val);
				SetInteractionContext(__instance, val, state);
				int instanceID = ((Object)__instance).GetInstanceID();
				TarotCardOwnerByInstance[instanceID] = val;
			}
		}
	}

	public static void InteractionTarotCard_DoRoutine_Prefix(Interaction_TarotCard __instance)
	{
		if ((Object)(object)__instance == (Object)null)
		{
			return;
		}
		int instanceID = ((Object)__instance).GetInstanceID();
		if (!TarotCardOwnerByInstance.TryGetValue(instanceID, out var value) || (Object)(object)value == (Object)null)
		{
			value = TryResolveInteractionPlayer(__instance);
		}
		if (!((Object)(object)value == (Object)null))
		{
			StateMachine val = TryResolveInteractionState(__instance);
			if ((Object)(object)val == (Object)null && (Object)(object)value != (Object)null)
			{
				val = value.state;
			}
			TrySetAllowedInputPlayer(value);
			SetInteractionContext(__instance, value, val);
			TarotCardOwnerByInstance[instanceID] = value;
		}
	}

	public static bool InteractionTarotCard_DelayEffectsRoutine_Prefix(Interaction_TarotCard __instance, ref PlayerFarming playerFarming)
	{
		if ((Object)(object)__instance == (Object)null)
		{
			return true;
		}
		int instanceID = ((Object)__instance).GetInstanceID();
		if (!TarotCardOwnerByInstance.TryGetValue(instanceID, out var value))
		{
			value = TryResolveInteractionPlayer(__instance);
		}
		if ((Object)(object)value == (Object)null)
		{
			return true;
		}
		if ((Object)(object)playerFarming == (Object)null || (Object)(object)playerFarming != (Object)(object)value)
		{
			playerFarming = value;
			if (VERBOSE_LOGS)
			{
				TarotAddonPlugin.Log.LogInfo((object)("[TarotCard] Rebound reward ownership to P" + (value.playerID + 1) + "."));
			}
		}
		return true;
	}

	public static void InteractionChest_SelectReward_Postfix(Interaction_Chest __instance)
	{
		//IL_0017: Unknown result type (might be due to invalid IL or missing references)
		//IL_001c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0025: Unknown result type (might be due to invalid IL or missing references)
		//IL_002a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0069: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b5: Invalid comparison between Unknown and I4
		if ((Object)(object)__instance == (Object)null)
		{
			return;
		}
		int instanceID = ((Object)__instance).GetInstanceID();
		ClearPendingChestTarot(instanceID);
		Vector3 value = Vector3.zero;
		bool flag = false;
		try
		{
			value = ((Component)__instance).transform.position;
			flag = true;
		}
		catch
		{
		}
		int effectivePlayerCountForChestTarot = GetEffectivePlayerCountForChestTarot();
		int num = Mathf.Clamp(effectivePlayerCountForChestTarot - 2, 0, 2);
		if (num <= 0)
		{
			return;
		}
		RecentChestRewardWindowByChest[instanceID] = Time.unscaledTime + 8f;
		if (flag)
		{
			RecentChestRewardPositionByChest[instanceID] = value;
		}
		RecentChestRewardSourceChestId = instanceID;
		RecentChestRewardAnyExpiry = Time.unscaledTime + 6f;
		if (TryGetChestReward(__instance, out var reward))
		{
			TarotAddonPlugin.Log.LogInfo((object)("[TarotCard] Chest reward rolled: " + ((object)(ITEM_TYPE)(ref reward)).ToString()));
			if ((int)reward != 26)
			{
				TarotAddonPlugin.Log.LogInfo((object)"[TarotCard] Chest did not roll tarot card this time.");
				return;
			}
			PendingChestTarotExtraByChest[instanceID] = num;
			PendingChestTarotExpiryByChest[instanceID] = Time.unscaledTime + 10f;
			PendingChestTarotExtraAny = num;
			PendingChestTarotAnyExpiry = Time.unscaledTime + 6f;
			PendingChestTarotSourceChestId = instanceID;
			TarotAddonPlugin.Log.LogInfo((object)("[TarotCard] Chest tarot bonus prepared: +" + num + " card(s) for effectivePlayers=" + effectivePlayerCountForChestTarot + " (playersCount=" + PlayerFarming.playersCount + ")."));
		}
	}

	public static void InteractionChest_OnDisableInteraction_Postfix(Interaction_Chest __instance)
	{
		_ = (Object)(object)__instance == (Object)null;
	}

	public static void InventoryItem_Spawn_Prefix(ITEM_TYPE type, int quantity, Vector3 position, float StartSpeed, Action<PickUp> result)
	{
		//IL_0008: Unknown result type (might be due to invalid IL or missing references)
		//IL_000b: Invalid comparison between Unknown and I4
		//IL_028b: Unknown result type (might be due to invalid IL or missing references)
		//IL_028d: Unknown result type (might be due to invalid IL or missing references)
		//IL_028e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0290: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
		//IL_01dd: Unknown result type (might be due to invalid IL or missing references)
		//IL_01df: Unknown result type (might be due to invalid IL or missing references)
		if (IsSpawningExtraChestTarot || (int)type != 26 || quantity <= 0)
		{
			return;
		}
		int value = 0;
		int num = 0;
		Interaction_Chest instance = Interaction_Chest.Instance;
		if ((Object)(object)instance != (Object)null)
		{
			int instanceID = ((Object)instance).GetInstanceID();
			num = instanceID;
			if (PendingChestTarotExpiryByChest.TryGetValue(instanceID, out var value2) && Time.unscaledTime > value2)
			{
				ClearPendingChestTarot(instanceID);
			}
			else if (!PendingChestTarotExtraByChest.TryGetValue(instanceID, out value))
			{
				value = 0;
			}
		}
		if (value <= 0 && PendingChestTarotExtraAny > 0)
		{
			if (PendingChestTarotAnyExpiry > 0f && Time.unscaledTime > PendingChestTarotAnyExpiry)
			{
				ClearPendingChestTarotAny();
			}
			else
			{
				value = PendingChestTarotExtraAny;
				if (num == 0)
				{
					num = PendingChestTarotSourceChestId;
				}
			}
		}
		if (value <= 0)
		{
			Interaction_Chest instance2 = Interaction_Chest.Instance;
			if ((Object)(object)instance2 != (Object)null)
			{
				int instanceID2 = ((Object)instance2).GetInstanceID();
				if (RecentChestRewardWindowByChest.TryGetValue(instanceID2, out var value3))
				{
					if (Time.unscaledTime > value3)
					{
						ClearRecentChestRewardState(instanceID2);
					}
					else
					{
						bool flag = true;
						try
						{
							flag = Vector3.Distance(((Component)instance2).transform.position, position) <= 6f;
						}
						catch
						{
							flag = true;
						}
						if (flag)
						{
							int effectivePlayerCountForChestTarot = GetEffectivePlayerCountForChestTarot();
							value = Mathf.Clamp(effectivePlayerCountForChestTarot - 2, 0, 2);
							if (value > 0)
							{
								num = instanceID2;
								TarotAddonPlugin.Log.LogInfo((object)("[TarotCard] Chest tarot fallback engaged: +" + value + " card(s) for effectivePlayers=" + effectivePlayerCountForChestTarot + "."));
							}
						}
					}
				}
			}
			else if (RecentChestRewardAnyExpiry > 0f)
			{
				if (Time.unscaledTime > RecentChestRewardAnyExpiry)
				{
					if (RecentChestRewardSourceChestId != 0)
					{
						RecentChestRewardPositionByChest.Remove(RecentChestRewardSourceChestId);
					}
					RecentChestRewardAnyExpiry = -1f;
					RecentChestRewardSourceChestId = 0;
				}
				else
				{
					int recentChestRewardSourceChestId = RecentChestRewardSourceChestId;
					bool flag2 = true;
					if (recentChestRewardSourceChestId != 0 && RecentChestRewardPositionByChest.TryGetValue(recentChestRewardSourceChestId, out var value4))
					{
						flag2 = Vector3.Distance(value4, position) <= 6f;
					}
					if (flag2)
					{
						int effectivePlayerCountForChestTarot2 = GetEffectivePlayerCountForChestTarot();
						value = Mathf.Clamp(effectivePlayerCountForChestTarot2 - 2, 0, 2);
						if (value > 0)
						{
							num = recentChestRewardSourceChestId;
							TarotAddonPlugin.Log.LogInfo((object)("[TarotCard] Chest tarot fallback(any) engaged: +" + value + " card(s) for effectivePlayers=" + effectivePlayerCountForChestTarot2 + "."));
						}
					}
				}
			}
		}
		if (value <= 0)
		{
			return;
		}
		try
		{
			IsSpawningExtraChestTarot = true;
			Vector3 val = default(Vector3);
			for (int i = 0; i < value; i++)
			{
				((Vector3)(ref val))..ctor(Random.Range(-0.35f, 0.35f), Random.Range(-0.2f, 0.2f), 0f);
				InventoryItem.Spawn(type, 1, position + val, StartSpeed, result);
			}
			TarotAddonPlugin.Log.LogInfo((object)("[TarotCard] Chest tarot multiplied: base drop + " + value + " extra."));
		}
		catch (Exception ex)
		{
			TarotAddonPlugin.Log.LogWarning((object)("[TarotCard] Failed chest tarot multiply: " + ex.Message));
		}
		finally
		{
			IsSpawningExtraChestTarot = false;
			if (num != 0)
			{
				if (PendingChestTarotExpiryByChest.TryGetValue(num, out var value5) && Time.unscaledTime > value5)
				{
					ClearPendingChestTarot(num);
				}
				if (RecentChestRewardWindowByChest.TryGetValue(num, out var value6) && Time.unscaledTime > value6)
				{
					ClearRecentChestRewardState(num);
				}
			}
			if (PendingChestTarotAnyExpiry > 0f && Time.unscaledTime > PendingChestTarotAnyExpiry)
			{
				ClearPendingChestTarotAny();
			}
			if (RecentChestRewardAnyExpiry > 0f && Time.unscaledTime > RecentChestRewardAnyExpiry)
			{
				if (RecentChestRewardSourceChestId != 0)
				{
					RecentChestRewardPositionByChest.Remove(RecentChestRewardSourceChestId);
				}
				RecentChestRewardAnyExpiry = -1f;
				RecentChestRewardSourceChestId = 0;
			}
		}
	}

	public static void InteractionTarotCard_OnDisable_Postfix(Interaction_TarotCard __instance)
	{
		if (!((Object)(object)__instance == (Object)null))
		{
			CleanupTarotCardState(((Object)__instance).GetInstanceID());
		}
	}

	private static void CleanupTarotCardState(int interactionId)
	{
		TarotCardOwnerByInstance.Remove(interactionId);
	}

	private static bool TryGetChestReward(Interaction_Chest chest, out ITEM_TYPE reward)
	{
		//IL_0032: Unknown result type (might be due to invalid IL or missing references)
		//IL_0038: Expected I4, but got Unknown
		reward = (ITEM_TYPE)0;
		if ((Object)(object)chest == (Object)null || InteractionChestRewardField == null)
		{
			return false;
		}
		try
		{
			object value = InteractionChestRewardField.GetValue(chest);
			if (value is ITEM_TYPE)
			{
				reward = (ITEM_TYPE)(int)(ITEM_TYPE)value;
				return true;
			}
		}
		catch
		{
		}
		return false;
	}

	private static int GetEffectivePlayerCountForChestTarot()
	{
		int num = Mathf.Clamp(PlayerFarming.playersCount, 0, 4);
		HashSet<int> hashSet = new HashSet<int>();
		int num2 = CountRelaxedActivePlayerSlots();
		if (CoopManager.AllPlayerGameObjects != null)
		{
			int num3 = Mathf.Min(CoopManager.AllPlayerGameObjects.Length, 4);
			for (int i = 0; i < num3; i++)
			{
				GameObject val = CoopManager.AllPlayerGameObjects[i];
				if ((Object)(object)val != (Object)null && val.activeInHierarchy)
				{
					hashSet.Add(i);
				}
			}
		}
		int num4 = Mathf.Max(hashSet.Count, num2);
		int num5 = 0;
		for (int j = 0; j < 4; j++)
		{
			if (HasInputAssignedToSlot(j))
			{
				num5++;
			}
		}
		int num6 = Mathf.Max(new int[3] { num, num4, num5 });
		if (num6 <= 0)
		{
			num6 = 1;
		}
		return Mathf.Clamp(num6, 1, 4);
	}

	private static int CountRelaxedActivePlayerSlots()
	{
		if (PlayerFarming.players == null)
		{
			return 0;
		}
		HashSet<int> hashSet = new HashSet<int>();
		for (int i = 0; i < PlayerFarming.players.Count; i++)
		{
			PlayerFarming val = PlayerFarming.players[i];
			if (!((Object)(object)val == (Object)null) && val.playerID >= 0 && val.playerID <= 3 && !((Object)(object)val.state == (Object)null) && !((Object)(object)((Component)val).gameObject == (Object)null) && ((Component)val).gameObject.activeInHierarchy && HasUsableInput(val))
			{
				hashSet.Add(val.playerID);
			}
		}
		return hashSet.Count;
	}

	private static bool HasInputAssignedToSlot(int slot)
	{
		try
		{
			Player player = RewiredInputManager.GetPlayer(slot);
			if (player == null || player.controllers == null)
			{
				return false;
			}
			if (player.controllers.hasKeyboard)
			{
				return true;
			}
			return player.controllers.Joysticks != null && player.controllers.Joysticks.Count > 0;
		}
		catch
		{
			return false;
		}
	}

	private static void ClearPendingChestTarot(int chestId)
	{
		PendingChestTarotExtraByChest.Remove(chestId);
		PendingChestTarotExpiryByChest.Remove(chestId);
	}

	private static void ClearPendingChestTarotAny()
	{
		PendingChestTarotExtraAny = 0;
		PendingChestTarotAnyExpiry = -1f;
		PendingChestTarotSourceChestId = 0;
	}

	private static void ClearRecentChestRewardState(int chestId)
	{
		if (chestId != 0)
		{
			RecentChestRewardWindowByChest.Remove(chestId);
			RecentChestRewardPositionByChest.Remove(chestId);
			if (RecentChestRewardSourceChestId == chestId)
			{
				RecentChestRewardSourceChestId = 0;
				RecentChestRewardAnyExpiry = -1f;
			}
		}
	}

	[IteratorStateMachine(typeof(<WrapAndAdvanceTarotQueue>d__54))]
	private static IEnumerator WrapAndAdvanceTarotQueue(IEnumerator original, Interaction_Tarot interaction, PlayerFarming owner)
	{
		//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
		return new <WrapAndAdvanceTarotQueue>d__54(0)
		{
			original = original,
			interaction = interaction,
			owner = owner
		};
	}

	private static void TriggerNextTarotInteraction(Interaction_Tarot interaction, PlayerFarming player)
	{
		if ((Object)(object)interaction == (Object)null || (Object)(object)player == (Object)null || (Object)(object)player.state == (Object)null)
		{
			return;
		}
		try
		{
			TrySetAllowedInputPlayer(player);
			SetInteractionContext(interaction, player, player.state);
			interaction.Activated = false;
			TarotAddonPlugin.Log.LogInfo((object)("[Tarot] Chained selection owner -> P" + (player.playerID + 1) + "."));
			((Interaction)interaction).OnInteract(player.state);
			if (VERBOSE_LOGS)
			{
				TarotAddonPlugin.Log.LogInfo((object)("[Tarot] Triggered chained interaction for P" + (player.playerID + 1) + "."));
			}
		}
		catch (Exception ex)
		{
			TarotAddonPlugin.Log.LogWarning((object)("[Tarot] Failed to trigger chained interaction: " + ex.Message));
			CleanupInteractionState(((Object)interaction).GetInstanceID());
		}
	}

	[IteratorStateMachine(typeof(<WrapAndAdvanceShrineTarotQueue>d__56))]
	private static IEnumerator WrapAndAdvanceShrineTarotQueue(IEnumerator original, Shrines shrine, PlayerFarming owner)
	{
		//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
		return new <WrapAndAdvanceShrineTarotQueue>d__56(0)
		{
			original = original,
			shrine = shrine,
			owner = owner
		};
	}

	private static void TriggerNextShrineTarotInteraction(Shrines shrine, PlayerFarming player)
	{
		if ((Object)(object)shrine == (Object)null || (Object)(object)player == (Object)null || (Object)(object)player.state == (Object)null)
		{
			return;
		}
		int instanceID = ((Object)shrine).GetInstanceID();
		try
		{
			TrySetAllowedInputPlayer(player);
			SetInteractionContext(shrine, player, player.state);
			ShrineTarotOwnerByInstance[instanceID] = player;
			if (!(Traverse.Create((object)shrine).Method("DrawCardRoutine", new object[1] { player }).GetValue() is IEnumerator enumerator))
			{
				TarotAddonPlugin.Log.LogWarning((object)("[ShrineTarot] Failed to resolve DrawCardRoutine for P" + (player.playerID + 1) + "."));
				CleanupShrineTarotState(instanceID);
			}
			else
			{
				TarotAddonPlugin.Log.LogInfo((object)("[ShrineTarot] Chained purchase owner -> P" + (player.playerID + 1) + "."));
				((MonoBehaviour)shrine).StartCoroutine(enumerator);
			}
		}
		catch (Exception ex)
		{
			TarotAddonPlugin.Log.LogWarning((object)("[ShrineTarot] Failed to trigger chained purchase: " + ex.Message));
			CleanupShrineTarotState(instanceID);
		}
	}

	private static Queue<int> BuildTarotQueue(PlayerFarming starter)
	{
		Queue<int> queue = new Queue<int>();
		if ((Object)(object)starter == (Object)null)
		{
			return queue;
		}
		int playerID = starter.playerID;
		if (playerID <= 1)
		{
			EnqueueSlotIfActive(queue, 2);
			EnqueueSlotIfActive(queue, 3);
			return queue;
		}
		int preferredVanillaOwnerSlot = GetPreferredVanillaOwnerSlot(starter);
		EnqueueSlotIfActive(queue, preferredVanillaOwnerSlot);
		switch (playerID)
		{
		case 2:
			EnqueueSlotIfActive(queue, 3);
			break;
		case 3:
			EnqueueSlotIfActive(queue, 2);
			break;
		}
		return queue;
	}

	private static void EnqueueSlotIfActive(Queue<int> queue, int slot)
	{
		if (queue != null && (Object)(object)GetActivePlayerBySlot(slot) != (Object)null)
		{
			queue.Enqueue(slot);
		}
	}

	private static PlayerFarming GetActivePlayerBySlot(int slot)
	{
		if (PlayerFarming.players == null)
		{
			return null;
		}
		for (int i = 0; i < PlayerFarming.players.Count; i++)
		{
			PlayerFarming val = PlayerFarming.players[i];
			if (!((Object)(object)val == (Object)null) && val.playerID == slot && (PlayerFarming.playersCount <= 0 || val.playerID < PlayerFarming.playersCount) && !((Object)(object)val.state == (Object)null) && !((Object)(object)((Component)val).gameObject == (Object)null) && ((Component)val).gameObject.activeInHierarchy && HasUsableInput(val))
			{
				return val;
			}
		}
		return null;
	}

	private static int GetPreferredVanillaOwnerSlot(PlayerFarming directStarter)
	{
		if ((Object)(object)directStarter != (Object)null && directStarter.playerID == 1)
		{
			return 1;
		}
		if ((Object)(object)GetActivePlayerBySlot(0) != (Object)null)
		{
			return 0;
		}
		return 1;
	}

	private static PlayerFarming ResolvePlayerFromState(StateMachine state)
	{
		if ((Object)(object)state == (Object)null)
		{
			return null;
		}
		PlayerFarming component = ((Component)state).GetComponent<PlayerFarming>();
		if ((Object)(object)component != (Object)null)
		{
			return component;
		}
		try
		{
			if ((Object)(object)((Component)state).gameObject != (Object)null)
			{
				return PlayerFarming.GetPlayerFarmingComponent(((Component)state).gameObject);
			}
		}
		catch
		{
		}
		return PlayerFarming.Instance;
	}

	private static PlayerFarming GetTrackedTarotOwner(Interaction_Tarot interaction)
	{
		if ((Object)(object)interaction == (Object)null)
		{
			return null;
		}
		if (TarotOwnerByInstance.TryGetValue(((Object)interaction).GetInstanceID(), out var value) && (Object)(object)value != (Object)null)
		{
			return value;
		}
		value = TryResolveInteractionPlayer(interaction);
		if ((Object)(object)value != (Object)null)
		{
			TarotOwnerByInstance[((Object)interaction).GetInstanceID()] = value;
		}
		return value;
	}

	private static PlayerFarming GetTrackedShrineTarotOwner(Shrines shrine)
	{
		if ((Object)(object)shrine == (Object)null)
		{
			return null;
		}
		int instanceID = ((Object)shrine).GetInstanceID();
		if (ShrineTarotOwnerByInstance.TryGetValue(instanceID, out var value) && (Object)(object)value != (Object)null)
		{
			return value;
		}
		value = TryResolveInteractionPlayer(shrine);
		if ((Object)(object)value != (Object)null)
		{
			ShrineTarotOwnerByInstance[instanceID] = value;
		}
		return value;
	}

	private static void SetInteractionContext(object interaction, PlayerFarming player, StateMachine state)
	{
		if (interaction != null)
		{
			if ((Object)(object)player != (Object)null)
			{
				TrySetInteractionPlayer(interaction, player);
			}
			if ((Object)(object)state != (Object)null)
			{
				TrySetInteractionState(interaction, state);
			}
			Interaction_Tarot val = (Interaction_Tarot)((interaction is Interaction_Tarot) ? interaction : null);
			if ((Object)(object)val != (Object)null && (Object)(object)player != (Object)null)
			{
				TarotOwnerByInstance[((Object)val).GetInstanceID()] = player;
			}
			Interaction_TarotCard val2 = (Interaction_TarotCard)((interaction is Interaction_TarotCard) ? interaction : null);
			if ((Object)(object)val2 != (Object)null && (Object)(object)player != (Object)null)
			{
				TarotCardOwnerByInstance[((Object)val2).GetInstanceID()] = player;
			}
			Shrines val3 = (Shrines)((interaction is Shrines) ? interaction : null);
			if ((Object)(object)val3 != (Object)null && (Object)(object)player != (Object)null)
			{
				ShrineTarotOwnerByInstance[((Object)val3).GetInstanceID()] = player;
			}
		}
	}

	private static void CleanupInteractionState(int interactionId)
	{
		TarotOwnerByInstance.Remove(interactionId);
		PendingTarotQueueByInstance.Remove(interactionId);
		WarnedSuppressedDiscardByInstance.Remove(interactionId);
	}

	private static void CleanupShrineTarotState(int interactionId)
	{
		ShrineTarotOwnerByInstance.Remove(interactionId);
		PendingShrineTarotQueueByInstance.Remove(interactionId);
		WarnedSuppressedShrineDiscardByInstance.Remove(interactionId);
	}

	[IteratorStateMachine(typeof(<SuppressedDelayRoutine>d__68))]
	private static IEnumerator SuppressedDelayRoutine(float delay)
	{
		//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
		return new <SuppressedDelayRoutine>d__68(0)
		{
			delay = delay
		};
	}

	private static bool HasUsableInput(PlayerFarming player)
	{
		if ((Object)(object)player == (Object)null)
		{
			return false;
		}
		try
		{
			if (player.isLamb)
			{
				return true;
			}
			if (player.rewiredPlayer == null || player.rewiredPlayer.controllers == null)
			{
				return false;
			}
			return player.rewiredPlayer.controllers.hasKeyboard || player.rewiredPlayer.controllers.joystickCount > 0;
		}
		catch
		{
			return true;
		}
	}

	private static void TrySetAllowedInputPlayer(PlayerFarming player)
	{
		if ((Object)(object)player == (Object)null)
		{
			return;
		}
		try
		{
			UINavigatorNew instance = MonoSingleton<UINavigatorNew>.Instance;
			if (!((Object)(object)instance == (Object)null))
			{
				instance.AllowInputOnlyFromPlayer = player;
				instance.TemporarilyAllowInputOnlyFromAnyPlayer = false;
			}
		}
		catch
		{
		}
	}

	private static bool SafeMoveNext(IEnumerator iterator)
	{
		if (iterator == null)
		{
			return false;
		}
		try
		{
			return iterator.MoveNext();
		}
		catch (Exception ex)
		{
			TarotAddonPlugin.Log.LogWarning((object)("[Tarot] Coroutine iteration failed: " + ex.Message));
			return false;
		}
	}

	private static T TryGetField<T>(object instance, string fieldName) where T : class
	{
		if (instance == null || string.IsNullOrEmpty(fieldName))
		{
			return null;
		}
		try
		{
			return Traverse.Create(instance).Field(fieldName).GetValue() as T;
		}
		catch
		{
			return null;
		}
	}

	private static T TryGetProperty<T>(object instance, string propertyName) where T : class
	{
		if (instance == null || string.IsNullOrEmpty(propertyName))
		{
			return null;
		}
		try
		{
			return Traverse.Create(instance).Property(propertyName, (object[])null).GetValue() as T;
		}
		catch
		{
			return null;
		}
	}

	private static bool TrySetField(object instance, string fieldName, object value)
	{
		if (instance == null || string.IsNullOrEmpty(fieldName))
		{
			return false;
		}
		try
		{
			Traverse.Create(instance).Field(fieldName).SetValue(value);
			return true;
		}
		catch
		{
			return false;
		}
	}

	private static bool TrySetProperty(object instance, string propertyName, object value)
	{
		if (instance == null || string.IsNullOrEmpty(propertyName))
		{
			return false;
		}
		try
		{
			Traverse.Create(instance).Property(propertyName, (object[])null).SetValue(value);
			return true;
		}
		catch
		{
			return false;
		}
	}

	private static PlayerFarming TryResolveInteractionPlayer(object interaction)
	{
		if (interaction == null)
		{
			return null;
		}
		PlayerFarming val = TryGetProperty<PlayerFarming>(interaction, "playerFarming");
		if ((Object)(object)val != (Object)null)
		{
			return val;
		}
		val = TryGetField<PlayerFarming>(interaction, "playerFarming");
		if ((Object)(object)val != (Object)null)
		{
			return val;
		}
		val = TryGetField<PlayerFarming>(interaction, "_playerFarming");
		if ((Object)(object)val != (Object)null)
		{
			return val;
		}
		return TryGetField<PlayerFarming>(interaction, "<playerFarming>k__BackingField");
	}

	private static StateMachine TryResolveInteractionState(object interaction)
	{
		if (interaction == null)
		{
			return null;
		}
		StateMachine val = TryGetProperty<StateMachine>(interaction, "state");
		if ((Object)(object)val != (Object)null)
		{
			return val;
		}
		val = TryGetField<StateMachine>(interaction, "state");
		if ((Object)(object)val != (Object)null)
		{
			return val;
		}
		val = TryGetField<StateMachine>(interaction, "_state");
		if ((Object)(object)val != (Object)null)
		{
			return val;
		}
		return TryGetField<StateMachine>(interaction, "<state>k__BackingField");
	}

	private static void TrySetInteractionPlayer(object interaction, PlayerFarming player)
	{
		if (interaction != null && !TrySetProperty(interaction, "playerFarming", player) && !TrySetField(interaction, "playerFarming", player) && !TrySetField(interaction, "_playerFarming", player))
		{
			TrySetField(interaction, "<playerFarming>k__BackingField", player);
		}
	}

	private static void TrySetInteractionState(object interaction, StateMachine state)
	{
		if (interaction != null && !TrySetProperty(interaction, "state", state) && !TrySetField(interaction, "state", state) && !TrySetField(interaction, "_state", state))
		{
			TrySetField(interaction, "<state>k__BackingField", state);
		}
	}
}