Decompiled source of BasedSpectateMode v0.0.7

BasedSpectateMode.dll

Decompiled 2 weeks 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 BasedSpectate.Behaviours;
using BasedSpectate.Compat;
using BasedSpectate.Patches;
using BasedSpectate.Utils;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using CullFactory.Behaviours.API;
using DunGen;
using GameNetcodeStuff;
using HarmonyLib;
using LethalCompanyInputUtils.Api;
using LethalCompanyInputUtils.BindingPathEnums;
using LethalConfig;
using LethalConfig.ConfigItems;
using LethalConfig.ConfigItems.Options;
using Microsoft.CodeAnalysis;
using TMPro;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.InputSystem.Utilities;
using UnityEngine.Rendering.HighDefinition;
using UnityEngine.UI;

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

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

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

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

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace BasedSpectate
{
	internal enum SpectateMode
	{
		Vanilla,
		Freecam
	}
	internal static class Config
	{
		internal static ConfigEntry<SpectateMode> StartMode { get; private set; }

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

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

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

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

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

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

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

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

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

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

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

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

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

		internal static void Bind(ConfigFile config)
		{
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Expected O, but got Unknown
			//IL_0139: Unknown result type (might be due to invalid IL or missing references)
			//IL_0143: Expected O, but got Unknown
			//IL_0171: Unknown result type (might be due to invalid IL or missing references)
			//IL_017b: Expected O, but got Unknown
			//IL_01a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b3: Expected O, but got Unknown
			StartMode = config.Bind<SpectateMode>("General", "Start spectate mode", SpectateMode.Vanilla, "Choose which spectate mode you start with after you die");
			EnableModeToggle = config.Bind<bool>("General", "Enable mode toggle", true, "Allow switching spectate mode while dead");
			EnableFreecamResetHotkey = config.Bind<bool>("General", "Enable freecam reset hotkey", false, "Allow resetting freecam to the currently spectated player while using freecam mode");
			ShowNextPlayerHint = config.Bind<bool>("General", "Show next player hint", true, "Show the Next Player line on the death screen");
			ShowToggleModeHint = config.Bind<bool>("General", "Show toggle mode hint", true, "Show the Toggle Mode line on the death screen");
			ShowBrightnessHint = config.Bind<bool>("General", "Show brightness hint", true, "Show the Brightness line on the death screen");
			ShowZoomHint = config.Bind<bool>("General", "Show zoom hint", true, "Show the Zoom line on the death screen");
			DisableCullFactoryCulling = config.Bind<bool>("Compatibility", "Disable CullFactory culling in freecam", false, "Show all interior rooms while dead and using freecam mode when CullFactory is installed");
			DefaultZoomDistance = config.Bind<float>("Zoom", "Default zoom distance", 1.4f, new ConfigDescription("Starting zoom distance when spectating resets", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 50f), Array.Empty<object>()));
			MinZoomDistance = config.Bind<float>("Zoom", "Minimum zoom distance", 1f, new ConfigDescription("Closest the spectate camera can zoom in", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 50f), Array.Empty<object>()));
			MaxZoomDistance = config.Bind<float>("Zoom", "Maximum zoom distance", 15f, new ConfigDescription("Furthest the spectate camera can zoom out", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 50f), Array.Empty<object>()));
			ZoomSpeed = config.Bind<float>("Zoom", "Zoom speed", 0.4f, new ConfigDescription("How fast the mouse wheel zooms the camera", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 5f), Array.Empty<object>()));
			CameraClipsThroughWalls = config.Bind<bool>("Zoom", "Camera clips through walls", false, "Let the spectate camera pass through walls instead of stopping at them");
			DebugLogging = config.Bind<bool>("Internal", "Enable debug logs", false, "If true, enables debug logging");
			DefaultZoomDistance.SettingChanged += delegate
			{
				SpectateModePatches.ResetZoomDistance();
			};
		}
	}
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInPlugin("MrHat.BasedSpectateMode", "BasedSpectateMode", "0.0.7")]
	internal class Plugin : BaseUnityPlugin
	{
		private const string LethalConfigGUID = "ainavt.lc.lethalconfig";

		private const string CullFactoryGUID = "com.fumiko.CullFactory";

		private const string LethalCompanyInputUtilsGUID = "com.rune580.LethalCompanyInputUtils";

		internal const string modGUID = "MrHat.BasedSpectateMode";

		internal const string modName = "BasedSpectateMode";

		internal const string modVersion = "0.0.7";

		internal static ManualLogSource mls;

		private readonly Harmony _harmony = new Harmony("MrHat.BasedSpectateMode");

		internal static Plugin Instance { get; private set; }

		internal static SpectateMode CurrentMode { get; set; }

		private static bool hasLethalConfig => Chainloader.PluginInfos.ContainsKey("ainavt.lc.lethalconfig");

		private static bool hasCullFactory => Chainloader.PluginInfos.ContainsKey("com.fumiko.CullFactory");

		private void Awake()
		{
			Instance = this;
			mls = Logger.CreateLogSource("MrHat.BasedSpectateMode");
			Config.Bind(((BaseUnityPlugin)this).Config);
			CurrentMode = Config.StartMode.Value;
			SpectateInputActions.Initialise();
			Log.Debug("BasedSpectateMode patches running...");
			if (hasLethalConfig)
			{
				LethalConfigCompat.Register();
				Log.Debug("LethalConfig compatibility ran");
			}
			if (hasCullFactory)
			{
				PatchCullFactoryCompatibility();
				Log.Debug("CullFactory compatibility ran");
			}
			else
			{
				_harmony.PatchAll(typeof(DisableVanillaCullingPatches));
			}
			_harmony.PatchAll(typeof(SpectateModePatches));
			Log.Info("BasedSpectateMode loaded");
		}

		[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
		private void PatchCullFactoryCompatibility()
		{
			_harmony.PatchAll(typeof(CullFactoryCompat));
		}
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "BasedSpectateMode";

		public const string PLUGIN_NAME = "BasedSpectateMode";

		public const string PLUGIN_VERSION = "0.0.7";
	}
}
namespace BasedSpectate.Utils
{
	internal static class Log
	{
		internal static void Debug(string message)
		{
			if (Config.DebugLogging.Value)
			{
				Write((LogLevel)32, message);
			}
		}

