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 FairAI v1.6.1
FairAI.dll
Decompiled 2 days ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Text; using System.Threading.Tasks; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using FairAI; using FairAI.Component; using FairAI.NetcodePatcher; using FairAI.Patches; using GameNetcodeStuff; using HarmonyLib; using LethalThings; using Microsoft.CodeAnalysis; using Unity.Netcode; using UnityEngine; using UnityEngine.AI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("FairAI")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("FairAI")] [assembly: AssemblyCopyright("Copyright © 2023")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("42deea12-f73e-4d63-81e9-5359e98c8d53")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] [module: NetcodePatchedAssembly] 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; } } } internal class TurretAIPatch { private readonly struct TurretTarget { public readonly PlayerControllerB Player; public readonly EnemyAI Enemy; public static readonly TurretTarget None = default(TurretTarget); public bool IsPlayer => (Object)(object)Player != (Object)null; public bool IsEnemy => (Object)(object)Enemy != (Object)null; public bool IsValid => IsPlayer || IsEnemy; public bool IsDead => (IsPlayer && Player.isPlayerDead) || (IsEnemy && (Enemy.isEnemyDead || Enemy.enemyHP <= 0)); public Vector3 AimPosition => IsPlayer ? ((Component)Player.gameplayCamera).transform.position : (((Component)Enemy).transform.position + Vector3.up * 0.5f); public Transform AimTransform => IsPlayer ? ((Component)Player.gameplayCamera).transform : ((Component)Enemy).transform; public TurretTarget(PlayerControllerB p) { Player = p; Enemy = null; } public TurretTarget(EnemyAI e) { Player = null; Enemy = e; } } private const float DetectRange = 30f; private const int SweepRays = 7; private static readonly Type TurretType = typeof(Turret); private static bool HasCustomSettings => Plugin.turretSettings.Count > 7; private static float FireInterval => HasCustomSettings ? Setting(1) : 0.21f; private static float SwitchInterval => HasCustomSettings ? Setting(3) : 7f; private static float DetectSpeed => HasCustomSettings ? Setting(5) : 28f; private static float ChargeSpeed => HasCustomSettings ? Setting(6) : 95f; private static float BerserkSpeed => HasCustomSettings ? Setting(7) : 77f; private static int PlayerDamage => HasCustomSettings ? ((int)Setting(0)) : Plugin.GetInt("TurretConfig", "Player Damage"); private static T GetField<T>(Turret t, string name) { return (T)TurretType.GetField(name, BindingFlags.Instance | BindingFlags.NonPublic).GetValue(t); } private static void SetField(Turret t, string name, object value) { TurretType.GetField(name, BindingFlags.Instance | BindingFlags.NonPublic).SetValue(t, value); } private static void CallMethod(Turret t, string name, params object[] args) { TurretType.GetMethod(name, BindingFlags.Instance | BindingFlags.NonPublic).Invoke(t, args); } private static float Setting(int index) { return Plugin.turretSettings[index]; } private static FAIR_AI GetAI(Turret turret) { FAIR_AI fAIR_AI = ((Component)turret).gameObject.GetComponent<FAIR_AI>(); if ((Object)(object)fAIR_AI == (Object)null) { Plugin.logger.LogError((object)"FAIR_AI missing on Turret at runtime — InjectFairAIIntoAllTurrets did not run for this turret. Enemy RPC sync will not work for it."); fAIR_AI = ((Component)turret).gameObject.AddComponent<FAIR_AI>(); } return fAIR_AI; } public static void InjectFairAIIntoAllTurrets() { Turret[] array = Resources.FindObjectsOfTypeAll<Turret>(); int num = 0; int num2 = 0; Turret[] array2 = array; foreach (Turret val in array2) { if (!((Object)(object)val == (Object)null)) { NetworkObject component = ((Component)val).GetComponent<NetworkObject>(); bool flag = (Object)(object)component != (Object)null && component.IsSpawned; ulong num3 = (((Object)(object)component != (Object)null) ? component.NetworkObjectId : 0); Plugin.logger.LogInfo((object)($"[INJECT-DIAG] Turret found. NetworkObjectId={num3}, " + $"IsSpawned={flag}, HasNetworkObject={(Object)(object)component != (Object)null}, " + $"AlreadyHasFAIR_AI={(Object)(object)((Component)val).gameObject.GetComponent<FAIR_AI>() != (Object)null}")); if ((Object)(object)((Component)val).gameObject.GetComponent<FAIR_AI>() == (Object)null) { ((Component)val).gameObject.AddComponent<FAIR_AI>(); num++; } else { num2++; } } } Plugin.logger.LogInfo((object)$"FAIR_AI injection complete: {num} added, {num2} already present (out of {array.Length} turrets found)."); } private static bool IsTargetGone(EnemyAI enemy) { return (Object)(object)enemy == (Object)null || (Object)(object)((Component)enemy).gameObject == (Object)null || enemy.isEnemyDead || enemy.enemyHP <= 0; } private static bool IsTargetGone(PlayerControllerB player) { return (Object)(object)player == (Object)null || player.isPlayerDead; } private static TurretTarget GetCurrentTarget(Turret turret, FAIR_AI ai) { if (!IsTargetGone(ai.targetWithRotation)) { return new TurretTarget(ai.targetWithRotation); } if (!IsTargetGone(turret.targetPlayerWithRotation)) { return new TurretTarget(turret.targetPlayerWithRotation); } return TurretTarget.None; } private static void SetCurrentTarget(Turret turret, FAIR_AI ai, TurretTarget target) { //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) turret.targetPlayerWithRotation = null; ai.targetWithRotation = null; if (target.IsPlayer) { turret.targetPlayerWithRotation = target.Player; } else { if (!target.IsEnemy) { return; } ai.targetWithRotation = target.Enemy; turret.targetTransform = ((Component)target.Enemy).transform; ai.replicatedAimPosition = target.AimPosition; if (((NetworkBehaviour)turret).IsServer) { NetworkObject networkObject = ((NetworkBehaviour)target.Enemy).NetworkObject; if ((Object)(object)networkObject == (Object)null || !networkObject.IsSpawned) { Plugin.logger.LogWarning((object)"[RPC-SEND-DIAG] Enemy's NetworkObject is null or not spawned — RPC will likely fail to resolve on clients!"); } ai.SwitchedTargetedEnemyClientRpc(NetworkObjectReference.op_Implicit(networkObject), target.AimPosition); } } } private static void ClearTarget(Turret turret, FAIR_AI ai) { turret.targetPlayerWithRotation = null; ai.targetWithRotation = null; turret.targetTransform = null; ai.targetWithRotation = null; if (((NetworkBehaviour)turret).IsServer) { turret.RemoveTargetedPlayerClientRpc(); ai.RemoveTargetedEnemyClientRpc(); } } public static bool PatchUpdate(ref Turret __instance) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Invalid comparison between Unknown and I4 //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Invalid comparison between Unknown and I4 //IL_0126: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Invalid comparison between Unknown and I4 //IL_015c: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_0163: Unknown result type (might be due to invalid IL or missing references) //IL_0165: Unknown result type (might be due to invalid IL or missing references) //IL_0167: Unknown result type (might be due to invalid IL or missing references) //IL_017e: Expected I4, but got Unknown //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_0154: Unknown result type (might be due to invalid IL or missing references) //IL_01ca: 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_0245: Unknown result type (might be due to invalid IL or missing references) //IL_0250: Unknown result type (might be due to invalid IL or missing references) //IL_0261: Unknown result type (might be due to invalid IL or missing references) //IL_022d: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)__instance == (Object)null || !Plugin.AllowFairness(((Component)__instance).transform.position)) { return false; } Turret val = __instance; FAIR_AI aI = GetAI(val); if (!val.turretActive) { SetField(val, "wasTargetingPlayerLastFrame", false); val.turretMode = (TurretMode)0; ClearTarget(val, aI); return false; } if (IsTargetGone(aI.targetWithRotation)) { aI.targetWithRotation = null; val.targetTransform = null; } if (IsTargetGone(val.targetPlayerWithRotation)) { val.targetPlayerWithRotation = null; } TurretTarget currentTarget = GetCurrentTarget(val, aI); if (currentTarget.IsValid) { if (!GetField<bool>(val, "wasTargetingPlayerLastFrame")) { SetField(val, "wasTargetingPlayerLastFrame", true); if ((int)val.turretMode == 0) { val.turretMode = (TurretMode)1; } } SyncTargetTransform(val, aI, currentTarget); } else if (GetField<bool>(val, "wasTargetingPlayerLastFrame") || (int)val.turretMode == 2 || (int)val.turretMode == 1) { ClearTarget(val, aI); SetField(val, "wasTargetingPlayerLastFrame", false); val.turretMode = (TurretMode)0; } TurretMode turretMode = val.turretMode; TurretMode val2 = turretMode; switch ((int)val2) { case 0: DetectionFunction(val, aI); break; case 1: ChargingFunction(val, aI); break; case 2: FiringFunction(val, aI); break; case 3: BerserkFunction(val); break; } if (GetField<bool>(val, "rotatingClockwise")) { val.turnTowardsObjectCompass.localEulerAngles = new Vector3(-180f, val.turretRod.localEulerAngles.y - Time.deltaTime * 20f, 180f); } else if (GetField<bool>(val, "rotatingSmoothly")) { val.turnTowardsObjectCompass.localEulerAngles = new Vector3(-180f, Mathf.Clamp(val.targetRotation, 0f - val.rotationRange, val.rotationRange), 180f); } val.turretRod.rotation = Quaternion.RotateTowards(val.turretRod.rotation, val.turnTowardsObjectCompass.rotation, val.rotationSpeed * Time.deltaTime); return false; } private static void DetectionFunction(Turret turret, FAIR_AI ai) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Invalid comparison between Unknown and I4 //IL_027e: Unknown result type (might be due to invalid IL or missing references) if ((int)GetField<TurretMode>(turret, "turretModeLastFrame") > 0) { SetField(turret, "turretModeLastFrame", (object)(TurretMode)0); SetField(turret, "rotatingClockwise", false); SetField(turret, "rotatingSmoothly", true); SetField(turret, "turretInterval", Random.Range(0f, 0.15f)); turret.mainAudio.Stop(); turret.farAudio.Stop(); turret.berserkAudio.Stop(); StopAndStartFadeBulletAudio(turret); turret.bulletParticles.Stop(true, (ParticleSystemStopBehavior)0); turret.rotationSpeed = DetectSpeed; turret.turretAnimator.SetInteger("TurretMode", 0); } if (!((NetworkBehaviour)turret).IsServer) { return; } float field = GetField<float>(turret, "switchRotationTimer"); if (field >= SwitchInterval) { SetField(turret, "switchRotationTimer", 0f); bool flag = !GetField<bool>(turret, "rotatingRight"); turret.SwitchRotationClientRpc(flag); turret.SwitchRotationOnInterval(flag); } else { SetField(turret, "switchRotationTimer", field + Time.deltaTime); } float field2 = GetField<float>(turret, "turretInterval"); if (field2 < 0.25f) { SetField(turret, "turretInterval", field2 + Time.deltaTime); return; } SetField(turret, "turretInterval", 0f); TurretTarget target = FindBestTarget(turret, angleRangeCheck: true); if (target.IsValid && (!target.IsEnemy || Plugin.CanMob("TurretTargetAllMobs", ".Turret Target", target.Enemy.enemyType.enemyName))) { SetCurrentTarget(turret, ai, target); if (target.IsEnemy) { Plugin.logger.LogInfo((object)("Turret: Detected enemy '" + target.Enemy.enemyType.enemyName + "', entering charging mode.")); } else { turret.SwitchTargetedPlayerClientRpc((int)target.Player.playerClientId, true); Plugin.logger.LogInfo((object)"Turret: Detected player, entering charging mode."); } CallMethod(turret, "SwitchTurretMode", (object)(TurretMode)1); turret.SetToModeClientRpc(1); turret.turretMode = (TurretMode)1; } } private static void ChargingFunction(Turret turret, FAIR_AI ai) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Invalid comparison between Unknown and I4 if ((int)GetField<TurretMode>(turret, "turretModeLastFrame") != 1) { SetField(turret, "turretModeLastFrame", (object)(TurretMode)1); SetField(turret, "rotatingClockwise", false); SetField(turret, "rotatingSmoothly", false); SetField(turret, "lostLOSTimer", 0f); turret.mainAudio.PlayOneShot(turret.detectPlayerSFX); WalkieTalkie.TransmitOneShotAudio(turret.mainAudio, turret.detectPlayerSFX, 1f); turret.berserkAudio.Stop(); turret.rotationSpeed = ChargeSpeed; turret.turretAnimator.SetInteger("TurretMode", 1); } TurnTowardsTarget(turret, ai); if (!((NetworkBehaviour)turret).IsServer) { return; } float field = GetField<float>(turret, "turretInterval"); if (field < 1.5f) { SetField(turret, "turretInterval", field + Time.deltaTime); return; } SetField(turret, "turretInterval", 0f); TurretTarget target = FindBestTarget(turret, angleRangeCheck: false); if (!target.IsValid) { Plugin.logger.LogInfo((object)"Turret: Lost LOS during charge wind-up, returning to detection."); ClearTarget(turret, ai); return; } if (target.IsEnemy && !Plugin.CanMob("TurretTargetAllMobs", ".Turret Target", target.Enemy.enemyType.enemyName)) { ClearTarget(turret, ai); return; } SetCurrentTarget(turret, ai, target); Plugin.logger.LogInfo((object)"Turret: Charge complete, opening fire."); CallMethod(turret, "SwitchTurretMode", (object)(TurretMode)2); turret.SetToModeClientRpc(2); } private static void FiringFunction(Turret turret, FAIR_AI ai) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Invalid comparison between Unknown and I4 //IL_0070: Unknown result type (might be due to invalid IL or missing references) if ((int)GetField<TurretMode>(turret, "turretModeLastFrame") != 2) { SetField(turret, "turretModeLastFrame", (object)(TurretMode)2); SetField(turret, "rotatingSmoothly", false); SetField(turret, "lostLOSTimer", 0f); turret.berserkAudio.Stop(); RoundManager.Instance.PlayAudibleNoise(((Component)turret.berserkAudio).transform.position, 15f, 0.9f, 0, false, 0); turret.mainAudio.clip = turret.firingSFX; turret.mainAudio.Play(); turret.farAudio.clip = turret.firingFarSFX; turret.farAudio.Play(); turret.bulletParticles.Play(true); turret.bulletCollisionAudio.Play(); StopAndStartFadeBulletAudio(turret); turret.bulletCollisionAudio.volume = 1f; turret.turretAnimator.SetInteger("TurretMode", 2); } TurnTowardsTarget(turret, ai); if (!GetField<bool>(turret, "hasLineOfSight")) { if (!((NetworkBehaviour)turret).IsServer) { return; } float num = GetField<float>(turret, "lostLOSTimer") + Time.deltaTime; SetField(turret, "lostLOSTimer", num); if (num >= 2f) { SetField(turret, "lostLOSTimer", 0f); TurretTarget target = FindBestTarget(turret, angleRangeCheck: false); if (target.IsValid && (!target.IsEnemy || Plugin.CanMob("TurretTargetAllMobs", ".Turret Target", target.Enemy.enemyType.enemyName))) { Plugin.logger.LogInfo((object)"Turret: Re-acquired target after LOS loss."); SetCurrentTarget(turret, ai, target); SetField(turret, "turretInterval", 0f); } else { Plugin.logger.LogInfo((object)"Turret: LOS lost for 2 s, no replacement — returning to detection."); ReturnToDetection(turret, ai); } } return; } SetField(turret, "lostLOSTimer", 0f); float field = GetField<float>(turret, "turretInterval"); if (field < FireInterval) { SetField(turret, "turretInterval", field + Time.deltaTime); return; } SetField(turret, "turretInterval", 0f); ApplyDamageToLocalPlayer(turret); PerformShootRaycast(turret, useCenterPoint: false); TurretTarget currentTarget = GetCurrentTarget(turret, ai); if (!currentTarget.IsValid || currentTarget.IsDead) { TurretTarget target2 = FindBestTarget(turret, angleRangeCheck: false); if (target2.IsValid && (!target2.IsEnemy || Plugin.CanMob("TurretTargetAllMobs", ".Turret Target", target2.Enemy.enemyType.enemyName))) { Plugin.logger.LogInfo((object)"Turret: Target died, acquired new target."); SetCurrentTarget(turret, ai, target2); } else { Plugin.logger.LogInfo((object)"Turret: Target died, no new targets — returning to detection."); ReturnToDetection(turret, ai); } } } private static void BerserkFunction(Turret turret) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Invalid comparison between Unknown and I4 if ((int)GetField<TurretMode>(turret, "turretModeLastFrame") != 3) { SetField(turret, "turretModeLastFrame", (object)(TurretMode)3); SetField(turret, "rotatingClockwise", false); SetField(turret, "rotatingSmoothly", true); SetField(turret, "lostLOSTimer", 0f); SetField(turret, "wasTargetingPlayerLastFrame", false); SetField(turret, "berserkTimer", 1.3f); SetField(turret, "enteringBerserkMode", true); turret.targetPlayerWithRotation = null; turret.rotationSpeed = BerserkSpeed; turret.berserkAudio.Play(); turret.turretAnimator.SetInteger("TurretMode", 1); } if (GetField<bool>(turret, "enteringBerserkMode")) { float num = GetField<float>(turret, "berserkTimer") - Time.deltaTime; SetField(turret, "berserkTimer", num); if (num <= 0f) { SetField(turret, "enteringBerserkMode", false); SetField(turret, "rotatingClockwise", true); SetField(turret, "berserkTimer", 9f); turret.turretAnimator.SetInteger("TurretMode", 2); turret.mainAudio.clip = turret.firingSFX; turret.mainAudio.Play(); turret.farAudio.clip = turret.firingFarSFX; turret.farAudio.Play(); turret.bulletParticles.Play(true); turret.bulletCollisionAudio.Play(); StopAndStartFadeBulletAudio(turret); turret.bulletCollisionAudio.volume = 1f; } return; } float field = GetField<float>(turret, "turretInterval"); if (field >= FireInterval) { SetField(turret, "turretInterval", 0f); ApplyDamageToLocalPlayer(turret); PerformShootRaycast(turret, useCenterPoint: true); } else { SetField(turret, "turretInterval", field + Time.deltaTime); } if (((NetworkBehaviour)turret).IsServer) { float num2 = GetField<float>(turret, "berserkTimer") - Time.deltaTime; SetField(turret, "berserkTimer", num2); if (num2 <= 0f) { CallMethod(turret, "SwitchTurretMode", 0); turret.SetToModeClientRpc(0); } } } private static TurretTarget FindBestTarget(Turret turret, bool angleRangeCheck) { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) EnemyAI val = SweepForEnemy(turret); if ((Object)(object)val != (Object)null && !val.isEnemyDead && (!angleRangeCheck || WithinAngleRange(turret, ((Component)val).transform.position + Vector3.up * 0.5f))) { return new TurretTarget(val); } PlayerControllerB val2 = SweepForPlayer(turret, angleRangeCheck); if ((Object)(object)val2 != (Object)null && !val2.isPlayerDead) { return new TurretTarget(val2); } return TurretTarget.None; } private static EnemyAI SweepForEnemy(Turret turret) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004d: 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_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: 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_0141: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Unknown result type (might be due to invalid IL or missing references) float rotationRange = turret.rotationRange; Vector3 val = Quaternion.Euler(0f, 0f - rotationRange, 0f) * turret.aimPoint.forward; float num = rotationRange * 2f / 6f; Ray val2 = default(Ray); for (int i = 0; i < 7; i++) { ((Ray)(ref val2))..ctor(turret.centerPoint.position, val); RaycastHit[] array = Physics.RaycastAll(val2, 30f, -5, (QueryTriggerInteraction)2); Array.Sort(array, (RaycastHit a, RaycastHit b) => ((RaycastHit)(ref a)).distance.CompareTo(((RaycastHit)(ref b)).distance)); RaycastHit[] array2 = array; for (int num2 = 0; num2 < array2.Length; num2++) { RaycastHit val3 = array2[num2]; if (Physics.Linecast(turret.centerPoint.position, ((RaycastHit)(ref val3)).point, StartOfRound.Instance.collidersAndRoomMask, (QueryTriggerInteraction)1)) { break; } EnemyAI val4 = ((Component)((RaycastHit)(ref val3)).transform).GetComponent<EnemyAI>() ?? ((Component)((RaycastHit)(ref val3)).transform).GetComponent<EnemyAICollisionDetect>()?.mainScript; if ((Object)(object)val4 != (Object)null && !val4.isEnemyDead && val4.enemyHP > 0) { return val4; } } val = Quaternion.Euler(0f, num, 0f) * val; } return null; } private static PlayerControllerB SweepForPlayer(Turret turret, bool angleRangeCheck) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004d: 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_0165: Unknown result type (might be due to invalid IL or missing references) //IL_016a: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Unknown result type (might be due to invalid IL or missing references) //IL_0170: 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) //IL_00f6: Invalid comparison between Unknown and I4 //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Invalid comparison between Unknown and I4 //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Unknown result type (might be due to invalid IL or missing references) float rotationRange = turret.rotationRange; Vector3 val = Quaternion.Euler(0f, 0f - rotationRange, 0f) * turret.aimPoint.forward; float num = rotationRange * 2f / 6f; Ray val2 = default(Ray); RaycastHit val3 = default(RaycastHit); for (int i = 0; i < 7; i++) { ((Ray)(ref val2))..ctor(turret.centerPoint.position, val); if (Physics.Raycast(val2, ref val3, 30f, 1051400, (QueryTriggerInteraction)1)) { if (((Component)((RaycastHit)(ref val3)).transform).CompareTag("Player")) { PlayerControllerB component = ((Component)((RaycastHit)(ref val3)).transform).GetComponent<PlayerControllerB>(); if ((Object)(object)component != (Object)null) { if (angleRangeCheck && !WithinAngleRange(turret, ((Component)component).transform.position + Vector3.up * 1.75f)) { return null; } return component; } } else if (((int)turret.turretMode == 2 || (int)turret.turretMode == 3) && !GetField<bool>(turret, "enteringBerserkMode") && ((Component)((RaycastHit)(ref val3)).transform).tag.StartsWith("PlayerRagdoll")) { Rigidbody component2 = ((Component)((RaycastHit)(ref val3)).transform).GetComponent<Rigidbody>(); if (component2 != null) { component2.AddForce(((Vector3)(ref val)).normalized * 42f, (ForceMode)1); } } } val = Quaternion.Euler(0f, num, 0f) * val; } return null; } private static bool WithinAngleRange(Turret turret, Vector3 worldPos) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) return Vector3.Angle(worldPos - turret.centerPoint.position, turret.forwardFacingPos.forward) <= turret.rotationRange; } private static void TurnTowardsTarget(Turret turret, FAIR_AI ai) { //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0064: 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) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: 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_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) TurretTarget currentTarget = GetCurrentTarget(turret, ai); if (currentTarget.IsValid) { SyncTargetTransform(turret, ai, currentTarget); Vector3 val = ((((NetworkBehaviour)turret).IsServer || currentTarget.IsPlayer) ? currentTarget.AimPosition : ((ai.replicatedAimPosition != Vector3.zero) ? ai.replicatedAimPosition : currentTarget.AimPosition)); bool flag = WithinAngleRange(turret, val); bool flag2 = flag && !Physics.Linecast(turret.aimPoint.position, val, StartOfRound.Instance.collidersAndRoomMask, (QueryTriggerInteraction)1); SetField(turret, "hasLineOfSight", flag2); if (flag2 || flag) { turret.tempTransform.position = val - Vector3.up * 0.15f; turret.turnTowardsObjectCompass.LookAt(turret.tempTransform); } if (((NetworkBehaviour)turret).IsServer && currentTarget.IsEnemy && flag2) { ai.SyncEnemyAimPositionClientRpc(val); } } } private static void SyncTargetTransform(Turret turret, FAIR_AI ai, TurretTarget target) { if (target.IsPlayer) { turret.targetTransform = ((target.Player.isPlayerDead && (Object)(object)target.Player.deadBody != (Object)null) ? ((Component)target.Player.deadBody.bodyParts[5]).transform : ((Component)target.Player.gameplayCamera).transform); } else if (target.IsEnemy) { turret.targetTransform = ((Component)target.Enemy).transform; } } private static void ApplyDamageToLocalPlayer(Turret turret) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) PlayerControllerB localPlayerController = GameNetworkManager.Instance.localPlayerController; if ((Object)(object)localPlayerController == (Object)null || localPlayerController.isPlayerDead) { return; } Ray val = default(Ray); ((Ray)(ref val))..ctor(turret.centerPoint.position, turret.aimPoint.forward); RaycastHit val2 = default(RaycastHit); if (Physics.Raycast(val, ref val2, 30f, 1051400, (QueryTriggerInteraction)1) && ((Component)((RaycastHit)(ref val2)).transform).CompareTag("Player") && !((Object)(object)((Component)((RaycastHit)(ref val2)).transform).GetComponent<PlayerControllerB>() != (Object)(object)localPlayerController)) { int playerDamage = PlayerDamage; if (playerDamage <= 0) { localPlayerController.MakeCriticallyInjured(false); localPlayerController.DamagePlayer(playerDamage, false, true, (CauseOfDeath)0, 0, false, default(Vector3)); localPlayerController.MakeCriticallyInjured(false); } else if (localPlayerController.health > playerDamage) { localPlayerController.DamagePlayer(playerDamage, true, true, (CauseOfDeath)7, 0, false, default(Vector3)); } else { localPlayerController.KillPlayer(turret.aimPoint.forward * 40f, true, (CauseOfDeath)7, 0, default(Vector3), false); } } } private static void PerformShootRaycast(Turret turret, bool useCenterPoint) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0030: 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_007b: Unknown result type (might be due to invalid IL or missing references) //IL_009d: 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_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: 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_00d9: Unknown result type (might be due to invalid IL or missing references) Ray val = default(Ray); ((Ray)(ref val))..ctor(turret.aimPoint.position, turret.aimPoint.forward); SetField(turret, "shootRay", val); RaycastHit val2 = default(RaycastHit); if (Physics.Raycast(val, ref val2, 30f, StartOfRound.Instance.collidersAndRoomMask, (QueryTriggerInteraction)1)) { SetField(turret, "hit", val2); ((Component)turret.bulletCollisionAudio).transform.position = ((Ray)(ref val)).GetPoint(((RaycastHit)(ref val2)).distance - 0.5f); } Vector3 aimPoint = (useCenterPoint ? turret.centerPoint.position : turret.aimPoint.position); Vector3 forward = Quaternion.Euler(0f, (float)(-(int)turret.rotationRange) / 3f, 0f) * turret.aimPoint.forward; Plugin.AttackTargets(((Component)turret).GetComponent<FAIR_AI>(), aimPoint, forward, 30f); } private static void ReturnToDetection(Turret turret, FAIR_AI ai) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) ClearTarget(turret, ai); turret.turretMode = (TurretMode)0; turret.SetToModeClientRpc(0); SetField(turret, "wasTargetingPlayerLastFrame", false); SetField(turret, "targetingDeadPlayer", true); turret.turretAnimator.SetInteger("TurretMode", 0); CallMethod(turret, "SwitchTurretMode", (object)(TurretMode)0); } public static bool CheckForTargetsInLOS(ref Turret __instance, float radius = 2f, bool angleRangeCheck = false) { FAIR_AI aI = GetAI(__instance); TurretTarget turretTarget = FindBestTarget(__instance, angleRangeCheck); if (!turretTarget.IsValid) { return false; } aI.targets = new Dictionary<int, GameObject> { { 0, turretTarget.IsPlayer ? ((Component)turretTarget.Player).gameObject : ((Component)turretTarget.Enemy).gameObject } }; return true; } public static bool SetTargetToEnemyBody(ref Turret __instance) { if ((Object)(object)__instance == (Object)null) { return false; } FAIR_AI aI = GetAI(__instance); SyncTargetTransform(__instance, aI, GetCurrentTarget(__instance, aI)); return false; } public static bool TurnTowardsTargetEnemyIfHasLOS(ref Turret __instance) { if ((Object)(object)__instance == (Object)null) { return false; } TurnTowardsTarget(__instance, GetAI(__instance)); return false; } private static void StopAndStartFadeBulletAudio(Turret turret) { FieldInfo field = TurretType.GetField("fadeBulletAudioCoroutine", BindingFlags.Instance | BindingFlags.NonPublic); object? obj = field?.GetValue(turret); Coroutine val = (Coroutine)((obj is Coroutine) ? obj : null); if (val != null) { ((MonoBehaviour)turret).StopCoroutine(val); } MethodInfo method = TurretType.GetMethod("FadeBulletAudio", BindingFlags.Instance | BindingFlags.NonPublic); field?.SetValue(turret, ((MonoBehaviour)turret).StartCoroutine((IEnumerator)method.Invoke(turret, null))); } } namespace FairAI { public class FAIR_AI : NetworkBehaviour { public EnemyAI targetWithRotation; public Dictionary<int, GameObject> targets; public Vector3 replicatedAimPosition; private void Awake() { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) targetWithRotation = null; replicatedAimPosition = Vector3.zero; } public override void OnNetworkSpawn() { ((NetworkBehaviour)this).OnNetworkSpawn(); } [ClientRpc] public void SwitchedTargetedEnemyClientRpc(NetworkObjectReference enemyRef, Vector3 initialAimPosition) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Invalid comparison between Unknown and I4 //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0083: 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) //IL_00e9: 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) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager; if (networkManager == null || !networkManager.IsListening) { return; } if ((int)base.__rpc_exec_stage != 1 && (networkManager.IsServer || networkManager.IsHost)) { ClientRpcParams val2 = default(ClientRpcParams); FastBufferWriter val = ((NetworkBehaviour)this).__beginSendClientRpc(2479104455u, val2, (RpcDelivery)0); ((FastBufferWriter)(ref val)).WriteValueSafe<NetworkObjectReference>(ref enemyRef, default(ForNetworkSerializable)); ((FastBufferWriter)(ref val)).WriteValueSafe(ref initialAimPosition); ((NetworkBehaviour)this).__endSendClientRpc(ref val, 2479104455u, val2, (RpcDelivery)0); } if ((int)base.__rpc_exec_stage == 1 && (networkManager.IsClient || networkManager.IsHost)) { base.__rpc_exec_stage = (__RpcExecStage)0; replicatedAimPosition = initialAimPosition; NetworkObject val3 = default(NetworkObject); if (((NetworkObjectReference)(ref enemyRef)).TryGet(ref val3, (NetworkManager)null)) { targetWithRotation = ((Component)val3).GetComponent<EnemyAI>(); } else { targetWithRotation = null; } } } [ClientRpc] public void RemoveTargetedEnemyClientRpc() { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Invalid comparison between Unknown and I4 //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: 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) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager; if (networkManager != null && networkManager.IsListening) { if ((int)base.__rpc_exec_stage != 1 && (networkManager.IsServer || networkManager.IsHost)) { ClientRpcParams val2 = default(ClientRpcParams); FastBufferWriter val = ((NetworkBehaviour)this).__beginSendClientRpc(1714866907u, val2, (RpcDelivery)0); ((NetworkBehaviour)this).__endSendClientRpc(ref val, 1714866907u, val2, (RpcDelivery)0); } if ((int)base.__rpc_exec_stage == 1 && (networkManager.IsClient || networkManager.IsHost)) { base.__rpc_exec_stage = (__RpcExecStage)0; targetWithRotation = null; replicatedAimPosition = Vector3.zero; } } } [ClientRpc] public void SyncEnemyAimPositionClientRpc(Vector3 aimPosition) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Invalid comparison between Unknown and I4 //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: 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_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager; if (networkManager != null && networkManager.IsListening) { if ((int)base.__rpc_exec_stage != 1 && (networkManager.IsServer || networkManager.IsHost)) { ClientRpcParams val2 = default(ClientRpcParams); FastBufferWriter val = ((NetworkBehaviour)this).__beginSendClientRpc(2335698067u, val2, (RpcDelivery)0); ((FastBufferWriter)(ref val)).WriteValueSafe(ref aimPosition); ((NetworkBehaviour)this).__endSendClientRpc(ref val, 2335698067u, val2, (RpcDelivery)0); } if ((int)base.__rpc_exec_stage == 1 && (networkManager.IsClient || networkManager.IsHost)) { base.__rpc_exec_stage = (__RpcExecStage)0; replicatedAimPosition = aimPosition; } } } protected override void __initializeVariables() { ((NetworkBehaviour)this).__initializeVariables(); } protected override void __initializeRpcs() { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Expected O, but got Unknown //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Expected O, but got Unknown //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Expected O, but got Unknown ((NetworkBehaviour)this).__registerRpc(2479104455u, new RpcReceiveHandler(__rpc_handler_2479104455), "SwitchedTargetedEnemyClientRpc"); ((NetworkBehaviour)this).__registerRpc(1714866907u, new RpcReceiveHandler(__rpc_handler_1714866907), "RemoveTargetedEnemyClientRpc"); ((NetworkBehaviour)this).__registerRpc(2335698067u, new RpcReceiveHandler(__rpc_handler_2335698067), "SyncEnemyAimPositionClientRpc"); ((NetworkBehaviour)this).__initializeRpcs(); } private static void __rpc_handler_2479104455(NetworkBehaviour target, FastBufferReader reader, __RpcParams rpcParams) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = target.NetworkManager; if (networkManager != null && networkManager.IsListening) { NetworkObjectReference enemyRef = default(NetworkObjectReference); ((FastBufferReader)(ref reader)).ReadValueSafe<NetworkObjectReference>(ref enemyRef, default(ForNetworkSerializable)); Vector3 initialAimPosition = default(Vector3); ((FastBufferReader)(ref reader)).ReadValueSafe(ref initialAimPosition); target.__rpc_exec_stage = (__RpcExecStage)1; ((FAIR_AI)(object)target).SwitchedTargetedEnemyClientRpc(enemyRef, initialAimPosition); target.__rpc_exec_stage = (__RpcExecStage)0; } } private static void __rpc_handler_1714866907(NetworkBehaviour target, FastBufferReader reader, __RpcParams rpcParams) { //IL_0029: 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) NetworkManager networkManager = target.NetworkManager; if (networkManager != null && networkManager.IsListening) { target.__rpc_exec_stage = (__RpcExecStage)1; ((FAIR_AI)(object)target).RemoveTargetedEnemyClientRpc(); target.__rpc_exec_stage = (__RpcExecStage)0; } } private static void __rpc_handler_2335698067(NetworkBehaviour target, FastBufferReader reader, __RpcParams rpcParams) { //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = target.NetworkManager; if (networkManager != null && networkManager.IsListening) { Vector3 aimPosition = default(Vector3); ((FastBufferReader)(ref reader)).ReadValueSafe(ref aimPosition); target.__rpc_exec_stage = (__RpcExecStage)1; ((FAIR_AI)(object)target).SyncEnemyAimPositionClientRpc(aimPosition); target.__rpc_exec_stage = (__RpcExecStage)0; } } protected internal override string __getTypeName() { return "FAIR_AI"; } } [BepInPlugin("GoldenKitten.FairAI", "Fair AI", "1.6.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { private const string modGUID = "GoldenKitten.FairAI"; private const string modName = "Fair AI"; private const string modVersion = "1.6.0"; private Harmony harmony = new Harmony("GoldenKitten.FairAI"); private static readonly float onMeshThreshold = 3f; public static Plugin Instance = null; public static ManualLogSource logger; public static List<EnemyType> allEnemies; public static List<EnemyType> enemies; public static List<Item> items; public static List<EnemyType> enemyList; public static List<Item> itemList; public static List<float> turretSettings; public static Dictionary<string, float[]> speeds; public static Dictionary<int, Vector3> positions; public static Dictionary<int, float> sinkingValues; public static Dictionary<int, float> sinkingProgress; public static Assembly codeRebirthAssembly; public static Assembly lethalConfigAssembly; public static Assembly lguAssembly; public static Assembly surfacedAssembly; public static Assembly turretSettingsAssembly; public static Type rubberBootsType; public static PropertyInfo tsBoundConfig; public const string ltModID = "evaisa.lethalthings"; public const string surfacedModID = "Surfaced"; public static bool codeRebirthEnabled = false; public static bool lethalConfigEnabled = false; public static bool lethalThingsEnabled = false; public static bool lguEnabled = false; public static bool playersEnteredInside = false; public static bool roundHasStarted = false; public static bool surfacedEnabled = false; public static bool turretSettingsEnabled = false; public static int wallsAndEnemyLayerMask = 524288; public static int enemyMask = 524288; public static int allHittablesMask; private async void Awake() { if ((Object)(object)Instance == (Object)null) { Instance = this; } logger = Logger.CreateLogSource("GoldenKitten.FairAI"); try { Type[] types = Assembly.GetExecutingAssembly().GetTypes(); int invokedCount = 0; Type[] array = types; foreach (Type type in array) { MethodInfo[] methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic); MethodInfo[] array2 = methods; foreach (MethodInfo method in array2) { object[] attributes = method.GetCustomAttributes(typeof(RuntimeInitializeOnLoadMethodAttribute), inherit: false); if (attributes.Length != 0) { logger.LogInfo((object)("[RPC-INIT-DIAG] Invoking initializer: " + type.FullName + "." + method.Name)); method.Invoke(null, null); invokedCount++; } } } logger.LogInfo((object)$"NetcodePatcher RPC initializers invoked. ({invokedCount} total)"); } catch (Exception arg) { logger.LogError((object)$"Failed to invoke NetcodePatcher RPC initializers: {arg}"); } allEnemies = new List<EnemyType>(); enemies = new List<EnemyType>(); items = new List<Item>(); itemList = new List<Item>(); enemyList = new List<EnemyType>(); speeds = new Dictionary<string, float[]>(); positions = new Dictionary<int, Vector3>(); sinkingProgress = new Dictionary<int, float>(); turretSettings = new List<float>(); sinkingValues = new Dictionary<int, float>(); harmony = new Harmony("GoldenKitten.FairAI"); harmony.PatchAll(typeof(Plugin)); Patch(typeof(RoundManager), "Start", null, typeof(RoundManagerPatch), "PatchStart", isPrefix: false); Patch(typeof(StartOfRound), "Awake", null, typeof(LevelGenManPatch), "PatchAwake", isPrefix: false); Patch(typeof(StartOfRound), "Start", null, typeof(StartOfRoundPatch), "PatchStart", isPrefix: false); Patch(typeof(StartOfRound), "Update", null, typeof(StartOfRoundPatch), "PatchUpdate", isPrefix: false); Patch(typeof(FlowermanAI), "HitEnemy", new Type[4] { typeof(int), typeof(PlayerControllerB), typeof(bool), typeof(int) }, typeof(EnemyAIPatch), "BrackenHitEnemyPatch", isPrefix: true); Patch(typeof(HoarderBugAI), "HitEnemy", new Type[4] { typeof(int), typeof(PlayerControllerB), typeof(bool), typeof(int) }, typeof(EnemyAIPatch), "HoardingBugHitEnemyPatch", isPrefix: true); Patch(typeof(EnemyAI), "KillEnemyOnOwnerClient", new Type[1] { typeof(bool) }, typeof(EnemyAIPatch), "KillEnemyOnOwnerClientPatch", isPrefix: false); Patch(typeof(QuicksandTrigger), "OnTriggerStay", new Type[1] { typeof(Collider) }, typeof(QuickSandPatch), "OnTriggerStayPatch", isPrefix: true); Patch(typeof(QuicksandTrigger), "StopSinkingLocalPlayer", new Type[1] { typeof(PlayerControllerB) }, typeof(QuickSandPatch), "StopSinkingLocalPlayerPatch", isPrefix: true); Patch(typeof(QuicksandTrigger), "OnTriggerExit", new Type[1] { typeof(Collider) }, typeof(QuickSandPatch), "OnTriggerExitPatch", isPrefix: true); Patch(typeof(Turret), "Update", null, typeof(TurretAIPatch), "PatchUpdate", isPrefix: true); Patch(typeof(Turret), "CheckForPlayersInLineOfSight", new Type[2] { typeof(float), typeof(bool) }, typeof(TurretAIPatch), "CheckForTargetsInLOS", isPrefix: true); Patch(typeof(Turret), "SetTargetToPlayerBody", null, typeof(TurretAIPatch), "SetTargetToEnemyBody", isPrefix: true); Patch(typeof(Turret), "TurnTowardsTargetIfHasLOS", null, typeof(TurretAIPatch), "TurnTowardsTargetEnemyIfHasLOS", isPrefix: true); Patch(typeof(Landmine), "SpawnExplosion", new Type[8] { typeof(Vector3), typeof(bool), typeof(float), typeof(float), typeof(int), typeof(float), typeof(GameObject), typeof(bool) }, typeof(MineAIPatch), "PatchSpawnExplosion", isPrefix: false); Patch(typeof(Landmine), "OnTriggerEnter", null, typeof(MineAIPatch), "PatchOnTriggerEnter", isPrefix: false); Patch(typeof(Landmine), "OnTriggerExit", null, typeof(MineAIPatch), "PatchOnTriggerExit", isPrefix: false); Patch(typeof(Landmine), "Detonate", null, typeof(MineAIPatch), "DetonatePatch", isPrefix: false); await WaitForProcess(1); GetTurretSettings(); logger.LogInfo((object)"Fair AI initiated!"); } private void Patch(Type type, string method, Type[] parameters, Type patchType, string patchMethod, bool isPrefix) { CreateHarmonyPatch(harmony, type, method, parameters, patchType, patchMethod, isPrefix); } public static void ImmortalAffected() { if (!GetBool("General", "ImmortalAffected")) { enemies = (from EnemyType e in Resources.FindObjectsOfTypeAll(typeof(EnemyType)) where (Object)(object)e != (Object)null && e.canDie select e).ToList(); } allEnemies = (from EnemyType e in Resources.FindObjectsOfTypeAll(typeof(EnemyType)) where (Object)(object)e != (Object)null select e).ToList(); } public static float[] SpeedAndAccelerationEnemyList(EnemyAICollisionDetect enemy) { if ((Object)(object)enemy?.mainScript?.enemyType == (Object)null) { logger.LogWarning((object)"No valid enemy to get speeds!"); return new float[2] { 1f, 1f }; } string key = RemoveInvalidCharacters(enemy.mainScript.enemyType.enemyName); if (speeds.TryGetValue(key, out var value)) { return value; } NavMeshAgent componentInChildren = ((Component)enemy.mainScript).GetComponentInChildren<NavMeshAgent>(); float[] array = ((!((Object)(object)componentInChildren != (Object)null)) ? new float[2] { 1f, 1f } : new float[2] { componentInChildren.speed, componentInChildren.acceleration }); speeds[key] = array; return array; } public static float[] GetSpeeds(string name) { if (speeds.TryGetValue(name, out var value)) { return value; } logger.LogWarning((object)("Speeds missing on: " + name)); return null; } public static void GetTurretSettings() { if (!turretSettingsEnabled) { turretSettings = new List<float>(); return; } object value = tsBoundConfig.GetValue(null); if (value == null) { logger.LogInfo((object)"Unable to get BoundConfig"); return; } Type type = value.GetType(); turretSettings.Clear(); string[] array = new string[8] { "turretDamage", "turretFireRate", "turretWarmupTime", "turretRotateTimer", "turretRotationRange", "turretIdleRotationSpeed", "turretFiringRotationSpeed", "turretBerzerkRotationSpeed" }; string[] array2 = array; foreach (string name in array2) { FieldInfo field = type.GetField(name, BindingFlags.Instance | BindingFlags.Public); if (!(field == null)) { object value2 = field.GetValue(value); PropertyInfo propertyInfo = value2?.GetType().GetProperty("Value"); if (!(propertyInfo == null)) { object value3 = propertyInfo.GetValue(value2); turretSettings.Add((value3 is int num) ? ((float)num) : ((float)value3)); } } } logger.LogInfo((object)$"Got Turret Settings: {turretSettings.Count}"); } public static async Task<IEnumerable<int>> WaitForProcess(int waitTime) { await Task.Delay(waitTime); await Instance.DelayedInitialization(); return Array.Empty<int>(); } private async Task DelayedInitialization() { await Task.Run(delegate { TryLoadCodeRebirth(); TryLoadLategameUpgrades(); TryLoadLethalConfig(); TryLoadLethalThings(); TryLoadSurfaced(); TryLoadTurretSettings(); logger.LogInfo((object)"Optional Components initiated!"); }); } private void TryLoadLethalThings() { TryLoadAssembly("LethalThings", "LethalThings", ref lethalThingsEnabled, delegate(Assembly assembly) { Type type = assembly.GetType("LethalThings.RoombaAI"); if (!(type == null) && BoombaPatch.enabled) { Patch(type, "Start", null, typeof(BoombaPatch), "PatchStart", isPrefix: false); Patch(type, "DoAIInterval", null, typeof(BoombaPatch), "PatchDoAIInterval", isPrefix: false); lethalThingsEnabled = true; } }); } private void TryLoadSurfaced() { TryLoadAssembly("Surfaced", "Surfaced", ref surfacedEnabled, delegate(Assembly assembly) { surfacedAssembly = assembly; if (SurfacedMinePatch.enabled) { Type type = assembly.GetType("Seamine"); if (type != null) { Patch(type, "OnTriggerEnter", new Type[1] { typeof(Collider) }, typeof(SurfacedMinePatch), "PatchOnTriggerEnter", isPrefix: false); surfacedEnabled = true; logger.LogInfo((object)"Surfaced Component Seamine Initiated!"); } Type type2 = assembly.GetType("Bertha"); if (type2 != null) { Patch(type2, "OnTriggerEnter", new Type[1] { typeof(Collider) }, typeof(SurfacedMinePatch), "PatchBerthaOnTriggerEnter", isPrefix: false); surfacedEnabled = true; logger.LogInfo((object)"Surfaced Component Bertha Initiated!"); } } }); } private void TryLoadTurretSettings() { TryLoadAssembly("TheNameIsTyler.TurretSettings", "TheNameIsTyler.TurretSettings", ref lethalConfigEnabled, delegate(Assembly assembly) { turretSettingsAssembly = assembly; PropertyInfo propertyInfo = turretSettingsAssembly.GetType("TurretSettings.TurretSettings")?.GetProperty("BoundConfig", BindingFlags.Static | BindingFlags.NonPublic); if (propertyInfo != null) { tsBoundConfig = propertyInfo; turretSettingsEnabled = true; logger.LogInfo((object)"TurretSettings Component Initiated!"); } }); } private void TryLoadLategameUpgrades() { TryLoadAssembly("MoreShipUpgrades", "MoreShipUpgrades", ref lguEnabled, delegate(Assembly assembly) { lguAssembly = assembly; Type type = lguAssembly.GetType("MoreShipUpgrades.UpgradeComponents.TierUpgrades.Player.RubberBoots"); if (type?.GetMethod("ReduceMovementHinderance") != null) { rubberBootsType = type; lguEnabled = true; logger.LogInfo((object)"LategameUpgrades Component Initiated!"); } }); } private void TryLoadLethalConfig() { TryLoadAssembly("LethalConfig", "LethalConfig", ref lethalConfigEnabled, delegate(Assembly assembly) { lethalConfigAssembly = assembly; if (assembly.GetType("LethalConfig.LethalConfigManager") != null) { lethalConfigEnabled = true; logger.LogInfo((object)"LethalConfig Component Initiated!"); } }); } private void TryLoadCodeRebirth() { TryLoadAssembly("CodeRebirth", "CodeRebirth", ref codeRebirthEnabled, delegate(Assembly assembly) { codeRebirthAssembly = assembly; if (assembly.GetType("CodeRebirth.CodeRebirthEnemyKeys.CutieFly") != null) { codeRebirthEnabled = true; logger.LogInfo((object)"CodeRebirth Component Initiated!"); } }); } private void TryLoadAssembly(string assemblyName, string pluginGuid, ref bool enabledFlag, Action<Assembly> onFound) { try { if (!Chainloader.PluginInfos.ContainsKey(pluginGuid)) { logger.LogWarning((object)(assemblyName + " assembly not found. Skipping optional patch.")); return; } Assembly assembly = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault((Assembly a) => a.GetName().Name == assemblyName); if (assembly != null) { onFound(assembly); } else { logger.LogWarning((object)(assemblyName + " assembly found in PluginInfos but not loaded. Skipping optional patch.")); } } catch (Exception e) { LogOptionalError(assemblyName, e); } } private static void LogOptionalError(string name, Exception e) { if (!e.Message.Contains("Could not load the file")) { logger.LogError((object)("An error occurred while trying to apply patches for " + name + ": " + e.Message)); } } public static List<PlayerControllerB> GetActivePlayers() { return StartOfRound.Instance.allPlayerScripts.Where((PlayerControllerB p) => (Object)(object)p != (Object)null && !p.isPlayerDead && ((Behaviour)p).isActiveAndEnabled && p.isPlayerControlled).ToList(); } public static bool AllowFairness(Vector3 position) { //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)StartOfRound.Instance == (Object)null) { return true; } if (!Can("CheckForPlayersInside")) { return true; } if (!StartOfRound.Instance.shipHasLanded) { return true; } if (!IsAPlayersOutside()) { goto IL_006d; } if (!(position.y > -80f)) { Bounds bounds = StartOfRound.Instance.shipInnerRoomBounds.bounds; if (!((Bounds)(ref bounds)).Contains(position)) { goto IL_006d; } } int result = 1; goto IL_0075; IL_006d: result = (playersEnteredInside ? 1 : 0); goto IL_0075; IL_0075: return (byte)result != 0; } public static bool IsAPlayersOutside() { if (!StartOfRound.Instance.shipHasLanded) { return false; } return GetActivePlayers().Any((PlayerControllerB p) => !p.isInsideFactory); } public static bool IsAPlayerInsideShip() { if (!StartOfRound.Instance.shipHasLanded) { return false; } return GetActivePlayers().Any((PlayerControllerB p) => p.isInHangarShipRoom); } public static bool IsAPlayerInsideDungeon() { if (!StartOfRound.Instance.shipHasLanded) { return false; } return GetActivePlayers().Any((PlayerControllerB p) => p.isInsideFactory); } public static bool CanMob(string parentIdentifier, string identifier, string mobName) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Expected O, but got Unknown if (!((BaseUnityPlugin)Instance).Config[new ConfigDefinition("Mobs", parentIdentifier)].BoxedValue.ToString().Equals("TRUE", StringComparison.OrdinalIgnoreCase)) { return false; } string text = RemoveInvalidCharacters(mobName).ToUpper(); string target = RemoveInvalidCharacters(text + identifier).ToUpper(); return ((BaseUnityPlugin)Instance).Config.Keys.Where((ConfigDefinition e) => RemoveInvalidCharacters(e.Key.ToUpper()) == target).Any((ConfigDefinition e) => ((BaseUnityPlugin)Instance).Config[e].BoxedValue.ToString().Equals("TRUE", StringComparison.OrdinalIgnoreCase)); } public static bool Can(string identifier) { string target = RemoveInvalidCharacters(identifier.ToUpper()); return ((BaseUnityPlugin)Instance).Config.Keys.Where((ConfigDefinition e) => RemoveInvalidCharacters(e.Key.ToUpper()) == target).Any((ConfigDefinition e) => ((BaseUnityPlugin)Instance).Config[e].BoxedValue.ToString().Equals("TRUE", StringComparison.OrdinalIgnoreCase)); } public static int GetInt(string parentIdentifier, string identifier) { try { int.TryParse(((BaseUnityPlugin)Instance).Config[parentIdentifier, identifier].BoxedValue.ToString(), out var result); return result; } catch { return 1; } } public static float GetFloat(string parentIdentifier, string identifier) { try { float.TryParse(((BaseUnityPlugin)Instance).Config[parentIdentifier, identifier].BoxedValue.ToString(), out var result); return result; } catch { return 1f; } } public static bool GetBool(string parentIdentifier, string identifier) { return ((BaseUnityPlugin)Instance).Config[parentIdentifier, identifier].BoxedValue.ToString().Equals("TRUE", StringComparison.OrdinalIgnoreCase); } public static string RemoveWhitespaces(string source) { return string.Join("", source.Split((string[]?)null, StringSplitOptions.RemoveEmptyEntries)); } public static string RemoveSpecialCharacters(string source) { StringBuilder stringBuilder = new StringBuilder(); foreach (char c in source) { if (char.IsLetterOrDigit(c)) { stringBuilder.Append(c); } } return stringBuilder.ToString(); } public static string RemoveInvalidCharacters(string source) { return RemoveWhitespaces(RemoveSpecialCharacters(source)); } public static Type FindType(string fullName) { try { return (from a in AppDomain.CurrentDomain.GetAssemblies() where !a.IsDynamic select a).SelectMany((Assembly a) => a.GetTypes()).FirstOrDefault((Type t) => t.FullName.Equals(fullName)); } catch { return null; } } public static void CreateHarmonyPatch(Harmony harmony, Type typeToPatch, string methodToPatch, Type[] parameters, Type patchType, string patchMethod, bool isPrefix, bool isTranspiler = false) { //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Expected O, but got Unknown //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Expected O, but got Unknown //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Expected O, but got Unknown if (typeToPatch == null || patchType == null) { logger.LogInfo((object)"Type is either incorrect or does not exist!"); return; } MethodInfo methodInfo = AccessTools.Method(typeToPatch, methodToPatch, parameters, (Type[])null); MethodInfo methodInfo2 = AccessTools.Method(patchType, patchMethod, (Type[])null, (Type[])null); if (isTranspiler) { harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null); } else if (isPrefix) { harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } else { harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } } public static bool IsAgentOnNavMesh(GameObject agentObject) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002e: 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_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) Vector3 position = agentObject.transform.position; NavMeshHit val = default(NavMeshHit); if (!NavMesh.SamplePosition(position, ref val, onMeshThreshold, -1)) { return false; } return Mathf.Approximately(position.x, ((NavMeshHit)(ref val)).position.x) && Mathf.Approximately(position.z, ((NavMeshHit)(ref val)).position.z) && position.y >= ((NavMeshHit)(ref val)).position.y; } public static List<GameObject> GetTargets(FAIR_AI turret_ai, Vector3 aimPoint, Vector3 forward, float range) { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003d: 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) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: 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) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_021b: Unknown result type (might be due to invalid IL or missing references) //IL_0220: Unknown result type (might be due to invalid IL or missing references) //IL_0222: Unknown result type (might be due to invalid IL or missing references) //IL_0227: Unknown result type (might be due to invalid IL or missing references) //IL_01f5: Unknown result type (might be due to invalid IL or missing references) //IL_01fa: Unknown result type (might be due to invalid IL or missing references) //IL_01a0: Unknown result type (might be due to invalid IL or missing references) //IL_01a5: Unknown result type (might be due to invalid IL or missing references) //IL_0192: Unknown result type (might be due to invalid IL or missing references) List<GameObject> list = new List<GameObject>(); HashSet<GameObject> hashSet = new HashSet<GameObject>(); float num = ((Component)turret_ai).GetComponent<Turret>()?.rotationRange ?? 45f; int num2 = 7; Vector3 val = Quaternion.Euler(0f, (0f - num) / 3f, 0f) * forward; float num3 = num / 3f * 2f / (float)(num2 - 1); Ray val2 = default(Ray); IHittable val5 = default(IHittable); EnemyAI val7 = default(EnemyAI); for (int i = 0; i < num2; i++) { ((Ray)(ref val2))..ctor(aimPoint, val); RaycastHit[] array = Physics.RaycastAll(val2, range, -5, (QueryTriggerInteraction)2); Array.Sort(array, (RaycastHit x, RaycastHit y) => ((RaycastHit)(ref x)).distance.CompareTo(((RaycastHit)(ref y)).distance)); Vector3 val3 = aimPoint + val * range; RaycastHit[] array2 = array; for (int num4 = 0; num4 < array2.Length; num4++) { RaycastHit val4 = array2[num4]; Transform transform = ((RaycastHit)(ref val4)).transform; if (((Component)transform).TryGetComponent<IHittable>(ref val5)) { EnemyAICollisionDetect val6 = (EnemyAICollisionDetect)(object)((val5 is EnemyAICollisionDetect) ? val5 : null); if (val6 != null) { EnemyAI mainScript = val6.mainScript; if ((Object)(object)mainScript != (Object)null && !mainScript.isEnemyDead && mainScript.enemyHP > 0 && hashSet.Add(((Component)transform).gameObject)) { list.Add(((Component)transform).gameObject); } } else if (!(val5 is PlayerControllerB) && !(val5 is SandSpiderWebTrap) && (!(val5 is Turret) || GetBool("TurretConfig", "HitOtherTurrets"))) { val5.Hit(1, val3, (PlayerControllerB)null, false, -1); } val3 = ((RaycastHit)(ref val4)).point; } else { if (((Component)transform).TryGetComponent<EnemyAI>(ref val7) && !val7.isEnemyDead && val7.enemyHP > 0 && hashSet.Add(((Component)transform).gameObject)) { list.Add(((Component)transform).gameObject); } val3 = ((RaycastHit)(ref val4)).point; } } val = Quaternion.Euler(0f, num3, 0f) * val; } return list; } public static List<EnemyAICollisionDetect> GetEnemyTargets(List<GameObject> originalTargets) { List<EnemyAICollisionDetect> list = new List<EnemyAICollisionDetect>(); EnemyAICollisionDetect item = default(EnemyAICollisionDetect); foreach (GameObject originalTarget in originalTargets) { if ((Object)(object)originalTarget == (Object)null) { continue; } if (originalTarget.TryGetComponent<EnemyAICollisionDetect>(ref item)) { list.Add(item); continue; } EnemyAICollisionDetect componentInChildren = originalTarget.GetComponentInChildren<EnemyAICollisionDetect>(); if ((Object)(object)componentInChildren != (Object)null) { list.Add(componentInChildren); } } return list; } public static bool AttackTargets(FAIR_AI turret_ai, Vector3 aimPoint, Vector3 forward, float range) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) return HitTargets(GetTargets(turret_ai, aimPoint, forward, range), forward); } public static bool HitTargets(List<GameObject> targets, Vector3 forward) { //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Unknown result type (might be due to invalid IL or missing references) if (!targets.Any()) { return false; } bool result = false; IHittable val3 = default(IHittable); foreach (GameObject target in targets) { if ((Object)(object)target == (Object)null) { continue; } EnemyAI val = target.GetComponent<EnemyAI>() ?? target.GetComponent<EnemyAICollisionDetect>()?.mainScript; if ((Object)(object)val != (Object)null) { if (CanMob("TurretDamageAllMobs", ".Turret Damage", val.enemyType.enemyName)) { int num = GetInt("TurretConfig", "Enemy Damage"); NutcrackerEnemyAI val2 = (NutcrackerEnemyAI)(object)((val is NutcrackerEnemyAI) ? val : null); if (val2 == null || ((EnemyAI)val2).currentBehaviourStateIndex > 0) { val.HitEnemyOnLocalClient(num, default(Vector3), (PlayerControllerB)null, false, -1); result = true; } } } else if (target.TryGetComponent<IHittable>(ref val3) && !(val3 is PlayerControllerB) && (!(val3 is Turret) || GetBool("TurretConfig", "HitOtherTurrets"))) { val3.Hit(1, forward, (PlayerControllerB)null, true, -1); result = true; } } return result; } } public class Utils { public static void AddLethalConfigBoolItem(ConfigEntry<bool> tempEntry) { Type type = Plugin.lethalConfigAssembly.GetType("LethalConfig.ConfigItems.BoolCheckBoxConfigItem"); ConstructorInfo constructor = type.GetConstructor(new Type[1] { typeof(ConfigEntry<bool>) }); object obj = constructor.Invoke(new object[1] { tempEntry }); Type type2 = Plugin.lethalConfigAssembly.GetType("LethalConfig.LethalConfigManager"); MethodInfo method = type2.GetMethod("AddConfigItem", new Type[1] { type.BaseType }); method.Invoke(null, new object[1] { obj }); } public static void AddLethalConfigFloatItem(ConfigEntry<float> tempEntry) { Type type = Plugin.lethalConfigAssembly.GetType("LethalConfig.ConfigItems.FloatInputFieldConfigItem"); ConstructorInfo constructor = type.GetConstructor(new Type[1] { typeof(ConfigEntry<float>) }); object obj = constructor.Invoke(new object[1] { tempEntry }); Type type2 = Plugin.lethalConfigAssembly.GetType("LethalConfig.LethalConfigManager"); MethodInfo method = type2.GetMethod("AddConfigItem", new Type[1] { type.BaseType }); method.Invoke(null, new object[1] { obj }); } public static IEnumerator WaitForTime(Action onComplete, float timeToWait) { yield return (object)new WaitForSeconds(timeToWait); onComplete?.Invoke(); } public static bool WaitInSeconds(float timeToWait, MonoBehaviour objectToTime = null) { if ((Object)(object)objectToTime == (Object)null) { objectToTime = (MonoBehaviour)(object)Plugin.Instance; } bool done = false; objectToTime.StartCoroutine(WaitForTime(delegate { done = true; }, timeToWait)); return done; } public static void SetupConfig() { //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Expected O, but got Unknown //IL_034a: Unknown result type (might be due to invalid IL or missing references) //IL_0354: Expected O, but got Unknown //IL_03ab: Unknown result type (might be due to invalid IL or missing references) //IL_03b5: Expected O, but got Unknown //IL_040c: Unknown result type (might be due to invalid IL or missing references) //IL_0416: Expected O, but got Unknown //IL_046d: Unknown result type (might be due to invalid IL or missing references) //IL_0477: Expected O, but got Unknown //IL_04ce: Unknown result type (might be due to invalid IL or missing references) //IL_04d8: Expected O, but got Unknown //IL_052f: Unknown result type (might be due to invalid IL or missing references) //IL_0539: Expected O, but got Unknown //IL_058c: Unknown result type (might be due to invalid IL or missing references) //IL_0596: Expected O, but got Unknown //IL_05e9: Unknown result type (might be due to invalid IL or missing references) //IL_05f3: Expected O, but got Unknown //IL_0646: Unknown result type (might be due to invalid IL or missing references) //IL_0650: Expected O, but got Unknown //IL_06a3: Unknown result type (might be due to invalid IL or missing references) //IL_06ad: Expected O, but got Unknown //IL_0700: Unknown result type (might be due to invalid IL or missing references) //IL_070a: Expected O, but got Unknown //IL_075d: Unknown result type (might be due to invalid IL or missing references) //IL_0767: Expected O, but got Unknown //IL_07ba: Unknown result type (might be due to invalid IL or missing references) //IL_07c4: Expected O, but got Unknown //IL_0817: Unknown result type (might be due to invalid IL or missing references) //IL_0821: Expected O, but got Unknown //IL_08a5: Unknown result type (might be due to invalid IL or missing references) //IL_08af: Expected O, but got Unknown //IL_09d2: Unknown result type (might be due to invalid IL or missing references) //IL_09dc: Expected O, but got Unknown //IL_0a43: Unknown result type (might be due to invalid IL or missing references) //IL_0a4d: Expected O, but got Unknown //IL_0ab4: Unknown result type (might be due to invalid IL or missing references) //IL_0abe: Expected O, but got Unknown //IL_0b25: Unknown result type (might be due to invalid IL or missing references) //IL_0b2f: Expected O, but got Unknown //IL_0b96: Unknown result type (might be due to invalid IL or missing references) //IL_0ba0: Expected O, but got Unknown //IL_0c07: Unknown result type (might be due to invalid IL or missing references) //IL_0c11: Expected O, but got Unknown if (!Plugin.itemList.SequenceEqual(Plugin.items) || Plugin.items.Count == 0) { Plugin.items = Resources.FindObjectsOfTypeAll<Item>().ToList(); Plugin.itemList = Plugin.items; } Plugin.allHittablesMask = StartOfRound.Instance.collidersRoomMaskDefaultAndPlayers | 0x280008 | Plugin.enemyMask; if (!((BaseUnityPlugin)Plugin.Instance).Config.ContainsKey(new ConfigDefinition("General", "ImmortalAffected"))) { ConfigEntry<bool> tempEntry = ((BaseUnityPlugin)Plugin.Instance).Config.Bind<bool>("General", "ImmortalAffected", false, "If set to on/true immortal enemies will be targeted and trip off traps."); if (Plugin.lethalConfigEnabled) { AddLethalConfigBoolItem(tempEntry); } if (Plugin.enemies.Count == 0) { if (!Plugin.GetBool("General", "ImmortalAffected")) { Plugin.enemies = (from e in Resources.FindObjectsOfTypeAll<EnemyType>() where e.canDie select e).ToList(); Plugin.allEnemies = (from EnemyType e in Resources.FindObjectsOfTypeAll(typeof(EnemyType)) where (Object)(object)e != (Object)null select e).ToList(); Plugin.enemyList = Plugin.enemies; } else { Plugin.enemies = (from e in Resources.FindObjectsOfTypeAll<EnemyType>() where (Object)(object)e != (Object)null select e).ToList(); Plugin.allEnemies = (from EnemyType e in Resources.FindObjectsOfTypeAll(typeof(EnemyType)) where (Object)(object)e != (Object)null select e).ToList(); Plugin.enemyList = Plugin.enemies; } } else if (!Plugin.enemyList.SequenceEqual(Plugin.enemies)) { if (!Plugin.GetBool("General", "ImmortalAffected")) { Plugin.enemies = (from e in Resources.FindObjectsOfTypeAll<EnemyType>() where (Object)(object)e != (Object)null && e.canDie select e).ToList(); Plugin.allEnemies = (from EnemyType e in Resources.FindObjectsOfTypeAll(typeof(EnemyType)) where (Object)(object)e != (Object)null select e).ToList(); Plugin.enemyList = Plugin.enemies; } else { Plugin.enemies = (from e in Resources.FindObjectsOfTypeAll<EnemyType>() where (Object)(object)e != (Object)null select e).ToList(); Plugin.allEnemies = (from EnemyType e in Resources.FindObjectsOfTypeAll(typeof(EnemyType)) where (Object)(object)e != (Object)null select e).ToList(); Plugin.enemyList = Plugin.enemies; } } } if (!((BaseUnityPlugin)Plugin.Instance).Config.ContainsKey(new ConfigDefinition("ExplosionConfig", "Damage"))) { ConfigEntry<float> tempEntry2 = ((BaseUnityPlugin)Plugin.Instance).Config.Bind<float>("ExplosionConfig", "Damage", 1f, "Damage explosions will do outside the kill radius"); if (Plugin.lethalConfigEnabled) { AddLethalConfigFloatItem(tempEntry2); } } if (!((BaseUnityPlugin)Plugin.Instance).Config.ContainsKey(new ConfigDefinition("Quick Sand Config", "Sink Time"))) { ConfigEntry<float> tempEntry3 = ((BaseUnityPlugin)Plugin.Instance).Config.Bind<float>("Quick Sand Config", "Sink Time", 5f, "Time Until A Enemy Is Considered Sunk And Will Be Killed"); if (Plugin.lethalConfigEnabled) { AddLethalConfigFloatItem(tempEntry3); } } if (!((BaseUnityPlugin)Plugin.Instance).Config.ContainsKey(new ConfigDefinition("Quick Sand Config", "Slowing Speed"))) { ConfigEntry<float> tempEntry4 = ((BaseUnityPlugin)Plugin.Instance).Config.Bind<float>("Quick Sand Config", "Slowing Speed", 33f, "Percentage of Original Speed Enemies Move In Quick Sand"); if (Plugin.lethalConfigEnabled) { AddLethalConfigFloatItem(tempEntry4); } } if (!((BaseUnityPlugin)Plugin.Instance).Config.ContainsKey(new ConfigDefinition("TurretConfig", "Enemy Damage"))) { ConfigEntry<float> tempEntry5 = ((BaseUnityPlugin)Plugin.Instance).Config.Bind<float>("TurretConfig", "Enemy Damage", 1f, "Damage Turrets will Do To Enemies"); if (Plugin.lethalConfigEnabled) { AddLethalConfigFloatItem(tempEntry5); } } if (!((BaseUnityPlugin)Plugin.Instance).Config.ContainsKey(new ConfigDefinition("TurretConfig", "Player Damage"))) { ConfigEntry<float> tempEntry6 = ((BaseUnityPlugin)Plugin.Instance).Config.Bind<float>("TurretConfig", "Player Damage", 50f, "Damage Turrets will Do To Players"); if (Plugin.lethalConfigEnabled) { AddLethalConfigFloatItem(tempEntry6); } } if (!((BaseUnityPlugin)Plugin.Instance).Config.ContainsKey(new ConfigDefinition("TurretConfig", "HitOtherTurrets"))) { ConfigEntry<bool> tempEntry7 = ((BaseUnityPlugin)Plugin.Instance).Config.Bind<bool>("TurretConfig", "HitOtherTurrets", false, "If turrets can hit other turrets when firing.(Does not make them target other turrets)"); if (Plugin.lethalConfigEnabled) { AddLethalConfigBoolItem(tempEntry7); } } if (!((BaseUnityPlugin)Plugin.Instance).Config.ContainsKey(new ConfigDefinition("Mobs", "QuicksandAllMobs"))) { ConfigEntry<bool> tempEntry8 = ((BaseUnityPlugin)Plugin.Instance).Config.Bind<bool>("Mobs", "QuicksandAllMobs", true, "Leave On To Customise Mobs Below Or Turn Off To Make All Mobs Unable To Set Off Quicksand interactions."); if (Plugin.lethalConfigEnabled) { AddLethalConfigBoolItem(tempEntry8); } } if (!((BaseUnityPlugin)Plugin.Instance).Config.ContainsKey(new ConfigDefinition("Mobs", "ExplodeAllMobs"))) { ConfigEntry<bool> tempEntry9 = ((BaseUnityPlugin)Plugin.Instance).Config.Bind<bool>("Mobs", "ExplodeAllMobs", true, "Leave On To Customise Mobs Below Or Turn Off To Make All Mobs Unable To Set Off Mines."); if (Plugin.lethalConfigEnabled) { AddLethalConfigBoolItem(tempEntry9); } } if (!((BaseUnityPlugin)Plugin.Instance).Config.ContainsKey(new ConfigDefinition("Mobs", "BoombaAllMobs"))) { ConfigEntry<bool> tempEntry10 = ((BaseUnityPlugin)Plugin.Instance).Config.Bind<bool>("Mobs", "BoombaAllMobs", true, "Leave On To Customise Mobs Below Or Turn Off To Make All Mobs Unable To Set Off Boombas."); if (Plugin.lethalConfigEnabled) { AddLethalConfigBoolItem(tempEntry10); } } if (!((BaseUnityPlugin)Plugin.Instance).Config.ContainsKey(new ConfigDefinition("Mobs", "SeamineAllMobs"))) { ConfigEntry<bool> tempEntry11 = ((BaseUnityPlugin)Plugin.Instance).Config.Bind<bool>("Mobs", "SeamineAllMobs", true, "Leave On To Customise Mobs Below Or Turn Off To Make All Mobs Unable To Set Off Seamines."); if (Plugin.lethalConfigEnabled) { AddLethalConfigBoolItem(tempEntry11); } } if (!((BaseUnityPlugin)Plugin.Instance).Config.ContainsKey(new ConfigDefinition("Mobs", "BerthaAllMobs"))) { ConfigEntry<bool> tempEntry12 = ((BaseUnityPlugin)Plugin.Instance).Config.Bind<bool>("Mobs", "BerthaAllMobs", true, "Leave On To Customise Mobs Below Or Turn Off To Make All Mobs Unable To Set Off Big Berthas."); if (Plugin.lethalConfigEnabled) { AddLethalConfigBoolItem(tempEntry12); } } if (!((BaseUnityPlugin)Plugin.Instance).Config.ContainsKey(new ConfigDefinition("Mobs", "TurretTargetAllMobs"))) { ConfigEntry<bool> tempEntry13 = ((BaseUnityPlugin)Plugin.Instance).Config.Bind<bool>("Mobs", "TurretTargetAllMobs", true, "Leave On To Customise Mobs Below Or Turn Off To Make All Mobs Unable To Be Targeted By Turrets."); if (Plugin.lethalConfigEnabled) { AddLethalConfigBoolItem(tempEntry13); } } if (!((BaseUnityPlugin)Plugin.Instance).Config.ContainsKey(new ConfigDefinition("Mobs", "TurretDamageAllMobs"))) { ConfigEntry<bool> tempEntry14 = ((BaseUnityPlugin)Plugin.Instance).Config.Bind<bool>("Mobs", "TurretDamageAllMobs", true, "Leave On To Customise Mobs Below Or Turn Off To Make All Mobs Unable To Be Killed By Turrets."); if (Plugin.lethalConfigEnabled) { AddLethalConfigBoolItem(tempEntry14); } } if (!((BaseUnityPlugin)Plugin.Instance).Config.ContainsKey(new ConfigDefinition("Mobs", "CheckForPlayersInside"))) { ConfigEntry<bool> tempEntry15 = ((BaseUnityPlugin)Plugin.Instance).Config.Bind<bool>("Mobs", "CheckForPlayersInside", false, "Whether to check for players inside the dungeon before anything else occurs."); if (Plugin.lethalConfigEnabled) { AddLethalConfigBoolItem(tempEntry15); } } foreach (EnemyType allEnemy in Plugin.allEnemies) { string text = Plugin.RemoveInvalidCharacters(allEnemy.enemyName); if (!((BaseUnityPlugin)Plugin.Instance).Config.ContainsKey(new ConfigDefinition("Mobs", text + ".Quicksand Kill"))) { if (allEnemy.canDie) { ConfigEntry<bool> tempEntry16 = ((!text.ToLower().Equals("cutieflyai") && !text.ToLower().Equals("cutieflyobj") && !text.ToLower().Equals("cutiefly")) ? ((BaseUnityPlugin)Plugin.Instance).Config.Bind<bool>("Mobs", text + ".Quicksand Kill", true, "Is it killable by quicksand?") : ((BaseUnityPlugin)Plugin.Instance).Config.Bind<bool>("Mobs", text + ".Quicksand Kill", false, "Is it killable by quicksand?")); if (Plugin.lethalConfigEnabled) { AddLethalConfigBoolItem(tempEntry16); } } else { ConfigEntry<bool> tempEntry16 = ((BaseUnityPlugin)Plugin.Instance).Config.Bind<bool>("Mobs", text + ".Quicksand Kill", false, "Is it killable by quicksand?"); if (Plugin.lethalConfigEnabled) { AddLethalConfigBoolItem(tempEntry16); } } } if (!((BaseUnityPlugin)Plugin.Instance).Config.ContainsKey(new ConfigDefinition("Mobs", text + ".Mine"))) { ConfigEntry<bool> tempEntry17 = ((BaseUnityPlugin)Plugin.Instance).Config.Bind<bool>("Mobs", text + ".Mine", allEnemy.canDie, "Does it set off the landmine or not?"); if (Plugin.lethalConfigEnabled) { AddLethalConfigBoolItem(tempEntry17); } } if (!((BaseUnityPlugin)Plugin.Instance).Config.ContainsKey(new ConfigDefinition("Mobs", text + ".Seamine"))) { ConfigEntry<bool> tempEntry18 = ((BaseUnityPlugin)Plugin.Instance).Config.Bind<bool>("Mobs", text + ".Seamine", allEnemy.canDie, "Does it set off the Surfaced Seamine or not?"); if (Plugin.lethalConfigEnabled) { AddLethalConfigBoolItem(tempEntry18); } } if (!((BaseUnityPlugin)Plugin.Instance).Config.ContainsKey(new ConfigDefinition("Mobs", text + ".Bertha"))) { ConfigEntry<bool> tempEntry19 = ((BaseUnityPlugin)Plugin.Instance).Config.Bind<bool>("Mobs", text + ".Bertha", allEnemy.canDie, "Does it set off the Surfaced Big Bertha or not?"); if (Plugin.lethalConfigEnabled) { AddLethalConfigBoolItem(tempEntry19); } } if (!((BaseUnityPlugin)Plugin.Instance).Config.ContainsKey(new ConfigDefinition("Mobs", text + ".Boomba"))) { ConfigEntry<bool> tempEntry20 = ((BaseUnityPlugin)Plugin.Instance).Config.Bind<bool>("Mobs", text + ".Boomba", allEnemy.canDie, "Does it set off the LethalThings Boomba or not?"); if (Plugin.lethalConfigEnabled) { AddLethalConfigBoolItem(tempEntry20); } } if (!((BaseUnityPlugin)Plugin.Instance).Config.ContainsKey(new ConfigDefinition("Mobs", text + ".Turret Target"))) { ConfigEntry<bool> tempEntry21 = ((BaseUnityPlugin)Plugin.Instance).Config.Bind<bool>("Mobs", text + ".Turret Target", allEnemy.canDie, "Is it targetable by turrets?"); if (Plugin.lethalConfigEnabled) { AddLethalConfigBoolItem(tempEntry21); } } if (!((BaseUnityPlugin)Plugin.Instance).Config.ContainsKey(new ConfigDefinition("Mobs", text + ".Turret Damage"))) { ConfigEntry<bool> tempEntry22 = ((BaseUnityPlugin)Plugin.Instance).Config.Bind<bool>("Mobs", text + ".Turret Damage", allEnemy.canDie, "Is it damageable by turrets?"); if (Plugin.lethalConfigEnabled) { AddLethalConfigBoolItem(tempEntry22); } } } } public static int[] GetLateGameUpgradeTier(string upgradeName) { try { Type type = Plugin.lguAssembly.GetType("MoreShipUpgrades.API.UpgradeApi"); if (type == null) { Plugin.logger.LogError((object)"[FairAI] Could not find UpgradeApi type!"); return Array.Empty<int>(); } MethodInfo method = type.GetMethod("GetRankableUpgradeNodes", BindingFlags.Static | BindingFlags.Public); if (method == null) { Plugin.logger.LogError((object)"[FairAI] Could not find GetRankableUpgradeNodes() method!"); return Array.Empty<int>(); } object obj = method.Invoke(null, null); if (!(obj is IEnumerable enumerable)) { Plugin.logger.LogError((object)"[FairAI] Result is not an IEnumerable!"); return Array.Empty<int>(); } foreach (object item in enumerable) { Type type2 = item.GetType(); PropertyInfo property = type2.GetProperty("Name", BindingFlags.Instance | BindingFlags.Public); PropertyInfo property2 = type2.GetProperty("MaxUpgrade", BindingFlags.Instance | BindingFlags.Public); PropertyInfo property3 = type2.GetProperty("CurrentUpgrade", BindingFlags.Instance | BindingFlags.Public); string text = property?.GetValue(item)?.ToString() ?? "(unknown)"; if (!text.Equals("(unknown)") && text.Equals(upgradeName, StringComparison.OrdinalIgnoreCase)) { int num = (int)(property2?.GetValue(item) ?? ((object)0)); int num2 = (int)(property3?.GetValue(item) ?? ((object)0)); Plugin.logger.LogInfo((object)$"[FairAI] {text} — Current: {num2}, Max: {num}"); return new int[2] { num2, num }; } } } catch (Exception arg) { Plugin.logger.LogError((object)$"[FairAI] Error: {arg}"); } return Array.Empty<int>(); } public static bool ReadSyncedEntryBool(object syncedEntry) { if (syncedEntry == null) { return false; } PropertyInfo property = syncedEntry.GetType().GetProperty("Value", BindingFlags.Instance | BindingFlags.Public); return property != null && (bool)property.GetValue(syncedEntry); } public static int ReadSyncedEntryInt(object syncedEntry) { if (syncedEntry == null) { return 0; } PropertyInfo property = syncedEntry.GetType().GetProperty("Value", BindingFlags.Instance | BindingFlags.Public); return (property != null) ? ((int)property.GetValue(syncedEntry)) : 0; } public static float CalculateDecreaseMultiplier() { Type rubberBootsType = Plugin.rubberBootsType; try { Type type = rubberBootsType.Assembly.GetType("MoreShipUpgrades.Misc.Upgrades.BaseUpgrade"); if (type == null) { return 0f; } object obj = type.GetMethod("GetConfiguration", BindingFlags.Static | BindingFlags.Public)?.Invoke(null, null); if (obj == null) { return 0f; } object obj2 = obj.GetType().GetProperty("RubberBootsConfiguration", BindingFlags.Instance | BindingFlags.Public)?.GetValue(obj); if (obj2 == null) { return 0f; } object syncedEntry = obj2.GetType().GetProperty("Enabled")?.GetValue(obj2); if (!ReadSyncedEntryBool(syncedEntry)) { return 0f; } MethodInfo method = type.GetMethod("GetActiveUpgrade", BindingFlags.Static | BindingFlags.Public); if (!(bool)method.Invoke(null, new object[1] { "Rubber Boots" })) { return 0f; } object syncedEntry2 = obj2.GetType().GetProperty("InitialEffect")?.GetValue(obj2); object syncedEntry3 = obj2.GetType().GetProperty("IncrementalEffect")?.GetValue(obj2); int num = ReadSyncedEntryInt(syncedEntry2); int num2 = ReadSyncedEntryInt(syncedEntry3); MethodInfo method2 = type.GetMethod("GetUpgradeLevel", BindingFlags.Static | BindingFlags.Public); int num3 = (int)method2.Invoke(null, new object[1] { "Rubber Boots" }) + 1; Plugin.logger.LogWarning((object)("Decrease: " + (float)(num + num2 * num3) / 100f)); return (float)(num + num2 * num3) / 100f; } catch (Exception arg) { Plugin.logger.LogError((object)$"CalculateDecreaseMultiplier reflection failed: {arg}"); return 0f; } } public static int ClearMovementHinderance(int defaultValue) { if (CalculateDecreaseMultiplier() >= 1f) { return 0; } return defaultValue; } public static float ReduceMovementHinderance(float defaultValue) { float num = CalculateDecreaseMultiplier(); return Mathf.Clamp(Mathf.Clamp(1f - num, 0f, 1f) * defaultValue, 1f, 100f); } } } namespace FairAI.Patches { public static class BoombaPatch { private static bool? _enabled; public static bool enabled { get { if (!_enabled.HasValue) { _enabled = Chainloader.PluginInfos.ContainsKey("evaisa.lethalthings"); } return _enabled.Value; } } [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)] public static void PatchStart(ref RoombaAI __instance) { ((Component)__instance).gameObject.AddComponent<BoombaTimer>(); } [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)] public static void PatchDoAIInterval(ref RoombaAI __instance) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0084: 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_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: 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_01b3: Unknown result type (might be due to invalid IL or missing references) //IL_01c3: Unknown result type (might be due to invalid IL or missing references) //IL_021e: Unknown result type (might be due to invalid IL or missing references) //IL_0224: Unknown result type (might be due to invalid IL or missing references) if (!Plugin.AllowFairness(((Component)__instance).transform.position) || !Plugin.IsAgentOnNavMesh(((Component)__instance).gameObject) || (((EnemyAI)__instance).currentSearch == null && !((EnemyAI)__instance).movingTowardsTargetPlayer) || (!__instance.mineAudio.isPlaying && !__instance.mineFarAudio.isPlaying) || !((Component)__instance).GetComponent<BoombaTimer>().IsActiveBomb()) { return; } Vector3 val = ((Component)__instance).transform.position + Vector3.up; Collider[] array = Physics.OverlapSphere(val, 6f, 2621448, (QueryTriggerInteraction)2); for (int i = 0; i < array.Length; i++) { float num = Vector3.Distance(val, ((Component)array[i]).transform.position); if ((num > 4f && Physics.Linecast(val, ((Component)array[i]).transform.position + Vector3.up * 0.3f, 256, (QueryTriggerInteraction)1)) || !((Object)(object)((Component)array[i]).gameObject.GetComponent<EnemyAICollisionDetect>() != (Object)null)) { continue; } EnemyAICollisionDetect component = ((Component)array[i]).gameObject.GetComponent<EnemyAICollisionDetect>(); if (!((Object)(object)((Component)component.mainScript).gameObject != (Object)(object)((Component)__instance).gameObject) || !Plugin.CanMob("BoombaAllMobs", ".Boomba", component.mainScript.enemyType.enemyName)) { continue; } if ((Object)(object)component != (Object)null && ((NetworkBehaviour)component.mainScript).IsOwner && !component.mainScript.isEnemyDead) { Object.Instantiate<GameObject>(StartOfRound.Instance.explosionPrefab, val, Quaternion.Euler(-90f, 0f, 0f), RoundManager.Instance.mapPropsContainer.transform).SetActive(true); if (num < 3f) { component.mainScript.KillEnemyOnOwnerClient(true); } else if (num < 6f) { component.mainScript.HitEnemyOnLocalClient(2, default(Vector3), (PlayerControllerB)null, false, -1); } } if (((NetworkBehaviour)__instance).IsServer) { ((EnemyAI)__instance).KillEnemy(true); } else { ((EnemyAI)__instance).KillEnemyServerRpc(true); } } } } internal class EnemyAIPatch { private static void BaseHitEnemy(EnemyAI ai, int force, PlayerControllerB playerWhoHit, bool playHitSFX, int hitID) { if (!((Object)(object)ai == (Object)null)) { if (playHitSFX && (Object)(object)ai.enemyType.hitBodySFX != (Object)null && !ai.isEnemyDead) { ai.creatureSFX.PlayOneShot(ai.enemyType.hitBodySFX); WalkieTalkie.TransmitOneShotAudio(ai.creatureSFX, ai.enemyType.hitBodySFX, 1f); } if ((Object)(object)ai.creatureVoice != (Object)null) { ai.creatureVoice.PlayOneShot(ai.enemyType.hitEnemyVoiceSFX); } if (ai.debugEnemyAI) { Debug.Log((object)$"Enemy #{ai.thisEnemyIndex} was hit with force of {force}"); } if ((Object)(object)playerWhoHit != (Object)null) { Debug.Log((object)$"Client #{playerWhoHit.playerClientId} hit enemy {((Object)((Component)ai.agent).transform).name} with force of {force}."); } } } public static void KillEnemyOnOwnerClientPatch(EnemyAI __instance, bool overrideDestroy = false) { if (overrideDestroy) { return; } int id = ((Object)__instance).GetInstanceID(); if (Plugin.sinkingProgress.ContainsKey(id)) { ((MonoBehaviour)__instance).StartCoroutine(Utils.WaitForTime(delegate { Plugin.sinkingProgress.Remove(id); Plugin.sinkingValues.Remove(id); Plugin.positions.Remove(id); __instance.KillEnemyOnOwnerClient(true); }, 1f)); } } public static bool BrackenHitEnemyPatch(ref FlowermanAI __instance, int force = 1, PlayerControllerB playerWhoHit = null, bool playHitSFX = false, int hitID = -1) { BaseHitEnemy((EnemyAI)(object)__instance, force, playerWhoHit, playHitSFX, hitID); if (((EnemyAI)__instance).isEnemyDead) { return false; } FlowermanAI obj = __instance; ((EnemyAI)obj