Decompiled source of AdvancedFreeCam v2.1.0

AdvancedFreeCam.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using AdvancedFreeCam.Config;
using AdvancedFreeCam.Core;
using AdvancedFreeCam.Ghost;
using AdvancedFreeCam.Network;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using ExitGames.Client.Photon;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Photon.Pun;
using Photon.Realtime;
using TMPro;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.UI;

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

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

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

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

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace AdvancedFreeCam
{
	[BepInPlugin("Kai.AdvancedFreeCam", "AdvancedFreeCam", "2.2.0")]
	public class AdvancedFreeCam : BaseUnityPlugin
	{
		private FreeCamManager? _freeCamManager;

		private FreeCamGhostManager? _ghostManager;

		private bool _handshakeApplied;

		private bool _voiceNetworkRegistered;

		private bool _ghostNetworkRegistered;

		private ConfigEntry<bool>? _allowHostAliveFreeCam;

		private ConfigEntry<bool>? _allowClientAliveFreeCam;

		private ConfigEntry<bool>? _allowClientDeadFreeCam;

		private ConfigEntry<bool>? _allowHostForceDisable;

		private ConfigEntry<bool>? _allowFreeCamVoice;

		private ConfigEntry<bool>? _allowClientFreeCamVoice;

		private ConfigEntry<bool>? _ghostVisibleToAlivePlayers;

		private ConfigEntry<bool>? _ghostVisibleToSpectators;

		private ConfigEntry<bool>? _ghostVisibleToFreeCamPlayers;

		internal static AdvancedFreeCam Instance { get; private set; }

		internal static ManualLogSource Logger => Instance._logger;

		private ManualLogSource _logger => ((BaseUnityPlugin)this).Logger;

		internal Harmony? Harmony { get; set; }

		internal bool HasAuthoritativeRoomConfig { get; private set; }

		private void Awake()
		{
			Instance = this;
			((Component)this).transform.parent = null;
			((Object)((Component)this).gameObject).hideFlags = (HideFlags)61;
			BindConfig();
			ApplyHostConfigToRuntime();
			_freeCamManager = new FreeCamManager();
			_ghostManager = new FreeCamGhostManager();
			Patch();
			Logger.LogInfo((object)$"{((BaseUnityPlugin)this).Info.Metadata.GUID} v{((BaseUnityPlugin)this).Info.Metadata.Version} has loaded!");
		}

		internal void Patch()
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Expected O, but got Unknown
			//IL_0025: Expected O, but got Unknown
			if (Harmony == null)
			{
				Harmony val = new Harmony(((BaseUnityPlugin)this).Info.Metadata.GUID);
				Harmony val2 = val;
				Harmony = val;
			}
			Harmony.PatchAll();
		}

		private void Update()
		{
			TryRegisterGhostNetwork();
			TryApplyHandshake();
			SyncRoomConfig();
			_freeCamManager?.Tick(Time.deltaTime);
			_ghostManager?.Tick();
		}

		private void LateUpdate()
		{
			FreeCamPhotoMode.LateTick();
		}

		private void BindConfig()
		{
			BindHostConfig();
			BindControlsConfig();
			BindClientConfig();
		}

		private void BindHostConfig()
		{
			_allowHostAliveFreeCam = ((BaseUnityPlugin)this).Config.Bind<bool>("Host", "AllowHostAliveFreeCam", true, "Allow the host to enable FreeCam while alive.");
			_allowClientAliveFreeCam = ((BaseUnityPlugin)this).Config.Bind<bool>("Host", "AllowClientAliveFreeCam", false, "Allow clients to enable FreeCam while alive.");
			_allowClientDeadFreeCam = ((BaseUnityPlugin)this).Config.Bind<bool>("Host", "AllowClientDeadFreeCam", true, "Allow clients to enable FreeCam while dead / spectating.");
			_ghostVisibleToAlivePlayers = ((BaseUnityPlugin)this).Config.Bind<bool>("Host", "GhostVisibleToAlivePlayers", false, "Show FreeCam ghost to alive players.");
			_ghostVisibleToSpectators = ((BaseUnityPlugin)this).Config.Bind<bool>("Host", "GhostVisibleToSpectators", true, "Show FreeCam ghost to spectators / dead players.");
			_ghostVisibleToFreeCamPlayers = ((BaseUnityPlugin)this).Config.Bind<bool>("Host", "GhostVisibleToFreeCamPlayers", true, "Show FreeCam ghost to other FreeCam players.");
		}

		private void BindControlsConfig()
		{
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Expected O, but got Unknown
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Expected O, but got Unknown
			//IL_0156: Unknown result type (might be due to invalid IL or missing references)
			//IL_0160: Expected O, but got Unknown
			//IL_0193: Unknown result type (might be due to invalid IL or missing references)
			//IL_019d: Expected O, but got Unknown
			//IL_01d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01da: Expected O, but got Unknown
			//IL_020d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0217: Expected O, but got Unknown
			//IL_024a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0254: Expected O, but got Unknown
			FreeCamLocalSettings.ToggleFreeCamKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Controls", "ToggleFreeCamKey", (KeyCode)289, "Toggle FreeCam on / off.");
			FreeCamLocalSettings.TogglePhotoModeKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Controls", "TogglePhotoModeKey", (KeyCode)122, "Toggle PhotoMode while FreeCam is active.");
			FreeCamLocalSettings.FreeCamLookSensitivity = ((BaseUnityPlugin)this).Config.Bind<float>("Controls", "FreeCamLookSensitivity", 1.5f, new ConfigDescription("Mouse look sensitivity while using FreeCam.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 5f), Array.Empty<object>()));
			FreeCamLocalSettings.FreeCamMaxMouseDelta = ((BaseUnityPlugin)this).Config.Bind<float>("Controls", "FreeCamMaxMouseDelta", 8f, new ConfigDescription("Maximum mouse input delta per frame while using FreeCam. Lower values reduce sudden camera swings.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 12f), Array.Empty<object>()));
			FreeCamLocalSettings.FastMoveKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Controls", "FastMoveKey", (KeyCode)304, "Hold to move faster while using FreeCam.");
			FreeCamLocalSettings.MoveUpKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Controls", "MoveUpKey", (KeyCode)32, "Move FreeCam upward.");
			FreeCamLocalSettings.MoveDownKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Controls", "MoveDownKey", (KeyCode)306, "Move FreeCam downward.");
			FreeCamLocalSettings.FreeCamBaseMoveSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("Controls", "FreeCamBaseMoveSpeed", 8f, new ConfigDescription("Default FreeCam movement speed.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 200f), Array.Empty<object>()));
			FreeCamLocalSettings.FreeCamFastMoveMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Controls", "FreeCamFastMoveMultiplier", 3f, new ConfigDescription("Movement speed multiplier while holding FastMoveKey.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 20f), Array.Empty<object>()));
			FreeCamLocalSettings.FreeCamMinMoveSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("Controls", "FreeCamMinMoveSpeed", 1f, new ConfigDescription("Minimum FreeCam movement speed when adjusted by mouse wheel.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 200f), Array.Empty<object>()));
			FreeCamLocalSettings.FreeCamMaxMoveSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("Controls", "FreeCamMaxMoveSpeed", 50f, new ConfigDescription("Maximum FreeCam movement speed when adjusted by mouse wheel.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 200f), Array.Empty<object>()));
			FreeCamLocalSettings.FreeCamMouseWheelSpeedStep = ((BaseUnityPlugin)this).Config.Bind<float>("Controls", "FreeCamMouseWheelSpeedStep", 1f, new ConfigDescription("FreeCam speed change amount per mouse wheel step.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 50f), Array.Empty<object>()));
		}

		private void BindClientConfig()
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Expected O, but got Unknown
			FreeCamLocalSettings.PhotoModeNightVision = ((BaseUnityPlugin)this).Config.Bind<float>("Client", "PhotoModeNightVision", 25f, new ConfigDescription("Ambient-light based night vision strength while PhotoMode is enabled. 0 = off, 100 = max.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), Array.Empty<object>()));
		}

		private void ApplyHostConfigToRuntime()
		{
			FreeCamConfig instance = FreeCamConfig.Instance;
			instance.AllowHostAliveFreeCam = _allowHostAliveFreeCam?.Value ?? true;
			instance.AllowClientAliveFreeCam = _allowClientAliveFreeCam?.Value ?? false;
			instance.AllowClientDeadFreeCam = _allowClientDeadFreeCam?.Value ?? true;
			instance.AllowHostForceDisable = _allowHostForceDisable?.Value ?? true;
			instance.GhostVisibleToAlivePlayers = _ghostVisibleToAlivePlayers?.Value ?? false;
			instance.GhostVisibleToSpectators = _ghostVisibleToSpectators?.Value ?? true;
			instance.GhostVisibleToFreeCamPlayers = _ghostVisibleToFreeCamPlayers?.Value ?? true;
		}

		private void SyncRoomConfig()
		{
			if (!SemiFunc.IsMultiplayer())
			{
				HasAuthoritativeRoomConfig = true;
				ApplyHostConfigToRuntime();
			}
			else if (!PhotonNetwork.InRoom)
			{
				HasAuthoritativeRoomConfig = false;
			}
			else if (PhotonNetwork.IsMasterClient)
			{
				ApplyHostConfigToRuntime();
				FreeCamRoomConfigSync.PushHostConfigToRoom();
				HasAuthoritativeRoomConfig = true;
			}
			else
			{
				HasAuthoritativeRoomConfig = FreeCamRoomConfigSync.TryApplyRoomConfigToRuntime();
			}
		}

		private void TryRegisterGhostNetwork()
		{
			bool flag = SemiFunc.IsMultiplayer() && PhotonNetwork.InRoom && PhotonNetwork.NetworkingClient != null;
			if (flag != _ghostNetworkRegistered)
			{
				if (flag)
				{
					FreeCamGhostNetwork.Register();
					_ghostNetworkRegistered = true;
				}
				else
				{
					FreeCamGhostNetwork.Unregister();
					_ghostNetworkRegistered = false;
				}
			}
		}

		private void TryApplyHandshake()
		{
			if (!SemiFunc.IsMultiplayer())
			{
				_handshakeApplied = false;
			}
			else if (!PhotonNetwork.InRoom)
			{
				_handshakeApplied = false;
			}
			else if (PhotonNetwork.LocalPlayer != null && !_handshakeApplied)
			{
				FreeCamPlayerHandshake.ApplyLocalProperties();
				_handshakeApplied = true;
			}
		}

		internal void SetPhotoModeNightVision(float value)
		{
			float value2 = Mathf.Clamp(value, 0f, 100f);
			if (FreeCamLocalSettings.PhotoModeNightVision != null)
			{
				FreeCamLocalSettings.PhotoModeNightVision.Value = value2;
			}
		}
	}
}
namespace AdvancedFreeCam.Patchs
{
	[HarmonyPatch(typeof(PlayerAvatar), "ReviveRPC")]
	internal static class Patch_PlayerAvatar_Revive_GhostReset
	{
		internal static void Prefix(PlayerAvatar __instance)
		{
			if (!((Object)(object)__instance == (Object)null) && __instance.isLocal)
			{
				FreeCamManager.Instance?.DisableFreeCam();
			}
		}
	}
	[HarmonyPatch(typeof(PlayerAvatar), "PlayerDeathRPC")]
	internal static class Patch_PlayerAvatar_Death_GhostReset
	{
		internal static void Prefix(PlayerAvatar __instance)
		{
			if (!((Object)(object)__instance == (Object)null) && __instance.isLocal)
			{
				FreeCamManager.Instance?.DisableFreeCam();
			}
		}
	}
	[HarmonyPatch(typeof(SemiFunc), "OnLevelGenDone")]
	internal static class Patch_SemiFunc_OnLevelGenDone_GhostReset
	{
		private static void Prefix()
		{
			FreeCamGhostManager.Instance?.ClearAll();
			FreeCamGhostManager.Instance?.PrewarmFromPlayerList();
		}
	}
	internal static class Patch_SpectateCameraDeathEffects_FreeCam
	{
		[HarmonyPatch(typeof(SpectateCamera), "StateDeath")]
		private static class SpectateCamera_StateDeath_Patch
		{
			private static void Prefix()
			{
				//IL_0045: Unknown result type (might be due to invalid IL or missing references)
				//IL_004a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0055: Unknown result type (might be due to invalid IL or missing references)
				//IL_005a: Unknown result type (might be due to invalid IL or missing references)
				_suppressingSpectateDeathEffects = false;
				_hasSnapshot = false;
				_hasTopCamera = false;
				if (!ShouldSuppress())
				{
					return;
				}
				Camera val = (((Object)(object)GameDirector.instance != (Object)null) ? GameDirector.instance.MainCamera : null);
				if ((Object)(object)val == (Object)null)
				{
					return;
				}
				_mainCameraLocalPosition = ((Component)val).transform.localPosition;
				_mainCameraLocalRotation = ((Component)val).transform.localRotation;
				_mainCameraFieldOfView = val.fieldOfView;
				_mainCameraNearClip = val.nearClipPlane;
				_mainCameraFarClip = val.farClipPlane;
				_fog = RenderSettings.fog;
				Camera[] componentsInChildren = ((Component)val).GetComponentsInChildren<Camera>();
				foreach (Camera val2 in componentsInChildren)
				{
					if (!((Object)(object)val2 == (Object)null) && !((Object)(object)val2 == (Object)(object)val))
					{
						_topCameraFieldOfView = val2.fieldOfView;
						_hasTopCamera = true;
						break;
					}
				}
				_hasSnapshot = true;
				_suppressingSpectateDeathEffects = true;
			}

			private static void Postfix()
			{
				//IL_0041: Unknown result type (might be due to invalid IL or missing references)
				//IL_0051: Unknown result type (might be due to invalid IL or missing references)
				if (!_suppressingSpectateDeathEffects || !_hasSnapshot)
				{
					ResetFlags();
					return;
				}
				Camera val = (((Object)(object)GameDirector.instance != (Object)null) ? GameDirector.instance.MainCamera : null);
				if ((Object)(object)val != (Object)null)
				{
					((Component)val).transform.localPosition = _mainCameraLocalPosition;
					((Component)val).transform.localRotation = _mainCameraLocalRotation;
					val.fieldOfView = _mainCameraFieldOfView;
					val.nearClipPlane = _mainCameraNearClip;
					val.farClipPlane = _mainCameraFarClip;
					if (_hasTopCamera)
					{
						Camera[] componentsInChildren = ((Component)val).GetComponentsInChildren<Camera>();
						foreach (Camera val2 in componentsInChildren)
						{
							if (!((Object)(object)val2 == (Object)null) && !((Object)(object)val2 == (Object)(object)val))
							{
								val2.fieldOfView = _topCameraFieldOfView;
								break;
							}
						}
					}
				}
				RenderSettings.fog = _fog;
				ResetFlags();
			}

			private static void ResetFlags()
			{
				_suppressingSpectateDeathEffects = false;
				_hasSnapshot = false;
				_hasTopCamera = false;
			}
		}

		[HarmonyPatch(typeof(CameraGlitch), "PlayShort")]
		private static class CameraGlitch_PlayShort_Patch
		{
			private static bool Prefix()
			{
				return !_suppressingSpectateDeathEffects;
			}
		}

		[HarmonyPatch(typeof(CameraShake), "Shake")]
		private static class CameraShake_Shake_Patch
		{
			private static bool Prefix(CameraShake __instance)
			{
				if (!_suppressingSpectateDeathEffects)
				{
					return true;
				}
				if ((Object)(object)GameDirector.instance == (Object)null)
				{
					return true;
				}
				if ((Object)(object)__instance == (Object)(object)GameDirector.instance.CameraShake)
				{
					return false;
				}
				if ((Object)(object)__instance == (Object)(object)GameDirector.instance.CameraImpact)
				{
					return false;
				}
				return true;
			}
		}

		[HarmonyPatch(typeof(CameraNoise), "Override")]
		private static class CameraNoise_Override_Patch
		{
			private static bool Prefix()
			{
				return !_suppressingSpectateDeathEffects;
			}
		}

		private static bool _suppressingSpectateDeathEffects;

		private static bool _hasSnapshot;

		private static bool _hasTopCamera;

		private static Vector3 _mainCameraLocalPosition;

		private static Quaternion _mainCameraLocalRotation;

		private static float _mainCameraFieldOfView;

		private static float _topCameraFieldOfView;

		private static float _mainCameraNearClip;

		private static float _mainCameraFarClip;

		private static bool _fog;

		private static bool IsFreeCamActive()
		{
			if (FreeCamManager.Instance != null)
			{
				return FreeCamManager.Instance.IsActive;
			}
			return false;
		}

		private static bool AllPlayersDead()
		{
			if ((Object)(object)GameDirector.instance == (Object)null || GameDirector.instance.PlayerList == null)
			{
				return false;
			}
			if (GameDirector.instance.PlayerList.Count == 0)
			{
				return false;
			}
			foreach (PlayerAvatar player in GameDirector.instance.PlayerList)
			{
				if ((Object)(object)player != (Object)null && !player.isDisabled)
				{
					return false;
				}
			}
			return true;
		}

		private static bool ShouldSuppress()
		{
			if (!IsFreeCamActive())
			{
				return false;
			}
			if ((Object)(object)SpectateCamera.instance == (Object)null)
			{
				return false;
			}
			if (!SpectateCamera.instance.CheckState((State)0))
			{
				return false;
			}
			if (AllPlayersDead())
			{
				return false;
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(SpectateCamera), "Awake")]
	internal static class Patch_SpectateCamera_Awake_FreeCamCleanup
	{
		private static void Prefix()
		{
			FreeCamManager.Instance?.ForceCleanup("SpectateCamera.Awake");
		}
	}
	[HarmonyPatch(typeof(SpectateCamera), "PlayerSwitch")]
	internal static class Patch_SpectateCamera_PlayerSwitch_FreeCamInputBlock
	{
		private static bool Prefix()
		{
			if (FreeCamManager.Instance == null || !FreeCamManager.Instance.IsActive)
			{
				return true;
			}
			if (Input.GetKeyDown((KeyCode)32) || Input.GetKeyDown((KeyCode)323) || Input.GetKeyDown((KeyCode)324))
			{
				return false;
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(RunManager), "ChangeLevel")]
	internal static class Patch_RunManager_ChangeLevel
	{
		private static void Prefix()
		{
			FreeCamManager.Instance?.PrepareForLevelTransition("RunManager.ChangeLevel");
		}
	}
	[HarmonyPatch(typeof(RunManager), "RestartScene")]
	internal static class Patch_RunManager_RestartScene
	{
		private static void Prefix()
		{
			FreeCamManager.Instance?.PrepareForLevelTransition("RunManager.RestartScene");
		}
	}
}
namespace AdvancedFreeCam.Network
{
	internal static class FreeCamEventCodes
	{
		internal const byte VoiceState = 71;

		internal const byte GhostState = 72;
	}
	internal static class FreeCamGhostNetwork
	{
		private const string PayloadTag = "Kai.AdvancedFreeCam:GhostState";

		private const int PayloadVersion = 1;

		private static readonly SendOptions UnreliableSendOptions;

		internal static void Register()
		{
			PhotonNetwork.NetworkingClient.EventReceived += OnEventReceived;
		}

		internal static void Unregister()
		{
			PhotonNetwork.NetworkingClient.EventReceived -= OnEventReceived;
		}

		internal static void SendState(bool active, Vector3 position, Quaternion rotation)
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: 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_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Expected O, but got Unknown
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			if (PhotonNetwork.InRoom)
			{
				int[] targetActorsWithAdvancedFreeCam = FreeCamPlayerHandshake.GetTargetActorsWithAdvancedFreeCam();
				if (targetActorsWithAdvancedFreeCam.Length != 0)
				{
					int actorNumber = PhotonNetwork.LocalPlayer.ActorNumber;
					object[] array = new object[11]
					{
						"Kai.AdvancedFreeCam:GhostState", 1, actorNumber, active, position.x, position.y, position.z, rotation.x, rotation.y, rotation.z,
						rotation.w
					};
					RaiseEventOptions val = new RaiseEventOptions
					{
						TargetActors = targetActorsWithAdvancedFreeCam
					};
					PhotonNetwork.RaiseEvent((byte)72, (object)array, val, UnreliableSendOptions);
				}
			}
		}

		private static void OnEventReceived(EventData photonEvent)
		{
			//IL_0162: Unknown result type (might be due to invalid IL or missing references)
			//IL_0164: Unknown result type (might be due to invalid IL or missing references)
			if (photonEvent.Code != 72 || !(photonEvent.CustomData is object[] array) || array.Length < 11 || !(array[0] is string text) || text != "Kai.AdvancedFreeCam:GhostState")
			{
				return;
			}
			object obj = array[1];
			if (!(obj is int))
			{
				return;
			}
			int num = (int)obj;
			if (num != 1)
			{
				return;
			}
			obj = array[2];
			if (!(obj is int))
			{
				return;
			}
			int actorNumber = (int)obj;
			obj = array[3];
			if (!(obj is bool))
			{
				return;
			}
			bool active = (bool)obj;
			obj = array[4];
			if (!(obj is float))
			{
				return;
			}
			float num2 = (float)obj;
			obj = array[5];
			if (!(obj is float))
			{
				return;
			}
			float num3 = (float)obj;
			obj = array[6];
			if (!(obj is float))
			{
				return;
			}
			float num4 = (float)obj;
			obj = array[7];
			if (!(obj is float))
			{
				return;
			}
			float num5 = (float)obj;
			obj = array[8];
			if (!(obj is float))
			{
				return;
			}
			float num6 = (float)obj;
			obj = array[9];
			if (obj is float)
			{
				float num7 = (float)obj;
				obj = array[10];
				if (obj is float)
				{
					float num8 = (float)obj;
					Vector3 position = default(Vector3);
					((Vector3)(ref position))..ctor(num2, num3, num4);
					Quaternion rotation = default(Quaternion);
					((Quaternion)(ref rotation))..ctor(num5, num6, num7, num8);
					FreeCamGhostRegistry.Set(actorNumber, active, position, rotation);
				}
			}
		}

		static FreeCamGhostNetwork()
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			SendOptions unreliableSendOptions = default(SendOptions);
			((SendOptions)(ref unreliableSendOptions)).Reliability = false;
			UnreliableSendOptions = unreliableSendOptions;
		}
	}
	internal static class FreeCamNetworkKeys
	{
		internal const string HasMod = "afc_mod";

		internal const string ModVersion = "afc_ver";

		internal const string RoomConfigVersion = "afc_cfg_ver";

		internal const string AllowHostAliveFreeCam = "afc_h_alive";

		internal const string AllowClientAliveFreeCam = "afc_c_alive";

		internal const string AllowClientDeadFreeCam = "afc_c_dead";

		internal const string AllowHostForceDisable = "afc_force";

		internal const string AllowFreeCamVoice = "afc_voice";

		internal const string AllowClientFreeCamVoice = "afc_c_voice";

		internal const string GhostVisibleToAlivePlayers = "afc_g_alive";

		internal const string GhostVisibleToSpectators = "afc_g_spec";

		internal const string GhostVisibleToFreeCamPlayers = "afc_g_fc";
	}
	internal static class FreeCamPlayerHandshake
	{
		internal const int CurrentProtocolVersion = 101;

		internal static void ApplyLocalProperties()
		{
			//IL_0008: 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_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Expected O, but got Unknown
			if (PhotonNetwork.LocalPlayer != null)
			{
				Hashtable val = new Hashtable
				{
					[(object)"afc_mod"] = true,
					[(object)"afc_ver"] = 101
				};
				PhotonNetwork.LocalPlayer.SetCustomProperties(val, (Hashtable)null, (WebFlags)null);
			}
		}

		internal static bool HasAdvancedFreeCam(Player? player)
		{
			if (player == null)
			{
				return false;
			}
			if (!((Dictionary<object, object>)(object)player.CustomProperties).TryGetValue((object)"afc_mod", out object value))
			{
				return false;
			}
			if (!(value is bool) || !(bool)value)
			{
				return false;
			}
			return true;
		}

		internal static bool TryGetProtocolVersion(Player? player, out int version)
		{
			version = 0;
			if (player == null)
			{
				return false;
			}
			if (!((Dictionary<object, object>)(object)player.CustomProperties).TryGetValue((object)"afc_ver", out object value))
			{
				return false;
			}
			if (!(value is int num))
			{
				return false;
			}
			version = num;
			return true;
		}

		internal static int[] GetTargetActorsWithAdvancedFreeCam(bool includeSelf = false)
		{
			if (!PhotonNetwork.InRoom)
			{
				return Array.Empty<int>();
			}
			List<int> list = new List<int>();
			Player[] playerList = PhotonNetwork.PlayerList;
			foreach (Player val in playerList)
			{
				if ((includeSelf || !val.IsLocal) && HasAdvancedFreeCam(val))
				{
					list.Add(val.ActorNumber);
				}
			}
			return list.ToArray();
		}
	}
	internal static class FreeCamRoomConfigSync
	{
		private const int CurrentRoomConfigVersion = 1;

		internal static void PushHostConfigToRoom()
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: 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_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Expected O, but got Unknown
			if (PhotonNetwork.InRoom && PhotonNetwork.IsMasterClient)
			{
				FreeCamConfig instance = FreeCamConfig.Instance;
				Hashtable val = new Hashtable
				{
					[(object)"afc_cfg_ver"] = 1,
					[(object)"afc_h_alive"] = instance.AllowHostAliveFreeCam,
					[(object)"afc_c_alive"] = instance.AllowClientAliveFreeCam,
					[(object)"afc_c_dead"] = instance.AllowClientDeadFreeCam,
					[(object)"afc_force"] = instance.AllowHostForceDisable,
					[(object)"afc_g_alive"] = instance.GhostVisibleToAlivePlayers,
					[(object)"afc_g_spec"] = instance.GhostVisibleToSpectators,
					[(object)"afc_g_fc"] = instance.GhostVisibleToFreeCamPlayers
				};
				PhotonNetwork.CurrentRoom.SetCustomProperties(val, (Hashtable)null, (WebFlags)null);
			}
		}

		internal static bool TryApplyRoomConfigToRuntime()
		{
			if (!PhotonNetwork.InRoom)
			{
				return false;
			}
			Room currentRoom = PhotonNetwork.CurrentRoom;
			if (currentRoom == null)
			{
				return false;
			}
			Hashtable customProperties = ((RoomInfo)currentRoom).CustomProperties;
			if (customProperties == null || ((Dictionary<object, object>)(object)customProperties).Count == 0)
			{
				return false;
			}
			if (!((Dictionary<object, object>)(object)customProperties).TryGetValue((object)"afc_cfg_ver", out object value))
			{
				return false;
			}
			if (!(value is int num) || num != 1)
			{
				return false;
			}
			FreeCamConfigSnapshot freeCamConfigSnapshot = new FreeCamConfigSnapshot
			{
				AllowHostAliveFreeCam = ReadBool(customProperties, "afc_h_alive", fallback: true),
				AllowClientAliveFreeCam = ReadBool(customProperties, "afc_c_alive", fallback: false),
				AllowClientDeadFreeCam = ReadBool(customProperties, "afc_c_dead", fallback: true),
				AllowHostForceDisable = ReadBool(customProperties, "afc_force", fallback: true),
				AllowFreeCamVoice = ReadBool(customProperties, "afc_voice", fallback: true),
				AllowClientFreeCamVoice = ReadBool(customProperties, "afc_c_voice", fallback: false),
				GhostVisibleToAlivePlayers = ReadBool(customProperties, "afc_g_alive", fallback: false),
				GhostVisibleToSpectators = ReadBool(customProperties, "afc_g_spec", fallback: true),
				GhostVisibleToFreeCamPlayers = ReadBool(customProperties, "afc_g_fc", fallback: true)
			};
			freeCamConfigSnapshot.ApplyToRuntime(FreeCamConfig.Instance);
			return true;
		}

		private static bool ReadBool(Hashtable props, string key, bool fallback)
		{
			if (!((Dictionary<object, object>)(object)props).TryGetValue((object)key, out object value))
			{
				return fallback;
			}
			if (value is bool)
			{
				return (bool)value;
			}
			return fallback;
		}
	}
}
namespace AdvancedFreeCam.Ghost
{
	internal sealed class FreeCamGhost
	{
		private readonly int _actorNumber;

		private readonly GameObject _root;

		private readonly Transform _transform;

		private GameObject _visualRoot;

		private bool _usingFallback;

		internal int ActorNumber => _actorNumber;

		internal Transform Transform => _transform;

		internal GameObject Root => _root;

		internal bool UsingFallback => _usingFallback;

		internal FreeCamGhost(int actorNumber, Vector3 position, Quaternion rotation)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Expected O, but got Unknown
			//IL_003f: 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)
			_actorNumber = actorNumber;
			_root = new GameObject($"AdvancedFreeCam_Ghost_{actorNumber}");
			_transform = _root.transform;
			_transform.position = position;
			_transform.rotation = rotation;
			_visualRoot = FreeCamGhostVisualFactory.CreateDefault(_root.transform, _actorNumber, out _usingFallback);
			ApplyVisualOffset();
		}

		private void ApplyVisualOffset()
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_visualRoot == (Object)null))
			{
				Transform transform = _visualRoot.transform;
				transform.localPosition += new Vector3(0f, -0.25f, 0f);
			}
		}

		internal void SetTransform(Vector3 position, Quaternion rotation)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			_transform.position = position;
			_transform.rotation = rotation;
		}

		internal void SetVisible(bool visible)
		{
			if ((Object)(object)_visualRoot != (Object)null)
			{
				_visualRoot.SetActive(visible);
			}
		}

		internal void TryRefreshVisual()
		{
			if (_usingFallback && !((Object)(object)FreeCamGhostVisualFactory.FindPlayerAvatarByActorNumber(_actorNumber) == (Object)null))
			{
				if ((Object)(object)_visualRoot != (Object)null)
				{
					Object.Destroy((Object)(object)_visualRoot);
				}
				_visualRoot = FreeCamGhostVisualFactory.CreateDefault(_root.transform, _actorNumber, out _usingFallback);
				ApplyVisualOffset();
			}
		}

		internal void Destroy()
		{
			Object.Destroy((Object)(object)_root);
		}
	}
	internal sealed class FreeCamGhostManager
	{
		private readonly Dictionary<int, FreeCamGhost> _ghosts = new Dictionary<int, FreeCamGhost>();

		private const float RemoteStateTimeout = 0.5f;

		internal static FreeCamGhostManager? Instance { get; private set; }

		internal FreeCamGhostManager()
		{
			Instance = this;
		}

		internal void Tick()
		{
			//IL_00b3: 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_00ca: 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)
			int num = ((PhotonNetwork.LocalPlayer != null) ? PhotonNetwork.LocalPlayer.ActorNumber : (-1));
			HashSet<int> hashSet = new HashSet<int>();
			foreach (KeyValuePair<int, FreeCamGhostState> item in FreeCamGhostRegistry.GetAll())
			{
				int key = item.Key;
				FreeCamGhostState value = item.Value;
				if (key == num)
				{
					RemoveGhost(key);
					FreeCamGhostRegistry.Remove(key);
					continue;
				}
				hashSet.Add(key);
				bool flag = Time.time - value.LastUpdatedTime > 0.5f;
				if (!value.IsActive || flag)
				{
					if (_ghosts.TryGetValue(key, out FreeCamGhost value2))
					{
						value2.SetVisible(visible: false);
					}
				}
				else
				{
					FreeCamGhost orCreateGhost = GetOrCreateGhost(key, value.Position, value.Rotation);
					orCreateGhost.SetTransform(value.Position, value.Rotation);
					orCreateGhost.TryRefreshVisual();
					orCreateGhost.SetVisible(ShouldGhostBeVisible());
				}
			}
			foreach (KeyValuePair<int, FreeCamGhost> ghost in _ghosts)
			{
				if (!hashSet.Contains(ghost.Key))
				{
					ghost.Value.SetVisible(visible: false);
				}
			}
		}

		internal void ClearAll()
		{
			foreach (FreeCamGhost value in _ghosts.Values)
			{
				value.Destroy();
			}
			_ghosts.Clear();
			FreeCamGhostRegistry.ClearAll();
		}

		internal void RemoveGhost(int actorNumber)
		{
			if (_ghosts.TryGetValue(actorNumber, out FreeCamGhost value))
			{
				value.Destroy();
				_ghosts.Remove(actorNumber);
			}
		}

		private FreeCamGhost GetOrCreateGhost(int actorNumber, Vector3 position, Quaternion rotation)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			if (_ghosts.TryGetValue(actorNumber, out FreeCamGhost value))
			{
				return value;
			}
			value = new FreeCamGhost(actorNumber, position, rotation);
			_ghosts[actorNumber] = value;
			return value;
		}

		internal void PrewarmFromPlayerList()
		{
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)GameDirector.instance == (Object)null)
			{
				return;
			}
			int num = ((PhotonNetwork.LocalPlayer != null) ? PhotonNetwork.LocalPlayer.ActorNumber : (-1));
			foreach (PlayerAvatar player in GameDirector.instance.PlayerList)
			{
				if ((Object)(object)player == (Object)null)
				{
					continue;
				}
				PhotonView component = ((Component)player).GetComponent<PhotonView>();
				if (!((Object)(object)component == (Object)null) && component.Owner != null)
				{
					int actorNumber = component.Owner.ActorNumber;
					if (actorNumber != num && !_ghosts.ContainsKey(actorNumber))
					{
						Transform transform = ((Component)player).transform;
						FreeCamGhost orCreateGhost = GetOrCreateGhost(actorNumber, transform.position, transform.rotation);
						orCreateGhost.SetVisible(visible: false);
					}
				}
			}
		}

		private bool ShouldGhostBeVisible()
		{
			if (FreeCamManager.Instance != null && FreeCamManager.Instance.IsActive)
			{
				return FreeCamPolicy.ShouldGhostBeVisibleToFreeCamViewer();
			}
			if ((Object)(object)PlayerAvatar.instance != (Object)null && PlayerAvatar.instance.isDisabled)
			{
				return FreeCamPolicy.ShouldGhostBeVisibleToSpectatorViewer();
			}
			return FreeCamPolicy.ShouldGhostBeVisibleToAliveViewer();
		}
	}
	internal static class FreeCamGhostMaterialTuner
	{
		private static readonly Color BaseTint = new Color(0.78f, 0.9f, 1f, 0.72f);

		private static readonly Color EmissionTint = new Color(0.25f, 0.55f, 0.9f, 1f);

		private const float EmissionIntensity = 1.8f;

		internal static void ApplyGhostLook(Renderer renderer)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Expected O, but got Unknown
			if ((Object)(object)renderer == (Object)null)
			{
				return;
			}
			Material[] materials = renderer.materials;
			Material[] array = (Material[])(object)new Material[materials.Length];
			for (int i = 0; i < materials.Length; i++)
			{
				Material val = materials[i];
				if (!((Object)(object)val == (Object)null))
				{
					Material val2 = new Material(val);
					ApplyBaseColor(val2);
					ApplyEmission(val2);
					ApplyTransparency(val2);
					array[i] = val2;
				}
			}
			renderer.materials = array;
		}

		private static void ApplyBaseColor(Material mat)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			if (mat.HasProperty("_Color"))
			{
				Color color = mat.GetColor("_Color");
				Color val = Color.Lerp(color, BaseTint, 0.45f);
				val.a = BaseTint.a;
				mat.SetColor("_Color", val);
			}
			if (mat.HasProperty("_BaseColor"))
			{
				Color color2 = mat.GetColor("_BaseColor");
				Color val2 = Color.Lerp(color2, BaseTint, 0.45f);
				val2.a = BaseTint.a;
				mat.SetColor("_EmissionColor", EmissionTint * 1.8f);
			}
		}

		private static void ApplyEmission(Material mat)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			if (mat.HasProperty("_EmissionColor"))
			{
				mat.EnableKeyword("_EMISSION");
				mat.SetColor("_EmissionColor", EmissionTint);
				DynamicGI.SetEmissive((Renderer)null, EmissionTint);
			}
		}

		private static void ApplyTransparency(Material mat)
		{
			if (mat.HasProperty("_Surface"))
			{
				try
				{
					mat.SetFloat("_Surface", 1f);
				}
				catch
				{
				}
			}
		}
	}
	internal sealed class FreeCamGhostNameTag : MonoBehaviour
	{
		private Camera _targetCamera;

		private Transform _followTarget;

		private Vector3 _offset;

		internal void Initialize(Transform followTarget, Vector3 offset)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			_followTarget = followTarget;
			_offset = offset;
		}

		private void LateUpdate()
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_followTarget != (Object)null)
			{
				((Component)this).transform.position = _followTarget.position + _offset;
			}
			if ((Object)(object)_targetCamera == (Object)null)
			{
				_targetCamera = Camera.main;
			}
			if (!((Object)(object)_targetCamera == (Object)null))
			{
				Vector3 val = ((Component)this).transform.position - ((Component)_targetCamera).transform.position;
				if (((Vector3)(ref val)).sqrMagnitude > 0.0001f)
				{
					((Component)this).transform.rotation = Quaternion.LookRotation(((Vector3)(ref val)).normalized, Vector3.up);
				}
			}
		}
	}
	internal static class FreeCamGhostPoseApplier
	{
		internal static void Apply(GameObject root, FreeCamGhostPoseData pose)
		{
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			int num = 0;
			int num2 = 0;
			foreach (FreeCamGhostPoseNode node in pose.Nodes)
			{
				Transform val = FindDeepChild(root.transform, node.Name);
				if ((Object)(object)val == (Object)null)
				{
					num2++;
					AdvancedFreeCam.Logger.LogWarning((object)("[GhostPose] Missing node: " + node.Name));
					continue;
				}
				val.localPosition = node.LocalPosition;
				val.localRotation = node.LocalRotation;
				val.localScale = node.LocalScale;
				num++;
			}
			AdvancedFreeCam.Logger.LogInfo((object)$"[GhostPose] Applied={num}, Missed={num2}");
		}

		private static Transform? FindDeepChild(Transform parent, string targetName)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Expected O, but got Unknown
			if (((Object)parent).name == targetName)
			{
				return parent;
			}
			foreach (Transform item in parent)
			{
				Transform parent2 = item;
				Transform val = FindDeepChild(parent2, targetName);
				if ((Object)(object)val != (Object)null)
				{
					return val;
				}
			}
			return null;
		}
	}
	internal sealed class FreeCamGhostPoseNode
	{
		public string Name = "";

		public Vector3 LocalPosition;

		public Quaternion LocalRotation;

		public Vector3 LocalScale;
	}
	internal sealed class FreeCamGhostPoseData
	{
		public readonly List<FreeCamGhostPoseNode> Nodes = new List<FreeCamGhostPoseNode>();
	}
	internal static class FreeCamGhostPoseLibrary
	{
		private static FreeCamGhostPoseData? _crawl;

		internal static FreeCamGhostPoseData Crawl => _crawl ?? (_crawl = BuildCrawl());

		private static FreeCamGhostPoseData BuildCrawl()
		{
			//IL_001b: 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_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: 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_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_014b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0164: Unknown result type (might be due to invalid IL or missing references)
			//IL_0178: Unknown result type (might be due to invalid IL or missing references)
			//IL_0197: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0210: Unknown result type (might be due to invalid IL or missing references)
			FreeCamGhostPoseData freeCamGhostPoseData = new FreeCamGhostPoseData();
			Add(freeCamGhostPoseData, "ANIM BOT", new Vector3(0f, 0f, 0f), new Quaternion(0f, 0f, 0f, 1f), new Vector3(0.9f, 0.9f, 0.9f));
			Add(freeCamGhostPoseData, "ANIM BODY BOT", new Vector3(0f, -0.507f, 0f), new Quaternion(0f, 0f, 0f, 1f), new Vector3(1f, 1f, 1f));
			Add(freeCamGhostPoseData, "ANIM BODY TOP", new Vector3(0f, -0.289f, 0f), new Quaternion(0f, 0f, 0f, 1f), new Vector3(1f, 1f, 1f));
			Add(freeCamGhostPoseData, "ANIM HEAD BOT", new Vector3(0f, -0.358802f, 0f), new Quaternion(0f, 0f, 0f, 1f), new Vector3(1f, 1f, 1f));
			Add(freeCamGhostPoseData, "ANIM HEAD TOP", new Vector3(0f, 0f, 0f), new Quaternion(0f, 0f, 0f, 1f), new Vector3(1f, 1f, 1f));
			Add(freeCamGhostPoseData, "ANIM EYE LEFT", new Vector3(0f, 0f, 0f), new Quaternion(0f, 0f, 0f, 1f), new Vector3(1f, 1f, 1f));
			Add(freeCamGhostPoseData, "ANIM EYE RIGHT", new Vector3(0f, 0f, 0f), new Quaternion(0f, 0f, 0f, 1f), new Vector3(1f, 1f, 1f));
			return freeCamGhostPoseData;
		}

		private static void Add(FreeCamGhostPoseData pose, string name, Vector3 localPosition, Quaternion localRotation, Vector3 localScale)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			pose.Nodes.Add(new FreeCamGhostPoseNode
			{
				Name = name,
				LocalPosition = localPosition,
				LocalRotation = localRotation,
				LocalScale = localScale
			});
		}
	}
	internal sealed class FreeCamGhostState
	{
		public bool IsActive;

		public Vector3 Position;

		public Quaternion Rotation = Quaternion.identity;

		public float LastUpdatedTime;

		public void Set(bool active, Vector3 position, Quaternion rotation)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			IsActive = active;
			Position = position;
			Rotation = rotation;
			LastUpdatedTime = Time.time;
		}
	}
	internal static class FreeCamGhostRegistry
	{
		private static readonly Dictionary<int, FreeCamGhostState> States = new Dictionary<int, FreeCamGhostState>();

		internal static void Set(int actorNumber, bool active, Vector3 position, Quaternion rotation)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			if (!States.TryGetValue(actorNumber, out FreeCamGhostState value))
			{
				value = new FreeCamGhostState();
				States[actorNumber] = value;
			}
			value.Set(active, position, rotation);
		}

		internal static bool TryGet(int actorNumber, out FreeCamGhostState state)
		{
			return States.TryGetValue(actorNumber, out state);
		}

		internal static IReadOnlyDictionary<int, FreeCamGhostState> GetAll()
		{
			return States;
		}

		internal static void Remove(int actorNumber)
		{
			States.Remove(actorNumber);
		}

		internal static void ClearAll()
		{
			States.Clear();
		}
	}
	internal sealed class FreeCamGhostTalkAnimation : MonoBehaviour
	{
		private PlayerAvatar _avatar;

		private Transform _target;

		private Quaternion _baseLocalRotation;

		private float _rotationMaxAngle = 45f;

		private float _smooth = 100f;

		internal void Initialize(PlayerAvatar avatar, Transform target, float rotationMaxAngle = 45f)
		{
			//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)
			_avatar = avatar;
			_target = target;
			_rotationMaxAngle = rotationMaxAngle;
			if ((Object)(object)_target != (Object)null)
			{
				_baseLocalRotation = _target.localRotation;
			}
		}

		private void Update()
		{
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_avatar == (Object)null) && !((Object)(object)_target == (Object)null) && GameManager.Multiplayer() && _avatar.voiceChatFetched && !((Object)(object)_avatar.voiceChat == (Object)null))
			{
				float num = 0f;
				if (_avatar.voiceChat.clipLoudness > 0.005f && _avatar.voiceChat.overrideNoTalkAnimationTimer <= 0f)
				{
					num = Mathf.Lerp(0f, 0f - _rotationMaxAngle, _avatar.voiceChat.clipLoudness * 4f);
				}
				Quaternion val = _baseLocalRotation * Quaternion.Euler(num, 0f, 0f);
				_target.localRotation = Quaternion.Slerp(_target.localRotation, val, _smooth * Time.deltaTime);
			}
		}
	}
	internal static class FreeCamGhostVisualBuilder
	{
		private const string CrawlStateName = "Crawl";

		private const float CrawlNormalizedTime = 1f;

		internal static void PrepareCloneAsGhost(GameObject root)
		{
			EnsureVisualRootVisible(root);
			ApplyAnimatorPose(root);
			DisableCloneBehaviours(root);
			ConfigureLights(root);
			ConfigureRenderers(root);
		}

		private static void EnsureVisualRootVisible(GameObject root)
		{
			PlayerAvatarVisuals component = root.GetComponent<PlayerAvatarVisuals>();
			if (!((Object)(object)component == (Object)null) && (Object)(object)component.meshParent != (Object)null)
			{
				component.meshParent.SetActive(true);
			}
		}

		private static void ApplyAnimatorPose(GameObject root)
		{
			Animator component = root.GetComponent<Animator>();
			if ((Object)(object)component == (Object)null)
			{
				AdvancedFreeCam.Logger.LogWarning((object)"[Ghost] Animator が見つかりません。");
				return;
			}
			int num = Animator.StringToHash("Crawl");
			if (!component.HasState(0, num))
			{
				AdvancedFreeCam.Logger.LogWarning((object)"[Ghost] Animator State が見つかりません: Crawl");
				return;
			}
			((Behaviour)component).enabled = true;
			component.speed = 1f;
			component.Play(num, 0, 1f);
			component.Update(0f);
			component.Update(0.01f);
			component.speed = 0f;
		}

		private static void DisableCloneBehaviours(GameObject root)
		{
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			MonoBehaviour[] componentsInChildren = root.GetComponentsInChildren<MonoBehaviour>(true);
			MonoBehaviour[] array = componentsInChildren;
			foreach (MonoBehaviour val in array)
			{
				((Behaviour)val).enabled = false;
			}
			ParticleSystem[] componentsInChildren2 = root.GetComponentsInChildren<ParticleSystem>(true);
			ParticleSystem[] array2 = componentsInChildren2;
			foreach (ParticleSystem val2 in array2)
			{
				EmissionModule emission = val2.emission;
				((EmissionModule)(ref emission)).enabled = false;
				val2.Stop(true, (ParticleSystemStopBehavior)0);
				((Component)val2).gameObject.SetActive(false);
			}
		}

		private static void ConfigureLights(GameObject root)
		{
			Light[] componentsInChildren = root.GetComponentsInChildren<Light>(true);
			Light[] array = componentsInChildren;
			foreach (Light val in array)
			{
				string text = ((Object)((Component)val).gameObject).name.ToLowerInvariant();
				if (text == "eye light")
				{
					((Behaviour)val).enabled = true;
				}
				else
				{
					((Behaviour)val).enabled = false;
				}
			}
		}

		private static void ConfigureRenderers(GameObject root)
		{
			Renderer[] componentsInChildren = root.GetComponentsInChildren<Renderer>(true);
			Renderer[] array = componentsInChildren;
			foreach (Renderer val in array)
			{
				string objectName = ((Object)((Component)val).gameObject).name.ToLowerInvariant();
				if (val.enabled = ShouldShowRenderer(objectName))
				{
					val.shadowCastingMode = (ShadowCastingMode)0;
					val.receiveShadows = false;
					FreeCamGhostMaterialTuner.ApplyGhostLook(val);
				}
			}
		}

		private static bool ShouldShowRenderer(string objectName)
		{
			switch (objectName)
			{
			case "mesh_body_bot":
				return true;
			case "mesh_body_top_sphere":
				return true;
			case "mesh_body_top_flat":
				return true;
			case "mesh_head_bot_sphere":
				return true;
			case "mesh_head_bot_flat":
				return true;
			case "mesh_head_top":
				return true;
			case "mesh_eye_l":
				return true;
			case "mesh_eye_r":
				return true;
			case "mesh_pupil_l":
				return true;
			case "mesh_pupil_r":
				return true;
			case "eyelid_upper":
				return true;
			case "eyelid_lower":
				return true;
			case "mesh_arm_l":
				return false;
			case "mesh_arm_r":
				return false;
			case "mesh_leg_l":
				return false;
			case "mesh_leg_r":
				return false;
			default:
				if (objectName.Contains("mesh_health"))
				{
					return false;
				}
				if (objectName == "wing mesh")
				{
					return false;
				}
				if (objectName == "arenacrown")
				{
					return false;
				}
				if (objectName.Contains("mesh_grabber"))
				{
					return false;
				}
				objectName.Contains("orb sphere");
				return false;
			}
		}
	}
	internal static class FreeCamGhostVisualCache
	{
		private static GameObject? _localCachedVisual;

		private static bool _rebuildRequested;

		private static int _waitFrames;

		internal static bool HasLocalCache => (Object)(object)_localCachedVisual != (Object)null;

		internal static void RequestRebuild(int waitFrames = 10)
		{
			_rebuildRequested = true;
			_waitFrames = waitFrames;
		}

		internal static void Tick()
		{
			if (_rebuildRequested && CanBuildNow())
			{
				if (_waitFrames > 0)
				{
					_waitFrames--;
					return;
				}
				RebuildLocalCache();
				_rebuildRequested = false;
			}
		}

		internal static void RebuildLocalCache()
		{
			if (!((Object)(object)PlayerAvatar.instance == (Object)null) && !((Object)(object)PlayerAvatar.instance.playerAvatarVisuals == (Object)null))
			{
				PlayerAvatar instance = PlayerAvatar.instance;
				GameObject gameObject = ((Component)instance.playerAvatarVisuals).gameObject;
				GameObject val = Object.Instantiate<GameObject>(gameObject);
				FreeCamGhostVisualBuilder.PrepareCloneAsGhost(val);
				_localCachedVisual = val;
				AdvancedFreeCam.Logger.LogInfo((object)"[GhostCache] Rebuilt local cache.");
			}
		}

		internal static GameObject? InstantiateLocalCache(Transform parent)
		{
			if ((Object)(object)_localCachedVisual == (Object)null)
			{
				return null;
			}
			GameObject val = Object.Instantiate<GameObject>(_localCachedVisual, parent);
			val.SetActive(true);
			return val;
		}

		internal static void ClearLocalCache()
		{
			if ((Object)(object)_localCachedVisual != (Object)null)
			{
				Object.Destroy((Object)(object)_localCachedVisual);
				_localCachedVisual = null;
			}
		}

		private static bool CanBuildNow()
		{
			if (!SemiFunc.RunIsLevel() && !SemiFunc.RunIsArena() && !SemiFunc.RunIsShop() && !SemiFunc.RunIsRecording())
			{
				return false;
			}
			if ((Object)(object)PlayerAvatar.instance == (Object)null)
			{
				return false;
			}
			if (PlayerAvatar.instance.isDisabled)
			{
				return false;
			}
			if ((Object)(object)PlayerAvatar.instance.playerAvatarVisuals == (Object)null)
			{
				return false;
			}
			return true;
		}
	}
	internal static class FreeCamGhostVisualFactory
	{
		internal static GameObject CreateDefault(Transform parent, int actorNumber, out bool usedFallback)
		{
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			PlayerAvatar val = FindPlayerAvatarByActorNumber(actorNumber);
			if ((Object)(object)val == (Object)null || (Object)(object)val.playerAvatarVisuals == (Object)null)
			{
				usedFallback = true;
				return CreateFallbackVisual(parent);
			}
			GameObject gameObject = ((Component)val.playerAvatarVisuals).gameObject;
			GameObject val2 = Object.Instantiate<GameObject>(gameObject);
			((Object)val2).name = $"{((Object)gameObject).name}_FreeCamGhost_{actorNumber}";
			val2.transform.SetParent(parent, false);
			val2.transform.localPosition = Vector3.zero;
			val2.transform.localRotation = Quaternion.identity;
			FreeCamGhostVisualBuilder.PrepareCloneAsGhost(val2);
			TryAttachTalkAnimation(val2, val);
			TryAttachNameTag(val2, val);
			usedFallback = false;
			return val2;
		}

		internal static PlayerAvatar? FindPlayerAvatarByActorNumber(int actorNumber)
		{
			if ((Object)(object)GameDirector.instance == (Object)null)
			{
				return null;
			}
			foreach (PlayerAvatar player in GameDirector.instance.PlayerList)
			{
				if (!((Object)(object)player == (Object)null))
				{
					PhotonView component = ((Component)player).GetComponent<PhotonView>();
					if (!((Object)(object)component == (Object)null) && component.Owner != null && component.Owner.ActorNumber == actorNumber)
					{
						return player;
					}
				}
			}
			return null;
		}

		private static GameObject CreateFallbackVisual(Transform parent)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Expected O, but got Unknown
			//IL_0051: 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_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("GhostFallbackVisual");
			val.transform.SetParent(parent, false);
			GameObject val2 = GameObject.CreatePrimitive((PrimitiveType)0);
			((Object)val2).name = "Head";
			val2.transform.SetParent(val.transform, false);
			val2.transform.localPosition = new Vector3(0f, 1.4f, 0f);
			val2.transform.localScale = new Vector3(0.35f, 0.35f, 0.35f);
			GameObject val3 = GameObject.CreatePrimitive((PrimitiveType)1);
			((Object)val3).name = "Body";
			val3.transform.SetParent(val.transform, false);
			val3.transform.localPosition = new Vector3(0f, 0.75f, 0f);
			val3.transform.localScale = new Vector3(0.7f, 0.75f, 0.5f);
			DisableCollider(val2);
			DisableCollider(val3);
			return val;
		}

		private static void DisableCollider(GameObject obj)
		{
			Collider component = obj.GetComponent<Collider>();
			if ((Object)(object)component != (Object)null)
			{
				Object.Destroy((Object)(object)component);
			}
		}

		private static void TryAttachTalkAnimation(GameObject clone, PlayerAvatar avatar)
		{
			if (!((Object)(object)clone == (Object)null) && !((Object)(object)avatar == (Object)null))
			{
				PlayerAvatarTalkAnimation componentInChildren = clone.GetComponentInChildren<PlayerAvatarTalkAnimation>(true);
				if ((Object)(object)componentInChildren == (Object)null)
				{
					AdvancedFreeCam.Logger.LogWarning((object)"[Ghost] PlayerAvatarTalkAnimation が見つかりません。口パクを付けられません。");
					return;
				}
				if ((Object)(object)componentInChildren.objectToRotate == (Object)null)
				{
					AdvancedFreeCam.Logger.LogWarning((object)"[Ghost] objectToRotate が null です。口パクを付けられません。");
					return;
				}
				FreeCamGhostTalkAnimation freeCamGhostTalkAnimation = clone.AddComponent<FreeCamGhostTalkAnimation>();
				freeCamGhostTalkAnimation.Initialize(avatar, componentInChildren.objectToRotate.transform, componentInChildren.rotationMaxAngle);
			}
		}

		private static void TryAttachNameTag(GameObject clone, PlayerAvatar avatar)
		{
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Expected O, but got Unknown
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)clone == (Object)null) && !((Object)(object)avatar == (Object)null))
			{
				string text = avatar.playerName;
				if (string.IsNullOrWhiteSpace(text))
				{
					text = "Unknown";
				}
				Transform val = FindHeadAnchor(clone);
				if ((Object)(object)val == (Object)null)
				{
					val = clone.transform;
				}
				Vector3 val2 = default(Vector3);
				((Vector3)(ref val2))..ctor(0f, 0.55f, 0f);
				GameObject val3 = new GameObject("GhostNameTag");
				val3.transform.SetParent(clone.transform, false);
				val3.transform.position = val.position + val2;
				TextMeshPro val4 = val3.AddComponent<TextMeshPro>();
				((TMP_Text)val4).text = text;
				((TMP_Text)val4).fontSize = 1.2f;
				((TMP_Text)val4).alignment = (TextAlignmentOptions)514;
				((Graphic)val4).color = Color.white;
				((TMP_Text)val4).outlineWidth = 0.2f;
				((TMP_Text)val4).enableWordWrapping = false;
				((Graphic)val4).raycastTarget = false;
				FreeCamGhostNameTag freeCamGhostNameTag = val3.AddComponent<FreeCamGhostNameTag>();
				freeCamGhostNameTag.Initialize(val, val2);
			}
		}

		private static Transform FindHeadAnchor(GameObject clone)
		{
			Transform[] componentsInChildren = clone.GetComponentsInChildren<Transform>(true);
			Transform[] array = componentsInChildren;
			foreach (Transform val in array)
			{
				string text = ((Object)val).name.ToLowerInvariant();
				if (text.Contains("head") || text.Contains("helmet") || text.Contains("neck"))
				{
					return val;
				}
			}
			return clone.transform;
		}
	}
}
namespace AdvancedFreeCam.Core
{
	internal sealed class FreeCamController
	{
		private const float DefaultLookSensitivity = 3f;