		internal static void Info(string message)
		{
			Write((LogLevel)16, message);
		}

		internal static void Warn(string message)
		{
			Write((LogLevel)4, message);
		}

		internal static void Error(string message)
		{
			Write((LogLevel)2, message);
		}

		internal static void Fatal(string message)
		{
			Write((LogLevel)1, message);
		}

		private static void Write(LogLevel logLevel, string message)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			if (Plugin.mls != null)
			{
				Plugin.mls.Log(logLevel, (object)message);
			}
		}
	}
	internal class SpectateInputActions : LcInputActions
	{
		private const string KeyboardAndMouseGroup = "KeyboardAndMouse";

		internal static SpectateInputActions Instance { get; private set; }

		internal static bool HasFreecamResetAction { get; private set; }

		internal InputAction MoveForwardAction => ((LcInputActions)this).Asset["freecamMoveForward"];

		internal InputAction MoveBackwardAction => ((LcInputActions)this).Asset["freecamMoveBackward"];

		internal InputAction MoveLeftAction => ((LcInputActions)this).Asset["freecamMoveLeft"];

		internal InputAction MoveRightAction => ((LcInputActions)this).Asset["freecamMoveRight"];

		internal InputAction MoveUpAction => ((LcInputActions)this).Asset["freecamMoveUp"];

		internal InputAction MoveDownAction => ((LcInputActions)this).Asset["freecamMoveDown"];

		internal InputAction SprintAction => ((LcInputActions)this).Asset["freecamSprint"];

		internal InputAction NextPlayerAction => ((LcInputActions)this).Asset["freecamNextPlayer"];

		internal InputAction ToggleModeAction => ((LcInputActions)this).Asset["toggleSpectateMode"];

		internal InputAction ResetFreecamAction => ((LcInputActions)this).Asset["resetFreecamToPlayer"];

		internal static InputAction MoveForward => Instance.MoveForwardAction;

		internal static InputAction MoveBackward => Instance.MoveBackwardAction;

		internal static InputAction MoveLeft => Instance.MoveLeftAction;

		internal static InputAction MoveRight => Instance.MoveRightAction;

		internal static InputAction MoveUp => Instance.MoveUpAction;

		internal static InputAction MoveDown => Instance.MoveDownAction;

		internal static InputAction Sprint => Instance.SprintAction;

		internal static InputAction NextPlayer => Instance.NextPlayerAction;

		internal static InputAction ToggleMode => Instance.ToggleModeAction;

		internal static InputAction ResetFreecam => Instance.ResetFreecamAction;

		internal static void Initialise()
		{
			if (Instance == null)
			{
				Instance = new SpectateInputActions();
			}
		}

		internal static Vector2 ReadMoveInput()
		{
			//IL_007b: 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)
			Vector2 result = default(Vector2);
			((Vector2)(ref result))..ctor((MoveRight.IsPressed() ? 1f : 0f) - (MoveLeft.IsPressed() ? 1f : 0f), (MoveForward.IsPressed() ? 1f : 0f) - (MoveBackward.IsPressed() ? 1f : 0f));
			if (!(((Vector2)(ref result)).sqrMagnitude > 1f))
			{
				return result;
			}
			return ((Vector2)(ref result)).normalized;
		}

		internal static float ReadVerticalInput()
		{
			return (MoveUp.IsPressed() ? 1f : 0f) - (MoveDown.IsPressed() ? 1f : 0f);
		}

		internal static bool SprintIsPressed()
		{
			return Sprint.IsPressed();
		}

		internal static bool NextPlayerWasPressedThisFrame()
		{
			return NextPlayer.WasPressedThisFrame();
		}

		internal static bool ToggleModeWasPressedThisFrame()
		{
			return ToggleMode.WasPressedThisFrame();
		}

		internal static bool ResetFreecamWasPressedThisFrame()
		{
			return ResetFreecam.WasPressedThisFrame();
		}

		internal static bool ScrollWheelModifierIsPressed()
		{
			Keyboard current = Keyboard.current;
			if (current == null || !((ButtonControl)current.leftShiftKey).isPressed)
			{
				Keyboard current2 = Keyboard.current;
				if (current2 == null)
				{
					return false;
				}
				return ((ButtonControl)current2.rightShiftKey).isPressed;
			}
			return true;
		}

		internal static string GetNextPlayerBindingText()
		{
			return GetBindingText(NextPlayer);
		}

		internal static string GetToggleModeBindingText()
		{
			return GetBindingText(ToggleMode);
		}

		internal static string GetResetFreecamBindingText()
		{
			return GetBindingText(ResetFreecam);
		}

		public override void CreateInputActions(in InputActionMapBuilder builder)
		{
			builder.NewActionBinding().WithActionId("freecamMoveForward").WithActionType((InputActionType)1)
				.WithKbmPath("<Keyboard>/w")
				.WithBindingName("Freecam Move Forward")
				.Finish();
			builder.NewActionBinding().WithActionId("freecamMoveBackward").WithActionType((InputActionType)1)
				.WithKbmPath("<Keyboard>/s")
				.WithBindingName("Freecam Move Backward")
				.Finish();
			builder.NewActionBinding().WithActionId("freecamMoveLeft").WithActionType((InputActionType)1)
				.WithKbmPath("<Keyboard>/a")
				.WithBindingName("Freecam Move Left")
				.Finish();
			builder.NewActionBinding().WithActionId("freecamMoveRight").WithActionType((InputActionType)1)
				.WithKbmPath("<Keyboard>/d")
				.WithBindingName("Freecam Move Right")
				.Finish();
			builder.NewActionBinding().WithActionId("freecamMoveUp").WithActionType((InputActionType)1)
				.WithKbmPath("<Keyboard>/space")
				.WithBindingName("Freecam Move Up")
				.Finish();
			builder.NewActionBinding().WithActionId("freecamMoveDown").WithActionType((InputActionType)1)
				.WithKbmPath("<Keyboard>/leftCtrl")
				.WithBindingName("Freecam Move Down")
				.Finish();
			builder.NewActionBinding().WithActionId("freecamSprint").WithActionType((InputActionType)1)
				.WithKbmPath("<Keyboard>/leftShift")
				.WithBindingName("Freecam Sprint")
				.Finish();
			builder.NewActionBinding().WithActionId("freecamNextPlayer").WithActionType((InputActionType)1)
				.WithMouseControl((MouseControl)11)
				.WithBindingName("Freecam Next Player")
				.Finish();
			builder.NewActionBinding().WithActionId("toggleSpectateMode").WithActionType((InputActionType)1)
				.WithKeyboardControl((KeyboardControl)42)
				.WithBindingName("Toggle Spectate Mode")
				.Finish();
			if (Config.EnableFreecamResetHotkey.Value)
			{
				HasFreecamResetAction = true;
				builder.NewActionBinding().WithActionId("resetFreecamToPlayer").WithActionType((InputActionType)1)
					.WithMouseControl((MouseControl)13)
					.WithBindingName("Reset Freecam to Player")
					.Finish();
			}
		}

		private static string FormatBindingText(string bindingText)
		{
			return bindingText switch
			{
				"Left Button" => "LMB", 
				"Right Button" => "RMB", 
				"Middle Button" => "MMB", 
				"Left Shift" => "L.Shift", 
				"Left Ctrl" => "L.Ctrl", 
				"Left Control" => "L.Ctrl", 
				_ => bindingText, 
			};
		}

		private static string GetBindingText(InputAction action)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_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)
			Enumerator<InputBinding> enumerator = action.bindings.GetEnumerator();
			try
			{
				while (enumerator.MoveNext())
				{
					InputBinding current = enumerator.Current;
					if (!((InputBinding)(ref current)).isComposite && !((InputBinding)(ref current)).isPartOfComposite && string.Equals(((InputBinding)(ref current)).groups, "KeyboardAndMouse", StringComparison.Ordinal) && !string.IsNullOrWhiteSpace(((InputBinding)(ref current)).effectivePath))
					{
						string text = InputControlPath.ToHumanReadableString(((InputBinding)(ref current)).effectivePath, (HumanReadableStringOptions)2, (InputControl)null);
						if (!string.IsNullOrWhiteSpace(text))
						{
							return FormatBindingText(text);
						}
					}
				}
			}
			finally
			{
				((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose();
			}
			return "Unbound";
		}
	}
}
namespace BasedSpectate.Patches
{
	internal static class DisableVanillaCullingPatches
	{
		private static bool isFreecamSpectating;

