Decompiled source of CameraUnlock v1.0.1

CameraUnlock.dll

Decompiled 11 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using Cinemachine;
using HarmonyLib;
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
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("CameraUnlock")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.1.0")]
[assembly: AssemblyInformationalVersion("1.0.1")]
[assembly: AssemblyProduct("CameraUnlock")]
[assembly: AssemblyTitle("CameraUnlock")]
[assembly: AssemblyVersion("1.0.1.0")]
namespace CameraUnlock;

internal sealed class FreeCamera
{
	private const float MaxPitch = 89f;

	private const float SpeedStepPerNotch = 1.2f;

	private const float MinSpeedScale = 0.05f;

	private const float MaxSpeedScale = 20f;

	private Camera _camera;

	private CinemachineBrain _brain;

	private bool _brainWasEnabled;

	private float _gameFov;

	private Vector3 _position;

	private Vector3 _targetPosition;

	private float _yaw;

	private float _targetYaw;

	private float _pitch;

	private float _targetPitch;

	private float _fov;

	private float _speedScale = 1f;

	public static bool IsActive { get; private set; }

	private static Plugin Settings => Plugin.Instance;

	public bool TryEnter(out string error)
	{
		//IL_0087: Unknown result type (might be due to invalid IL or missing references)
		//IL_008c: Unknown result type (might be due to invalid IL or missing references)
		//IL_008d: Unknown result type (might be due to invalid IL or missing references)
		//IL_008f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0094: Unknown result type (might be due to invalid IL or missing references)
		//IL_0096: Unknown result type (might be due to invalid IL or missing references)
		//IL_009c: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
		error = null;
		if ((Object)(object)GameAccess.LocalPlayer == (Object)null)
		{
			error = "join a world first";
			return false;
		}
		if (GameAccess.IsPlayerOnSwan())
		{
			error = "not available on the swan boat";
			return false;
		}
		Camera main = Camera.main;
		CinemachineBrain val = (((Object)(object)main != (Object)null) ? ((Component)main).GetComponent<CinemachineBrain>() : null);
		if ((Object)(object)val == (Object)null || !((Behaviour)val).enabled)
		{
			error = "the game camera is not available right now";
			return false;
		}
		_camera = main;
		_brain = val;
		_brainWasEnabled = ((Behaviour)val).enabled;
		((Behaviour)val).enabled = false;
		Transform transform = ((Component)main).transform;
		_position = (_targetPosition = transform.position);
		Quaternion rotation = transform.rotation;
		Vector3 eulerAngles = ((Quaternion)(ref rotation)).eulerAngles;
		_yaw = (_targetYaw = eulerAngles.y);
		_pitch = (_targetPitch = Mathf.Clamp(Mathf.DeltaAngle(0f, eulerAngles.x), -89f, 89f));
		_fov = (_gameFov = main.fieldOfView);
		IsActive = true;
		return true;
	}

	public void Exit()
	{
		if (IsActive)
		{
			IsActive = false;
			if ((Object)(object)_camera != (Object)null)
			{
				_camera.fieldOfView = _gameFov;
			}
			if ((Object)(object)_brain != (Object)null)
			{
				((Behaviour)_brain).enabled = _brainWasEnabled;
			}
			_camera = null;
			_brain = null;
		}
	}

	public void ResetFov()
	{
		_fov = _gameFov;
		Plugin.Toast($"Field of view: {_fov:0}° (default)");
	}

	public bool LateTick()
	{
		//IL_008f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0095: Unknown result type (might be due to invalid IL or missing references)
		//IL_009b: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
		if (!IsActive)
		{
			return true;
		}
		if ((Object)(object)_camera == (Object)null || (Object)(object)_brain == (Object)null || (Object)(object)GameAccess.LocalPlayer == (Object)null)
		{
			Exit();
			return false;
		}
		((Behaviour)_brain).enabled = false;
		float unscaledDeltaTime = Time.unscaledDeltaTime;
		if (!GameAccess.IsAnyTextFieldFocused())
		{
			ReadInput(unscaledDeltaTime);
		}
		float value = Settings.FreeCamSmoothing.Value;
		float num = ((value <= 0f) ? 1f : (1f - Mathf.Pow(value, unscaledDeltaTime * 10f)));
		_position = Vector3.Lerp(_position, _targetPosition, num);
		_yaw = Mathf.Lerp(_yaw, _targetYaw, num);
		_pitch = Mathf.Lerp(_pitch, _targetPitch, num);
		((Component)_camera).transform.SetPositionAndRotation(_position, Quaternion.Euler(_pitch, _yaw, 0f));
		_camera.fieldOfView = _fov;
		return true;
	}

