Decompiled source of BasedSpectateMode v0.0.1

BasedSpectateMode.dll

Decompiled 6 hours 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 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.Utilities;
using UnityEngine.Rendering.HighDefinition;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("BasedSpectateMode")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("0.0.1.0")]
[assembly: AssemblyInformationalVersion("0.0.1")]
[assembly: AssemblyProduct("BasedSpectateMode")]
[assembly: AssemblyTitle("BasedSpectateMode")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.0.1.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> ShowNextPlayerHint { get; private set; }

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

		internal static ConfigEntry<bool> ShowCameraInfoHint { 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 void Bind(ConfigFile config)
		{
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Expected O, but got Unknown
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Expected O, but got Unknown
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			//IL_0132: Expected O, but got Unknown
			//IL_0161: Unknown result type (might be due to invalid IL or missing references)
			//IL_016b: 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");
			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");
			ShowCameraInfoHint = config.Bind<bool>("General", "Show camera info hint", true, "Show the Brightness or Zoom line on the death screen");
			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");
			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.1")]
	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.1";

		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();
			if (hasLethalConfig)
			{
				LethalConfigCompat.Register();
				mls.LogInfo((object)"LethalConfig compatibility ran");
			}
			if (hasCullFactory)
			{
				mls.LogInfo((object)"CullFactory compatibility ran");
			}
			else
			{
				_harmony.PatchAll(typeof(DisableVanillaCullingPatches));
			}
			mls.LogDebug((object)"BasedSpectateMode patches running...");
			_harmony.PatchAll(typeof(SpectateModePatches));
			mls.LogInfo((object)"BasedSpectateMode loaded");
		}
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "BasedSpectateMode";

		public const string PLUGIN_NAME = "BasedSpectateMode";

		public const string PLUGIN_VERSION = "0.0.1";
	}
}
namespace BasedSpectate.Utils
{
	internal class SpectateInputActions : LcInputActions
	{
		private const string KeyboardAndMouseGroup = "KeyboardAndMouse";

		internal static SpectateInputActions Instance { 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 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 void Initialise()
		{
			if (Instance == null)
			{
				Instance = new SpectateInputActions();
			}
		}

		internal static Vector2 ReadMoveInput()
		{
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			Vector2 val = default(Vector2);
			((Vector2)(ref val))..ctor((MoveRight.IsPressed() ? 1f : 0f) - (MoveLeft.IsPressed() ? 1f : 0f), (MoveForward.IsPressed() ? 1f : 0f) - (MoveBackward.IsPressed() ? 1f : 0f));
			return (((Vector2)(ref val)).sqrMagnitude > 1f) ? ((Vector2)(ref val)).normalized : val;
		}

		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 string GetNextPlayerBindingText()
		{
			return GetBindingText(NextPlayer);
		}

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

		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();
		}

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

		private static string GetBindingText(InputAction action)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: 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);
			Plugin.mls.LogDebug((object)$"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)
			{
				PlayerControllerB localPlayerController = __instance.localPlayerController;
				if (localPlayerController != null && localPlayerController.isPlayerDead && Plugin.CurrentMode == SpectateMode.Freecam)
				{
					component.Enable(__instance.localPlayerController, keepCurrentCameraPosition: false);
					return;
				}
			}
			if (((Behaviour)component).enabled)
			{
				component.Disable();
			}
		}

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