		[HarmonyPatch(typeof(FreecamMode), "Enable")]
		[HarmonyPostfix]
		private static void EnablePostfix()
		{
			isFreecamSpectating = true;
			if ((Object)(object)StartOfRound.Instance.occlusionCuller != (Object)null)
			{
				((Behaviour)StartOfRound.Instance.occlusionCuller).enabled = false;
			}
		}

		[HarmonyPatch(typeof(FreecamMode), "Disable")]
		[HarmonyPostfix]
		private static void DisablePostfix()
		{
			if (isFreecamSpectating)
			{
				isFreecamSpectating = false;
				if ((Object)(object)StartOfRound.Instance.occlusionCuller != (Object)null)
				{
					((Behaviour)StartOfRound.Instance.occlusionCuller).enabled = true;
				}
			}
		}

		[HarmonyPatch(typeof(AdjacentRoomCullingModified), "UpdateRendererLists", new Type[]
		{
			typeof(List<Tile>),
			typeof(List<Door>)
		})]
		[HarmonyPrefix]
		private static bool UpdateRendererListsPrefix()
		{
			return !isFreecamSpectating;
		}
	}
	internal static class SpectateModePatches
	{
		private static Vector2 holdButtonToEndGameEarlyMeterPosition;

		private static Vector2 holdButtonToEndGameEarlyVotesTextPosition;

		private static float zoomDistance;

		private static bool hasHoldButtonToEndGameEarlyPositions;

		private static bool wasSpectating;

		private const float HitDistanceOffset = 0.25f;

		private const float OpenDistanceOffset = 0.1f;

		internal static float CurrentZoomDistance => Mathf.Clamp(zoomDistance, Config.MinZoomDistance.Value, Config.MaxZoomDistance.Value);

		internal static void ResetZoomDistance()
		{
			zoomDistance = Mathf.Clamp(Config.DefaultZoomDistance.Value, Config.MinZoomDistance.Value, Config.MaxZoomDistance.Value);
			Log.Debug($"Spectate zoom distance reset to {zoomDistance}");
		}

		[HarmonyPatch(typeof(StartOfRound), "Awake")]
		[HarmonyPostfix]
		private static void StartOfRoundAwakePostfix(StartOfRound __instance)
		{
			((Component)__instance.spectateCamera).gameObject.AddComponent<FreecamMode>();
		}