	private void ReadInput(float deltaTime)
	{
		//IL_0098: Unknown result type (might be due to invalid IL or missing references)
		//IL_0150: Unknown result type (might be due to invalid IL or missing references)
		//IL_0155: Unknown result type (might be due to invalid IL or missing references)
		//IL_0160: Unknown result type (might be due to invalid IL or missing references)
		//IL_0186: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ac: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d2: Unknown result type (might be due to invalid IL or missing references)
		//IL_01fe: Unknown result type (might be due to invalid IL or missing references)
		//IL_021c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0267: Unknown result type (might be due to invalid IL or missing references)
		//IL_0291: Unknown result type (might be due to invalid IL or missing references)
		//IL_02c2: Unknown result type (might be due to invalid IL or missing references)
		//IL_02c7: Unknown result type (might be due to invalid IL or missing references)
		//IL_02c8: Unknown result type (might be due to invalid IL or missing references)
		//IL_02cd: Unknown result type (might be due to invalid IL or missing references)
		//IL_02d3: Unknown result type (might be due to invalid IL or missing references)
		//IL_02d8: Unknown result type (might be due to invalid IL or missing references)
		//IL_02dd: Unknown result type (might be due to invalid IL or missing references)
		//IL_02e1: Unknown result type (might be due to invalid IL or missing references)
		//IL_02e6: 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)
		bool flag = Input.GetKey((KeyCode)304) || Input.GetKey((KeyCode)303);
		if (Input.GetMouseButton(1))
		{
			float value = Settings.FreeCamLookSensitivity.Value;
			float num = (Settings.FreeCamInvertY.Value ? (-1f) : 1f);
			_targetYaw += Input.GetAxisRaw("Mouse X") * value;
			_targetPitch = Mathf.Clamp(_targetPitch - Input.GetAxisRaw("Mouse Y") * value * num, -89f, 89f);
		}
		float y = Input.mouseScrollDelta.y;
		if (Mathf.Abs(y) > 0.001f && !GameAccess.IsPointerOverUi())
		{
			if (flag)
			{
				_fov = Mathf.Clamp(_fov - y * 2f, 10f, 120f);
				Plugin.Toast($"Field of view: {_fov:0}°");
			}
			else
			{
				_speedScale = Mathf.Clamp(_speedScale * Mathf.Pow(1.2f, y), 0.05f, 20f);
				Plugin.Toast($"Camera speed: {Settings.FreeCamSpeed.Value * _speedScale:0.##} m/s");
			}
		}
		Vector3 zero = Vector3.zero;
		if (Input.GetKey(Settings.FreeCamForward.Value))
		{
			zero.z += 1f;
		}
		if (Input.GetKey(Settings.FreeCamBack.Value))
		{
			zero.z -= 1f;
		}
		if (Input.GetKey(Settings.FreeCamRight.Value))
		{
			zero.x += 1f;
		}
		if (Input.GetKey(Settings.FreeCamLeft.Value))
		{
			zero.x -= 1f;
		}
		float num2 = 0f;
		if (Input.GetKey(Settings.FreeCamUp.Value))
		{
			num2 += 1f;
		}
		if (Input.GetKey(Settings.FreeCamDown.Value))
		{
			num2 -= 1f;
		}
		if (((Vector3)(ref zero)).sqrMagnitude > 1f)
		{
			((Vector3)(ref zero)).Normalize();
		}
		float num3 = Settings.FreeCamSpeed.Value * _speedScale;
		if (Input.GetKey(Settings.FreeCamFast.Value))
		{
			num3 *= Settings.FreeCamFastMultiplier.Value;
		}
		if (Input.GetKey(Settings.FreeCamSlow.Value))
		{
			num3 *= Settings.FreeCamSlowMultiplier.Value;
		}
		Vector3 val = Quaternion.Euler(_targetPitch, _targetYaw, 0f) * zero + Vector3.up * num2;
		_targetPosition += val * (num3 * deltaTime);
	}
}
internal static class InputBlocker
{
	private static readonly string[] KeptInputs = new string[5] { "IsMouseButton1", "IsMouseButton1Up", "IsEscapeKeyDown", "EnterKeyDown", "EnterKeyUp" };

	private static List<FieldInfo> _fields;

	internal static void AfterInputUpdate(InputManager input)
	{
		if (!FreeCamera.IsActive)
		{
			return;
		}
		if (_fields == null)
		{
			_fields = FindInputFields();
		}
		foreach (FieldInfo field in _fields)
		{
			field.SetValue(input, (field.FieldType == typeof(bool)) ? ((object)false) : ((object)0f));
		}
	}

	private static List<FieldInfo> FindInputFields()
	{
		List<FieldInfo> list = new List<FieldInfo>();
		FieldInfo[] fields = typeof(InputManager).GetFields(BindingFlags.Instance | BindingFlags.NonPublic);
		foreach (FieldInfo fieldInfo in fields)
		{
			if (fieldInfo.Name.StartsWith("<") && fieldInfo.Name.EndsWith(">k__BackingField") && (!(fieldInfo.FieldType != typeof(bool)) || !(fieldInfo.FieldType != typeof(float))))
			{
				string value = fieldInfo.Name.Substring(1, fieldInfo.Name.IndexOf('>') - 1);
				if (Array.IndexOf(KeptInputs, value) < 0)
				{
					list.Add(fieldInfo);
				}
			}
		}
		return list;
	}
}
internal static class GameAccess
{
	private const float LookupInterval = 1f;

	private static TextChannelManager _chat;

	private static float _nextChatLookup;

	private static TextChannelManager Chat
	{
		get
		{
			if ((Object)(object)_chat == (Object)null && Time.unscaledTime >= _nextChatLookup)
			{
				_nextChatLookup = Time.unscaledTime + 1f;
				_chat = NetworkSingleton<TextChannelManager>.I;
			}
			return _chat;
		}
	}

	public static Transform LocalPlayer
	{
		get
		{
			TextChannelManager chat = Chat;
			if (!((Object)(object)chat != (Object)null))
			{
				return null;
			}
			return chat.MainPlayer;
		}
	}

