Decompiled source of Slenderman v1.3.8

SlendermanMod.dll

Decompiled 2 hours 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 BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using GameNetcodeStuff;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.Networking;
using UnityEngine.Rendering;
using UnityEngine.UI;

[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("SlendermanMod")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.3.8.0")]
[assembly: AssemblyInformationalVersion("1.3.8")]
[assembly: AssemblyProduct("SlendermanMod")]
[assembly: AssemblyTitle("SlendermanMod")]
[assembly: AssemblyVersion("1.3.8.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace SlendermanMod
{
	[BepInPlugin("tonys.lethalcompany.slenderman", "Slenderman", "1.3.8")]
	[BepInProcess("Lethal Company.exe")]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "tonys.lethalcompany.slenderman";

		public const string PluginName = "Slenderman";

		public const string PluginVersion = "1.3.8";

		private static SlendermanRuntimeRunner _runtime;

		internal static ManualLogSource Log { get; private set; }

		internal static ConfigEntry<int> SpawnRarity { get; private set; }

		internal static ConfigEntry<int> GuaranteedSpawnChance { get; private set; }

		internal static ConfigEntry<int> MaxSlendermen { get; private set; }

		internal static ConfigEntry<float> WakeUpDelayHours { get; private set; }

		internal static ConfigEntry<float> BaseAppearanceInterval { get; private set; }

		internal static ConfigEntry<float> MinimumAppearanceInterval { get; private set; }

		internal static ConfigEntry<float> RoundEscalationSeconds { get; private set; }

		internal static ConfigEntry<float> MinimumStalkingDistance { get; private set; }

		internal static ConfigEntry<float> MaximumStalkingDistance { get; private set; }

		internal static ConfigEntry<float> AppearanceDuration { get; private set; }

		internal static ConfigEntry<float> GazeAngle { get; private set; }

		internal static ConfigEntry<float> GazeRange { get; private set; }

		internal static ConfigEntry<float> BaseStareKillSeconds { get; private set; }

		internal static ConfigEntry<float> StareKillReductionPerPage { get; private set; }

		internal static ConfigEntry<float> LookAwayRecoverySpeed { get; private set; }

		internal static ConfigEntry<float> StaticNoiseVolume { get; private set; }

		internal static ConfigEntry<float> StaticVisualIntensity { get; private set; }

		internal static ConfigEntry<float> DeathSoundVolume { get; private set; }

		internal static ConfigEntry<float> DeathCloseupDuration { get; private set; }

		internal static ConfigEntry<int> ContactDamage { get; private set; }

		internal static ConfigEntry<bool> Invulnerable { get; private set; }

		internal static ConfigEntry<int> PagesPerRound { get; private set; }

		internal static ConfigEntry<int> PageValue { get; private set; }

		internal static ConfigEntry<bool> EnableTestHotkey { get; private set; }

		internal static ConfigEntry<KeyCode> TestSpawnKey { get; private set; }

		private void Awake()
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			BindConfig();
			Harmony val = new Harmony("tonys.lethalcompany.slenderman");
			val.PatchAll(typeof(Plugin).Assembly);
			SlenderCriticalPatches.Install(val);
			_runtime?.Dispose();
			_runtime = new SlendermanRuntimeRunner();
			_runtime.Initialize();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Slenderman 1.3.8 loaded for Lethal Company v81 / BepInEx 5.4.x.");
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Slenderman is registered as a separate enemy; the Bracken is not replaced or modified.");
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Multiplayer strategy: cloned vanilla network component layouts; no custom NetworkBehaviour RPCs.");
		}

		internal static void TickRuntime()
		{
			_runtime?.TickFrame();
		}

		private void BindConfig()
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Expected O, but got Unknown
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Expected O, but got Unknown
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: 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_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Expected O, but got Unknown
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			//IL_014c: Expected O, but got Unknown
			//IL_017f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0189: Expected O, but got Unknown
			//IL_01bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c6: Expected O, but got Unknown
			//IL_01f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0203: Expected O, but got Unknown
			//IL_0236: Unknown result type (might be due to invalid IL or missing references)
			//IL_0240: Expected O, but got Unknown
			//IL_0269: Unknown result type (might be due to invalid IL or missing references)
			//IL_0273: Expected O, but got Unknown
			//IL_02c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d0: Expected O, but got Unknown
			//IL_0303: Unknown result type (might be due to invalid IL or missing references)
			//IL_030d: Expected O, but got Unknown
			//IL_0340: Unknown result type (might be due to invalid IL or missing references)
			//IL_034a: Expected O, but got Unknown
			//IL_037d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0387: Expected O, but got Unknown
			//IL_03ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c4: Expected O, but got Unknown
			//IL_03f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0401: Expected O, but got Unknown
			//IL_0434: Unknown result type (might be due to invalid IL or missing references)
			//IL_043e: Expected O, but got Unknown
			//IL_0471: Unknown result type (might be due to invalid IL or missing references)
			//IL_047b: Expected O, but got Unknown
			//IL_04ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_04b8: Expected O, but got Unknown
			//IL_04e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_04eb: Expected O, but got Unknown
			//IL_0517: Unknown result type (might be due to invalid IL or missing references)
			//IL_0521: Expected O, but got Unknown
			SpawnRarity = ((BaseUnityPlugin)this).Config.Bind<int>("01 - Spawning", "Slenderman spawn rarity", 35, new ConfigDescription("Indoor spawn weight for the separate Slenderman enemy on vanilla and custom moons. The Bracken entry is left untouched.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 200), Array.Empty<object>()));
			GuaranteedSpawnChance = ((BaseUnityPlugin)this).Config.Bind<int>("01 - Spawning", "Guaranteed spawn chance percent", 35, new ConfigDescription("Chance from 0 to 100 that one Slenderman is spawned automatically after the facility has generated. Set this to 100 for a guaranteed Slenderman every round.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>()));
			MaxSlendermen = ((BaseUnityPlugin)this).Config.Bind<int>("01 - Spawning", "Maximum Slendermen", 1, new ConfigDescription("Maximum number of Slendermen alive at once.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 5), Array.Empty<object>()));
			WakeUpDelayHours = ((BaseUnityPlugin)this).Config.Bind<float>("02 - Stalking", "Wake-up delay in game hours", 2f, new ConfigDescription("Slenderman stays dormant for this many in-game hours after landing, unless a page is collected first.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 8f), Array.Empty<object>()));
			BaseAppearanceInterval = ((BaseUnityPlugin)this).Config.Bind<float>("02 - Stalking", "Base appearance interval", 28f, new ConfigDescription("Seconds between early-round stalking appearances before time and pages increase the pressure.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(8f, 90f), Array.Empty<object>()));
			MinimumAppearanceInterval = ((BaseUnityPlugin)this).Config.Bind<float>("02 - Stalking", "Minimum appearance interval", 5f, new ConfigDescription("Shortest possible pause between appearances late in a round or after many pages.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(2f, 30f), Array.Empty<object>()));
			RoundEscalationSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("02 - Stalking", "Seconds per round escalation", 75f, new ConfigDescription("Every this many elapsed round seconds reduces the appearance interval further.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(20f, 240f), Array.Empty<object>()));
			MinimumStalkingDistance = ((BaseUnityPlugin)this).Config.Bind<float>("02 - Stalking", "Minimum stalking distance", 14f, new ConfigDescription("Minimum distance behind a stalking target when Slenderman appears.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(8f, 30f), Array.Empty<object>()));
			MaximumStalkingDistance = ((BaseUnityPlugin)this).Config.Bind<float>("02 - Stalking", "Maximum stalking distance", 24f, new ConfigDescription("Maximum distance behind a stalking target when Slenderman appears.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(12f, 45f), Array.Empty<object>()));
			AppearanceDuration = ((BaseUnityPlugin)this).Config.Bind<float>("02 - Stalking", "Appearance duration", 4f, new ConfigDescription("Minimum time Slenderman offers a chance to notice him before he may vanish outside everyone's view.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1.5f, 12f), Array.Empty<object>()));
			ContactDamage = ((BaseUnityPlugin)this).Config.Bind<int>("02 - Stalking", "Contact damage", 40, new ConfigDescription("Damage when a manifested Slenderman is physically touched after his short arrival grace period.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>()));
			Invulnerable = ((BaseUnityPlugin)this).Config.Bind<bool>("02 - Stalking", "Invulnerable", true, "When enabled, shovels and weapons cannot kill Slenderman.");
			GazeAngle = ((BaseUnityPlugin)this).Config.Bind<float>("03 - Gaze", "Gaze angle", 18f, new ConfigDescription("Half-angle in degrees used to detect a direct look at Slenderman.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(5f, 45f), Array.Empty<object>()));
			GazeRange = ((BaseUnityPlugin)this).Config.Bind<float>("03 - Gaze", "Gaze range", 65f, new ConfigDescription("Maximum distance at which looking at Slenderman causes static.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(10f, 120f), Array.Empty<object>()));
			BaseStareKillSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("03 - Gaze", "Seconds until stare kills", 6f, new ConfigDescription("Continuous effective stare time before death with zero collected pages.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1.5f, 20f), Array.Empty<object>()));
			StareKillReductionPerPage = ((BaseUnityPlugin)this).Config.Bind<float>("03 - Gaze", "Kill-time reduction per page", 0.27f, new ConfigDescription("Seconds removed from the safe stare time per collected page.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 0.75f), Array.Empty<object>()));
			LookAwayRecoverySpeed = ((BaseUnityPlugin)this).Config.Bind<float>("03 - Gaze", "Look-away recovery multiplier", 1.35f, new ConfigDescription("How quickly accumulated static recovers after looking away.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 5f), Array.Empty<object>()));
			StaticNoiseVolume = ((BaseUnityPlugin)this).Config.Bind<float>("03 - Gaze", "Static noise volume", 0.7f, new ConfigDescription("Maximum volume of the gaze static sound.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
			StaticVisualIntensity = ((BaseUnityPlugin)this).Config.Bind<float>("03 - Gaze", "Static visual intensity", 1f, new ConfigDescription("Strength of the screen grain and interference strokes. 1 is the intended intensity.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.25f, 2f), Array.Empty<object>()));
			DeathSoundVolume = ((BaseUnityPlugin)this).Config.Bind<float>("03 - Gaze", "Death sound volume", 1.35f, new ConfigDescription("Volume multiplier of the supplied Slenderman death sound during the close-up.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 2f), Array.Empty<object>()));
			DeathCloseupDuration = ((BaseUnityPlugin)this).Config.Bind<float>("03 - Gaze", "Death close-up duration", 2.6f, new ConfigDescription("Seconds the Slenderman close-up and maximum interference play before the stare kills the player.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 5f), Array.Empty<object>()));
			PagesPerRound = ((BaseUnityPlugin)this).Config.Bind<int>("04 - Pages", "Pages per round", 11, new ConfigDescription("Number of Slender scribble pages added as loot. Hard-capped at 11.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 11), Array.Empty<object>()));
			PageValue = ((BaseUnityPlugin)this).Config.Bind<int>("04 - Pages", "Page value", 60, new ConfigDescription("Credit value of every page. The intended value is 60.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 500), Array.Empty<object>()));
			EnableTestHotkey = ((BaseUnityPlugin)this).Config.Bind<bool>("05 - Testing", "Enable test spawn hotkey", true, "Allows the host to spawn one Slenderman with the configured test key while standing inside a facility.");
			TestSpawnKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("05 - Testing", "Test spawn key", (KeyCode)288, "Key used by the host to spawn one Slenderman for testing.");
			((BaseUnityPlugin)this).Config.SaveOnConfigSet = true;
			((BaseUnityPlugin)this).Config.Save();
		}
	}
	internal sealed class SlenderAudioAssets : IDisposable
	{
		private const string ResourcePrefix = "SlendermanMod.Assets.";

		private UnityWebRequest _stareRequest;

		private UnityWebRequest _deathRequest;

		private string _stareTemporaryPath;

		private string _deathTemporaryPath;

		private AudioClip _stareClip;

		private AudioClip _deathClip;

		internal AudioClip StareClip => _stareClip;

		internal AudioClip DeathClip => _deathClip;

		internal void BeginLoad()
		{
			_stareRequest = StartEmbeddedMp3Load("slenderman_stare.mp3", "stare", out _stareTemporaryPath);
			_deathRequest = StartEmbeddedMp3Load("slenderman_death.mp3", "death", out _deathTemporaryPath);
		}

		internal void Tick()
		{
			CompleteLoad(ref _stareRequest, ref _stareTemporaryPath, ref _stareClip, "SlendermanStareSound");
			CompleteLoad(ref _deathRequest, ref _deathTemporaryPath, ref _deathClip, "SlendermanDeathSound");
		}

		private static UnityWebRequest StartEmbeddedMp3Load(string resourceName, string suffix, out string temporaryPath)
		{
			temporaryPath = null;
			try
			{
				Assembly assembly = typeof(SlenderAudioAssets).Assembly;
				using Stream stream = assembly.GetManifestResourceStream("SlendermanMod.Assets." + resourceName);
				if (stream == null)
				{
					Plugin.Log.LogError((object)("Embedded Slenderman audio resource '" + resourceName + "' was not found."));
					return null;
				}
				string text = Path.Combine(Path.GetTempPath(), "TonyS-Slenderman-Audio");
				Directory.CreateDirectory(text);
				temporaryPath = Path.Combine(text, $"{Guid.NewGuid():N}-{suffix}.mp3");
				using (FileStream destination = File.Create(temporaryPath))
				{
					stream.CopyTo(destination);
				}
				UnityWebRequest audioClip = UnityWebRequestMultimedia.GetAudioClip(new Uri(temporaryPath).AbsoluteUri, (AudioType)13);
				DownloadHandler downloadHandler = audioClip.downloadHandler;
				DownloadHandlerAudioClip val = (DownloadHandlerAudioClip)(object)((downloadHandler is DownloadHandlerAudioClip) ? downloadHandler : null);
				if (val != null)
				{
					val.streamAudio = false;
					val.compressed = false;
				}
				audioClip.SendWebRequest();
				return audioClip;
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"Could not begin loading embedded Slenderman audio '{resourceName}': {arg}");
				DeleteTemporaryFile(ref temporaryPath);
				return null;
			}
		}

		private static void CompleteLoad(ref UnityWebRequest request, ref string temporaryPath, ref AudioClip clip, string clipName)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Invalid comparison between Unknown and I4
			if (request == null || !request.isDone)
			{
				return;
			}
			try
			{
				if ((int)request.result != 1)
				{
					Plugin.Log.LogError((object)("Could not decode " + clipName + ": " + request.error));
					return;
				}
				AudioClip content = DownloadHandlerAudioClip.GetContent(request);
				if ((Object)(object)content == (Object)null)
				{
					Plugin.Log.LogError((object)("Unity returned no clip while decoding " + clipName + "."));
					return;
				}
				float[] array = new float[content.samples * content.channels];
				if (!content.GetData(array, 0))
				{
					Plugin.Log.LogError((object)("Unity could not expose decoded PCM data for " + clipName + "."));
					return;
				}
				clip = AudioClip.Create(clipName, content.samples, content.channels, content.frequency, false);
				if (!clip.SetData(array, 0))
				{
					Object.Destroy((Object)(object)clip);
					clip = null;
					Plugin.Log.LogError((object)("Unity could not create a persistent PCM copy for " + clipName + "."));
				}
				else
				{
					((Object)clip).hideFlags = (HideFlags)61;
					Object.DontDestroyOnLoad((Object)(object)clip);
					Plugin.Log.LogInfo((object)$"Loaded embedded {clipName} ({clip.length:F1} seconds).");
				}
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"Could not finish loading {clipName}: {arg}");
			}
			finally
			{
				request.Dispose();
				request = null;
				DeleteTemporaryFile(ref temporaryPath);
			}
		}

		private static void DeleteTemporaryFile(ref string path)
		{
			if (string.IsNullOrEmpty(path))
			{
				return;
			}
			try
			{
				string directoryName = Path.GetDirectoryName(path);
				if (File.Exists(path))
				{
					File.Delete(path);
				}
				if (!string.IsNullOrEmpty(directoryName) && Directory.Exists(directoryName) && Directory.GetFileSystemEntries(directoryName).Length == 0)
				{
					Directory.Delete(directoryName);
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogDebug((object)("Temporary Slenderman audio file could not be removed yet: " + ex.Message));
			}
			finally
			{
				path = null;
			}
		}

		public void Dispose()
		{
			UnityWebRequest stareRequest = _stareRequest;
			if (stareRequest != null)
			{
				stareRequest.Dispose();
			}
			UnityWebRequest deathRequest = _deathRequest;
			if (deathRequest != null)
			{
				deathRequest.Dispose();
			}
			_stareRequest = null;
			_deathRequest = null;
			DeleteTemporaryFile(ref _stareTemporaryPath);
			DeleteTemporaryFile(ref _deathTemporaryPath);
			if ((Object)(object)_stareClip != (Object)null)
			{
				Object.Destroy((Object)(object)_stareClip);
				_stareClip = null;
			}
			if ((Object)(object)_deathClip != (Object)null)
			{
				Object.Destroy((Object)(object)_deathClip);
				_deathClip = null;
			}
		}
	}
	internal sealed class SlenderBootstrap
	{
		private float _nextRegistrationAttempt;

		private float _nextLevelRefresh;

		private float _nextAutomaticSpawnAttempt;

		private float _nextEnemyInitializationAttempt;

		private bool _registered;

		private int _roundSeed = int.MinValue;

		private bool _automaticSpawnHandled;

		private bool _invalidTestKeyReported;

		private bool _testKeyWasDown;

		internal void Tick()
		{
			TryRegisterBeforeNetworkingStarts();
			SlenderLethalEscapeCompatibility.TryInstall();
			InitializeSpawnedSlendermen();
			SlenderRuntime.TickAll();
			RefreshLevelSpawnLists();
			HandleGuaranteedRoundSpawn();
			HandlePageSpawn();
			HandleTestHotkey();
		}

		private void InitializeSpawnedSlendermen()
		{
			if (Time.unscaledTime < _nextEnemyInitializationAttempt)
			{
				return;
			}
			_nextEnemyInitializationAttempt = Time.unscaledTime + 0.25f;
			FlowermanAI[] array = Resources.FindObjectsOfTypeAll<FlowermanAI>();
			foreach (FlowermanAI val in array)
			{
				NetworkObject val2 = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponent<NetworkObject>() : null);
				if (!((Object)(object)val == (Object)null) && !((EnemyAI)val).isEnemyDead && !((Object)(object)val2 == (Object)null) && val2.IsSpawned && SlenderEnemyRegistry.IsSlendermanInstance((EnemyAI)(object)val))
				{
					SlenderRuntime.EnsureInitialized(val);
				}
			}
		}

		private void TryRegisterBeforeNetworkingStarts()
		{
			if (!_registered && !(Time.unscaledTime < _nextRegistrationAttempt))
			{
				_nextRegistrationAttempt = Time.unscaledTime + 0.5f;
				NetworkManager singleton = NetworkManager.Singleton;
				if (!((Object)(object)singleton == (Object)null))
				{
					_registered = SlenderEnemyRegistry.EnsureRegistered(singleton);
				}
			}
		}

		private void RefreshLevelSpawnLists()
		{
			if (!_registered || Time.unscaledTime < _nextLevelRefresh)
			{
				return;
			}
			_nextLevelRefresh = Time.unscaledTime + 2f;
			SelectableLevel[] array = StartOfRound.Instance?.levels;
			if (array != null)
			{
				for (int i = 0; i < array.Length; i++)
				{
					SlenderRuntime.AdjustSpawnList(array[i]);
				}
			}
		}

		private void HandleTestHotkey()
		{
			//IL_0134: Unknown result type (might be due to invalid IL or missing references)
			//IL_0139: Unknown result type (might be due to invalid IL or missing references)
			//IL_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0144: 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_0161: Unknown result type (might be due to invalid IL or missing references)
			//IL_0195: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
			if (!Plugin.EnableTestHotkey.Value || !WasTestKeyPressed())
			{
				return;
			}
			PlayerControllerB val = GameNetworkManager.Instance?.localPlayerController;
			NetworkManager singleton = NetworkManager.Singleton;
			RoundManager instance = RoundManager.Instance;
			if (!_registered && (Object)(object)singleton != (Object)null)
			{
				_registered = SlenderEnemyRegistry.EnsureRegistered(singleton);
			}
			if (!_registered || (Object)(object)SlenderEnemyRegistry.SlenderEnemyType == (Object)null)
			{
				ShowTip("SLENDERMAN-TEST", "Slenderman wurde noch nicht registriert. Spiel bitte neu starten.", warning: true);
				return;
			}
			if ((Object)(object)singleton == (Object)null || !singleton.IsServer)
			{
				ShowTip("SLENDERMAN-TEST", "Nur der Host kann den Testgegner erzeugen.", warning: true);
				return;
			}
			if ((Object)(object)val == (Object)null || (Object)(object)instance == (Object)null || (Object)(object)StartOfRound.Instance == (Object)null || StartOfRound.Instance.inShipPhase || !instance.dungeonFinishedGeneratingForAllPlayers)
			{
				ShowTip("SLENDERMAN-TEST", "Zuerst landen und warten, bis die Anlage fertig geladen ist.", warning: true);
				return;
			}
			try
			{
				SlenderPageSystem.ForceAwakeForTesting();
				SlenderMarker slenderMarker = FindLivingSlenderman(instance);
				if ((Object)(object)slenderMarker != (Object)null)
				{
					slenderMarker.ForceAppearanceForTest(val);
					ShowTip("SLENDERMAN-TEST", "Der vorhandene Slenderman erscheint jetzt hinter dir.", warning: false);
					Plugin.Log.LogInfo((object)$"F7 forced existing Slenderman network object {((NetworkBehaviour)slenderMarker.Ai).NetworkObjectId} to appear behind the host.");
				}
				else
				{
					Vector3 val2 = FindSpawnPosition(instance, val);
					NetworkObjectReference reference = instance.SpawnEnemyGameObject(val2, ((Component)val).transform.eulerAngles.y + 180f, 0, SlenderEnemyRegistry.SlenderEnemyType);
					InitializeSpawnedReference(reference, "F7")?.ForceAppearanceForTest(val);
					ShowTip("SLENDERMAN-TEST", "Slenderman erscheint jetzt hinter dir.", warning: false);
					Plugin.Log.LogInfo((object)$"Test Slenderman spawned at {val2} using {Plugin.TestSpawnKey.Value}.");
				}
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"Test spawn failed: {arg}");
				ShowTip("SLENDERMAN-TEST", "Erzeugen fehlgeschlagen. Bitte LogOutput.log prüfen.", warning: true);
			}
		}

		private bool WasTestKeyPressed()
		{
			//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_0037: 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)
			Keyboard current = Keyboard.current;
			if (current == null)
			{
				_testKeyWasDown = false;
				return false;
			}
			string text = ((object)Plugin.TestSpawnKey.Value/*cast due to .constrained prefix*/).ToString();
			if (Enum.TryParse<Key>(text, ignoreCase: true, out Key result) && (int)result != 0)
			{
				bool isPressed = ((ButtonControl)current[result]).isPressed;
				bool result2 = isPressed && !_testKeyWasDown;
				_testKeyWasDown = isPressed;
				return result2;
			}
			if (!_invalidTestKeyReported)
			{
				_invalidTestKeyReported = true;
				Plugin.Log.LogWarning((object)("Test key '" + text + "' is not supported by the active input system; using F7."));
			}
			bool isPressed2 = ((ButtonControl)current.f7Key).isPressed;
			bool result3 = isPressed2 && !_testKeyWasDown;
			_testKeyWasDown = isPressed2;
			return result3;
		}

		private void HandleGuaranteedRoundSpawn()
		{
			//IL_015e: 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_0166: 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_0182: 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_01ba: Unknown result type (might be due to invalid IL or missing references)
			StartOfRound instance = StartOfRound.Instance;
			RoundManager instance2 = RoundManager.Instance;
			NetworkManager singleton = NetworkManager.Singleton;
			if ((Object)(object)instance == (Object)null || (Object)(object)instance2 == (Object)null || (Object)(object)singleton == (Object)null || !singleton.IsServer || instance.inShipPhase)
			{
				_automaticSpawnHandled = false;
				return;
			}
			if (_roundSeed != instance.randomMapSeed)
			{
				_roundSeed = instance.randomMapSeed;
				_automaticSpawnHandled = false;
				SlenderPageSystem.ResetRound();
			}
			if (_automaticSpawnHandled || Time.unscaledTime < _nextAutomaticSpawnAttempt || !instance2.dungeonFinishedGeneratingForAllPlayers || instance2.insideAINodes == null || instance2.insideAINodes.Length == 0)
			{
				return;
			}
			_nextAutomaticSpawnAttempt = Time.unscaledTime + 1f;
			if (!_registered)
			{
				_registered = SlenderEnemyRegistry.EnsureRegistered(singleton);
			}
			if (!_registered || (Object)(object)SlenderEnemyRegistry.SlenderEnemyType == (Object)null)
			{
				Plugin.Log.LogError((object)"Guaranteed Slenderman spawn was skipped because registration was unavailable.");
				return;
			}
			_automaticSpawnHandled = true;
			int num = Mathf.Clamp(Plugin.GuaranteedSpawnChance.Value, 0, 100);
			int num2 = new Random(instance.randomMapSeed ^ 0x51EAD3).Next(0, 100);
			Plugin.Log.LogInfo((object)$"Guaranteed Slenderman spawn roll: {num2 + 1}/100 with configured chance {num}%.");
			if (num2 >= num || CountLivingSlendermen(instance2) >= Mathf.Clamp(Plugin.MaxSlendermen.Value, 1, 5))
			{
				return;
			}
			try
			{
				Vector3 val = FindSpawnPosition(instance2, null);
				NetworkObjectReference reference = instance2.SpawnEnemyGameObject(val, Random.Range(0f, 360f), 0, SlenderEnemyRegistry.SlenderEnemyType);
				InitializeSpawnedReference(reference, "automatic spawn");
				SlenderEnemyRegistry.SlenderEnemyType.numberSpawned = Mathf.Max(SlenderEnemyRegistry.SlenderEnemyType.numberSpawned, CountLivingSlendermen(instance2));
				Plugin.Log.LogInfo((object)$"Automatically spawned Slenderman at {val}.");
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"Guaranteed Slenderman spawn failed: {arg}");
			}
		}

		private void HandlePageSpawn()
		{
			StartOfRound instance = StartOfRound.Instance;
			RoundManager instance2 = RoundManager.Instance;
			NetworkManager singleton = NetworkManager.Singleton;
			if (!((Object)(object)instance == (Object)null) && !((Object)(object)instance2 == (Object)null) && !((Object)(object)singleton == (Object)null) && singleton.IsServer && !instance.inShipPhase && instance2.dungeonFinishedGeneratingForAllPlayers && !SlenderPageSystem.PagesSpawned)
			{
				if (!_registered)
				{
					_registered = SlenderEnemyRegistry.EnsureRegistered(singleton);
				}
				if (_registered)
				{
					SlenderPageSystem.SpawnPages(instance2);
				}
			}
		}

		private static int CountLivingSlendermen(RoundManager round)
		{
			int num = 0;
			for (int i = 0; i < round.SpawnedEnemies.Count; i++)
			{
				EnemyAI val = round.SpawnedEnemies[i];
				if ((Object)(object)val != (Object)null && !val.isEnemyDead && SlenderEnemyRegistry.IsSlendermanInstance(val))
				{
					num++;
				}
			}
			return num;
		}

		private static SlenderMarker FindLivingSlenderman(RoundManager round)
		{
			if ((Object)(object)round == (Object)null || round.SpawnedEnemies == null)
			{
				return null;
			}
			for (int i = 0; i < round.SpawnedEnemies.Count; i++)
			{
				EnemyAI obj = round.SpawnedEnemies[i];
				FlowermanAI val = (FlowermanAI)(object)((obj is FlowermanAI) ? obj : null);
				if ((Object)(object)val != (Object)null && !((EnemyAI)val).isEnemyDead && SlenderEnemyRegistry.IsSlendermanInstance((EnemyAI)(object)val))
				{
					return SlenderRuntime.ForceInitialize(val);
				}
			}
			return null;
		}

		private static SlenderMarker InitializeSpawnedReference(NetworkObjectReference reference, string source)
		{
			NetworkObject val = default(NetworkObject);
			if (!((NetworkObjectReference)(ref reference)).TryGet(ref val, (NetworkManager)null) || (Object)(object)val == (Object)null)
			{
				Plugin.Log.LogWarning((object)("Could not resolve the Slenderman network object immediately after " + source + "; the runtime scan will retry."));
				return null;
			}
			FlowermanAI val2 = ((Component)val).GetComponent<FlowermanAI>() ?? ((Component)val).GetComponentInParent<FlowermanAI>() ?? ((Component)val).GetComponentInChildren<FlowermanAI>(true);
			if ((Object)(object)val2 == (Object)null)
			{
				Plugin.Log.LogError((object)("The network object created by " + source + " did not contain a FlowermanAI component."));
				return null;
			}
			SlenderMarker result = SlenderRuntime.ForceInitialize(val2);
			Plugin.Log.LogInfo((object)$"Directly initialized the Slenderman network object {val.NetworkObjectId} after {source}.");
			return result;
		}

		private static Vector3 FindSpawnPosition(RoundManager round, PlayerControllerB player)
		{
			//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_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_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_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: 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_008b: 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)
			Vector3 val2;
			if ((Object)(object)player != (Object)null && player.isInsideFactory)
			{
				Vector3 val = Vector3.ProjectOnPlane(((Component)player).transform.forward, Vector3.up);
				Vector3 normalized = ((Vector3)(ref val)).normalized;
				val2 = ((Component)player).transform.position + normalized * 8f;
			}
			else
			{
				GameObject[] insideAINodes = round.insideAINodes;
				if (insideAINodes == null || insideAINodes.Length == 0)
				{
					throw new InvalidOperationException("No indoor AI nodes were available.");
				}
				val2 = insideAINodes[Random.Range(0, insideAINodes.Length)].transform.position;
			}
			return round.GetRandomNavMeshPositionInRadius(val2, 5f, default(NavMeshHit));
		}

		private static void ShowTip(string title, string message, bool warning)
		{
			if ((Object)(object)HUDManager.Instance != (Object)null)
			{
				HUDManager.Instance.DisplayTip(title, message, warning, false, "LC_Tip1");
			}
		}
	}
	internal static class SlenderCriticalPatches
	{
		private static readonly MethodInfo NetworkPrefix = AccessTools.Method(typeof(SlenderCriticalPatches), "BeforeNetworkStart", (Type[])null, (Type[])null);

		private static readonly MethodInfo GameHostPrefix = AccessTools.Method(typeof(SlenderCriticalPatches), "BeforeGameHostStart", (Type[])null, (Type[])null);

		private static readonly MethodInfo RuntimePostfix = AccessTools.Method(typeof(SlenderCriticalPatches), "AfterGameFrame", (Type[])null, (Type[])null);

		internal static void Install(Harmony harmony)
		{
			PatchPrefix(harmony, AccessTools.Method(typeof(GameNetworkManager), "StartHost", (Type[])null, (Type[])null), GameHostPrefix);
			PatchPrefix(harmony, AccessTools.Method(typeof(NetworkManager), "StartHost", (Type[])null, (Type[])null), NetworkPrefix);
			PatchPrefix(harmony, AccessTools.Method(typeof(NetworkManager), "StartClient", (Type[])null, (Type[])null), NetworkPrefix);
			PatchPrefix(harmony, AccessTools.Method(typeof(NetworkManager), "StartServer", (Type[])null, (Type[])null), NetworkPrefix);
			PatchPostfix(harmony, AccessTools.Method(typeof(MenuManager), "Update", (Type[])null, (Type[])null), RuntimePostfix);
			PatchPostfix(harmony, AccessTools.Method(typeof(StartOfRound), "Update", (Type[])null, (Type[])null), RuntimePostfix);
			PatchPostfix(harmony, AccessTools.Method(typeof(RoundManager), "Update", (Type[])null, (Type[])null), RuntimePostfix);
		}

		private static void PatchPostfix(Harmony harmony, MethodInfo original, MethodInfo postfix)
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Expected O, but got Unknown
			if (original == null || postfix == null)
			{
				Plugin.Log.LogError((object)"A required Slenderman runtime patch method could not be found.");
				return;
			}
			if (!HasOwnedPostfix(original))
			{
				harmony.Patch((MethodBase)original, (HarmonyMethod)null, new HarmonyMethod(postfix), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
			Plugin.Log.LogInfo((object)$"Verified runtime hook on {original.DeclaringType?.Name}.{original.Name}: {HasOwnedPostfix(original)}.");
		}

		private static void PatchPrefix(Harmony harmony, MethodInfo original, MethodInfo prefix)
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Expected O, but got Unknown
			if (original == null || prefix == null)
			{
				Plugin.Log.LogError((object)"A required Slenderman startup patch method could not be found.");
				return;
			}
			if (!HasOwnedPrefix(original))
			{
				harmony.Patch((MethodBase)original, new HarmonyMethod(prefix), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
			Plugin.Log.LogInfo((object)$"Verified early registration hook on {original.DeclaringType?.Name}.{original.Name}: {HasOwnedPrefix(original)}.");
		}

		private static bool HasOwnedPrefix(MethodBase original)
		{
			Patches patchInfo = Harmony.GetPatchInfo(original);
			if (patchInfo == null)
			{
				return false;
			}
			for (int i = 0; i < patchInfo.Prefixes.Count; i++)
			{
				if (string.Equals(patchInfo.Prefixes[i].owner, "tonys.lethalcompany.slenderman", StringComparison.Ordinal))
				{
					return true;
				}
			}
			return false;
		}

		private static bool HasOwnedPostfix(MethodBase original)
		{
			Patches patchInfo = Harmony.GetPatchInfo(original);
			if (patchInfo == null)
			{
				return false;
			}
			for (int i = 0; i < patchInfo.Postfixes.Count; i++)
			{
				if (string.Equals(patchInfo.Postfixes[i].owner, "tonys.lethalcompany.slenderman", StringComparison.Ordinal))
				{
					return true;
				}
			}
			return false;
		}

		private static void AfterGameFrame()
		{
			Plugin.TickRuntime();
		}

		private static void BeforeGameHostStart()
		{
			TryRegister(NetworkManager.Singleton, "game host");
		}

		private static void BeforeNetworkStart(NetworkManager __instance, MethodBase __originalMethod)
		{
			TryRegister(__instance, __originalMethod?.Name ?? "network");
		}

		private static void TryRegister(NetworkManager manager, string source)
		{
			Plugin.Log.LogInfo((object)("Preparing Slenderman before " + source + " startup."));
			if (!SlenderEnemyRegistry.EnsureRegistered(manager))
			{
				Plugin.Log.LogError((object)("Slenderman could not be registered before " + source + " startup."));
			}
		}
	}
	internal static class SlenderEnemyRegistry
	{
		private const uint SlendermanPrefabHash = 2051879369u;

		private const uint SlenderPagePrefabHash = 2051879370u;

		private static readonly FieldInfo GlobalHashField = AccessTools.Field(typeof(NetworkObject), "GlobalObjectIdHash");

		private static readonly FieldInfo PrefabHashField = AccessTools.Field(typeof(NetworkObject), "PrefabGlobalObjectIdHash");

		private static NetworkManager _registeredManager;

		internal static EnemyType SlenderEnemyType { get; private set; }

		internal static GameObject SlendermanPrefab { get; private set; }

		internal static Item PageItem { get; private set; }

		internal static GameObject PagePrefab { get; private set; }

		internal static bool IsSlendermanInstance(EnemyAI ai)
		{
			if ((Object)(object)ai == (Object)null)
			{
				return false;
			}
			if ((Object)(object)((Component)ai).GetComponent<SlenderMarker>() != (Object)null || (Object)(object)((Component)ai).GetComponent<SlenderIdentity>() != (Object)null)
			{
				return true;
			}
			if ((Object)(object)SlenderEnemyType != (Object)null && (Object)(object)ai.enemyType == (Object)(object)SlenderEnemyType)
			{
				return true;
			}
			if ((Object)(object)ai.enemyType != (Object)null && string.Equals(ai.enemyType.enemyName, "Slenderman", StringComparison.OrdinalIgnoreCase))
			{
				return true;
			}
			NetworkObject component = ((Component)ai).GetComponent<NetworkObject>();
			if ((Object)(object)component != (Object)null && component.PrefabIdHash == 2051879369)
			{
				return true;
			}
			return ((Object)((Component)ai).gameObject).name.StartsWith("SlendermanEnemyPrefab", StringComparison.OrdinalIgnoreCase);
		}

		internal static bool EnsureRegistered(NetworkManager manager = null)
		{
			if (manager == null)
			{
				manager = NetworkManager.Singleton;
			}
			if ((Object)(object)manager == (Object)null || manager.NetworkConfig?.Prefabs == null)
			{
				Plugin.Log.LogWarning((object)"NetworkManager was not ready; Slenderman registration will be retried.");
				return false;
			}
			if ((Object)(object)SlendermanPrefab == (Object)null && !BuildRuntimePrefabs(manager))
			{
				return false;
			}
			if ((Object)(object)_registeredManager == (Object)(object)manager)
			{
				return true;
			}
			try
			{
				RegisterPrefab(manager, SlendermanPrefab, 2051879369u);
				RegisterPrefab(manager, PagePrefab, 2051879370u);
				_registeredManager = manager;
				Plugin.Log.LogInfo((object)"Registered separate Slenderman enemy and Slender page network prefabs.");
				return true;
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"Could not register Slenderman network prefabs: {arg}");
				return false;
			}
		}

		private static bool BuildRuntimePrefabs(NetworkManager manager)
		{
			GameObject val = FindFlowermanPrefab(manager);
			if ((Object)(object)val == (Object)null)
			{
				Plugin.Log.LogError((object)"Could not find the vanilla Flowerman prefab. Slenderman cannot be created.");
				return false;
			}
			FlowermanAI component = val.GetComponent<FlowermanAI>();
			if ((Object)(object)component == (Object)null || (Object)(object)((EnemyAI)component).enemyType == (Object)null)
			{
				Plugin.Log.LogError((object)"The vanilla Flowerman prefab did not contain a valid enemy type.");
				return false;
			}
			SlenderEnemyType = Object.Instantiate<EnemyType>(((EnemyAI)component).enemyType);
			((Object)SlenderEnemyType).name = "SlendermanEnemyType";
			SlenderEnemyType.enemyName = "Slenderman";
			SlenderEnemyType.numberSpawned = 0;
			SlenderEnemyType.nestsSpawned = 0;
			SlenderEnemyType.hasSpawnedAtLeastOne = false;
			SlenderEnemyType.MaxCount = Mathf.Clamp(Plugin.MaxSlendermen.Value, 1, 5);
			SlenderEnemyType.canBeStunned = false;
			SlenderEnemyType.canDie = !Plugin.Invulnerable.Value;
			Object.DontDestroyOnLoad((Object)(object)SlenderEnemyType);
			SlendermanPrefab = CloneInactivePrefab(val, "SlendermanEnemyPrefab");
			FlowermanAI component2 = SlendermanPrefab.GetComponent<FlowermanAI>();
			((EnemyAI)component2).enemyType = SlenderEnemyType;
			SlendermanPrefab.AddComponent<SlenderIdentity>();
			SetNetworkHash(SlendermanPrefab, 2051879369u);
			SlenderEnemyType.enemyPrefab = SlendermanPrefab;
			GameObject val2 = FindPageShell(manager);
			if ((Object)(object)val2 == (Object)null)
			{
				Plugin.Log.LogError((object)"Could not find a vanilla scrap prefab to use for Slender pages.");
				return false;
			}
			GrabbableObject component3 = val2.GetComponent<GrabbableObject>();
			PageItem = Object.Instantiate<Item>(component3.itemProperties);
			((Object)PageItem).name = "SlenderPageItem";
			PageItem.itemName = "Slender-Kritzelzettel";
			PageItem.itemId = 2051879370;
			PageItem.isScrap = true;
			PageItem.creditsWorth = Plugin.PageValue.Value;
			PageItem.minValue = Plugin.PageValue.Value;
			PageItem.maxValue = Plugin.PageValue.Value + 1;
			PageItem.twoHanded = false;
			PageItem.weight = 1.02f;
			PageItem.toolTips = Array.Empty<string>();
			Object.DontDestroyOnLoad((Object)(object)PageItem);
			PagePrefab = CloneInactivePrefab(val2, "SlenderPagePrefab");
			GrabbableObject component4 = PagePrefab.GetComponent<GrabbableObject>();
			component4.itemProperties = PageItem;
			component4.scrapValue = Plugin.PageValue.Value;
			PagePrefab.AddComponent<SlenderPageIdentity>();
			SetNetworkHash(PagePrefab, 2051879370u);
			PageItem.spawnPrefab = PagePrefab;
			return true;
		}

		private static GameObject FindFlowermanPrefab(NetworkManager manager)
		{
			IReadOnlyList<NetworkPrefab> prefabs = manager.NetworkConfig.Prefabs.Prefabs;
			GameObject val = null;
			for (int i = 0; i < prefabs.Count; i++)
			{
				GameObject val2 = prefabs[i]?.Prefab;
				FlowermanAI val3 = (((Object)(object)val2 != (Object)null) ? val2.GetComponent<FlowermanAI>() : null);
				if (!((Object)(object)val3 == (Object)null) && !((Object)(object)val2.GetComponent<NetworkObject>() == (Object)null))
				{
					if (val == null)
					{
						val = val2;
					}
					string a = (((Object)(object)((EnemyAI)val3).enemyType != (Object)null) ? ((EnemyAI)val3).enemyType.enemyName : string.Empty);
					if (string.Equals(a, "Flowerman", StringComparison.OrdinalIgnoreCase))
					{
						return val2;
					}
				}
			}
			return val;
		}

		private static GameObject FindPageShell(NetworkManager manager)
		{
			IReadOnlyList<NetworkPrefab> prefabs = manager.NetworkConfig.Prefabs.Prefabs;
			GameObject val = null;
			for (int i = 0; i < prefabs.Count; i++)
			{
				GameObject val2 = prefabs[i]?.Prefab;
				GrabbableObject val3 = (((Object)(object)val2 != (Object)null) ? val2.GetComponent<GrabbableObject>() : null);
				Item val4 = (((Object)(object)val3 != (Object)null) ? val3.itemProperties : null);
				if (!((Object)(object)val4 == (Object)null) && val4.isScrap && !val4.twoHanded && !((Object)(object)val2.GetComponent<NetworkObject>() == (Object)null))
				{
					if ((Object)(object)val == (Object)null && ((object)val3).GetType().Name == "PhysicsProp")
					{
						val = val2;
					}
					string text = val4.itemName ?? string.Empty;
					if (text.IndexOf("big bolt", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("large axle", StringComparison.OrdinalIgnoreCase) >= 0)
					{
						return val2;
					}
				}
			}
			return val;
		}

		private static GameObject CloneInactivePrefab(GameObject source, string name)
		{
			bool activeSelf = source.activeSelf;
			if (activeSelf)
			{
				source.SetActive(false);
			}
			GameObject val = Object.Instantiate<GameObject>(source);
			if (activeSelf)
			{
				source.SetActive(true);
			}
			((Object)val).name = name;
			val.SetActive(false);
			Object.DontDestroyOnLoad((Object)(object)val);
			return val;
		}

		private static void SetNetworkHash(GameObject prefab, uint hash)
		{
			NetworkObject component = prefab.GetComponent<NetworkObject>();
			if ((Object)(object)component == (Object)null || GlobalHashField == null || PrefabHashField == null)
			{
				throw new InvalidOperationException("Network hash fields were unavailable for " + ((Object)prefab).name + ".");
			}
			GlobalHashField.SetValue(component, hash);
			PrefabHashField.SetValue(component, hash);
		}

		private static void RegisterPrefab(NetworkManager manager, GameObject prefab, uint expectedHash)
		{
			IReadOnlyList<NetworkPrefab> prefabs = manager.NetworkConfig.Prefabs.Prefabs;
			for (int i = 0; i < prefabs.Count; i++)
			{
				GameObject val = prefabs[i]?.Prefab;
				NetworkObject val2 = (((Object)(object)val != (Object)null) ? val.GetComponent<NetworkObject>() : null);
				if (!((Object)(object)val2 == (Object)null) && val2.PrefabIdHash == expectedHash)
				{
					if ((Object)(object)val != (Object)(object)prefab)
					{
						throw new InvalidOperationException($"Network prefab hash collision: 0x{expectedHash:X8}.");
					}
					return;
				}
			}
			manager.AddNetworkPrefab(prefab);
		}
	}
	internal sealed class SlenderIdentity : MonoBehaviour
	{
	}
	internal sealed class SlenderPageIdentity : MonoBehaviour
	{
		private void Start()
		{
			SlenderPageSystem.PreparePage(((Component)this).gameObject);
		}
	}
	internal static class SlenderLethalEscapeCompatibility
	{
		private const string HarmonyId = "tonys.lethalcompany.slenderman.lethalescape.compatibility";

		private static readonly MethodInfo FlowermanGuard = AccessTools.Method(typeof(SlenderLethalEscapeCompatibility), "AllowFlowermanPatch", (Type[])null, (Type[])null);

		private static readonly MethodInfo EnemyGuard = AccessTools.Method(typeof(SlenderLethalEscapeCompatibility), "AllowEnemyTransfer", (Type[])null, (Type[])null);

		private static bool _installed;

		private static float _nextAttempt;

		internal static void TryInstall()
		{
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Expected O, but got Unknown
			if (!_installed && !(Time.unscaledTime < _nextAttempt))
			{
				_nextAttempt = Time.unscaledTime + 1f;
				Type type = AccessTools.TypeByName("UpdatedEscape.Plugin");
				if (!(type == null))
				{
					Harmony harmony = new Harmony("tonys.lethalcompany.slenderman.lethalescape.compatibility");
					int num = 0;
					num += PatchGuard(harmony, type, "DoAIInterval_BrackenCarryBodyFix", FlowermanGuard);
					num += PatchGuard(harmony, type, "FlowermanAILEPrefixAI", FlowermanGuard);
					num += PatchGuard(harmony, type, "FlowerManAILEOutsideAttack", FlowermanGuard);
					num += PatchGuard(harmony, type, "FlowermanAILEPostfixStart", FlowermanGuard);
					num += PatchGuard(harmony, type, "SendEnemyInside", EnemyGuard);
					num += PatchGuard(harmony, type, "SendEnemyOutside", EnemyGuard);
					_installed = true;
					Plugin.Log.LogInfo((object)$"Lethal Escape compatibility active: guarded {num} transfer/Bracken patch method(s); normal Brackens and all other enemies remain unchanged.");
				}
			}
		}

		private static int PatchGuard(Harmony harmony, Type pluginType, string methodName, MethodInfo prefix)
		{
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Expected O, but got Unknown
			MethodInfo methodInfo = AccessTools.Method(pluginType, methodName, (Type[])null, (Type[])null);
			if (methodInfo == null || prefix == null)
			{
				Plugin.Log.LogWarning((object)("Lethal Escape compatibility could not find " + pluginType.FullName + "." + methodName + "."));
				return 0;
			}
			Patches patchInfo = Harmony.GetPatchInfo((MethodBase)methodInfo);
			if (patchInfo != null)
			{
				for (int i = 0; i < patchInfo.Prefixes.Count; i++)
				{
					if (string.Equals(patchInfo.Prefixes[i].owner, "tonys.lethalcompany.slenderman.lethalescape.compatibility", StringComparison.Ordinal))
					{
						return 1;
					}
				}
			}
			harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(prefix), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			return 1;
		}

		private static bool AllowFlowermanPatch(FlowermanAI __0)
		{
			return !SlenderEnemyRegistry.IsSlendermanInstance((EnemyAI)(object)__0);
		}

		private static bool AllowEnemyTransfer(EnemyAI __0)
		{
			return !SlenderEnemyRegistry.IsSlendermanInstance(__0);
		}
	}
	internal sealed class SlendermanRuntimeRunner : IDisposable
	{
		private SlenderBootstrap _bootstrap;

		private SlenderScreenEffect _screenEffect;

		private SlenderPageWatcher _pageWatcher;

		private bool _initialized;

		private bool _runtimeTickConfirmed;

		private bool _runtimeContinuationConfirmed;

		private int _firstTickFrame = -1;

		private int _lastTickFrame = -1;

		private float _nextRuntimeErrorLog;

		internal void Initialize()
		{
			if (!_initialized)
			{
				_initialized = true;
				_bootstrap = new SlenderBootstrap();
				_screenEffect = new SlenderScreenEffect();
				_pageWatcher = new SlenderPageWatcher();
				Plugin.Log.LogInfo((object)"Harmony-driven Slenderman runtime initialized.");
				RegisterAnyExistingNetworkManager();
				TickFrame();
			}
		}

		internal void TickFrame()
		{
			if (_initialized && _lastTickFrame != Time.frameCount)
			{
				_lastTickFrame = Time.frameCount;
				if (!_runtimeTickConfirmed)
				{
					_runtimeTickConfirmed = true;
					_firstTickFrame = Time.frameCount;
					Plugin.Log.LogInfo((object)$"Slenderman event runtime tick started at frame {_firstTickFrame}.");
				}
				else if (!_runtimeContinuationConfirmed && Time.frameCount != _firstTickFrame)
				{
					_runtimeContinuationConfirmed = true;
					Plugin.Log.LogInfo((object)$"Slenderman event runtime continued on frame {Time.frameCount}.");
				}
				RunSafely(_bootstrap.Tick, "bootstrap");
				RunSafely(_screenEffect.Tick, "screen effect");
				RunSafely(_pageWatcher.Tick, "page watcher");
			}
		}

		public void Dispose()
		{
			if (_initialized)
			{
				_initialized = false;
				_screenEffect?.Dispose();
			}
		}

		private void RegisterAnyExistingNetworkManager()
		{
			NetworkManager[] array = Resources.FindObjectsOfTypeAll<NetworkManager>();
			Plugin.Log.LogInfo((object)$"Found {array.Length} NetworkManager object(s) during runtime initialization.");
			foreach (NetworkManager val in array)
			{
				if ((Object)(object)val != (Object)null && val.NetworkConfig?.Prefabs != null && SlenderEnemyRegistry.EnsureRegistered(val))
				{
					break;
				}
			}
		}

		private void RunSafely(Action action, string operation)
		{
			try
			{
				action();
			}
			catch (Exception arg)
			{
				if (Time.unscaledTime >= _nextRuntimeErrorLog)
				{
					_nextRuntimeErrorLog = Time.unscaledTime + 2f;
					Plugin.Log.LogError((object)$"Slenderman {operation} failed: {arg}");
				}
			}
		}
	}
	internal sealed class SlenderMarker : MonoBehaviour
	{
		private readonly List<Renderer> _originalRenderers = new List<Renderer>();

		private readonly List<Renderer> _slenderRenderers = new List<Renderer>();

		private Transform[] _tentacles = Array.Empty<Transform>();

		private Vector3 _previousPosition;

		private float _manifestedAt;

		private float _visibleUntil;

		private float _nextAppearanceAt;

		private float _nextContactDamageAt;

		private float _nextAiDecisionAt;

		private float _walkPhase;

		private Random _stalkRandom;

		private PlayerControllerB _stalkTarget;

		private bool _isManifested;

		private bool _wasObservedThisAppearance;

		private bool _initialized;

		private bool _ownerAiConfirmed;

		internal FlowermanAI Ai { get; private set; }

		internal Vector3 LookTarget => ((Component)this).transform.position + ((Component)this).transform.up * 3.05f;

		internal bool IsManifested => _isManifested;

		internal void Initialize(FlowermanAI ai)
		{
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			if (!_initialized && !((Object)(object)ai == (Object)null))
			{
				_initialized = true;
				Ai = ai;
				_stalkRandom = new Random((int)(((NetworkBehaviour)ai).NetworkObjectId ^ 0x51E7D3A1));
				_previousPosition = ((Component)this).transform.position;
				_nextAppearanceAt = Time.realtimeSinceStartup + (SlenderPageSystem.IsSlendermanAwake ? 0.8f : Mathf.Min(10f, GetAppearanceInterval() * 0.45f));
				Renderer[] componentsInChildren = ((Component)ai).GetComponentsInChildren<Renderer>(true);
				for (int i = 0; i < componentsInChildren.Length; i++)
				{
					_originalRenderers.Add(componentsInChildren[i]);
					componentsInChildren[i].enabled = false;
				}
				SlenderVisualFactory.CreateSlenderman(((Component)this).transform, ((Component)this).gameObject.layer, _slenderRenderers, out _tentacles);
				ScanNodeProperties[] componentsInChildren2 = ((Component)ai).GetComponentsInChildren<ScanNodeProperties>(true);
				for (int j = 0; j < componentsInChildren2.Length; j++)
				{
					componentsInChildren2[j].headerText = "SLENDERMAN";
					componentsInChildren2[j].subText = "NICHT ANSEHEN";
				}
				((EnemyAI)ai).currentBehaviourStateIndex = 0;
				((EnemyAI)ai).movingTowardsTargetPlayer = false;
				((EnemyAI)ai).enemyHP = 9999;
				_isManifested = false;
				StopAgent();
				ForceRendererState();
				SilenceVanillaAudio();
				SlenderRuntime.Register(this);
				Plugin.Log.LogInfo((object)$"Separate stalking Slenderman network object {((NetworkBehaviour)ai).NetworkObjectId} initialized.");
			}
		}

		internal void BeforeVanillaUpdate()
		{
			if ((Object)(object)Ai == (Object)null)
			{
				return;
			}
			int currentBehaviourStateIndex = ((EnemyAI)Ai).currentBehaviourStateIndex;
			_isManifested = currentBehaviourStateIndex != 0;
			if (_isManifested)
			{
				bool flag = currentBehaviourStateIndex == 2;
				if (((EnemyAI)Ai).isOutside != flag)
				{
					((EnemyAI)Ai).SetEnemyOutside(flag);
				}
			}
			Ai.inKillAnimation = false;
			Ai.isInAngerMode = false;
			((EnemyAI)Ai).movingTowardsTargetPlayer = false;
			StopAgent();
			SilenceVanillaAudio();
		}

		internal void AfterVanillaUpdate()
		{
			//IL_0074: 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_0089: 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_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)Ai == (Object)null || ((EnemyAI)Ai).isEnemyDead)
			{
				return;
			}
			_isManifested = ((EnemyAI)Ai).currentBehaviourStateIndex != 0;
			PlayerControllerB observer = null;
			bool observed = _isManifested && SlenderRuntime.IsObservedByAnyPlayer(this, out observer);
			StopAgent();
			if (_isManifested)
			{
				PlayerControllerB val = observer ?? ((EnemyAI)Ai).targetPlayer;
				if ((Object)(object)val != (Object)null)
				{
					Vector3 val2 = ((Component)val).transform.position - ((Component)this).transform.position;
					val2.y = 0f;
					if (((Vector3)(ref val2)).sqrMagnitude > 0.01f)
					{
						((Component)this).transform.rotation = Quaternion.Slerp(((Component)this).transform.rotation, Quaternion.LookRotation(val2), Time.deltaTime * 5f);
					}
				}
			}
			AnimateVisual(observed);
			ForceRendererState();
			SilenceVanillaAudio();
		}

		internal void RunAIInterval()
		{
			NetworkManager singleton = NetworkManager.Singleton;
			if ((Object)(object)Ai == (Object)null || (Object)(object)singleton == (Object)null || !singleton.IsServer || ((EnemyAI)Ai).isEnemyDead || (Object)(object)StartOfRound.Instance == (Object)null || Time.unscaledTime < _nextAiDecisionAt)
			{
				return;
			}
			_nextAiDecisionAt = Time.unscaledTime + 0.1f;
			if (!_ownerAiConfirmed)
			{
				_ownerAiConfirmed = true;
				Plugin.Log.LogInfo((object)$"Stalking AI is active for Slenderman network object {((NetworkBehaviour)Ai).NetworkObjectId}; awake={SlenderPageSystem.IsSlendermanAwake}.");
			}
			if (!SlenderPageSystem.IsSlendermanAwake)
			{
				if (_isManifested)
				{
					SetManifested(manifested: false, ((EnemyAI)Ai).isOutside);
				}
				StopAgent();
				return;
			}
			PlayerControllerB val = ((_isManifested && IsValidTarget(_stalkTarget)) ? _stalkTarget : SelectStalkingTarget());
			if ((Object)(object)val == (Object)null)
			{
				SetManifested(manifested: false, ((EnemyAI)Ai).isOutside);
				StopAgent();
				return;
			}
			((EnemyAI)Ai).targetPlayer = val;
			((EnemyAI)Ai).movingTowardsTargetPlayer = false;
			StopAgent();
			float realtimeSinceStartup = Time.realtimeSinceStartup;
			if (!_isManifested)
			{
				if (realtimeSinceStartup >= _nextAppearanceAt)
				{
					AppearBehindTarget(val);
				}
				return;
			}
			if (SlenderRuntime.IsObservedByAnyPlayer(this, out var _))
			{
				_wasObservedThisAppearance = true;
				return;
			}
			bool flag = SlenderRuntime.IsWithinAnyPlayerView(this, 58f);
			bool flag2 = _wasObservedThisAppearance && realtimeSinceStartup >= _manifestedAt + 0.75f;
			bool flag3 = realtimeSinceStartup >= _visibleUntil && !flag;
			if (flag2 || flag3)
			{
				HideAndScheduleNext(val);
			}
		}

		internal void ForceAppearanceForTest(PlayerControllerB target)
		{
			if (!((Object)(object)Ai == (Object)null) && !((EnemyAI)Ai).isEnemyDead && IsValidTarget(target) && !((Object)(object)NetworkManager.Singleton == (Object)null) && NetworkManager.Singleton.IsServer)
			{
				_nextAppearanceAt = Time.realtimeSinceStartup;
				AppearBehindTarget(target);
			}
		}

		internal void RuntimeTick()
		{
			if (!((Object)(object)Ai == (Object)null) && !((EnemyAI)Ai).isEnemyDead)
			{
				BeforeVanillaUpdate();
				RunAIInterval();
				AfterVanillaUpdate();
			}
		}

		internal void HandlePlayerCollision(Collider other)
		{
			//IL_007e: 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_0093: 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_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_00ad: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)Ai == (Object)null || !_isManifested || Time.realtimeSinceStartup < _manifestedAt + 1.75f || Time.realtimeSinceStartup < _nextContactDamageAt)
			{
				return;
			}
			PlayerControllerB val = ((EnemyAI)Ai).MeetsStandardPlayerCollisionConditions(other, false, false);
			if (!((Object)(object)val == (Object)null))
			{
				_nextContactDamageAt = Time.realtimeSinceStartup + 0.8f;
				int num = Mathf.Clamp(Plugin.ContactDamage.Value, 0, 100);
				if (num > 0)
				{
					Vector3 val2 = ((Component)val).transform.position - ((Component)this).transform.position;
					Vector3 val3 = ((Vector3)(ref val2)).normalized * 4f;
					val.DamagePlayer(num, true, true, (CauseOfDeath)4, 0, false, val3);
				}
			}
		}

		private PlayerControllerB SelectStalkingTarget()
		{
			//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_0068: Unknown result type (might be due to invalid IL or missing references)
			PlayerControllerB[] array = StartOfRound.Instance?.allPlayerScripts;
			if (array == null)
			{
				return null;
			}
			PlayerControllerB result = null;
			int num = -1;
			float num2 = float.MaxValue;
			foreach (PlayerControllerB val in array)
			{
				if (!((Object)(object)val == (Object)null) && val.isPlayerControlled && !val.isPlayerDead)
				{
					int collectedPageCount = SlenderPageSystem.GetCollectedPageCount(val);
					float num3 = Vector3.SqrMagnitude(((Component)val).transform.position - ((Component)this).transform.position);
					if (collectedPageCount > num || (collectedPageCount == num && num3 < num2))
					{
						result = val;
						num = collectedPageCount;
						num2 = num3;
					}
				}
			}
			return result;
		}

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

		private void AppearBehindTarget(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_001b: 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_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0144: Unknown result type (might be due to invalid IL or missing references)
			bool flag = !target.isInsideFactory;
			_stalkTarget = target;
			Vector3 val = FindStalkingPosition(target, flag);
			WarpTo(val, flag);
			SetManifested(manifested: true, flag);
			_manifestedAt = Time.realtimeSinceStartup;
			_wasObservedThisAppearance = false;
			float num = SlenderPageSystem.RoundElapsedSeconds / Mathf.Max(20f, Plugin.RoundEscalationSeconds.Value);
			_visibleUntil = _manifestedAt + Mathf.Clamp(Plugin.AppearanceDuration.Value + (float)SlenderPageSystem.AggressionLevel * 0.12f + num * 0.08f, 1.5f, 12f);
			FaceTarget(target);
			((EnemyAI)Ai).SyncPositionToClients();
			int collectedPageCount = SlenderPageSystem.GetCollectedPageCount(target);
			int num2 = 0;
			for (int i = 0; i < _slenderRenderers.Count; i++)
			{
				if ((Object)(object)_slenderRenderers[i] != (Object)null && _slenderRenderers[i].enabled && !_slenderRenderers[i].forceRenderingOff)
				{
					num2++;
				}
			}
			float num3 = Vector3.Distance(((Component)target).transform.position, ((Component)this).transform.position);
			Plugin.Log.LogInfo((object)$"Slenderman appeared behind '{target.playerUsername}' at {val}; outside={flag}, distance={num3:F1}m, renderers={num2}/{_slenderRenderers.Count}, layer={((Component)this).gameObject.layer}, collector pages={collectedPageCount}, aggression={SlenderPageSystem.AggressionLevel}/11.");
		}

		private void HideAndScheduleNext(PlayerControllerB target)
		{
			//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)
			//IL_00b1: 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_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_009d: 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)
			bool flag = !target.isInsideFactory;
			_stalkTarget = null;
			SetManifested(manifested: false, flag);
			GameObject[] array = ((!flag) ? RoundManager.Instance?.insideAINodes : RoundManager.Instance?.outsideAINodes);
			Vector3 position = ((Component)this).transform.position;
			float num = -1f;
			if (array != null)
			{
				for (int i = 0; i < array.Length; i++)
				{
					if (!((Object)(object)array[i] == (Object)null))
					{
						float num2 = Vector3.SqrMagnitude(array[i].transform.position - ((Component)target).transform.position);
						if (num2 > num)
						{
							num = num2;
							position = array[i].transform.position;
						}
					}
				}
			}
			WarpTo(position, flag);
			((EnemyAI)Ai).SyncPositionToClients();
			float num3 = Mathf.Lerp(0.85f, 1.15f, (float)_stalkRandom.NextDouble());
			_nextAppearanceAt = Time.realtimeSinceStartup + GetAppearanceInterval() * num3;
			Plugin.Log.LogDebug((object)$"Slenderman vanished; next stalking window in {_nextAppearanceAt - Time.realtimeSinceStartup:F1}s.");
		}

		private Vector3 FindStalkingPosition(PlayerControllerB target, bool outside)
		{
			//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_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_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_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_005a: 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_0063: 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_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_00cc: 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_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: 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_0111: 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)
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_0238: Unknown result type (might be due to invalid IL or missing references)
			//IL_023d: Unknown result type (might be due to invalid IL or missing references)
			//IL_023f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0244: 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)
			//IL_0195: Unknown result type (might be due to invalid IL or missing references)
			//IL_019a: Unknown result type (might be due to invalid IL or missing references)
			//IL_019f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_022c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f0: Unknown result type (might be due to invalid IL or missing references)
			Transform val = (((Object)(object)target.playerEye != (Object)null) ? target.playerEye : ((Component)target).transform);
			Vector3 val2 = Vector3.ProjectOnPlane(val.forward, Vector3.up);
			Vector3 normalized = ((Vector3)(ref val2)).normalized;
			if (((Vector3)(ref normalized)).sqrMagnitude < 0.01f)
			{
				val2 = Vector3.ProjectOnPlane(((Component)target).transform.forward, Vector3.up);
				normalized = ((Vector3)(ref val2)).normalized;
			}
			float num = Mathf.Max(8f, Plugin.MinimumStalkingDistance.Value);
			float num2 = Mathf.Max(num + 1f, Plugin.MaximumStalkingDistance.Value);
			NavMeshHit val5 = default(NavMeshHit);
			for (int i = 0; i < 10; i++)
			{
				float num3 = Mathf.Lerp(-38f, 38f, (float)_stalkRandom.NextDouble());
				Vector3 val3 = Quaternion.AngleAxis(num3, Vector3.up) * -normalized;
				float num4 = Mathf.Lerp(num, num2, (float)_stalkRandom.NextDouble());
				Vector3 val4 = ((Component)target).transform.position + val3 * num4;
				if (NavMesh.SamplePosition(val4, ref val5, 7f, -1) && Vector3.Distance(((NavMeshHit)(ref val5)).position, ((Component)target).transform.position) >= num * 0.72f)
				{
					return ((NavMeshHit)(ref val5)).position;
				}
			}
			GameObject[] array = ((!outside) ? RoundManager.Instance?.insideAINodes : RoundManager.Instance?.outsideAINodes);
			if (array != null && array.Length != 0)
			{
				GameObject val6 = null;
				float num5 = float.MaxValue;
				Vector3 val7 = ((Component)target).transform.position - normalized * num;
				for (int j = 0; j < array.Length; j++)
				{
					if ((Object)(object)array[j] == (Object)null)
					{
						continue;
					}
					float num6 = Vector3.Distance(array[j].transform.position, ((Component)target).transform.position);
					if (!(num6 < num * 0.65f))
					{
						float num7 = Vector3.SqrMagnitude(array[j].transform.position - val7);
						if (num7 < num5)
						{
							val6 = array[j];
							num5 = num7;
						}
					}
				}
				if ((Object)(object)val6 != (Object)null)
				{
					return val6.transform.position;
				}
			}
			return ((Component)target).transform.position - normalized * num;
		}

		private void WarpTo(Vector3 position, bool outside)
		{
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: 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_006d: Unknown result type (might be due to invalid IL or missing references)
			((EnemyAI)Ai).SetEnemyOutside(outside);
			if ((Object)(object)((EnemyAI)Ai).agent != (Object)null && ((Behaviour)((EnemyAI)Ai).agent).enabled && ((EnemyAI)Ai).agent.isOnNavMesh)
			{
				if (!((EnemyAI)Ai).agent.Warp(position))
				{
					((Behaviour)((EnemyAI)Ai).agent).enabled = false;
					((Component)this).transform.position = position;
					((Behaviour)((EnemyAI)Ai).agent).enabled = true;
				}
			}
			else
			{
				((Component)this).transform.position = position;
			}
			((EnemyAI)Ai).serverPosition = ((Component)this).transform.position - Vector3.one * 100f;
		}

		private void SetManifested(bool manifested, bool outside)
		{
			_isManifested = manifested;
			int num = (manifested ? ((!outside) ? 1 : 2) : 0);
			if (((EnemyAI)Ai).currentBehaviourStateIndex != num)
			{
				((EnemyAI)Ai).SwitchToBehaviourState(num);
			}
			ForceRendererState();
		}

		private float GetAppearanceInterval()
		{
			float num = Mathf.Max(8f, Plugin.BaseAppearanceInterval.Value);
			float num2 = Mathf.Clamp(Plugin.MinimumAppearanceInterval.Value, 2f, num);
			float num3 = SlenderPageSystem.RoundElapsedSeconds / Mathf.Max(20f, Plugin.RoundEscalationSeconds.Value);
			float num4 = (float)SlenderPageSystem.AggressionLevel * 1.45f + num3 * 1.6f;
			return Mathf.Clamp(num - num4, num2, num);
		}

		private void FaceTarget(PlayerControllerB target)
		{
			//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_0046: 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)
			if (!((Object)(object)target == (Object)null))
			{
				Vector3 val = ((Component)target).transform.position - ((Component)this).transform.position;
				val.y = 0f;
				if (((Vector3)(ref val)).sqrMagnitude > 0.01f)
				{
					((Component)this).transform.rotation = Quaternion.LookRotation(val);
				}
			}
		}

		private void StopAgent()
		{
			//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)
			if (!((Object)(object)((EnemyAI)Ai).agent == (Object)null) && ((Behaviour)((EnemyAI)Ai).agent).enabled && ((EnemyAI)Ai).agent.isOnNavMesh)
			{
				((EnemyAI)Ai).agent.speed = 0f;
				((EnemyAI)Ai).agent.isStopped = true;
				((EnemyAI)Ai).destination = ((Component)this).transform.position;
			}
		}

		private void AnimateVisual(bool observed)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//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_009b: 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_00fd: Unknown result type (might be due to invalid IL or missing references)
			float num = Vector3.Distance(((Component)this).transform.position, _previousPosition) / Mathf.Max(Time.deltaTime, 0.001f);
			_previousPosition = ((Component)this).transform.position;
			_walkPhase += Time.deltaTime * Mathf.Clamp(num * 1.2f, 0.25f, 8f);
			for (int i = 0; i < _tentacles.Length; i++)
			{
				Transform val = _tentacles[i];
				if (!((Object)(object)val == (Object)null))
				{
					float num2 = (observed ? 2.5f : (11f + (float)SlenderPageSystem.AggressionLevel * 0.6f));
					Vector3 localEulerAngles = val.localEulerAngles;
					localEulerAngles.z += Mathf.Sin(_walkPhase * 0.8f + (float)i * 1.7f) * num2 * Time.deltaTime;
					localEulerAngles.x += Mathf.Cos(_walkPhase * 0.65f + (float)i) * num2 * 0.55f * Time.deltaTime;
					val.localEulerAngles = localEulerAngles;
				}
			}
		}

		private void ForceRendererState()
		{
			for (int i = 0; i < _originalRenderers.Count; i++)
			{
				if ((Object)(object)_originalRenderers[i] != (Object)null)
				{
					_originalRenderers[i].enabled = false;
				}
			}
			for (int j = 0; j < _slenderRenderers.Count; j++)
			{
				if ((Object)(object)_slenderRenderers[j] != (Object)null)
				{
					if (!((Component)_slenderRenderers[j]).gameObject.activeSelf)
					{
						((Component)_slenderRenderers[j]).gameObject.SetActive(true);
					}
					_slenderRenderers[j].forceRenderingOff = false;
					_slenderRenderers[j].enabled = _isManifested;
				}
			}
		}

		private void SilenceVanillaAudio()
		{
			if (!((Object)(object)Ai == (Object)null))
			{
				if ((Object)(object)((EnemyAI)Ai).creatureVoice != (Object)null)
				{
					((EnemyAI)Ai).creatureVoice.volume = 0f;
				}
				if ((Object)(object)((EnemyAI)Ai).creatureSFX != (Object)null)
				{
					((EnemyAI)Ai).creatureSFX.volume = 0f;
				}
				if ((Object)(object)Ai.creatureAngerVoice != (Object)null)
				{
					Ai.creatureAngerVoice.volume = 0f;
				}
			}
		}

		private void OnDestroy()
		{
			SlenderRuntime.Unregister(this);
		}
	}
	internal static class SlenderModelLoader
	{
		private readonly struct VertexKey : IEquatable<VertexKey>
		{
			internal readonly int Vertex;

			internal readonly int Uv;

			internal readonly int Normal;

			internal VertexKey(int vertex, int uv, int normal)
			{
				Vertex = vertex;
				Uv = uv;
				Normal = normal;
			}

			public bool Equals(VertexKey other)
			{
				if (Vertex == other.Vertex && Uv == other.Uv)
				{
					return Normal == other.Normal;
				}
				return false;
			}

			public override bool Equals(object obj)
			{
				if (obj is VertexKey other)
				{
					return Equals(other);
				}
				return false;
			}

			public override int GetHashCode()
			{
				int vertex = Vertex;
				vertex = (vertex * 397) ^ Uv;
				return (vertex * 397) ^ Normal;
			}
		}

		private const string ResourcePrefix = "SlendermanMod.Assets.";

		private static Mesh _mesh;

		private static Material _clothingMaterial;

		private static Material _skinMaterial;

		private static readonly List<Texture2D> Textures = new List<Texture2D>();

		internal static bool TryCreate(Transform parent, int layer, List<Renderer> renderers)
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Expected O, but got Unknown
			//IL_0058: 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_0087: 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)
			try
			{
				EnsureLoaded();
				if ((Object)(object)_mesh == (Object)null || (Object)(object)_clothingMaterial == (Object)null || (Object)(object)_skinMaterial == (Object)null)
				{
					return false;
				}
				GameObject val = new GameObject("RepromancerSlendermanVisual");
				val.layer = layer;
				val.transform.SetParent(parent, false);
				val.transform.localPosition = Vector3.zero;
				val.transform.localRotation = Quaternion.Euler(0f, 180f, 0f);
				val.transform.localScale = Vector3.one * 1.52f;
				MeshFilter val2 = val.AddComponent<MeshFilter>();
				val2.sharedMesh = _mesh;
				MeshRenderer val3 = val.AddComponent<MeshRenderer>();
				((Renderer)val3).sharedMaterials = (Material[])(object)new Material[2] { _clothingMaterial, _skinMaterial };
				((Renderer)val3).shadowCastingMode = (ShadowCastingMode)1;
				((Renderer)val3).receiveShadows = true;
				renderers?.Add((Renderer)(object)val3);
				return true;
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"Could not create the embedded Slenderman model; using fallback visuals: {arg}");
				return false;
			}
		}

		private static void EnsureLoaded()
		{
			if (!((Object)(object)_mesh != (Object)null))
			{
				_mesh = LoadObj("repromancer_slender_man_model.obj");
				Texture2D baseColor = LoadTexture("slender_clothing_basecolor.jpg", linear: false);
				Texture2D normal = LoadTexture("slender_clothing_normal.jpg", linear: true);
				Texture2D baseColor2 = LoadTexture("slender_skin_basecolor.jpg", linear: false);
				Texture2D normal2 = LoadTexture("slender_skin_normal.jpg", linear: true);
				_clothingMaterial = CreateMaterial("SlendermanClothing", baseColor, normal, 0.08f, 0.28f);
				_skinMaterial = CreateMaterial("SlendermanSkin", baseColor2, normal2, 0f, 0.18f);
				Plugin.Log.LogInfo((object)$"Loaded embedded Repromancer Slenderman model with {_mesh.vertexCount} vertices.");
			}
		}

		private static Mesh LoadObj(string resourceName)
		{
			//IL_02c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f4: Expected O, but got Unknown
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: 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_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0221: Unknown result type (might be due to invalid IL or missing references)
			//IL_0212: Unknown result type (might be due to invalid IL or missing references)
			//IL_024e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0240: Unknown result type (might be due to invalid IL or missing references)
			using Stream stream = OpenResource(resourceName);
			using StreamReader streamReader = new StreamReader(stream);
			List<Vector3> list = new List<Vector3>();
			List<Vector2> list2 = new List<Vector2>();
			List<Vector3> list3 = new List<Vector3>();
			List<Vector3> list4 = new List<Vector3>();
			List<Vector2> list5 = new List<Vector2>();
			List<Vector3> list6 = new List<Vector3>();
			List<int>[] array = new List<int>[2]
			{
				new List<int>(),
				new List<int>()
			};
			Dictionary<VertexKey, int> dictionary = new Dictionary<VertexKey, int>();
			int num = 0;
			bool flag = false;
			while (!streamReader.EndOfStream)
			{
				string text = streamReader.ReadLine();
				if (string.IsNullOrWhiteSpace(text) || text[0] == '#')
				{
					continue;
				}
				if (text.StartsWith("v ", StringComparison.Ordinal))
				{
					string[] array2 = Split(text);
					list.Add(new Vector3(ParseFloat(array2[1]), ParseFloat(array2[2]), 0f - ParseFloat(array2[3])));
				}
				else if (text.StartsWith("vt ", StringComparison.Ordinal))
				{
					string[] array3 = Split(text);
					list2.Add(new Vector2(ParseFloat(array3[1]), ParseFloat(array3[2])));
				}
				else if (text.StartsWith("vn ", StringComparison.Ordinal))
				{
					string[] array4 = Split(text);
					Vector3 val = new Vector3(ParseFloat(array4[1]), ParseFloat(array4[2]), 0f - ParseFloat(array4[3]));
					list3.Add(((Vector3)(ref val)).normalized);
				}
				else if (text.StartsWith("g ", StringComparison.Ordinal))
				{
					num = ((text.IndexOf("skin", StringComparison.OrdinalIgnoreCase) >= 0) ? 1 : 0);
				}
				else
				{
					if (!text.StartsWith("f ", StringComparison.Ordinal))
					{
						continue;
					}
					string[] array5 = Split(text);
					if (array5.Length < 4)
					{
						continue;
					}
					int[] array6 = new int[array5.Length - 1];
					for (int i = 1; i < array5.Length; i++)
					{
						VertexKey key = ParseKey(array5[i], list.Count, list2.Count, list3.Count);
						if (!dictionary.TryGetValue(key, out var value))
						{
							value = list4.Count;
							dictionary.Add(key, value);
							list4.Add(list[key.Vertex]);
							list5.Add((key.Uv >= 0) ? list2[key.Uv] : Vector2.zero);
							if (key.Normal >= 0)
							{
								list6.Add(list3[key.Normal]);
							}
							else
							{
								list6.Add(Vector3.up);
								flag = true;
							}
						}
						array6[i - 1] = value;
					}
					for (int j = 1; j < array6.Length - 1; j++)
					{
						array[num].Add(array6[0]);
						array[num].Add(array6[j + 1]);
						array[num].Add(array6[j]);
					}
				}
			}
			Mesh val2 = new Mesh
			{
				name = "RepromancerSlendermanMesh",
				indexFormat = (IndexFormat)(list4.Count > 65535),
				subMeshCount = 2
			};
			val2.SetVertices(list4);
			val2.SetUVs(0, list5);
			val2.SetNormals(list6);
			val2.SetTriangles(array[0], 0, true);
			val2.SetTriangles(array[1], 1, true);
			if (flag)
			{
				val2.RecalculateNormals();
			}
			val2.RecalculateBounds();
			try
			{
				val2.RecalculateTangents();
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Could not calculate model tangents: " + ex.Message));
			}
			return val2;
		}

		private static Texture2D LoadTexture(string resourceName, bool linear)
		{
			//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_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_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Expected O, but got Unknown
			using Stream stream = OpenResource(resourceName);
			byte[] array = new byte[stream.Length];
			int num;
			for (int i = 0; i < array.Length; i += num)
			{
				num = stream.Read(array, i, array.Length - i);
				if (num <= 0)
				{
					break;
				}
			}
			Texture2D val = new Texture2D(2, 2, (TextureFormat)3, true, linear)
			{
				name = resourceName,
				wrapMode = (TextureWrapMode)0,
				filterMode = (FilterMode)1,
				anisoLevel = 4
			};
			if (!ImageConversion.LoadImage(val, array, true))
			{
				Object.Destroy((Object)(object)val);
				throw new InvalidDataException("Texture resource '" + resourceName + "' could not be decoded.");
			}
			Textures.Add(val);
			return val;
		}

		private static Material CreateMaterial(string name, Texture2D baseColor, Texture2D normal, float metallic, float smoothness)
		{
			//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_0035: Expected O, but got Unknown
			Shader val = Shader.Find("HDRP/Lit") ?? Shader.Find("Standard") ?? Shader.Find("Legacy Shaders/Diffuse");
			Material val2 = new Material(val)
			{
				name = name
			};
			if (val2.HasProperty("_BaseColorMap"))
			{
				val2.SetTexture("_BaseColorMap", (Texture)(object)baseColor);
			}
			if (val2.HasProperty("_MainTex"))
			{
				val2.SetTexture("_MainTex", (Texture)(object)baseColor);
			}
			if (val2.HasProperty("_NormalMap"))
			{
				val2.SetTexture("_NormalMap", (Texture)(object)normal);
				val2.SetFloat("_NormalScale", 1f);
				val2.EnableKeyword("_NORMALMAP_TANGENT_SPACE");
			}
			if (val2.HasProperty("_BumpMap"))
			{
				val2.SetTexture("_BumpMap", (Texture)(object)normal);
				val2.SetFloat("_BumpScale", 1f);
				val2.EnableKeyword("_NORMALMAP");
			}
			if (val2.HasProperty("_Metallic"))
			{
				val2.SetFloat("_Metallic", metallic);
			}
			if (val2.HasProperty("_Smoothness"))
			{
				val2.SetFloat("_Smoothness", smoothness);
			}
			if (val2.HasProperty("_DoubleSidedEnable"))
			{
				val2.SetFloat("_DoubleSidedEnable", 1f);
			}
			if (val2.HasProperty("_CullMode"))
			{
				val2.SetFloat("_CullMode", 0f);
			}
			if (val2.HasProperty("_CullModeForward"))
			{
				val2.SetFloat("_CullModeForward", 0f);
			}
			return val2;
		}

		private static Stream OpenResource(string name)
		{
			Stream manifestResourceStream = Assembly.GetExecutingAssembly().GetManifestResourceStream("SlendermanMod.Assets." + name);
			return manifestResourceStream ?? throw new FileNotFoundException("Embedded Slenderman resource '" + name + "' was not found.");
		}

		private static string[] Split(string line)
		{
			return line.Split(new char[2] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);
		}

		private static float ParseFloat(string value)
		{
			return float.Parse(value, NumberStyles.Float, CultureInfo.InvariantCulture);
		}

		private static VertexKey ParseKey(string value, int vertexCount, int uvCount, int normalCount)
		{
			string[] array = value.Split('/');
			int vertex = ParseIndex(array[0], vertexCount);
			int uv = ((array.Length > 1 && array[1].Length > 0) ? ParseIndex(array[1], uvCount) : (-1));
			int normal = ((array.Length > 2 && array[2].Length > 0) ? ParseIndex(array[2], normalCount) : (-1));
			return new VertexKey(vertex, uv, normal);
		}

		private static int ParseIndex(string value, int count)
		{
			int num = int.Parse(value, CultureInfo.InvariantCulture);
			if (num <= 0)
			{
				return count + num;
			}
			return num - 1;
		}
	}
	internal static class SlenderPageSystem
	{
		private static readonly HashSet<ulong> CollectedPages = new HashSet<ulong>();

		private static readonly Dictionary<ulong, int> CollectorPageCounts = new Dictionary<ulong, int>();

		private static bool _landingClockCaptured;

		private static float _landingDayTime;

		private static bool _awakened;

		private static bool _testAwake;

		internal static int AggressionLevel { get; private set; }

		internal static bool PagesSpawned { get; private set; }

		internal static float RoundStartedAt { get; private set; }

		internal static float RoundElapsedSeconds => Mathf.Max(0f, Time.realtimeSinceStartup - RoundStartedAt);

		internal static bool IsSlendermanAwake
		{
			get
			{
				UpdateWakeState();
				return _awakened;
			}
		}

		internal static void ResetRound()
		{
			CollectedPages.Clear();
			CollectorPageCounts.Clear();
			AggressionLevel = 0;
			PagesSpawned = false;
			RoundStartedAt = Time.realtimeSinceStartup;
			_landingClockCaptured = false;
			_landingDayTime = 0f;
			_awakened = false;
			_testAwake = false;
			SlenderScreenEffect.ResetEffect();
		}

		internal static void SpawnPages(RoundManager roundManager)
		{
			//IL_00c1: 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_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_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_0101: 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_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_014a: Unknown result type (might be due to invalid IL or missing references)
			//IL_014f: 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_00b0: 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_00b5: Unknown result type (might be due to invalid IL or missing references)
			if (PagesSpawned || (Object)(object)roundManager == (Object)null || !((NetworkBehaviour)roundManager).IsServer || (Object)(object)SlenderEnemyRegistry.PagePrefab == (Object)null)
			{
				return;
			}
			int num = Mathf.Clamp(Plugin.PagesPerRound.Value, 0, 11);
			if (num == 0)
			{
				return;
			}
			RandomScrapSpawn[] array = Object.FindObjectsOfType<RandomScrapSpawn>();
			if (array == null || array.Length == 0)
			{
				Plugin.Log.LogWarning((object)"No scrap spawn points were available for Slender pages.");
				return;
			}
			List<NetworkObjectReference> list = new List<NetworkObjectReference>(num);
			int[] array2 = new int[num];
			for (int i = 0; i < num; i++)
			{
				RandomScrapSpawn val = array[roundManager.AnomalyRandom.Next(0, array.Length)];
				Vector3 val2 = ((!val.spawnedItemsCopyPosition) ? (roundManager.GetRandomNavMeshPositionInBoxPredictable(((Component)val).transform.position, val.itemSpawnRange, roundManager.navHit, roundManager.AnomalyRandom, -8193, 1f) + Vector3.up * SlenderEnemyRegistry.PageItem.verticalOffset) : (((Object)(object)val.spawnWithParent != (Object)null) ? val.spawnWithParent.position : ((Component)val).transform.position));
				GameObject val3 = Object.Instantiate<GameObject>(SlenderEnemyRegistry.PagePrefab, val2, Quaternion.identity);
				GrabbableObject component = val3.GetComponent<GrabbableObject>();
				component.scrapValue = Plugin.PageValue.Value;
				component.fallTime = 0f;
				((Component)component).transform.rotation = Quaternion.Euler(component.itemProperties.restingRotation);
				NetworkObject component2 = val3.GetComponent<NetworkObject>();
				component2.Spawn(true);
				component.SetScrapValue(Plugin.PageValue.Value);
				list.Add(NetworkObjectReference.op_Implicit(component2));
				array2[i] = Plugin.PageValue.Value;
			}
			roundManager.SyncScrapValuesClientRpc(list.ToArray(), array2);
			RecalculateTotalScrapValue(roundManager);
			PagesSpawned = true;
			Plugin.Log.LogInfo((object)$"Spawned {num} Slender pages worth {Plugin.PageValue.Value} credits each.");
		}

		internal static void PreparePage(GameObject pageObject)
		{
			if (!((Object)(object)pageObject == (Object)null) && !((Object)(object)pageObject.GetComponent<SlenderPageIdentity>() == (Object)null))
			{
				GrabbableObject component = pageObject.GetComponent<GrabbableObject>();
				if (!((Object)(object)component == (Object)null))
				{
					SlenderPageMarker slenderPageMarker = pageObject.GetComponent<SlenderPageMarker>() ?? pageObject.AddComponent<SlenderPageMarker>();
					slenderPageMarker.Initialize(component);
				}
			}
		}

		internal static void OnPageEquipped(GrabbableObject page)
		{
			if ((Object)(object)page == (Object)null || (Object)(object)((Component)page).GetComponent<SlenderPageIdentity>() == (Object)null || (Object)(object)((NetworkBehaviour)page).NetworkObject == (Object)null)
			{
				return;
			}
			PlayerControllerB playerHeldBy = page.playerHeldBy;
			if ((Object)(object)playerHeldBy == (Object)null)
			{
				return;
			}
			ulong networkObjectId = ((NetworkBehaviour)page).NetworkObjectId;
			if (CollectedPages.Add(networkObjectId))
			{
				AggressionLevel = Mathf.Clamp(AggressionLevel + 1, 0, 11);
				Awaken("the first Slender page was collected");
				ulong playerClientId = playerHeldBy.playerClientId;
				CollectorPageCounts.TryGetValue(playerClientId, out var value);
				CollectorPageCounts[playerClientId] = value + 1;
				Plugin.Log.LogInfo((object)$"Slender page collected by '{playerHeldBy.playerUsername}'. Aggression is now {AggressionLevel}/11; collector has {value + 1}.");
				PlayerControllerB val = GameNetworkManager.Instance?.localPlayerController;
				if ((Object)(object)val != (Object)null && (Object)(object)page.playerHeldBy == (Object)(object)val && (Object)(object)HUDManager.Instance != (Object)null)
				{
					HUDManager.Instance.DisplayTip($"SLENDER-ZETTEL {AggressionLevel}/11", "Er ist schneller geworden. Sieh ihn nicht zu lange an!", true, false, "LC_Tip1");
				}
			}
		}

		internal static int GetCollectedPageCount(PlayerControllerB player)
		{
			if ((Object)(object)player == (Object)null)
			{
				return 0;
			}
			if (!CollectorPageCounts.TryGetValue(player.playerClientId, out var value))
			{
				return 0;
			}
			return value;
		}

		internal static void ForceAwakeForTesting()
		{
			_testAwake = true;
			Awaken("the F7 test spawn was requested");
		}

		private static void UpdateWakeState()
		{
			if (_awakened)
			{
				return;
			}
			if (_testAwake || AggressionLevel > 0)
			{
				Awaken(_testAwake ? "testing is active" : "a Slender page was collected");
				return;
			}
			StartOfRound instance = StartOfRound.Instance;
			TimeOfDay instance2 = TimeOfDay.Instance;
			if (!((Object)(object)instance == (Object)null) && !((Object)(object)instance2 == (Object)null) && !instance.inShipPhase && instance.shipHasLanded && instance2.timeHasStarted)
			{
				if (!_landingClockCaptured)
				{
					_landingClockCaptured = true;
					_landingDayTime = instance2.currentDayTime;
					Plugin.Log.LogInfo((object)$"Slenderman wake timer started after landing at in-game hour {instance2.hour}; delay is {Plugin.WakeUpDelayHours.Value:F1} hours.");
				}
				float num = Mathf.Max(1f, instance2.lengthOfHours);
				float num2 = num * Mathf.Max(0f, Plugin.WakeUpDelayHours.Value);
				if (instance2.currentDayTime - _landingDayTime >= num2)
				{
					Awaken($"{Plugin.WakeUpDelayHours.Value:F1} in-game hours passed after landing");
				}
			}
		}

		private static void Awaken(string reason)
		{
			if (!_awakened)
			{
				_awakened = true;
				Plugin.Log.LogInfo((object)("Slenderman is now awake because " + reason + "."));
			}
		}

		internal static void RecalculateTotalScrapValue(RoundManager roundManager)
		{
			if ((Object)(object)roundManager == (Object)null)
			{
				return;
			}
			GrabbableObject[] array = Object.FindObjectsOfType<GrabbableObject>();
			int num = 0;
			foreach (GrabbableObject val in array)
			{
				if ((Object)(object)val != (Object)null && !val.deactivated && !val.scrapPersistedThroughRounds && (Object)(object)val.itemProperties != (Object)null && val.itemProperties.isScrap)
				{
					num += Mathf.Max(0, val.scrapValue);
				}
			}
			roundManager.totalScrapValueInLevel = num;
		}
	}
	internal sealed class SlenderPageMarker : MonoBehaviour
	{
		private readonly List<Renderer> _originalRenderers = new List<Renderer>();

		private readonly List<Renderer> _pageRenderers = new List<Renderer>();

		private GrabbableObject _page;

		private bool _initialized;

		internal void Initialize(GrabbableObject page)
		{
			if (!_initialized && !((Object)(object)page == (Object)null))
			{
				_initialized = true;
				_page = page;
				Renderer[] componentsInChildren = ((Component)page).GetComponentsInChildren<Renderer>(true);
				for (int i = 0; i < componentsInChildren.Length; i++)
				{
					_originalRenderers.Add(componentsInChildren[i]);
					componentsInChildren[i].enabled = false;
				}
				int num = ((!((Object)(object)((NetworkBehaviour)page).NetworkObject != (Object)null) || !((NetworkBehaviour)page).NetworkObject.IsSpawned) ? 1 : ((int)(((NetworkBehaviour)page).NetworkObjectId % 11) + 1));
				SlenderVisualFactory.CreatePage(((Component)this).transform, ((Component)this).gameObject.layer, num, _pageRenderers);
				ScanNodeProperties[] componentsInChildren2 = ((Component)page).GetComponentsInChildren<ScanNodeProperties>(true);
				for (int j = 0; j < componentsInChildren2.Length; j++)
				{
					componentsInChildren2[j].headerText = $"SLENDER-ZETTEL {num}/11";
					componentsInChildren2[j].subText = $"Wert: {page.scrapValue}";
				}
				page.customGrabTooltip = "Slender-Zettel nehmen";
			}
		}

		private void LateUpdate()
		{
			if ((Object)(object)_page == (Object)null)
			{
				return;
			}
			for (int i = 0; i < _originalRenderers.Count; i++)
			{
				if ((Object)(object)_origina