		[HarmonyPatch(typeof(StartOfRound), "SwitchCamera")]
		[HarmonyPostfix]
		private static void SwitchCameraPostfix(StartOfRound __instance, Camera newCamera)
		{
			FreecamMode component = ((Component)__instance.spectateCamera).GetComponent<FreecamMode>();
			if ((Object)(object)newCamera == (Object)(object)__instance.spectateCamera && __instance.localPlayerController.isPlayerDead && Plugin.CurrentMode == SpectateMode.Freecam)
			{
				component.Enable(__instance.localPlayerController, keepCurrentCameraPosition: false);
			}
			else if (((Behaviour)component).enabled)
			{
				component.Disable();
			}
		}

		[HarmonyPatch(typeof(StartOfRound), "SetSpectateCameraToGameOverMode")]
		[HarmonyPrefix]
		private static bool SetSpectateCameraToGameOverModePrefix()
		{
			return Plugin.CurrentMode != SpectateMode.Freecam;
		}

		[HarmonyPatch(typeof(HUDManager), "SetClockVisible")]
		[HarmonyPrefix]
		private static void SetClockVisiblePrefix(ref bool visible)
		{
			if (GameNetworkManager.Instance.localPlayerController.isPlayerDead && Plugin.CurrentMode == SpectateMode.Freecam)
			{
				visible = false;
			}
		}

		[HarmonyPatch(typeof(PlayerControllerB), "LateUpdate")]
		[HarmonyPriority(800)]
		[HarmonyPrefix]
		private static void PlayerControllerBLateUpdatePrefix(PlayerControllerB __instance)
		{
			//IL_0144: Unknown result type (might be due to invalid IL or missing references)
			if ((!((NetworkBehaviour)__instance).IsOwner || (((NetworkBehaviour)__instance).IsServer && !__instance.isHostPlayerObject)) && !__instance.isTestingPlayer)
			{
				return;
			}
			FreecamMode component = ((Component)__instance.playersManager.spectateCamera).GetComponent<FreecamMode>();
			if (!__instance.isPlayerDead)
			{
				wasSpectating = false;
				Plugin.CurrentMode = Config.StartMode.Value;
				component.DisableBrightnessLights();
				return;
			}
			if (!wasSpectating)
			{
				Plugin.CurrentMode = Config.StartMode.Value;
				ResetZoomDistance();
				FreecamMode.ResetBrightness();
				wasSpectating = true;
			}
			bool flag = __instance.isTypingChat || __instance.inTerminalMenu || __instance.quickMenuManager.isMenuOpen;
			if (!Config.EnableModeToggle.Value)
			{
				Plugin.CurrentMode = Config.StartMode.Value;
			}
			else if (!flag && SpectateInputActions.ToggleModeWasPressedThisFrame())
			{
				Plugin.CurrentMode = ((Plugin.CurrentMode == SpectateMode.Vanilla) ? SpectateMode.Freecam : SpectateMode.Vanilla);
				Log.Debug($"Spectate mode set to {Plugin.CurrentMode}");
			}
			if (Plugin.CurrentMode == SpectateMode.Freecam)
			{
				__instance.playersManager.overrideSpectateCamera = true;
				component.Enable(__instance, keepCurrentCameraPosition: true);
				return;
			}
			if (((Behaviour)component).enabled)
			{
				component.Disable();
			}
			component.UpdateBrightnessLights();
			if (__instance.playersManager.overrideSpectateCamera || flag || __instance.inSpecialInteractAnimation)
			{
				return;
			}
			Mouse current = Mouse.current;
			if (current == null)
			{
				return;
			}
			float y = ((InputControl<Vector2>)(object)current.scroll).ReadValue().y;
			if (!Mathf.Approximately(y, 0f))
			{
				if (SpectateInputActions.ScrollWheelModifierIsPressed())
				{
					FreecamMode.AdjustBrightness(y);
				}
				else
				{
					zoomDistance = Mathf.Clamp(zoomDistance + y / -120f * Config.ZoomSpeed.Value, Config.MinZoomDistance.Value, Config.MaxZoomDistance.Value);
				}
			}
			component.UpdateBrightnessLights();
		}

		[HarmonyPatch(typeof(PlayerControllerB), "RaycastSpectateCameraAroundPivot")]
		[HarmonyPrefix]
		private static bool RaycastSpectateCameraAroundPivotPrefix(PlayerControllerB __instance)
		{
			//IL_0046: 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)
			//IL_00b5: 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_00a5: Unknown result type (might be due to invalid IL or missing references)
			if (((!((NetworkBehaviour)__instance).IsOwner || (((NetworkBehaviour)__instance).IsServer && !__instance.isHostPlayerObject)) && !__instance.isTestingPlayer) || !__instance.isPlayerDead || Plugin.CurrentMode != SpectateMode.Vanilla || __instance.playersManager.overrideSpectateCamera)
			{
				return true;
			}
			Ray val = default(Ray);
			((Ray)(ref val))..ctor(__instance.spectateCameraPivot.position, -__instance.spectateCameraPivot.forward);
			Transform transform = ((Component)__instance.playersManager.spectateCamera).transform;
			float currentZoomDistance = CurrentZoomDistance;
			RaycastHit val2 = default(RaycastHit);
			transform.position = ((Config.CameraClipsThroughWalls.Value || !Physics.Raycast(val, ref val2, currentZoomDistance, __instance.walkableSurfacesNoPlayersMask, (QueryTriggerInteraction)1)) ? ((Ray)(ref val)).GetPoint(currentZoomDistance - 0.1f) : ((Ray)(ref val)).GetPoint(((RaycastHit)(ref val2)).distance - 0.25f));
			transform.LookAt(__instance.spectateCameraPivot);
			return false;
		}

