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.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Photon.Pun;
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: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp-firstpass")]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: IgnoresAccessChecksTo("Autodesk.Fbx")]
[assembly: IgnoresAccessChecksTo("Facepunch.Steamworks.Win64")]
[assembly: IgnoresAccessChecksTo("FbxBuildTestAssets")]
[assembly: IgnoresAccessChecksTo("Klattersynth")]
[assembly: IgnoresAccessChecksTo("Photon3Unity3D")]
[assembly: IgnoresAccessChecksTo("PhotonChat")]
[assembly: IgnoresAccessChecksTo("PhotonRealtime")]
[assembly: IgnoresAccessChecksTo("PhotonUnityNetworking")]
[assembly: IgnoresAccessChecksTo("PhotonUnityNetworking.Utilities")]
[assembly: IgnoresAccessChecksTo("PhotonVoice.API")]
[assembly: IgnoresAccessChecksTo("PhotonVoice")]
[assembly: IgnoresAccessChecksTo("PhotonVoice.PUN")]
[assembly: IgnoresAccessChecksTo("SingularityGroup.HotReload.Runtime")]
[assembly: IgnoresAccessChecksTo("SingularityGroup.HotReload.Runtime.Public")]
[assembly: IgnoresAccessChecksTo("Sirenix.OdinInspector.Attributes")]
[assembly: IgnoresAccessChecksTo("Sirenix.Serialization.Config")]
[assembly: IgnoresAccessChecksTo("Sirenix.Serialization")]
[assembly: IgnoresAccessChecksTo("Sirenix.Utilities")]
[assembly: IgnoresAccessChecksTo("Unity.AI.Navigation")]
[assembly: IgnoresAccessChecksTo("Unity.Formats.Fbx.Runtime")]
[assembly: IgnoresAccessChecksTo("Unity.InputSystem")]
[assembly: IgnoresAccessChecksTo("Unity.InputSystem.ForUI")]
[assembly: IgnoresAccessChecksTo("Unity.Postprocessing.Runtime")]
[assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.Core.Runtime")]
[assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.Core.ShaderLibrary")]
[assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.ShaderGraph.ShaderGraphLibrary")]
[assembly: IgnoresAccessChecksTo("Unity.TextMeshPro")]
[assembly: IgnoresAccessChecksTo("Unity.Timeline")]
[assembly: IgnoresAccessChecksTo("Unity.VisualScripting.Antlr3.Runtime")]
[assembly: IgnoresAccessChecksTo("Unity.VisualScripting.Core")]
[assembly: IgnoresAccessChecksTo("Unity.VisualScripting.Flow")]
[assembly: IgnoresAccessChecksTo("Unity.VisualScripting.State")]
[assembly: IgnoresAccessChecksTo("UnityEngine.ARModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.NVIDIAModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.UI")]
[assembly: IgnoresAccessChecksTo("websocket-sharp")]
[assembly: AssemblyCompany("PlusBlankPlus")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("VisionMonsters")]
[assembly: AssemblyTitle("VisionMonsters")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
internal sealed class NullableAttribute : Attribute
{
public readonly byte[] NullableFlags;
public NullableAttribute(byte P_0)
{
NullableFlags = new byte[1] { P_0 };
}
public NullableAttribute(byte[] P_0)
{
NullableFlags = P_0;
}
}
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
internal sealed class NullableContextAttribute : Attribute
{
public readonly byte Flag;
public NullableContextAttribute(byte P_0)
{
Flag = P_0;
}
}
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
internal sealed class RefSafetyRulesAttribute : Attribute
{
public readonly int Version;
public RefSafetyRulesAttribute(int P_0)
{
Version = P_0;
}
}
}
namespace VisionMonsters
{
public class EnemyAIHelper : MonoBehaviour
{
[CompilerGenerated]
private sealed class <ScanLoop>d__13 : IEnumerator<object>, IEnumerator, IDisposable
{
private int <>1__state;
private object <>2__current;
public EnemyAIHelper <>4__this;
object? IEnumerator<object>.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
object? IEnumerator.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
[DebuggerHidden]
public <ScanLoop>d__13(int <>1__state)
{
this.<>1__state = <>1__state;
}
[DebuggerHidden]
void IDisposable.Dispose()
{
<>1__state = -2;
}
private bool MoveNext()
{
//IL_009d: Unknown result type (might be due to invalid IL or missing references)
//IL_00a7: Expected O, but got Unknown
//IL_007e: Unknown result type (might be due to invalid IL or missing references)
//IL_0088: Expected O, but got Unknown
switch (<>1__state)
{
default:
return false;
case 0:
<>1__state = -1;
if (Plugin.RadarScanInterval == null)
{
ManualLogSource? log = <>4__this._log;
if (log != null)
{
log.LogError((object)"ScanLoop cannot start: RadarScanInterval config is null.");
}
return false;
}
if (<>4__this.scanWaitSeconds == null)
{
<>4__this.scanWaitSeconds = new WaitForSeconds(Plugin.RadarScanInterval.Value);
}
<>2__current = (object)new WaitForSeconds(Random.Range(1f, Plugin.RadarScanInterval.Value));
<>1__state = 1;
return true;
case 1:
<>1__state = -1;
break;
case 2:
<>1__state = -1;
break;
}
if (((Behaviour)<>4__this).enabled && Plugin.EnableCheatingAI != null && Plugin.EnableCheatingAI.Value && SemiFunc.IsMasterClientOrSingleplayer() && (Object)(object)<>4__this.enemyRef != (Object)null && ((Behaviour)<>4__this.enemyRef).isActiveAndEnabled)
{
<>4__this.ScanForPlayers();
}
<>2__current = <>4__this.scanWaitSeconds;
<>1__state = 2;
return true;
}
bool IEnumerator.MoveNext()
{
//ILSpy generated this explicit interface implementation from .override directive in MoveNext
return this.MoveNext();
}
[DebuggerHidden]
void IEnumerator.Reset()
{
throw new NotSupportedException();
}
}
internal Enemy? enemyRef;
private Coroutine? _scanCoroutine;
private ManualLogSource? _log;
public Vector3 lastKnownPlayerPosition = Vector3.zero;
public float timeSincePlayerKnown = float.MaxValue;
public bool hasMemory = false;
private WaitForSeconds? scanWaitSeconds;
private void Awake()
{
//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
//IL_00ca: Expected O, but got Unknown
_log = Plugin.Log;
enemyRef = ((Component)this).GetComponent<Enemy>();
if ((Object)(object)enemyRef == (Object)null)
{
ManualLogSource? log = _log;
if (log != null)
{
log.LogError((object)("EnemyAIHelper could not find Enemy component on " + ((Object)((Component)this).gameObject).name));
}
((Behaviour)this).enabled = false;
}
else if (Plugin.RadarScanInterval == null || Plugin.MemoryDuration == null || Plugin.RadarScanRadius == null || Plugin.EnableCheatingAI == null)
{
ManualLogSource? log2 = _log;
if (log2 != null)
{
log2.LogError((object)("EnemyAIHelper cannot run on " + ((Object)((Component)this).gameObject).name + ": required config entries are null."));
}
((Behaviour)this).enabled = false;
}
else
{
scanWaitSeconds = new WaitForSeconds(Plugin.RadarScanInterval.Value);
timeSincePlayerKnown = float.MaxValue;
}
}
private void OnEnable()
{
//IL_0011: Unknown result type (might be due to invalid IL or missing references)
//IL_0016: Unknown result type (might be due to invalid IL or missing references)
if (((Behaviour)this).enabled)
{
lastKnownPlayerPosition = Vector3.zero;
timeSincePlayerKnown = float.MaxValue;
hasMemory = false;
if (_scanCoroutine == null && (Object)(object)enemyRef != (Object)null)
{
_scanCoroutine = ((MonoBehaviour)this).StartCoroutine(ScanLoop());
}
}
}
private void OnDisable()
{
if (_scanCoroutine != null)
{
((MonoBehaviour)this).StopCoroutine(_scanCoroutine);
_scanCoroutine = null;
}
}
private void Update()
{
if (!((Behaviour)this).enabled || (Object)(object)enemyRef == (Object)null || Plugin.EnableCheatingAI == null || !Plugin.EnableCheatingAI.Value || !SemiFunc.IsMasterClientOrSingleplayer())
{
return;
}
if (hasMemory)
{
if (Plugin.MemoryDuration != null)
{
timeSincePlayerKnown += Time.deltaTime;
if (timeSincePlayerKnown >= Plugin.MemoryDuration.Value)
{
hasMemory = false;
}
}
else
{
hasMemory = false;
}
}
if (HasFreshMemory())
{
TryForceInvestigation();
}
}
public void UpdateMemory(Vector3 position)
{
//IL_0027: Unknown result type (might be due to invalid IL or missing references)
//IL_0028: Unknown result type (might be due to invalid IL or missing references)
if (((Behaviour)this).enabled && Plugin.EnableCheatingAI != null && Plugin.EnableCheatingAI.Value)
{
lastKnownPlayerPosition = position;
timeSincePlayerKnown = 0f;
hasMemory = true;
}
}
public bool HasFreshMemory()
{
if (!((Behaviour)this).enabled || Plugin.MemoryDuration == null)
{
return false;
}
return hasMemory && timeSincePlayerKnown < Plugin.MemoryDuration.Value;
}
[IteratorStateMachine(typeof(<ScanLoop>d__13))]
private IEnumerator ScanLoop()
{
//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
return new <ScanLoop>d__13(0)
{
<>4__this = this
};
}
private void ScanForPlayers()
{
//IL_004e: 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_005c: Unknown result type (might be due to invalid IL or missing references)
//IL_012b: 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_00e0: Unknown result type (might be due to invalid IL or missing references)
//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)enemyRef == (Object)null || (Object)(object)enemyRef.CenterTransform == (Object)null || Plugin.RadarScanRadius == null)
{
return;
}
float value = Plugin.RadarScanRadius.Value;
Vector3 position = enemyRef.CenterTransform.position;
PlayerAvatar val = null;
float num = float.MaxValue;
Collider[] array = Physics.OverlapSphere(position, value, LayerMask.GetMask(new string[1] { "Player" }), (QueryTriggerInteraction)1);
Collider[] array2 = array;
foreach (Collider val2 in array2)
{
if (((Component)val2).transform.IsChildOf(((Component)enemyRef).transform))
{
continue;
}
PlayerAvatar componentInParent = ((Component)val2).GetComponentInParent<PlayerAvatar>();
if ((Object)(object)componentInParent != (Object)null && !componentInParent.isDisabled)
{
Vector3 val3 = ((Component)componentInParent).transform.position - position;
float sqrMagnitude = ((Vector3)(ref val3)).sqrMagnitude;
if (sqrMagnitude < num)
{
num = sqrMagnitude;
val = componentInParent;
}
}
}
if ((Object)(object)val != (Object)null)
{
UpdateMemory(((Component)val).transform.position);
}
}
private void TryForceInvestigation()
{
//IL_0038: 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_005b: 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_0082: Invalid comparison between Unknown and I4
//IL_00b8: 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_015e: Unknown result type (might be due to invalid IL or missing references)
//IL_014b: Unknown result type (might be due to invalid IL or missing references)
//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
//IL_0118: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)enemyRef == (Object)null || (Object)(object)EnemyDirector.instance == (Object)null || !hasMemory || !CanInterruptForInvestigation(enemyRef.CurrentState))
{
return;
}
float num = Vector3.Distance(((Component)enemyRef).transform.position, lastKnownPlayerPosition);
if (!(num > 5f))
{
return;
}
if ((int)enemyRef.CurrentState == 7)
{
EnemyNavMeshAgent navMeshAgent = enemyRef.NavMeshAgent;
if (navMeshAgent != null && navMeshAgent.HasPath())
{
if (!(Vector3.Distance(enemyRef.NavMeshAgent.Agent.destination, lastKnownPlayerPosition) > 3f))
{
return;
}
if ((Object)(object)enemyRef.StateInvestigate != (Object)null)
{
enemyRef.StateInvestigate.Set(lastKnownPlayerPosition);
return;
}
EnemyNavMeshAgent navMeshAgent2 = enemyRef.NavMeshAgent;
if (navMeshAgent2 != null)
{
navMeshAgent2.SetDestination(lastKnownPlayerPosition);
}
return;
}
}
if ((Object)(object)enemyRef.StateInvestigate != (Object)null)
{
enemyRef.StateInvestigate.Set(lastKnownPlayerPosition);
}
else
{
EnemyDirector.instance.SetInvestigate(lastKnownPlayerPosition, 10f);
}
}
private bool CanInterruptForInvestigation(EnemyState currentState)
{
//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_0003: Unknown result type (might be due to invalid IL or missing references)
//IL_0004: Unknown result type (might be due to invalid IL or missing references)
//IL_0005: 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_0039: Expected I4, but got Unknown
switch (currentState - 1)
{
case 1:
case 5:
case 6:
return true;
case 0:
case 2:
case 3:
case 4:
case 8:
case 9:
case 10:
return false;
default:
return true;
}
}
}
public enum Formation
{
Line,
Triangle,
Box,
Circle,
Loose
}
public class EnemyGroup
{
public Enemy? Leader { get; private set; }
public List<GroupAIHelper> Followers { get; private set; } = new List<GroupAIHelper>();
public Formation CurrentFormation { get; set; }
public Vector3 CurrentPatrolTarget { get; set; }
public EnemyType GroupEnemyType { get; private set; }
public bool IsValid { get; private set; } = true;
public EnemyGroup(Enemy leader, Formation formation)
{
//IL_003a: 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)
if ((Object)(object)leader == (Object)null)
{
throw new ArgumentNullException("leader");
}
Leader = leader;
GroupEnemyType = leader.Type;
CurrentFormation = formation;
CurrentPatrolTarget = ((Component)leader).transform.position;
}
public void AddFollower(GroupAIHelper follower)
{
if ((Object)(object)follower != (Object)null && (Object)(object)Leader != (Object)null && (Object)(object)follower.enemyRef != (Object)(object)Leader && !Followers.Contains(follower))
{
Followers.Add(follower);
follower.AssignToGroup(this, isLeader: false);
}
}
public void RemoveMember(GroupAIHelper member)
{
if ((Object)(object)member != (Object)null && Followers.Remove(member))
{
if (Plugin.MinGroupSize != null && Followers.Count < Plugin.MinGroupSize.Value - 1)
{
DisbandGroup();
}
else
{
AssignFormationOffsets();
}
}
}
public void DisbandGroup()
{
if (!IsValid)
{
return;
}
IsValid = false;
Enemy? leader = Leader;
if (leader != null)
{
((Component)leader).GetComponent<GroupAIHelper>()?.LeaveGroup();
}
Leader = null;
foreach (GroupAIHelper item in Followers.ToList())
{
item?.LeaveGroup();
}
Followers.Clear();
}
public void AssignFormationOffsets()
{
//IL_0066: 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_00dd: Unknown result type (might be due to invalid IL or missing references)
//IL_02e5: Unknown result type (might be due to invalid IL or missing references)
if (!SemiFunc.IsMasterClientOrSingleplayer() || (Object)(object)Leader == (Object)null || !IsValid)
{
return;
}
int count = Followers.Count;
float num = 2.5f;
GroupAIHelper component = ((Component)Leader).GetComponent<GroupAIHelper>();
if ((Object)(object)component == (Object)null)
{
DisbandGroup();
return;
}
component.SetFormationOffset(Vector3.zero);
component.AssignToGroup(this, isLeader: true);
Formation formation = CurrentFormation;
bool flag = count >= 2;
bool flag2 = count >= 3;
if (formation == Formation.Triangle && !flag)
{
formation = Formation.Line;
}
if (formation == Formation.Box && !flag2)
{
formation = Formation.Triangle;
}
if (formation == Formation.Triangle && !flag)
{
formation = Formation.Line;
}
for (int i = 0; i < count; i++)
{
Vector3 zero = Vector3.zero;
switch (formation)
{
case Formation.Line:
((Vector3)(ref zero))..ctor(0f, 0f, (0f - num) * (float)(i + 1));
break;
case Formation.Triangle:
switch (i)
{
case 0:
((Vector3)(ref zero))..ctor((0f - num) * 0.8f, 0f, 0f - num);
break;
case 1:
((Vector3)(ref zero))..ctor(num * 0.8f, 0f, 0f - num);
break;
default:
((Vector3)(ref zero))..ctor(0f, 0f, (0f - num) * (1f + (float)(i - 1) * 0.8f));
break;
}
break;
case Formation.Box:
switch (i)
{
case 0:
((Vector3)(ref zero))..ctor(num, 0f, 0f);
break;
case 1:
((Vector3)(ref zero))..ctor(0f, 0f, 0f - num);
break;
case 2:
((Vector3)(ref zero))..ctor(num, 0f, 0f - num);
break;
default:
((Vector3)(ref zero))..ctor(num * 0.5f, 0f, (0f - num) * (1f + (float)(i - 2) * 0.8f));
break;
}
break;
case Formation.Circle:
{
float num4 = 360f / (float)(count + 1);
float num5 = num * 0.6f * (float)(count + 1) / MathF.PI;
float num6 = (float)(i + 1) * num4 * (MathF.PI / 180f);
((Vector3)(ref zero))..ctor(Mathf.Sin(num6) * num5, 0f, Mathf.Cos(num6) * num5 - num5 * 0.5f);
break;
}
default:
{
float num2 = Random.Range(-75f, 75f) * (MathF.PI / 180f);
float num3 = num * (1f + (float)i * 0.3f) * Random.Range(0.7f, 1.3f);
((Vector3)(ref zero))..ctor(Mathf.Sin(num2) * num3 * 0.6f, 0f, (0f - Mathf.Cos(num2)) * num3);
break;
}
}
Followers[i].SetFormationOffset(zero);
Followers[i].AssignToGroup(this, isLeader: false);
}
}
}
[RequireComponent(typeof(PhotonView))]
public class GroupAIHelper : MonoBehaviourPun
{
internal Enemy? enemyRef;
internal NavMeshAgent? agent;
private ManualLogSource? _log;
private PhotonView? pv;
public EnemyGroup? CurrentGroup { get; private set; }
public bool IsInGroup => CurrentGroup != null && CurrentGroup.IsValid;
public bool IsLeader { get; private set; } = false;
public Vector3 FormationOffset { get; private set; } = Vector3.zero;
public Vector3 CurrentWorldTargetPosition { get; private set; } = Vector3.zero;
private void Awake()
{
_log = Plugin.Log;
enemyRef = ((Component)this).GetComponent<Enemy>();
agent = ((Component)this).GetComponent<NavMeshAgent>();
pv = ((Component)this).GetComponent<PhotonView>();
if ((Object)(object)enemyRef == (Object)null)
{
ManualLogSource? log = _log;
if (log != null)
{
log.LogError((object)("GroupAIHelper missing Enemy on " + ((Object)((Component)this).gameObject).name));
}
((Behaviour)this).enabled = false;
}
else if ((Object)(object)pv == (Object)null)
{
ManualLogSource? log2 = _log;
if (log2 != null)
{
log2.LogError((object)("GroupAIHelper missing PhotonView on " + ((Object)((Component)this).gameObject).name));
}
((Behaviour)this).enabled = false;
}
else if ((Object)(object)agent == (Object)null && enemyRef.HasNavMeshAgent)
{
agent = ((Component)this).GetComponentInChildren<NavMeshAgent>();
}
}
private void Start()
{
if (((Behaviour)this).enabled && SemiFunc.IsMasterClientOrSingleplayer())
{
ConfigEntry<bool>? enableGrouping = Plugin.EnableGrouping;
if (enableGrouping != null && enableGrouping.Value)
{
((MonoBehaviour)this).Invoke("RegisterWithManager", Random.Range(0.5f, 1f));
}
}
}
private void OnDestroy()
{
if (((Behaviour)this).enabled && SemiFunc.IsMasterClientOrSingleplayer() && (Object)(object)GroupPatrolManager.Instance != (Object)null)
{
ConfigEntry<bool>? enableGrouping = Plugin.EnableGrouping;
if (enableGrouping != null && enableGrouping.Value)
{
GroupPatrolManager.Instance.UnregisterEnemy(this);
}
}
LeaveGroupInternal();
}
private void RegisterWithManager()
{
if ((Object)(object)GroupPatrolManager.Instance != (Object)null && (Object)(object)enemyRef != (Object)null)
{
GroupPatrolManager.Instance.RegisterEnemy(this);
return;
}
ManualLogSource? log = _log;
if (log != null)
{
Enemy? obj = enemyRef;
log.LogError((object)("Failed to register " + ((obj != null) ? ((Object)obj).name : null) + ": GroupPatrolManager instance is null."));
}
}
public void AssignToGroup(EnemyGroup group, bool isLeader)
{
//IL_0085: Unknown result type (might be due to invalid IL or missing references)
if (!SemiFunc.IsMasterClientOrSingleplayer() || (Object)(object)pv == (Object)null)
{
return;
}
CurrentGroup = group;
IsLeader = isLeader;
int num = (((Object)(object)group.Leader != (Object)null) ? ((MonoBehaviourPun)group.Leader).photonView.ViewID : (-1));
if (num != -1)
{
pv.RPC("AssignToGroupRPC", (RpcTarget)6, new object[3] { num, isLeader, FormationOffset });
return;
}
ManualLogSource? log = _log;
if (log != null)
{
Enemy? obj = enemyRef;
log.LogError((object)("HOST: Cannot send AssignToGroupRPC for " + ((obj != null) ? ((Object)obj).name : null) + " because leader is null!"));
}
}
[PunRPC]
public void AssignToGroupRPC(int leaderViewID, bool isLeader, Vector3 formationOffset)
{
//IL_000a: Unknown result type (might be due to invalid IL or missing references)
IsLeader = isLeader;
FormationOffset = formationOffset;
PhotonView val = PhotonView.Find(leaderViewID);
Enemy val2 = ((val != null) ? ((Component)val).GetComponent<Enemy>() : null);
if ((Object)(object)val2 != (Object)null)
{
CurrentGroup = null;
return;
}
ManualLogSource? log = _log;
if (log != null)
{
PhotonView? obj = pv;
log.LogError((object)$"CLIENT {((obj != null) ? new int?(obj.ViewID) : null)}: Received AssignToGroupRPC but could not find leader with ViewID {leaderViewID}!");
}
LeaveGroupInternal();
}
public void SetFormationOffset(Vector3 offset)
{
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
FormationOffset = offset;
}
public void LeaveGroup()
{
if (SemiFunc.IsMasterClientOrSingleplayer() && !((Object)(object)pv == (Object)null))
{
if (CurrentGroup != null || IsLeader)
{
pv.RPC("LeaveGroupRPC", (RpcTarget)6, Array.Empty<object>());
}
LeaveGroupInternal();
}
}
[PunRPC]
public void LeaveGroupRPC()
{
LeaveGroupInternal();
}
private void LeaveGroupInternal()
{
//IL_0012: Unknown result type (might be due to invalid IL or missing references)
//IL_001e: Unknown result type (might be due to invalid IL or missing references)
CurrentGroup = null;
IsLeader = false;
FormationOffset = Vector3.zero;
CurrentWorldTargetPosition = Vector3.zero;
}
public bool TryGroupMovement()
{
//IL_012a: Unknown result type (might be due to invalid IL or missing references)
//IL_012f: 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_0148: Unknown result type (might be due to invalid IL or missing references)
//IL_014a: Unknown result type (might be due to invalid IL or missing references)
//IL_014d: Unknown result type (might be due to invalid IL or missing references)
//IL_0152: Unknown result type (might be due to invalid IL or missing references)
//IL_0157: Unknown result type (might be due to invalid IL or missing references)
//IL_015c: Unknown result type (might be due to invalid IL or missing references)
//IL_015e: Unknown result type (might be due to invalid IL or missing references)
//IL_0087: Unknown result type (might be due to invalid IL or missing references)
//IL_008c: Unknown result type (might be due to invalid IL or missing references)
//IL_0183: Unknown result type (might be due to invalid IL or missing references)
//IL_0176: Unknown result type (might be due to invalid IL or missing references)
//IL_019b: Unknown result type (might be due to invalid IL or missing references)
//IL_01b6: Unknown result type (might be due to invalid IL or missing references)
//IL_01bc: Unknown result type (might be due to invalid IL or missing references)
//IL_01e3: Unknown result type (might be due to invalid IL or missing references)
//IL_01ea: Expected O, but got Unknown
//IL_01f1: Unknown result type (might be due to invalid IL or missing references)
//IL_0201: Unknown result type (might be due to invalid IL or missing references)
//IL_0207: Invalid comparison between Unknown and I4
//IL_0234: Unknown result type (might be due to invalid IL or missing references)
//IL_0239: Unknown result type (might be due to invalid IL or missing references)
//IL_021a: Unknown result type (might be due to invalid IL or missing references)
//IL_0260: Unknown result type (might be due to invalid IL or missing references)
//IL_026d: Unknown result type (might be due to invalid IL or missing references)
//IL_0273: Invalid comparison between Unknown and I4
//IL_0285: Unknown result type (might be due to invalid IL or missing references)
bool flag = !IsLeader && CurrentGroup != null && CurrentGroup.IsValid && (Object)(object)CurrentGroup.Leader != (Object)null;
if (!SemiFunc.IsMasterClientOrSingleplayer())
{
PhotonView val = PhotonView.Find((((Component)this).GetComponent<PhotonView>().InstantiationData != null) ? ((int)((Component)this).GetComponent<PhotonView>().InstantiationData[0]) : (-1));
flag = !IsLeader && (Object)(object)val != (Object)null;
flag = !IsLeader && FormationOffset != Vector3.zero;
}
if (flag)
{
if (SemiFunc.IsMasterClientOrSingleplayer())
{
if ((Object)(object)agent == (Object)null || !((Behaviour)agent).enabled || !agent.isOnNavMesh || CurrentGroup == null || (Object)(object)CurrentGroup.Leader == (Object)null || !((Behaviour)CurrentGroup.Leader).isActiveAndEnabled)
{
return false;
}
Vector3 position = ((Component)CurrentGroup.Leader).transform.position;
Quaternion rotation = ((Component)CurrentGroup.Leader).transform.rotation;
Vector3 val2 = position + rotation * FormationOffset;
NavMeshHit val3 = default(NavMeshHit);
if (NavMesh.SamplePosition(val2, ref val3, 1f, -1))
{
CurrentWorldTargetPosition = ((NavMeshHit)(ref val3)).position;
}
else
{
NavMeshHit val4 = default(NavMeshHit);
if (!NavMesh.SamplePosition(position, ref val4, 1f, -1))
{
return false;
}
CurrentWorldTargetPosition = ((NavMeshHit)(ref val4)).position;
}
if (Vector3.Distance(((Component)this).transform.position, CurrentWorldTargetPosition) > agent.stoppingDistance + 0.5f)
{
NavMeshPath val5 = new NavMeshPath();
if (agent.CalculatePath(CurrentWorldTargetPosition, val5) && (int)val5.status == 0)
{
agent.SetDestination(CurrentWorldTargetPosition);
return true;
}
if (Vector3.Distance(((Component)this).transform.position, position) > agent.stoppingDistance + 1f && agent.CalculatePath(position, val5) && (int)val5.status == 0)
{
agent.SetDestination(position);
return true;
}
return false;
}
if (agent.hasPath)
{
agent.ResetPath();
}
return false;
}
if ((Object)(object)agent != (Object)null && ((Behaviour)agent).enabled && agent.isOnNavMesh && agent.hasPath)
{
agent.ResetPath();
}
return true;
}
return false;
}
public void BreakFormationTemporarily()
{
if (SemiFunc.IsMasterClientOrSingleplayer())
{
if (IsInGroup)
{
CurrentGroup?.RemoveMember(this);
}
}
else
{
LeaveGroupInternal();
}
}
}
public class GroupPatrolManager : MonoBehaviour
{
private List<EnemyGroup> activeGroups = new List<EnemyGroup>();
private Dictionary<EnemyType, List<GroupAIHelper>> potentialGroupMembers = new Dictionary<EnemyType, List<GroupAIHelper>>();
private float groupCheckTimer = 0f;
private ManualLogSource? _log;
public static GroupPatrolManager? Instance { get; private set; }
private void Awake()
{
if ((Object)(object)Instance != (Object)null && (Object)(object)Instance != (Object)(object)this)
{
Object.Destroy((Object)(object)((Component)this).gameObject);
return;
}
Instance = this;
_log = Plugin.Log;
ManualLogSource? log = _log;
if (log != null)
{
log.LogInfo((object)"GroupPatrolManager Initialized.");
}
if (Plugin.GroupCheckInterval == null)
{
ManualLogSource? log2 = _log;
if (log2 != null)
{
log2.LogError((object)"GroupPatrolManager cannot run: GroupCheckInterval config is null.");
}
((Behaviour)this).enabled = false;
}
else
{
groupCheckTimer = Plugin.GroupCheckInterval.Value;
}
}
private void OnDestroy()
{
if (!((Object)(object)Instance == (Object)(object)this))
{
return;
}
Instance = null;
ManualLogSource? log = _log;
if (log != null)
{
log.LogInfo((object)"GroupPatrolManager Cleaning Up Groups...");
}
foreach (EnemyGroup item in activeGroups.ToList())
{
item.DisbandGroup();
}
activeGroups.Clear();
potentialGroupMembers.Clear();
ManualLogSource? log2 = _log;
if (log2 != null)
{
log2.LogInfo((object)"GroupPatrolManager Destroyed.");
}
}
private void Update()
{
if (!((Behaviour)this).enabled || !SemiFunc.IsMasterClientOrSingleplayer() || Plugin.EnableGrouping == null)
{
return;
}
if (!Plugin.EnableGrouping.Value)
{
if (activeGroups.Count <= 0)
{
return;
}
ManualLogSource? log = _log;
if (log != null)
{
log.LogInfo((object)"Grouping disabled, disbanding...");
}
foreach (EnemyGroup item in activeGroups.ToList())
{
item.DisbandGroup();
}
activeGroups.Clear();
potentialGroupMembers.Clear();
return;
}
groupCheckTimer -= Time.deltaTime;
if (groupCheckTimer <= 0f)
{
TryFormGroups();
CleanupInvalidGroups();
if (Plugin.GroupCheckInterval != null)
{
groupCheckTimer = Plugin.GroupCheckInterval.Value + Random.Range(-1f, 1f);
}
else
{
groupCheckTimer = 10f;
}
}
UpdateGroupPatrols();
}
public void RegisterEnemy(GroupAIHelper helper)
{
//IL_002a: Unknown result type (might be due to invalid IL or missing references)
//IL_002f: Unknown result type (might be due to invalid IL or missing references)
//IL_0036: Unknown result type (might be due to invalid IL or missing references)
//IL_005b: Unknown result type (might be due to invalid IL or missing references)
//IL_0049: Unknown result type (might be due to invalid IL or missing references)
//IL_007f: Unknown result type (might be due to invalid IL or missing references)
if (((Behaviour)this).enabled && !((Object)(object)helper?.enemyRef == (Object)null))
{
EnemyType type = helper.enemyRef.Type;
if (!potentialGroupMembers.ContainsKey(type))
{
potentialGroupMembers[type] = new List<GroupAIHelper>();
}
if (!potentialGroupMembers[type].Contains(helper) && !helper.IsInGroup)
{
potentialGroupMembers[type].Add(helper);
}
}
}
public void UnregisterEnemy(GroupAIHelper helper)
{
//IL_0069: Unknown result type (might be due to invalid IL or missing references)
//IL_006e: Unknown result type (might be due to invalid IL or missing references)
//IL_0075: Unknown result type (might be due to invalid IL or missing references)
//IL_0087: Unknown result type (might be due to invalid IL or missing references)
if (!((Behaviour)this).enabled || (Object)(object)helper?.enemyRef == (Object)null)
{
return;
}
if (helper.IsInGroup && helper.CurrentGroup != null)
{
if (helper.IsLeader)
{
helper.CurrentGroup.DisbandGroup();
}
else
{
helper.CurrentGroup.RemoveMember(helper);
}
}
EnemyType type = helper.enemyRef.Type;
if (potentialGroupMembers.ContainsKey(type))
{
potentialGroupMembers[type].Remove(helper);
}
}
private void TryFormGroups()
{
//IL_0053: 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_0061: 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_0231: Unknown result type (might be due to invalid IL or missing references)
if (Plugin.MinGroupSize == null || Plugin.MaxGroupSize == null)
{
return;
}
int value = Plugin.MinGroupSize.Value;
int value2 = Plugin.MaxGroupSize.Value;
List<EnemyType> list = potentialGroupMembers.Keys.ToList();
foreach (EnemyType item in list)
{
if (!potentialGroupMembers.ContainsKey(item))
{
continue;
}
List<GroupAIHelper> list2 = potentialGroupMembers[item];
list2.RemoveAll((GroupAIHelper h) => (Object)(object)h == (Object)null || (Object)(object)h.enemyRef == (Object)null || !((Behaviour)h.enemyRef).isActiveAndEnabled || h.IsInGroup);
while (list2.Count >= value)
{
int num = Mathf.Min(Random.Range(value, value2 + 1), list2.Count);
List<GroupAIHelper> list3 = list2.Where((GroupAIHelper p) => (Object)(object)p != (Object)null && (Object)(object)p.enemyRef != (Object)null && ((Behaviour)p.enemyRef).isActiveAndEnabled && !p.IsInGroup).ToList();
if (list3.Count < value)
{
break;
}
num = Mathf.Min(num, list3.Count);
List<GroupAIHelper> list4 = list3.Take(num).ToList();
GroupAIHelper groupAIHelper = list4[0];
if ((Object)(object)groupAIHelper.enemyRef == (Object)null)
{
ManualLogSource? log = _log;
if (log != null)
{
log.LogError((object)"Selected leader has null enemyRef!");
}
list2.Remove(groupAIHelper);
continue;
}
Formation formation = ParseFormation(Plugin.FormationType?.Value ?? "Loose");
EnemyGroup enemyGroup = new EnemyGroup(groupAIHelper.enemyRef, formation);
groupAIHelper.AssignToGroup(enemyGroup, isLeader: true);
for (int i = 1; i < list4.Count; i++)
{
enemyGroup.AddFollower(list4[i]);
}
foreach (GroupAIHelper item2 in list4)
{
list2.Remove(item2);
}
activeGroups.Add(enemyGroup);
ManualLogSource? log2 = _log;
if (log2 != null)
{
log2.LogInfo((object)$"Formed group for {item} size {num}.");
}
}
}
}
private void CleanupInvalidGroups()
{
activeGroups.RemoveAll((EnemyGroup group) => !group.IsValid || (Object)(object)group.Leader == (Object)null || !((Behaviour)group.Leader).isActiveAndEnabled);
}
private void UpdateGroupPatrols()
{
//IL_00bd: 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_00df: Expected O, but got Unknown
//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
//IL_00fd: Invalid comparison between Unknown and I4
//IL_0111: Unknown result type (might be due to invalid IL or missing references)
//IL_011e: Unknown result type (might be due to invalid IL or missing references)
foreach (EnemyGroup activeGroup in activeGroups)
{
if (!activeGroup.IsValid || (Object)(object)activeGroup.Leader == (Object)null || !((Behaviour)activeGroup.Leader).isActiveAndEnabled)
{
continue;
}
NavMeshAgent val = activeGroup.Leader.NavMeshAgent?.Agent;
if (!((Object)(object)val != (Object)null) || !((Behaviour)val).enabled || !val.isOnNavMesh || (val.hasPath && !(val.remainingDistance < val.stoppingDistance + 1.5f)))
{
continue;
}
LevelPoint val2 = FindNewPatrolPoint(((Component)activeGroup.Leader).transform.position);
if ((Object)(object)val2 != (Object)null)
{
NavMeshPath val3 = new NavMeshPath();
if (val.CalculatePath(((Component)val2).transform.position, val3) && (int)val3.status == 0)
{
activeGroup.CurrentPatrolTarget = ((Component)val2).transform.position;
val.SetDestination(activeGroup.CurrentPatrolTarget);
}
else if (val.hasPath)
{
val.ResetPath();
}
}
else if (val.hasPath)
{
val.ResetPath();
}
}
}
private LevelPoint? FindNewPatrolPoint(Vector3 currentPos)
{
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
//IL_0008: Unknown result type (might be due to invalid IL or missing references)
if (LevelGenerator.Instance?.LevelPathPoints == null || LevelGenerator.Instance.LevelPathPoints.Count == 0)
{
return null;
}
List<LevelPoint> list = LevelGenerator.Instance.LevelPathPoints.Where((LevelPoint p) => (Object)(object)p != (Object)null && Vector3.Distance(((Component)p).transform.position, currentPos) > 10f).ToList();
if (list.Count > 0)
{
return list[Random.Range(0, list.Count)];
}
return LevelGenerator.Instance.LevelPathPoints[Random.Range(0, LevelGenerator.Instance.LevelPathPoints.Count)];
}
private Formation ParseFormation(string formationName)
{
if (Enum.TryParse<Formation>(formationName, ignoreCase: true, out var result))
{
return result;
}
ManualLogSource? log = _log;
if (log != null)
{
log.LogWarning((object)("Invalid FormationType '" + formationName + "'. Defaulting to Loose."));
}
return Formation.Loose;
}
}
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInPlugin("PlusBlankPlus.VisionMonsters", "Vision and Hearing Monsters", "1.3.3")]
public class Plugin : BaseUnityPlugin
{
public const string PluginGuid = "PlusBlankPlus.VisionMonsters";
public const string PluginName = "Vision and Hearing Monsters";
public const string PluginVersion = "1.3.3";
public static ConfigEntry<float>? VisionDistanceMultiplier;
public static ConfigEntry<float>? CloseVisionDistanceMultiplier;
public static ConfigEntry<float>? CrouchCloseVisionDistanceMultiplier;
public static ConfigEntry<float>? PhysObjectVisionRadiusMultiplier;
public static ConfigEntry<float>? SoundSensitivityMultiplier;
public static ConfigEntry<bool>? EnableCheatingAI;
public static ConfigEntry<float>? RadarScanRadius;
public static ConfigEntry<float>? RadarScanInterval;
public static ConfigEntry<float>? MemoryDuration;
public static ConfigEntry<bool>? EnableGrouping;
public static ConfigEntry<int>? MinGroupSize;
public static ConfigEntry<int>? MaxGroupSize;
public static ConfigEntry<float>? GroupCheckInterval;
public static ConfigEntry<string>? FormationType;
internal static ManualLogSource? Log;
internal static bool firstPatchLogDone;
private void Awake()
{
//IL_0066: Unknown result type (might be due to invalid IL or missing references)
//IL_0070: Expected O, but got Unknown
//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
//IL_00ad: Expected O, but got Unknown
//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
//IL_00ea: Expected O, but got Unknown
//IL_011d: Unknown result type (might be due to invalid IL or missing references)
//IL_0127: Expected O, but got Unknown
//IL_015a: Unknown result type (might be due to invalid IL or missing references)
//IL_0164: Expected O, but got Unknown
//IL_01b7: Unknown result type (might be due to invalid IL or missing references)
//IL_01c1: Expected O, but got Unknown
//IL_01f4: Unknown result type (might be due to invalid IL or missing references)
//IL_01fe: Expected O, but got Unknown
//IL_0231: Unknown result type (might be due to invalid IL or missing references)
//IL_023b: Expected O, but got Unknown
//IL_0283: Unknown result type (might be due to invalid IL or missing references)
//IL_028d: Expected O, but got Unknown
//IL_02b5: Unknown result type (might be due to invalid IL or missing references)
//IL_02bf: Expected O, but got Unknown
//IL_02f2: Unknown result type (might be due to invalid IL or missing references)
//IL_02fc: Expected O, but got Unknown
//IL_0353: Unknown result type (might be due to invalid IL or missing references)
//IL_035d: Expected O, but got Unknown
//IL_037d: Unknown result type (might be due to invalid IL or missing references)
//IL_0383: Expected O, but got Unknown
Log = ((BaseUnityPlugin)this).Logger;
ManualLogSource? log = Log;
if (log != null)
{
log.LogInfo((object)"Loading Vision and Hearing Monsters v1.3.3...");
}
ManualLogSource? log2 = Log;
if (log2 != null)
{
log2.LogInfo((object)"Binding configuration...");
}
VisionDistanceMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("1. Vision", "VisionDistanceMultiplier", 1f, new ConfigDescription("Multiplier for base vision distance.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.01f, 20f), Array.Empty<object>()));
CloseVisionDistanceMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("1. Vision", "CloseVisionDistanceMultiplier", 1f, new ConfigDescription("Multiplier for close standing vision.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.01f, 10f), Array.Empty<object>()));
CrouchCloseVisionDistanceMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("1. Vision", "CrouchCloseVisionDistanceMultiplier", 1f, new ConfigDescription("Multiplier for close crouched vision.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.01f, 10f), Array.Empty<object>()));
PhysObjectVisionRadiusMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("1. Vision", "PhysObjectVisionRadiusMultiplier", 1f, new ConfigDescription("Multiplier for physics object vision radius.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.01f, 10f), Array.Empty<object>()));
SoundSensitivityMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("2. Hearing", "SoundSensitivityMultiplier", 1f, new ConfigDescription("Multiplier for sound investigation radius.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 10f), Array.Empty<object>()));
EnableCheatingAI = ((BaseUnityPlugin)this).Config.Bind<bool>("3. Cheating AI", "EnableCheatingAI", false, "Enables unfair AI enhancements (Radar, Memory, Targeted Patrols).");
RadarScanRadius = ((BaseUnityPlugin)this).Config.Bind<float>("3. Cheating AI", "RadarScanRadius", 25f, new ConfigDescription("Radius (meters) for enemy 'radar' scans (ignores walls).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(5f, 100f), Array.Empty<object>()));
RadarScanInterval = ((BaseUnityPlugin)this).Config.Bind<float>("3. Cheating AI", "RadarScanInterval", 5f, new ConfigDescription("How often (seconds) each enemy performs a radar scan.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 30f), Array.Empty<object>()));
MemoryDuration = ((BaseUnityPlugin)this).Config.Bind<float>("3. Cheating AI", "MemoryDuration", 60f, new ConfigDescription("How long (seconds) enemy remembers player's last known location.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(5f, 300f), Array.Empty<object>()));
EnableGrouping = ((BaseUnityPlugin)this).Config.Bind<bool>("4. Group Patrolling", "EnableGrouping", false, "Enables enemies of the same type to form patrol groups.");
MinGroupSize = ((BaseUnityPlugin)this).Config.Bind<int>("4. Group Patrolling", "MinGroupSize", 2, new ConfigDescription("Minimum number of same-type enemies needed to form a group.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(2, 10), Array.Empty<object>()));
MaxGroupSize = ((BaseUnityPlugin)this).Config.Bind<int>("4. Group Patrolling", "MaxGroupSize", 4, new ConfigDescription("Maximum number of enemies in a single patrol group.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(2, 10), Array.Empty<object>()));
GroupCheckInterval = ((BaseUnityPlugin)this).Config.Bind<float>("4. Group Patrolling", "GroupCheckInterval", 10f, new ConfigDescription("How often (seconds) the manager tries to form new groups.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(5f, 60f), Array.Empty<object>()));
FormationType = ((BaseUnityPlugin)this).Config.Bind<string>("4. Group Patrolling", "FormationType", "Loose", new ConfigDescription("How grouped enemies attempt to arrange themselves while patrolling.", (AcceptableValueBase)(object)new AcceptableValueList<string>(new string[5] { "Line", "Triangle", "Box", "Circle", "Loose" }), Array.Empty<object>()));
ManualLogSource? log3 = Log;
if (log3 != null)
{
log3.LogInfo((object)"Applying patches for PlusBlankPlus.VisionMonsters...");
}
Harmony val = new Harmony("PlusBlankPlus.VisionMonsters");
try
{
val.PatchAll(Assembly.GetExecutingAssembly());
ManualLogSource? log4 = Log;
if (log4 != null)
{
log4.LogInfo((object)"Patches applied successfully!");
}
}
catch (Exception ex)
{
ManualLogSource? log5 = Log;
if (log5 != null)
{
log5.LogError((object)("Error applying Harmony patches: " + ex.Message));
}
ManualLogSource? log6 = Log;
if (log6 != null)
{
log6.LogError((object)("Stack trace: " + ex.StackTrace));
}
if (ex is ReflectionTypeLoadException ex2 && ex2.LoaderExceptions != null)
{
Exception[] loaderExceptions = ex2.LoaderExceptions;
foreach (Exception ex3 in loaderExceptions)
{
if (ex3 != null)
{
ManualLogSource? log7 = Log;
if (log7 != null)
{
log7.LogError((object)("LoaderException: " + ex3.Message));
}
}
}
}
}
ManualLogSource? log8 = Log;
if (log8 != null)
{
log8.LogInfo((object)"Plugin Vision and Hearing Monsters (PlusBlankPlus.VisionMonsters) version 1.3.3 is loaded!");
}
}
}
[HarmonyPatch(typeof(GameDirector))]
internal static class GameDirectorStartPatch
{
private static bool managerChecked;
[HarmonyPatch("Start")]
[HarmonyPostfix]
private static void CreateGroupManagerIfNeeded()
{
//IL_0079: Unknown result type (might be due to invalid IL or missing references)
//IL_007f: Expected O, but got Unknown
if (managerChecked)
{
return;
}
managerChecked = true;
ManualLogSource? log = Plugin.Log;
if (log != null)
{
log.LogInfo((object)"GameDirector.Start Postfix: Checking if Group Manager needs creation...");
}
ConfigEntry<bool>? enableGrouping = Plugin.EnableGrouping;
if (enableGrouping != null && enableGrouping.Value && SemiFunc.IsMasterClientOrSingleplayer())
{
if ((Object)(object)GroupPatrolManager.Instance == (Object)null)
{
ManualLogSource? log2 = Plugin.Log;
if (log2 != null)
{
log2.LogInfo((object)"HOST: Creating GroupPatrolManager GameObject via GameDirector.Start patch...");
}
GameObject val = new GameObject("GroupPatrolManager_MOD");
if ((Object)(object)val.AddComponent<GroupPatrolManager>() != (Object)null)
{
Object.DontDestroyOnLoad((Object)(object)val);
ManualLogSource? log3 = Plugin.Log;
if (log3 != null)
{
log3.LogInfo((object)"GroupPatrolManager created successfully.");
}
}
else
{
ManualLogSource? log4 = Plugin.Log;
if (log4 != null)
{
log4.LogError((object)"Failed to add GroupPatrolManager component!");
}
Object.Destroy((Object)(object)val);
}
}
else
{
ManualLogSource? log5 = Plugin.Log;
if (log5 != null)
{
log5.LogInfo((object)"GroupPatrolManager instance already exists.");
}
}
return;
}
ConfigEntry<bool>? enableGrouping2 = Plugin.EnableGrouping;
if (enableGrouping2 != null && enableGrouping2.Value)
{
ManualLogSource? log6 = Plugin.Log;
if (log6 != null)
{
log6.LogInfo((object)"CLIENT: Grouping enabled, manager runs on host.");
}
}
else
{
ManualLogSource? log7 = Plugin.Log;
if (log7 != null)
{
log7.LogInfo((object)"Grouping disabled, manager not created.");
}
}
}
}
[HarmonyPatch(typeof(EnemyVision))]
internal static class EnemyVisionPatches
{
[HarmonyPatch("Awake")]
[HarmonyPostfix]
private static void ModifyVisionRanges(EnemyVision __instance)
{
if ((Object)(object)__instance == (Object)null || Plugin.Log == null || Plugin.VisionDistanceMultiplier == null || Plugin.CloseVisionDistanceMultiplier == null || Plugin.CrouchCloseVisionDistanceMultiplier == null || Plugin.PhysObjectVisionRadiusMultiplier == null)
{
return;
}
try
{
float visionDistance = __instance.VisionDistance;
__instance.VisionDistance *= Plugin.VisionDistanceMultiplier.Value;
__instance.VisionDistanceClose *= Plugin.CloseVisionDistanceMultiplier.Value;
__instance.VisionDistanceCloseCrouch *= Plugin.CrouchCloseVisionDistanceMultiplier.Value;
__instance.PhysObjectVisionRadius *= Plugin.PhysObjectVisionRadiusMultiplier.Value;
if (__instance.PhysObjectVisionRadiusOverride > 0f)
{
__instance.PhysObjectVisionRadiusOverride *= Plugin.PhysObjectVisionRadiusMultiplier.Value;
}
if (!Plugin.firstPatchLogDone && (Object)(object)((Component)__instance).gameObject != (Object)null)
{
Plugin.Log.LogInfo((object)string.Format("[{0}] Modifying EnemyVision on {1}: Vision={2}->{3}", "Vision and Hearing Monsters", ((Object)((Component)__instance).gameObject).name, visionDistance, __instance.VisionDistance));
}
}
catch (Exception arg)
{
ManualLogSource? log = Plugin.Log;
if (log != null)
{
log.LogError((object)$"Error in ModifyVisionRanges patch: {arg}");
}
}
}
}
[HarmonyPatch(typeof(EnemyDirector))]
internal static class EnemyDirectorPatches
{
[HarmonyPatch("SetInvestigate")]
[HarmonyPrefix]
private static void ModifyInvestigationRadius(ref float radius)
{
if (Plugin.Log == null || Plugin.SoundSensitivityMultiplier == null)
{
return;
}
try
{
radius *= Plugin.SoundSensitivityMultiplier.Value;
if (!Plugin.firstPatchLogDone)
{
Plugin.Log.LogInfo((object)string.Format("[{0}] Sound Sensitivity Multiplier Applied: {1}.", "Vision and Hearing Monsters", Plugin.SoundSensitivityMultiplier.Value));
Plugin.firstPatchLogDone = true;
}
}
catch (Exception arg)
{
ManualLogSource? log = Plugin.Log;
if (log != null)
{
log.LogError((object)$"Error in ModifyInvestigationRadius patch: {arg}");
}
}
}
}
[HarmonyPatch(typeof(Enemy))]
internal static class EnemyAwakePatch
{
[HarmonyPatch("Awake")]
[HarmonyPostfix]
private static void AddAIHelperComponents(Enemy __instance)
{
if ((Object)(object)((__instance != null) ? ((Component)__instance).gameObject : null) == (Object)null)
{
ManualLogSource? log = Plugin.Log;
if (log != null)
{
log.LogWarning((object)"AddAIHelperComponents patch __instance null.");
}
return;
}
if ((Object)(object)((Component)__instance).gameObject.GetComponent<EnemyAIHelper>() == (Object)null)
{
((Component)__instance).gameObject.AddComponent<EnemyAIHelper>();
}
if ((Object)(object)((Component)__instance).gameObject.GetComponent<GroupAIHelper>() == (Object)null)
{
((Component)__instance).gameObject.AddComponent<GroupAIHelper>();
}
}
}
[HarmonyPatch(typeof(EnemyHealth))]
internal static class EnemyHealthPatch
{
[HarmonyPatch("DeathImpulseRPC")]
[HarmonyPrefix]
private static void UnregisterOnDeathConfirmed(EnemyHealth __instance)
{
ConfigEntry<bool>? enableGrouping = Plugin.EnableGrouping;
if (enableGrouping == null || !enableGrouping.Value || !SemiFunc.IsMasterClientOrSingleplayer())
{
return;
}
if ((Object)(object)__instance != (Object)null && (Object)(object)GroupPatrolManager.Instance != (Object)null)
{
GroupAIHelper component = ((Component)__instance).GetComponent<GroupAIHelper>();
if ((Object)(object)component != (Object)null)
{
GroupPatrolManager.Instance.UnregisterEnemy(component);
}
}
else if ((Object)(object)__instance == (Object)null)
{
ManualLogSource? log = Plugin.Log;
if (log != null)
{
log.LogWarning((object)"UnregisterOnDeathConfirmed patch __instance null.");
}
}
}
}
[HarmonyPatch(typeof(EnemyVision))]
internal static class EnemyVisionTriggerPatch
{
[HarmonyPatch("VisionTrigger")]
[HarmonyPrefix]
private static void UpdateMemoryAndBreakFormationOnVision(EnemyVision __instance, PlayerAvatar player)
{
//IL_0042: Unknown result type (might be due to invalid IL or missing references)
if (!((Object)(object)__instance == (Object)null) && !((Object)(object)player == (Object)null))
{
ConfigEntry<bool>? enableCheatingAI = Plugin.EnableCheatingAI;
if (enableCheatingAI != null && enableCheatingAI.Value)
{
((Component)__instance).GetComponent<EnemyAIHelper>()?.UpdateMemory(((Component)player).transform.position);
}
ConfigEntry<bool>? enableGrouping = Plugin.EnableGrouping;
if (enableGrouping != null && enableGrouping.Value)
{
((Component)__instance).GetComponent<GroupAIHelper>()?.BreakFormationTemporarily();
}
}
}
}
[HarmonyPatch(typeof(EnemyStateInvestigate))]
internal static class EnemyInvestigatePatch
{
[HarmonyPatch("Set")]
[HarmonyPrefix]
private static void UpdateMemoryAndBreakFormationOnInvestigate(EnemyStateInvestigate __instance, Vector3 position)
{
//IL_004d: Unknown result type (might be due to invalid IL or missing references)
//IL_0052: 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_0064: 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_00b8: Unknown result type (might be due to invalid IL or missing references)
//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
if (!((Object)(object)__instance == (Object)null))
{
EnemyAIHelper component = ((Component)__instance).GetComponent<EnemyAIHelper>();
GroupAIHelper component2 = ((Component)__instance).GetComponent<GroupAIHelper>();
ConfigEntry<bool>? enableCheatingAI = Plugin.EnableCheatingAI;
if (enableCheatingAI != null && enableCheatingAI.Value && (Object)(object)component != (Object)null && (!component.HasFreshMemory() || Vector3.Distance(((Component)__instance).transform.position, position) < Vector3.Distance(((Component)__instance).transform.position, component.lastKnownPlayerPosition)))
{
component.UpdateMemory(position);
}
ConfigEntry<bool>? enableGrouping = Plugin.EnableGrouping;
if (enableGrouping != null && enableGrouping.Value && (Object)(object)component2 != (Object)null && component2.IsInGroup && component2.CurrentGroup != null && Vector3.Distance(position, component2.CurrentGroup.CurrentPatrolTarget) > 5f)
{
component2.BreakFormationTemporarily();
}
}
}
}
[HarmonyPatch(typeof(EnemyStateRoaming))]
internal static class EnemyRoamingPatch
{
[HarmonyPatch("Update")]
[HarmonyPrefix]
private static bool OverrideRoamingMovement(EnemyStateRoaming __instance)
{
if (Plugin.EnableGrouping == null || !Plugin.EnableGrouping.Value)
{
return true;
}
GroupAIHelper groupAIHelper = ((__instance != null) ? ((Component)__instance).GetComponent<GroupAIHelper>() : null);
if ((Object)(object)groupAIHelper != (Object)null && groupAIHelper.TryGroupMovement())
{
return false;
}
return true;
}
}
[HarmonyPatch(typeof(EnemyStateChaseBegin))]
internal static class EnemyStateChaseBeginPatch
{
[HarmonyPatch("Update")]
[HarmonyPrefix]
private static void BreakFormationOnChaseBegin(EnemyStateChaseBegin __instance)
{
if (Plugin.EnableGrouping != null && Plugin.EnableGrouping.Value && __instance != null)
{
((Component)__instance).GetComponent<GroupAIHelper>()?.BreakFormationTemporarily();
}
}
}
[HarmonyPatch(typeof(EnemyStateChase))]
internal static class EnemyStateChasePatch
{
[HarmonyPatch("Update")]
[HarmonyPrefix]
private static void BreakFormationOnChase(EnemyStateChase __instance)
{
if (Plugin.EnableGrouping != null && Plugin.EnableGrouping.Value && __instance != null)
{
((Component)__instance).GetComponent<GroupAIHelper>()?.BreakFormationTemporarily();
}
}
}
}