	public static bool IsPlayerOnSwan()
	{
		if ((Object)(object)LocalPlayer == (Object)null)
		{
			return false;
		}
		SwanManager i = NetworkSingleton<SwanManager>.I;
		if ((Object)(object)i != (Object)null)
		{
			return i.IsPlayerOnSwan();
		}
		return false;
	}

	public static bool IsAnyTextFieldFocused()
	{
		EventSystem current = EventSystem.current;
		if ((Object)(object)current == (Object)null)
		{
			return false;
		}
		GameObject currentSelectedGameObject = current.currentSelectedGameObject;
		if ((Object)(object)currentSelectedGameObject == (Object)null)
		{
			return false;
		}
		TMP_InputField component = currentSelectedGameObject.GetComponent<TMP_InputField>();
		if ((Object)(object)component != (Object)null && component.isFocused)
		{
			return true;
		}
		InputField component2 = currentSelectedGameObject.GetComponent<InputField>();
		if ((Object)(object)component2 != (Object)null)
		{
			return component2.isFocused;
		}
		return false;
	}

	public static bool IsPointerOverUi()
	{
		EventSystem current = EventSystem.current;
		if ((Object)(object)current != (Object)null)
		{
			return current.IsPointerOverGameObject();
		}
		return false;
	}

	public static bool GameWouldZoom()
	{
		//IL_0005: Unknown result type (might be due to invalid IL or missing references)
		//IL_000b: Invalid comparison between Unknown and I4
		if ((int)MonoSingleton<OverlayManager>.I.ResolutionMode == 3)
		{
			return false;
		}
		GameObject mouseOverUIObject = MonoSingleton<InputManager>.I.MouseOverUIObject;
		if (!((Object)(object)mouseOverUIObject == (Object)null))
		{
			return MonoSingleton<UIManager>.I.OverlayMasks.Contains(mouseOverUIObject.transform);
		}
		return true;
	}
}
internal static class Lens
{
	public const float MinFov = 10f;

	public const float MaxFov = 120f;

	public const float StepPerNotch = 2f;

	private static CinemachineVirtualCamera _vcam;

	private static float _gameFov;

	private static float? _wheelFov;

	private static bool _modified;

	private static Plugin Settings => Plugin.Instance;

	public static void Adjust(CinemachineVirtualCamera vcam, float scroll)
	{
		if (!((Object)(object)vcam == (Object)null))
		{
			Capture(vcam);
			_wheelFov = Mathf.Clamp(TargetFov() - scroll * 2f, 10f, 120f);
			Plugin.Toast($"Field of view: {_wheelFov.Value:0}°");
		}
	}

	public static void Reset()
	{
		_wheelFov = null;
		if ((Object)(object)_vcam != (Object)null)
		{
			Plugin.Toast($"Field of view: {TargetFov():0}° (default)");
		}
	}

	public static void Tick(CinemachineVirtualCamera vcam)
	{
		if (!((Object)(object)vcam == (Object)null))
		{
			Capture(vcam);
			float num = TargetFov();
			if (_modified || !Mathf.Approximately(num, _gameFov))
			{
				SetFov(vcam, num);
				_modified = !Mathf.Approximately(num, _gameFov);
			}
		}
	}

	public static void Restore()
	{
		_wheelFov = null;
		if ((Object)(object)_vcam != (Object)null && _modified)
		{
			SetFov(_vcam, _gameFov);
		}
		_modified = false;
	}

	private static void Capture(CinemachineVirtualCamera vcam)
	{
		if (!((Object)(object)vcam == (Object)(object)_vcam))
		{
			_vcam = vcam;
			_gameFov = vcam.m_Lens.FieldOfView;
			_modified = false;
		}
	}

	private static float TargetFov()
	{
		if (_wheelFov.HasValue)
		{
			return _wheelFov.Value;
		}
		float value = Settings.FieldOfView.Value;
		if (!(value >= 10f))
		{
			return _gameFov;
		}
		return Mathf.Min(value, 120f);
	}

	private static void SetFov(CinemachineVirtualCamera vcam, float fov)
	{
		//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_0007: Unknown result type (might be due to invalid IL or missing references)
		//IL_001f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0020: Unknown result type (might be due to invalid IL or missing references)
		LensSettings lens = vcam.m_Lens;
		if (!Mathf.Approximately(lens.FieldOfView, fov))
		{
			lens.FieldOfView = fov;
			vcam.m_Lens = lens;
		}
	}
}
internal static class OrbitCamera
{
	private const float GameShoulderRadius = 2f;

	private const float GameMouseToY = 0.05f;

	private const float DegreesPerY = 28.64789f;

	private static readonly FieldRef<PlayerMovementController, float> CurrentZoomRef = AccessTools.FieldRefAccess<PlayerMovementController, float>("_currentZoom");

	private static readonly FieldRef<PlayerMovementController, CinemachineVirtualCamera> VcamRef = AccessTools.FieldRefAccess<PlayerMovementController, CinemachineVirtualCamera>("_cinemachineVC");

	private static PlayerMovementController _controller;

	private static bool _engaged;

	private static float _pitch;

	private static float _distance;

	private static float _lastGameY;

	public static CinemachineVirtualCamera Vcam { get; private set; }

	private static Plugin Settings => Plugin.Instance;

