Decompiled source of Puppeteer v1.0.5

BepInEx/plugins/Puppeteer.dll

Decompiled 3 months ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using Fusion;
using Il2CppInterop.Runtime;
using Il2CppInterop.Runtime.Injection;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppSystem;
using Il2CppSystem.Collections.Generic;
using Microsoft.CodeAnalysis;
using Pathfinding;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.InputSystem;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("Puppeteer")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("Puppeteer")]
[assembly: AssemblyTitle("Puppeteer")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[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 ShiftAtMidnightPuppeteer
{
	internal sealed class AnimatorDriver
	{
		private enum CueKind
		{
			None,
			Trigger,
			Bool,
			State
		}

		private struct Cue
		{
			public CueKind Kind;

			public int Hash;

			public bool Valid => Kind != CueKind.None;
		}

		private static readonly string[] MoveNames = new string[5] { "walking", "walk", "moving", "ismoving", "iswalking" };

		private static readonly string[] RunNames = new string[6] { "running", "run", "sprint", "sprinting", "isrunning", "chasing" };

		private static readonly string[] CrouchNames = new string[3] { "crouching", "crouch", "iscrouching" };

		private static readonly string[] SpeedNames = new string[3] { "speed", "movespeed", "velocity" };

		private Animator _animator;

		private readonly List<int> _moveBools = new List<int>();

		private readonly List<int> _runBools = new List<int>();

		private readonly List<int> _crouchBools = new List<int>();

		private readonly List<int> _speedFloats = new List<int>();

		private readonly Dictionary<string, AnimatorControllerParameter> _paramsByName = new Dictionary<string, AnimatorControllerParameter>(StringComparer.OrdinalIgnoreCase);

		private Cue _walkCue;

		private Cue _runCue;

		private Cue _idleCue;

		private Cue _actionCue;

		private Cue _activeCue;

		private bool _useOverrides;

		private int _walkState;

		private int _runState;

		private int _idleState;

		private int _currentState;

		private int _walkTrigger;

		private int _runTrigger;

		private int _idleTrigger;

		private int _currentTrigger;

		public bool HasAnyMapping => _moveBools.Count > 0 || _runBools.Count > 0 || _crouchBools.Count > 0 || _speedFloats.Count > 0;

		public string MappingSummary => HasTriggers ? $"triggers walk/run/idle={_walkTrigger != 0}/{_runTrigger != 0}/{_idleTrigger != 0}" : (HasStates ? $"states walk/run/idle={_walkState != 0}/{_runState != 0}/{_idleState != 0}" : (HasAnyMapping ? $"params move:{_moveBools.Count} run:{_runBools.Count} crouch:{_crouchBools.Count}" : "nothing drivable - playing default clip"));

		public bool HasOverrides => _useOverrides;

		public bool HasAction => _actionCue.Valid;

		public bool HasTriggers => _walkTrigger != 0 || _runTrigger != 0 || _idleTrigger != 0;

		public bool HasStates => _walkState != 0 || _runState != 0 || _idleState != 0;

		public void Bind(GameObject model)
		{
			//IL_0156: Unknown result type (might be due to invalid IL or missing references)
			//IL_0185: Unknown result type (might be due to invalid IL or missing references)
			//IL_018b: Invalid comparison between Unknown and I4
			//IL_020c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0212: Invalid comparison between Unknown and I4
			//IL_0245: Unknown result type (might be due to invalid IL or missing references)
			//IL_024c: Invalid comparison between Unknown and I4
			_animator = null;
			_moveBools.Clear();
			_walkTrigger = (_runTrigger = (_idleTrigger = (_currentTrigger = 0)));
			_paramsByName.Clear();
			_useOverrides = false;
			_walkCue = (_runCue = (_idleCue = (_actionCue = (_activeCue = default(Cue)))));
			_runBools.Clear();
			_crouchBools.Clear();
			_speedFloats.Clear();
			if ((Object)(object)model == (Object)null)
			{
				return;
			}
			_animator = PickAnimator(model);
			if ((Object)(object)_animator == (Object)null)
			{
				return;
			}
			Il2CppReferenceArray<AnimatorControllerParameter> parameters = _animator.parameters;
			if (parameters == null)
			{
				return;
			}
			List<string> list = new List<string>();
			foreach (AnimatorControllerParameter item in (Il2CppArrayBase<AnimatorControllerParameter>)(object)parameters)
			{
				if (item == null)
				{
					continue;
				}
				string text = item.name.ToLowerInvariant();
				list.Add($"{item.name}:{item.type}");
				_paramsByName[item.name] = item;
				if ((int)item.type == 4)
				{
					if (Matches(text, RunNames))
					{
						_runBools.Add(item.nameHash);
					}
					else if (Matches(text, CrouchNames))
					{
						_crouchBools.Add(item.nameHash);
					}
					else if (Matches(text, MoveNames))
					{
						_moveBools.Add(item.nameHash);
					}
				}
				else if ((int)item.type == 1)
				{
					if (Matches(text, SpeedNames))
					{
						_speedFloats.Add(item.nameHash);
					}
				}
				else if ((int)item.type == 9)
				{
					CollectTrigger(item.name, text, item.nameHash);
				}
			}
			BindStates();
		}

		[Conditional("DEVTOOLS")]
		private void DumpPlayableStates()
		{
			RuntimeAnimatorController runtimeAnimatorController = _animator.runtimeAnimatorController;
			if ((Object)(object)runtimeAnimatorController == (Object)null)
			{
				return;
			}
			Il2CppReferenceArray<AnimationClip> animationClips = runtimeAnimatorController.animationClips;
			if (animationClips == null || ((Il2CppArrayBase<AnimationClip>)(object)animationClips).Length == 0)
			{
				return;
			}
			for (int i = 0; i < ((Il2CppArrayBase<AnimationClip>)(object)animationClips).Length; i++)
			{
				AnimationClip val = ((Il2CppArrayBase<AnimationClip>)(object)animationClips)[i];
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				string name = ((Object)val).name;
				string text = "";
				string[] array = new string[2]
				{
					name,
					"Base Layer." + name
				};
				foreach (string text2 in array)
				{
					try
					{
						if (_animator.HasState(0, Animator.StringToHash(text2)))
						{
							text = text + "  PLAYABLE:\"" + text2 + "\"";
						}
					}
					catch
					{
					}
				}
			}
		}

		private static Animator PickAnimator(GameObject model)
		{
			Il2CppArrayBase<Animator> componentsInChildren = model.GetComponentsInChildren<Animator>(true);
			if (componentsInChildren == null || componentsInChildren.Length == 0)
			{
				return null;
			}
			Animator val = null;
			Animator val2 = null;
			int num = -1;
			int num2 = -1;
			foreach (Animator item in componentsInChildren)
			{
				if ((Object)(object)item == (Object)null)
				{
					continue;
				}
				RuntimeAnimatorController runtimeAnimatorController = item.runtimeAnimatorController;
				Il2CppReferenceArray<AnimationClip> val3 = (((Object)(object)runtimeAnimatorController != (Object)null) ? runtimeAnimatorController.animationClips : null);
				int num3 = ((Il2CppArrayBase<AnimationClip>)(object)val3)?.Length ?? 0;
				int num4 = 0;
				if (val3 != null)
				{
					foreach (AnimationClip item2 in (Il2CppArrayBase<AnimationClip>)(object)val3)
					{
						if (!((Object)(object)item2 == (Object)null))
						{
							string text = ((Object)item2).name.ToLowerInvariant();
							if (text.Contains("walk") || text.Contains("run") || text.Contains("chase") || text.Contains("move"))
							{
								num4++;
							}
						}
					}
				}
				if (num4 > num)
				{
					num = num4;
					val = item;
				}
				if (num3 > num2)
				{
					num2 = num3;
					val2 = item;
				}
			}
			Animator val4 = ((num > 0) ? val : val2);
			if ((Object)(object)val4 != (Object)null)
			{
			}
			return val4;
		}

		private static bool Matches(string name, string[] candidates)
		{
			foreach (string text in candidates)
			{
				if (name == text)
				{
					return true;
				}
			}
			foreach (string value in candidates)
			{
				if (name.Contains(value))
				{
					return true;
				}
			}
			return false;
		}

		private Cue Resolve(string name)
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Invalid comparison between Unknown and I4
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Invalid comparison between Unknown and I4
			if (string.IsNullOrEmpty(name) || (Object)(object)_animator == (Object)null)
			{
				return default(Cue);
			}
			if (_paramsByName.TryGetValue(name, out var value))
			{
				if ((int)value.type == 9)
				{
					return new Cue
					{
						Kind = CueKind.Trigger,
						Hash = value.nameHash
					};
				}
				if ((int)value.type == 4)
				{
					return new Cue
					{
						Kind = CueKind.Bool,
						Hash = value.nameHash
					};
				}
			}
			string[] array = new string[2]
			{
				name,
				"Base Layer." + name
			};
			foreach (string text in array)
			{
				int num = Animator.StringToHash(text);
				try
				{
					if (_animator.HasState(0, num))
					{
						return new Cue
						{
							Kind = CueKind.State,
							Hash = num
						};
					}
				}
				catch
				{
				}
			}
			return default(Cue);
		}

		public void ApplyOverrides(VerifiedEntity cfg)
		{
			_useOverrides = false;
			if (cfg != null && !((Object)(object)_animator == (Object)null))
			{
				_walkCue = Resolve(cfg.Walk);
				_runCue = Resolve(cfg.Run);
				_idleCue = Resolve(cfg.Idle);
				_actionCue = Resolve(cfg.Action);
				_activeCue = default(Cue);
				_useOverrides = _walkCue.Valid || _idleCue.Valid || _runCue.Valid;
			}
		}

		private void Fire(Cue cue, bool on = true)
		{
			if (!cue.Valid)
			{
				return;
			}
			try
			{
				if (cue.Kind == CueKind.Trigger)
				{
					_animator.SetTrigger(cue.Hash);
				}
				else if (cue.Kind == CueKind.Bool)
				{
					_animator.SetBool(cue.Hash, on);
				}
				else
				{
					_animator.Play(cue.Hash, 0, 0f);
				}
			}
			catch
			{
			}
		}

		public void PlayAction()
		{
			if (_actionCue.Valid)
			{
				Fire(_actionCue);
				_activeCue = default(Cue);
			}
		}

		private void TickOverrides(bool isMoving, bool isRunning)
		{
			Cue cue = ((!isMoving) ? _idleCue : ((isRunning && _runCue.Valid) ? _runCue : _walkCue));
			if (!cue.Valid)
			{
				cue = _idleCue;
			}
			if (cue.Valid)
			{
				if (_walkCue.Kind == CueKind.Bool)
				{
					Fire(_walkCue, isMoving);
				}
				if (_runCue.Kind == CueKind.Bool)
				{
					Fire(_runCue, isMoving && isRunning);
				}
				if (cue.Kind != CueKind.Bool && (cue.Hash != _activeCue.Hash || cue.Kind != _activeCue.Kind))
				{
					_activeCue = cue;
					Fire(cue);
				}
			}
		}

		private void CollectTrigger(string original, string lower, int hash)
		{
			if (!lower.Contains("drunk") && !lower.Contains("zombie") && !lower.Contains("injured") && !lower.Contains("cane") && !lower.Contains("pistol") && !lower.Contains("crawl") && !lower.Contains("moonwalk") && !lower.Contains("catwalk") && !lower.Contains("slow"))
			{
				if (lower == "standard walk" || (_walkTrigger == 0 && lower.Contains("walk")))
				{
					_walkTrigger = hash;
				}
				if (lower == "standard run" || (_runTrigger == 0 && (lower.Contains("run") || lower == "jog")))
				{
					_runTrigger = hash;
				}
				if (lower == "standard idle" || (_idleTrigger == 0 && lower.Contains("idle")))
				{
					_idleTrigger = hash;
				}
			}
		}

		private void BindStates()
		{
			_walkState = (_runState = (_idleState = (_currentState = 0)));
			RuntimeAnimatorController runtimeAnimatorController = _animator.runtimeAnimatorController;
			Il2CppReferenceArray<AnimationClip> val = (((Object)(object)runtimeAnimatorController != (Object)null) ? runtimeAnimatorController.animationClips : null);
			if (val == null)
			{
				return;
			}
			foreach (AnimationClip item in (Il2CppArrayBase<AnimationClip>)(object)val)
			{
				if ((Object)(object)item == (Object)null)
				{
					continue;
				}
				int num = Animator.StringToHash(((Object)item).name);
				try
				{
					if (!_animator.HasState(0, num))
					{
						continue;
					}
				}
				catch
				{
					continue;
				}
				string text = ((Object)item).name.ToLowerInvariant();
				if (!text.Contains("crawl") && !text.Contains("zombie") && !text.Contains("drunk") && !text.Contains("injured") && !text.Contains("pistol") && !text.Contains("cane"))
				{
					if (_runState == 0 && (text.Contains("standard run") || text.Contains("jog") || text == "run"))
					{
						_runState = num;
					}
					if (_walkState == 0 && (text.Contains("standard walk") || text.Contains("male walking")))
					{
						_walkState = num;
					}
					if (_idleState == 0 && text.Contains("standard idle"))
					{
						_idleState = num;
					}
				}
			}
			foreach (AnimationClip item2 in (Il2CppArrayBase<AnimationClip>)(object)val)
			{
				if ((Object)(object)item2 == (Object)null)
				{
					continue;
				}
				int num2 = Animator.StringToHash(((Object)item2).name);
				try
				{
					if (!_animator.HasState(0, num2))
					{
						continue;
					}
				}
				catch
				{
					continue;
				}
				string text2 = ((Object)item2).name.ToLowerInvariant();
				if (_walkState == 0 && text2.Contains("walk"))
				{
					_walkState = num2;
				}
				if (_runState == 0 && text2.Contains("run"))
				{
					_runState = num2;
				}
				if (_idleState == 0 && text2.Contains("idle"))
				{
					_idleState = num2;
				}
			}
		}

		public void Tick(bool isMoving, bool isRunning, bool isCrouching)
		{
			if ((Object)(object)_animator == (Object)null)
			{
				return;
			}
			if (_useOverrides || HasStates || HasTriggers)
			{
				if (_useOverrides)
				{
					TickOverrides(isMoving, isRunning);
				}
				else if (HasTriggers)
				{
					int num = ((!isMoving) ? _idleTrigger : ((isRunning && _runTrigger != 0) ? _runTrigger : _walkTrigger));
					if (num == 0)
					{
						num = _idleTrigger;
					}
					if (num != 0 && num != _currentTrigger)
					{
						_currentTrigger = num;
						try
						{
							_animator.SetTrigger(num);
						}
						catch
						{
						}
					}
				}
				else
				{
					int num2 = ((!isMoving) ? _idleState : ((isRunning && _runState != 0) ? _runState : _walkState));
					if (num2 == 0)
					{
						num2 = _idleState;
					}
					if (num2 != 0 && num2 != _currentState)
					{
						_currentState = num2;
						try
						{
							_animator.Play(num2, 0, 0f);
						}
						catch
						{
						}
					}
				}
			}
			if (!HasAnyMapping)
			{
				return;
			}
			foreach (int moveBool in _moveBools)
			{
				_animator.SetBool(moveBool, isMoving);
			}
			foreach (int runBool in _runBools)
			{
				_animator.SetBool(runBool, isRunning);
			}
			foreach (int crouchBool in _crouchBools)
			{
				_animator.SetBool(crouchBool, isCrouching);
			}
			if (_speedFloats.Count <= 0)
			{
				return;
			}
			float num3 = ((!isMoving) ? 0f : (isRunning ? 1f : 0.5f));
			foreach (int speedFloat in _speedFloats)
			{
				_animator.SetFloat(speedFloat, num3);
			}
		}
	}
	internal sealed class BodyPark
	{
		private const float DriftTolerance = 0.75f;

		private const float DeliberateMoveDistance = 15f;

		private const float CorrectionCooldown = 0.5f;

		private const int MaxCorrections = 20;

		private Vector3 _spot;

		private Quaternion _rotation;

		private bool _weSetLockMove;

		private float _nextCorrection;

		private int _corrections;

		public bool Parked { get; private set; }

		public Vector3 Spot => _spot;

		public void Park()
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			PlayerManager localPlayerManager = NetworkContext.LocalPlayerManager;
			if ((Object)(object)localPlayerManager == (Object)null)
			{
				ModLog.Warning("Cannot park: no local player.");
				return;
			}
			_spot = ((Component)localPlayerManager).transform.position;
			_rotation = ((Component)localPlayerManager).transform.rotation;
			_nextCorrection = 0f;
			_corrections = 0;
			FPSController fpsScript = localPlayerManager.fpsScript;
			if ((Object)(object)fpsScript != (Object)null)
			{
				try
				{
					_weSetLockMove = !fpsScript.lockMove;
					fpsScript.lockMove = true;
					fpsScript.verticalVelocity = 0f;
				}
				catch (Exception ex)
				{
					ModLog.Warning("Could not lock body movement: " + ex.Message);
				}
			}
			Parked = true;
		}

		public void Hold()
		{
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_0181: Unknown result type (might be due to invalid IL or missing references)
			//IL_0187: Unknown result type (might be due to invalid IL or missing references)
			if (!Parked)
			{
				return;
			}
			PlayerManager localPlayerManager = NetworkContext.LocalPlayerManager;
			if ((Object)(object)localPlayerManager == (Object)null)
			{
				return;
			}
			FPSController fpsScript = localPlayerManager.fpsScript;
			if ((Object)(object)fpsScript != (Object)null)
			{
				try
				{
					if (!fpsScript.lockMove)
					{
						fpsScript.lockMove = true;
					}
				}
				catch
				{
				}
			}
			float num = Vector3.Distance(((Component)localPlayerManager).transform.position, _spot);
			if (num <= 0.75f)
			{
				return;
			}
			if (num >= 15f)
			{
				_spot = ((Component)localPlayerManager).transform.position;
				_rotation = ((Component)localPlayerManager).transform.rotation;
			}
			else
			{
				if (Time.time < _nextCorrection)
				{
					return;
				}
				_nextCorrection = Time.time + 0.5f;
				if (++_corrections > 20)
				{
					ModLog.Warning($"Body will not stay parked after {20} attempts - " + "leaving it where it is and unlocking it.");
					Unlock();
					Parked = false;
					return;
				}
				TeleportPlayer val = Teleporter(localPlayerManager);
				if (!((Object)(object)val == (Object)null))
				{
					try
					{
						val.RequestTeleport(_spot, _rotation);
					}
					catch (Exception ex)
					{
						ModLog.Warning("Drift correction failed, leaving the body where it is: " + ex.Message);
					}
				}
			}
		}

		public void Relocate(Vector3 position)
		{
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: 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)
			PlayerManager localPlayerManager = NetworkContext.LocalPlayerManager;
			if ((Object)(object)localPlayerManager == (Object)null)
			{
				return;
			}
			TeleportPlayer val = Teleporter(localPlayerManager);
			if ((Object)(object)val == (Object)null)
			{
				ModLog.Warning("No teleporter - body left where it was.");
				return;
			}
			try
			{
				val.RequestTeleport(position, _rotation);
				_spot = position;
			}
			catch (Exception ex)
			{
				ModLog.Warning("Could not bring the body over: " + ex.Message);
			}
		}

		private static TeleportPlayer Teleporter(PlayerManager pm)
		{
			try
			{
				if ((Object)(object)pm.tpPlayer != (Object)null)
				{
					return pm.tpPlayer;
				}
				ClientPlayer localPlayer = NetworkContext.LocalPlayer;
				if ((Object)(object)localPlayer != (Object)null && (Object)(object)localPlayer.teleportPlayer != (Object)null)
				{
					return localPlayer.teleportPlayer;
				}
			}
			catch
			{
			}
			return null;
		}

		private void Unlock()
		{
			if (!_weSetLockMove)
			{
				return;
			}
			_weSetLockMove = false;
			PlayerManager localPlayerManager = NetworkContext.LocalPlayerManager;
			FPSController val = (((Object)(object)localPlayerManager != (Object)null) ? localPlayerManager.fpsScript : null);
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			try
			{
				val.lockMove = false;
			}
			catch (Exception ex)
			{
				ModLog.Warning("Could not restore movement lock: " + ex.Message);
			}
		}

		public void Release()
		{
			if (Parked || _weSetLockMove)
			{
				Parked = false;
				Unlock();
			}
		}
	}
	internal sealed class MorphEntry
	{
		public string Name;

		public string Category;

		public GameObject Prefab;

		public bool Networked;

		public bool Curated;

		public bool Configured;

		public bool Released;

		public bool Verified;

		public float GroundOffset;

		public float ScaleOverride;

		public VerifiedEntity Anim;

		public string Label => (Configured ? "* " : "  ") + Name + (Networked ? "" : "  [local only]");
	}
	internal sealed class VerifiedEntity
	{
		public readonly string Match;

		public readonly float GroundOffset;

		public readonly float ScaleOverride;

		public readonly bool Released;

		public readonly float SweepRadius;

		public readonly string Walk;

		public readonly string Run;

		public readonly string Idle;

		public readonly string Action;

		public readonly string[] Pacify;

		public readonly string[] Hostility;

		public readonly string ActionMethod;

		public readonly string[] DeathFields;

		public readonly string[] ForceTrue;

		public readonly string FreezeField;

		public readonly string ActionTargetField;

		public readonly float ActionReleaseTime;

		public readonly string[] AttackGate;

		public readonly string SecondaryMethod;

		public readonly string[] SecondaryFields;

		public readonly float ActionDuration;

		public readonly float ActionCooldown;

		public readonly float SecondaryCooldown;

		public readonly string DetectionField;

		public readonly string DetectionListField;

		public readonly string DetectionThresholdField;

		public readonly string InFlightField;

		public VerifiedEntity(string match, float groundOffset = 0f, float scaleOverride = 0f, bool released = false, float sweepRadius = 0f, string walk = null, string run = null, string idle = null, string action = null, string[] pacify = null, string[] hostility = null, string[] attackGate = null, string actionMethod = null, string secondaryMethod = null, string[] deathFields = null, string[] forceTrue = null, string freezeField = null, string actionTargetField = null, float actionReleaseTime = 0f, string[] secondaryFields = null, float actionDuration = 1.5f, float actionCooldown = 1.2f, float secondaryCooldown = 2f, string detectionField = null, string detectionListField = null, string detectionThresholdField = null, string inFlightField = null)
		{
			Match = match;
			Released = released;
			GroundOffset = groundOffset;
			ScaleOverride = scaleOverride;
			SweepRadius = sweepRadius;
			Walk = walk;
			Run = run;
			Idle = idle;
			Action = action;
			Pacify = pacify;
			Hostility = hostility;
			AttackGate = attackGate;
			ActionMethod = actionMethod;
			DeathFields = deathFields;
			ForceTrue = forceTrue;
			FreezeField = freezeField;
			ActionTargetField = actionTargetField;
			ActionReleaseTime = actionReleaseTime;
			SecondaryMethod = secondaryMethod;
			SecondaryFields = secondaryFields;
			ActionDuration = actionDuration;
			ActionCooldown = actionCooldown;
			SecondaryCooldown = secondaryCooldown;
			DetectionField = detectionField;
			DetectionListField = detectionListField;
			DetectionThresholdField = detectionThresholdField;
			InFlightField = inFlightField;
		}
	}
	internal sealed class PlayableCreature
	{
		public readonly string Display;

		public readonly string Prefab;

		public PlayableCreature(string display, string prefab)
		{
			Display = display;
			Prefab = prefab;
		}
	}
	internal static class EntityCatalog
	{
		internal static readonly PlayableCreature[] Playables = new PlayableCreature[5]
		{
			new PlayableCreature("Spider", "Spider (Lv1)"),
			new PlayableCreature("Spider II", "Spider (Lv2)"),
			new PlayableCreature("Spider III", "Spider (Lv3)"),
			new PlayableCreature("Shrieking Doll", "Shrieking Doll LVL 1"),
			new PlayableCreature("Shrieking Doll II", "Shrieking Doll LVL 2")
		};

		private static readonly string[] BrowserPacify = new string[19]
		{
			"target", "goals", "generatedGoals", "useShelfGoals", "stopAtShelf", "goBehindCheckout", "waitingAtCounter", "hasPatience", "leaving", "forceTalkAtVeryStart",
			"dialogueInteractable", "_wanderAroundAimlessly", "timeStoppedWhileWandering", "isThief", "hasStolenItems", "doesntGiveBackItems", "countsAsCustomer", "addToReport", "startedFadingAway"
		};

		private static readonly string[] BrowserHostility = new string[3] { "chasingPlayer", "targPlayerMan", "attacking" };

		private static readonly string[] BrowserAttackGate = new string[1] { "chasingPlayer" };

		private static readonly string[] BrowserForceTrue = new string[1] { "canNeverInteract" };

		private static readonly VerifiedEntity[] Verified = new VerifiedEntity[23]
		{
			new VerifiedEntity("Rat", -0.08f, 0f, released: false, 0f, "Walk", null, "Idle", "Die"),
			new VerifiedEntity("Roach", -0.08f, 1f),
			new VerifiedEntity("Demented", -0.12f, 0f, released: false, 0f, "Standard Walk", "Standard Run", "Standard Idle", "Zombie Scream", new string[4] { "barricadeTarget", "breakingBarricade", "justAttackedBarricade", "spiderSpawn" }, new string[1] { "chaseTarget" }, new string[1] { "canAttack" }, null, null, null, null, "playersLookingAt", "chasingPlayerTarg"),
			new VerifiedEntity("Player Doppelgangers"),
			new VerifiedEntity("Player Doppelganger", -0.14f, 1f, released: false, 0f, "Standard Walk", "Standard Run", "Standard Idle", "Dancing", BrowserPacify, BrowserHostility, BrowserAttackGate, "Attack", "BreakFrontDoorBarricade", null, BrowserForceTrue, null, "targPlayerMan", 0f, null, 1.2f),
			new VerifiedEntity("PubertMotorCycle"),
			new VerifiedEntity("Pubert", -0.46f, 0f, released: false, 0f, "Standard Walk", "Standard Run", "Standard Idle", "Breakdancing", BrowserPacify, BrowserHostility, BrowserAttackGate, "Attack", "BreakFrontDoorBarricade", null, BrowserForceTrue, null, "targPlayerMan", 0f, null, 1.2f),
			new VerifiedEntity("Camouflaged", 0f, 0f, released: false, 0f, "Standard Walk", "Standard Run", "Standard Idle", "Airhorning"),
			new VerifiedEntity("Shrieking Doll", 0f, 0f, released: true, 0f, "Crawl", null, "Doll_Still", null, new string[8] { "barricadeTarget", "walkTarget", "breakingBarricade", "justAttackedBarricade", "chasingNonPlayerObject", "shotProj", "spiderSpawn", "dealtDamage" }, new string[3] { "chaseTarget", "scentTarget", "playerScentTarget" }, new string[1] { "canAttack" }, "JumpAtPlayer", null, forceTrue: new string[1] { "fastPacingButDontChasePlayer" }, deathFields: new string[2] { "died", "dealtDamage" }, freezeField: null, actionTargetField: "chasingPlayerTarg", actionReleaseTime: 3.5f, secondaryFields: null, actionDuration: 1.5f, actionCooldown: 1.2f, secondaryCooldown: 2f, detectionField: "detectionOfEachPlayer", detectionListField: "playerMans", detectionThresholdField: "detectsBeforeLookForJumpPoint", inFlightField: "actuallyJumping"),
			new VerifiedEntity("Bathroom Guy", -0.58f),
			new VerifiedEntity("Cow", -0.09f, 0f, released: false, 0f, "Walk", null, "Idle"),
			new VerifiedEntity("PET_Cat", -0.09f, 0f, released: false, 0f, "Arm_Cat|Walk_F_IP", "Arm_Cat|Run_F_IP", "Arm_Cat|Idle_1", "Arm_Cat|Lick"),
			new VerifiedEntity("PET_Puppy", -0.09f, 0f, released: false, 0f, "Arm_Labrador_Trot_F_IP", null, "Arm_Labrador_Idle_1", "Arm_Labrador_Eat_loop"),
			new VerifiedEntity("PET_Husky", -0.09f, 0f, released: false, 0f, "Arm_Husky_Trot_F_IP", null, "Arm_Husky_Idle_1", "Arm_Husky_Eat_loop"),
			new VerifiedEntity("PET_", -0.09f, 0f, released: false, 0f, "Walking", null, null, "Eat"),
			new VerifiedEntity("Tofu", -0.14f, 0f, released: false, 0f, "Walk", "Run", "Arm_Labrador|Idle_1", "Arm_Labrador|Bark", BrowserPacify, BrowserHostility, BrowserAttackGate, "Attack", "BreakFrontDoorBarricade", null, BrowserForceTrue, null, "targPlayerMan", 0f, null, 1.2f),
			new VerifiedEntity("Herbert", -0.12f, 0f, released: false, 0f, "Walk", "Run", "Idle", "Attack", BrowserPacify, BrowserHostility, BrowserAttackGate, "Attack", "BreakFrontDoorBarricade", null, BrowserForceTrue, null, "targPlayerMan", 0f, null, 1.2f),
			new VerifiedEntity("Marionette", 0f, 0f, released: false, 0f, "Bloodwraith_Idle", null, "Bloodwraith_Idle", "Marionette_Attack"),
			new VerifiedEntity("Fast Run", 0f, 0f, released: false, 0f, "Fast Run", "Fast Run", "Standing", "Zombie Attack"),
			new VerifiedEntity("Spider", 0f, 0f, released: true, 0f, null, null, null, "Attack", new string[9] { "silkEgg", "silkProjectile", "shotProj", "barricadeTarget", "ventTarget", "walkTarget", "breakingBarricade", "checkingVent", "chasingNonPlayerObject" }, new string[6] { "chasingPlayer", "chasingTarget", "chaseTarget", "chasingPlayerTarg", "scentTarget", "playerScentTarget" }, new string[1] { "canAttack" }, null, "PlaceInterstitialCobweb", null, null, null, null, 0f, new string[2] { "interstitialCobweb", "interstitialCobwebSpawnPoint" }),
			new VerifiedEntity("Dentist"),
			new VerifiedEntity("Vanessa"),
			new VerifiedEntity("Creepy Painting")
		};

		private static string[] _verifiedNames;

		private static List<MorphEntry> _entries;

		private static Dictionary<IntPtr, MorphEntry> _byObject;

		private static bool _prefabTableLoaded;

		public static string[] PlayableNames => Playables.Select((PlayableCreature p) => p.Display).ToArray();

		public static string[] VerifiedNames
		{
			get
			{
				if (_verifiedNames == null)
				{
					_verifiedNames = (from n in Verified.Select((VerifiedEntity v) => v.Match).Distinct()
						orderby n
						select n).ToArray();
				}
				return _verifiedNames;
			}
		}

		public static List<MorphEntry> Entries
		{
			get
			{
				if (_entries == null)
				{
					Build();
				}
				return _entries;
			}
		}

		public static List<MorphEntry> Supported => Entries.Where((MorphEntry e) => e.Released).ToList();

		private static VerifiedEntity FindVerified(string name)
		{
			VerifiedEntity[] verified = Verified;
			foreach (VerifiedEntity verifiedEntity in verified)
			{
				if (MatchesWord(name, verifiedEntity.Match))
				{
					return verifiedEntity;
				}
			}
			return null;
		}

		private static bool MatchesWord(string name, string match)
		{
			int startIndex = 0;
			while (true)
			{
				startIndex = name.IndexOf(match, startIndex, StringComparison.OrdinalIgnoreCase);
				if (startIndex < 0)
				{
					return false;
				}
				if (startIndex == 0 || !char.IsLetter(name[startIndex - 1]))
				{
					break;
				}
				startIndex++;
			}
			return true;
		}

		public static MorphEntry FindCurated(string match)
		{
			if (string.IsNullOrEmpty(match))
			{
				return null;
			}
			MorphEntry morphEntry = null;
			foreach (MorphEntry entry in Entries)
			{
				if (entry.Anim != null && string.Equals(entry.Anim.Match, match, StringComparison.OrdinalIgnoreCase))
				{
					if (entry.Networked)
					{
						return entry;
					}
					if (morphEntry == null)
					{
						morphEntry = entry;
					}
				}
			}
			return morphEntry;
		}

		public static void Invalidate()
		{
			_entries = null;
			_byObject = null;
			_prefabTableLoaded = false;
		}

		public static MorphEntry FindPlayable(string display)
		{
			if (string.IsNullOrWhiteSpace(display))
			{
				return null;
			}
			string wanted = display;
			PlayableCreature[] playables = Playables;
			foreach (PlayableCreature playableCreature in playables)
			{
				if (string.Equals(playableCreature.Display, display, StringComparison.OrdinalIgnoreCase))
				{
					wanted = playableCreature.Prefab;
					break;
				}
			}
			MorphEntry morphEntry = Resolve(wanted);
			if (morphEntry != null)
			{
				return morphEntry;
			}
			if (LoadPrefabTable())
			{
				morphEntry = Resolve(wanted);
				if (morphEntry != null)
				{
					return morphEntry;
				}
			}
			List<MorphEntry> supported = Supported;
			ModLog.Warning($"'{display}' was not found in this game build, even after loading the prefab table. Falling back to '{((supported.Count > 0) ? supported[0].Name : "nothing - no creature is available")}'.");
			return (supported.Count > 0) ? supported[0] : null;
		}

		private static MorphEntry Resolve(string wanted)
		{
			List<MorphEntry> supported = Supported;
			foreach (MorphEntry item in supported)
			{
				if (string.Equals(item.Name, wanted, StringComparison.OrdinalIgnoreCase))
				{
					return item;
				}
			}
			foreach (MorphEntry item2 in supported)
			{
				if (item2.Name.StartsWith(wanted, StringComparison.OrdinalIgnoreCase))
				{
					return item2;
				}
			}
			foreach (MorphEntry item3 in supported)
			{
				if (MatchesWord(item3.Name, wanted))
				{
					return item3;
				}
			}
			return null;
		}

		private static bool LoadPrefabTable()
		{
			if (_prefabTableLoaded || _byObject == null)
			{
				return false;
			}
			_prefabTableLoaded = true;
			Stopwatch stopwatch = Stopwatch.StartNew();
			int count = _byObject.Count;
			AddPrefabTable(_byObject);
			Compile();
			stopwatch.Stop();
			return true;
		}

		private static void Build()
		{
			_byObject = new Dictionary<IntPtr, MorphEntry>();
			_prefabTableLoaded = false;
			Stopwatch stopwatch = Stopwatch.StartNew();
			AddCurated(_byObject);
			Compile();
			stopwatch.Stop();
		}

		private static void Compile()
		{
			foreach (MorphEntry value in _byObject.Values)
			{
				VerifiedEntity verifiedEntity = FindVerified(value.Name);
				if (verifiedEntity != null)
				{
					value.Verified = true;
					value.Configured = (verifiedEntity.Pacify != null && verifiedEntity.Pacify.Length != 0) || (verifiedEntity.Hostility != null && verifiedEntity.Hostility.Length != 0);
					value.Released = verifiedEntity.Released;
					value.GroundOffset = verifiedEntity.GroundOffset;
					value.ScaleOverride = verifiedEntity.ScaleOverride;
					value.Anim = verifiedEntity;
				}
			}
			_entries = (from e in _byObject.Values
				where e.Networked
				orderby e.Released descending, e.Configured descending, e.Verified descending, e.Curated descending, e.Category, e.Name
				select e).ToList();
		}

		private static void Add(Dictionary<IntPtr, MorphEntry> map, GameObject go, string name, string category, bool curated)
		{
			if ((Object)(object)go == (Object)null)
			{
				return;
			}
			IntPtr pointer = ((Il2CppObjectBase)go).Pointer;
			if (map.TryGetValue(pointer, out var value))
			{
				if (curated && !value.Curated)
				{
					value.Name = name;
					value.Category = category;
					value.Curated = true;
				}
			}
			else if (HasVisibleGeometry(go))
			{
				map[pointer] = new MorphEntry
				{
					Name = (string.IsNullOrEmpty(name) ? ((Object)go).name : name),
					Category = category,
					Prefab = go,
					Networked = IsSpawnablePrefab(go),
					Curated = curated
				};
			}
		}

		private static void AddPrefabTable(Dictionary<IntPtr, MorphEntry> map)
		{
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				NetworkProjectConfig global = NetworkProjectConfig.Global;
				NetworkPrefabTable val = ((global != null) ? global.PrefabTable : null);
				List<INetworkPrefabSource> val2 = ((val != null) ? val._sources : null);
				if (val2 == null)
				{
					ModLog.Warning("Fusion prefab table unavailable.");
					return;
				}
				int num = 0;
				int num2 = 0;
				for (int i = 0; i < val2.Count; i++)
				{
					try
					{
						INetworkPrefabSource val3 = val2[i];
						if (val3 != null)
						{
							NetworkPrefabId id = val.GetId(val3.AssetGuid);
							NetworkObject val4 = val.Load(id, true);
							if ((Object)(object)val4 == (Object)null)
							{
								num2++;
								continue;
							}
							Add(map, ((Component)val4).gameObject, ((Object)((Component)val4).gameObject).name, "Networked", curated: false);
							num++;
						}
					}
					catch
					{
						num2++;
					}
				}
			}
			catch (Exception ex)
			{
				ModLog.Warning("Prefab table pass failed: " + ex.Message);
			}
		}

		private static bool HasVisibleGeometry(GameObject go)
		{
			if ((Object)(object)go.GetComponent<RectTransform>() != (Object)null)
			{
				return false;
			}
			if ((Object)(object)go.GetComponentInChildren<SkinnedMeshRenderer>(true) != (Object)null)
			{
				return true;
			}
			return (Object)(object)go.GetComponentInChildren<MeshRenderer>(true) != (Object)null;
		}

		private static bool IsSpawnablePrefab(GameObject go)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			if (!HasNetworkIdentity(go))
			{
				return false;
			}
			Scene scene = go.scene;
			return !((Scene)(ref scene)).IsValid();
		}

		private static bool HasNetworkIdentity(GameObject go)
		{
			if ((Object)(object)go == (Object)null)
			{
				return false;
			}
			try
			{
				return (Object)(object)go.GetComponent<NetworkObject>() != (Object)null;
			}
			catch
			{
				return false;
			}
		}

		private static void AddCurated(Dictionary<IntPtr, MorphEntry> map)
		{
			TryAdd(delegate
			{
				HuntManager instance = HuntManager.Instance;
				if (!((Object)(object)instance == (Object)null))
				{
					foreach (GameObject item in Interop.Safe<GameObject>(instance.monsterObjs))
					{
						Add(map, item, ((Object)item).name, "Monster", curated: true);
					}
					Add(map, instance.spiderLvl1, "Spider (Lv1)", "Monster", curated: true);
					Add(map, instance.spiderLvl2, "Spider (Lv2)", "Monster", curated: true);
					Add(map, instance.spiderLvl3, "Spider (Lv3)", "Monster", curated: true);
					Add(map, instance.jackInTheBox, "Jack In The Box", "Monster", curated: true);
				}
			}, "HuntManager");
			TryAdd(delegate
			{
				CurrentDayManager instance = CurrentDayManager.Instance;
				if ((Object)(object)instance == (Object)null)
				{
					return;
				}
				Add(map, instance.cow, "Cow", "Creature", curated: true);
				Add(map, instance.bathroomGuy, "Bathroom Guy", "Creature", curated: true);
				Add(map, instance.camouflagedMonster, "Camouflaged Monster", "Monster", curated: true);
				Add(map, instance.crawlingDentist, "Crawling Dentist", "Monster", curated: true);
				Add(map, instance.forestLimbs, "Forest Limbs", "Monster", curated: true);
				foreach (GameObject item2 in Interop.Safe<GameObject>(instance.allCars))
				{
					Add(map, item2, ((Object)item2).name, "Vehicle", curated: true);
				}
				foreach (GameObject item3 in Interop.Safe<GameObject>(instance.thieves))
				{
					Add(map, item3, ((Object)item3).name, "NPC", curated: true);
				}
				foreach (GameObject item4 in Interop.Safe<GameObject>(instance.eventNpcs))
				{
					Add(map, item4, ((Object)item4).name, "NPC", curated: true);
				}
				foreach (Pet item5 in Interop.Safe<Pet>(instance.allPets))
				{
					if ((Object)(object)item5 != (Object)null)
					{
						Add(map, ((Component)item5).gameObject, ((Object)((Component)item5).gameObject).name, "Pet", curated: true);
					}
				}
			}, "CurrentDayManager");
			TryAdd(delegate
			{
				EventManager instance = EventManager.Instance;
				if (!((Object)(object)instance == (Object)null))
				{
					Add(map, instance.playerDoppelganger, "Player Doppelganger", "Monster", curated: true);
					Add(map, instance.multiplePlayerDoppelgangers, "Player Doppelgangers (group)", "Monster", curated: true);
					Add(map, instance.rat, "Rat", "Creature", curated: true);
					Add(map, instance.roach, "Roach", "Creature", curated: true);
					if ((Object)(object)instance.vanessa != (Object)null)
					{
						Add(map, ((Component)instance.vanessa).gameObject, "Vanessa", "NPC", curated: true);
					}
				}
			}, "EventManager");
			TryAdd(delegate
			{
				StoreManager instance = StoreManager.Instance;
				if ((Object)(object)instance == (Object)null)
				{
					return;
				}
				foreach (GameObject item6 in Interop.Safe<GameObject>(instance.allBrowsingNpcs))
				{
					Add(map, item6, ((Object)item6).name, "Customer", curated: true);
				}
				foreach (GameObject item7 in Interop.Safe<GameObject>(instance.allNuisanceNpcs))
				{
					Add(map, item7, ((Object)item7).name, "Customer", curated: true);
				}
			}, "StoreManager");
		}

		private static void TryAdd(Action action, string source)
		{
			try
			{
				action();
			}
			catch (Exception ex)
			{
				ModLog.Warning("Curated source '" + source + "' failed: " + ex.Message);
			}
		}
	}
	internal static class GameInput
	{
		private static InputAction _move;

		private static InputAction _sprint;

		private static InputAction _jump;

		private static InputAction _crouch;

		private static bool _resolved;

		private static bool _loggedFallback;

		public static Vector2 Move
		{
			get
			{
				//IL_0069: Unknown result type (might be due to invalid IL or missing references)
				//IL_006e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0071: Unknown result type (might be due to invalid IL or missing references)
				//IL_002b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0024: Unknown result type (might be due to invalid IL or missing references)
				//IL_0030: Unknown result type (might be due to invalid IL or missing references)
				EnsureResolved();
				if (_move != null)
				{
					try
					{
						Object val = _move.ReadValueAsObject();
						return (val == null) ? Vector2.zero : ((Il2CppObjectBase)val).Unbox<Vector2>();
					}
					catch (Exception ex)
					{
						FallbackOnce("move read failed: " + ex.Message);
						_move = null;
					}
				}
				return new Vector2(Input.GetAxisRaw("Horizontal"), Input.GetAxisRaw("Vertical"));
			}
		}

		public static bool Sprint => Held(ref _sprint, (KeyCode)304);

		public static bool Jump => Held(ref _jump, (KeyCode)32);

		public static bool Crouch => Held(ref _crouch, (KeyCode)306);

		public static void Invalidate()
		{
			_resolved = false;
			_move = (_sprint = (_jump = (_crouch = null)));
		}

		private static void Resolve()
		{
			try
			{
				PlayerManager localPlayerManager = NetworkContext.LocalPlayerManager;
				FPSController val = (((Object)(object)localPlayerManager != (Object)null) ? localPlayerManager.fpsScript : null);
				PlayerInput val2 = (((Object)(object)val != (Object)null) ? val.playerInput : null);
				InputActionAsset val3 = (((Object)(object)val2 != (Object)null) ? val2.actions : null);
				if (!((Object)(object)val3 == (Object)null))
				{
					_move = val3.FindAction(InputConstants.k_MoveActionID, false);
					_sprint = val3.FindAction(InputConstants.k_SprintActionID, false);
					_jump = val3.FindAction(InputConstants.k_JumpActionID, false);
					_crouch = val3.FindAction(InputConstants.k_CrouchActionID, false);
					_resolved = _move != null;
				}
			}
			catch (Exception ex)
			{
				ModLog.Warning("Could not bind input actions, falling back to legacy: " + ex.Message);
			}
		}

		private static string Describe(InputAction action)
		{
			if (action == null)
			{
				return "unbound";
			}
			try
			{
				return "'" + action.name + "'";
			}
			catch
			{
				return "bound";
			}
		}

		private static void EnsureResolved()
		{
			if (!_resolved)
			{
				Resolve();
			}
		}

		private static bool Held(ref InputAction action, KeyCode legacy)
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			EnsureResolved();
			if (action != null)
			{
				try
				{
					return action.IsPressed();
				}
				catch (Exception ex)
				{
					FallbackOnce("button read failed: " + ex.Message);
					action = null;
				}
			}
			return Input.GetKey(legacy);
		}

		private static void FallbackOnce(string reason)
		{
			if (!_loggedFallback)
			{
				_loggedFallback = true;
				ModLog.Warning("Input System read failed, using legacy keys from here on (" + reason + "). Rebound keys and gamepads will not be honoured.");
			}
		}
	}
	internal static class Interop
	{
		private static Assembly _gameAssembly;

		private static Type[] _types;

		public static Assembly GameAssembly
		{
			get
			{
				if (_gameAssembly == null)
				{
					_gameAssembly = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault((Assembly a) => a.GetName().Name == "Assembly-CSharp");
				}
				return _gameAssembly;
			}
		}

		public static Type[] GameTypes
		{
			get
			{
				if (_types != null)
				{
					return _types;
				}
				Assembly gameAssembly = GameAssembly;
				if (gameAssembly == null)
				{
					return _types = Array.Empty<Type>();
				}
				try
				{
					_types = gameAssembly.GetTypes();
				}
				catch (ReflectionTypeLoadException ex)
				{
					_types = ex.Types.Where((Type t) => t != null).ToArray();
				}
				catch (Exception ex2)
				{
					ModLog.Warning("Could not enumerate game types: " + ex2.Message);
					_types = Array.Empty<Type>();
				}
				return _types;
			}
		}

		public static object WrapAs(Type generatedType, Component component)
		{
			return Activator.CreateInstance(generatedType, ((Il2CppObjectBase)component).Pointer);
		}

		public static Component FindComponent(GameObject go, Type generatedType, bool includeInactive = true)
		{
			Type val = Il2CppType.From(generatedType);
			if (val == (Type)null)
			{
				return null;
			}
			return go.GetComponentInChildren(val, includeInactive);
		}

		public static List<MoverType> DiscoverMoverTypes()
		{
			List<MoverType> list = new List<MoverType>();
			Type[] gameTypes = GameTypes;
			Type[] array = gameTypes;
			foreach (Type type in array)
			{
				if (type == null || !type.IsClass || type.IsAbstract)
				{
					continue;
				}
				PropertyInfo property = type.GetProperty("NetworkedPosition", BindingFlags.Instance | BindingFlags.Public);
				PropertyInfo property2 = type.GetProperty("NetworkedRotation", BindingFlags.Instance | BindingFlags.Public);
				if (!(property == null) && !(property2 == null) && property.CanWrite && property2.CanWrite && !(property.PropertyType != typeof(Vector3)) && !(property2.PropertyType != typeof(Quaternion)))
				{
					PropertyInfo propertyInfo = type.GetProperty("IsPositionInitialised", BindingFlags.Instance | BindingFlags.Public);
					if (propertyInfo != null && (!propertyInfo.CanWrite || propertyInfo.PropertyType != typeof(NetworkBool)))
					{
						propertyInfo = null;
					}
					list.Add(new MoverType
					{
						Type = type,
						Position = property,
						Rotation = property2,
						Initialised = propertyInfo
					});
				}
			}
			return list;
		}

		public static IEnumerable<T> Safe<T>(Il2CppReferenceArray<T> array) where T : Il2CppObjectBase
		{
			if (array == null)
			{
				yield break;
			}
			for (int i = 0; i < ((Il2CppArrayBase<T>)(object)array).Length; i++)
			{
				T v = ((Il2CppArrayBase<T>)(object)array)[i];
				if (v != null)
				{
					yield return v;
				}
			}
		}

		public static IEnumerable<T> Safe<T>(List<T> list)
		{
			if (list == null)
			{
				yield break;
			}
			for (int i = 0; i < list.Count; i++)
			{
				T v = list[i];
				if (v != null)
				{
					yield return v;
				}
			}
		}
	}
	internal sealed class MoverType
	{
		public Type Type;

		public PropertyInfo Position;

		public PropertyInfo Rotation;

		public PropertyInfo Initialised;
	}
	internal static class LocalModel
	{
		private const int MaxComponents = 4000;

		public static GameObject Create(GameObject prefab, Transform parent)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Expected O, but got Unknown
			//IL_00eb: 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)
			if ((Object)(object)prefab == (Object)null)
			{
				return null;
			}
			GameObject val = null;
			try
			{
				val = new GameObject("MorphHolder");
				val.SetActive(false);
				Object.DontDestroyOnLoad((Object)(object)val);
				GameObject val2 = Object.Instantiate<GameObject>(prefab, val.transform);
				int length = val2.GetComponentsInChildren<Component>(true).Length;
				if (length > 4000)
				{
					ModLog.Warning($"'{((Object)prefab).name}' has {length} components - too large to " + "strip safely, skipping to avoid freezing the game.");
					return null;
				}
				Stopwatch stopwatch = Stopwatch.StartNew();
				Strip(val2);
				Activate(val2);
				val2.transform.SetParent(parent, false);
				val2.transform.localPosition = Vector3.zero;
				val2.transform.localRotation = Quaternion.identity;
				((Object)val2).name = "Morph_" + ((Object)prefab).name;
				val2.SetActive(true);
				return val2;
			}
			catch (Exception value)
			{
				ModLog.Error($"Failed to build local model for '{((Object)prefab).name}': {value}");
				return null;
			}
			finally
			{
				if ((Object)(object)val != (Object)null)
				{
					Object.Destroy((Object)(object)val);
				}
			}
		}

		public static void Activate(GameObject root)
		{
			root.SetActive(true);
			foreach (SkinnedMeshRenderer componentsInChild in root.GetComponentsInChildren<SkinnedMeshRenderer>(true))
			{
				if ((Object)(object)componentsInChild == (Object)null)
				{
					continue;
				}
				((Renderer)componentsInChild).enabled = true;
				Transform val = ((Component)componentsInChild).transform;
				while ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)root.transform)
				{
					if (!((Component)val).gameObject.activeSelf)
					{
						((Component)val).gameObject.SetActive(true);
					}
					val = val.parent;
				}
			}
			foreach (MeshRenderer componentsInChild2 in root.GetComponentsInChildren<MeshRenderer>(true))
			{
				if ((Object)(object)componentsInChild2 != (Object)null && ((Component)componentsInChild2).gameObject.activeInHierarchy)
				{
					((Renderer)componentsInChild2).enabled = true;
				}
			}
		}

		private static void Strip(GameObject root)
		{
			Il2CppArrayBase<Component> componentsInChildren = root.GetComponentsInChildren<Component>(true);
			foreach (Component item in componentsInChildren)
			{
				if (!((Object)(object)item == (Object)null) && !((Object)(object)((Il2CppObjectBase)item).TryCast<Transform>() != (Object)null) && !((Object)(object)((Il2CppObjectBase)item).TryCast<Animator>() != (Object)null) && !((Object)(object)((Il2CppObjectBase)item).TryCast<SkinnedMeshRenderer>() != (Object)null) && !((Object)(object)((Il2CppObjectBase)item).TryCast<MeshRenderer>() != (Object)null) && !((Object)(object)((Il2CppObjectBase)item).TryCast<MeshFilter>() != (Object)null))
				{
					try
					{
						Object.DestroyImmediate((Object)(object)item, true);
					}
					catch
					{
					}
				}
			}
			foreach (Collider componentsInChild in root.GetComponentsInChildren<Collider>(true))
			{
				if ((Object)(object)componentsInChild != (Object)null)
				{
					try
					{
						Object.DestroyImmediate((Object)(object)componentsInChild, true);
					}
					catch
					{
					}
				}
			}
		}
	}
	internal static class ModLog
	{
		public static ManualLogSource Source;

		[Conditional("DEVTOOLS")]
		public static void Debug(string message)
		{
			ManualLogSource source = Source;
			if (source != null)
			{
				source.LogInfo((object)message);
			}
		}

		public static void Msg(string message)
		{
			ManualLogSource source = Source;
			if (source != null)
			{
				source.LogInfo((object)message);
			}
		}

		public static void Warning(string message)
		{
			ManualLogSource source = Source;
			if (source != null)
			{
				source.LogWarning((object)message);
			}
		}

		public static void Error(string message)
		{
			ManualLogSource source = Source;
			if (source != null)
			{
				source.LogError((object)message);
			}
		}
	}
	internal enum MorphMode
	{
		Phantom,
		Doppelganger,
		Puppet
	}
	[BepInPlugin("clementinise.shiftatmidnight.puppeteer", "Puppeteer", "1.0.0")]
	public class MorphPlugin : BasePlugin
	{
		public const string Guid = "clementinise.shiftatmidnight.puppeteer";

		internal static ConfigEntry<KeyCode> MorphKey;

		internal static ConfigEntry<KeyCode> MarkKey;

		internal static ConfigEntry<string> DefaultCreature;

		internal static ConfigEntry<MorphMode> Mode;

		public override void Load()
		{
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Expected O, but got Unknown
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			ModLog.Source = ((BasePlugin)this).Log;
			MorphKey = ((BasePlugin)this).Config.Bind<KeyCode>("Keybinds", "MorphKey", (KeyCode)285, "Become a creature, or return to your body. Also the way out if anything goes wrong.");
			MarkKey = ((BasePlugin)this).Config.Bind<KeyCode>("Keybinds", "MarkKey", (KeyCode)284, "Mark where you are standing. The next creature appears there instead of on you.");
			DefaultCreature = ((BasePlugin)this).Config.Bind<string>("Creature", "DefaultCreature", "Spider", new ConfigDescription("Which creature you become.", (AcceptableValueBase)(object)new AcceptableValueList<string>(EntityCatalog.PlayableNames), Array.Empty<object>()));
			Mode = ((BasePlugin)this).Config.Bind<MorphMode>("Creature", "Mode", MorphMode.Phantom, "Phantom: your body vanishes and you return to where you left it. Doppelganger: your body vanishes and you reappear where the creature was. Puppet: your body stays visible where it is while you drive the creature.");
			ClassInjector.RegisterTypeInIl2Cpp<MorphBehaviour>();
			((BasePlugin)this).AddComponent<MorphBehaviour>();
			ModLog.Msg($"Puppeteer ready [{Mode.Value}]. {MorphKey.Value} to swap into a creature and back, {MarkKey.Value} to mark a spawn point.");
		}
	}
	public class MorphBehaviour : MonoBehaviour
	{
		private PuppetController _puppet;

		private ThirdPersonView _thirdPerson;

		private int _lastSceneHandle;

		private float _nextHeartbeat;

		private static bool MenuOpen => false;

		public MorphBehaviour(IntPtr handle)
			: base(handle)
		{
		}

		private void Awake()
		{
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			_puppet = new PuppetController();
			_thirdPerson = new ThirdPersonView();
			_puppet.OnMorphed = delegate
			{
				_thirdPerson.Enable();
				_thirdPerson.SetDistance(_puppet.CameraDistance);
			};
			_puppet.OnReverted = delegate
			{
				_thirdPerson.Disable();
			};
			Scene activeScene = SceneManager.GetActiveScene();
			_lastSceneHandle = ((Scene)(ref activeScene)).handle;
		}

		[Conditional("DEVTOOLS")]
		private void Heartbeat()
		{
			if (Time.unscaledTime < _nextHeartbeat)
			{
				return;
			}
			_nextHeartbeat = Time.unscaledTime + 5f;
			if (!_puppet.Active && !_thirdPerson.Active && !MenuOpen)
			{
				return;
			}
			string text = "no player";
			try
			{
				PlayerManager localPlayerManager = NetworkContext.LocalPlayerManager;
				if ((Object)(object)localPlayerManager != (Object)null)
				{
					FPSController fpsScript = localPlayerManager.fpsScript;
					text = $"lockCam={(((Object)(object)fpsScript != (Object)null) ? fpsScript.lockCam.ToString() : "?")} lockMove={(((Object)(object)fpsScript != (Object)null) ? fpsScript.lockMove.ToString() : "?")} paused={localPlayerManager.paused} dead={localPlayerManager.dead} noCursorLock={localPlayerManager.dontAllowLockCursor} timeScale={Time.timeScale:0.##}";
				}
			}
			catch (Exception ex)
			{
				text = "read failed: " + ex.Message;
			}
		}

		private void Update()
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				DetectSceneChange();
				PauseSettings.Tick();
				Notify.Tick();
				if (Input.GetKeyDown(MorphPlugin.MorphKey.Value))
				{
					ToggleMorph();
				}
				if (Input.GetKeyDown(MorphPlugin.MarkKey.Value))
				{
					MarkSpawnPoint();
				}
				if (Input.GetMouseButtonDown(0) && !MenuOpen)
				{
					_puppet.PlayAction();
				}
				if (Input.GetMouseButtonDown(1) && !MenuOpen)
				{
					_puppet.PlaySecondary();
				}
				_puppet.Tick(_thirdPerson.Camera, !MenuOpen);
				_thirdPerson.Tick(!MenuOpen);
				if (_puppet.Active)
				{
					_thirdPerson.Target = _puppet.PuppetAnchor;
					_thirdPerson.PivotHeight = _puppet.CameraPivotHeight;
				}
				else
				{
					_thirdPerson.Target = null;
				}
			}
			catch (Exception value)
			{
				ModLog.Error($"Update: {value}");
			}
		}

		private static bool HostOnlyRefused()
		{
			MorphTier tier = NetworkContext.Tier;
			object message;
			switch (tier)
			{
			case MorphTier.Authority:
				return false;
			default:
				message = "Not in a game yet - nothing to morph into";
				break;
			case MorphTier.Client:
				message = "You are not the host - only the host can morph";
				break;
			}
			Notify.Show((string)message);
			ModLog.Msg($"Refused: tier is {tier}, host or solo required.");
			return true;
		}

		private void ToggleMorph()
		{
			if (_puppet.Active || _thirdPerson.Active)
			{
				ResetEverything();
			}
			else if (!HostOnlyRefused())
			{
				MorphEntry morphEntry;
				try
				{
					morphEntry = EntityCatalog.FindPlayable(MorphPlugin.DefaultCreature.Value);
				}
				catch (Exception ex)
				{
					ModLog.Error("Creature list: " + ex.Message);
					return;
				}
				if (morphEntry == null)
				{
					ModLog.Msg("No creatures available yet - the list is built when a day loads.");
				}
				else
				{
					_puppet.Apply(morphEntry);
				}
			}
		}

		private void MarkSpawnPoint()
		{
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0172: Unknown result type (might be due to invalid IL or missing references)
			if (HostOnlyRefused())
			{
				return;
			}
			if (MorphPlugin.Mode.Value == MorphMode.Doppelganger)
			{
				Notify.Show("Not used in Doppelganger - you swap places with the creature");
				return;
			}
			if (_puppet.SpawnOverride.HasValue)
			{
				_puppet.SpawnOverride = null;
				Notify.Show("Spawn point cleared");
				ModLog.Msg("Spawn point cleared - creatures appear where you are again.");
				return;
			}
			PlayerManager localPlayerManager = NetworkContext.LocalPlayerManager;
			if ((Object)(object)localPlayerManager == (Object)null)
			{
				Notify.Show("No player to mark from");
				return;
			}
			Vector3 value = (_puppet.Active ? _puppet.PuppetAnchor : ((Component)localPlayerManager).transform.position);
			_puppet.SpawnOverride = value;
			Notify.Show($"Spawn point set - press {MorphPlugin.MarkKey.Value} again to clear");
			ModLog.Msg($"Spawn point set at {((Vector3)(ref value)).ToString("0.#")} - creatures will appear there until you press {MorphPlugin.MarkKey.Value} again.");
		}

		private void ResetEverything()
		{
			try
			{
				_thirdPerson.Disable();
			}
			catch (Exception ex)
			{
				ModLog.Error("Reset camera: " + ex.Message);
			}
			try
			{
				_puppet.Revert();
			}
			catch (Exception ex2)
			{
				ModLog.Error("Reset puppet: " + ex2.Message);
			}
			try
			{
				PlayerManager localPlayerManager = NetworkContext.LocalPlayerManager;
				if ((Object)(object)localPlayerManager != (Object)null)
				{
					localPlayerManager.dontAllowLockCursor = false;
					FPSController fpsScript = localPlayerManager.fpsScript;
					if ((Object)(object)fpsScript != (Object)null)
					{
						fpsScript.lockCam = false;
						fpsScript.lockMove = false;
						fpsScript.LockCursor();
					}
				}
			}
			catch (Exception ex3)
			{
				ModLog.Error("Reset input: " + ex3.Message);
			}
			ModLog.Msg("Reset - body restored, camera unlocked.");
		}

		private void FixedUpdate()
		{
			try
			{
				_puppet.FixedTick();
			}
			catch (Exception value)
			{
				ModLog.Error($"FixedUpdate: {value}");
			}
		}

		private void LateUpdate()
		{
			try
			{
				_puppet.ReassertHide();
				_puppet.TickPendingRestore();
				_puppet.TickRealign();
				_thirdPerson.LateTick();
			}
			catch (Exception value)
			{
				ModLog.Error($"LateUpdate: {value}");
			}
		}

		private void OnDestroy()
		{
			try
			{
				ResetEverything();
			}
			catch
			{
			}
		}

		private void DetectSceneChange()
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			Scene activeScene = SceneManager.GetActiveScene();
			int handle = ((Scene)(ref activeScene)).handle;
			if (handle != _lastSceneHandle)
			{
				_lastSceneHandle = handle;
				_puppet.Revert();
				_thirdPerson.Disable();
				EntityCatalog.Invalidate();
				PauseSettings.Forget();
				Notify.Forget();
				_puppet.SpawnOverride = null;
				GameInput.Invalidate();
			}
		}
	}
	internal enum MorphTier
	{
		Offline,
		Authority,
		Client
	}
	internal static class NetworkContext
	{
		public static NetworkRunner Runner
		{
			get
			{
				FusionNetworkManager instance = FusionNetworkManager.Instance;
				if ((Object)(object)instance == (Object)null)
				{
					return null;
				}
				NetworkRunner runner = instance._runner;
				if ((Object)(object)runner == (Object)null || !runner.IsRunning)
				{
					return null;
				}
				return runner;
			}
		}

		public static MorphTier Tier
		{
			get
			{
				NetworkRunner runner = Runner;
				if ((Object)(object)runner == (Object)null)
				{
					return MorphTier.Offline;
				}
				if (runner.IsServer && runner.CanSpawn)
				{
					return MorphTier.Authority;
				}
				return MorphTier.Client;
			}
		}

		public static string TierDescription => Tier switch
		{
			MorphTier.Authority => "Host/Solo - everyone sees your morph, mod or not", 
			MorphTier.Client => "Client - morphing is disabled, only the host can morph", 
			_ => "Not in a session", 
		};

		public static ClientPlayer LocalPlayer => ClientPlayer.Instance;

		public static PlayerManager LocalPlayerManager
		{
			get
			{
				ClientPlayer instance = ClientPlayer.Instance;
				return ((Object)(object)instance == (Object)null) ? null : instance.playerMan;
			}
		}

		public static ThirdPersonManager LocalBody
		{
			get
			{
				PlayerManager localPlayerManager = LocalPlayerManager;
				return ((Object)(object)localPlayerManager == (Object)null) ? null : localPlayerManager.thirdPersonMan;
			}
		}
	}
	internal static class Notify
	{
		private const float DefaultSeconds = 3f;

		private const float BottomMargin = 140f;

		private static GameObject _label;

		private static TextMeshProUGUI _text;

		private static float _hideAt;

		private static float _nextComplaint;

		public static void Show(string message, float seconds = 3f)
		{
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			if (string.IsNullOrWhiteSpace(message))
			{
				return;
			}
			try
			{
				if (Ensure())
				{
					((TMP_Text)_text).text = message;
					((TMP_Text)_text).alpha = 1f;
					Color color = ((Graphic)_text).color;
					((Graphic)_text).color = new Color(color.r, color.g, color.b, 1f);
					((Behaviour)_text).enabled = true;
					_label.SetActive(true);
					_hideAt = Time.unscaledTime + seconds;
				}
			}
			catch (Exception ex)
			{
				ModLog.Warning("Notification failed: " + ex.Message);
			}
		}

		public static void Tick()
		{
			if ((Object)(object)_label == (Object)null || !_label.activeSelf || Time.unscaledTime < _hideAt)
			{
				return;
			}
			try
			{
				_label.SetActive(false);
			}
			catch
			{
			}
		}

		public static void Forget()
		{
			_label = null;
			_text = null;
			_hideAt = 0f;
		}

		private static bool Ensure()
		{
			//IL_0134: 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_0160: Unknown result type (might be due to invalid IL or missing references)
			//IL_0176: Unknown result type (might be due to invalid IL or missing references)
			//IL_0182: 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_019a: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cc: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_label != (Object)null && (Object)(object)_text != (Object)null)
			{
				return true;
			}
			TextMeshProUGUI val = Source();
			if ((Object)(object)val == (Object)null)
			{
				Complain("StoreManager.hintText is not available yet");
				return false;
			}
			Canvas val2 = LiveCanvas();
			if ((Object)(object)val2 == (Object)null)
			{
				Complain("no live UI canvas to attach to");
				return false;
			}
			_label = Object.Instantiate<GameObject>(((Component)val).gameObject, ((Component)val2).transform);
			((Object)_label).name = "Puppeteer Notification";
			_text = _label.GetComponent<TextMeshProUGUI>();
			if ((Object)(object)_text == (Object)null)
			{
				_text = _label.GetComponentInChildren<TextMeshProUGUI>(true);
			}
			if ((Object)(object)_text == (Object)null)
			{
				Object.Destroy((Object)(object)_label);
				_label = null;
				Complain("the cloned label has no TextMeshProUGUI");
				return false;
			}
			StripInterference(_label);
			RectTransform component = _label.GetComponent<RectTransform>();
			if ((Object)(object)component != (Object)null)
			{
				component.anchorMin = new Vector2(0.5f, 0f);
				component.anchorMax = new Vector2(0.5f, 0f);
				component.pivot = new Vector2(0.5f, 0f);
				component.anchoredPosition = new Vector2(0f, 140f);
				((Transform)component).localScale = Vector3.one;
				((Transform)component).localRotation = Quaternion.identity;
				if (component.sizeDelta.x < 400f)
				{
					component.sizeDelta = new Vector2(900f, Mathf.Max(component.sizeDelta.y, 60f));
				}
			}
			try
			{
				((TMP_Text)_text).alignment = (TextAlignmentOptions)514;
				((TMP_Text)_text).enableAutoSizing = false;
			}
			catch
			{
			}
			_label.transform.SetAsLastSibling();
			_label.SetActive(false);
			return true;
		}

		private static void Complain(string why)
		{
			if (!(Time.unscaledTime < _nextComplaint))
			{
				_nextComplaint = Time.unscaledTime + 10f;
				ModLog.Warning("[notify] cannot build the label yet - " + why + ".");
			}
		}

		private static void StripInterference(GameObject go)
		{
			StringBuilder stringBuilder = new StringBuilder();
			foreach (Component componentsInChild in go.GetComponentsInChildren<Component>(true))
			{
				if ((Object)(object)componentsInChild == (Object)null)
				{
					continue;
				}
				string text = TypeName(componentsInChild);
				if (text == "LanguageText" || text.IndexOf("Fade", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("Animator", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("Hint", StringComparison.OrdinalIgnoreCase) >= 0)
				{
					try
					{
						Object.Destroy((Object)(object)componentsInChild);
						stringBuilder.Append(text).Append(' ');
					}
					catch
					{
					}
				}
			}
			foreach (CanvasGroup componentsInChild2 in go.GetComponentsInChildren<CanvasGroup>(true))
			{
				if (!((Object)(object)componentsInChild2 == (Object)null))
				{
					try
					{
						componentsInChild2.alpha = 1f;
						componentsInChild2.blocksRaycasts = false;
						componentsInChild2.interactable = false;
					}
					catch
					{
					}
				}
			}
			if (stringBuilder.Length <= 0)
			{
			}
		}

		private static TextMeshProUGUI Source()
		{
			try
			{
				StoreManager instance = StoreManager.Instance;
				return ((Object)(object)instance != (Object)null) ? instance.hintText : null;
			}
			catch
			{
				return null;
			}
		}

		private static Canvas LiveCanvas()
		{
			try
			{
				PlayerManager localPlayerManager = NetworkContext.LocalPlayerManager;
				GameObject val = (((Object)(object)localPlayerManager != (Object)null) ? localPlayerManager.pauseMenu : null);
				if ((Object)(object)val == (Object)null)
				{
					return null;
				}
				Canvas val2 = Highest(val.transform);
				if ((Object)(object)val2 == (Object)null)
				{
					return null;
				}
				if (!((Component)val2).gameObject.activeInHierarchy)
				{
					Complain("canvas '" + ((Object)val2).name + "' is inactive");
					return null;
				}
				return val2;
			}
			catch
			{
				return null;
			}
		}

		private static Canvas Highest(Transform from)
		{
			Canvas result = null;
			try
			{
				Transform val = from;
				while ((Object)(object)val != (Object)null)
				{
					Canvas component = ((Component)val).GetComponent<Canvas>();
					if ((Object)(object)component != (Object)null)
					{
						result = component;
					}
					val = val.parent;
				}
			}
			catch
			{
			}
			return result;
		}

		private static string Describe(GameObject go)
		{
			StringBuilder stringBuilder = new StringBuilder();
			foreach (Component component in go.GetComponents<Component>())
			{
				if ((Object)(object)component != (Object)null)
				{
					stringBuilder.Append(TypeName(component)).Append(' ');
				}
			}
			return stringBuilder.ToString();
		}

		private static string TypeName(Component c)
		{
			try
			{
				string text = ((Object)c).ToString();
				int num = text.LastIndexOf('(');
				int num2 = text.LastIndexOf(')');
				if (num < 0 || num2 <= num)
				{
					return text;
				}
				string text2 = text.Substring(num + 1, num2 - num - 1);
				int num3 = text2.LastIndexOf('.');
				return (num3 >= 0) ? text2.Substring(num3 + 1) : text2;
			}
			catch
			{
				return "?";
			}
		}
	}
	internal static class PauseSettings
	{
		private const string ButtonHolder = "Button Vertical Layout Group";

		private const string ButtonTemplate = "Button Vertical Layout Group/Audio Button";

		private static readonly Vector2 CornerMargin = new Vector2(-70f, 60f);

		private const string PanelTemplate = "Video Menu";

		private const string ContentPath = "Scroll View/Viewport/Content";

		private const string KeyRowTemplate = "Controls Menu/Scroll View/Viewport/Content/Jump";

		private const string DropRowTemplate = "Video Menu/Scroll View/Viewport/Content/Change Resolution";

		private static GameObject _builtFor;

		private static GameObject _panel;

		private static GameObject _button;

		private static PauseMenu _pauseMenu;

		private static ControlsMenuSwitcher _switcher;

		private static Transform _holder;

		private static Transform _proxy;

		private static readonly List<GameObject> _overlays = new List<GameObject>();

		private static ConfigEntry<KeyCode> _capturing;

		private static TextMeshProUGUI _capturingText;

		private static GameObject _capturingBar;

		private static readonly KeyCode[] _keyCodes = BuildKeyCodes();

		public static void Tick()
		{
			try
			{
				PlayerManager localPlayerManager = NetworkContext.LocalPlayerManager;
				GameObject val = (((Object)(object)localPlayerManager != (Object)null) ? localPlayerManager.pauseMenu : null);
				if (!((Object)(object)val == (Object)null))
				{
					if ((Object)(object)_button == (Object)null || (Object)(object)_builtFor != (Object)(object)val)
					{
						Build(val);
					}
					FollowMenuVisibility();
					YieldToOtherMenus();
					CloseWithMenu(val);
					TickCapture();
				}
			}
			catch (Exception value)
			{
				ModLog.Error($"Pause settings: {value}");
				_builtFor = null;
			}
		}

		public static void Forget()
		{
			_builtFor = null;
			_panel = null;
			_button = null;
			_holder = null;
			_proxy = null;
			_overlays.Clear();
			_pauseMenu = null;
			_capturing = null;
		}

		private static void FollowMenuVisibility()
		{
			if (!((Object)(object)_button == (Object)null) && !((Object)(object)_proxy == (Object)null))
			{
				bool flag = ((Component)_proxy).gameObject.activeInHierarchy && Alpha(_proxy) > 0.01f && !AnyMenuOpen();
				if (_button.activeSelf != flag)
				{
					_button.SetActive(flag);
				}
			}
		}

		private static bool AnyMenuOpen()
		{
			if (AnyOverlayOpen())
			{
				return true;
			}
			try
			{
				if ((Object)(object)_pauseMenu == (Object)null)
				{
					return false;
				}
				if (_pauseMenu.inSubMenu)
				{
					return true;
				}
				Il2CppReferenceArray<GameObject> subMenus = _pauseMenu.subMenus;
				if (subMenus == null)
				{
					return false;
				}
				for (int i = 0; i < ((Il2CppArrayBase<GameObject>)(object)subMenus).Length; i++)
				{
					if ((Object)(object)((Il2CppArrayBase<GameObject>)(object)subMenus)[i] != (Object)null && ((Il2CppArrayBase<GameObject>)(object)subMenus)[i].activeSelf)
					{
						return true;
					}
				}
			}
			catch
			{
			}
			return false;
		}

		private static void CollectOverlays(GameObject menu)
		{
			_overlays.Clear();
			try
			{
				if ((Object)(object)_switcher != (Object)null)
				{
					Add(_switcher.gamepadControls);
				}
				foreach (KickPlayerMenu componentsInChild in menu.GetComponentsInChildren<KickPlayerMenu>(true))
				{
					if ((Object)(object)componentsInChild != (Object)null)
					{
						_overlays.Add(((Component)componentsInChild).gameObject);
					}
				}
			}
			catch (Exception ex)
			{
				ModLog.Warning("[pause] overlay scan: " + ex.Message);
			}
		}

		private static void Add(Il2CppReferenceArray<GameObject> items)
		{
			if (items == null)
			{
				return;
			}
			for (int i = 0; i < ((Il2CppArrayBase<GameObject>)(object)items).Length; i++)
			{
				if ((Object)(object)((Il2CppArrayBase<GameObject>)(object)items)[i] != (Object)null)
				{
					_overlays.Add(((Il2CppArrayBase<GameObject>)(object)items)[i]);
				}
			}
		}

		private static bool AnyOverlayOpen()
		{
			for (int i = 0; i < _overlays.Count; i++)
			{
				GameObject val = _overlays[i];
				if ((Object)(object)val != (Object)null && val.activeInHierarchy)
				{
					return true;
				}
			}
			return false;
		}

		private static float Alpha(Transform t)
		{
			float num = 1f;
			try
			{
				Transform val = t;
				while ((Object)(object)val != (Object)null)
				{
					CanvasGroup component = ((Component)val).GetComponent<CanvasGroup>();
					if ((Object)(object)component != (Object)null)
					{
						num *= component.alpha;
						if (component.ignoreParentGroups)
						{
							break;
						}
					}
					val = val.parent;
				}
			}
			catch
			{
			}
			return num;
		}

		private static void YieldToOtherMenus()
		{
			if ((Object)(object)_panel == (Object)null || !_panel.activeSelf)
			{
				return;
			}
			if (AnyOverlayOpen())
			{
				_panel.SetActive(false);
				return;
			}
			try
			{
				Il2CppReferenceArray<GameObject> val = (((Object)(object)_pauseMenu != (Object)null) ? _pauseMenu.subMenus : null);
				if (val == null)
				{
					return;
				}
				for (int i = 0; i < ((Il2CppArrayBase<GameObject>)(object)val).Length; i++)
				{
					GameObject val2 = ((Il2CppArrayBase<GameObject>)(object)val)[i];
					if (!((Object)(object)val2 == (Object)null) && !(((Il2CppObjectBase)val2).Pointer == ((Il2CppObjectBase)_panel).Pointer) && val2.activeSelf)
					{
						_panel.SetActive(false);
						break;
					}
				}
			}
			catch
			{
			}
		}

		private static void CloseWithMenu(GameObject menu)
		{
			if (!((Object)(object)_panel == (Object)null) && _panel.activeSelf && !menu.activeInHierarchy)
			{
				_panel.SetActive(false);
			}
		}

		private static void Build(GameObject menu)
		{
			Transform transform = menu.transform;
			Transform template = Require(transform, "Button Vertical Layout Group/Audio Button");
			Transform template2 = Require(transform, "Video Menu");
			Transform keyRow = Require(transform, "Controls Menu/Scroll View/Viewport/Content/Jump");
			Transform dropRow = Require(transform, "Video Menu/Scroll View/Viewport/Content/Change Resolution");
			Transform val = Require(transform, "Button Vertical Layout Group");
			_proxy = transform.Find("Button Vertical Layout Group/Quit Button");
			if ((Object)(object)_proxy == (Object)null)
			{
				_proxy = val;
			}
			CollectOverlays(menu);
			_pauseMenu = menu.GetComponentInChildren<PauseMenu>(true);
			_switcher = menu.GetComponentInChildren<ControlsMenuSwitcher>(true);
			_panel = BuildPanel(template2, keyRow, dropRow);
			_button = BuildButton(template, transform, ScreenRect(menu));
			_holder = val;
			_builtFor = menu;
			RegisterSubMenu(_panel);
		}

		private static GameObject BuildPanel(Transform template, Transform keyRow, Transform dropRow)
		{
			GameObject val = Object.Instantiate<GameObject>(((Component)template).gameObject, template.parent);
			((Object)val).name = "Puppeteer Menu";
			val.SetActive(false);
			Transform val2 = val.transform.Find("TITLE");
			if ((Object)(object)val2 != (Object)null)
			{
				SetLabel(((Component)val2).gameObject, "PUPPETEER");
			}
			Transform val3 = val.transform.Find("Scroll View/Viewport/Content");
			if ((Object)(object)val3 == (Object)null)
			{
				throw new InvalidOperationException("Cloned panel has no Content.");
			}
			for (int num = val3.childCount - 1; num >= 0; num--)
			{
				Object.DestroyImmediate((Object)(object)((Component)val3.GetChild(num)).gameObject);
			}
			AddDropdownRow(val3, dropRow, "Creature", MorphPlugin.DefaultCreature, EntityCatalog.PlayableNames);
			AddModeRow(val3, dropRow, "Mode", MorphPlugin.Mode);
			AddKeyRow(val3, keyRow, "Become creature / return", MorphPlugin.MorphKey);
			AddKeyRow(val3, keyRow, "Mark spawn point", MorphPlugin.MarkKey);
			return val;
		}

		private static RectTransform ScreenRect(GameObject menu)
		{
			try
			{
				Canvas componentInParent = menu.GetComponentInParent<Canvas>();
				if ((Object)(object)componentInParent == (Object)null)
				{
					return null;
				}
				Canvas val = (((Object)(object)componentInParent.rootCanvas != (Object)null) ? componentInParent.rootCanvas : componentInParent);
				RectTransform component = ((Component)val).GetComponent<RectTransform>();
				if ((Object)(object)component != (Object)null)
				{
				}
				return component;
			}
			catch
			{
				return null;
			}
		}

		private static GameObject BuildButton(Transform template, Transform menuRoot, RectTransform screen)
		{
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: 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_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			DestroyStrays(screen);
			Transform val = (((Object)(object)screen != (Object)null) ? ((Component)screen).transform : menuRoot);
			GameObject val2 = Object.Instantiate<GameObject>(((Component)template).gameObject, val);
			((Object)val2).name = "Puppeteer Button";
			SetLabel(val2, "PUPPETEER");
			RectTransform component = val2.GetComponent<RectTransform>();
			if ((Object)(object)component != (Object)null)
			{
				component.anchorMin = new Vector2(1f, 0f);
				component.anchorMax = new Vector2(1f, 0f);
				component.pivot = new Vector2(1f, 0f);
				component.anchoredPosition = CornerMargin;
				((Transform)component).localScale = Vector3.one;
				((Transform)component).localRotation = Quaternion.identity;
			}
			val2.transform.SetAsLastSibling();
			Wire(val2, Open);
			return val2;
		}

		private static void DestroyStrays(RectTransform screen)
		{
			if ((Object)(object)screen == (Object)null)
			{
				return;
			}
			try
			{
				for (int num = ((Transform)screen).childCount - 1; num >= 0; num--)
				{
					Transform child = ((Transform)screen).GetChild(num);
					if ((Object)(object)child != (Object)null && ((Object)((Component)child).gameObject).name == "Puppeteer Button")
					{
						Object.DestroyImmediate((Object)(object)((Component)child).gameObject);
					}
				}
			}
			catch
			{
			}
		}

		private static void Wire(GameObject go, Action onClick)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Expected O, but got Unknown
			Button component = go.GetComponent<Button>();
			if (!((Object)(object)component == (Object)null))
			{
				component.onClick = new ButtonClickedEvent();
				((UnityEvent)component.onClick).AddListener(DelegateSupport.ConvertDelegate<UnityAction>((Delegate)onClick));
			}
		}

		private static void AddKeyRow(Transform content, Transform template, string label, ConfigEntry<KeyCode> entry)
		{
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			if (entry == null)
			{
				return;
			}
			GameObject val = Object.Instantiate<GameObject>(((Component)template).gameObject, content);
			((Object)val).name = "Key " + label;
			val.SetActive(true);
			Transform val2 = val.transform.Find("Title");
			if ((Object)(object)val2 != (Object)null)
			{
				SetLabel(((Component)val2).gameObject, label);
			}
			Transform val3 = val.transform.Find("Button");
			if (!((Object)(object)val3 == (Object)null))
			{
				TextMeshProUGUI text = ((Component)val3).GetComponentInChildren<TextMeshProUGUI>(true);
				Transform bar = val.transform.Find("EditingBar");
				if ((Object)(object)text != (Object)null)
				{
					Strip(((Component)text).gameObject);
					((TMP_Text)text).text = ((object)entry.Value/*cast due to .constrained prefix*/).ToString();
				}
				Wire(((Component)val3).gameObject, delegate
				{
					BeginCapture(entry, text, ((Object)(object)bar != (Object)null) ? ((Component)bar).gameObject : null);
				});
			}
		}

		private static void AddModeRow(Transform content, Transform template, string label, ConfigEntry<MorphMode> entry)
		{
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Expected O, but got Unknown
			if (entry == null)
			{
				return;
			}
			MorphMode[] modes = (MorphMode[])Enum.GetValues(typeof(MorphMode));
			string[] array = new string[modes.Length];
			for (int i = 0; i < modes.Length; i++)
			{
				array[i] = modes[i].ToString();
			}
			TMP_Dropdown val = BuildDropdown(content, template, label, array, Array.IndexOf(modes, entry.Value));
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			val.onValueChanged = new DropdownEvent();
			((UnityEvent<int>)(object)val.onValueChanged).AddListener(DelegateSupport.ConvertDelegate<UnityAction<int>>((Delegate)(Action<int>)delegate(int index)
			{
				if (index >= 0 && index < modes.Length)
				{
					entry.Value = modes[index];
				}
			}));
		}

		private static void AddDropdownRow(Transform content, Transform template, string label, ConfigEntry<string> entry, string[] options)
		{
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Expected O, but got Unknown
			if (entry == null || options == null || options.Length == 0)
			{
				return;
			}
			int selected = 0;
			for (int i = 0; i < options.Length; i++)
			{
				if (string.Equals(options[i], entry.Value, StringComparison.OrdinalIgnoreCase))
				{
					selected = i;
				}
			}
			TMP_Dropdown val = BuildDropdown(content, template, label, options, selected);
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			val.onValueChanged = new DropdownEvent();
			((UnityEvent<int>)(object)val.onValueChanged).AddListener(DelegateSupport.ConvertDelegate<UnityAction<int>>((Delegate)(Action<int>)delegate(int index)
			{
				if (index >= 0 && index < options.Length)
				{
					entry.Value = options[index];
				}
			}));
		}

		private static TMP_Dropdown BuildDropdown(Transform content, Transform template, string label, string[] options, int selected)
		{
			GameObject val = Object.Instantiate<GameObject>(((Component)template).gameObject, content);
			((Object)val).name = "Choice " + label;
			val.SetActive(true);
			Transform val2 = val.transform.Find("Title");
			if ((Object)(object)val2 != (Object)null)
			{
				SetLabel(((Component)val2).gameObject, label);
			}
			TMP_Dropdown componentInChildren = val.GetComponentInChildren<TMP_Dropdown>(true);
			if ((Object)(object)componentInChildren == (Object)null)
			{
				return null;
			}
			StripForeignBehaviours(((Component)componentInChildren).gameObject);
			List<string> val3 = new List<string>();
			for (int i = 0; i < options.Length; i++)
			{
				val3.Add(options[i]);
			}
			componentInChildren.ClearOptions();
			componentInChildren.AddOptions(val3);
			componentInChildren.SetValueWithoutNotify(Mathf.Clamp(selected, 0, Mathf.Max(options.Length - 1, 0)));
			componentInChildren.RefreshShownValue();
			return componentInChildren;
		}

		private static void BeginCapture(ConfigEntry<KeyCode> entry, TextMeshProUGUI text, GameObject bar)
		{
			CancelCapture();
			_capturing = entry;
			_capturingText = text;
			_capturingBar = bar;
			if ((Object)(object)_capturingText != (Object)null)
			{
				((TMP_Text)_capturingText).text = "...";
			}
			if ((Object)(object)_capturingBar != (Object)null)
			{
				_capturingBar.SetActive(true);
			}
		}

		private static void CancelCapture()
		{
			if ((Object)(object)_capturingBar != (Object)null)
			{
				_capturingBar.SetActive(false);
			}
			_capturing = null;
			_capturingText = null;
			_capturingBar = null;
		}

		private unsafe static void TickCapture()
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			if (_capturing == null || !Input.anyKeyDown)
			{
				return;
			}
			if (Input.GetKeyDown((KeyCode)27))
			{
				KeyCode value = _capturing.Value;
				TextMeshProUGUI capturingText = _capturingText;
				CancelCapture();
				if ((Object)(object)capturingText != (Object)null)
				{
					((TMP_Text)capturingText).text = ((object)(*(KeyCode*)(&value))/*cast due to .constrained prefix*/).ToString();
				}
				return;
			}
			KeyCode[] keyCodes = _keyCodes;
			for (int i = 0; i < keyCodes.Length; i++)
			{
				KeyCode val = keyCodes[i];
				if (Input.GetKeyDown(val))
				{
					_capturing.Value = val;
					if ((Object)(object)_capturingText != (Object)null)
					{
						((TMP_Text)_capturingText).text = ((object)(*(KeyCode*)(&val))/*cast due to .constrained prefix*/).ToString();
					}
					CancelCapture();
					break;
				}
			}
		}

		private static KeyCode[] BuildKeyCodes()
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Invalid comparison between Unknown and I4
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Invalid comparison between Unknown and I4
			//IL_004c: 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_0054: Invalid comparison between Unknown and I4
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			KeyCode[] array = (KeyCode[])Enum.GetValues(typeof(KeyCode));
			List<KeyCode> list = new List<KeyCode>(array.Length);
			KeyCode[] array2 = array;
			foreach (KeyCode val in array2)
			{
				if (((int)val < 323 || (int)val > 329) && (int)val != 0 && (int)val != 27)
				{
					list.Add(val);
				}
			}
			return list.ToArray();
		}

		private static void Open()
		{
			if ((Object)(object)_panel == (Object)null)
			{
				return;
			}
			HideSiblingMenus();
			_panel.SetActive(true);
			try
			{
				if ((Object)(object)_pauseMenu != (Object)null)
				{
					_pauseMenu.inSubMenu = true;
				}
			}
			catch
			{
			}
		}

		private static void HideSiblingMenus()
		{
			try
			{
				Il2CppReferenceArray<GameObject> val = (((Object)(object)_pauseMenu != (Object)null) ? _pauseMenu.subMenus : null);
				if (val == null)
				{
					return;
				}
				for (int i = 0; i < ((Il2CppArrayBase<GameObject>)(object)val).Length; i++)
				{
					GameObject val2 = ((Il2CppArrayBase<GameObject>)(object)val)[i];
					if ((Object)(object)val2 != (Object)null && ((Il2CppObjectBase)val2).Pointer != ((Il2CppObjectBase)_panel).Pointer)
					{
						val2.SetActive(false);
					}
				}
			}
			catch
			{
			}
		}

		private static void RegisterSubMenu(GameObject panel)
		{
			try
			{
				Il2CppReferenceArray<GameObject> val = (((Object)(object)_pauseMenu != (Object)null) ? _pauseMenu.subMenus : null);
				if (val == null)
				{
					return;
				}
				for (int i = 0; i < ((Il2CppArrayBase<GameObject>)(object)val).Length; i++)
				{
					if ((Object)(object)((Il2CppArrayBase<GameObject>)(object)val)[i] != (Object)null && ((Object)((Il2CppArrayBase<GameObject>)(object)val)[i]).name == ((Object)panel).name)
					{
						return;
					}
				}
				Il2CppReferenceArray<GameObject> val2 = new Il2CppReferenceArray<GameObject>((long)(((Il2CppArrayBase<GameObject>)(object)val).Length + 1));
				for (int j = 0; j < ((Il2CppArrayBase<GameObject>)(object)val).Length; j++)
				{
					((Il2CppArrayBase<GameObject>)(object)val2)[j] = ((Il2CppArrayBase<GameObject>)(object)val)[j];
				}
				((Il2CppArrayBase<GameObject>)(object)val2)[((Il2CppArrayBase<GameObject>)(object)val).Length] = panel;
				_pauseMenu.subMenus = val2;
			}
			catch (Exception ex)
			{
				ModLog.Warning("Could not register the sub-menu: " + ex.Message);
			}
		}

		private static Transform Require(Transform root, string path)
		{
			Transform val = root.Find(path);
			if ((Object)(object)val == (Object)null)
			{
				throw new InvalidOperationException("Pause menu path missing: '" + path + "'");
			}
			return val;
		}

		private static void SetLabel(GameObject root, string text)
		{
			TextMeshProUGUI componentInChildren = root.GetComponentInChildren<TextMeshProUGUI>(true);
			if (!((Object)(object)componentInChildren == (Object)null))
			{
				Strip(((Component)componentInChildren).gameObject);
				((TMP_Text)componentInChildren).text = text;
			}
		}

		private static void Strip(GameObject go)
		{
			try
			{
				LanguageText component = go.GetComponent<LanguageText>();
				if ((Object)(object)component != (Object)null)
				{
					Object.Destroy((Object)(object)component);
				}
			}
			catch
			{
			}
		}

		private static void StripForeignBehaviours(GameObject go)
		{
			TryDestroy((Component)(object)go.GetComponent<ResolutionDropdown>());
			TryDestroy((Component)(object)go.GetComponent<MicPickerDropdown>());
		}

		private static void TryDestroy(Component c)
		{
			try
			{
				if ((Object)(object)c != (Object)null)
				{
					Object.Destroy((Object)(object)c);
				}
			}
			catch
			{
			}
		}
	}
	internal sealed class PossessionDriver
	{
		private const float Gravity = 22f;

		private const float TerminalVelocity = 30f;

		private const float GroundSnapTolerance = 0.35f;

		private const float GroundProbeHeight = 1.5f;

		private const float GroundProbeDepth = 8f;

		private const float TurnDegreesPerSecond = 540f;

		private const float MoveDeadzone = 0.1f;

		private const float SweepSkin = 0.05f;

		private const float DefaultRadius = 0.35f;

		private Vector3 _feet;

		private float _centreHeight = 0.9f;

		private float _radius = 0.35f;

		private float _verticalVelocity;

		private float _yaw;

		private GameObject _self;

		private Transform _body;

		private bool _sweepFailed;

		private const int MaxSweepHits = 16;

		private Il2CppStructArray<RaycastHit> _sweepHits;

		private bool _radiusSet;

		public Vector3 Position => _feet + Vector3.up * _centreHeight;

		public Vector3 Feet => _feet;

		public Quaternion Rotation => Quaternion.Euler(0f, _yaw, 0f);

		public bool Begun { get; private set; }

		public bool IsMoving { get; private set; }

		public bool IsRunning { get; private set; }

		public bool IsCrouching { get; private set; }

		public bool Grounded { get; private set; }

		public void Begin(PlayerManager pm, GameObject puppet, Vector3? origin = null, float yaw = 0f)
		{
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_011b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			_self = puppet;
			_body = (((Object)(object)pm != (Object)null) ? ((Component)pm).transform : null);
			_verticalVelocity = 0f;
			bool flag = (IsCrouching = false);
			bool isMoving = (IsRunning = flag);
			IsMoving = isMoving;
			Vector3 val = (Vector3)(((??)origin) ?? ((Component)pm).transform.position);
			_yaw = (origin.HasValue ? yaw : ((Component)pm).transform.eulerAngles.y);
			try
			{
				CharacterController charController = pm.charController;
				if ((Object)(object)charController != (Object)null && charController.height > 0.1f)
				{
					_centreHeight = charController.height * 0.5f - charController.center.y;
					if (!_radiusSet)
					{
						_radius = Mathf.Max(charController.radius, 0.1f);
					}
				}
			}
			catch
			{
			}
			_feet = val - Vector3.up * _centreHeight;
			SnapToGround(_feet.y);
			Begun = true;
		}

		public void End()
		{
			Begun = false;
			_radiusSet = false;
			_sweepFailed = false;
		}

		public void SyncFrom(Vector3 position)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			_feet = position - Vector3.up * _centreHeight;
			_verticalVelocity = 0f;
			SnapToGround(_feet.y);
		}

		public void Tick(Camera camera, PlayerManager pm, bool inputAllowed)
		{
			//IL_0027: 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_0183: Unknown result type (might be due to invalid IL or missing references)
			//IL_0188: Unknown result type (might be due to invalid IL or missing references)
			//IL_0189: Unknown result type (might be due to invalid IL or missing references)
			//IL_018e: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: 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_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: Unknown result type (might be due to invalid IL or missing references)
			//IL_0153: Unknown result type (might be due to invalid IL or missing references)
			//IL_0158: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: 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)
			float deltaTime = Time.deltaTime;
			if (deltaTime <= 0f)
			{
				return;
			}
			Vector2 val = (inputAllowed ? GameInput.Move : Vector2.zero);
			IsRunning = inputAllowed && GameInput.Sprint && ((Vector2)(ref val)).sqrMagnitude > 0.010000001f;
			IsCrouching = inputAllowed && GameInput.Crouch;
			IsMoving = ((Vector2)(ref val)).sqrMagnitude > 0.010000001f;
			Vector3 val2 = Vector3.zero;
			if (IsMoving)
			{
				float num = (((Object)(object)camera != (Object)null) ? ((Component)camera).transform.eulerAngles.y : _yaw);
				Vector3 val3 = Quaternion.Euler(0f, num, 0f) * new Vector3(val.x, 0f, val.y);
				if (((Vector3)(ref val3)).sqrMagnitude > 1f)
				{
					((Vector3)(ref val3)).Normalize();
				}
				val2 = val3 * SpeedFor(pm) * deltaTime;
				_yaw = Mathf.MoveTowardsAngle(_yaw, Mathf.Atan2(val3.x, val3.z) * 57.29578f, 540f * deltaTime);
			}
			if (!_sweepFailed)
			{
				try
				{
					val2 = Sweep(val2);
				}
				catch (Exception ex)
				{
					_sweepFailed = true;
					ModLog.Error("Wall collision disabled for this session: " + ex.Message);
				}
			}
			_feet += val2;
			float y = _feet.y;
			ApplyGravity(deltaTime);
			SnapToGround(y);
		}

		private float SpeedFor(PlayerManager pm)
		{
			float num = 4f;
			float num2 = 7f;
			float result = 2f;
			try
			{
				FPSController val = (((Object)(object)pm != (Object)null) ? pm.fpsScript : null);
				if ((Object)(object)val != (Object)null)
				{
					if (val.walkSpeed > 0.01f)
					{
						num = val.walkSpeed;
					}
					if (val.runSpeed > 0.01f)
					{
						num2 = val.runSpeed;
					}
					if (val.crouchSpeed > 0.01f)
					{
						result = val.crouchSpeed;
					}
				}
			}
			catch
			{
			}
			if (IsCrouching)
			{
				return result;
			}
			return IsRunning ? num2 : num;
		}

		private Vector3 Sweep(Vector3 step)
		{
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: 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_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to inv