		[HarmonyPatch(typeof(PlayerControllerB), "LateUpdate")]
		[HarmonyPriority(800)]
		[HarmonyPrefix]
		private static void PlayerControllerBLateUpdatePrefix(PlayerControllerB __instance)
		{
			//IL_0195: Unknown result type (might be due to invalid IL or missing references)
			if ((!((NetworkBehaviour)__instance).IsOwner || (((NetworkBehaviour)__instance).IsServer && !__instance.isHostPlayerObject)) && !__instance.isTestingPlayer)
			{
				return;
			}
			if (!__instance.isPlayerDead)
			{
				wasSpectating = false;
				Plugin.CurrentMode = Config.StartMode.Value;
				return;
			}
			if (!wasSpectating)
			{
				Plugin.CurrentMode = Config.StartMode.Value;
				ResetZoomDistance();
				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);
				Plugin.mls.LogDebug((object)$"Spectate mode set to {Plugin.CurrentMode}");
			}
			FreecamMode component = ((Component)__instance.playersManager.spectateCamera).GetComponent<FreecamMode>();
			if (Plugin.CurrentMode == SpectateMode.Freecam)
			{
				__instance.playersManager.overrideSpectateCamera = true;
				component.Enable(__instance, keepCurrentCameraPosition: true);
				return;
			}
			if (((Behaviour)component).enabled)
			{
				component.Disable();
			}
			if (__instance.playersManager.overrideSpectateCamera || flag || __instance.inSpecialInteractAnimation)
			{
				return;
			}
			Mouse current = Mouse.current;
			if (current != null)
			{
				float y = ((InputControl<Vector2>)(object)current.scroll).ReadValue().y;
				if (!Mathf.Approximately(y, 0f))
				{
					zoomDistance = Mathf.Clamp(zoomDistance + y / -120f * Config.ZoomSpeed.Value, Config.MinZoomDistance.Value, Config.MaxZoomDistance.Value);
				}
			}
		}

		[HarmonyPatch(typeof(PlayerControllerB), "RaycastSpectateCameraAroundPivot")]
		[HarmonyPrefix]
		private static bool RaycastSpectateCameraAroundPivotPrefix(PlayerControllerB __instance)
		{
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: 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_00b3: 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_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_0208: Unknown result type (might be due to invalid IL or missing references)
			//IL_0214: Unknown result type (might be due to invalid IL or missing references)
			//IL_0219: Unknown result type (might be due to invalid IL or missing references)
			//IL_022f: Unknown result type (might be due to invalid IL or missing references)
			//IL_023b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0240: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e6: 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 (!((Object)(object)GameNetworkManager.Instance?.localPlayerController != (Object)null) || !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++;
			}
			if (Config.ShowCameraInfoHint.Value)
			{
				string text4 = ((Plugin.CurrentMode == SpectateMode.Freecam) ? $"Brightness: [{FreecamMode.CurrentBrightness:0.0} / {FreecamMode.MaximumBrightness:0.0}]" : $"Zoom: [{CurrentZoomDistance:0.0} / {Config.MaxZoomDistance.Value:0.0}]");
				text2 = (string.IsNullOrEmpty(text2) ? text4 : (text2 + "\n" + text4));
				num++;
			}
			if (num == 0)
			{
				((Graphic)__instance.holdButtonToEndGameEarlyMeter).rectTransform.anchoredPosition = holdButtonToEndGameEarlyMeterPosition;
				((TMP_Text)__instance.holdButtonToEndGameEarlyVotesText).rectTransform.anchoredPosition = holdButtonToEndGameEarlyVotesTextPosition;
				return;
			}
			float num2 = -8f * (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 LethalConfigCompat
	{
		internal static void Register()
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Expected O, but got Unknown
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Expected O, but got Unknown
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Expected O, but got Unknown
			//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_0058: Expected O, but got Unknown
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Expected O, but got Unknown
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Expected O, but got Unknown
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Expected O, but got Unknown
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Expected O, but got Unknown
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Expected O, but got Unknown
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Expected O, but got Unknown
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Expected O, but got Unknown
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Expected O, but got Unknown
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Expected O, but got Unknown
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Expected O, but got Unknown
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Expected O, but got Unknown
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Expected O, but got Unknown
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Expected O, but got Unknown
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Expected O, but got Unknown
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Expected O, but got Unknown
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Expected O, but got Unknown
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0136: Expected O, but got Unknown
			//IL_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0141: Unknown result type (might be due to invalid IL or missing references)
			//IL_014c: Expected O, but got Unknown
			//IL_014d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0158: Expected O, but got Unknown
			//IL_0159: Unknown result type (might be due to invalid IL or missing references)
			//IL_0166: Expected O, but got Unknown
			//IL_0161: Unknown result type (might be due to invalid IL or missing references)
			//IL_016b: Expected O, but got Unknown
			//IL_0171: Unknown result type (might be due to invalid IL or missing references)
			//IL_0176: Unknown result type (might be due to invalid IL or missing references)
			//IL_0183: Expected O, but got Unknown
			//IL_017e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0188: 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.ShowNextPlayerHint, new BoolCheckBoxOptions
			{
				RequiresRestart = false
			}));
			LethalConfigManager.AddConfigItem((BaseConfigItem)new BoolCheckBoxConfigItem(Config.ShowToggleModeHint, new BoolCheckBoxOptions
			{
				RequiresRestart = false
			}));
			LethalConfigManager.AddConfigItem((BaseConfigItem)new BoolCheckBoxConfigItem(Config.ShowCameraInfoHint, 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;

		private void Awake()
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Expected O, but got Unknown
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			for (int i = 0; i < lights.Length; i++)
			{
				if (1 == 0)
				{
				}
				Vector3 val = (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), 
				});
				if (1 == 0)
				{
				}
				Vector3 eulerAngles = val;
				GameObject val2 = new GameObject(string.Format("{0} Freecam Light {1}", "BasedSpectateMode", i));
				Light val3 = val2.AddComponent<Light>();
				HDAdditionalLightData val4 = val2.AddComponent<HDAdditionalLightData>();
				((Object)val2).hideFlags = (HideFlags)52;
				val2.transform.eulerAngles = eulerAngles;
				val3.type = (LightType)1;
				val3.shadows = (LightShadows)0;
				((Behaviour)val3).enabled = false;
				val4.affectsVolumetric = false;
				lights[i] = val3;
			}
			currentMoveSpeed = 10f;
			((Behaviour)this).enabled = false;
		}

		internal void Enable(PlayerControllerB playerController, bool keepCurrentCameraPosition)
		{
			//IL_007f: 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_006c: Unknown result type (might be due to invalid IL or missing references)
			if (!((Behaviour)this).enabled || !((Object)(object)player == (Object)(object)playerController))
			{
				player = playerController;
				brightness = 0f;
				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)
			{
				return;
			}
			for (int i = 0; i < lights.Length; i++)
			{
				if ((Object)(object)lights[i] != (Object)null)
				{
					((Behaviour)lights[i]).enabled = false;
				}
			}
			((Behaviour)this).enabled = false;
			player = null;
			if ((Object)(object)StartOfRound.Instance != (Object)null)
			{
				StartOfRound.Instance.overrideSpectateCamera = false;
			}
		}

		private void LateUpdate()
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01da: Unknown result type (might be due to invalid IL or missing references)
			//IL_01df: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0168: Unknown result type (might be due to invalid IL or missing references)
			//IL_0227: Unknown result type (might be due to invalid IL or missing references)
			//IL_0241: Unknown result type (might be due to invalid IL or missing references)
			//IL_026f: Unknown result type (might be due to invalid IL or missing references)
			//IL_027e: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ce: 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_02e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0302: Unknown result type (might be due to invalid IL or missing references)
			//IL_0307: Unknown result type (might be due to invalid IL or missing references)
			//IL_0310: Unknown result type (might be due to invalid IL or missing references)
			//IL_0321: Unknown result type (might be due to invalid IL or missing references)
			//IL_0323: Unknown result type (might be due to invalid IL or missing references)
			//IL_0328: Unknown result type (might be due to invalid IL or missing references)
			PlayerControllerB? obj = player;
			if (obj == null || !obj.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);
			((Behaviour)TimeOfDay.Instance.sunDirect).enabled = !flag;
			((Behaviour)TimeOfDay.Instance.sunIndirect).enabled = !flag;
			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;
			}
			if (player.isTypingChat || player.inTerminalMenu || player.quickMenuManager.isMenuOpen)
			{
				return;
			}
			if (SpectateInputActions.NextPlayerWasPressedThisFrame())
			{
				SwitchSpectatedPlayer(1);
			}
			Mouse current = Mouse.current;
			if (current != null)
			{
				float y = ((InputControl<Vector2>)(object)current.scroll).ReadValue().y;
				if (!Mathf.Approximately(y, 0f))
				{
					brightness = Mathf.Clamp(brightness + y / 120f * 200f, 0f, MaximumBrightness);
				}
			}
			Vector2 val = SpectateInputActions.ReadMoveInput();
			float num = (float)IngamePlayerSettings.Instance.settings.lookSensitivity * 0.008f;
			MovementActions movement = player.playerActions.Movement;
			Vector2 val2 = num * ((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 num2 = (SpectateInputActions.SprintIsPressed() ? 50f : 10f);
			currentMoveSpeed = Mathf.Lerp(currentMoveSpeed, num2, 12f * Time.deltaTime);
			float num3 = SpectateInputActions.ReadVerticalInput();
			Vector3 val3 = ((Component)this).transform.right * val.x + ((Component)this).transform.forward * val.y + Vector3.up * num3;
			Transform transform = ((Component)this).transform;
			transform.position += currentMoveSpeed * Time.deltaTime * val3;
		}

		private void SwitchSpectatedPlayer(int direction)
		{
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0134: Unknown result type (might be due to invalid IL or missing references)
			//IL_0146: Unknown result type (might be due to invalid IL or missing references)
			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;
					}
					Plugin.mls.LogDebug((object)("Freecam spectating " + val.playerUsername));
					break;
				}
			}
		}

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