		[HarmonyPatch(typeof(HUDManager), "Update")]
		[HarmonyPostfix]
		private static void HUDManagerUpdatePostfix(HUDManager __instance)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0055: 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_0242: Unknown result type (might be due to invalid IL or missing references)
			//IL_024e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0253: Unknown result type (might be due to invalid IL or missing references)
			//IL_0268: Unknown result type (might be due to invalid IL or missing references)
			//IL_0274: Unknown result type (might be due to invalid IL or missing references)
			//IL_0279: Unknown result type (might be due to invalid IL or missing references)
			//IL_020d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0222: Unknown result type (might be due to invalid IL or missing references)
			if (!hasHoldButtonToEndGameEarlyPositions)
			{
				holdButtonToEndGameEarlyMeterPosition = ((Graphic)__instance.holdButtonToEndGameEarlyMeter).rectTransform.anchoredPosition;
				holdButtonToEndGameEarlyVotesTextPosition = ((TMP_Text)__instance.holdButtonToEndGameEarlyVotesText).rectTransform.anchoredPosition;
				hasHoldButtonToEndGameEarlyPositions = true;
			}
			if (!GameNetworkManager.Instance.localPlayerController.isPlayerDead)
			{
				((Graphic)__instance.holdButtonToEndGameEarlyMeter).rectTransform.anchoredPosition = holdButtonToEndGameEarlyMeterPosition;
				((TMP_Text)__instance.holdButtonToEndGameEarlyVotesText).rectTransform.anchoredPosition = holdButtonToEndGameEarlyVotesTextPosition;
				return;
			}
			string text = ((TMP_Text)__instance.holdButtonToEndGameEarlyText).text;
			string text2 = string.Empty;
			int num = 0;
			if (Config.ShowNextPlayerHint.Value)
			{
				text2 = "[" + SpectateInputActions.GetNextPlayerBindingText() + "] Next Player";
				num++;
			}
			if (Config.EnableModeToggle.Value && Config.ShowToggleModeHint.Value)
			{
				string text3 = "[" + SpectateInputActions.GetToggleModeBindingText() + "] Toggle Mode";
				text2 = (string.IsNullOrEmpty(text2) ? text3 : (text2 + "\n" + text3));
				num++;
			}
			PlayerControllerB spectatedPlayerScript = GameNetworkManager.Instance.localPlayerController.spectatedPlayerScript;
			if (SpectateInputActions.HasFreecamResetAction && Plugin.CurrentMode == SpectateMode.Freecam && (Object)(object)spectatedPlayerScript != (Object)null)
			{
				string text4 = "[" + SpectateInputActions.GetResetFreecamBindingText() + "] Reset freecam to " + spectatedPlayerScript.playerUsername;
				text2 = (string.IsNullOrEmpty(text2) ? text4 : (text2 + "\n" + text4));
				num++;
			}
			if (Config.ShowZoomHint.Value && Plugin.CurrentMode == SpectateMode.Vanilla)
			{
				string text5 = $"[Scroll] Zoom: [{CurrentZoomDistance:0.0} / {Config.MaxZoomDistance.Value:0.0}]";
				text2 = (string.IsNullOrEmpty(text2) ? text5 : (text2 + "\n" + text5));
				num++;
			}
			if (Config.ShowBrightnessHint.Value)
			{
				string text6 = $"[Shift + Scroll] Light: [{FreecamMode.CurrentBrightness:0} / {FreecamMode.MaximumBrightness:0}]";
				text2 = (string.IsNullOrEmpty(text2) ? text6 : (text2 + "\n" + text6));
				num++;
			}
			if (num == 0)
			{
				((Graphic)__instance.holdButtonToEndGameEarlyMeter).rectTransform.anchoredPosition = holdButtonToEndGameEarlyMeterPosition;
				((TMP_Text)__instance.holdButtonToEndGameEarlyVotesText).rectTransform.anchoredPosition = holdButtonToEndGameEarlyVotesTextPosition;
				return;
			}
			float num2 = -9f * (float)num;
			((Graphic)__instance.holdButtonToEndGameEarlyMeter).rectTransform.anchoredPosition = holdButtonToEndGameEarlyMeterPosition + new Vector2(0f, num2);
			((TMP_Text)__instance.holdButtonToEndGameEarlyVotesText).rectTransform.anchoredPosition = holdButtonToEndGameEarlyVotesTextPosition + new Vector2(0f, num2);
			((TMP_Text)__instance.holdButtonToEndGameEarlyText).text = (string.IsNullOrEmpty(text) ? text2 : (text2 + "\n" + text));
		}
	}
}
namespace BasedSpectate.Compat
{
	internal static class CullFactoryCompat
	{
		private static CameraCullingOptions? cameraOptions;

		private static bool freecamCullingDisabled;

		private static bool wasCullingDisabled;

		[HarmonyPatch(typeof(FreecamMode), "Enable")]
		[HarmonyPostfix]
		private static void EnablePostfix(FreecamMode __instance, PlayerControllerB playerController)
		{
			if ((Object)(object)cameraOptions == (Object)null)
			{
				cameraOptions = ((Component)__instance).gameObject.GetComponent<CameraCullingOptions>();
				if ((Object)(object)cameraOptions == (Object)null)
				{
					cameraOptions = ((Component)__instance).gameObject.AddComponent<CameraCullingOptions>();
				}
			}
			SetCullingDisabled(Config.DisableCullFactoryCulling.Value && playerController.isPlayerDead);
			Log.Debug("CullFactory culling disabled");
		}

		[HarmonyPatch(typeof(FreecamMode), "Disable")]
		[HarmonyPostfix]
		private static void DisablePostfix()
		{
			SetCullingDisabled(disabled: false);
			Log.Debug("CullFactory culling enabled");
		}