	internal static void BeforeRotation(PlayerMovementController controller, Vector2 mouseDelta)
	{
		//IL_0057: Unknown result type (might be due to invalid IL or missing references)
		Vcam = VcamRef.Invoke(controller);
		if (Settings.OrbitEnabled.Value)
		{
			if (!_engaged || (Object)(object)controller != (Object)(object)_controller)
			{
				Engage(controller);
			}
			else if (!Mathf.Approximately(controller.RotationXPosY, _lastGameY))
			{
				FollowGameTilt(controller);
			}
			float num = (0f - mouseDelta.y) * ScriptableSingleton<GameSettings>.I.CameraRotateSpeed * 0.05f;
			_pitch = ClampPitch(_pitch + num * 28.64789f * Settings.PitchSensitivity.Value);
		}
	}

	internal static void OnZoom(PlayerMovementController controller)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		float y = Input.mouseScrollDelta.y;
		if (Mathf.Abs(y) < 0.001f || !GameAccess.GameWouldZoom())
		{
			return;
		}
		if (MonoSingleton<InputManager>.I.IsShiftKey)
		{
			if (Settings.ShiftScrollFov.Value)
			{
				Lens.Adjust(VcamRef.Invoke(controller), y);
			}
		}
		else if (Settings.OrbitEnabled.Value && _engaged && !((Object)(object)controller != (Object)(object)_controller))
		{
			float num = 1f + Settings.ZoomStep.Value / 100f;
			_distance = ClampDistance(_distance * Mathf.Pow(num, 0f - y));
		}
	}

	internal static void Apply(PlayerMovementController controller)
	{
		//IL_0086: Unknown result type (might be due to invalid IL or missing references)
		//IL_008b: Unknown result type (might be due to invalid IL or missing references)
		if (Settings.OrbitEnabled.Value && _engaged && !((Object)(object)controller != (Object)(object)_controller))
		{
			Cinemachine3rdPersonFollow val = FollowOf(controller);
			if (!((Object)(object)val == (Object)null))
			{
				_pitch = ClampPitch(_pitch);
				_distance = ClampDistance(_distance);
				float num = _pitch * (MathF.PI / 180f);
				val.ShoulderOffset = new Vector3(val.ShoulderOffset.x, _distance * Mathf.Sin(num), (0f - _distance) * Mathf.Cos(num));
				val.CameraDistance = 0f;
				_lastGameY = controller.RotationXPosY;
			}
		}
	}

	internal static void Disengage()
	{
		//IL_0047: Unknown result type (might be due to invalid IL or missing references)
		if (!_engaged)
		{
			return;
		}
		_engaged = false;
		PlayerMovementController controller = _controller;
		_controller = null;
		if (!((Object)(object)controller == (Object)null))
		{
			Cinemachine3rdPersonFollow val = FollowOf(controller);
			if ((Object)(object)val != (Object)null)
			{
				val.CameraDistance = CurrentZoomRef.Invoke(controller);
			}
			controller.SetCameraRotation(Vector2.zero);
		}
	}

	private static void Engage(PlayerMovementController controller)
	{
		_controller = controller;
		_engaged = true;
		float rotationXPosY = controller.RotationXPosY;
		float num = VanillaBackOffset(controller, rotationXPosY);
		_pitch = ClampPitch(Mathf.Atan2(rotationXPosY, num) * 57.29578f);
		_distance = ClampDistance(Mathf.Sqrt(rotationXPosY * rotationXPosY + num * num));
		_lastGameY = rotationXPosY;
	}

	private static void FollowGameTilt(PlayerMovementController controller)
	{
		float rotationXPosY = controller.RotationXPosY;
		_pitch = ClampPitch(Mathf.Atan2(rotationXPosY, VanillaBackOffset(controller, rotationXPosY)) * 57.29578f);
		_lastGameY = rotationXPosY;
	}

	private static float VanillaBackOffset(PlayerMovementController controller, float y)
	{
		return Mathf.Sqrt(Mathf.Max(0f, 4f - y * y)) + Mathf.Max(0f, CurrentZoomRef.Invoke(controller));
	}

	private static Cinemachine3rdPersonFollow FollowOf(PlayerMovementController controller)
	{
		CinemachineVirtualCamera val = VcamRef.Invoke(controller);
		if (!((Object)(object)val != (Object)null))
		{
			return null;
		}
		return val.GetCinemachineComponent<Cinemachine3rdPersonFollow>();
	}

	private static float ClampPitch(float pitch)
	{
		float value = Settings.MinPitch.Value;
		float num = Mathf.Max(value, Settings.MaxPitch.Value);
		return Mathf.Clamp(pitch, value, num);
	}

	private static float ClampDistance(float distance)
	{
		float value = Settings.MinDistance.Value;
		float num = Mathf.Max(value, Settings.MaxDistance.Value);
		return Mathf.Clamp(distance, value, num);
	}
}
[BepInPlugin("ontogether.cameraunlock", "CameraUnlock", "1.0.1")]
[BepInProcess("OnTogether.exe")]
public sealed class Plugin : BaseUnityPlugin
{
	public const string PluginGuid = "ontogether.cameraunlock";

	public const string PluginName = "CameraUnlock";

	public const string PluginVersion = "1.0.1";

	private const float ToastDuration = 2f;

	private const float FreeCamHintDuration = 7f;

	internal ConfigEntry<bool> OrbitEnabled;

	internal ConfigEntry<float> MinDistance;

