Decompiled source of 3RdPersonCoeeEX v1.0.0

BepInEx\plugins\3RdPersonCoeeEX.dll

Decompiled 16 hours ago
using System;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.SceneManagement;

[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("3RdPersonCoeeEX")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Third-person camera switching for Lethal Company.")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("3RdPersonCoeeEX")]
[assembly: AssemblyTitle("3RdPersonCoeeEX")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

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

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

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace ProjectFolderName
{
	public enum CameraSwitchingMethod
	{
		Toggle,
		Wheel,
		Off
	}
	internal sealed class InGameCameraSettingsMenu : MonoBehaviour
	{
		private const float ScanInterval = 0.35f;

		private float nextScanTime;

		private bool settingsScreenVisible;

		private GUIStyle? titleStyle;

		private GUIStyle? labelStyle;

		private GUIStyle? buttonStyle;

		private GUIStyle? boxStyle;

		private Texture2D? whiteTexture;

		private void Update()
		{
			if (!(Time.unscaledTime < nextScanTime))
			{
				nextScanTime = Time.unscaledTime + 0.35f;
				settingsScreenVisible = Plugin.ShowInGameSettings.Value && IsVanillaSettingsScreenVisible();
			}
		}

		private void OnGUI()
		{
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_013d: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ef: Unknown result type (might be due to invalid IL or missing references)
			if (settingsScreenVisible)
			{
				EnsureStyles();
				float num = (float)Screen.width / 1920f;
				float num2 = (float)Screen.height / 1080f;
				float num3 = 412f * num;
				float num4 = 382f * num2;
				Rect val = default(Rect);
				((Rect)(ref val))..ctor(520f * num, 482f * num2, num3, num4);
				GUI.Box(val, GUIContent.none, boxStyle);
				DrawBorder(val, 2f * Mathf.Min(num, num2));
				GUI.Label(new Rect(((Rect)(ref val)).x + 20f * num, ((Rect)(ref val)).y + 18f * num2, ((Rect)(ref val)).width - 40f * num, 42f * num2), "SWITCH CAMERA", titleStyle);
				GUI.Label(new Rect(((Rect)(ref val)).x + 20f * num, ((Rect)(ref val)).y + 88f * num2, ((Rect)(ref val)).width - 40f * num, 28f * num2), "Camera switching method", labelStyle);
				if (GUI.Button(new Rect(((Rect)(ref val)).x + 20f * num, ((Rect)(ref val)).y + 124f * num2, ((Rect)(ref val)).width - 40f * num, 54f * num2), $"> {Plugin.SwitchingMethod.Value}", buttonStyle))
				{
					VanillaButtonSound.Play();
					CycleMethod();
				}
				GUI.Label(new Rect(((Rect)(ref val)).x + 20f * num, ((Rect)(ref val)).y + 216f * num2, ((Rect)(ref val)).width - 40f * num, 28f * num2), "Preserve height / distance", labelStyle);
				if (GUI.Button(new Rect(((Rect)(ref val)).x + 20f * num, ((Rect)(ref val)).y + 252f * num2, ((Rect)(ref val)).width - 40f * num, 54f * num2), "> " + (Plugin.PreserveCameraAdjustments.Value ? "On" : "Off"), buttonStyle))
				{
					VanillaButtonSound.Play();
					TogglePreserveAdjustments();
				}
			}
		}

		private static void CycleMethod()
		{
			ConfigEntry<CameraSwitchingMethod> switchingMethod = Plugin.SwitchingMethod;
			switchingMethod.Value = Plugin.SwitchingMethod.Value switch
			{
				CameraSwitchingMethod.Toggle => CameraSwitchingMethod.Wheel, 
				CameraSwitchingMethod.Wheel => CameraSwitchingMethod.Off, 
				_ => CameraSwitchingMethod.Toggle, 
			};
			((ConfigEntryBase)Plugin.SwitchingMethod).ConfigFile.Save();
			Plugin.Log.LogInfo((object)$"Camera switching method set to {Plugin.SwitchingMethod.Value} from in-game settings.");
		}

		private static void TogglePreserveAdjustments()
		{
			Plugin.PreserveCameraAdjustments.Value = !Plugin.PreserveCameraAdjustments.Value;
			((ConfigEntryBase)Plugin.PreserveCameraAdjustments).ConfigFile.Save();
			Plugin.Log.LogInfo((object)$"Preserve camera height and distance set to {Plugin.PreserveCameraAdjustments.Value} from in-game settings.");
		}

		private void EnsureStyles()
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Expected O, but got Unknown
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Expected O, but got Unknown
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Expected O, but got Unknown
			//IL_0046: 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_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: 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_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Expected O, but got Unknown
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: 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_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: Expected O, but got Unknown
			//IL_0139: Unknown result type (might be due to invalid IL or missing references)
			//IL_013e: 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_0172: Unknown result type (might be due to invalid IL or missing references)
			//IL_017c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0191: Unknown result type (might be due to invalid IL or missing references)
			//IL_019b: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d1: Expected O, but got Unknown
			//IL_01d6: Expected O, but got Unknown
			if (titleStyle == null)
			{
				GUIStyle val = new GUIStyle(GUI.skin.box)
				{
					border = new RectOffset(2, 2, 2, 2),
					margin = new RectOffset(0, 0, 0, 0),
					padding = new RectOffset(0, 0, 0, 0)
				};
				val.normal.background = Texture2D.blackTexture;
				val.normal.textColor = Color.white;
				boxStyle = val;
				GUIStyle val2 = new GUIStyle(GUI.skin.label)
				{
					fontSize = Mathf.RoundToInt(32f * Mathf.Min((float)Screen.width / 1920f, (float)Screen.height / 1080f))
				};
				val2.normal.textColor = new Color(1f, 0.18f, 0.25f);
				val2.alignment = (TextAnchor)3;
				titleStyle = val2;
				GUIStyle val3 = new GUIStyle(GUI.skin.label)
				{
					fontSize = Mathf.RoundToInt(22f * Mathf.Min((float)Screen.width / 1920f, (float)Screen.height / 1080f))
				};
				val3.normal.textColor = Color.white;
				val3.alignment = (TextAnchor)3;
				labelStyle = val3;
				GUIStyle val4 = new GUIStyle(GUI.skin.button)
				{
					fontSize = Mathf.RoundToInt(22f * Mathf.Min((float)Screen.width / 1920f, (float)Screen.height / 1080f))
				};
				val4.normal.textColor = Color.white;
				val4.hover.textColor = new Color(1f, 0.45f, 0.05f);
				val4.active.textColor = new Color(1f, 0.45f, 0.05f);
				val4.alignment = (TextAnchor)3;
				val4.padding = new RectOffset(16, 8, 4, 4);
				buttonStyle = val4;
			}
		}

		private void DrawBorder(Rect rect, float thickness)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: 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_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			if (whiteTexture == null)
			{
				whiteTexture = Texture2D.whiteTexture;
			}
			Color color = GUI.color;
			GUI.color = Color.white;
			GUI.DrawTexture(new Rect(((Rect)(ref rect)).x, ((Rect)(ref rect)).y, ((Rect)(ref rect)).width, thickness), (Texture)(object)whiteTexture);
			GUI.DrawTexture(new Rect(((Rect)(ref rect)).x, ((Rect)(ref rect)).yMax - thickness, ((Rect)(ref rect)).width, thickness), (Texture)(object)whiteTexture);
			GUI.DrawTexture(new Rect(((Rect)(ref rect)).x, ((Rect)(ref rect)).y, thickness, ((Rect)(ref rect)).height), (Texture)(object)whiteTexture);
			GUI.DrawTexture(new Rect(((Rect)(ref rect)).xMax - thickness, ((Rect)(ref rect)).y, thickness, ((Rect)(ref rect)).height), (Texture)(object)whiteTexture);
			GUI.color = color;
		}

		private static bool IsVanillaSettingsScreenVisible()
		{
			//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)
			bool flag = false;
			bool flag2 = false;
			Component[] array = Resources.FindObjectsOfTypeAll<Component>();
			foreach (Component val in array)
			{
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				Scene scene = val.gameObject.scene;
				if (!((Scene)(ref scene)).IsValid() || !val.gameObject.activeInHierarchy)
				{
					continue;
				}
				string text = GetText(val);
				if (!string.IsNullOrWhiteSpace(text))
				{
					if (text.Equals("ACCESSIBILITY", StringComparison.OrdinalIgnoreCase))
					{
						flag = true;
					}
					if (text.Equals("GRAPHICS", StringComparison.OrdinalIgnoreCase) || text.Equals("DISPLAY", StringComparison.OrdinalIgnoreCase))
					{
						flag2 = true;
					}
					if (flag && flag2)
					{
						return true;
					}
				}
			}
			return false;
		}

		private static string? GetText(Component component)
		{
			PropertyInfo property = ((object)component).GetType().GetProperty("text", BindingFlags.Instance | BindingFlags.Public);
			if (!(property?.PropertyType == typeof(string)))
			{
				return null;
			}
			return property.GetValue(component) as string;
		}
	}
	internal static class InputSystemReader
	{
		private static bool initialized;

		private static bool loggedMissingInputSystem;

		private static Type? keyboardType;

		private static Type? mouseType;

		private static PropertyInfo? keyboardCurrentProperty;

		private static PropertyInfo? mouseCurrentProperty;

		private static PropertyInfo? f5KeyProperty;

		private static PropertyInfo? leftAltKeyProperty;

		private static PropertyInfo? rightAltKeyProperty;

		private static PropertyInfo? upArrowKeyProperty;

		private static PropertyInfo? downArrowKeyProperty;

		private static PropertyInfo? leftArrowKeyProperty;

		private static PropertyInfo? rightArrowKeyProperty;

		private static PropertyInfo? wKeyProperty;

		private static PropertyInfo? sKeyProperty;

		private static PropertyInfo? scrollProperty;

		private static PropertyInfo? wasPressedThisFrameProperty;

		private static PropertyInfo? isPressedProperty;

		private static MethodInfo? readScrollValueMethod;

		public static bool WasF5PressedThisFrame()
		{
			EnsureInitialized();
			if (keyboardCurrentProperty == null || f5KeyProperty == null || wasPressedThisFrameProperty == null)
			{
				return false;
			}
			object value = keyboardCurrentProperty.GetValue(null);
			object obj = ((value == null) ? null : f5KeyProperty.GetValue(value));
			if (obj != null)
			{
				object value2 = wasPressedThisFrameProperty.GetValue(obj);
				if (value2 is bool)
				{
					return (bool)value2;
				}
				return false;
			}
			return false;
		}

		public static float ReadMouseScrollY()
		{
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			EnsureInitialized();
			if (mouseCurrentProperty == null || scrollProperty == null || readScrollValueMethod == null)
			{
				return 0f;
			}
			object value = mouseCurrentProperty.GetValue(null);
			object obj = ((value == null) ? null : scrollProperty.GetValue(value));
			object obj2 = ((obj == null) ? null : readScrollValueMethod.Invoke(obj, Array.Empty<object>()));
			if (obj2 is Vector2)
			{
				return ((Vector2)obj2).y;
			}
			return ReadYByReflection(obj2);
		}

		public static bool IsAltPressed()
		{
			EnsureInitialized();
			if (!IsKeyPressed(leftAltKeyProperty))
			{
				return IsKeyPressed(rightAltKeyProperty);
			}
			return true;
		}

		public static bool IsUpPressed()
		{
			EnsureInitialized();
			if (!IsKeyPressed(upArrowKeyProperty))
			{
				return IsKeyPressed(wKeyProperty);
			}
			return true;
		}

		public static bool IsDownPressed()
		{
			EnsureInitialized();
			if (!IsKeyPressed(downArrowKeyProperty))
			{
				return IsKeyPressed(sKeyProperty);
			}
			return true;
		}

		public static bool IsLeftPressed()
		{
			EnsureInitialized();
			return IsKeyPressed(leftArrowKeyProperty);
		}

		public static bool IsRightPressed()
		{
			EnsureInitialized();
			return IsKeyPressed(rightArrowKeyProperty);
		}

		public static bool IsWPressed()
		{
			EnsureInitialized();
			return IsKeyPressed(wKeyProperty);
		}

		public static bool IsSPressed()
		{
			EnsureInitialized();
			return IsKeyPressed(sKeyProperty);
		}

		private static void EnsureInitialized()
		{
			if (!initialized)
			{
				initialized = true;
				keyboardType = FindType("UnityEngine.InputSystem.Keyboard");
				mouseType = FindType("UnityEngine.InputSystem.Mouse");
				keyboardCurrentProperty = keyboardType?.GetProperty("current", BindingFlags.Static | BindingFlags.Public);
				mouseCurrentProperty = mouseType?.GetProperty("current", BindingFlags.Static | BindingFlags.Public);
				f5KeyProperty = keyboardType?.GetProperty("f5Key", BindingFlags.Instance | BindingFlags.Public);
				leftAltKeyProperty = keyboardType?.GetProperty("leftAltKey", BindingFlags.Instance | BindingFlags.Public);
				rightAltKeyProperty = keyboardType?.GetProperty("rightAltKey", BindingFlags.Instance | BindingFlags.Public);
				upArrowKeyProperty = keyboardType?.GetProperty("upArrowKey", BindingFlags.Instance | BindingFlags.Public);
				downArrowKeyProperty = keyboardType?.GetProperty("downArrowKey", BindingFlags.Instance | BindingFlags.Public);
				leftArrowKeyProperty = keyboardType?.GetProperty("leftArrowKey", BindingFlags.Instance | BindingFlags.Public);
				rightArrowKeyProperty = keyboardType?.GetProperty("rightArrowKey", BindingFlags.Instance | BindingFlags.Public);
				wKeyProperty = keyboardType?.GetProperty("wKey", BindingFlags.Instance | BindingFlags.Public);
				sKeyProperty = keyboardType?.GetProperty("sKey", BindingFlags.Instance | BindingFlags.Public);
				scrollProperty = mouseType?.GetProperty("scroll", BindingFlags.Instance | BindingFlags.Public);
				Type obj = f5KeyProperty?.PropertyType;
				wasPressedThisFrameProperty = obj?.GetProperty("wasPressedThisFrame", BindingFlags.Instance | BindingFlags.Public);
				isPressedProperty = obj?.GetProperty("isPressed", BindingFlags.Instance | BindingFlags.Public);
				readScrollValueMethod = (scrollProperty?.PropertyType)?.GetMethod("ReadValue", BindingFlags.Instance | BindingFlags.Public, null, Type.EmptyTypes, null);
				if (!loggedMissingInputSystem && (keyboardCurrentProperty == null || mouseCurrentProperty == null))
				{
					loggedMissingInputSystem = true;
					Plugin.Log.LogWarning((object)"Unity Input System was not found; keyboard and wheel camera controls are unavailable.");
				}
			}
		}

		private static bool IsKeyPressed(PropertyInfo? keyProperty)
		{
			if (keyboardCurrentProperty == null || keyProperty == null || isPressedProperty == null)
			{
				return false;
			}
			object value = keyboardCurrentProperty.GetValue(null);
			object obj = ((value == null) ? null : keyProperty.GetValue(value));
			if (obj != null)
			{
				object value2 = isPressedProperty.GetValue(obj);
				if (value2 is bool)
				{
					return (bool)value2;
				}
				return false;
			}
			return false;
		}

		private static float ReadYByReflection(object? value)
		{
			if (value == null)
			{
				return 0f;
			}
			Type type = value.GetType();
			object obj = type.GetProperty("y", BindingFlags.Instance | BindingFlags.Public)?.GetValue(value);
			if (obj is float)
			{
				return (float)obj;
			}
			obj = type.GetField("y", BindingFlags.Instance | BindingFlags.Public)?.GetValue(value);
			if (obj is float)
			{
				return (float)obj;
			}
			return 0f;
		}

		private static Type? FindType(string typeName)
		{
			Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
			for (int i = 0; i < assemblies.Length; i++)
			{
				Type type = assemblies[i].GetType(typeName, throwOnError: false);
				if (type != null)
				{
					return type;
				}
			}
			return null;
		}
	}
	[BepInPlugin("projectfoldername.3rdpersoncoeeex", "3RdPersonCoeeEX", "1.0.0")]
	public sealed class Plugin : BaseUnityPlugin
	{
		internal static ManualLogSource Log;

		internal static ConfigEntry<CameraSwitchingMethod> SwitchingMethod;

		internal static ConfigEntry<bool> ShowInGameSettings;

		internal static ConfigEntry<bool> PreserveCameraAdjustments;

		private void Awake()
		{
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Expected O, but got Unknown
			//IL_007b: 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)
			Log = ((BaseUnityPlugin)this).Logger;
			SwitchingMethod = ((BaseUnityPlugin)this).Config.Bind<CameraSwitchingMethod>("switch camera", "Camera switching method", CameraSwitchingMethod.Toggle, "Toggle: F5 cycles first/back/front like Minecraft. Wheel: mouse wheel freely adjusts first-to-third person like Roblox. Off: disables 3RdPersonCoeeEX.");
			ShowInGameSettings = ((BaseUnityPlugin)this).Config.Bind<bool>("switch camera", "Show in-game settings", true, "Shows the 3RdPersonCoeeEX camera setting directly on Lethal Company's in-game settings screen.");
			PreserveCameraAdjustments = ((BaseUnityPlugin)this).Config.Bind<bool>("switch camera", "Preserve camera height and distance", false, "Keeps Alt camera height/distance adjustments after returning to first person.");
			GameObject val = new GameObject("3RdPersonCoeeEX.CameraController");
			Object.DontDestroyOnLoad((Object)val);
			((Object)val).hideFlags = (HideFlags)61;
			val.AddComponent<ThirdPersonCameraController>();
			val.AddComponent<InGameCameraSettingsMenu>();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"3RdPersonCoeeEX 1.0.0 loaded.");
		}
	}
	internal static class PluginInfo
	{
		public const string Guid = "projectfoldername.3rdpersoncoeeex";

		public const string Name = "3RdPersonCoeeEX";

		public const string Version = "1.0.0";
	}
	internal sealed class ThirdPersonCameraController : MonoBehaviour
	{
		private enum ToggleView
		{
			FirstPerson,
			Back,
			Front
		}

		private const float MinWheelDistance = 0f;

		private const float MaxWheelDistance = 6f;

		private const float WheelStep = 1.1f;

		private const float AltWheelStep = 0.65f;

		private const float HeightAdjustSpeed = 1.8f;

		private const float DistanceAdjustSpeed = 2.6f;

		private const float MinHeightOffset = -1.1f;

		private const float MaxHeightOffset = 2.2f;

		private const float MinDistanceOffset = -2.4f;

		private const float MaxDistanceOffset = 4.5f;

		private const float MinThirdPersonDistance = 0.35f;

		private const float MaxThirdPersonDistance = 10f;

		private const float ShoulderOffset = 0.35f;

		private const float PivotHeight = 1.55f;

		private const float CollisionPadding = 0.18f;

		private object? player;

		private Camera? camera;

		private Camera? thirdPersonCamera;

		private Transform? playerTransform;

		private float wheelDistance;

		private float heightOffset;

		private float distanceOffset;

		private float lastToggleTime = -1f;

		private ToggleView toggleView;

		private bool cameraCaptured;

		private bool localBodyWasShadowOnly;

		private bool thirdPersonActive;

		private Type? startOfRoundType;

		private void Update()
		{
			if (ShouldSuppressForwardBackMovement())
			{
				SuppressForwardBackMovement();
			}
		}

		private void LateUpdate()
		{
			CameraSwitchingMethod value = Plugin.SwitchingMethod.Value;
			CaptureLocalPlayer();
			if (player == null || (Object)(object)camera == (Object)null || value == CameraSwitchingMethod.Off || IsPlayerDead(player))
			{
				RestoreFirstPerson();
			}
			else if (value == CameraSwitchingMethod.Toggle)
			{
				HandleToggleInput();
				if (toggleView == ToggleView.FirstPerson)
				{
					RestoreFirstPersonIfNeeded();
					return;
				}
				float signedDistance = ((toggleView == ToggleView.Back) ? 3.5f : (-3.5f));
				ApplyThirdPerson(signedDistance);
			}
			else
			{
				HandleWheelInput();
				if (wheelDistance <= 0.05f)
				{
					RestoreFirstPersonIfNeeded();
				}
				else
				{
					ApplyThirdPerson(wheelDistance);
				}
			}
		}

		private void CaptureLocalPlayer()
		{
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Invalid comparison between Unknown and I4
			object localPlayer = GetLocalPlayer();
			if (localPlayer == null || (localPlayer == player && cameraCaptured))
			{
				return;
			}
			RestoreFirstPerson();
			player = localPlayer;
			object obj = ((localPlayer is Component) ? localPlayer : null);
			playerTransform = ((obj != null) ? ((Component)obj).transform : null);
			camera = GetFieldOrProperty<Camera>(localPlayer, "gameplayCamera");
			if (!((Object)(object)camera == (Object)null))
			{
				cameraCaptured = true;
				thirdPersonActive = false;
				wheelDistance = 0f;
				toggleView = ToggleView.FirstPerson;
				SkinnedMeshRenderer fieldOrProperty = GetFieldOrProperty<SkinnedMeshRenderer>(localPlayer, "thisPlayerModel");
				if ((Object)(object)fieldOrProperty != (Object)null)
				{
					localBodyWasShadowOnly = (int)((Renderer)fieldOrProperty).shadowCastingMode == 3;
				}
			}
		}

		private void HandleToggleInput()
		{
			if (InputSystemReader.WasF5PressedThisFrame() && !(Time.unscaledTime - lastToggleTime < 0.25f))
			{
				lastToggleTime = Time.unscaledTime;
				toggleView = toggleView switch
				{
					ToggleView.FirstPerson => ToggleView.Back, 
					ToggleView.Back => ToggleView.Front, 
					_ => ToggleView.FirstPerson, 
				};
			}
		}

		private void HandleWheelInput()
		{
			float num = InputSystemReader.ReadMouseScrollY();
			if (!(Math.Abs(num) < 0.01f))
			{
				float num2 = ((InputSystemReader.IsAltPressed() && thirdPersonActive) ? 0.65f : 1.1f);
				wheelDistance = Mathf.Clamp(wheelDistance - num * num2, 0f, 6f);
			}
		}

		private void ApplyThirdPerson(float signedDistance)
		{
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: 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_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: 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)
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_013e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0143: Unknown result type (might be due to invalid IL or missing references)
			//IL_015c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0153: Unknown result type (might be due to invalid IL or missing references)
			//IL_0154: Unknown result type (might be due to invalid IL or missing references)
			//IL_0175: 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_016e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0177: Unknown result type (might be due to invalid IL or missing references)
			//IL_017c: Unknown result type (might be due to invalid IL or missing references)
			if (player == null || (Object)(object)playerTransform == (Object)null || (Object)(object)camera == (Object)null)
			{
				return;
			}
			EnsureThirdPersonCamera();
			ShowLocalBody(visible: true);
			HandleAltCameraAdjustments();
			if (ShouldSuppressForwardBackMovement())
			{
				SuppressForwardBackMovement();
			}
			Camera val = thirdPersonCamera;
			if (!((Object)(object)val == (Object)null))
			{
				Vector3 val2 = playerTransform.position + Vector3.up * (1.55f + heightOffset);
				Vector3 forward = playerTransform.forward;
				forward.y = 0f;
				if (((Vector3)(ref forward)).sqrMagnitude < 0.001f)
				{
					forward = Vector3.forward;
				}
				((Vector3)(ref forward)).Normalize();
				Vector3 val3 = Vector3.Cross(Vector3.up, forward);
				Vector3 normalized = ((Vector3)(ref val3)).normalized;
				bool flag = signedDistance >= 0f;
				float num = Mathf.Clamp(Mathf.Abs(signedDistance) + distanceOffset, 0.35f, 10f);
				Vector3 val4 = (flag ? (-forward) : forward);
				Vector3 val5 = normalized * 0.35f;
				Vector3 desired = val2 + val5 + val4 * num;
				Vector3 position = ResolveCameraCollision(val2 + val5, desired);
				Vector3 val6 = ((Component)camera).transform.forward;
				if (((Vector3)(ref val6)).sqrMagnitude < 0.001f)
				{
					val6 = forward;
				}
				((Component)val).transform.position = position;
				((Component)val).transform.rotation = Quaternion.LookRotation(flag ? val6 : (-val6), Vector3.up);
				thirdPersonActive = true;
			}
		}

		private Vector3 ResolveCameraCollision(Vector3 pivot, Vector3 desired)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: 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)
			Vector3 val = desired - pivot;
			float magnitude = ((Vector3)(ref val)).magnitude;
			if (magnitude < 0.01f)
			{
				return desired;
			}
			RaycastHit val2 = default(RaycastHit);
			if (Physics.SphereCast(pivot, 0.18f, ((Vector3)(ref val)).normalized, ref val2, magnitude, -1, (QueryTriggerInteraction)1))
			{
				return pivot + ((Vector3)(ref val)).normalized * Mathf.Max(0.1f, ((RaycastHit)(ref val2)).distance - 0.18f);
			}
			return desired;
		}

		private void RestoreFirstPerson()
		{
			if (thirdPersonActive)
			{
				RestoreFirstPersonIfNeeded();
			}
		}

		private void RestoreFirstPersonIfNeeded()
		{
			if (cameraCaptured && !((Object)(object)camera == (Object)null))
			{
				ShowLocalBody(visible: false);
				if ((Object)(object)camera != (Object)null)
				{
					((Behaviour)camera).enabled = true;
				}
				if ((Object)(object)thirdPersonCamera != (Object)null)
				{
					Object.Destroy((Object)(object)((Component)thirdPersonCamera).gameObject);
					thirdPersonCamera = null;
				}
				thirdPersonActive = false;
				ResetAdjustmentsIfNeeded();
			}
		}

		private void HandleAltCameraAdjustments()
		{
			if (InputSystemReader.IsAltPressed())
			{
				float unscaledDeltaTime = Time.unscaledDeltaTime;
				float num = 0f;
				float num2 = 0f;
				if (InputSystemReader.IsUpPressed())
				{
					num += 1f;
				}
				if (InputSystemReader.IsDownPressed())
				{
					num -= 1f;
				}
				if (InputSystemReader.IsRightPressed())
				{
					num2 += 1f;
				}
				if (InputSystemReader.IsLeftPressed())
				{
					num2 -= 1f;
				}
				if (Math.Abs(num) > 0.01f)
				{
					heightOffset = Mathf.Clamp(heightOffset + num * 1.8f * unscaledDeltaTime, -1.1f, 2.2f);
				}
				if (Math.Abs(num2) > 0.01f)
				{
					distanceOffset = Mathf.Clamp(distanceOffset + num2 * 2.6f * unscaledDeltaTime, -2.4f, 4.5f);
				}
			}
		}

		private bool ShouldSuppressForwardBackMovement()
		{
			if (thirdPersonActive && InputSystemReader.IsAltPressed())
			{
				if (!InputSystemReader.IsWPressed())
				{
					return InputSystemReader.IsSPressed();
				}
				return true;
			}
			return false;
		}

		private void SuppressForwardBackMovement()
		{
			if (player != null && !TryZeroMovementY(player, "moveInputVector") && !TryZeroMovementY(player, "movementInput"))
			{
				TryZeroMovementY(player, "moveInput");
			}
		}

		private static bool TryZeroMovementY(object instance, string memberName)
		{
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			Type type = instance.GetType();
			FieldInfo field = type.GetField(memberName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (field != null && field.FieldType == typeof(Vector2) && field.GetValue(instance) is Vector2 val)
			{
				val.y = 0f;
				field.SetValue(instance, val);
				return true;
			}
			PropertyInfo property = type.GetProperty(memberName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (property != null && property.PropertyType == typeof(Vector2) && property.CanRead && property.CanWrite && property.GetValue(instance) is Vector2 val2)
			{
				val2.y = 0f;
				property.SetValue(instance, val2);
				return true;
			}
			return false;
		}

		private void ResetAdjustmentsIfNeeded()
		{
			if (!Plugin.PreserveCameraAdjustments.Value)
			{
				heightOffset = 0f;
				distanceOffset = 0f;
			}
		}

		private void EnsureThirdPersonCamera()
		{
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Expected O, but got Unknown
			if ((Object)(object)camera == (Object)null)
			{
				return;
			}
			if ((Object)(object)thirdPersonCamera != (Object)null)
			{
				if (((Behaviour)camera).enabled)
				{
					((Behaviour)camera).enabled = false;
				}
			}
			else
			{
				GameObject val = new GameObject("3RdPersonCoeeEX.ThirdPersonCamera");
				thirdPersonCamera = val.AddComponent<Camera>();
				thirdPersonCamera.CopyFrom(camera);
				((Behaviour)thirdPersonCamera).enabled = true;
				((Behaviour)camera).enabled = false;
			}
		}

		private void ShowLocalBody(bool visible)
		{
			if (player != null)
			{
				SkinnedMeshRenderer fieldOrProperty = GetFieldOrProperty<SkinnedMeshRenderer>(player, "thisPlayerModel");
				if (!((Object)(object)fieldOrProperty == (Object)null))
				{
					((Renderer)fieldOrProperty).shadowCastingMode = (ShadowCastingMode)((visible || !localBodyWasShadowOnly) ? 1 : 3);
				}
			}
		}

		private object? GetLocalPlayer()
		{
			if ((object)startOfRoundType == null)
			{
				startOfRoundType = FindType("StartOfRound");
			}
			if (startOfRoundType == null)
			{
				return null;
			}
			object staticFieldOrProperty = GetStaticFieldOrProperty<object>(startOfRoundType, "Instance");
			if (staticFieldOrProperty != null)
			{
				return GetFieldOrProperty<object>(staticFieldOrProperty, "localPlayerController");
			}
			return null;
		}

		private static bool IsPlayerDead(object player)
		{
			return GetFieldOrProperty<bool>(player, "isPlayerDead");
		}

		private static Type? FindType(string typeName)
		{
			Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
			for (int i = 0; i < assemblies.Length; i++)
			{
				Type type = assemblies[i].GetType(typeName, throwOnError: false);
				if (type != null)
				{
					return type;
				}
			}
			return null;
		}

		private static T? GetStaticFieldOrProperty<T>(Type type, string name)
		{
			FieldInfo field = type.GetField(name, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
			if (field != null)
			{
				return Cast<T>(field.GetValue(null));
			}
			PropertyInfo property = type.GetProperty(name, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
			if (!(property == null))
			{
				return Cast<T>(property.GetValue(null));
			}
			return default(T);
		}

		private static T? GetFieldOrProperty<T>(object instance, string name)
		{
			Type type = instance.GetType();
			FieldInfo field = type.GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (field != null)
			{
				return Cast<T>(field.GetValue(instance));
			}
			PropertyInfo property = type.GetProperty(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (!(property == null))
			{
				return Cast<T>(property.GetValue(instance));
			}
			return default(T);
		}

		private static T? Cast<T>(object? value)
		{
			if (value is T)
			{
				return (T)value;
			}
			return default(T);
		}
	}
	internal static class VanillaButtonSound
	{
		private static AudioSource? cachedSource;

		private static AudioClip? cachedClip;

		private static float nextSearchTime;

		public static void Play()
		{
			TryRefreshCache();
			if ((Object)(object)cachedSource != (Object)null && (Object)(object)cachedClip != (Object)null)
			{
				cachedSource.PlayOneShot(cachedClip);
				return;
			}
			AudioSource? obj = cachedSource;
			if (obj != null)
			{
				obj.Play();
			}
		}

		private static void TryRefreshCache()
		{
			if ((!((Object)(object)cachedSource != (Object)null) || !((Object)(object)((Component)cachedSource).gameObject != (Object)null) || !((Component)cachedSource).gameObject.activeInHierarchy || !((Object)(object)cachedClip != (Object)null)) && !(Time.unscaledTime < nextSearchTime))
			{
				nextSearchTime = Time.unscaledTime + 1f;
				cachedSource = FindMenuAudioSource();
				cachedClip = FindLikelyButtonClip();
			}
		}

		private static AudioSource? FindMenuAudioSource()
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			AudioSource[] array = Resources.FindObjectsOfTypeAll<AudioSource>();
			Scene scene;
			foreach (AudioSource val in array)
			{
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				scene = ((Component)val).gameObject.scene;
				if (((Scene)(ref scene)).IsValid() && ((Component)val).gameObject.activeInHierarchy)
				{
					string text = ((Object)((Component)val).gameObject).name.ToLowerInvariant();
					if (text.Contains("menu") || text.Contains("ui") || text.Contains("button"))
					{
						return val;
					}
				}
			}
			array = Resources.FindObjectsOfTypeAll<AudioSource>();
			foreach (AudioSource val2 in array)
			{
				if ((Object)(object)val2 != (Object)null)
				{
					scene = ((Component)val2).gameObject.scene;
					if (((Scene)(ref scene)).IsValid() && ((Component)val2).gameObject.activeInHierarchy)
					{
						return val2;
					}
				}
			}
			return null;
		}

		private static AudioClip? FindLikelyButtonClip()
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			Component[] array = Resources.FindObjectsOfTypeAll<Component>();
			Scene scene;
			foreach (Component val in array)
			{
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				scene = val.gameObject.scene;
				if (((Scene)(ref scene)).IsValid())
				{
					AudioClip val2 = FindClipOnObject(val, "button");
					if ((Object)(object)val2 != (Object)null)
					{
						return val2;
					}
				}
			}
			array = Resources.FindObjectsOfTypeAll<Component>();
			foreach (Component val3 in array)
			{
				if ((Object)(object)val3 == (Object)null)
				{
					continue;
				}
				scene = val3.gameObject.scene;
				if (((Scene)(ref scene)).IsValid())
				{
					AudioClip val4 = FindClipOnObject(val3, "click");
					if ((Object)(object)val4 != (Object)null)
					{
						return val4;
					}
				}
			}
			return null;
		}

		private static AudioClip? FindClipOnObject(object instance, string nameHint)
		{
			Type type = instance.GetType();
			FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (FieldInfo fieldInfo in fields)
			{
				if (typeof(AudioClip).IsAssignableFrom(fieldInfo.FieldType) && fieldInfo.Name.Contains(nameHint, StringComparison.OrdinalIgnoreCase))
				{
					object? value = fieldInfo.GetValue(instance);
					AudioClip val = (AudioClip)((value is AudioClip) ? value : null);
					if (val != null)
					{
						return val;
					}
				}
			}
			PropertyInfo[] properties = type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (PropertyInfo propertyInfo in properties)
			{
				if (typeof(AudioClip).IsAssignableFrom(propertyInfo.PropertyType) && propertyInfo.Name.Contains(nameHint, StringComparison.OrdinalIgnoreCase) && propertyInfo.CanRead)
				{
					object? value2 = propertyInfo.GetValue(instance);
					AudioClip val2 = (AudioClip)((value2 is AudioClip) ? value2 : null);
					if (val2 != null)
					{
						return val2;
					}
				}
			}
			return null;
		}
	}
}