		private static void SetCullingDisabled(bool disabled)
		{
			if ((Object)(object)cameraOptions == (Object)null)
			{
				cameraOptions = null;
				freecamCullingDisabled = false;
				return;
			}
			if (disabled)
			{
				if (!freecamCullingDisabled)
				{
					wasCullingDisabled = cameraOptions.DisableCulling;
				}
				cameraOptions.DisableCulling = true;
			}
			else if (freecamCullingDisabled)
			{
				cameraOptions.DisableCulling = wasCullingDisabled;
			}
			freecamCullingDisabled = disabled;
		}
	}
	internal static class LethalConfigCompat
	{
		internal static void Register()
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			//IL_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_0036: Expected O, but got Unknown
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Expected O, but got Unknown
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Expected O, but got Unknown
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Expected O, but got Unknown
			//IL_005b: 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: Expected O, but got Unknown
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Expected O, but got Unknown
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Expected O, but got Unknown
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Expected O, but got Unknown
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Expected O, but got Unknown
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Expected O, but got Unknown
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Expected O, but got Unknown
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Expected O, but got Unknown
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Expected O, but got Unknown
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Expected O, but got Unknown
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Expected O, but got Unknown
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Expected O, but got Unknown
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Expected O, but got Unknown
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Expected O, but got Unknown
			//IL_0113: 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_0123: Expected O, but got Unknown
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: Expected O, but got Unknown
			//IL_012e: Unknown result type (might be due to invalid IL or missing references)
			//IL_013a: Expected O, but got Unknown
			//IL_0135: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: Expected O, but got Unknown
			//IL_0144: Unknown result type (might be due to invalid IL or missing references)
			//IL_0149: Unknown result type (might be due to invalid IL or missing references)
			//IL_0154: Expected O, but got Unknown
			//IL_0154: Unknown result type (might be due to invalid IL or missing references)
			//IL_015f: Expected O, but got Unknown
			//IL_015f: Unknown result type (might be due to invalid IL or missing references)
			//IL_016b: Expected O, but got Unknown
			//IL_0166: Unknown result type (might be due to invalid IL or missing references)
			//IL_0170: Expected O, but got Unknown
			//IL_0175: Unknown result type (might be due to invalid IL or missing references)
			//IL_017a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0185: Expected O, but got Unknown
			//IL_0185: Unknown result type (might be due to invalid IL or missing references)
			//IL_0190: Expected O, but got Unknown
			//IL_0190: Unknown result type (might be due to invalid IL or missing references)
			//IL_019c: Expected O, but got Unknown
			//IL_0197: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a1: Expected O, but got Unknown
			//IL_01a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b7: Expected O, but got Unknown
			//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bc: Expected O, but got Unknown
			LethalConfigManager.SkipAutoGen();
			LethalConfigManager.AddConfigItem((BaseConfigItem)(object)new EnumDropDownConfigItem<SpectateMode>(Config.StartMode, new EnumDropDownOptions
			{
				RequiresRestart = false
			}));
			LethalConfigManager.AddConfigItem((BaseConfigItem)new BoolCheckBoxConfigItem(Config.EnableModeToggle, new BoolCheckBoxOptions
			{
				RequiresRestart = false
			}));
			LethalConfigManager.AddConfigItem((BaseConfigItem)new BoolCheckBoxConfigItem(Config.EnableFreecamResetHotkey, new BoolCheckBoxOptions
			{
				RequiresRestart = true
			}));
			LethalConfigManager.AddConfigItem((BaseConfigItem)new BoolCheckBoxConfigItem(Config.ShowNextPlayerHint, new BoolCheckBoxOptions
			{
				RequiresRestart = false
			}));
			LethalConfigManager.AddConfigItem((BaseConfigItem)new BoolCheckBoxConfigItem(Config.ShowToggleModeHint, new BoolCheckBoxOptions
			{
				RequiresRestart = false
			}));
			LethalConfigManager.AddConfigItem((BaseConfigItem)new BoolCheckBoxConfigItem(Config.ShowBrightnessHint, new BoolCheckBoxOptions
			{
				RequiresRestart = false
			}));
			LethalConfigManager.AddConfigItem((BaseConfigItem)new BoolCheckBoxConfigItem(Config.ShowZoomHint, new BoolCheckBoxOptions
			{
				RequiresRestart = false
			}));
			LethalConfigManager.AddConfigItem((BaseConfigItem)new BoolCheckBoxConfigItem(Config.DisableCullFactoryCulling, new BoolCheckBoxOptions
			{
				RequiresRestart = false
			}));
			ConfigEntry<float> defaultZoomDistance = Config.DefaultZoomDistance;
			FloatSliderOptions val = new FloatSliderOptions();
			((BaseRangeOptions<float>)val).Min = 0.1f;
			((BaseRangeOptions<float>)val).Max = 50f;
			((BaseOptions)val).RequiresRestart = false;
			LethalConfigManager.AddConfigItem((BaseConfigItem)new FloatSliderConfigItem(defaultZoomDistance, val));
			ConfigEntry<float> minZoomDistance = Config.MinZoomDistance;
			FloatSliderOptions val2 = new FloatSliderOptions();
			((BaseRangeOptions<float>)val2).Min = 0.1f;
			((BaseRangeOptions<float>)val2).Max = 50f;
			((BaseOptions)val2).RequiresRestart = false;
			LethalConfigManager.AddConfigItem((BaseConfigItem)new FloatSliderConfigItem(minZoomDistance, val2));
			ConfigEntry<float> maxZoomDistance = Config.MaxZoomDistance;
			FloatSliderOptions val3 = new FloatSliderOptions();
			((BaseRangeOptions<float>)val3).Min = 0.1f;
			((BaseRangeOptions<float>)val3).Max = 50f;
			((BaseOptions)val3).RequiresRestart = false;
			LethalConfigManager.AddConfigItem((BaseConfigItem)new FloatSliderConfigItem(maxZoomDistance, val3));
			ConfigEntry<float> zoomSpeed = Config.ZoomSpeed;
			FloatSliderOptions val4 = new FloatSliderOptions();
			((BaseRangeOptions<float>)val4).Min = 0f;
			((BaseRangeOptions<float>)val4).Max = 5f;
			((BaseOptions)val4).RequiresRestart = false;
			LethalConfigManager.AddConfigItem((BaseConfigItem)new FloatSliderConfigItem(zoomSpeed, val4));
			LethalConfigManager.AddConfigItem((BaseConfigItem)new BoolCheckBoxConfigItem(Config.CameraClipsThroughWalls, new BoolCheckBoxOptions
			{
				RequiresRestart = false
			}));
		}
	}
}
namespace BasedSpectate.Behaviours
{
	internal class FreecamMode : MonoBehaviour
	{
		private const float MoveSpeed = 10f;