	internal ConfigEntry<float> MaxDistance;

	internal ConfigEntry<float> MinPitch;

	internal ConfigEntry<float> MaxPitch;

	internal ConfigEntry<float> ZoomStep;

	internal ConfigEntry<float> PitchSensitivity;

	internal ConfigEntry<bool> CameraCollision;

	internal ConfigEntry<float> FieldOfView;

	internal ConfigEntry<bool> ShiftScrollFov;

	internal ConfigEntry<KeyboardShortcut> FreeCamToggleKey;

	internal ConfigEntry<float> FreeCamSpeed;

	internal ConfigEntry<float> FreeCamFastMultiplier;

	internal ConfigEntry<float> FreeCamSlowMultiplier;

	internal ConfigEntry<float> FreeCamLookSensitivity;

	internal ConfigEntry<bool> FreeCamInvertY;

	internal ConfigEntry<float> FreeCamSmoothing;

	internal ConfigEntry<bool> HideUiInFreeCam;

	internal ConfigEntry<KeyCode> FreeCamForward;

	internal ConfigEntry<KeyCode> FreeCamBack;

	internal ConfigEntry<KeyCode> FreeCamLeft;

	internal ConfigEntry<KeyCode> FreeCamRight;

	internal ConfigEntry<KeyCode> FreeCamUp;

	internal ConfigEntry<KeyCode> FreeCamDown;

	internal ConfigEntry<KeyCode> FreeCamFast;

	internal ConfigEntry<KeyCode> FreeCamSlow;

	internal ConfigEntry<KeyboardShortcut> HideUiKey;

	internal ConfigEntry<bool> HideWorldSpaceUi;

	internal ConfigEntry<bool> ShowHints;

	private Harmony _harmony;

	private readonly FreeCamera _freeCamera = new FreeCamera();

	private readonly UiHider _uiHider = new UiHider();

	private bool _uiHiddenByFreeCam;

	private readonly ColliderSwitch _collider = new ColliderSwitch();

	private static string _toast;

	private static float _toastUntil;

	private float _hintUntil;

	private GUIStyle _hintStyle;

	private static string _lastError;

	internal static Plugin Instance { get; private set; }

	internal static ManualLogSource Log { get; private set; }

	private void Awake()
	{
		//IL_001d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0027: Expected O, but got Unknown
		//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
		Instance = this;
		Log = ((BaseUnityPlugin)this).Logger;
		BindConfig();
		_harmony = new Harmony("ontogether.cameraunlock");
		TryPatch(typeof(SetCameraRotationPatch), "camera tilt");
		TryPatch(typeof(ZoomPatch), "camera zoom");
		TryPatch(typeof(InputManagerUpdatePatch), "input blocking for the free camera");
		OrbitEnabled.SettingChanged += delegate
		{
			if (!OrbitEnabled.Value)
			{
				OrbitCamera.Disengage();
			}
		};
		Log.LogInfo((object)string.Format("{0} {1} loaded. Free camera: {2}, hide UI: {3}", "CameraUnlock", "1.0.1", FreeCamToggleKey.Value, HideUiKey.Value));
	}

