using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using AIGraph; using Agents; using BepInEx; using BepInEx.Core.Logging.Interpolation; using BepInEx.Logging; using BepInEx.Unity.IL2CPP; using Enemies; using HarmonyLib; using Il2CppSystem.Collections.Generic; using LevelGeneration; using Microsoft.CodeAnalysis; using Player; using SNetwork; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyVersion("0.0.0.0")] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } } namespace Zose_hostType6SpawnEnemyFix { [BepInPlugin("com.zose.hostType6SpawnEnemyFix", "Zose_hostType6SpawnEnemyFix", "1.3.0")] public class EntryPoint : BasePlugin { public static ManualLogSource? L; public override void Load() { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Expected O, but got Unknown L = ((BasePlugin)this).Log; Harmony val = new Harmony("com.zose.hostType6SpawnEnemyFix"); try { Assembly executingAssembly = Assembly.GetExecutingAssembly(); L.LogInfo((object)"Applying patches..."); val.PatchAll(executingAssembly); List list = val.GetPatchedMethods().ToList(); L.LogInfo((object)("Zose_hostType6SpawnEnemyFix patches applied count: " + list.Count)); if (list.Count == 0) { L.LogWarning((object)"NO PATCHES APPLIED! Attempting fallback manual patch of SpawnPatch..."); val.PatchAll(typeof(SpawnPatch)); list = val.GetPatchedMethods().ToList(); L.LogInfo((object)("Fallback patch count: " + list.Count)); } foreach (MethodBase item in list) { L.LogInfo((object)(" - Patch Applied: " + item.DeclaringType?.FullName + "." + item.Name)); } L.LogInfo((object)"Zose_hostType6SpawnEnemyFix init."); } catch (Exception ex) { L.LogError((object)("patch fail: " + ex.Message + "\n" + ex.StackTrace)); } } } public static class SpawnPatch { private class PlayerNodeHistory { public AIG_CourseNode? LastValidNode = null; public float LastValidDistance = -1f; public float LastValidTime = 0f; } [HarmonyPatch(typeof(SurvivalWave), "MastermindUpdate")] public static class SurvivalWave_MastermindUpdate_Patch { [HarmonyPrefix] public static void Prefix(SurvivalWave __instance) { //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.m_spawnType == 6) { RecalcAndApply(__instance); } } [HarmonyPostfix] public static void Postfix(SurvivalWave __instance) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Invalid comparison between Unknown and I4 //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Expected O, but got Unknown if (!((Object)(object)__instance != (Object)null) || (int)__instance.m_spawnType != 6 || __instance.m_courseNode == null) { return; } string debugPlayerName = "Unknown"; AIG_CourseNode nearestPlayerCourseNodeToElevator = GetNearestPlayerCourseNodeToElevator(__instance.m_courseNode, out debugPlayerName); if (nearestPlayerCourseNodeToElevator == null || __instance.m_courseNode.NodeID == nearestPlayerCourseNodeToElevator.NodeID) { return; } ManualLogSource l = EntryPoint.L; if (l != null) { bool flag = default(bool); BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(108, 3, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[TowardsPositionFix] Postfix detected m_courseNode overwritten by vanilla! Current: "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(FormatNodeLocation(__instance.m_courseNode)); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" → Fixed to: "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(FormatNodeLocation(nearestPlayerCourseNodeToElevator)); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" (Player: "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(debugPlayerName); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(")"); } l.LogInfo(val); } __instance.m_courseNode = nearestPlayerCourseNodeToElevator; LastLockedPlayerName = debugPlayerName; } } [HarmonyPatch(typeof(EnemyGroup), "Spawn", new Type[] { typeof(Vector3), typeof(Quaternion), typeof(AIG_CourseNode), typeof(EnemyGroupType), typeof(eEnemyGroupSpawnType), typeof(uint), typeof(float), typeof(IReplicator), typeof(SurvivalWave) })] public static class EnemyGroup_Spawn_Patch { [HarmonyPrefix] public static void Prefix(ref AIG_CourseNode courseNode, SurvivalWave __8) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Invalid comparison between Unknown and I4 //IL_01b9: Unknown result type (might be due to invalid IL or missing references) //IL_01c0: Expected O, but got Unknown //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Expected O, but got Unknown //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Expected O, but got Unknown if ((Object)(object)__8 == (Object)null || (int)__8.m_spawnType != 6) { return; } AIG_CourseNode val = RecalcAndApply(__8); bool flag = default(bool); if (courseNode != null && val != null) { AIG_CourseNode dimensionStartNode = GetDimensionStartNode(val); if (dimensionStartNode != null) { float num = AIG_CourseGraph.GetDistanceBetweenToNodes(courseNode, dimensionStartNode); float num2 = AIG_CourseGraph.GetDistanceBetweenToNodes(val, dimensionStartNode); if (num >= num2) { AIG_CourseNode fallbackNodeTowardsElevator = GetFallbackNodeTowardsElevator(val); if (fallbackNodeTowardsElevator != null) { ManualLogSource l = EntryPoint.L; if (l != null) { BepInExWarningLogInterpolatedStringHandler val2 = new BepInExWarningLogInterpolatedStringHandler(111, 4, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("[TowardsPositionFix] OVERRIDE SPAWN ROOM: Engine chose "); ((BepInExLogInterpolatedStringHandler)val2).AppendFormatted(FormatNodeLocation(courseNode)); ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" (Dist:"); ((BepInExLogInterpolatedStringHandler)val2).AppendFormatted(num); ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(") which is >= base "); ((BepInExLogInterpolatedStringHandler)val2).AppendFormatted(num2); ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("! Using manual fallback node: "); ((BepInExLogInterpolatedStringHandler)val2).AppendFormatted(FormatNodeLocation(fallbackNodeTowardsElevator)); } l.LogWarning(val2); } courseNode = fallbackNodeTowardsElevator; } else { ManualLogSource l2 = EntryPoint.L; if (l2 != null) { BepInExWarningLogInterpolatedStringHandler val2 = new BepInExWarningLogInterpolatedStringHandler(88, 3, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("[TowardsPositionFix] Engine chose "); ((BepInExLogInterpolatedStringHandler)val2).AppendFormatted(FormatNodeLocation(courseNode)); ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" (Dist:"); ((BepInExLogInterpolatedStringHandler)val2).AppendFormatted(num); ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(") >= base "); ((BepInExLogInterpolatedStringHandler)val2).AppendFormatted(num2); ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(", AND NO FALLBACK FOUND! Allowing it."); } l2.LogWarning(val2); } } } } } ManualLogSource l3 = EntryPoint.L; if (l3 != null) { BepInExInfoLogInterpolatedStringHandler val3 = new BepInExInfoLogInterpolatedStringHandler(91, 4, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("[TowardsPositionFix] Spawning Group | spawnRoom: "); ((BepInExLogInterpolatedStringHandler)val3).AppendFormatted(FormatNodeLocation(courseNode)); ((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(" | wave.m_courseNode: "); ((BepInExLogInterpolatedStringHandler)val3).AppendFormatted(FormatNodeLocation(__8.m_courseNode)); ((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(" | Player: "); ((BepInExLogInterpolatedStringHandler)val3).AppendFormatted(LastLockedPlayerName); ((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(" | Eval: "); ((BepInExLogInterpolatedStringHandler)val3).AppendFormatted(LastEvaluationDebug); } l3.LogInfo(val3); } } } [HarmonyPatch(typeof(SurvivalWave), "SpawnGroup")] public static class SurvivalWave_SpawnGroup_Patch { [HarmonyPrefix] public static void Prefix(SurvivalWave __instance) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Invalid comparison between Unknown and I4 //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Expected O, but got Unknown if ((Object)(object)__instance == (Object)null || (int)__instance.m_spawnType != 6) { return; } string debugPlayerName = "Unknown"; AIG_CourseNode nearestPlayerCourseNodeToElevator = GetNearestPlayerCourseNodeToElevator(__instance.m_courseNode, out debugPlayerName); if (nearestPlayerCourseNodeToElevator == null || __instance.m_courseNode == null || nearestPlayerCourseNodeToElevator.NodeID == __instance.m_courseNode.NodeID) { return; } ManualLogSource l = EntryPoint.L; if (l != null) { bool flag = default(bool); BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(121, 3, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[TowardsPositionFix] [SpawnGroup TEST] DANGER: Engine is about to calculate using WRONG baseline "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(FormatNodeLocation(__instance.m_courseNode)); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("! Should be: "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(FormatNodeLocation(nearestPlayerCourseNodeToElevator)); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" (Player: "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(debugPlayerName); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(")"); } l.LogWarning(val); } ManualLogSource? l2 = EntryPoint.L; if (l2 != null) { l2.LogWarning((object)"[TowardsPositionFix] [SpawnGroup TEST] Applying fix right before calculation!"); } __instance.m_courseNode = nearestPlayerCourseNodeToElevator; LastLockedPlayerName = debugPlayerName; } } public static string LastLockedPlayerName = "Unknown"; public static string LastEvaluationDebug = ""; private static Dictionary _playerHistory = new Dictionary(); private static AIG_CourseNode RecalcAndApply(SurvivalWave wave) { if ((Object)(object)wave == (Object)null || wave.m_courseNode == null) { return null; } string debugPlayerName = "Unknown"; AIG_CourseNode nearestPlayerCourseNodeToElevator = GetNearestPlayerCourseNodeToElevator(wave.m_courseNode, out debugPlayerName); if (nearestPlayerCourseNodeToElevator == null) { return null; } LastLockedPlayerName = debugPlayerName; if (wave.m_courseNode.NodeID != nearestPlayerCourseNodeToElevator.NodeID) { wave.m_courseNode = nearestPlayerCourseNodeToElevator; } return nearestPlayerCourseNodeToElevator; } private static string FormatNodeLocation(AIG_CourseNode node) { if (node == null) { return "NULL Node"; } string value = (((Object)(object)node.m_zone != (Object)null) ? node.m_zone.Alias.ToString() : "?"); string value2 = (((Object)(object)node.m_area != (Object)null) ? node.m_area.m_geoArea : "?"); return $"Zone_{value}_Area_{value2} (Node {node.NodeID})"; } private static AIG_CourseNode GetDimensionStartNode(AIG_CourseNode originalNode) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) eDimensionIndex val = (eDimensionIndex)0; if (originalNode != null && (Object)(object)originalNode.m_zone != (Object)null) { Dimension dimension = originalNode.m_zone.Dimension; if (dimension != null) { AIG_CourseNode startCourseNode = dimension.GetStartCourseNode(); if (startCourseNode != null) { return startCourseNode; } } val = originalNode.m_zone.DimensionIndex; } AIG_CourseNode val2 = null; Enumerator enumerator = AIG_CourseNode.s_allNodes.GetEnumerator(); while (enumerator.MoveNext()) { AIG_CourseNode current = enumerator.Current; if (current != null && (Object)(object)current.m_zone != (Object)null && current.m_zone.DimensionIndex == val && (val2 == null || current.m_zone.ID < val2.m_zone.ID)) { val2 = current; } } return val2; } private static AIG_CourseNode GetFallbackNodeTowardsElevator(AIG_CourseNode baseNode) { //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) if (baseNode == null) { return null; } AIG_CourseNode dimensionStartNode = GetDimensionStartNode(baseNode); if (dimensionStartNode == null) { return null; } float num = AIG_CourseGraph.GetDistanceBetweenToNodes(baseNode, dimensionStartNode); if (num <= 0.1f) { return baseNode; } AIG_CourseNode result = null; float num2 = float.MaxValue; Enumerator enumerator = AIG_CourseNode.s_allNodes.GetEnumerator(); while (enumerator.MoveNext()) { AIG_CourseNode current = enumerator.Current; if (current == null || (Object)(object)current.m_zone == (Object)null || current.m_zone.DimensionIndex != baseNode.m_zone.DimensionIndex) { continue; } float num3 = AIG_CourseGraph.GetDistanceBetweenToNodes(current, baseNode); if (num3 < 1f || num3 > 3f) { continue; } float num4 = AIG_CourseGraph.GetDistanceBetweenToNodes(current, dimensionStartNode); if (num4 >= num) { continue; } float num5 = Math.Abs(num3 - 2f); bool flag = false; if (PlayerManager.PlayerAgentsInLevel != null) { Enumerator enumerator2 = PlayerManager.PlayerAgentsInLevel.GetEnumerator(); while (enumerator2.MoveNext()) { PlayerAgent current2 = enumerator2.Current; if ((Object)(object)current2 != (Object)null && ((Agent)current2).CourseNode != null && ((Agent)current2).CourseNode.NodeID == current.NodeID) { flag = true; break; } } } if (flag) { num5 += 1000f; } if (num5 < num2) { num2 = num5; result = current; } } return result; } private static AIG_CourseNode GetNearestPlayerCourseNodeToElevator(AIG_CourseNode originalNode, out string debugPlayerName) { //IL_0154: Unknown result type (might be due to invalid IL or missing references) //IL_0159: 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_0077: 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) AIG_CourseNode result = null; float num = float.MaxValue; debugPlayerName = "Unknown"; string text = ""; AIG_CourseNode dimensionStartNode = GetDimensionStartNode(originalNode); if (dimensionStartNode == null || PlayerManager.PlayerAgentsInLevel == null) { LastEvaluationDebug = "[Error: dimensionStartNode or PlayerAgentsInLevel is null]"; return null; } eDimensionIndex? obj; if (originalNode == null) { obj = null; } else { LG_Zone zone = originalNode.m_zone; obj = ((zone != null) ? new eDimensionIndex?(zone.DimensionIndex) : ((eDimensionIndex?)null)); } eDimensionIndex? val = obj; eDimensionIndex valueOrDefault = val.GetValueOrDefault(); Enumerator enumerator = PlayerManager.PlayerAgentsInLevel.GetEnumerator(); while (enumerator.MoveNext()) { PlayerAgent current = enumerator.Current; if ((Object)(object)current == (Object)null || !((Agent)current).Alive) { continue; } string text2 = "Unknown"; try { SNet_Player owner = current.Owner; text2 = ((owner != null) ? owner.NickName : null) ?? ((Object)current).name; } catch { } int instanceID = ((Object)current).GetInstanceID(); if (!_playerHistory.TryGetValue(instanceID, out PlayerNodeHistory value)) { value = new PlayerNodeHistory(); _playerHistory[instanceID] = value; } float num2 = -1f; if (((Agent)current).CourseNode != null && (Object)(object)((Agent)current).CourseNode.m_zone != (Object)null && ((Agent)current).CourseNode.m_zone.DimensionIndex == valueOrDefault) { num2 = AIG_CourseGraph.GetDistanceBetweenToNodes(((Agent)current).CourseNode, dimensionStartNode); } AIG_CourseNode val2 = null; float num3 = -1f; if (num2 >= 0f && num2 <= 9999f) { value.LastValidNode = ((Agent)current).CourseNode; value.LastValidDistance = num2; value.LastValidTime = Time.time; val2 = ((Agent)current).CourseNode; num3 = num2; } else if (value.LastValidNode != null && Time.time - value.LastValidTime <= 3f) { val2 = value.LastValidNode; num3 = value.LastValidDistance; } if (val2 == null || num3 < 0f || num3 > 9999f) { text += $"[{text2}:ERR(cur:{num2:F1}, age:{Time.time - value.LastValidTime:F1}s)] "; continue; } text += $"[{text2}:{num3:F1}Grids] "; if (num3 < num) { num = num3; result = val2; debugPlayerName = text2; } } LastEvaluationDebug = text; return result; } } }