		private const float SprintMultiplier = 5f;

		private const float SpeedLerp = 12f;

		private const float LookScale = 0.008f;

		private const float MinBrightness = 0f;

		private const float MaxBrightness = 800f;

		private const float BrightnessScrollSpeed = 200f;

		private const float BrightnessIntensityScale = 0.01f;

		private const float InsideFactoryY = -80f;

		private static float brightness;

		private readonly Light[] lights = (Light[])(object)new Light[4];

		private PlayerControllerB? player;

		private float pitch;

		private float currentMoveSpeed;

		internal static float CurrentBrightness => Mathf.Clamp(brightness, 0f, MaximumBrightness);

		internal static float MaximumBrightness => 800f;

		internal static void ResetBrightness()
		{
			brightness = 0f;
		}

		internal static void AdjustBrightness(float scroll)
		{
			brightness = Mathf.Clamp(brightness + scroll / 120f * 200f, 0f, MaximumBrightness);
		}

		private void Awake()
		{
			//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_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_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_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Expected O, but got Unknown
			//IL_00b4: 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)
			for (int i = 0; i < lights.Length; i++)
			{
				Vector3 eulerAngles = (Vector3)(i switch
				{
					0 => new Vector3(50f, 0f, 0f), 
					1 => new Vector3(120f, 0f, 0f), 
					2 => new Vector3(50f, 90f, 0f), 
					_ => new Vector3(50f, -90f, 0f), 
				});
				GameObject val = new GameObject(string.Format("{0} Freecam Light {1}", "BasedSpectateMode", i));
				Light val2 = val.AddComponent<Light>();
				HDAdditionalLightData val3 = val.AddComponent<HDAdditionalLightData>();
				((Object)val).hideFlags = (HideFlags)52;
				val.transform.eulerAngles = eulerAngles;
				val2.type = (LightType)1;
				val2.shadows = (LightShadows)0;
				((Behaviour)val2).enabled = false;
				val3.affectsVolumetric = false;
				lights[i] = val2;
			}
			currentMoveSpeed = 10f;
			((Behaviour)this).enabled = false;
		}

		internal void Enable(PlayerControllerB playerController, bool keepCurrentCameraPosition)
		{
			//IL_0062: 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)
			if (!((Behaviour)this).enabled || !((Object)(object)player == (Object)(object)playerController))
			{
				player = playerController;
				currentMoveSpeed = 10f;
				((Component)this).transform.SetParent((Transform)null);
				if (!keepCurrentCameraPosition)
				{
					Transform transform = ((Component)playerController.gameplayCamera).transform;
					((Component)this).transform.SetPositionAndRotation(transform.position, transform.rotation);
				}
				pitch = ((Component)this).transform.eulerAngles.x;
				if (pitch > 180f)
				{
					pitch -= 360f;
				}
				StartOfRound.Instance.overrideSpectateCamera = true;
				((Behaviour)this).enabled = true;
			}
		}

		internal void Disable()
		{
			if (((Behaviour)this).enabled)
			{
				DisableBrightnessLights();
				((Behaviour)this).enabled = false;
				player = null;
				if ((Object)(object)StartOfRound.Instance != (Object)null)
				{
					StartOfRound.Instance.overrideSpectateCamera = false;
				}
			}
		}