		private const float DefaultMoveSmooth = 8f;

		private const float DefaultRotateSmooth = 14f;

		private const float MinPitch = -89f;

		private const float MaxPitch = 89f;

		private bool _entered;

		private Vector3 _currentVelocity = Vector3.zero;

		private Vector3 _targetVelocity = Vector3.zero;

		private float _yaw;

		private float _pitch;

		internal float LookSensitivity { get; set; } = 3f;


		internal float MoveSmooth { get; set; } = 8f;


		internal float RotateSmooth { get; set; } = 14f;


		public void Enter(Vector3 startPosition, Quaternion startRotation)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			Vector3 eulerAngles = ((Quaternion)(ref startRotation)).eulerAngles;
			_pitch = NormalizeAngle(eulerAngles.x);
			_yaw = NormalizeAngle(eulerAngles.y);
			_pitch = Mathf.Clamp(_pitch, -89f, 89f);
			_currentVelocity = Vector3.zero;
			_targetVelocity = Vector3.zero;
			_entered = true;
		}

		public void Exit()
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_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)
			_entered = false;
			_currentVelocity = Vector3.zero;
			_targetVelocity = Vector3.zero;
		}

		public void Tick(float deltaTime, Transform rigTransform, float moveSpeed)
		{
			if (_entered && !((Object)(object)rigTransform == (Object)null))
			{
				UpdateRotation(deltaTime, rigTransform);
				UpdateMovement(deltaTime, rigTransform, moveSpeed);
			}
		}

		private void UpdateRotation(float deltaTime, Transform rigTransform)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			Vector2 val = ReadLookInput();
			float freeCamLookSensitivity = FreeCamLocalConfig.GetFreeCamLookSensitivity();
			_yaw += val.x * freeCamLookSensitivity;
			_pitch -= val.y * freeCamLookSensitivity;
			_pitch = Mathf.Clamp(_pitch, -89f, 89f);
			Quaternion val2 = Quaternion.Euler(_pitch, _yaw, 0f);
			rigTransform.rotation = Quaternion.Slerp(rigTransform.rotation, val2, RotateSmooth * deltaTime);
		}

		private void UpdateMovement(float deltaTime, Transform rigTransform, float moveSpeed)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = ReadMoveInput();
			_targetVelocity = val * moveSpeed;
			_currentVelocity = Vector3.Lerp(_currentVelocity, _targetVelocity, MoveSmooth * deltaTime);
			Quaternion val2 = Quaternion.Euler(0f, _yaw, 0f);
			Vector3 val3 = val2 * Vector3.forward;
			Vector3 val4 = val2 * Vector3.right;
			Vector3 val5 = val3 * _currentVelocity.z + val4 * _currentVelocity.x + Vector3.up * _currentVelocity.y;
			rigTransform.position += val5 * deltaTime;
		}

		private static Vector2 ReadLookInput()
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			Vector2 val = default(Vector2);
			((Vector2)(ref val))..ctor(Input.GetAxisRaw("Mouse X"), Input.GetAxisRaw("Mouse Y"));
			float freeCamMaxMouseDelta = FreeCamLocalConfig.GetFreeCamMaxMouseDelta();
			val.x = Mathf.Clamp(val.x, 0f - freeCamMaxMouseDelta, freeCamMaxMouseDelta);
			val.y = Mathf.Clamp(val.y, 0f - freeCamMaxMouseDelta, freeCamMaxMouseDelta);
			return val;
		}

		private static Vector3 ReadMoveInput()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = Vector3.zero;
			if (Input.GetKey((KeyCode)119))
			{
				val += Vector3.forward;
			}
			if (Input.GetKey((KeyCode)115))
			{
				val += Vector3.back;
			}
			if (Input.GetKey((KeyCode)97))
			{
				val += Vector3.left;
			}
			if (Input.GetKey((KeyCode)100))
			{
				val += Vector3.right;
			}
			if (Input.GetKey(FreeCamLocalConfig.GetMoveUpKey()))
			{
				val += Vector3.up;
			}
			if (Input.GetKey(FreeCamLocalConfig.GetMoveDownKey()))
			{
				val += Vector3.down;
			}
			if (((Vector3)(ref val)).sqrMagnitude > 1f)
			{
				((Vector3)(ref val)).Normalize();
			}
			return val;
		}

		private static float NormalizeAngle(float angle)
		{
			if (angle > 180f)
			{
				angle -= 360f;
			}
			return angle;
		}
	}
	internal static class FreeCamLocalBodyMeshController
	{
		private static bool _wasEnabledByFreeCam;

		internal static void ShowHiddenLocalMeshes()
		{
			PlayerAvatarVisuals val = PlayerAvatar.instance?.playerAvatarVisuals;
			if (!((Object)(object)val == (Object)null) && !((Object)(object)val.meshParent == (Object)null) && (!val.meshParent.activeSelf || !((Object)(object)val.animator != (Object)null) || !((Behaviour)val.animator).enabled))
			{
				val.meshParent.SetActive(true);
				if ((Object)(object)val.animator != (Object)null)
				{
					((Behaviour)val.animator).enabled = true;
				}
				_wasEnabledByFreeCam = true;
			}
		}

		internal static void HideRestoredLocalMeshes()
		{
			if (!_wasEnabledByFreeCam)
			{
				return;
			}
			PlayerAvatarVisuals val = PlayerAvatar.instance?.playerAvatarVisuals;
			if ((Object)(object)val == (Object)null)
			{
				_wasEnabledByFreeCam = false;
				return;
			}
			if ((Object)(object)val.animator != (Object)null)
			{
				((Behaviour)val.animator).enabled = false;
			}
			if ((Object)(object)val.meshParent != (Object)null)
			{
				val.meshParent.SetActive(false);
			}
			_wasEnabledByFreeCam = false;
		}
	}
	internal sealed class FreeCamManager
	{
		private readonly FreeCamController _controller = new FreeCamController();

		private readonly FreeCamRig _rig = new FreeCamRig();

		private FreeCamState _state;

		private float _currentMoveSpeed = -1f;

		private float _speedLogTimer;

		private Transform? _cameraAimTransform;

		private Transform? _originalParent;

		private Vector3 _originalLocalPosition;

		private Quaternion _originalLocalRotation;

		private bool _isPreparingLevelTransition;

		private string _lastCleanupLogReason;

		private float _lastCleanupLogTime = -999f;

		internal static FreeCamManager? Instance { get; private set; }

		public bool IsActive => _state == FreeCamState.Active;

		public Vector3 CurrentPosition
		{
			get
			{
				//IL_001c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0015: Unknown result type (might be due to invalid IL or missing references)
				Transform transform = _rig.Transform;
				if (!((Object)(object)transform != (Object)null))
				{
					return Vector3.zero;
				}
				return transform.position;
			}
		}

		public Vector3 CurrentVoicePosition
		{
			get
			{
				//IL_001e: 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_004e: Unknown result type (might be due to invalid IL or missing references)
				Transform transform = _rig.Transform;
				if ((Object)(object)transform != (Object)null && IsActive)
				{
					return transform.position;
				}
				Camera val = (((Object)(object)GameDirector.instance != (Object)null) ? GameDirector.instance.MainCamera : null);
				if ((Object)(object)val != (Object)null)
				{
					return ((Component)val).transform.position;
				}
				return Vector3.zero;
			}
		}

		public FreeCamManager()
		{
			Instance = this;
		}

		public void Tick(float deltaTime)
		{
			if (!ValidateGameState())
			{
				return;
			}
			HandleInput();
			if (IsActive)
			{
				TickActive(deltaTime);
				if (FreeCamPhotoMode.IsEnabled)
				{
					FreeCamPhotoMode.Tick();
				}
			}
		}

		public void ToggleFreeCam()
		{
			if (IsActive)
			{
				DisableFreeCam();
			}
			else
			{
				EnableFreeCam();
			}
		}

		public void EnableFreeCam()
		{
			//IL_006d: 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_009c: 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)
			if (IsActive)
			{
				return;
			}
			_isPreparingLevelTransition = false;
			if (CanUseFreeCamNow() && FreeCamPolicy.CanToggleFreeCam() && !((Object)(object)CameraAim.Instance == (Object)null))
			{
				_cameraAimTransform = ((Component)CameraAim.Instance).transform;
				CacheOriginalCameraParent();
				_rig.EnsureCreated();
				Transform transform = _rig.Transform;
				if (!((Object)(object)transform == (Object)null))
				{
					transform.position = _cameraAimTransform.position;
					transform.rotation = _cameraAimTransform.rotation;
					_cameraAimTransform.SetParent(transform, true);
					_controller.Enter(transform.position, transform.rotation);
					_state = FreeCamState.Active;
					FreeCamLocalBodyMeshController.ShowHiddenLocalMeshes();
					AdvancedFreeCam.Logger.LogInfo((object)"FreeCam Enabled");
				}
			}
		}

		public void DisableFreeCam()
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			if (IsActive)
			{
				FreeCamPhotoMode.Disable();
				if (SemiFunc.IsMultiplayer())
				{
					FreeCamGhostNetwork.SendState(active: false, Vector3.zero, Quaternion.identity);
				}
				CleanupInternal(resetAimDisable: true);
				FreeCamLocalBodyMeshController.HideRestoredLocalMeshes();
				AdvancedFreeCam.Logger.LogInfo((object)"FreeCam Disabled");
			}
		}

		public void ForceCleanup(string reason = "")
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			bool flag = IsActive || _rig.IsValid || (Object)(object)_cameraAimTransform != (Object)null;
			if (SemiFunc.IsMultiplayer() && IsActive)
			{
				FreeCamGhostNetwork.SendState(active: false, Vector3.zero, Quaternion.identity);
			}
			CleanupInternal(resetAimDisable: true);
			if (flag)
			{
				LogCleanupReasonOnce("FreeCam cleanup", reason);
			}
		}

		public void PrepareForLevelTransition(string reason = "")
		{
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			bool flag = IsActive || _rig.IsValid || (Object)(object)_cameraAimTransform != (Object)null || FreeCamPhotoMode.IsEnabled;
			_isPreparingLevelTransition = true;
			if (SemiFunc.IsMultiplayer() && IsActive)
			{
				FreeCamGhostNetwork.SendState(active: false, Vector3.zero, Quaternion.identity);
			}
			FreeCamPhotoMode.ForceReset(isChangeLevel: true);
			_controller.Exit();
			_state = FreeCamState.Disabled;
			if (flag)
			{
				LogCleanupReasonOnce("FreeCam prepare level transition", reason);
			}
		}

		private void LogCleanupReasonOnce(string prefix, string reason)
		{
			if (!string.IsNullOrWhiteSpace(reason) && (!(_lastCleanupLogReason == reason) || !(Time.unscaledTime - _lastCleanupLogTime < 0.5f)))
			{
				_lastCleanupLogReason = reason;
				_lastCleanupLogTime = Time.unscaledTime;
				AdvancedFreeCam.Logger.LogWarning((object)(prefix + ": " + reason));
			}
		}

		private bool ValidateGameState()
		{
			if (CanUseFreeCamNow())
			{
				if (_isPreparingLevelTransition)
				{
					_isPreparingLevelTransition = false;
					FinalizePreparedTransitionCleanup();
				}
				return true;
			}
			if (_isPreparingLevelTransition)
			{
				return false;
			}
			if (IsActive || _rig.IsValid || (Object)(object)_cameraAimTransform != (Object)null)
			{
				ForceCleanup("Invalid game state");
			}
			return false;
		}

		private void HandleSpeedWheelInput()
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			if (IsActive && ((!Input.GetKey((KeyCode)308) && !Input.GetKey((KeyCode)307)) || !FreeCamPhotoMode.IsEnabled))
			{
				EnsureMoveSpeedInitialized();
				float y = Input.mouseScrollDelta.y;
				if (!(Mathf.Abs(y) <= 0.001f))
				{
					float freeCamMouseWheelSpeedStep = FreeCamLocalConfig.GetFreeCamMouseWheelSpeedStep();
					float freeCamMinMoveSpeed = FreeCamLocalConfig.GetFreeCamMinMoveSpeed();
					float freeCamMaxMoveSpeed = FreeCamLocalConfig.GetFreeCamMaxMoveSpeed();
					_currentMoveSpeed = Mathf.Clamp(_currentMoveSpeed + y * freeCamMouseWheelSpeedStep, freeCamMinMoveSpeed, freeCamMaxMoveSpeed);
					AdvancedFreeCam.Logger.LogInfo((object)$"FreeCam speed: {_currentMoveSpeed:0.0}");
				}
			}
		}

		private void EnsureMoveSpeedInitialized()
		{
			if (!(_currentMoveSpeed > 0f))
			{
				_currentMoveSpeed = FreeCamLocalConfig.GetFreeCamBaseMoveSpeed();
			}
		}

		private void FinalizePreparedTransitionCleanup()
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			_rig.Destroy();
			_cameraAimTransform = null;
			_originalParent = null;
			_originalLocalPosition = Vector3.zero;
			_originalLocalRotation = Quaternion.identity;
		}

		private void HandleInput()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			if (Input.GetKeyDown(FreeCamLocalConfig.GetToggleFreeCamKey()))
			{
				if (!IsActive && !FreeCamPolicy.CanToggleFreeCam())
				{
					AdvancedFreeCam.Logger.LogInfo((object)"FreeCam denied by policy");
				}
				else
				{
					ToggleFreeCam();
				}
			}
			else
			{
				if (!IsActive)
				{
					return;
				}
				HandleSpeedWheelInput();
				if (Input.GetKeyDown(FreeCamLocalConfig.GetTogglePhotoModeKey()))
				{
					FreeCamPhotoMode.Toggle();
				}
				if (FreeCamPhotoMode.IsEnabled && (Input.GetKey((KeyCode)308) || Input.GetKey((KeyCode)307)))
				{
					float y = Input.mouseScrollDelta.y;
					if (Mathf.Abs(y) > 0.001f)
					{
						float photoModeNightVision = FreeCamLocalConfig.GetPhotoModeNightVision();
						float num = Mathf.Clamp(photoModeNightVision + y * 5f, 0f, 100f);
						AdvancedFreeCam.Instance.SetPhotoModeNightVision(num);
						FreeCamPhotoMode.ApplyNightVisionOnly();
						AdvancedFreeCam.Logger.LogInfo((object)$"PhotoMode NightVision: {num:0}");
					}
				}
			}
		}

		private void TickActive(float deltaTime)
		{
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			CameraAim instance = CameraAim.Instance;
			if (instance != null)
			{
				instance.OverridePlayerAimDisable(true);
			}
			PlayerController instance2 = PlayerController.instance;
			if (instance2 != null)
			{
				instance2.InputDisable(0.1f);
			}
			Transform transform = _rig.Transform;
			if ((Object)(object)transform == (Object)null || (Object)(object)_cameraAimTransform == (Object)null || (Object)(object)CameraAim.Instance == (Object)null)
			{
				ForceCleanup("Lost references while active");
				return;
			}
			EnsureMoveSpeedInitialized();
			float num = _currentMoveSpeed;
			if (Input.GetKey(FreeCamLocalConfig.GetFastMoveKey()))
			{
				num *= FreeCamLocalConfig.GetFreeCamFastMoveMultiplier();
			}
			_controller.Tick(deltaTime, transform, num);
			ApplyRigToCameraAim();
			if (SemiFunc.IsMultiplayer())
			{
				FreeCamGhostNetwork.SendState(active: true, transform.position, transform.rotation);
			}
		}

		private void CacheOriginalCameraParent()
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_cameraAimTransform == (Object)null))
			{
				_originalParent = _cameraAimTransform.parent;
				_originalLocalPosition = _cameraAimTransform.localPosition;
				_originalLocalRotation = _cameraAimTransform.localRotation;
			}
		}

		private void CleanupInternal(bool resetAimDisable)
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			FreeCamPhotoMode.ForceReset();
			RestoreCameraAimSafe(resetAimDisable);
			_rig.Destroy();
			_controller.Exit();
			_cameraAimTransform = null;
			_originalParent = null;
			_originalLocalPosition = Vector3.zero;
			_originalLocalRotation = Quaternion.identity;
			_state = FreeCamState.Disabled;
		}

		private bool CanUseFreeCamNow()
		{
			if ((Object)(object)RunManager.instance == (Object)null)
			{
				return false;
			}
			if (RunManager.instance.restarting)
			{
				return false;
			}
			if (!SemiFunc.RunIsLevel() && !SemiFunc.RunIsShop() && !SemiFunc.RunIsArena() && !SemiFunc.RunIsRecording())
			{
				return false;
			}
			if ((Object)(object)PlayerController.instance == (Object)null)
			{
				return false;
			}
			if ((Object)(object)PlayerAvatar.instance == (Object)null)
			{
				return false;
			}
			if ((Object)(object)CameraAim.Instance == (Object)null)
			{
				return false;
			}
			return true;
		}

		private void RestoreCameraAimSafe(bool resetAimDisable)
		{
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_cameraAimTransform == (Object)null)
			{
				return;
			}
			try
			{
				if ((Object)(object)_originalParent != (Object)null)
				{
					_cameraAimTransform.SetParent(_originalParent, true);
					_cameraAimTransform.localPosition = _originalLocalPosition;
					_cameraAimTransform.localRotation = _originalLocalRotation;
				}
				else
				{
					_cameraAimTransform.SetParent((Transform)null, true);
				}
				if (resetAimDisable && (Object)(object)CameraAim.Instance != (Object)null)
				{
					CameraAim.Instance.OverridePlayerAimDisableReset();
				}
			}
			catch (Exception arg)
			{
				AdvancedFreeCam.Logger.LogWarning((object)$"RestoreCameraAimSafe failed: {arg}");
			}
		}

		private void ApplyRigToCameraAim()
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_cameraAimTransform == (Object)null))
			{
				_cameraAimTransform.localPosition = Vector3.zero;
				_cameraAimTransform.localRotation = Quaternion.identity;
			}
		}
	}
	internal static class FreeCamPhotoMode
	{
		private static bool _enabled;

		private static bool _savedFog;

		private static bool _fogSaved;

		private static float _savedFarClipPlane;

		private static bool _farClipSaved;

		private static float _savedShadowDistance;

		private static bool _shadowDistanceSaved;

		private static float _savedLodBias;

		private static bool _lodBiasSaved;

		private static int _savedMaximumLodLevel;

		private static bool _maximumLodLevelSaved;

		private static Color _savedAmbientLight;

		private static bool _ambientLightSaved;

		private static MenuSpectateList _menuSpectateList;

		private static SpectateHeadUI _spectateHeadUI;

		private static SpectateNameUI _spectateNameUI;

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

		private const float PhotoModeFarClipPlane = 500f;

		private const float PhotoModeShadowDistance = 300f;

		private const float PhotoModeLodBias = 3f;

		private const int PhotoModeMaximumLodLevel = 0;

		internal static bool IsEnabled => _enabled;

		internal static void Toggle()
		{
			if (_enabled)
			{
				Disable();
			}
			else
			{
				Enable();
			}
		}

		internal static void LateTick()
		{
			if (IsEnabled)
			{
				ApplyPhotoModeValues();
				ApplyNightVision();
			}
		}

		internal static void Enable()
		{
			if (!_enabled)
			{
				_enabled = true;
				SaveCurrentValues();
				CacheUIReferences();
				ApplyPhotoModeValues();
				ApplyNightVision();
				HidePhotoModeUI();
				HidePhotoModeEquipment();
				AdvancedFreeCam.Logger.LogInfo((object)"FreeCam PhotoMode Enabled");
			}
		}

		internal static void Disable()
		{
			if (_enabled)
			{
				_enabled = false;
				RestoreSavedValues();
				ClearSavedFlags();
				RestorePhotoModeUI();
				RestorePhotoModeEquipment();
				ResetCachedReferences();
				AdvancedFreeCam.Logger.LogInfo((object)"FreeCam PhotoMode Disabled");
			}
		}

		internal static void ForceReset(bool isChangeLevel = false)
		{
			_enabled = false;
			if (isChangeLevel)
			{
				ClearSavedFlags();
				ResetCachedReferences();
				return;
			}
			RestoreSavedValues();
			ClearSavedFlags();
			RestorePhotoModeUI();
			RestorePhotoModeEquipment();
			ResetCachedReferences();
		}

		internal static void Tick()
		{
			if (_enabled)
			{
				ApplyPhotoModeValues();
				ApplyNightVision();
				HidePhotoModeUI();
				HidePhotoModeEquipment();
			}
		}

		internal static void ApplyNightVisionOnly()
		{
			if (_enabled)
			{
				ApplyNightVision();
			}
		}

		private static void SaveCurrentValues()
		{
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			_savedFog = RenderSettings.fog;
			_fogSaved = true;
			Camera mainCamera = GetMainCamera();
			if ((Object)(object)mainCamera != (Object)null)
			{
				_savedFarClipPlane = mainCamera.farClipPlane;
				_farClipSaved = true;
			}
			else
			{
				_farClipSaved = false;
			}
			_savedShadowDistance = QualitySettings.shadowDistance;
			_shadowDistanceSaved = true;
			_savedLodBias = QualitySettings.lodBias;
			_lodBiasSaved = true;
			_savedMaximumLodLevel = QualitySettings.maximumLODLevel;
			_maximumLodLevelSaved = true;
			_savedAmbientLight = RenderSettings.ambientLight;
			_ambientLightSaved = true;
		}

		private static void ApplyPhotoModeValues()
		{
			Camera main = Camera.main;
			if (!((Object)(object)main == (Object)null))
			{
				RenderSettings.fog = false;
				main.farClipPlane = 500f;
				QualitySettings.shadowDistance = 300f;
				QualitySettings.lodBias = Mathf.Max(QualitySettings.lodBias, 3f);
				QualitySettings.maximumLODLevel = 0;
			}
		}

		private static void ApplyNightVision()
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			float num = Mathf.Clamp(FreeCamLocalConfig.GetPhotoModeNightVision(), 0f, 100f);
			if (!(num <= 0.001f))
			{
				float num2 = Mathf.Clamp01(num / 100f);
				Color ambientLight = RenderSettings.ambientLight;
				Color ambientLight2 = Color.Lerp(ambientLight, Color.white * 2f, num2);
				RenderSettings.ambientLight = ambientLight2;
			}
		}

		private static void RestoreSavedValues()
		{
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			if (_fogSaved)
			{
				RenderSettings.fog = _savedFog;
			}
			Camera mainCamera = GetMainCamera();
			if ((Object)(object)mainCamera != (Object)null && _farClipSaved)
			{
				mainCamera.farClipPlane = _savedFarClipPlane;
			}
			if (_shadowDistanceSaved)
			{
				QualitySettings.shadowDistance = _savedShadowDistance;
			}
			if (_lodBiasSaved)
			{
				QualitySettings.lodBias = _savedLodBias;
			}
			if (_maximumLodLevelSaved)
			{
				QualitySettings.maximumLODLevel = _savedMaximumLodLevel;
			}
			if (_ambientLightSaved)
			{
				RenderSettings.ambientLight = _savedAmbientLight;
			}
		}

		private static void ClearSavedFlags()
		{
			_fogSaved = false;
			_farClipSaved = false;
			_shadowDistanceSaved = false;
			_lodBiasSaved = false;
			_maximumLodLevelSaved = false;
			_ambientLightSaved = false;
		}

		private static void CacheUIReferences()
		{
			if ((Object)(object)_menuSpectateList == (Object)null)
			{
				_menuSpectateList = Object.FindObjectOfType<MenuSpectateList>(true);
			}
			if ((Object)(object)_spectateHeadUI == (Object)null)
			{
				_spectateHeadUI = SpectateHeadUI.instance;
				if ((Object)(object)_spectateHeadUI == (Object)null)
				{
					_spectateHeadUI = Object.FindObjectOfType<SpectateHeadUI>(true);
				}
			}
			if ((Object)(object)_spectateNameUI == (Object)null)
			{
				_spectateNameUI = SpectateNameUI.instance;
				if ((Object)(object)_spectateNameUI == (Object)null)
				{
					_spectateNameUI = Object.FindObjectOfType<SpectateNameUI>(true);
				}
			}
		}

		private static void HidePhotoModeUI()
		{
			if ((Object)(object)HUD.instance != (Object)null)
			{
				HUD.instance.Hide();
			}
			if ((Object)(object)MissionUI.instance != (Object)null)
			{
				((SemiUI)MissionUI.instance).Hide();
			}
			if ((Object)(object)BatteryUI.instance != (Object)null)
			{
				((SemiUI)BatteryUI.instance).Hide();
			}
			if ((Object)(object)_spectateNameUI != (Object)null)
			{
				((SemiUI)_spectateNameUI).Hide();
			}
			if ((Object)(object)_spectateHeadUI != (Object)null)
			{
				((SemiUI)_spectateHeadUI).Hide();
			}
			if ((Object)(object)_menuSpectateList != (Object)null)
			{
				((SemiUI)_menuSpectateList).Hide();
				HideMenuPlayerListedChildren();
			}
			SemiFunc.UIHideHealth();
			SemiFunc.UIHideOvercharge();
			SemiFunc.UIHideEnergy();
			SemiFunc.UIHideInventory();
			SemiFunc.UIHideHaul();
			SemiFunc.UIHideGoal();
			SemiFunc.UIHideCurrency();
			SemiFunc.UIHideAim();
			SemiFunc.UIHideTumble();
			SemiFunc.UIHideWorldSpace();
			SemiFunc.UIHideValuableDiscover();
			SemiFunc.UIHideShopCost();
		}

		private static void HideMenuPlayerListedChildren()
		{
			for (int i = 0; i < _menuSpectateList.listObjects.Count; i++)
			{
				GameObject val = _menuSpectateList.listObjects[i];
				if (!((Object)(object)val == (Object)null) && val.activeSelf)
				{
					val.SetActive(false);
					if (!_disabledMenuPlayerListedObjects.Contains(val))
					{
						_disabledMenuPlayerListedObjects.Add(val);
					}
				}
			}
		}

		private static void RestorePhotoModeUI()
		{
			if ((Object)(object)HUD.instance != (Object)null)
			{
				HUD.instance.Show();
			}
			if ((Object)(object)_menuSpectateList != (Object)null)
			{
				((Behaviour)_menuSpectateList).enabled = true;
				((SemiUI)_menuSpectateList).Show();
			}
			for (int i = 0; i < _disabledMenuPlayerListedObjects.Count; i++)
			{
				GameObject val = _disabledMenuPlayerListedObjects[i];
				if (!((Object)(object)val == (Object)null) && !val.activeSelf)
				{
					val.SetActive(true);
				}
			}
			_disabledMenuPlayerListedObjects.Clear();
			if ((Object)(object)_spectateNameUI != (Object)null)
			{
				((Behaviour)_spectateNameUI).enabled = true;
				((SemiUI)_spectateNameUI).Show();
			}
			if ((Object)(object)_spectateHeadUI != (Object)null)
			{
				((Behaviour)_spectateHeadUI).enabled = true;
				((SemiUI)_spectateHeadUI).Show();
			}
			if ((Object)(object)SpectateCamera.instance != (Object)null)
			{
				SemiFunc.UIShowSpectate();
			}
		}

		private static void HidePhotoModeEquipment()
		{
			FlashlightController instance = FlashlightController.Instance;
			if (!((Object)(object)instance == (Object)null))
			{
				instance.hideFlashlight = true;
				instance.active = false;
				instance.LightActive = false;
				if ((Object)(object)instance.mesh != (Object)null)
				{
					((Renderer)instance.mesh).enabled = false;
				}
				if ((Object)(object)instance.spotlight != (Object)null)
				{
					((Behaviour)instance.spotlight).enabled = false;
				}
				if ((Object)(object)instance.halo != (Object)null)
				{
					instance.halo.enabled = false;
				}
			}
		}

		private static void RestorePhotoModeEquipment()
		{
			FlashlightController instance = FlashlightController.Instance;
			if (!((Object)(object)instance == (Object)null))
			{
				instance.hideFlashlight = false;
			}
		}

		private static void ResetCachedReferences()
		{
			_menuSpectateList = null;
			_spectateHeadUI = null;
			_spectateNameUI = null;
			_disabledMenuPlayerListedObjects.Clear();
		}

		private static Camera GetMainCamera()
		{
			if ((Object)(object)GameDirector.instance != (Object)null && (Object)(object)GameDirector.instance.MainCamera != (Object)null)
			{
				return GameDirector.instance.MainCamera;
			}
			return Camera.main;
		}
	}
	[HarmonyPatch(typeof(SemiFunc), "UIShowSpectate")]
	internal static class Patch_SemiFunc_UIShowSpectate_PhotoModeBlock
	{
		private static bool Prefix()
		{
			return !FreeCamPhotoMode.IsEnabled;
		}
	}
	internal static class Patch_MenuSpectateList_PhotoModeBlock
	{
		private static bool Prefix(MenuSpectateList __instance)
		{
			if (!FreeCamPhotoMode.IsEnabled)
			{
				return true;
			}
			((SemiUI)__instance).Hide();
			return false;
		}
	}
	[HarmonyPatch(typeof(MenuPlayerListed), "Update")]
	internal static class Patch_MenuPlayerListed_PhotoModeBlock
	{
		private static bool Prefix()
		{
			return !FreeCamPhotoMode.IsEnabled;
		}
	}
	[HarmonyPatch(typeof(LobbyChatUI), "Update")]
	internal static class Patch_LobbyChatUI_PhotoModeBlock
	{
		private static bool Prefix(LobbyChatUI __instance)
		{
			if (!FreeCamPhotoMode.IsEnabled)
			{
				return true;
			}
			((SemiUI)__instance).Hide();
			return false;
		}
	}
	[HarmonyPatch(typeof(MenuPlayerHead), "Update")]
	internal static class Patch_MenuPlayerHead_PhotoModeBlock
	{
		private static bool Prefix()
		{
			return !FreeCamPhotoMode.IsEnabled;
		}
	}
	internal se