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.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: 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: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace COTLMultiplayerEnemySpawnScaling { [BepInDependency(/*Could not decode attribute arguments.*/)] [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 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("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; } 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 _scaledEncounterInstanceIds = new HashSet(); private static readonly HashSet _scaledSpawnInstanceIds = new HashSet(); private static readonly HashSet _scaledBossHealthIds = new HashSet(); private static readonly HashSet _trackedScaledClones = new HashSet(); private static readonly List _cloneSweep = new List(); 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(true); } catch { return; } if (componentsInChildren == null || componentsInChildren.Length == 0) { return; } List list = new List(); 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() != (Object)null) && !TryScaleBossLikeHealth(((Component)val).gameObject, "RoomEncounter") && !((Object)(object)((Component)val).GetComponent() != (Object)null) && !((Object)(object)((Component)val).GetComponent() != (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(((Component)val2).gameObject, ((Component)val2).transform.parent); ((Object)val3).name = ((Object)((Component)val2).gameObject).name + "_SpawnScale"; SpawnScaleCloneMarker spawnScaleCloneMarker = val3.AddComponent(); 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(spawnPrefab, parent); SpawnScaleCloneMarker spawnScaleCloneMarker = val.AddComponent(); 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(); if ((Object)(object)component == (Object)null) { LogReject("no_health"); return false; } if ((int)component.team != 2) { LogReject("team_" + ((object)Unsafe.As(ref component.team)/*cast due to .constrained prefix*/).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(); 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(); if ((Object)(object)component == (Object)null) { return false; } string text = ((object)component.EnemyType/*cast due to .constrained prefix*/).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() : null); if (!((Object)(object)val != (Object)null)) { return "Unknown"; } return ((object)val.EnemyType/*cast due to .constrained prefix*/).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(); if ((Object)(object)component != (Object)null) { Object.Destroy((Object)(object)component); } LineRenderer component2 = clone.GetComponent(); if ((Object)(object)component2 != (Object)null) { Object.Destroy((Object)(object)component2); } UnitObject component3 = clone.GetComponent(); 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(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(); 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; } private static IEnumerator DeferredRoomCompletionRoutine() { float deadline = Time.unscaledTime + 25f; while (Time.unscaledTime < deadline && CountAliveTrackedScaledClones() > 0) { yield return (object)new WaitForSecondsRealtime(0.2f); } 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})"); } else { RoomLockController.RoomCompleted(true, _deferredDoorsDown); } } catch (Exception ex) { EnemySpawnScalingPlugin.Log.LogWarning((object)("[SpawnScale] deferred completion failed: " + ex.Message)); } finally { _allowRoomCompletePassThrough = false; } } } }