Decompiled source of TheEavesdropper v0.6.2

BepInEx/plugins/TheEavesdropper/Eavesdropper.dll

Decompiled 4 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Numerics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using Dissonance;
using Eavesdropper.Art;
using Eavesdropper.Core;
using GameNetcodeStuff;
using HarmonyLib;
using LethalLib.Modules;
using Microsoft.CodeAnalysis;
using Unity.Collections;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.Rendering;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("Eavesdropper")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.6.2.0")]
[assembly: AssemblyInformationalVersion("0.6.2")]
[assembly: AssemblyProduct("Eavesdropper")]
[assembly: AssemblyTitle("Eavesdropper")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.6.2.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace Eavesdropper
{
	internal sealed class AdvancedVisual
	{
		private sealed class Take
		{
			internal float Fps;

			internal Vector3[][] Positions;

			internal Quaternion[][] Rotations;
		}

		internal Mesh Mesh;

		internal Material[] Materials = Array.Empty<Material>();

		private readonly Dictionary<string, Take> takes = new Dictionary<string, Take>();

		private static string ReadName(BinaryReader r)
		{
			int num = r.ReadInt32();
			if (num < 0 || num > 256)
			{
				throw new InvalidDataException("Invalid asset name");
			}
			return Encoding.UTF8.GetString(r.ReadBytes(num));
		}

		private static int Count(BinaryReader r, int max)
		{
			int num = r.ReadInt32();
			if (num < 0 || num > max)
			{
				throw new InvalidDataException("Invalid asset count");
			}
			return num;
		}

		private static float Float(BinaryReader r)
		{
			float num = r.ReadSingle();
			if (!float.IsFinite(num))
			{
				throw new InvalidDataException("Nonfinite visual data");
			}
			return num;
		}

		internal static AdvancedVisual? Load()
		{
			string text = Path.Combine(Path.GetDirectoryName(((BaseUnityPlugin)Plugin.Instance).Info.Location), "eavesdropper-visual");
			if (!File.Exists(Path.Combine(text, "eavesdropper.mesh")))
			{
				return null;
			}
			AdvancedVisual advancedVisual = new AdvancedVisual();
			try
			{
				advancedVisual.Read(text);
				Plugin.Instance.Log("Loaded Blender visual and " + advancedVisual.takes.Count + " animation takes.");
				return advancedVisual;
			}
			catch (Exception ex)
			{
				Plugin.Instance.Error("Blender visual rejected; using built-in fallback. " + ex.Message);
				return null;
			}
		}

		private void Read(string folder)
		{
			//IL_031c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0321: Unknown result type (might be due to invalid IL or missing references)
			//IL_032c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0338: Expected O, but got Unknown
			//IL_03b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_018f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01af: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c9: 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_02bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_049d: Unknown result type (might be due to invalid IL or missing references)
			//IL_04a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_04c2: Expected O, but got Unknown
			//IL_04f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_04e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0538: Unknown result type (might be due to invalid IL or missing references)
			//IL_0522: Unknown result type (might be due to invalid IL or missing references)
			Creature model = CreatureRig.Model;
			List<Vector3> list = new List<Vector3>();
			List<Vector3> list2 = new List<Vector3>();
			List<Vector2> list3 = new List<Vector2>();
			List<BoneWeight> list4 = new List<BoneWeight>();
			List<int>[] array = new List<int>[5];
			for (int i = 0; i < 5; i++)
			{
				array[i] = new List<int>();
			}
			int[] array2;
			using (BinaryReader binaryReader = new BinaryReader(File.OpenRead(Path.Combine(folder, "eavesdropper.mesh"))))
			{
				if (Encoding.ASCII.GetString(binaryReader.ReadBytes(8)) != "EAVMESH1")
				{
					throw new InvalidDataException("Mesh version");
				}
				int num = Count(binaryReader, 100);
				if (num != model.Joints.Count)
				{
					throw new InvalidDataException("Rig size");
				}
				array2 = new int[num];
				HashSet<int> hashSet = new HashSet<int>();
				for (int j = 0; j < num; j++)
				{
					array2[j] = model.Bone(ReadName(binaryReader));
					if (array2[j] < 0 || !hashSet.Add(array2[j]))
					{
						throw new InvalidDataException("Rig names");
					}
				}
				int num2 = Count(binaryReader, 300);
				for (int k = 0; k < num2; k++)
				{
					ReadName(binaryReader);
					int num3 = Count(binaryReader, 4);
					int num4 = Count(binaryReader, 300000);
					int num5 = Count(binaryReader, 900000);
					int count = list.Count;
					if (count + num4 > 400000 || num5 % 3 != 0)
					{
						throw new InvalidDataException("Mesh budget");
					}
					for (int l = 0; l < num4; l++)
					{
						list.Add(new Vector3(Float(binaryReader), Float(binaryReader), Float(binaryReader)));
						list2.Add(new Vector3(Float(binaryReader), Float(binaryReader), Float(binaryReader)));
						list3.Add(new Vector2(Float(binaryReader), Float(binaryReader)));
						int[] array3 = new int[4];
						float[] array4 = new float[4];
						float num6 = 0f;
						for (int m = 0; m < 4; m++)
						{
							int num7 = Count(binaryReader, num - 1);
							array3[m] = array2[num7];
							array4[m] = Float(binaryReader);
							if (array4[m] < 0f)
							{
								throw new InvalidDataException("Weight");
							}
							num6 += array4[m];
						}
						if (Math.Abs(num6 - 1f) > 0.01f)
						{
							throw new InvalidDataException("Weight sum");
						}
						BoneWeight item = default(BoneWeight);
						((BoneWeight)(ref item)).boneIndex0 = array3[0];
						((BoneWeight)(ref item)).boneIndex1 = array3[1];
						((BoneWeight)(ref item)).boneIndex2 = array3[2];
						((BoneWeight)(ref item)).boneIndex3 = array3[3];
						((BoneWeight)(ref item)).weight0 = array4[0];
						((BoneWeight)(ref item)).weight1 = array4[1];
						((BoneWeight)(ref item)).weight2 = array4[2];
						((BoneWeight)(ref item)).weight3 = array4[3];
						list4.Add(item);
					}
					for (int n = 0; n < num5; n++)
					{
						array[num3].Add(count + Count(binaryReader, num4 - 1));
					}
				}
			}
			Mesh = new Mesh
			{
				name = "Blender armored Eavesdropper",
				indexFormat = (IndexFormat)1
			};
			Mesh.SetVertices(list);
			Mesh.SetNormals(list2);
			Mesh.SetUVs(0, list3);
			Mesh.boneWeights = list4.ToArray();
			Matrix4x4[] array5 = (Matrix4x4[])(object)new Matrix4x4[array2.Length];
			for (int num8 = 0; num8 < array5.Length; num8++)
			{
				Vector3 position = model.Joints[num8].Position;
				array5[num8] = Matrix4x4.Translate(new Vector3(0f - position.X, 0f - position.Y, 0f - position.Z));
			}
			Mesh.bindposes = array5;
			Mesh.subMeshCount = 5;
			for (int num9 = 0; num9 < 5; num9++)
			{
				Mesh.SetTriangles(array[num9], num9);
			}
			Mesh.RecalculateBounds();
			Mesh.RecalculateTangents();
			Shader val = Shader.Find("HDRP/Lit") ?? Shader.Find("Standard");
			if ((Object)(object)val == (Object)null)
			{
				throw new InvalidDataException("Missing lit shader");
			}
			string[] names = new string[5] { "Armor", "Sinew", "EarMembrane", "Ivory", "Mouth" };
			Materials = (Material[])(object)new Material[5];
			int num10;
			for (num10 = 0; num10 < 5; num10++)
			{
				Material val2 = new Material(val)
				{
					name = "Eavesdropper " + names[num10]
				};
				Materials[num10] = val2;
				val2.SetColor("_BaseColor", (Color)((num10 == 4) ? new Color(0.012f, 0.006f, 0.007f) : Color.white));
				if (val2.HasProperty("_Color"))
				{
					val2.SetColor("_Color", (Color)((num10 == 4) ? new Color(0.012f, 0.006f, 0.007f) : Color.white));
				}
				val2.SetFloat("_Smoothness", (num10 == 0) ? 0.22f : 0.4f);
				val2.SetFloat("_DoubleSidedEnable", 1f);
				val2.SetFloat("_CullMode", 0f);
				val2.SetFloat("_CullModeForward", 0f);
				val2.EnableKeyword("_DOUBLESIDED_ON");
				if (num10 != 4)
				{
					Texture2D val3 = LoadTexture("_BaseColor", linear: false);
					val2.SetTexture("_BaseColorMap", (Texture)(object)val3);
					if (val2.HasProperty("_MainTex"))
					{
						val2.SetTexture("_MainTex", (Texture)(object)val3);
					}
					Texture2D val4 = LoadTexture("_Normal", linear: true);
					val2.SetTexture("_NormalMap", (Texture)(object)val4);
					if (val2.HasProperty("_BumpMap"))
					{
						val2.SetTexture("_BumpMap", (Texture)(object)val4);
					}
					val2.EnableKeyword("_NORMALMAP");
					val2.EnableKeyword("_NORMALMAP_TANGENT_SPACE");
					val2.SetFloat("_NormalScale", 0.45f);
					Texture2D val5 = LoadTexture("_Mask", linear: true);
					val2.SetTexture("_MaskMap", (Texture)(object)val5);
					val2.EnableKeyword("_MASKMAP");
					val2.SetFloat("_SmoothnessRemapMin", 0f);
					val2.SetFloat("_SmoothnessRemapMax", 1f);
				}
			}
			using (BinaryReader binaryReader2 = new BinaryReader(File.OpenRead(Path.Combine(folder, "eavesdropper.anim"))))
			{
				if (Encoding.ASCII.GetString(binaryReader2.ReadBytes(8)) != "EAVANIM1" || Count(binaryReader2, 100) != array2.Length)
				{
					throw new InvalidDataException("Animation rig/version");
				}
				int num11 = Count(binaryReader2, 64);
				for (int num12 = 0; num12 < num11; num12++)
				{
					string key = ReadName(binaryReader2);
					int num13 = Count(binaryReader2, 1000);
					float num14 = Float(binaryReader2);
					if (num13 < 2 || num14 < 1f || num14 > 120f)
					{
						throw new InvalidDataException("Animation rate");
					}
					Take take = new Take
					{
						Fps = num14,
						Positions = new Vector3[num13][],
						Rotations = new Quaternion[num13][]
					};
					for (int num15 = 0; num15 < num13; num15++)
					{
						take.Positions[num15] = new Vector3[array2.Length];
						take.Rotations[num15] = new Quaternion[array2.Length];
						for (int num16 = 0; num16 < array2.Length; num16++)
						{
							take.Positions[num15][array2[num16]] = new Vector3(Float(binaryReader2), Float(binaryReader2), Float(binaryReader2));
							Quaternion value = new Quaternion(Float(binaryReader2), Float(binaryReader2), Float(binaryReader2), Float(binaryReader2));
							if (value.LengthSquared() < 0.5f)
							{
								throw new InvalidDataException("Invalid joint rotation");
							}
							take.Rotations[num15][array2[num16]] = Quaternion.Normalize(value);
						}
					}
					takes.Add(key, take);
				}
			}
			if (!takes.ContainsKey("DoorBash"))
			{
				throw new InvalidDataException("Missing DoorBash clip");
			}
			string[] clips = Creature.Clips;
			foreach (string text in clips)
			{
				if (!takes.ContainsKey(text))
				{
					throw new InvalidDataException("Missing clip " + text);
				}
			}
			Texture2D LoadTexture(string suffix, bool linear)
			{
				//IL_0005: Unknown result type (might be due to invalid IL or missing references)
				//IL_000a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0023: Unknown result type (might be due to invalid IL or missing references)
				//IL_002a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0059: Expected O, but got Unknown
				//IL_0067: Expected O, but got Unknown
				Texture2D val6 = new Texture2D(2, 2, (TextureFormat)4, true, linear)
				{
					name = names[num10] + suffix,
					wrapMode = (TextureWrapMode)0
				};
				if (!ImageConversion.LoadImage(val6, File.ReadAllBytes(Path.Combine(folder, names[num10] + suffix + ".png")), true))
				{
					throw new InvalidDataException("Invalid texture");
				}
				return val6;
			}
		}

		internal void Sample(string clip, float time, Vector3[] p, Quaternion[] q)
		{
			Take take = takes[clip];
			float num = (float)(take.Positions.Length - 1) / take.Fps;
			bool flag;
			switch (clip)
			{
			case "Listen":
			case "Sprint":
			case "Wander":
			case "Dormant":
			case "Retreat":
			case "Stunned":
			case "Investigate":
			case "DoorCrawl":
				flag = true;
				break;
			default:
				flag = false;
				break;
			}
			float num2 = (flag ? Mathf.Repeat(Mathf.Max(0f, time), num) : Mathf.Clamp(time, 0f, num)) * take.Fps;
			int num3 = Mathf.Min((int)num2, take.Positions.Length - 1);
			int num4 = Mathf.Min(num3 + 1, take.Positions.Length - 1);
			float amount = num2 - (float)num3;
			for (int i = 0; i < p.Length; i++)
			{
				p[i] = Vector3.Lerp(take.Positions[num3][i], take.Positions[num4][i], amount);
				q[i] = Quaternion.Slerp(take.Rotations[num3][i], take.Rotations[num4][i], amount);
			}
		}
	}
	internal static class ConfigMenu
	{
		private static bool pending;

		private static bool oldLook;

		private static bool oldMove;

		private static bool oldSpecial;

		private static bool oldCursor;

		private static CursorLockMode oldLock;

		private static PlayerControllerB? player;

		private static Vector2 scroll;

		private static string search = "";

		private static string message = "";

		private static readonly Dictionary<ConfigEntryBase, string> drafts = new Dictionary<ConfigEntryBase, string>();

		internal static bool Open { get; private set; }

		private static bool Authority
		{
			get
			{
				if (!((Object)(object)NetworkManager.Singleton == (Object)null) && NetworkManager.Singleton.IsListening)
				{
					return NetworkManager.Singleton.IsServer;
				}
				return true;
			}
		}

		private static bool Editable(ConfigEntryBase e)
		{
			if (!Authority)
			{
				return e.Definition.Section == "Accessibility";
			}
			return true;
		}

		private static string Text(object o)
		{
			return Convert.ToString(o, CultureInfo.InvariantCulture) ?? "";
		}

		private static void Load()
		{
			drafts.Clear();
			foreach (KeyValuePair<ConfigDefinition, ConfigEntryBase> item in from p in (IEnumerable<KeyValuePair<ConfigDefinition, ConfigEntryBase>>)((BaseUnityPlugin)Plugin.Instance).Config
				orderby p.Key.Section, p.Key.Key
				select p)
			{
				drafts[item.Value] = Text(item.Value.BoxedValue);
			}
		}

		internal static void Close()
		{
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			if (Open)
			{
				Open = false;
				if ((Object)(object)player != (Object)null)
				{
					player.disableLookInput = oldLook;
					player.disableMoveInput = oldMove;
					player.inSpecialMenu = oldSpecial;
				}
				Cursor.visible = oldCursor;
				Cursor.lockState = oldLock;
				player = null;
			}
		}

		internal static void Tick()
		{
			//IL_021e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0223: Unknown result type (might be due to invalid IL or missing references)
			//IL_0237: Unknown result type (might be due to invalid IL or missing references)
			//IL_023c: Unknown result type (might be due to invalid IL or missing references)
			if (pending && !EavesdropperAI.Live.Any((EavesdropperAI e) => e.DisplayState == Mode.Attacking || e.DisplayState == Mode.Echolocating))
			{
				Configuration.BindAll(((BaseUnityPlugin)Plugin.Instance).Config, Plugin.Settings);
				foreach (EavesdropperAI item in EavesdropperAI.Live)
				{
					if ((Object)(object)((EnemyAI)item).creatureSFX != (Object)null)
					{
						((EnemyAI)item).creatureSFX.maxDistance = Mathf.Max(35f, Plugin.Settings.EchoRange + 4f);
					}
					if ((Object)(object)((EnemyAI)item).creatureVoice != (Object)null)
					{
						((EnemyAI)item).creatureVoice.maxDistance = Mathf.Max(35f, Plugin.Settings.EchoRange + 4f);
					}
				}
				pending = false;
				message = "Saved and applied. Spawn rarity requires a game restart; initial agitation affects new enemies.";
			}
			if (Open && (Object)(object)player != (Object)null && (player.isPlayerDead || (Object)(object)GameNetworkManager.Instance?.localPlayerController != (Object)(object)player))
			{
				Close();
			}
			if (Open && (Object)(object)player == (Object)null)
			{
				Keyboard current2 = Keyboard.current;
				if (current2 != null && ((ButtonControl)current2.escapeKey).wasPressedThisFrame)
				{
					Close();
					return;
				}
			}
			Keyboard current3 = Keyboard.current;
			if (current3 == null || !((ButtonControl)current3.f6Key).wasPressedThisFrame)
			{
				return;
			}
			if (Open)
			{
				Close();
				return;
			}
			PlayerControllerB val = GameNetworkManager.Instance?.localPlayerController;
			if (!((Object)(object)val != (Object)null) || (!val.isPlayerDead && !val.isTypingChat && !val.inTerminalMenu && !val.inSpecialMenu && (!((Object)(object)val.quickMenuManager != (Object)null) || !val.quickMenuManager.isMenuOpen)))
			{
				player = val;
				if ((Object)(object)val != (Object)null)
				{
					oldLook = val.disableLookInput;
					oldMove = val.disableMoveInput;
					oldSpecial = val.inSpecialMenu;
				}
				oldCursor = Cursor.visible;
				oldLock = Cursor.lockState;
				Load();
				search = "";
				scroll = Vector2.zero;
				Open = true;
				message = "Edit values, then Save & apply. Closing discards unsaved edits. The game continues while this screen is open.";
				HoldInput();
			}
		}

		internal static void HoldInput()
		{
			if (Open)
			{
				if ((Object)(object)player != (Object)null)
				{
					player.disableLookInput = true;
					player.disableMoveInput = true;
					player.inSpecialMenu = true;
				}
				Cursor.visible = true;
				Cursor.lockState = (CursorLockMode)0;
			}
		}

		private static void Save()
		{
			Dictionary<ConfigEntryBase, object> parsed = new Dictionary<ConfigEntryBase, object>();
			foreach (KeyValuePair<ConfigEntryBase, string> draft in drafts)
			{
				if (Editable(draft.Key))
				{
					if (!ConfigInput.Parse(draft.Value, draft.Key.SettingType, out object value) || (draft.Key.Description.AcceptableValues != null && !draft.Key.Description.AcceptableValues.IsValid(value)))
					{
						message = "Invalid value: " + draft.Key.Definition.Key + ". Use the displayed range and a decimal point.";
						return;
					}
					parsed[draft.Key] = value;
				}
			}
			if (Authority && !ConfigInput.Tiers(Value("AgitationInitial"), Value("AgitationIrritatedThreshold"), Value("AgitationAngryThreshold"), Value("AgitationEnragedThreshold"), Value("AgitationMaximum")))
			{
				message = "Require 0 < Irritated < Angry < Enraged < Maximum, and Initial between zero and Maximum.";
				return;
			}
			ConfigFile config = ((BaseUnityPlugin)Plugin.Instance).Config;
			bool saveOnConfigSet = config.SaveOnConfigSet;
			Dictionary<ConfigEntryBase, object> dictionary = parsed.ToDictionary<KeyValuePair<ConfigEntryBase, object>, ConfigEntryBase, object>((KeyValuePair<ConfigEntryBase, object> p) => p.Key, (KeyValuePair<ConfigEntryBase, object> p) => p.Key.BoxedValue);
			try
			{
				config.SaveOnConfigSet = false;
				foreach (KeyValuePair<ConfigEntryBase, object> item in parsed)
				{
					if (!object.Equals(item.Key.BoxedValue, item.Value))
					{
						item.Key.BoxedValue = item.Value;
					}
				}
				config.Save();
				pending = Authority;
				message = (pending ? "Saved. Gameplay changes apply when active scans and attacks finish." : "Local accessibility settings saved.");
				Load();
				Plugin.Instance.Log("F6 configuration saved; gameplay apply queued=" + pending);
			}
			catch (Exception ex)
			{
				foreach (KeyValuePair<ConfigEntryBase, object> item2 in dictionary)
				{
					item2.Key.BoxedValue = item2.Value;
				}
				message = "Could not save configuration: " + ex.Message;
				Plugin.Instance.Error(message);
			}
			finally
			{
				config.SaveOnConfigSet = saveOnConfigSet;
			}
			float Value(string name)
			{
				ConfigEntryBase val = drafts.Keys.First((ConfigEntryBase e) => e.Definition.Key == name);
				object value2;
				return Convert.ToSingle(parsed.TryGetValue(val, out value2) ? value2 : val.BoxedValue, CultureInfo.InvariantCulture);
			}
		}

		internal static void Draw()
		{
			//IL_0008: 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_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: 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_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: Unknown result type (might be due to invalid IL or missing references)
			//IL_013a: Unknown result type (might be due to invalid IL or missing references)
			//IL_048d: Unknown result type (might be due to invalid IL or missing references)
			if (!Open)
			{
				return;
			}
			Matrix4x4 matrix = GUI.matrix;
			float num = Mathf.Min(1f, Mathf.Min((float)Screen.width / 980f, (float)Screen.height / 740f));
			GUI.matrix = Matrix4x4.Scale(new Vector3(num, num, 1f));
			float num2 = (float)Screen.width / num;
			float num3 = (float)Screen.height / num;
			GUI.Box(new Rect(0f, 0f, num2, num3), "");
			GUILayout.BeginArea(new Rect((num2 - 940f) / 2f, (num3 - 700f) / 2f, 940f, 700f), GUI.skin.box);
			GUILayout.Label("THE EAVESDROPPER  /  CONFIGURATION  /  F6 or Esc to close", Array.Empty<GUILayoutOption>());
			GUILayout.Label(Authority ? "Host settings • changes affect this host's creatures" : "Client • only local accessibility is editable. Other values are this PC's saved settings, not the host's values.", Array.Empty<GUILayoutOption>());
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.Label("Search", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(55f) });
			search = GUILayout.TextField(search, Array.Empty<GUILayoutOption>());
			GUILayout.EndHorizontal();
			scroll = GUILayout.BeginScrollView(scroll, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(525f) });
			string text = "";
			ConfigEntryBase[] array = drafts.Keys.ToArray();
			foreach (ConfigEntryBase val in array)
			{
				if (search.Length <= 0 || (val.Definition.Key + " " + val.Definition.Section + " " + val.Description.Description).IndexOf(search, StringComparison.OrdinalIgnoreCase) >= 0)
				{
					if (text != val.Definition.Section)
					{
						text = val.Definition.Section;
						GUILayout.Space(10f);
						GUILayout.Label("— " + text + " —", Array.Empty<GUILayoutOption>());
					}
					bool enabled = GUI.enabled;
					GUI.enabled = Editable(val);
					GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
					GUILayout.Label(val.Definition.Key, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(330f) });
					if (val.SettingType == typeof(bool))
					{
						drafts[val] = GUILayout.Toggle(bool.TryParse(drafts[val], out var result) && result, "Enabled", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(155f) }).ToString();
					}
					else
					{
						drafts[val] = GUILayout.TextField(drafts[val], (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(155f) });
					}
					if (GUILayout.Button("Default", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(70f) }))
					{
						drafts[val] = Text(val.DefaultValue);
					}
					AcceptableValueBase acceptableValues = val.Description.AcceptableValues;
					GUILayout.Label(((acceptableValues != null) ? acceptableValues.ToDescriptionString().Replace("# ", "") : null) ?? "", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(300f) });
					GUILayout.EndHorizontal();
					GUI.enabled = enabled;
					GUILayout.Label(val.Description.Description + ((val.Definition.Key == "Rarity") ? " RESTART REQUIRED." : ((val.Definition.Key == "AgitationInitial") ? " New enemies only." : "")), Array.Empty<GUILayoutOption>());
				}
			}
			GUILayout.EndScrollView();
			GUILayout.Label(message, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(50f) });
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			if (GUILayout.Button("Save & apply", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(30f) }))
			{
				Save();
			}
			if (GUILayout.Button("Discard edits", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(30f) }))
			{
				Load();
				message = "Unsaved edits discarded.";
			}
			if (GUILayout.Button("Close", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(30f) }))
			{
				Close();
			}
			GUILayout.EndHorizontal();
			GUILayout.EndArea();
			GUI.matrix = matrix;
		}
	}
	[HarmonyPatch]
	internal static class ConfigInputGuard
	{
		private static IEnumerable<MethodBase> TargetMethods()
		{
			return from m in typeof(PlayerControllerB).GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
				where m.Name.EndsWith("_performed", StringComparison.Ordinal) && m.GetParameters().Length == 1 && m.GetParameters()[0].ParameterType == typeof(CallbackContext)
				select m;
		}

		private static bool Prefix(PlayerControllerB __instance, MethodBase __originalMethod)
		{
			if (!ConfigMenu.Open || (Object)(object)GameNetworkManager.Instance?.localPlayerController != (Object)(object)__instance)
			{
				return true;
			}
			if (__originalMethod.Name == "OpenMenu_performed")
			{
				ConfigMenu.Close();
			}
			return false;
		}
	}
	internal static class Configuration
	{
		private static readonly HashSet<string> retired = new HashSet<string>
		{
			"FixationWarning", "NoiseHuntSeconds", "NoiseAgitationThreshold", "AgitationDecay", "DoorLungeSeconds", "EchoMotionThreshold", "EchoHuntSeconds", "EchoInterval", "LoudNoisesToHunt", "DistractionLock",
			"ListenSeconds"
		};

		internal static void BindAll(ConfigFile file, Settings values)
		{
			//IL_0450: Unknown result type (might be due to invalid IL or missing references)
			//IL_045a: Expected O, but got Unknown
			//IL_05fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0607: Expected O, but got Unknown
			FieldInfo[] fields = typeof(Settings).GetFields(BindingFlags.Instance | BindingFlags.Public);
			foreach (FieldInfo fieldInfo in fields)
			{
				if (retired.Contains(fieldInfo.Name))
				{
					continue;
				}
				string text = ((fieldInfo.Name == "Damage") ? "Combat" : "Tuning");
				string text2 = ((fieldInfo.Name == "EchoIntervalStirred") ? "EchoInterval" : fieldInfo.Name);
				string text3;
				switch (fieldInfo.Name)
				{
				case "NoiseRange":
					text3 = "Maximum ordinary hearing radius in metres (HearingRadius).";
					break;
				case "VoiceRange":
					text3 = "Speech hearing range in metres, capped by NoiseRange (VoiceDetectionRange).";
					break;
				case "ObstructionMultiplier":
					text3 = "Ordinary hearing attenuation per obstruction (OccludedHearingMultiplier).";
					break;
				case "FixationSeconds":
					text3 = "Listening window in seconds (FixationWindowSeconds); any audible speaker may confirm pursuit.";
					break;
				case "CompactPursuitSpeed":
					text3 = "Maximum folded/crawling pursuit speed in meters per second. Tight turns still slow movement. Default 6.5; existing RushSpeed remains the upper limit.";
					break;
				case "EchoDoorMultiplier":
					text3 = "Range multiplier through an open doorway (EchoDoorwayRangeMultiplier).";
					break;
				case "EchoMovementThreshold":
					text3 = "Body displacement in metres between chirps, not speed or camera rotation.";
					break;
				case "AttackWarning":
					text3 = "Stationary attack telegraph duration in seconds before a direction-locked leap.";
					break;
				case "EchoIntervalIrritated":
				case "EchoIntervalEnraged":
				case "EchoIntervalStirred":
				case "EchoIntervalAngry":
					text3 = "Minimum seconds between sound-led scans at this agitation tier. A fresh heard lead and arrival are required; this does not schedule periodic scans.";
					break;
				default:
					text3 = (fieldInfo.Name.Contains("Multiplier") ? "Dimensionless tier/baseline multiplier." : ((fieldInfo.Name.Contains("Range") || fieldInfo.Name == "HallwayCommitDistance") ? "Metres." : (fieldInfo.Name.Contains("Speed") ? "Metres per second." : ((fieldInfo.Name.Contains("Seconds") || fieldInfo.Name.Contains("Interval") || fieldInfo.Name == "DistractionCooldown" || fieldInfo.Name == "PathTimeout") ? "Seconds." : ((fieldInfo.Name.Contains("PerSecond") || fieldInfo.Name.Contains("PerVoiceSecond") || fieldInfo.Name.Contains("PerNoiseSecond")) ? "Agitation points per audible second." : (fieldInfo.Name.StartsWith("Agitation") ? "Agitation points; ordinary gains scale with audibility." : "Host-authoritative behavior tuning; see docs/CONFIGURATION.md."))))));
					break;
				}
				string text4 = text3;
				if (fieldInfo.FieldType == typeof(bool))
				{
					fieldInfo.SetValue(values, file.Bind<bool>(text, text2, (bool)fieldInfo.GetValue(values), text4).Value);
				}
				else if (fieldInfo.FieldType == typeof(int))
				{
					int num = ((fieldInfo.Name == "Damage") ? 100 : 10);
					fieldInfo.SetValue(values, file.Bind<int>(text, text2, (int)fieldInfo.GetValue(values), new ConfigDescription(text4, (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, num), Array.Empty<object>())).Value);
				}
				else if (!(fieldInfo.FieldType != typeof(float)))
				{
					float num2 = 0f;
					float num3 = 10000f;
					if (fieldInfo.Name.Contains("Seconds") || fieldInfo.Name.Contains("Interval") || fieldInfo.Name == "AttackWarning" || fieldInfo.Name == "LungeSeconds" || fieldInfo.Name == "PathTimeout" || fieldInfo.Name == "DistractionCooldown")
					{
						num2 = 0.05f;
					}
					if (fieldInfo.Name.Contains("Range") || fieldInfo.Name.Contains("Speed"))
					{
						num2 = 0.1f;
						num3 = 80f;
					}
					if (fieldInfo.Name.Contains("Multiplier"))
					{
						num2 = 0.05f;
						num3 = ((fieldInfo.Name.Contains("Obstruction") || fieldInfo.Name.Contains("Door")) ? 1 : 3);
					}
					if (fieldInfo.Name == "AgitationMaximum")
					{
						num2 = 1f;
					}
					if (fieldInfo.Name == "EchoMovementThreshold")
					{
						num2 = 0.01f;
						num3 = 2f;
					}
					if (fieldInfo.Name == "EchoWarningSeconds")
					{
						num2 = 0.2f;
						num3 = 5f;
					}
					float num4 = (float)fieldInfo.GetValue(values);
					float num5 = file.Bind<float>(text, text2, num4, new ConfigDescription(text4, (AcceptableValueBase)(object)new AcceptableValueRange<float>(num2, num3), Array.Empty<object>())).Value;
					if (!float.IsFinite(num5))
					{
						Plugin.Instance.Error($"Non-finite {text2}; using default {num4} for this session.");
						num5 = num4;
					}
					fieldInfo.SetValue(values, num5);
				}
			}
			float agitationMaximum = values.AgitationMaximum;
			if (!(values.AgitationIrritatedThreshold > 0f) || !(values.AgitationIrritatedThreshold < values.AgitationAngryThreshold) || !(values.AgitationAngryThreshold < values.AgitationEnragedThreshold) || !(values.AgitationEnragedThreshold < agitationMaximum))
			{
				Plugin.Instance.Error("Agitation tier thresholds must be ascending and below AgitationMaximum. Using 20%, 45%, 75% of maximum for this session; saved entries unchanged.");
				values.AgitationIrritatedThreshold = agitationMaximum * 0.2f;
				values.AgitationAngryThreshold = agitationMaximum * 0.45f;
				values.AgitationEnragedThreshold = agitationMaximum * 0.75f;
			}
			values.AgitationInitial = Math.Clamp(values.AgitationInitial, 0f, agitationMaximum);
		}
	}
	public sealed class CreatureRig : MonoBehaviour
	{
		internal static readonly Creature Model = new Creature();

		private static AdvancedVisual? advanced;

		private static bool checkedAsset;

		public Transform[] joints = Array.Empty<Transform>();

		private readonly Vector3[] positions = new Vector3[Model.Joints.Count];

		private readonly Quaternion[] rotations = new Quaternion[Model.Joints.Count];

		internal static GameObject Build(Transform parent)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Expected O, but got Unknown
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Expected O, but got Unknown
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Expected O, but got Unknown
			//IL_014f: 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_015f: Unknown result type (might be due to invalid IL or missing references)
			//IL_017f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0181: 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_01c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0268: Unknown result type (might be due to invalid IL or missing references)
			//IL_027c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0281: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0307: Unknown result type (might be due to invalid IL or missing references)
			//IL_030c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0325: Unknown result type (might be due to invalid IL or missing references)
			//IL_032c: Expected O, but got Unknown
			//IL_0363: Unknown result type (might be due to invalid IL or missing references)
			//IL_0386: Unknown result type (might be due to invalid IL or missing references)
			//IL_046b: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("EavesdropperVisual");
			val.transform.SetParent(parent, false);
			CreatureRig creatureRig = val.AddComponent<CreatureRig>();
			creatureRig.joints = (Transform[])(object)new Transform[Model.Joints.Count];
			for (int i = 0; i < creatureRig.joints.Length; i++)
			{
				Joint joint = Model.Joints[i];
				GameObject val2 = new GameObject(joint.Name);
				val2.transform.SetParent((Transform)((joint.Parent < 0) ? ((object)val.transform) : ((object)creatureRig.joints[joint.Parent])), false);
				val2.transform.localPosition = V(joint.Position - ((joint.Parent < 0) ? Vector3.Zero : Model.Joints[joint.Parent].Position));
				creatureRig.joints[i] = val2.transform;
			}
			Mesh val3 = new Mesh
			{
				name = "Eavesdropper sinew crawler — original skinned mesh"
			};
			Vector3[] array = (Vector3[])(object)new Vector3[Model.Vertices.Count];
			BoneWeight[] array2 = (BoneWeight[])(object)new BoneWeight[array.Length];
			for (int j = 0; j < array.Length; j++)
			{
				Vertex vertex = Model.Vertices[j];
				array[j] = V(vertex.Position);
				int num = j;
				BoneWeight val4 = default(BoneWeight);
				((BoneWeight)(ref val4)).boneIndex0 = vertex.Joint;
				((BoneWeight)(ref val4)).weight0 = 1f;
				array2[num] = val4;
			}
			Matrix4x4[] array3 = (Matrix4x4[])(object)new Matrix4x4[creatureRig.joints.Length];
			for (int k = 0; k < array3.Length; k++)
			{
				array3[k] = Matrix4x4.Translate(-V(Model.Joints[k].Position));
			}
			val3.vertices = array;
			val3.boneWeights = array2;
			val3.bindposes = array3;
			val3.subMeshCount = 3;
			for (int l = 0; l < 3; l++)
			{
				val3.SetTriangles(Model.Triangles[l], l);
			}
			val3.RecalculateNormals();
			val3.RecalculateBounds();
			SkinnedMeshRenderer val5 = val.AddComponent<SkinnedMeshRenderer>();
			val5.sharedMesh = val3;
			val5.bones = creatureRig.joints;
			val5.rootBone = creatureRig.joints[0];
			val5.updateWhenOffscreen = true;
			((Renderer)val5).localBounds = new Bounds(Vector3.up, new Vector3(7f, 6f, 7f));
			Shader val6 = Shader.Find("HDRP/Lit") ?? Shader.Find("Standard");
			if ((Object)(object)val6 == (Object)null)
			{
				throw new InvalidOperationException("HDRP/Lit shader unavailable; supply the documented art bundle.");
			}
			Color[] array4 = (Color[])(object)new Color[3]
			{
				new Color(0.095f, 0.105f, 0.11f),
				new Color(0.012f, 0.004f, 0.004f),
				new Color(0.39f, 0.34f, 0.25f)
			};
			Material[] array5 = (Material[])(object)new Material[3];
			for (int m = 0; m < 3; m++)
			{
				Material val7 = new Material(val6);
				((Object)val7).name = (new string[3] { "Charred sinew", "Facial cavity", "Worn claws" })[m];
				Material val8 = val7;
				val8.SetColor("_BaseColor", array4[m]);
				if (val8.HasProperty("_Color"))
				{
					val8.SetColor("_Color", array4[m]);
				}
				if (val8.HasProperty("_Smoothness"))
				{
					val8.SetFloat("_Smoothness", (m == 0) ? 0.25f : 0.3f);
				}
				if (val8.HasProperty("_Metallic"))
				{
					val8.SetFloat("_Metallic", 0f);
				}
				array5[m] = val8;
			}
			((Renderer)val5).sharedMaterials = array5;
			if (!checkedAsset)
			{
				checkedAsset = true;
				advanced = AdvancedVisual.Load();
			}
			if (advanced != null)
			{
				val5.sharedMesh = advanced.Mesh;
				((Renderer)val5).sharedMaterials = advanced.Materials;
				val5.quality = (SkinQuality)4;
				Object.Destroy((Object)(object)val3);
				Material[] array6 = array5;
				for (int n = 0; n < array6.Length; n++)
				{
					Object.Destroy((Object)(object)array6[n]);
				}
			}
			new GameObject("FacialSlit").transform.SetParent(val.transform, false);
			creatureRig.Apply("Dormant", 0f, instant: true);
			return val;
		}

		internal void Apply(string clip, float time, bool instant = false, float lookYaw = 0f, float agitation = 0f, float pulse = 0f)
		{
			//IL_00ac: 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_00bc: 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_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: 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_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_011b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0229: Unknown result type (might be due to invalid IL or missing references)
			//IL_023b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0241: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0137: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0159: Unknown result type (might be due to invalid IL or missing references)
			//IL_0170: Unknown result type (might be due to invalid IL or missing references)
			//IL_0174: Unknown result type (might be due to invalid IL or missing references)
			//IL_0190: Unknown result type (might be due to invalid IL or missing references)
			//IL_0195: Unknown result type (might be due to invalid IL or missing references)
			//IL_019a: Unknown result type (might be due to invalid IL or missing references)
			//IL_019f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0354: Unknown result type (might be due to invalid IL or missing references)
			//IL_0359: Unknown result type (might be due to invalid IL or missing references)
			//IL_035c: Unknown result type (might be due to invalid IL or missing references)
			//IL_032f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0334: Unknown result type (might be due to invalid IL or missing references)
			//IL_0339: Unknown result type (might be due to invalid IL or missing references)
			//IL_033b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0340: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0302: Unknown result type (might be due to invalid IL or missing references)
			//IL_0304: Unknown result type (might be due to invalid IL or missing references)
			//IL_0309: Unknown result type (might be due to invalid IL or missing references)
			Model.Pose((clip == "DoorBash") ? "DoorWarn" : clip, time, positions, rotations, agitation);
			if (advanced != null)
			{
				advanced.Sample(clip, time, positions, rotations);
			}
			if (!instant && (Object)(object)StartOfRound.Instance != (Object)null)
			{
				string[] array = new string[2] { "L", "R" };
				RaycastHit val5 = default(RaycastHit);
				foreach (string text in array)
				{
					Vector3 val = ((Component)this).transform.TransformPoint(V(Model.JointPosition("Hand" + text, positions, rotations)));
					Vector3 val2 = ((Component)this).transform.position + Vector3.up;
					Vector3 val3 = val + ((Component)this).transform.forward * 0.55f;
					val3.y = Mathf.Max(val3.y, ((Component)this).transform.position.y + 0.25f);
					Vector3 val4 = val3 - val2;
					if (((Vector3)(ref val4)).sqrMagnitude > 0.01f && Physics.SphereCast(val2, 0.18f, ((Vector3)(ref val4)).normalized, ref val5, ((Vector3)(ref val4)).magnitude, StartOfRound.Instance.collidersAndRoomMaskAndDefault, (QueryTriggerInteraction)1) && ((RaycastHit)(ref val5)).normal.y < 0.6f)
					{
						Vector3 val6 = ((Component)this).transform.InverseTransformPoint(val2 + ((Vector3)(ref val4)).normalized * Mathf.Max(0.05f, ((RaycastHit)(ref val5)).distance - 0.65f));
						Model.RefitHand(text, new Vector3(val6.x, val6.y, val6.z), positions, rotations);
					}
				}
			}
			float num = (instant ? 1f : (1f - Mathf.Exp((float)(-((clip == "Dormant") ? 3 : 14)) * Time.deltaTime)));
			Quaternion val7 = default(Quaternion);
			for (int j = 0; j < joints.Length; j++)
			{
				joints[j].localPosition = Vector3.Lerp(joints[j].localPosition, V(positions[j]), num);
				Quaternion quaternion = rotations[j];
				((Quaternion)(ref val7))..ctor(quaternion.X, quaternion.Y, quaternion.Z, quaternion.W);
				if (Model.Joints[j].Name == "Chest")
				{
					val7 = Quaternion.AngleAxis(pulse * 6f, Vector3.right) * val7;
				}
				if (advanced != null && Model.Joints[j].Name == "Chest")
				{
					val7 = Quaternion.AngleAxis(agitation * (2f + Mathf.Sin(time * 9f)), Vector3.right) * val7;
				}
				if (Model.Joints[j].Name == "Head")
				{
					val7 = Quaternion.AngleAxis(lookYaw, Vector3.up) * val7;
				}
				joints[j].localRotation = Quaternion.Slerp(joints[j].localRotation, val7, num);
			}
		}

		private static Vector3 V(Vector3 p)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			return new Vector3(p.X, p.Y, p.Z);
		}
	}
	public sealed class EavesdropperAI : EnemyAI, IWorld
	{
		private sealed class EchoObject
		{
			public Transform Transform;

			public PlayerControllerB? Player;

			public GrabbableObject? Item;

			public Point First;

			public float Exposure;

			public bool Covered;
		}

		private DoorLock? doorApproach;

		private bool suppressDoorNoise;

		private Vector3 afterDoorGoal;

		private float doorDeadline;

		private float doorStarted;

		private bool doorOpened;

		private float nextAlternative;

		internal static readonly HashSet<EavesdropperAI> Live = new HashSet<EavesdropperAI>();

		internal Brain Brain;

		internal Mode DisplayState;

		internal ulong DisplayTarget = ulong.MaxValue;

		internal float DisplayHunt;

		internal float DisplayWarning;

		internal bool DisplayRecovering;

		internal bool DisplayCrawling;

		internal bool DisplayDoorLunge;

		internal bool DisplayDoorBash;

		internal float DisplayDoorPhase;

		private float nextBestiaryRepair;

		internal float DisplayPhase;

		internal float DisplayAgitation;

		internal float MotionPhase;

		internal float DisplaySpeed;

		internal float EchoHeadYaw;

		internal float PulseFlashUntil;

		internal string NavigationStatus = "Waiting";

		internal float HeardLevel;

		internal bool HeardVoice;

		internal readonly Dictionary<ulong, (float Level, bool Audible)> VoiceReadings = new Dictionary<ulong, (float, bool)>();

		private DoorLock[] doors = Array.Empty<DoorLock>();

		private float nextDoors;

		internal uint SnapshotSequence;

		internal uint LastSnapshot;

		internal uint LastDamage;

		internal Vector3 RemotePosition;

		internal Quaternion RemoteRotation;

		internal bool ReceivedSnapshot;

		internal bool HasBeenAwake;

		private float nextClientPath;

		private Vector3 clientCorner;

		private bool clientDetour;

		public Transform visualRoot;

		public Transform facialSlit;

		public AudioClip rustle;

		public AudioClip fixation;

		public AudioClip inhale;

		public AudioClip echoClick;

		public AudioClip echoPulse;

		internal uint HitSequence;

		public Animator? presentationAnimator;

		internal bool AnimatorHasAgitation;

		public CapsuleCollider bodyCollider;

		private float nextBehaviorLog;

		private Mode loggedMode;

		private float loggedAgitation = -1f;

		private float nextSnapshot;

		private float pathStarted;

		private float stuckSince;

		private Vector3 progressPosition;

		private bool started;

		private bool moving;

		private bool movementBlocked;

		private readonly NavMeshPath navPath = new NavMeshPath();

		private readonly Collider[] attackColliders = (Collider[])(object)new Collider[32];

		private readonly SoundEventGate soundEvents = new SoundEventGate();

		private readonly RaycastHit[] hearingHits = (RaycastHit[])(object)new RaycastHit[16];

		private readonly List<EchoObject> echoObjects = new List<EchoObject>();

		private readonly StationaryEvidence stationary = new StationaryEvidence();

		private bool finishingEcho;

		private readonly RaycastHit[] movementHits = (RaycastHit[])(object)new RaycastHit[24];

		private readonly FailedRoutes failedRoutes = new FailedRoutes();

		private readonly NavMeshPath legPath = new NavMeshPath();

		private readonly List<Point> perceivedThreats = new List<Point>();

		private readonly List<Point> routePoints = new List<Point>();

		private readonly Dictionary<ulong, (Point Position, float Time)> soundMemory = new Dictionary<ulong, (Point, float)>();

		private Vector3 travelGoal;

		private Vector3[] plannedCorners = Array.Empty<Vector3>();

		private Vector3[] travelCorners = Array.Empty<Vector3>();

		private int travelCorner;

		private float requestedSpeed;

		private float nextRepath;

		private float blockedFor;

		private float foldedUntil;

		private float nextClearance;

		private float nextDetour;

		private float nextRecovery;

		private float routeDeadline;

		private int recoveries;

		private Vector3 Ear => ((Component)this).transform.position + Vector3.up * 1.5f;

		Point IWorld.Position => P(((Component)this).transform.position);

		private int RoomMask => StartOfRound.Instance.collidersAndRoomMaskAndDefault;

		bool IWorld.Arrived
		{
			get
			{
				if ((Object)(object)doorApproach == (Object)null && !DisplayDoorBash && moving && travelCorner >= travelCorners.Length - 1 && !base.agent.pathPending)
				{
					return base.agent.remainingDistance <= 0.65f;
				}
				return false;
			}
		}

		bool IWorld.PathFailed
		{
			get
			{
				//IL_003d: 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_006b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0070: 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)
				if ((Object)(object)doorApproach != (Object)null || DisplayDoorBash)
				{
					return false;
				}
				if (!((Behaviour)base.agent).enabled || !base.agent.isOnNavMesh || movementBlocked)
				{
					return true;
				}
				if (Vector3.Distance(progressPosition, ((Component)this).transform.position) > 0.2f)
				{
					stuckSince = Time.time;
					progressPosition = ((Component)this).transform.position;
				}
				if (moving && ((!base.agent.pathPending && (int)base.agent.pathStatus != 0) || Time.time - stuckSince > 1.2f || Time.time > routeDeadline))
				{
					if (Time.time <= routeDeadline && RecoverRoute())
					{
						return false;
					}
					FailRoute("No travel progress after bounded recovery");
					return true;
				}
				return false;
			}
		}

		private bool TryAlternateRoute(Vector3 desired, out Vector3 endpoint)
		{
			//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)
			//IL_000e: 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_0068: 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_00bb: 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_00d6: 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_00f9: 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)
			//IL_012c: 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_0165: Unknown result type (might be due to invalid IL or missing references)
			//IL_0194: Unknown result type (might be due to invalid IL or missing references)
			//IL_0196: Unknown result type (might be due to invalid IL or missing references)
			endpoint = default(Vector3);
			if (Time.time < nextAlternative || base.allAINodes == null)
			{
				return false;
			}
			nextAlternative = Time.time + 1.5f;
			List<Vector3> list = new List<Vector3>();
			GameObject[] allAINodes = base.allAINodes;
			foreach (GameObject val in allAINodes)
			{
				if ((Object)(object)val != (Object)null)
				{
					list.Add(val.transform.position);
				}
			}
			Vector3 start = ((Component)this).transform.position;
			list.Sort((Vector3 a, Vector3 b) => (Vector3.Distance(start, a) + Vector3.Distance(a, desired)).CompareTo(Vector3.Distance(start, b) + Vector3.Distance(b, desired)));
			float num = float.PositiveInfinity;
			Vector3[] array = null;
			for (int num2 = 0; num2 < Math.Min(12, list.Count); num2++)
			{
				Vector3 val2 = list[num2];
				if (Vector3.Distance(start, val2) < 2f || !TryPathFrom(start, val2, navPath, out var endpoint2))
				{
					continue;
				}
				Vector3[] collection = plannedCorners;
				if (TryPathFrom(endpoint2, desired, legPath, out var endpoint3))
				{
					List<Vector3> list2 = new List<Vector3>(collection);
					for (int num3 = 1; num3 < plannedCorners.Length; num3++)
					{
						list2.Add(plannedCorners[num3]);
					}
					float num4 = 0f;
					for (int num5 = 1; num5 < list2.Count; num5++)
					{
						num4 += Vector3.Distance(list2[num5 - 1], list2[num5]);
					}
					if (num4 < num)
					{
						num = num4;
						array = list2.ToArray();
						endpoint = endpoint3;
					}
				}
			}
			if (array == null)
			{
				return false;
			}
			plannedCorners = array;
			NavigationStatus = "Following reachable route via adjoining rooms";
			return true;
		}

		private bool TryApproachDoor(Vector3 desired, float speed)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Expected O, but got Unknown
			//IL_002a: 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_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: 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_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_017a: 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)
			//IL_019c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c5: 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_01cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_022a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0237: Unknown result type (might be due to invalid IL or missing references)
			NavMeshHit val = default(NavMeshHit);
			if (!NavMesh.SamplePosition(desired, ref val, 3.5f, base.agent.areaMask))
			{
				return false;
			}
			NavMeshPath val2 = new NavMeshPath();
			if (!base.agent.CalculatePath(((NavMeshHit)(ref val)).position, val2) || val2.corners.Length == 0)
			{
				return false;
			}
			Vector3 val3 = val2.corners[val2.corners.Length - 1];
			DoorLock val4 = null;
			Vector3[] array = null;
			float num = float.PositiveInfinity;
			int num2 = 0;
			DoorLock[] array2 = doors;
			foreach (DoorLock val5 in array2)
			{
				if ((Object)(object)val5 == (Object)null || val5.isLocked)
				{
					continue;
				}
				NavMeshObstacle component = ((Component)val5).GetComponent<NavMeshObstacle>();
				if ((Object)(object)component == (Object)null || !((Behaviour)component).enabled)
				{
					continue;
				}
				bool flag = Vector3.Distance(val3, ((Component)val5).transform.position) < 3.5f;
				for (int j = 1; j < val2.corners.Length; j++)
				{
					if (flag)
					{
						break;
					}
					flag = NavigationPolicy.SegmentDistance(P(((Component)val5).transform.position), P(val2.corners[j - 1]), P(val2.corners[j])) < 1.5f;
				}
				if (!flag || num2++ >= 8 || (Object)(object)((Component)val5).GetComponent<AnimatedObjectTrigger>() == (Object)null)
				{
					continue;
				}
				for (int k = 0; k < 8; k++)
				{
					float num3 = (float)k * MathF.PI / 4f;
					Vector3 desired2 = ((Component)val5).transform.position + new Vector3(Mathf.Cos(num3), 0f, Mathf.Sin(num3)) * 1.6f;
					if (!TryPath(desired2, navPath, out var endpoint))
					{
						continue;
					}
					Vector3 step = ((Component)val5).transform.position - endpoint;
					step.y = 0f;
					if (!BodyHit(endpoint, step, out var nearest, compact: true) || (!((Object)(object)((RaycastHit)(ref nearest)).collider == (Object)null) && !((Object)(object)((Component)((RaycastHit)(ref nearest)).collider).GetComponentInParent<DoorLock>() != (Object)(object)val5)))
					{
						float num4 = 0f;
						for (int l = 1; l < plannedCorners.Length; l++)
						{
							num4 += Vector3.Distance(plannedCorners[l - 1], plannedCorners[l]);
						}
						if (num4 < num)
						{
							num = num4;
							val4 = val5;
							array = plannedCorners;
						}
					}
				}
			}
			if ((Object)(object)val4 == (Object)null || array == null)
			{
				return false;
			}
			doorApproach = val4;
			afterDoorGoal = desired;
			requestedSpeed = speed;
			travelCorners = array;
			travelCorner = 1;
			travelGoal = array[^1];
			base.agent.isStopped = false;
			base.agent.speed = Mathf.Min(speed, 4f);
			moving = SetLeg();
			movementBlocked = false;
			blockedFor = 0f;
			doorDeadline = Time.time + Mathf.Max(10f, num / Mathf.Max(1f, base.agent.speed) * 2f + 5f);
			doorStarted = -1f;
			doorOpened = false;
			if (!moving)
			{
				doorApproach = null;
				return false;
			}
			NavigationStatus = "Approaching closed ordinary door on route to sound";
			return true;
		}

		private bool UpdateDoorInteraction()
		{
			//IL_01a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: 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_00c2: 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_00d2: 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_00eb: 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_0229: Unknown result type (might be due to invalid IL or missing references)
			//IL_022e: Unknown result type (might be due to invalid IL or missing references)
			//IL_024e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0143: 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_0162: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)doorApproach == (Object)null)
			{
				return false;
			}
			Mode state = Brain.State;
			bool flag = ((state == Mode.Dormant || state - 6 <= Mode.Fixated) ? true : false);
			if (flag || base.stunNormalizedTimer > 0f || base.stunnedIndefinitely > 0 || Time.time > doorDeadline)
			{
				doorApproach = null;
				DisplayDoorBash = false;
				FailRoute("Door interaction interrupted or timed out");
				return false;
			}
			DoorLock val = doorApproach;
			if (val.isLocked)
			{
				FailRoute("Door became locked");
				return false;
			}
			if (doorStarted < 0f)
			{
				if (Vector3.Distance(((Component)this).transform.position, ((Component)val).transform.position) > 2.3f)
				{
					return false;
				}
				Vector3 val2 = ((Component)val).transform.position - ((Component)this).transform.position;
				val2.y = 0f;
				if (BodyHit(((Component)this).transform.position, val2, out var nearest, compact: true) && ((Object)(object)((RaycastHit)(ref nearest)).collider == (Object)null || (Object)(object)((Component)((RaycastHit)(ref nearest)).collider).GetComponentInParent<DoorLock>() != (Object)(object)val))
				{
					return false;
				}
				doorStarted = Time.time;
				base.agent.isStopped = true;
				base.agent.nextPosition = ((Component)this).transform.position;
				if (((Vector3)(ref val2)).sqrMagnitude > 0.01f)
				{
					((Component)this).transform.rotation = Quaternion.LookRotation(val2);
				}
			}
			DisplayDoorBash = true;
			DisplayDoorPhase = Time.time - doorStarted;
			DisplaySpeed = 0f;
			DisplayCrawling = true;
			base.agent.nextPosition = ((Component)this).transform.position;
			stuckSince = Time.time;
			if (!doorOpened && DisplayDoorPhase >= 0.5f)
			{
				doorOpened = true;
				NavMeshObstacle component = ((Component)val).GetComponent<NavMeshObstacle>();
				if ((Object)(object)component != (Object)null && ((Behaviour)component).enabled)
				{
					suppressDoorNoise = true;
					try
					{
						((Component)val).GetComponent<AnimatedObjectTrigger>().TriggerAnimationNonPlayer(true, true, false);
					}
					finally
					{
						suppressDoorNoise = false;
					}
					val.OpenDoorAsEnemy(true);
					val.OpenDoorAsEnemyClientRpc();
				}
			}
			if (DisplayDoorPhase >= 1.2f)
			{
				Vector3 v = afterDoorGoal;
				float speed = requestedSpeed;
				doorApproach = null;
				DisplayDoorBash = false;
				moving = false;
				if (!((IWorld)this).Move(P(v), speed))
				{
					movementBlocked = true;
				}
			}
			return true;
		}

		public override void Awake()
		{
		}

		public override void Start()
		{
			//IL_01ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b0: 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_01c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0162: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Invalid comparison between Unknown and I4
			if (!((NetworkBehaviour)this).IsSpawned || (Object)(object)RoundManager.Instance == (Object)null)
			{
				return;
			}
			((EnemyAI)this).Awake();
			((EnemyAI)this).Start();
			base.movingTowardsTargetPlayer = false;
			base.moveTowardsDestination = false;
			started = true;
			Live.Add(this);
			if ((Object)(object)presentationAnimator != (Object)null)
			{
				AnimatorControllerParameter[] parameters = presentationAnimator.parameters;
				foreach (AnimatorControllerParameter val in parameters)
				{
					if (val.name == "Agitation" && (int)val.type == 1)
					{
						AnimatorHasAgitation = true;
					}
				}
			}
			Brain = new Brain(Plugin.Settings, this);
			((Behaviour)base.agent).enabled = ((NetworkBehaviour)this).IsServer;
			base.agent.updatePosition = false;
			base.agent.updateRotation = false;
			base.agent.radius = 0.55f;
			base.agent.autoBraking = true;
			base.agent.autoRepath = true;
			base.agent.stoppingDistance = 0.08f;
			base.agent.obstacleAvoidanceType = (ObstacleAvoidanceType)4;
			base.ventAnimationFinished = true;
			base.postStunInvincibilityTimer = -1f;
			NavMeshHit val2 = default(NavMeshHit);
			if (((NetworkBehaviour)this).IsServer && !base.agent.isOnNavMesh && NavMesh.SamplePosition(((Component)this).transform.position, ref val2, 3f, base.agent.areaMask))
			{
				base.agent.Warp(((NavMeshHit)(ref val2)).position);
			}
			if (((NetworkBehaviour)this).IsServer && !base.agent.isOnNavMesh)
			{
				Plugin.Instance.Log("Eavesdropper spawn had no nearby NavMesh; despawning safely.");
				((NetworkBehaviour)this).NetworkObject.Despawn(true);
				return;
			}
			RepairBestiary();
			RemotePosition = ((Component)this).transform.position;
			RemoteRotation = ((Component)this).transform.rotation;
			progressPosition = ((Component)this).transform.position;
			stuckSince = Time.time;
			if (((NetworkBehaviour)this).IsServer)
			{
				((IWorld)this).Stop();
			}
		}

		public override void Update()
		{
			//IL_030d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0313: Unknown result type (might be due to invalid IL or missing references)
			//IL_032e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0333: Unknown result type (might be due to invalid IL or missing references)
			//IL_033b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0340: Unknown result type (might be due to invalid IL or missing references)
			//IL_0347: Unknown result type (might be due to invalid IL or missing references)
			//IL_034c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0361: Unknown result type (might be due to invalid IL or missing references)
			//IL_0391: Unknown result type (might be due to invalid IL or missing references)
			//IL_0397: Unknown result type (might be due to invalid IL or missing references)
			//IL_0462: Unknown result type (might be due to invalid IL or missing references)
			//IL_0468: Unknown result type (might be due to invalid IL or missing references)
			//IL_0483: Unknown result type (might be due to invalid IL or missing references)
			//IL_0553: Unknown result type (might be due to invalid IL or missing references)
			//IL_0569: Unknown result type (might be due to invalid IL or missing references)
			//IL_03fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0402: Unknown result type (might be due to invalid IL or missing references)
			//IL_041d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0422: Unknown result type (might be due to invalid IL or missing references)
			//IL_042a: Unknown result type (might be due to invalid IL or missing references)
			//IL_042f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0436: Unknown result type (might be due to invalid IL or missing references)
			//IL_043b: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0450: Unknown result type (might be due to invalid IL or missing references)
			//IL_03e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_03e9: Unknown result type (might be due to invalid IL or missing references)
			if (!started || !((NetworkBehaviour)this).IsSpawned)
			{
				return;
			}
			if (Time.time >= nextBestiaryRepair)
			{
				nextBestiaryRepair = Time.time + 2f;
				RepairBestiary();
			}
			if (((NetworkBehaviour)this).IsServer)
			{
				StartOfRound instance = StartOfRound.Instance;
				if ((Object)(object)instance != (Object)null && RoundLifetime.ShouldDespawn(((NetworkBehaviour)this).IsServer, ((NetworkBehaviour)this).IsSpawned, instance.shipIsLeaving, instance.inShipPhase, instance.allPlayersDead))
				{
					((IWorld)this).Stop();
					SessionWire.Forget(((NetworkBehaviour)this).NetworkObjectId);
					((NetworkBehaviour)this).NetworkObject.Despawn(true);
					return;
				}
				if (Time.time >= nextDoors)
				{
					doors = Object.FindObjectsOfType<DoorLock>();
					nextDoors = Time.time + 5f;
				}
				UpdateClearance();
				if (!UpdateDoorInteraction())
				{
					ApplyAgentMovement();
				}
				if (base.stunnedIndefinitely <= 0)
				{
					base.stunNormalizedTimer -= Time.deltaTime / Math.Max(0.01f, base.enemyType.stunTimeMultiplier);
				}
				if (base.stunNormalizedTimer < 0f)
				{
					base.postStunInvincibilityTimer -= Time.deltaTime * 5f;
				}
				if (base.stunnedIndefinitely > 0 && !SessionWire.Valid(base.stunnedByPlayer))
				{
					base.stunnedIndefinitely = 0;
				}
				Brain.Tick(Time.deltaTime, base.stunNormalizedTimer > 0f || base.stunnedIndefinitely > 0);
				CopyDisplay();
				if (Time.time >= nextBehaviorLog)
				{
					nextBehaviorLog = Time.time + 1f;
					if (Plugin.Settings.DebugBehaviorLogging && loggedMode != Brain.State)
					{
						Plugin.Instance.Log($"Enemy {((NetworkBehaviour)this).NetworkObjectId}: {loggedMode} -> {Brain.State}, confidence={Brain.Confidence:F2}, persistence={Brain.HuntRemaining:F1}s");
					}
					if (Plugin.Settings.DebugAgitationLogging && Mathf.Abs(loggedAgitation - Brain.Agitation) >= 1f)
					{
						Plugin.Instance.Log($"Enemy {((NetworkBehaviour)this).NetworkObjectId}: agitation={Brain.Agitation:F1}, tier={Brain.Tier}, dormant inactivity={Brain.RestSeconds:F1}s");
					}
					loggedMode = Brain.State;
					loggedAgitation = Brain.Agitation;
				}
				if (Time.time >= nextSnapshot)
				{
					nextSnapshot = Time.time + 0.1f;
					SessionWire.Snapshot(this);
				}
			}
			else if (ReceivedSnapshot)
			{
				Vector3 val = Vector3.Lerp(((Component)this).transform.position, RemotePosition, 1f - Mathf.Exp(-18f * Time.deltaTime));
				if (!BodyHit(((Component)this).transform.position, val - ((Component)this).transform.position, out var nearest))
				{
					((Component)this).transform.position = val;
				}
				else
				{
					if (Time.time >= nextClientPath)
					{
						nextClientPath = Time.time + 0.2f;
						clientDetour = NavMesh.CalculatePath(((Component)this).transform.position, RemotePosition, -1, navPath) && (int)navPath.status == 0 && navPath.corners.Length > 1;
						if (clientDetour)
						{
							clientCorner = navPath.corners[1];
						}
					}
					if (clientDetour)
					{
						Vector3 val2 = Vector3.MoveTowards(((Component)this).transform.position, clientCorner, Mathf.Max(1f, DisplaySpeed) * Time.deltaTime);
						if (!BodyHit(((Component)this).transform.position, val2 - ((Component)this).transform.position, out nearest))
						{
							((Component)this).transform.position = val2;
						}
					}
				}
				((Component)this).transform.rotation = Quaternion.Slerp(((Component)this).transform.rotation, RemoteRotation, 1f - Mathf.Exp(-18f * Time.deltaTime));
				DisplayHunt = Mathf.Max(0f, DisplayHunt - Time.deltaTime);
				DisplayWarning = Mathf.Max(0f, DisplayWarning - Time.deltaTime);
				DisplayPhase += Time.deltaTime;
				if (DisplayDoorBash)
				{
					DisplayDoorPhase += Time.deltaTime;
				}
				if (DisplaySpeed > 0.08f)
				{
					MotionPhase += Time.deltaTime;
				}
			}
			if ((Object)(object)bodyCollider != (Object)null)
			{
				bodyCollider.height = (DisplayCrawling ? 1.65f : 2.45f);
				bodyCollider.radius = 0.55f;
				bodyCollider.center = Vector3.up * (bodyCollider.height * 0.5f);
			}
			EchoHeadYaw = Mathf.MoveTowards(EchoHeadYaw, 0f, Time.deltaTime * 180f);
			Presentation.Pose(this);
		}

		internal void CopyDisplay()
		{
			DisplayState = Brain.State;
			DisplayTarget = Brain.Target;
			DisplayHunt = Brain.HuntRemaining;
			DisplayWarning = Brain.WarningRemaining;
			DisplayRecovering = Brain.Recovering;
			DisplayDoorLunge = Brain.DoorLunge;
			DisplayPhase = Brain.StateSeconds;
			DisplayAgitation = Brain.Agitation;
			base.currentBehaviourStateIndex = (int)DisplayState;
		}

		private void RepairBestiary()
		{
			Terminal val = Object.FindObjectOfType<Terminal>();
			if (!((Object)(object)val == (Object)null) && !((Object)(object)Plugin.Bestiary == (Object)null) && val.enemyFiles.Contains(Plugin.Bestiary))
			{
				int creatureFileID = Plugin.Bestiary.creatureFileID;
				ScanNodeProperties[] componentsInChildren = ((Component)this).GetComponentsInChildren<ScanNodeProperties>(true);
				for (int i = 0; i < componentsInChildren.Length; i++)
				{
					componentsInChildren[i].creatureScanID = creatureFileID;
				}
			}
		}

		public override void DoAIInterval()
		{
		}

		public override void OnCollideWithPlayer(Collider other)
		{
		}

		public override void SetEnemyStunned(bool setToStunned, float setToStunTime = 1f, PlayerControllerB? setStunnedByPlayer = null)
		{
			if (started && ((NetworkBehaviour)this).IsServer)
			{
				((EnemyAI)this).SetEnemyStunned(setToStunned, setToStunTime, setStunnedByPlayer);
			}
		}

		public override void HitEnemy(int force = 1, PlayerControllerB? playerWhoHit = null, bool playHitSFX = false, int hitID = -1)
		{
			//IL_0023: 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_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: 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)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			if (started && ((NetworkBehaviour)this).IsServer && SessionWire.Valid(playerWhoHit) && force >= 1 && !(Vector3.Distance(((Component)this).transform.position, ((Component)playerWhoHit).transform.position) > 4f) && !Blocked(Ear, ((Component)playerWhoHit).transform.position + Vector3.up))
			{
				((EnemyAI)this).SetEnemyStunned(true, 0.6f, playerWhoHit);
			}
		}

		public override void DetectNoise(Vector3 noisePosition, float noiseLoudness, int timesPlayedInSameSpot = 0, int noiseID = 0)
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			if (started && ((NetworkBehaviour)this).IsServer && !GameSoundHooks.InSourceCallback && !suppressDoorNoise && noiseID != 1974301 && noiseID != 75 && noiseID != 6 && Finite(noisePosition) && float.IsFinite(noiseLoudness) && !(noiseLoudness < Plugin.Settings.NoiseThreshold) && soundEvents.Accept(noiseID, P(noisePosition), Time.time, 0.15f))
			{
				HeardSound(SoundKind.Ordinary, (ulong)noiseID, noisePosition, Plugin.Settings.NoiseRange, noiseLoudness, 0.15f, ulong.MaxValue);
			}
		}

		internal void HeardSound(SoundKind kind, ulong source, Vector3 position, float range, float loudness, float duration, ulong player = ulong.MaxValue)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: 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)
			if (!started || !((NetworkBehaviour)this).IsServer)
			{
				return;
			}
			float num = Audibility(position + Vector3.up * 0.5f, range, loudness);
			if (!(num <= 0f))
			{
				if (!Brain.SensorySuppressed)
				{
					RememberSound(position, source);
				}
				Brain.Sound(kind, source, P(position), num, duration, player);
			}
		}

		internal void Repellent(ulong source, Vector3 position, float loudness, bool initial, float duration)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: 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_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			if (!started || !((NetworkBehaviour)this).IsServer)
			{
				return;
			}
			float num = Audibility(position + Vector3.up * 0.5f, Plugin.Settings.ContinuousNoiseRange, loudness);
			if (num <= 0f)
			{
				return;
			}
			if (initial)
			{
				RememberSound(position, source);
				Brain.Scare(P(position));
			}
			if (duration > 0f)
			{
				if (Brain.SensorySuppressed || Brain.State == Mode.Retreating)
				{
					Brain.Irritation(num, duration);
				}
				else
				{
					Brain.Sound(SoundKind.Ordinary, source, P(position), num, duration, ulong.MaxValue);
				}
			}
		}

		internal void Voice(PlayerControllerB player, ushort amplitude, float credit)
		{
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: 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_0076: 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_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			if (!started || !((NetworkBehaviour)this).IsServer)
			{
				return;
			}
			HeardLevel = VoiceActivity.Level(amplitude, Plugin.Settings.VoiceSensitivity);
			HeardVoice = false;
			if (HeardLevel < Plugin.Settings.VoiceThreshold)
			{
				VoiceReadings[player.actualClientId] = (HeardLevel, false);
				return;
			}
			Vector3 position = ((Component)player).transform.position;
			float num = Audibility(position + Vector3.up * 1.5f, Plugin.Settings.VoiceRange, 1f);
			HeardVoice = num > 0f && !Brain.SensorySuppressed;
			VoiceReadings[player.actualClientId] = (HeardLevel, HeardVoice);
			if (HeardVoice)
			{
				RememberSound(position, player.actualClientId);
			}
			Brain.Sound(SoundKind.Voice, player.actualClientId, P(position), num, credit, player.actualClientId);
		}

		private float Audibility(Vector3 point, float range, float level)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: 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_0041: 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_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			range = Mathf.Min(range, Plugin.Settings.NoiseRange);
			float num = Vector3.Distance(Ear, point);
			if (range <= 0f || num > range || level <= 0f)
			{
				return 0f;
			}
			Vector3 ear = Ear;
			Vector3 val = point - Ear;
			int num2 = Physics.RaycastNonAlloc(ear, ((Vector3)(ref val)).normalized, hearingHits, num, StartOfRound.Instance.collidersAndRoomMaskAndDefault, (QueryTriggerInteraction)1);
			HashSet<int> hashSet = new HashSet<int>();
			for (int i = 0; i < num2; i++)
			{
				if ((Object)(object)((RaycastHit)(ref hearingHits[i])).collider != (Object)null)
				{
					hashSet.Add(((Object)((RaycastHit)(ref hearingHits[i])).collider).GetInstanceID());
				}
			}
			float num3 = Mathf.Pow(Plugin.Settings.ObstructionMultiplier, (float)Mathf.Min(4, hashSet.Count));
			float num4 = range * num3;
			if (num > num4)
			{
				return 0f;
			}
			return Mathf.Clamp01(level) * num3 * Mathf.Max(0.05f, 1f - num / Mathf.Max(0.1f, num4));
		}

		internal static bool Blocked(Vector3 a, Vector3 b)
		{
			//IL_000d: 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)
			if (!((Object)(object)StartOfRound.Instance == (Object)null))
			{
				return Physics.Linecast(a, b, StartOfRound.Instance.collidersAndRoomMaskAndDefault, (QueryTriggerInteraction)1);
			}
			return true;
		}

		internal static bool Finite(Vector3 p)
		{
			//IL_0000: 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_001a: Unknown result type (might be due to invalid IL or missing references)
			if (float.IsFinite(p.x) && float.IsFinite(p.y))
			{
				return float.IsFinite(p.z);
			}
			return false;
		}

		internal static Point P(Vector3 v)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: 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)
			return new Point(v.x, v.y, v.z);
		}

		internal static Vector3 V(Point p)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			return new Vector3(p.X, p.Y, p.Z);
		}

		bool IWorld.ValidPlayer(ulong id)
		{
			return (Object)(object)SessionWire.FindPlayer(id) != (Object)null;
		}

		private DoorLock? NearbyDoor()
		{
			//IL_0026: 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)
			DoorLock[] array = doors;
			foreach (DoorLock val in array)
			{
				if (!((Object)(object)val == (Object)null) && !val.isLocked && !(Vector3.Distance(((Component)this).transform.position, ((Component)val).transform.position) > 2.1f))
				{
					NavMeshObstacle component = ((Component)val).GetComponent<NavMeshObstacle>();
					if ((Object)(object)component != (Object)null && !((Behaviour)component).enabled)
					{
						return val;
					}
				}
			}
			return null;
		}

		void IWorld.Face(Point aim)
		{
			//IL_0001: 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_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)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = V(aim) - ((Component)this).transform.position;
			val.y = 0f;
			if (((Vector3)(ref val)).sqrMagnitude > 0.01f)
			{
				((Component)this).transform.rotation = Quaternion.LookRotation(val);
			}
		}

		bool IWorld.AttackOpportunity(Point aim)
		{
			return (Object)(object)CloseVictim(aim) != (Object)null;
		}

		private PlayerControllerB? CloseVictim(Point aim)
		{
			//IL_0001: 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_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)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: 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_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: 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_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			int num = Physics.OverlapSphereNonAlloc(Ear, Plugin.Settings.AttackRange, attackColliders, StartOfRound.Instance.playersMask, (QueryTriggerInteraction)2);
			PlayerControllerB result = null;
			float num2 = float.MaxValue;
			Vector3 val = V(aim) - ((Component)this).transform.position;
			val.y = 0f;
			if (((Vector3)(ref val)).sqrMagnitude < 0.01f)
			{
				val = ((Component)this).transform.forward;
			}
			for (int i = 0; i < num; i++)
			{
				PlayerControllerB componentInParent = ((Component)attackColliders[i]).GetComponentInParent<PlayerControllerB>();
				if (SessionWire.Valid(componentInParent))
				{
					Vector3 val2 = ((Component)componentInParent).transform.position + Vector3.up;
					Vector3 val3 = val2 - Ear;
					Vector3 val4 = val3;
					val4.y = 0f;
					if (!(Vector3.Angle(val, val4) > 60f) && !(((Vector3)(ref val3)).magnitude > Plugin.Settings.AttackRange) && !Blocked(Ear, val2) && ((Vector3)(ref val3)).sqrMagnitude < num2)
					{
						result = componentInParent;
						num2 = ((Vector3)(ref val3)).sqrMagnitude;
					}
				}
			}
			return result;
		}

		bool IWorld.Strike(Point aim, int damage)
		{
			if (!((NetworkBehaviour)this).IsServer || Brain.State != Mode.Attacking || base.stunNormalizedTimer > 0f || base.stunnedIndefinitely > 0)
			{
				return false;
			}
			PlayerControllerB val = CloseVictim(aim);
			if ((Object)(object)val != (Object)null)
			{
				return SessionWire.Damage(this, val, damage);
			}
			return false;
		}

		void IWorld.Search(Point center, float speed)
		{
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: 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)
			//IL_00d2: 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_0052: 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_0057: 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_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			if (base.allAINodes != null && base.allAINodes.Length != 0)
			{
				int num = Random.Range(0, base.allAINodes.Length);
				for (int i = 0; i < Math.Min(12, base.allAINodes.Length); i++)
				{
					GameObject val = base.allAINodes[(num + i) % base.allAINodes.Length];
					if (!((Object)(object)val == (Object)null))
					{
						Vector3 position = val.transform.position;
						if (!(Vector3.Distance(position, V(center)) > 18f) && !(Vector3.Distance(position, ((Component)this).transform.position) < 2f) && ((IWorld)this).Move(P(position), speed))
						{
							return;
						}
					}
				}
			}
			Vector2 val2 = Random.insideUnitCircle * 5f;
			((IWorld)this).Move(new Point(center.X + val2.x, center.Y, center.Z + val2.y), speed);
		}

		void IWorld.Signal(Cue cue)
		{
			if (cue == Cue.EchoWarning)
			{
				PrepareEcho();
			}
			CopyDisplay();
			SessionWire.Signal(this, cue);
		}

		public override void OnDestroy()
		{
			Live.Remove(this);
			if (started)
			{
				SessionWire.Forget(((NetworkBehaviour)this).NetworkObjectId);
			}
			if (started && (Object)(object)RoundManager.Instance != (Object)null)
			{
				((EnemyAI)this).OnDestroy();
			}
		}

		private void PrepareEcho()
		{
			echoObjects.Clear();
			NavigationStatus = "Echo preparation: ears spread, throat rattle";
		}

		void IWorld.CancelEcho()
		{
			echoObjects.Clear();
			if (!finishingEcho)
			{
				stationary.Clear();
			}
			finishingEcho = false;
		}

		bool IWorld.EchoReady()
		{
			return SessionWire.EchoReady(this);
		}

		void IWorld.EchoFirst()
		{
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_0132: Unknown result type (might be due to invalid IL or missing references)
			//IL_0158: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: 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)
			echoObjects.Clear();
			PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts;
			foreach (PlayerControllerB val in allPlayerScripts)
			{
				if (SessionWire.Valid(val) && SessionWire.EchoWarned(this, val.actualClientId))
				{
					echoObjects.Add(new EchoObject
					{
						Transform = ((Component)val).transform,
						Player = val
					});
				}
			}
			GrabbableObject[] array = Object.FindObjectsOfType<GrabbableObject>();
			foreach (GrabbableObject val2 in array)
			{
				if ((Object)(object)val2 != (Object)null && val2.isInFactory && !val2.isHeld && !val2.isHeldByEnemy && Vector3.Distance(((Component)this).transform.position, ((Component)val2).transform.position) < Plugin.Settings.EchoRange + 2f)
				{
					echoObjects.Add(new EchoObject
					{
						Transform = ((Component)val2).transform,
						Item = val2
					});
				}
			}
			foreach (EchoObject echoObject in echoObjects)
			{
				echoObject.First = P(echoObject.Transform.position);
				echoObject.Exposure = Exposure(echoObject.Transform.position, (Object)(object)echoObject.Item != (Object)null);
				echoObject.Covered = Clutter(echoObject.Transform.position);
			}
			NavigationStatus = "First chirp sampled; waiting for second";
		}

		private float Exposure(Vector3 point, bool item)
		{
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: 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_014c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0156: Unknown result type (might be due to invalid IL or missing references)
			//IL_015b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0160: 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_0168: Unknown result type (might be due to invalid IL or missing references)
			//IL_016d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0172: Unknown result type (might be due to invalid IL or missing references)
			//IL_0179: Unknown result type (might be due to invalid IL or missing references)
			//IL_017a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0184: Unknown result type (might be due to invalid IL or missing references)
			//IL_0189: Unknown result type (might be due to invalid IL or missing references)
			//IL_018e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0195: Unknown result type (might be due to invalid IL or missing references)
			//IL_0196: 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_01a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_01af: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bb: 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_01c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01da: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_0136: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: 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_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: 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_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f0: 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_00bc: 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_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0216: 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_0228: Unknown result type (might be due to invalid IL or missing references)
			//IL_0221: Unknown result type (might be due to invalid IL or missing references)
			float num = Plugin.Settings.EchoRange;
			DoorLock[] array = doors;
			foreach (DoorLock val in array)
			{
				if ((Object)(object)val == (Object)null || val.isLocked)
				{
					continue;
				}
				NavMeshObstacle component = ((Component)val).GetComponent<NavMeshObstacle>();
				if (!((Object)(object)component == (Object)null) && !((Behaviour)component).enabled)
				{
					Vector3 val2 = point - ((Component)this).transform.position;
					float num2 = Vector3.Dot(((Component)val).transform.position - ((Component)this).transform.position, val2) / Mathf.Max(0.001f, ((Vector3)(ref val2)).sqrMagnitude);
					if (num2 > 0f && num2 < 1f && NavigationPolicy.SegmentDistance(P(((Component)val).transform.position), P(((Component)this).transform.position), P(point)) < 1.1f)
					{
						num *= Plugin.Settings.EchoDoorMultiplier;
						break;
					}
				}
			}
			if (Vector3.Distance(Ear, point + Vector3.up * (float)((!item) ? 1 : 0)) > num)
			{
				return 0f;
			}
			if (item)
			{
				return (!Blocked(Ear, point)) ? 1 : 0;
			}
			int num3 = 0;
			Vector3[] array2 = (Vector3[])(object)new Vector3[5]
			{
				point + Vector3.up * 1.55f,
				point + Vector3.up,
				point + Vector3.up * 0.45f,
				point + Vector3.up + Vector3.right * 0.22f,
				point + Vector3.up - Vector3.right * 0.22f
			};
			foreach (Vector3 val3 in array2)
			{
				bool flag = !Blocked(Ear, val3);
				if (flag)
				{
					num3++;
				}
				if (Plugin.Settings.DebugEchoVisualization)
				{
					Debug.DrawLine(Ear, val3, flag ? Color.green : Color.red, 1f);
				}
			}
			return (float)num3 / 5f;
		}

		private bool Clutter(Vector3 point)
		{
			//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_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: 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)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			int num = 0;
			Vector3 val = point + Vector3.up * 0.9f;
			Vector3 val2 = default(Vector3);
			for (int i = 0; i < 8; i++)
			{
				float num2 = (float)i * MathF.PI / 4f;
				((Vector3)(ref val2))..ctor(Mathf.Cos(num2), 0f, Mathf.Sin(num2));
				if (Physics.Raycast(val, val2, 1.2f, RoomMask, (QueryTriggerInteraction)1))
				{
					num++;
				}
			}
			return num >= 3;
		}

		EchoResult IWorld.EchoTarget()
		{
			//IL_009f: 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_00ad: 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_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0160: 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_0178: Unknown result type (mig