Decompiled source of Anomalies v1.2.1

EyeMonster.dll

Decompiled a week ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using Dawn;
using EyeMonster.AI;
using EyeMonster.NetcodePatcher;
using EyeMonster.Utils;
using GameNetcodeStuff;
using Microsoft.CodeAnalysis;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.Audio;
using UnityEngine.Rendering;
using UnityEngine.SceneManagement;
using Y4NGZMonsters.Shared;

[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("EyeMonster")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+c64a155fd64c47528940e53659e5b5ada665b9d4")]
[assembly: AssemblyProduct("EyeMonster")]
[assembly: AssemblyTitle("EyeMonster")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
[module: NetcodePatchedAssembly]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.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 EyeMonster
{
	public sealed class EyeMonsterConfig
	{
		public ConfigEntry<bool> Enabled { get; }

		public ConfigEntry<float> SpawnWeightMultiplier { get; }

		public ConfigEntry<string> MoonWeightOverrides { get; }

		public ConfigEntry<int> MaxCount { get; }

		public ConfigEntry<float> PowerLevel { get; }

		public ConfigEntry<int> Health { get; }

		public ConfigEntry<float> NoticeRange { get; }

		public ConfigEntry<float> GazeAngle { get; }

		public ConfigEntry<float> FlashlightRange { get; }

		public ConfigEntry<float> RoamSpeed { get; }

		public ConfigEntry<float> ChaseSpeed { get; }

		public ConfigEntry<float> FleeSpeed { get; }

		public ConfigEntry<int> AttackDamage { get; }

		public ConfigEntry<float> AttackCooldown { get; }

		public ConfigEntry<float> FleeDuration { get; }

		public ConfigEntry<bool> DebugLogs { get; }

		public EyeMonsterConfig(ConfigFile config)
		{
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Expected O, but got Unknown
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Expected O, but got Unknown
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Expected O, but got Unknown
			//IL_012e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0138: Expected O, but got Unknown
			//IL_0167: Unknown result type (might be due to invalid IL or missing references)
			//IL_0171: Expected O, but got Unknown
			//IL_01a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01aa: Expected O, but got Unknown
			//IL_01d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e3: Expected O, but got Unknown
			//IL_0212: Unknown result type (might be due to invalid IL or missing references)
			//IL_021c: Expected O, but got Unknown
			//IL_024b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0255: Expected O, but got Unknown
			//IL_0284: Unknown result type (might be due to invalid IL or missing references)
			//IL_028e: Expected O, but got Unknown
			//IL_02b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c0: Expected O, but got Unknown
			//IL_02ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f9: Expected O, but got Unknown
			//IL_0328: Unknown result type (might be due to invalid IL or missing references)
			//IL_0332: Expected O, but got Unknown
			using (ConfigPersistence.BeginBinding(config, Plugin.Log, "Eye Monster"))
			{
				EyeMonsterConfigMigration.TryMigrate(config, Plugin.Log);
				ConfigSectionNameMigration.TryMigrate(config, Plugin.Log, "Eye Monster");
				Enabled = config.Bind<bool>("General", "Enabled", true, "Enable the Eye Monster encounter. Host-only: the host's value decides whether it spawns; every install still registers the creature so clients stay in sync.");
				SpawnWeightMultiplier = config.Bind<float>("Spawning", "SpawnWeightMultiplier", 1f, new ConfigDescription("Multiplier applied to Eye Monster's contextual moon/interior spawn policy. 0 disables natural spawns.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 5f), Array.Empty<object>()));
				MoonWeightOverrides = config.Bind<string>("Spawning", "MoonWeightOverrides", string.Empty, "Optional comma-separated base moon weights, e.g. Experimentation:8,Offense:15 or namespace:moon=12. Use 0 to disable a moon; unlisted moons keep authored defaults.");
				MaxCount = config.Bind<int>("Spawning", "MaxCount", 2, new ConfigDescription("Maximum number of living Eye Monsters at once.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 4), Array.Empty<object>()));
				PowerLevel = config.Bind<float>("Spawning", "PowerLevel", 2f, new ConfigDescription("Indoor enemy power budget cost for each Eye Monster.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 20f), Array.Empty<object>()));
				Health = config.Bind<int>("Core Stats", "Health", 5, new ConfigDescription("Hits the Eye Monster can take before dying.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 100), Array.Empty<object>()));
				NoticeRange = config.Bind<float>("Detection", "NoticeRange", 12f, new ConfigDescription("Maximum range at which an Eye Monster facing a player can begin investigating.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(2f, 80f), Array.Empty<object>()));
				GazeAngle = config.Bind<float>("Detection", "GazeAngle", 28f, new ConfigDescription("Half-angle within which looking at its eye confirms aggression.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(5f, 90f), Array.Empty<object>()));
				FlashlightRange = config.Bind<float>("Detection", "FlashlightRange", 15f, new ConfigDescription("Maximum range at which a direct flashlight beam makes the Eye Monster flee.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(2f, 80f), Array.Empty<object>()));
				RoamSpeed = config.Bind<float>("Movement", "RoamSpeed", 2f, new ConfigDescription("Movement speed while roaming.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 10f), Array.Empty<object>()));
				ChaseSpeed = config.Bind<float>("Movement", "ChaseSpeed", 5f, new ConfigDescription("Movement speed after a player confirms aggression through eye contact.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 15f), Array.Empty<object>()));
				FleeSpeed = config.Bind<float>("Movement", "FleeSpeed", 7f, new ConfigDescription("Movement speed while fleeing a direct flashlight beam.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 20f), Array.Empty<object>()));
				AttackDamage = config.Bind<int>("Combat", "AttackDamage", 35, new ConfigDescription("Damage dealt by a successful attack.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 200), Array.Empty<object>()));
				AttackCooldown = config.Bind<float>("Combat", "AttackCooldown", 1.5f, new ConfigDescription("Seconds between attack attempts.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 30f), Array.Empty<object>()));
				FleeDuration = config.Bind<float>("Abilities", "FleeDuration", 6f, new ConfigDescription("Seconds the Eye Monster flees after being directly lit.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 30f), Array.Empty<object>()));
				DebugLogs = config.Bind<bool>("Diagnostics", "DebugLogs", false, "Log detailed Eye Monster targeting and setup diagnostics.");
			}
		}
	}
	internal static class EyeMonsterConfigMigration
	{
		private static readonly ConfigDefinition LegacySpawnWeight = new ConfigDefinition("Spawning", "SpawnWeight");

		private static readonly LegacyMigrationSpec Spec = new LegacyMigrationSpec("Eye Monster", (IReadOnlyList<ConfigDefinition>)(object)new ConfigDefinition[6]
		{
			LegacySpawnWeight,
			new ConfigDefinition("Combat", "EnemyHP"),
			new ConfigDefinition("Detection", "AggroRange"),
			new ConfigDefinition("Detection", "PlayerGazeAngle"),
			new ConfigDefinition("Detection", "FlashlightDetectionRange"),
			new ConfigDefinition("Behavior", "FleeDuration")
		}, null, new Dictionary<ConfigDefinition, string>
		{
			{
				new ConfigDefinition("Movement", "InvestigateSpeed"),
				"2.6"
			},
			{
				new ConfigDefinition("Combat", "AttackRange"),
				"2.5"
			},
			{
				new ConfigDefinition("Detection", "NoticeViewAngle"),
				"52"
			},
			{
				new ConfigDefinition("Behavior", "InvestigationStopDistance"),
				"4.5"
			},
			{
				new ConfigDefinition("Behavior", "InvestigationDecisionDelay"),
				"0.8"
			},
			{
				new ConfigDefinition("Detection", "FlashlightDetectionAngle"),
				"25"
			},
			{
				new ConfigDefinition("Behavior", "LoseTargetSeconds"),
				"3.5"
			},
			{
				new ConfigDefinition("Behavior", "FailedNoticeCooldown"),
				"4"
			}
		}, Build);

		internal static bool TryMigrate(ConfigFile config, ManualLogSource log)
		{
			return LegacyConfigMigrator.TryMigrate(config, log, Spec);
		}

		private static void Build(LegacyConfigValues values, MigratedConfigWriter output)
		{
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Expected O, but got Unknown
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Expected O, but got Unknown
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Expected O, but got Unknown
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Expected O, but got Unknown
			//IL_018a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0190: Expected O, but got Unknown
			output.Carry("General", "Enabled");
			output.CarrySpawnWeightMultiplier(LegacySpawnWeight, 40f);
			output.Carry("Spawning", "MoonWeightOverrides");
			output.Carry("Spawning", "MaxCount");
			output.Carry("Spawning", "PowerLevel");
			output.Carry("Core Stats", "Health", new ConfigDefinition("Combat", "EnemyHP"));
			output.Carry("Detection", "NoticeRange", new ConfigDefinition("Detection", "AggroRange"));
			output.Carry("Detection", "GazeAngle", new ConfigDefinition("Detection", "PlayerGazeAngle"));
			output.Carry("Detection", "FlashlightRange", new ConfigDefinition("Detection", "FlashlightDetectionRange"));
			output.Carry("Movement", "RoamSpeed");
			output.Carry("Movement", "ChaseSpeed");
			output.Carry("Movement", "FleeSpeed");
			output.Carry("Combat", "AttackDamage");
			output.Carry("Combat", "AttackCooldown");
			output.Carry("Abilities", "FleeDuration", new ConfigDefinition("Behavior", "FleeDuration"));
			output.Carry("Diagnostics", "DebugLogs");
		}
	}
	internal sealed class EyeMonsterSpawnWeights : ContextualSpawnWeights
	{
		internal EyeMonsterSpawnWeights(Func<float> multiplier, Func<string> moonOverrides, Action<string> logWarning)
			: base(SpawnWeightTable.EyeMonster, "Eye Monster", multiplier, moonOverrides, logWarning)
		{
		}
	}
	internal static class EyeMonsterTuning
	{
		internal const float InvestigateSpeed = 2.6f;

		internal const float AttackRange = 2.5f;

		internal const float NoticeViewAngle = 52f;

		internal const float InvestigationStopDistance = 4.5f;

		internal const float InvestigationDecisionDelay = 0.8f;

		internal const float InvestigationTimeout = 8f;

		internal const float FlashlightDetectionAngle = 25f;

		internal const float LoseTargetSeconds = 3.5f;

		internal const float FailedNoticeCooldown = 4f;

		internal const float AgentAngularSpeed = 180f;

		internal const float AgentAcceleration = 12f;

		internal const float AgentRadius = 0.42f;

		internal const float AgentHeight = 2.45f;
	}
	[BepInPlugin("y4ngz.lethalcompany.eyemonster", "Y4NGZ Eye Monster", "1.2.1")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		internal const string DawnNamespace = "y4ngz_monsters";

		internal const string DawnEnemyKey = "eye_monster";

		internal const string ScanNodeSubtitle = "Avoid its gaze";

		internal const string BestiaryText = "Eye Monster\n\nDanger level: high\n\nA roaming ocular predator that approaches cautiously until a worker meets its gaze. Avoid eye contact to make it lose interest, or drive it away with a direct flashlight beam.\n\n";

		internal static ManualLogSource Log;

		internal static EyeMonsterConfig ModConfig;

		internal static AssetBundle ModAssets;

		internal static EnemyType EyeMonsterEnemy;

		private static bool _netcodeInitialized;

		private static bool _loggedScanNodeLayer;

		private void Awake()
		{
			Log = ((BaseUnityPlugin)this).Logger;
			try
			{
				InitializeNetcodeRPCs();
				ModConfig = new EyeMonsterConfig(((BaseUnityPlugin)this).Config);
				string text = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "eyemonster.bundle");
				ModAssets = AssetBundle.LoadFromFile(text);
				if ((Object)(object)ModAssets == (Object)null)
				{
					Log.LogError((object)("Failed to load asset bundle at: " + text));
					return;
				}
				GameObject val = ModAssets.LoadAsset<GameObject>("EyeMonster");
				if ((Object)(object)val == (Object)null)
				{
					Log.LogError((object)"Failed to load EyeMonster prefab from bundle.");
					return;
				}
				SetupPrefabComponents(val);
				EyeMonsterEnemy = CreateEnemyType(val);
				EyeMonsterAI component = val.GetComponent<EyeMonsterAI>();
				if ((Object)(object)component == (Object)null)
				{
					Log.LogError((object)"EyeMonster prefab does not contain EyeMonsterAI.");
					return;
				}
				((EnemyAI)component).enemyType = EyeMonsterEnemy;
				RegisterWithDawn(val);
				if (!ModConfig.Enabled.Value)
				{
					Log.LogInfo((object)"Y4NGZ Eye Monster: registered network prefab; spawning disabled by config.");
				}
				Log.LogInfo((object)"Y4NGZ Eye Monster v1.2.1 loaded.");
			}
			catch (Exception arg)
			{
				Log.LogError((object)string.Format("Failed to initialize {0}: {1}", "Y4NGZ Eye Monster", arg));
			}
		}

		private static void RegisterWithDawn(GameObject prefab)
		{
			EyeMonsterSpawnWeights spawnWeights = new EyeMonsterSpawnWeights(() => (!ModConfig.Enabled.Value) ? 0f : ModConfig.SpawnWeightMultiplier.Value, () => ModConfig.MoonWeightOverrides.Value, delegate(string message)
			{
				Log.LogWarning((object)message);
			});
			DawnLib.RegisterNetworkPrefab(prefab);
			DawnLib.DefineEnemy(NamespacedKey<DawnEnemyInfo>.From("y4ngz_monsters", "eye_monster"), EyeMonsterEnemy, (Action<EnemyInfoBuilder>)delegate(EnemyInfoBuilder builder)
			{
				((BaseInfoBuilder<DawnEnemyInfo, EnemyType, EnemyInfoBuilder>)(object)builder.DefineInside((Action<EnemyLocationBuilder>)delegate(EnemyLocationBuilder location)
				{
					location.SetWeights((Action<WeightTableBuilder<DawnMoonInfo, SpawnWeightContext>>)delegate(WeightTableBuilder<DawnMoonInfo, SpawnWeightContext> table)
					{
						table.SetGlobalWeight((IWeighted)(object)spawnWeights);
					});
				}).CreateBestiaryNode("Eye Monster\n\nDanger level: high\n\nA roaming ocular predator that approaches cautiously until a worker meets its gaze. Avoid eye contact to make it lose interest, or drive it away with a direct flashlight beam.\n\n").CreateNameKeyword("eye monster")).AddTags((IEnumerable<NamespacedKey>)(object)new NamespacedKey[4]
				{
					Tags.Hostile,
					Tags.Organic,
					Tags.Killable,
					Tags.Medium
				});
			});
		}

		private static void InitializeNetcodeRPCs()
		{
			if (_netcodeInitialized)
			{
				return;
			}
			_netcodeInitialized = true;
			Type[] types = Assembly.GetExecutingAssembly().GetTypes();
			foreach (Type type in types)
			{
				MethodInfo[] methods;
				try
				{
					methods = type.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				}
				catch
				{
					continue;
				}
				foreach (MethodInfo methodInfo in methods)
				{
					if (methodInfo.GetCustomAttributes(typeof(RuntimeInitializeOnLoadMethodAttribute), inherit: false).Length == 0)
					{
						continue;
					}
					try
					{
						methodInfo.Invoke(null, null);
					}
					catch (Exception ex)
					{
						ManualLogSource log = Log;
						if (log != null)
						{
							log.LogWarning((object)("[NetcodeInit] " + type.Name + "." + methodInfo.Name + " failed: " + ex.Message));
						}
					}
				}
			}
		}

		private static void SetupPrefabComponents(GameObject prefab)
		{
			TrySetTag(prefab, "Enemy");
			TrySetLayer(prefab, "Enemies");
			EyeMonsterAI component = prefab.GetComponent<EyeMonsterAI>();
			if ((Object)(object)component == (Object)null)
			{
				Log.LogError((object)"[EyeMon] EyeMonsterAI is missing from the bundled prefab.");
				return;
			}
			NavMeshAgent val = prefab.GetComponent<NavMeshAgent>();
			if ((Object)(object)val == (Object)null)
			{
				val = prefab.AddComponent<NavMeshAgent>();
			}
			ConfigureAgent(val);
			((EnemyAI)component).agent = val;
			Animator animator = ResolveAnimator(prefab, component);
			EnsureAnimationRelay(prefab, component, animator);
			EnsureEyeAnchor(prefab, component);
			EnsureScanNode(prefab);
			EnsureMapDot(prefab);
			EnsureCollision(prefab, component);
			EnsureExclusiveAudio(prefab, component);
			EnsureSlimeTrail(prefab, component);
			EnsureBehaviourStates(component);
			WireAudioClips(component);
		}

		private static void ConfigureAgent(NavMeshAgent agent)
		{
			agent.speed = ModConfig.RoamSpeed.Value;
			agent.angularSpeed = 180f;
			agent.acceleration = 12f;
			agent.stoppingDistance = 0f;
			agent.radius = 0.42f;
			agent.height = 2.45f;
			agent.baseOffset = 0f;
			agent.autoRepath = true;
			agent.autoTraverseOffMeshLink = true;
		}

		private static Animator ResolveAnimator(GameObject prefab, EyeMonsterAI ai)
		{
			Transform val = prefab.transform.Find("VisualRoot");
			Animator val2 = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponent<Animator>() : prefab.GetComponent<Animator>());
			if ((Object)(object)val2 == (Object)null)
			{
				val2 = prefab.GetComponentInChildren<Animator>(true);
			}
			((EnemyAI)ai).creatureAnimator = val2;
			return val2;
		}

		private static void EnsureAnimationRelay(GameObject prefab, EyeMonsterAI ai, Animator animator)
		{
			if (!((Object)(object)animator == (Object)null) && !((Object)(object)((Component)animator).gameObject == (Object)(object)prefab))
			{
				EyeMonsterAnimationRelay eyeMonsterAnimationRelay = ((Component)animator).GetComponent<EyeMonsterAnimationRelay>();
				if ((Object)(object)eyeMonsterAnimationRelay == (Object)null)
				{
					eyeMonsterAnimationRelay = ((Component)animator).gameObject.AddComponent<EyeMonsterAnimationRelay>();
				}
				eyeMonsterAnimationRelay.owner = ai;
			}
		}

		private static void EnsureEyeAnchor(GameObject prefab, EyeMonsterAI ai)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			Transform val = FindOrCreateChild(prefab.transform, "Eye", new Vector3(0f, 1.45f, 0.45f));
			TrySetLayer(((Component)val).gameObject, "Enemies");
			((EnemyAI)ai).eye = val;
		}

		internal static void EnsureScanNode(GameObject prefab)
		{
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_0214: 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)
			ScanNodeProperties val = null;
			ScanNodeProperties[] componentsInChildren = prefab.GetComponentsInChildren<ScanNodeProperties>(true);
			foreach (ScanNodeProperties val2 in componentsInChildren)
			{
				bool flag = val2.creatureScanID >= 0;
				bool flag2 = (Object)(object)val != (Object)null && val.creatureScanID >= 0;
				bool flag3 = string.Equals(((Object)((Component)val2).gameObject).name, "ScanNode", StringComparison.Ordinal);
				bool flag4 = (Object)(object)val != (Object)null && string.Equals(((Object)((Component)val).gameObject).name, "ScanNode", StringComparison.Ordinal);
				if ((Object)(object)val == (Object)null || (flag && !flag2) || (flag == flag2 && flag3 && !flag4))
				{
					val = val2;
				}
			}
			if (componentsInChildren.Length > 1)
			{
				ManualLogSource log = Log;
				if (log != null)
				{
					log.LogWarning((object)$"[EyeMon] Found {componentsInChildren.Length} scan nodes; retiring every duplicate.");
				}
			}
			for (int j = 0; j < componentsInChildren.Length; j++)
			{
				if ((Object)(object)componentsInChildren[j] != (Object)(object)val)
				{
					RetireExtraScanNode(componentsInChildren[j], val, prefab);
				}
			}
			Transform val3 = (((Object)(object)val != (Object)null) ? ((Component)val).transform : FindOrCreateChild(prefab.transform, "ScanNode", new Vector3(0f, 1.45f, 0f)));
			((Object)((Component)val3).gameObject).name = "ScanNode";
			TrySetTag(((Component)val3).gameObject, "DoNotSet");
			TrySetLayer(((Component)val3).gameObject, "ScanNode");
			EnsureHierarchyActive(val3, prefab.transform);
			((Component)val3).gameObject.SetActive(true);
			if (!_loggedScanNodeLayer)
			{
				_loggedScanNodeLayer = true;
				Log.LogInfo((object)($"[EyeMon] Scan node layer resolved to {((Component)val3).gameObject.layer} " + string.Format("(NameToLayer(\"ScanNode\")={0}, fallback 22); ", LayerMask.NameToLayer("ScanNode")) + $"active={((Component)val3).gameObject.activeInHierarchy}."));
			}
			BoxCollider val4 = ((Component)val3).GetComponent<BoxCollider>();
			if ((Object)(object)val4 == (Object)null)
			{
				val4 = ((Component)val3).gameObject.AddComponent<BoxCollider>();
			}
			((Collider)val4).enabled = true;
			((Collider)val4).isTrigger = true;
			val4.center = Vector3.zero;
			val4.size = new Vector3(1.8f, 2.2f, 1.8f);
			val = val ?? ((Component)val3).gameObject.AddComponent<ScanNodeProperties>();
			val.headerText = "Eye Monster";
			val.subText = "Avoid its gaze";
			val.maxRange = 25;
			val.minRange = 1;
			val.nodeType = 1;
			val.requiresLineOfSight = true;
		}

		private static void RetireExtraScanNode(ScanNodeProperties extra, ScanNodeProperties preferred, GameObject root)
		{
			//IL_0035: 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_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)extra == (Object)null)
			{
				return;
			}
			Scene scene;
			if ((Object)(object)((Component)extra).gameObject == (Object)(object)root || ((Object)(object)preferred != (Object)null && (Object)(object)((Component)extra).gameObject == (Object)(object)((Component)preferred).gameObject))
			{
				scene = root.scene;
				if (((Scene)(ref scene)).IsValid())
				{
					Object.Destroy((Object)(object)extra);
				}
				else
				{
					Object.DestroyImmediate((Object)(object)extra, true);
				}
				return;
			}
			GameObject gameObject = ((Component)extra).gameObject;
			gameObject.SetActive(false);
			Collider[] components = gameObject.GetComponents<Collider>();
			for (int i = 0; i < components.Length; i++)
			{
				components[i].enabled = false;
			}
			scene = root.scene;
			if (((Scene)(ref scene)).IsValid())
			{
				Object.Destroy((Object)(object)gameObject);
			}
			else
			{
				Object.DestroyImmediate((Object)(object)gameObject, true);
			}
		}

		private static void EnsureMapDot(GameObject prefab)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			Transform obj = FindOrCreateChild(prefab.transform, "MapDot", new Vector3(0f, 1.2f, 0f));
			TrySetTag(((Component)obj).gameObject, "DoNotSet");
			TrySetLayer(((Component)obj).gameObject, "MapRadar");
		}

		private static void EnsureCollision(GameObject prefab, EyeMonsterAI ai)
		{
			//IL_0035: 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)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			BoxCollider val = prefab.GetComponent<BoxCollider>();
			if ((Object)(object)val == (Object)null)
			{
				val = prefab.AddComponent<BoxCollider>();
			}
			((Collider)val).enabled = true;
			((Collider)val).isTrigger = false;
			val.center = new Vector3(0f, 1.4f, 0f);
			val.size = new Vector3(2.05f, 2.8f, 2.05f);
			Transform val2 = FindOrCreateChild(prefab.transform, "Collision", Vector3.zero);
			TrySetTag(((Component)val2).gameObject, "Enemy");
			TrySetLayer(((Component)val2).gameObject, "Enemies");
			BoxCollider val3 = ((Component)val2).GetComponent<BoxCollider>();
			if ((Object)(object)val3 == (Object)null)
			{
				val3 = ((Component)val2).gameObject.AddComponent<BoxCollider>();
			}
			((Collider)val3).enabled = true;
			((Collider)val3).isTrigger = true;
			val3.center = new Vector3(0f, 1.45f, 0f);
			val3.size = new Vector3(2.3f, 2.9f, 2.3f);
			Rigidbody val4 = ((Component)val2).GetComponent<Rigidbody>();
			if ((Object)(object)val4 == (Object)null)
			{
				val4 = ((Component)val2).gameObject.AddComponent<Rigidbody>();
			}
			val4.isKinematic = true;
			val4.useGravity = false;
			val4.detectCollisions = true;
			WireHitDetector(((Component)val2).gameObject, ai);
		}

		private static void WireHitDetector(GameObject host, EyeMonsterAI ai)
		{
			EnemyAICollisionDetect val = host.GetComponent<EnemyAICollisionDetect>();
			if ((Object)(object)val == (Object)null)
			{
				val = host.AddComponent<EnemyAICollisionDetect>();
			}
			val.mainScript = (EnemyAI)(object)ai;
			val.alwaysAllowHitting = true;
			val.canCollideWithEnemies = false;
			val.onlyCollideWhenGrounded = false;
		}

		private static void EnsureExclusiveAudio(GameObject prefab, EyeMonsterAI ai)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			Transform val = FindOrCreateChild(prefab.transform, "CreatureAudio", new Vector3(0f, 1.35f, 0f));
			TrySetLayer(((Component)val).gameObject, "Enemies");
			AudioSource val2 = ((Component)val).GetComponent<AudioSource>();
			if ((Object)(object)val2 == (Object)null)
			{
				val2 = ((Component)val).gameObject.AddComponent<AudioSource>();
			}
			ConfigureSpatialAudio(val2);
			ai.exclusiveAudioSource = val2;
			((EnemyAI)ai).creatureSFX = val2;
			((EnemyAI)ai).creatureVoice = val2;
			DisableLegacyAudio(prefab.transform.Find("CreatureSFX"), val2);
			DisableLegacyAudio(prefab.transform.Find("CreatureVoice"), val2);
			DisableLegacyAudio(prefab.transform.Find("LoopSource"), val2);
		}

		private static void DisableLegacyAudio(Transform legacyTransform, AudioSource retainedSource)
		{
			if (!((Object)(object)legacyTransform == (Object)null))
			{
				AudioSource component = ((Component)legacyTransform).GetComponent<AudioSource>();
				if (!((Object)(object)component == (Object)null) && !((Object)(object)component == (Object)(object)retainedSource))
				{
					component.Stop();
					component.playOnAwake = false;
					component.loop = false;
					component.clip = null;
					((Behaviour)component).enabled = false;
				}
			}
		}

		private static void ConfigureSpatialAudio(AudioSource source)
		{
			source.playOnAwake = false;
			source.loop = false;
			source.spatialBlend = 1f;
			source.rolloffMode = (AudioRolloffMode)1;
			source.minDistance = 1f;
			source.maxDistance = 25f;
		}

		private static void EnsureSlimeTrail(GameObject prefab, EyeMonsterAI ai)
		{
			EyeMonsterSlimeTrail eyeMonsterSlimeTrail = prefab.GetComponent<EyeMonsterSlimeTrail>();
			if ((Object)(object)eyeMonsterSlimeTrail == (Object)null)
			{
				eyeMonsterSlimeTrail = prefab.AddComponent<EyeMonsterSlimeTrail>();
			}
			eyeMonsterSlimeTrail.slimeMaterial = LoadMaterial("EyeMonsterSlime");
			ai.slimeTrail = eyeMonsterSlimeTrail;
			if ((Object)(object)eyeMonsterSlimeTrail.slimeMaterial == (Object)null)
			{
				Log.LogWarning((object)"[EyeMon] EyeMonsterSlime material is missing from the bundle.");
			}
		}

		private static void EnsureBehaviourStates(EyeMonsterAI ai)
		{
			((EnemyAI)ai).enemyBehaviourStates = (EnemyBehaviourState[])(object)new EnemyBehaviourState[5]
			{
				WalkingState("Roaming", walking: false),
				WalkingState("Investigating", walking: true),
				WalkingState("Chasing", walking: true),
				WalkingState("Attacking", walking: false),
				WalkingState("Fleeing", walking: true)
			};
			((EnemyAI)ai).currentBehaviourStateIndex = 0;
			((EnemyAI)ai).previousBehaviourStateIndex = 0;
			((EnemyAI)ai).currentBehaviourState = ((EnemyAI)ai).enemyBehaviourStates[0];
		}

		private static EnemyBehaviourState WalkingState(string name, bool walking)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: 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_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Expected O, but got Unknown
			return new EnemyBehaviourState
			{
				name = name,
				IsAnimTrigger = false,
				parameterString = "isWalking",
				boolValue = walking
			};
		}

		private static void WireAudioClips(EyeMonsterAI ai)
		{
			ai.idleClips = LoadAudioClips("eyemonster_idle_01", "eyemonster_idle_02");
			ai.vocalClips = LoadAudioClips("eyemonster_vocal_01", "eyemonster_vocal_02");
			ai.playerHitClips = LoadAudioClips("eyemonster_player_hit_01");
			ai.runStepClips = LoadAudioClips("eyemonster_step_01", "eyemonster_step_02", "eyemonster_step_03");
		}

		private static AudioClip[] LoadAudioClips(params string[] names)
		{
			AudioClip[] array = (AudioClip[])(object)new AudioClip[names.Length];
			int num = 0;
			for (int i = 0; i < names.Length; i++)
			{
				AudioClip val = LoadAudioClip(names[i]);
				if ((Object)(object)val != (Object)null)
				{
					array[num++] = val;
				}
			}
			if (num == array.Length)
			{
				return array;
			}
			AudioClip[] array2 = (AudioClip[])(object)new AudioClip[num];
			Array.Copy(array, array2, num);
			return array2;
		}

		private static AudioClip LoadAudioClip(string shortName)
		{
			AudioClip val = ModAssets.LoadAsset<AudioClip>(shortName) ?? ModAssets.LoadAsset<AudioClip>(shortName + ".wav");
			if ((Object)(object)val != (Object)null)
			{
				return val;
			}
			string[] allAssetNames = ModAssets.GetAllAssetNames();
			foreach (string text in allAssetNames)
			{
				if (text.EndsWith("/" + shortName + ".wav", StringComparison.OrdinalIgnoreCase))
				{
					return ModAssets.LoadAsset<AudioClip>(text);
				}
			}
			Log.LogWarning((object)("[EyeMon] Audio clip missing from bundle: " + shortName));
			return null;
		}

		private static Material LoadMaterial(string shortName)
		{
			Material val = ModAssets.LoadAsset<Material>(shortName) ?? ModAssets.LoadAsset<Material>(shortName + ".mat");
			if ((Object)(object)val != (Object)null)
			{
				return val;
			}
			string[] allAssetNames = ModAssets.GetAllAssetNames();
			foreach (string text in allAssetNames)
			{
				if (text.EndsWith("/" + shortName + ".mat", StringComparison.OrdinalIgnoreCase))
				{
					return ModAssets.LoadAsset<Material>(text);
				}
			}
			return null;
		}

		private static Transform FindOrCreateChild(Transform parent, string name, Vector3 localPosition)
		{
			//IL_0026: 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)
			Transform val = parent.Find(name);
			if ((Object)(object)val == (Object)null)
			{
				val = new GameObject(name).transform;
				val.SetParent(parent, false);
			}
			val.localPosition = localPosition;
			return val;
		}

		private static void TrySetTag(GameObject target, string tagName)
		{
			try
			{
				target.tag = tagName;
			}
			catch (UnityException)
			{
				Log.LogWarning((object)("[EyeMon] Tag '" + tagName + "' is unavailable for '" + ((Object)target).name + "'."));
			}
		}

		internal static void TrySetLayer(GameObject target, string layerName)
		{
			if (!((Object)(object)target == (Object)null))
			{
				int num = LayerMask.NameToLayer(layerName);
				if (num < 0)
				{
					num = ResolveLayerFallback(layerName);
				}
				if (num < 0 || num > 31)
				{
					Log.LogWarning((object)("[EyeMon] Layer '" + layerName + "' is unavailable for '" + ((Object)target).name + "'."));
				}
				else
				{
					target.layer = num;
				}
			}
		}

		private static int ResolveLayerFallback(string layerName)
		{
			if (string.Equals(layerName, "ScanNode", StringComparison.OrdinalIgnoreCase))
			{
				return 22;
			}
			if (string.Equals(layerName, "Enemies", StringComparison.OrdinalIgnoreCase))
			{
				return 19;
			}
			return -1;
		}

		private static void EnsureHierarchyActive(Transform child, Transform stopAt)
		{
			Transform val = child;
			while ((Object)(object)val != (Object)null)
			{
				((Component)val).gameObject.SetActive(true);
				if (!((Object)(object)val == (Object)(object)stopAt))
				{
					val = val.parent;
					continue;
				}
				break;
			}
		}

		private static EnemyType CreateEnemyType(GameObject prefab)
		{
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			EnemyType obj = ScriptableObject.CreateInstance<EnemyType>();
			obj.enemyName = "Eye Monster";
			obj.enemyPrefab = prefab;
			obj.PowerLevel = ModConfig.PowerLevel.Value;
			obj.DiversityPowerLevel = 1;
			obj.MaxCount = ModConfig.MaxCount.Value;
			obj.canDie = true;
			obj.canBeStunned = true;
			obj.stunTimeMultiplier = 1f;
			obj.doorSpeedMultiplier = 1f;
			obj.stunGameDifficultyMultiplier = 1f;
			obj.destroyOnDeath = false;
			obj.isOutsideEnemy = false;
			obj.isDaytimeEnemy = false;
			obj.probabilityCurve = AnimationCurve.Constant(0f, 1f, 1f);
			obj.numberSpawnedFalloff = AnimationCurve.Linear(0f, 1f, 1f, 0.65f);
			obj.useNumberSpawnedFalloff = true;
			obj.SizeLimit = (NavSizeLimit)1;
			EyeMonsterAI component = prefab.GetComponent<EyeMonsterAI>();
			AudioClip[] array = (((Object)(object)component != (Object)null) ? component.vocalClips : null);
			CreatureSfx.Apply(obj, (EnemyAI)(object)component, (array != null && array.Length != 0) ? array[0] : null, (array != null && array.Length != 0) ? array[^1] : null);
			return obj;
		}
	}
	public static class PluginInfo
	{
		public const string PLUGIN_GUID = "y4ngz.lethalcompany.eyemonster";

		public const string PLUGIN_NAME = "Y4NGZ Eye Monster";

		public const string PLUGIN_VERSION = "1.2.1";
	}
}
namespace EyeMonster.Utils
{
	public static class CreatureAudio
	{
		public static bool PlayExclusive(AudioSource source, AudioClip clip, bool interrupt)
		{
			if ((Object)(object)source == (Object)null || (Object)(object)clip == (Object)null)
			{
				return false;
			}
			if (source.isPlaying && !interrupt)
			{
				return false;
			}
			source.Stop();
			source.loop = false;
			source.clip = clip;
			source.Play();
			return true;
		}

		public static void Stop(AudioSource source)
		{
			if (!((Object)(object)source == (Object)null))
			{
				source.Stop();
				source.loop = false;
				source.clip = null;
			}
		}
	}
}
namespace EyeMonster.AI
{
	public class EyeMonsterAI : EnemyAI
	{
		private enum AudioCue
		{
			Idle,
			Vocal,
			PlayerHit,
			Step
		}

		public const int StateRoaming = 0;

		public const int StateInvestigating = 1;

		public const int StateChasing = 2;

		public const int StateAttacking = 3;

		public const int StateFleeing = 4;

		[Header("Exclusive audio")]
		public AudioClip[] idleClips;

		public AudioClip[] vocalClips;

		public AudioClip[] playerHitClips;

		public AudioClip[] runStepClips;

		public AudioSource exclusiveAudioSource;

		[Header("Cosmetics")]
		public EyeMonsterSlimeTrail slimeTrail;

		private const float LightCheckInterval = 0.2f;

		private const float PassiveEyelidClosure = 0.24f;

		private const float FlashlightEyelidClosure = 0.72f;

		private const float PassiveEyelidSmoothTime = 0.42f;

		private const float RevealEyelidSmoothTime = 0.24f;

		private const float FlashlightEyelidSmoothTime = 0.16f;

		private const float DeathEyelidSmoothTime = 0.13f;

		private const float IdleAudioMinSeconds = 7.5f;

		private const float IdleAudioMaxSeconds = 14f;

		private const float ChaseRangeMultiplier = 1.75f;

		private const string StunnedParameter = "stunned";

		private const float BiteForce = 12f;

		private const float FleeRouteRefreshSeconds = 1f;

		private const float FleeNodeMaxDistance = 40f;

		private const float FleePathThreatClearance = 2.5f;

		private const int FleeMaxPathChecks = 6;

		private static readonly RaycastHit[] LightPathHits = (RaycastHit[])(object)new RaycastHit[8];

		private const float NoiseMinLoudness = 0.5f;

		private const float NoiseHearingRange = 20f;

		private const float NoiseMemorySeconds = 3f;

		private const float NoiseReseedCooldown = 4f;

		private const int NoiseMaxRepeatsInOneSpot = 10;

		private static readonly Vector3 UpperLidOpenPosition = new Vector3(0f, 0.53408f, 0.668f);

		private static readonly Vector3 LowerLidOpenPosition = new Vector3(0f, 0.53408f, 0.668f);

		private static readonly Vector3 UpperLidClosedPosition = new Vector3(0f, 0.53408f, 0.668f);

		private static readonly Vector3 LowerLidClosedPosition = new Vector3(0.44242f, 0.53408f, 0.668f);

		private static readonly Quaternion UpperLidOpenRotation = Quaternion.identity;

		private static readonly Quaternion LowerLidOpenRotation = Quaternion.identity;

		private static readonly Quaternion UpperLidClosedRotation = Quaternion.Euler(35.10085f, 0.00239f, 0.00126f);

		private static readonly Quaternion LowerLidClosedRotation = Quaternion.Euler(-37.8065f, 0.00281f, -0.00115f);

		private readonly Dictionary<ulong, float> _noticeCooldownUntil = new Dictionary<ulong, float>();

		private readonly int[] _lastAudioIndices = new int[4] { -1, -1, -1, -1 };

		private readonly ServerOwnershipGuard _ownership = new ServerOwnershipGuard();

		private readonly NoiseMemory _noiseMemory = new NoiseMemory();

		private float _loseTargetTimer;

		private float _attackCooldownTimer;

		private float _lightCheckTimer;

		private float _fleeTimer;

		private float _investigationStartedAt;

		private float _nextIdleAudioTime;

		private float _eyelidClosure = 0.24f;

		private float _eyelidClosureVelocity;

		private float _remoteMovingUntil;

		private Vector3 _lastAnimationPosition;

		private bool _hasLastAnimationPosition;

		private bool _eyelidsInitialized;

		private float _nextFleeRouteTime;

		private Vector3 _lastLightThreatPosition;

		private Coroutine _attackCoroutine;

		private bool _gazeConfirmedForTarget;

		private bool _deathAnimationStarted;

		private float _nextNoiseReseedTime;

		private bool _wasStunned;

		private bool _audioRouted;

		private bool _attackSwingPending;

		private bool _deathPoseFrozen;

		private bool _corpseAnimatorStopped;

		private Transform _eyeBone;

		private Transform _upperLid;

		private Transform _lowerLid;

		private float RoamSpeed => Mathf.Max(0.1f, Plugin.ModConfig.RoamSpeed.Value);

		private float InvestigateSpeed => 2.6f;

		private float ChaseSpeed => Mathf.Max(0.1f, Plugin.ModConfig.ChaseSpeed.Value);

		private float FleeSpeed => Mathf.Max(0.1f, Plugin.ModConfig.FleeSpeed.Value);

		private int AttackDamage => Mathf.Max(0, Plugin.ModConfig.AttackDamage.Value);

		private float AttackCooldown => Mathf.Max(0.1f, Plugin.ModConfig.AttackCooldown.Value);

		private float AttackRange => 2.5f;

		private float NoticeRange => Mathf.Max(2f, Plugin.ModConfig.NoticeRange.Value);

		private float NoticeViewAngle => 52f;

		private float PlayerGazeAngle => Mathf.Clamp(Plugin.ModConfig.GazeAngle.Value, 5f, 90f);

		private float InvestigationStopDistance => 4.5f;

		private float InvestigationDecisionDelay => 0.8f;

		private float InvestigationTimeout => 8f;

		private float FlashlightDetectionRange => Mathf.Max(2f, Plugin.ModConfig.FlashlightRange.Value);

		private float FlashlightDetectionAngle => 25f;

		private float FleeDuration => Mathf.Max(0.5f, Plugin.ModConfig.FleeDuration.Value);

		private float LoseTargetSeconds => 3.5f;

		private float FailedNoticeCooldown => 4f;

		internal bool ShouldEmitSlimeTrail
		{
			get
			{
				if (!base.isEnemyDead && base.ventAnimationFinished)
				{
					return base.currentBehaviourStateIndex != 3;
				}
				return false;
			}
		}

		private bool AgentCanNavigate
		{
			get
			{
				if ((Object)(object)base.agent != (Object)null && ((Behaviour)base.agent).enabled)
				{
					return base.agent.isOnNavMesh;
				}
				return false;
			}
		}

		private void LogError(string message)
		{
			Plugin.Log.LogError((object)message);
		}

		private void LogDebug(string message)
		{
			EyeMonsterConfig modConfig = Plugin.ModConfig;
			if (modConfig != null && modConfig.DebugLogs.Value)
			{
				Plugin.Log.LogInfo((object)("[EyeMon] " + message));
			}
		}

		public override void Awake()
		{
			try
			{
				((EnemyAI)this).Awake();
				Plugin.EnsureScanNode(((Component)this).gameObject);
				CacheVisualRig();
			}
			catch (Exception arg)
			{
				LogError($"EyeMonsterAI.Awake: {arg}");
			}
		}

		public override void Start()
		{
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				((EnemyAI)this).Start();
				_audioRouted = CreatureAudioSetup.ConfigureSpatial(exclusiveAudioSource);
				base.enemyHP = Mathf.Max(1, Plugin.ModConfig.Health.Value);
				ConfigureSearchDefaults();
				if (((NetworkBehaviour)this).IsServer)
				{
					RepairAgentPlacementIfNeeded();
				}
				ConfigureAgent(RoamSpeed, 0f);
				slimeTrail?.Bind(this);
				if (((NetworkBehaviour)this).IsServer)
				{
					ResetIdleAudioTimer();
				}
				LogDebug($"Spawned at {((Component)this).transform.position}, HP={base.enemyHP}");
			}
			catch (Exception arg)
			{
				LogError($"EyeMonsterAI.Start: {arg}");
			}
		}

		private void CacheVisualRig()
		{
			if ((Object)(object)base.eye == (Object)null)
			{
				base.eye = ((Component)this).transform.Find("Eye");
			}
			_eyeBone = FindDescendantByExactName(((Component)this).transform, "eye");
			_upperLid = FindDescendantByExactName(((Component)this).transform, "lid_up");
			_lowerLid = FindDescendantByExactName(((Component)this).transform, "lid_down");
		}

		private static Transform FindDescendantByExactName(Transform root, string childName)
		{
			if ((Object)(object)root == (Object)null)
			{
				return null;
			}
			for (int i = 0; i < root.childCount; i++)
			{
				Transform child = root.GetChild(i);
				if (string.Equals(((Object)child).name, childName, StringComparison.OrdinalIgnoreCase))
				{
					return child;
				}
				Transform val = FindDescendantByExactName(child, childName);
				if ((Object)(object)val != (Object)null)
				{
					return val;
				}
			}
			return null;
		}

		private void LateUpdate()
		{
			try
			{
				if (!_corpseAnimatorStopped)
				{
					if (base.isEnemyDead)
					{
						UpdateDeathAnimation();
					}
					SyncEyeAnchorToBone();
					UpdateEyelidExpression();
					if (base.isEnemyDead)
					{
						TryStopCorpseAnimator();
					}
				}
			}
			catch (Exception arg)
			{
				LogError($"EyeMonsterAI.LateUpdate: {arg}");
			}
		}

		private void TryStopCorpseAnimator()
		{
			bool num = (Object)(object)base.creatureAnimator == (Object)null || _deathPoseFrozen;
			bool flag = (Object)(object)_upperLid == (Object)null || (Object)(object)_lowerLid == (Object)null || _eyelidClosure >= 1f;
			if (num && flag)
			{
				if ((Object)(object)base.creatureAnimator != (Object)null)
				{
					((Behaviour)base.creatureAnimator).enabled = false;
				}
				_corpseAnimatorStopped = true;
			}
		}

		private void SyncEyeAnchorToBone()
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)base.eye == (Object)null) && !((Object)(object)_eyeBone == (Object)null))
			{
				base.eye.position = _eyeBone.position;
				base.eye.rotation = ((Component)this).transform.rotation;
			}
		}

		private void UpdateEyelidExpression()
		{
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: 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_011c: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_upperLid == (Object)null) && !((Object)(object)_lowerLid == (Object)null))
			{
				if (!_eyelidsInitialized)
				{
					_eyelidClosure = (base.isEnemyDead ? 1f : GetDesiredEyelidClosure());
					_eyelidClosureVelocity = 0f;
					_eyelidsInitialized = true;
				}
				float num = (base.isEnemyDead ? 1f : GetDesiredEyelidClosure());
				float eyelidSmoothTime = GetEyelidSmoothTime(num);
				_eyelidClosure = Mathf.SmoothDamp(_eyelidClosure, num, ref _eyelidClosureVelocity, eyelidSmoothTime, 4f, Time.deltaTime);
				if (Mathf.Abs(_eyelidClosure - num) < 0.0005f)
				{
					_eyelidClosure = num;
				}
				float num2 = Mathf.Clamp01(_eyelidClosure);
				_upperLid.localPosition = Vector3.Lerp(UpperLidOpenPosition, UpperLidClosedPosition, num2);
				_lowerLid.localPosition = Vector3.Lerp(LowerLidOpenPosition, LowerLidClosedPosition, num2);
				_upperLid.localRotation = Quaternion.Slerp(UpperLidOpenRotation, UpperLidClosedRotation, num2);
				_lowerLid.localRotation = Quaternion.Slerp(LowerLidOpenRotation, LowerLidClosedRotation, num2);
			}
		}

		private float GetDesiredEyelidClosure()
		{
			switch (base.currentBehaviourStateIndex)
			{
			case 1:
			case 2:
			case 3:
				return 0f;
			case 4:
				return 0.72f;
			default:
				return 0.24f;
			}
		}

		private float GetEyelidSmoothTime(float desiredClosure)
		{
			if (base.isEnemyDead)
			{
				return 0.13f;
			}
			if (base.currentBehaviourStateIndex == 4)
			{
				return 0.16f;
			}
			if (desiredClosure <= 0.001f)
			{
				return 0.24f;
			}
			return 0.42f;
		}

		private void RepairAgentPlacementIfNeeded()
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: 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_006f: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)base.agent == (Object)null) && ((Behaviour)base.agent).enabled && !base.agent.isOnNavMesh)
			{
				int num = ((base.agent.areaMask == 0) ? (-1) : base.agent.areaMask);
				NavMeshHit val = default(NavMeshHit);
				if (!NavMesh.SamplePosition(((Component)this).transform.position, ref val, 4f, num))
				{
					Plugin.Log.LogWarning((object)$"[EyeMon] Could not place NavMeshAgent near spawn position {((Component)this).transform.position}.");
					return;
				}
				((Behaviour)base.agent).enabled = false;
				((Component)this).transform.position = ((NavMeshHit)(ref val)).position;
				((Behaviour)base.agent).enabled = true;
				LogDebug($"Repaired NavMeshAgent placement to {((NavMeshHit)(ref val)).position}.");
			}
		}

		public override void Update()
		{
			try
			{
				_ownership.Ensure((EnemyAI)(object)this, Plugin.Log);
				((EnemyAI)this).Update();
				if (!_audioRouted)
				{
					_audioRouted = CreatureAudioSetup.ConfigureSpatial(exclusiveAudioSource);
				}
				if (base.isEnemyDead || (Object)(object)StartOfRound.Instance == (Object)null || StartOfRound.Instance.allPlayersDead)
				{
					return;
				}
				UpdateStun();
				if (base.currentBehaviourStateIndex != 3)
				{
					_attackSwingPending = false;
				}
				UpdateWalkingAnimation();
				if (((NetworkBehaviour)this).IsServer && !_wasStunned)
				{
					if (_attackCooldownTimer > 0f)
					{
						_attackCooldownTimer -= Time.deltaTime;
					}
					TickIdleAudio();
				}
			}
			catch (Exception arg)
			{
				LogError($"EyeMonsterAI.Update: {arg}");
			}
		}

		private void UpdateStun()
		{
			StunEdge stunEdge = ((EnemyAI)(object)this).TrackStun(ref _wasStunned);
			if (stunEdge != StunEdge.None && (Object)(object)base.creatureAnimator != (Object)null)
			{
				base.creatureAnimator.SetBool("stunned", _wasStunned);
			}
			if (stunEdge == StunEdge.Started)
			{
				_attackSwingPending = false;
			}
			if (!((NetworkBehaviour)this).IsServer)
			{
				return;
			}
			if (_wasStunned)
			{
				if (stunEdge == StunEdge.Started && _attackCoroutine != null)
				{
					((MonoBehaviour)this).StopCoroutine(_attackCoroutine);
					_attackCoroutine = null;
				}
				((EnemyAI)(object)this).HoldAgent();
			}
			else if (stunEdge == StunEdge.Ended)
			{
				((EnemyAI)(object)this).ReleaseAgent();
			}
		}

		private void UpdateWalkingAnimation()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: 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_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: 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)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			Vector3 position = ((Component)this).transform.position;
			Vector3 val;
			if (_hasLastAnimationPosition)
			{
				val = position - _lastAnimationPosition;
				if (((Vector3)(ref val)).sqrMagnitude > 1E-06f)
				{
					_remoteMovingUntil = Time.time + 0.15f;
				}
			}
			_lastAnimationPosition = position;
			_hasLastAnimationPosition = true;
			if (!((Object)(object)base.creatureAnimator == (Object)null))
			{
				int num;
				if (!((NetworkBehaviour)this).IsOwner)
				{
					num = ((Time.time < _remoteMovingUntil) ? 1 : 0);
				}
				else if (AgentCanNavigate)
				{
					val = base.agent.velocity;
					num = ((((Vector3)(ref val)).sqrMagnitude > 0.01f) ? 1 : 0);
				}
				else
				{
					num = 0;
				}
				bool flag = (byte)num != 0;
				if (!base.ventAnimationFinished || base.currentBehaviourStateIndex == 3)
				{
					flag = false;
				}
				base.creatureAnimator.SetBool("isWalking", flag);
			}
		}

		public override void DoAIInterval()
		{
			try
			{
				((EnemyAI)this).DoAIInterval();
				if (!base.isEnemyDead && !((Object)(object)StartOfRound.Instance == (Object)null) && !StartOfRound.Instance.allPlayersDead && ((NetworkBehaviour)this).IsServer && !((EnemyAI)(object)this).IsStunned() && (base.currentBehaviourStateIndex == 4 || !TryBeginFlashlightFlee()))
				{
					switch (base.currentBehaviourStateIndex)
					{
					case 0:
						DoRoaming();
						break;
					case 1:
						DoInvestigating();
						break;
					case 2:
						DoChasing();
						break;
					case 4:
						DoFleeing();
						break;
					case 3:
						RecoverInterruptedAttack();
						break;
					}
				}
			}
			catch (Exception arg)
			{
				LogError($"EyeMonsterAI.DoAIInterval: {arg}");
			}
		}

		private void DoRoaming()
		{
			ConfigureAgent(RoamSpeed, 0f);
			if (!TryReseedSearchAtNoise())
			{
				StartFacilitySearchIfNeeded();
			}
			PlayerControllerB val = FindNoticeTarget();
			if (!((Object)(object)val == (Object)null))
			{
				StopFacilitySearch();
				base.targetPlayer = val;
				_gazeConfirmedForTarget = false;
				_loseTargetTimer = 0f;
				_investigationStartedAt = Time.time;
				((EnemyAI)this).SetMovingTowardsTargetPlayer(val);
				BroadcastAudioCue(AudioCue.Vocal, interrupt: true);
				((EnemyAI)this).SwitchToBehaviourState(1);
				LogDebug("Noticed " + val.playerUsername + "; beginning cautious approach.");
			}
		}

		private bool TryReseedSearchAtNoise()
		{
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			if (Time.time < _nextNoiseReseedTime || !AgentCanNavigate)
			{
				return false;
			}
			if (!_noiseMemory.TryTake(3f, out var position))
			{
				return false;
			}
			_nextNoiseReseedTime = Time.time + 4f;
			ConfigureSearchDefaults();
			((EnemyAI)this).StopSearch(base.currentSearch, true);
			((EnemyAI)this).StartSearch(position, base.currentSearch);
			LogDebug($"Heard a noise at {position}; searching there.");
			return true;
		}

		private void DoInvestigating()
		{
			//IL_0036: 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)
			if (!IsTargetable(base.targetPlayer))
			{
				DropTarget(addNoticeCooldown: false);
				return;
			}
			float num = Time.time - _investigationStartedAt;
			bool flag = num >= InvestigationTimeout;
			float num2 = Vector3.Distance(((Component)this).transform.position, ((Component)base.targetPlayer).transform.position);
			if (!(num2 <= NoticeRange * 1.75f) || !HasClearSightToPlayer(base.targetPlayer))
			{
				_loseTargetTimer += base.AIIntervalTime;
				if (_loseTargetTimer >= LoseTargetSeconds || flag)
				{
					DropTarget(addNoticeCooldown: true);
				}
				return;
			}
			_loseTargetTimer = 0f;
			ConfigureAgent(InvestigateSpeed, InvestigationStopDistance);
			((EnemyAI)this).SetMovingTowardsTargetPlayer(base.targetPlayer);
			if ((num2 <= InvestigationStopDistance + 1f || AgentHasStopped() || flag) && !(num < InvestigationDecisionDelay))
			{
				StopAgentPath();
				FaceTarget(base.targetPlayer);
				if (IsMutualGaze(base.targetPlayer))
				{
					_gazeConfirmedForTarget = true;
					BroadcastAudioCue(AudioCue.Vocal, interrupt: true);
					ConfigureAgent(ChaseSpeed, Mathf.Max(0.25f, AttackRange * 0.65f));
					((EnemyAI)this).SwitchToBehaviourState(2);
					LogDebug(base.targetPlayer.playerUsername + " looked at the eye; aggro confirmed.");
				}
				else
				{
					LogDebug(base.targetPlayer.playerUsername + " refused eye contact; forgetting target.");
					DropTarget(addNoticeCooldown: true);
				}
			}
		}

		private void DoChasing()
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			if (!IsTargetable(base.targetPlayer) || !_gazeConfirmedForTarget)
			{
				DropTarget(addNoticeCooldown: false);
				return;
			}
			float num = Vector3.Distance(((Component)this).transform.position, ((Component)base.targetPlayer).transform.position);
			if (!(num <= NoticeRange * 1.75f) || !HasClearSightToPlayer(base.targetPlayer))
			{
				_loseTargetTimer += base.AIIntervalTime;
				if (_loseTargetTimer >= LoseTargetSeconds)
				{
					LogDebug($"Lost {base.targetPlayer.playerUsername} after {_loseTargetTimer:F1}s.");
					DropTarget(addNoticeCooldown: false);
					return;
				}
			}
			else
			{
				_loseTargetTimer = 0f;
			}
			ConfigureAgent(ChaseSpeed, Mathf.Max(0.25f, AttackRange * 0.65f));
			((EnemyAI)this).SetMovingTowardsTargetPlayer(base.targetPlayer);
			if (num <= AttackRange && _attackCooldownTimer <= 0f)
			{
				EnterAttacking();
			}
		}

		private void EnterAttacking()
		{
			if (_gazeConfirmedForTarget && IsTargetable(base.targetPlayer))
			{
				StopAgentPath();
				((EnemyAI)this).SwitchToBehaviourState(3);
				PlayAttackAnimationClientRpc();
				if (_attackCoroutine != null)
				{
					((MonoBehaviour)this).StopCoroutine(_attackCoroutine);
				}
				_attackCoroutine = ((MonoBehaviour)this).StartCoroutine(AttackRoutine());
			}
		}

		private IEnumerator AttackRoutine()
		{
			try
			{
				_attackCooldownTimer = AttackCooldown;
			}
			catch (Exception arg)
			{
				LogError($"AttackRoutine begin: {arg}");
				_attackCoroutine = null;
				yield break;
			}
			yield return (object)new WaitForSeconds(AttackCooldown);
			try
			{
				if (base.isEnemyDead || base.currentBehaviourStateIndex == 4)
				{
					_attackCoroutine = null;
					yield break;
				}
				if (!IsTargetable(base.targetPlayer) || !_gazeConfirmedForTarget)
				{
					DropTarget(addNoticeCooldown: false);
				}
				else if (Vector3.Distance(((Component)this).transform.position, ((Component)base.targetPlayer).transform.position) <= NoticeRange * 1.75f)
				{
					((EnemyAI)this).SwitchToBehaviourState(2);
				}
				else
				{
					DropTarget(addNoticeCooldown: false);
				}
			}
			catch (Exception arg2)
			{
				LogError($"AttackRoutine end: {arg2}");
			}
			_attackCoroutine = null;
		}

		private void RecoverInterruptedAttack()
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			if (_attackCoroutine == null)
			{
				if (IsTargetable(base.targetPlayer) && _gazeConfirmedForTarget && Vector3.Distance(((Component)this).transform.position, ((Component)base.targetPlayer).transform.position) <= NoticeRange * 1.75f)
				{
					((EnemyAI)this).SwitchToBehaviourState(2);
				}
				else
				{
					DropTarget(addNoticeCooldown: false);
				}
			}
		}

		[ClientRpc]
		public void PlayAttackAnimationClientRpc()
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Invalid comparison between Unknown and I4
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Invalid comparison between Unknown and I4
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager;
			if (networkManager == null || !networkManager.IsListening)
			{
				return;
			}
			if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 && (networkManager.IsServer || networkManager.IsHost))
			{
				ClientRpcParams val2 = default(ClientRpcParams);
				FastBufferWriter val = ((NetworkBehaviour)this).__beginSendClientRpc(1996458905u, val2, (RpcDelivery)0);
				((NetworkBehaviour)this).__endSendClientRpc(ref val, 1996458905u, val2, (RpcDelivery)0);
			}
			if ((int)((NetworkBehaviour)this).__rpc_exec_stage == 1 && (networkManager.IsClient || networkManager.IsHost))
			{
				((NetworkBehaviour)this).__rpc_exec_stage = (__RpcExecStage)0;
				if (!base.isEnemyDead && !((Object)(object)base.creatureAnimator == (Object)null))
				{
					_attackSwingPending = true;
					base.creatureAnimator.SetTrigger("doAttack");
				}
			}
		}

		private PlayerControllerB FindNoticeTarget()
		{
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: 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)
			if ((Object)(object)StartOfRound.Instance == (Object)null || StartOfRound.Instance.allPlayerScripts == null)
			{
				return null;
			}
			PlayerControllerB result = null;
			float num = float.PositiveInfinity;
			float num2 = NoticeRange * NoticeRange;
			PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts;
			foreach (PlayerControllerB val in allPlayerScripts)
			{
				if (IsTargetable(val) && !IsNoticeCoolingDown(val))
				{
					Vector3 val2 = (((Object)(object)val.gameplayCamera != (Object)null) ? ((Component)val.gameplayCamera).transform.position : (((Component)val).transform.position + Vector3.up));
					Vector3 val3 = val2 - GetEyeFocusPosition();
					float sqrMagnitude = ((Vector3)(ref val3)).sqrMagnitude;
					if (!(sqrMagnitude > num2) && !(sqrMagnitude >= num) && ((EnemyAI)this).CheckLineOfSightForPosition(val2, NoticeViewAngle, Mathf.CeilToInt(NoticeRange), -1f, base.eye))
					{
						result = val;
						num = sqrMagnitude;
					}
				}
			}
			return result;
		}

		private bool IsMutualGaze(PlayerControllerB player)
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_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_0083: Unknown result type (might be due to invalid IL or missing references)
			if (!IsTargetable(player))
			{
				return false;
			}
			Vector3 val = (((Object)(object)player.gameplayCamera != (Object)null) ? ((Component)player.gameplayCamera).transform.position : (((Component)player).transform.position + Vector3.up)) - GetEyeFocusPosition();
			if (!(((Vector3)(ref val)).sqrMagnitude > 0.001f) || !(Vector3.Angle(((Component)this).transform.forward, val) <= NoticeViewAngle) || !HasClearSightToPlayer(player))
			{
				return false;
			}
			return player.HasLineOfSightToPosition(GetEyeFocusPosition(), PlayerGazeAngle, Mathf.CeilToInt(NoticeRange + 6f), -1f, -1);
		}

		private bool HasClearSightToPlayer(PlayerControllerB player)
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: 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)
			if (!IsTargetable(player))
			{
				return false;
			}
			Vector3 val = (((Object)(object)player.gameplayCamera != (Object)null) ? ((Component)player.gameplayCamera).transform.position : (((Component)player).transform.position + Vector3.up));
			return ((EnemyAI)this).CheckLineOfSightForPosition(val, 180f, Mathf.CeilToInt(NoticeRange * 1.75f), -1f, base.eye);
		}

		private Vector3 GetEyeFocusPosition()
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: 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_0028: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)base.eye != (Object)null))
			{
				return ((Component)this).transform.position + Vector3.up * 1.45f;
			}
			return base.eye.position;
		}

		private bool IsTargetable(PlayerControllerB player)
		{
			if ((Object)(object)player != (Object)null)
			{
				return ((EnemyAI)this).PlayerIsTargetable(player, false, false, true);
			}
			return false;
		}

		private static bool IsLivingPlayer(PlayerControllerB player)
		{
			if ((Object)(object)player != (Object)null && player.isPlayerControlled)
			{
				return !player.isPlayerDead;
			}
			return false;
		}

		private bool AgentHasStopped()
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			if (AgentCanNavigate && !base.agent.pathPending && base.agent.remainingDistance <= base.agent.stoppingDistance + 0.25f)
			{
				Vector3 velocity = base.agent.velocity;
				return ((Vector3)(ref velocity)).sqrMagnitude < 0.04f;
			}
			return false;
		}

		private bool IsNoticeCoolingDown(PlayerControllerB player)
		{
			if ((Object)(object)player == (Object)null)
			{
				return false;
			}
			if (_noticeCooldownUntil.TryGetValue(player.actualClientId, out var value))
			{
				return Time.time < value;
			}
			return false;
		}

		private void DropTarget(bool addNoticeCooldown)
		{
			PlayerControllerB targetPlayer = base.targetPlayer;
			if (addNoticeCooldown && (Object)(object)targetPlayer != (Object)null)
			{
				_noticeCooldownUntil[targetPlayer.actualClientId] = Time.time + FailedNoticeCooldown;
			}
			base.targetPlayer = null;
			base.movingTowardsTargetPlayer = false;
			_gazeConfirmedForTarget = false;
			_loseTargetTimer = 0f;
			if (_attackCoroutine != null)
			{
				((MonoBehaviour)this).StopCoroutine(_attackCoroutine);
				_attackCoroutine = null;
			}
			ConfigureAgent(RoamSpeed, 0f);
			if (base.currentBehaviourStateIndex != 0)
			{
				((EnemyAI)this).SwitchToBehaviourState(0);
			}
		}

		private void FaceTarget(PlayerControllerB player)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: 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_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: 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)
			if (!((Object)(object)player == (Object)null))
			{
				Vector3 val = ((Component)player).transform.position - ((Component)this).transform.position;
				val.y = 0f;
				if (!(((Vector3)(ref val)).sqrMagnitude < 0.001f))
				{
					Quaternion rotation = Quaternion.LookRotation(((Vector3)(ref val)).normalized, Vector3.up);
					((Component)this).transform.rotation = rotation;
				}
			}
		}

		private void ConfigureSearchDefaults()
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Expected O, but got Unknown
			if (base.currentSearch == null)
			{
				base.currentSearch = new AISearchRoutine();
			}
			base.currentSearch.loopSearch = true;
			base.currentSearch.randomized = true;
			base.currentSearch.searchWidth = 200f;
			base.currentSearch.searchPrecision = 5f;
		}

		private void StartFacilitySearchIfNeeded()
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			if (((NetworkBehaviour)this).IsServer && AgentCanNavigate)
			{
				ConfigureSearchDefaults();
				if (!base.currentSearch.inProgress)
				{
					((EnemyAI)this).StartSearch(((Component)this).transform.position, base.currentSearch);
				}
			}
		}

		private void StopFacilitySearch()
		{
			if (base.currentSearch != null && base.currentSearch.inProgress)
			{
				((EnemyAI)this).StopSearch(base.currentSearch, false);
			}
		}

		private void ConfigureAgent(float speed, float stoppingDistance)
		{
			if (AgentCanNavigate)
			{
				base.agent.speed = speed;
				base.agent.stoppingDistance = stoppingDistance;
			}
		}

		private void StopAgentPath()
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			base.movingTowardsTargetPlayer = false;
			if (AgentCanNavigate)
			{
				base.agent.ResetPath();
				base.agent.velocity = Vector3.zero;
				base.agent.speed = 0f;
			}
		}

		private bool TryBeginFlashlightFlee()
		{
			//IL_0056: 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)
			_lightCheckTimer += base.AIIntervalTime;
			if (_lightCheckTimer < 0.2f)
			{
				return false;
			}
			_lightCheckTimer = 0f;
			if (!TryGetFlashlightThreat(out var threatPosition, out var threatPlayer))
			{
				return false;
			}
			if ((Object)(object)threatPlayer != (Object)null)
			{
				_lastLightThreatPosition = ((Component)threatPlayer).transform.position;
			}
			StartFleeFrom(threatPosition);
			return true;
		}

		private void DoFleeing()
		{
			ConfigureAgent(FleeSpeed, 0f);
			TryRefreshFlashlightFlee();
			_fleeTimer -= base.AIIntervalTime;
			if (_fleeTimer <= 0f)
			{
				LogDebug("Flashlight flee expired; returning to facility search.");
				DropTarget(addNoticeCooldown: false);
			}
		}

		private void TryRefreshFlashlightFlee()
		{
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			_lightCheckTimer += base.AIIntervalTime;
			if (_lightCheckTimer < 0.2f)
			{
				return;
			}
			_lightCheckTimer = 0f;
			if (TryGetFlashlightThreat(out var threatPosition, out var threatPlayer))
			{
				if ((Object)(object)threatPlayer != (Object)null)
				{
					_lastLightThreatPosition = ((Component)threatPlayer).transform.position;
				}
				StartFleeFrom(threatPosition);
			}
		}

		private void StartFleeFrom(Vector3 threatPosition)
		{
			//IL_008b: 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_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			bool num = base.currentBehaviourStateIndex != 4;
			_fleeTimer = FleeDuration;
			base.targetPlayer = null;
			base.movingTowardsTargetPlayer = false;
			_gazeConfirmedForTarget = false;
			_loseTargetTimer = 0f;
			if (_attackCoroutine != null)
			{
				((MonoBehaviour)this).StopCoroutine(_attackCoroutine);
				_attackCoroutine = null;
			}
			StopFacilitySearch();
			ConfigureAgent(FleeSpeed, 0f);
			if (num || Time.time >= _nextFleeRouteTime)
			{
				_nextFleeRouteTime = Time.time + 1f;
				Vector3 threat = ((threatPosition == Vector3.zero) ? _lastLightThreatPosition : threatPosition);
				if (!TrySetFleeRoute(threat) && AgentCanNavigate)
				{
					((EnemyAI)this).SetDestinationToPosition(((Component)this).transform.position, false);
				}
			}
			if (num)
			{
				((EnemyAI)this).SwitchToBehaviourState(4);
			}
		}

		private bool TrySetFleeRoute(Vector3 threat)
		{
			//IL_001e: 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_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: 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_0048: 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)
			//IL_0054: 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_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: 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_010d: 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_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: 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_00cb: 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_00ce: 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)
			GameObject[] allAINodes = base.allAINodes;
			if (!AgentCanNavigate || allAINodes == null || allAINodes.Length == 0)
			{
				return false;
			}
			Vector3 position = ((Component)this).transform.position;
			Vector3 val = position - threat;
			float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude;
			Vector2 val2 = new Vector2(position.x - threat.x, position.z - threat.z);
			float magnitude = ((Vector2)(ref val2)).magnitude;
			float num = 1600f;
			float num2 = float.PositiveInfinity;
			int num3 = -1;
			for (int i = 0; i < 6; i++)
			{
				int num4 = -1;
				float num5 = sqrMagnitude;
				for (int j = 0; j < allAINodes.Length; j++)
				{
					GameObject val3 = allAINodes[j];
					if ((Object)(object)val3 == (Object)null)
					{
						continue;
					}
					Vector3 position2 = val3.transform.position;
					val = position2 - threat;
					float sqrMagnitude2 = ((Vector3)(ref val)).sqrMagnitude;
					if (!(sqrMagnitude2 <= num5) && !(sqrMagnitude2 > num2) && (sqrMagnitude2 != num2 || j > num3))
					{
						val = position2 - position;
						if (!(((Vector3)(ref val)).sqrMagnitude > num))
						{
							num4 = j;
							num5 = sqrMagnitude2;
						}
					}
				}
				if (num4 < 0)
				{
					return false;
				}
				num2 = num5;
				num3 = num4;
				Vector3 position3 = allAINodes[num4].transform.position;
				if (!((EnemyAI)this).PathIsIntersectedByLineOfSight(position3, false, false, false) && !PathClosesOnThreat(threat, magnitude))
				{
					((EnemyAI)this).SetDestinationToPosition(position3, false);
					return true;
				}
			}
			return false;
		}

		private bool PathClosesOnThreat(Vector3 threat, float currentDistance)
		{
			//IL_0042: 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_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: 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_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: 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)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			float num = Mathf.Min(2.5f, currentDistance - 0.1f);
			if (num <= 0f || base.path1 == null)
			{
				return false;
			}
			Vector3[] storedPathCorners = RoundManager.Instance.storedPathCorners;
			int cornersNonAlloc = base.path1.GetCornersNonAlloc(storedPathCorners);
			float num2 = num * num;
			Vector3 val = default(Vector3);
			((Vector3)(ref val))..ctor(threat.x, 0f, threat.z);
			Vector3 val2 = default(Vector3);
			for (int i = 1; i < cornersNonAlloc; i++)
			{
				((Vector3)(ref val2))..ctor(storedPathCorners[i - 1].x, 0f, storedPathCorners[i - 1].z);
				Vector3 val3 = new Vector3(storedPathCorners[i].x, 0f, storedPathCorners[i].z) - val2;
				float sqrMagnitude = ((Vector3)(ref val3)).sqrMagnitude;
				float num3 = ((sqrMagnitude > 0.0001f) ? Mathf.Clamp01(Vector3.Dot(val - val2, val3) / sqrMagnitude) : 0f);
				Vector3 val4 = val2 + val3 * num3 - val;
				if (((Vector3)(ref val4)).sqrMagnitude < num2)
				{
					return true;
				}
			}
			return false;
		}

		private bool TryGetFlashlightThreat(out Vector3 threatPosition, out PlayerControllerB threatPlayer)
		{
			//IL_0001: 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_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			threatPosition = Vector3.zero;
			threatPlayer = null;
			if ((Object)(object)StartOfRound.Instance == (Object)null || StartOfRound.Instance.allPlayerScripts == null)
			{
				return false;
			}
			float angleCosine = Mathf.Cos(Mathf.Clamp(FlashlightDetectionAngle, 1f, 89f) * (MathF.PI / 180f));
			PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts;
			foreach (PlayerControllerB val in allPlayerScripts)
			{
				if (IsLivingPlayer(val) && (CheckFlashlightSource(val, FlashlightDetectionRange, angleCosine, out threatPosition) || CheckHelmetLight(val, FlashlightDetectionRange, angleCosine, out threatPosition)))
				{
					threatPlayer = val;
					_lastLightThreatPosition = threatPosition;
					return true;
				}
			}
			return false;
		}

		private bool CheckFlashlightSource(PlayerControllerB player, float range, float angleCosine, out Vector3 sourcePosition)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: 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_00c8: Unknown result type (might be due to invalid IL or missing references)
			sourcePosition = Vector3.zero;
			GrabbableObject currentlyHeldObjectServer = player.currentlyHeldObjectServer;
			FlashlightItem val = (FlashlightItem)(object)((currentlyHeldObjectServer is FlashlightItem) ? currentlyHeldObjectServer : null);
			if ((Object)(object)val == (Object)null || !((GrabbableObject)val).isBeingUsed)
			{
				return false;
			}
			Transform val2 = (((Object)(object)val.flashlightBulb != (Object)null) ? ((Component)val.flashlightBulb).transform : ((Component)val).transform);
			if (CheckLightBeam(val2.position, val2.forward, GetEyeFocusPosition(), range, angleCosine))
			{
				sourcePosition = val2.position;
				return true;
			}
			if ((Object)(object)val.flashlightBulbGlow != (Object)null && CheckLightBeam(((Component)val.flashlightBulbGlow).transform.position, ((Component)val.flashlightBulbGlow).transform.forward, GetEyeFocusPosition(), range, angleCosine))
			{
				sourcePosition = ((Component)val.flashlightBulbGlow).transform.position;
				return true;
			}
			return false;
		}

		private bool CheckHelmetLight(PlayerControllerB player, float range, float angleCosine, out Vector3 sourcePosition)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: 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)
			sourcePosition = Vector3.zero;
			Light helmetLight = player.helmetLight;
			if ((Object)(object)helmetLight == (Object)null || !((Behaviour)helmetLight).enabled || helmetLight.intensity <= 0f)
			{
				return false;
			}
			Transform val = (((Object)(object)player.gameplayCamera != (Object)null) ? ((Component)player.gameplayCamera).transform : ((Component)helmetLight).transform);
			if (!CheckLightBeam(val.position, val.forward, GetEyeFocusPosition(), range, angleCosine))
			{
				return false;
			}
			sourcePosition = val.position;
			return true;
		}

		private bool CheckLightBeam(Vector3 sourcePosition, Vector3 sourceForward, Vector3 detectionPoint, float range, float angleCosine)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: 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_0039: 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)
			Vector3 val = detectionPoint - sourcePosition;
			float magnitude = ((Vector3)(ref val)).magnitude;
			if (magnitude <= 0.01f || magnitude > range)
			{
				return false;
			}
			Vector3 val2 = val / magnitude;
			if (Vector3.Dot(((Vector3)(ref sourceForward)).normalized, val2) > angleCosine)
			{
				return HasClearLightPath(sourcePosition, detectionPoint);
			}
			return false;
		}

		private bool HasClearLightPath(Vector3 sourcePosition, Vector3 detectionPoint)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: 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_0029: 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_002c: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)StartOfRound.Instance == (Object)null)
			{
				return true;
			}
			Vector3 val = detectionPoint - sourcePosition;
			float magnitude = ((Vector3)(ref val)).magnitude;
			if (magnitude <= 0.01f)
			{
				return true;
			}
			int num = Physics.RaycastNonAlloc(sourcePosition, val / magnitude, LightPathHits, magnitude, StartOfRound.Instance.collidersAndRoomMaskAndDefault, (QueryTriggerInteraction)1);
			for (int i = 0; i < num; i++)
			{
				Collider collider = ((RaycastHit)(ref LightPathHits[i])).collider;
				if (!((Object)(object)collider == (Object)null) && !((Component)collider).transform.IsChildOf(((Component)this).transform))
				{
					return false;
				}
			}
			return true;
		}

		private void TickIdleAudio()
		{
			if (!(Time.time < _nextIdleAudioTime))
			{
				ResetIdleAudioTimer();
				if (base.currentBehaviourStateIndex == 0 || base.currentBehaviourStateIndex == 1)
				{
					BroadcastAudioCue(AudioCue.Idle, interrupt: false);
				}
			}
		}

		private void ResetIdleAudioTimer()
		{
			_nextIdleAudioTime = Time.time + Random.Range(7.5f, 14f);
		}

		private void BroadcastAudioCue(AudioCue cue, bool interrupt)
		{
			if (!base.isEnemyDead)
			{
				AudioClip[] audioPool = GetAudioPool(cue);
				if (audioPool != null && audioPool.Length != 0)
				{
					int num = ChooseAudioIndex(audioPool, _lastAudioIndices[(int)cue]);
					_lastAudioIndices[(int)cue] = num;
					PlayAudioCueClientRpc((int)cue, num, interrupt);
				}
			}
		}

		[ClientRpc]
		public void PlayAudioCueClientRpc(int cueValue, int clipIndex, bool interrupt)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Invalid comparison between Unknown and I4
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Invalid comparison between Unknown and I4
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: 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_0097: 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_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager;
			if (networkManager == null || !networkManager.IsListening)
			{
				return;
			}
			if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 && (networkManager.IsServer || networkManager.IsHost))
			{
				ClientRpcParams val2 = default(ClientRpcParams);
				FastBufferWriter val = ((NetworkBehaviour)this).__beginSendClientRpc(3333831235u, val2, (RpcDelivery)0);
				BytePacker.WriteValueBitPacked(val, cueValue);
				BytePacker.WriteValueBitPacked(val, clipIndex);
				((FastBufferWriter)(ref val)).WriteValueSafe<bool>(ref interrupt, default(ForPrimitives));
				((NetworkBehaviour)this).__endSendClientRpc(ref val, 3333831235u, val2, (RpcDelivery)0);
			}
			if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 || (!networkManager.IsClient && !networkManager.IsHost))
			{
				return;
			}
			((NetworkBehaviour)this).__rpc_exec_stage = (__RpcExecStage)0;
			if (base.isEnemyDead || !Enum.IsDefined(typeof(AudioCue), cueValue))
			{
				return;
			}
			AudioClip[] audioPool = GetAudioPool((AudioCue)cueValue);
			if (audioPool != null && clipIndex >= 0 && clipIndex < audioPool.Length)
			{
				AudioClip val3 = audioPool[clipIndex];
				if (CreatureAudio.PlayExclusive(exclusiveAudioSource, val3, interrupt))
				{
					WalkieTalkie.TransmitOneShotAudio(exclusiveAudioSource, val3, 1f);
				}
			}
		}

		private AudioClip[] GetAudioPool(AudioCue cue)
		{
			return cue switch
			{
				AudioCue.Idle => idleClips, 
				AudioCue.Vocal => vocalClips, 
				AudioCue.PlayerHit => playerHitClips, 
				AudioCue.Step => runStepClips, 
				_ => null, 
			};
		}

		private static int ChooseAudioIndex(AudioClip[] pool, int previous)
		{
			if (pool == null || pool.Length <= 1)
			{
				return 0;
			}
			int num = Random.Range(0, pool.Length);
			if (num == previous)
			{
				num = (num + Random.Range(1, pool.Length)) % pool.Length;
			}
			return num;
		}

		public void Anim_RunStep()
		{
			try
			{
				if (!base.isEnemyDead && base.currentBehaviourStateIndex != 3 && runStepClips != null && runStepClips.Length != 0)
				{
					int num = ChooseAudioIndex(runStepClips, _lastAudioIndices[3]);
					AudioClip val = runStepClips[num];
					if (CreatureAudio.PlayExclusive(exclusiveAudioSource, val, interrupt: false))
					{
						_lastAudioIndices[3] = num;
						WalkieTalkie.TransmitOneShotAudio(exclusiveAudioSource, val, 1f);
					}
				}
			}
			catch (Exception arg)
			{
				LogError($"Anim_RunStep: {arg}");
			}
		}

		public void Anim_AttackDamage()
		{
			//IL_0066: 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_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: 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_00ea: 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_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_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)
			try
			{
				_attackSwingPending = false;
				if (!((NetworkBehaviour)this).IsServer || base.isEnemyDead || ((EnemyAI)(object)this).IsStunned() || !_gazeConfirmedForTarget || !IsTargetable(base.targetPlayer) || base.currentBehaviourStateIndex == 4)
				{
					return;
				}
				if (TryGetFlashlightThreat(out var threatPosition, out var _))
				{
					StartFleeFrom(threatPosition);
				}
				else if (!(Vector3.Distance(((Component)this).transform.position, ((Component)base.targetPlayer).transform.position) > AttackRange * 1.5f) && HasClearSightToPlayer(base.targetPlayer))
				{
					Vector3 force = ((Component)base.targetPlayer).transform.position - ((Component)this).transform.position;
					force.y = 0f;
					if (((Vector3)(ref force)).sqrMagnitude < 0.01f)
					{
						force = ((Component)this).transform.forward;
					}
					force = ((Vector3)(ref force)).normalized * 12f;
					ApplyAttackDamageClientRpc(base.targetPlayer.actualClientId, AttackDamage, force, VictimRpc.TargetOnly(base.targetPlayer));
					BroadcastAudioCue(AudioCue.PlayerHit, interrupt: true);
				}
			}
			catch (Exception arg)
			{
				LogError($"Anim_AttackDamage: {arg}");
			}
		}

		[ClientRpc]
		public void ApplyAttackDamageClientRpc(ulong targetClientId, int damage, Vector3 force, ClientRpcParams clientRpcParams = default(ClientRpcParams))
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Invalid comparison between Unknown and I4
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Invalid comparison between Unknown and I4
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: 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_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager;
			if (networkManager == null || !networkManager.IsListening)
			{
				return;
			}
			if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 && (networkManager.IsServer || networkManager.IsHost))
			{
				FastBufferWriter val = ((NetworkBehaviour)this).__beginSendClientRpc(3973268519u, clientRpcParams, (RpcDelivery)0);
				BytePacker.WriteValueBitPacked(val, targetClientId);
				BytePacker.WriteValueBitPacked(val, damage);
				((FastBufferWriter)(ref val)).WriteValueSafe(ref force);
				((NetworkBehaviour)this).__endSendClientRpc(ref val, 3973268519u, clientRpcParams, (RpcDelivery)0);
			}
			if ((int)((NetworkBehaviour)this).__rpc_exec_stage == 1 && (networkManager.IsClient || networkManager.IsHost))
			{
				((NetworkBehaviour)this).__rpc_exec_stage = (__RpcExecStage)0;
				PlayerControllerB val2 = (((Object)(object)GameNetworkManager.Instance != (Object)null) ? GameNetworkManager.Instance.localPlayerController : null);
				if (!((Object)(object)val2 == (Object)null) && !val2.isPlayerDead && VictimRpc.IsLocalVictim(targetClientId))
				{
					val2.DamagePlayer(damage, true, true, (CauseOfDeath)6, 0, false, force);
				}
			}
		}

		public override void DetectNoise(Vector3 noisePosition, float noiseLoudness, int timesPlayedInOneSpot = 0, int noiseID = 0)
		{
			//IL_0001: 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_0042: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				((EnemyAI)this).DetectNoise(noisePosition, noiseLoudness, timesPlayedInOneSpot, noiseID);
				if (((NetworkBehaviour)this).IsServer && !base.isEnemyDead && !((EnemyAI)(object)this).IsStunned() && timesPlayedInOneSpot <= 10 && base.currentBehaviourStateIndex == 0)
				{
					_noiseMemory.Record(noisePosition, noiseLoudness, 0.5f, GetEyeFocusPosition(), 20f);
				}
			}
			catch (Exception arg)
			{
				LogError($"EyeMonsterAI.DetectNoise: {arg}");
			}
		}

		public override void HitEnemy(int force = 1, PlayerControllerB playerWhoHit = null, bool playHitSFX = false, int hitID = -1)
		{
			try
			{
				((EnemyAI)this).HitEnemy(force, playerWhoHit, playHitSFX, hitID);
				if (base.isEnemyDead)
				{
					return;
				}
				base.enemyHP -= force;
				if (base.enemyHP <= 0)
				{
					if (((NetworkBehaviour)this).IsOwner)
					{
						((EnemyAI)this).KillEnemyOnOwnerClient(false);
					}
					return;
				}
				if ((Object)(object)base.creatureAnimator != (Object)null && (!_attackSwingPending || base.currentBehaviourStateIndex != 3))
				{
					base.creatureAnimator.SetTrigger("doHit");
				}
				if (((NetworkBehaviour)this).IsServer)
				{
					RetaliateAgainst(playerWhoHit);
				}
			}
			catch (Exception arg)
			{
				LogError($"EyeMonsterAI.HitEnemy: {arg}");
			}
		}

		private void RetaliateAgainst(PlayerControllerB attacker)
		{
			if (IsTargetable(attacker) && base.currentBehaviourStateIndex != 4 && base.currentBehaviourStateIndex != 3)
			{
				StopFacilitySearch();
				((EnemyAI)this).SetMovingTowardsTargetPlayer(attacker);
				_gazeConfirmedForTarget = true;
				_loseTargetTimer = 0f;
				ConfigureAgent(ChaseSpeed, Mathf.Max(0.25f, AttackRange * 0.65f));
				if (base.currentBehaviourStateIndex != 2)
				{
					((EnemyAI)this).SwitchToBehaviourState(2);
				}
				LogDebug("Hit by " + attacker.playerUsername + "; retaliating.");
			}
		}

		public override void KillEnemy(bool destroy = false)
		{
			try
			{
				bool flag = destroy && base.enemyType.canBeDestroyed;
				if (base.isEnemyDead && !flag)
				{
					return;
				}
				if (!flag && base.enemyType.canDie)
				{
					CreatureAudio.Stop(exclusiveAudioSource);
				}
				((EnemyAI)this).KillEnemy(destroy);
				if (!(!base.isEnemyDead || flag))
				{
					_attackSwingPending = false;
					UpdateDeathAnimation();
					StopFacilitySearch();
					StopAgentPath();
					base.targetPlayer = null;
					_gazeConfirmedForTarget = false;
					if (_attackCoroutine != null)
					{
						((MonoBehaviour)this).StopCoroutine(_attackCoroutine);
						_attackCoroutine = null;
					}
				}
			}
			catch (Exception arg)
			{
				LogError($"EyeMonsterAI.KillEnemy: {arg}");
			}
		}

		private void UpdateDeathAnimation()
		{
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)base.creatureAnimator == (Object)null || _deathPoseFrozen)
			{
				return;
			}
			if (!_deathAnimationStarted)
			{
				PlayDeathAnimation(base.creatureAnimator);
				_deathAnimationStarted = true;
			}
			else if (!base.creatureAnimator.IsInTransition(0))
			{
				AnimatorStateInfo currentAnimatorStateInfo = base.creatureAnimator.GetCurrentAnimatorStateInfo(0);
				if (((AnimatorStateInfo)(ref currentAnimatorStateInfo)).IsName("Base Layer.DeadIdle"))
				{
					base.creatureAnimator.speed = 0f;
					_deathPoseFrozen = true;
				}
			}
		}

		private static void PlayDeathAnimation(Animator animator)
		{
			((Behaviour)animator).enabled = true;
			animator.cullingMode = (AnimatorCullingMode)0;
			animator.speed = 1f;
			animator.SetBool("isWalking", false);
			animator.SetBool("Dead", true);
			animator.ResetTrigger("doAttack");
			animator.ResetTrigger("doHit");
			animator.ResetTrigger("doDeath");
			animator.ResetTrigger("KillEnemy");
			animator.Play("Base Layer.Dead", 0, 0f);
		}

		public override void OnDestroy()
		{
			CreatureAudio.Stop(exclusiveAudioSource);
			((EnemyAI)this).OnDestroy();
		}

		protected override void __initializeVariables()
		{
			((EnemyAI)this).__initializeVariables();
		}

		protected override void __initiali

SimonSays.dll

Decompiled a week ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using Dawn;
using GameNetcodeStuff;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using SimonSays.AI;
using SimonSays.NetcodePatcher;
using SimonSays.Utils;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.Audio;
using UnityEngine.Networking;
using UnityEngine.Rendering;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
using Y4NGZMonsters.Shared;

[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("SimonSays")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+c64a155fd64c47528940e53659e5b5ada665b9d4")]
[assembly: AssemblyProduct("SimonSays")]
[assembly: AssemblyTitle("SimonSays")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
[module: NetcodePatchedAssembly]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.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 SimonSays
{
	[BepInPlugin("y4ngz.lethalcompany.simonsays", "Y4NGZ Simon Says", "1.2.1")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		internal const string DisplayName = "Simon Says";

		internal const string DawnNamespace = "y4ngz_monsters";

		internal const string DawnEnemyKey = "simon_says";

		internal const string TerminalKeyword = "simon";

		internal const string ScanNodeSubtitle = "Only obey when Simon says";

		internal const string BestiaryText = "Simon Says\n\nDanger level: 100%\n\nSigurd's notes: It's a wheeled jester cart with a clockwork skull. It picks one crew member, puts a spotlight on them, and plays a game. Three commands. It cannot be killed, and when it is done it leaves in a cloud of smoke.\n\nThe rule is the whole trick: only obey a command it prefixes with \"Simon says\". Obey one it does not, and it kills you for it. Ignore one it does, and it kills you for that too. Listen for the words \"and\" (either order) versus \"then\" (that order).\n\n";

		internal static ManualLogSource Log;

		private static bool _loggedScanNodeLayer;

		internal static SimonSaysConfig ModConfig;

		internal static AssetBundle ModAssets;

		internal static EnemyType SimonSaysEnemy;

		internal static AudioClip LetsPlayClip;

		internal static AudioClip SimonSaysWordClip;

		internal static AudioClip AndClip;

		internal static AudioClip ThenClip;

		internal static AudioClip CongratulationsClip;

		internal static AudioClip GoodbyeClip;

		private static readonly AudioClip[] _actionClips = (AudioClip[])(object)new AudioClip[4];

		internal static AudioClip SpotlightStartClip;

		internal static GameObject VanishSmokePrefab;

		private const string SpotlightStartSfxFileName = "simon_says_spotlight.mp3";

		private static bool _netcodeInitialized = false;

		private Harmony _harmony;

		internal static AudioClip ActionClip(ActionType action)
		{
			if (action < ActionType.Jump || (int)action >= _actionClips.Length)
			{
				return null;
			}
			return _actionClips[(int)action];
		}

		private void Awake()
		{
			//IL_01f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0200: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			try
			{
				InitializeNetcodeRPCs();
				ModConfig = new SimonSaysConfig(((BaseUnityPlugin)this).Config);
				string directoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
				((MonoBehaviour)this).StartCoroutine(LoadSpotlightStartClip(directoryName));
				string text = Path.Combine(directoryName, "simonsays.bundle");
				ModAssets = AssetBundle.LoadFromFile(text);
				if ((Object)(object)ModAssets == (Object)null)
				{
					Log.LogError((object)("Failed to load asset bundle at: " + text));
					return;
				}
				GameObject val = LoadEnemyPrefab();
				if ((Object)(object)val == (Object)null)
				{
					Log.LogError((object)"Failed to load SimonSays prefab from bundle. Available assets:");
					string[] allAssetNames = ModAssets.GetAllAssetNames();
					foreach (string text2 in allAssetNames)
					{
						Log.LogError((object)("  - " + text2));
					}
					return;
				}
				Log.LogInfo((object)("Loaded prefab '" + ((Object)val).name + "' with " + $"{val.GetComponents<Component>().Length} root components."));
				LoadAudioFromBundle();
				LoadEffectsFromBundle();
				AssignUniqueNetworkHash(val);
				RebindTexturesFromBundle(val);
				SetupPrefabComponents(val);
				SimonSaysEnemy = CreateEnemyType(val);
				SimonSaysAI component = val.GetComponent<SimonSaysAI>();
				if ((Object)(object)component != (Object)null)
				{
					((EnemyAI)component).enemyType = SimonSaysEnemy;
				}
				SimonSaysSpawnWeights spawnWeights = new SimonSaysSpawnWeights(() => (!ModConfig.Enabled.Value) ? 0f : ModConfig.SpawnWeightMultiplier.Value, () => ModConfig.MoonWeightOverrides.Value, delegate(string message)
				{
					Log.LogWarning((object)message);
				});
				DawnLib.RegisterNetworkPrefab(val);
				DawnLib.DefineEnemy(NamespacedKey<DawnEnemyInfo>.From("y4ngz_monsters", "simon_says"), SimonSaysEnemy, (Action<EnemyInfoBuilder>)delegate(EnemyInfoBuilder builder)
				{
					((BaseInfoBuilder<DawnEnemyInfo, EnemyType, EnemyInfoBuilder>)(object)builder.DefineInside((Action<EnemyLocationBuilder>)delegate(EnemyLocationBuilder location)
					{
						location.SetWeights((Action<WeightTableBuilder<DawnMoonInfo, SpawnWeightContext>>)delegate(WeightTableBuilder<DawnMoonInfo, SpawnWeightContext> table)
						{
							table.SetGlobalWeight((IWeighted)(object)spawnWeights);
						});
					}).CreateBestiaryNode("Simon Says\n\nDanger level: 100%\n\nSigurd's notes: It's a wheeled jester cart with a clockwork skull. It picks one crew member, puts a spotlight on them, and plays a game. Three commands. It cannot be killed, and when it is done it leaves in a cloud of smoke.\n\nThe rule is the whole trick: only obey a command it prefixes with \"Simon says\". Obey one it does not, and it kills you for it. Ignore one it does, and it kills you for that too. Listen for the words \"and\" (either order) versus \"then\" (that order).\n\n").CreateNameKeyword("simon")).AddTags((IEnumerable<NamespacedKey>)(object)new NamespacedKey[3]
					{
						Tags.Hostile,
						Tags.Mechanical,
						Tags.Medium
					});
				});
				_harmony = new Harmony("y4ngz.lethalcompany.simonsays");
				_harmony.PatchAll(typeof(Plugin).Assembly);
				if (!ModConfig.Enabled.Value)
				{
					Log.LogInfo((object)"Y4NGZ Simon Says: registered network prefab; spawning disabled by config.");
				}
				Log.LogInfo((object)"Y4NGZ Simon Says v1.2.1 loaded.");
			}
			catch (Exception arg)
			{
				Log.LogError((object)string.Format("Failed to initialize {0}: {1}", "Y4NGZ Simon Says", arg));
			}
		}

		private static void InitializeNetcodeRPCs()
		{
			if (_netcodeInitialized)
			{
				return;
			}
			_netcodeInitialized = true;
			Type[] types = Assembly.GetExecutingAssembly().GetTypes();
			foreach (Type type in types)
			{
				MethodInfo[] methods;
				try
				{
					methods = type.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				}
				catch (Exception ex)
				{
					Log.LogWarning((object)("[NetcodeInit] skipped type " + type.FullName + ": " + ex.GetType().Name));
					continue;
				}
				MethodInfo[] array = methods;
				foreach (MethodInfo methodInfo in array)
				{
					if (methodInfo.GetCustomAttributes(typeof(RuntimeInitializeOnLoadMethodAttribute), inherit: false).Length != 0)
					{
						try
						{
							methodInfo.Invoke(null, null);
							Log.LogInfo((object)("[NetcodeInit] invoked " + type.Name + "." + methodInfo.Name));
						}
						catch (Exception arg)
						{
							Log.LogError((object)$"[NetcodeInit] {type.Name}.{methodInfo.Name} threw: {arg}");
						}
					}
				}
			}
		}

		private static GameObject LoadEnemyPrefab()
		{
			string[] array = new string[4] { "Assets/Y4NGZ/SimonSays/SimonSays.prefab", "assets/y4ngz/simonsays/simonsays.prefab", "Assets/SimonSays/SimonSays.prefab", "assets/simonsays/simonsays.prefab" };
			foreach (string text in array)
			{
				GameObject val = ModAssets.LoadAsset<GameObject>(text);
				if ((Object)(object)val != (Object)null && (Object)(object)val.GetComponent<SimonSaysAI>() != (Object)null)
				{
					Log.LogInfo((object)("Loaded SimonSays prefab by path '" + text + "'."));
					return val;
				}
			}
			GameObject[] array2 = ModAssets.LoadAllAssets<GameObject>();
			foreach (GameObject val2 in array2)
			{
				if ((Object)(object)val2 != (Object)null && (Object)(object)val2.GetComponent<SimonSaysAI>() != (Object)null)
				{
					Log.LogWarning((object)("SimonSays prefab not at any known path; recovered '" + ((Object)val2).name + "' by scanning the bundle for SimonSaysAI. Update knownPaths."));
					return val2;
				}
			}
			return null;
		}

		private static void LoadAudioFromBundle()
		{
			LetsPlayClip = LoadClip("ss_lets_play");
			SimonSaysWordClip = LoadClip("ss_simon_says");
			AndClip = LoadClip("ss_and");
			ThenClip = LoadClip("ss_then");
			CongratulationsClip = LoadClip("ss_congratulations");
			GoodbyeClip = LoadClip("ss_goodbye");
			_actionClips[0] = LoadClip("ss_jump");
			_actionClips[1] = LoadClip("ss_crouch");
			_actionClips[2] = LoadClip("ss_dance");
			_actionClips[3] = LoadClip("ss_turn_around");
			WarnIfMissing(LetsPlayClip, "ss_lets_play");
			WarnIfMissing(CongratulationsClip, "ss_congratulations");
			WarnIfMissing(GoodbyeClip, "ss_goodbye");
			if ((1u & (RequireCommandClip(SimonSaysWordClip, "ss_simon_says") ? 1u : 0u) & (RequireCommandClip(AndClip, "ss_and") ? 1u : 0u) & (RequireCommandClip(ThenClip, "ss_then") ? 1u : 0u) & (RequireCommandClip(_actionClips[0], "ss_jump") ? 1u : 0u) & (RequireCommandClip(_actionClips[1], "ss_crouch") ? 1u : 0u) & (RequireCommandClip(_actionClips[2], "ss_dance") ? 1u : 0u) & (RequireCommandClip(_actionClips[3], "ss_turn_around") ? 1u : 0u)) == 0)
			{
				Log.LogFatal((object)"[SimonSays] Command word bank is incomplete; SimonSays will not register because a partial spoken command must never be judged.");
				throw new InvalidDataException("[SimonSays] Command word bank is incomplete; SimonSays will not register because a partial spoken command must never be judged.");
			}
		}

		private static void WarnIfMissing(AudioClip clip, string name)
		{
			if ((Object)(object)clip == (Object)null)
			{
				Log.LogError((object)("SimonSays audio '" + name + "' not found in bundle."));
			}
		}

		private static bool RequireCommandClip(AudioClip clip, string name)
		{
			if ((Object)(object)clip != (Object)null)
			{
				return true;
			}
			Log.LogFatal((object)("[SimonSays] Required command clip '" + name + "' not found in bundle."));
			return false;
		}

		private static void LoadEffectsFromBundle()
		{
			VanishSmokePrefab = ModAssets.LoadAsset<GameObject>("SimonSaysVanishSmoke") ?? ModAssets.LoadAsset<GameObject>("Assets/Y4NGZ/SimonSays/Effects/SimonSaysVanishSmoke.prefab");
			if ((Object)(object)VanishSmokePrefab == (Object)null)
			{
				Log.LogWarning((object)"SimonSaysVanishSmoke prefab not in bundle; the vanish will use the code-built smoke cloud instead.");
			}
		}

		private static void RebindTexturesFromBundle(GameObject prefab)
		{
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				Texture2D val = ModAssets.LoadAsset<Texture2D>("Meshy_AI_Clockwork_Jester_0505033555_texture");
				Texture2D val2 = ModAssets.LoadAsset<Texture2D>("Meshy_AI_Clockwork_Jester_0505033555_texture_normal");
				Texture2D val3 = ModAssets.LoadAsset<Texture2D>("Meshy_AI_Clockwork_Jester_0505033555_texture_metallic");
				Texture2D val4 = ModAssets.LoadAsset<Texture2D>("Meshy_AI_Clockwork_Jester_0505033555_texture_emission");
				if ((Object)(object)val == (Object)null)
				{
					Log.LogWarning((object)"Albedo texture missing from bundle.");
				}
				else
				{
					Log.LogInfo((object)$"Albedo loaded: {((Texture)val).width}x{((Texture)val).height}");
				}
				int num = 0;
				Renderer[] componentsInChildren = prefab.GetComponentsInChildren<Renderer>(true);
				for (int i = 0; i < componentsInChildren.Length; i++)
				{
					Material[] sharedMaterials = componentsInChildren[i].sharedMaterials;
					foreach (Material val5 in sharedMaterials)
					{
						if (!((Object)(object)val5 == (Object)null))
						{
							if ((Object)(object)val != (Object)null)
							{
								val5.SetTexture("_BaseColorMap", (Texture)(object)val);
								val5.SetTexture("_MainTex", (Texture)(object)val);
								val5.SetColor("_BaseColor", Color.white);
								val5.SetColor("_Color", Color.white);
							}
							if ((Object)(object)val2 != (Object)null)
							{
								val5.SetTexture("_NormalMap", (Texture)(object)val2);
								val5.SetTexture("_BumpMap", (Texture)(object)val2);
								val5.EnableKeyword("_NORMALMAP");
								val5.EnableKeyword("_NORMALMAP_TANGENT_SPACE");
							}
							if ((Object)(object)val3 != (Object)null)
							{
								val5.SetTexture("_MaskMap", (Texture)(object)val3);
								val5.SetTexture("_MetallicGlossMap", (Texture)(object)val3);
								val5.EnableKeyword("_MASKMAP");
							}
							if ((Object)(object)val4 != (Object)null)
							{
								val5.SetTexture("_EmissiveColorMap", (Texture)(object)val4);
								val5.SetTexture("_EmissionMap", (Texture)(object)val4);
								val5.EnableKeyword("_EMISSIVE_COLOR_MAP");
							}
							num++;
						}
					}
				}
				Log.LogInfo((object)$"RebindTexturesFromBundle: applied to {num} material slot(s).");
			}
			catch (Exception arg)
			{
				Log.LogError((object)$"RebindTexturesFromBundle: {arg}");
			}
		}

		private static void AssignUniqueNetworkHash(GameObject prefab)
		{
			try
			{
				NetworkObject component = prefab.GetComponent<NetworkObject>();
				if ((Object)(object)component == (Object)null)
				{
					Log.LogWarning((object)"Prefab missing NetworkObject — skipping hash override");
					return;
				}
				uint num = BitConverter.ToUInt32(MD5.Create().ComputeHash(Encoding.UTF8.GetBytes("y4ngz.lethalcompany.simonsays.SimonSays")), 0);
				PropertyInfo property = typeof(NetworkObject).GetProperty("GlobalObjectIdHash", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (property != null && property.CanWrite)
				{
					property.SetValue(component, num);
				}
				else
				{
					FieldInfo field = typeof(NetworkObject).GetField("GlobalObjectIdHash", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
					if (field != null)
					{
						field.SetValue(component, num);
					}
					else
					{
						Log.LogWarning((object)"Could not locate GlobalObjectIdHash via property or field — hash unchanged");
					}
				}
				Log.LogInfo((object)$"SimonSays NetworkObject GlobalObjectIdHash = {num}");
			}
			catch (Exception arg)
			{
				Log.LogError((object)$"AssignUniqueNetworkHash: {arg}");
			}
		}

		private static AudioClip LoadClip(params string[] candidates)
		{
			foreach (string text in candidates)
			{
				AudioClip val = ModAssets.LoadAsset<AudioClip>(text);
				if ((Object)(object)val != (Object)null)
				{
					return val;
				}
			}
			return null;
		}

		private IEnumerator LoadSpotlightStartClip(string assemblyDir)
		{
			string path = Path.Combine(assemblyDir, "simon_says_spotlight.mp3");
			if (!File.Exists(path))
			{
				Log.LogWarning((object)("Spotlight start sound missing: " + path));
				yield break;
			}
			UnityWebRequest request = UnityWebRequestMultimedia.GetAudioClip(new Uri(path).AbsoluteUri, (AudioType)13);
			try
			{
				yield return request.SendWebRequest();
				if ((int)request.result != 1)
				{
					Log.LogWarning((object)("Failed loading spotlight start sound '" + path + "': " + request.error));
					yield break;
				}
				AudioClip content = DownloadHandlerAudioClip.GetContent(request);
				if ((Object)(object)content == (Object)null)
				{
					Log.LogWarning((object)("Spotlight start sound decoded null: " + path));
					yield break;
				}
				((Object)content).name = "SimonSays_SpotlightStart";
				SpotlightStartClip = content;
				Log.LogInfo((object)("Loaded spotlight start sound from '" + path + "'."));
			}
			finally
			{
				((IDisposable)request)?.Dispose();
			}
		}

		private static void SetupPrefabComponents(GameObject prefab)
		{
			//IL_0029: 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_0039: 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_0053: Expected O, but got Unknown
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Expected O, but got Unknown
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Expected O, but got Unknown
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: 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_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Expected O, but got Unknown
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: 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_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Expected O, but got Unknown
			//IL_00f7: 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_0107: 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_011a: Expected O, but got Unknown
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: 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_0133: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: Expected O, but got Unknown
			//IL_0141: Unknown result type (might be due to invalid IL or missing references)
			//IL_0146: Unknown result type (might be due to invalid IL or missing references)
			//IL_0151: 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_0163: Unknown result type (might be due to invalid IL or missing references)
			//IL_016b: Expected O, but got Unknown
			EnsureScanNode(prefab);
			SimonSaysAI component = prefab.GetComponent<SimonSaysAI>();
			if ((Object)(object)component != (Object)null)
			{
				EnsureNavigation(prefab, component);
				((EnemyAI)component).enemyBehaviourStates = (EnemyBehaviourState[])(object)new EnemyBehaviourState[8]
				{
					new EnemyBehaviourState
					{
						name = "Roaming",
						IsAnimTrigger = false,
						parameterString = "isWalking",
						boolValue = true
					},
					new EnemyBehaviourState
					{
						name = "Approaching",
						IsAnimTrigger = false,
						parameterString = "isWalking",
						boolValue = true
					},
					new EnemyBehaviourState
					{
						name = "Intro",
						IsAnimTrigger = true,
						parameterString = "command"
					},
					new EnemyBehaviourState
					{
						name = "Commanding",
						IsAnimTrigger = true,
						parameterString = "command"
					},
					new EnemyBehaviourState
					{
						name = "Judging",
						IsAnimTrigger = false,
						parameterString = "isWalking",
						boolValue = false
					},
					new EnemyBehaviourState
					{
						name = "Punishing",
						IsAnimTrigger = true,
						parameterString = "playerFailed"
					},
					new EnemyBehaviourState
					{
						name = "Celebrating",
						IsAnimTrigger = true,
						parameterString = "playerPassed"
					},
					new EnemyBehaviourState
					{
						name = "Departing",
						IsAnimTrigger = false,
						parameterString = "isWalking",
						boolValue = true
					}
				};
				EnsureCollision(prefab, component);
			}
		}

		private static void EnsureNavigation(GameObject prefab, SimonSaysAI ai)
		{
			NavMeshAgent val = prefab.GetComponent<NavMeshAgent>();
			if ((Object)(object)val == (Object)null)
			{
				val = prefab.AddComponent<NavMeshAgent>();
				val.radius = 0.5f;
				val.height = 2f;
				val.baseOffset = 0f;
				val.angularSpeed = 240f;
				val.acceleration = 12f;
				val.autoBraking = true;
				val.areaMask = -1;
				Log.LogWarning((object)"[SimonSays] Prefab was missing a root NavMeshAgent; added a vanilla-compatible runtime agent.");
			}
			val.speed = ModConfig?.ApproachSpeed?.Value ?? 3.5f;
			((EnemyAI)ai).agent = val;
		}

		internal static void EnsureScanNode(GameObject prefab)
		{
			//IL_0144: 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_0173: Unknown result type (might be due to invalid IL or missing references)
			//IL_024f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0269: Unknown result type (might be due to invalid IL or missing references)
			ScanNodeProperties val = null;
			ScanNodeProperties[] componentsInChildren = prefab.GetComponentsInChildren<ScanNodeProperties>(true);
			foreach (ScanNodeProperties val2 in componentsInChildren)
			{
				if (!((Object)(object)val2 == (Object)null) && !((Object)(object)((Component)val2).gameObject == (Object)(object)prefab))
				{
					bool flag = val2.creatureScanID >= 0;
					bool flag2 = (Object)(object)val != (Object)null && val.creatureScanID >= 0;
					bool flag3 = string.Equals(((Object)((Component)val2).gameObject).name, "ScanNode", StringComparison.Ordinal);
					bool flag4 = (Object)(object)val != (Object)null && string.Equals(((Object)((Component)val).gameObject).name, "ScanNode", StringComparison.Ordinal);
					if ((Object)(object)val == (Object)null || (flag && !flag2) || (flag == flag2 && flag3 && !flag4))
					{
						val = val2;
					}
				}
			}
			if (componentsInChildren.Length > 1)
			{
				ManualLogSource log = Log;
				if (log != null)
				{
					log.LogWarning((object)$"[SimonSays] Found {componentsInChildren.Length} scan nodes; retiring every duplicate.");
				}
			}
			for (int j = 0; j < componentsInChildren.Length; j++)
			{
				if ((Object)(object)componentsInChildren[j] != (Object)(object)val)
				{
					RetireExtraScanNode(componentsInChildren[j], val, prefab);
				}
			}
			Transform val3 = (((Object)(object)val != (Object)null) ? ((Component)val).transform : FindOrCreateChild(prefab.transform, "ScanNode", new Vector3(0f, 1.25f, 0f)));
			((Object)((Component)val3).gameObject).name = "ScanNode";
			val3.localRotation = Quaternion.identity;
			val3.localScale = Vector3.one;
			TrySetTag(((Component)val3).gameObject, "DoNotSet");
			TrySetLayer(((Component)val3).gameObject, "ScanNode");
			EnsureHierarchyActive(val3, prefab.transform);
			((Component)val3).gameObject.SetActive(true);
			if (!_loggedScanNodeLayer)
			{
				_loggedScanNodeLayer = true;
				ManualLogSource log2 = Log;
				if (log2 != null)
				{
					log2.LogInfo((object)($"[SimonSays] Scan node layer resolved to {((Component)val3).gameObject.layer} " + string.Format("(NameToLayer(\"ScanNode\")={0}, fallback 22); ", LayerMask.NameToLayer("ScanNode")) + $"active={((Component)val3).gameObject.activeInHierarchy}."));
				}
			}
			BoxCollider val4 = ((Component)val3).GetComponent<BoxCollider>();
			if ((Object)(object)val4 == (Object)null)
			{
				val4 = ((Component)val3).gameObject.AddComponent<BoxCollider>();
			}
			((Collider)val4).enabled = true;
			((Collider)val4).isTrigger = true;
			val4.center = Vector3.zero;
			val4.size = new Vector3(1.2f, 1.8f, 1.2f);
			if ((Object)(object)val == (Object)null)
			{
				val = ((Component)val3).gameObject.AddComponent<ScanNodeProperties>();
			}
			val.headerText = "Simon Says";
			val.subText = "Only obey when Simon says";
			val.maxRange = 13;
			val.minRange = 1;
			val.requiresLineOfSight = true;
			val.nodeType = 1;
		}

		private static void RetireExtraScanNode(ScanNodeProperties extra, ScanNodeProperties preferred, GameObject root)
		{
			//IL_003c: 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_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)
			if ((Object)(object)extra == (Object)null)
			{
				return;
			}
			Scene scene;
			if ((Object)(object)((Component)extra).gameObject == (Object)(object)root || ((Object)(object)preferred != (Object)null && (Object)(object)((Component)extra).gameObject == (Object)(object)((Component)preferred).gameObject))
			{
				((Behaviour)extra).enabled = false;
				scene = root.scene;
				if (((Scene)(ref scene)).IsValid())
				{
					Object.Destroy((Object)(object)extra);
				}
				else
				{
					Object.DestroyImmediate((Object)(object)extra, true);
				}
				return;
			}
			GameObject gameObject = ((Component)extra).gameObject;
			gameObject.SetActive(false);
			Collider[] components = gameObject.GetComponents<Collider>();
			for (int i = 0; i < components.Length; i++)
			{
				components[i].enabled = false;
			}
			scene = root.scene;
			if (((Scene)(ref scene)).IsValid())
			{
				Object.Destroy((Object)(object)gameObject);
			}
			else
			{
				Object.DestroyImmediate((Object)(object)gameObject, true);
			}
		}

		private static void EnsureCollision(GameObject prefab, SimonSaysAI ai)
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			TrySetTag(prefab, "Enemy");
			TrySetLayer(prefab, "Enemies");
			Transform val = FindOrCreateChild(prefab.transform, "Collision", new Vector3(0f, 1f, 0f));
			TrySetTag(((Component)val).gameObject, "Enemy");
			TrySetLayer(((Component)val).gameObject, "Enemies");
			BoxCollider obj = ((Component)val).GetComponent<BoxCollider>() ?? ((Component)val).gameObject.AddComponent<BoxCollider>();
			((Collider)obj).enabled = true;
			((Collider)obj).isTrigger = true;
			obj.center = Vector3.zero;
			obj.size = new Vector3(1.25f, 1.85f, 1.25f);
			Rigidbody obj2 = ((Component)val).GetComponent<Rigidbody>() ?? ((Component)val).gameObject.AddComponent<Rigidbody>();
			obj2.isKinematic = true;
			obj2.useGravity = false;
			obj2.detectCollisions = true;
			EnemyAICollisionDetect obj3 = ((Component)val).GetComponent<EnemyAICollisionDetect>() ?? ((Component)val).gameObject.AddComponent<EnemyAICollisionDetect>();
			obj3.mainScript = (EnemyAI)(object)ai;
			obj3.alwaysAllowHitting = true;
			obj3.canCollideWithEnemies = false;
			obj3.onlyCollideWhenGrounded = false;
		}

		private static EnemyType CreateEnemyType(GameObject prefab)
		{
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: 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_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Expected O, but got Unknown
			//IL_00f7: 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_010d: 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_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: Expected O, but got Unknown
			EnemyType val = ScriptableObject.CreateInstance<EnemyType>();
			val.enemyName = "Simon Says";
			val.enemyPrefab = prefab;
			val.PowerLevel = ModConfig.PowerLevel.Value;
			val.DiversityPowerLevel = 1;
			val.MaxCount = 1;
			val.canDie = false;
			val.canBeStunned = false;
			val.canBeDestroyed = true;
			val.stunTimeMultiplier = 1f;
			val.stunGameDifficultyMultiplier = 1f;
			val.destroyOnDeath = false;
			val.doorSpeedMultiplier = 1f;
			val.SizeLimit = (NavSizeLimit)1;
			CreatureSfx.Apply(val, (EnemyAI)(object)prefab.GetComponent<SimonSaysAI>());
			val.isOutsideEnemy = false;
			val.isDaytimeEnemy = false;
			val.normalizedTimeInDayToLeave = 1f;
			val.probabilityCurve = new AnimationCurve((Keyframe[])(object)new Keyframe[2]
			{
				new Keyframe(0f, 1f),
				new Keyframe(1f, 1f)
			});
			val.numberSpawnedFalloff = new AnimationCurve((Keyframe[])(object)new Keyframe[2]
			{
				new Keyframe(0f, 1f),
				new Keyframe(1f, 1f)
			});
			return val;
		}

		private static Transform FindOrCreateChild(Transform parent, string name, Vector3 localPosition)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			Transform val = parent.Find(name);
			if ((Object)(object)val != (Object)null)
			{
				return val;
			}
			val = new GameObject(name).transform;
			val.SetParent(parent, false);
			val.localPosition = localPosition;
			return val;
		}

		private static void TrySetTag(GameObject gameObject, string tag)
		{
			try
			{
				gameObject.tag = tag;
			}
			catch
			{
			}
		}

		private static void TrySetLayer(GameObject gameObject, string layerName)
		{
			if ((Object)(object)gameObject == (Object)null)
			{
				return;
			}
			int num = LayerMask.NameToLayer(layerName);
			if (num < 0)
			{
				num = ResolveLayerFallback(layerName);
			}
			if (num >= 0 && num <= 31)
			{
				gameObject.layer = num;
				return;
			}
			ManualLogSource log = Log;
			if (log != null)
			{
				log.LogWarning((object)$"[SimonSays] Layer '{layerName}' unresolved; '{((Object)gameObject).name}' stays on layer {gameObject.layer}.");
			}
		}

		private static int ResolveLayerFallback(string layerName)
		{
			if (string.Equals(layerName, "ScanNode", StringComparison.OrdinalIgnoreCase))
			{
				return 22;
			}
			if (string.Equals(layerName, "Enemies", StringComparison.OrdinalIgnoreCase))
			{
				return 19;
			}
			return -1;
		}

		private static void EnsureHierarchyActive(Transform child, Transform stopAt)
		{
			Transform val = child;
			while ((Object)(object)val != (Object)null)
			{
				((Component)val).gameObject.SetActive(true);
				if (!((Object)(object)val == (Object)(object)stopAt))
				{
					val = val.parent;
					continue;
				}
				break;
			}
		}
	}
	public static class PluginInfo
	{
		public const string PLUGIN_GUID = "y4ngz.lethalcompany.simonsays";

		public const string PLUGIN_NAME = "Y4NGZ Simon Says";

		public const string PLUGIN_VERSION = "1.2.1";
	}
	public sealed class SimonSaysConfig
	{
		private const string SectionGeneral = "General";

		private const string SectionSpawning = "Spawning";

		private const string SectionMovement = "Movement";

		private const string SectionAbilities = "Abilities";

		private const string SectionPresentation = "Audio and Presentation";

		private const string SectionDiagnostics = "Diagnostics";

		internal const float DefaultSpotlightIntensity = 24f;

		public ConfigEntry<bool> Enabled { get; }

		public ConfigEntry<float> SpawnWeightMultiplier { get; }

		public ConfigEntry<string> MoonWeightOverrides { get; }

		public ConfigEntry<float> PowerLevel { get; }

		public ConfigEntry<float> ApproachSpeed { get; }

		public ConfigEntry<float> RetreatDuration { get; }

		public ConfigEntry<int> RoundsPerEncounter { get; }

		public ConfigEntry<float> ComplianceWindowSeconds { get; }

		public ConfigEntry<float> TrapWindowSeconds { get; }

		public ConfigEntry<float> SimonSaysChance { get; }

		public ConfigEntry<float> TwoActionRoundChance { get; }

		public ConfigEntry<float> BetweenRoundPause { get; }

		public ConfigEntry<float> SpotlightIntensity { get; }

		public ConfigEntry<bool> DebugLogs { get; }

		public ConfigEntry<bool> VanishSmokeForceHdrpShaders { get; }

		public int Rounds => Mathf.Clamp(RoundsPerEncounter.Value, 1, 8);

		public float Window => Mathf.Clamp(ComplianceWindowSeconds.Value, 0.75f, 30f);

		public float TrapWindow => Mathf.Clamp(TrapWindowSeconds.Value, 0.5f, 30f);

		public float SimonChance => Mathf.Clamp01(SimonSaysChance.Value);

		public float TwoActionChance => Mathf.Clamp01(TwoActionRoundChance.Value);

		public float RoundPause => Mathf.Clamp(BetweenRoundPause.Value, 0f, 5f);

		public SimonSaysConfig(ConfigFile config)
		{
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Expected O, but got Unknown
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Expected O, but got Unknown
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Expected O, but got Unknown
			//IL_0145: Unknown result type (might be due to invalid IL or missing references)
			//IL_014f: Expected O, but got Unknown
			//IL_0172: Unknown result type (might be due to invalid IL or missing references)
			//IL_017c: Expected O, but got Unknown
			//IL_01ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b5: Expected O, but got Unknown
			//IL_01e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ee: Expected O, but got Unknown
			//IL_021d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0227: Expected O, but got Unknown
			//IL_0256: Unknown result type (might be due to invalid IL or missing references)
			//IL_0260: Expected O, but got Unknown
			//IL_028f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0299: Expected O, but got Unknown
			//IL_02c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d2: Expected O, but got Unknown
			using (ConfigPersistence.BeginBinding(config, Plugin.Log, "Simon Says"))
			{
				SimonSaysConfigMigration.TryMigrate(config, Plugin.Log);
				ConfigSectionNameMigration.TryMigrate(config, Plugin.Log, "Simon Says");
				Enabled = config.Bind<bool>("General", "Enabled", true, "Enable the Simon Says encounter. Host-only: the host's value decides whether it spawns; every install still registers the creature so clients stay in sync.");
				SpawnWeightMultiplier = config.Bind<float>("Spawning", "SpawnWeightMultiplier", 1f, new ConfigDescription("Multiplier applied to Simon Says' contextual moon/interior spawn policy. 0 disables natural spawns.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 5f), Array.Empty<object>()));
				MoonWeightOverrides = config.Bind<string>("Spawning", "MoonWeightOverrides", string.Empty, "Optional comma-separated base moon weights, e.g. Experimentation:8,Offense:15 or namespace:moon=12. Use 0 to disable a moon; unlisted moons keep authored defaults.");
				PowerLevel = config.Bind<float>("Spawning", "PowerLevel", 2.5f, new ConfigDescription("Indoor enemy power budget cost for Simon Says.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 20f), Array.Empty<object>()));
				ApproachSpeed = config.Bind<float>("Movement", "ApproachSpeed", 3.5f, new ConfigDescription("Movement speed while rolling toward the selected worker.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 20f), Array.Empty<object>()));
				RetreatDuration = config.Bind<float>("Movement", "RetreatDuration", 3f, new ConfigDescription("Seconds Simon holds the stage after goodbye begins before vanishing in smoke.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 15f), Array.Empty<object>()));
				RoundsPerEncounter = config.Bind<int>("Abilities", "RoundsPerEncounter", 3, new ConfigDescription("Number of challenges issued during one encounter.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 8), Array.Empty<object>()));
				ComplianceWindowSeconds = config.Bind<float>("Abilities", "ComplianceWindowSeconds", 4f, new ConfigDescription("Seconds available to obey a command prefixed with 'Simon says'.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.75f, 30f), Array.Empty<object>()));
				TrapWindowSeconds = config.Bind<float>("Abilities", "TrapWindowSeconds", 0.85f, new ConfigDescription("Seconds after speech that an unprefixed command remains dangerous. Named actions are also judged while their words are spoken.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 30f), Array.Empty<object>()));
				SimonSaysChance = config.Bind<float>("Abilities", "SimonSaysChance", 0.6f, new ConfigDescription("Chance that a round is a genuine 'Simon says' command instead of a trap.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
				TwoActionRoundChance = config.Bind<float>("Abilities", "TwoActionRoundChance", 0.5f, new ConfigDescription("Chance that a round requests two actions instead of one.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
				BetweenRoundPause = config.Bind<float>("Abilities", "BetweenRoundPause", 0.05f, new ConfigDescription("Additional pause after a successful genuine command. Traps advance directly into the next command boundary cue.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 5f), Array.Empty<object>()));
				SpotlightIntensity = config.Bind<float>("Audio and Presentation", "SpotlightIntensity", 24f, new ConfigDescription("Light intensity of the client-side stage spotlight, for the selected player and for everyone watching. 0 turns it off.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 50f), Array.Empty<object>()));
				DebugLogs = config.Bind<bool>("Diagnostics", "DebugLogs", false, "Write verbose encounter and RPC diagnostics.");
				VanishSmokeForceHdrpShaders = config.Bind<bool>("Diagnostics", "VanishSmokeForceHdrpShaders", false, "Force fallback HDRP particle shaders when intact source materials render incorrectly.");
			}
		}
	}
	internal static class SimonSaysConfigMigration
	{
		private static readonly ConfigDefinition LegacySpawnWeight = new ConfigDefinition("Spawning", "SpawnWeight");

		private static readonly LegacyMigrationSpec Spec = new LegacyMigrationSpec("SimonSays", (IReadOnlyList<ConfigDefinition>)(object)new ConfigDefinition[1] { LegacySpawnWeight }, new string[4] { "Visuals", "Behavior", "Encounter", "Detection" }, new Dictionary<ConfigDefinition, string>
		{
			{
				new ConfigDefinition("Movement", "StoppingDistance"),
				"3.5"
			},
			{
				new ConfigDefinition("Encounter", "WordGapSeconds"),
				"0.06"
			},
			{
				new ConfigDefinition("Detection", "TurnAroundYawDegrees"),
				"150"
			},
			{
				new ConfigDefinition("Detection", "AllowTurnAroundInTrapRounds"),
				"false"
			}
		}, Build);

		internal static bool TryMigrate(ConfigFile config, ManualLogSource log)
		{
			return LegacyConfigMigrator.TryMigrate(config, log, Spec);
		}

		private static void Build(LegacyConfigValues values, MigratedConfigWriter output)
		{
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Expected O, but got Unknown
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Expected O, but got Unknown
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Expected O, but got Unknown
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Expected O, but got Unknown
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Expected O, but got Unknown
			//IL_0149: Unknown result type (might be due to invalid IL or missing references)
			//IL_014f: Expected O, but got Unknown
			//IL_0171: Unknown result type (might be due to invalid IL or missing references)
			//IL_0177: Expected O, but got Unknown
			//IL_0199: Unknown result type (might be due to invalid IL or missing references)
			//IL_019f: Expected O, but got Unknown
			//IL_01c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c7: Expected O, but got Unknown
			//IL_01e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ef: Expected O, but got Unknown
			output.Carry("General", "Enabled");
			output.CarrySpawnWeightMultiplier(LegacySpawnWeight, 30f);
			output.Carry("Spawning", "MoonWeightOverrides");
			output.Carry("Spawning", "PowerLevel");
			output.Carry("Movement", "ApproachSpeed");
			output.Carry("Movement", "RetreatDuration", new ConfigDefinition("Behavior", "RetreatDuration"));
			output.Carry("Abilities", "RoundsPerEncounter", new ConfigDefinition("Encounter", "RoundsPerEncounter"));
			output.Carry("Abilities", "ComplianceWindowSeconds", new ConfigDefinition("Encounter", "ComplianceWindowSeconds"));
			output.Carry("Abilities", "TrapWindowSeconds", new ConfigDefinition("Encounter", "TrapWindowSeconds"));
			output.Carry("Abilities", "SimonSaysChance", new ConfigDefinition("Encounter", "SimonSaysChance"));
			output.Carry("Abilities", "TwoActionRoundChance", new ConfigDefinition("Encounter", "TwoActionRoundChance"));
			output.Carry("Abilities", "BetweenRoundPause", new ConfigDefinition("Encounter", "BetweenRoundPause"));
			output.Carry("Audio and Presentation", "SpotlightIntensity", new ConfigDefinition("Visuals", "SpotlightIntensity"));
			output.Carry("Diagnostics", "DebugLogs", new ConfigDefinition("Behavior", "DebugLogs"));
			output.Carry("Diagnostics", "VanishSmokeForceHdrpShaders", new ConfigDefinition("Visuals", "VanishSmokeForceHdrpShaders"));
		}
	}
	internal sealed class SimonSaysSpawnWeights : ContextualSpawnWeights
	{
		internal SimonSaysSpawnWeights(Func<float> multiplier, Func<string> moonOverrides, Action<string> logWarning)
			: base(SpawnWeightTable.SimonSays, "Simon Says", multiplier, moonOverrides, logWarning)
		{
		}
	}
	internal static class SimonSaysTuning
	{
		internal const int MaxCount = 1;

		internal const float StoppingDistance = 3.5f;

		internal const float ApproachBudgetSeconds = 25f;

		internal const int MaxStageAttempts = 8;

		internal const float ApproachPathFailureGraceSeconds = 1f;

		internal const float ApproachCooldownSeconds = 30f;

		internal const float WordGapSeconds = 0.04f;

		internal const float CommandBoundarySeconds = 0.2f;

		internal const float IntroPause = 1.2f;

		internal const float FinalJudgmentPause = 0.55f;

		internal const float CongratulationsPause = 0.9f;

		internal const float ReportGrace = 2.5f;

		internal const float StageHeight = 4f;

		internal const float TurnAroundYawDegrees = 150f;

		internal const bool AllowTurnAroundInTrapRounds = false;
	}
}
namespace SimonSays.Utils
{
	public static class CreatureAudio
	{
		public static void StartLoop(AudioSource source, AudioClip clip)
		{
			if (!((Object)(object)source == (Object)null) && !((Object)(object)clip == (Object)null) && (!source.isPlaying || !((Object)(object)source.clip == (Object)(object)clip)))
			{
				source.loop = true;
				source.clip = clip;
				source.Play();
			}
		}

		public static void StopLoop(AudioSource source)
		{
			if (!((Object)(object)source == (Object)null) && source.isPlaying)
			{
				source.Stop();
				source.clip = null;
			}
		}
	}
}
namespace SimonSays.AI
{
	public static class BlackHoleEffect
	{
		public static void BeginFor(PlayerControllerB player)
		{
			//IL_000c: 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_001c: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)player == (Object)null)
			{
				return;
			}
			try
			{
				player.KillPlayer(Vector3.zero, true, (CauseOfDeath)2, 0, default(Vector3), false);
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"BlackHoleEffect.BeginFor: {arg}");
			}
		}
	}
	internal static class SimonCommandAudio
	{
		internal sealed class Sentence
		{
			internal AudioClip Clip;

			internal float FirstAt;

			internal float SecondAt;
		}

		private const int Rate = 44100;

		private static readonly Dictionary<int, Sentence> Cache = new Dictionary<int, Sentence>();

		internal static Sentence Build(SimonRound round)
		{
			//IL_0139: Unknown result type (might be due to invalid IL or missing references)
			int key = round.Pack();
			if (Cache.TryGetValue(key, out var value) && (Object)(object)value.Clip != (Object)null)
			{
				return value;
			}
			List<AudioClip> list = SimonSaysWords.BuildUtterance(round);
			float num = 0.04f;
			float num2 = 0.2f + SimonSaysWords.SequenceLength(list, num);
			float num3 = 0.2f + (round.SimonSaid ? (Plugin.SimonSaysWordClip.length + num) : 0f);
			float secondAt = (round.HasSecond ? (num3 + Plugin.ActionClip(round.First).length + num + ((round.Connector == RoundConnector.Then) ? Plugin.ThenClip.length : Plugin.AndClip.length) + num) : float.PositiveInfinity);
			float[] array = new float[Mathf.CeilToInt(num2 * 44100f)];
			for (int i = 0; i < Mathf.Min(array.Length, 5733); i++)
			{
				float num4 = (float)i / 44100f;
				array[i] = Tick(num4, 0.22f) + ((num4 >= 0.018f) ? Tick(num4 - 0.018f, 0.12f) : 0f);
			}
			float num5 = 0.2f;
			foreach (AudioClip item in list)
			{
				if ((int)item.loadState == 0)
				{
					item.LoadAudioData();
				}
				float[] array2 = new float[item.samples * item.channels];
				if (!item.GetData(array2, 0))
				{
					throw new InvalidOperationException("Cannot read Simon word PCM: " + ((Object)item).name);
				}
				int num6 = Mathf.RoundToInt(num5 * 44100f);
				int num7 = Mathf.RoundToInt(item.length * 44100f);
				for (int j = 0; j < num7 && num6 + j < array.Length; j++)
				{
					float num8 = (float)j * (float)item.frequency / 44100f;
					int num9 = Mathf.Min((int)num8, item.samples - 1);
					int num10 = Mathf.Min(num9 + 1, item.samples - 1);
					float num11 = 0f;
					for (int k = 0; k < item.channels; k++)
					{
						num11 += Mathf.Lerp(array2[num9 * item.channels + k], array2[num10 * item.channels + k], num8 - (float)num9);
					}
					array[num6 + j] = num11 / (float)item.channels;
				}
				num5 += item.length + num;
			}
			AudioClip val = AudioClip.Create("SimonCommand_" + key, array.Length, 1, 44100, false);
			val.SetData(array, 0);
			value = new Sentence
			{
				Clip = val,
				FirstAt = num3,
				SecondAt = secondAt
			};
			Cache[key] = value;
			return value;
		}

		private static float Tick(float t, float volume)
		{
			float num = Mathf.Min(1f, t / 0.001f);
			return volume * num * Mathf.Exp((0f - t) * 75f) * (Mathf.Sin(MathF.PI * 3700f * t) + 0.3f * Mathf.Sin(MathF.PI * 6540f * t));
		}
	}
	internal sealed class SimonCommandJudge
	{
		private int _previous;

		private int _eligible;

		private int _first;

		private int _second;

		private bool _hasSecond;

		private bool _ordered;

		private bool _simonSaid;

		private bool _firstDone;

		private bool _secondDone;

		public bool Complete { get; private set; }

		public bool Violated { get; private set; }

		public void Begin(int first, int second, bool hasSecond, bool ordered, bool simonSaid, int held)
		{
			_first = 1 << first;
			_second = 1 << second;
			_hasSecond = hasSecond;
			_ordered = ordered;
			_simonSaid = simonSaid;
			_previous = held;
			_eligible = 0;
			bool flag = (Violated = false);
			bool secondDone = (Complete = flag);
			_firstDone = (_secondDone = secondDone);
		}

		public void Activate(int action)
		{
			_eligible |= 1 << action;
		}

		public void Observe(int held)
		{
			int num = held & ~_previous & _eligible;
			_previous = held;
			if (Complete || Violated)
			{
				return;
			}
			if (!_simonSaid)
			{
				Violated = (num & (_first | (_hasSecond ? _second : 0))) != 0;
				return;
			}
			if ((num & _first) != 0)
			{
				_firstDone = true;
			}
			if (_hasSecond && (num & _second) != 0 && (!_ordered || _firstDone))
			{
				_secondDone = true;
			}
			Complete = _firstDone && (!_hasSecond || _secondDone);
		}
	}
	public enum SimonState
	{
		ROAMING,
		APPROACHING,
		INTRO,
		COMMANDING,
		JUDGING,
		PUNISHING,
		CELEBRATING,
		DEPARTING
	}
	internal enum SimonAbortReason
	{
		UnsafeBounds,
		TargetLeftStage,
		CommandAudio
	}
	public class SimonSaysAI : EnemyAI
	{
		private AudioSource _sfxSource;

		private AudioSource _voiceSource;

		private const float VoiceVolume = 1.35f;

		private const float SfxVolume = 1.15f;

		private const float MinAudibleDistance = 30f;

		private const float FocusLeadIn = 0.8f;

		private const float PunishHold = 1.5f;

		private const float DespawnRpcGrace = 0.4f;

		public AudioClip wheelsRollLoopClip;

		public AudioClip jesterSwingClip;

		public AudioSource loopSource;

		private bool _wheelsLoopDesired;

		private Coroutine _stateCoroutine;

		private Coroutine _speechCoroutine;

		private bool _encounterStarted;

		private bool _encounterFinished;

		private ulong _targetClientId;

		private bool _hasTarget;

		private float _approachStartedAt;

		private int _failedStageAttempts;

		private float _pathFailingSince = -1f;

		private float[] _approachCooldownUntil;

		private readonly NoiseMemory _noiseMemory = new NoiseMemory();

		private float _nextNoiseReseedTime;

		private const float NoiseMinLoudness = 0.5f;

		private const float NoiseHearingRange = 20f;

		private const float NoiseMemorySeconds = 3f;

		private const float NoiseReseedCooldown = 4f;

		private const int NoiseMaxRepeatsInOneSpot = 10;

		private const float SightWidth = 70f;

		private const float SightRange = 30f;

		private readonly ServerOwnershipGuard _ownership = new ServerOwnershipGuard();

		private bool _audioRouted;

		private int _awaitingRoundIndex = -1;

		private bool _roundReported;

		private bool _roundComplied;

		private bool _roundImplausible;

		private float _roundBegan;

		private float _roundSpeechSeconds;

		private float _roundWindow;

		private bool _roundSimonSaid;

		private const float ReportClockTolerance = 0.25f;

		private bool _judging;

		private SimonRound _judgeRound;

		private int _judgeRoundIndex = -1;

		private bool _judgeReported;

		private readonly SimonCommandJudge _inputJudge = new SimonCommandJudge();

		private SimonCommandAudio.Sentence _localSentence;

		private double _speechStartedAt;

		private bool _firstActivated;

		private bool _secondActivated;

		private bool _jumpLatched;

		private bool _vanished;

		private bool _stageFailed;

		private float _nextStageAttempt;

		private Vector3 _stageCenter;

		private float _stageRadius;

		private SimonStageBoundary _stage;

		private float _yawNet;

		private float _lastYaw;

		private bool _turnAroundFired;

		private SpotlightController _observerSpotlight;

		private Vector3 _lastAnimPosition;

		private bool _animInitialized;

		private float _smoothedSpeed;

		private bool _walkAnimOn;

		internal Transform StageAnchor
		{
			get
			{
				if (!((Object)(object)_stage != (Object)null))
				{
					return ((Component)this).transform;
				}
				return ((Component)_stage).transform;
			}
		}

		internal float StageRadius => _stageRadius;

		private static SimonSaysConfig Cfg => Plugin.ModConfig;

		private float ApproachSpeed => Cfg?.ApproachSpeed?.Value ?? 3.5f;

		private float StoppingDist => 3.5f;

		private float RetreatDuration => Cfg?.RetreatDuration?.Value ?? 3f;

		private bool DebugLogs => Cfg?.DebugLogs?.Value == true;

		private float SpotlightIntensity => Cfg?.SpotlightIntensity?.Value ?? 24f;

		private float WordGap => 0.04f;

		private void DLog(string m)
		{
			if (DebugLogs)
			{
				Plugin.Log.LogInfo((object)("[SimonSays] " + m));
			}
		}

		private static float ClipLen(AudioClip c)
		{
			if (!((Object)(object)c != (Object)null))
			{
				return 0f;
			}
			return c.length;
		}

		public override void Awake()
		{
			try
			{
				((EnemyAI)this).Awake();
				Transform val = ((Component)this).transform.Find("CreatureSFX");
				if ((Object)(object)val != (Object)null)
				{
					_sfxSource = ((Component)val).GetComponent<AudioSource>();
				}
				Transform val2 = ((Component)this).transform.Find("CreatureVoice");
				if ((Object)(object)val2 != (Object)null)
				{
					_voiceSource = ((Component)val2).GetComponent<AudioSource>();
				}
				if ((Object)(object)base.creatureSFX == (Object)null && (Object)(object)_sfxSource != (Object)null)
				{
					base.creatureSFX = _sfxSource;
				}
				if ((Object)(object)base.creatureVoice == (Object)null && (Object)(object)_voiceSource != (Object)null)
				{
					base.creatureVoice = _voiceSource;
				}
				if ((Object)(object)_sfxSource == (Object)null)
				{
					_sfxSource = base.creatureSFX;
				}
				if ((Object)(object)_voiceSource == (Object)null)
				{
					_voiceSource = base.creatureVoice;
				}
				if ((Object)(object)base.creatureAnimator == (Object)null)
				{
					base.creatureAnimator = ((Component)this).GetComponent<Animator>();
				}
				if ((Object)(object)base.eye == (Object)null)
				{
					Transform val3 = ((Component)this).transform.Find("Eye");
					if ((Object)(object)val3 != (Object)null)
					{
						base.eye = val3;
					}
				}
				ConfigureVoiceMix();
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"SimonSaysAI.Awake: {arg}");
			}
		}

		public override void Start()
		{
			//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)
			try
			{
				((EnemyAI)this).Start();
				Plugin.EnsureScanNode(((Component)this).gameObject);
				ConfigureVoiceMix();
				_audioRouted = RouteAudioSources();
				if ((Object)(object)base.agent != (Object)null)
				{
					base.agent.speed = ApproachSpeed;
					base.agent.stoppingDistance = 0f;
					if (base.agent.areaMask == 0)
					{
						base.agent.areaMask = -1;
					}
					base.agent.autoTraverseOffMeshLink = true;
					if (base.openDoorSpeedMultiplier <= 0f)
					{
						base.openDoorSpeedMultiplier = (((Object)(object)base.enemyType != (Object)null && base.enemyType.doorSpeedMultiplier > 0f) ? base.enemyType.doorSpeedMultiplier : 1f);
					}
				}
				_lastAnimPosition = ((Component)this).transform.position;
				_animInitialized = true;
				if (((NetworkBehaviour)this).IsServer)
				{
					((EnemyAI)this).SwitchToBehaviourClientRpc(0);
				}
				DLog($"spawned. IsServer={((NetworkBehaviour)this).IsServer} agentOnNavMesh={(Object)(object)base.agent != (Object)null && base.agent.isOnNavMesh} " + $"areaMask={(((Object)(object)base.agent != (Object)null) ? base.agent.areaMask : 0)} doorSpeed={base.openDoorSpeedMultiplier}");
				if (((NetworkBehaviour)this).IsServer && (Object)(object)RoundManager.Instance != (Object)null && (Object)(object)base.enemyType != (Object)null)
				{
					DLog($"inside enemy power with Simon spawned: {RoundManager.Instance.currentEnemyPower} (PowerLevel {base.enemyType.PowerLevel})");
				}
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"SimonSaysAI.Start: {arg}");
			}
		}

		public override void Update()
		{
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				_ownership.Ensure((EnemyAI)(object)this, Plugin.Log);
				if (_vanished)
				{
					return;
				}
				((EnemyAI)this).Update();
				if (!_audioRouted)
				{
					_audioRouted = RouteAudioSources();
				}
				UpdateWalkAnimation();
				if (((NetworkBehaviour)this).IsServer)
				{
					int num;
					if ((Object)(object)base.agent != (Object)null)
					{
						Vector3 velocity = base.agent.velocity;
						num = ((((Vector3)(ref velocity)).sqrMagnitude > 0.01f) ? 1 : 0);
					}
					else
					{
						num = 0;
					}
					bool flag = (byte)num != 0;
					if (flag != _wheelsLoopDesired)
					{
						_wheelsLoopDesired = flag;
						SetWheelsLoopClientRpc(flag);
					}
				}
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"SimonSaysAI.Update: {arg}");
			}
		}

		private void UpdateWalkAnimation()
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)base.creatureAnimator == (Object)null)
			{
				return;
			}
			if (!_animInitialized)
			{
				_lastAnimPosition = ((Component)this).transform.position;
				_animInitialized = true;
				return;
			}
			Vector3 val = ((Component)this).transform.position - _lastAnimPosition;
			val.y = 0f;
			_lastAnimPosition = ((Component)this).transform.position;
			float num = ((Time.deltaTime > 0f) ? (((Vector3)(ref val)).magnitude / Time.deltaTime) : 0f);
			_smoothedSpeed = Mathf.Lerp(_smoothedSpeed, num, 1f - Mathf.Exp(-8f * Time.deltaTime));
			if (_walkAnimOn && _smoothedSpeed < 0.1f)
			{
				_walkAnimOn = false;
			}
			else if (!_walkAnimOn && _smoothedSpeed > 0.22f)
			{
				_walkAnimOn = true;
			}
			base.creatureAnimator.SetBool("isWalking", _walkAnimOn);
		}

		public override void DoAIInterval()
		{
			try
			{
				if (_vanished)
				{
					return;
				}
				((EnemyAI)this).DoAIInterval();
				if (((NetworkBehaviour)this).IsServer && !((Object)(object)StartOfRound.Instance == (Object)null) && !StartOfRound.Instance.allPlayersDead && !_encounterFinished)
				{
					switch ((SimonState)base.currentBehaviourStateIndex)
					{
					case SimonState.ROAMING:
						DoRoaming();
						break;
					case SimonState.APPROACHING:
						DoApproaching();
						break;
					}
				}
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"SimonSaysAI.DoAIInterval: {arg}");
			}
		}

		public override void HitEnemy(int force = 1, PlayerControllerB playerWhoHit = null, bool playHitSFX = false, int hitID = -1)
		{
			try
			{
				if (playHitSFX && !_vanished)
				{
					CreatureAudioSetup.TransmitOneShot(base.creatureSFX, jesterSwingClip, 1.15f);
				}
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"SimonSaysAI.HitEnemy: {arg}");
			}
		}

		public override void KillEnemy(bool destroy = false)
		{
			try
			{
				if (((NetworkBehaviour)this).IsServer)
				{
					StopEncounterRoutine();
				}
				CleanupEffects();
				if (destroy && (Object)(object)base.enemyType != (Object)null && base.enemyType.canBeDestroyed)
				{
					((EnemyAI)this).KillEnemy(true);
				}
				else if (((NetworkBehaviour)this).IsServer)
				{
					DespawnSelf();
				}
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"SimonSaysAI.KillEnemy: {arg}");
			}
		}

		public override void DetectNoise(Vector3 noisePosition, float noiseLoudness, int timesPlayedInOneSpot = 0, int noiseID = 0)
		{
			//IL_0001: 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_005f: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				((EnemyAI)this).DetectNoise(noisePosition, noiseLoudness, timesPlayedInOneSpot, noiseID);
				if (((NetworkBehaviour)this).IsServer && !_vanished && !_encounterFinished && timesPlayedInOneSpot <= 10 && base.currentBehaviourStateIndex == 0)
				{
					Transform val = (((Object)(object)base.eye != (Object)null) ? base.eye : ((Component)this).transform);
					_noiseMemory.Record(noisePosition, noiseLoudness, 0.5f, val.position, 20f);
				}
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"SimonSaysAI.DetectNoise: {arg}");
			}
		}

		private void DoRoaming()
		{
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)base.agent == (Object)null) && !_hasTarget)
			{
				base.agent.speed = ApproachSpeed;
				base.agent.stoppingDistance = 0f;
				PlayerControllerB val = FindTargetInSight();
				if ((Object)(object)val != (Object)null)
				{
					BeginApproach(val);
				}
				else if (!TryReseedSearchAtNoise() && (base.currentSearch == null || !base.currentSearch.inProgress))
				{
					((EnemyAI)this).StartSearch(((Component)this).transform.position, (AISearchRoutine)null);
				}
			}
		}

		private PlayerControllerB FindTargetInSight()
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: 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)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: 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_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: 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_00c1: 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)
			if ((Object)(object)base.eye == (Object)null)
			{
				return null;
			}
			PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts;
			int collidersAndRoomMaskAndDefault = StartOfRound.Instance.collidersAndRoomMaskAndDefault;
			Vector3 position = base.eye.position;
			foreach (PlayerControllerB val in allPlayerScripts)
			{
				if (!((Object)(object)val == (Object)null) && !((Object)(object)val.gameplayCamera == (Object)null) && ((EnemyAI)this).PlayerIsTargetable(val, false, false, true) && !OnApproachCooldown(val))
				{
					Vector3 position2 = ((Component)val.gameplayCamera).transform.position;
					Vector3 val2 = position2 - position;
					if (!(((Vector3)(ref val2)).sqrMagnitude >= 900f) && !(Vector3.Angle(base.eye.forward, val2) >= 70f) && !Physics.Linecast(position, position2, collidersAndRoomMaskAndDefault, (QueryTriggerInteraction)1) && !Physics.Linecast(position2, position, collidersAndRoomMaskAndDefault, (QueryTriggerInteraction)1))
					{
						return val;
					}
				}
			}
			return null;
		}

		private bool TryReseedSearchAtNoise()
		{
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			if (Time.time < _nextNoiseReseedTime)
			{
				return false;
			}
			if (!_noiseMemory.TryTake(3f, out var position))
			{
				return false;
			}
			_nextNoiseReseedTime = Time.time + 4f;
			((EnemyAI)this).StopSearch(base.currentSearch, true);
			((EnemyAI)this).StartSearch(position, base.currentSearch);
			return true;
		}

		private void BeginApproach(PlayerControllerB player)
		{
			((EnemyAI)this).StopSearch(base.currentSearch, true);
			_noiseMemory.Clear();
			_targetClientId = player.actualClientId;
			_hasTarget = true;
			base.targetPlayer = player;
			_approachStartedAt = Time.time;
			_failedStageAttempts = 0;
			_pathFailingSince = -1f;
			DLog("acquired target " + player.playerUsername);
			SetTargetPlayerClientRpc(_targetClientId);
			((EnemyAI)this).SwitchToBehaviourClientRpc(1);
		}

		private void DoApproaching()
		{
			//IL_0092: 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_00fb: Unknown result type (might be due to invalid IL or missing references)
			if (_encounterStarted || !_hasTarget)
			{
				return;
			}
			if (!TargetStillValid() || !((EnemyAI)this).PlayerIsTargetable(base.targetPlayer, false, false, true))
			{
				AbandonApproach("target is no longer targetable");
			}
			else if (Time.time - _approachStartedAt > 25f)
			{
				AbandonApproach("approach budget spent");
			}
			else
			{
				if ((Object)(object)base.agent == (Object)null)
				{
					return;
				}
				base.agent.speed = ApproachSpeed;
				base.agent.stoppingDistance = StoppingDist;
				if (((EnemyAI)this).SetDestinationToPosition(((Component)base.targetPlayer).transform.position, true))
				{
					_pathFailingSince = -1f;
				}
				else if (_pathFailingSince < 0f)
				{
					_pathFailingSince = Time.time;
				}
				else if (Time.time - _pathFailingSince >= 1f)
				{
					AbandonApproach("no path to the target");
					return;
				}
				if (Vector3.Distance(((Component)this).transform.position, ((Component)base.targetPlayer).transform.position) > StoppingDist || Time.realtimeSinceStartup < _nextStageAttempt)
				{
					return;
				}
				_nextStageAttempt = Time.realtimeSinceStartup + 1f;
				if (!SimonStageBoundary.TryFindStage(this, base.targetPlayer, out _stageCenter, out _stageRadius))
				{
					if (++_failedStageAttempts >= 8)
					{
						AbandonApproach("no room for a stage");
					}
					return;
				}
				_encounterStarted = true;
				if (base.currentSearch != null && base.currentSearch.inProgress)
				{
					((EnemyAI)this).StopSearch(base.currentSearch, true);
				}
				HoldStationForEncounter();
				_stateCoroutine = ((MonoBehaviour)this).StartCoroutine(EncounterRoutine());
			}
		}

		private void AbandonApproach(string reason)
		{
			DLog("giving up the approach: " + reason);
			if ((Object)(object)base.targetPlayer != (Object)null)
			{
				StartApproachCooldown(base.targetPlayer);
			}
			_hasTarget = false;
			base.targetPlayer = null;
			if ((Object)(object)base.agent != (Object)null)
			{
				base.agent.stoppingDistance = 0f;
			}
			ClearTargetPlayerClientRpc();
			((EnemyAI)this).SwitchToBehaviourClientRpc(0);
		}

		private void StartApproachCooldown(PlayerControllerB player)
		{
			PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts;
			if (_approachCooldownUntil == null || _approachCooldownUntil.Length != allPlayerScripts.Length)
			{
				_approachCooldownUntil = new float[allPlayerScripts.Length];
			}
			int num = (int)player.playerClientId;
			if (num >= 0 && num < _approachCooldownUntil.Length)
			{
				_approachCooldownUntil[num] = Time.time + 30f;
			}
		}

		private bool OnApproachCooldown(PlayerControllerB player)
		{
			int num = (int)player.playerClientId;
			if (_approachCooldownUntil != null && num >= 0 && num < _approachCooldownUntil.Length)
			{
				return Time.time < _approachCooldownUntil[num];
			}
			return false;
		}

		private void HoldStationForEncounter()
		{
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			base.movingTowardsTargetPlayer = false;
			base.moveTowardsDestination = false;
			if (!((Object)(object)base.agent == (Object)null) && ((Behaviour)base.agent).enabled && base.agent.isOnNavMesh)
			{
				base.agent.ResetPath();
				base.agent.velocity = Vector3.zero;
				base.agent.isStopped = true;
			}
		}

		private bool TargetStillValid()
		{
			if (_hasTarget && (Object)(object)base.targetPlayer != (Object)null && !base.targetPlayer.isPlayerDead && base.targetPlayer.isPlayerControlled && base.targetPlayer.isInsideFactory == !base.isOutside)
			{
				if (((NetworkBehaviour)this).IsServer)
				{
					if ((Object)(object)((NetworkBehaviour)this).NetworkManager != (Object)null)
					{
						return ((NetworkBehaviour)this).NetworkManager.ConnectedClients.ContainsKey(_targetClientId);
					}
					return false;
				}
				return true;
			}
			return false;
		}

		private void FaceTarget()
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: 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_002f: 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_0051: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)base.targetPlayer == (Object)null))
			{
				Vector3 val = ((Component)base.targetPlayer).transform.position - ((Component)this).transform.position;
				val.y = 0f;
				if (((Vector3)(ref val)).sqrMagnitude > 0.01f)
				{
					((Component)this).transform.rotation = Quaternion.LookRotation(val);
				}
			}
		}

		private IEnumerator EncounterRoutine()
		{
			FaceTarget();
			BeginStageClientRpc(_stageCenter, _stageRadius, _targetClientId);
			if (_stageFailed)
			{
				yield return DepartRoutine();
				yield break;
			}
			((EnemyAI)this).SwitchToBehaviourClientRpc(2);
			BeginFocusClientRpc(_targetClientId);
			yield return (object)new WaitForSeconds(0.8f);
			PlayIntroClientRpc();
			yield return (object)new WaitForSeconds(ClipLen(Plugin.LetsPlayClip) + 1.2f);
			int rounds = ((Cfg != null) ? Cfg.Rounds : 3);
			List<SimonRound> sequence = new List<SimonRound>(rounds);
			for (int i = 0; i < 32; i++)
			{
				sequence.Clear();
				bool flag = false;
				bool flag2 = false;
				for (int j = 0; j < rounds; j++)
				{
					SimonRound item = SimonSaysWords.Roll((Cfg != null) ? Cfg.SimonChance : 0.6f, (Cfg != null) ? Cfg.TwoActionChance : 0.5f, allowTurnAroundInTraps: false);
					sequence.Add(item);
					flag |= item.SimonSaid;
					flag2 |= !item.SimonSaid;
				}
				float num = ((Cfg != null) ? Cfg.SimonChance : 0.6f);
				if (rounds < 2 || num <= 0f || num >= 1f || (flag && flag2))
				{
					break;
				}
			}
			float num2 = ((Cfg != null) ? Cfg.SimonChance : 0.6f);
			if (rounds > 1 && num2 > 0f && num2 < 1f)
			{
				bool flag3 = sequence.TrueForAll((SimonRound r) => r.SimonSaid);
				bool flag4 = sequence.TrueForAll((SimonRound r) => !r.SimonSaid);
				if (flag3 || flag4)
				{
					int index = Random.Range(0, rounds);
					sequence[index] = SimonSaysWords.Roll(flag3 ? 0f : 1f, (Cfg != null) ? Cfg.TwoActionChance : 0.5f, allowTurnAroundInTraps: false);
				}
			}
			for (int i2 = 0; i2 < rounds; i2++)
			{
				if (!TargetStillValid())
				{
					EndFocusClientRpc();
					yield return DepartRoutine();
					yield break;
				}
				SimonRound round = sequence[i2];
				float window = ((!round.SimonSaid) ? ((Cfg != null) ? Cfg.TrapWindow : 0.85f) : ((Cfg != null) ? Cfg.Window : 4f));
				SimonCommandAudio.Sentence sentence = null;
				try
				{
					sentence = SimonCommandAudio.Build(round);
				}
				catch (Exception arg)
				{
					Plugin.Log.LogError((object)$"[SimonSays] Cannot compose command: {arg}");
				}
				if (sentence == null)
				{
					EndFocusClientRpc();
					yield return DepartRoutine();
					yield break;
				}
				DLog($"round {i2 + 1}/{rounds}: {round}");
				_awaitingRoundIndex = i2;
				SimonSaysAI simonSaysAI = this;
				SimonSaysAI simonSaysAI2 = this;
				SimonSaysAI simonSaysAI3 = this;
				bool roundComplied = false;
				simonSaysAI3._roundImplausible = false;
				simonSaysAI._roundReported = (simonSaysAI2._roundComplied = roundComplied);
				_roundSpeechSeconds = sentence.Clip.length;
				_roundWindow = window;
				_roundSimonSaid = round.SimonSaid;
				((EnemyAI)this).SwitchToBehaviourClientRpc(3);
				float began = (_roundBegan = Time.realtimeSinceStartup);
				SpeakRoundClientRpc(round.Pack(), i2, window);
				bool judgingState = false;
				while (!_roundReported && Time.realtimeSinceStartup - began < sentence.Clip.length + window + 2.5f && TargetStillValid())
				{
					if (!judgingState && Time.realtimeSinceStartup - began >= sentence.Clip.length)
					{
						judgingState = true;
						((EnemyAI)this).SwitchToBehaviourClientRpc(4);
					}
					yield return null;
				}
				CloseWindowClientRpc();
				_awaitingRoundIndex = -1;
				if (!TargetStillValid() || !_roundReported || _roundImplausible)
				{
					if (!_roundReported)
					{
						Plugin.Log.LogWarning((object)"[SimonSays] Round report timed out; releasing the encounter.");
					}
					EndFocusClientRpc();
					yield return DepartRoutine();
					yield break;
				}
				bool flag5 = (round.SimonSaid ? _roundComplied : (!_roundComplied));
				DLog(string.Format("round {0}: {1}", i2 + 1, flag5 ? "PASS" : "FAIL"));
				if (!flag5)
				{
					yield return PunishRoutine();
					yield break;
				}
				if (i2 + 1 < rounds && round.SimonSaid)
				{
					yield return (object)new WaitForSeconds((Cfg != null) ? Cfg.RoundPause : 0.05f);
				}
			}
			yield return (object)new WaitForSeconds(0.55f);
			((EnemyAI)this).SwitchToBehaviourClientRpc(6);
			PlayCongratulationsClientRpc();
			yield return (object)new WaitForSeconds(ClipLen(Plugin.CongratulationsClip) + 0.9f);
			yield return DepartRoutine();
		}

		private IEnumerator PunishRoutine()
		{
			((EnemyAI)this).SwitchToBehaviourClientRpc(5);
			PlayerFailedClientRpc(_targetClientId);
			yield return (object)new WaitForSeconds(1.5f);
			yield return DepartRoutine();
		}

		private IEnumerator DepartRoutine()
		{
			if (!_encounterFinished)
			{
				_encounterFinished = true;
				((EnemyAI)this).SwitchToBehaviourClientRpc(7);
				CloseWindowClientRpc();
				PlayGoodbyeClientRpc();
				HoldStationForEncounter();
				float num = Mathf.Max(RetreatDuration, ClipLen(Plugin.GoodbyeClip) + 0.2f);
				yield return (object)new WaitForSeconds(num);
				HoldStationForEncounter();
				VanishClientRpc(((Component)this).transform.position);
				yield return (object)new WaitForSeconds(0.4f);
				DespawnSelf();
			}
		}

		private void DespawnSelf()
		{
			try
			{
				if (((NetworkBehaviour)this).IsServer && (Object)(object)((NetworkBehaviour)this).NetworkObject != (Object)null && ((NetworkBehaviour)this).NetworkObject.IsSpawned)
				{
					((NetworkBehaviour)this).NetworkObject.Despawn(true);
				}
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"despawn failed: {arg}");
			}
		}

		private void StopEncounterRoutine()
		{
			_encounterFinished = true;
			if (_stateCoroutine != null)
			{
				((MonoBehaviour)this).StopCoroutine(_stateCoroutine);
				_stateCoroutine = null;
			}
		}

		internal void AbortStageEncounter(SimonAbortReason reason)
		{
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			if (((NetworkBehaviour)this).IsServer)
			{
				if (_encounterStarted && !_encounterFinished)
				{
					Plugin.Log.LogWarning((object)("[SimonSays] Releasing the game: " + Describe(reason) + " on the host."));
					AbortEncounter();
				}
			}
			else
			{
				AbortStageServerRpc((int)reason);
			}
		}

		[ServerRpc(RequireOwnership = false)]
		public void AbortStageServerRpc(int reason, ServerRpcParams rpcParams = default(ServerRpcParams))
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Invalid comparison between Unknown and I4
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Invalid comparison between Unknown and I4
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager;
			if (networkManager == null || !networkManager.IsListening)
			{
				return;
			}
			if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 && (networkManager.IsClient || networkManager.IsHost))
			{
				FastBufferWriter val = ((NetworkBehaviour)this).__beginSendServerRpc(1013095394u, rpcParams, (RpcDelivery)0);
				BytePacker.WriteValueBitPacked(val, reason);
				((NetworkBehaviour)this).__endSendServerRpc(ref val, 1013095394u, rpcParams, (RpcDelivery)0);
			}
			if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 || (!networkManager.IsServer && !networkManager.IsHost))
			{
				return;
			}
			((NetworkBehaviour)this).__rpc_exec_stage = (__RpcExecStage)0;
			ulong senderClientId = rpcParams.Receive.SenderClientId;
			if (_encounterStarted && !_encounterFinished && !((Object)(object)((NetworkBehaviour)this).NetworkManager == (Object)null) && ((NetworkBehaviour)this).NetworkManager.ConnectedClients.ContainsKey(senderClientId))
			{
				if (reason == 1 && (!_hasTarget || senderClientId != _targetClientId))
				{
					DLog($"ignored TargetLeftStage from client {senderClientId}; the target is {_targetClientId}");
					return;
				}
				Plugin.Log.LogWarning((object)$"[SimonSays] Releasing the game: {Describe((SimonAbortReason)reason)} on client {senderClientId}.");
				AbortEncounter();
			}
		}

		private static string Describe(SimonAbortReason reason)
		{
			switch (reason)
			{
			case SimonAbortReason.UnsafeBounds:
				return "the stage could not keep its bounds safe";
			case SimonAbortReason.TargetLeftStage:
				return "the selected player left the stage";
			case SimonAbortReason.CommandAudio:
				return "a command sentence could not be composed";
			default:
			{
				int num = (int)reason;
				return "unknown reason " + num;
			}
			}
		}

		private void AbortEncounter()
		{
			if (!_encounterFinished)
			{
				_encounterStarted = true;
				if (_stateCoroutine != null)
				{
					((MonoBehaviour)this).StopCoroutine(_stateCoroutine);
					_stateCoroutine = null;
				}
				EndFocusClientRpc();
				_stateCoroutine = ((MonoBehaviour)this).StartCoroutine(DepartRoutine());
			}
		}

		[ClientRpc]
		public void SetTargetPlayerClientRpc(ulong clientId)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Invalid comparison between Unknown and I4
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Invalid comparison between Unknown and I4
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager;
			if (networkManager == null || !networkManager.IsListening)
			{
				return;
			}
			if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 && (networkManager.IsServer || networkManager.IsHost))
			{
				ClientRpcParams val2 = default(ClientRpcParams);
				FastBufferWriter val = ((NetworkBehaviour)this).__beginSendClientRpc(3618932334u, val2, (RpcDelivery)0);
				BytePacker.WriteValueBitPacked(val, clientId);
				((NetworkBehaviour)this).__endSendClientRpc(ref val, 3618932334u, val2, (RpcDelivery)0);
			}
			if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 || (!networkManager.IsClient && !networkManager.IsHost))
			{
				return;
			}
			((NetworkBehaviour)this).__rpc_exec_stage = (__RpcExecStage)0;
			try
			{
				if (!((NetworkBehaviour)this).IsServer)
				{
					_targetClientId = clientId;
					_hasTarget = true;
					PlayerControllerB val3 = VictimRpc.FromActualClientId(clientId);
					if ((Object)(object)val3 != (Object)null)
					{
						base.targetPlayer = val3;
					}
				}
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"SetTargetPlayerClientRpc: {arg}");
			}
		}

		[ClientRpc]
		public void ClearTargetPlayerClientRpc()
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Invalid comparison between Unknown and I4
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Invalid comparison between Unknown and I4
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager;
			if (networkManager == null || !networkManager.IsListening)
			{
				return;
			}
			if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 && (networkManager.IsServer || networkManager.IsHost))
			{
				ClientRpcParams val2 = default(ClientRpcParams);
				FastBufferWriter val = ((NetworkBehaviour)this).__beginSendClientRpc(1536047456u, val2, (RpcDelivery)0);
				((NetworkBehaviour)this).__endSendClientRpc(ref val, 1536047456u, val2, (RpcDelivery)0);
			}
			if ((int)((NetworkBehaviour)this).__rpc_exec_stage == 1 && (networkManager.IsClient || networkManager.IsHost))
			{
				((NetworkBehaviour)this).__rpc_exec_stage = (__RpcExecStage)0;
				if (!((NetworkBehaviour)this).IsServer)
				{
					_hasTarget = false;
					base.targetPlayer = null;
				}
			}
		}

		[ClientRpc]
		public void BeginStageClientRpc(Vector3 center, float radius, ulong targetClientId)
		{
			//IL_0181: Unknown result type (might be due to invalid IL or missing references)
			//IL_0187: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Invalid comparison between Unknown and I4
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Invalid comparison between Unknown and I4
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: 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_00f6: 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_00fd: 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)
			NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager;
			if (networkManager == null || !networkManager.IsListening)
			{
				return;
			}
			if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 && (networkManager.IsServer || networkManager.IsHost))
			{
				ClientRpcParams val2 = default(ClientRpcParams);
				FastBufferWriter val = ((NetworkBehaviour)this).__beginSendClientRpc(724007251u, val2, (RpcDelivery)0);
				((FastBufferWriter)(ref val)).WriteValueSafe(ref center);
				((FastBufferWriter)(ref val)).WriteValueSafe<float>(ref radius, default(ForPrimitives));
				BytePacker.WriteValueBitPacked(val, targetClientId);
				((NetworkBehaviour)this).__endSendClientRpc(ref val, 724007251u, val2, (RpcDelivery)0);
			}
			if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 || (!networkManager.IsClient && !networkManager.IsHost))
			{
				return;
			}
			((NetworkBehaviour)this).__rpc_exec_stage = (__RpcExecStage)0;
			_stageCenter = center;
			_stageRadius = radius;
			_stageFailed = false;
			try
			{
				if ((Object)(object)_stage != (Object)null)
				{
					_stage.Release();
				}
				_stage = SimonStageBoundary.Create(this, VictimRpc.FromActualClientId(targetClientId), center, radius);
				if ((Object)(object)_stage == (Object)null)
				{
					throw new InvalidOperationException("Stage target unavailable.");
				}
			}
			catch (Exception arg)
			{
				_stageFailed = true;
				Plugin.Log.LogError((object)$"[SimonSays] Stage creation failed: {arg}");
				if (!((NetworkBehaviour)this).IsServer)
				{
					AbortStageServerRpc(0);
				}
			}
		}

		[ClientRpc]
		public void BeginFocusClientRpc(ulong targetClientId)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Invalid comparison between Unknown and I4
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Invalid comparison between Unknown and I4
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_017f: 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_018e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0193: Unknown result type (might be due to invalid IL or missing references)
			NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager;
			if (networkManager == null || !networkManager.IsListening)
			{
				return;
			}
			if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 && (networkManager.IsServer || networkManager.IsHost))
			{
				ClientRpcParams val2 = default(ClientRpcParams);
				FastBufferWriter val = ((NetworkBehaviour)this).__beginSendClientRpc(1593938165u, val2, (RpcDelivery)0);
				BytePacker.WriteValueBitPacked(val, targetClientId);
				((NetworkBehaviour)this).__endSendClientRpc(ref val, 1593938165u, val2, (RpcDelivery)0);
			}
			if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 || (!networkManager.IsClient && !networkManager.IsHost))
			{
				return;
			}
			((NetworkBehaviour)this).__rpc_exec_stage = (__RpcExecStage)0;
			try
			{
				_targetClientId = targetClientId;
				_hasTarget = true;
				PlayerControllerB val3 = VictimRpc.FromActualClientId(targetClientId);
				if ((Object)(object)val3 != (Object)null)
				{
					base.targetPlayer = val3;
				}
				if (VictimRpc.IsLocalVictim(_targetClientId))
				{
					PlayerControllerB val4 = (((Object)(object)StartOfRound.Instance != (Object)null) ? StartOfRound.Instance.localPlayerController : null);
					if ((Object)(object)val4 != (Object)null)
					{
						SimonSaysFocusEffect.Begin(this, val4, SpotlightIntensity);
					}
				}
				else if ((Object)(object)val3 != (Object)null)
				{
					if ((Object)(object)_observerSpotlight == (Object)null)
					{
						_observerSpotlight = SpotlightController.SpawnForStage(StageAnchor, _stageRadius, SpotlightIntensity);
					}
					else
					{
						((Component)_observerSpotlight).transform.position = StageAnchor.position + Vector3.up * 10f;
					}
				}
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"BeginFocusClientRpc: {arg}");
			}
		}

		[ClientRpc]
		public void EndFocusClientRpc()
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Invalid comparison between Unknown and I4
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Invalid comparison between Unknown and I4
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager;
			if (networkManager == null || !networkManager.IsListening)
			{
				return;
			}
			if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 && (networkManager.IsServer || networkManager.IsHost))
			{
				ClientRpcParams val2 = default(ClientRpcParams);
				FastBufferWriter val = ((NetworkBehaviour)this).__beginSendClientRpc(1344786899u, val2, (RpcDelivery)0);
				((NetworkBehaviour)this).__endSendClientRpc(ref val, 1344786899u, val2, (RpcDelivery)0);
			}
			if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 || (!networkManager.IsClient && !networkManager.IsHost))
			{
				return;
			}
			((NetworkBehaviour)this).__rpc_exec_stage = (__RpcExecStage)0;
			try
			{
				EndFocusLocal();
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"EndFocusClientRpc: {arg}");
			}
		}

		private void EndFocusLocal()
		{
			SimonSaysFocusEffect.EndFor(this);
			if ((Object)(object)_stage != (Object)null)
			{
				_stage.Release();
				_stage = null;
			}
			if ((Object)(object)_observerSpotlight != (Object)null)
			{
				_observerSpotlight.Despawn();
				_observerSpotlight = null;
			}
		}

		[ClientRpc]
		public void PlayIntroClientRpc()
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Invalid comparison between Unknown and I4
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Invalid comparison between Unknown and I4
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager;
			if (networkManager == null || !networkManager.IsListening)
			{
				return;
			}
			if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 && (networkManager.IsServer || networkManager.IsHost))
			{
				ClientRpcParams val2 = default(ClientRpcParams);
				FastBufferWriter val = ((NetworkBehaviour)this).__beginSendClientRpc(1746222514u, val2, (RpcDelivery)0);
				((NetworkBehaviour)this).__endSendClientRpc(ref val, 1746222514u, val2, (RpcDelivery)0);
			}
			if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 || (!networkManager.IsClient && !networkManager.IsHost))
			{
				return;
			}
			((NetworkBehaviour)this).__rpc_exec_stage = (__RpcExecStage)0;
			try
			{
				SpeakClips(new List<AudioClip> { Plugin.LetsPlayClip });
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"PlayIntroClientRpc: {arg}");
			}
		}

		[ClientRpc]
		public void SpeakRoundClientRpc(int packedRound, int roundIndex, float window)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Invalid comparison between Unknown and I4
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Invalid comparison between Unknown and I4
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: 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_0097: 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_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager;
			if (networkManager == null || !networkManager.IsListening)
			{
				return;
			}
			if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 && (networkManager.IsServer || networkManager.IsHost))
			{
				ClientRpcParams val2 = default(ClientRpcParams);
				FastBufferWriter val = ((NetworkBehaviour)this).__beginSendClientRpc(927865291u, val2, (RpcDelivery)0);
				BytePacker.WriteValueBitPacked(val, packedRound);
				BytePacker.WriteValueBitPacked(val, roundIndex);
				((FastBufferWriter)(ref val)).WriteValueSafe<float>(ref window, default(ForPrimitives));
				((NetworkBehaviour)this).__endSendClientRpc(ref val, 927865291u, val2, (RpcDelivery)0);
			}
			if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 || (!networkManager.IsClient && !networkManager.IsHost))
			{
				return;
			}
			((NetworkBehaviour)this).__rpc_exec_stage = (__RpcExecStage)0;
			try
			{
				StopSpeech();
				_speechCoroutine = ((MonoBehaviour)this).StartCoroutine(SpeakCommandRoutine(SimonRound.Unpack(packedRound), roundIndex, window));
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"SpeakRoundClientRpc: {arg}");
			}
		}

		[ClientRpc]
		public void CloseWindowClientRpc()
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Invalid comparison between Unknown and I4
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Invalid comparison between Unknown and I4
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager;
			if (networkManager != null && networkManager.IsListening)
			{
				if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 && (networkManager.IsServer || networkManager.IsHost))
				{
					ClientRpcParams val2 = default(ClientRpcParams);
					FastBufferWriter val = ((NetworkBehaviour)this).__beginSendClientRpc(447314282u, val2, (RpcDelivery)0);
					((NetworkBehaviour)this).__endSendClientRpc(ref val, 447314282u, val2, (RpcDelivery)0);
				}
				if ((int)((NetworkBehaviour)this).__rpc_exec_stage == 1 && (networkManager.IsClient || networkManager.IsHost))
				{
					((NetworkBehaviour)this).__rpc_exec_stage = (__RpcExecStage)0;
					_judging = false;
					_judgeRoundIndex = -1;
				}
			}
		}

		[ClientRpc]
		public void PlayCongratulationsClientRpc()
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Invalid comparison between Unknown and I4
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Invalid comparison between Unknown and I4
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager;
			if (networkManager == null || !networkManager.IsListening)
			{
				return;
			}
			if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 && (networkManager.IsServer || networkManager.IsHost))
			{
				ClientRpcParams val2 = default(ClientRpcParams);
				FastBufferWriter val = ((NetworkBehaviour)this).__beginSendClientRpc(3841940082u, val2, (RpcDelivery)0);
				((NetworkBehaviour)this).__endSendClientRpc(ref val, 3841940082u, val2, (RpcDelivery)0);
			}
			if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 || (!networkManager.IsClient && !networkManager.IsHost))
			{
				return;
			}
			((NetworkBehaviour)this).__rpc_exec_stage = (__RpcExecStage)0;
			try
			{
				SpeakClips(new List<AudioClip> { Plugin.CongratulationsClip });
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"PlayCongratulationsClientRpc: {arg}");
			}
		}

		[ClientRpc]
		public void PlayGoodbyeClientRpc()
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Invalid comparison between Unknown and I4
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Invalid comparison between Unknown and I4
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager;
			if (networkManager == null || !networkManager.IsListening)
			{
				return;
			}
			if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 && (networkManager.IsServer || networkManager.IsHost))
			{
				ClientRpcParams val2 = default(ClientRpcParams);
				FastBufferWriter val = ((NetworkBehaviour)this).__beginSendClientRpc(2046626769u, val2, (RpcDelivery)0);
				((NetworkBehaviour)this).

Y4NGZCreepyDoll.dll

Decompiled a week ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using Dawn;
using GameNetcodeStuff;
using Microsoft.CodeAnalysis;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.Audio;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.Rendering;
using UnityEngine.SceneManagement;
using Y4NGZCreepyDoll;
using Y4NGZCreepyDoll.NetcodePatcher;
using Y4NGZMonsters.Shared;

[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("Y4NGZCreepyDoll")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+c64a155fd64c47528940e53659e5b5ada665b9d4")]
[assembly: AssemblyProduct("Y4NGZCreepyDoll")]
[assembly: AssemblyTitle("Y4NGZCreepyDoll")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
[module: NetcodePatchedAssembly]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.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 Y4NGZCreepyDoll
{
	public sealed class CreepyDollAI : EnemyAI
	{
		private enum EncounterState
		{
			Dormant,
			Suspicious,
			Chase,
			Search,
			Hypnosis
		}

		private struct HushdollSharedSettings : INetworkSerializable, IEquatable<HushdollSharedSettings>
		{
			private const float DefaultMoveSpeed = 0.6f;

			private const float DefaultPullSpeed = 0.85f;

			private const float DefaultMovementLockDelay = 3f;

			private const float DefaultNeckSlashRange = 2.15f;

			private const float DefaultAttackCooldown = 2.4f;

			public bool Published;

			public float MoveSpeed;

			public float PullSpeed;

			public float MovementLockDelay;

			public float NeckSlashRange;

			public float AttackCooldown;

			public static HushdollSharedSettings FromLocalConfig()
			{
				CreepyDollConfig modConfig = Plugin.ModConfig;
				HushdollSharedSettings hushdollSharedSettings = new HushdollSharedSettings
				{
					MoveSpeed = (modConfig?.MoveSpeed?.Value ?? 0.6f),
					PullSpeed = (modConfig?.PullSpeed?.Value ?? 0.85f),
					MovementLockDelay = (modConfig?.MovementLockDelay?.Value ?? 3f),
					NeckSlashRange = (modConfig?.NeckSlashRange?.Value ?? 2.15f),
					AttackCooldown = (modConfig?.AttackCooldown?.Value ?? 2.4f)
				};
				return hushdollSharedSettings.Sanitized();
			}

			public HushdollSharedSettings Sanitized()
			{
				HushdollSharedSettings result = this;
				result.MoveSpeed = Sanitize(MoveSpeed, 0.6f, 0.34f, 5f);
				result.PullSpeed = Sanitize(PullSpeed, 0.85f, 0.1f, 5f);
				result.MovementLockDelay = Sanitize(MovementLockDelay, 3f, 0f, 10f);
				result.NeckSlashRange = Sanitize(NeckSlashRange, 2.15f, 0.5f, 5f);
				result.AttackCooldown = Sanitize(AttackCooldown, 2.4f, 0.1f, 30f);
				return result;
			}

			private static float Sanitize(float value, float fallback, float minimum, float maximum)
			{
				return Mathf.Clamp(HushdollPerception.IsFinite(value) ? value : fallback, minimum, maximum);
			}

			public unsafe void NetworkSerialize<T>(BufferSerializer<T> serializer) where T : IReaderWriter
			{
				//IL_000a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0010: Unknown result type (might be due to invalid IL or missing references)
				//IL_0020: Unknown result type (might be due to invalid IL or missing references)
				//IL_0026: Unknown result type (might be due to invalid IL or missing references)
				//IL_0036: Unknown result type (might be due to invalid IL or missing references)
				//IL_003c: Unknown result type (might be due to invalid IL or missing references)
				//IL_004c: 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_0062: 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_0078: 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)
				((BufferSerializer<bool>*)(&serializer))->SerializeValue<bool>(ref Published, default(ForPrimitives));
				((BufferSerializer<float>*)(&serializer))->SerializeValue<float>(ref MoveSpeed, default(ForPrimitives));
				((BufferSerializer<float>*)(&serializer))->SerializeValue<float>(ref PullSpeed, default(ForPrimitives));
				((BufferSerializer<float>*)(&serializer))->SerializeValue<float>(ref MovementLockDelay, default(ForPrimitives));
				((BufferSerializer<float>*)(&serializer))->SerializeValue<float>(ref NeckSlashRange, default(ForPrimitives));
				((BufferSerializer<float>*)(&serializer))->SerializeValue<float>(ref AttackCooldown, default(ForPrimitives));
			}

			public bool Equals(HushdollSharedSettings other)
			{
				if (Published == other.Published && MoveSpeed == other.MoveSpeed && PullSpeed == other.PullSpeed && MovementLockDelay == other.MovementLockDelay && NeckSlashRange == other.NeckSlashRange)
				{
					return AttackCooldown == other.AttackCooldown;
				}
				return false;
			}
		}

		private struct HushdollLookTarget : INetworkSerializable, IEquatable<HushdollLookTarget>
		{
			public byte Kind;

			public ulong ClientId;

			public Vector3 Point;

			public int SnapEpoch;

			public unsafe void NetworkSerialize<T>(BufferSerializer<T> serializer) where T : IReaderWriter
			{
				//IL_0017: 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_003a: 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)
				serializer.SerializeValue(ref Kind);
				((BufferSerializer<ulong>*)(&serializer))->SerializeValue<ulong>(ref ClientId, default(ForPrimitives));
				serializer.SerializeValue(ref Point);
				((BufferSerializer<int>*)(&serializer))->SerializeValue<int>(ref SnapEpoch, default(ForPrimitives));
			}

			public bool Equals(HushdollLookTarget other)
			{
				//IL_001d: 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)
				if (Kind == other.Kind && ClientId == other.ClientId && Point == other.Point)
				{
					return SnapEpoch == other.SnapEpoch;
				}
				return false;
			}
		}

		private struct HushdollPeekState : INetworkSerializable, IEquatable<HushdollPeekState>
		{
			public byte Phase;

			public Vector3 Point;

			public float LeanPitchDegrees;

			public float LeanRollDegrees;

			public unsafe void NetworkSerialize<T>(BufferSerializer<T> serializer) where T : IReaderWriter
			{
				//IL_0024: 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_003a: 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)
				serializer.SerializeValue(ref Phase);
				serializer.SerializeValue(ref Point);
				((BufferSerializer<float>*)(&serializer))->SerializeValue<float>(ref LeanPitchDegrees, default(ForPrimitives));
				((BufferSerializer<float>*)(&serializer))->SerializeValue<float>(ref LeanRollDegrees, default(ForPrimitives));
			}

			public bool Equals(HushdollPeekState other)
			{
				//IL_000f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0015: Unknown result type (might be due to invalid IL or missing references)
				if (Phase == other.Phase && Point == other.Point && LeanPitchDegrees == other.LeanPitchDegrees)
				{
					return LeanRollDegrees == other.LeanRollDegrees;
				}
				return false;
			}
		}

		private sealed class RaycastHitDistanceComparer : IComparer<RaycastHit>
		{
			internal static readonly RaycastHitDistanceComparer Instance = new RaycastHitDistanceComparer();

			public int Compare(RaycastHit x, RaycastHit y)
			{
				return ((RaycastHit)(ref x)).distance.CompareTo(((RaycastHit)(ref y)).distance);
			}
		}

		private enum PeekCandidateKind : byte
		{
			Opening,
			WallEdge
		}

		private struct PeekCandidate
		{
			internal PeekCandidateKind Kind;

			internal Vector3 Point;

			internal Vector3 Axis;

			internal float AheadMeters;

			internal int SampleIndex;

			internal float ApertureHeight;

			internal float ApertureWidth;

			internal DoorLock Door;
		}

		private struct PeekPlan
		{
			internal Vector3 Stop;

			internal bool StopOnNavMesh;

			internal float StopWalkMeters;

			internal Vector3 Eye;

			internal float Crouch;

			internal float Lean;

			internal float Pitch;

			internal float Roll;

			internal Collider ViewBlocker;
		}

		private enum PeekSearchEnd : byte
		{
			PathEnd,
			ClosedDoor,
			DoorSearchSaturated
		}

		private static readonly int AnimUseAnimatronic = Animator.StringToHash("UseAnimatronic");

		private static readonly int AnimSprintRate = Animator.StringToHash("SprintRate");

		private static readonly int AnimTurnRate = Animator.StringToHash("TurnRate");

		private static readonly int AnimCrouchAmount = Animator.StringToHash("CrouchAmount");

		private static bool _loggedCrouchSupport;

		private int _animatronicPresence;

		private int _animatronicGait;

		private string _animatronicState;

		private float _animatronicStateSince;

		private float _signedBodyTurnSpeed;

		private bool _localClawAttack;

		public const int StateIdle = 0;

		public const int StateLuring = 1;

		public const int StateNeckSlash = 2;

		private const float ConstantLoopVolume = 0.3f;

		private const float MindControlVolume = 0.95f;

		private const float MindControlDampenedDecibels = -18f;

		private const float PursuitSirenVolume = 0.55f;

		private const float IdleBeatVolume = 0.4f;

		private const int IdleBeatMinimumSteps = 5;

		private const int IdleBeatMaximumSteps = 9;

		private const float FootstepPhaseWindow = 0.09f;

		private const float MinimumMoveSpeed = 0.34f;

		private const float MinimumAcceleration = 22.5f;

		private const float MinimumAngularSpeed = 120f;

		private const float MinimumGazeRange = 80f;

		private const float NavigationRadius = 0.5f;

		private const float NavigationHeight = 2f;

		private const float NavigationStoppingDistance = 0.6f;

		private const float SlowWalkClipDurationSeconds = 4.85f;

		private const float SlowWalkCycleDistance = 4.56f;

		private const float SlowWalkControllerStateSpeed = 0.625f;

		private const float RunClipDurationSeconds = 1.9f;

		private const float RunCycleDistance = 4.54f;

		private const float RunGaitEnterSpeedMetersPerSecond = 1.3f;

		private const float RunGaitExitSpeedMetersPerSecond = 1.1f;

		private const float HeadFocusHeardSeconds = 4.5f;

		private const float HeadTrackingAimDeadZoneDegrees = 0.35f;

		private const float NoisePlayerMatchRadius = 4f;

		private const float VoiceHearingMinimumAmplitude = 0.02f;

		private const float OccludedHearingRangeFraction = 0.5f;

		private const float NeckPitchShare = 0.38f;

		private const float IdleSoundMinDistance = 2f;

		private const float IdleSoundMaxDistance = 30f;

		private const float CreatureAudioSpread = 40f;

		private const float ScheduledExecutionKillDelay = 2f;

		private const float ExecutionCloseMinimumSpeed = 2.35f;

		private const float ExecutionHeadFocusRefreshSeconds = 0.08f;

		private const float SuspiciousMinDwellSeconds = 3f;

		private const float SuspiciousTimeoutSeconds = 6f;

		private const float ChaseLostSeconds = 12f;

		private const float ReacquireRefractorySeconds = 20f;

		private const float SearchVocalIntervalSeconds = 4f;

		private const float SearchScanSpeedMultiplier = 2f;

		private const float SearchScanHoldScale = 0.5f;

		private const float PossessionCommandAckSeconds = 1f;

		private const float InvestigateTravelTimeoutSeconds = 12f;

		private const float InvestigateArriveRadius = 1.6f;

		private const float InvestigateLookHoldSeconds = 5f;

		private const float SearchLingerSeconds = 30f;

		private const float SearchLingerWidthScale = 0.5f;

		private const int MinLingerSearchNodes = 4;

		private const float ChaseSpeedMetersPerSecond = 2f;

		private const float ChaseSprintSpeedMetersPerSecond = 6.5f;

		private const float SprintDurationSeconds = 3f;

		private const float SprintCooldownSeconds = 30f;

		private const float SprintChance = 0.35f;

		private const float SprintMinimumTriggerDistance = 6f;

		private const float SprintReleaseDistance = 2.5f;

		private const float SprintWindupDelaySeconds = 0.8f;

		private const float SprintRerollIntervalSeconds = 20f;

		private const float SprintSpawnGraceSeconds = 30f;

		private const float SprintVocalVolume = 0.85f;

		private const float SprintVocalPitchMinimum = 1.12f;

		private const float SprintVocalPitchMaximum = 1.18f;

		private const float SpotConfirmHysteresisDegrees = 8f;

		private const float SpotConfirmRangeHysteresis = 1.15f;

		private const float NoiseAcceptCooldownSeconds = 1.75f;

		private const float NoiseMinimumLoudness = 0.3f;

		private const float NoiseMinimumPerceivedLoudness = 0.04f;

		private const float SightFocusOcclusionGraceSeconds = 0.4f;

		private const float ObservationHoldSeconds = 4.5f;

		private const float ObservationPlantMaximumSeconds = 4.5f;

		private const float ObservationReplantCooldownSeconds = 10f;

		private const float FootGroundedDistance = 0.14f;

		private const float FootstepContactCooldown = 0.24f;

		private const float MinimumTravelPerFootstep = 0.34f;

		private const float GroundRaycastVerticalPadding = 1.4f;

		private const float VisualGroundSmoothSpeed = 14f;

		private const float FootBoneGroundingFallbackSoleOffset = 0.18f;

		private const float DoorwayDuckCastRadius = 0.13f;

		private const float DoorwayDuckChestProbeHeight = 0.95f;

		private const float DoorwayDuckMinimumClearanceHeight = 1.25f;

		private const float DoorwayDuckMinimumLocomotionSpeed = 0.06f;

		private const float DoorwayLintelProbeInset = 0.21f;

		private const float HeadPostureSyncStepDegrees = 1.5f;

		private const float GazeAuthorityBlendPerSecond = 8f;

		private const float HypnosisPitchBlendSeconds = 0.3f;

		private const float NeckRollShare = 0.3f;

		private const double IdleScanEpochCellSeconds = 60.0;

		private const long IdleScanBeatsPerCell = 128L;

		private const float IdleScanGlanceHoldMinSeconds = 0.6f;

		private const float IdleScanGlanceHoldMaxSeconds = 1.2f;

		private const float IdleScanDownwardPitchDegrees = 4f;

		private const float FootClearanceProbeHeight = 1f;

		private const float FootClearanceProbeDepth = 2.5f;

		private const float FootSoleOffsetDecayPerSecond = 0.08f;

		private const float FootSoleOffsetMinimumSample = 0.02f;

		private const float FootSoleOffsetSeedCeiling = 0.35f;

		private const float StandingHeadHeightDecayPerSecond = 0.15f;

		private const float RoamSearchMinimumWidth = 12f;

		private const float RoamSearchMaximumWidth = 40f;

		private const float RoamSearchNodeBudgetSeconds = 16f;

		private const float RoamSearchRegionSpread = 2.5f;

		private const float RoamSearchPrecision = 1.5f;

		private const float BodyTurnStepThresholdDegreesPerSecond = 10f;

		private const float BodyTurnStepMetersPerDegree = 0.006f;

		private const float NeckSlashRecoverySeconds = 0.32f;

		private const int ClientConfirmLogReceived = 1;

		private const int FootstepSurfaceConcrete = 0;

		private const int FootstepSurfaceMetal = 1;

		private const int FootstepSurfaceWood = 2;

		private const float FootstepGainConcrete = 11.2f;

		private const float FootstepGainMetal = 15f;

		private const float FootstepGainWood = 5.3f;

		private const float FootstepGainCeiling = 64f;

		private const float StandardFootstepBroadcastVolume = 1f;

		private const float FolleyChance = 0.35f;

		private const float FolleyVolumeScale = 0.8f;

		private const float FolleyGainQuietClip = 5.6f;

		private const string FolleyQuietClipName = "folley02";

		public Transform attackOrigin;

		public AudioSource stepAudioSource;

		public AudioSource idleAudioSource;

		public AudioSource constantAudioSource;

		public AudioSource mindControlAudioSource;

		public AudioClip[] stepClips = (AudioClip[])(object)new AudioClip[0];

		public AudioClip[] stepClipsConcrete = (AudioClip[])(object)new AudioClip[0];

		public AudioClip[] stepClipsMetal = (AudioClip[])(object)new AudioClip[0];

		public AudioClip[] stepClipsWood = (AudioClip[])(object)new AudioClip[0];

		public AudioClip[] idleClips = (AudioClip[])(object)new AudioClip[0];

		public AudioClip idleBeatClip;

		public AudioClip[] folleyClips = (AudioClip[])(object)new AudioClip[0];

		public AudioClip constantClip;

		public AudioClip mindControlClip;

		public AudioClip[] mindControlClips = (AudioClip[])(object)new AudioClip[0];

		public AudioClip killClip;

		public AudioClip headSnapClip;

		public AISearchRoutine facilitySearch = new AISearchRoutine();

		private static readonly int AnimIsMoving = Animator.StringToHash("IsMoving");

		private static readonly int AnimIsRunning = Animator.StringToHash("IsRunning");

		private static readonly int AnimWalkRate = Animator.StringToHash("WalkRate");

		private static readonly int AnimRunRate = Animator.StringToHash("RunRate");

		private static readonly int AnimNeckSlash = Animator.StringToHash("NeckSlash");

		private static readonly float[] StandardWalkFootstepPhases = new float[2] { 0.08f, 0.56f };

		private static readonly string[] VoiceSpeakingMemberNames = new string[4] { "IsSpeaking", "isSpeaking", "Speaking", "speaking" };

		private static readonly string[] VoiceAmplitudeMemberNames = new string[2] { "Amplitude", "amplitude" };

		private static readonly float[] VoiceOutputSamples = new float[64];

		private const BindingFlags VoiceMemberFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;

		private static FieldInfo _voicePlayerStateField;

		private static bool _voicePlayerStateFieldResolved;

		private static readonly Dictionary<Type, MemberInfo[]> VoiceSpeakingMembers = new Dictionary<Type, MemberInfo[]>();

		private static readonly Dictionary<Type, MemberInfo[]> VoiceAmplitudeMembers = new Dictionary<Type, MemberInfo[]>();

		private static readonly Dictionary<Type, FieldInfo> VoiceSettingsStateFields = new Dictionary<Type, FieldInfo>();

		private static readonly MemberInfo[] NoVoiceMembers = new MemberInfo[0];

		private EncounterState _encounterState;

		private float _encounterStateEnteredTime;

		private ulong _encounterTargetClientId = ulong.MaxValue;

		private float _encounterLastStimulusTime;

		private ulong _chaseRefractoryClientId = ulong.MaxValue;

		private float _chaseRefractoryUntilTime;

		private float _nextSearchVocalTime;

		private ulong _serverDetectionBeatClientId = ulong.MaxValue;

		private float _serverDetectionBeatStartTime;

		private string _serverDetectionBeatReason;

		private PlayerControllerB _serverEntrancedPlayer;

		private ulong _serverEntrancedClientId = ulong.MaxValue;

		private float _serverPossessionCommandTime;

		private bool _serverPossessionAcknowledged;

		private readonly NetworkVariable<ulong> _networkEntrancedClientId = new NetworkVariable<ulong>(ulong.MaxValue, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)0);

		private float _serverRescueBlockedSince = -1f;

		private ulong _serverRescueBlockerClientId = ulong.MaxValue;

		private float _serverTranceSightLostSince = -1f;

		private Collider _serverTranceSightBlocker;

		private float _nextExecutionAttemptTime;

		private float _serverTranceBestDistance = float.PositiveInfinity;

		private float _serverTranceProgressTime;

		private int _serverExecutionMissStreak;

		private float _serverHypnosisContactSeconds;

		private bool _serverHypnosisContactHeld;

		private int _serverHypnosisContactFrame = -1;

		private ulong _serverHypnosisContactClientId = ulong.MaxValue;

		private PlayerControllerB _serverPursuitPlayer;

		private ulong _serverPursuitClientId = ulong.MaxValue;

		private float _serverPursuitLastVisibleTime;

		private string _serverPursuitSource = "none";

		private Vector3 _serverPursuitLastSeenPosition;

		private bool _hasServerPursuitLastSeen;

		private bool _serverInvestigating;

		private bool _serverInvestigateLooking;

		private Vector3 _serverInvestigatePoint;

		private float _serverInvestigateStartedTime;

		private float _serverInvestigateLookUntilTime;

		private bool _serverInvestigateLingering;

		private float _serverInvestigateLingerUntilTime;

		private string _serverSearchExitReason = "search complete";

		private float _serverSprintPendingStartTime = -1f;

		private float _serverSprintUntilTime;

		private float _nextSprintAllowedTime;

		private float _nextSprintRollTime;

		private bool _serverSprintGuaranteePending;

		private bool _serverSprintWasActive;

		private ulong _serverSlashTargetClientId = ulong.MaxValue;

		private bool _isNeckSlashing;

		private bool _serverClawCrouchRefusalLogged;

		private bool _serverStandingToClaw;

		private bool _serverSlashPresentationOpen;

		private int _serverSlashSequence;

		private float _serverSlashLatchedTime;

		private float _serverSlashLatchLimitSeconds;

		private float _serverSlashMomentumSpeed;

		private float _serverSlashMomentumUntil;

		private bool _audioParityApplied;

		private AudioSource _constantLoopConfiguredSource;

		private AudioSource _idleAudioConfiguredSource;

		private bool _serverExecutionShouldCloseDistance;

		private float _nextNeckSlashTime;

		private ulong _serverObservationClientId = ulong.MaxValue;

		private bool _serverObservationFromNoise;

		private float _serverObservationUntilTime;

		private float _serverGazeContactSeconds;

		private float _serverGazeLastContactTime;

		private bool _serverGazeGraceLogged;

		private bool _serverSpotConfirmed;

		private float _serverSpotConfirmedAtTime;

		private int _serverSpotConfirmEpoch;

		private int _possessionRangeRefusalEpoch = -1;

		private ulong _possessionRangeRefusalClientId = ulong.MaxValue;

		private Vector3 _serverNoiseStimulusPoint;

		private float _serverSightLastSeenTime;

		private float _nextNoiseAcceptTime;

		private float _nextVoiceAcceptTime;

		private ulong _syncedObservedClientId = ulong.MaxValue;

		private bool _syncedSpotConfirmed;

		private int _syncedSpotConfirmEpoch;

		private float _nextObservationSyncRefreshTime;

		private ulong _replicatedObservedClientId = ulong.MaxValue;

		private bool _replicatedSpotConfirmed;

		private float _replicatedSpotConfirmedTime;

		private int _replicatedSpotConfirmEpoch;

		private int _clientConfirmLogEpoch = -1;

		private int _clientConfirmLogFlags;

		private float _serverEntrancedStartTime;

		private float _serverBodyRotationUnlockTime;

		private bool _localPossessed;

		private bool _localControlsSaved;

		private bool _localSavedDisableLookInput;

		private bool _localSavedDisableMoveInput;

		private float _localPossessionStartTime;

		private PlayerControllerB _localClaimedPlayer;

		private ulong _localAppliedEntrancedClientId = ulong.MaxValue;

		private ulong _localSuppressedTranceClientId = ulong.MaxValue;

		private NavMeshPath _victimPullPath;

		private readonly Vector3[] _victimPullCorners = (Vector3[])(object)new Vector3[64];

		private int _victimPullCornerCount;

		private bool _victimPullHoldAtRouteEnd;

		private float _nextVictimPullRepathTime;

		private static bool _loggedVictimPullBufferFull;

		private bool _localSlashPresentationActive;

		private bool _localSlashImpactReceived;

		private float _localSlashStartedTime;

		private float _localSlashImpactTime;

		private float _localSlashWindupSeconds;

		private bool _localSlashUsesClip;

		private bool _localSlashClipRecoveryStarted;

		private int _strikeClipPresence;

		private float _nextMovementDiagnosticTime;

		private readonly RaycastHit[] _lineOfSightHits = (RaycastHit[])(object)new RaycastHit[32];

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

		private static bool _loggedGroundProbeBufferFull;

		private bool _headTrackingReferencesResolved;

		private bool _footReferencesResolved;

		private readonly Vector3[] _bodyProbePoints = (Vector3[])(object)new Vector3[3];

		private float _hypnosisPitchBlend;

		private int _lastFootstepClipIndex = -1;

		private int _lastFolleyClipIndex = -1;

		private int _lastStandardFootstepKey = -1;

		private int _stepsUntilIdleBeat = -1;

		private bool _mindControlAudioPlaying;

		private bool _mindControlAudioDampened;

		private float _nextMindControlSnapshotRefreshTime;

		private bool _localMindControlCameraSaved;

		private float _localMindControlBaseFov;

		private Transform _headBone;

		private Transform _neckBone;

		private Transform _lowerSpineBone;

		private Transform _upperSpineBone;

		private Transform _rightClavicleBone;

		private Transform _rightUpperArmBone;

		private Transform _rightForearmBone;

		private float _headFocusUntilTime;

		private float _headBodyFollowAllowedTime;

		private float _serverLastSnapTime = float.NegativeInfinity;

		private HushdollLookTarget _serverPendingLook = new HushdollLookTarget
		{
			Kind = 0,
			ClientId = ulong.MaxValue
		};

		private bool _serverPendingForceSnap;

		private HushdollPerception.HeadAimState _headAim;

		private float _headAimRollDegrees;

		private float _headAimRollVelocity;

		private float _headAimBodyYawDegrees;

		private bool _headAimInitialized;

		private float _headAimTargetYawDegrees;

		private float _headAimTargetPitchDegrees;

		private bool _headAimHasLookTarget;

		private int _localSeenSnapEpoch;

		private bool _localSnapEpochPrimed;

		private Quaternion _headRestToRoot = Quaternion.identity;

		private Quaternion _neckRestToRoot = Quaternion.identity;

		private bool _hasHeadChainRestPose;

		private string _headRestPoseSource = "none";

		private float _gazeAuthorityWeight;

		private readonly NetworkVariable<byte> _networkCrouchSteps = new NetworkVariable<byte>((byte)0, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)0);

		private const float NetworkPositionSyncThreshold = 0.05f;

		private const float NetworkPositionSmoothSeconds = 0.25f;

		private const int PursuitSirenOff = -1;

		private readonly NetworkVariable<byte> _networkEncounterState = new NetworkVariable<byte>((byte)0, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)0);

		private readonly NetworkVariable<ulong> _networkEncounterTargetClientId = new NetworkVariable<ulong>(ulong.MaxValue, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)0);

		private readonly NetworkVariable<int> _networkPursuitSirenClip = new NetworkVariable<int>(-1, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)0);

		private AudioSource _pursuitSirenSource;

		private float _pursuitSirenSourceVolume = 1f;

		private readonly NetworkVariable<HushdollSharedSettings> _networkSharedSettings = new NetworkVariable<HushdollSharedSettings>(default(HushdollSharedSettings), (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)0);

		private ulong _serverReportedForeignOwner = ulong.MaxValue;

		private bool _networkDespawning;

		private const byte LookKindNone = 0;

		private const byte LookKindPlayer = 1;

		private const byte LookKindPoint = 2;

		private readonly NetworkVariable<HushdollLookTarget> _networkLookTarget = new NetworkVariable<HushdollLookTarget>(new HushdollLookTarget
		{
			Kind = 0,
			ClientId = ulong.MaxValue
		}, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)0);

		private HushdollLookTarget _serverLookTarget = new HushdollLookTarget
		{
			Kind = 0,
			ClientId = ulong.MaxValue
		};

		private readonly NetworkVariable<HushdollPeekState> _networkPeekState = new NetworkVariable<HushdollPeekState>(default(HushdollPeekState), (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)0);

		private HushdollPeekState _serverPeekState;

		private ulong _serverPeekTargetClientId = ulong.MaxValue;

		private float _serverPeekPhaseStartTime;

		private float _serverPeekHoldSeconds;

		private Vector3 _serverPeekStopPoint;

		private Vector3 _serverPeekAxis;

		private Vector3 _serverPeekEyePoint;

		private Vector3 _serverPeekLineDirection;

		private float _serverPeekSightLostSeconds;

		private float _serverPeekCrouchAmount;

		private float _serverPeekLeanMeters;

		private float _serverPeekApertureHeight;

		private float _serverPeekApertureWidth;

		private bool _serverPeekIsWallEdge;

		private DoorLock _serverPeekDoor;

		private AnimatedObjectTrigger _serverPeekDoorTrigger;

		private ulong _serverPeekCooldownClientId = ulong.MaxValue;

		private float _serverPeekCooldownUntilTime;

		private Vector3 _serverLastPeekOpening;

		private float _serverLastPeekOpeningUntilTime;

		private readonly Vector3[] _serverPeekRefusalLogged = (Vector3[])(object)new Vector3[4];

		private int _serverPeekRefusalLoggedCount;

		private float _serverPeekRefusalEncounterTime = -1f;

		private ulong _serverPeekRefusalTargetId = ulong.MaxValue;

		private bool _serverPeekSearchRefusalLogged;

		private readonly PeekCandidate[] _peekCandidates = new PeekCandidate[3];

		private float _peekFitRequiredDrop;

		private float _peekFitThrowClear;

		private float _peekFitWantedLean;

		private float _peekFitHeadClear;

		private float _peekFitChestClear;

		private bool _peekCastSaturated;

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

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

		private readonly RaycastHit[] _peekDoorRouteHits = (RaycastHit[])(object)new RaycastHit[8];

		private float _peekLeanPitchDegrees;

		private float _peekLeanRollDegrees;

		private float _nextHeadPostureMeasureTime;

		private float _serverDoorwayCrouchAmount;

		private bool _serverDuckActive;

		private float _serverRequiredDoorwayDropMeters;

		private bool _serverDuckHoldActive;

		private float _serverDuckHoldDropMeters;

		private float _serverDuckHoldApertureHeight;

		private Vector3 _serverDuckLowestOverheadPoint;

		private Vector3 _serverDuckLowestOverheadAxis;

		private Collider _serverDuckHoldCollider;

		private float _serverDuckHoldAheadMeters;

		private float _serverDuckHoldFloorOffset;

		private bool _serverDuckHoldFromFootprint;

		private readonly Vector3[] _duckPathCornerBuffer = (Vector3[])(object)new Vector3[16];

		private readonly Vector3[] _duckSampleBuffer = (Vector3[])(object)new Vector3[24];

		private readonly Vector3[] _duckSampleAxisBuffer = (Vector3[])(object)new Vector3[24];

		private readonly float[] _duckSampleAheadBuffer = new float[24];

		private long _idleScanBeatIndex;

		private long _idleScanCell;

		private long _idleScanBeatStep;

		private double _idleScanBeatStartTime;

		private double _idleScanBeatEndTime;

		private bool _hasIdleScanCursor;

		private float _idleScanHoldScale = 1f;

		private bool _idleScanActive;

		private Transform _leftFootBone;

		private Transform _rightFootBone;

		private Vector3 _leftFootPreviousPosition;

		private Vector3 _rightFootPreviousPosition;

		private bool _leftFootWasGrounded;

		private bool _rightFootWasGrounded;

		private float _leftFootSoleOffset = -1f;

		private float _rightFootSoleOffset = -1f;

		private bool _contactFootstepClockActive;

		private float _nextContactFootstepTime;

		private Vector3 _lastFootstepTravelPosition;

		private bool _hasFootstepTravelPosition;

		private float _footstepTravelAccumulator;

		private Transform _visualRoot;

		private Vector3 _lastLocomotionSamplePosition;

		private float _lastLocomotionSampleYawDegrees;

		private bool _hasLocomotionSample;

		private float _smoothedLocomotionSpeed;

		private float _smoothedBodyTurnSpeed;

		private float _lastSlowWalkPlaybackRate;

		private string _lastGaitName = "none";

		private bool _runGaitEngaged;

		private int _runClipPresence;

		private int _gaitRateParameterPresence;

		private float _localCrouchAmount;

		private int _crouchParameterPresence;

		private CapsuleCollider _upperBodyCollider;

		private float _upperBodyColliderHeight = -1f;

		private bool _crouchCapHeadLogged;

		private bool _localCrouchWasAtCap;

		private float _standingHeadHeight;

		private bool _hasStandingHeadHeight;

		private bool _standingHeadHeightIsBoundsSeed;

		private BodyRestPose _bodyRest;

		private bool _hasBodyRest;

		private bool _bodyRestLogged;

		private int _bodyRestAccumulatedFrames;

		private Vector3 _bodyRestAccumulatedLower;

		private Vector3 _bodyRestAccumulatedUpper;

		private Vector3 _bodyRestAccumulatedNeck;

		private Vector3 _bodyRestAccumulatedHead;

		private bool _bodyRestAccumulatedHasLowerSpine;

		private bool _bodyRestAccumulatedHasUpperSpine;

		private bool _serverObservationPlanted;

		private float _serverObservationPlantStartTime;

		private float _serverObservationPlantAlignedTime;

		private bool _serverObservationPlantSpent;

		private ulong _serverLastPlantedClientId = ulong.MaxValue;

		private float _serverLastPlantCompletedTime = float.NegativeInfinity;

		private bool _loggedRuntimeDiagnostics;

		private float _nextHeadDiagnosticTime;

		private float _nextRoamDiagnosticTime;

		private string _lastHeadStateLogLine;

		private float _nextHeadStateLogTime;

		private bool _loggedEyeOrigin;

		private bool _serverBodyTurnInProgress;

		private int _contactFootstepCount;

		private int _phasedFootstepCount;

		private float _nextFootstepDiagnosticTime;

		private const float BodyProbeChestHeight = 2f;

		private const float BodyProbeLowHeight = 0.5f;

		private const int GazeAngleProbePointCount = 2;

		private const float PeekWallEdgeMinimumLateralMeters = 0.25f;

		private const int PeekDoorLayerMask = 576;

		private bool ServerMobileClawActive
		{
			get
			{
				if (_isNeckSlashing && !_serverExecutionShouldCloseDistance)
				{
					return HasAnimatronicController();
				}
				return false;
			}
		}

		private HushdollSharedSettings SharedSettings
		{
			get
			{
				if (!((NetworkBehaviour)this).IsSpawned || !_networkSharedSettings.Value.Published)
				{
					return HushdollSharedSettings.FromLocalConfig();
				}
				return _networkSharedSettings.Value.Sanitized();
			}
		}

		private EncounterState ReplicatedEncounterState
		{
			get
			{
				if (!((NetworkBehaviour)this).IsServer)
				{
					return (EncounterState)_networkEncounterState.Value;
				}
				return _encounterState;
			}
		}

		private ulong ReplicatedEncounterTargetClientId
		{
			get
			{
				if (!((NetworkBehaviour)this).IsServer)
				{
					return _networkEncounterTargetClientId.Value;
				}
				return _encounterTargetClientId;
			}
		}

		private HushdollLookTarget CurrentLookTarget
		{
			get
			{
				if (!((NetworkBehaviour)this).IsServer)
				{
					return _networkLookTarget.Value;
				}
				return _serverLookTarget;
			}
		}

		private HushdollPeekState CurrentPeekState
		{
			get
			{
				if (!((NetworkBehaviour)this).IsServer)
				{
					return _networkPeekState.Value;
				}
				return _serverPeekState;
			}
		}

		private PeekPhase ServerPeekPhase => (PeekPhase)_serverPeekState.Phase;

		private bool ServerPeekActive => _serverPeekState.Phase != 0;

		private bool ServerPeekLeaning => _serverPeekState.Phase == 2;

		private float MoveSpeed => SharedSettings.MoveSpeed;

		private float Acceleration => Mathf.Max(22.5f, 22.5f);

		private float AngularSpeed => Mathf.Max(120f, 150f);

		private float HypnosisEyeContactSeconds => Mathf.Clamp(Plugin.ModConfig?.HypnosisEyeContactSeconds?.Value ?? 2f, 0.5f, 10f);

		private float GazeHalfAngleDegrees => 18f;

		private float CloseRangeGazeHalfAngleDegrees => 40f;

		private float MovementLockDelay => SharedSettings.MovementLockDelay;

		private float PossessionStrafeSeconds => 2f;

		private float PossessedWalkSpeed => SharedSettings.PullSpeed;

		private float PossessedStrafeSpeed => 0.75f;

		private float PossessedLookTurnSpeed => 280f;

		private float RoamRadius => 18f;

		private float RoamRepathSeconds => 5f;

		private float RoamSearchWidth
		{
			get
			{
				float num = Mathf.Clamp(MoveSpeed * 16f * 2.5f, 12f, 40f);
				return Mathf.Clamp(RoamRadius * 2.5f, 12f, num);
			}
		}

		private bool HeadTrackingEnabled => true;

		private float HeadTrackingRange => Mathf.Max(80f, 80f);

		private float HeadSightRange => Mathf.Clamp(Plugin.ModConfig?.SightRange?.Value ?? 32f, 2f, HeadTrackingRange);

		private float HeadHearingRange => Mathf.Clamp(Plugin.ModConfig?.HearingRange?.Value ?? 20f, 4f, 80f);

		private float HeadVisionConeDegrees => 55f;

		private float HeadProximityAwareness => 3f;

		private float HeadRearAwarenessRange => 4.5f;

		private float HeadSightHoldSeconds => 3.5f;

		private float HeadRearTurnDelaySeconds => 1.2f;

		private float SpotConfirmSeconds => 0.8f;

		private float SpotConfirmGraceSeconds => 0.6f;

		private float PossessionBeginMaxDistance => 12f;

		private float HeadRearRegionDegrees => 78f;

		private float HeadPitchUpLimitDegrees => 47f;

		private float EffectiveHeadPitchDownLimitDegrees => Mathf.Lerp(75f, 82f, _hypnosisPitchBlend);

		private float HeadTrackSpeed => 240f;

		private float HeadBodyFollowDelay => 3f;

		private float HeadBodyFollowSpeed => 60f;

		private float PursuitDropRange => Mathf.Clamp(Plugin.ModConfig?.PursuitRange?.Value ?? 60f, 12f, HeadTrackingRange);

		private float NeckSlashRange => SharedSettings.NeckSlashRange;

		private float NeckSlashCooldown => SharedSettings.AttackCooldown;

		private float NeckSlashKillDelay => Mathf.Max(2f, 2f);

		private bool PlayNeckSlashAnimation => Plugin.PlayAttackAnimation;

		private bool StaticVisualTestMode => Plugin.StaticVisualTestMode;

		private bool DoorwayDuckEnabled => true;

		private float DoorwayDuckCrownAboveHeadBone => 0.55f;

		private float DoorwayDuckSampleSpacingMeters => 0.35f;

		private float DoorwayDuckClearanceMargin => 0.08f;

		private float HeadPoseAuthority => 1f;

		private float HeadRestPitchTrimDegrees => 0f;

		private float HeadRollLimitDegrees => 18f;

		private bool IdleExamineEnabled => true;

		private float IdleScanYawRangeDegrees => 55f;

		private float IdleScanPitchRangeDegrees => 12f;

		private float IdleScanRollDegrees => 6f;

		private float IdleScanSpeedDegreesPerSecond => 26f;

		private float IdleScanHoldMinSeconds => 2.5f;

		private float IdleScanHoldMaxSeconds => 6f;

		private float IdleScanGlanceChance => 0.2f;

		private float FootstepVolume => Mathf.Clamp(Plugin.ModConfig?.FootstepVolume?.Value ?? 1f, 0f, 4f);

		private float MindControlVisualIntensity => Mathf.Clamp01(Plugin.ModConfig?.MindControlVisualIntensity?.Value ?? 0.65f);

		private bool DevSnapSpawnNearPlayer => false;

		private float DevSpawnDistance => 6f;

		private bool DebugLogs => Plugin.ModConfig?.DebugLogs?.Value == true;

		private bool ServerMindControlMovementUnlocked
		{
			get
			{
				if (_serverEntrancedClientId != ulong.MaxValue)
				{
					return Time.time - _serverEntrancedStartTime >= MovementLockDelay;
				}
				return false;
			}
		}

		private bool ServerDetectionBeatActive => _serverDetectionBeatClientId != ulong.MaxValue;

		private bool ServerSprintActive => Time.time < _serverSprintUntilTime;

		private float ReplicatedCrouchAmount => HushdollPerception.DequantizeCrouchAmount(_networkCrouchSteps.Value);

		private void ContinueMobileClawPursuit(PlayerControllerB player)
		{
			//IL_0078: 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_008d: 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_00c9: 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_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			if (!((NetworkBehaviour)this).IsServer || !ServerMobileClawActive || (Object)(object)player == (Object)null || player.isPlayerDead || !PlayerIsTargetableByHushdoll(player, cannotBeInShip: true))
			{
				StopAgentPath();
			}
			else if (EnsureAgentOnNavMesh() && PlayerFitsNeckSlashGeometry(player, NeckSlashRange + 4f, requireFacing: false, requireLineOfSight: true))
			{
				base.movingTowardsTargetPlayer = false;
				ApplyAgentSpeed();
				base.agent.updateRotation = false;
				Vector3 val = ((Component)player).transform.position - ((Component)this).transform.position;
				val.y = 0f;
				float magnitude = ((Vector3)(ref val)).magnitude;
				if (magnitude <= 1.2f)
				{
					StopAgentPath();
					return;
				}
				base.agent.isStopped = false;
				((EnemyAI)this).SetDestinationToPosition(((Component)player).transform.position - val / magnitude * 1.2f, true);
			}
		}

		private void BeginMobileClawPresentation()
		{
			int layerIndex = base.creatureAnimator.GetLayerIndex("UpperBodyAttack");
			base.creatureAnimator.SetLayerWeight(layerIndex, 0f);
			base.creatureAnimator.Play("UpperBodyAttack.ClawAttack", layerIndex, 0f);
		}

		private void UpdateMobileClawPresentation()
		{
			if (!((Object)(object)base.creatureAnimator == (Object)null))
			{
				int layerIndex = base.creatureAnimator.GetLayerIndex("UpperBodyAttack");
				if (layerIndex >= 1)
				{
					float num = Mathf.Clamp01((Time.time - _localSlashStartedTime) / 0.16f);
					float num2 = (_localSlashImpactReceived ? Mathf.Clamp01((Time.time - _localSlashImpactTime - 0.18f) / 0.37f) : 0f);
					base.creatureAnimator.SetLayerWeight(layerIndex, Mathf.SmoothStep(0f, 1f, num) * (1f - Mathf.SmoothStep(0f, 1f, num2)));
				}
			}
		}

		private void EndMobileClawPresentation()
		{
			if (!((Object)(object)base.creatureAnimator == (Object)null))
			{
				int layerIndex = base.creatureAnimator.GetLayerIndex("UpperBodyAttack");
				if (layerIndex >= 1)
				{
					base.creatureAnimator.SetLayerWeight(layerIndex, 0f);
				}
			}
		}

		private bool HasAnimatronicController()
		{
			if (_animatronicPresence != 0)
			{
				return _animatronicPresence > 0;
			}
			if ((Object)(object)base.creatureAnimator == (Object)null || (Object)(object)base.creatureAnimator.runtimeAnimatorController == (Object)null)
			{
				return false;
			}
			_animatronicPresence = -1;
			string[] array = new string[5] { "Sprint", "MoveStart", "MoveStop", "TurnLeft", "TurnRight" };
			foreach (string text in array)
			{
				if (!base.creatureAnimator.HasState(0, Animator.StringToHash("Base Layer." + text)))
				{
					return false;
				}
			}
			if (base.creatureAnimator.GetLayerIndex("UpperBodyAttack") < 1 || !base.creatureAnimator.HasState(base.creatureAnimator.GetLayerIndex("UpperBodyAttack"), Animator.StringToHash("UpperBodyAttack.ClawAttack")))
			{
				return false;
			}
			bool flag = false;
			bool flag2 = false;
			bool flag3 = false;
			AnimatorControllerParameter[] parameters = base.creatureAnimator.parameters;
			foreach (AnimatorControllerParameter val in parameters)
			{
				flag |= val.nameHash == AnimUseAnimatronic;
				flag2 |= val.nameHash == AnimSprintRate;
				flag3 |= val.nameHash == AnimTurnRate;
			}
			if (flag && flag2 && flag3)
			{
				_animatronicPresence = 1;
			}
			return _animatronicPresence > 0;
		}

		private void ApplyAnimatorCrouchAmount(float amount)
		{
			if ((Object)(object)base.creatureAnimator == (Object)null || (Object)(object)base.creatureAnimator.runtimeAnimatorController == (Object)null)
			{
				return;
			}
			if (_crouchParameterPresence == 0)
			{
				if (!base.creatureAnimator.isInitialized)
				{
					return;
				}
				ResolveCrouchSupport();
			}
			if (_crouchParameterPresence > 0)
			{
				base.creatureAnimator.SetFloat(AnimCrouchAmount, amount);
			}
		}

		private void ResolveCrouchSupport()
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Invalid comparison between Unknown and I4
			bool flag = false;
			AnimatorControllerParameter[] parameters = base.creatureAnimator.parameters;
			foreach (AnimatorControllerParameter val in parameters)
			{
				flag |= val.nameHash == AnimCrouchAmount && (int)val.type == 1;
			}
			int layerIndex = base.creatureAnimator.GetLayerIndex("Crouch");
			bool flag2 = layerIndex >= 0;
			float num = (flag2 ? base.creatureAnimator.GetLayerWeight(layerIndex) : 0f);
			bool flag3 = flag2 && num > 0.01f;
			_crouchParameterPresence = ((flag && flag3) ? 1 : (-1));
			if (_loggedCrouchSupport)
			{
				return;
			}
			_loggedCrouchSupport = true;
			string name = ((Object)base.creatureAnimator.runtimeAnimatorController).name;
			string text = (flag2 ? $"Crouch layer at index {layerIndex}, weight {num:0.00}" : "no Crouch layer");
			if (_crouchParameterPresence > 0)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogInfo((object)("[CreepyDollAI][crouch] controller '" + name + "' supports the stoop: CrouchAmount float, " + text + "."));
				}
				return;
			}
			if (!flag)
			{
				ManualLogSource log2 = Plugin.Log;
				if (log2 != null)
				{
					log2.LogError((object)("[CreepyDollAI][crouch] controller '" + name + "' has no CrouchAmount float (" + text + "): the doorway stoop and the peek crouch will not render."));
				}
			}
			if (!flag3)
			{
				string text2 = ((!flag2) ? "no Crouch layer" : $"Crouch layer weight {num:0.00} (≤ 0.01)");
				ManualLogSource log3 = Plugin.Log;
				if (log3 != null)
				{
					log3.LogError((object)("[CreepyDollAI][crouch] controller '" + name + "' has " + text2 + ": the doorway stoop and the peek crouch will not render."));
				}
			}
		}

		private bool UpdateAnimatronicMovement(float speed)
		{
			//IL_02a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0298: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ab: Unknown result type (might be due to invalid IL or missing references)
			if (!HasAnimatronicController())
			{
				return false;
			}
			base.creatureAnimator.SetBool(AnimUseAnimatronic, true);
			base.creatureAnimator.speed = 1f;
			base.creatureAnimator.SetFloat(AnimWalkRate, GaitPlaybackRate(speed, 4.85f, 4.56f));
			base.creatureAnimator.SetFloat(AnimRunRate, GaitPlaybackRate(speed, 1.9f, 4.54f));
			base.creatureAnimator.SetFloat(AnimSprintRate, GaitPlaybackRate(speed, 1.6f, 4.54f));
			base.creatureAnimator.SetFloat(AnimTurnRate, Mathf.Clamp(_smoothedBodyTurnSpeed / 60f, 0.5f, 2f));
			if (_localSlashPresentationActive && !_localClawAttack)
			{
				_animatronicState = null;
				_animatronicGait = 0;
				_runGaitEngaged = false;
				return true;
			}
			int animatronicGait = _animatronicGait;
			_animatronicGait = HushdollPerception.SelectGait(speed, animatronicGait);
			_runGaitEngaged = _animatronicGait >= 2;
			bool flag = _animatronicGait == 0 && _smoothedBodyTurnSpeed > 18f;
			string text = ((_animatronicGait == 3) ? "Sprint" : ((_animatronicGait == 2) ? "Run" : ((_animatronicGait == 1) ? "SlowWalk" : ((!flag) ? "Idle" : ((_signedBodyTurnSpeed >= 0f) ? "TurnRight" : "TurnLeft")))));
			float num = Time.time - _animatronicStateSince;
			if (_animatronicState == "MoveStart" && _animatronicGait == 1 && num < 0.3f)
			{
				text = "MoveStart";
			}
			else if (_animatronicState == "MoveStop" && _animatronicGait == 0 && !flag && num < 0.35f)
			{
				text = "MoveStop";
			}
			else if (animatronicGait == 0 && _animatronicGait == 1 && _animatronicState == "Idle")
			{
				text = "MoveStart";
			}
			else if (animatronicGait > 0 && _animatronicGait == 0 && !flag)
			{
				text = "MoveStop";
			}
			base.creatureAnimator.SetBool(AnimIsMoving, _animatronicGait > 0 || flag);
			base.creatureAnimator.SetBool(AnimIsRunning, _runGaitEngaged);
			if (_animatronicState != text)
			{
				float num2 = 0f;
				switch (text)
				{
				case "SlowWalk":
				case "Run":
				case "Sprint":
				{
					AnimatorStateInfo val = (base.creatureAnimator.IsInTransition(0) ? base.creatureAnimator.GetNextAnimatorStateInfo(0) : base.creatureAnimator.GetCurrentAnimatorStateInfo(0));
					if (((AnimatorStateInfo)(ref val)).IsName("SlowWalk") || ((AnimatorStateInfo)(ref val)).IsName("Run") || ((AnimatorStateInfo)(ref val)).IsName("Sprint"))
					{
						float num3 = ((text == "Sprint") ? 1.6f : ((text == "Run") ? 1.9f : 4.85f));
						float num4 = base.creatureAnimator.GetFloat((text == "Sprint") ? AnimSprintRate : ((text == "Run") ? AnimRunRate : AnimWalkRate));
						num2 = Mathf.Repeat(((AnimatorStateInfo)(ref val)).normalizedTime, 1f) * num3 / Mathf.Max(0.01f, num4);
					}
					break;
				}
				}
				_animatronicState = text;
				_animatronicStateSince = Time.time;
				float num5;
				switch (text)
				{
				default:
					num5 = 0.1f;
					break;
				case "Sprint":
				case "Run":
					num5 = 0.16f;
					break;
				case "MoveStop":
					num5 = 0.22f;
					break;
				}
				float num6 = num5;
				base.creatureAnimator.CrossFadeInFixedTime(text, num6, 0, num2);
			}
			_lastGaitName = text;
			_lastSlowWalkPlaybackRate = ((_animatronicGait == 3) ? GaitPlaybackRate(speed, 1.6f, 4.54f) : ((_animatronicGait == 2) ? GaitPlaybackRate(speed, 1.9f, 4.54f) : ((_animatronicGait == 1) ? GaitPlaybackRate(speed, 4.85f, 4.56f) : 0f)));
			return true;
		}

		public override void Awake()
		{
			try
			{
				EnsureBehaviourStates();
				((EnemyAI)this).Awake();
				ResolveRuntimeReferences();
				ConfigureSearchDefaults();
			}
			catch (Exception arg)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogError((object)$"[CreepyDollAI] Awake failed: {arg}");
				}
			}
		}

		public override void Start()
		{
			//IL_013e: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				EnsureBehaviourStates();
				base.updatePositionThreshold = 0.05f;
				base.syncMovementSpeed = 0.25f;
				((EnemyAI)this).Start();
				ResolveRuntimeReferences();
				CorrectPrototypeSpawnPlacement();
				ConfigureAgent();
				ConfigureSearchDefaults();
				Plugin.EnsureCollision(((Component)this).gameObject, this);
				_upperBodyCollider = ((Component)this).GetComponent<CapsuleCollider>();
				_upperBodyColliderHeight = -1f;
				Plugin.EnsureScanNode(((Component)this).gameObject);
				Plugin.DisablePhysicalVisualColliders(((Component)this).gameObject);
				RepairFacilityAINodes();
				Plugin.RepairVisuals(((Component)this).gameObject, "spawned instance");
				Plugin.ApplyVisualYawOffset(((Component)this).gameObject, "spawned instance");
				SeedStandingHeadHeightFromBounds();
				base.enemyHP = 999;
				base.isOutside = false;
				if ((Object)(object)base.creatureAnimator != (Object)null)
				{
					Plugin.ConfigureAnimatorForCurrentMode(base.creatureAnimator, "spawned instance");
					if (!StaticVisualTestMode)
					{
						base.creatureAnimator.SetBool(AnimIsMoving, false);
						base.creatureAnimator.SetBool(AnimIsRunning, false);
						_runGaitEngaged = false;
						base.creatureAnimator.ResetTrigger(AnimNeckSlash);
						base.creatureAnimator.Play("Idle", 0, 0f);
					}
				}
				EnsureConstantLoop();
				if (((NetworkBehaviour)this).IsServer)
				{
					StartRoamingSearch(((Component)this).transform.position);
					_nextSprintAllowedTime = Time.time + 30f;
				}
				if (DebugLogs)
				{
					LogSpawnDiagnostic("Started");
				}
				LogHushdollRuntimeDiagnostics("start");
			}
			catch (Exception arg)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogError((object)$"[CreepyDollAI] Start failed: {arg}");
				}
			}
		}

		public override void Update()
		{
			try
			{
				EnsureServerOwnership();
				((EnemyAI)this).Update();
				if (base.isEnemyDead)
				{
					ReleaseLocalTranceState("her death");
					EndServerPeek(PeekAbort.Killed);
					if (((NetworkBehaviour)this).IsServer)
					{
						ClearServerDoorwayDuck();
						WriteServerCrouchTarget(0f);
					}
					StopConstantLoop();
					StopPursuitSirenLocal();
					return;
				}
				if ((Object)(object)base.creatureAnimator == (Object)null || (Object)(object)base.agent == (Object)null)
				{
					ResolveRuntimeReferences();
				}
				Plugin.ApplyVisualYawOffset(((Component)this).gameObject, "static visual tick", log: false);
				TickLocalTranceState();
				UpdateAnimatorMovementFlag();
				TickCreatureAudio();
				UpdateEyeTransform();
				TickServerHeadDetectionState();
				TickServerEncounterState();
				TickServerPeek();
				SyncServerReplicatedEncounter();
				SyncServerObservationState();
				SyncServerLookTarget();
				RefreshAgentRotationOwnership();
				TickServerBodyFollowHeadFocus();
				TickServerHeadPosture();
				LogRoamDiagnostic();
			}
			catch (Exception arg)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogError((object)$"[CreepyDollAI] Update failed: {arg}");
				}
			}
		}

		public override void OnNetworkSpawn()
		{
			((NetworkBehaviour)this).OnNetworkSpawn();
			try
			{
				_networkDespawning = false;
				if (((NetworkBehaviour)this).IsServer)
				{
					HushdollSharedSettings value = HushdollSharedSettings.FromLocalConfig();
					value.Published = true;
					_networkSharedSettings.Value = value;
					_networkLookTarget.Value = _serverLookTarget;
					_networkPeekState.Value = _serverPeekState;
				}
				_localSnapEpochPrimed = false;
				NetworkVariable<int> networkPursuitSirenClip = _networkPursuitSirenClip;
				networkPursuitSirenClip.OnValueChanged = (OnValueChangedDelegate<int>)(object)Delegate.Combine((Delegate?)(object)networkPursuitSirenClip.OnValueChanged, (Delegate?)(object)new OnValueChangedDelegate<int>(OnPursuitSirenClipChanged));
				if (_networkPursuitSirenClip.Value != -1)
				{
					StartPursuitSirenLocal(_networkPursuitSirenClip.Value);
				}
			}
			catch (Exception arg)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogError((object)$"[CreepyDollAI] OnNetworkSpawn failed: {arg}");
				}
			}
		}

		public override void OnNetworkDespawn()
		{
			try
			{
				_networkDespawning = true;
				CancelServerNeckSlash();
				NetworkVariable<int> networkPursuitSirenClip = _networkPursuitSirenClip;
				networkPursuitSirenClip.OnValueChanged = (OnValueChangedDelegate<int>)(object)Delegate.Remove((Delegate?)(object)networkPursuitSirenClip.OnValueChanged, (Delegate?)(object)new OnValueChangedDelegate<int>(OnPursuitSirenClipChanged));
				StopPursuitSirenLocal();
				ReleaseLocalTranceState("her despawn");
				EndServerPeek(PeekAbort.Despawned);
			}
			catch (Exception arg)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogError((object)$"[CreepyDollAI] OnNetworkDespawn failed: {arg}");
				}
			}
			((NetworkBehaviour)this).OnNetworkDespawn();
		}

		public override void OnDestroy()
		{
			try
			{
				ReleaseLocalTranceState("her destroy");
			}
			catch (Exception arg)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogError((object)$"[CreepyDollAI] OnDestroy failed: {arg}");
				}
			}
			((EnemyAI)this).OnDestroy();
		}

		public override void CancelSpecialAnimationWithPlayer()
		{
			((EnemyAI)this).CancelSpecialAnimationWithPlayer();
			try
			{
				ulong num = ReadReplicatedEntrancedClientId();
				if (num != ulong.MaxValue && num != _localSuppressedTranceClientId)
				{
					string reason = (base.isEnemyDead ? "her death" : "victim teleported");
					PlayerControllerB val = ResolveLocalPlayer();
					if (!((NetworkBehaviour)this).IsServer && (Object)(object)val != (Object)null && val.actualClientId == num)
					{
						ReportLocalPossession(val, active: false);
					}
					ReleaseLocalTranceState(reason);
				}
			}
			catch (Exception arg)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogError((object)$"[CreepyDollAI] CancelSpecialAnimationWithPlayer failed: {arg}");
				}
			}
		}

		private void EnsureServerOwnership()
		{
			if (!((NetworkBehaviour)this).IsServer || !((NetworkBehaviour)this).IsSpawned)
			{
				return;
			}
			ulong ownerClientId = ((NetworkBehaviour)this).OwnerClientId;
			if (ownerClientId == 0L)
			{
				_serverReportedForeignOwner = ulong.MaxValue;
			}
			else if (_serverReportedForeignOwner != ownerClientId)
			{
				_serverReportedForeignOwner = ownerClientId;
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogWarning((object)$"[CreepyDollAI] NetworkObject owner moved to client {ownerClientId}; restoring server ownership.");
				}
				((NetworkBehaviour)this).NetworkObject.ChangeOwnership(0uL);
				if ((Object)(object)StartOfRound.Instance != (Object)null && StartOfRound.Instance.ClientPlayerList.TryGetValue(0uL, out var value))
				{
					base.currentOwnershipOnThisClient = value;
					((EnemyAI)this).ChangeEnemyOwnerClientRpc(value);
				}
			}
		}

		private void SyncServerReplicatedEncounter()
		{
			if (((NetworkBehaviour)this).IsServer && ((NetworkBehaviour)this).IsSpawned)
			{
				byte b = (byte)_encounterState;
				if (_networkEncounterState.Value != b)
				{
					_networkEncounterState.Value = b;
				}
				if (_networkEncounterTargetClientId.Value != _encounterTargetClientId)
				{
					_networkEncounterTargetClientId.Value = _encounterTargetClientId;
				}
			}
		}

		private void LateUpdate()
		{
			try
			{
				TickLocalPossessionControl();
				StabilizeVisualRootOnGround();
				ResolveHeadTrackingReferences();
				TrackStandingHeadHeight();
				TickHeadPostureSmoothing();
				ApplyProceduralPose();
				LogCrouchCapHeadOnce();
				ApplyProceduralNeckSlash();
			}
			catch (Exception arg)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogError((object)$"[CreepyDollAI] LateUpdate failed: {arg}");
				}
			}
		}

		private void OnDisable()
		{
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				ReleaseLocalTranceState("her disable");
				StopConstantLoop();
				StopPursuitSirenLocal();
				CancelServerNeckSlash();
				EndServerPeek(PeekAbort.Disabled);
				ClearServerDoorwayDuck();
				if (((NetworkBehaviour)this).IsServer && ((NetworkBehaviour)this).IsSpawned && !_networkDespawning)
				{
					WriteServerCrouchTarget(0f);
				}
				_localCrouchAmount = 0f;
				_localCrouchWasAtCap = false;
				ApplyAnimatorCrouchAmount(0f);
				if ((Object)(object)_upperBodyCollider != (Object)null)
				{
					float num = (_upperBodyColliderHeight = 3.5f);
					_upperBodyCollider.height = num;
					_upperBodyCollider.center = new Vector3(0f, num * 0.5f, 0f);
				}
				_localSlashPresentationActive = false;
				_localSlashImpactReceived = false;
				_localSlashUsesClip = false;
				_localSlashClipRecoveryStarted = false;
			}
			catch (Exception arg)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogError((object)$"[CreepyDollAI] OnDisable failed: {arg}");
				}
			}
		}

		public override void DoAIInterval()
		{
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				((EnemyAI)this).DoAIInterval();
				if (!((NetworkBehaviour)this).IsServer || base.isEnemyDead || (Object)(object)StartOfRound.Instance == (Object)null || StartOfRound.Instance.allPlayersDead)
				{
					return;
				}
				ConfigureAgent();
				ConfigureSearchDefaults();
				RepairFacilityAINodes();
				if (_isNeckSlashing)
				{
					if (ReleaseStaleNeckSlashLatch())
					{
						return;
					}
					PlayerControllerB val = FindPlayerByClientId(_serverSlashTargetClientId);
					if ((Object)(object)val != (Object)null && !val.isPlayerDead)
					{
						if (ServerMobileClawActive)
						{
							ContinueMobileClawPursuit(val);
						}
						else
						{
							StopAgentPath();
							FacePosition(((Component)val).transform.position);
						}
						FocusHeadOnPlayerServer(val, 0.45f);
					}
					else
					{
						StopAgentPath();
					}
				}
				else
				{
					if (_encounterState == EncounterState.Hypnosis && TryBeginServerExecution())
					{
						return;
					}
					if (Time.time >= _nextNeckSlashTime)
					{
						PlayerControllerB val2 = FindBasicAttackTarget();
						if ((Object)(object)val2 != (Object)null && BeginNeckSlashServer(val2, execution: false))
						{
							return;
						}
					}
					switch (_encounterState)
					{
					case EncounterState.Hypnosis:
					{
						PlayerControllerB val3 = ResolveServerEntrancedPlayer();
						if ((Object)(object)val3 != (Object)null)
						{
							PursueServerTarget(val3, respectMindControlDelay: true);
						}
						else
						{
							StopMovingServer();
						}
						break;
					}
					case EncounterState.Chase:
					{
						PlayerControllerB val4 = ResolveServerPursuitPlayer();
						if ((Object)(object)val4 != (Object)null)
						{
							if (!TickServerPeekMovement() && !TryBeginServerPeek(val4))
							{
								TickServerSprint(val4);
								PursueServerTarget(val4, respectMindControlDelay: false);
							}
						}
						else
						{
							StopMovingServer();
						}
						break;
					}
					case EncounterState.Search:
						if (!TickServerPeekMovement())
						{
							PlayerControllerB val5 = (_serverInvestigating ? ResolveEncounterTargetPlayer() : null);
							if ((!((Object)(object)val5 != (Object)null) || !TryBeginServerPeek(val5)) && !TickServerInvestigation())
							{
								StopMovingServer();
							}
						}
						break;
					case EncounterState.Suspicious:
						if (ServerDetectionBeatActive || ServerHoldsStillForObservation())
						{
							StopMovingServer();
						}
						else
						{
							RoamServer();
						}
						break;
					default:
						RoamServer();
						break;
					}
				}
			}
			catch (Exception arg)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogError((object)$"[CreepyDollAI] DoAIInterval failed: {arg}");
				}
			}
		}

		private void TickServerEncounterState()
		{
			if (!((NetworkBehaviour)this).IsServer || base.isEnemyDead)
			{
				return;
			}
			PlayerControllerB val = ResolveEncounterTargetPlayer();
			if (_isNeckSlashing)
			{
				if ((Object)(object)val == (Object)null && (_encounterState == EncounterState.Suspicious || _encounterState == EncounterState.Chase))
				{
					LeaveChaseBookkeeping();
					TransitionEncounterState(EncounterState.Dormant, "target invalid during slash");
				}
				if (_encounterState == EncounterState.Hypnosis && !TickServerTrance())
				{
					LeaveHypnosisAfterRelease();
				}
				return;
			}
			switch (_encounterState)
			{
			case EncounterState.Suspicious:
				TickSuspiciousEncounterState(val);
				break;
			case EncounterState.Chase:
				TickChaseEncounterState(val);
				break;
			case EncounterState.Search:
				TickSearchEncounterState();
				break;
			case EncounterState.Hypnosis:
				TickHypnosisEncounterState();
				break;
			}
		}

		private void TickSuspiciousEncounterState(PlayerControllerB target)
		{
			if ((Object)(object)target == (Object)null)
			{
				TransitionEncounterState(EncounterState.Dormant, "target invalid");
			}
			else
			{
				if (TryEnterHypnosisFromGaze(target))
				{
					return;
				}
				if (ServerDetectionBeatActive)
				{
					TickServerDetectionBeat();
					return;
				}
				float num = Time.time - _encounterStateEnteredTime;
				if (Time.time - _encounterLastStimulusTime > 6f && num >= 3f)
				{
					TransitionEncounterState(EncounterState.Dormant, "no stimulus refresh");
				}
			}
		}

		private void BeginChaseOrDetectionBeat(PlayerControllerB player, string reason)
		{
			if (TargetIsInChaseRefractory(player.actualClientId))
			{
				ForceHeadSnapToPlayerServer(player, HeadSightHoldSeconds);
				TryBeginChase(player, reason);
			}
			else
			{
				BeginServerDetectionBeat(player, reason);
			}
		}

		private void BeginServerDetectionBeat(PlayerControllerB player, string reason)
		{
			//IL_0054: 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)
			_serverDetectionBeatClientId = player.actualClientId;
			_serverDetectionBeatStartTime = Time.time;
			_serverDetectionBeatReason = reason;
			StopMovingServer();
			ForceHeadSnapToPlayerServer(player, HeadSightHoldSeconds);
			LogHeadStateEvent($"detection beat begin: player={player.actualClientId}, reason={reason}, " + $"bodyYawToTarget={BodyYawErrorTo(((Component)player).transform.position):0} deg, " + $"distance={Vector3.Distance(((Component)this).transform.position, ((Component)player).transform.position):0.0} m.");
		}

		private void TickServerDetectionBeat()
		{
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			PlayerControllerB val = FindPlayerByClientId(_serverDetectionBeatClientId);
			if ((Object)(object)val == (Object)null || val.isPlayerDead || !PlayerIsTargetableByHushdoll(val, cannotBeInShip: true))
			{
				EndServerDetectionBeat("target invalid");
				return;
			}
			FocusHeadOnPlayerServer(val, HeadSightHoldSeconds);
			float num = Time.time - _serverDetectionBeatStartTime;
			if (num >= 0.25f)
			{
				FacePosition(((Component)val).transform.position, Time.deltaTime, 180f);
			}
			bool flag = num >= 0.25f && BodyYawErrorTo(((Component)val).transform.position) <= 20f;
			if (flag || !(num < 1.2f))
			{
				string serverDetectionBeatReason = _serverDetectionBeatReason;
				EndServerDetectionBeat(flag ? "body aligned" : "time cap");
				TryBeginChase(val, serverDetectionBeatReason);
			}
		}

		private void EndServerDetectionBeat(string reason)
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			if (ServerDetectionBeatActive)
			{
				PlayerControllerB val = FindPlayerByClientId(_serverDetectionBeatClientId);
				string arg = (((Object)(object)val != (Object)null) ? $"{BodyYawErrorTo(((Component)val).transform.position):0} deg" : "n/a");
				LogHeadStateEvent($"detection beat end: player={_serverDetectionBeatClientId}, reason={reason}, " + $"after {Time.time - _serverDetectionBeatStartTime:0.00} s, bodyYawToTarget={arg}.");
				_serverDetectionBeatClientId = ulong.MaxValue;
				_serverDetectionBeatReason = null;
			}
		}

		private float BodyYawErrorTo(Vector3 point)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: 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)
			Vector3 val = point - ((Component)this).transform.position;
			val.y = 0f;
			if (!(((Vector3)(ref val)).sqrMagnitude < 0.0001f))
			{
				return Vector3.Angle(((Component)this).transform.forward, val);
			}
			return 0f;
		}

		private void TickChaseEncounterState(PlayerControllerB target)
		{
			//IL_002c: 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_003c: 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_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: 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_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)target == (Object)null)
			{
				LeaveChaseBookkeeping();
				TransitionEncounterState(EncounterState.Dormant, "chase target invalid");
			}
			else
			{
				if (TryEnterHypnosisFromGaze(target))
				{
					return;
				}
				Vector3 val = ((Component)target).transform.position - ((Component)this).transform.position;
				float magnitude = ((Vector3)(ref val)).magnitude;
				bool flag = magnitude <= HeadTrackingRange && HasClearLineOfSightToPlayerFace(target);
				if (flag)
				{
					_serverPursuitPlayer = target;
					_serverPursuitLastVisibleTime = Time.time;
					_serverPursuitLastSeenPosition = ((Component)target).transform.position;
					_hasServerPursuitLastSeen = true;
					return;
				}
				float num = Time.time - _serverPursuitLastVisibleTime;
				if (!HushdollPerception.RetainPursuit(magnitude, flag, num, Time.time - _encounterStateEnteredTime, PursuitDropRange, 12f))
				{
					LogHeadStateEvent($"chase lost: player={_encounterTargetClientId}, source={_serverPursuitSource}, " + $"distance={magnitude:0.0}/{PursuitDropRange:0.0} m, unseen={num:0.00} s.");
					bool hasServerPursuitLastSeen = _hasServerPursuitLastSeen;
					Vector3 serverPursuitLastSeenPosition = _serverPursuitLastSeenPosition;
					ulong encounterTargetClientId = _encounterTargetClientId;
					LeaveChaseBookkeeping();
					ArmChaseRefractory(encounterTargetClientId);
					if (hasServerPursuitLastSeen)
					{
						BeginServerInvestigation(serverPursuitLastSeenPosition);
						_encounterTargetClientId = encounterTargetClientId;
						TransitionEncounterState(EncounterState.Search, "lost sight");
					}
					else
					{
						TransitionEncounterState(EncounterState.Dormant, "lost sight, nowhere to search");
					}
				}
			}
		}

		private void TickSearchEncounterState()
		{
			if (!_serverInvestigating)
			{
				TransitionEncounterState(EncounterState.Dormant, _serverSearchExitReason);
			}
			else if (Time.time >= _nextSearchVocalTime)
			{
				_nextSearchVocalTime = Time.time + 4f;
				PlayIdleBeatClientRpc(0.5f, 1f);
			}
		}

		private void TickHypnosisEncounterState()
		{
			if (TickServerTrance())
			{
				_encounterTargetClientId = _serverEntrancedClientId;
			}
			else
			{
				LeaveHypnosisAfterRelease();
			}
		}

		private bool TickServerTrance()
		{
			PlayerControllerB val = ResolveServerEntrancedPlayer();
			if ((Object)(object)val == (Object)null)
			{
				return false;
			}
			if (!_serverPossessionAcknowledged && Time.time - _serverPossessionCommandTime > 1f)
			{
				ClearServerEntrancedPlayer("possession command unacknowledged after " + $"{Time.time - _serverPossessionCommandTime:0.00} s", ulong.MaxValue);
				return false;
			}
			string text = DescribeTranceSoftlock(val);
			if (text != null)
			{
				ClearServerEntrancedPlayer(text, ulong.MaxValue);
				return false;
			}
			if (!TickServerTranceSight(val))
			{
				return false;
			}
			PlayerControllerB val2 = FindPlayerBlockingTranceSight(val);
			if ((Object)(object)val2 == (Object)null)
			{
				_serverRescueBlockedSince = -1f;
				_serverRescueBlockerClientId = ulong.MaxValue;
				return true;
			}
			if (_serverRescueBlockedSince < 0f)
			{
				_serverRescueBlockedSince = Time.time;
			}
			_serverRescueBlockerClientId = val2.actualClientId;
			float num = Time.time - _serverRescueBlockedSince;
			if (num < 0.25f)
			{
				return true;
			}
			ClearServerEntrancedPlayer($"rescued: player={_serverRescueBlockerClientId} blocked the victim's " + $"view of her for {num:0.00} s", ulong.MaxValue);
			return false;
		}

		private bool TickServerTranceSight(PlayerControllerB victim)
		{
			Collider faceLineBlocker;
			bool num = TranceSightHolds(victim, out faceLineBlocker);
			if (!num)
			{
				_serverTranceSightBlocker = faceLineBlocker;
			}
			if (!HushdollPerception.AdvanceTranceSightLoss(num, Time.time, ref _serverTranceSightLostSince, 0.35f))
			{
				return true;
			}
			float num2 = Time.time - _serverTranceSightLostSince;
			Collider serverTranceSightBlocker = _serverTranceSightBlocker;
			ClearServerEntrancedPlayer("line of sight broken: " + (((Object)(object)serverTranceSightBlocker != (Object)null) ? ((Object)serverTranceSightBlocker).name : "unknown") + " " + $"for {num2:0.00} s", ulong.MaxValue);
			return false;
		}

		private bool TranceSightHolds(PlayerControllerB victim, out Collider faceLineBlocker)
		{
			//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_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: 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_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: 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_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: 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_0088: 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_0095: Unknown result type (might be due to invalid IL or missing references)
			Transform transform = ((Component)victim).transform;
			Vector3 facePoint = GetFacePoint();
			Vector3 origin = ((Component)this).transform.position + Vector3.up * 2f;
			Vector3 playerFocusPoint = GetPlayerFocusPoint(victim);
			Vector3 target = (((Object)(object)victim.upperSpine != (Object)null) ? victim.upperSpine.position : (transform.position + Vector3.up * 1.4f));
			if (!SightLineIsClear(facePoint, playerFocusPoint, transform, out faceLineBlocker) && !SightLineIsClear(facePoint, target, transform, out var blocker) && !SightLineIsClear(origin, playerFocusPoint, transform, out blocker))
			{
				return SightLineIsClear(origin, target, transform, out blocker);
			}
			return true;
		}

		private string DescribeTranceSoftlock(PlayerControllerB victim)
		{
			//IL_0006: 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_001b: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = ((Component)victim).transform.position - ((Component)this).transform.position;
			val.y = 0f;
			float magnitude = ((Vector3)(ref val)).magnitude;
			bool serverMindControlMovementUnlocked = ServerMindControlMovementUnlocked;
			if (!serverMindControlMovementUnlocked || HushdollPerception.TranceApproachProgressed(_serverTranceBestDistance, magnitude))
			{
				_serverTranceBestDistance = magnitude;
				_serverTranceProgressTime = Time.time;
			}
			float num = Time.time - _serverTranceProgressTime;
			return HushdollPerception.ClassifyTranceSoftlock(serverMindControlMovementUnlocked, num, _serverExecutionMissStreak) switch
			{
				TranceSoftlock.ExecutionFailedRepeatedly => $"execution failed repeatedly: {_serverExecutionMissStreak} misses in this trance, " + $"distance {magnitude:0.00} m", 
				TranceSoftlock.VictimUnreachable => $"victim unreachable: no approach progress or execution windup for {num:0.0} s, " + $"distance {magnitude:0.00} m (best {_serverTranceBestDistance:0.00} m)", 
				_ => null, 
			};
		}

		private PlayerControllerB FindPlayerBlockingTranceSight(PlayerControllerB victim)
		{
			//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_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: 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_0058: 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_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: 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_0150: Unknown result type (might be due to invalid IL or missing references)
			//IL_015a: 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_0164: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: 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_00fd: 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_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: Unknown result type (might be due to invalid IL or missing references)
			//IL_0176: Unknown result type (might be due to invalid IL or missing references)
			//IL_017d: 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_018e: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)victim == (Object)null || (Object)(object)victim.gameplayCamera == (Object)null || (Object)(object)StartOfRound.Instance == (Object)null || StartOfRound.Instance.allPlayerScripts == null)
			{
				return null;
			}
			Vector3 position = ((Component)victim.gameplayCamera).transform.position;
			Vector3 lookTargetPoint = GetLookTargetPoint();
			PerceptionPoint perceptionPoint = new PerceptionPoint(position.x, position.y, position.z);
			PerceptionPoint to = new PerceptionPoint(lookTargetPoint.x, lookTargetPoint.y, lookTargetPoint.z);
			PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts;
			foreach (PlayerControllerB val in allPlayerScripts)
			{
				if (!((Object)(object)val == (Object)null) && !((Object)(object)val == (Object)(object)victim) && val.isPlayerControlled && !val.isPlayerDead)
				{
					CharacterController thisController = val.thisController;
					Vector3 val2;
					float radius;
					float num;
					if ((Object)(object)thisController != (Object)null)
					{
						Vector3 lossyScale = ((Component)val).transform.lossyScale;
						val2 = ((Component)val).transform.TransformPoint(thisController.center);
						radius = thisController.radius * Mathf.Max(Mathf.Abs(lossyScale.x), Mathf.Abs(lossyScale.z));
						num = thisController.height * 0.5f * Mathf.Abs(lossyScale.y);
					}
					else
					{
						val2 = ((Component)val).transform.position + Vector3.up * 1.28f;
						radius = 0.4f;
						num = 1.25f;
					}
					if (HushdollPerception.SegmentCrossesUprightCapsule(perceptionPoint, to, val2.x, val2.z, val2.y - num, val2.y + num, radius))
					{
						return val;
					}
				}
			}
			return null;
		}

		private void LeaveHypnosisAfterRelease()
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: 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_0067: Unknown result type (might be due to invalid IL or missing references)
			PlayerControllerB val = ResolveEncounterTargetPlayer();
			if ((Object)(object)val != (Object)null)
			{
				ArmChaseRefractory(val.actualClientId);
				Vector3 val2 = ((Component)val).transform.position - ((Component)this).transform.position;
				if (!(((Vector3)(ref val2)).magnitude <= PursuitDropRange) || !HasClearLineOfSightToPlayerFace(val, allowBodyPoints: true) || !TryBeginChase(val, "trance released, still visible"))
				{
					BeginServerInvestigation(((Component)val).transform.position);
					TransitionEncounterState(EncounterState.Search, "trance released, victim gone");
				}
			}
			else
			{
				ArmChaseRefractory(_encounterTargetClientId);
				TransitionEncounterState(EncounterState.Dormant, "trance released, no victim");
			}
		}

		private bool TryEnterHypnosisFromGaze(PlayerControllerB target)
		{
			//IL_0061: 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)
			if (!((NetworkBehaviour)this).IsServer || (Object)(object)target == (Object)null || _serverEntrancedClientId != ulong.MaxValue || _serverHypnosisContactClientId != target.actualClientId || _serverHypnosisContactFrame != Time.frameCount || !HushdollPerception.HypnosisOnsetDue(_serverHypnosisContactSeconds, _serverHypnosisContactHeld, HypnosisEyeContactSeconds) || !PlayerIsTargetableByHushdoll(target, cannotBeInShip: true))
			{
				return false;
			}
			float num = Vector3.Distance(((Component)this).transform.position, ((Component)target).transform.position);
			if (num > PossessionBeginMaxDistance)
			{
				LogPossessionRangeRefusal(target.actualClientId, num);
				return false;
			}
			BeginServerPossession(target);
			_encounterTargetClientId = target.actualClientId;
			ArmChaseRefractory(target.actualClientId);
			TransitionEncounterState(EncounterState.Hypnosis, "mutual gaze held");
			return true;
		}

		private void LogPossessionRangeRefusal(ulong clientId, float distance)
		{
			if (_possessionRangeRefusalEpoch != _serverSpotConfirmEpoch || _possessionRangeRefusalClientId != clientId)
			{
				_possessionRangeRefusalEpoch = _serverSpotConfirmEpoch;
				_possessionRangeRefusalClientId = clientId;
				LogHeadStateEvent($"possession refused (out of reach): player={clientId}, " + $"epoch={_serverSpotConfirmEpoch}, distance={distance:0.0} m, " + $"max={PossessionBeginMaxDistance:0.0} m.");
			}
		}

		private void BeginServerPossession(PlayerControllerB player)
		{
			//IL_013a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0145: Unknown result type (might be due to invalid IL or missing references)
			if (((NetworkBehaviour)this).IsServer && !((Object)(object)player == (Object)null))
			{
				ulong actualClientId = player.actualClientId;
				float serverHypnosisContactSeconds = _serverHypnosisContactSeconds;
				ClearServerPursuitTarget(clearObservationForSameTarget: false);
				_serverEntrancedPlayer = player;
				_serverEntrancedClientId = actualClientId;
				_serverEntrancedStartTime = Time.time;
				_serverPossessionCommandTime = Time.time;
				_serverPossessionAcknowledged = false;
				_serverBodyRotationUnlockTime = Time.time;
				_serverRescueBlockedSince = -1f;
				_serverRescueBlockerClientId = ulong.MaxValue;
				_serverTranceSightLostSince = -1f;
				_serverTranceSightBlocker = null;
				_nextExecutionAttemptTime = 0f;
				ResetServerTranceSoftlock();
				ResetServerHypnosisContact();
				if (((NetworkBehaviour)this).IsSpawned)
				{
					_networkEntrancedClientId.Value = actualClientId;
				}
				ClearServerObservationTarget();
				ResetServerObservationPlantHistory();
				base.targetPlayer = player;
				base.movingTowardsTargetPlayer = false;
				_headBodyFollowAllowedTime = Time.time;
				ForceHeadSnapToPlayerServer(player, 0.65f);
				StopSearchIfNeeded(clear: false);
				StopAgentPath();
				if (!StaticVisualTestMode && base.currentBehaviourStateIndex != 0)
				{
					((EnemyAI)this).SwitchToBehaviourState(0);
				}
				LogHeadStateEvent($"possession commanded: player={actualClientId}, " + $"eyeContact={serverHypnosisContactSeconds:0.00}/{HypnosisEyeContactSeconds:0.00} s uninterrupted, " + $"distance={Vector3.Distance(((Component)this).transform.position, ((Component)player).transform.position):0.0} m.");
			}
		}

		private void ResetServerHypnosisContact()
		{
			_serverHypnosisContactSeconds = 0f;
			_serverHypnosisContactHeld = false;
			_serverHypnosisContactFrame = -1;
			_serverHypnosisContactClientId = ulong.MaxValue;
		}

		private void ResetServerTranceSoftlock()
		{
			_serverTranceBestDistance = float.PositiveInfinity;
			_serverTranceProgressTime = Time.time;
			_serverExecutionMissStreak = 0;
		}

		private void TransitionEncounterState(EncounterState next, string reason)
		{
			if (!((NetworkBehaviour)this).IsServer || next == _encounterState)
			{
				return;
			}
			EncounterState encounterState = _encounterState;
			float num = Time.time - _encounterStateEnteredTime;
			_encounterState = next;
			_encounterStateEnteredTime = Time.time;
			if (encounterState == EncounterState.Suspicious)
			{
				EndServerDetectionBeat($"interrupted by {next}: {reason}");
			}
			bool num2 = encounterState == EncounterState.Chase || encounterState == EncounterState.Hypnosis;
			bool flag = next == EncounterState.Chase || next == EncounterState.Hypnosis;
			if (num2 && !flag)
			{
				StopPursuitSirenServer();
			}
			switch (next)
			{
			case EncounterState.Suspicious:
				if (encounterState == EncounterState.Dormant && TargetIsInChaseRefractory(_encounterTargetClientId))
				{
					reason += ", re-entered (remembered)";
				}
				break;
			case EncounterState.Chase:
				if (TargetIsInChaseRefractory(_encounterTargetClientId))
				{
					reason += ", re-entered (remembered)";
				}
				StartPursuitSirenServer();
				_serverSprintGuaranteePending = true;
				break;
			case EncounterState.Search:
				_nextSearchVocalTime = Time.time + 4f;
				PlayIdleBeatClientRpc(0.55f, 1f);
				break;
			case EncounterState.Dormant:
				if (encounterState == EncounterState.Search)
				{
					PlayIdleBeatClientRpc(0.3f, 0.94f);
				}
				_encounterTargetClientId = ulong.MaxValue;
				break;
			}
			if (encounterState == EncounterState.Chase)
			{
				_serverSprintUntilTime = 0f;
				_serverSprintPendingStartTime = -1f;
				_serverSprintWasActive = false;
			}
			ApplyAgentSpeed();
			LogHeadStateEvent($"[encounter] {encounterState} -> {next}: reason={reason}, " + "target=" + ((_encounterTargetClientId == ulong.MaxValue) ? "none" : _encounterTargetClientId.ToString()) + ", " + $"dwell={num:0.0}s");
		}

		private void ArmChaseRefractory(ulong clientId)
		{
			if (clientId != ulong.MaxValue)
			{
				_chaseRefractoryClientId = clientId;
				_chaseRefractoryUntilTime = Time.time + 20f;
			}
		}

		private bool TargetIsInChaseRefractory(ulong clientId)
		{
			if (clientId != ulong.MaxValue && _chaseRefractoryClientId == clientId)
			{
				return Time.time <= _chaseRefractoryUntilTime;
			}
			return false;
		}

		private void NoteEncounterStimulus(PlayerControllerB player, bool seen, Vector3? point = null)
		{
			//IL_00d5: 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_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: 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_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			if (!((NetworkBehaviour)this).IsServer || base.isEnemyDead || (Object)(object)player == (Object)null || player.isPlayerDead || !PlayerIsTargetableByHushdoll(player, cannotBeInShip: true))
			{
				return;
			}
			ulong actualClientId = player.actualClientId;
			switch (_encounterState)
			{
			case EncounterState.Dormant:
				_encounterTargetClientId = actualClientId;
				_encounterLastStimulusTime = Time.time;
				TransitionEncounterState(EncounterState.Suspicious, seen ? "sighted" : "heard");
				if (!seen)
				{
					break;
				}
				goto case EncounterState.Suspicious;
			case EncounterState.Suspicious:
				_encounterLastStimulusTime = Time.time;
				if (_serverObservationClientId == actualClientId)
				{
					_encounterTargetClientId = actualClientId;
				}
				if (seen && !ServerDetectionBeatActive)
				{
					BeginChaseOrDetectionBeat(player, "clear sight of a player");
				}
				break;
			case EncounterState.Chase:
			{
				if (!seen || actualClientId == _encounterTargetClientId)
				{
					break;
				}
				PlayerControllerB val = ResolveEncounterTargetPlayer();
				if ((Object)(object)val != (Object)null)
				{
					Vector3 val2 = ((Component)val).transform.position - ((Component)this).transform.position;
					float sqrMagnitude = ((Vector3)(ref val2)).sqrMagnitude;
					val2 = ((Component)player).transform.position - ((Component)this).transform.position;
					if (sqrMagnitude <= ((Vector3)(ref val2)).sqrMagnitude)
					{
						break;
					}
				}
				SetServerPursuitTarget(player, "sight");
				if (_serverPursuitClientId == actualClientId)
				{
					_encounterTargetClientId = actualClientId;
					LogHeadStateEvent($"[encounter] chase retargeted to player={actualClientId} (no announcement).");
				}
				break;
			}
			case EncounterState.Search:
				if (!seen)
				{
					break;
				}
				if (ServerPeekActive && actualClientId == _serverPeekTargetClientId)
				{
					if (TryBeginChase(player, "sighted during peek"))
					{
						EndServerInvestigation("target sighted during peek");
					}
				}
				else if (!TargetIsInChaseRefractory(actualClientId))
				{
					EndServerInvestigation("new player sighted");
					_encounterTargetClientId = actualClientId;
					_encounterLastStimulusTime = Time.time;
					TransitionEncounterState(EncounterState.Suspicious, "sighted during search");
					BeginServerDetectionBeat(player, "sighted during search");
				}
				else
				{
					ForceHeadSnapToPlayerServer(player, HeadSightHoldSeconds);
					if (TryBeginChase(player, "sighted during search"))
					{
						EndServerInvestigation("target sighted again");
					}
				}
				break;
			}
		}

		private bool TryBeginChase(PlayerControllerB player, string reason)
		{
			if ((Object)(object)player == (Object)null)
			{
				return false;
			}
			SetServerPursuitTarget(player, "sight");
			if (_serverPursuitClientId != player.actualClientId)
			{
				return false;
			}
			_encounterTargetClientId = player.actualClientId;
			TransitionEncounterState(EncounterState.Chase, reason);
			return true;
		}

		private void LeaveChaseBookkeeping()
		{
			ClearServerPursuitTarget(clearObservationForSameTarget: true);
		}

		private PlayerControllerB ResolveEncounterTargetPlayer()
		{
			if (_encounterTargetClientId == ulong.MaxValue)
			{
				return null;
			}
			PlayerControllerB val = FindPlayerByClientId(_encounterTargetClientId);
			if ((Object)(object)val == (Object)null || val.isPlayerDead || !PlayerIsTargetableByHushdoll(val, cannotBeInShip: true))
			{
				return null;
			}
			return val;
		}

		private bool EncounterStateAllowsRoaming()
		{
			if (_encounterState == EncounterState.Dormant)
			{
				return true;
			}
			if (_encounterState == EncounterState.Suspicious && !ServerDetectionBeatActive)
			{
				return !ServerHoldsStillForObservation();
			}
			return false;
		}

		private void PursueServerTarget(PlayerControllerB target, bool respectMindControlDelay)
		{
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			if (!((NetworkBehaviour)this).IsServer || (Object)(object)target == (Object)null || target.isPlayerDead)
			{
				return;
			}
			base.targetPlayer = target;
			StopSearchIfNeeded(clear: false);
			int num;
			if (respectMindControlDelay)
			{
				num = (ServerMindControlMovementUnlocked ? 1 : 0);
				if (num == 0)
				{
					base.movingTowardsTargetPlayer = false;
					StopAgentPath();
					goto IL_004d;
				}
			}
			else
			{
				num = 1;
			}
			((EnemyAI)this).SetMovingTowardsTargetPlayer(target);
			goto IL_004d;
			IL_004d:
			FocusHeadOnPlayerServer(target, 0.65f);
			if (num == 0)
			{
				FacePosition(((Component)target).transform.position);
				if (!StaticVisualTestMode && base.currentBehaviourStateIndex != 0)
				{
					((EnemyAI)this).SwitchToBehaviourState(0);
				}
				return;
			}
			if (EnsureAgentOnNavMesh())
			{
				base.agent.updateRotation = AgentDrivesBodyRotation();
				base.agent.isStopped = false;
			}
			else
			{
				StopAgentPath();
				LogMovementDiagnostic("target movement skipped: agent is not on NavMesh");
			}
			if (!AgentDrivesBodyRotation())
			{
				FacePosition(((Component)target).transform.position);
			}
			if (!StaticVisualTestMode && base.currentBehaviourStateIndex != 1)
			{
				((EnemyAI)this).SwitchToBehaviourState(1);
			}
		}

		private PlayerControllerB FindBasicAttackTarget()
		{
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			if (!((NetworkBehaviour)this).IsServer || (Object)(object)StartOfRound.Instance == (Object)null || StartOfRound.Instance.allPlayerScripts == null)
			{
				return null;
			}
			PlayerControllerB result = null;
			float num = float.PositiveInfinity;
			PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts;
			foreach (PlayerControllerB val in allPlayerScripts)
			{
				if (!((Object)(object)val == (Object)null) && val.actualClientId != _serverEntrancedClientId && PlayerFitsNeckSlashGeometry(val, NeckSlashRange, requireFacing: false, requireLineOfSight: true))
				{
					Vector3 val2 = ((Component)val).transform.position - ((Component)this).transform.position;
					val2.y = 0f;
					float sqrMagnitude = ((Vector3)(ref val2)).sqrMagnitude;
					if (!(sqrMagnitude >= num))
					{
						num = sqrMagnitude;
						result = val;
					}
				}
			}
			return result;
		}

		private void PromoteClawTargetToChase(PlayerControllerB player)
		{
			if (_encounterState != EncounterState.Hypnosis && (_encounterState != EncounterState.Chase || _encounterTargetClientId != player.actualClientId))
			{
				TryBeginChase(player, "clawed a player in reach");
			}
		}

		private void RoamServer()
		{
			if (!((NetworkBehaviour)this).IsServer || _isNeckSlashing || !EncounterStateAllowsRoaming())
			{
				return;
			}
			base.targetPlayer = null;
			base.movingTowardsTargetPlayer = false;
			if (!EnsureAgentOnNavMesh())
			{
				LogMovementDiagnostic("roam skipped: agent is not on NavMesh");
				return;
			}
			base.agent.updateRotation = AgentDrivesBodyRotation();
			base.agent.isStopped = false;
			EnsureRoamingSearch();
			if (!StaticVisualTestMode && base.currentBehaviourStateIndex != 1)
			{
				((EnemyAI)this).SwitchToBehaviourState(1);
			}
		}

		private void ConfigureSearchDefaults()
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Expected O, but got Unknown
			if (facilitySearch == null)
			{
				facilitySearch = new AISearchRoutine();
			}
			facilitySearch.loopSearch = true;
			facilitySearch.randomized = false;
			facilitySearch.onlySearchNodesInLOS = false;
			bool flag = _serverInvestigating && _serverInvestigateLingering && _encounterState == EncounterState.Search;
			facilitySearch.searchWidth = (flag ? (RoamSearchWidth * 0.5f) : RoamSearchWidth);
			facilitySearch.searchPrecision = 1.5f;
		}

		private void EnsureRoamingSearch()
		{
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			if (((NetworkBehaviour)this).IsServer && !base.isEnemyDead && !_isNeckSlashing && EncounterStateAllowsRoaming() && !((Object)(object)base.agent == (Object)null) && ((Behaviour)base.agent).enabled && base.agent.isOnNavMesh)
			{
				ConfigureSearchDefaults();
				if (facilitySearch == null || base.currentSearch != facilitySearch || !facilitySearch.inProgress)
				{
					StartRoamingSearch(((Component)this).transform.position);
				}
			}
		}

		private void StartRoamingSearch(Vector3 start)
		{
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			if (((NetworkBehaviour)this).IsServer && !base.isEnemyDead && !((Object)(object)base.agent == (Object)null) && ((Behaviour)base.agent).enabled && base.agent.isOnNavMesh)
			{
				ConfigureSearchDefaults();
				StopSearchIfNeeded(clear: false);
				((EnemyAI)this).StartSearch(start, facilitySearch);
			}
		}

		private void StartLingerSearch()
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			StartRoamingSearch(_serverInvestigatePoint);
			NarrowSearchToLingerArea();
		}

		private void NarrowSearchToLingerArea()
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: 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_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			List<GameObject> list = facilitySearch?.unsearchedNodes;
			if (list == null || list.Count <= 4)
			{
				return;
			}
			Vector3 anchor = _serverInvestigatePoint;
			list.Sort(delegate(GameObject a, GameObject b)
			{
				//IL_000f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0015: 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)
				//IL_001f: Unknown result type (might be due to invalid IL or missing references)
				//IL_003e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0044: Unknown result type (might be due to invalid IL or missing references)
				//IL_0049: Unknown result type (might be due to invalid IL or missing references)
				//IL_004e: Unknown result type (might be due to invalid IL or missing references)
				Vector3 val3;
				float num3;
				if (!((Object)(object)a == (Object)null))
				{
					val3 = a.transform.position - anchor;
					num3 = ((Vector3)(ref val3)).sqrMagnitude;
				}
				else
				{
					num3 = float.MaxValue;
				}
				float num4 = num3;
				float num5;
				if (!((Object)(object)b == (Object)null))
				{
					val3 = b.transform.position - anchor;
					num5 = ((Vector3)(ref val3)).sqrMagnitude;
				}
				else
				{
					num5 = float.MaxValue;
				}
				floa

Y4NGZDreadweaver.dll

Decompiled a week ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using Dawn;
using GameNetcodeStuff;
using Microsoft.CodeAnalysis;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.Audio;
using UnityEngine.Rendering;
using UnityEngine.SceneManagement;
using Y4NGZDreadweaver.AI;
using Y4NGZDreadweaver.NetcodePatcher;
using Y4NGZMonsters.Shared;

[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("Y4NGZDreadweaver")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+c64a155fd64c47528940e53659e5b5ada665b9d4")]
[assembly: AssemblyProduct("Y4NGZDreadweaver")]
[assembly: AssemblyTitle("Y4NGZDreadweaver")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
[module: NetcodePatchedAssembly]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.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 Y4NGZDreadweaver
{
	internal sealed class DreadweaverConfig
	{
		public ConfigEntry<bool> Enabled { get; }

		public ConfigEntry<float> SpawnWeightMultiplier { get; }

		public ConfigEntry<string> MoonWeightOverrides { get; }

		public ConfigEntry<int> MaxCount { get; }

		public ConfigEntry<float> PowerLevel { get; }

		public ConfigEntry<int> Health { get; }

		public ConfigEntry<float> SightingIntervalMinSeconds { get; }

		public ConfigEntry<float> SightingIntervalMaxSeconds { get; }

		public ConfigEntry<float> AttackDelayMinSeconds { get; }

		public ConfigEntry<float> AttackDelayMaxSeconds { get; }

		public ConfigEntry<float> StalkMoveSpeed { get; }

		public ConfigEntry<float> CrawlSpeed { get; }

		public ConfigEntry<float> AttackSpeed { get; }

		public ConfigEntry<int> AttackDamage { get; }

		public ConfigEntry<float> AttackCooldown { get; }

		public ConfigEntry<bool> CreatureSpotlightEnabled { get; }

		public ConfigEntry<bool> FlashlightHarassEnabled { get; }

		public ConfigEntry<bool> DebugLogs { get; }

		public DreadweaverConfig(ConfigFile config)
		{
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Expected O, but got Unknown
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Expected O, but got Unknown
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Expected O, but got Unknown
			//IL_012e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0138: Expected O, but got Unknown
			//IL_0167: Unknown result type (might be due to invalid IL or missing references)
			//IL_0171: Expected O, but got Unknown
			//IL_01a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01aa: Expected O, but got Unknown
			//IL_01d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e3: Expected O, but got Unknown
			//IL_0212: Unknown result type (might be due to invalid IL or missing references)
			//IL_021c: Expected O, but got Unknown
			//IL_024b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0255: Expected O, but got Unknown
			//IL_0284: Unknown result type (might be due to invalid IL or missing references)
			//IL_028e: Expected O, but got Unknown
			//IL_02bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c7: Expected O, but got Unknown
			//IL_02ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f6: Expected O, but got Unknown
			//IL_0325: Unknown result type (might be due to invalid IL or missing references)
			//IL_032f: Expected O, but got Unknown
			using (ConfigPersistence.BeginBinding(config, Plugin.Log, "Dreadweaver"))
			{
				DreadweaverConfigMigration.TryMigrate(config, Plugin.Log);
				ConfigSectionNameMigration.TryMigrate(config, Plugin.Log, "Dreadweaver");
				Enabled = config.Bind<bool>("General", "Enabled", true, "Enable the Dreadweaver encounter. Host-only: the host's value decides whether it spawns; every install still registers the creature so clients stay in sync.");
				SpawnWeightMultiplier = config.Bind<float>("Spawning", "SpawnWeightMultiplier", 1f, new ConfigDescription("Multiplier applied to Dreadweaver's contextual moon/interior spawn policy. 0 disables natural spawns.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 5f), Array.Empty<object>()));
				MoonWeightOverrides = config.Bind<string>("Spawning", "MoonWeightOverrides", string.Empty, "Optional comma-separated base moon weights, e.g. Experimentation:8,Offense:15 or namespace:moon=12. Use 0 to disable a moon; unlisted moons keep authored defaults.");
				MaxCount = config.Bind<int>("Spawning", "MaxCount", 1, new ConfigDescription("Maximum number of living Dreadweavers at once.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 4), Array.Empty<object>()));
				PowerLevel = config.Bind<float>("Spawning", "PowerLevel", 2.8f, new ConfigDescription("Indoor enemy power budget cost for each Dreadweaver.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 20f), Array.Empty<object>()));
				Health = config.Bind<int>("Core Stats", "Health", 5, new ConfigDescription("Hits the Dreadweaver can take before dying.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 100), Array.Empty<object>()));
				SightingIntervalMinSeconds = config.Bind<float>("Encounter Pacing", "SightingIntervalMinSeconds", 45f, new ConfigDescription("Minimum hidden time between completed sightings.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(8f, 120f), Array.Empty<object>()));
				SightingIntervalMaxSeconds = config.Bind<float>("Encounter Pacing", "SightingIntervalMaxSeconds", 65f, new ConfigDescription("Maximum hidden time between completed sightings; values below the minimum are raised at runtime.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(8f, 150f), Array.Empty<object>()));
				AttackDelayMinSeconds = config.Bind<float>("Encounter Pacing", "AttackDelayMinSeconds", 15f, new ConfigDescription("Minimum hidden time between the final sighting and attack reveal.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(5f, 60f), Array.Empty<object>()));
				AttackDelayMaxSeconds = config.Bind<float>("Encounter Pacing", "AttackDelayMaxSeconds", 30f, new ConfigDescription("Maximum hidden time before attack reveal; values below the minimum are raised at runtime.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(5f, 90f), Array.Empty<object>()));
				StalkMoveSpeed = config.Bind<float>("Movement", "StalkMoveSpeed", 1.5f, new ConfigDescription("Movement speed outside committed attacks.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 4f), Array.Empty<object>()));
				CrawlSpeed = config.Bind<float>("Movement", "CrawlSpeed", 2.1f, new ConfigDescription("Movement speed during a crawl attack reveal.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.8f, 4f), Array.Empty<object>()));
				AttackSpeed = config.Bind<float>("Movement", "AttackSpeed", 5.15f, new ConfigDescription("Movement speed during committed pursuit.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(2f, 9f), Array.Empty<object>()));
				AttackDamage = config.Bind<int>("Combat", "AttackDamage", 40, new ConfigDescription("Damage dealt by a successful strike.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 100), Array.Empty<object>()));
				AttackCooldown = config.Bind<float>("Combat", "AttackCooldown", 1.8f, new ConfigDescription("Additional cooldown after the full attack animation, before another swing can begin.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 6f), Array.Empty<object>()));
				CreatureSpotlightEnabled = config.Bind<bool>("Presentation", "CreatureSpotlightEnabled", true, "Light the visible Dreadweaver so the encounter remains readable in dark interiors.");
				FlashlightHarassEnabled = config.Bind<bool>("Presentation", "FlashlightHarassEnabled", true, "Briefly glitch the stalked player's flashlight or helmet lamp when it cloaks nearby.");
				DebugLogs = config.Bind<bool>("Diagnostics", "DebugLogs", false, "Log detailed Dreadweaver targeting and setup diagnostics.");
			}
		}
	}
	internal static class DreadweaverConfigMigration
	{
		private static readonly ConfigDefinition LegacySpawnWeight = new ConfigDefinition("Spawning", "SpawnWeight");

		private static readonly LegacyMigrationSpec Spec = new LegacyMigrationSpec("Dreadweaver", (IReadOnlyList<ConfigDefinition>)(object)new ConfigDefinition[11]
		{
			LegacySpawnWeight,
			new ConfigDefinition("Stats", "Health"),
			new ConfigDefinition("Sightings", "SightingIntervalMinSeconds"),
			new ConfigDefinition("Sightings", "SightingIntervalMaxSeconds"),
			new ConfigDefinition("Attack", "AttackDelayMinSeconds"),
			new ConfigDefinition("Attack", "AttackDelayMaxSeconds"),
			new ConfigDefinition("Attack", "AttackDamage"),
			new ConfigDefinition("Attack", "AttackCooldown"),
			new ConfigDefinition("Visuals", "CreatureSpotlightEnabled"),
			new ConfigDefinition("Visuals", "FlashlightHarassEnabled"),
			new ConfigDefinition("Debug", "DebugLogs")
		}, null, new Dictionary<ConfigDefinition, string>
		{
			{
				new ConfigDefinition("Spawning", "LevelMask"),
				"-1"
			},
			{
				new ConfigDefinition("Stats", "ModelScale"),
				"1.75"
			},
			{
				new ConfigDefinition("Movement", "TurnSpeed"),
				"420"
			},
			{
				new ConfigDefinition("Movement", "Acceleration"),
				"18"
			},
			{
				new ConfigDefinition("Sightings", "LongSightingMinDistance"),
				"30"
			},
			{
				new ConfigDefinition("Sightings", "LongSightingMaxDistance"),
				"50"
			},
			{
				new ConfigDefinition("Sightings", "LongSightingHoldSeconds"),
				"1.35"
			},
			{
				new ConfigDefinition("Sightings", "MediumSightingMinDistance"),
				"15"
			},
			{
				new ConfigDefinition("Sightings", "MediumSightingMaxDistance"),
				"30"
			},
			{
				new ConfigDefinition("Sightings", "MediumSightingHoldSeconds"),
				"1.15"
			},
			{
				new ConfigDefinition("Sightings", "ShortSightingMinDistance"),
				"4"
			},
			{
				new ConfigDefinition("Sightings", "ShortSightingMaxDistance"),
				"8"
			},
			{
				new ConfigDefinition("Sightings", "ShortSightingHoldSeconds"),
				"1"
			},
			{
				new ConfigDefinition("Sightings", "SightingRetryMinSeconds"),
				"15"
			},
			{
				new ConfigDefinition("Sightings", "SightingRetryMaxSeconds"),
				"30"
			},
			{
				new ConfigDefinition("Sightings", "SightingTimeoutSeconds"),
				"12"
			},
			{
				new ConfigDefinition("Sightings", "PlayerSpotAngle"),
				"25"
			},
			{
				new ConfigDefinition("Sightings", "CreatureSightRange"),
				"60"
			},
			{
				new ConfigDefinition("Stalking ambience", "LightFlickerRadius"),
				"18"
			},
			{
				new ConfigDefinition("Stalking ambience", "LightFlickerIntervalMinSeconds"),
				"40"
			},
			{
				new ConfigDefinition("Stalking ambience", "LightFlickerIntervalMaxSeconds"),
				"70"
			},
			{
				new ConfigDefinition("Stalking ambience", "DoorSlamRadius"),
				"14"
			},
			{
				new ConfigDefinition("Stalking ambience", "DoorSlamIntervalMinSeconds"),
				"35"
			},
			{
				new ConfigDefinition("Stalking ambience", "DoorSlamIntervalMaxSeconds"),
				"70"
			},
			{
				new ConfigDefinition("Attack", "AttackRevealMinDistance"),
				"8"
			},
			{
				new ConfigDefinition("Attack", "AttackRevealMaxDistance"),
				"16"
			},
			{
				new ConfigDefinition("Attack", "CrawlAdvanceSeconds"),
				"3"
			},
			{
				new ConfigDefinition("Attack", "AttackRange"),
				"2.35"
			},
			{
				new ConfigDefinition("Attack", "AttackDamageDelay"),
				"0.48"
			},
			{
				new ConfigDefinition("Attack", "AttackHitArcDegrees"),
				"120"
			},
			{
				new ConfigDefinition("Attack", "AttackLoseDistance"),
				"48"
			},
			{
				new ConfigDefinition("Attack", "AttackLostSightGraceSeconds"),
				"12"
			},
			{
				new ConfigDefinition("Attack", "PursuitRepositionCooldownMinSeconds"),
				"2"
			},
			{
				new ConfigDefinition("Attack", "PursuitRepositionCooldownMaxSeconds"),
				"5"
			},
			{
				new ConfigDefinition("Attack", "PursuitRepositionMinDistance"),
				"10"
			},
			{
				new ConfigDefinition("Attack", "ChainAttackRadius"),
				"13"
			},
			{
				new ConfigDefinition("Camo", "VanishFlickerSeconds"),
				"0.65"
			},
			{
				new ConfigDefinition("Camo", "DecloakFlickerSeconds"),
				"0.55"
			},
			{
				new ConfigDefinition("Animation", "MatchAnimationToMovement"),
				"true"
			},
			{
				new ConfigDefinition("Animation", "AuthoredWalkSpeed"),
				"1.9"
			},
			{
				new ConfigDefinition("Animation", "AuthoredCrawlSpeed"),
				"1.9"
			},
			{
				new ConfigDefinition("Animation", "AuthoredRunSpeed"),
				"3.6"
			},
			{
				new ConfigDefinition("Visuals", "CreatureSpotlightIntensity"),
				"18"
			},
			{
				new ConfigDefinition("Visuals", "CreatureSpotlightRange"),
				"14"
			},
			{
				new ConfigDefinition("Visuals", "CreatureSpotlightAngle"),
				"42"
			},
			{
				new ConfigDefinition("Visuals", "CreatureSpotlightHeight"),
				"5"
			},
			{
				new ConfigDefinition("Visuals", "DramaticSpotlightChance"),
				"0.35"
			}
		}, Build);

		internal static bool TryMigrate(ConfigFile config, ManualLogSource log)
		{
			return LegacyConfigMigrator.TryMigrate(config, log, Spec);
		}

		private static void Build(LegacyConfigValues values, MigratedConfigWriter output)
		{
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Expected O, but got Unknown
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Expected O, but got Unknown
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Expected O, but got Unknown
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Expected O, but got Unknown
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Expected O, but got Unknown
			//IL_0188: Unknown result type (might be due to invalid IL or missing references)
			//IL_018e: Expected O, but got Unknown
			//IL_01b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b6: Expected O, but got Unknown
			//IL_01d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01de: Expected O, but got Unknown
			//IL_0200: Unknown result type (might be due to invalid IL or missing references)
			//IL_0206: Expected O, but got Unknown
			//IL_0228: Unknown result type (might be due to invalid IL or missing references)
			//IL_022e: Expected O, but got Unknown
			output.Carry("General", "Enabled");
			output.CarrySpawnWeightMultiplier(LegacySpawnWeight, 12f);
			output.Carry("Spawning", "MoonWeightOverrides");
			output.Carry("Spawning", "MaxCount");
			output.Carry("Spawning", "PowerLevel");
			output.Carry("Core Stats", "Health", new ConfigDefinition("Stats", "Health"));
			output.Carry("Encounter Pacing", "SightingIntervalMinSeconds", new ConfigDefinition("Sightings", "SightingIntervalMinSeconds"));
			output.Carry("Encounter Pacing", "SightingIntervalMaxSeconds", new ConfigDefinition("Sightings", "SightingIntervalMaxSeconds"));
			output.Carry("Encounter Pacing", "AttackDelayMinSeconds", new ConfigDefinition("Attack", "AttackDelayMinSeconds"));
			output.Carry("Encounter Pacing", "AttackDelayMaxSeconds", new ConfigDefinition("Attack", "AttackDelayMaxSeconds"));
			output.Carry("Movement", "StalkMoveSpeed");
			output.Carry("Movement", "CrawlSpeed");
			output.Carry("Movement", "AttackSpeed");
			output.Carry("Combat", "AttackDamage", new ConfigDefinition("Attack", "AttackDamage"));
			output.Carry("Combat", "AttackCooldown", new ConfigDefinition("Attack", "AttackCooldown"));
			output.Carry("Presentation", "CreatureSpotlightEnabled", new ConfigDefinition("Visuals", "CreatureSpotlightEnabled"));
			output.Carry("Presentation", "FlashlightHarassEnabled", new ConfigDefinition("Visuals", "FlashlightHarassEnabled"));
			output.Carry("Diagnostics", "DebugLogs", new ConfigDefinition("Debug", "DebugLogs"));
		}
	}
	internal static class DreadweaverGameplayPolicy
	{
		internal const float MinimumVisibleWarning = 1.5f;

		internal const float NavigationRadius = 0.35f;

		internal const float NavigationHeight = 1.9f;

		internal static float NextSwingTime(float startedAt, float clipSeconds, float cooldownSeconds)
		{
			return startedAt + Math.Max(0f, clipSeconds) + Math.Max(0f, cooldownSeconds);
		}

		internal static float EarliestRevealDamage(float revealedAt, float dissolveSeconds)
		{
			return revealedAt + Math.Max(0f, dissolveSeconds) + 1.5f;
		}

		internal static float LocalDimension(float worldDimension, float axisScale)
		{
			return worldDimension / Math.Max(0.01f, Math.Abs(axisScale));
		}
	}
	internal sealed class DreadweaverSpawnWeights : ContextualSpawnWeights
	{
		internal DreadweaverSpawnWeights(Func<float> multiplier, Func<string> moonOverrides, Action<string> logWarning)
			: base(SpawnWeightTable.Dreadweaver, "Dreadweaver", multiplier, moonOverrides, logWarning)
		{
		}
	}
	internal static class DreadweaverTuning
	{
		internal const float ModelScale = 1.75f;

		internal const float TurnSpeed = 420f;

		internal const float Acceleration = 18f;

		internal const float AgentRadius = 0.35f;

		internal const float AgentHeight = 1.9f;

		internal const float LongSightingMinDistance = 30f;

		internal const float LongSightingMaxDistance = 50f;

		internal const float LongSightingHoldSeconds = 1.35f;

		internal const float MediumSightingMinDistance = 15f;

		internal const float MediumSightingMaxDistance = 30f;

		internal const float MediumSightingHoldSeconds = 1.15f;

		internal const float ShortSightingMinDistance = 4f;

		internal const float ShortSightingMaxDistance = 8f;

		internal const float ShortSightingHoldSeconds = 1f;

		internal const float SightingRetryMinSeconds = 15f;

		internal const float SightingRetryMaxSeconds = 30f;

		internal const float PlayerSpotAngle = 25f;

		internal const float CreatureSightRange = 60f;

		internal const float StalkLightFlickerRadius = 18f;

		internal const float StalkLightFlickerIntervalMinSeconds = 40f;

		internal const float StalkLightFlickerIntervalMaxSeconds = 70f;

		internal const float StalkDoorSlamRadius = 14f;

		internal const float StalkDoorSlamIntervalMinSeconds = 35f;

		internal const float StalkDoorSlamIntervalMaxSeconds = 70f;

		internal const float AttackRevealMinDistance = 8f;

		internal const float AttackRevealMaxDistance = 16f;

		internal const float CrawlAdvanceSeconds = 3f;

		internal const float AttackRange = 2.35f;

		internal const float AttackDamageDelay = 0.48f;

		internal const float AttackHitArcDegrees = 120f;

		internal const float AttackLoseDistance = 48f;

		internal const float AttackLostSightGraceSeconds = 12f;

		internal const float PursuitRepositionCooldownMinSeconds = 2f;

		internal const float PursuitRepositionCooldownMaxSeconds = 5f;

		internal const float PursuitRepositionMinDistance = 10f;

		internal const float ChainAttackRadius = 13f;

		internal const float VanishFlickerSeconds = 0.65f;

		internal const float DecloakFlickerSeconds = 0.55f;

		internal const bool MatchAnimationToMovement = true;

		internal const float AuthoredWalkSpeed = 1.9f;

		internal const float AuthoredCrawlSpeed = 1.9f;

		internal const float AuthoredRunSpeed = 3.6f;

		internal const float CreatureSpotlightIntensity = 18f;

		internal const float CreatureSpotlightRange = 14f;

		internal const float CreatureSpotlightAngle = 42f;

		internal const float CreatureSpotlightHeight = 5f;
	}
	[BepInPlugin("y4ngz.lethalcompany.dreadweaver", "Y4NGZ Dreadweaver", "1.2.1")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public sealed class Plugin : BaseUnityPlugin
	{
		internal const string BundleFilename = "dreadweaver.bundle";

		internal const string PrefabName = "SK_Dreadweaver";

		internal const string AlternatePrefabName = "Dreadweaver";

		internal const string DawnNamespace = "y4ngz_monsters";

		internal const string DawnEnemyKey = "dreadweaver";

		internal const string ScanNodeSubtitle = "";

		internal const string BestiaryText = "Dreadweaver\n\nDanger level: high\n\nA facility stalker that fixates on a single worker. It stages a sequence of sightings, each closer than the last, vanishing the moment it is approached or watched too long. A third, very close sighting means the hunt is nearly over.\n\n";

		internal static ManualLogSource Log;

		internal static DreadweaverConfig ModConfig;

		internal static AssetBundle ModAssets;

		internal static EnemyType DreadweaverEnemyType;

		private static bool _netcodeInitialized;

		private static bool _loggedScanNodeLayer;

		private void Awake()
		{
			Log = ((BaseUnityPlugin)this).Logger;
			try
			{
				InitializeNetcodeRPCs();
				ModConfig = new DreadweaverConfig(((BaseUnityPlugin)this).Config);
				if (!LoadBundle())
				{
					return;
				}
				GameObject val = LoadBundlePrefab();
				if ((Object)(object)val == (Object)null)
				{
					Log.LogError((object)"Prefab 'SK_Dreadweaver' not found in dreadweaver.bundle.");
					DumpBundleAssets();
					return;
				}
				PreparePrefab(val);
				DreadweaverEnemyType = CreateEnemyType(val);
				DreadweaverAI component = val.GetComponent<DreadweaverAI>();
				if ((Object)(object)component != (Object)null)
				{
					((EnemyAI)component).enemyType = DreadweaverEnemyType;
				}
				RegisterWithDawn(val);
				if (!ModConfig.Enabled.Value)
				{
					Log.LogInfo((object)"Y4NGZ Dreadweaver: registered network prefab; spawning disabled by config.");
				}
				Log.LogInfo((object)"Y4NGZ Dreadweaver v1.2.1 loaded. Registered as 'dreadweaver'.");
			}
			catch (Exception arg)
			{
				Log.LogError((object)string.Format("[{0}] Initialization failed: {1}", "Y4NGZ Dreadweaver", arg));
			}
		}

		private static void RegisterWithDawn(GameObject prefab)
		{
			DreadweaverSpawnWeights spawnWeights = new DreadweaverSpawnWeights(() => (!ModConfig.Enabled.Value) ? 0f : ModConfig.SpawnWeightMultiplier.Value, () => ModConfig.MoonWeightOverrides.Value, delegate(string message)
			{
				Log.LogWarning((object)message);
			});
			DawnLib.RegisterNetworkPrefab(prefab);
			DawnLib.DefineEnemy(NamespacedKey<DawnEnemyInfo>.From("y4ngz_monsters", "dreadweaver"), DreadweaverEnemyType, (Action<EnemyInfoBuilder>)delegate(EnemyInfoBuilder builder)
			{
				((BaseInfoBuilder<DawnEnemyInfo, EnemyType, EnemyInfoBuilder>)(object)builder.DefineInside((Action<EnemyLocationBuilder>)delegate(EnemyLocationBuilder location)
				{
					location.SetWeights((Action<WeightTableBuilder<DawnMoonInfo, SpawnWeightContext>>)delegate(WeightTableBuilder<DawnMoonInfo, SpawnWeightContext> table)
					{
						table.SetGlobalWeight((IWeighted)(object)spawnWeights);
					});
				}).CreateBestiaryNode("Dreadweaver\n\nDanger level: high\n\nA facility stalker that fixates on a single worker. It stages a sequence of sightings, each closer than the last, vanishing the moment it is approached or watched too long. A third, very close sighting means the hunt is nearly over.\n\n").CreateNameKeyword("dreadweaver")).AddTags((IEnumerable<NamespacedKey>)(object)new NamespacedKey[5]
				{
					Tags.Hostile,
					Tags.Organic,
					Tags.Killable,
					Tags.Biped,
					Tags.Medium
				});
			});
		}

		private static void InitializeNetcodeRPCs()
		{
			if (_netcodeInitialized)
			{
				return;
			}
			_netcodeInitialized = true;
			Type[] types;
			try
			{
				types = Assembly.GetExecutingAssembly().GetTypes();
			}
			catch (ReflectionTypeLoadException ex)
			{
				ManualLogSource log = Log;
				if (log != null)
				{
					log.LogWarning((object)("[NetcodeInit] Some types failed to load; initializing the rest: " + ex.Message));
				}
				types = ex.Types;
			}
			Type[] array = types;
			foreach (Type type in array)
			{
				if (type == null)
				{
					continue;
				}
				MethodInfo[] methods;
				try
				{
					methods = type.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				}
				catch (Exception ex2)
				{
					ManualLogSource log2 = Log;
					if (log2 != null)
					{
						log2.LogWarning((object)("[NetcodeInit] " + type.FullName + ": method scan failed: " + ex2.Message));
					}
					continue;
				}
				foreach (MethodInfo methodInfo in methods)
				{
					if (methodInfo.GetCustomAttributes(typeof(RuntimeInitializeOnLoadMethodAttribute), inherit: false).Length == 0)
					{
						continue;
					}
					try
					{
						methodInfo.Invoke(null, null);
					}
					catch (Exception ex3)
					{
						ManualLogSource log3 = Log;
						if (log3 != null)
						{
							log3.LogWarning((object)("[NetcodeInit] " + type.Name + "." + methodInfo.Name + " failed: " + ex3.Message));
						}
					}
				}
			}
		}

		private static bool LoadBundle()
		{
			string directoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
			if (string.IsNullOrEmpty(directoryName))
			{
				Log.LogError((object)"Could not resolve plugin assembly directory.");
				return false;
			}
			string text = Path.Combine(directoryName, "dreadweaver.bundle");
			if (!File.Exists(text))
			{
				Log.LogError((object)("Missing asset bundle: " + text));
				return false;
			}
			ModAssets = AssetBundle.LoadFromFile(text);
			if ((Object)(object)ModAssets == (Object)null)
			{
				Log.LogError((object)("AssetBundle.LoadFromFile returned null for " + text + "."));
				return false;
			}
			return true;
		}

		private static GameObject LoadBundlePrefab()
		{
			GameObject val = ModAssets.LoadAsset<GameObject>("SK_Dreadweaver") ?? ModAssets.LoadAsset<GameObject>("Dreadweaver");
			if ((Object)(object)val != (Object)null)
			{
				return val;
			}
			string[] allAssetNames = ModAssets.GetAllAssetNames();
			foreach (string text in allAssetNames)
			{
				string text2 = text.Replace('\\', '/');
				string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(text2);
				if (text2.EndsWith("/sk_dreadweaver.prefab", StringComparison.OrdinalIgnoreCase) || text2.EndsWith("/dreadweaver.prefab", StringComparison.OrdinalIgnoreCase) || string.Equals(fileNameWithoutExtension, "SK_Dreadweaver", StringComparison.OrdinalIgnoreCase) || string.Equals(fileNameWithoutExtension, "Dreadweaver", StringComparison.OrdinalIgnoreCase))
				{
					val = ModAssets.LoadAsset<GameObject>(text);
					if ((Object)(object)val != (Object)null)
					{
						return val;
					}
				}
			}
			return null;
		}

		private static void PreparePrefab(GameObject prefab)
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_0153: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: Unknown result type (might be due to invalid IL or missing references)
			AssignUniqueNetworkHash(prefab);
			prefab.SetActive(true);
			TrySetTag(prefab, "Enemy");
			TrySetLayer(prefab, "Enemies");
			prefab.transform.localScale = Vector3.one * 1.75f;
			DreadweaverAI dreadweaverAI = prefab.GetComponent<DreadweaverAI>();
			if ((Object)(object)dreadweaverAI == (Object)null)
			{
				dreadweaverAI = prefab.AddComponent<DreadweaverAI>();
			}
			if ((Object)(object)prefab.GetComponent<NetworkObject>() == (Object)null)
			{
				prefab.AddComponent<NetworkObject>();
			}
			Animator val = prefab.GetComponent<Animator>() ?? prefab.GetComponentInChildren<Animator>(true);
			if ((Object)(object)val != (Object)null)
			{
				val.applyRootMotion = false;
				val.cullingMode = (AnimatorCullingMode)0;
				dreadweaverAI.visualAnimator = val;
			}
			else
			{
				Log.LogWarning((object)"[Dreadweaver] Prefab has no Animator.");
			}
			NavMeshAgent val2 = prefab.GetComponent<NavMeshAgent>();
			if ((Object)(object)val2 == (Object)null)
			{
				val2 = prefab.AddComponent<NavMeshAgent>();
			}
			ConfigureAgent(val2);
			((EnemyAI)dreadweaverAI).agent = val2;
			((EnemyAI)dreadweaverAI).creatureSFX = FindOrCreateAudioSource(prefab.transform, "CreatureSFX", 42f);
			((EnemyAI)dreadweaverAI).creatureVoice = FindOrCreateAudioSource(prefab.transform, "CreatureVoice", 46f);
			((EnemyAI)dreadweaverAI).eye = FindOrCreateChild(prefab.transform, "EyeTransform", new Vector3(0f, 1.65f, 0.25f) / 1.75f);
			dreadweaverAI.attackOrigin = FindOrCreateChild(prefab.transform, "AttackOrigin", new Vector3(0f, 1.2f, 0.35f) / 1.75f);
			AssignDreadweaverAudio(dreadweaverAI);
			EnsureDreadweaverRendering(prefab, (EnemyAI)(object)dreadweaverAI);
			EnsureBehaviourStates(dreadweaverAI);
			EnsureScanNode(prefab);
			EnsureCollision(prefab, dreadweaverAI);
		}

		private static void ConfigureAgent(NavMeshAgent agent)
		{
			agent.speed = ModConfig.StalkMoveSpeed.Value;
			agent.angularSpeed = 420f;
			agent.acceleration = 18f;
			agent.stoppingDistance = Mathf.Max(0.5f, 1.5274999f);
			agent.radius = 0.35f;
			agent.height = 1.9f;
			agent.baseOffset = 0f;
			agent.autoBraking = true;
			agent.autoRepath = true;
			agent.updateRotation = false;
			agent.areaMask = -1;
			agent.obstacleAvoidanceType = (ObstacleAvoidanceType)4;
			agent.avoidancePriority = 31;
		}

		private static void EnsureDreadweaverRendering(GameObject prefab, EnemyAI ai)
		{
			//IL_0020: 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_003e: 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)
			SkinnedMeshRenderer[] componentsInChildren = prefab.GetComponentsInChildren<SkinnedMeshRenderer>(true);
			MeshRenderer[] componentsInChildren2 = prefab.GetComponentsInChildren<MeshRenderer>(true);
			ai.skinnedMeshRenderers = componentsInChildren;
			ai.meshRenderers = componentsInChildren2;
			Bounds localBounds = default(Bounds);
			((Bounds)(ref localBounds))..ctor(Vector3.up * 1.25f, new Vector3(7.5f, 5.5f, 7.5f));
			foreach (SkinnedMeshRenderer val in componentsInChildren)
			{
				if (!((Object)(object)val == (Object)null) && !IsRuntimeHelperRenderer((Renderer)(object)val))
				{
					ActivateRendererHierarchy(prefab.transform, ((Component)val).transform);
					((Component)val).gameObject.SetActive(true);
					((Renderer)val).enabled = true;
					((Renderer)val).forceRenderingOff = false;
					val.updateWhenOffscreen = true;
					((Renderer)val).localBounds = localBounds;
					((Renderer)val).shadowCastingMode = (ShadowCastingMode)1;
					((Renderer)val).receiveShadows = true;
					EnsureRendererHasOpaqueMaterial((Renderer)(object)val);
				}
			}
			foreach (MeshRenderer val2 in componentsInChildren2)
			{
				if (!((Object)(object)val2 == (Object)null) && !IsRuntimeHelperRenderer((Renderer)(object)val2))
				{
					ActivateRendererHierarchy(prefab.transform, ((Component)val2).transform);
					((Component)val2).gameObject.SetActive(true);
					((Renderer)val2).enabled = true;
					((Renderer)val2).forceRenderingOff = false;
					((Renderer)val2).shadowCastingMode = (ShadowCastingMode)1;
					((Renderer)val2).receiveShadows = true;
					EnsureRendererHasOpaqueMaterial((Renderer)(object)val2);
				}
			}
			ManualLogSource log = Log;
			if (log != null)
			{
				log.LogInfo((object)$"[DreadweaverRenderer] Prepared {componentsInChildren.Length} skinned renderer(s), {componentsInChildren2.Length} mesh renderer(s).");
			}
		}

		private static void ActivateRendererHierarchy(Transform prefabRoot, Transform rendererTransform)
		{
			Transform val = rendererTransform;
			while ((Object)(object)val != (Object)null)
			{
				if (!((Component)val).gameObject.activeSelf)
				{
					((Component)val).gameObject.SetActive(true);
				}
				if (!((Object)(object)val == (Object)(object)prefabRoot))
				{
					val = val.parent;
					continue;
				}
				break;
			}
		}

		private static bool IsRuntimeHelperRenderer(Renderer renderer)
		{
			Transform val = (((Object)(object)renderer != (Object)null) ? ((Component)renderer).transform : null);
			while ((Object)(object)val != (Object)null)
			{
				string text = ((Object)val).name ?? string.Empty;
				if (text.IndexOf("ScanNode", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("Collision", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("MapDot", StringComparison.OrdinalIgnoreCase) >= 0)
				{
					return true;
				}
				val = val.parent;
			}
			return false;
		}

		private static void EnsureRendererHasOpaqueMaterial(Renderer renderer)
		{
			Material[] array = renderer.sharedMaterials;
			if (array == null || array.Length == 0)
			{
				array = (Material[])(object)new Material[1];
			}
			bool flag = false;
			for (int i = 0; i < array.Length; i++)
			{
				Material val = array[i];
				if ((Object)(object)val == (Object)null || (Object)(object)val.shader == (Object)null || ShouldReplaceDreadweaverMaterial(val))
				{
					array[i] = CreateOpaqueDreadweaverMaterial(val);
					flag = true;
				}
				else
				{
					ForceOpaqueMaterial(val);
				}
			}
			if (flag)
			{
				renderer.sharedMaterials = array;
			}
		}

		private static bool ShouldReplaceDreadweaverMaterial(Material material)
		{
			string text = (((Object)(object)material.shader != (Object)null) ? ((Object)material.shader).name : string.Empty);
			if (text.IndexOf("InternalError", StringComparison.OrdinalIgnoreCase) >= 0)
			{
				return true;
			}
			if (text.IndexOf("Standard", StringComparison.OrdinalIgnoreCase) >= 0)
			{
				return true;
			}
			if (material.IsKeywordEnabled("_ALPHATEST_ON") || material.renderQueue == 2450 || material.renderQueue >= 3000)
			{
				return true;
			}
			return false;
		}

		private static Material CreateOpaqueDreadweaverMaterial(Material source)
		{
			//IL_0055: 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_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Expected O, but got Unknown
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Expected O, but got Unknown
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Expected O, but got Unknown
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Expected O, but got Unknown
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: Expected O, but got Unknown
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: Expected O, but got Unknown
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_013d: Expected O, but got Unknown
			//IL_013d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0143: Expected O, but got Unknown
			//IL_0144: Expected O, but got Unknown
			Shader val = Shader.Find("HDRP/Lit") ?? Shader.Find("HDRP/Unlit") ?? Shader.Find("Universal Render Pipeline/Lit") ?? Shader.Find("Standard") ?? Shader.Find("Diffuse");
			Material val2 = (((Object)(object)val != (Object)null) ? new Material(val) : new Material(source));
			((Object)val2).name = "M_DreadweaverRuntimeVisible";
			Texture texture = (((Object)(object)source != (Object)null) ? source.mainTexture : null);
			Texture texture2 = (((Object)(object)source != (Object)null && source.HasProperty("_BumpMap")) ? source.GetTexture("_BumpMap") : null);
			Texture texture3 = (((Object)(object)source != (Object)null && source.HasProperty("_MetallicGlossMap")) ? source.GetTexture("_MetallicGlossMap") : null);
			Texture texture4 = (((Object)(object)source != (Object)null && source.HasProperty("_OcclusionMap")) ? source.GetTexture("_OcclusionMap") : null);
			SetMaterialTexture(val2, "_BaseColorMap", texture);
			SetMaterialTexture(val2, "_MainTex", texture);
			SetMaterialTexture(val2, "_NormalMap", texture2);
			SetMaterialTexture(val2, "_BumpMap", texture2);
			SetMaterialTexture(val2, "_MaskMap", texture3);
			SetMaterialTexture(val2, "_MetallicGlossMap", texture3);
			SetMaterialTexture(val2, "_OcclusionMap", texture4);
			ForceOpaqueMaterial(val2);
			return val2;
		}

		private static void ForceOpaqueMaterial(Material material)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)material == (Object)null))
			{
				SetMaterialColor(material, "_BaseColor", Color.white);
				SetMaterialColor(material, "_Color", Color.white);
				SetMaterialFloat(material, "_SurfaceType", 0f);
				SetMaterialFloat(material, "_BlendMode", 0f);
				SetMaterialFloat(material, "_AlphaCutoffEnable", 0f);
				SetMaterialFloat(material, "_AlphaClip", 0f);
				SetMaterialFloat(material, "_Cutoff", 0f);
				SetMaterialFloat(material, "_ZWrite", 1f);
				SetMaterialFloat(material, "_SrcBlend", 1f);
				SetMaterialFloat(material, "_DstBlend", 0f);
				SetMaterialFloat(material, "_AlphaSrcBlend", 1f);
				SetMaterialFloat(material, "_AlphaDstBlend", 0f);
				SetMaterialFloat(material, "_Mode", 0f);
				SetMaterialFloat(material, "_DoubleSidedEnable", 1f);
				SetMaterialFloat(material, "_CullMode", 0f);
				SetMaterialFloat(material, "_Cull", 0f);
				material.SetOverrideTag("RenderType", "Opaque");
				material.renderQueue = -1;
				material.DisableKeyword("_ALPHATEST_ON");
				material.DisableKeyword("_ALPHATESTENABLE_ON");
				material.DisableKeyword("_SURFACE_TYPE_TRANSPARENT");
				material.DisableKeyword("_ALPHABLEND_ON");
			}
		}

		private static void SetMaterialTexture(Material material, string propertyName, Texture texture)
		{
			if ((Object)(object)material != (Object)null && (Object)(object)texture != (Object)null && material.HasProperty(propertyName))
			{
				material.SetTexture(propertyName, texture);
			}
		}

		private static void SetMaterialColor(Material material, string propertyName, Color color)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)material != (Object)null && material.HasProperty(propertyName))
			{
				material.SetColor(propertyName, color);
			}
		}

		private static void SetMaterialFloat(Material material, string propertyName, float value)
		{
			if ((Object)(object)material != (Object)null && material.HasProperty(propertyName))
			{
				material.SetFloat(propertyName, value);
			}
		}

		private static void EnsureBehaviourStates(DreadweaverAI ai)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			//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_002e: Expected O, but got Unknown
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Expected O, but got Unknown
			//IL_0043: 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_0054: Expected O, but got Unknown
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Expected O, but got Unknown
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Expected O, but got Unknown
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Expected O, but got Unknown
			//IL_008f: 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_00a0: Expected O, but got Unknown
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Expected O, but got Unknown
			//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_00c7: Expected O, but got Unknown
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Expected O, but got Unknown
			((EnemyAI)ai).enemyBehaviourStates = (EnemyBehaviourState[])(object)new EnemyBehaviourState[11]
			{
				new EnemyBehaviourState
				{
					name = "HiddenAcquireTarget"
				},
				new EnemyBehaviourState
				{
					name = "HiddenFindWatch"
				},
				new EnemyBehaviourState
				{
					name = "SightingVisible"
				},
				new EnemyBehaviourState
				{
					name = "HiddenBetweenSightings"
				},
				new EnemyBehaviourState
				{
					name = "HiddenPreAttackDelay"
				},
				new EnemyBehaviourState
				{
					name = "AttackSetup"
				},
				new EnemyBehaviourState
				{
					name = "CrawlAdvance"
				},
				new EnemyBehaviourState
				{
					name = "Pursuit"
				},
				new EnemyBehaviourState
				{
					name = "AttackVanishReposition"
				},
				new EnemyBehaviourState
				{
					name = "Hit"
				},
				new EnemyBehaviourState
				{
					name = "Dead"
				}
			};
			((EnemyAI)ai).currentBehaviourStateIndex = 0;
			((EnemyAI)ai).previousBehaviourStateIndex = 0;
			((EnemyAI)ai).currentBehaviourState = ((EnemyAI)ai).enemyBehaviourStates[0];
		}

		internal static void EnsureScanNode(GameObject prefab)
		{
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_021a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0234: Unknown result type (might be due to invalid IL or missing references)
			ScanNodeProperties val = null;
			ScanNodeProperties[] componentsInChildren = prefab.GetComponentsInChildren<ScanNodeProperties>(true);
			foreach (ScanNodeProperties val2 in componentsInChildren)
			{
				bool flag = val2.creatureScanID >= 0;
				bool flag2 = (Object)(object)val != (Object)null && val.creatureScanID >= 0;
				bool flag3 = string.Equals(((Object)((Component)val2).gameObject).name, "ScanNode", StringComparison.Ordinal);
				bool flag4 = (Object)(object)val != (Object)null && string.Equals(((Object)((Component)val).gameObject).name, "ScanNode", StringComparison.Ordinal);
				if ((Object)(object)val == (Object)null || (flag && !flag2) || (flag == flag2 && flag3 && !flag4))
				{
					val = val2;
				}
			}
			if (componentsInChildren.Length > 1)
			{
				ManualLogSource log = Log;
				if (log != null)
				{
					log.LogWarning((object)$"[Dreadweaver] Found {componentsInChildren.Length} scan nodes; retiring every duplicate.");
				}
			}
			for (int j = 0; j < componentsInChildren.Length; j++)
			{
				if ((Object)(object)componentsInChildren[j] != (Object)(object)val)
				{
					RetireExtraScanNode(componentsInChildren[j], val, prefab);
				}
			}
			Transform val3 = (((Object)(object)val != (Object)null) ? ((Component)val).transform : FindOrCreateChild(prefab.transform, "ScanNode", new Vector3(0f, 1.45f, 0f)));
			((Object)((Component)val3).gameObject).name = "ScanNode";
			TrySetTag(((Component)val3).gameObject, "DoNotSet");
			TrySetLayer(((Component)val3).gameObject, "ScanNode");
			EnsureHierarchyActive(val3, prefab.transform);
			((Component)val3).gameObject.SetActive(true);
			if (!_loggedScanNodeLayer)
			{
				_loggedScanNodeLayer = true;
				ManualLogSource log2 = Log;
				if (log2 != null)
				{
					log2.LogInfo((object)($"[Dreadweaver] Scan node layer resolved to {((Component)val3).gameObject.layer} " + string.Format("(NameToLayer(\"ScanNode\")={0}, fallback 22); ", LayerMask.NameToLayer("ScanNode")) + $"active={((Component)val3).gameObject.activeInHierarchy}."));
				}
			}
			BoxCollider val4 = ((Component)val3).GetComponent<BoxCollider>();
			if ((Object)(object)val4 == (Object)null)
			{
				val4 = ((Component)val3).gameObject.AddComponent<BoxCollider>();
			}
			((Collider)val4).enabled = true;
			((Collider)val4).isTrigger = true;
			val4.center = Vector3.zero;
			val4.size = new Vector3(1.75f, 2.35f, 1.35f);
			if ((Object)(object)val == (Object)null)
			{
				val = ((Component)val3).gameObject.AddComponent<ScanNodeProperties>();
			}
			val.headerText = "Dreadweaver";
			val.subText = "";
			val.maxRange = 25;
			val.minRange = 1;
			val.requiresLineOfSight = true;
			val.nodeType = 1;
		}

		private static void RetireExtraScanNode(ScanNodeProperties extra, ScanNodeProperties preferred, GameObject root)
		{
			//IL_0035: 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_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)extra == (Object)null)
			{
				return;
			}
			Scene scene;
			if ((Object)(object)((Component)extra).gameObject == (Object)(object)root || ((Object)(object)preferred != (Object)null && (Object)(object)((Component)extra).gameObject == (Object)(object)((Component)preferred).gameObject))
			{
				scene = root.scene;
				if (((Scene)(ref scene)).IsValid())
				{
					Object.Destroy((Object)(object)extra);
				}
				else
				{
					Object.DestroyImmediate((Object)(object)extra, true);
				}
				return;
			}
			GameObject gameObject = ((Component)extra).gameObject;
			gameObject.SetActive(false);
			Collider[] components = gameObject.GetComponents<Collider>();
			for (int i = 0; i < components.Length; i++)
			{
				components[i].enabled = false;
			}
			scene = root.scene;
			if (((Scene)(ref scene)).IsValid())
			{
				Object.Destroy((Object)(object)gameObject);
			}
			else
			{
				Object.DestroyImmediate((Object)(object)gameObject, true);
			}
		}

		private static void EnsureCollision(GameObject prefab, DreadweaverAI ai)
		{
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: 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_00e6: 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_01ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b3: Unknown result type (might be due to invalid IL or missing references)
			CapsuleCollider obj = prefab.GetComponent<CapsuleCollider>() ?? prefab.AddComponent<CapsuleCollider>();
			((Collider)obj).isTrigger = false;
			obj.direction = 1;
			float num = Mathf.Max(0.01f, 1.75f);
			obj.center = new Vector3(0f, 0.95f / num, 0f);
			obj.radius = DreadweaverGameplayPolicy.LocalDimension(0.35f, num);
			obj.height = DreadweaverGameplayPolicy.LocalDimension(1.9f, num);
			Transform val = FindOrCreateChild(prefab.transform, "Collision", new Vector3(0f, 1.1f, 0f));
			TrySetTag(((Component)val).gameObject, "Enemy");
			TrySetLayer(((Component)val).gameObject, "Enemies");
			BoxCollider obj2 = ((Component)val).GetComponent<BoxCollider>() ?? ((Component)val).gameObject.AddComponent<BoxCollider>();
			((Collider)obj2).isTrigger = true;
			obj2.center = Vector3.zero;
			obj2.size = new Vector3(0.75f, 2.04f, 0.65f);
			Rigidbody obj3 = ((Component)val).GetComponent<Rigidbody>() ?? ((Component)val).gameObject.AddComponent<Rigidbody>();
			obj3.isKinematic = true;
			obj3.useGravity = false;
			obj3.detectCollisions = true;
			EnemyAICollisionDetect obj4 = ((Component)val).GetComponent<EnemyAICollisionDetect>() ?? ((Component)val).gameObject.AddComponent<EnemyAICollisionDetect>();
			obj4.mainScript = (EnemyAI)(object)ai;
			obj4.alwaysAllowHitting = true;
			obj4.canCollideWithEnemies = true;
			obj4.onlyCollideWhenGrounded = false;
			Transform val2 = FindOrCreateChild(prefab.transform, "DoorNavigation", new Vector3(0f, 0.75f / num, 0f));
			TrySetLayer(((Component)val2).gameObject, "Enemies");
			BoxCollider val3 = ((Component)val2).GetComponent<BoxCollider>() ?? ((Component)val2).gameObject.AddComponent<BoxCollider>();
			((Collider)val3).isTrigger = true;
			val3.size = new Vector3(0.9f, 1.4f, 0.9f) / num;
			Rigidbody obj5 = ((Component)val2).GetComponent<Rigidbody>() ?? ((Component)val2).gameObject.AddComponent<Rigidbody>();
			obj5.isKinematic = true;
			obj5.useGravity = false;
			(((Component)val2).GetComponent<DreadweaverDoorTrigger>() ?? ((Component)val2).gameObject.AddComponent<DreadweaverDoorTrigger>()).owner = ai;
			ai.doorNavigationTrigger = (Collider)(object)val3;
		}

		private static EnemyType CreateEnemyType(GameObject prefab)
		{
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			EnemyType obj = ScriptableObject.CreateInstance<EnemyType>();
			obj.enemyName = "Dreadweaver";
			obj.enemyPrefab = prefab;
			obj.PowerLevel = ModConfig.PowerLevel.Value;
			obj.DiversityPowerLevel = 1;
			obj.MaxCount = ModConfig.MaxCount.Value;
			obj.canDie = true;
			obj.canBeStunned = true;
			obj.canBeDestroyed = true;
			obj.stunTimeMultiplier = 1f;
			obj.stunGameDifficultyMultiplier = 1f;
			obj.destroyOnDeath = false;
			obj.doorSpeedMultiplier = 1.1f;
			obj.isOutsideEnemy = false;
			obj.isDaytimeEnemy = false;
			obj.normalizedTimeInDayToLeave = 1f;
			obj.probabilityCurve = AnimationCurve.Constant(0f, 1f, 1f);
			obj.numberSpawnedFalloff = AnimationCurve.Linear(0f, 1f, 1f, 0.35f);
			obj.useNumberSpawnedFalloff = true;
			obj.disableAnimatorWhenFar = false;
			obj.SizeLimit = (NavSizeLimit)1;
			CreatureSfx.Apply(obj, (EnemyAI)(object)prefab.GetComponent<DreadweaverAI>());
			return obj;
		}

		private static AudioSource FindOrCreateAudioSource(Transform parent, string childName, float maxDistance)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			Transform val = FindOrCreateChild(parent, childName, Vector3.zero);
			AudioSource obj = ((Component)val).GetComponent<AudioSource>() ?? ((Component)val).gameObject.AddComponent<AudioSource>();
			obj.playOnAwake = false;
			obj.spatialBlend = 1f;
			obj.rolloffMode = (AudioRolloffMode)1;
			obj.minDistance = 3f;
			obj.maxDistance = maxDistance;
			return obj;
		}

		private static void AssignDreadweaverAudio(DreadweaverAI ai)
		{
			if ((Object)(object)ai == (Object)null || (Object)(object)ModAssets == (Object)null)
			{
				return;
			}
			string[] allAssetNames = ModAssets.GetAllAssetNames();
			ai.spotClips = LoadAudioClipSet(allAssetNames, "Spot_01", "Spot_02", "Spot_03");
			ai.footstepClips = LoadAudioClipSet(allAssetNames, "Footstep Metal Running 1_01", "Footstep Metal Running 1_02", "Footstep Metal Running 1_03", "Footstep Metal Running 1_04", "Footstep Metal Running 1_05", "Footstep Metal Running 1_06", "Footstep Metal Running 1_07", "Footstep Metal Running 1_08");
			ai.initialAttackClip = LoadAudioClip(allAssetNames, "Jumpscare_InitialAttack_01");
			if (ai.spotClips.Length != 3 || ai.footstepClips.Length != 8 || (Object)(object)ai.initialAttackClip == (Object)null)
			{
				ManualLogSource log = Log;
				if (log != null)
				{
					log.LogWarning((object)($"[DreadweaverAudio] Incomplete bundle audio: spots={ai.spotClips.Length}/3, " + $"footsteps={ai.footstepClips.Length}/8, initialAttack={(((Object)(object)ai.initialAttackClip != (Object)null) ? 1 : 0)}/1."));
				}
			}
			else
			{
				ManualLogSource log2 = Log;
				if (log2 != null)
				{
					log2.LogInfo((object)"[DreadweaverAudio] Loaded 3 stalking stingers, 8 footsteps, and 1 initial-attack jumpscare.");
				}
			}
		}

		private static AudioClip[] LoadAudioClipSet(string[] bundleAssets, params string[] clipNames)
		{
			List<AudioClip> list = new List<AudioClip>(clipNames.Length);
			for (int i = 0; i < clipNames.Length; i++)
			{
				AudioClip val = LoadAudioClip(bundleAssets, clipNames[i]);
				if ((Object)(object)val != (Object)null)
				{
					list.Add(val);
				}
			}
			return list.ToArray();
		}

		private static AudioClip LoadAudioClip(string[] bundleAssets, string clipName)
		{
			foreach (string text in bundleAssets)
			{
				if (string.Equals(Path.GetFileNameWithoutExtension(text), clipName, StringComparison.OrdinalIgnoreCase))
				{
					AudioClip val = ModAssets.LoadAsset<AudioClip>(text);
					if ((Object)(object)val != (Object)null)
					{
						return val;
					}
				}
			}
			ManualLogSource log = Log;
			if (log != null)
			{
				log.LogWarning((object)("[DreadweaverAudio] Missing AudioClip '" + clipName + "' in dreadweaver.bundle."));
			}
			return null;
		}

		private static Transform FindOrCreateChild(Transform parent, string name, Vector3 localPosition)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			Transform val = parent.Find(name);
			if ((Object)(object)val != (Object)null)
			{
				val.localPosition = localPosition;
				return val;
			}
			val = new GameObject(name).transform;
			val.SetParent(parent, false);
			val.localPosition = localPosition;
			return val;
		}

		private static void AssignUniqueNetworkHash(GameObject prefab)
		{
			try
			{
				NetworkObject val = prefab.GetComponent<NetworkObject>();
				if ((Object)(object)val == (Object)null)
				{
					val = prefab.AddComponent<NetworkObject>();
				}
				uint num = BitConverter.ToUInt32(MD5.Create().ComputeHash(Encoding.UTF8.GetBytes("y4ngz.lethalcompany.dreadweaver.SK_Dreadweaver")), 0);
				PropertyInfo property = typeof(NetworkObject).GetProperty("GlobalObjectIdHash", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (property != null && property.CanWrite)
				{
					property.SetValue(val, num);
					return;
				}
				FieldInfo fieldInfo = typeof(NetworkObject).GetField("GlobalObjectIdHash", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) ?? typeof(NetworkObject).GetField("<GlobalObjectIdHash>k__BackingField", BindingFlags.Instance | BindingFlags.NonPublic);
				if (fieldInfo != null)
				{
					fieldInfo.SetValue(val, num);
				}
			}
			catch (Exception ex)
			{
				Log.LogWarning((object)("Could not assign NetworkObject hash for Dreadweaver: " + ex.Message));
			}
		}

		private static void DumpBundleAssets()
		{
			if (!((Object)(object)ModAssets == (Object)null))
			{
				string[] allAssetNames = ModAssets.GetAllAssetNames();
				foreach (string text in allAssetNames)
				{
					Log.LogError((object)("  - " + text));
				}
			}
		}

		private static void TrySetTag(GameObject gameObject, string tag)
		{
			try
			{
				gameObject.tag = tag;
			}
			catch
			{
			}
		}

		private static void TrySetLayer(GameObject gameObject, string layerName)
		{
			if ((Object)(object)gameObject == (Object)null)
			{
				return;
			}
			int num = LayerMask.NameToLayer(layerName);
			if (num < 0)
			{
				num = ResolveLayerFallback(layerName);
			}
			if (num >= 0 && num <= 31)
			{
				gameObject.layer = num;
				return;
			}
			ManualLogSource log = Log;
			if (log != null)
			{
				log.LogWarning((object)$"[Dreadweaver] Layer '{layerName}' unresolved; '{((Object)gameObject).name}' stays on layer {gameObject.layer}.");
			}
		}

		private static int ResolveLayerFallback(string layerName)
		{
			if (string.Equals(layerName, "ScanNode", StringComparison.OrdinalIgnoreCase))
			{
				return 22;
			}
			if (string.Equals(layerName, "Enemies", StringComparison.OrdinalIgnoreCase))
			{
				return 19;
			}
			return -1;
		}

		private static void EnsureHierarchyActive(Transform child, Transform stopAt)
		{
			Transform val = child;
			while ((Object)(object)val != (Object)null)
			{
				((Component)val).gameObject.SetActive(true);
				if (!((Object)(object)val == (Object)(object)stopAt))
				{
					val = val.parent;
					continue;
				}
				break;
			}
		}
	}
	internal static class PluginInfo
	{
		public const string PLUGIN_GUID = "y4ngz.lethalcompany.dreadweaver";

		public const string PLUGIN_NAME = "Y4NGZ Dreadweaver";

		public const string PLUGIN_VERSION = "1.2.1";
	}
}
namespace Y4NGZDreadweaver.AI
{
	public sealed class DreadweaverAI : EnemyAI
	{
		private struct AttackProfile
		{
			public readonly int AnimationCode;

			public readonly float StrikeTimeSeconds;

			public readonly float RecoverySeconds;

			public readonly float RangeMultiplier;

			public readonly float ArcMultiplier;

			public readonly float SelectionWeight;

			public AttackProfile(int animationCode, float strikeTimeSeconds, float recoverySeconds, float rangeMultiplier, float arcMultiplier, float selectionWeight)
			{
				AnimationCode = animationCode;
				StrikeTimeSeconds = strikeTimeSeconds;
				RecoverySeconds = recoverySeconds;
				RangeMultiplier = rangeMultiplier;
				ArcMultiplier = arcMultiplier;
				SelectionWeight = selectionWeight;
			}
		}

		private struct FlickerLight
		{
			public Light Light;

			public float Intensity;
		}

		private enum SightingStage
		{
			Long,
			Medium,
			Short
		}

		private enum SightingPresentation
		{
			HallwayEnd,
			CornerReveal,
			DeadEndBehind
		}

		private enum AttackEngageMode
		{
			WalkThenRun,
			RunImmediately,
			CrawlThenRun
		}

		private sealed class CamoShellRenderer
		{
			public Renderer Renderer;

			public Material[] Materials;
		}

		private sealed class LightBaseline
		{
			public float Intensity;

			public int Holders;
		}

		public const int StateHiddenAcquireTarget = 0;

		public const int StateHiddenFindWatch = 1;

		public const int StateSightingVisible = 2;

		public const int StateHiddenBetweenSightings = 3;

		public const int StateHiddenPreAttackDelay = 4;

		public const int StateAttackSetup = 5;

		public const int StateCrawlAdvance = 6;

		public const int StatePursuit = 7;

		public const int StateAttackVanishReposition = 8;

		public const int StateHit = 9;

		public const int StateDead = 10;

		private const ulong NoTargetClientId = ulong.MaxValue;

		private const float EyeHeight = 1.65f;

		private const float RevealUnseenHalfAngle = 35f;

		private const float DirectRevealHalfAngle = 12f;

		private const float AttackRevealUnseenHalfAngle = 45f;

		private const float ShortCornerMaxPathDistance = 16f;

		private const float ShortApproachVanishDistance = 2.4f;

		private const float DirectRevealDelaySeconds = 0.75f;

		private const float ReengageCamoPreviewSeconds = 0.72f;

		private const int MaxRapidReengagements = 3;

		private const float WatchSearchRelaxSeconds = 5f;

		private const float LongSearchRelaxSeconds = 8f;

		private const float RevealSearchTimeoutSeconds = 12f;

		private const int MaxAttackPlacementRetries = 3;

		private const float SightingSeenCloseThreshold = 1.1f;

		private const float WatchLosGraceSeconds = 2.5f;

		private const float MinDistanceFromLastVanish = 8f;

		private const float VisibilityResyncInterval = 6f;

		private const float PresentationSyncInterval = 0.08f;

		private const float PresentationYawThreshold = 1.25f;

		private const float RevealFacingLockSeconds = 0.8f;

		private const float RevealReadableFraction = 0.72f;

		private const float VanishColliderDisableFraction = 0.6f;

		private const float ReplicatedFacingTurnSpeed = 540f;

		private const float AnimationCrossFadeSeconds = 0.18f;

		private const float SightingMinimumStareSeconds = 0.85f;

		private const float CornerPresentationMaxPathDistance = 23f;

		private const float DeadEndBehindMaxPathDistance = 26f;

		private const float RequiredSightingIntervalMinSeconds = 45f;

		private const float RequiredSightingIntervalFallbackMaxSeconds = 65f;

		private const float AttackReadyDelayMinSeconds = 15f;

		private const float AttackReadyDelayMaxSeconds = 30f;

		private const float ExitDodgeSeconds = 0.42f;

		private const float ExitDodgeVisibleSeconds = 0.16f;

		private const float ExitDodgeCamoSeconds = 0.24f;

		private const float LongSightingDodgeChance = 0.12f;

		private const float MediumSightingDodgeChance = 0.06f;

		private const float ExitDodgeDistance = 6.5f;

		private const float PlacementClearanceRadius = 0.82f;

		private const float PlacementClearanceHeight = 2.45f;

		private const float DefaultAttackDamageDelay = 0.48f;

		private const float AttackStuckRecoverySeconds = 7f;

		private const float AttackSoftPathRepairSeconds = 1.6f;

		private const float AttackPathRepairCooldownSeconds = 1.4f;

		private const float AttackProgressCheckIntervalSeconds = 0.35f;

		private const float AttackProgressMinDistance = 0.18f;

		private const float AttackWalkIntroSeconds = 3f;

		private const float StalkLightFlickerInitialMinSeconds = 12f;

		private const float StalkLightFlickerInitialMaxSeconds = 24f;

		private const float StalkLightFlickerDurationSeconds = 1.15f;

		private const int StalkLightFlickerBudgetMin = 2;

		private const int StalkLightFlickerBudgetMax = 3;

		private const int MaxStalkFlickerLights = 10;

		private const int MaxStalkFlickerAnimators = 8;

		private const int MaxPoweredLightSightingCandidates = 16;

		private const float PoweredLightCandidateSearchPadding = 8f;

		private const float PoweredLightCandidateSampleRadius = 4.5f;

		private const float PoweredLightAffinityRadius = 9f;

		private const float PoweredLightAffinityMaxScore = 4.75f;

		private const float StalkDoorSlamInitialMinSeconds = 24f;

		private const float StalkDoorSlamInitialMaxSeconds = 40f;

		private const float DoorSlamOpenSeconds = 0.2f;

		private const float DoorSlamClosedSeconds = 0.16f;

		private const int DoorSlamCycles = 3;

		private const float DamageStunFreezeSeconds = 0.78f;

		private const float FootstepPhaseOffset = 0.08f;

		private const int FootstepsPerLocomotionCycle = 2;

		private const float PerceptionCheckInterval = 0.1f;

		private const float StalkTargetGraceSeconds = 30f;

		private const float PoweredLightsRefreshIntervalSeconds = 10f;

		private const float NoiseMinLoudness = 0.5f;

		private const float NoiseHearingRange = 20f;

		private const float NoiseMemorySeconds = 3f;

		private const float NoiseReseedCooldown = 4f;

		private const int NoiseMaxRepeatsInOneSpot = 10;

		private const float NoiseNearLastKnownRadius = 12f;

		private const int OneShotInitialAttack = 0;

		private const int OneShotDirectionalCamo = 1;

		private const string CamoShellName = "_DreadweaverCamoShell";

		private const int AnimIdle1 = 0;

		private const int AnimIdle2 = 1;

		private const int AnimIdle3 = 2;

		private const int AnimIdle4 = 3;

		private const int AnimWalk1 = 4;

		private const int AnimWalk2 = 5;

		private const int AnimWalkBack = 6;

		private const int AnimWalkLeft = 7;

		private const int AnimWalkLeft2 = 8;

		private const int AnimWalkRight = 9;

		private const int AnimRun = 10;

		private const int AnimCrawl = 11;

		private const int AnimDodgeLeft = 12;

		private const int AnimDodgeRight = 13;

		private const int AnimDodgeForward = 14;

		private const int AnimDodgeBackward = 15;

		private const int AnimTurnLeft = 16;

		private const int AnimTurnRight = 17;

		private const int AnimWeaveFear = 18;

		private const int AnimAttackBase = 20;

		private const int AnimTakingDamage1 = 40;

		private const int AnimTakingDamage2 = 41;

		private const int AnimDeath1 = 50;

		private const int AnimDeath2 = 51;

		private static readonly AttackProfile[] AttackProfiles = new AttackProfile[9]
		{
			new AttackProfile(21, 0.37f, 0.83f, 0.92f, 0.92f, 1.15f),
			new AttackProfile(22, 0.48f, 1.5f, 1f, 1f, 1f),
			new AttackProfile(23, 0.43f, 1.2f, 0.96f, 1.06f, 1.1f),
			new AttackProfile(24, 0.53f, 1.83f, 1f, 1f, 1f),
			new AttackProfile(25, 0.53f, 1.83f, 1f, 1f, 1f),
			new AttackProfile(26, 0.65f, 2.67f, 1.08f, 0.9f, 0.7f),
			new AttackProfile(27, 0.6f, 2.43f, 1.05f, 0.95f, 0.8f),
			new AttackProfile(28, 0.58f, 2.43f, 1.05f, 1f, 0.8f),
			new AttackProfile(29, 0.55f, 2.13f, 1f, 1.08f, 0.9f)
		};

		private static readonly int DissolveId = Shader.PropertyToID("_Dissolve");

		private static readonly int DissolveAmountId = Shader.PropertyToID("_DissolveAmount");

		private static readonly int CutoffId = Shader.PropertyToID("_Cutoff");

		private static readonly int AlphaCutoffId = Shader.PropertyToID("_AlphaCutoff");

		private static readonly int EdgeWidthId = Shader.PropertyToID("_EdgeWidth");

		private static readonly int EmissionIntensityId = Shader.PropertyToID("_EmissionIntensity");

		private static readonly int EmissiveIntensityId = Shader.PropertyToID("_EmissiveIntensity");

		private static readonly int EdgeColorId = Shader.PropertyToID("_EdgeColor");

		private static readonly int EmissionColorId = Shader.PropertyToID("_EmissionColor");

		private static readonly int EmissiveColorId = Shader.PropertyToID("_EmissiveColor");

		[Header("Dreadweaver anchors")]
		public Transform attackOrigin;

		public Animator visualAnimator;

		public Collider doorNavigationTrigger;

		[Header("Dreadweaver search")]
		public AISearchRoutine attackRecoverySearch = new AISearchRoutine();

		[Header("Dreadweaver audio")]
		public AudioClip[] spotClips = (AudioClip[])(object)new AudioClip[0];

		public AudioClip[] footstepClips = (AudioClip[])(object)new AudioClip[0];

		public AudioClip initialAttackClip;

		private readonly RaycastHit[] _lineOfSightHits = (RaycastHit[])(object)new RaycastHit[48];

		private readonly Collider[] _placementColliders = (Collider[])(object)new Collider[24];

		private readonly List<CamoShellRenderer> _camoShells = new List<CamoShellRenderer>();

		private readonly List<FlickerLight> _activeLightFlickerStates = new List<FlickerLight>();

		private readonly NetworkVariable<int> _networkState = new NetworkVariable<int>(0, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)0);

		private readonly NetworkVariable<ulong> _networkTargetClientId = new NetworkVariable<ulong>(ulong.MaxValue, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)0);

		private readonly NetworkVariable<int> _networkStage = new NetworkVariable<int>(0, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)0);

		private readonly NetworkVariable<int> _networkPresentation = new NetworkVariable<int>(0, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)0);

		private readonly NetworkVariable<int> _networkAnimationCode = new NetworkVariable<int>(0, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)0);

		private readonly NetworkVariable<float> _networkAnimationNormalizedTime = new NetworkVariable<float>(0f, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)0);

		private readonly NetworkVariable<bool> _networkVisible = new NetworkVariable<bool>(true, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)0);

		private readonly NetworkVariable<int> _networkVisibilitySequence = new NetworkVariable<int>(0, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)0);

		private readonly NetworkVariable<float> _networkFacingYaw = new NetworkVariable<float>(0f, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)0);

		private readonly NetworkVariable<int> _networkRevealSequence = new NetworkVariable<int>(0, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)0);

		private readonly NetworkVariable<float> _networkFacingLockDuration = new NetworkVariable<float>(0.8f, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)0);

		private readonly NetworkVariable<float> _networkPresentationReadyDelay = new NetworkVariable<float>(0f, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)0);

		private readonly NetworkVariable<Vector3> _networkModelScale = new NetworkVariable<Vector3>(Vector3.one, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)0);

		private readonly NetworkVariable<float> _networkMovementSpeed = new NetworkVariable<float>(0f, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)0);

		private readonly NetworkVariable<float> _networkLocomotionPlayback = new NetworkVariable<float>(1f, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)0);

		private readonly NetworkVariable<bool> _networkSpotlightActive = new NetworkVariable<bool>(false, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)0);

		private readonly NetworkVariable<float> _networkSpotlightIntensity = new NetworkVariable<float>(0f, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)0);

		private readonly NetworkVariable<float> _networkSpotlightAngle = new NetworkVariable<float>(42f, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)0);

		private readonly NetworkVariable<float> _networkSpotlightRange = new NetworkVariable<float>(14f, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)0);

		private readonly NetworkVariable<float> _networkSpotlightHeight = new NetworkVariable<float>(5f, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)0);

		private readonly NetworkVariable<Vector3> _networkSpotlightColor = new NetworkVariable<Vector3>(Vector3.one, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)0);

		private Renderer[] _bodyRenderers = (Renderer[])(object)new Renderer[0];

		private bool[] _bodyRendererDefaults = new bool[0];

		private Collider[] _bodyColliders = (Collider[])(object)new Collider[0];

		private bool[] _bodyColliderDefaults = new bool[0];

		private bool _visualsCaptured;

		private bool _camoShellsCreated;

		private bool _usingBundledCamoMaterial;

		private bool _loggedCamoFallback;

		private bool _logicalVisible = true;

		private bool _renderersShown = true;

		private int _visSeq;

		private int _appliedVisSeq = -1;

		private Coroutine _flickerRoutine;

		private Coroutine _camoPreviewRoutine;

		private Coroutine _localLightFlickerRoutine;

		private float _nextVisibilityResyncTime;

		private int _lastResyncVisSeq = -1;

		private bool _lastResyncVisible = true;

		private int _lastSentState = int.MinValue;

		private ulong _lastSentTargetClientId = ulong.MaxValue;

		private int _lastSentAnimationCode = int.MinValue;

		private bool _spotlightProfilePublished;

		private float _presentationReadyAt;

		private float _nextPresentationSyncTime;

		private float _lastPublishedFacingYaw;

		private float _lastPublishedMovementSpeed = -1f;

		private float _lastPublishedLocomotionPlayback = -1f;

		private int _clientAppliedRevealSequence;

		private float _clientFacingLockUntil;

		private SightingStage _stage;

		private SightingPresentation _pendingPresentation;

		private ulong _targetClientId = ulong.MaxValue;

		private ulong _lastKilledTargetClientId = ulong.MaxValue;

		private ulong _lastHitByClientId = ulong.MaxValue;

		private float _phaseEnteredAt;

		private float _nextActionTime;

		private bool _hasPendingWatchPosition;

		private float _watchRevealDeadline;

		private float _sightingFirstSeenAt = -1f;

		private float _sightingSeenDistance;

		private float _losLostSince = -1f;

		private Vector3 _lastVanishPosition;

		private bool _hasLastVanishPosition;

		private Coroutine _sightingExitRoutine;

		private bool _isEndingSighting;

		private Coroutine _stalkDoorSlamRoutine;

		private DoorLock _stalkDoorSlamDoor;

		private float _nextStalkLightFlickerTime;

		private float _nextStalkDoorSlamTime;

		private int _remainingStalkLightFlickers;

		private Vector3 _lastAttackRevealPosition;

		private bool _hasLastAttackRevealPosition;

		private AttackEngageMode _attackEngageMode = AttackEngageMode.CrawlThenRun;

		private int _attackAdvanceAnimation = 11;

		private float _attackAdvanceEndTime;

		private float _nextAttackTime;

		private float _lostSightTimer;

		private float _repositionRelaxAt;

		private Vector3 _lastKnownAttackTargetPosition;

		private Vector3 _lastAttackProgressPosition;

		private float _lastAttackProgressDistance;

		private float _attackStuckTimer;

		private float _nextAttackProgressCheckTime;

		private float _nextAttackPathRepairTime;

		private Coroutine _attackRoutine;

		private Coroutine _reengageCueRoutine;

		private bool _isAttackAnimating;

		private bool _isHitStaggering;

		private Coroutine _hitStaggerRoutine;

		private AttackProfile _activeAttackProfile;

		private bool _resolvePostTargetDownAfterSwing;

		private float _attackMovementReadyAt;

		private bool _pursuitSpotlightProfileApplied;

		private int _rapidReengagementCount;

		private int _attackPlacementRetries;

		private float _nextLocalFearTime;

		private float _lastLocalMovementAnimTime;

		private float _animationLockUntil;

		private float _damageStunUntil;

		private float _preDamageStunAnimatorSpeed = 1f;

		private string _currentAnimationName;

		private int _currentAnimationCode = int.MinValue;

		private float _currentAnimationNormalizedTime;

		private bool _damageStunFrozen;

		private bool _wasStunned;

		private bool _agentHeldForFreeze;

		private bool _locomotionMoving;

		private int _footstepAnimatorStateHash;

		private int _footstepTick = int.MinValue;

		private float _lastFootstepNormalizedTime;

		private int _lastFootstepClipIndex = -1;

		private bool _hasPlayedInitialAttackJumpscare;

		private static AudioClip _directionalCamoCue;

		private bool _startRan;

		private readonly ServerOwnershipGuard _ownership = new ServerOwnershipGuard();

		private readonly NoiseMemory _noiseMemory = new NoiseMemory();

		private float _nextNoiseReseedTime;

		private float _nextStrikeCheckTime;

		private float _nextPerceptionTime;

		private bool _perceivedTargetSees;

		private bool _perceivedByOtherPlayer;

		private bool _perceivedLineOfSight;

		private float _stalkTargetGapSince = -1f;

		private float _appliedAgentSpeed = -1f;

		private bool _agentFixedSettingsApplied;

		private bool _referencesResolved;

		private bool _audioRouted;

		private DoorLock[] _stalkDoors;

		private NavMeshPath _pathBuffer;

		private readonly Vector3[] _pathCorners = (Vector3[])(object)new Vector3[64];

		private readonly List<Vector3> _poweredLightCandidates = new List<Vector3>(16);

		private static float _nextPoweredLightsRefreshTime;

		private static readonly Dictionary<Light, LightBaseline> LightBaselines = new Dictionary<Light, LightBaseline>();

		private static bool _lightBaselineUnloadHooked;

		private DreadweaverSpotlight _spotlight;

		private bool _spotlightActive;

		private float _spotlightIntensity;

		private float _spotlightAngle = 42f;

		private float _spotlightRange = 14f;

		private float _spotlightHeight = 5f;

		private Vector3 _spotlightColor = Vector3.one;

		private Coroutine _flashlightHarassRoutine;

		private readonly List<FlickerLight> _flashlightHarassLights = new List<FlickerLight>();

		private float _nextFlashlightHarassTime;

		private float StalkMoveSpeed => Mathf.Clamp(Plugin.ModConfig?.StalkMoveSpeed.Value ?? 1.5f, 0.5f, 4f);

		private float CrawlSpeed => Mathf.Clamp(Plugin.ModConfig?.CrawlSpeed.Value ?? 2.1f, 0.8f, 4f);

		private float AttackWalkSpeed => Mathf.Clamp(Mathf.Max(StalkMoveSpeed, CrawlSpeed * 0.85f), 1.25f, 3.2f);

		private float AttackSpeed => Mathf.Clamp(Plugin.ModConfig?.AttackSpeed.Value ?? 5.15f, 2f, 9f);

		private float TurnSpeed => 420f;

		private float Acceleration => 18f;

		private float SpotHalfAngle => 25f;

		private float CreatureSightRange => 60f;

		private float SightingIntervalMin => Mathf.Clamp(Plugin.ModConfig?.SightingIntervalMinSeconds.Value ?? 45f, 8f, 120f);

		private float SightingIntervalMax => ResolveIntervalMax(Plugin.ModConfig?.SightingIntervalMaxSeconds.Value ?? 65f, SightingIntervalMin, 65f, 150f);

		private float SightingRetryMin => 15f;

		private float SightingRetryMax => 30f;

		private float StalkLightFlickerRadius => 18f;

		private float StalkLightFlickerIntervalMin => 40f;

		private float StalkLightFlickerIntervalMax => 70f;

		private float StalkDoorSlamRadius => 14f;

		private float StalkDoorSlamIntervalMin => 35f;

		private float StalkDoorSlamIntervalMax => 70f;

		private float AttackDelayMin => Mathf.Clamp(Plugin.ModConfig?.AttackDelayMinSeconds.Value ?? 15f, 5f, 60f);

		private float AttackDelayMax => Mathf.Max(AttackDelayMin, Mathf.Clamp(Plugin.ModConfig?.AttackDelayMaxSeconds.Value ?? 30f, AttackDelayMin, 90f));

		private float AttackRevealMin => 8f;

		private float AttackRevealMax => 16f;

		private float CrawlAdvanceSeconds => 3f;

		private float AttackRange => 2.35f;

		private float AttackCooldown => Mathf.Clamp(Plugin.ModConfig?.AttackCooldown.Value ?? 1.8f, 0.5f, 6f);

		private float AttackDamageDelay => 0.48f;

		private float AttackHitHalfAngle => 60f;

		private int AttackDamage => Mathf.Clamp(Plugin.ModConfig?.AttackDamage.Value ?? 40, 1, 100);

		private float AttackLoseDistance => 48f;

		private float AttackLostSightGraceSeconds => 12f;

		private float PursuitRepositionCooldownMin => 2f;

		private float PursuitRepositionCooldownMax => 5f;

		private float PursuitRepositionMinDistance => 10f;

		private float ChainAttackRadius => 13f;

		private float VanishFlickerSeconds => 0.65f;

		private float DecloakFlickerSeconds => 0.55f;

		private bool DebugLogs => Plugin.ModConfig?.DebugLogs.Value ?? false;

		private bool MatchAnimationToMovement => true;

		private float AuthoredWalkSpeed => 1.9f;

		private float AuthoredCrawlSpeed => 1.9f;

		private float AuthoredRunSpeed => 3.6f;

		private bool CreatureSpotlightEnabled => Plugin.ModConfig?.CreatureSpotlightEnabled.Value ?? true;

		private bool FlashlightHarassEnabled => Plugin.ModConfig?.FlashlightHarassEnabled.Value ?? true;

		private bool CanSendRpc
		{
			get
			{
				if ((Object)(object)((NetworkBehaviour)this).NetworkObject != (Object)null)
				{
					return ((NetworkBehaviour)this).NetworkObject.IsSpawned;
				}
				return false;
			}
		}

		private static float ResolveIntervalMax(float configuredValue, float min, float fallbackMax, float hardMax)
		{
			if (configuredValue < min + 0.1f)
			{
				return Mathf.Max(min + 1f, fallbackMax);
			}
			return Mathf.Max(min, Mathf.Clamp(configuredValue, min, hardMax));
		}

		public override void Awake()
		{
			try
			{
				((EnemyAI)this).Awake();
				ResolveReferences();
				ConfigureAttackSearchDefaults();
				if (!_lightBaselineUnloadHooked)
				{
					_lightBaselineUnloadHooked = true;
					SceneManager.sceneUnloaded += ClearLightBaselinesOnSceneUnload;
				}
			}
			catch (Exception arg)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogError((object)$"[DreadweaverAI] Awake failed: {arg}");
				}
			}
		}

		public override void OnNetworkSpawn()
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			((NetworkBehaviour)this).OnNetworkSpawn();
			_clientAppliedRevealSequence = -1;
			if (((NetworkBehaviour)this).IsServer)
			{
				_networkModelScale.Value = ((Component)this).transform.localScale;
			}
			else
			{
				ApplyNetworkSnapshotLocal(force: true);
			}
		}

		public override void Start()
		{
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				((EnemyAI)this).Start();
				Plugin.EnsureScanNode(((Component)this).gameObject);
				ResolveReferences();
				_audioRouted = RouteAudioSources();
				ConfigureAttackSearchDefaults();
				CaptureVisuals();
				base.enemyHP = Plugin.ModConfig?.Health.Value ?? 5;
				if (((NetworkBehaviour)this).IsServer)
				{
					ConfigureAgent(StalkMoveSpeed);
					StopAgent();
				}
				SetStateLocal(0);
				PlayAnimationLocal(0, 0.18f, 0f);
				_hasPlayedInitialAttackJumpscare = false;
				ResetFootstepTracking();
				_startRan = true;
				if (((NetworkBehaviour)this).IsServer)
				{
					RepairFacilityAINodes();
					PublishAuthoritativePresentationServer(force: true);
					VanishServer(playCue: false);
					_nextActionTime = Time.time + Random.Range(2f, 4f);
				}
				else if (((NetworkBehaviour)this).IsSpawned)
				{
					ApplyNetworkSnapshotLocal(force: true);
				}
				if (DebugLogs)
				{
					ManualLogSource log = Plugin.Log;
					if (log != null)
					{
						log.LogInfo((object)$"[DreadweaverAI] Spawned #{base.thisEnemyIndex} at {((Component)this).transform.position}.");
					}
				}
			}
			catch (Exception arg)
			{
				ManualLogSource log2 = Plugin.Log;
				if (log2 != null)
				{
					log2.LogError((object)$"[DreadweaverAI] Start failed: {arg}");
				}
			}
		}

		public override void Update()
		{
			try
			{
				_ownership.Ensure((EnemyAI)(object)this, Plugin.Log);
				((EnemyAI)this).Update();
				if (!_audioRouted)
				{
					_audioRouted = RouteAudioSources();
				}
				if (base.isEnemyDead)
				{
					return;
				}
				if (!_referencesResolved)
				{
					ResolveReferences();
				}
				ApplyNetworkSnapshotLocal();
				ApplyReplicatedFacingLocal();
				if (ApplyDamageStunFreeze())
				{
					PublishAuthoritativePresentationServer();
					return;
				}
				TickLocalFear();
				TickAnimatorPlaybackSpeed();
				TickLocalFootsteps();
				if (!((NetworkBehaviour)this).IsServer || (Object)(object)StartOfRound.Instance == (Object)null || StartOfRound.Instance.allPlayersDead)
				{
					return;
				}
				if (Time.time >= _nextVisibilityResyncTime)
				{
					_nextVisibilityResyncTime = Time.time + 6f;
					if (CanSendRpc && (_visSeq != _lastResyncVisSeq || _logicalVisible != _lastResyncVisible))
					{
						_lastResyncVisSeq = _visSeq;
						_lastResyncVisible = _logicalVisible;
						ResyncVisibilityClientRpc(_logicalVisible, _visSeq);
					}
				}
				if (_isHitStaggering)
				{
					PublishAuthoritativePresentationServer();
					return;
				}
				TickStalkingEnvironmentScares();
				switch (base.currentBehaviourStateIndex)
				{
				case 0:
					TickHiddenAcquireTarget();
					break;
				case 1:
					TickHiddenFindWatch();
					break;
				case 2:
					TickSightingVisible(Time.deltaTime);
					break;
				case 3:
					TickHiddenWait(1);
					break;
				case 4:
					TickHiddenWait(5);
					break;
				case 5:
					TickAttackSetup();
					break;
				case 6:
					TickCrawlAdvance(Time.deltaTime);
					break;
				case 7:
					TickPursuit(Time.deltaTime);
					break;
				case 8:
					TickAttackVanishReposition();
					break;
				}
				TickAuthoritativeLocomotionAnimation();
				PublishAuthoritativePresentationServer();
			}
			catch (Exception arg)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogError((object)$"[DreadweaverAI] Update failed: {arg}");
				}
			}
		}

		public override void DoAIInterval()
		{
			try
			{
				((EnemyAI)this).DoAIInterval();
			}
			catch (Exception arg)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogError((object)$"[DreadweaverAI] DoAIInterval failed: {arg}");
				}
			}
		}

		public override void HitEnemy(int force = 1, PlayerControllerB playerWhoHit = null, bool playHitSFX = false, int hitID = -1)
		{
			try
			{
				((EnemyAI)this).HitEnemy(force, playerWhoHit, playHitSFX, hitID);
				if (base.isEnemyDead)
				{
					return;
				}
				BeginDamageStunFreeze();
				if (!((NetworkBehaviour)this).IsServer)
				{
					return;
				}
				base.enemyHP -= Mathf.Max(1, force);
				if (base.enemyHP <= 0)
				{
					DieFromDamage();
					return;
				}
				_lastHitByClientId = (((Object)(object)playerWhoHit != (Object)null) ? playerWhoHit.actualClientId : ulong.MaxValue);
				if (_hitStaggerRoutine == null)
				{
					StopHitInterruptedRoutines();
					_hitStaggerRoutine = ((MonoBehaviour)this).StartCoroutine(HitStaggerRoutine());
				}
			}
			catch (Exception arg)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogError((object)$"[DreadweaverAI] HitEnemy failed: {arg}");
				}
			}
		}

		public override void DetectNoise(Vector3 noisePosition, float noiseLoudness, int timesPlayedInOneSpot = 0, int noiseID = 0)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				((EnemyAI)this).DetectNoise(noisePosition, noiseLoudness, timesPlayedInOneSpot, noiseID);
				if (((NetworkBehaviour)this).IsServer && !base.isEnemyDead && !((EnemyAI)(object)this).IsStunned() && !_isHitStaggering && timesPlayedInOneSpot <= 10 && (base.currentBehaviourStateIndex == 7 || base.currentBehaviourStateIndex == 8) && _reengageCueRoutine == null)
				{
					_noiseMemory.Record(noisePosition, noiseLoudness, 0.5f, GetCreatureFocusPoint(), 20f);
				}
			}
			catch (Exception arg)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogError((object)$"[DreadweaverAI] DetectNoise failed: {arg}");
				}
			}
		}

		public override void KillEnemy(bool destroy = false)
		{
			try
			{
				if (((NetworkBehaviour)this).IsServer)
				{
					StopSearchIfNeeded();
					DisableCreatureSpotlightServer();
				}
				int num = ResolveDeathAnimation();
				_logicalVisible = true;
				StopRoutinesAndRestoreBody();
				StopAgent();
				if (((NetworkBehaviour)this).IsServer)
				{
					_visSeq++;
					if (CanSendRpc)
					{
						_networkVisible.Value = true;
						_networkVisibilitySequence.Value = _visSeq;
					}
					SetStateServer(10);
				}
				else
				{
					SetStateLocal(10);
				}
				Animator creatureAnimator = base.creatureAnimator;
				base.creatureAnimator = null;
				try
				{
					((EnemyAI)this).KillEnemy(destroy);
				}
				finally
				{
					base.creatureAnimator = creatureAnimator;
				}
				base.isEnemyDead = true;
				if (((NetworkBehaviour)this).IsServer)
				{
					PlayAnimationServer(num, 0.08f, 0f);
				}
				else if (_currentAnimationCode != num)
				{
					PlayAnimationLocal(num, 0.08f, 0f);
				}
			}
			catch (Exception arg)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogError((object)$"[DreadweaverAI] KillEnemy failed: {arg}");
				}
			}
		}

		private int ResolveDeathAnimation()
		{
			if (((NetworkBehaviour)this).IsServer)
			{
				if (!(Random.value < 0.5f))
				{
					return 51;
				}
				return 50;
			}
			if (IsDeathAnimation(_currentAnimationCode))
			{
				return _currentAnimationCode;
			}
			int value = _networkAnimationCode.Value;
			if (!IsDeathAnimation(value))
			{
				return 50;
			}
			return value;
		}

		private static bool IsDeathAnimation(int animationCode)
		{
			if (animationCode != 50)
			{
				return animationCode == 51;
			}
			return true;
		}

		private void TickHiddenAcquireTarget()
		{
			if (!(Time.time < _nextActionTime))
			{
				_nextActionTime = Time.time + 1.5f;
				PlayerControllerB val = ChooseFixationTarget();
				if (!((Object)(object)val == (Object)null))
				{
					SetFixationTarget(val, "new stalking target");
					_stage = SightingStage.Long;
					EnterPhase(1);
				}
			}
		}

		private void TickHiddenWait(int nextState)
		{
			if ((Object)(object)RequireStalkTarget() == (Object)null)
			{
				if (!HoldStalkThroughTargetGap())
				{
					RestartStalkCycle("target lost while hidden");
				}
			}
			else if (!(Time.time < _nextActionTime))
			{
				EnterPhase(nextState);
			}
		}

		private void TickHiddenFindWatch()
		{
			//IL_00bf: 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_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: 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_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_0185: Unknown result type (might be due to invalid IL or missing references)
			PlayerControllerB val = RequireStalkTarget();
			if ((Object)(object)val == (Object)null)
			{
				if (!HoldStalkThroughTargetGap())
				{
					RestartStalkCycle("target lost while finding watch position");
				}
			}
			else if (!_hasPendingWatchPosition)
			{
				if (Time.time < _nextActionTime)
				{
					return;
				}
				_nextActionTime = Time.time + 0.65f;
				if (!TryFindSightingPosition(val, _stage, out var position))
				{
					RestartStalkCycleIfWatchSearchTimedOut();
					return;
				}
				Vector3 val2 = ResolveRootPlacement(position);
				if (!ValidateWatchPosition(val, _stage, val2))
				{
					RestartStalkCycleIfWatchSearchTimedOut();
					return;
				}
				TeleportFacing(val2, GetPlayerFocusPoint(val));
				_hasPendingWatchPosition = true;
				_watchRevealDeadline = Time.time + 0.75f;
			}
			else
			{
				if (!PerceptionDue())
				{
					return;
				}
				if (!ValidateWatchPosition(val, _stage, ((Component)this).transform.position))
				{
					_hasPendingWatchPosition = false;
					RestartStalkCycleIfWatchSearchTimedOut();
				}
				else
				{
					if (AnyPlayerWouldSeePosition(GetCreatureFocusPoint(), 12f) && Time.time < _watchRevealDeadline)
					{
						return;
					}
					TeleportFacing(((Component)this).transform.position, GetPlayerFocusPoint(val));
					RevealServer(Mathf.Max(0.08f, DecloakFlickerSeconds * 0.75f));
					PlayStalkingRevealSoundServer(val);
					PlayAnimationServer(ChooseSightingIntroAnimation(), 0.2f, GetSightingIntroNormalizedTime());
					EnterPhase(2);
					if (DebugLogs)
					{
						ManualLogSource log = Plugin.Log;
						if (log != null)
						{
							log.LogInfo((object)$"[DreadweaverAI] {_stage}/{_pendingPresentation} sighting revealed at {((Component)this).transform.position}.");
						}
					}
				}
			}
		}

		private void RestartStalkCycleIfWatchSearchTimedOut()
		{
			if (Time.time - _phaseEnteredAt > 12f)
			{
				RestartStalkCycle("no stalking presentation found");
			}
		}

		private bool ValidateWatchPosition(PlayerControllerB target, SightingStage stage, Vector3 rootPosition)
		{
			//IL_000f: 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_0042: 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_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: 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)
			GetStageParameters(stage, out var min, out var max, out var _, out var panic);
			float num = Vector3.Distance(rootPosition, ((Component)target).transform.position);
			float radius = ((_pendingPresentation == SightingPresentation.HallwayEnd && stage != SightingStage.Short) ? panic : Mathf.Max(2.6f, 2.4f));
			if (TooCloseToAnyPlayer(rootPosition, radius))
			{
				return false;
			}
			if (_pendingPresentation == SightingPresentation.CornerReveal)
			{
				if (num <= Mathf.Max(max + 10f, 13f))
				{
					return HasShortCompletePath(rootPosition, ((Component)target).transform.position, 23f);
				}
				return false;
			}
			if (_pendingPresentation == SightingPresentation.DeadEndBehind)
			{
				if (num >= 3.5f && num <= Mathf.Max(max + 12f, 18f))
				{
					return HasShortCompletePath(rootPosition, ((Component)target).transform.position, 26f);
				}
				return false;
			}
			if (num < min * 0.6f || num > max * 1.35f)
			{
				return false;
			}
			return HasClearLineOfSight(GetCandidateSightPoint(rootPosition), GetPlayerFocusPoint(target), ((Component)target).transform);
		}

		private void TickSightingVisible(float deltaTime)
		{
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: 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_0283: Unknown result type (might be due to invalid IL or missing references)
			//IL_028e: Unknown result type (might be due to invalid IL or missing references)
			PlayerControllerB val = RequireStalkTarget();
			if ((Object)(object)val == (Object)null)
			{
				if (!HoldStalkThroughTargetGap())
				{
					RestartStalkCycle("target lost while visible");
				}
				else
				{
					EndSighting("target briefly untargetable");
				}
			}
			else
			{
				if (_isEndingSighting)
				{
					return;
				}
				StopAgent();
				FaceTargetForStalking(val);
				GetStageParameters(_stage, out var min, out var max, out var hold, out var panic);
				hold = Mathf.Max(0.85f, hold);
				float num = Vector3.Distance(((Component)this).transform.position, ((Component)val).transform.position);
				float num2 = Mathf.Max(panic, GetApproachExitDistance(_pendingPresentation, _stage, min, max));
				if (PerceptionDue())
				{
					_perceivedTargetSees = TargetSeesCreature(val);
					_perceivedByOtherPlayer = NonTargetPlayerSeesCreature(val);
					_perceivedLineOfSight = _stage == SightingStage.Short || _sightingFirstSeenAt >= 0f || HasClearLineOfSight(GetCreatureFocusPoint(), GetPlayerFocusPoint(val), ((Component)val).transform);
				}
				bool flag = Time.time >= _presentationReadyAt && _perceivedTargetSees;
				if (flag && _sightingFirstSeenAt < 0f)
				{
					_sightingFirstSeenAt = Time.time;
					_sightingSeenDistance = num;
				}
				if ((_stage != SightingStage.Short || _sightingFirstSeenAt >= 0f) && TryGetClosestLivingPlayer(out var _, out var closestDistance) && closestDistance <= num2)
				{
					EndSighting("player too close");
					return;
				}
				if (_perceivedByOtherPlayer)
				{
					EndSighting("seen by another player");
					return;
				}
				if (flag)
				{
					if (num < _sightingSeenDistance - 1.1f)
					{
						EndSighting("target moved closer");
					}
					else if (Time.time - _sightingFirstSeenAt >= Mathf.Max(0.85f, hold))
					{
						EndSighting("hold complete");
					}
					return;
				}
				if (_sightingFirstSeenAt >= 0f)
				{
					if (Time.time - _sightingFirstSeenAt >= hold)
					{
						EndSighting("hold complete after look-away");
					}
					return;
				}
				if (_stage != SightingStage.Short)
				{
					if (_perceivedLineOfSight)
					{
						_losLostSince = -1f;
					}
					else if (_losLostSince < 0f)
					{
						_losLostSince = Time.time;
					}
					if ((_losLostSince >= 0f && Time.time - _losLostSince > 2.5f) || num > max * 1.35f)
					{
						EndSighting("watch position became bad");
						return;
					}
				}
				else if (Time.time >= _nextActionTime)
				{
					_nextActionTime = Time.time + 0.75f;
					if (!HasShortCompletePath(((Component)this).transform.position, ((Component)val).transform.position, 22f))
					{
						EndSighting("target left the corner area");
						return;
					}
				}
				if (Time.time - _phaseEnteredAt > GetUnseenPresentationTimeout(_pendingPresentation))
				{
					EndSighting("sighting timed out");
				}
			}
		}

		private void EndSighting(string reason)
		{
			if (!_isEndingSighting)
			{
				_sightingExitRoutine = ((MonoBehaviour)this).StartCoroutine(EndSightingRoutine(reason));
			}
		}

		private IEnumerator EndSightingRoutine(string reason)
		{
			_isEndingSighting = true;
			bool wasSeen = _sightingFirstSeenAt >= 0f;
			PlayerControllerB val = ResolveTargetById(_targetClientId);
			if (DebugLogs)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogInfo((object)$"[DreadweaverAI] {_stage}/{_pendingPresentation} sighting ending ({reason}); seen={wasSeen}.");
				}
			}
			if ((Object)(object)val != (Object)null)
			{
				FaceTargetForStalking(val);
			}
			if (!wasSeen && _stage == SightingStage.Short)
			{
				VanishServer(playCue: false, 0f);
				_isEndingSighting = false;
				_sightingExitRoutine = null;
				CompleteSightingTransition(wasSeen);
				yield break;
			}
			Vector3 dodgeDestination = Vector3.zero;
			int animationCode = 15;
			if (ShouldAttemptDodgeExit(val) && TryFindDodgeExitDestination(val, out dodgeDestination, out animationCode))
			{
				PlayAnimationServer(animationCode, 0.04f, 0f);
				MoveAgentTo(dodgeDestination, Mathf.Max(7.5f, AttackSpeed + 1.5f), 0.15f, autoBrake: false);
				yield return (object)new WaitForSeconds(0.16f);
				VanishServer(playCue: true, 0.24f);
				yield return (object)new WaitForSeconds(Mathf.Max(0.05f, 0.26f));
				if (TrySampleNavPosition(dodgeDestination, 2f, out var position))
				{
					MoveRootTo(position, ((Component)this).transform.rotation);
				}
			}
			else
			{
				StopAgent();
				yield return (object)new WaitForSeconds(0.08f);
				VanishServer(playCue: true);
				yield return (object)new WaitForSeconds(Mathf.Max(0.12f, VanishFlickerSeconds));
			}
			_isEndingSighting = false;
			_sightingExitRoutine = null;
			CompleteSightingTransition(wasSeen);
		}

		private void CompleteSightingTransition(bool wasSeen)
		{
			if (!wasSeen)
			{
				EnterPhase(3);
				_nextActionTime = Time.time + Random.Range(SightingRetryMin, SightingRetryMax);
			}
			else if (_stage == SightingStage.Short)
			{
				EnterPhase(4);
				_nextActionTime = Time.time + Random.Range(AttackDelayMin, AttackDelayMax);
			}
			else
			{
				_stage = ((_stage == SightingStage.Long) ? SightingStage.Medium : SightingStage.Short);
				EnterPhase(3);
				_nextActionTime = Time.time + Random.Range(SightingIntervalMin, SightingIntervalMax);
			}
		}

		private int ChooseSightingIntroAnimation()
		{
			return 18;
		}

		private float GetSightingIntroNormalizedTime()
		{
			return _stage switch
			{
				SightingStage.Long => 0.08f, 
				SightingStage.Medium => 0.12f, 
				_ => 0.16f, 
			};
		}

		private void PlayStalkingRevealSoundServer(PlayerControllerB target)
		{
			//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_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			if (!((NetworkBehaviour)this).IsServer || (Object)(object)target == (Object)null)
			{
				return;
			}
			int num = ((spotClips != null && spotClips.Length != 0) ? Random.Range(0, spotClips.Length) : (-1));
			if (num >= 0)
			{
				float spotStingerVolume = GetSpotStingerVolume(num);
				Vector3 worldPosition = ((Component)target).transform.position + Vector3.up * 1.1f;
				if (CanSendRpc)
			

Y4NGZFlyingTV.dll

Decompiled a week ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Net.Http;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using Dawn;
using GameNetcodeStuff;
using Microsoft.CodeAnalysis;
using Unity.Netcode;
using Unity.Netcode.Components;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.Audio;
using UnityEngine.SceneManagement;
using UnityEngine.Video;
using Y4NGZFlyingTV.NetcodePatcher;
using Y4NGZMonsters.Shared;

[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("Y4NGZFlyingTV")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+c64a155fd64c47528940e53659e5b5ada665b9d4")]
[assembly: AssemblyProduct("Y4NGZFlyingTV")]
[assembly: AssemblyTitle("Y4NGZFlyingTV")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
[module: NetcodePatchedAssembly]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.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 Y4NGZFlyingTV
{
	public sealed class FlyingTVAi : EnemyAI
	{
		private struct ScreenMaterialTarget
		{
			public Renderer Renderer;

			public int MaterialIndex;

			public ScreenMaterialTarget(Renderer renderer, int materialIndex)
			{
				Renderer = renderer;
				MaterialIndex = materialIndex;
			}
		}

		private struct PlayerMovementSample
		{
			public float Timestamp;

			public Vector3 Position;

			public PlayerMovementSample(float timestamp, Vector3 position)
			{
				//IL_0008: Unknown result type (might be due to invalid IL or missing references)
				//IL_0009: Unknown result type (might be due to invalid IL or missing references)
				Timestamp = timestamp;
				Position = position;
			}
		}

		private const int StateRoaming = 0;

		private const int StateApproach = 1;

		private const int StateChecking = 2;

		private const int StateVideo = 3;

		private const int StateAttack = 4;

		private const int StateLeave = 5;

		private const int StateDead = 6;

		private const float StopSampleIntervalSeconds = 0.1f;

		private const float AttackDamage = 25f;

		private const float AttackCooldown = 1.4f;

		private const float AttackRange = 2.2f;

		private const int FlyingTVHealth = 6;

		private const float VoiceToVideoGapSeconds = 0.15f;

		private const float PlaybackStartLeadSeconds = 0.35f;

		private const float VideoNoncomplianceGraceSeconds = 5f;

		private const float YoutubeResolutionTimeoutSeconds = 90f;

		private const float VideoPrepareTimeoutSeconds = 20f;

		private const int StaticTextureWidth = 256;

		private const int StaticTextureHeight = 144;

		private const int StaticFrameCount = 12;

		private const float StaticFrameIntervalSeconds = 1f / 12f;

		private const float RoamSearchWidth = 70f;

		private const float RoamSearchPrecision = 4f;

		private const float RoamSearchRetargetMinSeconds = 3.5f;

		private const float RoamSearchRetargetMaxSeconds = 7.5f;

		private const float HoverBobSpeed = 1.2f;

		private const float HoverBobAmplitude = 0.16f;

		private const float CeilingClearance = 0.6f;

		private const float HoverProbeIntervalSeconds = 0.1f;

		private const float NavMeshRepairIntervalSeconds = 1f;

		private const float PositionSyncThreshold = 0.3f;

		private const float TargetStoppingDistance = 0.6f;

		private const float DamageSlowPerHit = 0.09f;

		private const float MinDamageSpeedMultiplier = 0.55f;

		private const float DamageWobblePerHit = 0.2f;

		private const float MaxDamageWobble = 1.1f;

		private const float DeathExplosionKnockbackRadius = 10f;

		private const float DeathExplosionMaxKnockback = 34f;

		private const float DeathExplosionMinKnockback = 12f;

		private const float DeathDespawnDelaySeconds = 0.35f;

		private const float DamageStunFreezeSeconds = 1f;

		private const float DamageFreezeGraceSeconds = 1.5f;

		private const float AttackVerticalTolerance = 1.6f;

		private const float ApproachProgressStep = 1f;

		private const float ApproachKeepUpSlack = 2f;

		private const float ApproachNoProgressSeconds = 8f;

		private const float UnreachableGiveUpSeconds = 3f;

		private const float UnreachableIgnoreDetectionSeconds = 20f;

		private const float LeaveSightHalfAngle = 70f;

		private const int LeaveSightRange = 60;

		private const float NoiseMinLoudness = 0.5f;

		private const float NoiseHearingRange = 20f;

		private const float NoiseMemorySeconds = 3f;

		private const float NoiseReseedCooldownSeconds = 4f;

		private const int NoiseMaxRepeatsInOneSpot = 10;

		private const float NoiseSearchWidth = 35f;

		private const int VoiceGreeting = 0;

		private const int VoiceNoncompliance = 1;

		private const int VoiceCompliance = 2;

		private const int NoPlayerSlot = -1;

		private const string EmbeddedScreenSurfaceName = "FlyingTVEmbeddedScreenSurface";

		internal const float BodyColliderRadius = 0.65f;

		internal const float BodyColliderHeight = 1.35f;

		private static readonly int MovingHash = Animator.StringToHash("Moving");

		private static readonly string[] VideoExtensions = new string[6] { ".mp4", ".webm", ".mov", ".m4v", ".ogv", ".avi" };

		private static readonly int[] ScreenTexturePropertyIds = new int[6]
		{
			Shader.PropertyToID("_BaseColorMap"),
			Shader.PropertyToID("_UnlitColorMap"),
			Shader.PropertyToID("_EmissiveColorMap"),
			Shader.PropertyToID("_MainTex"),
			Shader.PropertyToID("_BaseMap"),
			Shader.PropertyToID("_EmissionMap")
		};

		private static Texture2D[] s_staticFrames;

		public Transform visualRoot;

		public Renderer screenRenderer;

		public AudioSource videoAudioSource;

		public AudioClip greetingsClip;

		public AudioClip noncomplianceClip;

		public AudioClip complianceClip;

		public AudioClip propellerLoopClip;

		public AISearchRoutine facilitySearch = new AISearchRoutine();

		private AudioSource _voiceSource;

		private AudioSource _propellerSource;

		private Coroutine _checkRoutine;

		private Coroutine _videoRoutine;

		private Vector3 _leaveDestination;

		private Vector3 _lastKnownTargetPosition;

		private Quaternion _videoHoldRotation;

		private float _leaveDeadline;

		private float _leaveMovementStartTime;

		private float _nextAttackTime;

		private float _serverVideoEndTime;

		private float _serverNoncomplianceEnableTime = float.PositiveInfinity;

		private float _lastVoiceStartTime;

		private float _nextRoamSearchRetargetTime;

		private float _roamAngle;

		private int _damageHitCount;

		private bool _checkActive;

		private bool _videoActive;

		private bool _selectedVideoPlaying;

		private bool _destroying;

		private bool _leaveMovementStarted;

		private bool _deathExplosionTriggered;

		private Coroutine _deathDespawnRoutine;

		private string _videoName = string.Empty;

		private float _forcedDurationSeconds;

		private Vector3 _lastPosition;

		private Vector3 _visualBaseLocalPosition;

		private bool _hasVisualBaseLocalPosition;

		private float _hoverHeight;

		private float _nextNavMeshRepairTime;

		private float _attackLostAggroSince = -1f;

		private float _videoNoncomplianceSince = -1f;

		private float _ignoreDetectionUntil;

		private float _damageStunUntil;

		private float _preDamageStunAnimatorSpeed = 1f;

		private bool _hasMovingParameter;

		private bool _damageStunFrozen;

		private AudioClip _lastVoiceClip;

		private float _videoPresentationStartTime;

		private bool _hasPendingSearchSeed;

		private Vector3 _pendingSearchSeed;

		private float _pendingSearchWidth;

		private int _assignedPlayerIndex = -1;

		private bool _hiddenFromLocalPlayer;

		private Renderer[] _visibilityRenderers;

		private readonly ServerOwnershipGuard _ownership = new ServerOwnershipGuard();

		private readonly NoiseMemory _noiseMemory = new NoiseMemory();

		private float _nextNoiseReseedTime;

		private bool _audioRouted;

		private bool _playbackBroadcast;

		private bool _targetInSight;

		private float _approachBestDistance = float.PositiveInfinity;

		private float _approachProgressSince;

		private float _unreachableSince = -1f;

		private float _checkLookAwaySince = -1f;

		private int _appliedAgentState = -1;

		private int _appliedAgentHitCount = -1;

		private float _nextHoverProbeTime;

		private float _hoverTargetHeight;

		private float _appliedPropellerVolume = -1f;

		private float _damageFreezeImmuneUntil;

		private readonly NetworkVariable<int> _networkTargetSlot = new NetworkVariable<int>(-1, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)0);

		private readonly NetworkVariable<bool> _networkVisibleOnlyToTarget = new NetworkVariable<bool>(false, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)0);

		private CapsuleCollider _bodyCollider;

		private Rigidbody _bodyRigidbody;

		private readonly List<PlayerMovementSample> _playerMovementSamples = new List<PlayerMovementSample>();

		private Material _screenMaterial;

		private Material _screenBlankMaterial;

		private int _screenMaterialIndex = -1;

		private readonly List<ScreenMaterialTarget> _screenMaterialTargets = new List<ScreenMaterialTarget>();

		private bool _screenTargetsCollected;

		private bool _screenMaterialApplied;

		private bool _missingScreenTargetLogged;

		private VideoPlayer _videoPlayer;

		private Coroutine _playbackRoutine;

		private RenderTexture _renderTexture;

		private Texture2D _fallbackTexture;

		private bool _staticPlaying;

		private float _nextStaticFrameTime;

		private int _staticFrameIndex;

		private bool _videoPausedForFreeze;

		private float _videoFreezePausedSeconds;

		private float _localVideoEndTime;

		private string _leasedVideoPath;

		private float FollowDistance => Mathf.Max(1f, FlyingTVConfig.FollowDistance.Value);

		private float PlayerStopWindowSeconds => Mathf.Max(0.1f, 1f);

		private float PlayerStopThreshold => 0.35f;

		private float VideoNoncomplianceDistance => Mathf.Max(FollowDistance, FlyingTVConfig.VideoNoncomplianceDistance.Value);

		private float TurnAwayAngleThreshold => Mathf.Clamp(FlyingTVConfig.TurnAwayAngleThreshold.Value, 10f, 89f);

		private float VideoNoncomplianceSustainSeconds => Mathf.Max(0f, FlyingTVConfig.VideoNoncomplianceSustainSeconds.Value);

		private float ApproachSpeed => Mathf.Max(1f, FlyingTVConfig.ApproachSpeed.Value);

		private float LeaveSpeed => 7f;

		private float ChaseLoseAggroDistance => 28f;

		private float ChaseLoseAggroSeconds => 4f;

		private float ApproachLoseAggroDistance => Mathf.Max(FlyingTVConfig.DetectionRange.Value + 5f, 45f);

		private float ApproachLoseAggroSeconds => 8f;

		private float ConfiguredHoverHeight => 1.9f;

		private float RoamSpeed => Mathf.Max(0.1f, FlyingTVConfig.RoamSpeed.Value);

		private float ChaseSpeed => Mathf.Max(0.1f, FlyingTVConfig.ChaseSpeed.Value);

		private float DamageSpeedMultiplier => Mathf.Max(0.55f, 1f - (float)_damageHitCount * 0.09f);

		private float DamageWobbleAmount => Mathf.Min(1.1f, (float)_damageHitCount * 0.2f);

		private bool IsFrozen
		{
			get
			{
				if (!((EnemyAI)(object)this).IsStunned())
				{
					return Time.time < _damageStunUntil;
				}
				return true;
			}
		}

		private bool AgentReady
		{
			get
			{
				if ((Object)(object)base.agent != (Object)null && ((Behaviour)base.agent).enabled)
				{
					return base.agent.isOnNavMesh;
				}
				return false;
			}
		}

		public override void OnNetworkSpawn()
		{
			//IL_013e: Unknown result type (might be due to invalid IL or missing references)
			((NetworkBehaviour)this).OnNetworkSpawn();
			_hoverHeight = ConfiguredHoverHeight;
			_hoverTargetHeight = _hoverHeight;
			EnsureNavigationAgent();
			ResolveReferences();
			EnsureBehaviourStates();
			ConfigureSearchDefaults();
			_voiceSource = EnsureAudioSource(base.creatureVoice, "FlyingTVVoice", 34f);
			base.creatureVoice = _voiceSource;
			_propellerSource = EnsureAudioSource(_propellerSource, "FlyingTVPropellerLoop", 38f);
			_audioRouted = RouteAudioSources();
			EnsurePropellerLoopPlaying();
			_staticFrameIndex = Random.Range(0, 12);
			StartStaticPlayback();
			_roamAngle = Random.Range(0f, 360f);
			if (((NetworkBehaviour)this).IsServer)
			{
				_videoName = FlyingTVConfig.ResolveVideoSource();
				_forcedDurationSeconds = ((FlyingTVConfig.PlaybackDurationSeconds != null) ? Mathf.Max(0f, FlyingTVConfig.PlaybackDurationSeconds.Value) : 0f);
				_networkVisibleOnlyToTarget.Value = FlyingTVConfig.VisibleOnlyToTarget != null && FlyingTVConfig.VisibleOnlyToTarget.Value;
				SnapToNavMesh(logAlways: true);
				base.currentBehaviourStateIndex = 0;
				((EnemyAI)this).SwitchToBehaviourState(0);
				base.movingTowardsTargetPlayer = false;
				base.moveTowardsDestination = true;
				StartFacilitySearch(((Component)this).transform.position, 70f);
			}
		}

		public override void Start()
		{
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			((EnemyAI)this).Start();
			EnsureNavigationAgent();
			base.updatePositionThreshold = 0.3f;
			Plugin.EnsureScanNode(((Component)this).gameObject);
			EnsureEyeTransform();
			EnsureCollisionBody();
			ConfigureSearchDefaults();
			base.enemyHP = 6;
			_lastPosition = ((Component)this).transform.position;
			if (((NetworkBehaviour)this).IsServer)
			{
				PrefetchYoutubePlaybackClientRpc(_videoName);
			}
		}

		public override void FinishedCurrentSearchRoutine()
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			((EnemyAI)this).FinishedCurrentSearchRoutine();
			if (base.currentSearch == facilitySearch && base.currentBehaviourStateIndex == 0)
			{
				StartFacilitySearch(((Component)this).transform.position, 70f);
			}
		}

		private void EnsureNavigationAgent()
		{
			if ((Object)(object)base.agent == (Object)null)
			{
				base.agent = ((Component)this).GetComponentInChildren<NavMeshAgent>(true);
			}
			if ((Object)(object)base.agent == (Object)null)
			{
				base.agent = ((Component)this).gameObject.AddComponent<NavMeshAgent>();
			}
			base.agent.updatePosition = true;
			base.agent.updateRotation = false;
			base.agent.updateUpAxis = false;
			ConfigureAgentBody();
			if (((NetworkBehaviour)this).IsServer)
			{
				((Behaviour)base.agent).enabled = true;
				base.agent.baseOffset = _hoverHeight;
				_appliedAgentState = -1;
			}
		}

		private void ConfigureAgentBody()
		{
			base.agent.acceleration = 10f;
			base.agent.angularSpeed = 360f;
			base.agent.radius = 0.65f;
			base.agent.height = 1.35f;
			base.agent.autoBraking = true;
			base.agent.autoRepath = true;
			base.agent.autoTraverseOffMeshLink = true;
			base.agent.obstacleAvoidanceType = (ObstacleAvoidanceType)4;
			base.agent.avoidancePriority = 45;
			if (base.agent.areaMask == 0)
			{
				base.agent.areaMask = -1;
			}
			if (base.openDoorSpeedMultiplier <= 0f)
			{
				base.openDoorSpeedMultiplier = 1f;
			}
		}

		private void ApplyAgentStateSettings()
		{
			int currentBehaviourStateIndex = base.currentBehaviourStateIndex;
			if ((currentBehaviourStateIndex != _appliedAgentState || _damageHitCount != _appliedAgentHitCount) && !((Object)(object)base.agent == (Object)null) && ((Behaviour)base.agent).enabled)
			{
				_appliedAgentState = currentBehaviourStateIndex;
				_appliedAgentHitCount = _damageHitCount;
				float num;
				switch (currentBehaviourStateIndex)
				{
				case 1:
				case 2:
					num = ApproachSpeed;
					break;
				case 4:
					num = ChaseSpeed;
					break;
				case 5:
					num = LeaveSpeed;
					break;
				default:
					num = RoamSpeed;
					break;
				}
				base.agent.speed = Mathf.Max(0.1f, num * DamageSpeedMultiplier);
				base.agent.stoppingDistance = ((currentBehaviourStateIndex == 0 || currentBehaviourStateIndex == 5) ? 0f : 0.6f);
			}
		}

		private void ApplyHoverHeight()
		{
			//IL_004a: 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)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)base.agent == (Object)null || !((Behaviour)base.agent).enabled)
			{
				return;
			}
			if (Time.time >= _nextHoverProbeTime)
			{
				_nextHoverProbeTime = Time.time + 0.1f;
				float num = ConfiguredHoverHeight;
				Vector3 val = ((Component)this).transform.position - Vector3.up * base.agent.baseOffset;
				float num2 = num + 0.675f + 0.6f;
				RaycastHit val2 = default(RaycastHit);
				if (Physics.Raycast(val + Vector3.up * 0.1f, Vector3.up, ref val2, num2, GetWorldCollisionMask(), (QueryTriggerInteraction)1))
				{
					num = Mathf.Clamp(((RaycastHit)(ref val2)).distance + 0.1f - 0.675f - 0.6f, 0f, num);
				}
				_hoverTargetHeight = num;
			}
			if (_hoverHeight != _hoverTargetHeight)
			{
				_hoverHeight = Mathf.MoveTowards(_hoverHeight, _hoverTargetHeight, Mathf.Max(0.5f, _hoverTargetHeight) * 2f * Time.deltaTime);
				base.agent.baseOffset = _hoverHeight;
			}
		}

		private void RepairOffNavMeshIfNeeded()
		{
			if (((NetworkBehaviour)this).IsServer && !((Object)(object)base.agent == (Object)null) && !(Time.time < _nextNavMeshRepairTime) && (!((Behaviour)base.agent).enabled || !base.agent.isOnNavMesh))
			{
				_nextNavMeshRepairTime = Time.time + 1f;
				SnapToNavMesh(logAlways: false);
			}
		}

		private bool SnapToNavMesh(bool logAlways)
		{
			//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_005c: 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)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: 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_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			if (!((NetworkBehaviour)this).IsServer || (Object)(object)base.agent == (Object)null)
			{
				return false;
			}
			if (((Behaviour)base.agent).enabled && base.agent.isOnNavMesh)
			{
				return true;
			}
			Vector3 position = ((Component)this).transform.position;
			int areaMask = ((base.agent.areaMask == 0) ? (-1) : base.agent.areaMask);
			if (TrySampleNavMesh(position, 14f, areaMask, out var position2) || TrySampleNearestAINode(position, areaMask, out position2) || TrySampleNavMesh(position, 80f, -1, out position2))
			{
				((Behaviour)base.agent).enabled = false;
				((Component)this).transform.position = position2;
				((Behaviour)base.agent).enabled = true;
				bool flag = base.agent.Warp(position2);
				if (logAlways)
				{
					ManualLogSource log = Plugin.Log;
					if (log != null)
					{
						log.LogInfo((object)$"[FlyingTV] Placed on the NavMesh at {position2} (from {position}, warp={flag}).");
					}
				}
				if (!flag)
				{
					return base.agent.isOnNavMesh;
				}
				return true;
			}
			ManualLogSource log2 = Plugin.Log;
			if (log2 != null)
			{
				log2.LogWarning((object)$"[FlyingTV] No NavMesh point found near spawn at {position}; the TV cannot path.");
			}
			return false;
		}

		private static bool TrySampleNavMesh(Vector3 candidate, float radius, int areaMask, out Vector3 position)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			NavMeshHit val = default(NavMeshHit);
			if (NavMesh.SamplePosition(candidate, ref val, Mathf.Max(0.25f, radius), areaMask))
			{
				position = ((NavMeshHit)(ref val)).position;
				return true;
			}
			position = Vector3.zero;
			return false;
		}

		private bool TrySampleNearestAINode(Vector3 from, int areaMask, out Vector3 position)
		{
			//IL_0001: 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_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_0043: 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_0077: Unknown result type (might be due to invalid IL or missing references)
			position = Vector3.zero;
			GameObject[] allAINodes = base.allAINodes;
			if (allAINodes == null || allAINodes.Length == 0)
			{
				return false;
			}
			GameObject val = null;
			float num = float.PositiveInfinity;
			foreach (GameObject val2 in allAINodes)
			{
				if (!((Object)(object)val2 == (Object)null))
				{
					Vector3 val3 = val2.transform.position - from;
					float sqrMagnitude = ((Vector3)(ref val3)).sqrMagnitude;
					if (sqrMagnitude < num)
					{
						num = sqrMagnitude;
						val = val2;
					}
				}
			}
			if ((Object)(object)val != (Object)null)
			{
				return TrySampleNavMesh(val.transform.position, 12f, areaMask, out position);
			}
			return false;
		}

		private void EnsureEyeTransform()
		{
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: 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_002d: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)base.eye == (Object)null)
			{
				Transform val = ((Component)this).transform.Find("FlyingTVEye");
				if ((Object)(object)val == (Object)null)
				{
					val = new GameObject("FlyingTVEye").transform;
					val.SetParent(((Component)this).transform, false);
				}
				base.eye = val;
			}
			base.eye.localPosition = Vector3.zero;
			base.eye.localRotation = Quaternion.LookRotation(FlyingTVManager.GetScreenLocalFacingDirection(), Vector3.up);
		}

		private void EnsureCollisionBody()
		{
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			_bodyCollider = ((Component)this).GetComponent<CapsuleCollider>() ?? ((Component)this).gameObject.AddComponent<CapsuleCollider>();
			((Collider)_bodyCollider).enabled = true;
			((Collider)_bodyCollider).isTrigger = false;
			_bodyCollider.direction = 1;
			_bodyCollider.center = Vector3.zero;
			_bodyCollider.radius = 0.65f;
			_bodyCollider.height = 1.35f;
			_bodyRigidbody = ((Component)this).GetComponent<Rigidbody>() ?? ((Component)this).gameObject.AddComponent<Rigidbody>();
			_bodyRigidbody.isKinematic = true;
			_bodyRigidbody.useGravity = false;
			_bodyRigidbody.detectCollisions = true;
			_bodyRigidbody.collisionDetectionMode = (CollisionDetectionMode)3;
		}

		public override void Update()
		{
			_ownership.Ensure((EnemyAI)(object)this, Plugin.Log);
			((EnemyAI)this).Update();
			if (!_audioRouted)
			{
				_audioRouted = RouteAudioSources();
			}
			UpdateStaticPlayback();
			if (base.isEnemyDead)
			{
				return;
			}
			EnsurePropellerLoopPlaying();
			if (((NetworkBehaviour)this).IsServer)
			{
				SyncTargetSlot();
			}
			UpdateLocalVisibility();
			if (ApplyDamageStunFreeze())
			{
				PauseLocalVideoTimers(Time.deltaTime);
				if (((NetworkBehaviour)this).IsServer)
				{
					PauseServerTimers(Time.deltaTime);
				}
				return;
			}
			UpdateAnimation();
			TickVisualHover();
			if (((NetworkBehaviour)this).IsServer)
			{
				UpdateServerMovement();
			}
		}

		public override void DoAIInterval()
		{
			((EnemyAI)this).DoAIInterval();
			if (((NetworkBehaviour)this).IsServer && !base.isEnemyDead && !((Object)(object)StartOfRound.Instance == (Object)null) && !StartOfRound.Instance.allPlayersDead && !IsFrozen)
			{
				int currentBehaviourStateIndex = base.currentBehaviourStateIndex;
				switch (currentBehaviourStateIndex)
				{
				case 0:
					EvaluateRoaming();
					break;
				case 5:
					EvaluateLeave();
					break;
				case 1:
				case 2:
				case 3:
				case 4:
					EvaluateEngagement(currentBehaviourStateIndex);
					break;
				}
			}
		}

		public override void DetectNoise(Vector3 noisePosition, float noiseLoudness, int timesPlayedInOneSpot = 0, int noiseID = 0)
		{
			//IL_0001: 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)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			((EnemyAI)this).DetectNoise(noisePosition, noiseLoudness, timesPlayedInOneSpot, noiseID);
			if (((NetworkBehaviour)this).IsServer && !base.isEnemyDead && !IsFrozen && timesPlayedInOneSpot <= 10 && base.currentBehaviourStateIndex == 0)
			{
				_noiseMemory.Record(noisePosition, noiseLoudness, 0.5f, ((Component)this).transform.position, 20f);
			}
		}

		private void EvaluateRoaming()
		{
			if (Time.time >= _ignoreDetectionUntil)
			{
				PlayerControllerB val = FindDetectedPlayer();
				if ((Object)(object)val != (Object)null)
				{
					base.targetPlayer = val;
					StartApproach();
					return;
				}
			}
			TryReseedSearchAtNoise();
		}

		private void TryReseedSearchAtNoise()
		{
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			if (!(Time.time < _nextNoiseReseedTime) && CanUseVanillaSearch() && _noiseMemory.TryTake(3f, out var position))
			{
				_nextNoiseReseedTime = Time.time + 4f;
				StartFacilitySearch(position, 35f, recentre: true);
			}
		}

		private void EvaluateEngagement(int state)
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			PlayerControllerB targetPlayer = base.targetPlayer;
			if (!FlyingTVManager.IsValidLivingPlayer(targetPlayer) || !((EnemyAI)this).PlayerIsTargetable(targetPlayer, false, false, true))
			{
				LoseAttackAggro(ChaseLoseAggroSeconds);
				return;
			}
			_lastKnownTargetPosition = ((Component)targetPlayer).transform.position;
			_targetInSight = HasLineOfSightToTarget(targetPlayer);
			switch (state)
			{
			case 3:
				return;
			case 4:
				if (ShouldLoseAggro(targetPlayer, ChaseLoseAggroDistance, ChaseLoseAggroSeconds))
				{
					LoseAttackAggro(ChaseLoseAggroSeconds);
				}
				else
				{
					TryStrike(targetPlayer);
				}
				return;
			}
			if (ShouldLoseAggro(targetPlayer, ApproachLoseAggroDistance, ApproachLoseAggroSeconds))
			{
				LoseAttackAggro(ChaseLoseAggroSeconds);
			}
			else if (IsApproachStalled(targetPlayer))
			{
				LoseAttackAggro(20f, sweepLastKnown: false);
			}
		}

		private bool IsApproachStalled(PlayerControllerB target)
		{
			//IL_005e: 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_006e: 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)
			float time = Time.time;
			if (!IsPathEndAwayFrom(target))
			{
				_unreachableSince = -1f;
			}
			else if (_unreachableSince < 0f)
			{
				_unreachableSince = time;
			}
			else if (time - _unreachableSince >= 3f)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogInfo((object)"[FlyingTV] Target is unreachable (path ends away from them); giving up.");
				}
				return true;
			}
			Vector3 val = ((Component)target).transform.position - ((Component)this).transform.position;
			val.y = 0f;
			float magnitude = ((Vector3)(ref val)).magnitude;
			if (magnitude <= FollowDistance + 2f && _targetInSight)
			{
				_approachBestDistance = magnitude;
				_approachProgressSince = time;
				return false;
			}
			if (magnitude < _approachBestDistance - 1f)
			{
				_approachBestDistance = magnitude;
				_approachProgressSince = time;
				return false;
			}
			if (time - _approachProgressSince < 8f)
			{
				return false;
			}
			ManualLogSource log2 = Plugin.Log;
			if (log2 != null)
			{
				log2.LogInfo((object)$"[FlyingTV] Approach made no progress for {8f:0} s; giving up.");
			}
			return true;
		}

		private void ResetApproachProgress()
		{
			_approachBestDistance = float.PositiveInfinity;
			_approachProgressSince = Time.time;
			_unreachableSince = -1f;
		}

		private bool IsPathEndAwayFrom(PlayerControllerB target)
		{
			//IL_0025: 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_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Invalid comparison between Unknown and I4
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			if (!AgentReady || !base.movingTowardsTargetPlayer || base.agent.pathPending)
			{
				return false;
			}
			NavMeshPathStatus pathStatus = base.agent.pathStatus;
			if ((int)pathStatus == 2)
			{
				return true;
			}
			if ((int)pathStatus == 0 || !base.agent.hasPath)
			{
				return false;
			}
			Vector3 pathEndPosition = base.agent.pathEndPosition;
			Vector3 position = ((Component)target).transform.position;
			if (Mathf.Abs(pathEndPosition.y - position.y) > 1.6f)
			{
				return true;
			}
			pathEndPosition.y = position.y;
			float num = FollowDistance + 1f;
			Vector3 val = pathEndPosition - position;
			return ((Vector3)(ref val)).sqrMagnitude > num * num;
		}

		private void TryStrike(PlayerControllerB target)
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			if (!(Time.time < _nextAttackTime) && IsTargetInStrikeReach(target))
			{
				_nextAttackTime = Time.time + 1.4f;
				ApplyAttackDamageClientRpc(target.actualClientId, 25, VictimRpc.TargetOnly(target));
			}
		}

		private void EvaluateLeave()
		{
			if (_leaveMovementStarted && (Time.time >= _leaveDeadline || !IsInViewOfAudience()))
			{
				DespawnSelf();
			}
		}

		private bool IsInViewOfAudience()
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts;
			if (allPlayerScripts == null)
			{
				return false;
			}
			bool value = _networkVisibleOnlyToTarget.Value;
			int value2 = _networkTargetSlot.Value;
			Vector3 position = ((Component)this).transform.position;
			foreach (PlayerControllerB val in allPlayerScripts)
			{
				if (FlyingTVManager.IsValidLivingPlayer(val) && (!value || (int)val.playerClientId == value2) && val.HasLineOfSightToPosition(position, 70f, 60, -1f, -1))
				{
					return true;
				}
			}
			return false;
		}

		private void DespawnSelf()
		{
			if ((Object)(object)((NetworkBehaviour)this).NetworkObject != (Object)null && ((NetworkBehaviour)this).NetworkObject.IsSpawned)
			{
				((NetworkBehaviour)this).NetworkObject.Despawn(true);
			}
		}

		public override void HitEnemy(int force = 1, PlayerControllerB playerWhoHit = null, bool playHitSFX = false, int hitID = -1)
		{
			((EnemyAI)this).HitEnemy(force, playerWhoHit, playHitSFX, hitID);
			if (base.isEnemyDead)
			{
				return;
			}
			base.enemyHP -= Mathf.Max(1, force);
			RegisterDamageHit();
			BeginDamageStunFreeze();
			if (base.enemyHP <= 0)
			{
				if (((NetworkBehaviour)this).IsOwner)
				{
					((EnemyAI)this).KillEnemyOnOwnerClient(false);
				}
			}
			else if (((NetworkBehaviour)this).IsServer && (Object)(object)playerWhoHit != (Object)null)
			{
				TriggerNonComplianceFromAttack(playerWhoHit);
			}
		}

		public override void KillEnemy(bool destroy = false)
		{
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			if (!base.isEnemyDead)
			{
				base.isEnemyDead = true;
				_destroying = true;
				StopAllServerRoutines();
				CleanupVideoResources();
				StopPropellerLoop();
				ClearDamageStunFreeze();
				if ((Object)(object)_voiceSource != (Object)null)
				{
					_voiceSource.Stop();
				}
				TriggerDeathExplosionPresentation(((Component)this).transform.position);
				((EnemyAI)this).SwitchToBehaviourStateOnLocalClient(6);
				base.movingTowardsTargetPlayer = false;
				base.moveTowardsDestination = false;
				((EnemyAI)this).KillEnemy(destroy);
				if (((NetworkBehaviour)this).IsServer && _deathDespawnRoutine == null && (Object)(object)((NetworkBehaviour)this).NetworkObject != (Object)null && ((NetworkBehaviour)this).NetworkObject.IsSpawned)
				{
					_deathDespawnRoutine = ((MonoBehaviour)this).StartCoroutine(DeathDespawnRoutine());
				}
			}
		}

		public override void OnDestroy()
		{
			_destroying = true;
			CleanupVideoResources();
			((EnemyAI)this).OnDestroy();
		}

		internal void InitializeServer(int targetPlayerIndex, string videoName, float durationSeconds)
		{
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			if (((NetworkBehaviour)this).IsServer)
			{
				ResolveReferences();
				_videoName = videoName ?? string.Empty;
				_forcedDurationSeconds = Mathf.Max(0f, durationSeconds);
				PlayerControllerB player = FlyingTVManager.GetPlayer(targetPlayerIndex);
				if (FlyingTVManager.IsValidLivingPlayer(player))
				{
					_assignedPlayerIndex = targetPlayerIndex;
					_lastKnownTargetPosition = ((Component)player).transform.position;
					StartFacilitySearch(((Component)player).transform.position, 70f);
				}
			}
		}

		internal bool IsEngagedWith(int playerIndex)
		{
			if (!((NetworkBehaviour)this).IsSpawned || base.isEnemyDead || base.currentBehaviourStateIndex == 5)
			{
				return false;
			}
			if (_assignedPlayerIndex != playerIndex)
			{
				if ((Object)(object)base.targetPlayer != (Object)null)
				{
					return (int)base.targetPlayer.playerClientId == playerIndex;
				}
				return false;
			}
			return true;
		}

		private void SyncTargetSlot()
		{
			int num = (((Object)(object)base.targetPlayer != (Object)null) ? ((int)base.targetPlayer.playerClientId) : _assignedPlayerIndex);
			if (_networkTargetSlot.Value != num)
			{
				_networkTargetSlot.Value = num;
			}
		}

		private void UpdateLocalVisibility()
		{
			ApplyLocalVisibility(_networkTargetSlot.Value);
		}

		private void ApplyLocalVisibility(int audienceSlot)
		{
			PlayerControllerB val = (((Object)(object)GameNetworkManager.Instance != (Object)null) ? GameNetworkManager.Instance.localPlayerController : null);
			bool flag = _networkVisibleOnlyToTarget.Value && ((Object)(object)val == (Object)null || audienceSlot != (int)val.playerClientId);
			if (flag == _hiddenFromLocalPlayer)
			{
				return;
			}
			_hiddenFromLocalPlayer = flag;
			if (_visibilityRenderers == null)
			{
				_visibilityRenderers = ((Component)this).GetComponentsInChildren<Renderer>(true);
			}
			for (int i = 0; i < _visibilityRenderers.Length; i++)
			{
				if ((Object)(object)_visibilityRenderers[i] != (Object)null)
				{
					_visibilityRenderers[i].forceRenderingOff = flag;
				}
			}
			if ((Object)(object)_voiceSource != (Object)null)
			{
				_voiceSource.mute = flag;
			}
			if ((Object)(object)_propellerSource != (Object)null)
			{
				_propellerSource.mute = flag;
			}
			if ((Object)(object)videoAudioSource != (Object)null)
			{
				videoAudioSource.mute = flag;
			}
		}

		private bool LocalPlayerIsTarget()
		{
			PlayerControllerB val = (((Object)(object)GameNetworkManager.Instance != (Object)null) ? GameNetworkManager.Instance.localPlayerController : null);
			if ((Object)(object)val == (Object)null)
			{
				return false;
			}
			if (!((NetworkBehaviour)this).IsServer)
			{
				return _networkTargetSlot.Value == (int)val.playerClientId;
			}
			return (Object)(object)base.targetPlayer == (Object)(object)val;
		}

		private void PauseServerTimers(float deltaTime)
		{
			_nextAttackTime += deltaTime;
			if (_attackLostAggroSince >= 0f)
			{
				_attackLostAggroSince += deltaTime;
			}
			_approachProgressSince += deltaTime;
			if (_unreachableSince >= 0f)
			{
				_unreachableSince += deltaTime;
			}
			if (_videoActive)
			{
				_videoPresentationStartTime += deltaTime;
				_serverVideoEndTime += deltaTime;
				_serverNoncomplianceEnableTime += deltaTime;
				if (_videoNoncomplianceSince >= 0f)
				{
					_videoNoncomplianceSince += deltaTime;
				}
			}
			if (base.currentBehaviourStateIndex == 5)
			{
				_leaveMovementStartTime += deltaTime;
				_leaveDeadline += deltaTime;
			}
		}

		private void StartApproach()
		{
			if (base.currentBehaviourStateIndex == 0)
			{
				StopSearchIfNeeded(clear: false);
				base.movingTowardsTargetPlayer = true;
				base.moveTowardsDestination = true;
				if ((Object)(object)base.targetPlayer != (Object)null)
				{
					((EnemyAI)this).SetMovingTowardsTargetPlayer(base.targetPlayer);
				}
				((EnemyAI)(object)this).ReleaseAgent();
				_targetInSight = true;
				ResetApproachProgress();
				((EnemyAI)this).SwitchToBehaviourState(1);
				PlayVoiceLine(0);
			}
		}

		private void StartCheckPhase()
		{
			if (!_checkActive)
			{
				_checkActive = true;
				_playerMovementSamples.Clear();
				_checkLookAwaySince = -1f;
				base.movingTowardsTargetPlayer = false;
				base.moveTowardsDestination = false;
				StopAgentForHold();
				((EnemyAI)this).SwitchToBehaviourState(2);
				_checkRoutine = ((MonoBehaviour)this).StartCoroutine(CheckRoutine());
			}
		}

		private IEnumerator CheckRoutine()
		{
			while (((NetworkBehaviour)this).IsServer && !base.isEnemyDead && _checkActive && base.currentBehaviourStateIndex == 2 && FlyingTVManager.IsValidLivingPlayer(base.targetPlayer))
			{
				if (IsFrozen)
				{
					_playerMovementSamples.Clear();
					_checkLookAwaySince = -1f;
					yield return null;
					continue;
				}
				PlayerControllerB targetPlayer = base.targetPlayer;
				float time = Time.time;
				float playerStopWindowSeconds = PlayerStopWindowSeconds;
				Vector3 position = ((Component)targetPlayer).transform.position;
				_playerMovementSamples.Add(new PlayerMovementSample(time, position));
				float num = time - playerStopWindowSeconds;
				while (_playerMovementSamples.Count > 1 && _playerMovementSamples[1].Timestamp <= num)
				{
					_playerMovementSamples.RemoveAt(0);
				}
				bool flag = _playerMovementSamples[0].Timestamp <= num;
				if (flag)
				{
					for (int i = 0; i < _playerMovementSamples.Count; i++)
					{
						if (Vector3.Distance(position, _playerMovementSamples[i].Position) > PlayerStopThreshold)
						{
							flag = false;
							break;
						}
					}
				}
				if (flag && IsWithinFollowRange(targetPlayer))
				{
					bool flag2 = !IsPlayerLookingAwayFromTV(targetPlayer, TurnAwayAngleThreshold);
					if (!flag2 && _checkLookAwaySince < 0f)
					{
						_checkLookAwaySince = time;
					}
					if (flag2 || time - _checkLookAwaySince >= VideoNoncomplianceSustainSeconds)
					{
						_checkActive = false;
						_checkRoutine = null;
						_playerMovementSamples.Clear();
						_checkLookAwaySince = -1f;
						if (flag2)
						{
							StartVideoPhase();
						}
						else
						{
							StartAttack();
						}
						yield break;
					}
				}
				else
				{
					_checkLookAwaySince = -1f;
				}
				yield return (object)new WaitForSeconds(0.1f);
			}
			_checkActive = false;
			_checkRoutine = null;
			_playerMovementSamples.Clear();
			_checkLookAwaySince = -1f;
		}

		private void StartVideoPhase()
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			if (!_videoActive)
			{
				_videoActive = true;
				_videoNoncomplianceSince = -1f;
				_serverNoncomplianceEnableTime = float.PositiveInfinity;
				_videoHoldRotation = ((Component)this).transform.rotation;
				base.movingTowardsTargetPlayer = false;
				base.moveTowardsDestination = false;
				StopAgentForHold();
				((EnemyAI)this).SwitchToBehaviourState(3);
				float num = ResolveVideoDuration();
				float currentVoiceRemainingSeconds = GetCurrentVoiceRemainingSeconds();
				_serverVideoEndTime = Time.time + currentVoiceRemainingSeconds + num;
				if (_videoRoutine != null)
				{
					((MonoBehaviour)this).StopCoroutine(_videoRoutine);
				}
				_videoRoutine = ((MonoBehaviour)this).StartCoroutine(VideoStartAndMonitorRoutine(currentVoiceRemainingSeconds, num));
			}
		}

		private float ResolveVideoDuration()
		{
			if (_forcedDurationSeconds > 0f)
			{
				return _forcedDurationSeconds;
			}
			return 300f;
		}

		private IEnumerator VideoStartAndMonitorRoutine(float videoStartDelay, float videoDuration)
		{
			_videoPresentationStartTime = Time.time + Mathf.Max(0f, videoStartDelay);
			while (_videoActive && !base.isEnemyDead && (Object)(object)base.targetPlayer != (Object)null && (IsFrozen || Time.time < _videoPresentationStartTime))
			{
				yield return null;
			}
			if (!_videoActive || base.isEnemyDead || (Object)(object)base.targetPlayer == (Object)null)
			{
				_videoRoutine = null;
				yield break;
			}
			if (YoutubeVideoResolver.IsYoutubeUrl(_videoName) && LocalPlayerIsTarget())
			{
				Task<YoutubeVideoStreams> localPrefetchTask = YoutubeVideoResolver.ResolveAsync(_videoName);
				float prefetchDeadline = Time.time + 90f;
				while (_videoActive && !base.isEnemyDead && (Object)(object)base.targetPlayer != (Object)null && (IsFrozen || (!localPrefetchTask.IsCompleted && Time.time < prefetchDeadline)))
				{
					if (IsFrozen)
					{
						prefetchDeadline += Time.deltaTime;
					}
					yield return null;
				}
				if (!_videoActive || base.isEnemyDead || (Object)(object)base.targetPlayer == (Object)null)
				{
					_videoRoutine = null;
					yield break;
				}
				if (!localPrefetchTask.IsCompleted)
				{
					ManualLogSource log = Plugin.Log;
					if (log != null)
					{
						log.LogWarning((object)"[FlyingTV] YouTube prefetch did not finish before the presentation deadline.");
					}
				}
			}
			double playbackStartServerTime = GetSynchronizedServerTime() + 0.3499999940395355;
			_serverVideoEndTime = Time.time + 0.35f + videoDuration;
			_serverNoncomplianceEnableTime = Time.time + 0.35f + 5f;
			StartPlaybackClientRpc(_videoName, _forcedDurationSeconds, playbackStartServerTime);
			_playbackBroadcast = true;
			while (_videoActive && !base.isEnemyDead && (Object)(object)base.targetPlayer != (Object)null)
			{
				if (IsFrozen)
				{
					yield return null;
					continue;
				}
				if (ShouldTriggerVideoNonCompliance(base.targetPlayer))
				{
					_videoActive = false;
					_videoRoutine = null;
					StartAttack();
					yield break;
				}
				if (Time.time >= _serverVideoEndTime)
				{
					CompleteVideoAndLeave();
					_videoRoutine = null;
					yield break;
				}
				yield return (object)new WaitForSeconds(0.25f);
			}
			CompleteVideoAndLeave();
			_videoRoutine = null;
		}

		private void StartAttack()
		{
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			if (base.currentBehaviourStateIndex != 4)
			{
				StopAllServerRoutines();
				StopBroadcastPlayback();
				StopSearchIfNeeded(clear: false);
				base.movingTowardsTargetPlayer = true;
				base.moveTowardsDestination = true;
				if ((Object)(object)base.targetPlayer != (Object)null)
				{
					_lastKnownTargetPosition = ((Component)base.targetPlayer).transform.position;
					((EnemyAI)this).SetMovingTowardsTargetPlayer(base.targetPlayer);
				}
				((EnemyAI)(object)this).ReleaseAgent();
				((EnemyAI)this).SwitchToBehaviourState(4);
				_attackLostAggroSince = -1f;
				PlayVoiceLine(1);
			}
		}

		private void StartLeave(float movementDelaySeconds = 0f)
		{
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: 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_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			if (base.currentBehaviourStateIndex != 5)
			{
				StopAllServerRoutines();
				StopSearchIfNeeded(clear: false);
				base.movingTowardsTargetPlayer = false;
				base.moveTowardsDestination = false;
				((EnemyAI)this).SwitchToBehaviourState(5);
				Vector3 val = (((Object)(object)base.targetPlayer != (Object)null) ? FlyingTVManager.FlatDirection(((Component)this).transform.position - ((Component)base.targetPlayer).transform.position, -((Component)base.targetPlayer).transform.forward) : ((Component)this).transform.forward);
				_leaveDestination = ((Component)this).transform.position + val * 16f;
				if (TrySampleNavMesh(_leaveDestination, 16f, ((Object)(object)base.agent != (Object)null && base.agent.areaMask != 0) ? base.agent.areaMask : (-1), out var position))
				{
					_leaveDestination = position;
				}
				_leaveMovementStartTime = Time.time + Mathf.Max(0f, movementDelaySeconds);
				_leaveDeadline = _leaveMovementStartTime + 10f;
				_leaveMovementStarted = false;
				StopAgentForHold();
				if (movementDelaySeconds <= 0f)
				{
					BeginLeaveMovement();
				}
			}
		}

		private void BeginLeaveMovement()
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			if (_leaveMovementStarted)
			{
				return;
			}
			_leaveMovementStarted = true;
			((EnemyAI)(object)this).ReleaseAgent();
			if (!AgentReady || !((EnemyAI)this).SetDestinationToPosition(_leaveDestination, true))
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogInfo((object)"[FlyingTV] No path to a leave point; despawning in place.");
				}
				DespawnSelf();
			}
		}

		private void TriggerDeathExplosionPresentation(Vector3 position)
		{
			//IL_003d: 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)
			if (!_deathExplosionTriggered)
			{
				_deathExplosionTriggered = true;
				StopLocalPlayback(resumeStatic: false);
				StopPropellerLoop();
				if ((Object)(object)_voiceSource != (Object)null)
				{
					_voiceSource.Stop();
				}
				HideDeathBody();
				SpawnVanillaDeathExplosions(position);
				ApplyLocalDeathExplosionKnockback(position);
			}
		}

		private void SpawnVanillaDeathExplosions(Vector3 position)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: 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_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: 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)
			Vector3 val = position + Vector3.up * 0.7f;
			SpawnVanillaExplosionVisual(val);
			SpawnVanillaExplosionVisual(val + Vector3.up * 0.9f);
			SpawnVanillaExplosionVisual(val - Vector3.up * 0.45f);
		}

		private static void SpawnVanillaExplosionVisual(Vector3 position)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			Landmine.SpawnExplosion(position, true, 0f, 0f, 0, 0f, (GameObject)null, false);
		}

		private void ApplyLocalDeathExplosionKnockback(Vector3 position)
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: 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_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_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: 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_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: 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_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: 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_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			PlayerControllerB val = (((Object)(object)GameNetworkManager.Instance != (Object)null) ? GameNetworkManager.Instance.localPlayerController : null);
			if (!FlyingTVManager.IsValidLivingPlayer(val))
			{
				return;
			}
			Vector3 val2 = ((Component)val).transform.position - position;
			float magnitude = ((Vector3)(ref val2)).magnitude;
			if (!(magnitude > 10f) && !Physics.Linecast(position + Vector3.up * 0.7f, ((Component)val).transform.position + Vector3.up * 1f, GetWorldCollisionMask(), (QueryTriggerInteraction)1))
			{
				val2.y = 0f;
				if (((Vector3)(ref val2)).sqrMagnitude < 0.01f)
				{
					val2 = ((Component)val).transform.forward;
				}
				float num = Mathf.Clamp01(1f - magnitude / 10f);
				Vector3 val3 = ((Vector3)(ref val2)).normalized * Mathf.Lerp(12f, 34f, num) + Vector3.up * Mathf.Lerp(4f, 9f, num);
				val.externalForces += val3;
				if ((Object)(object)val.playerBodyAnimator != (Object)null)
				{
					val.playerBodyAnimator.SetTrigger("Damage");
				}
			}
		}

		private void HideDeathBody()
		{
			Renderer[] componentsInChildren = ((Component)this).GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val in componentsInChildren)
			{
				if (!((Object)(object)val == (Object)null))
				{
					val.enabled = false;
					val.forceRenderingOff = true;
				}
			}
			Collider[] componentsInChildren2 = ((Component)this).GetComponentsInChildren<Collider>(true);
			foreach (Collider val2 in componentsInChildren2)
			{
				if ((Object)(object)val2 != (Object)null)
				{
					val2.enabled = false;
				}
			}
			if ((Object)(object)_bodyRigidbody != (Object)null)
			{
				_bodyRigidbody.detectCollisions = false;
			}
		}

		private IEnumerator DeathDespawnRoutine()
		{
			yield return (object)new WaitForSeconds(0.35f);
			DespawnSelf();
			_deathDespawnRoutine = null;
		}

		private void LoseAttackAggro(float ignoreDetectionSeconds, bool sweepLastKnown = true)
		{
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: 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_0077: 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)
			StopAllServerRoutines();
			StopBroadcastPlayback();
			_attackLostAggroSince = -1f;
			_targetInSight = false;
			_ignoreDetectionUntil = Time.time + ignoreDetectionSeconds;
			Vector3 start = ((!sweepLastKnown || _lastKnownTargetPosition == Vector3.zero) ? ((Component)this).transform.position : _lastKnownTargetPosition);
			base.targetPlayer = null;
			base.movingTowardsTargetPlayer = false;
			base.moveTowardsDestination = true;
			((EnemyAI)(object)this).ReleaseAgent();
			((EnemyAI)this).SwitchToBehaviourState(0);
			StartFacilitySearch(start, 52.5f);
		}

		private void StopBroadcastPlayback()
		{
			if (_playbackBroadcast)
			{
				_playbackBroadcast = false;
				StopPlaybackClientRpc();
			}
		}

		private void StopAllServerRoutines()
		{
			if (_checkRoutine != null)
			{
				((MonoBehaviour)this).StopCoroutine(_checkRoutine);
				_checkRoutine = null;
			}
			if (_videoRoutine != null)
			{
				((MonoBehaviour)this).StopCoroutine(_videoRoutine);
				_videoRoutine = null;
			}
			_checkActive = false;
			_videoActive = false;
			_playerMovementSamples.Clear();
			_videoNoncomplianceSince = -1f;
		}

		private void TriggerNonComplianceFromAttack(PlayerControllerB attacker)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			if (((NetworkBehaviour)this).IsServer && !base.isEnemyDead && FlyingTVManager.IsValidLivingPlayer(attacker))
			{
				base.targetPlayer = attacker;
				_lastKnownTargetPosition = ((Component)attacker).transform.position;
				if (base.currentBehaviourStateIndex != 4 && base.currentBehaviourStateIndex != 6 && base.currentBehaviourStateIndex != 5)
				{
					StartAttack();
				}
			}
		}

		private void RegisterDamageHit()
		{
			_damageHitCount = Mathf.Clamp(_damageHitCount + 1, 0, 10);
			_roamAngle += Random.Range(12f, 38f);
		}

		private void BeginDamageStunFreeze()
		{
			if (!(Time.time < _damageFreezeImmuneUntil))
			{
				_damageStunUntil = Time.time + 1f;
				_damageFreezeImmuneUntil = _damageStunUntil + 1.5f;
				ApplyDamageStunFreeze();
			}
		}

		private bool ApplyDamageStunFreeze()
		{
			if (!IsFrozen)
			{
				bool damageStunFrozen = _damageStunFrozen;
				ClearDamageStunFreeze();
				if (damageStunFrozen)
				{
					ResumeVideoAfterFreeze();
					if (((NetworkBehaviour)this).IsServer && !IsInStationaryHold())
					{
						((EnemyAI)(object)this).ReleaseAgent();
					}
				}
				return false;
			}
			((EnemyAI)(object)this).HoldAgent();
			if (!_damageStunFrozen)
			{
				_preDamageStunAnimatorSpeed = (((Object)(object)base.creatureAnimator != (Object)null) ? Mathf.Max(0.01f, base.creatureAnimator.speed) : 1f);
				_damageStunFrozen = true;
				PauseVideoForFreeze();
			}
			if ((Object)(object)base.creatureAnimator != (Object)null)
			{
				base.creatureAnimator.speed = 0f;
			}
			return true;
		}

		private bool IsInStationaryHold()
		{
			return base.currentBehaviourStateIndex switch
			{
				2 => !base.movingTowardsTargetPlayer, 
				3 => true, 
				5 => !_leaveMovementStarted, 
				_ => false, 
			};
		}

		private void PauseVideoForFreeze()
		{
			if (!((Object)(object)_videoPlayer == (Object)null) && _videoPlayer.isPlaying)
			{
				_videoPlayer.Pause();
				_videoPausedForFreeze = true;
			}
		}

		private void ResumeVideoAfterFreeze()
		{
			if (_videoPausedForFreeze)
			{
				_videoPausedForFreeze = false;
				if ((Object)(object)_videoPlayer != (Object)null && _selectedVideoPlaying && _videoPlayer.isPrepared)
				{
					_videoPlayer.Play();
				}
			}
		}

		private void PauseLocalVideoTimers(float deltaTime)
		{
			if (_selectedVideoPlaying)
			{
				_videoFreezePausedSeconds += deltaTime;
				_localVideoEndTime += deltaTime;
			}
		}

		private void ClearDamageStunFreeze()
		{
			if (_damageStunFrozen)
			{
				if ((Object)(object)base.creatureAnimator != (Object)null)
				{
					base.creatureAnimator.speed = _preDamageStunAnimatorSpeed;
				}
				_damageStunFrozen = false;
			}
		}

		private void ConfigureSearchDefaults()
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Expected O, but got Unknown
			if (facilitySearch == null)
			{
				facilitySearch = new AISearchRoutine();
			}
			facilitySearch.loopSearch = true;
			facilitySearch.randomized = true;
			facilitySearch.onlySearchNodesInLOS = false;
			facilitySearch.searchPrecision = 4f;
			if (facilitySearch.searchWidth <= 0f)
			{
				facilitySearch.searchWidth = 70f;
			}
		}

		private void EnsureRoamingSearch()
		{
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			if (((NetworkBehaviour)this).IsServer && !base.isEnemyDead && base.currentBehaviourStateIndex == 0 && (facilitySearch == null || base.currentSearch != facilitySearch || !facilitySearch.inProgress) && !(Time.time < _nextRoamSearchRetargetTime))
			{
				if (_hasPendingSearchSeed)
				{
					StartFacilitySearch(_pendingSearchSeed, _pendingSearchWidth);
				}
				else
				{
					StartFacilitySearch(((Component)this).transform.position, 70f);
				}
			}
		}

		private void StartFacilitySearch(Vector3 start, float width, bool recentre = false)
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			if (!((NetworkBehaviour)this).IsServer || base.isEnemyDead)
			{
				return;
			}
			ConfigureSearchDefaults();
			facilitySearch.searchWidth = Mathf.Clamp(width, 8f, 160f);
			facilitySearch.searchPrecision = 4f;
			if (!CanUseVanillaSearch())
			{
				_pendingSearchSeed = start;
				_pendingSearchWidth = width;
				_hasPendingSearchSeed = true;
				_nextRoamSearchRetargetTime = Time.time + 0.5f;
				return;
			}
			_hasPendingSearchSeed = false;
			if (!facilitySearch.inProgress || recentre)
			{
				((EnemyAI)this).StopSearch(facilitySearch, true);
			}
			((EnemyAI)this).StartSearch(start, facilitySearch);
			_nextRoamSearchRetargetTime = Time.time + Random.Range(3.5f, 7.5f);
		}

		private bool CanUseVanillaSearch()
		{
			if (((NetworkBehaviour)this).IsServer && AgentReady && base.allAINodes != null)
			{
				return base.allAINodes.Length != 0;
			}
			return false;
		}

		private void StopSearchIfNeeded(bool clear)
		{
			if (((NetworkBehaviour)this).IsServer && base.currentSearch != null && base.currentSearch.inProgress)
			{
				((EnemyAI)this).StopSearch(base.currentSearch, clear);
			}
		}

		private void UpdateRoamingSearch()
		{
			EnsureRoamingSearch();
			float damageWobbleAmount = DamageWobbleAmount;
			_roamAngle += Time.deltaTime * (0.6f + damageWobbleAmount * 0.45f);
			FaceTravelDirection();
		}

		private void FaceTravelDirection()
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//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_004a: 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)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: 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)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = (((Object)(object)base.agent != (Object)null && ((Behaviour)base.agent).enabled) ? base.agent.velocity : Vector3.zero);
			val.y = 0f;
			Quaternion val2 = ((!(((Vector3)(ref val)).sqrMagnitude > 0.04f)) ? FlyingTVManager.BuildScreenFacingRotation(new Vector3(Mathf.Cos(_roamAngle * 0.5f), 0f, Mathf.Sin(_roamAngle * 0.5f))) : FlyingTVManager.BuildScreenFacingRotation(((Vector3)(ref val)).normalized));
			((Component)this).transform.rotation = Quaternion.Slerp(((Component)this).transform.rotation, val2, Mathf.Clamp01(Time.deltaTime * 2.5f));
		}

		private PlayerControllerB FindDetectedPlayer()
		{
			float num = Mathf.Max(1f, FlyingTVConfig.DetectionRange.Value);
			float num2 = Mathf.Clamp(FlyingTVConfig.DetectionConeDegrees.Value, 10f, 360f);
			int num3 = Mathf.RoundToInt(3f);
			PlayerControllerB val = ((EnemyAI)this).CheckLineOfSightForPlayer(num2 * 0.5f, Mathf.RoundToInt(num), num3);
			if (!FlyingTVManager.IsValidLivingPlayer(val) || !((EnemyAI)this).PlayerIsTargetable(val, false, false, true))
			{
				return null;
			}
			return val;
		}

		private void UpdateServerMovement()
		{
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			int currentBehaviourStateIndex = base.currentBehaviourStateIndex;
			if (currentBehaviourStateIndex == 6)
			{
				return;
			}
			RepairOffNavMeshIfNeeded();
			ApplyHoverHeight();
			ApplyAgentStateSettings();
			switch (currentBehaviourStateIndex)
			{
			case 0:
				UpdateRoamingSearch();
				return;
			case 5:
				UpdateLeave();
				return;
			}
			PlayerControllerB targetPlayer = base.targetPlayer;
			if (!FlyingTVManager.IsValidLivingPlayer(targetPlayer))
			{
				return;
			}
			switch (currentBehaviourStateIndex)
			{
			case 1:
				FaceTarget(targetPlayer);
				if (!_checkActive && IsWithinFollowRange(targetPlayer))
				{
					StartCheckPhase();
				}
				break;
			case 2:
				FollowTargetDuringCheck(targetPlayer);
				break;
			case 3:
				((Component)this).transform.rotation = _videoHoldRotation;
				break;
			case 4:
				FaceTarget(targetPlayer);
				break;
			}
		}

		private void StopAgentForHold()
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			StopSearchIfNeeded(clear: false);
			if (AgentReady)
			{
				base.agent.isStopped = true;
				base.agent.ResetPath();
				base.agent.velocity = Vector3.zero;
			}
		}

		private void FollowTargetDuringCheck(PlayerControllerB target)
		{
			FaceTarget(target);
			if (IsWithinFollowRange(target))
			{
				if (base.movingTowardsTargetPlayer || base.moveTowardsDestination || (AgentReady && !base.agent.isStopped))
				{
					base.movingTowardsTargetPlayer = false;
					base.moveTowardsDestination = false;
					StopAgentForHold();
				}
				return;
			}
			int num;
			if (base.movingTowardsTargetPlayer)
			{
				num = ((!base.moveTowardsDestination) ? 1 : 0);
				if (num == 0)
				{
					goto IL_0076;
				}
			}
			else
			{
				num = 1;
			}
			base.movingTowardsTargetPlayer = true;
			base.moveTowardsDestination = true;
			((EnemyAI)this).SetMovingTowardsTargetPlayer(target);
			goto IL_0076;
			IL_0076:
			if (num != 0 || (AgentReady && base.agent.isStopped))
			{
				((EnemyAI)(object)this).ReleaseAgent();
			}
		}

		private bool IsWithinFollowRange(PlayerControllerB target)
		{
			//IL_0006: 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_001b: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = ((Component)target).transform.position - ((Component)this).transform.position;
			val.y = 0f;
			if (((Vector3)(ref val)).sqrMagnitude <= FollowDistance * FollowDistance)
			{
				return _targetInSight;
			}
			return false;
		}

		private void UpdateLeave()
		{
			if (FlyingTVManager.IsValidLivingPlayer(base.targetPlayer))
			{
				FaceTarget(base.targetPlayer);
			}
			if (!(Time.time < _leaveMovementStartTime))
			{
				BeginLeaveMovement();
			}
		}

		private bool IsTargetInStrikeReach(PlayerControllerB target)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: 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_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)
			if (!((EnemyAI)this).PlayerIsTargetable(target, false, false, true))
			{
				return false;
			}
			Vector3 position = ((Component)this).transform.position;
			Vector3 position2 = ((Component)target).transform.position;
			float num = position.y - (((Object)(object)base.agent != (Object)null) ? base.agent.baseOffset : 0f);
			if (Mathf.Abs(position2.y - num) > 1.6f)
			{
				return false;
			}
			Vector3 val = position2 - position;
			val.y = 0f;
			float num2 = 3.2f;
			if (((Vector3)(ref val)).sqrMagnitude > num2 * num2)
			{
				return false;
			}
			Vector3 val2 = position2 + Vector3.up * 1.4f;
			if (!IsSightLineBlocked(position, val2))
			{
				return !IsSightLineBlocked(val2, position);
			}
			return false;
		}

		[ClientRpc]
		private void ApplyAttackDamageClientRpc(ulong targetClientId, int damage, ClientRpcParams clientRpcParams = default(ClientRpcParams))
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Invalid comparison between Unknown and I4
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Invalid comparison between Unknown and I4
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: 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_0096: 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_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager;
			if (networkManager == null || !networkManager.IsListening)
			{
				return;
			}
			if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 && (networkManager.IsServer || networkManager.IsHost))
			{
				FastBufferWriter val = ((NetworkBehaviour)this).__beginSendClientRpc(333013693u, clientRpcParams, (RpcDelivery)0);
				BytePacker.WriteValueBitPacked(val, targetClientId);
				BytePacker.WriteValueBitPacked(val, damage);
				((NetworkBehaviour)this).__endSendClientRpc(ref val, 333013693u, clientRpcParams, (RpcDelivery)0);
			}
			if ((int)((NetworkBehaviour)this).__rpc_exec_stage == 1 && (networkManager.IsClient || networkManager.IsHost))
			{
				((NetworkBehaviour)this).__rpc_exec_stage = (__RpcExecStage)0;
				PlayerControllerB val2 = (((Object)(object)GameNetworkManager.Instance != (Object)null) ? GameNetworkManager.Instance.localPlayerController : null);
				if (!((Object)(object)val2 == (Object)null) && !val2.isPlayerDead && VictimRpc.IsLocalVictim(targetClientId))
				{
					val2.DamagePlayer(damage, true, true, (CauseOfDeath)1, 0, false, default(Vector3));
				}
			}
		}

		private bool ShouldLoseAggro(PlayerControllerB target, float loseDistance, float loseSeconds)
		{
			//IL_0006: 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)
			float num = Vector3.Distance(((Component)this).transform.position, ((Component)target).transform.position);
			bool flag = num >= loseDistance;
			bool flag2 = num > 3.2f && !_targetInSight;
			if (!flag && !flag2)
			{
				_attackLostAggroSince = -1f;
				return false;
			}
			if (_attackLostAggroSince < 0f)
			{
				_attackLostAggroSince = Time.time;
				return false;
			}
			return Time.time - _attackLostAggroSince >= loseSeconds;
		}

		private bool HasLineOfSightToTarget(PlayerControllerB target)
		{
			//IL_0007: 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_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			return !IsSightLineBlocked(((Component)this).transform.position, ((Component)target).transform.position + Vector3.up * 1.4f);
		}

		private bool IsSightLineBlocked(Vector3 from, Vector3 to)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			RaycastHit val = default(RaycastHit);
			if (Physics.Linecast(from, to, ref val, GetWorldCollisionMask(), (QueryTriggerInteraction)1))
			{
				return !((RaycastHit)(ref val)).transform.IsChildOf(((Component)this).transform);
			}
			return false;
		}

		private void TickVisualHover()
		{
			//IL_001e: 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_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)visualRoot == (Object)null))
			{
				if (!_hasVisualBaseLocalPosition)
				{
					_visualBaseLocalPosition = visualRoot.localPosition;
					_hasVisualBaseLocalPosition = true;
				}
				if (base.isEnemyDead)
				{
					visualRoot.localPosition = _visualBaseLocalPosition;
					return;
				}
				float damageWobbleAmount = DamageWobbleAmount;
				float num = Time.time * 1.2f;
				float num2 = Mathf.Sin(num * 1.3f) * (0.16f + damageWobbleAmount * 0.09f);
				float num3 = Mathf.Sin(num * 1.7f + _roamAngle) * damageWobbleAmount * 0.11f;
				visualRoot.localPosition = _visualBaseLocalPosition + new Vector3(num3, num2, 0f);
			}
		}

		private static int GetWorldCollisionMask()
		{
			if ((Object)(object)StartOfRound.Instance != (Object)null)
			{
				return StartOfRound.Instance.collidersAndRoomMaskAndDefault;
			}
			int mask = 1;
			AddLayerToMask(ref mask, "Room");
			AddLayerToMask(ref mask, "MapProps");
			AddLayerToMask(ref mask, "Colliders");
			return mask;
		}

		private static void AddLayerToMask(ref int mask, string layerName)
		{
			int num = LayerMask.NameToLayer(layerName);
			if (num >= 0)
			{
				mask |= 1 << num;
			}
		}

		private void FaceTarget(PlayerControllerB target)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: 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_00be: 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_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: 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 (!((Object)(object)target == (Object)null))
			{
				Vector3 val = ((Component)target).transform.position + Vector3.up * 1.4f - ((Component)this).transform.position;
				if (((Vector3)(ref val)).sqrMagnitude < 0.001f)
				{
					val = ((Component)this).transform.forward;
				}
				val.y = 0f;
				if (((Vector3)(ref val)).sqrMagnitude < 0.001f)
				{
					val = ((Component)this).transform.forward;
				}
				Vector3 val2 = GetCurrentScreenSideDirection();
				if (((Vector3)(ref val2)).sqrMagnitude < 0.001f)
				{
					val2 = ((Component)this).transform.forward;
				}
				Quaternion val3 = Quaternion.FromToRotation(((Vector3)(ref val2)).normalized, ((Vector3)(ref val)).normalized) * ((Component)this).transform.rotation;
				((Component)this).transform.rotation = Quaternion.Slerp(((Component)this).transform.rotation, val3, Mathf.Clamp01(Time.deltaTime * 8f));
			}
		}

		private Vector3 GetCurrentScreenSideDirection()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			Vector3 screenFacingDirection = FlyingTVManager.GetScreenFacingDirection(((Component)this).transform);
			screenFacingDirection.y = 0f;
			if (((Vector3)(ref screenFacingDirection)).sqrMagnitude > 0.0025f)
			{
				return ((Vector3)(ref screenFacingDirection)).normalized;
			}
			return ((Component)this).transform.forward;
		}

		private bool IsPlayerLookingAwayFromTV(PlayerControllerB player, float angleThreshold)
		{
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: 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_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_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)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: 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_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)player == (Object)null)
			{
				return false;
			}
			Transform val = (((Object)(object)player.gameplayCamera != (Object)null) ? ((Component)player.gameplayCamera).transform : ((Component)player).transform);
			Vector3 val2;
			if (!((Object)(object)screenRenderer != (Object)null))
			{
				val2 = ((Component)this).transform.position + Vector3.up * 0.5f;
			}
			else
			{
				Bounds bounds = screenRenderer.bounds;
				val2 = ((Bounds)(ref bounds)).center;
			}
			Vector3 val3 = val2 - val.position;
			Vector3 forward = val.forward;
			if (((Vector3)(ref forward)).sqrMagnitude < 0.001f || ((Vector3)(ref val3)).sqrMagnitude < 0.001f)
			{
				return false;
			}
			float num = Mathf.Cos(angleThreshold * (MathF.PI / 180f));
			forward = val.forward;
			return Vector3.Dot(((Vector3)(ref forward)).normalized, ((Vector3)(ref val3)).normalized) < num;
		}

		private bool ShouldTriggerVideoNonCompliance(PlayerControllerB player)
		{
			//IL_0035: 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)
			if (!FlyingTVManager.IsValidLivingPlayer(player))
			{
				_videoNoncomplianceSince = -1f;
				return false;
			}
			if (Time.time < _serverNoncomplianceEnableTime)
			{
				_videoNoncomplianceSince = -1f;
				return false;
			}
			float num = Vector3.Distance(((Component)player).transform.position, ((Component)this).transform.position);
			bool num2 = num > VideoNoncomplianceDistance;
			bool flag = IsPlayerLookingAwayFromTV(player, TurnAwayAngleThreshold);
			if (!(num2 || flag))
			{
				_videoNoncomplianceSince = -1f;
				return false;
			}
			if (_videoNoncomplianceSince < 0f)
			{
				_videoNoncomplianceSince = Time.time;
			}
			if (Time.time - _videoNoncomplianceSince < VideoNoncomplianceSustainSeconds)
			{
				return false;
			}
			ManualLogSource log = Plugin.Log;
			if (log != null)
			{
				log.LogInfo((object)($"[FlyingTV] Video noncompliance detected: distance={num:0.0}m " + $"(limit {VideoNoncomplianceDistance:0.0}m), outsideViewCone={flag}."));
			}
			return true;
		}

		private void CompleteVideoAndLeave()
		{
			if (((NetworkBehaviour)this).IsServer && !base.isEnemyDead && base.currentBehaviourStateIndex == 3)
			{
				_videoActive = false;
				StopBroadcastPlayback();
				PlayVoiceLine(2);
				float currentVoiceRemainingSeconds = GetCurrentVoiceRemainingSeconds();
				StartLeave(currentVoiceRemainingSeconds);
			}
		}

		private void UpdateAnimation()
		{
			//IL_001d: 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_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)base.creatureAnimator == (Object)null) && _hasMovingParameter)
			{
				Vector3 val = ((Component)this).transform.position - _lastPosition;
				float num = ((Vector3)(ref val)).magnitude / Mathf.Max(Time.deltaTime, 0.001f);
				bool flag = base.currentBehaviourStateIndex == 1 || base.currentBehaviourStateIndex == 4 || base.currentBehaviourStateIndex == 5 || num > 0.2f;
				base.creatureAnimator.SetBool(MovingHash, flag);
				_lastPosition = ((Component)this).transform.position;
			}
		}

		private void PlayVoiceLine(int voiceId)
		{
			AudioClip val = (_lastVoiceClip = ResolveVoiceClip(voiceId));
			_lastVoiceStartTime = Time.time;
			if (!((Object)(object)val == (Object)null))
			{
				SyncTargetSlot();
				PlayVoiceClientRpc(voiceId, _networkTargetSlot.Value);
			}
		}

		[ClientRpc]
		private void PlayVoiceClientRpc(int voiceId, int audienceSlot)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Invalid comparison between Unknown and I4
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Invalid comparison between Unknown and I4
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: 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_0096: 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)
			NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager;
			if (networkManager != null && networkManager.IsListening)
			{
				if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 && (networkManager.IsServer || networkManager.IsHost))
				{
					ClientRpcParams val2 = default(ClientRpcParams);
					FastBufferWriter val = ((NetworkBehaviour)this).__beginSendClientRpc(2817593449u, val2, (RpcDelivery)0);
					BytePacker.WriteValueBitPacked(val, voiceId);
					BytePacker.WriteValueBitPacked(val, audienceSlot);
					((NetworkBehaviour)this).__endSendClientRpc(ref val, 2817593449u, val2, (RpcDelivery)0);
				}
				if ((int)((NetworkBehaviour)this).__rpc_exec_stage == 1 && (networkManager.IsClient || networkManager.IsHost))
				{
					((NetworkBehaviour)this).__rpc_exec_stage = (__RpcExecStage)0;
					ApplyLocalVisibility(audienceSlot);
					PlayVoiceClip(ResolveVoiceClip(voiceId));
				}
			}
		}

		private AudioClip ResolveVoiceClip(int voiceId)
		{
			return (AudioClip)(voiceId switch
			{
				0 => greetingsClip, 
				1 => noncomplianceClip, 
				2 => complianceClip, 
				_ => null, 
			});
		}

		private void PlayVoiceClip(AudioClip clip)
		{
			if (!((Object)(object)_voiceSource == (Object)null) && !((Object)(object)clip == (Object)null) && !base.isEnemyDead)
			{
				_voiceSource.Stop();
				if (!_hiddenFromLocalPlayer)
				{
					CreatureAudioSetup.TransmitOneShot(_voiceSource, clip);
				}
			}
		}

		private float GetCurrentVoiceRemainingSeconds()
		{
			if ((Object)(object)_lastVoiceClip == (Object)null)
			{
				return 0f;
			}
			float num = _lastVoiceClip.length - Mathf.Max(0f, Time.time - _lastVoiceStartTime);
			if (!(num > 0f))
			{
				return 0f;
			}
			return num + 0.15f;
		}

		private void EnsurePropellerLoopPlaying()
		{
			if ((Object)(object)_propellerSource == (Object)null)
			{
				return;
			}
			if ((Object)(object)propellerLoopClip == (Object)null)
			{
				propellerLoopClip = Plugin.PropellerClip;
			}
			if (!((Object)(object)propellerLoopClip == (Object)null))
			{
				float num = ((FlyingTVConfig.PropellerVolume != null) ? Mathf.Clamp01(FlyingTVConfig.PropellerVolume.Value) : 0.65f);
				if (num != _appliedPropellerVolume)
				{
					_appliedPropellerVolume = num;
					_propellerSource.volume = num;
				}
				if ((Object)(object)_propellerSource.clip != (Object)(object)propellerLoopClip)
				{
					_propellerSource.clip = propellerLoopClip;
					_propellerSource.loop = true;
				}
				if (!_propellerSource.isPlaying)
				{
					_propellerSource.Play();
				}
			}
		}

		private void StopPropellerLoop()
		{
			if ((Object)(object)_propellerSource != (Object)null)
			{
				_propellerSource.Stop();
			}
		}

		[ClientRpc]
		private void PrefetchYoutubePlaybackClientRpc(string youtubeUrl)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Invalid comparison between Unknown and I4
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Invalid comparison between Unknown and I4
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager;
			if (networkManager == null || !networkManager.IsListening)
			{
				return;
			}
			if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 && (networkManager.IsServer || networkManager.IsHost))
			{
				ClientRpcParams val2 = default(ClientRpcParams);
				FastBufferWriter val = ((NetworkBehaviour)this).__beginSendClientRpc(2130784982u, val2, (RpcDelivery)0);
				bool flag = youtubeUrl != null;
				((FastBufferWriter)(ref val)).WriteValueSafe<bool>(ref flag, default(ForPrimitives));
				if (flag)
				{
					((FastBufferWriter)(ref val)).WriteValueSafe(youtubeUrl, false);
				}
				((NetworkBehaviour)this).__endSendClientRpc(ref val, 2130784982u, val2, (RpcDelivery)0);
			}
			if ((int)((NetworkBehaviour)this).__rpc_exec_stage == 1 && (networkManager.IsClient || networkManager.IsHost))
			{
				((NetworkBehaviour)this).__rpc_exec_stage = (__RpcExecStage)0;
				if (YoutubeVideoResolver.IsYoutubeUrl(youtubeUrl))
				{
					YoutubeVideoResolver.ResolveAsync(youtubeUrl);
				}
			}
		}

		[ClientRpc]
		private void StartPlaybackClientRpc(string videoName, float durationSeconds, double playbackStartServerTime)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Invalid comparison between Unknown and I4
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Invalid comparison between Unknown and I4
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: 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_00bb: 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_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager;
			if (networkManager == null || !networkManager.IsListening)
			{
				return;
			}
			if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 && (networkManager.IsServer || networkManager.IsHost))
			{
				ClientRpcParams val2 = default(ClientRpcParams);
				FastBufferWriter val = ((NetworkBehaviour)this).__beginSendClientRpc(3395646845u, val2, (RpcDelivery)0);
				bool flag = videoName != null;
				((FastBufferWriter)(ref val)).WriteValueSafe<bool>(ref flag, default(ForPrimitives));
				if (flag)
				{
					((FastBufferWriter)(ref val)).WriteValueSafe(videoName, false);
				}
				((FastBufferWriter)(ref val)).WriteValueSafe<float>(ref durationSeconds, default(ForPrimitives));
				((FastBufferWriter)(ref val)).WriteValueSafe<double>(ref playbackStartServerTime, default(ForPrimitives));
				((NetworkBehaviour)this).__endSendClientRpc(ref val, 3395646845u, val2, (RpcDelivery)0);
			}
			if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 || (!networkManager.IsClient && !networkManager.IsHost))
			{
				return;
			}
			((NetworkBehaviour)this).__rpc_exec_stage = (__RpcExecStage)0;
			_videoName = videoName ?? string.Empty;
			_forcedDurationSeconds = Mathf.Max(0f, durationSeconds);
			if (!_selectedVideoPlaying)
			{
				ResolveReferences();
				_selectedVideoPlaying = true;
				_videoFreezePausedSeconds = 0f;
				_videoPausedForFreeze = false;
				if (YoutubeVideoResolver.IsYoutubeUrl(videoName))
				{
					StartYoutubeVideoPlayback(videoName, _forcedDurationSeconds, playbackStartServerTime);
					return;
				}
				string videoLocation = ResolveVideoLocation(videoName);
				StartVideoPlayback(videoLocation, loop: false, playAudio: true, selectedVideo: true, _forcedDurationSeconds, playbackStartServerTime);
			}
		}

		private void StartYoutubeVideoPlayback(string youtubeUrl, float durationSeconds, double playbackStartServerTime)
		{
			if (_playbackRoutine != null)
			{
				((MonoBehaviour)this).StopCoroutine(_playbackRoutine);
				_playbackRoutine = null;
			}
			StopVideoPlayer();
			_playbackRoutine = ((MonoBehaviour)this).StartCoroutine(ResolveAndStartYoutubePlayback(youtubeUrl, durationSeconds, playbackStartServerTime));
		}

		private IEnumerator ResolveAndStartYoutubePlayback(string youtubeUrl, float durationSeconds, double playbackStartServerTime)
		{
			Task<YoutubeVideoStreams> resolutionTask = YoutubeVideoResolver.ResolveAsync(youtubeUrl);
			float resolutionDeadline = Time.realtimeSinceStartup + 90f;
			while (!resolutionTask.IsCompleted && _selectedVideoPlaying && !_destroying && !base.isEnemyDead && Time.realtimeSinceStartup < resolutionDeadline)
			{
				yield return null;
			}
			if (!_selectedVideoPlaying || _destroying || base.isEnemyDead)
			{
				_playbackRoutine = null;
				yield break;
			}
			YoutubeVideoStreams youtubeVideoStreams = null;
			if (!resolutionTask.IsCompleted)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogWarning((object)"[FlyingTV] Local YouTube resolution timed out; showing the fallback screen.");
				}
			}
			else if (!resolutionTask.IsCanceled && !resolutionTask.IsFaulted)
			{
				youtubeVideoStreams = resolutionTask.Result;
			}
			_playbackRoutine = null;
			StartVideoPlayback(youtubeVideoStreams?.VideoUrl, loop: false, playAudio: true, selectedVideo: true, durationSeconds, playbackStartServerTime);
		}

		[ClientRpc]
		private void StopPlaybackClientRpc()
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Invalid comparison between Unknown and I4
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Invalid comparison between Unknown and I4
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager;
			if (networkManager != null && networkManager.IsListening)
			{
				if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 && (networkManager.IsServer || networkManager.IsHost))
				{
					ClientRpcParams val2 = default(ClientRpcParams);
					FastBufferWriter val = ((NetworkBehaviour)this).__beginSendClientRpc(2066075155u, val2, (RpcDelivery)0);
					((NetworkBehaviour)this).__endSendClientRpc(ref val, 2066075155u, val2, (RpcDelivery)0);
				}
				if ((int)((NetworkBehaviour)this).__rpc_exec_stage == 1 && (networkManager.IsClient || networkManager.IsHost))
				{
					((NetworkBehaviour)this).__rpc_exec_stage = (__RpcExecStage)0;
					StopLocalPlayback(resumeStatic: true);
				}
			}
		}

		[ServerRpc(RequireOwnership = false)]
		private void SelectedPlaybackFinishedServerRpc(ServerRpcParams rpcParams = default(ServerRpcParams))
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Invalid comparison between Unknown and I4
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Invalid comparison between Unknown and I4
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager;
			if (networkManager == null || !networkManager.IsListening)
			{
				return;
			}
			if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 && (networkManager.IsClient || networkManager.IsHost))
			{
				FastBufferWriter val = ((NetworkBehaviour)this).__beginSendServerRpc(2905851093u, rpcParams, (RpcDelivery)0);
				((NetworkBehaviour)this).__endSendServerRpc(ref val, 2905851093u, rpcParams, (RpcDelivery)0);
			}
			if ((int)((NetworkBehaviour)this).__rpc_exec_stage == 1 && (networkManager.IsServer || networkManager.IsHost))
			{
				((NetworkBehaviour)this).__rpc_exec_stage = (__RpcExecStage)0;
				if (IsReportFromTarget(rpcParams))
				{
					RequestVideoCompletion();
				}
			}
		}

		[ServerRpc(RequireOwnership = false)]
		private void SelectedPlaybackFailedServerRpc(ServerRpcParams rpcParams = default(ServerRpcParams))
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Invalid comparison between Unknown and I4
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Invalid comparison between Unknown and I4
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager;
			if (networkManager == null || !networkManager.IsListening)
			{
				return;
			}
			if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 && (networkManager.IsClient || networkManager.IsHost))
			{
				FastBufferWriter val = ((NetworkBehaviour)this).__beginSendServerRpc(629388963u, rpcParams, (RpcDelivery)0);
				((NetworkBehaviour)this).__endSendServerRpc(ref val, 629388963u, rpcParams, (RpcDelivery)0);
			}
			if ((int)((NetworkBehaviour)this).__rpc_exec_stage == 1 && (networkManager.IsServer || networkManager.IsHost))
			{
				((NetworkBehaviour)this).__rpc_exec_stage = (__RpcExecStage)0;
				if (IsReportFromTarget(rpcParams))
				{
					ShortenVideoToFallback();
				}
			}
		}

		private bool 

Y4NGZHarmonic.dll

Decompiled a week ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using Dawn;
using GameNetcodeStuff;
using Microsoft.CodeAnalysis;
using Unity.Netcode;
using Unity.Netcode.Components;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.Audio;
using UnityEngine.Networking;
using UnityEngine.Rendering.HighDefinition;
using Y4NGZHarmonic.AI;
using Y4NGZHarmonic.NetcodePatcher;
using Y4NGZMonsters.Shared;

[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("Y4NGZHarmonic")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+c64a155fd64c47528940e53659e5b5ada665b9d4")]
[assembly: AssemblyProduct("Y4NGZHarmonic")]
[assembly: AssemblyTitle("Y4NGZHarmonic")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
[module: NetcodePatchedAssembly]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.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 Y4NGZHarmonic
{
	internal static class HarmonicBloodFxBridge
	{
		internal const string PluginGuid = "com.y4ngz.bloodfx";

		private const string CreatureBloodTypeName = "Y4NGZCompany.Experience.BloodFX.BloodFXCreatureBlood";

		private static bool? _pluginPresent;

		private static bool _bridgeResolved;

		private static PropertyInfo _isAvailable;

		private static MethodInfo _playCreatureBleed;

		internal static void PlayCreatureBleed(int creatureKey, Vector3 point, Vector3 direction, Color tint, int contacts, float scale)
		{
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: 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)
			if (!BloodFxPluginPresent() || !ResolveBridge())
			{
				return;
			}
			try
			{
				if (_isAvailable != null)
				{
					object value = _isAvailable.GetValue(null);
					if (value is bool && !(bool)value)
					{
						return;
					}
				}
				_playCreatureBleed.Invoke(null, new object[6] { creatureKey, point, direction, tint, contacts, scale });
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("[Harmonic] Optional BloodFX bridge failed: " + ex.GetBaseException().Message));
				}
			}
		}

		private static bool BloodFxPluginPresent()
		{
			if (!_pluginPresent.HasValue)
			{
				_pluginPresent = Chainloader.PluginInfos.ContainsKey("com.y4ngz.bloodfx");
			}
			return _pluginPresent.Value;
		}

		private static bool ResolveBridge()
		{
			if (_bridgeResolved)
			{
				return _playCreatureBleed != null;
			}
			_bridgeResolved = true;
			if (!Chainloader.PluginInfos.TryGetValue("com.y4ngz.bloodfx", out var value) || (Object)(object)value.Instance == (Object)null)
			{
				return false;
			}
			Type type = ((object)value.Instance).GetType().Assembly.GetType("Y4NGZCompany.Experience.BloodFX.BloodFXCreatureBlood", throwOnError: false);
			if (type == null)
			{
				return false;
			}
			_isAvailable = type.GetProperty("IsAvailable", BindingFlags.Static | BindingFlags.Public);
			_playCreatureBleed = type.GetMethod("PlayCreatureBleed", BindingFlags.Static | BindingFlags.Public, null, new Type[6]
			{
				typeof(int),
				typeof(Vector3),
				typeof(Vector3),
				typeof(Color),
				typeof(int),
				typeof(float)
			}, null);
			return _playCreatureBleed != null;
		}
	}
	internal sealed class HarmonicConfig
	{
		public ConfigEntry<bool> Enabled { get; }

		public ConfigEntry<float> SpawnWeightMultiplier { get; }

		public ConfigEntry<string> MoonWeightOverrides { get; }

		public ConfigEntry<int> MaxCount { get; }

		public ConfigEntry<float> PowerLevel { get; }

		public ConfigEntry<int> Health { get; }

		public ConfigEntry<float> MoveSpeed { get; }

		public ConfigEntry<float> AlarmChance { get; }

		public ConfigEntry<float> AlarmAttractionRadius { get; }

		public ConfigEntry<float> MusicVolume { get; }

		public ConfigEntry<float> SfxVolume { get; }

		public ConfigEntry<float> MusicMaxDistance { get; }

		public ConfigEntry<float> SfxMaxDistance { get; }

		public ConfigEntry<bool> DebugLogs { get; }

		public HarmonicConfig(ConfigFile config)
		{
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Expected O, but got Unknown
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Expected O, but got Unknown
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Expected O, but got Unknown
			//IL_012f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0139: Expected O, but got Unknown
			//IL_0168: Unknown result type (might be due to invalid IL or missing references)
			//IL_0172: Expected O, but got Unknown
			//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ab: Expected O, but got Unknown
			//IL_01da: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e4: Expected O, but got Unknown
			//IL_0213: Unknown result type (might be due to invalid IL or missing references)
			//IL_021d: Expected O, but got Unknown
			//IL_024c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0256: Expected O, but got Unknown
			//IL_0285: Unknown result type (might be due to invalid IL or missing references)
			//IL_028f: Expected O, but got Unknown
			//IL_02be: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c8: Expected O, but got Unknown
			using (ConfigPersistence.BeginBinding(config, Plugin.Log, "Harmonic"))
			{
				HarmonicConfigMigration.TryMigrate(config, Plugin.Log);
				ConfigSectionNameMigration.TryMigrate(config, Plugin.Log, "Harmonic");
				Enabled = config.Bind<bool>("General", "Enabled", true, "Enable the Harmonic encounter. Host-only: the host's value decides whether it spawns; every install still registers the creature so clients stay in sync.");
				SpawnWeightMultiplier = config.Bind<float>("Spawning", "SpawnWeightMultiplier", 1f, new ConfigDescription("Multiplier applied to Harmonic's contextual moon/interior spawn policy. 0 disables natural spawns.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 5f), Array.Empty<object>()));
				MoonWeightOverrides = config.Bind<string>("Spawning", "MoonWeightOverrides", string.Empty, "Optional comma-separated base moon weights, e.g. Experimentation:8,Offense:15 or namespace:moon=12. Use 0 to disable a moon; unlisted moons keep authored defaults.");
				MaxCount = config.Bind<int>("Spawning", "MaxCount", 1, new ConfigDescription("Maximum number of living Harmonics at once.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 20), Array.Empty<object>()));
				PowerLevel = config.Bind<float>("Spawning", "PowerLevel", 1.1f, new ConfigDescription("Indoor enemy power budget cost for each Harmonic.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 10f), Array.Empty<object>()));
				Health = config.Bind<int>("Core Stats", "Health", 4, new ConfigDescription("Hits the Harmonic can take before dying.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 100), Array.Empty<object>()));
				MoveSpeed = config.Bind<float>("Movement", "MoveSpeed", 1.15f, new ConfigDescription("Passive roaming speed.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 10f), Array.Empty<object>()));
				AlarmChance = config.Bind<float>("Abilities", "AlarmChance", 0.2f, new ConfigDescription("Chance that the next selected track will be the alarm.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
				AlarmAttractionRadius = config.Bind<float>("Abilities", "AlarmAttractionRadius", 30f, new ConfigDescription("Maximum distance in metres at which an alarm attracts other indoor enemies.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 200f), Array.Empty<object>()));
				MusicVolume = config.Bind<float>("Audio and Presentation", "MusicVolume", 0.95f, new ConfigDescription("Volume for idle music.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
				SfxVolume = config.Bind<float>("Audio and Presentation", "SfxVolume", 1f, new ConfigDescription("Shared volume for the alarm, hit, and death sounds.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
				MusicMaxDistance = config.Bind<float>("Audio and Presentation", "MusicMaxDistance", 65f, new ConfigDescription("Maximum audible distance for Harmonic music.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(8f, 65f), Array.Empty<object>()));
				SfxMaxDistance = config.Bind<float>("Audio and Presentation", "SfxMaxDistance", 42f, new ConfigDescription("Maximum audible distance for alarm, hit, and death sounds.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(8f, 42f), Array.Empty<object>()));
				DebugLogs = config.Bind<bool>("Diagnostics", "DebugLogs", false, "Write verbose Harmonic diagnostics to the BepInEx log.");
			}
		}
	}
	internal static class HarmonicConfigMigration
	{
		private static readonly ConfigDefinition LegacySpawnWeight = new ConfigDefinition("Spawning", "SpawnWeight");

		private static readonly LegacyMigrationSpec Spec = new LegacyMigrationSpec("Harmonic", (IReadOnlyList<ConfigDefinition>)(object)new ConfigDefinition[1] { LegacySpawnWeight }, null, new Dictionary<ConfigDefinition, string>
		{
			{
				new ConfigDefinition("Spawning", "LevelMask"),
				"-1"
			},
			{
				new ConfigDefinition("Spawning", "SpawnType"),
				"Default"
			},
			{
				new ConfigDefinition("Stats", "ModelScale"),
				"0.72"
			},
			{
				new ConfigDefinition("Movement", "Acceleration"),
				"4.5"
			},
			{
				new ConfigDefinition("Movement", "AngularSpeed"),
				"70"
			},
			{
				new ConfigDefinition("Movement", "HoverHeight"),
				"0.55"
			},
			{
				new ConfigDefinition("Movement", "RoamSearchWidth"),
				"120"
			},
			{
				new ConfigDefinition("Movement", "RoamSearchPrecision"),
				"8"
			},
			{
				new ConfigDefinition("Movement", "RoamStuckRecoverySeconds"),
				"3.5"
			},
			{
				new ConfigDefinition("Movement", "MovementBobAmount"),
				"0.06"
			},
			{
				new ConfigDefinition("Movement", "MovementTiltDegrees"),
				"4"
			},
			{
				new ConfigDefinition("Collision", "BodyColliderRadius"),
				"0.32"
			},
			{
				new ConfigDefinition("Collision", "BodyColliderHeight"),
				"1.25"
			},
			{
				new ConfigDefinition("Alarm", "RefreshSeconds"),
				"0.35"
			},
			{
				new ConfigDefinition("Audio", "AlarmVolume"),
				"1"
			},
			{
				new ConfigDefinition("Audio", "DeathVolume"),
				"1"
			},
			{
				new ConfigDefinition("Death", "HitInflateAmount"),
				"0.13"
			},
			{
				new ConfigDefinition("Death", "DeathEffectScale"),
				"0.75"
			},
			{
				new ConfigDefinition("Pulse", "IdlePulseRate"),
				"0.42"
			},
			{
				new ConfigDefinition("Pulse", "WarningPulseRate"),
				"1.55"
			},
			{
				new ConfigDefinition("Pulse", "PitchPulseAmount"),
				"0.025"
			},
			{
				new ConfigDefinition("Pulse", "VolumePulseAmount"),
				"0.08"
			},
			{
				new ConfigDefinition("Pulse", "WarningPitchMultiplier"),
				"1.18"
			},
			{
				new ConfigDefinition("Pulse", "AnimationPulseAmount"),
				"0"
			},
			{
				new ConfigDefinition("Pulse", "HornPulseScale"),
				"0.06"
			},
			{
				new ConfigDefinition("Light", "BaseIntensity"),
				"45"
			},
			{
				new ConfigDefinition("Light", "PulseIntensity"),
				"35"
			},
			{
				new ConfigDefinition("Light", "Range"),
				"8.5"
			},
			{
				new ConfigDefinition("Light", "EmissionIntensity"),
				"0.22"
			}
		}, Build);

		internal static bool TryMigrate(ConfigFile config, ManualLogSource log)
		{
			return LegacyConfigMigrator.TryMigrate(config, log, Spec);
		}

		private static void Build(LegacyConfigValues values, MigratedConfigWriter output)
		{
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Expected O, but got Unknown
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Expected O, but got Unknown
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Expected O, but got Unknown
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: Expected O, but got Unknown
			//IL_0136: Unknown result type (might be due to invalid IL or missing references)
			//IL_013c: Expected O, but got Unknown
			//IL_015e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0164: Expected O, but got Unknown
			//IL_0186: Unknown result type (might be due to invalid IL or missing references)
			//IL_018c: Expected O, but got Unknown
			//IL_01ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b4: Expected O, but got Unknown
			output.Carry("General", "Enabled");
			output.CarrySpawnWeightMultiplier(LegacySpawnWeight, 18f);
			output.Carry("Spawning", "MoonWeightOverrides");
			output.Carry("Spawning", "MaxCount");
			output.Carry("Spawning", "PowerLevel");
			output.Carry("Core Stats", "Health", new ConfigDefinition("Stats", "Health"));
			output.Carry("Movement", "MoveSpeed");
			output.Carry("Abilities", "AlarmChance", new ConfigDefinition("Audio", "AlarmChance"));
			output.Carry("Abilities", "AlarmAttractionRadius", new ConfigDefinition("Alarm", "AttractionRadius"));
			output.Carry("Audio and Presentation", "MusicVolume", new ConfigDefinition("Audio", "IdleMusicVolume"));
			output.Carry("Audio and Presentation", "SfxVolume", new ConfigDefinition("Audio", "HitVolume"));
			output.Carry("Audio and Presentation", "MusicMaxDistance", new ConfigDefinition("Audio", "MusicMaxDistance"));
			output.Carry("Audio and Presentation", "SfxMaxDistance", new ConfigDefinition("Audio", "SfxMaxDistance"));
			output.Carry("Diagnostics", "DebugLogs", new ConfigDefinition("Debug", "DebugLogs"));
		}
	}
	internal sealed class HarmonicSpawnWeights : ContextualSpawnWeights
	{
		internal HarmonicSpawnWeights(Func<float> multiplier, Func<string> moonOverrides, Action<string> logWarning)
			: base(SpawnWeightTable.Harmonic, "Harmonic", multiplier, moonOverrides, logWarning)
		{
		}
	}
	internal static class HarmonicTuning
	{
		internal const float ModelScale = 0.72f;

		internal const float Acceleration = 4.5f;

		internal const float AngularSpeed = 70f;

		internal const float HoverHeight = 0.55f;

		internal const float RoamSearchWidth = 120f;

		internal const float RoamSearchPrecision = 8f;

		internal const float RoamStuckRecoverySeconds = 3.5f;

		internal const float MovementBobAmount = 0.06f;

		internal const float MovementTiltDegrees = 4f;

		internal const float BodyColliderRadius = 0.32f;

		internal const float BodyColliderHeight = 1.25f;

		internal const float AlarmRefreshSeconds = 0.35f;

		internal const float HitInflateAmount = 0.13f;

		internal const float DeathEffectScale = 0.75f;

		internal const float IdlePulseRate = 0.42f;

		internal const float WarningPulseRate = 1.55f;

		internal const float PitchPulseAmount = 0.025f;

		internal const float VolumePulseAmount = 0.08f;

		internal const float WarningPitchMultiplier = 1.18f;

		internal const float HornPulseScale = 0.06f;

		internal const float LightBaseIntensity = 45f;

		internal const float LightPulseIntensity = 35f;

		internal const float LightRange = 8.5f;

		internal const float EmissionIntensity = 0.22f;
	}
	[BepInPlugin("y4ngz.lethalcompany.harmonic", "Y4NGZ Harmonic", "1.2.1")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public sealed class Plugin : BaseUnityPlugin
	{
		internal const string BundleFilename = "harmonic.bundle";

		internal const string PrefabName = "Harmonic";

		internal const string DeathEffectName = "DustExplosion";

		internal const string AudioFolderName = "Harmonic";

		internal const string DawnNamespace = "y4ngz_monsters";

		internal const string DawnEnemyKey = "harmonic";

		internal const string BestiaryText = "Harmonic\n\nDanger level: ambient\n\nA passive floating organism that wanders facilities while playing warped music. Its alarm call can briefly draw other creatures toward its location.\n\n";

		internal const float MusicMaxAudibleDistance = 65f;

		internal const float SfxMaxAudibleDistance = 42f;

		internal const float ClearAudioCutoff = 22000f;

		private const string BundleBuilderPath = "Assets/Y4NGZ/Harmonic/Editor/HarmonicAssetBuilder.cs";

		private const int ScanNodeLayerFallback = 22;

		private const double AudioLoadTimeoutSeconds = 10.0;

		internal static ManualLogSource Log;

		internal static HarmonicConfig ModConfig;

		internal static AssetBundle ModAssets;

		internal static EnemyType EnemyType;

		internal static string AssemblyDirectory;

		private static bool _netcodeInitialized;

		private static Material _fallbackParticleMaterial;

		private static Texture2D _runtimeParticleTexture;

		private static readonly Color RuntimeParticleDustColor = new Color(0.52f, 0.5f, 0.46f, 0.72f);

		private static readonly Dictionary<Material, Material> RuntimeParticleMaterials = new Dictionary<Material, Material>();

		private void Awake()
		{
			Log = ((BaseUnityPlugin)this).Logger;
			try
			{
				InitializeNetcodeRPCs();
				ModConfig = new HarmonicConfig(((BaseUnityPlugin)this).Config);
				AssemblyDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
				if (!LoadBundle())
				{
					return;
				}
				GameObject val = ModAssets.LoadAsset<GameObject>("Harmonic");
				if ((Object)(object)val == (Object)null)
				{
					Log.LogError((object)"Prefab 'Harmonic' not found in harmonic.bundle. Bundle contents:");
					DumpBundleAssets();
					return;
				}
				GameObject val2 = ModAssets.LoadAsset<GameObject>("DustExplosion");
				if ((Object)(object)val2 == (Object)null)
				{
					Log.LogWarning((object)"[Harmonic] Death effect 'DustExplosion' not found in harmonic.bundle; death pop will hide the creature without particles.");
				}
				ValidateAuthoredPrefab(val);
				HarmonicAI harmonicAI = PreparePrefab(val, val2);
				LoadLooseAudio(harmonicAI);
				EnemyType = CreateEnemyType(val, harmonicAI);
				((EnemyAI)harmonicAI).enemyType = EnemyType;
				RegisterWithDawn(val);
				if (!ModConfig.Enabled.Value)
				{
					Log.LogInfo((object)"Y4NGZ Harmonic: registered network prefab; spawning disabled by config.");
				}
				Log.LogInfo((object)"Y4NGZ Harmonic v1.2.1 loaded. Registered as 'Harmonic'.");
			}
			catch (Exception arg)
			{
				Log.LogError((object)string.Format("[{0}] Initialization failed: {1}", "Y4NGZ Harmonic", arg));
			}
		}

		private static void RegisterWithDawn(GameObject prefab)
		{
			HarmonicSpawnWeights spawnWeights = new HarmonicSpawnWeights(() => (!ModConfig.Enabled.Value) ? 0f : ModConfig.SpawnWeightMultiplier.Value, () => ModConfig.MoonWeightOverrides.Value, delegate(string message)
			{
				Log.LogWarning((object)message);
			});
			DawnLib.RegisterNetworkPrefab(prefab);
			DawnLib.DefineEnemy(NamespacedKey<DawnEnemyInfo>.From("y4ngz_monsters", "harmonic"), EnemyType, (Action<EnemyInfoBuilder>)delegate(EnemyInfoBuilder builder)
			{
				((BaseInfoBuilder<DawnEnemyInfo, EnemyType, EnemyInfoBuilder>)(object)builder.DefineInside((Action<EnemyLocationBuilder>)delegate(EnemyLocationBuilder location)
				{
					location.SetWeights((Action<WeightTableBuilder<DawnMoonInfo, SpawnWeightContext>>)delegate(WeightTableBuilder<DawnMoonInfo, SpawnWeightContext> table)
					{
						table.SetGlobalWeight((IWeighted)(object)spawnWeights);
					});
				}).CreateBestiaryNode("Harmonic\n\nDanger level: ambient\n\nA passive floating organism that wanders facilities while playing warped music. Its alarm call can briefly draw other creatures toward its location.\n\n").CreateNameKeyword("harmonic")).AddTags((IEnumerable<NamespacedKey>)(object)new NamespacedKey[3]
				{
					Tags.Passive,
					Tags.Organic,
					Tags.Killable
				});
			});
		}

		private static void InitializeNetcodeRPCs()
		{
			if (_netcodeInitialized)
			{
				return;
			}
			_netcodeInitialized = true;
			Type[] types = Assembly.GetExecutingAssembly().GetTypes();
			foreach (Type type in types)
			{
				MethodInfo[] methods;
				try
				{
					methods = type.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				}
				catch
				{
					continue;
				}
				foreach (MethodInfo methodInfo in methods)
				{
					if (methodInfo.GetCustomAttributes(typeof(RuntimeInitializeOnLoadMethodAttribute), inherit: false).Length == 0)
					{
						continue;
					}
					try
					{
						methodInfo.Invoke(null, null);
					}
					catch (Exception ex)
					{
						ManualLogSource log = Log;
						if (log != null)
						{
							log.LogWarning((object)("[NetcodeInit] " + type.Name + "." + methodInfo.Name + " failed: " + ex.Message));
						}
					}
				}
			}
		}

		private static bool LoadBundle()
		{
			if (string.IsNullOrEmpty(AssemblyDirectory))
			{
				Log.LogError((object)"Could not resolve plugin assembly directory.");
				return false;
			}
			string text = Path.Combine(AssemblyDirectory, "harmonic.bundle");
			if (!File.Exists(text))
			{
				Log.LogError((object)("Missing asset bundle: " + text));
				return false;
			}
			ModAssets = AssetBundle.LoadFromFile(text);
			if ((Object)(object)ModAssets == (Object)null)
			{
				Log.LogError((object)("AssetBundle.LoadFromFile returned null for " + text + "."));
				return false;
			}
			return true;
		}

		private static void LoadLooseAudio(HarmonicAI ai)
		{
			string text = Path.Combine(AssemblyDirectory ?? string.Empty, "assets", "Harmonic");
			if (!Directory.Exists(text))
			{
				Log.LogWarning((object)("[Harmonic] Audio directory not found: " + text));
				return;
			}
			List<AudioClip> list = new List<AudioClip>();
			string path = Path.Combine(text, "idle music");
			if (Directory.Exists(path))
			{
				string[] files = Directory.GetFiles(path, "*.mp3", SearchOption.TopDirectoryOnly);
				Array.Sort(files, (IComparer<string>?)StringComparer.OrdinalIgnoreCase);
				for (int i = 0; i < files.Length; i++)
				{
					AudioClip val = LoadAudioClip(files[i]);
					if ((Object)(object)val != (Object)null)
					{
						list.Add(val);
					}
				}
			}
			List<AudioClip> list2 = new List<AudioClip>();
			string[] array = new string[3] { "hit01.wav", "hit02.wav", "hit03.wav" };
			for (int j = 0; j < array.Length; j++)
			{
				AudioClip val2 = LoadAudioClip(Path.Combine(text, array[j]));
				if ((Object)(object)val2 != (Object)null)
				{
					list2.Add(val2);
				}
			}
			ai.idleMusicClips = list.ToArray();
			ai.alarmClip = LoadAudioClip(Path.Combine(text, "alarm.mp3"));
			ai.deathClip = LoadAudioClip(Path.Combine(text, "death.wav"));
			ai.deathPopClip = LoadAudioClip(Path.Combine(text, "pop.mp3"));
			ai.hitClips = list2.ToArray();
			Log.LogInfo((object)$"[Harmonic] Audio loaded. idle={ai.idleMusicClips.Length}, alarm={(Object)(object)ai.alarmClip != (Object)null}, death={(Object)(object)ai.deathClip != (Object)null}, pop={(Object)(object)ai.deathPopClip != (Object)null}, hits={ai.hitClips.Length}.");
		}

		private static AudioClip LoadAudioClip(string path)
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Invalid comparison between Unknown and I4
			if (!File.Exists(path))
			{
				Log.LogWarning((object)("[Harmonic] Audio file not found: " + path));
				return null;
			}
			UnityWebRequest audioClip = UnityWebRequestMultimedia.GetAudioClip("file:///" + path.Replace('\\', '/'), ResolveAudioType(path));
			try
			{
				UnityWebRequestAsyncOperation val = audioClip.SendWebRequest();
				Stopwatch stopwatch = Stopwatch.StartNew();
				while (!((AsyncOperation)val).isDone)
				{
					if (stopwatch.Elapsed.TotalSeconds > 10.0)
					{
						audioClip.Abort();
						Log.LogWarning((object)("[Harmonic] Timed out loading audio " + path + "."));
						return null;
					}
					Thread.Sleep(1);
				}
				if ((int)audioClip.result != 1)
				{
					Log.LogWarning((object)("[Harmonic] Failed to load audio " + path + ": " + audioClip.error));
					return null;
				}
				AudioClip content = DownloadHandlerAudioClip.GetContent(audioClip);
				if ((Object)(object)content != (Object)null)
				{
					((Object)content).name = Path.GetFileNameWithoutExtension(path);
				}
				return content;
			}
			finally
			{
				((IDisposable)audioClip)?.Dispose();
			}
		}

		private static AudioType ResolveAudioType(string path)
		{
			string extension = Path.GetExtension(path);
			if (!string.Equals(extension, ".mp3", StringComparison.OrdinalIgnoreCase))
			{
				if (!string.Equals(extension, ".wav", StringComparison.OrdinalIgnoreCase))
				{
					return (AudioType)0;
				}
				return (AudioType)20;
			}
			return (AudioType)13;
		}

		private static void ValidateAuthoredPrefab(GameObject prefab)
		{
			if ((Object)(object)prefab.transform.Find("VisualRoot") == (Object)null)
			{
				LogBundleError("the VisualRoot child is missing, so the hover visual cannot run");
			}
			if ((Object)(object)prefab.GetComponentInChildren<Animator>(true) == (Object)null)
			{
				LogBundleError("no Animator");
			}
			SkinnedMeshRenderer componentInChildren = prefab.GetComponentInChildren<SkinnedMeshRenderer>(true);
			if ((Object)(object)componentInChildren == (Object)null)
			{
				LogBundleError("no SkinnedMeshRenderer");
			}
			else
			{
				Material[] sharedMaterials = ((Renderer)componentInChildren).sharedMaterials;
				for (int i = 0; i < sharedMaterials.Length; i++)
				{
					Material val = sharedMaterials[i];
					if ((Object)(object)val == (Object)null || (Object)(object)val.shader == (Object)null || !val.shader.isSupported)
					{
						LogBundleError(string.Format("model material slot {0} ('{1}') has no supported shader", i, ((Object)(object)val != (Object)null) ? ((Object)val).name : "null"));
					}
				}
			}
			ScanNodeProperties componentInChildren2 = prefab.GetComponentInChildren<ScanNodeProperties>(true);
			if ((Object)(object)componentInChildren2 == (Object)null)
			{
				LogBundleError("no ScanNode with ScanNodeProperties, so the Harmonic cannot be scanned");
			}
			else
			{
				Collider component = ((Component)componentInChildren2).GetComponent<Collider>();
				if ((Object)(object)component == (Object)null || !component.isTrigger)
				{
					LogBundleError("the ScanNode has no trigger collider");
				}
				int num = LayerMask.NameToLayer("ScanNode");
				if (num < 0)
				{
					num = 22;
				}
				if (((Component)componentInChildren2).gameObject.layer != num)
				{
					LogBundleError($"the ScanNode is on layer {((Component)componentInChildren2).gameObject.layer}, not ScanNode ({num})");
				}
			}
			if ((Object)(object)prefab.GetComponentInChildren<NetworkTransform>(true) != (Object)null)
			{
				LogBundleError("the prefab carries a NetworkTransform; remove it in the builder, because EnemyAI already replicates position through serverPosition and two writers jitter clients");
			}
		}

		private static void LogBundleError(string problem)
		{
			Log.LogError((object)("[Harmonic] harmonic.bundle: " + problem + ". Fix it in Assets/Y4NGZ/Harmonic/Editor/HarmonicAssetBuilder.cs and rebuild the bundle; the plugin does not repair authored parts."));
		}

		private static HarmonicAI PreparePrefab(GameObject prefab, GameObject deathEffect)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			AssignUniqueNetworkHash(prefab, "Harmonic");
			TrySetTag(prefab, "Enemy");
			TrySetLayer(prefab, "Enemies");
			prefab.transform.localScale = Vector3.one * 0.72f;
			HarmonicAI orAddComponent = GetOrAddComponent<HarmonicAI>(prefab);
			((EnemyAI)orAddComponent).updatePositionThreshold = 0.3f;
			Animator componentInChildren = prefab.GetComponentInChildren<Animator>(true);
			if ((Object)(object)componentInChildren != (Object)null)
			{
				componentInChildren.cullingMode = (AnimatorCullingMode)1;
				((EnemyAI)orAddComponent).creatureAnimator = componentInChildren;
			}
			NavMeshAgent orAddComponent2 = GetOrAddComponent<NavMeshAgent>(prefab);
			ConfigureAgent(orAddComponent2);
			((EnemyAI)orAddComponent).agent = orAddComponent2;
			orAddComponent.visualRoot = prefab.transform.Find("VisualRoot");
			((EnemyAI)orAddComponent).eye = GetOrCreateChild(prefab.transform, "EyeTransform", new Vector3(0f, 0.35f, 0.2f));
			orAddComponent.musicSource = GetOrCreateAudioSource(prefab.transform, "HarmonicMusic");
			orAddComponent.sfxSource = GetOrCreateAudioSource(prefab.transform, "HarmonicSFX");
			ApplyAudioDistances(orAddComponent.musicSource, orAddComponent.sfxSource);
			((EnemyAI)orAddComponent).creatureVoice = orAddComponent.musicSource;
			((EnemyAI)orAddComponent).creatureSFX = orAddComponent.sfxSource;
			orAddComponent.glowLight = GetOrCreateLight(prefab.transform);
			orAddComponent.deathEffectPrefab = deathEffect;
			AddScanNodeBody(prefab);
			BuildCollision(prefab, orAddComponent);
			EnsureBehaviourStates(orAddComponent);
			return orAddComponent;
		}

		private static void ConfigureAgent(NavMeshAgent agent)
		{
			agent.speed = Mathf.Max(0.1f, ModConfig.MoveSpeed.Value);
			agent.acceleration = 4.5f;
			agent.angularSpeed = 70f;
			agent.stoppingDistance = 0.55f;
			agent.radius = 0.32f;
			agent.height = 1.25f;
			agent.baseOffset = 0f;
			agent.autoBraking = true;
			agent.autoRepath = true;
			agent.obstacleAvoidanceType = (ObstacleAvoidanceType)4;
			agent.avoidancePriority = 55;
		}

		internal static void ApplyAudioDistances(AudioSource music, AudioSource sfx)
		{
			if ((Object)(object)music != (Object)null)
			{
				music.maxDistance = Mathf.Clamp(ModConfig.MusicMaxDistance.Value, 8f, 65f);
			}
			if ((Object)(object)sfx != (Object)null)
			{
				sfx.maxDistance = Mathf.Clamp(ModConfig.SfxMaxDistance.Value, 8f, 42f);
			}
		}

		private static void EnsureBehaviourStates(HarmonicAI ai)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Expected O, but got Unknown
			//IL_0035: 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_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Expected O, but got Unknown
			//IL_0061: 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_0071: 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_0084: Expected O, but got Unknown
			((EnemyAI)ai).enemyBehaviourStates = (EnemyBehaviourState[])(object)new EnemyBehaviourState[3]
			{
				new EnemyBehaviourState
				{
					name = "Roaming",
					IsAnimTrigger = false,
					parameterString = "Moving",
					boolValue = true
				},
				new EnemyBehaviourState
				{
					name = "Alarm",
					IsAnimTrigger = false,
					parameterString = "Moving",
					boolValue = true
				},
				new EnemyBehaviourState
				{
					name = "Dead",
					IsAnimTrigger = true,
					parameterString = "Death"
				}
			};
			((EnemyAI)ai).currentBehaviourStateIndex = 0;
			((EnemyAI)ai).previousBehaviourStateIndex = 0;
			((EnemyAI)ai).currentBehaviourState = ((EnemyAI)ai).enemyBehaviourStates[0];
		}

		private static void AddScanNodeBody(GameObject prefab)
		{
			ScanNodeProperties componentInChildren = prefab.GetComponentInChildren<ScanNodeProperties>(true);
			if (!((Object)(object)componentInChildren == (Object)null))
			{
				Rigidbody orAddComponent = GetOrAddComponent<Rigidbody>(((Component)componentInChildren).gameObject);
				orAddComponent.isKinematic = true;
				orAddComponent.useGravity = false;
				orAddComponent.detectCollisions = true;
			}
		}

		private static void BuildCollision(GameObject prefab, HarmonicAI ai)
		{
			//IL_0043: 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_00bf: Unknown result type (might be due to invalid IL or missing references)
			float num = 0.72f;
			float num2 = 0.32f / num;
			float num3 = 1.25f / num;
			Vector3 center = default(Vector3);
			((Vector3)(ref center))..ctor(0f, 1.175f / num, 0f);
			CapsuleCollider orAddComponent = GetOrAddComponent<CapsuleCollider>(prefab);
			((Collider)orAddComponent).isTrigger = false;
			orAddComponent.direction = 1;
			orAddComponent.center = center;
			orAddComponent.radius = num2;
			orAddComponent.height = num3;
			Rigidbody orAddComponent2 = GetOrAddComponent<Rigidbody>(prefab);
			orAddComponent2.isKinematic = true;
			orAddComponent2.useGravity = false;
			orAddComponent2.detectCollisions = true;
			Transform orCreateChild = GetOrCreateChild(prefab.transform, "Collision", Vector3.zero);
			TrySetTag(((Component)orCreateChild).gameObject, "Enemy");
			TrySetLayer(((Component)orCreateChild).gameObject, "Enemies");
			CapsuleCollider orAddComponent3 = GetOrAddComponent<CapsuleCollider>(((Component)orCreateChild).gameObject);
			((Collider)orAddComponent3).isTrigger = true;
			orAddComponent3.direction = 1;
			orAddComponent3.center = center;
			orAddComponent3.radius = num2 * 1.15f;
			orAddComponent3.height = num3 * 1.12f;
			Rigidbody orAddComponent4 = GetOrAddComponent<Rigidbody>(((Component)orCreateChild).gameObject);
			orAddComponent4.isKinematic = true;
			orAddComponent4.useGravity = false;
			orAddComponent4.detectCollisions = true;
			EnemyAICollisionDetect orAddComponent5 = GetOrAddComponent<EnemyAICollisionDetect>(((Component)orCreateChild).gameObject);
			orAddComponent5.mainScript = (EnemyAI)(object)ai;
			orAddComponent5.alwaysAllowHitting = true;
			orAddComponent5.canCollideWithEnemies = true;
			orAddComponent5.onlyCollideWhenGrounded = false;
		}

		private static EnemyType CreateEnemyType(GameObject prefab, HarmonicAI ai)
		{
			//IL_0103: Unknown result type (might be due to invalid IL or missing references)
			EnemyType obj = ScriptableObject.CreateInstance<EnemyType>();
			obj.enemyName = "Harmonic";
			obj.enemyPrefab = prefab;
			obj.PowerLevel = ModConfig.PowerLevel.Value;
			obj.DiversityPowerLevel = 1;
			obj.MaxCount = Mathf.Max(1, ModConfig.MaxCount.Value);
			obj.canDie = true;
			obj.canBeStunned = true;
			obj.canBeDestroyed = true;
			obj.stunTimeMultiplier = 1f;
			obj.stunGameDifficultyMultiplier = 1f;
			obj.destroyOnDeath = false;
			obj.doorSpeedMultiplier = 1f;
			obj.isOutsideEnemy = false;
			obj.isDaytimeEnemy = false;
			obj.pushPlayerDistance = 0f;
			obj.pushPlayerForce = 0f;
			obj.normalizedTimeInDayToLeave = 1f;
			obj.probabilityCurve = AnimationCurve.Constant(0f, 1f, 1f);
			obj.numberSpawnedFalloff = AnimationCurve.Linear(0f, 1f, 1f, 0f);
			obj.useNumberSpawnedFalloff = true;
			obj.disableAnimatorWhenFar = false;
			obj.SizeLimit = (NavSizeLimit)0;
			AudioClip stun = ((ai.hitClips != null && ai.hitClips.Length != 0) ? ai.hitClips[0] : null);
			CreatureSfx.Apply(obj, (EnemyAI)(object)ai, stun);
			return obj;
		}

		private static T GetOrAddComponent<T>(GameObject target) where T : Component
		{
			T component = target.GetComponent<T>();
			if (!((Object)(object)component != (Object)null))
			{
				return target.AddComponent<T>();
			}
			return component;
		}

		private static AudioSource GetOrCreateAudioSource(Transform parent, string childName)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			Transform orCreateChild = GetOrCreateChild(parent, childName, Vector3.zero);
			AudioSource val = ((Component)orCreateChild).GetComponent<AudioSource>();
			if ((Object)(object)val == (Object)null)
			{
				val = ((Component)orCreateChild).gameObject.AddComponent<AudioSource>();
				val.playOnAwake = false;
				val.loop = false;
				val.spatialBlend = 1f;
				val.rolloffMode = (AudioRolloffMode)0;
				val.minDistance = 4f;
				val.dopplerLevel = 0f;
				val.spread = 55f;
			}
			if ((Object)(object)((Component)val).GetComponent<AudioLowPassFilter>() == (Object)null)
			{
				AudioLowPassFilter obj = ((Component)val).gameObject.AddComponent<AudioLowPassFilter>();
				obj.cutoffFrequency = 22000f;
				obj.lowpassResonanceQ = 1f;
			}
			return val;
		}

		private static Light GetOrCreateLight(Transform parent)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			Transform orCreateChild = GetOrCreateChild(parent, "HarmonicLight", new Vector3(0f, 1.1f, 0f));
			Light component = ((Component)orCreateChild).GetComponent<Light>();
			if ((Object)(object)component != (Object)null)
			{
				return component;
			}
			component = ((Component)orCreateChild).gameObject.AddComponent<Light>();
			component.type = (LightType)2;
			component.color = new Color(0.34f, 0.24f, 1f, 1f);
			component.intensity = 45f;
			component.range = 8.5f;
			component.shadows = (LightShadows)0;
			component.renderMode = (LightRenderMode)1;
			return component;
		}

		private static Transform GetOrCreateChild(Transform parent, string name, Vector3 localPosition)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: 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)
			Transform val = parent.Find(name);
			if ((Object)(object)val != (Object)null)
			{
				return val;
			}
			val = new GameObject(name).transform;
			val.SetParent(parent, false);
			val.localPosition = localPosition;
			val.localRotation = Quaternion.identity;
			val.localScale = Vector3.one;
			return val;
		}

		internal static Transform FindChildRecursive(Transform parent, string name)
		{
			if ((Object)(object)parent == (Object)null || string.IsNullOrWhiteSpace(name))
			{
				return null;
			}
			if (string.Equals(((Object)parent).name, name, StringComparison.OrdinalIgnoreCase))
			{
				return parent;
			}
			for (int i = 0; i < parent.childCount; i++)
			{
				Transform val = FindChildRecursive(parent.GetChild(i), name);
				if ((Object)(object)val != (Object)null)
				{
					return val;
				}
			}
			return null;
		}

		internal static void RepairParticleRenderers(GameObject root)
		{
			if ((Object)(object)root == (Object)null)
			{
				return;
			}
			Renderer[] componentsInChildren = root.GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val in componentsInChildren)
			{
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				Material[] sharedMaterials = val.sharedMaterials;
				if (sharedMaterials == null || sharedMaterials.Length == 0)
				{
					continue;
				}
				bool flag = false;
				for (int j = 0; j < sharedMaterials.Length; j++)
				{
					Material val2 = sharedMaterials[j];
					if (!((Object)(object)val2 != (Object)null) || ShouldReplaceShader(val2.shader) || !((Object)(object)GetBaseTexture(val2) != (Object)null))
					{
						sharedMaterials[j] = GetOrCreateRuntimeParticleMaterial(val2);
						flag = true;
					}
				}
				if (flag)
				{
					val.sharedMaterials = sharedMaterials;
				}
			}
		}

		private static Material GetOrCreateRuntimeParticleMaterial(Material source)
		{
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Expected O, but got Unknown
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)source != (Object)null && RuntimeParticleMaterials.TryGetValue(source, out var value) && (Object)(object)value != (Object)null)
			{
				return value;
			}
			if ((Object)(object)source == (Object)null && (Object)(object)_fallbackParticleMaterial != (Object)null)
			{
				return _fallbackParticleMaterial;
			}
			Shader val = FindRuntimeParticleShader();
			if ((Object)(object)val == (Object)null)
			{
				return source;
			}
			Material val2 = new Material(val);
			((Object)val2).name = "HarmonicRuntimeParticle";
			((Object)val2).hideFlags = (HideFlags)61;
			Texture texture = (Texture)(((object)GetBaseTexture(source)) ?? ((object)GetOrCreateRuntimeParticleTexture()));
			ApplyBaseTexture(val2, texture);
			ApplyParticleColor(val2, RuntimeParticleDustColor);
			MakeTransparentUnlit(val2);
			if ((Object)(object)source != (Object)null)
			{
				RuntimeParticleMaterials[source] = val2;
			}
			else
			{
				_fallbackParticleMaterial = val2;
			}
			return val2;
		}

		private static Shader FindRuntimeParticleShader()
		{
			string[] array = new string[3] { "Particles/Standard Unlit", "Legacy Shaders/Particles/Alpha Blended", "Sprites/Default" };
			for (int i = 0; i < array.Length; i++)
			{
				Shader val = Shader.Find(array[i]);
				if ((Object)(object)val != (Object)null && val.isSupported)
				{
					return val;
				}
			}
			Shader val2 = Shader.Find("HDRP/Unlit");
			if ((Object)(object)val2 != (Object)null && val2.isSupported)
			{
				return val2;
			}
			return Shader.Find("Unlit/Transparent") ?? FindVisibleShader();
		}

		private static Texture2D GetOrCreateRuntimeParticleTexture()
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Expected O, but got Unknown
			//IL_0176: Unknown result type (might be due to invalid IL or missing references)
			//IL_017b: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_runtimeParticleTexture != (Object)null)
			{
				return _runtimeParticleTexture;
			}
			Texture2D val = new Texture2D(64, 64, (TextureFormat)4, true)
			{
				name = "HarmonicRuntimeDustSprite",
				hideFlags = (HideFlags)61,
				filterMode = (FilterMode)1,
				wrapMode = (TextureWrapMode)1
			};
			Color32[] array = (Color32[])(object)new Color32[4096];
			for (int i = 0; i < 64; i++)
			{
				float num = ((float)i + 0.5f) / 64f * 2f - 1f;
				for (int j = 0; j < 64; j++)
				{
					float num2 = ((float)j + 0.5f) / 64f * 2f - 1f;
					float num3 = Mathf.Atan2(num, num2);
					float num4 = Mathf.Sqrt(num2 * num2 + num * num);
					float num5 = 0.94f + Mathf.Sin(num3 * 3f + 0.45f) * 0.045f + Mathf.Sin(num3 * 7f - 0.8f) * 0.025f;
					float num6 = Mathf.InverseLerp(0.08f, num5, num4);
					float num7 = Mathf.SmoothStep(1f, 0f, num6);
					float num8 = 0.88f + 0.08f * Mathf.Sin(num2 * 8.3f + num * 3.7f) + 0.04f * Mathf.Sin(num * 11.1f - num2 * 2.9f);
					byte b = (byte)Mathf.RoundToInt(Mathf.Clamp01(num7 * num8) * 255f);
					array[i * 64 + j] = new Color32(byte.MaxValue, byte.MaxValue, byte.MaxValue, b);
				}
			}
			val.SetPixels32(array);
			val.Apply(true, true);
			_runtimeParticleTexture = val;
			return val;
		}

		private static void ApplyParticleColor(Material material, Color color)
		{
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)material == (Object)null)
			{
				return;
			}
			string[] array = new string[4] { "_BaseColor", "_Color", "_TintColor", "_UnlitColor" };
			for (int i = 0; i < array.Length; i++)
			{
				if (material.HasProperty(array[i]))
				{
					material.SetColor(array[i], color);
				}
			}
		}

		private static void MakeTransparentUnlit(Material material)
		{
			SetFloatIfPresent(material, "_SurfaceType", 1f);
			SetFloatIfPresent(material, "_BlendMode", 0f);
			SetFloatIfPresent(material, "_AlphaCutoffEnable", 0f);
			SetFloatIfPresent(material, "_SrcBlend", 5f);
			SetFloatIfPresent(material, "_DstBlend", 10f);
			SetFloatIfPresent(material, "_AlphaSrcBlend", 5f);
			SetFloatIfPresent(material, "_AlphaDstBlend", 10f);
			SetFloatIfPresent(material, "_ZWrite", 0f);
			SetFloatIfPresent(material, "_TransparentZWrite", 0f);
			SetFloatIfPresent(material, "_ZTestDepthEqualForOpaque", 4f);
			SetFloatIfPresent(material, "_CullMode", 0f);
			SetFloatIfPresent(material, "_TransparentCullMode", 0f);
			material.SetOverrideTag("RenderType", "Transparent");
			material.EnableKeyword("_SURFACE_TYPE_TRANSPARENT");
			material.EnableKeyword("_BLENDMODE_ALPHA");
			material.EnableKeyword("_ALPHABLEND_ON");
			material.EnableKeyword("_ENABLE_FOG_ON_TRANSPARENT");
			material.DisableKeyword("_BLENDMODE_ADD");
			material.DisableKeyword("_ALPHATEST_ON");
			material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
			material.renderQueue = 3000;
			if ((Object)(object)material.shader != (Object)null && ((Object)material.shader).name.StartsWith("HDRP/", StringComparison.OrdinalIgnoreCase))
			{
				HDMaterial.ValidateMaterial(material);
			}
		}

		private static bool ShouldReplaceShader(Shader shader)
		{
			if (IsInvalidShader(shader))
			{
				return true;
			}
			if (!shader.isSupported)
			{
				return true;
			}
			string text = ((Object)shader).name ?? string.Empty;
			if (!string.Equals(text, "Standard", StringComparison.OrdinalIgnoreCase))
			{
				return text.IndexOf("Universal Render Pipeline", StringComparison.OrdinalIgnoreCase) >= 0;
			}
			return true;
		}

		private static bool IsInvalidShader(Shader shader)
		{
			if ((Object)(object)shader == (Object)null)
			{
				return true;
			}
			return (((Object)shader).name ?? string.Empty).IndexOf("Hidden/InternalErrorShader", StringComparison.OrdinalIgnoreCase) >= 0;
		}

		private static Shader FindVisibleShader()
		{
			return Shader.Find("HDRP/Lit") ?? Shader.Find("HDRP/Unlit") ?? Shader.Find("Standard") ?? Shader.Find("Universal Render Pipeline/Lit") ?? Shader.Find("Unlit/Texture");
		}

		private static Texture GetBaseTexture(Material material)
		{
			if ((Object)(object)material == (Object)null)
			{
				return null;
			}
			string[] array = new string[4] { "_BaseColorMap", "_UnlitColorMap", "_MainTex", "_BaseMap" };
			for (int i = 0; i < array.Length; i++)
			{
				if (material.HasProperty(array[i]))
				{
					Texture texture = material.GetTexture(array[i]);
					if ((Object)(object)texture != (Object)null)
					{
						return texture;
					}
				}
			}
			return null;
		}

		private static void ApplyBaseTexture(Material material, Texture texture)
		{
			if ((Object)(object)material == (Object)null || (Object)(object)texture == (Object)null)
			{
				return;
			}
			string[] array = new string[4] { "_BaseColorMap", "_UnlitColorMap", "_MainTex", "_BaseMap" };
			for (int i = 0; i < array.Length; i++)
			{
				if (material.HasProperty(array[i]))
				{
					material.SetTexture(array[i], texture);
				}
			}
		}

		private static void SetFloatIfPresent(Material material, string property, float value)
		{
			if ((Object)(object)material != (Object)null && material.HasProperty(property))
			{
				material.SetFloat(property, value);
			}
		}

		private static void AssignUniqueNetworkHash(GameObject prefab, string key)
		{
			try
			{
				NetworkObject orAddComponent = GetOrAddComponent<NetworkObject>(prefab);
				uint num = BitConverter.ToUInt32(MD5.Create().ComputeHash(Encoding.UTF8.GetBytes("y4ngz.lethalcompany.harmonic." + key)), 0);
				PropertyInfo property = typeof(NetworkObject).GetProperty("GlobalObjectIdHash", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (property != null && property.CanWrite)
				{
					property.SetValue(orAddComponent, num);
					return;
				}
				FieldInfo fieldInfo = typeof(NetworkObject).GetField("GlobalObjectIdHash", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) ?? typeof(NetworkObject).GetField("<GlobalObjectIdHash>k__BackingField", BindingFlags.Instance | BindingFlags.NonPublic);
				if (fieldInfo != null)
				{
					fieldInfo.SetValue(orAddComponent, num);
				}
			}
			catch (Exception ex)
			{
				Log.LogWarning((object)("[Harmonic] Could not assign NetworkObject hash: " + ex.Message));
			}
		}

		private static void TrySetTag(GameObject obj, string tag)
		{
			try
			{
				obj.tag = tag;
			}
			catch
			{
			}
		}

		private static void TrySetLayer(GameObject obj, string layerName)
		{
			if ((Object)(object)obj == (Object)null)
			{
				return;
			}
			int num = LayerMask.NameToLayer(layerName);
			if (num < 0)
			{
				num = ResolveLayerFallback(layerName);
			}
			if (num >= 0 && num <= 31)
			{
				obj.layer = num;
				return;
			}
			ManualLogSource log = Log;
			if (log != null)
			{
				log.LogWarning((object)$"[Harmonic] Layer '{layerName}' unresolved; '{((Object)obj).name}' stays on layer {obj.layer}.");
			}
		}

		private static int ResolveLayerFallback(string layerName)
		{
			if (string.Equals(layerName, "ScanNode", StringComparison.OrdinalIgnoreCase))
			{
				return 22;
			}
			if (string.Equals(layerName, "Enemies", StringComparison.OrdinalIgnoreCase))
			{
				return 19;
			}
			return -1;
		}

		private static void DumpBundleAssets()
		{
			if (!((Object)(object)ModAssets == (Object)null))
			{
				string[] allAssetNames = ModAssets.GetAllAssetNames();
				foreach (string text in allAssetNames)
				{
					Log.LogError((object)("  - " + text));
				}
			}
		}
	}
	internal static class PluginInfo
	{
		public const string PLUGIN_GUID = "y4ngz.lethalcompany.harmonic";

		public const string PLUGIN_NAME = "Y4NGZ Harmonic";

		public const string PLUGIN_VERSION = "1.2.1";
	}
}
namespace Y4NGZHarmonic.AI
{
	public sealed class HarmonicAI : EnemyAI
	{
		private sealed class HornPulseTarget
		{
			public readonly Transform Transform;

			public readonly Vector3 BaseScale;

			public HornPulseTarget(Transform transform)
			{
				//IL_001f: 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_0024: Unknown result type (might be due to invalid IL or missing references)
				Transform = transform;
				BaseScale = (((Object)(object)transform != (Object)null) ? transform.localScale : Vector3.one);
			}
		}

		private struct AlarmedEnemyState
		{
			public PlayerControllerB TargetPlayer;

			public bool MovingTowardsTargetPlayer;

			public bool MoveTowardsDestination;

			public Vector3 Destination;

			public AISearchRoutine Search;

			public Vector3 ForcedDestination;
		}

		public const int StateRoaming = 0;

		public const int StateAlarm = 1;

		public const int StateDead = 2;

		private const int LocalTrackNone = 0;

		private const int LocalTrackIdle = 1;

		private const int LocalTrackAlarm = 2;

		private const float DistantAudioCutoff = 6500f;

		private const float ObstructedAudioCutoff = 2400f;

		private const float AudioOcclusionInterval = 0.15f;

		private const float CeilingProbeInterval = 0.2f;

		private const float CeilingProbeDistance = 5.5f;

		private const float DamageStunFreezeSeconds = 1f;

		private const float DeathPopDelaySeconds = 0.08f;

		private const float AlarmArrivalReleaseRadius = 4f;

		private const float AlarmArrivalReleaseImmunitySeconds = 1f;

		private const float MovingSpeedThreshold = 0.1f;

		private const float MovementAmountSharpness = 6f;

		private const float NoiseMinLoudness = 0.5f;

		private const float NoiseHearingRange = 20f;

		private const float NoiseMemorySeconds = 3f;

		private const float NoiseReseedCooldown = 4f;

		private const int NoiseMaxRepeatsInOneSpot = 10;

		private static readonly string[] IdleAnimationStates = new string[4] { "Idle_1", "Idle_2", "Idle_3", "Idle_4" };

		private static readonly string[] HornPulseBoneNames = new string[6] { "JNT_Trumpet_a4", "JNT_Trumpet_b4", "JNT_Trumpet_c4", "JNT_Trumpet_d4", "JNT_Trumpet_e4", "JNT_Trumpet_f4" };

		public AISearchRoutine facilitySearch = new AISearchRoutine();

		public Transform visualRoot;

		public AudioSource musicSource;

		public AudioSource sfxSource;

		public Light glowLight;

		public AudioClip[] idleMusicClips;

		public AudioClip alarmClip;

		public AudioClip deathClip;

		public AudioClip deathPopClip;

		public AudioClip[] hitClips;

		public GameObject deathEffectPrefab;

		private readonly ServerOwnershipGuard _ownership = new ServerOwnershipGuard();

		private readonly NoiseMemory _noiseMemory = new NoiseMemory();

		private readonly Dictionary<EnemyAI, AlarmedEnemyState> _alarmedEnemies = new Dictionary<EnemyAI, AlarmedEnemyState>();

		private readonly Dictionary<EnemyAI, float> _alarmReleaseImmunityUntil = new Dictionary<EnemyAI, float>();

		private readonly List<Material> _runtimeMaterials = new List<Material>();

		private readonly List<HornPulseTarget> _hornPulseTargets = new List<HornPulseTarget>();

		private readonly RaycastHit[] _audioOcclusionHits = (RaycastHit[])(object)new RaycastHit[8];

		private readonly RaycastHit[] _ceilingHits = (RaycastHit[])(object)new RaycastHit[8];

		private Coroutine _serverMusicRoutine;

		private Coroutine _deathPresentationRoutine;

		private Vector3 _visualBaseLocalPosition;

		private Vector3 _visualBaseLocalScale = Vector3.one;

		private Quaternion _visualBaseLocalRotation = Quaternion.identity;

		private Vector3 _lastFramePosition;

		private float _planarSpeed;

		private float _movementAmount;

		private float _visualLocalMinY;

		private float _visualLocalMaxY;

		private float _visualHoverVelocity;

		private float _hornPulseAmount;

		private float _hornPulseVelocity;

		private float _desiredHornPulseAmount;

		private float _targetHitInflateAmount;

		private float _hitInflateAmount;

		private float _hitInflateVelocity;

		private float _pulsePhase;

		private float _localClipStartedAt;

		private float _localClipDuration;

		private float _stuckTimer;

		private float _nextSearchRepairTime;

		private float _nextAlarmRefreshTime;

		private float _nextAudioOcclusionUpdateTime;

		private float _nextCeilingProbeTime;

		private float _ceilingClearanceLocal;

		private float _nextNavMeshRepairTime;

		private float _nextNoiseReseedTime;

		private float _damageStunUntil;

		private float _preDamageStunAnimatorSpeed = 1f;

		private int _lastIdleIndex = -1;

		private int _localTrackKind;

		private string _currentAnimationState;

		private AudioLowPassFilter _musicLowPass;

		private AudioLowPassFilter _sfxLowPass;

		private bool _hasCapturedVisualBase;

		private bool _hasVisualBounds;

		private bool _hornPulseTargetsScanned;

		private bool _hasCeilingClearance;

		private bool _localWarningRamp;

		private bool _serverAlarmActive;

		private bool _deathPresentationStarted;

		private bool _deathBodyHidden;

		private bool _damageStunFrozen;

		private bool _wasStunned;

		private bool _audioRouted;

		private bool _configSubscribed;

		private int Health => Plugin.ModConfig?.Health.Value ?? 4;

		private float MoveSpeed => Mathf.Max(0.1f, Plugin.ModConfig?.MoveSpeed.Value ?? 1.15f);

		private float AlarmChance => Mathf.Clamp01(Plugin.ModConfig?.AlarmChance.Value ?? 0.2f);

		private float AlarmRefreshSeconds => 0.35f;

		private float AlarmAttractionRadius => Mathf.Max(0f, Plugin.ModConfig?.AlarmAttractionRadius.Value ?? 30f);

		private float IdleVolume => Mathf.Clamp01(Plugin.ModConfig?.MusicVolume.Value ?? 0.95f);

		private float SfxVolume => Mathf.Clamp01(Plugin.ModConfig?.SfxVolume.Value ?? 1f);

		private float PulseRate => 0.42f;

		private float WarningPulseRate => 1.55f;

		private float PitchPulseAmount => 0.025f;

		private float VolumePulseAmount => 0.08f;

		private float WarningPitchMultiplier => 1.18f;

		private float HoverHeight => 0.55f;

		private float MaxHitInflateAmount => 0.13f;

		private float DeathEffectScale => 0.75f;

		private float RoamSearchWidth => 120f;

		private float RoamSearchPrecision => 8f;

		private float RoamStuckRecoverySeconds => 3.5f;

		private float MovementBobAmount => 0.06f;

		private float MovementTiltDegrees => 4f;

		private float HornPulseScale => 0.06f;

		private float LightBaseIntensity => 45f;

		private float LightPulseIntensity => 35f;

		private float LightRange => 8.5f;

		private float EmissionIntensity => 0.22f;

		private bool DebugLogs => Plugin.ModConfig?.DebugLogs.Value ?? false;

		private bool IsFrozen
		{
			get
			{
				if (!((EnemyAI)(object)this).IsStunned())
				{
					return Time.time < _damageStunUntil;
				}
				return true;
			}
		}

		public override void Awake()
		{
			try
			{
				((EnemyAI)this).Awake();
				ConfigureSearchDefaults();
				_musicLowPass = (((Object)(object)musicSource != (Object)null) ? ((Component)musicSource).GetComponent<AudioLowPassFilter>() : null);
				_sfxLowPass = (((Object)(object)sfxSource != (Object)null) ? ((Component)sfxSource).GetComponent<AudioLowPassFilter>() : null);
			}
			catch (Exception arg)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogError((object)$"[HarmonicAI] Awake failed: {arg}");
				}
			}
		}

		public override void Start()
		{
			//IL_0061: 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)
			try
			{
				CaptureRuntimeMaterials();
				SubscribeConfig();
				ApplyMoveSpeed();
				Plugin.ApplyAudioDistances(musicSource, sfxSource);
				if (((NetworkBehaviour)this).IsServer)
				{
					SnapToInteriorNavMeshIfNeeded(logAlways: true);
				}
				((EnemyAI)this).Start();
				base.enemyHP = Health;
				_pulsePhase = Random.Range(0f, 1000f);
				_lastFramePosition = ((Component)this).transform.position;
				_audioRouted = RouteAudioSources();
				if (((NetworkBehaviour)this).IsServer)
				{
					SwitchState(0);
					EnsureRoamingSearch();
					RestartMusicLoop();
				}
			}
			catch (Exception arg)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogError((object)$"[HarmonicAI] Start failed: {arg}");
				}
			}
		}

		public override void Update()
		{
			try
			{
				_ownership.Ensure((EnemyAI)(object)this, Plugin.Log);
				((EnemyAI)this).Update();
				if (!_audioRouted)
				{
					_audioRouted = RouteAudioSources();
				}
				if (base.isEnemyDead)
				{
					return;
				}
				((EnemyAI)(object)this).TrackStun(ref _wasStunned);
				TrackMovement(Time.deltaTime);
				if (!ApplyDamageStunFreeze())
				{
					if (((NetworkBehaviour)this).IsServer)
					{
						RepairOffNavMeshIfNeeded();
						TickRoamingSearch(Time.deltaTime);
						TickAlarmAttraction();
					}
					TickLocalPulse();
				}
			}
			catch (Exception arg)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogError((object)$"[HarmonicAI] Update failed: {arg}");
				}
			}
		}

		private void LateUpdate()
		{
			try
			{
				if (!_damageStunFrozen && !_deathBodyHidden)
				{
					ApplyHornPulse(Time.deltaTime);
				}
			}
			catch (Exception arg)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogError((object)$"[HarmonicAI] LateUpdate failed: {arg}");
				}
			}
		}

		public override void DoAIInterval()
		{
			try
			{
				if (!((NetworkBehaviour)this).IsServer || base.isEnemyDead)
				{
					return;
				}
				if (IsFrozen)
				{
					((EnemyAI)(object)this).HoldAgent();
					((EnemyAI)this).SyncPositionToClients();
					return;
				}
				RepairOffNavMeshIfNeeded();
				if (!((Object)(object)base.agent == (Object)null) && ((Behaviour)base.agent).enabled && base.agent.isOnNavMesh)
				{
					((EnemyAI)this).DoAIInterval();
					if (!((Object)(object)StartOfRound.Instance == (Object)null) && !StartOfRound.Instance.allPlayersDead && (base.currentBehaviourStateIndex == 0 || base.currentBehaviourStateIndex == 1) && !TryReseedSearchAtNoise())
					{
						EnsureRoamingSearch();
					}
				}
			}
			catch (Exception arg)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogError((object)$"[HarmonicAI] DoAIInterval failed: {arg}");
				}
			}
		}

		public override void HitEnemy(int force = 1, PlayerControllerB playerWhoHit = null, bool playHitSFX = false, int hitID = -1)
		{
			try
			{
				((EnemyAI)this).HitEnemy(force, playerWhoHit, playHitSFX, hitID);
				if (base.isEnemyDead)
				{
					return;
				}
				BeginDamageStunFreeze();
				if (((NetworkBehaviour)this).IsServer)
				{
					base.enemyHP -= Mathf.Max(1, force);
					if (base.enemyHP <= 0)
					{
						((EnemyAI)this).KillEnemyOnOwnerClient(false);
						return;
					}
					PlayHitClientRpc(PickHitClipIndex(), Random.Range(0.92f, 1.08f), CalculateHitInflateAmount(base.enemyHP));
					RestartMusicLoop();
				}
			}
			catch (Exception arg)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogError((object)$"[HarmonicAI] HitEnemy failed: {arg}");
				}
			}
		}

		public override void DetectNoise(Vector3 noisePosition, float noiseLoudness, int timesPlayedInOneSpot = 0, int noiseID = 0)
		{
			//IL_0001: 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)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			((EnemyAI)this).DetectNoise(noisePosition, noiseLoudness, timesPlayedInOneSpot, noiseID);
			if (((NetworkBehaviour)this).IsServer && !base.isEnemyDead && !IsFrozen && timesPlayedInOneSpot <= 10 && base.currentBehaviourStateIndex == 0)
			{
				_noiseMemory.Record(noisePosition, noiseLoudness, 0.5f, ((Component)this).transform.position, 20f);
			}
		}

		public override void KillEnemy(bool destroy = false)
		{
			StopServerMusicLoop();
			if (((NetworkBehaviour)this).IsServer)
			{
				EndAlarmAttraction(returnToRoaming: false);
			}
			StopLocalMusic();
			EndDamageStunFreeze();
			((EnemyAI)this).KillEnemy(destroy);
			if (base.isEnemyDead)
			{
				if (((NetworkBehaviour)this).IsServer)
				{
					SwitchState(2);
				}
				BeginDeathPresentation();
			}
		}

		public override void OnDestroy()
		{
			try
			{
				UnsubscribeConfig();
				StopServerMusicLoop();
				_serverAlarmActive = false;
				ReleaseAllAlarmedEnemies();
				if (_deathPresentationRoutine != null)
				{
					((MonoBehaviour)this).StopCoroutine(_deathPresentationRoutine);
					_deathPresentationRoutine = null;
				}
				DestroyRuntimeMaterials();
			}
			finally
			{
				((EnemyAI)this).OnDestroy();
			}
		}

		private void SubscribeConfig()
		{
			HarmonicConfig modConfig = Plugin.ModConfig;
			if (!_configSubscribed && modConfig != null)
			{
				modConfig.MoveSpeed.SettingChanged += OnMoveSpeedChanged;
				modConfig.MusicMaxDistance.SettingChanged += OnAudioDistanceChanged;
				modConfig.SfxMaxDistance.SettingChanged += OnAudioDistanceChanged;
				_configSubscribed = true;
			}
		}

		private void UnsubscribeConfig()
		{
			HarmonicConfig modConfig = Plugin.ModConfig;
			if (_configSubscribed && modConfig != null)
			{
				modConfig.MoveSpeed.SettingChanged -= OnMoveSpeedChanged;
				modConfig.MusicMaxDistance.SettingChanged -= OnAudioDistanceChanged;
				modConfig.SfxMaxDistance.SettingChanged -= OnAudioDistanceChanged;
				_configSubscribed = false;
			}
		}

		private void OnMoveSpeedChanged(object sender, EventArgs e)
		{
			ApplyMoveSpeed();
		}

		private void OnAudioDistanceChanged(object sender, EventArgs e)
		{
			Plugin.ApplyAudioDistances(musicSource, sfxSource);
		}

		private void ApplyMoveSpeed()
		{
			if ((Object)(object)base.agent != (Object)null)
			{
				base.agent.speed = MoveSpeed;
			}
		}

		private bool RouteAudioSources()
		{
			bool num = CreatureAudioSetup.ConfigureSpatial(musicSource, occlude: false);
			bool flag = CreatureAudioSetup.ConfigureSpatial(sfxSource, occlude: false);
			return num && flag;
		}

		private void RestartMusicLoop()
		{
			if (((NetworkBehaviour)this).IsServer && !base.isEnemyDead)
			{
				StopServerMusicLoop();
				EndAlarmAttraction(returnToRoaming: true);
				StopMusicClientRpc();
				_serverMusicRoutine = ((MonoBehaviour)this).StartCoroutine(ServerMusicLoop());
			}
		}

		private void StopServerMusicLoop()
		{
			if (_serverMusicRoutine != null)
			{
				((MonoBehaviour)this).StopCoroutine(_serverMusicRoutine);
				_serverMusicRoutine = null;
			}
		}

		private IEnumerator ServerMusicLoop()
		{
			yield return (object)new WaitForSeconds(0.05f);
			if (!HasIdleMusic())
			{
				yield break;
			}
			bool nextWillAlarm = RollAlarm();
			while (!base.isEnemyDead)
			{
				int num = PickIdleClipIndex();
				if (num < 0)
				{
					break;
				}
				SwitchState(0);
				PlayIdleClientRpc(num, nextWillAlarm, Random.Range(0f, 1000f));
				yield return (object)new WaitForSeconds(GetIdleClipLength(num));
				if (base.isEnemyDead)
				{
					break;
				}
				if (nextWillAlarm && (Object)(object)alarmClip != (Object)null)
				{
					SwitchState(1);
					PlayAlarmClientRpc(Random.Range(0f, 1000f));
					BeginAlarmAttraction();
					yield return (object)new WaitForSeconds(Mathf.Max(0.5f, alarmClip.length));
					EndAlarmAttraction(returnToRoaming: true);
					if (base.isEnemyDead)
					{
						break;
					}
				}
				nextWillAlarm = RollAlarm();
			}
		}

		private bool HasIdleMusic()
		{
			if (idleMusicClips == null)
			{
				return false;
			}
			for (int i = 0; i < idleMusicClips.Length; i++)
			{
				if ((Object)(object)idleMusicClips[i] != (Object)null)
				{
					return true;
				}
			}
			return false;
		}

		private bool RollAlarm()
		{
			if ((Object)(object)alarmClip != (Object)null)
			{
				return Random.value < AlarmChance;
			}
			return false;
		}

		private int PickIdleClipIndex()
		{
			if (idleMusicClips == null || idleMusicClips.Length == 0)
			{
				return -1;
			}
			int num = Random.Range(0, idleMusicClips.Length);
			for (int i = 0; i < idleMusicClips.Length; i++)
			{
				int num2 = (num + i) % idleMusicClips.Length;
				if (!((Object)(object)idleMusicClips[num2] == (Object)null) && (idleMusicClips.Length <= 1 || num2 != _lastIdleIndex))
				{
					_lastIdleIndex = num2;
					return num2;
				}
			}
			for (int j = 0; j < idleMusicClips.Length; j++)
			{
				if ((Object)(object)idleMusicClips[j] != (Object)null)
				{
					_lastIdleIndex = j;
					return j;
				}
			}
			return -1;
		}

		private float GetIdleClipLength(int index)
		{
			AudioClip val = ((idleMusicClips != null && index >= 0 && index < idleMusicClips.Length) ? idleMusicClips[index] : null);
			return Mathf.Max(0.5f, ((Object)(object)val != (Object)null) ? val.length : 5f);
		}

		private int PickHitClipIndex()
		{
			if (hitClips == null || hitClips.Length == 0)
			{
				return -1;
			}
			int num = Random.Range(0, hitClips.Length);
			for (int i = 0; i < hitClips.Length; i++)
			{
				int num2 = (num + i) % hitClips.Length;
				if ((Object)(object)hitClips[num2] != (Object)null)
				{
					return num2;
				}
			}
			return -1;
		}

		private float CalculateHitInflateAmount(int hpAfterDamage)
		{
			int num = Mathf.Max(1, Health);
			float num2 = Mathf.Clamp01((float)(num - Mathf.Max(0, hpAfterDamage)) / (float)num);
			return MaxHitInflateAmount * num2;
		}

		private Vector3 ResolveDeathEffectPosition()
		{
			//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_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			if (TryGetRendererBounds(((Component)this).gameObject, out var bounds))
			{
				return ((Bounds)(ref bounds)).center;
			}
			return ((Component)this).transform.position + Vector3.up * 1.15f;
		}

		private void BeginAlarmAttraction()
		{
			if (((NetworkBehaviour)this).IsServer)
			{
				_serverAlarmActive = true;
				_nextAlarmRefreshTime = 0f;
				RefreshAlarmAttraction();
			}
		}

		private void TickAlarmAttraction()
		{
			if (_serverAlarmActive && !(Time.time < _nextAlarmRefreshTime))
			{
				RefreshAlarmAttraction();
			}
		}

		private void RefreshAlarmAttraction()
		{
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			if (!_serverAlarmActive || (Object)(object)RoundManager.Instance == (Object)null)
			{
				return;
			}
			_nextAlarmRefreshTime = Time.time + AlarmRefreshSeconds;
			List<EnemyAI> spawnedEnemies = RoundManager.Instance.SpawnedEnemies;
			if (spawnedEnemies == null)
			{
				return;
			}
			for (int i = 0; i < spawnedEnemies.Count; i++)
			{
				EnemyAI val = spawnedEnemies[i];
				if ((Object)(object)val == (Object)null || (Object)(object)val == (Object)(object)this || val is HarmonicAI)
				{
					continue;
				}
				bool flag = _alarmedEnemies.ContainsKey(val);
				if (!CanPull(val))
				{
					if (flag)
					{
						ReleaseAlarmedEnemy(val, grantImmunity: false);
					}
					continue;
				}
				Vector3 val2 = ((Component)val).transform.position - ((Component)this).transform.position;
				float sqrMagnitude = ((Vector3)(ref val2)).sqrMagnitude;
				if (flag && sqrMagnitude <= 16f)
				{
					ReleaseAlarmedEnemy(val, grantImmunity: true);
					continue;
				}
				float alarmAttractionRadius = AlarmAttractionRadius;
				if (sqrMagnitude > alarmAttractionRadius * alarmAttractionRadius)
				{
					if (flag)
					{
						ReleaseAlarmedEnemy(val, grantImmunity: false);
					}
				}
				else if ((flag || !(sqrMagnitude <= 16f)) && (flag || !IsTemporarilyImmuneToAlarm(val)))
				{
					AttractEnemy(val);
				}
			}
		}

		private static bool CanPull(EnemyAI enemy)
		{
			if (!enemy.isEnemyDead && !enemy.isOutside && ((NetworkBehaviour)enemy).IsSpawned && ((NetworkBehaviour)enemy).IsOwner && !enemy.inSpecialAnimation && !enemy.IsStunned() && (Object)(object)enemy.agent != (Object)null && ((Behaviour)enemy.agent).enabled)
			{
				return enemy.agent.isOnNavMesh;
			}
			return false;
		}

		private void AttractEnemy(EnemyAI enemy)
		{
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			if (!_alarmedEnemies.TryGetValue(enemy, out var value))
			{
				AISearchRoutine val = ((enemy.currentSearch != null && enemy.currentSearch.inProgress) ? enemy.currentSearch : null);
				value = new AlarmedEnemyState
				{
					TargetPlayer = enemy.targetPlayer,
					MovingTowardsTargetPlayer = enemy.movingTowardsTargetPlayer,
					MoveTowardsDestination = enemy.moveTowardsDestination,
					Destination = enemy.destination,
					Search = val
				};
				if (val != null)
				{
					enemy.StopSearch(val, false);
				}
			}
			enemy.targetPlayer = null;
			enemy.movingTowardsTargetPlayer = false;
			enemy.SetDestinationToPosition(ResolveAlarmDestinationFor(enemy), false);
			value.ForcedDestination = enemy.destination;
			_alarmedEnemies[enemy] = value;
		}

		private Vector3 ResolveAlarmDestinationFor(EnemyAI enemy)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: 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)
			Vector3 position = ((Component)this).transform.position;
			int num = (((Object)(object)enemy.agent != (Object)null) ? enemy.agent.areaMask : (-1));
			NavMeshHit val = default(NavMeshHit);
			if (NavMesh.SamplePosition(position, ref val, 8f, num))
			{
				return ((NavMeshHit)(ref val)).position;
			}
			return position;
		}

		private bool IsTemporarilyImmuneToAlarm(EnemyAI enemy)
		{
			if (!_alarmReleaseImmunityUntil.TryGetValue(enemy, out var value))
			{
				return false;
			}
			if (Time.time < value)
			{
				return true;
			}
			_alarmReleaseImmunityUntil.Remove(enemy);
			return false;
		}

		private void ReleaseAlarmedEnemy(EnemyAI enemy, bool grantImmunity)
		{
			if (_alarmedEnemies.TryGetValue(enemy, out var value))
			{
				_alarmedEnemies.Remove(enemy);
				RestoreAlarmedEnemy(enemy, value);
				if (grantImmunity && !enemy.isEnemyDead)
				{
					_alarmReleaseImmunityUntil[enemy] = Time.time + 1f;
				}
			}
		}

		private void EndAlarmAttraction(bool returnToRoaming)
		{
			if (_serverAlarmActive || _alarmedEnemies.Count != 0)
			{
				_serverAlarmActive = false;
				ReleaseAllAlarmedEnemies();
				if (returnToRoaming && !base.isEnemyDead)
				{
					SwitchState(0);
				}
			}
		}

		private void ReleaseAllAlarmedEnemies()
		{
			foreach (KeyValuePair<EnemyAI, AlarmedEnemyState> alarmedEnemy in _alarmedEnemies)
			{
				RestoreAlarmedEnemy(alarmedEnemy.Key, alarmedEnemy.Value);
			}
			_alarmedEnemies.Clear();
			_alarmReleaseImmunityUntil.Clear();
		}

		private static void RestoreAlarmedEnemy(EnemyAI enemy, AlarmedEnemyState state)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: 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_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			if (CanRestore(enemy))
			{
				if (enemy.destination == state.ForcedDestination)
				{
					enemy.moveTowardsDestination = state.MoveTowardsDestination;
					enemy.destination = state.Destination;
				}
				if (state.Search != null && enemy.currentSearch == state.Search && !state.Search.inProgress)
				{
					enemy.StartSearch(state.Search.currentSearchStartPosition, state.Search);
				}
				if ((Object)(object)enemy.targetPlayer == (Object)null && (Object)(object)state.TargetPlayer != (Object)null && enemy.PlayerIsTargetable(state.TargetPlayer, false, false, true))
				{
					enemy.targetPlayer = state.TargetPlayer;
					enemy.movingTowardsTargetPlayer = state.MovingTowardsTargetPlayer;
				}
			}
		}

		private static bool CanRestore(EnemyAI enemy)
		{
			NetworkManager singleton = NetworkManager.Singleton;
			if ((Object)(object)enemy != (Object)null && (Object)(object)singleton != (Object)null && !singleton.ShutdownInProgress && ((NetworkBehaviour)enemy).IsSpawned && ((NetworkBehaviour)enemy).IsOwner && ((Behaviour)enemy).isActiveAndEnabled)
			{
				return !enemy.isEnemyDead;
			}
			return false;
		}

		[ClientRpc]
		private void PlayIdleClientRpc(int clipIndex, bool warningRamp, float phase)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Invalid comparison between Unknown and I4
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Invalid comparison between Unknown and I4
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: 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_0104: Unknown result type (might be due to invalid IL or missing references)
			NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager;
			if (networkManager != null && networkManager.IsListening)
			{
				if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 && (networkManager.IsServer || networkManager.IsHost))
				{
					ClientRpcParams val2 = default(ClientRpcParams);
					FastBufferWriter val = ((NetworkBehaviour)this).__beginSendClientRpc(2294735284u, val2, (RpcDelivery)0);
					BytePacker.WriteValueBitPacked(val, clipIndex);
					((FastBufferWriter)(ref val)).WriteValueSafe<bool>(ref warningRamp, default(ForPrimitives));
					((FastBufferWriter)(ref val)).WriteValueSafe<float>(ref phase, default(ForPrimitives));
					((NetworkBehaviour)this).__endSendClientRpc(ref val, 2294735284u, val2, (RpcDelivery)0);
				}
				if ((int)((NetworkBehaviour)this).__rpc_exec_stage == 1 && (networkManager.IsClient || networkManager.IsHost))
				{
					((NetworkBehaviour)this).__rpc_exec_stage = (__RpcExecStage)0;
					AudioClip clip = ((idleMusicClips != null && clipIndex >= 0 && clipIndex < idleMusicClips.Length) ? idleMusicClips[clipIndex] : null);
					PlayLocalMusicClip(1, clipIndex, clip, warningRamp, phase);
				}
			}
		}

		[ClientRpc]
		private void PlayAlarmClientRpc(float phase)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Invalid comparison between Unknown and I4
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Invalid comparison between Unknown and I4
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager;
			if (networkManager != null && networkManager.IsListening)
			{
				if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 && (networkManager.IsServer || networkManager.IsHost))
				{
					ClientRpcParams val2 = default(ClientRpcParams);
					FastBufferWriter val = ((NetworkBehaviour)this).__beginSendClientRpc(643380925u, val2, (RpcDelivery)0);
					((FastBufferWriter)(ref val)).WriteValueSafe<float>(ref phase, default(ForPrimitives));
					((NetworkBehaviour)this).__endSendClientRpc(ref val, 643380925u, val2, (RpcDelivery)0);
				}
				if ((int)((NetworkBehaviour)this).__rpc_exec_stage == 1 && (networkManager.IsClient || networkManager.IsHost))
				{
					((NetworkBehaviour)this).__rpc_exec_stage = (__RpcExecStage)0;
					PlayLocalMusicClip(2, -1, alarmClip, warningRamp: false, phase);
				}
			}
		}

		[ClientRpc]
		private void StopMusicClientRpc()
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Invalid comparison between Unknown and I4
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Invalid comparison between Unknown and I4
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager;
			if (networkManager != null && networkManager.IsListening)
			{
				if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 && (networkManager.IsServer || networkManager.IsHost))
				{
					ClientRpcParams val2 = default(ClientRpcParams);
					FastBufferWriter val = ((NetworkBehaviour)this).__beginSendClientRpc(4194604744u, val2, (RpcDelivery)0);
					((NetworkBehaviour)this).__endSendClientRpc(ref val, 4194604744u, val2, (RpcDelivery)0);
				}
				if ((int)((NetworkBehaviour)this).__rpc_exec_stage == 1 && (networkManager.IsClient || networkManager.IsHost))
				{
					((NetworkBehaviour)this).__rpc_exec_stage = (__RpcExecStage)0;
					StopLocalMusic();
				}
			}
		}

		[ClientRpc]
		private void PlayHitClientRpc(int clipIndex, float pitch, float inflateAmount)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Invalid comparison between Unknown and I4
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Invalid comparison between Unknown and I4
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: 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_0104: Unknown result type (might be due to invalid IL or missing references)
			NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager;
			if (networkManager == null || !networkManager.IsListening)
			{
				return;
			}
			if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 && (networkManager.IsServer || networkManager.IsHost))
			{
				ClientRpcParams val2 = default(ClientRpcParams);
				FastBufferWriter val = ((NetworkBehaviour)this).__beginSendClientRpc(1244013670u, val2, (RpcDelivery)0);
				BytePacker.WriteValueBitPacked(val, clipIndex);
				((FastBufferWriter)(ref val)).WriteValueSafe<float>(ref pitch, default(ForPrimitives));
				((FastBufferWriter)(ref val)).WriteValueSafe<float>(ref inflateAmount, default(ForPrimitives));
				((NetworkBehaviour)this).__endSendClientRpc(ref val, 1244013670u, val2, (RpcDelivery)0);
			}
			if ((int)((NetworkBehaviour)this).__rpc_exec_stage == 1 && (networkManager.IsClient || networkManager.IsHost))
			{
				((NetworkBehaviour)this).__rpc_exec_stage = (__RpcExecStage)0;
				SetInflationTarget(inflateAmount);
				AudioClip val3 = ((hitClips != null && clipIndex >= 0 && clipIndex < hitClips.Length) ? hitClips[clipIndex] : null);
				if (!((Object)(object)val3 == (Object)null) && !((Object)(object)sfxSource == (Object)null))
				{
					sfxSource.pitch = Mathf.Clamp(pitch, 0.75f, 1.3f);
					CreatureAudioSetup.TransmitOneShot(sfxSource, val3, SfxVolume);
				}
			}
		}

		private void PlayLocalMusicClip(int kind, int clipIndex, AudioClip clip, bool warningRamp, float phase)
		{
			if (!((Object)(object)musicSource == (Object)null) && !((Object)(object)clip == (Object)null) && !base.isEnemyDead)
			{
				CrossFadeAnimationForTrack(kind, clipIndex, warningRamp);
				bool flag = kind == 2;
				musicSource.Stop();
				musicSource.clip = clip;
				musicSource.loop = false;
				musicSource.pitch = 1f;
				musicSource.volume = ResolveEffectiveMusicVolume(flag);
				musicSource.Play();
				if (flag)
				{
					WalkieTalkie.TransmitOneShotAudio(musicSource, clip, musicSource.volume);
				}
				_pulsePhase = phase;
				_localTrackKind = kind;
				_localWarningRamp = warningRamp;
				_localClipStartedAt = Time.time;
				_localClipDuration = Mathf.Max(0.1f, clip.length);
			}
		}

		private void StopLocalMusic()
		{
			if ((Object)(object)musicSource != (Object)null)
			{
				musicSource.Stop();
				musicSource.pitch = 1f;
			}
			_localTrackKind = 0;
			_localWarningRamp = false;
			_desiredHornPulseAmount = 0f;
		}

		private void CrossFadeAnimationForTrack(int kind, int clipIndex, bool warningRamp)
		{
			if (!((Object)(object)base.creatureAnimator == (Object)null) && IdleAnimationStates.Length != 0)
			{
				string text;
				if (kind == 2)
				{
					text = "Idle_4";
				}
				else if (warningRamp)
				{
					text = "Idle_3";
				}
				else
				{
					int num = Mathf.Abs(clipIndex) % IdleAnimationStates.Length;
					text = IdleAnimationStates[num];
				}
				if (!string.Equals(_currentAnimationState, text, StringComparison.Ordinal))
				{
					base.creatureAnimator.CrossFade(text, 0.35f, 0, 0f);
					_currentAnimationState = text;
				}
			}
		}

		private void TrackMovement(float deltaTime)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: 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_000e: 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_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			Vector3 position = ((Component)this).transform.position;
			Vector3 val = position - _lastFramePosition;
			val.y = 0f;
			_lastFramePosition = position;
			_planarSpeed = ((deltaTime > 0f) ? (((Vector3)(ref val)).magnitude / deltaTime) : 0f);
			float num = Mathf.Clamp01(_planarSpeed / MoveSpeed);
			_movementAmount = Mathf.Lerp(_movementAmount, num, 1f - Mathf.Exp((0f - deltaTime) * 6f));
		}

		private void TickLocalPulse()
		{
			TickAudioOcclusion();
			float warningAmount = GetWarningAmount();
			bool flag = _localTrackKind == 2;
			float num = (flag ? 1f : warningAmount);
			float num2 = Mathf.Lerp(PulseRate, WarningPulseRate, num);
			float num3 = (Mathf.Sin((Time.time + _pulsePhase) * num2 * MathF.PI * 2f) + 1f) * 0.5f;
			float centeredPulse = num3 * 2f - 1f;
			TickMusicModulation(warningAmount, flag, centeredPulse);
			TickLightAndEmission(num3, num);
			TickAnimatorSpeed(num);
			TickVisualHover(num3, num);
			TickHornPulseTarget(num3, num);
		}

		private float GetWarningAmount()
		{
			if (!_localWarningRamp || _localTrackKind != 1 || _localClipDuration <= 0f)
			{
				return 0f;
			}
			float num = Mathf.Clamp01((Time.time - _localClipStartedAt) / _localClipDuration);
			return Mathf.SmoothStep(0f, 1f, num);
		}

		private void TickMusicModulation(float warningAmount, bool alarmActive, float centeredPulse)
		{
			if (!((Object)(object)musicSource == (Object)null) && musicSource.isPlaying)
			{
				float num = ResolveEffectiveMusicVolume(alarmActive);
				float num2 = (alarmActive ? 1f : Mathf.Lerp(1f, WarningPitchMultiplier, warningAmount));
				float num3 = centeredPulse * PitchPulseAmount * (alarmActive ? 1.35f : 1f);
				float num4 = centeredPulse * VolumePulseAmount * (alarmActive ? 1.25f : 1f);
				musicSource.pitch = Mathf.Clamp(num2 + num3, 0.65f, 1.65f);
				musicSource.volume = Mathf.Clamp01(num * (1f + num4 + warningAmount * 0.12f));
			}
		}

		private void TickLightAndEmission(float pulse, float urgency)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: 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)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: 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_0080: 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)
			Color val = Color.Lerp(new Color(0.28f, 0.18f, 0.72f, 1f), new Color(0.72f, 0.36f, 0.9f, 1f), urgency);
			float intensity = LightBaseIntensity + LightPulseIntensity * Mathf.Lerp(pulse * 0.55f, 1f, urgency * 0.35f);
			if ((Object)(object)glowLight != (Object)null)
			{
				((Behaviour)glowLight).enabled = true;
				glowLight.color = val;
				glowLight.range = LightRange;
				glowLight.intensity = intensity;
			}
			Color color = val * (EmissionIntensity * Mathf.Lerp(0.08f + pulse * 0.14f, 0.42f, urgency * 0.55f));
			for (int i = 0; i < _runtimeMaterials.Count; i++)
			{
				ApplyEmission(_runtimeMaterials[i], color);
			}
		}

		private void TickAnimatorSpeed(float urgency)
		{
			if ((Object)(object)base.creatureAnimator != (Object)null)
			{
				base.creatureAnimator.speed = Mathf.Clamp(1f + urgency * 0.1f, 0.85f, 1.25f);
			}
		}

		private void TickVisualHover(float pulse, float urgency)
		{
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: 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_0047: 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_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_0157: Unknown result type (might be due to invalid IL or missing references)
			//IL_015c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0160: 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_01cf: 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_01e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_0211: 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_021a: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)visualRoot == (Object)null) && !((Object)(object)visualRoot == (Object)(object)((Component)this).transform))
			{
				if (!_hasCapturedVisualBase)
				{
					_visualBaseLocalPosition = visualRoot.localPosition;
					_visualBaseLocalRotation = visualRoot.localRotation;
					_visualBaseLocalScale = visualRoot.localScale;
					_hasCapturedVisualBase = true;
					CaptureVisualBounds();
				}
				float num = Mathf.Max(0.05f, Mathf.Abs(((Component)this).transform.lossyScale.y));
				float num2 = HoverHeight / num;
				float num3 = Mathf.Lerp(0.018f, 0.04f, urgency) * (pulse * 2f - 1f) / num;
				float num4 = Mathf.Sin((Time.time + _pulsePhase * 0.17f) * MathF.PI * 2f * 0.72f) * MovementBobAmount * _movementAmount / num;
				float num5 = num3 + num4;
				float num6 = (_hasVisualBounds ? (num2 - _visualLocalMinY + num5) : (_visualBaseLocalPosition.y + num2 + num5));
				RefreshCeilingClearance();
				if (_hasVisualBounds && _hasCeilingClearance)
				{
					float num7 = 0.18f / num;
					float num8 = _ceilingClearanceLocal - num7 - _visualLocalMaxY;
					num6 = Mathf.Min(num6, num8);
				}
				Vector3 localPosition = visualRoot.localPosition;
				localPosition.y = Mathf.SmoothDamp(localPosition.y, num6, ref _visualHoverVelocity, 0.18f, 6f, Time.deltaTime);
				visualRoot.localPosition = localPosition;
				float num9 = Mathf.Sin((Time.time + _pulsePhase * 0.11f) * MathF.PI * 2f * 0.55f) * MovementTiltDegrees * _movementAmount;
				Quaternion val = _visualBaseLocalRotation * Quaternion.Euler(0f, 0f, num9);
				float num10 = 1f - Mathf.Exp((0f - Time.deltaTime) * 5f);
				visualRoot.localRotation = Quaternion.Slerp(visualRoot.localRotation, val, num10);
				TickVisualInflation(Time.deltaTime);
			}
		}

		private void SetInflationTarget(float inflateAmount)
		{
			_targetHitInflateAmount = Mathf.Max(_targetHitInflateAmount, Mathf.Clamp(inflateAmount, 0f, MaxHitInflateAmount));
		}

		private void TickVisualInflation(float deltaTime)
		{
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)visualRoot == (Object)null) && !_deathBodyHidden)
			{
				_hitInflateAmount = Mathf.SmoothDamp(_hitInflateAmount, _targetHitInflateAmount, ref _hitInflateVelocity, 0.12f, 8f, Mathf.Max(0.0001f, deltaTime));
				visualRoot.localScale = _visualBaseLocalScale * (1f + _hitInflateAmount);
			}
		}

		private void BeginDeathPresentation()
		{
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			if (!_deathPresentationStarted)
			{
				_deathPresentationStarted = true;
				_desiredHornPulseAmount = 0f;
				AudioClip val = (((Object)(object)deathPopClip != (Object)null) ? deathPopClip : deathClip);
				if ((Object)(object)sfxSource != (Object)null && (Object)(object)val != (Object)null)
				{
					sfxSource.pitch = 1f;
					CreatureAudioSetup.TransmitOneShot(sfxSource, val, SfxVolume);
				}
				_deathPresentationRoutine = ((MonoBehaviour)this).StartCoroutine(DeathPopPresentation(ResolveDeathEffectPosition()));
			}
		}

		private IEnumerator DeathPopPresentation(Vector3 effectPosition)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			_targetHitInflateAmount = MaxHitInflateAmount;
			_hitInflateAmount = MaxHitInflateAmount;
			if ((Object)(object)visualRoot != (Object)null)
			{
				visualRoot.localScale = _visualBaseLocalScale * (1f + _hitInflateAmount);
			}
			yield return (object)new WaitForSeconds(0.08f);
			SpawnDeathEffect(effectPosition);
			SpawnDeathBloodSplatter(effectPosition);
			HideDeathBody();
			_deathPresentationRoutine = null;
		}

		private void SpawnDeathBloodSplatter(Vector3 point)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: 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)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: 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_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: 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_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: 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_0107: 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_0113: 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_0147: Unknown result type (might be due to invalid IL 

Y4NGZPoltergeist.dll

Decompiled a week ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using Dawn;
using GameNetcodeStuff;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Unity.Netcode;
using Unity.Netcode.Components;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.Animations;
using UnityEngine.Audio;
using UnityEngine.Events;
using UnityEngine.Networking;
using UnityEngine.Playables;
using UnityEngine.Rendering;
using UnityEngine.SceneManagement;
using Y4NGZMonsters.Shared;
using Y4NGZPoltergeist.AI;
using Y4NGZPoltergeist.NetcodePatcher;
using Y4NGZPoltergeist.Patches;

[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("Y4NGZPoltergeist")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+c64a155fd64c47528940e53659e5b5ada665b9d4")]
[assembly: AssemblyProduct("Y4NGZPoltergeist")]
[assembly: AssemblyTitle("Y4NGZPoltergeist")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
[module: NetcodePatchedAssembly]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.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 Y4NGZPoltergeist
{
	internal static class PassengerContract
	{
		internal const string DisplayName = "Passenger";

		internal const string ScanNodeSubtitle = "";

		internal const int ScanNodeMaxRange = 18;

		internal const int ScanNodeMinRange = 1;

		internal const float DefaultPowerLevel = 2.5f;

		internal const int DefaultMaxCount = 1;

		internal const int DefaultHealth = 5;

		internal static void RepairScanNode(bool created, ref string header, ref string subtitle, ref int maxRange, ref int minRange)
		{
			if (created || string.IsNullOrEmpty(header))
			{
				header = "Passenger";
			}
			if (created || subtitle == null)
			{
				subtitle = "";
			}
			if (created || maxRange <= 0)
			{
				maxRange = 18;
				minRange = 1;
			}
		}
	}
	[BepInPlugin("y4ngz.lethalcompany.poltergeist", "Y4NGZ Poltergeist", "1.2.1")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public sealed class Plugin : BaseUnityPlugin
	{
		internal const string BundleFilename = "y4ngzpoltergeist.bundle";

		internal const string PrefabName = "Poltergeist";

		internal const string AlternatePrefabName = "thc3";

		internal const string DawnNamespace = "y4ngz_monsters";

		internal const string DawnEnemyKey = "passenger";

		internal const string BestiaryText = "Passenger\n\nDanger level: high\n\nAn intangible facility resident that ignores walls entirely, drifting through them to reach a worker it has chosen. Its claws are survivable. What follows them is not: a sufficiently wounded worker can be worn like a coat, and will turn on their own crew for as long as the thing keeps its grip. It does not enjoy being shot at, and leaves when it is.\n\n";

		internal static ManualLogSource Log;

		private static bool _loggedScanNodeLayer;

		internal static PoltergeistConfig ModConfig;

		internal static AssetBundle ModAssets;

		internal static EnemyType PoltergeistEnemyType;

		internal static Material PhaseMaterial;

		internal static Material TransitBodyMaterial;

		internal static Material WallDisturbanceMaterial;

		internal static AudioClip PossessedLoopClip;

		internal const string LooseAudioFolderName = "Poltergeist";

		private static AudioMixerGroup _diegeticMaster;

		private static bool _netcodeInitialized;

		private void Awake()
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			Log = ((BaseUnityPlugin)this).Logger;
			try
			{
				InitializeNetcodeRPCs();
				ModConfig = new PoltergeistConfig(((BaseUnityPlugin)this).Config);
				new Harmony("y4ngz.lethalcompany.poltergeist").PatchAll(typeof(Plugin).Assembly);
				if (!LoadBundle())
				{
					return;
				}
				LoadPresentationMaterials();
				((MonoBehaviour)this).StartCoroutine(LoadLoosePossessionAudio());
				GameObject val = LoadBundlePrefab();
				if ((Object)(object)val == (Object)null)
				{
					Log.LogError((object)"Prefab 'Poltergeist' not found in y4ngzpoltergeist.bundle.");
					DumpBundleAssets();
					return;
				}
				PreparePrefab(val);
				PoltergeistEnemyType = CreateEnemyType(val);
				PoltergeistAI component = val.GetComponent<PoltergeistAI>();
				if ((Object)(object)component != (Object)null)
				{
					((EnemyAI)component).enemyType = PoltergeistEnemyType;
				}
				PoltergeistSpawnWeights spawnWeights = new PoltergeistSpawnWeights(() => (!ModConfig.Enabled.Value) ? 0f : ModConfig.SpawnWeightMultiplier.Value, () => ModConfig.MoonWeightOverrides.Value, delegate(string message)
				{
					Log.LogWarning((object)message);
				});
				DawnLib.RegisterNetworkPrefab(val);
				DawnLib.DefineEnemy(NamespacedKey<DawnEnemyInfo>.From("y4ngz_monsters", "passenger"), PoltergeistEnemyType, (Action<EnemyInfoBuilder>)delegate(EnemyInfoBuilder builder)
				{
					((BaseInfoBuilder<DawnEnemyInfo, EnemyType, EnemyInfoBuilder>)(object)builder.DefineInside((Action<EnemyLocationBuilder>)delegate(EnemyLocationBuilder location)
					{
						location.SetWeights((Action<WeightTableBuilder<DawnMoonInfo, SpawnWeightContext>>)delegate(WeightTableBuilder<DawnMoonInfo, SpawnWeightContext> table)
						{
							table.SetGlobalWeight((IWeighted)(object)spawnWeights);
						});
					}).CreateBestiaryNode("Passenger\n\nDanger level: high\n\nAn intangible facility resident that ignores walls entirely, drifting through them to reach a worker it has chosen. Its claws are survivable. What follows them is not: a sufficiently wounded worker can be worn like a coat, and will turn on their own crew for as long as the thing keeps its grip. It does not enjoy being shot at, and leaves when it is.\n\n").CreateNameKeyword("passenger")).AddTags((IEnumerable<NamespacedKey>)(object)new NamespacedKey[5]
					{
						Tags.Hostile,
						Tags.Organic,
						Tags.Biped,
						Tags.Killable,
						Tags.Medium
					});
				});
				if (!ModConfig.Enabled.Value)
				{
					Log.LogInfo((object)"Y4NGZ Poltergeist: registered network prefab; spawning disabled by config.");
				}
				Log.LogInfo((object)"Y4NGZ Poltergeist v1.2.1 loaded. Registered as 'Passenger'.");
			}
			catch (Exception arg)
			{
				Log.LogError((object)string.Format("[{0}] Initialization failed: {1}", "Y4NGZ Poltergeist", arg));
			}
		}

		private static void InitializeNetcodeRPCs()
		{
			if (_netcodeInitialized)
			{
				return;
			}
			_netcodeInitialized = true;
			Type[] types = Assembly.GetExecutingAssembly().GetTypes();
			foreach (Type type in types)
			{
				MethodInfo[] methods;
				try
				{
					methods = type.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				}
				catch
				{
					continue;
				}
				foreach (MethodInfo methodInfo in methods)
				{
					if (methodInfo.GetCustomAttributes(typeof(RuntimeInitializeOnLoadMethodAttribute), inherit: false).Length == 0)
					{
						continue;
					}
					try
					{
						methodInfo.Invoke(null, null);
					}
					catch (Exception ex)
					{
						ManualLogSource log = Log;
						if (log != null)
						{
							log.LogWarning((object)("[NetcodeInit] " + type.Name + "." + methodInfo.Name + " failed: " + ex.Message));
						}
					}
				}
			}
		}

		private static bool LoadBundle()
		{
			string directoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
			if (string.IsNullOrEmpty(directoryName))
			{
				Log.LogError((object)"Could not resolve plugin assembly directory.");
				return false;
			}
			string text = Path.Combine(directoryName, "y4ngzpoltergeist.bundle");
			if (!File.Exists(text))
			{
				Log.LogError((object)("Missing asset bundle: " + text));
				return false;
			}
			ModAssets = AssetBundle.LoadFromFile(text);
			if ((Object)(object)ModAssets == (Object)null)
			{
				Log.LogError((object)("AssetBundle.LoadFromFile returned null for " + text + "."));
				return false;
			}
			return true;
		}

		private IEnumerator LoadLoosePossessionAudio()
		{
			string text = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) ?? string.Empty, "assets", "Poltergeist");
			if (!Directory.Exists(text))
			{
				Log.LogWarning((object)("[PoltergeistAudio] Loose audio folder not found: " + text + ". The local possession loop will be silent."));
				yield break;
			}
			yield return LoadLooseClip(Path.Combine(text, "plt_possession_loop_01.ogg"), delegate(AudioClip clip)
			{
				PossessedLoopClip = clip;
			});
			Log.LogInfo((object)$"[PoltergeistAudio] Local possession loop loaded: {(Object)(object)PossessedLoopClip != (Object)null}.");
		}

		private static IEnumerator LoadLooseClip(string path, Action<AudioClip> onLoaded)
		{
			if (!File.Exists(path))
			{
				Log.LogWarning((object)("[PoltergeistAudio] Audio file not found: " + path));
				yield break;
			}
			string text = "file:///" + path.Replace('\\', '/');
			AudioType val = (AudioType)(string.Equals(Path.GetExtension(path), ".ogg", StringComparison.OrdinalIgnoreCase) ? 14 : 20);
			UnityWebRequest request = UnityWebRequestMultimedia.GetAudioClip(text, val);
			try
			{
				yield return request.SendWebRequest();
				if ((int)request.result != 1)
				{
					Log.LogWarning((object)("[PoltergeistAudio] Failed to load " + path + ": " + request.error));
					yield break;
				}
				AudioClip content = DownloadHandlerAudioClip.GetContent(request);
				if ((Object)(object)content == (Object)null)
				{
					yield break;
				}
				((Object)content).name = Path.GetFileNameWithoutExtension(path);
				onLoaded(content);
			}
			finally
			{
				((IDisposable)request)?.Dispose();
			}
		}

		private static GameObject LoadBundlePrefab()
		{
			GameObject val = ModAssets.LoadAsset<GameObject>("Poltergeist") ?? ModAssets.LoadAsset<GameObject>("thc3");
			if ((Object)(object)val != (Object)null)
			{
				return val;
			}
			string[] allAssetNames = ModAssets.GetAllAssetNames();
			foreach (string text in allAssetNames)
			{
				string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(text.Replace('\\', '/'));
				if (string.Equals(fileNameWithoutExtension, "Poltergeist", StringComparison.OrdinalIgnoreCase) || string.Equals(fileNameWithoutExtension, "thc3", StringComparison.OrdinalIgnoreCase))
				{
					val = ModAssets.LoadAsset<GameObject>(text);
					if ((Object)(object)val != (Object)null)
					{
						return val;
					}
				}
			}
			return null;
		}

		private static void LoadPresentationMaterials()
		{
			PhaseMaterial = LoadBundleMaterial("Poltergeist_Phase");
			TransitBodyMaterial = LoadBundleMaterial("PassengerTransitBody");
			WallDisturbanceMaterial = LoadBundleMaterial("PassengerWallDisturbance");
			if ((Object)(object)PhaseMaterial == (Object)null)
			{
				ManualLogSource log = Log;
				if (log != null)
				{
					log.LogError((object)"[PoltergeistMaterial] Poltergeist_Phase is missing from the bundle: phasing and the death fade lose their translucency.");
				}
			}
			if ((Object)(object)WallDisturbanceMaterial == (Object)null)
			{
				ManualLogSource log2 = Log;
				if (log2 != null)
				{
					log2.LogError((object)"[PoltergeistMaterial] PassengerWallDisturbance is missing: install the matching wall-combat-v3 bundle.");
				}
			}
		}

		private static Material LoadBundleMaterial(string materialName)
		{
			if ((Object)(object)ModAssets == (Object)null)
			{
				return null;
			}
			Material val = ModAssets.LoadAsset<Material>(materialName);
			if ((Object)(object)val != (Object)null)
			{
				return val;
			}
			Material[] array = ModAssets.LoadAllAssets<Material>();
			for (int i = 0; i < array.Length; i++)
			{
				if ((Object)(object)array[i] != (Object)null && string.Equals(((Object)array[i]).name, materialName, StringComparison.OrdinalIgnoreCase))
				{
					return array[i];
				}
			}
			for (int j = 0; j < array.Length; j++)
			{
				if ((Object)(object)array[j] != (Object)null && ((Object)array[j]).name.IndexOf(materialName, StringComparison.OrdinalIgnoreCase) >= 0)
				{
					return array[j];
				}
			}
			return null;
		}

		internal static Color ResolvePhaseLightColor()
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			Color result = default(Color);
			((Color)(ref result))..ctor(0.44f, 0.66f, 1f, 1f);
			string text = "#6FA8FF";
			if (string.IsNullOrWhiteSpace(text))
			{
				return result;
			}
			Color result2 = default(Color);
			if (!ColorUtility.TryParseHtmlString(text.Trim(), ref result2))
			{
				return result;
			}
			return result2;
		}

		private static void PreparePrefab(GameObject prefab)
		{
			//IL_0029: 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_0150: 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)
			AssignUniqueNetworkHash(prefab);
			prefab.SetActive(true);
			TrySetTag(prefab, "Enemy");
			TrySetLayer(prefab, "Enemies");
			prefab.transform.localScale = Vector3.one * Mathf.Clamp(1f, 0.5f, 2.5f);
			PoltergeistAI poltergeistAI = prefab.GetComponent<PoltergeistAI>();
			if ((Object)(object)poltergeistAI == (Object)null)
			{
				poltergeistAI = prefab.AddComponent<PoltergeistAI>();
			}
			if ((Object)(object)prefab.GetComponent<NetworkObject>() == (Object)null)
			{
				prefab.AddComponent<NetworkObject>();
			}
			NetworkTransform[] components = prefab.GetComponents<NetworkTransform>();
			for (int i = 0; i < components.Length; i++)
			{
				Object.DestroyImmediate((Object)(object)components[i]);
			}
			Animator val = prefab.GetComponent<Animator>() ?? prefab.GetComponentInChildren<Animator>(true);
			if ((Object)(object)val != (Object)null)
			{
				val.applyRootMotion = false;
				val.cullingMode = (AnimatorCullingMode)0;
				((EnemyAI)poltergeistAI).creatureAnimator = val;
			}
			else
			{
				Log.LogWarning((object)"[Poltergeist] Prefab has no Animator.");
			}
			NavMeshAgent val2 = prefab.GetComponent<NavMeshAgent>();
			if ((Object)(object)val2 == (Object)null)
			{
				val2 = prefab.AddComponent<NavMeshAgent>();
			}
			ConfigureAgent(val2);
			((EnemyAI)poltergeistAI).agent = val2;
			((EnemyAI)poltergeistAI).creatureSFX = FindOrCreateAudioSource(prefab.transform, "CreatureSFX", 38f);
			((EnemyAI)poltergeistAI).creatureVoice = FindOrCreateAudioSource(prefab.transform, "CreatureVoice", 44f);
			((EnemyAI)poltergeistAI).eye = FindOrCreateChild(prefab.transform, "EyeTransform", new Vector3(0f, 1.7f, 0.4f));
			poltergeistAI.attackOrigin = FindOrCreateChild(prefab.transform, "AttackOrigin", new Vector3(0f, 1.15f, 0.85f));
			AssignPoltergeistAudio(poltergeistAI);
			EnsureRenderers(prefab, (EnemyAI)(object)poltergeistAI);
			RepairBrokenMaterials(prefab);
			EnsureBehaviourStates(poltergeistAI);
			EnsureScanNode(prefab);
			EnsureCollision(prefab, poltergeistAI);
		}

		private static void ConfigureAgent(NavMeshAgent agent)
		{
			agent.speed = ModConfig.RoamSpeed.Value;
			agent.angularSpeed = 380f;
			agent.acceleration = 16f;
			agent.stoppingDistance = 0.12f;
			agent.radius = 0.55f;
			agent.height = 2.1f;
			agent.baseOffset = 0f;
			agent.autoBraking = true;
			agent.autoRepath = true;
			agent.updateRotation = false;
			agent.areaMask = -1;
			agent.obstacleAvoidanceType = (ObstacleAvoidanceType)4;
			agent.avoidancePriority = 34;
		}

		private static void EnsureRenderers(GameObject prefab, EnemyAI ai)
		{
			//IL_0020: 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_003e: 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)
			SkinnedMeshRenderer[] componentsInChildren = prefab.GetComponentsInChildren<SkinnedMeshRenderer>(true);
			MeshRenderer[] componentsInChildren2 = prefab.GetComponentsInChildren<MeshRenderer>(true);
			ai.skinnedMeshRenderers = componentsInChildren;
			ai.meshRenderers = componentsInChildren2;
			Bounds localBounds = default(Bounds);
			((Bounds)(ref localBounds))..ctor(Vector3.up * 1.1f, new Vector3(5.5f, 4.5f, 5.5f));
			foreach (SkinnedMeshRenderer val in componentsInChildren)
			{
				if (!((Object)(object)val == (Object)null) && !IsRuntimeHelperRenderer((Renderer)(object)val))
				{
					ActivateRendererHierarchy(prefab.transform, ((Component)val).transform);
					((Component)val).gameObject.SetActive(true);
					((Renderer)val).enabled = true;
					((Renderer)val).forceRenderingOff = false;
					val.updateWhenOffscreen = true;
					((Renderer)val).localBounds = localBounds;
					((Renderer)val).shadowCastingMode = (ShadowCastingMode)1;
					((Renderer)val).receiveShadows = true;
				}
			}
			foreach (MeshRenderer val2 in componentsInChildren2)
			{
				if (!((Object)(object)val2 == (Object)null) && !IsRuntimeHelperRenderer((Renderer)(object)val2))
				{
					ActivateRendererHierarchy(prefab.transform, ((Component)val2).transform);
					((Component)val2).gameObject.SetActive(true);
					((Renderer)val2).enabled = true;
					((Renderer)val2).forceRenderingOff = false;
					((Renderer)val2).shadowCastingMode = (ShadowCastingMode)1;
					((Renderer)val2).receiveShadows = true;
				}
			}
			ManualLogSource log = Log;
			if (log != null)
			{
				log.LogInfo((object)$"[PoltergeistRenderer] Prepared {componentsInChildren.Length} skinned renderer(s), {componentsInChildren2.Length} mesh renderer(s).");
			}
		}

		private static void RepairBrokenMaterials(GameObject prefab)
		{
			Renderer[] componentsInChildren = prefab.GetComponentsInChildren<Renderer>(true);
			int num = 0;
			foreach (Renderer val in componentsInChildren)
			{
				if ((Object)(object)val == (Object)null || IsRuntimeHelperRenderer(val))
				{
					continue;
				}
				Material[] sharedMaterials = val.sharedMaterials;
				if (sharedMaterials == null || sharedMaterials.Length == 0)
				{
					continue;
				}
				bool flag = false;
				for (int j = 0; j < sharedMaterials.Length; j++)
				{
					if (IsMaterialBroken(sharedMaterials[j]))
					{
						Material val2 = RebuildMaterial(sharedMaterials[j]);
						if (!((Object)(object)val2 == (Object)null))
						{
							sharedMaterials[j] = val2;
							flag = true;
							num++;
						}
					}
				}
				if (flag)
				{
					val.sharedMaterials = sharedMaterials;
				}
			}
			if (num > 0)
			{
				ManualLogSource log = Log;
				if (log != null)
				{
					log.LogWarning((object)$"[PoltergeistMaterial] Rebuilt {num} material(s) that lost their shader during bundling.");
				}
			}
			else
			{
				ManualLogSource log2 = Log;
				if (log2 != null)
				{
					log2.LogInfo((object)"[PoltergeistMaterial] All bundled materials kept their shader; no repair needed.");
				}
			}
		}

		private static bool IsMaterialBroken(Material material)
		{
			if ((Object)(object)material == (Object)null)
			{
				return false;
			}
			if ((Object)(object)material.shader == (Object)null)
			{
				return true;
			}
			if (((Object)material.shader).name.IndexOf("InternalError", StringComparison.OrdinalIgnoreCase) < 0)
			{
				return ((Object)material.shader).name.IndexOf("Hidden/InternalError", StringComparison.OrdinalIgnoreCase) >= 0;
			}
			return true;
		}

		private static Material RebuildMaterial(Material source)
		{
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Expected O, but got Unknown
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			Shader val = Shader.Find("HDRP/Lit") ?? Shader.Find("High Definition Render Pipeline/Lit") ?? Shader.Find("Universal Render Pipeline/Lit") ?? Shader.Find("Standard");
			if ((Object)(object)val == (Object)null)
			{
				ManualLogSource log = Log;
				if (log != null)
				{
					log.LogError((object)"[PoltergeistMaterial] No usable shader found in the game; cannot repair materials.");
				}
				return null;
			}
			Material val2 = new Material(val)
			{
				name = (((Object)(object)source != (Object)null) ? ((Object)source).name : "Poltergeist") + "_Runtime"
			};
			CopyTexture(source, val2, "_BaseColorMap", "_MainTex");
			CopyTexture(source, val2, "_NormalMap", "_BumpMap");
			CopyTexture(source, val2, "_MaskMap", "_MetallicGlossMap");
			CopyTexture(source, val2, "_EmissiveColorMap", "_EmissionMap");
			SetMaterialColor(val2, "_BaseColor", Color.white);
			SetMaterialColor(val2, "_Color", Color.white);
			SetMaterialFloat(val2, "_SurfaceType", 0f);
			SetMaterialFloat(val2, "_AlphaCutoffEnable", 1f);
			SetMaterialFloat(val2, "_AlphaCutoff", 0.5f);
			SetMaterialFloat(val2, "_Cutoff", 0.5f);
			val2.EnableKeyword("_ALPHATEST_ON");
			SetMaterialFloat(val2, "_DoubleSidedEnable", 1f);
			SetMaterialFloat(val2, "_CullMode", 0f);
			SetMaterialFloat(val2, "_CullModeForward", 0f);
			val2.EnableKeyword("_DOUBLESIDED_ON");
			val2.doubleSidedGI = true;
			if ((Object)(object)val2.GetTexture("_NormalMap") != (Object)null || (Object)(object)val2.GetTexture("_BumpMap") != (Object)null)
			{
				val2.EnableKeyword("_NORMALMAP");
			}
			return val2;
		}

		private static void CopyTexture(Material source, Material destination, string hdrpProperty, string standardProperty)
		{
			if ((Object)(object)source == (Object)null)
			{
				return;
			}
			Texture val = GetTextureIfPresent(source, hdrpProperty) ?? GetTextureIfPresent(source, standardProperty);
			if (!((Object)(object)val == (Object)null))
			{
				if (destination.HasProperty(hdrpProperty))
				{
					destination.SetTexture(hdrpProperty, val);
				}
				if (destination.HasProperty(standardProperty))
				{
					destination.SetTexture(standardProperty, val);
				}
			}
		}

		private static Texture GetTextureIfPresent(Material material, string property)
		{
			if (!((Object)(object)material != (Object)null) || !material.HasProperty(property))
			{
				return null;
			}
			return material.GetTexture(property);
		}

		private static void SetMaterialColor(Material material, string property, Color value)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)material != (Object)null && material.HasProperty(property))
			{
				material.SetColor(property, value);
			}
		}

		private static void SetMaterialFloat(Material material, string property, float value)
		{
			if ((Object)(object)material != (Object)null && material.HasProperty(property))
			{
				material.SetFloat(property, value);
			}
		}

		private static void ActivateRendererHierarchy(Transform prefabRoot, Transform rendererTransform)
		{
			Transform val = rendererTransform;
			while ((Object)(object)val != (Object)null)
			{
				if (!((Component)val).gameObject.activeSelf)
				{
					((Component)val).gameObject.SetActive(true);
				}
				if (!((Object)(object)val == (Object)(object)prefabRoot))
				{
					val = val.parent;
					continue;
				}
				break;
			}
		}

		private static bool IsRuntimeHelperRenderer(Renderer renderer)
		{
			Transform val = (((Object)(object)renderer != (Object)null) ? ((Component)renderer).transform : null);
			while ((Object)(object)val != (Object)null)
			{
				string text = ((Object)val).name ?? string.Empty;
				if (text.IndexOf("ScanNode", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("Collision", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("MapDot", StringComparison.OrdinalIgnoreCase) >= 0)
				{
					return true;
				}
				val = val.parent;
			}
			return false;
		}

		private static void EnsureBehaviourStates(PoltergeistAI ai)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Expected O, but got Unknown
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Expected O, but got Unknown
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Expected O, but got Unknown
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Expected O, but got Unknown
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Expected O, but got Unknown
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Expected O, but got Unknown
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Expected O, but got Unknown
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Expected O, but got Unknown
			((EnemyAI)ai).enemyBehaviourStates = (EnemyBehaviourState[])(object)new EnemyBehaviourState[8]
			{
				new EnemyBehaviourState
				{
					name = "Roaming"
				},
				new EnemyBehaviourState
				{
					name = "Stalking"
				},
				new EnemyBehaviourState
				{
					name = "Phasing"
				},
				new EnemyBehaviourState
				{
					name = "Attacking"
				},
				new EnemyBehaviourState
				{
					name = "PossessCast"
				},
				new EnemyBehaviourState
				{
					name = "Possessing"
				},
				new EnemyBehaviourState
				{
					name = "Fleeing"
				},
				new EnemyBehaviourState
				{
					name = "Dead"
				}
			};
			((EnemyAI)ai).currentBehaviourStateIndex = 0;
			((EnemyAI)ai).previousBehaviourStateIndex = 0;
			((EnemyAI)ai).currentBehaviourState = ((EnemyAI)ai).enemyBehaviourStates[0];
		}

		internal static void EnsureScanNode(GameObject prefab)
		{
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_021a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0234: Unknown result type (might be due to invalid IL or missing references)
			ScanNodeProperties val = null;
			ScanNodeProperties[] componentsInChildren = prefab.GetComponentsInChildren<ScanNodeProperties>(true);
			foreach (ScanNodeProperties val2 in componentsInChildren)
			{
				bool flag = val2.creatureScanID >= 0;
				bool flag2 = (Object)(object)val != (Object)null && val.creatureScanID >= 0;
				bool flag3 = string.Equals(((Object)((Component)val2).gameObject).name, "ScanNode", StringComparison.Ordinal);
				bool flag4 = (Object)(object)val != (Object)null && string.Equals(((Object)((Component)val).gameObject).name, "ScanNode", StringComparison.Ordinal);
				if ((Object)(object)val == (Object)null || (flag && !flag2) || (flag == flag2 && flag3 && !flag4))
				{
					val = val2;
				}
			}
			if (componentsInChildren.Length > 1)
			{
				ManualLogSource log = Log;
				if (log != null)
				{
					log.LogWarning((object)$"[Poltergeist] Found {componentsInChildren.Length} scan nodes; retiring every duplicate.");
				}
			}
			for (int j = 0; j < componentsInChildren.Length; j++)
			{
				if ((Object)(object)componentsInChildren[j] != (Object)(object)val)
				{
					RetireExtraScanNode(componentsInChildren[j], val, prefab);
				}
			}
			Transform val3 = (((Object)(object)val != (Object)null) ? ((Component)val).transform : FindOrCreateChild(prefab.transform, "ScanNode", new Vector3(0f, 1.3f, 0f)));
			((Object)((Component)val3).gameObject).name = "ScanNode";
			TrySetTag(((Component)val3).gameObject, "DoNotSet");
			TrySetLayer(((Component)val3).gameObject, "ScanNode");
			EnsureHierarchyActive(val3, prefab.transform);
			((Component)val3).gameObject.SetActive(true);
			if (!_loggedScanNodeLayer)
			{
				_loggedScanNodeLayer = true;
				ManualLogSource log2 = Log;
				if (log2 != null)
				{
					log2.LogInfo((object)($"[Poltergeist] Scan node layer resolved to {((Component)val3).gameObject.layer} " + string.Format("(NameToLayer(\"ScanNode\")={0}, fallback 22); ", LayerMask.NameToLayer("ScanNode")) + $"active={((Component)val3).gameObject.activeInHierarchy}."));
				}
			}
			BoxCollider val4 = ((Component)val3).GetComponent<BoxCollider>();
			if ((Object)(object)val4 == (Object)null)
			{
				val4 = ((Component)val3).gameObject.AddComponent<BoxCollider>();
			}
			((Collider)val4).enabled = true;
			((Collider)val4).isTrigger = true;
			val4.center = Vector3.zero;
			val4.size = new Vector3(1.5f, 2.1f, 1.2f);
			bool num = (Object)(object)val == (Object)null;
			if (num)
			{
				val = ((Component)val3).gameObject.AddComponent<ScanNodeProperties>();
			}
			PassengerContract.RepairScanNode(num, ref val.headerText, ref val.subText, ref val.maxRange, ref val.minRange);
			val.requiresLineOfSight = true;
			val.nodeType = 1;
		}

		private static void RetireExtraScanNode(ScanNodeProperties extra, ScanNodeProperties preferred, GameObject root)
		{
			//IL_0035: 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_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)extra == (Object)null)
			{
				return;
			}
			Scene scene;
			if ((Object)(object)((Component)extra).gameObject == (Object)(object)root || ((Object)(object)preferred != (Object)null && (Object)(object)((Component)extra).gameObject == (Object)(object)((Component)preferred).gameObject))
			{
				scene = root.scene;
				if (((Scene)(ref scene)).IsValid())
				{
					Object.Destroy((Object)(object)extra);
				}
				else
				{
					Object.DestroyImmediate((Object)(object)extra, true);
				}
				return;
			}
			GameObject gameObject = ((Component)extra).gameObject;
			gameObject.SetActive(false);
			Collider[] components = gameObject.GetComponents<Collider>();
			for (int i = 0; i < components.Length; i++)
			{
				components[i].enabled = false;
			}
			scene = root.scene;
			if (((Scene)(ref scene)).IsValid())
			{
				Object.Destroy((Object)(object)gameObject);
			}
			else
			{
				Object.DestroyImmediate((Object)(object)gameObject, true);
			}
		}

		private static void EnsureCollision(GameObject prefab, PoltergeistAI ai)
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			CapsuleCollider obj = prefab.GetComponent<CapsuleCollider>() ?? prefab.AddComponent<CapsuleCollider>();
			((Collider)obj).isTrigger = false;
			obj.direction = 1;
			obj.center = new Vector3(0f, 1.05f, 0f);
			obj.radius = 0.55f;
			obj.height = 2.1f;
			Transform val = FindOrCreateChild(prefab.transform, "Collision", new Vector3(0f, 1f, 0f));
			TrySetTag(((Component)val).gameObject, "Enemy");
			TrySetLayer(((Component)val).gameObject, "Enemies");
			BoxCollider obj2 = ((Component)val).GetComponent<BoxCollider>() ?? ((Component)val).gameObject.AddComponent<BoxCollider>();
			((Collider)obj2).isTrigger = true;
			obj2.center = Vector3.zero;
			obj2.size = new Vector3(1.5f, 2f, 1.4f);
			Rigidbody obj3 = ((Component)val).GetComponent<Rigidbody>() ?? ((Component)val).gameObject.AddComponent<Rigidbody>();
			obj3.isKinematic = true;
			obj3.useGravity = false;
			obj3.detectCollisions = true;
			EnemyAICollisionDetect obj4 = ((Component)val).GetComponent<EnemyAICollisionDetect>() ?? ((Component)val).gameObject.AddComponent<EnemyAICollisionDetect>();
			obj4.mainScript = (EnemyAI)(object)ai;
			obj4.alwaysAllowHitting = true;
			obj4.canCollideWithEnemies = true;
			obj4.onlyCollideWhenGrounded = false;
		}

		private static EnemyType CreateEnemyType(GameObject prefab)
		{
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			EnemyType obj = ScriptableObject.CreateInstance<EnemyType>();
			obj.enemyName = "Passenger";
			obj.enemyPrefab = prefab;
			obj.PowerLevel = ModConfig.PowerLevel.Value;
			obj.DiversityPowerLevel = 1;
			obj.MaxCount = ModConfig.MaxCount.Value;
			obj.canDie = true;
			obj.canBeStunned = true;
			obj.canBeDestroyed = true;
			obj.stunTimeMultiplier = 1f;
			obj.stunGameDifficultyMultiplier = 1f;
			obj.destroyOnDeath = false;
			obj.doorSpeedMultiplier = 1f;
			obj.isOutsideEnemy = false;
			obj.isDaytimeEnemy = false;
			obj.normalizedTimeInDayToLeave = 1f;
			obj.probabilityCurve = AnimationCurve.Constant(0f, 1f, 1f);
			obj.numberSpawnedFalloff = AnimationCurve.Linear(0f, 1f, 1f, 0.35f);
			obj.useNumberSpawnedFalloff = true;
			obj.disableAnimatorWhenFar = false;
			obj.SizeLimit = (NavSizeLimit)1;
			PoltergeistAI component = prefab.GetComponent<PoltergeistAI>();
			CreatureSfx.Apply(obj, (EnemyAI)(object)component, null, ((Object)(object)component != (Object)null && component.attackImpactClips != null && component.attackImpactClips.Length != 0) ? component.attackImpactClips[0] : null, ((Object)(object)component != (Object)null) ? component.vanishClip : null);
			return obj;
		}

		private static AudioSource FindOrCreateAudioSource(Transform parent, string childName, float maxDistance)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			Transform val = FindOrCreateChild(parent, childName, Vector3.zero);
			AudioSource obj = ((Component)val).GetComponent<AudioSource>() ?? ((Component)val).gameObject.AddComponent<AudioSource>();
			ConfigureWorldAudioSource(obj, 3f, maxDistance);
			return obj;
		}

		internal static void ConfigureWorldAudioSource(AudioSource source, float minDistance, float maxDistance)
		{
			if (!((Object)(object)source == (Object)null))
			{
				source.playOnAwake = false;
				source.spatialBlend = 1f;
				source.rolloffMode = (AudioRolloffMode)1;
				source.minDistance = Mathf.Max(0.1f, minDistance);
				source.maxDistance = Mathf.Max(source.minDistance, maxDistance);
				source.reverbZoneMix = 1f;
				source.bypassReverbZones = false;
				AudioMixerGroup val = ResolveDiegeticMaster();
				if ((Object)(object)val != (Object)null)
				{
					source.outputAudioMixerGroup = val;
				}
				OccludeAudio val2 = ((Component)source).GetComponent<OccludeAudio>();
				if ((Object)(object)val2 == (Object)null)
				{
					val2 = ((Component)source).gameObject.AddComponent<OccludeAudio>();
				}
				val2.useReverb = true;
			}
		}

		internal static void ConfigureLocalAudioSource(AudioSource source)
		{
			if (!((Object)(object)source == (Object)null))
			{
				source.playOnAwake = false;
				source.spatialBlend = 0f;
				source.rolloffMode = (AudioRolloffMode)1;
				source.reverbZoneMix = 0f;
				source.bypassReverbZones = true;
				AudioMixerGroup val = ResolveDiegeticMaster();
				if ((Object)(object)val != (Object)null)
				{
					source.outputAudioMixerGroup = val;
				}
			}
		}

		private static AudioMixerGroup ResolveDiegeticMaster()
		{
			if ((Object)(object)_diegeticMaster != (Object)null)
			{
				return _diegeticMaster;
			}
			SoundManager instance = SoundManager.Instance;
			if ((Object)(object)instance == (Object)null || (Object)(object)instance.diageticMixer == (Object)null)
			{
				return null;
			}
			AudioMixerGroup[] array = instance.diageticMixer.FindMatchingGroups("Master");
			if (array != null && array.Length != 0)
			{
				_diegeticMaster = array[0];
			}
			return _diegeticMaster;
		}

		private static void AssignPoltergeistAudio(PoltergeistAI ai)
		{
			if (!((Object)(object)ai == (Object)null) && !((Object)(object)ModAssets == (Object)null))
			{
				string[] allAssetNames = ModAssets.GetAllAssetNames();
				ai.attackWhooshClips = LoadAudioClipSet(allAssetNames, "plt_attack_swipe_01");
				ai.attackImpactClips = LoadAudioClipSet(allAssetNames, "plt_impact_body_01", "plt_impact_body_02");
				ai.footstepClips = LoadAudioClipSet(allAssetNames, "plt_foley_01", "plt_foley_02");
				ai.phaseInClips = LoadAudioClipSet(allAssetNames, "plt_phase_03");
				AudioClip[] array = LoadAudioClipSet(allAssetNames, "plt_emerge_01");
				ai.emergenceClip = ((array.Length != 0) ? array[0] : null);
				AudioClip[] array2 = LoadAudioClipSet(allAssetNames, "plt_vanish_01");
				ai.vanishClip = ((array2.Length != 0) ? array2[0] : null);
				ai.possessionClips = LoadAudioClipSet(allAssetNames, "plt_possession_01");
				AudioClip[] array3 = LoadAudioClipSet(allAssetNames, "plt_presence_loop_01");
				ai.presenceLoopClip = ((array3.Length != 0) ? array3[0] : null);
				AudioClip[] array4 = (ai.growlClips = LoadAudioClipSet(allAssetNames, "plt_growl_01", "plt_growl_02"));
				ai.shriekClip = ((array4.Length != 0) ? array4[0] : null);
				if ((Object)(object)ai.shriekClip == (Object)null)
				{
					Log.LogError((object)"Passenger shriek missing: install the paired wall-combat bundle.");
				}
				int num = ai.attackWhooshClips.Length + ai.attackImpactClips.Length + ai.footstepClips.Length + ai.phaseInClips.Length + ai.possessionClips.Length + array3.Length + array4.Length + array.Length + array2.Length;
				ManualLogSource log = Log;
				if (log != null)
				{
					log.LogInfo((object)string.Format("[PoltergeistAudio] Loaded {0} authored world clip(s) from {1}.", num, "y4ngzpoltergeist.bundle"));
				}
			}
		}

		private static AudioClip[] LoadAudioClipSet(string[] bundleAssets, params string[] clipNames)
		{
			List<AudioClip> list = new List<AudioClip>(clipNames.Length);
			for (int i = 0; i < clipNames.Length; i++)
			{
				AudioClip val = LoadAudioClip(bundleAssets, clipNames[i]);
				if ((Object)(object)val != (Object)null)
				{
					list.Add(val);
				}
			}
			return list.ToArray();
		}

		private static AudioClip LoadAudioClip(string[] bundleAssets, string clipName)
		{
			foreach (string text in bundleAssets)
			{
				if (string.Equals(Path.GetFileNameWithoutExtension(text), clipName, StringComparison.OrdinalIgnoreCase))
				{
					AudioClip val = ModAssets.LoadAsset<AudioClip>(text);
					if ((Object)(object)val != (Object)null)
					{
						return val;
					}
				}
			}
			return null;
		}

		private static Transform FindOrCreateChild(Transform parent, string name, Vector3 localPosition)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			Transform val = parent.Find(name);
			if ((Object)(object)val != (Object)null)
			{
				val.localPosition = localPosition;
				return val;
			}
			val = new GameObject(name).transform;
			val.SetParent(parent, false);
			val.localPosition = localPosition;
			return val;
		}

		private static void AssignUniqueNetworkHash(GameObject prefab)
		{
			try
			{
				NetworkObject val = prefab.GetComponent<NetworkObject>();
				if ((Object)(object)val == (Object)null)
				{
					val = prefab.AddComponent<NetworkObject>();
				}
				uint num = BitConverter.ToUInt32(MD5.Create().ComputeHash(Encoding.UTF8.GetBytes("y4ngz.lethalcompany.poltergeist.Poltergeist")), 0);
				PropertyInfo property = typeof(NetworkObject).GetProperty("GlobalObjectIdHash", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (property != null && property.CanWrite)
				{
					property.SetValue(val, num);
					return;
				}
				FieldInfo fieldInfo = typeof(NetworkObject).GetField("GlobalObjectIdHash", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) ?? typeof(NetworkObject).GetField("<GlobalObjectIdHash>k__BackingField", BindingFlags.Instance | BindingFlags.NonPublic);
				if (fieldInfo != null)
				{
					fieldInfo.SetValue(val, num);
				}
			}
			catch (Exception ex)
			{
				Log.LogWarning((object)("Could not assign NetworkObject hash for Poltergeist: " + ex.Message));
			}
		}

		private static void DumpBundleAssets()
		{
			if (!((Object)(object)ModAssets == (Object)null))
			{
				string[] allAssetNames = ModAssets.GetAllAssetNames();
				foreach (string text in allAssetNames)
				{
					Log.LogError((object)("  - " + text));
				}
			}
		}

		private static void TrySetTag(GameObject gameObject, string tag)
		{
			try
			{
				gameObject.tag = tag;
			}
			catch
			{
			}
		}

		private static void TrySetLayer(GameObject gameObject, string layerName)
		{
			if ((Object)(object)gameObject == (Object)null)
			{
				return;
			}
			int num = LayerMask.NameToLayer(layerName);
			if (num < 0)
			{
				num = ResolveLayerFallback(layerName);
			}
			if (num >= 0 && num <= 31)
			{
				gameObject.layer = num;
				return;
			}
			ManualLogSource log = Log;
			if (log != null)
			{
				log.LogWarning((object)$"[Poltergeist] Layer '{layerName}' unresolved; '{((Object)gameObject).name}' stays on layer {gameObject.layer}.");
			}
		}

		private static int ResolveLayerFallback(string layerName)
		{
			if (string.Equals(layerName, "ScanNode", StringComparison.OrdinalIgnoreCase))
			{
				return 22;
			}
			if (string.Equals(layerName, "Enemies", StringComparison.OrdinalIgnoreCase))
			{
				return 19;
			}
			return -1;
		}

		private static void EnsureHierarchyActive(Transform child, Transform stopAt)
		{
			Transform val = child;
			while ((Object)(object)val != (Object)null)
			{
				((Component)val).gameObject.SetActive(true);
				if (!((Object)(object)val == (Object)(object)stopAt))
				{
					val = val.parent;
					continue;
				}
				break;
			}
		}
	}
	internal static class PluginInfo
	{
		public const string PLUGIN_GUID = "y4ngz.lethalcompany.poltergeist";

		public const string PLUGIN_NAME = "Y4NGZ Poltergeist";

		public const string PLUGIN_VERSION = "1.2.1";
	}
	internal sealed class PoltergeistConfig
	{
		private const string SectionGeneral = "General";

		private const string SectionSpawning = "Spawning";

		private const string SectionCoreStats = "Core Stats";

		private const string SectionDetection = "Detection";

		private const string SectionMovement = "Movement";

		private const string SectionCombat = "Combat";

		private const string SectionAbilities = "Abilities";

		private const string SectionPresentation = "Audio and Presentation";

		private const string SectionDiagnostics = "Diagnostics";

		public ConfigEntry<bool> Enabled { get; }

		public ConfigEntry<float> SpawnWeightMultiplier { get; }

		public ConfigEntry<string> MoonWeightOverrides { get; }

		public ConfigEntry<int> MaxCount { get; }

		public ConfigEntry<float> PowerLevel { get; }

		public ConfigEntry<int> Health { get; }

		public ConfigEntry<float> SightRange { get; }

		public ConfigEntry<float> RoamSpeed { get; }

		public ConfigEntry<float> StalkSpeed { get; }

		public ConfigEntry<float> ChaseSpeed { get; }

		public ConfigEntry<float> FleeSpeed { get; }

		public ConfigEntry<int> AttackDamage { get; }

		public ConfigEntry<float> AttackRange { get; }

		public ConfigEntry<float> AttackCooldown { get; }

		public ConfigEntry<bool> TacticsEnabled { get; }

		public ConfigEntry<bool> WallPhasingEnabled { get; }

		public ConfigEntry<float> PhaseCooldown { get; }

		public ConfigEntry<float> ManifestPressureSeconds { get; }

		public ConfigEntry<float> GhostCrossingSeconds { get; }

		public ConfigEntry<float> GhostConcealSeconds { get; }

		public ConfigEntry<float> GhostTraversalWeight { get; }

		public ConfigEntry<float> GhostFloorWeight { get; }

		public ConfigEntry<bool> PresenceLoopEnabled { get; }

		public ConfigEntry<float> GhostSolidWeight { get; }

		public ConfigEntry<float> WallPassSpeed { get; }

		public ConfigEntry<float> WallPassAttackChance { get; }

		public ConfigEntry<float> WallPassWeight { get; }

		public ConfigEntry<float> AttackFeintWeight { get; }

		public ConfigEntry<float> WallAssaultWeight { get; }

		public ConfigEntry<float> PursuitBreachWeight { get; }

		public ConfigEntry<float> WallLurkWeight { get; }

		public ConfigEntry<bool> PossessionEnabled { get; }

		public ConfigEntry<int> PossessionHealthThreshold { get; }

		public ConfigEntry<float> PossessionDurationSeconds { get; }

		public ConfigEntry<float> PossessionRange { get; }

		public ConfigEntry<float> PossessionCooldownPerPlayerSeconds { get; }

		public ConfigEntry<bool> PossessedFriendlyFire { get; }

		public ConfigEntry<bool> PossessedAttacksEnabled { get; }

		public ConfigEntry<float> PossessedAttackCooldownSeconds { get; }

		public ConfigEntry<int> PossessedAttackDamage { get; }

		public ConfigEntry<bool> StealthPossessionEnabled { get; }

		public ConfigEntry<bool> PhaseVfxEnabled { get; }

		public ConfigEntry<float> PossessionLoopVolume { get; }

		public ConfigEntry<bool> PossessedVoiceFilterEnabled { get; }

		public ConfigEntry<bool> DebugLogs { get; }

		public ConfigEntry<bool> PhaseDiagnostics { get; }

		public ConfigEntry<float> PhaseDiagnosticsSeconds { get; }

		public ConfigEntry<bool> PossessionDiagnostics { get; }

		public ConfigEntry<bool> PossessionDebugAllowSolo { get; }

		public PoltergeistConfig(ConfigFile config)
		{
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Expected O, but got Unknown
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Expected O, but got Unknown
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Expected O, but got Unknown
			//IL_012e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0138: Expected O, but got Unknown
			//IL_0167: Unknown result type (might be due to invalid IL or missing references)
			//IL_0171: Expected O, but got Unknown
			//IL_0202: Unknown result type (might be due to invalid IL or missing references)
			//IL_020c: Expected O, but got Unknown
			//IL_023b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0245: Expected O, but got Unknown
			//IL_0274: Unknown result type (might be due to invalid IL or missing references)
			//IL_027e: Expected O, but got Unknown
			//IL_02e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ef: Expected O, but got Unknown
			//IL_031e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0328: Expected O, but got Unknown
			//IL_0357: Unknown result type (might be due to invalid IL or missing references)
			//IL_0361: Expected O, but got Unknown
			//IL_0390: Unknown result type (might be due to invalid IL or missing references)
			//IL_039a: Expected O, but got Unknown
			//IL_03c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d3: Expected O, but got Unknown
			//IL_0402: Unknown result type (might be due to invalid IL or missing references)
			//IL_040c: Expected O, but got Unknown
			//IL_048d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0497: Expected O, but got Unknown
			//IL_055f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0569: Expected O, but got Unknown
			//IL_0598: Unknown result type (might be due to invalid IL or missing references)
			//IL_05a2: Expected O, but got Unknown
			//IL_05d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_05db: Expected O, but got Unknown
			//IL_060a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0614: Expected O, but got Unknown
			//IL_067b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0685: Expected O, but got Unknown
			//IL_06aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_06b4: Expected O, but got Unknown
			//IL_071b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0725: Expected O, but got Unknown
			//IL_07a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_07b2: Expected O, but got Unknown
			using (ConfigPersistence.BeginBinding(config, Plugin.Log, "Passenger"))
			{
				PoltergeistConfigMigration.TryMigrate(config, Plugin.Log);
				ConfigSectionNameMigration.TryMigrate(config, Plugin.Log, "Passenger");
				Enabled = config.Bind<bool>("General", "Enabled", true, "Enable the Passenger encounter. Host-only: the host's value decides whether it spawns; every install still registers the creature so clients stay in sync.");
				SpawnWeightMultiplier = config.Bind<float>("Spawning", "SpawnWeightMultiplier", 1f, new ConfigDescription("Multiplier applied to Passenger's contextual moon/interior spawn policy. 0 disables natural spawns.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 5f), Array.Empty<object>()));
				MoonWeightOverrides = config.Bind<string>("Spawning", "MoonWeightOverrides", string.Empty, "Optional comma-separated base moon weights, e.g. Experimentation:8,Offense:15 or namespace:moon=12. Use 0 to disable a moon; unlisted moons keep authored defaults.");
				MaxCount = config.Bind<int>("Spawning", "MaxCount", 1, new ConfigDescription("Maximum number of living Passengers at once.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 4), Array.Empty<object>()));
				PowerLevel = config.Bind<float>("Spawning", "PowerLevel", 2.5f, new ConfigDescription("Indoor enemy power budget cost for each Passenger.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 20f), Array.Empty<object>()));
				Health = config.Bind<int>("Core Stats", "Health", 5, new ConfigDescription("Hits Passenger can take before dying.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 100), Array.Empty<object>()));
				SightRange = config.Bind<float>("Detection", "SightRange", 45f, new ConfigDescription("Maximum distance at which Passenger tracks line of sight to players.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(5f, 150f), Array.Empty<object>()));
				RoamSpeed = BindSpeed(config, "RoamSpeed", 2.2f, "Movement speed while searching the interior.");
				StalkSpeed = BindSpeed(config, "StalkSpeed", 3f, "Movement speed while stalking a known target.");
				ChaseSpeed = BindSpeed(config, "ChaseSpeed", 6.2f, "Movement speed during committed pursuit.");
				FleeSpeed = BindSpeed(config, "FleeSpeed", 5.4f, "Movement speed while retreating after damage.");
				AttackDamage = config.Bind<int>("Combat", "AttackDamage", 20, new ConfigDescription("Damage dealt by one claw swing.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>()));
				AttackRange = config.Bind<float>("Combat", "AttackRange", 2.2f, new ConfigDescription("Distance required to begin a claw attack.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 8f), Array.Empty<object>()));
				AttackCooldown = config.Bind<float>("Combat", "AttackCooldown", 1.1f, new ConfigDescription("Seconds between claw attacks.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 30f), Array.Empty<object>()));
				TacticsEnabled = config.Bind<bool>("Combat", "TacticsEnabled", true, "Allow wall passes, attack feints, and lurks alongside direct breaches and wall assaults.");
				WallPhasingEnabled = config.Bind<bool>("Abilities", "WallPhasingEnabled", true, "Allow paced ghost combat and independent wall traversal while exploring.");
				PhaseCooldown = config.Bind<float>("Abilities", "PhaseCooldown", 5f, new ConfigDescription("Base spacing after a completed wall action before the next one (varied by 0.75-1.2x, at least 3 seconds), and the cooldown between escape crossings while fleeing. Ghost combat uses GhostCrossingSeconds and GhostConcealSeconds.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 60f), Array.Empty<object>()));
				ManifestPressureSeconds = config.Bind<float>("Combat", "ManifestPressureSeconds", 3f, new ConfigDescription("Useful movement/attack time between ghost actions; a blocked route ends early.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(2f, 6f), Array.Empty<object>()));
				GhostCrossingSeconds = config.Bind<float>("Abilities", "GhostCrossingSeconds", 4f, new ConfigDescription("Spacing for continuous wall traversal, independent of concealed relocation. A crossing that solves an obstacle blocking the approach uses half this spacing, clamped to 3-5 seconds.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(3f, 20f), Array.Empty<object>()));
				GhostConcealSeconds = config.Bind<float>("Abilities", "GhostConcealSeconds", 12f, new ConfigDescription("Spacing for full disappearances, varied by twenty percent. A crossing or floor emergence that solves an obstacle blocking the approach instead uses half the GhostCrossingSeconds spacing, clamped to 3-5 seconds.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(10f, 40f), Array.Empty<object>()));
				GhostFloorWeight = config.Bind<float>("Combat", "GhostFloorWeight", 30f, new ConfigDescription("Weight for a fast floor emergence 5-10 metres ahead of a known worker.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), Array.Empty<object>()));
				GhostTraversalWeight = config.Bind<float>("Combat", "GhostTraversalWeight", 40f, new ConfigDescription("Relative preference for a useful continuous wall crossing.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), Array.Empty<object>()));
				PresenceLoopEnabled = config.Bind<bool>("Audio and Presentation", "PresenceLoopEnabled", false, "Play the legacy continuous ghost ambience. Disabled for the quieter authored mix.");
				GhostSolidWeight = BindGhostWeight(config, "GhostSolidWeight", 35f, "Committed visible pressure between wall actions.");
				WallPassSpeed = BindSpeed(config, "WallPassSpeed", 8f, "Movement speed during a committed pass between walls.");
				WallPassAttackChance = config.Bind<float>("Combat", "WallPassAttackChance", 0.6f, new ConfigDescription("Chance a wall-to-wall pass includes a real claw swing; other passes are feints.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
				WallPassWeight = BindGhostWeight(config, "WallPassWeight", 35f, "Visible passes between two walls.");
				AttackFeintWeight = BindGhostWeight(config, "AttackFeintWeight", 20f, "Visible attack wind-ups that vanish before contact.");
				WallAssaultWeight = BindGhostWeight(config, "WallAssaultWeight", 25f, "Wall emergence followed by one or two real strikes.");
				PursuitBreachWeight = BindGhostWeight(config, "PursuitBreachWeight", 12f, "Direct wall crossings toward a nearby target.");
				WallLurkWeight = BindGhostWeight(config, "WallLurkWeight", 8f, "Longer hidden returns, occasionally from behind.");
				PossessionEnabled = config.Bind<bool>("Abilities", "PossessionEnabled", true, "Allow Passenger to possess eligible workers.");
				PossessionHealthThreshold = config.Bind<int>("Abilities", "PossessionHealthThreshold", 60, new ConfigDescription("A wounded worker below this health can be possessed while Passenger is visible.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>()));
				PossessionDurationSeconds = config.Bind<float>("Abilities", "PossessionDurationSeconds", 20f, new ConfigDescription("Base possession duration in seconds.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 120f), Array.Empty<object>()));
				PossessionRange = config.Bind<float>("Abilities", "PossessionRange", 3f, new ConfigDescription("Maximum distance for Passenger to begin possession.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 12f), Array.Empty<object>()));
				PossessionCooldownPerPlayerSeconds = config.Bind<float>("Abilities", "PossessionCooldownPerPlayerSeconds", 90f, new ConfigDescription("Seconds before the same worker can be possessed again.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 600f), Array.Empty<object>()));
				PossessedFriendlyFire = config.Bind<bool>("Abilities", "PossessedFriendlyFire", true, "Allow a possessed worker to attack teammates.");
				PossessedAttacksEnabled = config.Bind<bool>("Abilities", "PossessedAttacksEnabled", true, "Allow Passenger to force possessed workers to perform claw attacks.");
				PossessedAttackCooldownSeconds = config.Bind<float>("Abilities", "PossessedAttackCooldownSeconds", 1.6f, new ConfigDescription("Seconds between forced attacks by a possessed worker.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 30f), Array.Empty<object>()));
				PossessedAttackDamage = config.Bind<int>("Abilities", "PossessedAttackDamage", 10, new ConfigDescription("Damage dealt when a possessed worker hits a teammate.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>()));
				StealthPossessionEnabled = config.Bind<bool>("Abilities", "StealthPossessionEnabled", true, "Allow Passenger to attempt possession before the worker is wounded when it remains unseen.");
				PhaseVfxEnabled = config.Bind<bool>("Audio and Presentation", "PhaseVfxEnabled", true, "Show brief monochrome disturbances on entry/exit walls and body breakup during transit; clear both on emergence.");
				PossessionLoopVolume = config.Bind<float>("Audio and Presentation", "PossessionLoopVolume", 0.7f, new ConfigDescription("Volume of the local possession loop.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
				PossessedVoiceFilterEnabled = config.Bind<bool>("Audio and Presentation", "PossessedVoiceFilterEnabled", true, "Apply Passenger's authored voice effect to a possessed worker.");
				DebugLogs = config.Bind<bool>("Diagnostics", "DebugLogs", false, "Write verbose Passenger AI state logs.");
				PhaseDiagnostics = config.Bind<bool>("Diagnostics", "PhaseDiagnostics", false, "Write periodic wall-phase planning diagnostics. Off by default; an existing config keeps its value.");
				PhaseDiagnosticsSeconds = config.Bind<float>("Diagnostics", "PhaseDiagnosticsSeconds", 20f, new ConfigDescription("Seconds between phase diagnostic summaries.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(2f, 300f), Array.Empty<object>()));
				PossessionDiagnostics = config.Bind<bool>("Diagnostics", "PossessionDiagnostics", false, "Write possession eligibility and lifecycle diagnostics. Off by default; an existing config keeps its value.");
				PossessionDebugAllowSolo = config.Bind<bool>("Diagnostics", "PossessionDebugAllowSolo", false, "Permit possession with no other living teammate for local diagnostics.");
			}
		}

		private static ConfigEntry<float> BindGhostWeight(ConfigFile config, string key, float value, string description)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Expected O, but got Unknown
			return config.Bind<float>("Combat", key, value, new ConfigDescription(description + " Relative selection weight among legal actions; 0 disables this pattern.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), Array.Empty<object>()));
		}

		private static ConfigEntry<float> BindSpeed(ConfigFile config, string key, float defaultValue, string description)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Expected O, but got Unknown
			return config.Bind<float>("Movement", key, defaultValue, new ConfigDescription(description, (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 20f), Array.Empty<object>()));
		}
	}
	internal static class PoltergeistConfigMigration
	{
		private static readonly ConfigDefinition LegacySpawnWeight = new ConfigDefinition("10 - Spawning", "SpawnWeight");

		private static readonly LegacyMigrationSpec Spec = new LegacyMigrationSpec("Poltergeist", (IReadOnlyList<ConfigDefinition>)(object)new ConfigDefinition[1] { LegacySpawnWeight }, null, new Dictionary<ConfigDefinition, string>
		{
			{
				new ConfigDefinition("10 - Spawning", "LevelMask"),
				"-1"
			},
			{
				new ConfigDefinition("20 - Core Stats", "ModelScale"),
				"1.0"
			},
			{
				new ConfigDefinition("30 - Detection", "SightConeWidth"),
				"75"
			},
			{
				new ConfigDefinition("30 - Detection", "ProximityAwarenessRange"),
				"4"
			},
			{
				new ConfigDefinition("30 - Detection", "LoseTargetSeconds"),
				"6"
			},
			{
				new ConfigDefinition("30 - Detection", "LoseTargetDistance"),
				"55"
			},
			{
				new ConfigDefinition("30 - Detection", "RoamSearchWidth"),
				"50"
			},
			{
				new ConfigDefinition("30 - Detection", "RoamSearchPrecision"),
				"6"
			},
			{
				new ConfigDefinition("40 - Movement", "TurnSpeed"),
				"380"
			},
			{
				new ConfigDefinition("40 - Movement", "Acceleration"),
				"16"
			},
			{
				new ConfigDefinition("50 - Combat", "AttackDamageDelay"),
				"0.42"
			},
			{
				new ConfigDefinition("50 - Combat", "FleeSeconds"),
				"9"
			},
			{
				new ConfigDefinition("50 - Combat", "FleeBackpedalSeconds"),
				"1.2"
			},
			{
				new ConfigDefinition("50 - Combat", "TacticCommitSeconds"),
				"3"
			},
			{
				new ConfigDefinition("50 - Combat", "TacticStalkHoldDistance"),
				"11"
			},
			{
				new ConfigDefinition("50 - Combat", "TacticAmbushRange"),
				"6.5"
			},
			{
				new ConfigDefinition("50 - Combat", "TacticPlayerGazeAngle"),
				"50"
			},
			{
				new ConfigDefinition("50 - Combat", "TacticWeightDirect"),
				"16"
			},
			{
				new ConfigDefinition("50 - Combat", "TacticWeightFlank"),
				"22"
			},
			{
				new ConfigDefinition("50 - Combat", "TacticWeightStalk"),
				"16"
			},
			{
				new ConfigDefinition("50 - Combat", "TacticWeightAmbush"),
				"20"
			},
			{
				new ConfigDefinition("50 - Combat", "TacticWeightWithdraw"),
				"16"
			},
			{
				new ConfigDefinition("50 - Combat", "TacticWeightPhaseReposition"),
				"22"
			},
			{
				new ConfigDefinition("60 - Abilities", "PhasePathRatioThreshold"),
				"1.7"
			},
			{
				new ConfigDefinition("60 - Abilities", "PhaseMinDistance"),
				"4"
			},
			{
				new ConfigDefinition("60 - Abilities", "PhaseMaxDistance"),
				"18"
			},
			{
				new ConfigDefinition("60 - Abilities", "PhaseDriftSpeed"),
				"3.2"
			},
			{
				new ConfigDefinition("60 - Abilities", "PhaseRepositionPathRatio"),
				"1.2"
			},
			{
				new ConfigDefinition("60 - Abilities", "PhaseImpulseChance"),
				"0.35"
			},
			{
				new ConfigDefinition("60 - Abilities", "PhaseWhileRoaming"),
				"true"
			},
			{
				new ConfigDefinition("60 - Abilities", "PhaseRoamPathRatio"),
				"1.5"
			},
			{
				new ConfigDefinition("60 - Abilities", "PossessionCastSeconds"),
				"1.6"
			},
			{
				new ConfigDefinition("60 - Abilities", "PossessionBreakHealthFloor"),
				"20"
			},
			{
				new ConfigDefinition("60 - Abilities", "PuppetWalkSpeed"),
				"3.5"
			},
			{
				new ConfigDefinition("60 - Abilities", "PuppetSprintDistance"),
				"6"
			},
			{
				new ConfigDefinition("60 - Abilities", "PuppetSprintMultiplier"),
				"2.25"
			},
			{
				new ConfigDefinition("60 - Abilities", "PossessionExtensionSeconds"),
				"10"
			},
			{
				new ConfigDefinition("60 - Abilities", "PossessionExtensionRange"),
				"2.5"
			},
			{
				new ConfigDefinition("60 - Abilities", "PuppetTurretAvoidRadius"),
				"5"
			},
			{
				new ConfigDefinition("60 - Abilities", "PuppetMineAvoidRadius"),
				"2.5"
			},
			{
				new ConfigDefinition("60 - Abilities", "PossessedAttackRange"),
				"2.2"
			},
			{
				new ConfigDefinition("60 - Abilities", "PossessionShipSafeRadius"),
				"20"
			},
			{
				new ConfigDefinition("60 - Abilities", "StealthSneakAbortDistance"),
				"4"
			},
			{
				new ConfigDefinition("60 - Abilities", "StealthSneakCooldownSeconds"),
				"12"
			},
			{
				new ConfigDefinition("70 - Audio and Presentation", "MatchAnimationToMovement"),
				"true"
			},
			{
				new ConfigDefinition("70 - Audio and Presentation", "AuthoredWalkSpeed"),
				"1.9"
			},
			{
				new ConfigDefinition("70 - Audio and Presentation", "DeathDissipateDelay"),
				"0.9"
			},
			{
				new ConfigDefinition("70 - Audio and Presentation", "DeathDissipateSeconds"),
				"2"
			},
			{
				new ConfigDefinition("70 - Audio and Presentation", "AuthoredRunSpeed"),
				"4.2"
			},
			{
				new ConfigDefinition("70 - Audio and Presentation", "PhaseVfxVariant"),
				"0"
			},
			{
				new ConfigDefinition("70 - Audio and Presentation", "PhaseBreachAlignAxis"),
				"0"
			},
			{
				new ConfigDefinition("70 - Audio and Presentation", "PhaseBreachScale"),
				"1"
			},
			{
				new ConfigDefinition("70 - Audio and Presentation", "PhaseForceHdrpParticleShaders"),
				"false"
			},
			{
				new ConfigDefinition("70 - Audio and Presentation", "PhaseBreachLingerSeconds"),
				"2.5"
			},
			{
				new ConfigDefinition("70 - Audio and Presentation", "PhaseLightIntensity"),
				"14"
			},
			{
				new ConfigDefinition("70 - Audio and Presentation", "PhaseLightRange"),
				"7"
			},
			{
				new ConfigDefinition("70 - Audio and Presentation", "PhaseLightColor"),
				"#6FA8FF"
			},
			{
				new ConfigDefinition("70 - Audio and Presentation", "PhaseDissolveEnabled"),
				"true"
			},
			{
				new ConfigDefinition("70 - Audio and Presentation", "PhaseDissolveOffsetAxis"),
				"0"
			},
			{
				new ConfigDefinition("70 - Audio and Presentation", "PhaseDissolveDepth"),
				"0.65"
			},
			{
				new ConfigDefinition("70 - Audio and Presentation", "PhaseDissolveEdgeWidth"),
				"0.5"
			},
			{
				new ConfigDefinition("70 - Audio and Presentation", "PhaseDissolveEdgeIntensity"),
				"40"
			},
			{
				new ConfigDefinition("70 - Audio and Presentation", "PhaseDissolveEdgeColor"),
				"#6FA8FF"
			},
			{
				new ConfigDefinition("70 - Audio and Presentation", "PossessionMergeVfxEnabled"),
				"true"
			},
			{
				new ConfigDefinition("70 - Audio and Presentation", "PossessionMergeSeconds"),
				"0.7"
			},
			{
				new ConfigDefinition("70 - Audio and Presentation", "PossessionEmergeSeconds"),
				"0.9"
			},
			{
				new ConfigDefinition("70 - Audio and Presentation", "PossessionMergeMinScale"),
				"0.12"
			},
			{
				new ConfigDefinition("70 - Audio and Presentation", "PossessionRelocateOnRelease"),
				"true"
			},
			{
				new ConfigDefinition("70 - Audio and Presentation", "PossessionVisorGlowIntensity"),
				"10"
			},
			{
				new ConfigDefinition("70 - Audio and Presentation", "PossessionVisorGlowRange"),
				"3"
			},
			{
				new ConfigDefinition("70 - Audio and Presentation", "PossessedVoicePitch"),
				"0.68"
			},
			{
				new ConfigDefinition("70 - Audio and Presentation", "PossessedVoiceDistortionV2"),
				"0.35"
			},
			{
				new ConfigDefinition("70 - Audio and Presentation", "PossessedVoiceEchoDelayV2"),
				"110"
			},
			{
				new ConfigDefinition("70 - Audio and Presentation", "PossessedVoiceEchoDecayV2"),
				"0.45"
			},
			{
				new ConfigDefinition("70 - Audio and Presentation", "PossessedVoiceEchoWetMixV2"),
				"0.45"
			},
			{
				new ConfigDefinition("70 - Audio and Presentation", "PossessedVoiceDemonLayerMix"),
				"0.8"
			},
			{
				new ConfigDefinition("70 - Audio and Presentation", "PossessedVoiceRingModHzV2"),
				"48"
			},
			{
				new ConfigDefinition("70 - Audio and Presentation", "PossessedVoiceRingModMixV2"),
				"0.5"
			},
			{
				new ConfigDefinition("70 - Audio and Presentation", "PossessedVoiceNoiseGateMix"),
				"0.12"
			},
			{
				new ConfigDefinition("70 - Audio and Presentation", "PossessedVoiceBitcrushMixV2"),
				"0.25"
			},
			{
				new ConfigDefinition("70 - Audio and Presentation", "PossessedVoiceDriveV2"),
				"1.6"
			},
			{
				new ConfigDefinition("70 - Audio and Presentation", "SpectralArmsEnabled"),
				"true"
			},
			{
				new ConfigDefinition("70 - Audio and Presentation", "SpectralArmsScale"),
				"0.8"
			},
			{
				new ConfigDefinition("70 - Audio and Presentation", "SpectralArmsHeightOffset"),
				"0.08"
			},
			{
				new ConfigDefinition("70 - Audio and Presentation", "PossessedHandsOutEnabled"),
				"true"
			},
			{
				new ConfigDefinition("70 - Audio and Presentation", "PossessedHandsOutWeight"),
				"1"
			},
			{
				new ConfigDefinition("70 - Audio and Presentation", "PossessionBlurIntensity"),
				"0.75"
			},
			{
				new ConfigDefinition("70 - Audio and Presentation", "PossessionAudioLowPassCutoff"),
				"1000"
			},
			{
				new ConfigDefinition("70 - Audio and Presentation", "UpdateBoundsWhenOffscreen"),
				"true"
			},
			{
				new ConfigDefinition("70 - Audio and Presentation", "AlwaysAnimate"),
				"true"
			},
			{
				new ConfigDefinition("70 - Audio and Presentation", "PossessedHitVolume"),
				"0.9"
			}
		}, Build);

		internal static bool TryMigrate(ConfigFile config, ManualLogSource log)
		{
			return LegacyConfigMigrator.TryMigrate(config, log, Spec);
		}

		private static void Build(LegacyConfigValues values, MigratedConfigWriter output)
		{
			output.Carry("General", "Enabled");
			output.CarrySpawnWeightMultiplier(LegacySpawnWeight, 14f);
			output.Carry("Spawning", "MoonWeightOverrides");
			output.Carry("Spawning", "MaxCount");
			output.Carry("Spawning", "PowerLevel");
			output.Carry("Core Stats", "Health");
			output.Carry("Detection", "SightRange");
			output.Carry("Movement", "RoamSpeed");
			output.Carry("Movement", "StalkSpeed");
			output.Carry("Movement", "ChaseSpeed");
			output.Carry("Movement", "FleeSpeed");
			output.Carry("Combat", "AttackDamage");
			output.Carry("Combat", "AttackRange");
			output.Carry("Combat", "AttackCooldown");
			output.Carry("Combat", "TacticsEnabled");
			output.Carry("Abilities", "WallPhasingEnabled");
			output.Carry("Abilities", "PhaseCooldown");
			output.Carry("Abilities", "PossessionEnabled");
			output.Carry("Abilities", "PossessionHealthThreshold");
			output.Carry("Abilities", "PossessionDurationSeconds");
			output.Carry("Abilities", "PossessionRange");
			output.Carry("Abilities", "PossessionCooldownPerPlayerSeconds");
			output.Carry("Abilities", "PossessedFriendlyFire");
			output.Carry("Abilities", "PossessedAttacksEnabled");
			output.Carry("Abilities", "PossessedAttackCooldownSeconds");
			output.Carry("Abilities", "PossessedAttackDamage");
			output.Carry("Abilities", "StealthPossessionEnabled");
			output.Carry("Audio and Presentation", "PhaseVfxEnabled");
			output.Carry("Audio and Presentation", "PossessionLoopVolume");
			output.Carry("Audio and Presentation", "PossessedVoiceFilterEnabled");
			output.Carry("Diagnostics", "DebugLogs");
			output.Carry("Diagnostics", "PhaseDiagnostics");
			output.Carry("Diagnostics", "PhaseDiagnosticsSeconds");
			output.Carry("Diagnostics", "PossessionDiagnostics");
			output.Carry("Diagnostics", "PossessionDebugAllowSolo");
		}
	}
	internal sealed class PoltergeistSpawnWeights : ContextualSpawnWeights
	{
		internal PoltergeistSpawnWeights(Func<float> multiplier, Func<string> moonOverrides, Action<string> logWarning)
			: base(SpawnWeightTable.Passenger, "Passenger", multiplier, moonOverrides, logWarning)
		{
		}
	}
	internal static class PoltergeistTuning
	{
		internal const float ModelScale = 1f;

		internal const float SightConeWidth = 75f;

		internal const float ProximityAwarenessRange = 4f;

		internal const float LoseTargetSeconds = 6f;

		internal const float LoseTargetDistance = 55f;

		internal const float RoamSearchWidth = 50f;

		internal const float RoamSearchPrecision = 6f;

		internal const float TurnSpeed = 380f;

		internal const float Acceleration = 16f;

		internal const float AgentStoppingDistance = 0.12f;

		internal const float AttackAnimationSpeed = 1.7f;

		internal const float AttackContactWindupSeconds = 0.08f;

		internal const float AttackContactWindowSeconds = 0.58f;

		internal const float AttackHandRadius = 0.18f;

		internal const float FleeSeconds = 9f;

		internal const float FleeBackpedalSeconds = 1.2f;

		internal const float TacticCommitSeconds = 3f;

		internal const float TacticStalkHoldDistance = 11f;

		internal const float TacticAmbushRange = 6.5f;

		internal const float TacticPlayerGazeAngle = 50f;

		internal const int TacticWeightDirect = 16;

		internal const int TacticWeightFlank = 22;

		internal const int TacticWeightStalk = 16;

		internal const int TacticWeightAmbush = 20;

		internal const int TacticWeightWithdraw = 16;

		internal const float PhaseMinDistance = 4f;

		internal const float PhaseMaxDistance = 18f;

		internal const float PhaseDriftSpeed = 14f;

		internal const float PhaseBodyClearanceMargin = 0.15f;

		internal const float PhaseLandingSearchStep = 0.35f;

		internal const float PhaseLandingSearchDistance = 6f;

		internal const float PossessionCastSeconds = 1.6f;

		internal const int PossessionBreakHealthFloor = 20;

		internal const float PuppetWalkSpeed = 3.5f;

		internal const float PuppetSprintDistance = 6f;

		internal const float PuppetSprintMultiplier = 2.25f;

		internal const float PossessionExtensionSeconds = 10f;

		internal const float PossessionExtensionRange = 2.5f;

		internal const float PuppetTurretAvoidRadius = 5f;

		internal const float PuppetMineAvoidRadius = 2.5f;

		internal const float PossessedAttackRange = 2.2f;

		internal const float PossessionShipSafeRadius = 20f;

		internal const float StealthSneakAbortDistance = 4f;

		internal const float StealthSneakCooldownSeconds = 12f;

		internal const float DeathDissipateDelay = 0.9f;

		internal const float DeathDissipateSeconds = 2f;

		internal const float PresenceLoopVolume = 0.45f;

		internal const float PresenceLoopFadePerSecond = 1.5f;

		internal const float PresenceLoopMaxDistance = 12f;

		internal const float SwipeVolume = 0.65f;

		internal const float SwipeMaxDistance = 18f;

		internal const float PhaseAudioVolume = 0.75f;

		internal const float PhaseAudioMaxDistance = 30f;

		internal const string PhaseLightColor = "#6FA8FF";

		internal const bool PossessionMergeVfxEnabled = true;

		internal const float PossessionMergeSeconds = 0.7f;

		internal const float PossessionEmergeSeconds = 0.9f;

		internal const float PossessionMergeMinScale = 0.12f;

		internal const bool PossessionRelocateOnRelease = true;

		internal const float PossessionVisorGlowIntensity = 10f;

		internal const float PossessionVisorGlowRange = 3f;

		internal const float PossessedVoicePitch = 1f;

		internal const float PossessedVoiceDistortion = 0f;

		internal const float PossessedVoiceEchoDelay = 110f;

		internal const float PossessedVoiceEchoDecay = 0.45f;

		internal const float PossessedVoiceEchoWetMix = 0f;

		internal const float PossessedVoiceDemonLayerMix = 0.5f;

		internal const float PossessedVoiceRingModHz = 48f;

		internal const float PossessedVoiceRingModMix = 0.15f;

		internal const float PossessedVoiceNoiseGateMix = 0.018f;

		internal const float PossessedVoiceBitcrushMix = 0.05f;

		internal const float PossessedVoiceDrive = 1.3f;

		internal const bool SpectralArmsEnabled = true;

		internal const float SpectralArmsScale = 0.8f;

		internal const float SpectralArmsHeightOffset = 0.08f;

		internal const bool PossessedHandsOutEnabled = true;

		internal const float PossessedHandsOutWeight = 1f;

		internal const bool UpdateBoundsWhenOffscreen = true;

		internal const bool AlwaysAnimate = true;

		internal const float SuspensionDriftAmplitude = 0.05f;

		internal const float SuspensionLeanDegrees = 6f;

		internal const float SuspensionLeanSpeed = 4.5f;

		internal const float SuspensionBlendPerSecond = 3f;
	}
}
namespace Y4NGZPoltergeist.Patches
{
	[HarmonyPatch]
	internal static class PossessedVoicePatches
	{
		[HarmonyPatch(typeof(PlayerControllerB), "Update")]
		[HarmonyPostfix]
		private static void UpdatePostfix(PlayerControllerB __instance)
		{
			if (PoltergeistPossessedVoice.AnyActive && !((Object)(object)__instance == (Object)null))
			{
				PoltergeistPossessedVoice.ReassertPitchFor(__instance);
			}
		}

		[HarmonyPatch(typeof(StartOfRound), "UpdatePlayerVoiceEffects")]
		[HarmonyPostfix]
		private static void UpdatePlayerVoiceEffectsPostfix()
		{
			if (PoltergeistPossessedVoice.AnyActive)
			{
				PoltergeistPossessedVoice.ReassertAll();
			}
		}
	}
	[HarmonyPatch]
	internal static class PossessionInputPatches
	{
		private static bool LocalPlayerIsPossessed(PlayerControllerB player)
		{
			if (PoltergeistAI.LiveCount == 0 || (Object)(object)player == (Object)null || (Object)(object)GameNetworkManager.Instance == (Object)null || (Object)(object)player != (Object)(object)GameNetworkManager.Instance.localPlayerController)
			{
				return false;
			}
			PoltergeistPossessionLock component = ((Component)player).GetComponent<PoltergeistPossessionLock>();
			if ((Object)(object)component != (Object)null)
			{
				return component.Holds;
			}
			return false;
		}

		[HarmonyPatch(typeof(PlayerControllerB), "Jump_performed")]
		[HarmonyPrefix]
		private static bool JumpPerformedPrefix(PlayerControllerB __instance)
		{
			return !LocalPlayerIsPossessed(__instance);
		}

		[HarmonyPatch(typeof(PlayerControllerB), "Crouch_performed")]
		[HarmonyPrefix]
		private static bool CrouchPerformedPrefix(PlayerControllerB __instance)
		{
			return !LocalPlayerIsPossessed(__instance);
		}

		[HarmonyPatch(typeof(PlayerControllerB), "ClickHoldInteraction")]
		[HarmonyPrefix]
		private static bool ClickHoldInteractionPrefix(PlayerControllerB __instance)
		{
			if (!LocalPlayerIsPossessed(__instance))
			{
				return true;
			}
			__instance.isHoldingInteract = false;
			return false;
		}

		[HarmonyPatch(typeof(PlayerControllerB), "Interact_performed")]
		[HarmonyPrefix]
		private static bool InteractPerformedPrefix(PlayerControllerB __instance)
		{
			return !LocalPlayerIsPossessed(__instance);
		}

		[HarmonyPatch(typeof(PlayerControllerB), "PerformEmote")]
		[HarmonyPrefix]
		private static bool PerformEmotePrefix(PlayerControllerB __instance)
		{
			return !LocalPlayerIsPossessed(__instance);
		}

		[HarmonyPatch(typeof(PlayerControllerB), "Discard_performed")]
		[HarmonyPrefix]
		private static bool DiscardPerformedPrefix(PlayerControllerB __instance)
		{
			return !LocalPlayerIsPossessed(__instance);
		}

		[HarmonyPatch(typeof(PlayerControllerB), "Update")]
		[HarmonyPostfix]
		private static void UpdatePostfix(PlayerControllerB __instance)
		{
			if (PoltergeistAI.LiveCount != 0 && !((Object)(object)__instance == (Object)null) && VictimRpc.IsVictimLocal(__instance))
			{
				PoltergeistPossessionLock component = ((Component)__instance).GetComponent<PoltergeistPossessionLock>();
				if ((Object)(object)component != (Object)null && component.Holds)
				{
					component.DrivePuppetMovement();
				}
			}
		}

		[HarmonyPatch(typeof(PlayerControllerB), "LateUpdate")]
		[HarmonyPostfix]
		private static void LateUpdatePostfix(PlayerControllerB __instance)
		{
			if (PoltergeistAI.LiveCount != 0 && !((Object)(object)__instance == (Object)null) && VictimRpc.IsVictimLocal(__instance))
			{
				PoltergeistPossessionLock component = ((Component)__instance).GetComponent<PoltergeistPossessionLock>();
				if ((Object)(object)component != (Object)null && component.Holds)
				{
					component.DrivePuppetLook();
				}
			}
		}

		[HarmonyPatch(typeof(PlayerControllerB), "ActivateItem_performed")]
		[HarmonyPriority(800)]
		[HarmonyPrefix]
		private static bool ActivateItemPerformedPrefix(PlayerControllerB __instance)
		{
			return !LocalPlayerIsPossessed(__instance);
		}
	}
	internal static class PossessionInteractionBridge
	{
		private const string PackId = "y4ngz.poltergeist.possessed-claws";

		private const string FirstPersonManifestFile = "y4ngz-upgrades-fists-firstperson.manifest.json";

		private const string ThirdPersonManifestFile = "y4ngz-upgrades-fists-thirdperson.manifest.json";

		internal const string FirstPersonInteractionId = "y4ngz.native-fists.firstperson";

		internal const string ThirdPersonInteractionId = "y4ngz.native-fists.thirdperson";

		internal const string EnterTrigger = "Y4NGZ_Fists_Enter";

		internal const string PunchLeftTrigger = "PunchLeft";

		internal const string PunchRightTrigger = "PunchRight";

		private static bool _resolved;

		private static MethodInfo _tryStopPlayerInteractions;

		private static object _interruptedReason;

		private static Type _packType;

		private static Type _definitionType;

		private static Type _requestType;

		private static Type _presentationKindType;

		private static MethodInfo _tryRegisterPack;

		private static MethodInfo _tryStartInteraction;

		private static MethodInfo _tryStopInteraction;

		private static MethodInfo _isInteractionActive;

		private static MethodInfo _tryFireTrigger;

		private static MethodInfo _tryBeginExit;

		private static bool _packRegistered;

		private static bool _packUnavailableLogged;

		internal static void TryStopInteractions(PlayerControllerB player)
		{
			if ((Object)(object)player == (Object)null)
			{
				return;
			}
			try
			{
				if (!_resolved)
				{
					Resolve();
				}
				if (_tryStopPlayerInteractions != null)
				{
					_tryStopPlayerInteractions.Invoke(null, new object[2] { player, _interruptedReason });
				}
			}
			catch (Exception ex)
			{
				PoltergeistAI.LogPossession("Interaction-API arbitration failed: " + ex.Message);
			}
		}

		private static void Resolve()
		{
			_resolved = true;
			Type type = Type.GetType("Y4NGZInteractions.InteractionAnimationApi.LCInteractionAnimationAPI, Y4NGZInteractions");
			Type type2 = Type.GetType("Y4NGZInteractions.InteractionAnimationApi.InteractionAnimationStopReason, Y4NGZInteractions");
			if (!(type == null) && !(type2 == null))
			{
				_interruptedReason = Enum.Parse(type2, "Interrupted");
				_tryStopPlayerInteractions = type.GetMethod("TryStopPlayerInteractions", BindingFlags.Static | BindingFlags.Public, null, new Type[2]
				{
					typeof(PlayerControllerB),
					type2
				}, null);
				_packType = Type.GetType("Y4NGZInteractions.InteractionAnimationApi.InteractionAnimationPackDefinition, Y4NGZInteractions");
				_definitionType = Type.GetType("Y4NGZInteractions.InteractionAnimationApi.InteractionAnimationDefinition, Y4NGZInteractions");
				_requestType = Type.GetType("Y4NGZInteractions.InteractionAnimationApi.InteractionAnimationRequest, Y4NGZInteractions");
				_presentationKindType = Type.GetType("Y4NGZInteractions.InteractionAnimationApi.InteractionAnimationPresentationKind, Y4NGZInteractions");
				_tryRegisterPack = type.GetMethod("TryRegisterInteractionPack", BindingFlags.Static | BindingFlags.Public);
				_tryStartInteraction = type.GetMethod("TryStartInteraction", BindingFlags.Static | BindingFlags.Public);
				_tryStopInteraction = type.GetMethod("TryStopInteraction", BindingFlags.Static | BindingFlags.Public);
				_isInteractionActive = type.GetMethod("IsInteractionActive", BindingFlags.Static | BindingFlags.Public);
				_tryFireTrigger = type.GetMethod("TryFireInteractionTrigger", BindingFlags.Static | BindingFlags.Public);
				_tryBeginExit = type.GetMethod("TryBeginInteractionExit", BindingFlags.Static | BindingFlags.Public);
			}
		}

		internal static bool EnsureFistsPackRegistered()
		{
			if (_packRegistered)
			{
				return true;
			}
			try
			{
				if (!_resolved)
				{
					Resolve();
				}
				if (_tryRegisterPack == null || _packType == null || _definitionType == null)
				{
					return LogPackUnavailable("Y4NGZInteractions' animation API is not present");
				}
				if (!TryFindFistsAssetRoot(out var root))
				{
					return LogPackUnavailable("Y4NGZUpgrades' fists manifests were not found under BepInEx/plugins");
				}
				object obj = Activator.CreateInstance(_packType);
				SetProperty(obj, "PackId", "y4ngz.poltergeist.possessed-claws");
				SetProperty(obj, "DisplayName", "Y4NGZ Poltergeist Possessed Claws");
				SetProperty(obj, "Version", "1.2.1");
				SetProperty(obj, "Author", "Y4NGZ");
				SetProperty(obj, "AssetRootPath", root);
				Array array = Array.CreateInstance(_definitionType, 2);
				array.SetValue(BuildDefinition("y4ngz.native-fists.firstperson", "Possessed Claws (First Person)", "DedicatedLocalViewmodel", File.ReadAllText(Path.Combine(root, "y4ngz-upgrades-fists-firstperson.manifest.json"))), 0);
				array.SetValue(BuildDefinition("y4ngz.native-fists.thirdperson", "Possessed Claws (Third Person)", "BodyWorld", File.ReadAllText(Path.Combine(root, "y4ngz-upgrades-fists-thirdperson.manifest.json"))), 1);
				SetProperty(obj, "Interactions", array);
				object[] array2 = new object[2] { obj, null };
				bool num = (bool)_tryRegisterPack.Invoke(null, array2);
				string text = (array2[1] as string) ?? string.Empty;
				if (!num && !string.Equals(text, "pack_already_registered", StringComparison.OrdinalIgnoreCase))
				{
					return LogPackUnavailable("pack registration refused (" + text + ")");
				}
				_packRegistered = true;
				PoltergeistAI.LogPossession("Possessed-attack pack registered against '" + root + "'.");
				return true;
			}
			catch (Exception ex)
			{
				return LogPackUnavailable(ex.Message);
			}
		}

		internal static bool TryStartFistsPresentation(PlayerControllerB player, bool firstPerson, out object handle)
		{
			handle = null;
			if ((Object)(object)player == (Object)null || !EnsureFistsPackRegistered() || _requestType == null || _tryStartInteraction == null)
			{
				return false;
			}
			try
			{
				object obj = Activator.CreateInstance(_requestType);
				SetProperty(obj, "Player", player);
				SetProperty(obj, "PackId", "y4ngz.poltergeist.possessed-claws");
				SetProperty(obj, "InteractionId", firstPerson ? "y4ngz.native-fists.firstperson" : "y4ngz.native-fists.thirdperson");
				SetProperty(obj, "OwnerModId", "y4ngz.lethalcompany.poltergeist");
				object[] array = new object[3] { obj, null, null };
				if (!(bool)_tryStartInteraction.Invoke(null, array))
				{
					PoltergeistAI.LogPossession("Possessed-attack " + (firstPerson ? "FP" : "TP") + " presentation refused: " + (array[2] as string) + ".");
					return false;
				}
				handle = array[1];
				return true;
			}
			catch (Exception ex)
			{
				PoltergeistAI.LogPossession("Possessed-attack presentation failed: " + ex.Message);
				return false;
			}
		}

		internal static bool IsPresentationActive(object handle)
		{
			if (handle != null && _isInteractionActive != null)
			{
				return Safe(() => (bool)_isInteractionActive.Invoke(null, new object[1] { handle }));
			}
			return false;
		}

		internal static bool FirePresentationTrigger(object handle, string trigger)
		{
			if (IsPresentationActive(handle) && _tryFireTrigger != null)
			{
				return Safe(() => (bool)_tryFireTrigger.Invoke(null, new object[2] { handle, trigger }));
			}
			return false;
		}

		internal static void EndPresentation(object handle, bool immediate)
		{
			if (IsPresentationActive(handle) && (immediate || !(_tryBeginExit != null) || !Safe(() => (bool)_tryBeginExit.Invoke(null, new object[2] { handle, null }))) && _tryStopInteraction != null && _interruptedReason != null)
			{
				Safe(() => (bool)_tryStopInteraction.Invoke(null, new object[2] { handle, _interruptedReason }));
			}
		}

		private static bool TryFindFistsAssetRoot(out string root)
		{
			root = null;
			string pluginPath = Paths.PluginPath;
			if (string.IsNullOrEmpty(pluginPath) || !Directory.Exists(pluginPath))
			{
				return false;
			}
			string[] files = Directory.GetFiles(pluginPath, "y4ngz-upgrades-fists-firstperson.manifest.json", SearchOption.AllDirectories);
			for (int i = 0; i < files.Length; i++)
			{
				string directoryName = Path.GetDirectoryName(files[i]);
				if (directoryName != null && File.Exists(Path.Combine(directoryName, "y4ngz-upgrades-fists-thirdperson.manifest.json")))
				{
					root = directoryName;
					return true;
				}
			}
			return false;
		}

		private static object BuildDefinition(string interactionId, string displayName, string kind, string manifestJson)
		{
			object? obj = Activator.CreateInstance(_definitionType);
			SetProperty(obj, "InteractionId", interactionId);
			SetProperty(obj, "DisplayName", displayName);
			SetProperty(obj, "ExpectedDurationSeconds", 0f);
			SetProperty(obj, "PresentationKind", Enum.Parse(_presentationKindType, kind));
			SetProperty(obj, "ManifestJson", manifestJson);
			return obj;
		}

		private static void SetProperty(object target, string name, object value)
		{
			target.GetType().GetProperty(name, BindingFlags.Instance | BindingFlags.Public)?.SetValue(target, value);
		}

		private static bool Safe(Func<bool> call)
		{
			try
			{
				return call();
			}
			catch (Exception ex)
			{
				PoltergeistAI.LogPossession("Interaction-API call failed: " + ex.Message);
				return false;
			}
		}

		private static bool LogPackUnavailable(string why)
		{
			if (!_packUnavailableLogged)
			{
				_packUnavailableLogged = true;
				PoltergeistAI.LogPossession("Possessed attacks disabled: " + why + ".");
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(StartOfRound))]
	internal static class RoundResetPatches
	{
		[HarmonyPatch("ReviveDeadPlayers")]
		[HarmonyPostfix]
		private static void ReviveDeadPlayersPostfix()
		{
			ResetRoundState();
		}

		[HarmonyPatch("Start")]
		[HarmonyPostfix]
		private static void StartPostfix()
		{
			ResetRoundState();
		}

		private static void ResetRoundState()
		{
			PlayerInputLock.ClearAll();
			PoltergeistAI.ResetRoundState();
		}
	}
}
namespace Y4NGZPoltergeist.AI
{
	internal enum GhostPattern : byte
	{
		None,
		WallPass,
		AttackFeint,
		Assault,
		Breach,
		Lurk,
		Solid,
		Traverse,
		Floor
	}
	internal enum GhostStage : byte
	{
		None,
		Approach,
		Windup,
		Enter,
		Hidden,
		Emerge,
		Grace,
		Pass,
		Contact,
		Recovery
	}
	internal enum FacingIntent : byte
	{
		Previous,
		Target,
		Path,
		Travel
	}
	internal static class FacingPolicy
	{
		internal const float DeadZone = 0.35f;

		internal const float DeadZoneSqr = 0.122499995f;

		internal static FacingIntent Resolve(bool targetKnown, bool roaming, float toTargetSqr, float pathHeadingSqr, float travelSqr)
		{
			if (targetKnown && !roaming)
			{
				if (!Usable(toTargetSqr, 0.0001f))
				{
					return FacingIntent.Previous;
				}
				return FacingIntent.Target;
			}
			if (Usable(pathHeadingSqr, 0.122499995f))
			{
				return FacingIntent.Path;
			}
			if (!Usable(travelSqr, 0.122499995f))
			{
				return FacingIntent.Previous;
			}
			return FacingIntent.Travel;
		}

		private static bool Usable(float sqr, float minimum)
		{
			if (!float.IsNaN(sqr) && !float.IsInfinity(sqr))
			{
				return sqr > minimum;
			}
			return false;
		}
	}
	internal static class GhostCombatPolicy
	{
		internal const float EntryLimit = 2f;

		internal const float SurfaceRange = 12f;

		internal const float HiddenRange = 24f;

		internal const float SurfaceSeconds = 0.24f;

		internal const float VanishSeconds = 0.22f;

		internal const float ArrivalGrace = 0.7f;

		internal const float FeintWindup = 0.32f;

		internal const float HitStagger = 0.7f;

		internal const int SurfaceBudget = 48;

		internal const int ObstacleRoutes = 400;

		internal static int Bit(GhostPattern pattern)
		{
			return 1 << (int)pattern;
		}

		internal static GhostPattern Choose(int available, GhostPattern previous, int sincePass, int sinceFeint, float roll, float pass, float feint, float assault, float breach, float lurk, float solid = 0f, float traverse = 0f, float floor = 0f)
		{
			for (int i = 1; i <= 8; i++)
			{
				if (!Finite(Weight((GhostPattern)i)) || Weight((GhostPattern)i) <= 0f)
				{
					available &= ~(1 << i);
				}
			}
			if (available == 0)
			{
				return GhostPattern.None;
			}
			float num = 0f;
			for (int j = 1; j <= 8; j++)
			{
				if ((available & (1 << j)) != 0)
				{
					num += Adjusted((GhostPattern)j);
				}
			}
			float num2 = (Finite(roll) ? Math.Clamp(roll, 0f, 0.999999f) : 0f) * num;
			for (int k = 1; k <= 8; k++)
			{
				if ((available & (1 << k)) != 0)
				{
					num2 -= Adjusted((GhostPattern)k);
					if (num2 < 0f)
					{
						return (GhostPattern)k;
					}
				}
			}
			return GhostPattern.None;
			float Adjusted(GhostPattern p)
			{
				return Weight(p) * ((p == previous) ? 0.35f : 1f);
			}
			float Weight(GhostPattern p)
			{
				return p switch
				{
					GhostPattern.Floor => floor, 
					GhostPattern.Traverse => traverse, 
					GhostPattern.Lurk => lurk, 
					GhostPattern.Breach => breach, 
					GhostPattern.Assault => assault, 
					GhostPattern.AttackFeint => feint, 
					GhostPattern.WallPass => pass, 
					_ => solid, 
				};
			}
		}

		internal static bool ShortEntry(float straight, float walked)
		{
			if (Finite(straight) && Finite(walked) && straight >= 0f && walked >= 0f && walked <= 2f)
			{
				return walked <= straight * 1.5f + 0.4f;
			}
			return false;
		}

		internal static bool SurfaceLanding(float distance, float floor)
		{
			if (Finite(distance) && Finite(floor) && distance >= 1.25f && distance <= 12f)
			{
				return Math.Abs(floor) <= 0.8f;
			}
			return false;
		}

		internal static bool ContactAllowed(uint epoch, uint currentEpoch, byte transit, bool alive, bool active)
		{
			return epoch == currentEpoch && (transit == 0 || transit == 3) && alive && active;
		}

		internal static float ObstacleCrossingCooldown(float crossingSeconds)
		{
			if (!Finite(crossingSeconds))
			{
				return 5f;
			}
			return Math.Clamp(crossingSeconds * 0.5f, 3f, 5f);
		}

		internal static bool ObstacleRecent(float now, float blockedAt, float window = 2f)
		{
			if (Finite(now) && Finite(blockedAt) && Finite(window) && now - blockedAt >= 0f)
			{
				return now - blockedAt <= window;
			}
			return false;
		}

		internal static int PreferObstacleRoutes(int available)
		{
			if ((available & 0x190) == 0)
			{
				return available;
			}
			return available & 0x190;
		}

		internal static int StrikeBudget(float roll)
		{
			if (!Finite(roll) || !(roll < 0.3f))
			{
				return 1;
			}
			return 2;
		}

		internal static int ExcludeSolidWhenRepositioning(int available, bool due)
		{
			if (!due || (available & ~Bit(GhostPattern.Solid)) == 0)
			{
				return available;
			}
			return available & ~Bit(GhostPattern.Solid);
		}

		private static bool Finite(float value)
		{
			if (!float.IsNaN(value))
			{
				return !float.IsInfinity(value);
			}
			return false;
		}
	}
	public static class PassengerVocalPose
	{
		public const float AccentSeconds = 1.2f;

		public const float MaximumJawDegrees = 32f;

		public const float InterruptFadeSeconds = 0.08f;

		public static float Opening(float normalizedTime, float energy)
		{
			if (normalizedTime <= 0f || normalizedTime >= 1f)
			{
				return 0f;
			}
			if (normalizedTime < 0.12f)
			{
				return 0.08f * Smooth(normalizedTime / 0.12f);
			}
			if (normalizedTime < 0.28f)
			{
				return 0.08f + 0.86f * Smooth((normalizedTime - 0.12f) / 0.16f);
			}
			if (normalizedTime < 0.68f)
			{
				float num = (float)Math.Sin(Math.PI * (double)(normalizedTime - 0.28f) / 0.4000000059604645);
				return 0.94f + 0.06f * Clamp(energy) * num;
			}
			return 0.94f * (1f - Smooth((normalizedTime - 0.68f) / 0.32f));
		}

		private static float Clamp(float value)
		{
			return Math.Max(0f, Math.Min(1f, value));
		}

		private static float Smooth(float value)
		{
			value = Clamp(value);
			return value * value * (3f - 2f * value);
		}
	}
	public class PoltergeistAI : EnemyAI, INoiseListener
	{
		private enum PhaseReject
		{
			Throttled,
			Disabled,
			Busy,
			Cooldown,
			NoAnchor,
			NoAgent,
			NoTarget,
			OutOfBand,
			NoNavPoint,
			DestinationTooFar,
			TravelTooShort,
			NoWall,
			NoClearLanding,
			PathNotWorse,
			Started,
			Count
		}

		private enum PhaseSource
		{
			Opportunistic,
			Reposition,
			Roam,
			Flee,
			Wall
		}

		private struct CachedAnimatorParam
		{
			public int Hash;

			public AnimatorControllerParameterType Type;
		}

		private struct ReleasePoint : INetworkSerializable, IEquatable<ReleasePoint>
		{
			public uint Sequence;

			public Vector3 Position;

			public float Yaw;

			public unsafe void NetworkSerialize<T>(BufferSerializer<T> serializer) where T : IReaderWriter
			{
				//IL_000a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0010: Unknown result type (might be due to invalid IL or missing references)
				//IL_002d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0033: Unknown result type (might be due to invalid IL or missing references)
				((BufferSerializer<uint>*)(&serializer))->SerializeValue<uint>(ref Sequence, default(ForPrimitives));
				serializer.SerializeValue(ref Position);
				((BufferSerializer<float>*)(&serializer))->SerializeValue<float>(ref Yaw, default(ForPrimitives));
			}

			public bool Equals(ReleasePoint other)
			{
				//IL_000f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0015: Unknown result type (might be due to invalid IL or missing references)
				if (Sequence == other.Sequence && Position == other.Position)
				{
					return Yaw == other.Yaw;
				}
				return false;
			}
		}

		private enum PossessionEndReason
		{
			Expired,
			PoltergeistDamaged,
			VictimHealthFloor,
			VictimLost,
			PoltergeistDied,
			VictimLeftFacility,
			VictimInShipSafety,
			VictimTeleported,
			VictimHeldByEnemy,
			VictimInputHeldElsewhere,
			Stunned
		}

		private enum Tactic
		{
			Direct,
			Flank,
			Stalk,
			Ambush,
			Withdraw,
			SneakPossess
		}

		private struct PhasePlan
		{
			public Vector3 Destination;

			public Vector3 ResumeDestination;

			public Vector3 EntryPoint;

			public Vector3 EntryNormal;

			public Vector3 ExitPoint;

			public Vector3 ExitNormal;

			public float Duration;
		}

		[Flags]
		private enum ColliderOwner : byte
		{
			None = 0,
			Player = 1,
			Enemy = 2,
			Grabbable = 4
		}

		private struct Transit : INetworkSerializable, IEquatable<Transit>
		{
			public byte Mode;

			public uint GhostId;

			public byte Pattern;

			public byte Stage;

			public uint Sequence;

			public Vector3 From;

			public Vector3 To;

			public Vector3 WallA;

			public Vector3 NormalA;

			public Vector3 WallB;

			public Vector3 NormalB;

			public float Yaw;

			public float Duration;

			public double Started;

			public unsafe void NetworkSerialize<T>(BufferSerializer<T> serializer) where T : IReaderWriter
			{
				//IL_0017: 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_002d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0033: Unknown result type (might be due to invalid IL or missing references)
				//IL_0077: Unknown result type (might be due to invalid IL or missing references)
				//IL_007d: Unknown result type (might be due to invalid IL or missing references)
				//IL_008d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0093: 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_00a9: Unknown result type (might be due to invalid IL or missing references)
				serializer.SerializeValue(ref Mode);
				((BufferSerializer<uint>*)(&serializer))->SerializeValue<uint>(ref Sequence, default(ForPrimitives));
				((BufferSerializer<uint>*)(&serializer))->SerializeValue<uint>(ref GhostId, default(ForPrimitives));
				serializer.SerializeValue(ref Pattern);
				serializer.SerializeValue(ref Stage);
				serializer.SerializeValue(ref From);
				serializer.SerializeValue(ref To);
				((BufferSerializer<float>*)(&serializer))->SerializeValue<float>(ref Yaw, default(ForPri

Y4NGZScissorsCreature.dll

Decompiled a week ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using Dawn;
using GameNetcodeStuff;
using Microsoft.CodeAnalysis;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.Audio;
using UnityEngine.Events;
using UnityEngine.SceneManagement;
using Y4NGZMonsters.Shared;
using Y4NGZScissorsCreature.NetcodePatcher;

[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("Y4NGZScissorsCreature")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+c64a155fd64c47528940e53659e5b5ada665b9d4")]
[assembly: AssemblyProduct("Y4NGZScissorsCreature")]
[assembly: AssemblyTitle("Y4NGZScissorsCreature")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
[module: NetcodePatchedAssembly]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.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 Y4NGZScissorsCreature
{
	public sealed class ScissorsCreatureAI : EnemyAI
	{
		public const int StateIdleWalk = 0;

		public const int StateWindupWalk = 1;

		public const int StateRushSnipping = 2;

		[Header("Scissors Creature anchors")]
		public Transform attackOrigin;

		public Transform wheelBone;

		public Collider bodyBlockerCollider;

		[Header("Scissors Creature audio")]
		public AudioClip windupClip;

		public AudioClip wheelUnwindClip;

		public AudioClip attackedByPlayerClip;

		public AudioClip footstepClip;

		public AudioClip attackRunClip;

		public AudioClip tickingClip;

		public AudioClip alarmClip;

		public AudioClip idleGrowlClip;

		public AudioClip snipKillClip;

		public AudioClip[] snipClips;

		public AudioSource tickingAudioSource;

		public AudioSource alarmAudioSource;

		private const float ScissorsDamageBehindOrigin = 1.1f;

		private const float ScissorsDamageAheadOfOrigin = 2.75f;

		private const float ScissorsDamageHalfWidth = 1.35f;

		private const float ScissorsDamageBelowOrigin = 0.75f;

		private const float ScissorsDamageAboveOrigin = 1.35f;

		private const float ScissorsApproachDistance = 2.35f;

		private const float ScissorsRushStoppingDistance = 0.6f;

		private const int ScissorsHittableForce = 2;

		private const float SnipjackDoorwayAgentRadius = 0.32f;

		private const float ScissorsNavigationRadius = 0.32f;

		private const float ScissorsIdleStoppingDistance = 0f;

		private const float ScissorsProgressSpeedFraction = 0.25f;

		private const float ScissorsStuckRecoverySeconds = 1.2f;

		private const float ScissorsOffMeshRepairInterval = 0.8f;

		private const float NavigationDoorProbeRadius = 0.75f;

		private const float AttackOverlapInterval = 0.15f;

		private const int EnemiesLayerFallback = 19;

		private const int MapHazardsLayerFallback = 21;

		private const int InteractableObjectLayerFallback = 9;

		private const float AttackedByPlayerVolume = 9f;

		private const float SnipKillVolume = 2.8f;

		private const float NoiseMinLoudness = 0.5f;

		private const float NoiseHearingRange = 20f;

		private const float NoiseMemorySeconds = 3f;

		private const float NoiseReseedCooldown = 4f;

		private const int NoiseMaxRepeatsInOneSpot = 10;

		private const float WheelConnectorRadius = 0.055f;

		private const float HeadTrackYawGeometryLimit = 45f;

		private const float HeadTrackPitchGeometryLimit = 30f;

		private const float HeadTrackAbandonYawDegrees = 100f;

		private const float HeadTrackSearchInterval = 0.25f;

		private const float HeadTrackDeadZoneDegrees = 0.4f;

		private const int NoTargetSlot = -1;

		private const int DefaultAttackDamage = 35;

		private const int SnipDeathAnimation = 7;

		private const float FootstepMinSpeed = 0.1f;

		private const float MeasuredSpeedSmoothingSeconds = 1.2f;

		private static readonly string[] StunnedAnimatorBoolNames = new string[3] { "stunned", "Stunned", "stun" };

		private static readonly Vector3 WheelFallbackLocalPosition = new Vector3(0f, 1.18f, -0.55f);

		private static readonly Vector3 WheelConnectorBodyAnchorLocalPosition = new Vector3(0f, 1.18f, -0.12f);

		private readonly RaycastHit[] _lineOfSightHits = (RaycastHit[])(object)new RaycastHit[32];

		private readonly Collider[] _attackOverlapResults = (Collider[])(object)new Collider[64];

		private readonly Dictionary<ulong, float> _lastDamageTimes = new Dictionary<ulong, float>();

		private readonly Dictionary<int, float> _lastHittableDamageTimes = new Dictionary<int, float>();

		private readonly Collider[] _doorProbeResults = (Collider[])(object)new Collider[16];

		private readonly NoiseMemory _noiseMemory = new NoiseMemory();

		private float _windupTimer;

		private float _snipAudioTimer;

		private float _footstepAudioTimer;

		private float _idleGrowlTimer;

		private int _tickingRepeatCount;

		private Vector3 _lastKnownTargetPosition;

		private float _lastTargetContactTime;

		private float _currentTargetLastContactTime;

		private Transform _wheelInteractionProxy;

		private Transform _wheelConnector;

		private Quaternion _wheelBaseLocalRotation = Quaternion.identity;

		private float _wheelVisualAngle;

		private Vector3 _lastNavigationRecoveryPosition;

		private float _navigationStuckTimer;

		private float _nextAgentRepairTime;

		private bool _capturedWheelBase;

		private bool _windupTickingActive;

		private Transform _headTrackBone;

		private bool _headTrackCalibrated;

		private Quaternion _headTrackBaseLocalRotation = Quaternion.identity;

		private Vector3 _headTrackFaceLocalAxis = Vector3.forward;

		private float _headTrackYawDegrees;

		private float _headTrackPitchDegrees;

		private float _nextHeadTrackSearchTime;

		private PlayerControllerB _headTrackTarget;

		private bool _audioRouted;

		private readonly ServerOwnershipGuard _ownershipGuard = new ServerOwnershipGuard();

		private readonly NetworkVariable<int> _networkState = new NetworkVariable<int>(0, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)0);

		private readonly NetworkVariable<int> _networkTargetSlot = new NetworkVariable<int>(-1, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)0);

		private readonly NetworkVariable<int> _networkAttackDamage = new NetworkVariable<int>(35, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)0);

		private bool _wasStunned;

		private float _stunStartTime;

		private int _stunnedAnimatorHash;

		private Vector3 _lastFootstepPosition;

		private float _measuredSpeed;

		private float _attackOverlapTimer;

		private int _attackOverlapMask;

		private int _doorProbeMask;

		private int _appliedAgentState = -1;

		private bool _navigationRepathed;

		private float _nextNoiseReseedTime;

		private Material _connectorMaterial;

		public bool CanUseWindupWheel
		{
			get
			{
				if (!base.isEnemyDead)
				{
					if (base.currentBehaviourStateIndex != 1)
					{
						return base.currentBehaviourStateIndex == 2;
					}
					return true;
				}
				return false;
			}
		}

		private float WalkSpeed
		{
			get
			{
				if (Plugin.ModConfig == null)
				{
					return 0.286f;
				}
				return Plugin.ModConfig.WalkSpeed.Value;
			}
		}

		private float WindupMoveSpeed => 0.05f;

		private float WalkTurnSpeed => 11.7f;

		private float RushSpeed
		{
			get
			{
				if (Plugin.ModConfig == null)
				{
					return 6.24f;
				}
				return Plugin.ModConfig.RushSpeed.Value;
			}
		}

		private float DetectionRange
		{
			get
			{
				if (Plugin.ModConfig == null)
				{
					return 28f;
				}
				return Plugin.ModConfig.DetectionRange.Value;
			}
		}

		private float DetectionWidth => 75f;

		private float ProximityAwareness => 4f;

		private float WindupDuration
		{
			get
			{
				if (Plugin.ModConfig == null)
				{
					return 12f;
				}
				return Plugin.ModConfig.WindupDuration.Value;
			}
		}

		private float AttackDamageCooldown => 0.45f;

		private int ConfiguredAttackDamage
		{
			get
			{
				if (Plugin.ModConfig == null)
				{
					return 35;
				}
				return Plugin.ModConfig.AttackDamage.Value;
			}
		}

		private float WheelInteractDistance => 3f;

		private float DisengageDistance => 20f;

		private float LostContactGracePeriod => 7f;

		private bool HeadTrackingEnabled => true;

		private float HeadTrackingRange => 18f;

		private float HeadTrackingMaxYaw => Mathf.Clamp(22f, 0f, 45f);

		private float HeadTrackingMaxPitch => Mathf.Clamp(12f, 0f, 30f);

		private float HeadTrackingTurnSpeed => 90f;

		public override void Awake()
		{
			try
			{
				((EnemyAI)this).Awake();
				ResolveRuntimeReferences();
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"[ScissorsCreatureAI] Awake failed: {arg}");
			}
		}

		public override void Start()
		{
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_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)
			try
			{
				((EnemyAI)this).Start();
				Plugin.EnsureScanNode(((Component)this).gameObject);
				ResolveRuntimeReferences();
				DisableStaleWheelScanNode();
				_audioRouted = RouteAudioSources();
				_idleGrowlTimer = Random.Range(2f, 6f);
				_attackOverlapMask = (1 << ResolveLayer("Enemies", 19)) | (1 << ResolveLayer("MapHazards", 21));
				_doorProbeMask = 1 << ResolveLayer("InteractableObject", 9);
				ApplyFixedBodyAndAgentSettings();
				ConfigureAgentForState(base.currentBehaviourStateIndex);
				_lastNavigationRecoveryPosition = ((Component)this).transform.position;
				_lastFootstepPosition = ((Component)this).transform.position;
				if ((Object)(object)base.creatureAnimator != (Object)null)
				{
					base.creatureAnimator.applyRootMotion = false;
					((EnemyAI)this).PlayAnimationOfCurrentState();
					_stunnedAnimatorHash = FindStunnedAnimatorBool(base.creatureAnimator);
				}
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"[ScissorsCreatureAI] Start failed: {arg}");
			}
		}

		public override void OnNetworkSpawn()
		{
			((NetworkBehaviour)this).OnNetworkSpawn();
			if (((NetworkBehaviour)this).IsServer)
			{
				_networkAttackDamage.Value = Mathf.Max(0, ConfiguredAttackDamage);
				_networkState.Value = base.currentBehaviourStateIndex;
				return;
			}
			NetworkVariable<int> networkState = _networkState;
			networkState.OnValueChanged = (OnValueChangedDelegate<int>)(object)Delegate.Combine((Delegate?)(object)networkState.OnValueChanged, (Delegate?)(object)new OnValueChangedDelegate<int>(OnNetworkStateChanged));
			NetworkVariable<int> networkTargetSlot = _networkTargetSlot;
			networkTargetSlot.OnValueChanged = (OnValueChangedDelegate<int>)(object)Delegate.Combine((Delegate?)(object)networkTargetSlot.OnValueChanged, (Delegate?)(object)new OnValueChangedDelegate<int>(OnNetworkTargetSlotChanged));
			ApplyNetworkState(_networkState.Value);
			base.targetPlayer = VictimRpc.FromSlot(_networkTargetSlot.Value);
		}

		public override void OnNetworkDespawn()
		{
			NetworkVariable<int> networkState = _networkState;
			networkState.OnValueChanged = (OnValueChangedDelegate<int>)(object)Delegate.Remove((Delegate?)(object)networkState.OnValueChanged, (Delegate?)(object)new OnValueChangedDelegate<int>(OnNetworkStateChanged));
			NetworkVariable<int> networkTargetSlot = _networkTargetSlot;
			networkTargetSlot.OnValueChanged = (OnValueChangedDelegate<int>)(object)Delegate.Remove((Delegate?)(object)networkTargetSlot.OnValueChanged, (Delegate?)(object)new OnValueChangedDelegate<int>(OnNetworkTargetSlotChanged));
			((NetworkBehaviour)this).OnNetworkDespawn();
		}

		private void OnNetworkStateChanged(int previous, int next)
		{
			ApplyNetworkState(next);
		}

		private void ApplyNetworkState(int state)
		{
			if (base.enemyBehaviourStates != null && state >= 0 && state < base.enemyBehaviourStates.Length && state != base.currentBehaviourStateIndex)
			{
				((EnemyAI)this).SwitchToBehaviourStateOnLocalClient(state);
			}
		}

		private void OnNetworkTargetSlotChanged(int previous, int next)
		{
			base.targetPlayer = VictimRpc.FromSlot(next);
		}

		public override void Update()
		{
			try
			{
				_ownershipGuard.Ensure((EnemyAI)(object)this, Plugin.Log);
				((EnemyAI)this).Update();
				if (!_audioRouted)
				{
					_audioRouted = RouteAudioSources();
				}
				if (base.isEnemyDead || (Object)(object)StartOfRound.Instance == (Object)null)
				{
					return;
				}
				if (StartOfRound.Instance.allPlayersDead)
				{
					StopAllLoops();
					return;
				}
				if ((Object)(object)base.creatureAnimator != (Object)null)
				{
					base.creatureAnimator.applyRootMotion = false;
				}
				StunEdge stunEdge = ((EnemyAI)(object)this).TrackStun(ref _wasStunned);
				if (stunEdge != StunEdge.None)
				{
					OnStunEdge(stunEdge);
				}
				if (((NetworkBehaviour)this).IsServer)
				{
					if (_wasStunned)
					{
						((EnemyAI)(object)this).HoldAgent();
					}
					else
					{
						TickServerState(Time.deltaTime);
						RepairAgentIfNeeded();
						TickNavigationRecovery(Time.deltaTime);
					}
				}
				TickMeasuredSpeed(Time.deltaTime);
				TickAttackAlarmAudio();
				TickIdleGrowlAudio(Time.deltaTime);
				if (!_wasStunned)
				{
					TickFootstepAudio(Time.deltaTime);
					TickWindupTickingAudio();
					TickSnipAudio(Time.deltaTime);
					DamageObjectsInAttackVolume(Time.deltaTime);
				}
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"[ScissorsCreatureAI] Update failed: {arg}");
			}
		}

		private void OnStunEdge(StunEdge edge)
		{
			bool flag = edge == StunEdge.Started;
			if (_stunnedAnimatorHash != 0 && (Object)(object)base.creatureAnimator != (Object)null)
			{
				base.creatureAnimator.SetBool(_stunnedAnimatorHash, flag);
			}
			if (flag)
			{
				PlayAttackedByPlayerAudio();
			}
			if (!((NetworkBehaviour)this).IsServer)
			{
				return;
			}
			if (flag)
			{
				_stunStartTime = Time.time;
				((EnemyAI)(object)this).HoldAgent();
				return;
			}
			if (base.currentBehaviourStateIndex != 0)
			{
				float num = Time.time - _stunStartTime;
				_currentTargetLastContactTime = Mathf.Min(_currentTargetLastContactTime + num, Time.time);
				_lastTargetContactTime = Mathf.Min(_lastTargetContactTime + num, Time.time);
			}
			((EnemyAI)(object)this).ReleaseAgent();
			ResetNavigationRecovery();
		}

		private static int FindStunnedAnimatorBool(Animator animator)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Invalid comparison between Unknown and I4
			if ((Object)(object)animator.runtimeAnimatorController == (Object)null)
			{
				return 0;
			}
			AnimatorControllerParameter[] parameters = animator.parameters;
			foreach (AnimatorControllerParameter val in parameters)
			{
				if ((int)val.type == 4 && Array.IndexOf(StunnedAnimatorBoolNames, val.name) >= 0)
				{
					return val.nameHash;
				}
			}
			return 0;
		}

		private void TickMeasuredSpeed(float deltaTime)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: 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_000e: 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_0018: 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)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			Vector3 position = ((Component)this).transform.position;
			Vector3 val = position - _lastFootstepPosition;
			_lastFootstepPosition = position;
			if (!(deltaTime <= 0f))
			{
				val.y = 0f;
				float num = ((Vector3)(ref val)).magnitude / deltaTime;
				_measuredSpeed = Mathf.Lerp(_measuredSpeed, num, 1f - Mathf.Exp((0f - deltaTime) / 1.2f));
			}
		}

		private void LateUpdate()
		{
			try
			{
				if (!base.isEnemyDead)
				{
					TickWheelVisual(Time.deltaTime);
				}
				AlignWheelTargetsAndConnector();
				TickHeadTracking(Time.deltaTime);
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"[ScissorsCreatureAI] LateUpdate failed: {arg}");
			}
		}

		private void TickHeadTracking(float deltaTime)
		{
			//IL_0139: 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_017e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0186: Unknown result type (might be due to invalid IL or missing references)
			//IL_0188: Unknown result type (might be due to invalid IL or missing references)
			//IL_018d: 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_0197: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01aa: 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)
			//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)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: 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)
			//IL_0096: 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_01d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dd: 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)
			if ((Object)(object)_headTrackBone == (Object)null || !HeadTrackingEnabled || !CalibrateHeadTracking())
			{
				return;
			}
			float num = 0f;
			float num2 = 0f;
			if (!base.isEnemyDead && TryGetHeadTrackFocusPoint(out var focusPoint))
			{
				Vector3 val = focusPoint - _headTrackBone.position;
				Vector3 val2 = ((Component)this).transform.InverseTransformDirection(val);
				if (((Vector3)(ref val2)).sqrMagnitude > 0.0001f)
				{
					((Vector3)(ref val2)).Normalize();
					float num3 = Mathf.Atan2(val2.x, val2.z) * 57.29578f;
					float num4 = (0f - Mathf.Asin(Mathf.Clamp(val2.y, -1f, 1f))) * 57.29578f;
					if (Mathf.Abs(num3) <= 100f)
					{
						num = Mathf.Clamp(num3, 0f - HeadTrackingMaxYaw, HeadTrackingMaxYaw);
						num2 = Mathf.Clamp(num4, 0f - HeadTrackingMaxPitch, HeadTrackingMaxPitch);
					}
				}
			}
			float num5 = HeadTrackingTurnSpeed * deltaTime;
			float num6 = HeadTrackingTurnSpeed * 0.6f * deltaTime;
			_headTrackYawDegrees = Mathf.MoveTowards(_headTrackYawDegrees, num, num5);
			_headTrackPitchDegrees = Mathf.MoveTowards(_headTrackPitchDegrees, num2, num6);
			_headTrackBone.localRotation = _headTrackBaseLocalRotation;
			if (!(Mathf.Abs(_headTrackYawDegrees) < 0.4f) || !(Mathf.Abs(_headTrackPitchDegrees) < 0.4f))
			{
				Quaternion val3 = Quaternion.Euler(_headTrackPitchDegrees, _headTrackYawDegrees, 0f);
				Vector3 val4 = ((Component)this).transform.TransformDirection(val3 * Vector3.forward);
				Vector3 val5 = _headTrackBone.TransformDirection(_headTrackFaceLocalAxis);
				if (!(((Vector3)(ref val4)).sqrMagnitude < 0.0001f) && !(((Vector3)(ref val5)).sqrMagnitude < 0.0001f))
				{
					_headTrackBone.rotation = Quaternion.FromToRotation(((Vector3)(ref val5)).normalized, ((Vector3)(ref val4)).normalized) * _headTrackBone.rotation;
				}
			}
		}

		private bool CalibrateHeadTracking()
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			if (_headTrackCalibrated)
			{
				return true;
			}
			if ((Object)(object)_headTrackBone == (Object)null)
			{
				return false;
			}
			_headTrackBaseLocalRotation = _headTrackBone.localRotation;
			Vector3 val = _headTrackBone.InverseTransformDirection(((Component)this).transform.forward);
			_headTrackFaceLocalAxis = ((((Vector3)(ref val)).sqrMagnitude > 0.0001f) ? ((Vector3)(ref val)).normalized : Vector3.forward);
			_headTrackCalibrated = true;
			return true;
		}

		private bool TryGetHeadTrackFocusPoint(out Vector3 focusPoint)
		{
			//IL_0001: 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_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			focusPoint = Vector3.zero;
			PlayerControllerB val = base.targetPlayer;
			if ((Object)(object)val == (Object)null || val.isPlayerDead || !((EnemyAI)this).PlayerIsTargetable(val, false, false, true))
			{
				if (Time.time >= _nextHeadTrackSearchTime)
				{
					_nextHeadTrackSearchTime = Time.time + 0.25f;
					_headTrackTarget = FindClosestVisibleTargetablePlayer(HeadTrackingRange);
				}
				val = _headTrackTarget;
			}
			if ((Object)(object)val == (Object)null || val.isPlayerDead || !((EnemyAI)this).PlayerIsTargetable(val, false, false, true))
			{
				_headTrackTarget = null;
				return false;
			}
			Transform val2 = (((Object)(object)val.gameplayCamera != (Object)null) ? ((Component)val.gameplayCamera).transform : ((Component)val).transform);
			if (Vector3.Distance(_headTrackBone.position, val2.position) > HeadTrackingRange)
			{
				return false;
			}
			focusPoint = val2.position;
			return true;
		}

		public override void DoAIInterval()
		{
			try
			{
				((EnemyAI)this).DoAIInterval();
				if (!((NetworkBehaviour)this).IsServer || base.isEnemyDead || (Object)(object)StartOfRound.Instance == (Object)null || StartOfRound.Instance.allPlayersDead)
				{
					return;
				}
				if (_wasStunned || ((EnemyAI)(object)this).IsStunned())
				{
					((EnemyAI)(object)this).HoldAgent();
					return;
				}
				switch (base.currentBehaviourStateIndex)
				{
				case 0:
					DoIdleWalk();
					break;
				case 1:
					DoWindupWalk();
					break;
				case 2:
					DoRushSnipping();
					break;
				}
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"[ScissorsCreatureAI] DoAIInterval failed: {arg}");
			}
		}

		private void TickServerState(float deltaTime)
		{
			if (base.currentBehaviourStateIndex != 1)
			{
				return;
			}
			_windupTimer += deltaTime;
			if (_windupTimer >= WindupDuration)
			{
				if (CanBeginRushSnipping())
				{
					BeginRushSnipping();
				}
				else
				{
					WindDownToIdle();
				}
			}
		}

		private void DoIdleWalk()
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			PlayerControllerB val = FindClosestVisibleTargetablePlayer(DetectionRange);
			if ((Object)(object)val != (Object)null)
			{
				BeginWindup(val);
			}
			else if (!TryReseedSearchAtNoise() && !base.currentSearch.inProgress)
			{
				((EnemyAI)this).StartSearch(((Component)this).transform.position, (AISearchRoutine)null);
			}
		}

		private bool TryReseedSearchAtNoise()
		{
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			if (Time.time < _nextNoiseReseedTime)
			{
				return false;
			}
			if (!_noiseMemory.TryTake(3f, out var position))
			{
				return false;
			}
			_nextNoiseReseedTime = Time.time + 4f;
			((EnemyAI)this).StopSearch(base.currentSearch, true);
			((EnemyAI)this).StartSearch(position, base.currentSearch);
			ResetNavigationRecovery();
			return true;
		}

		private void DoWindupWalk()
		{
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			bool hasMeaningfulContact;
			bool flag = TryKeepCurrentTarget(out hasMeaningfulContact);
			if (!flag)
			{
				flag = TryAcquireMeaningfulTarget();
				hasMeaningfulContact = flag;
			}
			if (!flag)
			{
				if (HasLostEveryTargetLongEnough())
				{
					WindDownToIdle();
				}
				else
				{
					MoveTowardLastKnownTarget();
				}
			}
			else if (hasMeaningfulContact)
			{
				MoveTowardCurrentOrLastTarget();
			}
			else
			{
				((EnemyAI)this).SetDestinationToPosition(_lastKnownTargetPosition, false);
			}
		}

		private void DoRushSnipping()
		{
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			bool hasMeaningfulContact;
			bool flag = TryKeepCurrentTarget(out hasMeaningfulContact);
			if (!flag)
			{
				flag = TryAcquireMeaningfulTarget();
				hasMeaningfulContact = flag;
			}
			if (!flag)
			{
				WindDownToIdle();
				return;
			}
			if (base.currentSearch != null && base.currentSearch.inProgress)
			{
				((EnemyAI)this).StopSearch(base.currentSearch, true);
			}
			if (hasMeaningfulContact)
			{
				MoveTowardCurrentOrLastTarget();
				return;
			}
			base.movingTowardsTargetPlayer = false;
			((EnemyAI)this).SetDestinationToPosition(_lastKnownTargetPosition, false);
		}

		private bool CanBeginRushSnipping()
		{
			if (!TryKeepCurrentTarget(out var _))
			{
				return TryAcquireMeaningfulTarget();
			}
			return true;
		}

		private bool TryKeepCurrentTarget(out bool hasMeaningfulContact)
		{
			hasMeaningfulContact = false;
			PlayerControllerB targetPlayer = base.targetPlayer;
			if (!TargetIsWithinDisengageDistance(targetPlayer))
			{
				DropCurrentTarget();
				return false;
			}
			if (PlayerHasMeaningfulContact(targetPlayer, DisengageDistance))
			{
				SetTargetWithContact(targetPlayer);
				hasMeaningfulContact = true;
				return true;
			}
			if (Time.time - _currentTargetLastContactTime >= LostContactGracePeriod)
			{
				DropCurrentTarget();
				return false;
			}
			return true;
		}

		private bool TryAcquireMeaningfulTarget()
		{
			PlayerControllerB val = FindClosestMeaningfulContactTargetablePlayer(DisengageDistance);
			if ((Object)(object)val == (Object)null)
			{
				return false;
			}
			SetTargetWithContact(val);
			return true;
		}

		private void SetTargetWithContact(PlayerControllerB player)
		{
			//IL_000e: 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)
			base.targetPlayer = player;
			_lastKnownTargetPosition = ((Component)player).transform.position;
			_currentTargetLastContactTime = Time.time;
			_lastTargetContactTime = Time.time;
			_networkTargetSlot.Value = (int)player.playerClientId;
		}

		private void DropCurrentTarget()
		{
			base.targetPlayer = null;
			base.movingTowardsTargetPlayer = false;
			_networkTargetSlot.Value = -1;
		}

		private bool TargetIsWithinDisengageDistance(PlayerControllerB player)
		{
			//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)
			if ((Object)(object)player != (Object)null && !player.isPlayerDead && ((EnemyAI)this).PlayerIsTargetable(player, false, false, true))
			{
				return Vector3.Distance(((Component)this).transform.position, ((Component)player).transform.position) <= DisengageDistance;
			}
			return false;
		}

		private bool HasLostEveryTargetLongEnough()
		{
			if ((Object)(object)FindClosestMeaningfulContactTargetablePlayer(DisengageDistance) != (Object)null)
			{
				_lastTargetContactTime = Time.time;
				return false;
			}
			return Time.time - _lastTargetContactTime >= LostContactGracePeriod;
		}

		private void WindDownToIdle()
		{
			_wheelVisualAngle += 180f;
			ReturnToIdleWalk();
			PlayWheelUnwindClientRpc(_wheelVisualAngle);
		}

		private void BeginWindup(PlayerControllerB player)
		{
			((EnemyAI)this).StopSearch(base.currentSearch, true);
			SetTargetWithContact(player);
			_windupTimer = 0f;
			_tickingRepeatCount = 0;
			ConfigureAgentForState(1);
			SwitchState(1);
			PlayWindupClientRpc();
		}

		private void BeginRushSnipping()
		{
			((EnemyAI)this).StopSearch(base.currentSearch, true);
			_attackOverlapTimer = 0f;
			ConfigureAgentForState(2);
			SwitchState(2);
			PlaySnipClientRpc();
		}

		private void ReturnToIdleWalk()
		{
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			_windupTimer = 0f;
			DropCurrentTarget();
			_currentTargetLastContactTime = 0f;
			ConfigureAgentForState(0);
			SwitchState(0);
			if (!base.currentSearch.inProgress)
			{
				((EnemyAI)this).StartSearch(((Component)this).transform.position, (AISearchRoutine)null);
			}
		}

		private void SwitchState(int state)
		{
			if (base.currentBehaviourStateIndex != state)
			{
				((EnemyAI)this).SwitchToBehaviourState(state);
				_networkState.Value = state;
			}
		}

		private void ConfigureAgentForState(int state)
		{
			if (!((Object)(object)base.agent == (Object)null) && state != _appliedAgentState)
			{
				_appliedAgentState = state;
				base.agent.speed = state switch
				{
					1 => WindupMoveSpeed, 
					2 => RushSpeed, 
					_ => WalkSpeed, 
				};
				base.agent.angularSpeed = ((state == 2) ? 324f : WalkTurnSpeed);
				base.agent.acceleration = state switch
				{
					1 => 0.6f, 
					2 => 36f, 
					_ => 2.6f, 
				};
				base.agent.stoppingDistance = state switch
				{
					1 => 2.35f, 
					2 => 0.6f, 
					_ => 0f, 
				};
				base.agent.autoBraking = state != 2;
			}
		}

		private void ApplyFixedBodyAndAgentSettings()
		{
			if ((Object)(object)bodyBlockerCollider != (Object)null)
			{
				bodyBlockerCollider.isTrigger = false;
				bodyBlockerCollider.enabled = true;
			}
			if (!((Object)(object)base.agent == (Object)null))
			{
				base.agent.radius = 0.32f;
				base.agent.obstacleAvoidanceType = (ObstacleAvoidanceType)4;
				base.agent.avoidancePriority = 35;
			}
		}

		private static int ResolveLayer(string layerName, int fallback)
		{
			int num = LayerMask.NameToLayer(layerName);
			if (num < 0)
			{
				return fallback;
			}
			return num;
		}

		private void MoveTowardLastKnownTarget()
		{
			//IL_0044: 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)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)base.targetPlayer != (Object)null && !base.targetPlayer.isPlayerDead && ((EnemyAI)this).PlayerIsTargetable(base.targetPlayer, false, false, true))
			{
				_lastKnownTargetPosition = ((Component)base.targetPlayer).transform.position;
			}
			((EnemyAI)this).SetDestinationToPosition(_lastKnownTargetPosition, false);
		}

		private void MoveTowardCurrentOrLastTarget()
		{
			//IL_0051: 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)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)base.targetPlayer != (Object)null && !base.targetPlayer.isPlayerDead && ((EnemyAI)this).PlayerIsTargetable(base.targetPlayer, false, false, true))
			{
				_lastKnownTargetPosition = ((Component)base.targetPlayer).transform.position;
				((EnemyAI)this).SetMovingTowardsTargetPlayer(base.targetPlayer);
			}
			else
			{
				((EnemyAI)this).SetDestinationToPosition(_lastKnownTargetPosition, false);
			}
		}

		private void RepairAgentIfNeeded()
		{
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)base.agent == (Object)null) && ((Behaviour)base.agent).enabled && !base.agent.isOnNavMesh && !(Time.time < _nextAgentRepairTime))
			{
				_nextAgentRepairTime = Time.time + 0.8f;
				int num = ((base.agent.areaMask != 0) ? base.agent.areaMask : (-1));
				NavMeshHit val = default(NavMeshHit);
				if (NavMesh.SamplePosition(((Component)this).transform.position, ref val, 4f, num) && base.agent.Warp(((NavMeshHit)(ref val)).position))
				{
					ResetNavigationRecovery();
				}
			}
		}

		private void TickNavigationRecovery(float deltaTime)
		{
			//IL_0117: 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_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_0169: Unknown result type (might be due to invalid IL or missing references)
			//IL_016e: 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_01ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_020a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0279: Unknown result type (might be due to invalid IL or missing references)
			//IL_0267: Unknown result type (might be due to invalid IL or missing references)
			//IL_0246: Unknown result type (might be due to invalid IL or missing references)
			//IL_027e: 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)
			if ((Object)(object)base.agent == (Object)null || !((Behaviour)base.agent).enabled || !base.agent.isOnNavMesh)
			{
				ResetNavigationRecovery();
				return;
			}
			bool flag = base.currentSearch != null && base.currentSearch.inProgress;
			bool num = base.currentBehaviourStateIndex == 1 || base.currentBehaviourStateIndex == 2 || flag;
			bool flag2 = base.agent.hasPath && !base.agent.pathPending && base.agent.remainingDistance <= Mathf.Max(base.agent.stoppingDistance + 0.45f, 0.9f);
			if (!num || flag2)
			{
				ResetNavigationRecovery();
				return;
			}
			if (base.agent.pathPending || (flag && (base.currentSearch.waitingForTargetNode || (Object)(object)base.currentSearch.currentTargetNode == (Object)null)))
			{
				ResetNavigationWindow();
				return;
			}
			_navigationStuckTimer += Mathf.Max(0f, deltaTime);
			if (_navigationStuckTimer < 1.2f)
			{
				return;
			}
			Vector3 val = ((Component)this).transform.position - _lastNavigationRecoveryPosition;
			val.y = 0f;
			float num2 = Mathf.Max(0.01f, base.agent.speed) * 0.25f * _navigationStuckTimer;
			_navigationStuckTimer = 0f;
			_lastNavigationRecoveryPosition = ((Component)this).transform.position;
			if (((Vector3)(ref val)).sqrMagnitude >= num2 * num2)
			{
				_navigationRepathed = false;
			}
			else
			{
				if (IsTouchingClosedDoor())
				{
					return;
				}
				if (!_navigationRepathed)
				{
					_navigationRepathed = true;
					base.agent.SetDestination(base.destination);
					return;
				}
				_navigationRepathed = false;
				_nextAgentRepairTime = Time.time + 0.8f;
				int num3 = ((base.agent.areaMask != 0) ? base.agent.areaMask : (-1));
				NavMeshHit val2 = default(NavMeshHit);
				if (NavMesh.SamplePosition(((Component)this).transform.position, ref val2, 1.5f, num3))
				{
					base.agent.Warp(((NavMeshHit)(ref val2)).position);
				}
				if (base.currentBehaviourStateIndex == 0)
				{
					if (base.currentSearch != null && base.currentSearch.inProgress)
					{
						((EnemyAI)this).StopSearch(base.currentSearch, false);
					}
					((EnemyAI)this).StartSearch(((Component)this).transform.position, (AISearchRoutine)null);
				}
				else
				{
					Vector3 val3 = (PlayerHasMeaningfulContact(base.targetPlayer, DisengageDistance) ? ((Component)base.targetPlayer).transform.position : _lastKnownTargetPosition);
					((EnemyAI)this).SetDestinationToPosition(val3, false);
				}
			}
		}

		private bool IsTouchingClosedDoor()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: 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)
			int num = Physics.OverlapSphereNonAlloc(((Component)this).transform.position + Vector3.up * 0.7f, 0.75f, _doorProbeResults, _doorProbeMask, (QueryTriggerInteraction)2);
			bool flag = false;
			DoorLock val2 = default(DoorLock);
			AnimatedObjectTrigger val3 = default(AnimatedObjectTrigger);
			for (int i = 0; i < num; i++)
			{
				Collider val = _doorProbeResults[i];
				_doorProbeResults[i] = null;
				if (!flag && !((Object)(object)val == (Object)null) && ((Component)val).TryGetComponent<DoorLock>(ref val2) && !val2.isLocked)
				{
					flag = !((Component)val).TryGetComponent<AnimatedObjectTrigger>(ref val3) || !val3.boolValue;
				}
			}
			return flag;
		}

		private void ResetNavigationRecovery()
		{
			_navigationRepathed = false;
			ResetNavigationWindow();
		}

		private void ResetNavigationWindow()
		{
			//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)
			_navigationStuckTimer = 0f;
			_lastNavigationRecoveryPosition = ((Component)this).transform.position;
		}

		private PlayerControllerB FindClosestMeaningfulContactTargetablePlayer(float range)
		{
			//IL_004d: 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)
			if ((Object)(object)StartOfRound.Instance == (Object)null)
			{
				return null;
			}
			PlayerControllerB result = null;
			float num = range;
			PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts;
			foreach (PlayerControllerB val in allPlayerScripts)
			{
				if (!((Object)(object)val == (Object)null) && !val.isPlayerDead && ((EnemyAI)this).PlayerIsTargetable(val, false, false, true))
				{
					float num2 = Vector3.Distance(((Component)this).transform.position, ((Component)val).transform.position);
					if (!(num2 > num) && PlayerHasMeaningfulContact(val, range))
					{
						num = num2;
						result = val;
					}
				}
			}
			return result;
		}

		private bool PlayerHasMeaningfulContact(PlayerControllerB player, float range)
		{
			//IL_0025: 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_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)player == (Object)null || player.isPlayerDead || !((EnemyAI)this).PlayerIsTargetable(player, false, false, true))
			{
				return false;
			}
			float num = Vector3.Distance(((Component)this).transform.position, ((Component)player).transform.position);
			if (num > range)
			{
				return false;
			}
			if (num <= ProximityAwareness)
			{
				return true;
			}
			Transform val = (((Object)(object)base.eye != (Object)null) ? base.eye : ((Component)this).transform);
			Transform val2 = (((Object)(object)player.gameplayCamera != (Object)null) ? ((Component)player.gameplayCamera).transform : ((Component)player).transform);
			return !IsLineOfSightBlocked(val.position, val2.position);
		}

		private PlayerControllerB FindClosestVisibleTargetablePlayer(float range)
		{
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: 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_00c9: 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_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)StartOfRound.Instance == (Object)null)
			{
				return null;
			}
			Transform val = (((Object)(object)base.eye != (Object)null) ? base.eye : ((Component)this).transform);
			PlayerControllerB result = null;
			float num = range;
			PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts;
			foreach (PlayerControllerB val2 in allPlayerScripts)
			{
				if (!((Object)(object)val2 == (Object)null) && !val2.isPlayerDead && ((EnemyAI)this).PlayerIsTargetable(val2, false, false, true))
				{
					Transform val3 = (((Object)(object)val2.gameplayCamera != (Object)null) ? ((Component)val2.gameplayCamera).transform : ((Component)val2).transform);
					float num2 = Vector3.Distance(val.position, val3.position);
					if (!(num2 > num) && (!(num2 > ProximityAwareness) || (!(Vector3.Angle(val.forward, val3.position - val.position) > DetectionWidth) && !IsLineOfSightBlocked(val.position, val3.position))))
					{
						num = num2;
						result = val2;
					}
				}
			}
			return result;
		}

		private bool IsLineOfSightBlocked(Vector3 from, Vector3 to)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: 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)
			if (!RaycastHasNonSelfBlocker(from, to))
			{
				return RaycastHasNonSelfBlocker(to, from);
			}
			return true;
		}

		private bool RaycastHasNonSelfBlocker(Vector3 from, Vector3 to)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = to - from;
			float magnitude = ((Vector3)(ref val)).magnitude;
			if (magnitude <= 0.05f)
			{
				return false;
			}
			int collidersAndRoomMaskAndDefault = StartOfRound.Instance.collidersAndRoomMaskAndDefault;
			int num = Physics.RaycastNonAlloc(new Ray(from, val / magnitude), _lineOfSightHits, magnitude, collidersAndRoomMaskAndDefault, (QueryTriggerInteraction)1);
			for (int i = 0; i < num; i++)
			{
				Collider collider = ((RaycastHit)(ref _lineOfSightHits[i])).collider;
				if (!((Object)(object)collider == (Object)null) && !((Component)collider).transform.IsChildOf(((Component)this).transform))
				{
					return true;
				}
			}
			return false;
		}

		private void DamageObjectsInAttackVolume(float deltaTime)
		{
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: 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_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: 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_00c7: 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_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_013e: 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)
			if (base.currentBehaviourStateIndex != 2 || (Object)(object)attackOrigin == (Object)null || (Object)(object)StartOfRound.Instance == (Object)null)
			{
				return;
			}
			PlayerControllerB val = (((Object)(object)GameNetworkManager.Instance != (Object)null) ? GameNetworkManager.Instance.localPlayerController : null);
			if ((Object)(object)val != (Object)null && PlayerIsInsideScissorsDamageVolume(val))
			{
				TryDamagePlayer(val, requireScissorsVolume: false);
			}
			if (!((NetworkBehaviour)this).IsServer)
			{
				return;
			}
			_attackOverlapTimer -= deltaTime;
			if (_attackOverlapTimer > 0f)
			{
				return;
			}
			_attackOverlapTimer = 0.15f;
			Vector3 scissorsForward = GetScissorsForward();
			Quaternion val2 = Quaternion.LookRotation(scissorsForward, Vector3.up);
			Vector3 val3 = attackOrigin.position + scissorsForward * 0.825f + Vector3.up * 0.3f;
			Vector3 val4 = default(Vector3);
			((Vector3)(ref val4))..ctor(1.35f, 1.05f, 1.925f);
			int num = Physics.OverlapBoxNonAlloc(val3, val4, _attackOverlapResults, val2, _attackOverlapMask, (QueryTriggerInteraction)2);
			EnemyAICollisionDetect enemyCollision = default(EnemyAICollisionDetect);
			IHittable hittable = default(IHittable);
			for (int i = 0; i < num; i++)
			{
				Collider val5 = _attackOverlapResults[i];
				_attackOverlapResults[i] = null;
				if (!((Object)(object)val5 == (Object)null) && !((Component)val5).transform.IsChildOf(((Component)this).transform))
				{
					if (((Component)val5).TryGetComponent<EnemyAICollisionDetect>(ref enemyCollision))
					{
						TryDamageEnemy(enemyCollision, scissorsForward);
					}
					else if (((Component)val5).TryGetComponent<IHittable>(ref hittable))
					{
						TryHitGenericHittable(hittable, scissorsForward);
					}
				}
			}
		}

		public override void OnCollideWithPlayer(Collider other)
		{
			((EnemyAI)this).OnCollideWithPlayer(other);
			if (base.currentBehaviourStateIndex == 2)
			{
				PlayerControllerB val = ((EnemyAI)this).MeetsStandardPlayerCollisionConditions(other, false, false);
				if ((Object)(object)val != (Object)null)
				{
					TryDamagePlayer(val);
				}
			}
		}

		public override void OnCollideWithEnemy(Collider other, EnemyAI collidedEnemy = null)
		{
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			((EnemyAI)this).OnCollideWithEnemy(other, collidedEnemy);
			if (((NetworkBehaviour)this).IsServer && !base.isEnemyDead && !((EnemyAI)(object)this).IsStunned() && base.currentBehaviourStateIndex == 2 && !((Object)(object)collidedEnemy == (Object)null) && !collidedEnemy.isEnemyDead && ColliderIsInsideScissorsDamageVolume(other))
			{
				EnemyAICollisionDetect val = ((Component)other).GetComponent<EnemyAICollisionDetect>() ?? ((Component)other).GetComponentInParent<EnemyAICollisionDetect>();
				if ((Object)(object)val != (Object)null)
				{
					TryDamageEnemy(val, GetScissorsForward());
				}
			}
		}

		private void TryDamageEnemy(EnemyAICollisionDetect enemyCollision, Vector3 hitDirection)
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)enemyCollision == (Object)null) && !((Object)(object)enemyCollision.mainScript == (Object)null) && !((Object)(object)enemyCollision.mainScript == (Object)(object)this) && !enemyCollision.mainScript.isEnemyDead)
			{
				int instanceID = ((Object)enemyCollision.mainScript).GetInstanceID();
				if (CanDamageHittable(instanceID) && ((IHittable)enemyCollision).Hit(2, hitDirection, (PlayerControllerB)null, true, 7))
				{
					_lastHittableDamageTimes[instanceID] = Time.realtimeSinceStartup;
				}
			}
		}

		private void TryHitGenericHittable(IHittable hittable, Vector3 hitDirection)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			Object val = (Object)(object)((hittable is Object) ? hittable : null);
			if (val == (Object)null)
			{
				return;
			}
			int instanceID = val.GetInstanceID();
			if (!CanDamageHittable(instanceID))
			{
				return;
			}
			try
			{
				if (hittable.Hit(2, hitDirection, (PlayerControllerB)null, true, 7))
				{
					_lastHittableDamageTimes[instanceID] = Time.realtimeSinceStartup;
				}
			}
			catch (Exception ex)
			{
				_lastHittableDamageTimes[instanceID] = Time.realtimeSinceStartup;
				Plugin.Log.LogWarning((object)("[ScissorsCreatureAI] Failed to hit " + val.name + " with scissors: " + ex.Message));
			}
		}

		private bool CanDamageHittable(int key)
		{
			float realtimeSinceStartup = Time.realtimeSinceStartup;
			if (_lastHittableDamageTimes.TryGetValue(key, out var value))
			{
				return realtimeSinceStartup - value >= AttackDamageCooldown;
			}
			return true;
		}

		private void TryDamagePlayer(PlayerControllerB player, bool requireScissorsVolume = true)
		{
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: 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_00c9: 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_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: 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_00fb: 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_011a: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)player == (Object)null || player.isPlayerDead || !((EnemyAI)this).PlayerIsTargetable(player, false, false, true))
			{
				return;
			}
			PlayerControllerB val = (((Object)(object)GameNetworkManager.Instance != (Object)null) ? GameNetworkManager.Instance.localPlayerController : null);
			if (((Object)(object)val != (Object)null && (Object)(object)player != (Object)(object)val) || !MeetsSnipCollisionConditions(player) || (requireScissorsVolume && !PlayerIsInsideScissorsDamageVolume(player)))
			{
				return;
			}
			float realtimeSinceStartup = Time.realtimeSinceStartup;
			if (!_lastDamageTimes.TryGetValue(player.playerClientId, out var value) || !(realtimeSinceStartup - value < AttackDamageCooldown))
			{
				_lastDamageTimes[player.playerClientId] = realtimeSinceStartup;
				Vector3 val2 = (((Object)(object)attackOrigin != (Object)null) ? attackOrigin.position : ((Component)this).transform.position);
				Vector3 val3 = ((Component)player).transform.position - val2;
				Vector3 val4 = ((Vector3)(ref val3)).normalized * 8f;
				player.DamagePlayer(_networkAttackDamage.Value, true, true, (CauseOfDeath)17, 7, false, val4);
				if (player.isPlayerDead)
				{
					ReportSnipKillServerRpc((int)player.playerClientId);
				}
			}
		}

		private bool MeetsSnipCollisionConditions(PlayerControllerB player)
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			if (!base.isEnemyDead && !((EnemyAI)(object)this).IsStunned() && base.ventAnimationFinished && (Object)(object)player.inAnimationWithEnemy == (Object)null)
			{
				return !IsSeparatedByClosedElevator(((Component)player).transform.position);
			}
			return false;
		}

		private bool IsSeparatedByClosedElevator(Vector3 target)
		{
			//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)
			//IL_0058: 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)
			RoundManager instance = RoundManager.Instance;
			if ((Object)(object)instance == (Object)null || instance.currentDungeonType != 4 || base.isOutside)
			{
				return false;
			}
			MineshaftElevatorController currentMineshaftElevator = instance.currentMineshaftElevator;
			if ((Object)(object)currentMineshaftElevator == (Object)null || currentMineshaftElevator.elevatorDoorOpen || (Object)(object)currentMineshaftElevator.elevatorBounds == (Object)null)
			{
				return false;
			}
			Bounds bounds = currentMineshaftElevator.elevatorBounds.bounds;
			return ((Bounds)(ref bounds)).Contains(target) != ((Bounds)(ref bounds)).Contains(((Component)this).transform.position);
		}

		private bool PlayerIsInsideScissorsDamageVolume(PlayerControllerB player)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: 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)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: 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_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)player == (Object)null || (Object)(object)attackOrigin == (Object)null)
			{
				return false;
			}
			Vector3 val = ((Component)player).transform.position + Vector3.up * 0.9f - attackOrigin.position;
			Vector3 scissorsForward = GetScissorsForward();
			Vector3 val2 = Vector3.Cross(Vector3.up, scissorsForward);
			if (((Vector3)(ref val2)).sqrMagnitude <= 0.001f)
			{
				val2 = ((Component)this).transform.right;
			}
			((Vector3)(ref val2)).Normalize();
			float num = Vector3.Dot(val, scissorsForward);
			float num2 = Vector3.Dot(val, val2);
			float num3 = Vector3.Dot(val, Vector3.up);
			if (num >= -1.1f && num <= 2.75f && Mathf.Abs(num2) <= 1.35f && num3 >= -0.75f)
			{
				return num3 <= 1.35f;
			}
			return false;
		}

		private bool ColliderIsInsideScissorsDamageVolume(Collider hitCollider)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: 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)
			if ((Object)(object)hitCollider != (Object)null)
			{
				Bounds bounds = hitCollider.bounds;
				return PointIsInsideScissorsDamageVolume(((Bounds)(ref bounds)).center);
			}
			return false;
		}

		private bool PointIsInsideScissorsDamageVolume(Vector3 point)
		{
			//IL_0010: 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_001c: 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_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: 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_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)attackOrigin == (Object)null)
			{
				return false;
			}
			Vector3 val = point - attackOrigin.position;
			Vector3 scissorsForward = GetScissorsForward();
			Vector3 val2 = Vector3.Cross(Vector3.up, scissorsForward);
			if (((Vector3)(ref val2)).sqrMagnitude <= 0.001f)
			{
				val2 = ((Component)this).transform.right;
			}
			((Vector3)(ref val2)).Normalize();
			float num = Vector3.Dot(val, scissorsForward);
			float num2 = Vector3.Dot(val, val2);
			float num3 = Vector3.Dot(val, Vector3.up);
			if (num >= -1.1f && num <= 2.75f && Mathf.Abs(num2) <= 1.35f && num3 >= -0.75f)
			{
				return num3 <= 1.35f;
			}
			return false;
		}

		private Vector3 GetScissorsForward()
		{
			//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_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: 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)
			if ((Object)(object)attackOrigin != (Object)null)
			{
				Vector3 val = attackOrigin.position - ((Component)this).transform.position;
				val.y = 0f;
				if (((Vector3)(ref val)).sqrMagnitude > 0.001f)
				{
					return ((Vector3)(ref val)).normalized;
				}
			}
			Vector3 val2 = -((Component)this).transform.forward;
			val2.y = 0f;
			if (!(((Vector3)(ref val2)).sqrMagnitude > 0.001f))
			{
				return -((Component)this).transform.forward;
			}
			return ((Vector3)(ref val2)).normalized;
		}

		[ServerRpc(RequireOwnership = false)]
		public void RequestWheelUnwindServerRpc(ServerRpcParams rpcParams = default(ServerRpcParams))
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Invalid comparison between Unknown and I4
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Invalid comparison between Unknown and I4
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0126: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0132: 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_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager;
			if (networkManager == null || !networkManager.IsListening)
			{
				return;
			}
			if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 && (networkManager.IsClient || networkManager.IsHost))
			{
				FastBufferWriter val = ((NetworkBehaviour)this).__beginSendServerRpc(3538766455u, rpcParams, (RpcDelivery)0);
				((NetworkBehaviour)this).__endSendServerRpc(ref val, 3538766455u, rpcParams, (RpcDelivery)0);
			}
			if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 || (!networkManager.IsServer && !networkManager.IsHost))
			{
				return;
			}
			((NetworkBehaviour)this).__rpc_exec_stage = (__RpcExecStage)0;
			if (!CanUseWindupWheel)
			{
				return;
			}
			PlayerControllerB val2 = VictimRpc.FromActualClientId(rpcParams.Receive.SenderClientId);
			if (!((Object)(object)val2 == (Object)null))
			{
				Vector3 val3 = (((Object)(object)_wheelInteractionProxy != (Object)null) ? _wheelInteractionProxy.position : (((Object)(object)wheelBone != (Object)null) ? wheelBone.position : ((Component)this).transform.position));
				if (!(Vector3.Distance(((Component)val2).transform.position, val3) > WheelInteractDistance + 1.25f))
				{
					WindDownToIdle();
				}
			}
		}

		private void ResolveRuntimeReferences()
		{
			if ((Object)(object)base.creatureAnimator == (Object)null)
			{
				base.creatureAnimator = ((Component)this).GetComponent<Animator>() ?? ((Component)this).GetComponentInChildren<Animator>(true);
			}
			if ((Object)(object)base.agent == (Object)null)
			{
				base.agent = ((Component)this).GetComponent<NavMeshAgent>() ?? ((Component)this).GetComponentInChildren<NavMeshAgent>(true);
			}
			if ((Object)(object)base.creatureSFX == (Object)null)
			{
				base.creatureSFX = FindAudioSource("CreatureSFX");
			}
			if ((Object)(object)base.creatureVoice == (Object)null)
			{
				base.creatureVoice = FindAudioSource("CreatureVoice");
			}
			if ((Object)(object)tickingAudioSource == (Object)null)
			{
				tickingAudioSource = FindAudioSource("TickingAudio");
			}
			if ((Object)(object)alarmAudioSource == (Object)null)
			{
				alarmAudioSource = FindAudioSource("AlarmAudio");
			}
			if ((Object)(object)attackOrigin == (Object)null)
			{
				attackOrigin = FindChildRecursive(((Component)this).transform, "AttackOrigin") ?? ((Component)this).transform;
			}
			if ((Object)(object)wheelBone == (Object)null)
			{
				wheelBone = FindChildRecursive(((Component)this).transform, "back_windup_wheel_mount");
			}
			if ((Object)(object)_headTrackBone == (Object)null)
			{
				_headTrackBone = FindChildRecursive(((Component)this).transform, "head_track");
			}
			if ((Object)(object)_wheelInteractionProxy == (Object)null)
			{
				_wheelInteractionProxy = FindChildRecursive(((Component)this).transform, "BackWindupWheel_InteractionProxy");
			}
			if ((Object)(object)_wheelConnector == (Object)null)
			{
				_wheelConnector = FindChildRecursive(((Component)this).transform, "BackWindupWheelConnector");
			}
			if ((Object)(object)bodyBlockerCollider == (Object)null)
			{
				object obj = ((Component)this).GetComponent<CapsuleCollider>();
				if (obj == null)
				{
					obj = ((Component)this).GetComponent<Collider>();
					if (obj == null)
					{
						Transform obj2 = FindChildRecursive(((Component)this).transform, "BodyBlocker");
						obj = ((obj2 != null) ? ((Component)obj2).GetComponent<Collider>() : null);
					}
				}
				bodyBlockerCollider = (Collider)obj;
			}
			if ((Object)(object)base.eye == (Object)null)
			{
				base.eye = FindChildRecursive(((Component)this).transform, "EyeTransform") ?? ((Component)this).transform;
			}
			EnsureWheelConnector();
			AlignWheelTargetsAndConnector();
		}

		private void DisableStaleWheelScanNode()
		{
			Transform val = FindChildRecursive(((Component)this).transform, "WheelScanNode");
			if ((Object)(object)val != (Object)null && ((Component)val).gameObject.activeSelf)
			{
				((Component)val).gameObject.SetActive(false);
			}
		}

		private AudioSource FindAudioSource(string childName)
		{
			Transform val = FindChildRecursive(((Component)this).transform, childName);
			AudioSource val2 = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponent<AudioSource>() : null);
			if ((Object)(object)val2 != (Object)null)
			{
				return val2;
			}
			AudioSource componentInChildren = ((Component)this).GetComponentInChildren<AudioSource>(true);
			if ((Object)(object)componentInChildren != (Object)null && string.Equals(childName, "TickingAudio", StringComparison.Ordinal))
			{
				Plugin.Log.LogWarning((object)("[ScissorsCreatureAI] Dedicated TickingAudio source is missing; ticking is falling back to shared AudioSource '" + ((Object)componentInChildren).name + "'."));
			}
			return componentInChildren;
		}

		private static Transform FindChildRecursive(Transform parent, string name)
		{
			if ((Object)(object)parent == (Object)null)
			{
				return null;
			}
			if (((Object)parent).name == name)
			{
				return parent;
			}
			for (int i = 0; i < parent.childCount; i++)
			{
				Transform val = FindChildRecursive(parent.GetChild(i), name);
				if ((Object)(object)val != (Object)null)
				{
					return val;
				}
			}
			return null;
		}

		private void TickWheelVisual(float deltaTime)
		{
			//IL_001e: 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_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)wheelBone == (Object)null))
			{
				if (!_capturedWheelBase)
				{
					_wheelBaseLocalRotation = wheelBone.localRotation;
					_capturedWheelBase = true;
				}
				float num = ((base.currentBehaviourStateIndex == 2) ? (420f * deltaTime) : 0f);
				if (num > 0f)
				{
					_wheelVisualAngle += num;
				}
				wheelBone.localRotation = _wheelBaseLocalRotation * Quaternion.AngleAxis(_wheelVisualAngle, Vector3.up);
			}
		}

		private void AlignWheelTargetsAndConnector()
		{
			//IL_0001: 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_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: 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_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = ResolveWheelCenterPosition();
			if ((Object)(object)_wheelInteractionProxy != (Object)null)
			{
				_wheelInteractionProxy.position = val;
				_wheelInteractionProxy.rotation = ((Component)this).transform.rotation;
			}
			EnsureWheelConnector();
			if (!((Object)(object)_wheelConnector == (Object)null))
			{
				Vector3 start = ((Component)this).transform.TransformPoint(WheelConnectorBodyAnchorLocalPosition);
				AlignConnectorCylinder(_wheelConnector, start, val, 0.055f);
			}
		}

		private Vector3 ResolveWheelCenterPosition()
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)wheelBone != (Object)null))
			{
				return ((Component)this).transform.TransformPoint(WheelFallbackLocalPosition);
			}
			return wheelBone.position;
		}

		private void EnsureWheelConnector()
		{
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_wheelConnector == (Object)null)
			{
				_wheelConnector = FindChildRecursive(((Component)this).transform, "BackWindupWheelConnector");
			}
			if ((Object)(object)_wheelConnector != (Object)null)
			{
				return;
			}
			GameObject val = GameObject.CreatePrimitive((PrimitiveType)2);
			((Object)val).name = "BackWindupWheelConnector";
			val.transform.SetParent(((Component)this).transform, false);
			_wheelConnector = val.transform;
			Collider component = val.GetComponent<Collider>();
			if ((Object)(object)component != (Object)null)
			{
				Object.Destroy((Object)(object)component);
			}
			Renderer component2 = val.GetComponent<Renderer>();
			if ((Object)(object)component2 == (Object)null)
			{
				return;
			}
			Material val2 = (_connectorMaterial = component2.material);
			if (!((Object)(object)val2 == (Object)null))
			{
				Color val3 = default(Color);
				((Color)(ref val3))..ctor(0.035f, 0.03f, 0.028f, 1f);
				if (val2.HasProperty("_BaseColor"))
				{
					val2.SetColor("_BaseColor", val3);
				}
				else if (val2.HasProperty("_Color"))
				{
					val2.color = val3;
				}
			}
		}

		private void AlignConnectorCylinder(Transform connector, Vector3 start, Vector3 end, float radius)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: 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_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: 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)
			Vector3 val = end - start;
			float magnitude = ((Vector3)(ref val)).magnitude;
			if (magnitude < 0.04f)
			{
				if (((Component)connector).gameObject.activeSelf)
				{
					((Component)connector).gameObject.SetActive(false);
				}
				return;
			}
			if (!((Component)connector).gameObject.activeSelf)
			{
				((Component)connector).gameObject.SetActive(true);
			}
			connector.position = (start + end) * 0.5f;
			connector.rotation = Quaternion.FromToRotation(Vector3.up, ((Vector3)(ref val)).normalized);
			Vector3 lossyScale = ((Component)this).transform.lossyScale;
			connector.localScale = new Vector3(radius / Mathf.Max(0.001f, Mathf.Abs(lossyScale.x)), magnitude * 0.5f / Mathf.Max(0.001f, Mathf.Abs(lossyScale.y)), radius / Mathf.Max(0.001f, Mathf.Abs(lossyScale.z)));
		}

		private void TickFootstepAudio(float deltaTime)
		{
			if ((Object)(object)base.creatureSFX == (Object)null)
			{
				return;
			}
			if (base.currentBehaviourStateIndex != 0 && base.currentBehaviourStateIndex != 1 && base.currentBehaviourStateIndex != 2)
			{
				_footstepAudioTimer = 0f;
			}
			else
			{
				if (base.currentBehaviourStateIndex == 0 && _measuredSpeed < 0.1f)
				{
					return;
				}
				bool flag = base.currentBehaviourStateIndex == 2;
				AudioClip val = ((flag && (Object)(object)attackRunClip != (Object)null) ? attackRunClip : footstepClip);
				if (!((Object)(object)val == (Object)null))
				{
					_footstepAudioTimer -= deltaTime;
					if (!(_footstepAudioTimer > 0f))
					{
						float num = (flag ? 0.42f : 1.35f);
						_footstepAudioTimer = Mathf.Max(0.12f, (val.length > 0f) ? (val.length * 0.9f) : num);
						base.creatureSFX.PlayOneShot(val, flag ? 1.35f : 1.15f);
					}
				}
			}
		}

		private void TickWindupTickingAudio()
		{
			if (!_windupTickingActive && base.currentBehaviourStateIndex != 1)
			{
				StopWindupTicking(resetRepeatCount: true);
				return;
			}
			_windupTickingActive = true;
			if (!((Object)(object)tickingClip == (Object)null) && !((Object)(object)tickingAudioSource == (Object)null) && !tickingAudioSource.isPlaying)
			{
				tickingAudioSource.clip = tickingClip;
				tickingAudioSource.loop = false;
				tickingAudioSource.volume = 1.25f;
				tickingAudioSource.pitch = Mathf.Min(2.5f, 1.15f + (float)_tickingRepeatCount * 0.2f);
				tickingAudioSource.time = 0f;
				tickingAudioSource.Play();
				_tickingRepeatCount++;
			}
		}

		private void StopWindupTicking(bool resetRepeatCount)
		{
			if ((Object)(object)tickingAudioSource != (Object)null)
			{
				tickingAudioSource.Stop();
				tickingAudioSource.loop = false;
				tickingAudioSource.pitch = 1f;
				tickingAudioSource.time = 0f;
			}
			if (resetRepeatCount)
			{
				_tickingRepeatCount = 0;
			}
		}

		private void TickAttackAlarmAudio()
		{
			if (base.currentBehaviourStateIndex != 2)
			{
				StopAttackAlarm();
			}
			else if (!((Object)(object)alarmClip == (Object)null) && !((Object)(object)alarmAudioSource == (Object)null) && !alarmAudioSource.isPlaying)
			{
				alarmAudioSource.clip = alarmClip;
				alarmAudioSource.loop = true;
				alarmAudioSource.volume = 1.25f;
				alarmAudioSource.pitch = 1f;
				alarmAudioSource.Play();
			}
		}

		private void StopAttackAlarm()
		{
			if (!((Object)(object)alarmAudioSource == (Object)null))
			{
				alarmAudioSource.Stop();
				alarmAudioSource.loop = false;
				alarmAudioSource.pitch = 1f;
				alarmAudioSource.time = 0f;
			}
		}

		private void TickSnipAudio(float deltaTime)
		{
			if (base.currentBehaviourStateIndex != 2 || snipClips == null || snipClips.Length == 0 || (Object)(object)base.creatureSFX == (Object)null)
			{
				return;
			}
			_snipAudioTimer -= deltaTime;
			if (!(_snipAudioTimer > 0f))
			{
				_snipAudioTimer = 0.27f;
				AudioClip val = snipClips[Random.Range(0, snipClips.Length)];
				if ((Object)(object)val != (Object)null)
				{
					base.creatureSFX.PlayOneShot(val, 2.6f);
				}
			}
		}

		private void PlayAttackedByPlayerAudio()
		{
			if (!((Object)(object)attackedByPlayerClip == (Object)null))
			{
				AudioSource val = (((Object)(object)base.creatureVoice != (Object)null) ? base.creatureVoice : base.creatureSFX);
				if ((Object)(object)val != (Object)null)
				{
					val.PlayOneShot(attackedByPlayerClip, 9f);
				}
			}
		}

		[ServerRpc(RequireOwnership = false)]
		public void ReportSnipKillServerRpc(int victimSlot, ServerRpcParams rpcParams = default(ServerRpcParams))
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Invalid comparison between Unknown and I4
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Invalid comparison between Unknown and I4
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager;
			if (networkManager == null || !networkManager.IsListening)
			{
				return;
			}
			if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 && (networkManager.IsClient || networkManager.IsHost))
			{
				FastBufferWriter val = ((NetworkBehaviour)this).__beginSendServerRpc(2154611850u, rpcParams, (RpcDelivery)0);
				BytePacker.WriteValueBitPacked(val, victimSlot);
				((NetworkBehaviour)this).__endSendServerRpc(ref val, 2154611850u, rpcParams, (RpcDelivery)0);
			}
			if ((int)((NetworkBehaviour)this).__rpc_exec_stage == 1 && (networkManager.IsServer || networkManager.IsHost))
			{
				((NetworkBehaviour)this).__rpc_exec_stage = (__RpcExecStage)0;
				PlayerControllerB val2 = VictimRpc.FromSlot(victimSlot);
				if (!((Object)(object)val2 == (Object)null) && val2.actualClientId == rpcParams.Receive.SenderClientId)
				{
					PlaySnipKillClientRpc();
				}
			}
		}

		[ClientRpc]
		private void PlaySnipKillClientRpc()
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Invalid comparison between Unknown and I4
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Invalid comparison between Unknown and I4
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager;
			if (networkManager != null && networkManager.IsListening)
			{
				if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 && (networkManager.IsServer || networkManager.IsHost))
				{
					ClientRpcParams val2 = default(ClientRpcParams);
					FastBufferWriter val = ((NetworkBehaviour)this).__beginSendClientRpc(48023000u, val2, (RpcDelivery)0);
					((NetworkBehaviour)this).__endSendClientRpc(ref val, 48023000u, val2, (RpcDelivery)0);
				}
				if ((int)((NetworkBehaviour)this).__rpc_exec_stage == 1 && (networkManager.IsClient || networkManager.IsHost))
				{
					((NetworkBehaviour)this).__rpc_exec_stage = (__RpcExecStage)0;
					CreatureAudioSetup.TransmitOneShot(base.creatureSFX, snipKillClip, 2.8f);
				}
			}
		}

		private void TickIdleGrowlAudio(float deltaTime)
		{
			if (base.currentBehaviourStateIndex == 2)
			{
				return;
			}
			if (base.currentBehaviourStateIndex != 0 && base.currentBehaviourStateIndex != 1)
			{
				_idleGrowlTimer = 0f;
			}
			else
			{
				if ((Object)(object)idleGrowlClip == (Object)null || (Object)(object)base.creatureVoice == (Object)null)
				{
					return;
				}
				_idleGrowlTimer -= deltaTime;
				if (!(_idleGrowlTimer > 0f))
				{
					float num = ((base.currentBehaviourStateIndex == 1) ? 4f : 7f);
					float num2 = ((base.currentBehaviourStateIndex == 1) ? 7f : 12f);
					_idleGrowlTimer = Random.Range(num, num2);
					if (!base.creatureVoice.isPlaying)
					{
						base.creatureVoice.PlayOneShot(idleGrowlClip, (base.currentBehaviourStateIndex == 1) ? 1.45f : 1.1f);
					}
				}
			}
		}

		[ClientRpc]
		private void PlayWindupClientRpc()
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Invalid comparison between Unknown and I4
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Invalid comparison between Unknown and I4
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager;
			if (networkManager != null && networkManager.IsListening)
			{
				if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 && (networkManager.IsServer || networkManager.IsHost))
				{
					ClientRpcParams val2 = default(ClientRpcParams);
					FastBufferWriter val = ((NetworkBehaviour)this).__beginSendClientRpc(2316245045u, val2, (RpcDelivery)0);
					((NetworkBehaviour)this).__endSendClientRpc(ref val, 2316245045u, val2, (RpcDelivery)0);
				}
				if ((int)((NetworkBehaviour)this).__rpc_exec_stage == 1 && (networkManager.IsClient || networkManager.IsHost))
				{
					((NetworkBehaviour)this).__rpc_exec_stage = (__RpcExecStage)0;
					_windupTickingActive = true;
					StopAttackAlarm();
					StopWindupTicking(resetRepeatCount: true);
					CreatureAudioSetup.TransmitOneShot(base.creatureSFX, windupClip, 1.25f);
					TickWindupTickingAudio();
				}
			}
		}

		[ClientRpc]
		private void PlaySnipClientRpc()
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Invalid comparison between Unknown and I4
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Invalid comparison between Unknown and I4
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager;
			if (networkManager != null && networkManager.IsListening)
			{
				if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 && (networkManager.IsServer || networkManager.IsHost))
				{
					ClientRpcParams val2 = default(ClientRpcParams);
					FastBufferWriter val = ((NetworkBehaviour)this).__beginSendClientRpc(1552068909u, val2, (RpcDelivery)0);
					((NetworkBehaviour)this).__endSendClientRpc(ref val, 1552068909u, val2, (RpcDelivery)0);
				}
				if ((int)((NetworkBehaviour)this).__rpc_exec_stage == 1 && (networkManager.IsClient || networkManager.IsHost))
				{
					((NetworkBehaviour)this).__rpc_exec_stage = (__RpcExecStage)0;
					_snipAudioTimer = 0f;
					_windupTickingActive = false;
					StopWindupTicking(resetRepeatCount: true);
					TickAttackAlarmAudio();
				}
			}
		}

		[ClientRpc]
		private void PlayWheelUnwindClientRpc(float wheelAngle)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Invalid comparison between Unknown and I4
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Invalid comparison between Unknown and I4
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager;
			if (networkManager != null && networkManager.IsListening)
			{
				if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 && (networkManager.IsServer || networkManager.IsHost))
				{
					ClientRpcParams val2 = default(ClientRpcParams);
					FastBufferWriter val = ((NetworkBehaviour)this).__beginSendClientRpc(159684443u, val2, (RpcDelivery)0);
					((FastBufferWriter)(ref val)).WriteValueSafe<float>(ref wheelAngle, default(ForPrimitives));
					((NetworkBehaviour)this).__endSendClientRpc(ref val, 159684443u, val2, (RpcDelivery)0);
				}
				if ((int)((NetworkBehaviour)this).__rpc_exec_stage == 1 && (networkManager.IsClient || networkManager.IsHost))
				{
					((NetworkBehaviour)this).__rpc_exec_stage = (__RpcExecStage)0;
					_wheelVisualAngle = wheelAngle;
					_windupTickingActive = false;
					StopWindupTicking(resetRepeatCount: true);
					StopAttackAlarm();
					CreatureAudioSetup.TransmitOneShot(base.creatureSFX, wheelUnwindClip);
				}
			}
		}

		private bool RouteAudioSources()
		{
			return CreatureAudioSetup.ConfigureSpatial(base.creatureSFX) & CreatureAudioSetup.ConfigureSpatial(base.creatureVoice) & CreatureAudioSetup.ConfigureSpatial(tickingAudioSource) & CreatureAudioSetup.ConfigureSpatial(alarmAudioSource);
		}

		private void OnDisable()
		{
			StopAllLoops();
		}

		public override void OnDestroy()
		{
			StopAllLoops();
			if ((Object)(object)_connectorMaterial != (Object)null)
			{
				Object.Destroy((Object)(object)_connectorMaterial);
				_connectorMaterial = null;
			}
			((EnemyAI)this).OnDestroy();
		}

		public override void KillEnemy(bool destroy = false)
		{
			((EnemyAI)this).KillEnemy(destroy);
			StopAllLoops();
			if ((Object)(object)base.creatureSFX != (Object)null)
			{
				base.creatureSFX.Stop();
			}
		}

		private void StopAllLoops()
		{
			_windupTickingActive = false;
			StopWindupTicking(resetRepeatCount: true);
			StopAttackAlarm();
		}

		public override void HitEnemy(int force = 1, PlayerControllerB playerWhoHit = null, bool playHitSFX = false, int hitID = -1)
		{
			((EnemyAI)this).HitEnemy(force, playerWhoHit, playHitSFX, hitID);
			if (base.isEnemyDead)
			{
				return;
			}
			if ((Object)(object)playerWhoHit != (Object)null)
			{
				PlayAttackedByPlayerAudio();
			}
			base.enemyHP -= force;
			if (base.enemyHP <= 0)
			{
				if (((NetworkBehaviour)this).IsOwner)
				{
					((EnemyAI)this).KillEnemyOnOwnerClient(false);
				}
			}
			else if (((NetworkBehaviour)this).IsServer && base.currentBehaviourStateIndex == 0 && (Object)(object)playerWhoHit != (Object)null && !playerWhoHit.isPlayerDead && ((EnemyAI)this).PlayerIsTargetable(playerWhoHit, false, false, true))
			{
				BeginWindup(playerWhoHit);
			}
		}

		public override void DetectNoise(Vector3 noisePosition, float noiseLoudness, int timesPlayedInOneSpot = 0, int noiseID = 0)
		{
			//IL_0001: 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_005f: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				((EnemyAI)this).DetectNoise(noisePosition, noiseLoudness, timesPlayedInOneSpot, noiseID);
				if (((NetworkBehaviour)this).IsServer && !base.isEnemyDead && !((EnemyAI)(object)this).IsStunned() && timesPlayedInOneSpot <= 10 && base.currentBehaviourStateIndex == 0)
				{
					Transform val = (((Object)(object)base.eye != (Object)null) ? base.eye : ((Component)this).transform);
					_noiseMemory.Record(noisePosition, noiseLoudness, 0.5f, val.position, 20f);
				}
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"[ScissorsCreatureAI] DetectNoise failed: {arg}");
			}
		}

		protected override void __initializeVariables()
		{
			if (_networkState == null)
			{
				throw new Exception("ScissorsCreatureAI._networkState cannot be null. All NetworkVariableBase instances must be initialized.");
			}
			((NetworkVariableBase)_networkState).Initialize((NetworkBehaviour)(object)this);
			((NetworkBehaviour)this).__nameNetworkVariable((NetworkVariableBase)(object)_networkState, "_networkState");
			((NetworkBehaviour)this).NetworkVariableFields.Add((NetworkVariableBase)(object)_networkState);
			if (_networkTargetSlot == null)
			{
				throw new Exception("ScissorsCreatureAI._networkTargetSlot cannot be null. All NetworkVariableBase instances must be initialized.");
			}
			((NetworkVariableBase)_networkTargetSlot).Initialize((NetworkBehaviour)(object)this);
			((NetworkBehaviour)this).__nameNetworkVariable((NetworkVariableBase)(object)_networkTargetSlot, "_networkTargetSlot");
			((NetworkBehaviour)this).NetworkVariableFields.Add((NetworkVariableBase)(object)_networkTargetSlot);
			if (_networkAttackDamage == null)
			{
				throw new Exception("ScissorsCreatureAI._networkAttackDamage cannot be null. All NetworkVariableBase instances must be initialized.");
			}
			((NetworkVariableBase)_networkAttackDamage).Initialize((NetworkBehaviour)(object)this);
			((NetworkBehaviour)this).__nameNetworkVariable((NetworkVariableBase)(object)_networkAttackDamage, "_networkAttackDamage");
			((NetworkBehaviour)this).NetworkVariableFields.Add((NetworkVariableBase)(object)_networkAttackDamage);
			((EnemyAI)this).__initializeVariables();
		}

		protected override void __initializeRpcs()
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Expected O, but got Unknown
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Expected O, but got Unknown
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Expected O, but got Unknown
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Expected O, but got Unknown
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Expected O, but got Unknown
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Expected O, but got Unknown
			((NetworkBehaviour)this).__registerRpc(3538766455u, new RpcReceiveHandler(__rpc_handler_3538766455), "RequestWheelUnwindServerRpc");
			((NetworkBehaviour)this).__registerRpc(2154611850u, new RpcReceiveHandler(__rpc_handler_2154611850), "ReportSnipKillServerRpc");
			((NetworkBehaviour)this).__registerRpc(48023000u, new RpcReceiveHandler(__rpc_handler_48023000), "PlaySnipKillClientRpc");
			((NetworkBehaviour)this).__registerRpc(2316245045u, new RpcReceiveHandler(__rpc_handler_2316245045), "PlayWindupClientRpc");
			((NetworkBehaviour)this).__registerRpc(1552068909u, new RpcReceiveHandler(__rpc_handler_1552068909), "PlaySnipClientRpc");
			((NetworkBehaviour)this).__registerRpc(159684443u, new RpcReceiveHandler(__rpc_handler_159684443), "PlayWheelUnwindClientRpc");
			((EnemyAI)this).__initializeRpcs();
		}

		private static void __rpc_handler_3538766455(NetworkBehaviour target, FastBufferReader reader, __RpcParams rpcParams)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			NetworkManager networkManager = target.NetworkManager;
			if (networkManager != null && networkManager.IsListening)
			{
				ServerRpcParams server = rpcParams.Server;
				target.__rpc_exec_stage = (__RpcExecStage)1;
				((ScissorsCreatureAI)(object)target).RequestWheelUnwindServerRpc(server);
				target.__rpc_exec_stage = (__RpcExecStage)0;
			}
		}

		private static void __rpc_handler_2154611850(NetworkBehaviour target, FastBufferReader reader, __RpcParams rpcParams)
		{
			//IL_0023: 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_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: 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)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			NetworkManager networkManager = target.NetworkManager;
			if (networkManager != null && networkManager.IsListening)
			{
				int victimSlot = default(int);
				ByteUnpacker.ReadValueBitPacked(reader, ref victimSlot);
				ServerRpcParams server = rpcParams.Server;
				target.__rpc_exec_stage = (__RpcExecStage)1;
				((ScissorsCreatureAI)(object)target).ReportSnipKillServerRpc(victimSlot, server);
				target.__rpc_exec_stage = (__RpcExecStage)0;
			}
		}

		private static void __rpc_handler_48023000(NetworkBehaviour target, FastBufferReader reader, __RpcParams rpcParams)
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			NetworkManager networkManager = target.NetworkManager;
			if (networkManager != null && networkManager.IsListening)
			{
				target.__rpc_exec_stage = (__RpcExecStage)1;
				((ScissorsCreatureAI)(object)target).PlaySnipKillClientRpc();
				target.__rpc_exec_stage = (__RpcExecStage)0;
			}
		}

		private static void __rpc_handler_2316245045(NetworkBehaviour target, FastBufferReader reader, __RpcParams rpcParams)
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			NetworkManager networkManager = target.NetworkManager;
			if (networkManager != null && networkManager.IsListening)
			{
				target.__rpc_exec_stage = (__RpcExecStage)1;
				((ScissorsCreatureAI)(object)target).PlayWindupClientRpc();
				target.__rpc_exec_stage = (__RpcExecStage)0;
			}
		}

		private static void __rpc_handler_1552068909(NetworkBehaviour target, FastBufferReader reader, __RpcParams rpcParams)
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			NetworkManager networkManager = target.NetworkManager;
			if (networkManager != null && networkManager.IsListening)
			{
				target.__rpc_exec_stage = (__RpcExecStage)1;
				((ScissorsCreatureAI)(object)target).PlaySnipClientRpc();
				target.__rpc_exec_stage = (__RpcExecStage)0;
			}
		}

		private static void __rpc_handler_159684443(NetworkBehaviour target, FastBufferReader reader, __RpcParams rpcParams)
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			NetworkManager networkManager = target.NetworkManager;
			if (networkManager != null && networkManager.IsListening)
			{
				float wheelAngle = default(float);
				((FastBufferReader)(ref reader)).ReadValueSafe<float>(ref wheelAngle, default(ForPrimitives));
				target.__rpc_exec_stage = (__RpcExecStage)1;
				((ScissorsCreatureAI)(object)target).PlayWheelUnwindClientRpc(wheelAngle);
				target.__rpc_exec_stage = (__RpcExecStage)0;
			}
		}

		protected internal override string __getTypeName()
		{
			return "ScissorsCreatureAI";
		}
	}
	[BepInPlugin("y4ngz.lethalcompany.scissorscreature", "Y4NGZ Scissors Creature", "1.2.1")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public sealed class Plugin : BaseUnityPlugin
	{
		internal const string BundleFilename = "y4ngzscissorscreature.bundle";

		internal const string PrefabName = "Y4NGZScissorsCreature";

		internal const string LegacyPrefabName = "LGUScissorsCreature";

		internal const string DawnNamespace = "y4ngz_monsters";

		internal const string DawnEnemyKey = "snipjack";

		internal const string BestiaryText = "Snipjack\n\nDanger level: high\n\nA slow-moving construct with a clockwork wheel on its back and oversized shears mounted forward. It winds itself at whatever it sees ahead of it. If the wheel winds fully, the creature begins rapid snipping until the back wheel is unwound. Unwinding the wheel stops it at once; left alone with nothing in reach, its spring eventually runs down on its own.\n\n";

		internal const string ScanNodeSubtitle = "Try unwinding the back wheel";

		private const float CreatureScale = 0.7f;

		private const float ScissorsAgentRadius = 0.32f;

		internal static ManualLogSource Log;

		internal static ScissorsCreatureConfig ModConfig;

		internal static AssetBundle ModAssets;

		internal static EnemyType EnemyType;

		private static AudioClip[] _bundleAudioClips;

		private static bool _netcodeInitialized;

		private static bool _loggedScanNodeLayer;

		private void Awake()
		{
			Log = ((BaseUnityPlugin)this).Logger;
			try
			{
				InitializeNetcodeRPCs();
				ModConfig = new ScissorsCreatureConfig(((BaseUnityPlugin)this).Config);
				if (!LoadBundle())
				{
					return;
				}
				GameObject val = LoadBundlePrefab();
				if ((Obj