	private void BindConfig()
	{
		//IL_0050: Unknown result type (might be due to invalid IL or missing references)
		//IL_005a: Expected O, but got Unknown
		//IL_008e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0098: Expected O, but got Unknown
		//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d6: Expected O, but got Unknown
		//IL_010a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0114: Expected O, but got Unknown
		//IL_0148: Unknown result type (might be due to invalid IL or missing references)
		//IL_0152: Expected O, but got Unknown
		//IL_0186: Unknown result type (might be due to invalid IL or missing references)
		//IL_0190: Expected O, but got Unknown
		//IL_01e5: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ef: Expected O, but got Unknown
		//IL_0230: Unknown result type (might be due to invalid IL or missing references)
		//IL_0273: Unknown result type (might be due to invalid IL or missing references)
		//IL_027d: Expected O, but got Unknown
		//IL_02b1: Unknown result type (might be due to invalid IL or missing references)
		//IL_02bb: Expected O, but got Unknown
		//IL_02ef: Unknown result type (might be due to invalid IL or missing references)
		//IL_02f9: Expected O, but got Unknown
		//IL_032d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0337: Expected O, but got Unknown
		//IL_038c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0396: Expected O, but got Unknown
		//IL_04ed: Unknown result type (might be due to invalid IL or missing references)
		OrbitEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Orbit", "Enabled", true, "Replace the game's short zoom and tilt range with a free orbit around your character (mouse wheel = distance, right mouse button = tilt). Off: the game's own camera.");
		MinDistance = ((BaseUnityPlugin)this).Config.Bind<float>("Orbit", "MinDistance", 0.4f, new ConfigDescription("Closest camera distance in metres (the game: about 2.3).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 5f), Array.Empty<object>()));
		MaxDistance = ((BaseUnityPlugin)this).Config.Bind<float>("Orbit", "MaxDistance", 40f, new ConfigDescription("Farthest camera distance in metres (the game: about 4.3).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(3f, 300f), Array.Empty<object>()));
		MinPitch = ((BaseUnityPlugin)this).Config.Bind<float>("Orbit", "MinPitch", -75f, new ConfigDescription("Lowest camera angle in degrees; negative looks up at your character from below.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-89f, 0f), Array.Empty<object>()));
		MaxPitch = ((BaseUnityPlugin)this).Config.Bind<float>("Orbit", "MaxPitch", 89f, new ConfigDescription("Highest camera angle in degrees; 89 is a straight top-down view.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 89f), Array.Empty<object>()));
		ZoomStep = ((BaseUnityPlugin)this).Config.Bind<float>("Orbit", "ZoomStepPercent", 12f, new ConfigDescription("How much one wheel notch changes the distance, in percent.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(2f, 50f), Array.Empty<object>()));
		PitchSensitivity = ((BaseUnityPlugin)this).Config.Bind<float>("Orbit", "TiltSensitivity", 1f, new ConfigDescription("Multiplier for vertical mouse movement (1 = like the game near the horizon).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 5f), Array.Empty<object>()));
		CameraCollision = ((BaseUnityPlugin)this).Config.Bind<bool>("Orbit", "CameraCollision", true, "Keep the camera in front of walls and the ground, as the game does. Turn off to see through walls.");
		FieldOfView = ((BaseUnityPlugin)this).Config.Bind<float>("Lens", "FieldOfView", 0f, new ConfigDescription("Vertical field of view of the normal camera in degrees; 0 = the game's default.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 120f), Array.Empty<object>()));
		ShiftScrollFov = ((BaseUnityPlugin)this).Config.Bind<bool>("Lens", "ShiftWheelChangesFov", true, "Shift + mouse wheel changes the field of view (both cameras); Shift + middle click resets it.");
		FreeCamToggleKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("FreeCamera", "ToggleKey", new KeyboardShortcut((KeyCode)287, Array.Empty<KeyCode>()), "Turns the free camera on/off (ignored while typing). Your character stays in place.");
		FreeCamSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("FreeCamera", "Speed", 4f, new ConfigDescription("Flying speed in metres per second (the mouse wheel scales it while flying).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 100f), Array.Empty<object>()));
		FreeCamFastMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("FreeCamera", "FastMultiplier", 4f, new ConfigDescription("Speed multiplier while the Fast key is held.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 50f), Array.Empty<object>()));
		FreeCamSlowMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("FreeCamera", "SlowMultiplier", 0.25f, new ConfigDescription("Speed multiplier while the Slow key is held.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.01f, 1f), Array.Empty<object>()));
		FreeCamLookSensitivity = ((BaseUnityPlugin)this).Config.Bind<float>("FreeCamera", "LookSensitivity", 2f, new ConfigDescription("Mouse look sensitivity.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 20f), Array.Empty<object>()));
		FreeCamInvertY = ((BaseUnityPlugin)this).Config.Bind<bool>("FreeCamera", "InvertY", false, "Invert vertical mouse look.");
		FreeCamSmoothing = ((BaseUnityPlugin)this).Config.Bind<float>("FreeCamera", "Smoothing", 0f, new ConfigDescription("Smooth, cinematic movement: 0 = none, 0.9 = very smooth.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 0.98f), Array.Empty<object>()));
		HideUiInFreeCam = ((BaseUnityPlugin)this).Config.Bind<bool>("FreeCamera", "HideUiWhileFlying", false, "Hide the interface automatically while the free camera is on.");
		FreeCamForward = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("FreeCamera.Keys", "Forward", (KeyCode)119, "Fly forward.");
		FreeCamBack = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("FreeCamera.Keys", "Back", (KeyCode)115, "Fly back.");
		FreeCamLeft = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("FreeCamera.Keys", "Left", (KeyCode)97, "Fly left.");
		FreeCamRight = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("FreeCamera.Keys", "Right", (KeyCode)100, "Fly right.");
		FreeCamUp = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("FreeCamera.Keys", "Up", (KeyCode)101, "Fly straight up.");
		FreeCamDown = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("FreeCamera.Keys", "Down", (KeyCode)113, "Fly straight down.");
		FreeCamFast = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("FreeCamera.Keys", "Fast", (KeyCode)304, "Hold to fly faster.");
		FreeCamSlow = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("FreeCamera.Keys", "Slow", (KeyCode)306, "Hold to fly slower.");
		HideUiKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Screenshots", "HideUiKey", new KeyboardShortcut((KeyCode)288, Array.Empty<KeyCode>()), "Hides/shows the game's interface (ignored while typing).");
		HideWorldSpaceUi = ((BaseUnityPlugin)this).Config.Bind<bool>("Screenshots", "HideWorldSpaceUi", false, "Also hide interface elements placed in the world (signs, screens and labels drawn with canvases).");
		ShowHints = ((BaseUnityPlugin)this).Config.Bind<bool>("Screenshots", "ShowHints", true, "Show short on-screen hints (controls, field of view, speed). Never drawn while the interface is hidden.");
	}

	private void TryPatch(Type patch, string feature)
	{
		try
		{
			_harmony.CreateClassProcessor(patch).Patch();
		}
		catch (Exception arg)
		{
			Log.LogError((object)$"Could not patch the game for {feature}; that part will not work: {arg}");
		}
	}

	private void Update()
	{
		//IL_000e: 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)
		if (GameAccess.IsAnyTextFieldFocused())
		{
			return;
		}
		ReadShortcuts(FreeCamToggleKey.Value, HideUiKey.Value, out var firstPressed, out var secondPressed);
		if (firstPressed)
		{
			ToggleFreeCamera();
		}
		if (secondPressed)
		{
			if (_uiHider.IsHidden)
			{
				_uiHider.Show();
			}
			else
			{
				_uiHider.Hide();
			}
			_uiHiddenByFreeCam = false;
		}
		if (ShiftScrollFov.Value && Input.GetMouseButtonDown(2) && (Input.GetKey((KeyCode)304) || Input.GetKey((KeyCode)303)))
		{
			if (FreeCamera.IsActive)
			{
				_freeCamera.ResetFov();
			}
			else
			{
				Lens.Reset();
			}
		}
	}

	private static void ReadShortcuts(KeyboardShortcut first, KeyboardShortcut second, out bool firstPressed, out bool secondPressed)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0009: Unknown result type (might be due to invalid IL or missing references)
		//IL_001a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0021: Unknown result type (might be due to invalid IL or missing references)
		firstPressed = Pressed(first);
		secondPressed = Pressed(second);
		if (firstPressed && secondPressed && ((KeyboardShortcut)(ref first)).MainKey == ((KeyboardShortcut)(ref second)).MainKey)
		{
			int num = ((KeyboardShortcut)(ref first)).Modifiers.Count() - ((KeyboardShortcut)(ref second)).Modifiers.Count();
			firstPressed = num >= 0;
			secondPressed = num <= 0;
		}
	}

	private static bool Pressed(KeyboardShortcut shortcut)
	{
		//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_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_0025: Unknown result type (might be due to invalid IL or missing references)
		KeyCode mainKey = ((KeyboardShortcut)(ref shortcut)).MainKey;
		if ((int)mainKey == 0 || !Input.GetKeyDown(mainKey))
		{
			return false;
		}
		foreach (KeyCode modifier in ((KeyboardShortcut)(ref shortcut)).Modifiers)
		{
			if (!Input.GetKey(modifier))
			{
				return false;
			}
		}
		return true;
	}

	private void LateUpdate()
	{
		try
		{
			if (!_freeCamera.LateTick())
			{
				OnFreeCameraEnded("Free camera: off (the camera changed)");
			}
			Lens.Tick(OrbitCamera.Vcam);
			_collider.Apply(OrbitCamera.Vcam, CameraCollision.Value);
			_uiHider.Tick();
		}
		catch (Exception e)
		{
			LogOnce(e);
		}
	}

	internal static void LogOnce(Exception e)
	{
		string text = e.GetType().Name + ": " + e.Message;
		if (!(text == _lastError))
		{
			_lastError = text;
			Log.LogError((object)e);
		}
	}

	private void ToggleFreeCamera()
	{
		if (FreeCamera.IsActive)
		{
			_freeCamera.Exit();
			OnFreeCameraEnded("Free camera: off");
			return;
		}
		if (!_freeCamera.TryEnter(out var error))
		{
			Toast("Free camera: " + error);
			return;
		}
		if (HideUiInFreeCam.Value && !_uiHider.IsHidden)
		{
			_uiHider.Hide();
			_uiHiddenByFreeCam = true;
		}
		_hintUntil = Time.unscaledTime + 7f;
		_toastUntil = 0f;
	}

	private void OnFreeCameraEnded(string message)
	{
		if (_uiHiddenByFreeCam)
		{
			_uiHider.Show();
		}
		_uiHiddenByFreeCam = false;
		_hintUntil = 0f;
		Toast(message);
	}

	internal static void Toast(string message)
	{
		_toast = message;
		_toastUntil = Time.unscaledTime + 2f;
	}

	private string FreeCamHint()
	{
		//IL_0013: Unknown result type (might be due to invalid IL or missing references)
		//IL_0026: Unknown result type (might be due to invalid IL or missing references)
		//IL_0039: Unknown result type (might be due to invalid IL or missing references)
		//IL_004c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0067: Unknown result type (might be due to invalid IL or missing references)
		//IL_0077: 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_00a1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
		return $"Free camera — {FreeCamForward.Value}/{FreeCamLeft.Value}/{FreeCamBack.Value}/{FreeCamRight.Value} fly, " + $"{FreeCamUp.Value}/{FreeCamDown.Value} up/down, hold right mouse to look, " + $"{FreeCamFast.Value} fast, {FreeCamSlow.Value} slow, wheel = speed, Shift + wheel = zoom (FOV), " + $"{HideUiKey.Value} hide UI, {FreeCamToggleKey.Value} back to the character";
	}

	private void OnGUI()
	{
		//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
		//IL_0101: Expected O, but got Unknown
		//IL_0121: Unknown result type (might be due to invalid IL or missing references)
		//IL_012c: Expected O, but got Unknown
		//IL_0146: 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_006b: 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_007e: Expected O, but got Unknown
		//IL_0089: Unknown result type (might be due to invalid IL or missing references)
		if (!ShowHints.Value || _uiHider.IsHidden)
		{
			return;
		}
		float unscaledTime = Time.unscaledTime;
		string text = ((unscaledTime < _toastUntil) ? _toast : ((unscaledTime < _hintUntil) ? FreeCamHint() : null));
		if (!string.IsNullOrEmpty(text))
		{
			if (_hintStyle == null)
			{
				_hintStyle = new GUIStyle(GUI.skin.box)
				{
					alignment = (TextAnchor)4,
					wordWrap = true,
					richText = false
				};
				_hintStyle.normal.textColor = Color.white;
			}
			float num = Mathf.Max(1f, (float)Screen.height / 1080f);
			_hintStyle.fontSize = Mathf.RoundToInt(16f * num);
			_hintStyle.padding = new RectOffset(Mathf.RoundToInt(12f * num), Mathf.RoundToInt(12f * num), Mathf.RoundToInt(8f * num), Mathf.RoundToInt(8f * num));
			float num2 = Mathf.Min((float)Screen.width - 32f, 900f * num);
			float num3 = _hintStyle.CalcHeight(new GUIContent(text), num2);
			GUI.Box(new Rect(((float)Screen.width - num2) / 2f, 24f * num, num2, num3), text, _hintStyle);
		}
	}

	private void OnDestroy()
	{
		try
		{
			_freeCamera.Exit();
			_uiHider.Show();
			OrbitCamera.Disengage();
			Lens.Restore();
			_collider.Restore();
		}
		catch (Exception ex)
		{
			Log.LogDebug((object)("Cleanup skipped: " + ex.Message));
		}
		if (_harmony != null)
		{
			_harmony.UnpatchSelf();
		}
	}
}
internal sealed class ColliderSwitch
{
	private CinemachineCollider _collider;

	private bool _gameEnabled;

	public void Apply(CinemachineVirtualCamera vcam, bool enabled)
	{
		if ((Object)(object)vcam == (Object)null)
		{
			return;
		}
		if ((Object)(object)_collider == (Object)null || (Object)(object)((Component)_collider).gameObject != (Object)(object)((Component)vcam).gameObject)
		{
			_collider = ((Component)vcam).GetComponent<CinemachineCollider>();
			if ((Object)(object)_collider == (Object)null)
			{
				return;
			}
			_gameEnabled = ((Behaviour)_collider).enabled;
		}
		bool flag = enabled && _gameEnabled;
		if (((Behaviour)_collider).enabled != flag)
		{
			((Behaviour)_collider).enabled = flag;
		}
	}

	public void Restore()
	{
		if ((Object)(object)_collider != (Object)null)
		{
			((Behaviour)_collider).enabled = _gameEnabled;
		}
	}
}
[HarmonyPatch(typeof(PlayerMovementController), "SetCameraRotation")]
internal static class SetCameraRotationPatch
{
	private static void Prefix(PlayerMovementController __instance, Vector2 mouseDelta)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			OrbitCamera.BeforeRotation(__instance, mouseDelta);
		}
		catch (Exception e)
		{
			Plugin.LogOnce(e);
		}
	}

	private static void Postfix(PlayerMovementController __instance)
	{
		try
		{
			OrbitCamera.Apply(__instance);
		}
		catch (Exception e)
		{
			Plugin.LogOnce(e);
		}
	}
}
[HarmonyPatch(typeof(PlayerMovementController), "Zoom")]
internal static class ZoomPatch
{
	private static bool Prefix(PlayerMovementController __instance)
	{
		if (FreeCamera.IsActive)
		{
			return false;
		}
		try
		{
			OrbitCamera.OnZoom(__instance);
		}
		catch (Exception e)
		{
			Plugin.LogOnce(e);
		}
		return true;
	}

	private static void Postfix(PlayerMovementController __instance)
	{
		try
		{
			OrbitCamera.Apply(__instance);
		}
		catch (Exception e)
		{
			Plugin.LogOnce(e);
		}
	}
}
[HarmonyPatch(typeof(InputManager), "Update")]
internal static class InputManagerUpdatePatch
{
	private static void Postfix(InputManager __instance)
	{
		try
		{
			InputBlocker.AfterInputUpdate(__instance);
		}
		catch (Exception e)
		{
			Plugin.LogOnce(e);
		}
	}
}
internal sealed class UiHider
{
	private const float RescanInterval = 0.5f;

	private readonly List<Behaviour> _disabled = new List<Behaviour>();

	private float _nextScan;

	public bool IsHidden { get; private set; }

	public void Hide()
	{
		if (!IsHidden)
		{
			IsHidden = true;
			Scan();
		}
	}

	public void Show()
	{
		if (!IsHidden)
		{
			return;
		}
		IsHidden = false;
		foreach (Behaviour item in _disabled)
		{
			if ((Object)(object)item != (Object)null)
			{
				item.enabled = true;
			}
		}
		_disabled.Clear();
	}

	public void Tick()
	{
		if (IsHidden && Time.unscaledTime >= _nextScan)
		{
			Scan();
		}
	}

	private void Scan()
	{
		//IL_0041: Unknown result type (might be due to invalid IL or missing references)
		//IL_0047: Invalid comparison between Unknown and I4
		_nextScan = Time.unscaledTime + 0.5f;
		bool value = Plugin.Instance.HideWorldSpaceUi.Value;
		Canvas[] array = Object.FindObjectsByType<Canvas>((FindObjectsSortMode)0);
		foreach (Canvas val in array)
		{
			if (!((Behaviour)val).enabled || !val.isRootCanvas || ((int)val.renderMode == 2 && !value))
			{
				continue;
			}
			((Behaviour)val).enabled = false;
			_disabled.Add((Behaviour)(object)val);
			BaseRaycaster[] components = ((Component)val).GetComponents<BaseRaycaster>();
			foreach (BaseRaycaster val2 in components)
			{
				if (((Behaviour)val2).enabled)
				{
					((Behaviour)val2).enabled = false;
					_disabled.Add((Behaviour)(object)val2);
				}
			}
		}
	}
}