Decompiled source of ReLegend 3rd Person v0.3.1

ReLegendThirdPerson.dll

Decompiled a month ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using Cinemachine;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = ".NET Standard 2.0")]
[assembly: AssemblyCompany("ReLegendThirdPerson")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.3.1.0")]
[assembly: AssemblyInformationalVersion("0.3.1")]
[assembly: AssemblyProduct("ReLegendThirdPerson")]
[assembly: AssemblyTitle("ReLegendThirdPerson")]
[assembly: AssemblyVersion("0.3.1.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[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 ReLegendThirdPerson
{
	[HarmonyPatch]
	internal static class CameraPatches
	{
		[HarmonyPatch(typeof(MinimapCamera), "Update")]
		[HarmonyPostfix]
		private static void MinimapCamera_Update_Postfix()
		{
			if (ThirdPersonRig.Active && Plugin.Enabled.Value)
			{
				MinimapCamera.yRot = 0f;
			}
		}
	}
	internal static class DepthOfFieldControl
	{
		private static float _lastApplied = float.NaN;

		private static bool _lastEnabled;

		private static bool _warned;

		internal static void Tick()
		{
			try
			{
				CameraManager instance = CameraManager.instance;
				if ((Object)(object)instance == (Object)null)
				{
					return;
				}
				bool value = Plugin.DofEnabled.Value;
				Behaviour val = Reflect.Get<Behaviour>(typeof(CameraManager), "depthOfField", instance);
				if ((Object)(object)val == (Object)null)
				{
					if (!_warned)
					{
						_warned = true;
						Plugin.Log.LogWarning((object)"No depth-of-field effect on CameraManager; DOF control is inert.");
					}
					return;
				}
				if (val.enabled != value)
				{
					val.enabled = value;
					_lastEnabled = value;
					_lastApplied = float.NaN;
				}
				if (value)
				{
					float num = Mathf.Clamp01(Plugin.DofIntensity.Value);
					float num2 = (Plugin.DofAutoFocus.Value ? Mathf.Max(0.1f, Plugin.Distance.Value) : Plugin.DofFocalLength.Value);
					float value2 = Plugin.DofFocalSize.Value;
					float num3 = num * Mathf.Max(0f, Plugin.DofMaxAperture.Value);
					float num4 = num2 * 1000f + value2 * 100f + num3;
					if (float.IsNaN(_lastApplied) || !Mathf.Approximately(num4, _lastApplied))
					{
						_lastApplied = num4;
						instance.SetDoF(num2, value2, num3);
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Depth-of-field update failed: " + ex));
			}
		}

		internal static void Reset()
		{
			_lastApplied = float.NaN;
			_lastEnabled = false;
		}
	}
	[HarmonyPatch]
	internal static class FacingPatches
	{
		[HarmonyPatch(typeof(MovementPlayer), "MovementDirection")]
		[HarmonyPostfix]
		private static void MovementDirection_Postfix(MovementPlayer __instance)
		{
			if (!Plugin.Enabled.Value || !Plugin.FacingFollowsInput.Value || !ThirdPersonRig.Active || (Plugin.FacingFreezeWhileOrbiting.Value && Plugin.RequireRightMouse.Value && Input.GetMouseButton(1)))
			{
				return;
			}
			try
			{
				Apply(__instance);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Facing update failed: " + ex));
			}
		}

		private static void Apply(MovementPlayer move)
		{
			//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_0058: 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_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			Vector3 moveDirection = move._moveDirection;
			moveDirection.y = 0f;
			if (!(((Vector3)(ref moveDirection)).sqrMagnitude < 0.0001f))
			{
				PlayerHandler val = (((Object)(object)GameManager.instance != (Object)null) ? GameManager.instance.player : null);
				if (!((Object)(object)val == (Object)null) && ShouldTurn(val))
				{
					Transform transform = ((Component)val).transform;
					Quaternion val2 = Quaternion.LookRotation(((Vector3)(ref moveDirection)).normalized);
					float num = Mathf.Max(1f, Plugin.FacingTurnSpeed.Value) * Time.deltaTime;
					transform.rotation = Quaternion.RotateTowards(transform.rotation, val2, num);
				}
			}
		}

		private static bool ShouldTurn(PlayerHandler hero)
		{
			try
			{
				AttackPlayer attack = hero.Attack;
				if ((Object)(object)attack != (Object)null)
				{
					if (attack.isAttacking)
					{
						return false;
					}
					if (Reflect.Get<bool>(typeof(AttackPlayer), "isMining", attack))
					{
						return false;
					}
					if (Reflect.Get<bool>(typeof(AttackPlayer), "isRolling", attack))
					{
						return false;
					}
				}
				FarmActionPlayer farmAction = hero.farmAction;
				if ((Object)(object)farmAction != (Object)null && (farmAction.IsWatering || farmAction.IsHoe))
				{
					return false;
				}
				MovementPlayer movement = hero.Movement;
				if ((Object)(object)movement != (Object)null && movement.isSwim)
				{
					return false;
				}
				TamingPlayer taming = hero.Taming;
				if ((Object)(object)taming != (Object)null && taming.isMounted)
				{
					return false;
				}
			}
			catch
			{
				return false;
			}
			return true;
		}
	}
	[BepInPlugin("com.community.relegend.thirdperson", "Re:Legend Third Person", "0.3.1")]
	public class Plugin : BaseUnityPlugin
	{
		public const string GUID = "com.community.relegend.thirdperson";

		public const string NAME = "Re:Legend Third Person";

		public const string VERSION = "0.3.1";

		internal static ManualLogSource Log;

		internal static Plugin Instance;

		private Harmony _harmony;

		internal static ConfigEntry<bool> Enabled;

		internal static ConfigEntry<KeyboardShortcut> ToggleKey;

		internal static ConfigEntry<float> ShoulderOffset;

		internal static ConfigEntry<float> ShoulderHeight;

		internal static ConfigEntry<float> Distance;

		internal static ConfigEntry<float> DistanceMin;

		internal static ConfigEntry<float> DistanceMax;

		internal static ConfigEntry<float> ZoomStep;

		internal static ConfigEntry<float> Pitch;

		internal static ConfigEntry<float> PitchMin;

		internal static ConfigEntry<float> PitchMax;

		internal static ConfigEntry<float> Fov;

		internal static ConfigEntry<bool> ZoomIgnoreCtrl;

		internal static ConfigEntry<float> SensitivityX;

		internal static ConfigEntry<float> SensitivityY;

		internal static ConfigEntry<bool> InvertY;

		internal static ConfigEntry<bool> RequireRightMouse;

		internal static ConfigEntry<bool> FacingFollowsInput;

		internal static ConfigEntry<float> FacingTurnSpeed;

		internal static ConfigEntry<bool> FacingFreezeWhileOrbiting;

		internal static ConfigEntry<bool> DofEnabled;

		internal static ConfigEntry<float> DofIntensity;

		internal static ConfigEntry<bool> DofAutoFocus;

		internal static ConfigEntry<float> DofFocalLength;

		internal static ConfigEntry<float> DofFocalSize;

		internal static ConfigEntry<float> DofMaxAperture;

		internal static ConfigEntry<bool> TargetingEnabled;

		internal static ConfigEntry<KeyboardShortcut> TargetNextKey;

		internal static ConfigEntry<KeyboardShortcut> TargetClearKey;

		internal static ConfigEntry<float> TargetMaxRange;

		internal static ConfigEntry<bool> TargetRequireOnScreen;

		internal static ConfigEntry<bool> TargetExcludeParty;

		internal static ConfigEntry<bool> TargetIncludeAllies;

		private void Awake()
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_041a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0445: Unknown result type (might be due to invalid IL or missing references)
			//IL_04a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_04ad: Expected O, but got Unknown
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Master switch. Turning this off hands the camera straight back to the game.");
			ToggleKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("General", "ToggleKey", new KeyboardShortcut((KeyCode)286, Array.Empty<KeyCode>()), "Switches between third person and the vanilla camera in-game.");
			ShoulderOffset = ((BaseUnityPlugin)this).Config.Bind<float>("Rig", "ShoulderOffset", 0.6f, "Sideways offset from the player. Positive is over the right shoulder,\nnegative the left, 0 is centred behind.");
			ShoulderHeight = ((BaseUnityPlugin)this).Config.Bind<float>("Rig", "ShoulderHeight", 1.6f, "Height of the look-at pivot above the player's feet, roughly head height.");
			Distance = ((BaseUnityPlugin)this).Config.Bind<float>("Rig", "Distance", 4.5f, "Current camera distance. Updated as you zoom.");
			DistanceMin = ((BaseUnityPlugin)this).Config.Bind<float>("Rig", "DistanceMin", 1.2f, "Closest zoom. Around 1.2 is close over-the-shoulder.");
			DistanceMax = ((BaseUnityPlugin)this).Config.Bind<float>("Rig", "DistanceMax", 18f, "Furthest zoom. Large values approach the vanilla pulled-back feel.");
			ZoomStep = ((BaseUnityPlugin)this).Config.Bind<float>("Rig", "ZoomStep", 1.1f, "Distance change per mouse-wheel notch.");
			Pitch = ((BaseUnityPlugin)this).Config.Bind<float>("Rig", "Pitch", 18f, "Starting downward pitch in degrees.");
			PitchMin = ((BaseUnityPlugin)this).Config.Bind<float>("Rig", "PitchMin", -25f, "Highest the camera can look up.");
			PitchMax = ((BaseUnityPlugin)this).Config.Bind<float>("Rig", "PitchMax", 70f, "Lowest the camera can look down. Steep values approach a top-down view.");
			Fov = ((BaseUnityPlugin)this).Config.Bind<float>("Rig", "FieldOfView", 55f, "Vertical field of view for the third-person camera.");
			ZoomIgnoreCtrl = ((BaseUnityPlugin)this).Config.Bind<bool>("Rig", "ZoomIgnoreCtrl", true, "Do not zoom while Ctrl is held. Ctrl + scroll cycles the tool belt in the QOL\npack, and both acting on the same input made scrolling do two things at once.");
			SensitivityX = ((BaseUnityPlugin)this).Config.Bind<float>("Look", "SensitivityX", 3.2f, "Horizontal look speed.");
			SensitivityY = ((BaseUnityPlugin)this).Config.Bind<float>("Look", "SensitivityY", 2.2f, "Vertical look speed.");
			InvertY = ((BaseUnityPlugin)this).Config.Bind<bool>("Look", "InvertY", false, "Invert vertical look.");
			RequireRightMouse = ((BaseUnityPlugin)this).Config.Bind<bool>("Look", "HoldRightMouseToRotate", true, "Rotate only while right mouse is held. Turning this off gives free look,\nwhich conflicts with cursor-driven aiming and menu clicks.");
			FacingFollowsInput = ((BaseUnityPlugin)this).Config.Bind<bool>("Facing", "FollowMovementInput", true, "Turn the character to face the movement keys, independently of the camera.\nCamera orbit on its own never changes facing; only pressing a direction does.");
			FacingTurnSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("Facing", "TurnSpeed", 720f, "Degrees per second. Vanilla lerps at rotateRate 3, which visibly lags behind\nthe keys once the camera can swing freely. Lower this for a heavier feel.");
			FacingFreezeWhileOrbiting = ((BaseUnityPlugin)this).Config.Bind<bool>("Facing", "FreezeWhileOrbiting", true, "While right mouse is held the camera orbits and the character keeps its\nfacing. Movement input is camera-relative, so without this holding a\ndirection key while orbiting drags the body around with the camera.");
			DofEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("DepthOfField", "Enabled", false, "Take over the game's depth-of-field effect. Off leaves the scene's own\nsettings completely untouched.");
			DofIntensity = ((BaseUnityPlugin)this).Config.Bind<float>("DepthOfField", "Intensity", 0.35f, "0 to 1. Scales the aperture, which is what controls how strongly the\nbackground blurs.");
			DofAutoFocus = ((BaseUnityPlugin)this).Config.Bind<bool>("DepthOfField", "AutoFocusPlayer", true, "Track focal length to the current camera distance so the character stays\nsharp as you zoom. Turn off to set the focal length by hand.");
			DofFocalLength = ((BaseUnityPlugin)this).Config.Bind<float>("DepthOfField", "FocalLength", 4.5f, "Manual focus distance, used only when AutoFocusPlayer is off.");
			DofFocalSize = ((BaseUnityPlugin)this).Config.Bind<float>("DepthOfField", "FocalSize", 0.05f, "Size of the in-focus band. Larger keeps more of the scene sharp.");
			DofMaxAperture = ((BaseUnityPlugin)this).Config.Bind<float>("DepthOfField", "MaxAperture", 2.5f, "Aperture at Intensity 1.0. Raise for a more extreme blur ceiling.");
			TargetingEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Targeting", "Enabled", false, "Tab targeting. Selection and camera framing only - it does not redirect\nattacks, because melee resolves through the game's own collider volumes and\nis sensitive to approach angle.\nTab steps nearest-first and then off the end back to no target, so the camera\ncannot end up permanently locked on.");
			TargetExcludeParty = ((BaseUnityPlugin)this).Config.Bind<bool>("Targeting", "ExcludePartyMagnus", true, "Never target the magnus in your party. It follows you everywhere and is\ntherefore almost always the nearest thing, which made it the default lock-on.");
			TargetIncludeAllies = ((BaseUnityPlugin)this).Config.Bind<bool>("Targeting", "IncludeAllies", false, "Include other tamed magnus in the cycle. Off by default so Tab finds enemies.");
			TargetNextKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Targeting", "NextTargetKey", new KeyboardShortcut((KeyCode)9, Array.Empty<KeyCode>()), "Cycle to the next valid target.");
			TargetClearKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Targeting", "ClearTargetKey", new KeyboardShortcut((KeyCode)27, Array.Empty<KeyCode>()), "Drop the current target.");
			TargetMaxRange = ((BaseUnityPlugin)this).Config.Bind<float>("Targeting", "MaxRange", 25f, "Maximum distance for a target to be selectable.");
			TargetRequireOnScreen = ((BaseUnityPlugin)this).Config.Bind<bool>("Targeting", "RequireOnScreen", true, "Only cycle through targets currently visible on screen.");
			_harmony = new Harmony("com.community.relegend.thirdperson");
			try
			{
				_harmony.PatchAll(typeof(CameraPatches));
				_harmony.PatchAll(typeof(FacingPatches));
				Log.LogInfo((object)("Re:Legend Third Person 0.3.1 loaded. BepInEx " + typeof(BaseUnityPlugin).Assembly.GetName().Version?.ToString() + ", Harmony " + typeof(Harmony).Assembly.GetName().Version?.ToString() + "."));
			}
			catch (Exception ex)
			{
				Log.LogError((object)("Patching failed, mod is inert: " + ex));
			}
		}

		private void OnDestroy()
		{
			ThirdPersonRig.Teardown();
			DepthOfFieldControl.Reset();
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}

		private void Update()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_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)
			try
			{
				KeyboardShortcut value = ToggleKey.Value;
				if ((int)((KeyboardShortcut)(ref value)).MainKey != 0)
				{
					value = ToggleKey.Value;
					if (((KeyboardShortcut)(ref value)).IsDown())
					{
						Enabled.Value = !Enabled.Value;
						SaveConfig();
						Log.LogInfo((object)("Third person " + (Enabled.Value ? "enabled." : "disabled.")));
					}
				}
				ThirdPersonRig.Tick();
				Targeting.Tick();
				DepthOfFieldControl.Tick();
			}
			catch (Exception ex)
			{
				Log.LogError((object)("Update failed: " + ex));
			}
		}

		internal static IEnumerable<KeyValuePair<string, ConfigEntry<bool>>> Features()
		{
			yield return new KeyValuePair<string, ConfigEntry<bool>>("Third person camera", Enabled);
			yield return new KeyValuePair<string, ConfigEntry<bool>>("Invert vertical look", InvertY);
			yield return new KeyValuePair<string, ConfigEntry<bool>>("Hold RMB to rotate", RequireRightMouse);
			yield return new KeyValuePair<string, ConfigEntry<bool>>("Facing follows movement", FacingFollowsInput);
			yield return new KeyValuePair<string, ConfigEntry<bool>>("Freeze facing while orbiting", FacingFreezeWhileOrbiting);
			yield return new KeyValuePair<string, ConfigEntry<bool>>("Depth of field", DofEnabled);
			yield return new KeyValuePair<string, ConfigEntry<bool>>("Tab targeting", TargetingEnabled);
		}

		internal static void SaveConfig()
		{
			try
			{
				((BaseUnityPlugin)Instance).Config.Save();
			}
			catch (Exception ex)
			{
				Log.LogError((object)("Could not save config: " + ex));
			}
		}
	}
	internal static class Reflect
	{
		private static readonly Dictionary<string, FieldInfo> Cache = new Dictionary<string, FieldInfo>();

		private static readonly HashSet<string> Reported = new HashSet<string>();

		private static FieldInfo Find(Type type, string name)
		{
			string text = type.FullName + "::" + name;
			if (Cache.TryGetValue(text, out var value))
			{
				return value;
			}
			value = AccessTools.Field(type, name);
			Cache[text] = value;
			if (value == null && Reported.Add(text))
			{
				Plugin.Log.LogError((object)("Field not found: " + text + ". The game may have been updated."));
			}
			return value;
		}

		internal static T Get<T>(Type type, string name, object instance)
		{
			FieldInfo fieldInfo = Find(type, name);
			if (fieldInfo == null)
			{
				return default(T);
			}
			try
			{
				object value = fieldInfo.GetValue(instance);
				return (value is T) ? ((T)value) : default(T);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Reading " + type.Name + "." + name + " failed: " + ex.Message));
				return default(T);
			}
		}

		internal static void Set(Type type, string name, object instance, object value)
		{
			FieldInfo fieldInfo = Find(type, name);
			if (fieldInfo == null)
			{
				return;
			}
			try
			{
				fieldInfo.SetValue(instance, value);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Writing " + type.Name + "." + name + " failed: " + ex.Message));
			}
		}

		internal static bool Invoke(Type type, string name, object instance)
		{
			MethodInfo methodInfo = AccessTools.Method(type, name, (Type[])null, (Type[])null);
			if (methodInfo == null)
			{
				Plugin.Log.LogError((object)("Method not found: " + type.FullName + "::" + name));
				return false;
			}
			try
			{
				methodInfo.Invoke(instance, null);
				return true;
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Invoking " + type.Name + "." + name + " failed: " + ex.Message));
				return false;
			}
		}
	}
	internal static class Targeting
	{
		private static readonly List<MonsterDamage> Candidates = new List<MonsterDamage>();

		private static int _index = -1;

		private static MonsterDamage _current;

		private static float _nextRefresh;

		internal static MonsterDamage Current => _current;

		internal static Transform CurrentTransform
		{
			get
			{
				if (!Plugin.TargetingEnabled.Value)
				{
					return null;
				}
				if ((Object)(object)_current == (Object)null)
				{
					return null;
				}
				return ((Component)_current).transform;
			}
		}

		internal static void Tick()
		{
			//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_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: 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_0032: 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_0062: Unknown result type (might be due to invalid IL or missing references)
			if (!Plugin.TargetingEnabled.Value)
			{
				Clear(log: false);
				return;
			}
			try
			{
				KeyboardShortcut value = Plugin.TargetClearKey.Value;
				if ((int)((KeyboardShortcut)(ref value)).MainKey != 0)
				{
					value = Plugin.TargetClearKey.Value;
					if (((KeyboardShortcut)(ref value)).IsDown())
					{
						Clear(log: true);
						return;
					}
				}
				value = Plugin.TargetNextKey.Value;
				if ((int)((KeyboardShortcut)(ref value)).MainKey != 0)
				{
					value = Plugin.TargetNextKey.Value;
					if (((KeyboardShortcut)(ref value)).IsDown())
					{
						Advance();
					}
				}
				if ((Object)(object)_current != (Object)null && !IsValid(_current))
				{
					Clear(log: true);
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Targeting failed: " + ex));
				Clear(log: false);
			}
		}

		private static void Advance()
		{
			Refresh(force: true);
			if (Candidates.Count == 0)
			{
				if ((Object)(object)_current != (Object)null)
				{
					Clear(log: true);
				}
				else
				{
					Plugin.Log.LogInfo((object)"No targets in range.");
				}
				return;
			}
			int num = (((Object)(object)_current != (Object)null) ? Candidates.IndexOf(_current) : (-1)) + 1;
			if (num >= Candidates.Count)
			{
				Clear(log: true);
				return;
			}
			_index = num;
			SetTarget(Candidates[num]);
			Plugin.Log.LogInfo((object)("Target " + (num + 1) + "/" + Candidates.Count + ": " + Describe(Candidates[num])));
		}

		private static void SetTarget(MonsterDamage target)
		{
			ShowIndicator(_current, show: false);
			_current = target;
			ShowIndicator(_current, show: true);
		}

		private static void Clear(bool log)
		{
			ShowIndicator(_current, show: false);
			_current = null;
			_index = -1;
			if (log)
			{
				Plugin.Log.LogInfo((object)"Target cleared.");
			}
		}

		private static void ShowIndicator(MonsterDamage target, bool show)
		{
			try
			{
				if (!((Object)(object)target == (Object)null))
				{
					MonsterHandler monster = target.Monster;
					if (!((Object)(object)monster == (Object)null))
					{
						monster.DisplayTarget(show);
					}
				}
			}
			catch
			{
			}
		}

		private static void Refresh(bool force)
		{
			//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)
			if (!force && Time.unscaledTime < _nextRefresh && Candidates.Count > 0)
			{
				return;
			}
			_nextRefresh = Time.unscaledTime + 0.5f;
			Candidates.Clear();
			PlayerHandler val = (((Object)(object)GameManager.instance != (Object)null) ? GameManager.instance.player : null);
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			MonsterDamage[] array = Object.FindObjectsOfType<MonsterDamage>();
			if (array == null)
			{
				return;
			}
			Vector3 origin = ((Component)val).transform.position;
			for (int i = 0; i < array.Length; i++)
			{
				if (IsValid(array[i]))
				{
					Candidates.Add(array[i]);
				}
			}
			Candidates.Sort(delegate(MonsterDamage a, MonsterDamage b)
			{
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				//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_0016: Unknown result type (might be due to invalid IL or missing references)
				//IL_0025: Unknown result type (might be due to invalid IL or missing references)
				//IL_002b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0030: Unknown result type (might be due to invalid IL or missing references)
				//IL_0035: Unknown result type (might be due to invalid IL or missing references)
				Vector3 val2 = ((Component)a).transform.position - origin;
				float sqrMagnitude = ((Vector3)(ref val2)).sqrMagnitude;
				val2 = ((Component)b).transform.position - origin;
				float sqrMagnitude2 = ((Vector3)(ref val2)).sqrMagnitude;
				return sqrMagnitude.CompareTo(sqrMagnitude2);
			});
		}

		private static bool IsValid(MonsterDamage m)
		{
			//IL_005b: 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_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)m == (Object)null)
			{
				return false;
			}
			if (m.deadMotionStart)
			{
				return false;
			}
			if (!((Component)m).gameObject.activeInHierarchy)
			{
				return false;
			}
			PlayerHandler val = (((Object)(object)GameManager.instance != (Object)null) ? GameManager.instance.player : null);
			if ((Object)(object)val == (Object)null)
			{
				return false;
			}
			if (IsExcludedMagnus(val, m))
			{
				return false;
			}
			Vector3 val2 = ((Component)m).transform.position - ((Component)val).transform.position;
			float value = Plugin.TargetMaxRange.Value;
			if (((Vector3)(ref val2)).sqrMagnitude > value * value)
			{
				return false;
			}
			if (Plugin.TargetRequireOnScreen.Value && !IsOnScreen(((Component)m).transform.position))
			{
				return false;
			}
			return true;
		}

		private static bool IsExcludedMagnus(PlayerHandler hero, MonsterDamage m)
		{
			try
			{
				MonsterHandler monster = m.Monster;
				if ((Object)(object)monster == (Object)null)
				{
					return false;
				}
				if (Plugin.TargetExcludeParty.Value && IsPartyMagnus(hero, monster))
				{
					return true;
				}
				if (!Plugin.TargetIncludeAllies.Value && monster.IsTamed())
				{
					return true;
				}
			}
			catch
			{
				return false;
			}
			return false;
		}

		private static bool IsPartyMagnus(PlayerHandler hero, MonsterHandler monster)
		{
			try
			{
				TamingPlayer taming = hero.Taming;
				if ((Object)(object)taming == (Object)null || taming.partyMonsterSlot < 0)
				{
					return false;
				}
				StatPlayer stat = hero.Stat;
				if ((Object)(object)stat == (Object)null || stat.currentPetStat == null)
				{
					return false;
				}
				if (taming.partyMonsterSlot >= stat.currentPetStat.Count)
				{
					return false;
				}
				MonsterHandler val = stat.currentPetStat[taming.partyMonsterSlot];
				if ((Object)(object)val == (Object)null)
				{
					return false;
				}
				return val == monster;
			}
			catch
			{
				return monster.IsTamed();
			}
		}

		private static string Describe(MonsterDamage m)
		{
			try
			{
				MonsterHandler monster = m.Monster;
				string text = (((Object)(object)monster != (Object)null && monster.IsTamed()) ? " (ally)" : "");
				return ((Object)((Component)m).gameObject).name + text;
			}
			catch
			{
				return "?";
			}
		}

		private static bool IsOnScreen(Vector3 worldPos)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: 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_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: 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)
			Camera main = Camera.main;
			if ((Object)(object)main == (Object)null)
			{
				return true;
			}
			Vector3 val = main.WorldToViewportPoint(worldPos);
			if (val.z > 0f && val.x >= 0f && val.x <= 1f && val.y >= 0f)
			{
				return val.y <= 1f;
			}
			return false;
		}
	}
	internal static class ThirdPersonRig
	{
		private const int ActivePriority = 5000;

		private const int IdlePriority = -100;

		private static GameObject _rigRoot;

		private static GameObject _vcamObject;

		private static CinemachineVirtualCamera _vcam;

		private static Transform _lookTarget;

		private static float _yaw;

		private static float _pitch;

		private static bool _initialised;

		private static bool _wasActive;

		internal static bool Active { get; private set; }

		internal static float Yaw => _yaw;

		internal static void Tick()
		{
			if (!Plugin.Enabled.Value || VanillaShouldOwnCamera())
			{
				if (_wasActive)
				{
					SetActive(active: false);
				}
				_wasActive = false;
				Active = false;
			}
			else if (EnsureRig())
			{
				if (!_wasActive)
				{
					SetActive(active: true);
					_wasActive = true;
					SeedFromPlayerFacing();
				}
				Active = true;
				ReadLookInput();
				ReadZoomInput();
				ApplyTransform();
			}
		}

		internal static void Teardown()
		{
			try
			{
				if ((Object)(object)_vcamObject != (Object)null)
				{
					Object.Destroy((Object)(object)_vcamObject);
				}
				if ((Object)(object)_rigRoot != (Object)null)
				{
					Object.Destroy((Object)(object)_rigRoot);
				}
			}
			catch
			{
			}
			_vcamObject = null;
			_rigRoot = null;
			_vcam = null;
			_lookTarget = null;
			_initialised = false;
			Active = false;
		}

		private static bool VanillaShouldOwnCamera()
		{
			try
			{
				GameManager instance = GameManager.instance;
				PlayerHandler val = (((Object)(object)instance != (Object)null) ? instance.player : null);
				if ((Object)(object)val == (Object)null)
				{
					return true;
				}
				if ((Object)(object)val.Taming != (Object)null && (val.Taming.tamingStarted || val.Taming.isMounted))
				{
					return true;
				}
				if ((Object)(object)val.Fishing != (Object)null && val.Fishing.GetFish())
				{
					return true;
				}
				if ((Object)(object)CustomCameraControl.instance == (Object)null)
				{
					return true;
				}
				CameraFollow val2 = Object.FindObjectOfType<CameraFollow>();
				if ((Object)(object)val2 != (Object)null && (val2.cameraTaming || val2.isShopping || val2.fishResult))
				{
					return true;
				}
			}
			catch
			{
				return true;
			}
			return false;
		}

		private static bool EnsureRig()
		{
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: 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_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Expected O, but got Unknown
			if (_initialised && (Object)(object)_vcam != (Object)null && (Object)(object)_rigRoot != (Object)null)
			{
				return true;
			}
			try
			{
				GameManager instance = GameManager.instance;
				if ((Object)(object)(((Object)(object)instance != (Object)null) ? instance.player : null) == (Object)null)
				{
					return false;
				}
				if ((Object)(object)_rigRoot == (Object)null)
				{
					_rigRoot = new GameObject("ReLegendThirdPerson_Pivot");
					Object.DontDestroyOnLoad((Object)(object)_rigRoot);
					GameObject val = new GameObject("LookTarget");
					val.transform.SetParent(_rigRoot.transform, false);
					_lookTarget = val.transform;
				}
				if ((Object)(object)_vcamObject == (Object)null)
				{
					_vcamObject = new GameObject("ReLegendThirdPerson_VCam");
					Object.DontDestroyOnLoad((Object)(object)_vcamObject);
					_vcam = _vcamObject.AddComponent<CinemachineVirtualCamera>();
					((CinemachineVirtualCameraBase)_vcam).Priority = -100;
					_vcam.m_Lens.FieldOfView = Plugin.Fov.Value;
					((CinemachineVirtualCameraBase)_vcam).Follow = null;
					((CinemachineVirtualCameraBase)_vcam).LookAt = null;
				}
				_initialised = true;
				Plugin.Log.LogInfo((object)"Third-person rig created.");
				return true;
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Could not create the third-person rig: " + ex));
				return false;
			}
		}

		private static void SetActive(bool active)
		{
			if (!((Object)(object)_vcam == (Object)null))
			{
				((CinemachineVirtualCameraBase)_vcam).Priority = (active ? 5000 : (-100));
				Plugin.Log.LogInfo((object)("Third-person camera " + (active ? "engaged" : "released") + "."));
			}
		}

		private static void SeedFromPlayerFacing()
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				PlayerHandler player = GameManager.instance.player;
				if (!((Object)(object)player == (Object)null))
				{
					_yaw = ((Component)player).transform.eulerAngles.y;
					_pitch = Plugin.Pitch.Value;
				}
			}
			catch
			{
			}
		}

		private static void ReadLookInput()
		{
			if (!Plugin.RequireRightMouse.Value || Input.GetMouseButton(1))
			{
				float num = Input.GetAxisRaw("Mouse X") * Plugin.SensitivityX.Value;
				float num2 = Input.GetAxisRaw("Mouse Y") * Plugin.SensitivityY.Value;
				if (Plugin.InvertY.Value)
				{
					num2 = 0f - num2;
				}
				_yaw += num;
				_pitch = Mathf.Clamp(_pitch - num2, Plugin.PitchMin.Value, Plugin.PitchMax.Value);
				if (_yaw > 360f)
				{
					_yaw -= 360f;
				}
				else if (_yaw < 0f)
				{
					_yaw += 360f;
				}
			}
		}

		private static void ReadZoomInput()
		{
			if (!Plugin.ZoomIgnoreCtrl.Value || (!Input.GetKey((KeyCode)306) && !Input.GetKey((KeyCode)305)))
			{
				float axisRaw = Input.GetAxisRaw("Mouse ScrollWheel");
				if (!Mathf.Approximately(axisRaw, 0f))
				{
					float num = Plugin.Distance.Value - axisRaw * Plugin.ZoomStep.Value * 10f;
					Plugin.Distance.Value = Mathf.Clamp(num, Plugin.DistanceMin.Value, Plugin.DistanceMax.Value);
				}
			}
		}

		private static void ApplyTransform()
		{
			//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_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: 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_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: 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)
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: 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_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: 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_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: 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_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_0126: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: 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_005c: 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_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			PlayerHandler player = GameManager.instance.player;
			if ((Object)(object)player == (Object)null || (Object)(object)_vcamObject == (Object)null)
			{
				return;
			}
			Vector3 val = ((Component)player).transform.position + Vector3.up * Plugin.ShoulderHeight.Value;
			Transform currentTransform = Targeting.CurrentTransform;
			if ((Object)(object)currentTransform != (Object)null)
			{
				Vector3 val2 = currentTransform.position - val;
				val2.y = 0f;
				if (((Vector3)(ref val2)).sqrMagnitude > 0.01f)
				{
					Quaternion val3 = Quaternion.LookRotation(((Vector3)(ref val2)).normalized);
					_yaw = ((Quaternion)(ref val3)).eulerAngles.y;
				}
			}
			Quaternion val4 = Quaternion.Euler(_pitch, _yaw, 0f);
			Vector3 val5 = val4 * Vector3.right;
			Vector3 val6 = val4 * Vector3.back;
			Vector3 val7 = val + val5 * Plugin.ShoulderOffset.Value;
			Vector3 val8 = val7 + val6 * Plugin.Distance.Value;
			_lookTarget.position = val7;
			_vcamObject.transform.position = val8;
			_vcamObject.transform.rotation = Quaternion.LookRotation(val7 - val8);
			if ((Object)(object)_vcam != (Object)null && !Mathf.Approximately(_vcam.m_Lens.FieldOfView, Plugin.Fov.Value))
			{
				_vcam.m_Lens.FieldOfView = Plugin.Fov.Value;
			}
		}
	}
}