Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of SpawnCycleFixes v1.1.3
SpawnCycleFixes.dll
Decompiled 2 weeks agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using LobbyCompatibility.Enums; using LobbyCompatibility.Features; using Microsoft.CodeAnalysis; using Unity.Netcode; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: IgnoresAccessChecksTo("Assembly-CSharp")] [assembly: AssemblyCompany("SpawnCycleFixes")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("Fixes bugs with the spawn cycle")] [assembly: AssemblyFileVersion("1.1.3.0")] [assembly: AssemblyInformationalVersion("1.1.3+320519c5da9e62e0c3ac137f749e7fd9c8ff73ab")] [assembly: AssemblyProduct("SpawnCycleFixes")] [assembly: AssemblyTitle("SpawnCycleFixes")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.1.3.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.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 SpawnCycleFixes { internal static class LobbyCompatibility { internal static void Init() { PluginHelper.RegisterPlugin("butterystancakes.lethalcompany.spawncyclefixes", Version.Parse("1.1.3"), (CompatibilityLevel)1, (VersionStrictness)0); } } [HarmonyPatch] internal static class Patches { private static readonly FieldInfo SPAWN_PROBABILITIES = AccessTools.Field(typeof(RoundManager), "SpawnProbabilities"); private static readonly FieldInfo CURRENT_LEVEL = AccessTools.Field(typeof(RoundManager), "currentLevel"); private static readonly FieldInfo CURRENT_HOUR = AccessTools.Field(typeof(RoundManager), "currentHour"); private static readonly FieldInfo TIME_SCRIPT = AccessTools.Field(typeof(RoundManager), "timeScript"); private static readonly FieldInfo HOUR = AccessTools.Field(typeof(TimeOfDay), "hour"); private static readonly MethodInfo SPAWN_PROBABILITIES_POST_PROCESS = AccessTools.Method(typeof(Utilities), "SpawnProbabilitiesPostProcess", (Type[])null, (Type[])null); [HarmonyPatch(/*Could not decode attribute arguments.*/)] [HarmonyTranspiler] private static IEnumerable<CodeInstruction> LungProp_Trans_DisconnectFromMachinery(IEnumerable<CodeInstruction> instructions) { //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Expected O, but got Unknown //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Expected O, but got Unknown //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Expected O, but got Unknown List<CodeInstruction> list = instructions.ToList(); MethodInfo methodInfo = AccessTools.Method(typeof(RoundManager), "SpawnEnemyGameObject", (Type[])null, (Type[])null); for (int i = 2; i < list.Count; i++) { if (list[i].opcode == OpCodes.Callvirt && (MethodInfo)list[i].operand == methodInfo) { list.InsertRange(i + 2, new <>z__ReadOnlyArray<CodeInstruction>((CodeInstruction[])(object)new CodeInstruction[3] { new CodeInstruction(OpCodes.Ldloc_1, (object)null), new CodeInstruction(OpCodes.Ldfld, (object)AccessTools.Field(typeof(LungProp), "radMechEnemyType")), new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(Utilities), "UpdateEnemySpawnVariables", (Type[])null, (Type[])null)) })); Plugin.Logger.LogDebug((object)"Transpiler (Radiation warning): Add Old Bird values after spawning"); return list; } } Plugin.Logger.LogError((object)"Radiation warning transpiler failed"); return instructions; } private static IEnumerable<CodeInstruction> TransSpawnRandomEnemy(List<CodeInstruction> codes, string firstTime, string enemies, string id) { //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Expected O, but got Unknown //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Expected O, but got Unknown //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Expected O, but got Unknown //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Expected O, but got Unknown //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Expected O, but got Unknown //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Expected O, but got Unknown FieldInfo fieldInfo = AccessTools.Field(typeof(RoundManager), firstTime); for (int i = 2; i < codes.Count; i++) { if (codes[i].opcode == OpCodes.Stfld && (FieldInfo)codes[i].operand == fieldInfo) { codes.InsertRange(i - 2, new <>z__ReadOnlyArray<CodeInstruction>((CodeInstruction[])(object)new CodeInstruction[6] { new CodeInstruction(OpCodes.Ldarg_0, (object)null), new CodeInstruction(OpCodes.Ldflda, (object)SPAWN_PROBABILITIES), new CodeInstruction(OpCodes.Ldarg_0, (object)null), new CodeInstruction(OpCodes.Ldfld, (object)CURRENT_LEVEL), new CodeInstruction(OpCodes.Ldfld, (object)AccessTools.Field(typeof(SelectableLevel), enemies)), new CodeInstruction(OpCodes.Call, (object)SPAWN_PROBABILITIES_POST_PROCESS) })); Plugin.Logger.LogDebug((object)("Transpiler (" + id + "): Post process probabilities")); return codes; } } Plugin.Logger.LogError((object)(id + " transpiler failed")); return codes; } [HarmonyPatch(typeof(RoundManager), "AssignRandomEnemyToVent")] [HarmonyTranspiler] private static IEnumerable<CodeInstruction> RoundManager_Trans_AssignRandomEnemyToVent(IEnumerable<CodeInstruction> instructions) { return TransCurrentHour(instructions.ToList(), "Spawner"); } [HarmonyPatch(typeof(RoundManager), "SpawnRandomOutsideEnemy")] [HarmonyTranspiler] private static IEnumerable<CodeInstruction> RoundManager_Trans_SpawnRandomOutsideEnemy(IEnumerable<CodeInstruction> instructions) { return TransSpawnRandomEnemy(instructions.ToList(), "firstTimeSpawningOutsideEnemies", "OutsideEnemies", "Outside spawner"); } [HarmonyPatch(typeof(EnemyAI), "SubtractFromPowerLevel")] [HarmonyPrefix] [HarmonyPriority(800)] private static void EnemyAI_Pre_SubtractFromPowerLevel(EnemyAI __instance, ref object[] __state) { __state = new object[4] { __instance.removedPowerLevel, RoundManager.Instance.currentEnemyPower, RoundManager.Instance.currentOutsideEnemyPower, RoundManager.Instance.currentDaytimeEnemyPower }; } [HarmonyPatch(typeof(EnemyAI), "SubtractFromPowerLevel")] [HarmonyPostfix] [HarmonyPriority(0)] private static void EnemyAI_Post_SubtractFromPowerLevel(EnemyAI __instance, object[] __state) { if ((bool)__state[0] || !__instance.removedPowerLevel) { return; } ButlerEnemyAI val = (ButlerEnemyAI)(object)((__instance is ButlerEnemyAI) ? __instance : null); if (val == null || !Plugin.configMaskHornetsPower.Value) { return; } float powerLevel = val.butlerBeesEnemyType.PowerLevel; if (powerLevel <= 0f || ((EnemyAI)val).enemyType.PowerLevel <= 0f) { return; } float num = (float)__state[1]; float num2 = (float)__state[2]; float num3 = (float)__state[3]; if (RoundManager.Instance.currentEnemyPower < num) { Plugin.Logger.LogDebug((object)"Butler died and subtracted inside power"); RoundManager instance = RoundManager.Instance; instance.currentEnemyPower += powerLevel; Plugin.Logger.LogDebug((object)"Mask hornets added inside power"); if (!RoundManager.Instance.cannotSpawnMoreInsideEnemies && RoundManager.Instance.currentEnemyPower >= RoundManager.Instance.currentMaxInsidePower) { RoundManager.Instance.cannotSpawnMoreInsideEnemies = true; Plugin.Logger.LogDebug((object)$"Mask hornets canceled vent spawns again ({RoundManager.Instance.currentEnemyPower} > {RoundManager.Instance.currentMaxInsidePower})"); } } else if (RoundManager.Instance.currentOutsideEnemyPower < num2) { Plugin.Logger.LogDebug((object)"Butler died and subtracted outside power"); RoundManager instance2 = RoundManager.Instance; instance2.currentOutsideEnemyPower += powerLevel; Plugin.Logger.LogDebug((object)"Mask hornets added outside power"); } else if (RoundManager.Instance.currentDaytimeEnemyPower < num3) { Plugin.Logger.LogDebug((object)"Butler died and subtracted daytime power"); RoundManager instance3 = RoundManager.Instance; instance3.currentDaytimeEnemyPower += powerLevel; Plugin.Logger.LogDebug((object)"Mask hornets added daytime power"); } else { Plugin.Logger.LogWarning((object)"Butler died, unable to determine power type"); } } [HarmonyPatch(typeof(RoundManager), "BeginEnemySpawning")] [HarmonyPrefix] private static void RoundManager_Pre_BeginEnemySpawning(RoundManager __instance) { //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Invalid comparison between Unknown and I4 if (!Plugin.configConsistentSpawnTimes.Value || !((NetworkBehaviour)__instance).IsServer || __instance.allEnemyVents.Length == 0 || __instance.currentLevel.maxEnemyPowerCount <= 0) { return; } __instance.currentHour += __instance.hourTimeBetweenEnemySpawnBatches; Plugin.Logger.LogDebug((object)"First spawn cycle occurring - force timer for next spawn cycle"); if ((int)__instance.timeScript.currentLevelWeather == 5) { __instance.minEnemiesToSpawn = (int)__instance.timeScript.currentWeatherVariable; __instance.minOutsideEnemiesToSpawn = (int)__instance.timeScript.currentWeatherVariable; Plugin.Logger.LogDebug((object)"Applied bonus spawns for eclipse"); } if (__instance.playersManager.isChallengeFile) { if (__instance.playersManager.daysPlayersSurvivedInARow > 0) { Plugin.Logger.LogDebug((object)"Cancelled survival streak for challenge moon"); } __instance.playersManager.daysPlayersSurvivedInARow = 0; } else if (__instance.minEnemiesToSpawn == 0 && __instance.timeScript.daysUntilDeadline <= 2 && __instance.playersManager.daysPlayersSurvivedInARow >= 5) { __instance.minEnemiesToSpawn = 1; Plugin.Logger.LogDebug((object)"Applied bonus spawns for 5 day survival streak"); } __instance.SpawnDaytimeEnemiesOutside(); Plugin.Logger.LogDebug((object)"Early daytime spawn cycle (for bees/sapsucker)"); __instance.SpawnEnemiesOutside(); Plugin.Logger.LogDebug((object)"Early outside spawn cycle (for eclipses)"); __instance.SpawnWeedEnemies(); Plugin.Logger.LogDebug((object)"Early outside spawn cycle (for weeds)"); } [HarmonyPatch(typeof(RoundManager), "AssignRandomEnemyToVent")] [HarmonyPrefix] private static bool RoundManager_Pre_AssignRandomEnemyToVent(RoundManager __instance, ref EnemyVent vent, ref float spawnTime, ref bool __result) { if (vent.occupied) { Plugin.Logger.LogDebug((object)("A new enemy tried to occupy vent with \"" + vent.enemyType.enemyName + "\" already inside")); List<EnemyVent> list = __instance.allEnemyVents.Where((EnemyVent enemyVent) => !enemyVent.occupied).ToList(); if (list.Count < 1) { Plugin.Logger.LogDebug((object)"Enemy spawn cancelled because all vents on the map are occupied"); __result = false; return false; } vent = list[__instance.EnemySpawnRandom.Next(0, list.Count)]; Plugin.Logger.LogDebug((object)"Enemy successfully reassigned to another empty vent"); } return true; } [HarmonyPatch(typeof(RoundManager), "AssignRandomEnemyToVent")] [HarmonyPostfix] private static void RoundManager_Post_AssignRandomEnemyToVent(RoundManager __instance, EnemyVent vent, bool __result) { if (!__result) { return; } EnemyType enemy = vent?.enemyType; if ((Object)(object)enemy == (Object)null) { Plugin.Logger.LogWarning((object)"AssignRandomEnemyToVent completed without assigning an enemy to the vent. This shouldn't happen"); } else if (vent.enemyTypeIndex < 0 || vent.enemyTypeIndex > __instance.currentLevel.Enemies.Count || !__instance.currentLevel.Enemies.Any((SpawnableEnemyWithRarity spawnableEnemyWithRarity) => (Object)(object)spawnableEnemyWithRarity.enemyType == (Object)(object)enemy)) { Plugin.Logger.LogWarning((object)"AssignRandomEnemyToVent assigned an enemy with an invalid index. This shouldn't happen"); } else { if (enemy.spawnInGroupsOf <= 1) { return; } Plugin.Logger.LogDebug((object)$"Enemy \"{enemy.enemyName}\" spawned in vent, requesting group of {enemy.spawnInGroupsOf}"); int num = enemy.spawnInGroupsOf - 1; List<EnemyVent> list = __instance.allEnemyVents.Where((EnemyVent enemyVent) => !enemyVent.occupied).ToList(); while (num > 0) { if (list.Count <= 0) { Plugin.Logger.LogDebug((object)("Can't spawn additional \"" + enemy.enemyName + "\" (all vents are occupied)")); break; } if (enemy.numberSpawned >= enemy.MaxCount) { Plugin.Logger.LogDebug((object)$"Can't spawn additional \"{enemy.enemyName}\" ({enemy.MaxCount} have already spawned)"); break; } if (enemy.PowerLevel > __instance.currentMaxInsidePower - __instance.currentEnemyPower) { Plugin.Logger.LogDebug((object)$"Can't spawn additional \"{enemy.enemyName}\" ({__instance.currentEnemyPower} + {enemy.PowerLevel} would exceed max power level of {__instance.currentMaxInsidePower})"); break; } int num2 = (int)vent.spawnTime; EnemyVent val = list[__instance.EnemySpawnRandom.Next(0, list.Count)]; __instance.currentEnemyPower += enemy.PowerLevel; __instance.currentEnemyPowerNoDeaths += enemy.PowerLevel; val.enemyType = enemy; val.enemyTypeIndex = vent.enemyTypeIndex; val.occupied = true; val.spawnTime = num2; if (__instance.timeScript.hour - __instance.currentHour <= 0) { val.SyncVentSpawnTimeClientRpc(num2, vent.enemyTypeIndex); } EnemyType obj = enemy; obj.numberSpawned++; __instance.enemySpawnTimes.Add(num2); list.Remove(val); Plugin.Logger.LogDebug((object)("Spawning additional \"" + enemy.enemyName + "\" in vent")); num--; } if (num < enemy.spawnInGroupsOf - 1) { __instance.enemySpawnTimes.Sort(); } } } [HarmonyPatch(typeof(RoundManager), "PlotOutEnemiesForNextHour")] [HarmonyPostfix] private static void RoundManager_Post_PlotOutEnemiesForNextHour(RoundManager __instance) { if (!((NetworkBehaviour)__instance).IsServer) { return; } __instance.enemySpawnTimes.Clear(); EnemyVent[] allEnemyVents = __instance.allEnemyVents; foreach (EnemyVent val in allEnemyVents) { if (val.occupied) { __instance.enemySpawnTimes.Add((int)val.spawnTime); } } if (__instance.enemySpawnTimes.Count > 0) { __instance.enemySpawnTimes.Sort(); __instance.currentEnemySpawnIndex = 0; } } [HarmonyPatch(typeof(RoundManager), "PredictAllOutsideEnemies")] [HarmonyPrefix] private static bool RoundManager_Pre_PredictAllOutsideEnemies(RoundManager __instance) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Invalid comparison between Unknown and I4 //IL_0530: Unknown result type (might be due to invalid IL or missing references) if (!Plugin.configConsistentSpawnTimes.Value) { return true; } if (!((NetworkBehaviour)__instance).IsServer) { return false; } if ((int)__instance.timeScript.currentLevelWeather == 5) { __instance.minOutsideEnemiesToSpawn = (int)__instance.timeScript.currentWeatherVariable; Plugin.Logger.LogDebug((object)"Predictor: Factor in eclipse rates"); } __instance.enemyNestSpawnObjects.Clear(); float num = 0f; int num2 = 0; bool flag = true; Random random = new Random(__instance.playersManager.randomMapSeed + 41); Random random2 = new Random(__instance.playersManager.randomMapSeed + 42); for (int i = 0; i < __instance.timeScript.numberOfHours / __instance.hourTimeBetweenEnemySpawnBatches; i++) { float num3 = ((i == 0) ? 100f : ((float)(i * __instance.hourTimeBetweenEnemySpawnBatches + 1) * __instance.timeScript.lengthOfHours)); Plugin.Logger.LogDebug((object)$"Predictor: Spawn wave at time {num3}"); float num4 = (float)(int)(Mathf.Floor(num3 / __instance.timeScript.lengthOfHours) * __instance.timeScript.lengthOfHours) / __instance.timeScript.totalTime; float num5 = __instance.currentLevel.outsideEnemySpawnChanceThroughDay.Evaluate(num4); Plugin.Logger.LogDebug((object)$"Predictor: Base amount is {num5}"); if (__instance.playersManager.isChallengeFile) { num5 += 1f; } float num6 = num5 + (float)Mathf.Abs(__instance.timeScript.daysUntilDeadline - 3) / 1.6f; Plugin.Logger.LogDebug((object)string.Format("Predictor: Adjusted amount is {0} ({1})", num6, __instance.playersManager.isChallengeFile ? "challenge" : $"{__instance.timeScript.daysUntilDeadline} days left")); int num7 = Mathf.Clamp(random.Next((int)(num6 - 3f), (int)(num5 + 3f)), __instance.minOutsideEnemiesToSpawn, 20); Plugin.Logger.LogDebug((object)$"Predictor: Spawning {num7} enemies"); for (int j = 0; j < num7; j++) { __instance.SpawnProbabilities.Clear(); int num8 = 0; for (int k = 0; k < __instance.currentLevel.OutsideEnemies.Count; k++) { EnemyType enemyType = __instance.currentLevel.OutsideEnemies[k].enemyType; Plugin.Logger.LogDebug((object)("Predictor: Processing \"" + ((Object)enemyType).name + "\"")); if (flag) { enemyType.numberSpawned = 0; enemyType.hasSpawnedAtLeastOne = false; } if (enemyType.PowerLevel > __instance.currentMaxOutsidePower - num || (enemyType.numberSpawned < 1 && enemyType.DiversityPowerLevel > __instance.currentMaxOutsideDiversityLevel - num2) || enemyType.numberSpawned >= enemyType.MaxCount || enemyType.spawningDisabled) { __instance.SpawnProbabilities.Add(0); continue; } int num9 = ((__instance.increasedOutsideEnemySpawnRateIndex == k) ? 100 : ((!enemyType.useNumberSpawnedFalloff) ? ((int)((float)__instance.currentLevel.OutsideEnemies[k].rarity * enemyType.probabilityCurve.Evaluate(num4))) : ((int)((float)__instance.currentLevel.OutsideEnemies[k].rarity * enemyType.probabilityCurve.Evaluate(num4) * enemyType.numberSpawnedFalloff.Evaluate((float)enemyType.numberSpawned / 10f))))); __instance.SpawnProbabilities.Add(num9); num8 += num9; Plugin.Logger.LogDebug((object)$"Predictor: \"{((Object)enemyType).name}\" at {num9} weight ({enemyType.numberSpawned} spawned)"); } flag = false; Plugin.Logger.LogDebug((object)$"Predictor: {num8} total weight"); if (num8 <= 0) { continue; } int randomWeightedIndex = __instance.GetRandomWeightedIndex(__instance.SpawnProbabilities.ToArray(), random); EnemyType enemyType2 = __instance.currentLevel.OutsideEnemies[randomWeightedIndex].enemyType; int num10 = Mathf.Max(enemyType2.spawnInGroupsOf, 1); for (int l = 0; l < num10; l++) { if (enemyType2.PowerLevel > __instance.currentMaxOutsidePower - num) { break; } Plugin.Logger.LogDebug((object)("Predictor: Tracking \"" + ((Object)enemyType2).name + "\"")); num += enemyType2.PowerLevel; if (enemyType2.numberSpawned < 1) { num2 += enemyType2.DiversityPowerLevel; } enemyType2.numberSpawned++; if ((Object)(object)enemyType2.nestSpawnPrefab != (Object)null && (!enemyType2.useMinEnemyThresholdForNest || (enemyType2.nestsSpawned < 1 && enemyType2.numberSpawned > enemyType2.minEnemiesToSpawnNest))) { Plugin.Logger.LogDebug((object)("Predictor: Spawning \"" + ((Object)enemyType2).name + "\" nest")); __instance.SpawnNestObjectForOutsideEnemy(enemyType2, random2); } } } } __instance.enemyNestSpawnObjects.TrimExcess(); List<NetworkObjectReference> list = new List<NetworkObjectReference>(); for (int m = 0; m < __instance.enemyNestSpawnObjects.Count; m++) { NetworkObject component = ((Component)__instance.enemyNestSpawnObjects[m]).GetComponent<NetworkObject>(); if ((Object)(object)component != (Object)null) { list.Add(NetworkObjectReference.op_Implicit(component)); } } if (list.Count > 0) { __instance.SyncNestSpawnObjectsOrderServerRpc(list.ToArray()); } Plugin.Logger.LogDebug((object)"Predictor: Complete"); return false; } private static IEnumerable<CodeInstruction> TransCurrentHour(List<CodeInstruction> codes, string id) { //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Expected O, but got Unknown if (!Plugin.configConsistentSpawnTimes.Value) { return codes; } for (int i = 0; i < codes.Count; i++) { if (codes[i].opcode == OpCodes.Ldfld && (FieldInfo)codes[i].operand == CURRENT_HOUR) { codes[i].operand = HOUR; codes.Insert(i, new CodeInstruction(OpCodes.Ldfld, (object)TIME_SCRIPT)); i++; } } Plugin.Logger.LogDebug((object)("Transpiler (" + id + "): Correct time of day")); return codes; } [HarmonyPatch(typeof(RoundManager), "PlotOutEnemiesForNextHour")] [HarmonyTranspiler] private static IEnumerable<CodeInstruction> RoundManager_Trans_PlotOutEnemiesForNextHour(IEnumerable<CodeInstruction> instructions) { return TransCurrentHour(instructions.ToList(), "Inside spawns"); } [HarmonyPatch(typeof(RoundManager), "SpawnEnemiesOutside")] [HarmonyTranspiler] private static IEnumerable<CodeInstruction> RoundManager_Trans_SpawnEnemiesOutside(IEnumerable<CodeInstruction> instructions) { return TransCurrentHour(instructions.ToList(), "Outside spawns"); } [HarmonyPatch(typeof(RoundManager), "SpawnDaytimeEnemiesOutside")] [HarmonyTranspiler] private static IEnumerable<CodeInstruction> RoundManager_Trans_SpawnDaytimeEnemiesOutside(IEnumerable<CodeInstruction> instructions) { return TransCurrentHour(instructions.ToList(), "Daytime spawns"); } [HarmonyPatch(typeof(RoundManager), "SpawnWeedEnemies")] [HarmonyTranspiler] private static IEnumerable<CodeInstruction> RoundManager_Trans_SpawnWeedEnemies(IEnumerable<CodeInstruction> instructions) { return TransCurrentHour(instructions.ToList(), "Weed spawns"); } } [BepInPlugin("butterystancakes.lethalcompany.spawncyclefixes", "Spawn Cycle Fixes", "1.1.3")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { internal const string PLUGIN_GUID = "butterystancakes.lethalcompany.spawncyclefixes"; internal const string PLUGIN_NAME = "Spawn Cycle Fixes"; internal const string PLUGIN_VERSION = "1.1.3"; internal static ManualLogSource Logger; private const string GUID_LOBBY_COMPATIBILITY = "BMX.LobbyCompatibility"; internal static ConfigEntry<bool> configConsistentSpawnTimes; internal static ConfigEntry<bool> configLimitOldBirds; internal static ConfigEntry<bool> configMaskHornetsPower; private void Awake() { //IL_00e6: Unknown result type (might be due to invalid IL or missing references) Logger = ((BaseUnityPlugin)this).Logger; if (Chainloader.PluginInfos.ContainsKey("BMX.LobbyCompatibility")) { Logger.LogInfo((object)"CROSS-COMPATIBILITY - Lobby Compatibility detected"); LobbyCompatibility.Init(); } configConsistentSpawnTimes = ((BaseUnityPlugin)this).Config.Bind<bool>("Miscellaneous", "Consistent Spawn Times", true, "(REQUIRES RESTART) Fixes two spawn waves occurring at the start of each day, and also fixes vent timers overlapping future spawn waves which delays them until later in the day.\nWith this setting enabled, spawn waves will always occur at 7:39 AM, 9:00 AM, 11:00 AM, 1:00 PM, 3:00 PM, 5:00 PM, 7:00 PM, 9:00 PM, and 11:00 PM."); configLimitOldBirds = ((BaseUnityPlugin)this).Config.Bind<bool>("Enemies", "Limit Old Birds", true, "When unplugging the apparatus, any Old Birds that spawn will now add to the power count and number of Old Birds, preventing outside spawns from \"overflowing\" past the intended maximum values.\nOld Birds will also be blocked from spawning once all the dormant ones on the map have \"woken up\", preventing an issue where they waste other enemy slots and then immediately despawn."); configMaskHornetsPower = ((BaseUnityPlugin)this).Config.Bind<bool>("Enemies", "Mask Hornets Power", false, "Mask hornets do not add power level since they spawn in a non-standard way, from killing butlers. Enabling this will fix that.\nIn vanilla, mask hornets and butlers have the same power level (of 2), so enabling this will prevent enemies from spawning to replace dead butlers."); ((BaseUnityPlugin)this).Config.Bind<string>("Miscellaneous", "Limit Spawn Chance", string.Empty, "Legacy setting, doesn't work"); ((BaseUnityPlugin)this).Config.Remove(((BaseUnityPlugin)this).Config["Miscellaneous", "Limit Spawn Chance"].Definition); ((BaseUnityPlugin)this).Config.Save(); new Harmony("butterystancakes.lethalcompany.spawncyclefixes").PatchAll(); Logger.LogInfo((object)"Spawn Cycle Fixes v1.1.3 loaded"); } } public static class Utilities { public static void SpawnProbabilitiesPostProcess(ref List<int> spawnProbabilities, List<SpawnableEnemyWithRarity> enemies) { if (spawnProbabilities.Count != enemies.Count) { Plugin.Logger.LogWarning((object)"SpawnProbabilities is a different size from the current enemies list. This should never happen outside of mod conflicts!"); } for (int i = 0; i < spawnProbabilities.Count && i < enemies.Count; i++) { EnemyType enemyType = enemies[i].enemyType; if (enemyType.requireNestObjectsToSpawn && spawnProbabilities[i] > 0 && !Object.FindObjectsByType<EnemyAINestSpawnObject>((FindObjectsSortMode)0).Any((EnemyAINestSpawnObject nest) => (Object)(object)nest.enemyType == (Object)(object)enemyType)) { Plugin.Logger.LogDebug((object)("Enemy \"" + enemyType.enemyName + "\" has no nests present on map")); if (RoundManager.Instance.currentMaxOutsidePower <= RoundManager.Instance.currentOutsideEnemyPowerNoDeaths) { spawnProbabilities[i] = 0; Plugin.Logger.LogDebug((object)("Enemy \"" + enemyType.enemyName + "\" spawning disabled")); } else { Plugin.Logger.LogDebug((object)("Enemy \"" + enemyType.enemyName + "\" ignored, as natural spawns are still not finished")); } } } } public static void UpdateEnemySpawnVariables(EnemyType enemyType) { if ((!(((Object)enemyType).name == "RadMech") || Plugin.configLimitOldBirds.Value) && (Object)(object)enemyType != (Object)null) { enemyType.numberSpawned++; if (enemyType.isDaytimeEnemy) { RoundManager instance = RoundManager.Instance; instance.currentDaytimeEnemyPower += enemyType.PowerLevel; } else if (enemyType.isDaytimeEnemy) { RoundManager instance2 = RoundManager.Instance; instance2.currentOutsideEnemyPower += enemyType.PowerLevel; } else { RoundManager instance3 = RoundManager.Instance; instance3.currentEnemyPower += enemyType.PowerLevel; } } } } public static class PluginInfo { public const string PLUGIN_GUID = "SpawnCycleFixes"; public const string PLUGIN_NAME = "SpawnCycleFixes"; public const string PLUGIN_VERSION = "1.1.3"; } } namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] internal sealed class IgnoresAccessChecksToAttribute : Attribute { public IgnoresAccessChecksToAttribute(string assemblyName) { } } } [CompilerGenerated] internal sealed class <>z__ReadOnlyArray<T> : IEnumerable, ICollection, IList, IEnumerable<T>, IReadOnlyCollection<T>, IReadOnlyList<T>, ICollection<T>, IList<T> { int ICollection.Count => _items.Length; bool ICollection.IsSynchronized => false; object ICollection.SyncRoot => this; object IList.this[int index] { get { return _items[index]; } set { throw new NotSupportedException(); } } bool IList.IsFixedSize => true; bool IList.IsReadOnly => true; int IReadOnlyCollection<T>.Count => _items.Length; T IReadOnlyList<T>.this[int index] => _items[index]; int ICollection<T>.Count => _items.Length; bool ICollection<T>.IsReadOnly => true; T IList<T>.this[int index] { get { return _items[index]; } set { throw new NotSupportedException(); } } public <>z__ReadOnlyArray(T[] items) { _items = items; } IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)_items).GetEnumerator(); } void ICollection.CopyTo(Array array, int index) { ((ICollection)_items).CopyTo(array, index); } int IList.Add(object value) { throw new NotSupportedException(); } void IList.Clear() { throw new NotSupportedException(); } bool IList.Contains(object value) { return ((IList)_items).Contains(value); } int IList.IndexOf(object value) { return ((IList)_items).IndexOf(value); } void IList.Insert(int index, object value) { throw new NotSupportedException(); } void IList.Remove(object value) { throw new NotSupportedException(); } void IList.RemoveAt(int index) { throw new NotSupportedException(); } IEnumerator<T> IEnumerable<T>.GetEnumerator() { return ((IEnumerable<T>)_items).GetEnumerator(); } void ICollection<T>.Add(T item) { throw new NotSupportedException(); } void ICollection<T>.Clear() { throw new NotSupportedException(); } bool ICollection<T>.Contains(T item) { return ((ICollection<T>)_items).Contains(item); } void ICollection<T>.CopyTo(T[] array, int arrayIndex) { ((ICollection<T>)_items).CopyTo(array, arrayIndex); } bool ICollection<T>.Remove(T item) { throw new NotSupportedException(); } int IList<T>.IndexOf(T item) { return ((IList<T>)_items).IndexOf(item); } void IList<T>.Insert(int index, T item) { throw new NotSupportedException(); } void IList<T>.RemoveAt(int index) { throw new NotSupportedException(); } }