		private void LateUpdate()
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0221: Unknown result type (might be due to invalid IL or missing references)
			//IL_0226: Unknown result type (might be due to invalid IL or missing references)
			//IL_0248: Unknown result type (might be due to invalid IL or missing references)
			//IL_024d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0256: Unknown result type (might be due to invalid IL or missing references)
			//IL_025b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0260: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_028e: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_016c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0173: Unknown result type (might be due to invalid IL or missing references)
			//IL_017a: Unknown result type (might be due to invalid IL or missing references)
			//IL_017f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0186: 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_032e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0333: Unknown result type (might be due to invalid IL or missing references)
			//IL_0339: Unknown result type (might be due to invalid IL or missing references)
			//IL_0344: Unknown result type (might be due to invalid IL or missing references)
			//IL_0349: Unknown result type (might be due to invalid IL or missing references)
			//IL_034f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0354: Unknown result type (might be due to invalid IL or missing references)
			//IL_0359: Unknown result type (might be due to invalid IL or missing references)
			//IL_0360: Unknown result type (might be due to invalid IL or missing references)
			//IL_0365: Unknown result type (might be due to invalid IL or missing references)
			//IL_036a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0373: Unknown result type (might be due to invalid IL or missing references)
			//IL_0384: Unknown result type (might be due to invalid IL or missing references)
			//IL_0386: Unknown result type (might be due to invalid IL or missing references)
			//IL_038b: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)player == (Object)null || !player.isPlayerDead)
			{
				Disable();
				return;
			}
			bool flag = ((Component)this).transform.position.y < -80f;
			StartOfRound.Instance.overrideSpectateCamera = true;
			StartOfRound.Instance.SetOcclusionCullerToPosition(((Component)this).transform.position);
			StartOfRound.Instance.blackSkyVolume.weight = (flag ? 1f : 0f);
			TimeOfDay instance = TimeOfDay.Instance;
			if ((Object)(object)instance == (Object)null || (Object)(object)instance.sunDirect == (Object)null || (Object)(object)instance.sunIndirect == (Object)null)
			{
				Disable();
				return;
			}
			((Behaviour)instance.sunDirect).enabled = !flag;
			((Behaviour)instance.sunIndirect).enabled = !flag;
			if (player.isTypingChat || player.inTerminalMenu || player.quickMenuManager.isMenuOpen)
			{
				return;
			}
			if (SpectateInputActions.NextPlayerWasPressedThisFrame())
			{
				SwitchSpectatedPlayer(1);
			}
			if (SpectateInputActions.HasFreecamResetAction && SpectateInputActions.ResetFreecamWasPressedThisFrame() && (Object)(object)player.spectatedPlayerScript != (Object)null)
			{
				Transform playerEye = player.spectatedPlayerScript.playerEye;
				float num = Mathf.Clamp(Config.DefaultZoomDistance.Value, Config.MinZoomDistance.Value, Config.MaxZoomDistance.Value);
				((Component)this).transform.SetPositionAndRotation(playerEye.position - playerEye.forward * num, playerEye.rotation);
				pitch = ((Component)this).transform.eulerAngles.x;
				if (pitch > 180f)
				{
					pitch -= 360f;
				}
				Log.Debug("Freecam reset to " + player.spectatedPlayerScript.playerUsername);
			}
			Mouse current = Mouse.current;
			if (current != null)
			{
				float y = ((InputControl<Vector2>)(object)current.scroll).ReadValue().y;
				if (!Mathf.Approximately(y, 0f) && SpectateInputActions.ScrollWheelModifierIsPressed())
				{
					AdjustBrightness(y);
				}
			}
			UpdateBrightnessLights();
			Vector2 val = SpectateInputActions.ReadMoveInput();
			float num2 = (float)IngamePlayerSettings.Instance.settings.lookSensitivity * 0.008f;
			MovementActions movement = player.playerActions.Movement;
			Vector2 val2 = num2 * ((MovementActions)(ref movement)).Look.ReadValue<Vector2>();
			if (!IngamePlayerSettings.Instance.settings.invertYAxis)
			{
				val2.y *= -1f;
			}
			((Component)this).transform.Rotate(0f, val2.x, 0f, (Space)0);
			pitch = Mathf.Clamp(pitch + val2.y, -90f, 90f);
			((Component)this).transform.eulerAngles = new Vector3(pitch, ((Component)this).transform.eulerAngles.y, 0f);
			float num3 = (SpectateInputActions.SprintIsPressed() ? 50f : 10f);
			currentMoveSpeed = Mathf.Lerp(currentMoveSpeed, num3, 12f * Time.deltaTime);
			float num4 = SpectateInputActions.ReadVerticalInput();
			Vector3 val3 = ((Component)this).transform.right * val.x + ((Component)this).transform.forward * val.y + Vector3.up * num4;
			Transform transform = ((Component)this).transform;
			transform.position += currentMoveSpeed * Time.deltaTime * val3;
		}

		internal void UpdateBrightnessLights()
		{
			float intensity = CurrentBrightness * 0.01f;
			bool enabled = !Mathf.Approximately(CurrentBrightness, 0f);
			for (int i = 0; i < lights.Length; i++)
			{
				((Behaviour)lights[i]).enabled = enabled;
				lights[i].intensity = intensity;
			}
		}

		internal void DisableBrightnessLights()
		{
			for (int i = 0; i < lights.Length; i++)
			{
				if ((Object)(object)lights[i] != (Object)null)
				{
					((Behaviour)lights[i]).enabled = false;
				}
			}
		}

		private void SwitchSpectatedPlayer(int direction)
		{
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)player == (Object)null)
			{
				return;
			}
			PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts;
			int num = (int)(((Object)(object)player.spectatedPlayerScript == (Object)null) ? player.playerClientId : player.spectatedPlayerScript.playerClientId);
			for (int i = 0; i < allPlayerScripts.Length; i++)
			{
				num += direction;
				if (num < 0)
				{
					num = allPlayerScripts.Length - 1;
				}
				else if (num >= allPlayerScripts.Length)
				{
					num = 0;
				}
				PlayerControllerB val = allPlayerScripts[num];
				if (!((Object)(object)val == (Object)(object)player) && !val.isPlayerDead && val.isPlayerControlled)
				{
					player.spectatedPlayerScript = val;
					player.SetSpectatedPlayerEffects(false);
					HUDManager.Instance.SetSpectatingTextToPlayer(val);
					Transform transform = ((Component)val.gameplayCamera).transform;
					float num2 = Mathf.Clamp(Config.DefaultZoomDistance.Value, Config.MinZoomDistance.Value, Config.MaxZoomDistance.Value);
					((Component)this).transform.SetPositionAndRotation(transform.position - transform.forward * num2, transform.rotation);
					pitch = ((Component)this).transform.eulerAngles.x;
					if (pitch > 180f)
					{
						pitch -= 360f;
					}
					Log.Debug("Freecam spectating " + val.playerUsername);
					break;
				}
			}
		}

		private void OnDestroy()
		{
			Disable();
			for (int i = 0; i < lights.Length; i++)
			{
				if ((Object)(object)lights[i] != (Object)null)
				{
					Object.Destroy((Object)(object)((Component)lights[i]).gameObject);
				}
			}
		}
	}
}