Decompiled source of MagicBullet v1.2.3

HowToFishMagicBullet.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 FishNet.Connection;
using FishNet.Object;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;

[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("HowToFishMagicBullet")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+2f660ad313a00267b0a116e575897e1ec7022d25")]
[assembly: AssemblyProduct("HowToFishMagicBullet")]
[assembly: AssemblyTitle("HowToFishMagicBullet")]
[assembly: AssemblyVersion("1.0.0.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 HowToFishMagicBullet
{
	public static class Compatibility
	{
		private static MethodInfo _hitMethod;

		private static MethodInfo _hitWaterMethod;

		private static MethodInfo _addToRemoveQueueMethod;

		private static FieldInfo _playerProjectilesField;

		private static FieldInfo _catchUpSpeedField;

		private static FieldInfo _sqrMaxProjRangeField;

		public static bool IsInitialized { get; private set; }

		public static bool WallPenetrationSupported { get; private set; }

		public static void Initialize()
		{
			try
			{
				Type typeFromHandle = typeof(ProjectileManager);
				_hitMethod = AccessTools.Method(typeFromHandle, "Hit", new Type[3]
				{
					typeof(Projectile),
					typeof(ProjectileType),
					typeof(RaycastHit)
				}, (Type[])null);
				_hitWaterMethod = AccessTools.Method(typeFromHandle, "HitWater", new Type[1] { typeof(Projectile) }, (Type[])null);
				_addToRemoveQueueMethod = AccessTools.Method(typeFromHandle, "AddToRemoveQueue", new Type[1] { typeof(Projectile) }, (Type[])null);
				_playerProjectilesField = AccessTools.Field(typeFromHandle, "_playerProjectiles");
				_catchUpSpeedField = AccessTools.Field(typeFromHandle, "_catchUpSpeed");
				_sqrMaxProjRangeField = AccessTools.Field(typeFromHandle, "_sqrMaxProjRange");
				if (_hitMethod != null && _playerProjectilesField != null)
				{
					WallPenetrationSupported = true;
					DebugLogger.LogInfo("[Compatibility] ProjectileManager methods verified successfully. Wall Penetration is supported.");
				}
				else
				{
					WallPenetrationSupported = false;
					DebugLogger.LogWarning("[Compatibility] ProjectileManager expected members were not found. Wall Penetration disabled for safety.");
				}
				IsInitialized = true;
			}
			catch (Exception arg)
			{
				WallPenetrationSupported = false;
				DebugLogger.LogError($"[Compatibility] Validation failed with exception: {arg}");
			}
		}

		public static void DisableWallPenetration()
		{
			WallPenetrationSupported = false;
		}

		public static void CallHit(ProjectileManager pm, Projectile projectile, ProjectileType type, RaycastHit hit)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			if (_hitMethod != null && (Object)(object)pm != (Object)null)
			{
				_hitMethod.Invoke(pm, new object[3] { projectile, type, hit });
			}
		}

		public static void CallHitWater(ProjectileManager pm, Projectile projectile)
		{
			if (_hitWaterMethod != null && (Object)(object)pm != (Object)null)
			{
				_hitWaterMethod.Invoke(pm, new object[1] { projectile });
			}
		}

		public static void CallAddToRemoveQueue(ProjectileManager pm, Projectile projectile)
		{
			if (_addToRemoveQueueMethod != null && (Object)(object)pm != (Object)null)
			{
				_addToRemoveQueueMethod.Invoke(pm, new object[1] { projectile });
			}
		}

		public static float GetCatchUpSpeed(ProjectileManager pm)
		{
			if (_catchUpSpeedField != null && (Object)(object)pm != (Object)null)
			{
				return (float)_catchUpSpeedField.GetValue(pm);
			}
			return 0.1f;
		}

		public static float GetSqrMaxProjRange(ProjectileManager pm)
		{
			if (_sqrMaxProjRangeField != null && (Object)(object)pm != (Object)null)
			{
				return (float)_sqrMaxProjRangeField.GetValue(pm);
			}
			return 250000f;
		}

		public static Projectile FindSpawnedProjectile(ProjectileManager pm, Player owner, uint id)
		{
			if ((Object)(object)pm == (Object)null || (Object)(object)owner == (Object)null || _playerProjectilesField == null)
			{
				return null;
			}
			try
			{
				if (_playerProjectilesField.GetValue(pm) is Dictionary<NetworkConnection, Dictionary<uint, Projectile>> dictionary && ((NetworkBehaviour)owner).Owner != (NetworkConnection)null && dictionary.TryGetValue(((NetworkBehaviour)owner).Owner, out var value) && value.TryGetValue(id, out var value2))
				{
					return value2;
				}
			}
			catch (Exception ex)
			{
				Exception ex2 = ex;
				Exception ex3 = ex2;
				DebugLogger.Debug(() => "[Compatibility] FindSpawnedProjectile exception: " + ex3.Message);
			}
			return null;
		}
	}
	public static class DebugLogger
	{
		private static ManualLogSource _logger;

		public static void Initialize(ManualLogSource logger)
		{
			_logger = logger;
		}

		public static void LogInfo(string message)
		{
			ManualLogSource logger = _logger;
			if (logger != null)
			{
				logger.LogInfo((object)message);
			}
		}

		public static void LogWarning(string message)
		{
			ManualLogSource logger = _logger;
			if (logger != null)
			{
				logger.LogWarning((object)message);
			}
		}

		public static void LogError(string message)
		{
			ManualLogSource logger = _logger;
			if (logger != null)
			{
				logger.LogError((object)message);
			}
		}

		public static void Debug(string message)
		{
			if (ModConfig.DebugLogging != null && ModConfig.DebugLogging.Value)
			{
				ManualLogSource logger = _logger;
				if (logger != null)
				{
					logger.LogInfo((object)("[DEBUG] " + message));
				}
			}
		}

		public static void Debug(Func<string> messageFactory)
		{
			if (ModConfig.DebugLogging != null && ModConfig.DebugLogging.Value && messageFactory != null)
			{
				ManualLogSource logger = _logger;
				if (logger != null)
				{
					logger.LogInfo((object)("[DEBUG] " + messageFactory()));
				}
			}
		}
	}
	public static class FovRenderer
	{
		private static Texture2D _whiteTexture;

		private static Texture2D WhiteTexture
		{
			get
			{
				//IL_0011: Unknown result type (might be due to invalid IL or missing references)
				//IL_001b: Expected O, but got Unknown
				//IL_0022: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)_whiteTexture == (Object)null)
				{
					_whiteTexture = new Texture2D(1, 1, (TextureFormat)4, false);
					_whiteTexture.SetPixel(0, 0, Color.white);
					_whiteTexture.Apply();
				}
				return _whiteTexture;
			}
		}

		public static void Render()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Invalid comparison between Unknown and I4
			//IL_00bb: 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_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_011b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_0138: Unknown result type (might be due to invalid IL or missing references)
			//IL_0146: Unknown result type (might be due to invalid IL or missing references)
			//IL_0157: Unknown result type (might be due to invalid IL or missing references)
			//IL_0164: Unknown result type (might be due to invalid IL or missing references)
			//IL_0171: 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_0174: Unknown result type (might be due to invalid IL or missing references)
			if ((int)Event.current.type != 7 || ModConfig.Enabled == null || !ModConfig.Enabled.Value || !Object.op_Implicit((Object)(object)Player.LocalPlayer))
			{
				return;
			}
			Camera aimCamera = TargetManager.GetAimCamera();
			if (!Object.op_Implicit((Object)(object)aimCamera))
			{
				return;
			}
			Vector2 val = default(Vector2);
			((Vector2)(ref val))..ctor((float)Screen.width * 0.5f, (float)Screen.height * 0.5f);
			if (ModConfig.ShowFOVCircle == null || ModConfig.ShowFOVCircle.Value)
			{
				float num = Mathf.Clamp(ModConfig.FovDegrees.Value, 1f, 89f);
				float num2 = aimCamera.fieldOfView * 0.5f;
				float radius = Mathf.Tan(num * (MathF.PI / 180f)) / Mathf.Tan(num2 * (MathF.PI / 180f)) * ((float)Screen.height * 0.5f);
				DrawCircle(val, radius, Color.white, 2f);
			}
			if (ModConfig.ShowTargetLine != null && !ModConfig.ShowTargetLine.Value)
			{
				return;
			}
			Creature currentTarget = TargetManager.CurrentTarget;
			if (TargetManager.IsAllowedTarget(currentTarget))
			{
				Vector3 val2 = HeadResolver.ResolveAimPoint(currentTarget);
				Vector3 val3 = aimCamera.WorldToScreenPoint(val2);
				if (val3.z > 0f && val3.x >= 0f && val3.x <= (float)Screen.width && val3.y >= 0f && val3.y <= (float)Screen.height)
				{
					Vector2 pointB = default(Vector2);
					((Vector2)(ref pointB))..ctor(val3.x, (float)Screen.height - val3.y);
					DrawLine(val, pointB, Color.white, 2f);
				}
			}
		}

		public static void DrawLine(Vector2 pointA, Vector2 pointB, Color color, float width)
		{
			//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_0019: 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_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: 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_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: 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)
			Vector2 val = pointB - pointA;
			float magnitude = ((Vector2)(ref val)).magnitude;
			if (!(magnitude < 0.001f))
			{
				float num = Mathf.Atan2(val.y, val.x) * 57.29578f;
				Color color2 = GUI.color;
				Matrix4x4 matrix = GUI.matrix;
				GUI.color = color;
				GUIUtility.RotateAroundPivot(num, pointA);
				GUI.DrawTexture(new Rect(pointA.x, pointA.y - width * 0.5f, magnitude, width), (Texture)(object)WhiteTexture);
				GUI.matrix = matrix;
				GUI.color = color2;
			}
		}

		public static void DrawCircle(Vector2 center, float radius, Color color, float width, int segments = 128)
		{
			//IL_0018: 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_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: 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_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: 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_0057: 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_0060: 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 (!(radius <= 0.001f) && segments >= 3)
			{
				float num = 360f / (float)segments;
				Vector2 pointA = center + new Vector2(radius, 0f);
				for (int i = 1; i <= segments; i++)
				{
					float num2 = (float)i * num * (MathF.PI / 180f);
					Vector2 val = center + new Vector2(Mathf.Cos(num2) * radius, Mathf.Sin(num2) * radius);
					DrawLine(pointA, val, color, width);
					pointA = val;
				}
			}
		}
	}
	public enum HeadPointSource
	{
		HeadTransform,
		HeadPos,
		HeadCollider,
		CenterOfMass,
		TransformFallback
	}
	public static class HeadResolver
	{
		private static readonly Dictionary<int, Transform> _headTransformCache = new Dictionary<int, Transform>();

		public static bool TryGetAimPoint(Creature target, out Vector3 aimPoint, out HeadPointSource source)
		{
			//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_0069: 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_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: 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_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c2: 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_0196: Unknown result type (might be due to invalid IL or missing references)
			//IL_019a: Unknown result type (might be due to invalid IL or missing references)
			//IL_019f: Unknown result type (might be due to invalid IL or missing references)
			//IL_014a: Unknown result type (might be due to invalid IL or missing references)
			//IL_014f: 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_0158: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: Unknown result type (might be due to invalid IL or missing references)
			//IL_015f: Unknown result type (might be due to invalid IL or missing references)
			//IL_016a: Unknown result type (might be due to invalid IL or missing references)
			aimPoint = Vector3.zero;
			source = HeadPointSource.TransformFallback;
			if (!Object.op_Implicit((Object)(object)target))
			{
				return false;
			}
			int instanceID = ((Object)target).GetInstanceID();
			if (_headTransformCache.TryGetValue(instanceID, out var value) && Object.op_Implicit((Object)(object)value))
			{
				aimPoint = value.position;
				source = HeadPointSource.HeadTransform;
				return true;
			}
			Transform val = FindHeadTransform(((Component)target).transform);
			if (Object.op_Implicit((Object)(object)val))
			{
				_headTransformCache[instanceID] = val;
				aimPoint = val.position;
				source = HeadPointSource.HeadTransform;
				return true;
			}
			if (Mathf.Abs(target.HeadPos) > 0.001f || target is Fish || target is Bird || target is Albatross)
			{
				Vector3 val2 = Vector3.zero;
				if (Object.op_Implicit((Object)(object)((Item)target).Rig))
				{
					val2 = ((Component)target).transform.InverseTransformPoint(((Item)target).Rig.worldCenterOfMass);
				}
				Vector3 val3 = default(Vector3);
				((Vector3)(ref val3))..ctor(val2.x, val2.y, target.HeadPos + 0.15f);
				aimPoint = ((Component)target).transform.TransformPoint(val3);
				source = HeadPointSource.HeadPos;
				return true;
			}
			Collider[] componentsInChildren = ((Component)target).GetComponentsInChildren<Collider>();
			if (componentsInChildren != null && componentsInChildren.Length != 0)
			{
				Collider val4 = null;
				float num = float.MinValue;
				Bounds bounds;
				foreach (Collider val5 in componentsInChildren)
				{
					if (Object.op_Implicit((Object)(object)val5) && val5.enabled)
					{
						Transform transform = ((Component)target).transform;
						bounds = val5.bounds;
						Vector3 val6 = transform.InverseTransformPoint(((Bounds)(ref bounds)).center);
						if (val6.z > num)
						{
							num = val6.z;
							val4 = val5;
						}
					}
				}
				if ((Object)(object)val4 != (Object)null)
				{
					bounds = val4.bounds;
					aimPoint = ((Bounds)(ref bounds)).center;
					source = HeadPointSource.HeadCollider;
					return true;
				}
			}
			if (Object.op_Implicit((Object)(object)((Item)target).Rig))
			{
				aimPoint = ((Item)target).Rig.worldCenterOfMass;
				source = HeadPointSource.CenterOfMass;
				return true;
			}
			aimPoint = ((Component)target).transform.position;
			source = HeadPointSource.TransformFallback;
			return true;
		}

		public static Vector3 ResolveAimPoint(Creature target)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			TryGetAimPoint(target, out var aimPoint, out var _);
			return aimPoint;
		}

		private static Transform FindHeadTransform(Transform root)
		{
			if (!Object.op_Implicit((Object)(object)root))
			{
				return null;
			}
			for (int i = 0; i < root.childCount; i++)
			{
				Transform child = root.GetChild(i);
				string name = ((Object)child).name;
				if (name.IndexOf("head", StringComparison.OrdinalIgnoreCase) >= 0 || name.IndexOf("mouth", StringComparison.OrdinalIgnoreCase) >= 0 || name.IndexOf("beak", StringComparison.OrdinalIgnoreCase) >= 0)
				{
					return child;
				}
				Transform val = FindHeadTransform(child);
				if (Object.op_Implicit((Object)(object)val))
				{
					return val;
				}
			}
			return null;
		}

		public static void ClearCache()
		{
			_headTransformCache.Clear();
		}
	}
	[BepInPlugin("com.openai.howtofish.magicbullet", "How To Fish - Magic Bullet", "1.2.3")]
	public sealed class MagicBulletPlugin : BaseUnityPlugin
	{
		public const string PluginGuid = "com.openai.howtofish.magicbullet";

		public const string PluginName = "How To Fish - Magic Bullet";

		public const string PluginVersion = "1.2.3";

		internal static MagicBulletPlugin Instance;

		private Harmony _harmony;

		private void Awake()
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Expected O, but got Unknown
			Instance = this;
			DebugLogger.Initialize(((BaseUnityPlugin)this).Logger);
			ModConfig.Initialize(((BaseUnityPlugin)this).Config);
			Compatibility.Initialize();
			_harmony = new Harmony("com.openai.howtofish.magicbullet");
			InstallPatches();
			TargetCache.Reconcile();
			DebugLogger.LogInfo("How To Fish - Magic Bullet v1.2.3 loaded.");
			DebugLogger.LogInfo($"Target mode: {ModConfig.TargetMode.Value} | FOV: {ModConfig.FovDegrees.Value:0.#}° | Sticky: {ModConfig.StickyTarget.Value} | WallPen: {ModConfig.WallPenetration.Value}");
		}

		private void InstallPatches()
		{
			PatchCategory("Core Ballistics", true, typeof(WeaponShootPatch), typeof(AddProjectilePatch), typeof(AddProjectilesPatch), typeof(CreatureLocalHitPatch));
			PatchCategory("Target Lifecycle", false, typeof(CreatureAwakePatch), typeof(CreatureOnStopClientPatch), typeof(ItemDestroyItemPatch));
			PatchCategory("Wall Penetration", false, typeof(UpdateProjectileScanPatch), typeof(HitScanPatch), typeof(AddToRemoveQueuePatch));
		}

		private bool PatchCategory(string categoryName, bool isCritical, params Type[] patchTypes)
		{
			bool flag = true;
			foreach (Type patchType in patchTypes)
			{
				try
				{
					PatchClassProcessor val = _harmony.CreateClassProcessor(patchType);
					List<MethodInfo> patches = val.Patch();
					if (patches == null || patches.Count == 0)
					{
						DebugLogger.LogWarning("[Harmony] Patch class " + patchType.Name + " in '" + categoryName + "' returned 0 hooks.");
					}
					else
					{
						DebugLogger.Debug(() => $"[Harmony] Applied patch: {patchType.Name} ({patches.Count} hooks)");
					}
				}
				catch (Exception ex)
				{
					flag = false;
					if (isCritical)
					{
						DebugLogger.LogError("[Harmony] CRITICAL patch failure in '" + categoryName + "' on " + patchType.Name + ": " + ex.Message);
					}
					else
					{
						DebugLogger.LogWarning("[Harmony] Optional patch failure in '" + categoryName + "' on " + patchType.Name + ": " + ex.Message);
					}
				}
			}
			if (!flag)
			{
				if (isCritical)
				{
					DebugLogger.LogError("[MagicBullet] Critical patches failed. Disabling Magic Bullet.");
					ModConfig.Enabled.Value = false;
				}
				else if (categoryName == "Wall Penetration")
				{
					DebugLogger.LogWarning("[MagicBullet] Wall Penetration patch failed. Wall Penetration feature disabled.");
					Compatibility.DisableWallPenetration();
				}
			}
			return flag;
		}

		private void OnDestroy()
		{
			TargetManager.ClearTarget();
			TargetCache.Clear();
			ProjectileTracker.Clear();
			HeadResolver.ClearCache();
			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_005f: 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)
			if (Input.GetKeyDown(ModConfig.ToggleKey.Value))
			{
				ModConfig.Enabled.Value = !ModConfig.Enabled.Value;
				((BaseUnityPlugin)this).Config.Save();
				DebugLogger.LogInfo("Magic Bullet: " + (ModConfig.Enabled.Value ? "ON" : "OFF"));
			}
			if (Input.GetKeyDown(ModConfig.FovDecreaseKey.Value))
			{
				ModConfig.FovDegrees.Value = Mathf.Clamp(ModConfig.FovDegrees.Value - ModConfig.FovStep.Value, 1f, 180f);
				((BaseUnityPlugin)this).Config.Save();
				DebugLogger.LogInfo($"Magic Bullet FOV: {ModConfig.FovDegrees.Value:0.#}°");
			}
			if (Input.GetKeyDown(ModConfig.FovIncreaseKey.Value))
			{
				ModConfig.FovDegrees.Value = Mathf.Clamp(ModConfig.FovDegrees.Value + ModConfig.FovStep.Value, 1f, 180f);
				((BaseUnityPlugin)this).Config.Save();
				DebugLogger.LogInfo($"Magic Bullet FOV: {ModConfig.FovDegrees.Value:0.#}°");
			}
			TargetManager.UpdateLiveTargeting();
		}

		private void OnGUI()
		{
			FovRenderer.Render();
		}
	}
	public static class MagicBulletShotContext
	{
		private static bool _isActive;

		private static Weapon _activeWeapon;

		private static Creature _activeTarget;

		public static bool IsActive => _isActive;

		public static Weapon ActiveWeapon => _activeWeapon;

		public static Creature ActiveTarget => _activeTarget;

		public static void Begin(Weapon weapon, Creature target)
		{
			_isActive = true;
			_activeWeapon = weapon;
			_activeTarget = target;
		}

		public static void End()
		{
			_isActive = false;
			_activeWeapon = null;
			_activeTarget = null;
		}
	}
	public enum TargetSelectionMode
	{
		Crosshair,
		Nearest,
		LowestHealth,
		BossPriority
	}
	public static class ModConfig
	{
		public static ConfigEntry<bool> Enabled { get; private set; }

		public static ConfigEntry<TargetSelectionMode> TargetMode { get; private set; }

		public static ConfigEntry<float> FovDegrees { get; private set; }

		public static ConfigEntry<float> FovStep { get; private set; }

		public static ConfigEntry<float> MaxTargetDistance { get; private set; }

		public static ConfigEntry<float> MaxPredictionTime { get; private set; }

		public static ConfigEntry<bool> StickyTarget { get; private set; }

		public static ConfigEntry<float> StickyFovMultiplier { get; private set; }

		public static ConfigEntry<bool> RequireLineOfSight { get; private set; }

		public static ConfigEntry<bool> WallPenetration { get; private set; }

		public static ConfigEntry<bool> TargetFish { get; private set; }

		public static ConfigEntry<bool> TargetBirds { get; private set; }

		public static ConfigEntry<bool> TargetAlbatross { get; private set; }

		public static ConfigEntry<KeyCode> ToggleKey { get; private set; }

		public static ConfigEntry<KeyCode> FovDecreaseKey { get; private set; }

		public static ConfigEntry<KeyCode> FovIncreaseKey { get; private set; }

		public static ConfigEntry<bool> ShowFOVCircle { get; private set; }

		public static ConfigEntry<bool> ShowTargetLine { get; private set; }

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

		public static void Initialize(ConfigFile config)
		{
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Expected O, but got Unknown
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Expected O, but got Unknown
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Expected O, but got Unknown
			//IL_013d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0147: Expected O, but got Unknown
			//IL_0190: Unknown result type (might be due to invalid IL or missing references)
			//IL_019a: Expected O, but got Unknown
			Enabled = config.Bind<bool>("MagicBullet", "Enabled", true, "Enable or disable magic bullet / silent aim.");
			ShowFOVCircle = config.Bind<bool>("Visuals", "ShowFOVCircle", true, "Render the centered white FOV targeting circle on screen.");
			ShowTargetLine = config.Bind<bool>("Visuals", "ShowTargetLine", true, "Render the white line connecting crosshair center to the locked target's head weak point.");
			TargetMode = config.Bind<TargetSelectionMode>("Targeting", "TargetMode", TargetSelectionMode.Crosshair, "Target selection strategy: Crosshair (closest to center), Nearest (world distance), LowestHealth (lowest HP), BossPriority (prefer Albatross / bosses).");
			FovDegrees = config.Bind<float>("Targeting", "FOV", 35f, new ConfigDescription("Maximum angular distance from crosshair center in degrees (FOV radius).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 180f), Array.Empty<object>()));
			FovStep = config.Bind<float>("Targeting", "FOVStep", 5f, new ConfigDescription("Degrees changed per FOV hotkey press.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 30f), Array.Empty<object>()));
			MaxTargetDistance = config.Bind<float>("Targeting", "MaxTargetDistance", 500f, new ConfigDescription("Maximum distance in meters to acquire targets.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(10f, 2000f), Array.Empty<object>()));
			MaxPredictionTime = config.Bind<float>("Targeting", "MaxPredictionTime", 2f, new ConfigDescription("Maximum movement/gravity prediction time in seconds.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 5f), Array.Empty<object>()));
			StickyTarget = config.Bind<bool>("Targeting", "StickyTarget", true, "If enabled, retains the current target across shots while it remains valid and within the sticky FOV.");
			StickyFovMultiplier = config.Bind<float>("Targeting", "StickyFOVMultiplier", 1.25f, new ConfigDescription("Multiplier applied to FOV for retaining an existing sticky target (hysteresis).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 3f), Array.Empty<object>()));
			RequireLineOfSight = config.Bind<bool>("Targeting", "RequireLineOfSight", false, "If true, targets blocked by walls / environmental geometry cannot be acquired.");
			WallPenetration = config.Bind<bool>("Targeting", "WallPenetration", false, "If true, Magic Bullet projectiles fired by the local player will pass through terrain and environmental geometry to hit the locked target.");
			TargetFish = config.Bind<bool>("Filtering", "TargetFish", true, "Allow targeting Fish (including Bowhead Whale, Mutated Whale, AttackingFish, Pufferfish, RunningFish, Piranha).");
			TargetBirds = config.Bind<bool>("Filtering", "TargetBirds", true, "Allow targeting Birds (Seagulls).");
			TargetAlbatross = config.Bind<bool>("Filtering", "TargetAlbatross", true, "Allow targeting Albatross.");
			ToggleKey = config.Bind<KeyCode>("Hotkeys", "Toggle", (KeyCode)289, "Hotkey to toggle Magic Bullet ON/OFF.");
			FovDecreaseKey = config.Bind<KeyCode>("Hotkeys", "FOVDecrease", (KeyCode)91, "Hotkey to decrease FOV.");
			FovIncreaseKey = config.Bind<KeyCode>("Hotkeys", "FOVIncrease", (KeyCode)93, "Hotkey to increase FOV.");
			DebugLogging = config.Bind<bool>("Diagnostics", "DebugLogging", false, "Enable detailed debug logging for targeting, ballistics, and penetration events.");
		}
	}
	[HarmonyPatch(typeof(Creature), "Awake")]
	internal static class CreatureAwakePatch
	{
		private static void Postfix(Creature __instance)
		{
			TargetCache.Register(__instance);
		}
	}
	[HarmonyPatch(typeof(Creature), "OnStopClient")]
	internal static class CreatureOnStopClientPatch
	{
		private static void Prefix(Creature __instance)
		{
			TargetCache.Unregister(__instance);
		}
	}
	[HarmonyPatch(typeof(Item), "DestroyItem")]
	internal static class ItemDestroyItemPatch
	{
		private static void Prefix(Item __instance)
		{
			Creature val = (Creature)(object)((__instance is Creature) ? __instance : null);
			if (val != null)
			{
				TargetCache.Unregister(val);
			}
		}
	}
	[HarmonyPatch(typeof(Weapon), "Shoot")]
	internal static class WeaponShootPatch
	{
		private static void Prefix(Weapon __instance)
		{
			if (ModConfig.Enabled != null && ModConfig.Enabled.Value && !((Object)(object)__instance == (Object)null) && Object.op_Implicit((Object)(object)((Item)__instance).Holder) && Object.op_Implicit((Object)(object)Player.LocalPlayer) && !((Object)(object)((Item)__instance).Holder != (Object)(object)Player.LocalPlayer) && !(((NetworkBehaviour)((Item)__instance).Holder).Owner == (NetworkConnection)null) && ((NetworkBehaviour)((Item)__instance).Holder).Owner.IsLocalClient)
			{
				TargetManager.UpdateLiveTargeting();
				Creature target = TargetManager.CurrentTarget;
				MagicBulletShotContext.Begin(__instance, target);
				DebugLogger.Debug(delegate
				{
					string[] obj = new string[5]
					{
						"[ProjectileGate] Authorized Weapon.Shoot context started for ",
						((Object)__instance).name,
						" (Target: ",
						null,
						null
					};
					Creature obj2 = target;
					obj[3] = ((obj2 != null) ? ((Object)obj2).name : null) ?? "None";
					obj[4] = ")";
					return string.Concat(obj);
				});
			}
		}

		private static Exception Finalizer(Exception __exception)
		{
			if (MagicBulletShotContext.IsActive)
			{
				MagicBulletShotContext.End();
				DebugLogger.Debug(() => "[ProjectileGate] Authorized Weapon.Shoot context ended.");
			}
			return __exception;
		}
	}
	[HarmonyPatch(typeof(ProjectileManager), "AddProjectile", new Type[]
	{
		typeof(Player),
		typeof(WeaponInfo),
		typeof(bool),
		typeof(Vector3),
		typeof(Vector3),
		typeof(uint),
		typeof(uint),
		typeof(bool)
	})]
	internal static class AddProjectilePatch
	{
		private static void Prefix(Player owner, WeaponInfo weaponInfo, bool isLocal, Vector3 pos, ref Vector3 velocity, bool fromNpc)
		{
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: 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)
			if (!MagicBulletShotContext.IsActive || fromNpc || !isLocal || !Object.op_Implicit((Object)(object)owner) || !Object.op_Implicit((Object)(object)Player.LocalPlayer) || (Object)(object)owner != (Object)(object)Player.LocalPlayer || !ModConfig.Enabled.Value)
			{
				return;
			}
			Creature target = MagicBulletShotContext.ActiveTarget;
			if (TargetManager.IsAllowedTarget(target))
			{
				velocity = TargetPrediction.CalculateRedirectedVelocity(pos, velocity, target, weaponInfo);
				DebugLogger.Debug(() => "[ProjectileGate] Accepted player Weapon.Shoot projectile toward " + ((Object)target).name);
			}
		}

		private static void Postfix(ProjectileManager __instance, Player owner, bool isLocal, uint id, bool fromNpc)
		{
			if (!MagicBulletShotContext.IsActive || fromNpc || !isLocal || !Object.op_Implicit((Object)(object)owner) || !Object.op_Implicit((Object)(object)Player.LocalPlayer) || (Object)(object)owner != (Object)(object)Player.LocalPlayer || !ModConfig.Enabled.Value || ModConfig.WallPenetration == null || !ModConfig.WallPenetration.Value)
			{
				return;
			}
			Creature activeTarget = MagicBulletShotContext.ActiveTarget;
			if (TargetManager.IsAllowedTarget(activeTarget))
			{
				Projectile val = Compatibility.FindSpawnedProjectile(__instance, owner, id);
				if (val != null)
				{
					ProjectileTracker.Register(val, activeTarget);
				}
			}
		}
	}
	[HarmonyPatch(typeof(ProjectileManager), "AddProjectiles", new Type[]
	{
		typeof(Player),
		typeof(WeaponInfo),
		typeof(bool),
		typeof(Vector3),
		typeof(Vector3[]),
		typeof(uint),
		typeof(uint),
		typeof(bool)
	})]
	internal static class AddProjectilesPatch
	{
		private static void Prefix(Player owner, WeaponInfo weaponInfo, bool isLocal, Vector3 pos, Vector3[] velocities, bool canHitOwner)
		{
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: 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)
			if (!MagicBulletShotContext.IsActive || !isLocal || !Object.op_Implicit((Object)(object)owner) || !Object.op_Implicit((Object)(object)Player.LocalPlayer) || (Object)(object)owner != (Object)(object)Player.LocalPlayer || velocities == null || !ModConfig.Enabled.Value)
			{
				return;
			}
			Creature target = MagicBulletShotContext.ActiveTarget;
			if (TargetManager.IsAllowedTarget(target))
			{
				for (int i = 0; i < velocities.Length; i++)
				{
					velocities[i] = TargetPrediction.CalculateRedirectedVelocity(pos, velocities[i], target, weaponInfo);
				}
				DebugLogger.Debug(() => $"[ProjectileGate] Accepted player Weapon.Shoot multi-projectile batch ({velocities.Length}) toward {((Object)target).name}");
			}
		}

		private static void Postfix(ProjectileManager __instance, Player owner, bool isLocal, Vector3[] velocities, uint id, bool canHitOwner)
		{
			if (!MagicBulletShotContext.IsActive || !isLocal || !Object.op_Implicit((Object)(object)owner) || !Object.op_Implicit((Object)(object)Player.LocalPlayer) || (Object)(object)owner != (Object)(object)Player.LocalPlayer || velocities == null || !ModConfig.Enabled.Value || ModConfig.WallPenetration == null || !ModConfig.WallPenetration.Value)
			{
				return;
			}
			Creature activeTarget = MagicBulletShotContext.ActiveTarget;
			if (!TargetManager.IsAllowedTarget(activeTarget))
			{
				return;
			}
			for (int i = 0; i < velocities.Length; i++)
			{
				uint id2 = id + (uint)i;
				Projectile val = Compatibility.FindSpawnedProjectile(__instance, owner, id2);
				if (val != null)
				{
					ProjectileTracker.Register(val, activeTarget);
				}
			}
		}
	}
	[HarmonyPatch(typeof(ProjectileManager), "UpdateProjectileScan", new Type[]
	{
		typeof(Projectile),
		typeof(ProjectileType)
	})]
	internal static class UpdateProjectileScanPatch
	{
		private static bool Prefix(ProjectileManager __instance, Projectile projectile, ProjectileType type)
		{
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: 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_015a: Unknown result type (might be due to invalid IL or missing references)
			//IL_015f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0167: Unknown result type (might be due to invalid IL or missing references)
			//IL_0178: Unknown result type (might be due to invalid IL or missing references)
			//IL_017f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d3: 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)
			if (ModConfig.Enabled == null || !ModConfig.Enabled.Value)
			{
				return true;
			}
			if (ModConfig.WallPenetration == null || !ModConfig.WallPenetration.Value || !Compatibility.WallPenetrationSupported)
			{
				return true;
			}
			if (projectile == null || !projectile.IsLocal || (Object)(object)projectile.Owner == (Object)null || (Object)(object)projectile.Owner != (Object)(object)Player.LocalPlayer)
			{
				return true;
			}
			if (!ProjectileTracker.TryGetTarget(projectile, out var target))
			{
				return true;
			}
			float catchUpSpeed = Compatibility.GetCatchUpSpeed(__instance);
			float sqrMaxProjRange = Compatibility.GetSqrMaxProjRange(__instance);
			float num = 1f + (float)projectile.CatchingUpToDo * catchUpSpeed;
			if (Object.op_Implicit((Object)(object)projectile.Owner))
			{
				Vector3 val = projectile.Position - projectile.Owner.Transform.position;
				if (!(((Vector3)(ref val)).sqrMagnitude > sqrMaxProjRange))
				{
					if (projectile.Position.y < WaterManager.WaterHeight - 0.5f)
					{
						Compatibility.CallAddToRemoveQueue(__instance, projectile);
						Compatibility.CallHitWater(__instance, projectile);
						return false;
					}
					float num2 = ((Vector3)(ref projectile.Velocity)).magnitude * num * Time.fixedDeltaTime;
					LayerMask projectileHitLayer = GameInfo.ProjectileHitLayer;
					RaycastHit[] array = Physics.SphereCastAll(projectile.Position, type.WidthRadius, projectile.Velocity, num2, LayerMask.op_Implicit(projectileHitLayer));
					if (array != null && array.Length != 0)
					{
						Array.Sort(array, (RaycastHit a, RaycastHit b) => ((RaycastHit)(ref a)).distance.CompareTo(((RaycastHit)(ref b)).distance));
						for (int num3 = 0; num3 < array.Length; num3++)
						{
							RaycastHit hit = array[num3];
							if (!Object.op_Implicit((Object)(object)((RaycastHit)(ref hit)).collider))
							{
								continue;
							}
							Item val2 = ItemManager.Get(((RaycastHit)(ref hit)).collider);
							if (((Object)(object)val2 != (Object)null && (Object)(object)val2 == (Object)(object)target) || ((Component)((RaycastHit)(ref hit)).collider).transform.IsChildOf(((Component)target).transform))
							{
								DebugLogger.Debug(() => $"[WallPenetration] Projectile {projectile.Id} reached target {((Object)target).name} through wall!");
								ProjectileTracker.Unregister(projectile);
								Compatibility.CallHit(__instance, projectile, type, hit);
								return false;
							}
						}
						DebugLogger.Debug(() => $"[WallPenetration] Projectile {projectile.Id} penetrated environmental obstruction towards {((Object)target).name}.");
						return false;
					}
					return false;
				}
			}
			Compatibility.CallAddToRemoveQueue(__instance, projectile);
			return false;
		}
	}
	[HarmonyPatch(typeof(ProjectileManager), "HitScan", new Type[]
	{
		typeof(Projectile),
		typeof(ProjectileType)
	})]
	internal static class HitScanPatch
	{
		private static bool Prefix(ProjectileManager __instance, Projectile projectile, ProjectileType type, ref float __result)
		{
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: 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)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: 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)
			if (ModConfig.Enabled == null || !ModConfig.Enabled.Value)
			{
				return true;
			}
			if (ModConfig.WallPenetration == null || !ModConfig.WallPenetration.Value || !Compatibility.WallPenetrationSupported)
			{
				return true;
			}
			if (projectile == null || !projectile.IsLocal || (Object)(object)projectile.Owner == (Object)null || (Object)(object)projectile.Owner != (Object)(object)Player.LocalPlayer)
			{
				return true;
			}
			if (!ProjectileTracker.TryGetTarget(projectile, out var target))
			{
				return true;
			}
			RaycastHit[] array = Physics.SphereCastAll(projectile.Position, type.WidthRadius, projectile.Velocity, float.PositiveInfinity, LayerMask.op_Implicit(GameInfo.ProjectileHitLayer));
			if (array != null && array.Length != 0 && !type.ProjectilesToRemove.Contains(projectile))
			{
				Array.Sort(array, (RaycastHit a, RaycastHit b) => ((RaycastHit)(ref a)).distance.CompareTo(((RaycastHit)(ref b)).distance));
				for (int num = 0; num < array.Length; num++)
				{
					RaycastHit hit = array[num];
					if (!Object.op_Implicit((Object)(object)((RaycastHit)(ref hit)).collider))
					{
						continue;
					}
					Item val = ItemManager.Get(((RaycastHit)(ref hit)).collider);
					if (((Object)(object)val != (Object)null && (Object)(object)val == (Object)(object)target) || ((Component)((RaycastHit)(ref hit)).collider).transform.IsChildOf(((Component)target).transform))
					{
						DebugLogger.Debug(() => "[WallPenetration] Hitscan projectile reached target " + ((Object)target).name + " through wall!");
						ProjectileTracker.Unregister(projectile);
						Compatibility.CallHit(__instance, projectile, type, hit);
						__result = 0f;
						return false;
					}
				}
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(ProjectileManager), "AddToRemoveQueue", new Type[] { typeof(Projectile) })]
	internal static class AddToRemoveQueuePatch
	{
		private static void Postfix(Projectile projectile)
		{
			ProjectileTracker.Unregister(projectile);
		}
	}
	[HarmonyPatch(typeof(Creature), "LocalHit")]
	internal static class CreatureLocalHitPatch
	{
		private static void Prefix(Creature __instance, ref Vector3 point, Player player, ref int damage, bool rangedHit)
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: 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)
			//IL_008e: 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)
			if (ModConfig.Enabled != null && ModConfig.Enabled.Value && Object.op_Implicit((Object)(object)player) && Object.op_Implicit((Object)(object)Player.LocalPlayer) && !((Object)(object)player != (Object)(object)Player.LocalPlayer) && rangedHit && TargetManager.IsAllowedTarget(__instance) && ((Component)__instance).transform.InverseTransformPoint(point).z <= __instance.HeadPos)
			{
				Vector3 val = ((Component)__instance).transform.InverseTransformPoint(point);
				val.z = __instance.HeadPos + 0.15f;
				point = ((Component)__instance).transform.TransformPoint(val);
			}
		}
	}
	public static class ProjectileTracker
	{
		private static readonly Dictionary<Projectile, Creature> _projectileToTarget = new Dictionary<Projectile, Creature>();

		private static readonly Dictionary<uint, Creature> _idToTarget = new Dictionary<uint, Creature>();

		public static void Register(Projectile projectile, Creature target)
		{
			if (projectile != null && !((Object)(object)target == (Object)null))
			{
				lock (_projectileToTarget)
				{
					_projectileToTarget[projectile] = target;
					_idToTarget[projectile.Id] = target;
				}
				DebugLogger.Debug(() => $"[ProjectileTracker] Tracked projectile ID {projectile.Id} -> Target: {((Object)target).name}");
			}
		}

		public static bool TryGetTarget(Projectile projectile, out Creature target)
		{
			target = null;
			if (projectile == null)
			{
				return false;
			}
			lock (_projectileToTarget)
			{
				if (_projectileToTarget.TryGetValue(projectile, out target) && (Object)(object)target != (Object)null && !target.IsDead && !((Item)target).IsDestroying)
				{
					return true;
				}
				if (_idToTarget.TryGetValue(projectile.Id, out target) && (Object)(object)target != (Object)null && !target.IsDead && !((Item)target).IsDestroying)
				{
					return true;
				}
			}
			return false;
		}

		public static void Unregister(Projectile projectile)
		{
			if (projectile != null)
			{
				lock (_projectileToTarget)
				{
					_projectileToTarget.Remove(projectile);
					_idToTarget.Remove(projectile.Id);
				}
				DebugLogger.Debug(() => $"[ProjectileTracker] Untracked projectile ID {projectile.Id}");
			}
		}

		public static void Clear()
		{
			lock (_projectileToTarget)
			{
				_projectileToTarget.Clear();
				_idToTarget.Clear();
			}
		}
	}
	public static class TargetCache
	{
		private static readonly HashSet<Creature> _creatures = new HashSet<Creature>();

		private static readonly List<Creature> _staleList = new List<Creature>(32);

		private static float _nextReconcileTime = 0f;

		private const float ReconcileIntervalSeconds = 3f;

		public static int Count => _creatures.Count;

		public static void Register(Creature creature)
		{
			if (Object.op_Implicit((Object)(object)creature))
			{
				lock (_creatures)
				{
					_creatures.Add(creature);
				}
				DebugLogger.Debug(() => $"[TargetCache] Registered creature: {((Object)creature).name} (Total: {_creatures.Count})");
			}
		}

		public static void Unregister(Creature creature)
		{
			if (Object.op_Implicit((Object)(object)creature))
			{
				lock (_creatures)
				{
					_creatures.Remove(creature);
				}
				DebugLogger.Debug(() => $"[TargetCache] Unregistered creature: {((Object)creature).name} (Total: {_creatures.Count})");
			}
		}

		public static void Clear()
		{
			lock (_creatures)
			{
				_creatures.Clear();
			}
		}

		public static void GetActiveCreatures(List<Creature> buffer)
		{
			if (buffer == null)
			{
				return;
			}
			buffer.Clear();
			if (Time.time >= _nextReconcileTime)
			{
				Reconcile();
				_nextReconcileTime = Time.time + 3f;
			}
			lock (_creatures)
			{
				_staleList.Clear();
				foreach (Creature creature in _creatures)
				{
					if (!Object.op_Implicit((Object)(object)creature) || creature.IsDead || ((Item)creature).IsDestroying)
					{
						_staleList.Add(creature);
					}
					else if (((Behaviour)creature).isActiveAndEnabled)
					{
						buffer.Add(creature);
					}
				}
				for (int i = 0; i < _staleList.Count; i++)
				{
					_creatures.Remove(_staleList[i]);
				}
				_staleList.Clear();
			}
		}

		public static void Reconcile()
		{
			try
			{
				Creature[] array = Object.FindObjectsOfType<Creature>();
				lock (_creatures)
				{
					if (array == null)
					{
						return;
					}
					foreach (Creature val in array)
					{
						if (Object.op_Implicit((Object)(object)val) && !val.IsDead && !((Item)val).IsDestroying)
						{
							_creatures.Add(val);
						}
					}
				}
			}
			catch (Exception ex)
			{
				DebugLogger.LogWarning("[TargetCache] Reconcile exception: " + ex.Message);
			}
		}
	}
	public static class TargetManager
	{
		private static readonly List<Creature> _candidateBuffer = new List<Creature>(64);

		public static Creature CurrentTarget { get; private set; }

		public static void ClearTarget()
		{
			CurrentTarget = null;
		}

		public static bool IsAllowedTarget(Creature candidate)
		{
			if (!Object.op_Implicit((Object)(object)candidate) || !((Behaviour)candidate).isActiveAndEnabled || candidate.IsDead || ((Item)candidate).IsDestroying)
			{
				return false;
			}
			if (candidate is Albatross)
			{
				if (ModConfig.TargetAlbatross != null)
				{
					return ModConfig.TargetAlbatross.Value;
				}
				return false;
			}
			if (candidate is Bird)
			{
				if (ModConfig.TargetBirds != null)
				{
					return ModConfig.TargetBirds.Value;
				}
				return false;
			}
			if (candidate is Fish)
			{
				if (ModConfig.TargetFish != null)
				{
					return ModConfig.TargetFish.Value;
				}
				return false;
			}
			return false;
		}

		public static bool CheckLineOfSight(Vector3 origin, Vector3 targetPoint, Creature target)
		{
			//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_0024: 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_0033: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = targetPoint - origin;
			float magnitude = ((Vector3)(ref val)).magnitude;
			if (magnitude <= 0.01f)
			{
				return true;
			}
			int num = LayerMask.op_Implicit(GameInfo.LevelLayer) | LayerMask.op_Implicit(GameInfo.BoatLayer);
			RaycastHit val2 = default(RaycastHit);
			if (Physics.Raycast(origin, ((Vector3)(ref val)).normalized, ref val2, magnitude, num, (QueryTriggerInteraction)1) && (Object)(object)((RaycastHit)(ref val2)).collider != (Object)null)
			{
				Item val3 = ItemManager.Get(((RaycastHit)(ref val2)).collider);
				if ((Object)(object)val3 != (Object)null && (Object)(object)val3 == (Object)(object)target)
				{
					return true;
				}
				if (((Component)((RaycastHit)(ref val2)).collider).transform.IsChildOf(((Component)target).transform))
				{
					return true;
				}
				return false;
			}
			return true;
		}

		public static void UpdateLiveTargeting()
		{
			if (!ModConfig.Enabled.Value || !Object.op_Implicit((Object)(object)Player.LocalPlayer))
			{
				CurrentTarget = null;
				return;
			}
			Camera aimCamera = GetAimCamera();
			if (!Object.op_Implicit((Object)(object)aimCamera))
			{
				CurrentTarget = null;
			}
			else
			{
				CurrentTarget = FindBestTarget(aimCamera);
			}
		}

		public static Camera GetAimCamera()
		{
			Player localPlayer = Player.LocalPlayer;
			if (Object.op_Implicit((Object)(object)localPlayer) && Object.op_Implicit((Object)(object)localPlayer.CurCam))
			{
				return localPlayer.CurCam;
			}
			return Camera.main;
		}

		public static Creature FindBestTarget(Camera cam)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: 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_0175: Unknown result type (might be due to invalid IL or missing references)
			//IL_017a: Unknown result type (might be due to invalid IL or missing references)
			//IL_017c: Unknown result type (might be due to invalid IL or missing references)
			//IL_017e: Unknown result type (might be due to invalid IL or missing references)
			//IL_017f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0184: 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_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: 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)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01be: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ad: Invalid comparison between Unknown and I4
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)cam))
			{
				return null;
			}
			Vector3 position = ((Component)cam).transform.position;
			Vector3 forward = ((Component)cam).transform.forward;
			float num = ((ModConfig.MaxTargetDistance != null) ? ModConfig.MaxTargetDistance.Value : 500f);
			float num2 = num * num;
			float num3 = ((ModConfig.FovDegrees != null) ? ModConfig.FovDegrees.Value : 35f);
			bool flag = ModConfig.RequireLineOfSight != null && ModConfig.RequireLineOfSight.Value;
			TargetSelectionMode targetSelectionMode = ((ModConfig.TargetMode != null) ? ModConfig.TargetMode.Value : TargetSelectionMode.Crosshair);
			if (ModConfig.StickyTarget != null && ModConfig.StickyTarget.Value && (Object)(object)CurrentTarget != (Object)null && IsAllowedTarget(CurrentTarget))
			{
				Vector3 val = HeadResolver.ResolveAimPoint(CurrentTarget);
				Vector3 val2 = val - position;
				if (((Vector3)(ref val2)).sqrMagnitude <= num2)
				{
					float num4 = Vector3.Angle(forward, val2);
					float num5 = num3 * ((ModConfig.StickyFovMultiplier != null) ? ModConfig.StickyFovMultiplier.Value : 1.25f);
					bool num6 = targetSelectionMode == TargetSelectionMode.Nearest || num4 <= num5;
					bool flag2 = !flag || CheckLineOfSight(position, val, CurrentTarget);
					if (num6 && flag2)
					{
						return CurrentTarget;
					}
				}
			}
			TargetCache.GetActiveCreatures(_candidateBuffer);
			Creature result = null;
			float num7 = float.MaxValue;
			float num8 = float.MaxValue;
			float num9 = float.MaxValue;
			for (int i = 0; i < _candidateBuffer.Count; i++)
			{
				Creature val3 = _candidateBuffer[i];
				if (!IsAllowedTarget(val3))
				{
					continue;
				}
				Vector3 val4 = HeadResolver.ResolveAimPoint(val3);
				Vector3 val5 = val4 - position;
				float sqrMagnitude = ((Vector3)(ref val5)).sqrMagnitude;
				if (sqrMagnitude > num2 || sqrMagnitude <= 0.0001f)
				{
					continue;
				}
				float num10 = Vector3.Angle(forward, val5);
				if ((targetSelectionMode != TargetSelectionMode.Nearest && num10 > num3) || (flag && !CheckLineOfSight(position, val4, val3)))
				{
					continue;
				}
				switch (targetSelectionMode)
				{
				case TargetSelectionMode.Crosshair:
					if (num10 < num9 - 0.01f || (Mathf.Abs(num10 - num9) <= 0.01f && sqrMagnitude < num8))
					{
						result = val3;
						num9 = num10;
						num8 = sqrMagnitude;
					}
					break;
				case TargetSelectionMode.Nearest:
					if (sqrMagnitude < num8 - 0.01f || (Mathf.Abs(sqrMagnitude - num8) <= 0.01f && num10 < num9))
					{
						result = val3;
						num8 = sqrMagnitude;
						num9 = num10;
					}
					break;
				case TargetSelectionMode.LowestHealth:
				{
					float num12 = val3.Hp;
					if (num12 < num7 - 0.01f || (Mathf.Abs(num12 - num7) <= 0.01f && num10 < num9))
					{
						result = val3;
						num7 = num12;
						num9 = num10;
						num8 = sqrMagnitude;
					}
					break;
				}
				case TargetSelectionMode.BossPriority:
				{
					float num11 = ((val3 is Albatross || (int)val3.BossType > 0) ? 0f : 1000f) + num10;
					if (num11 < num7 - 0.01f || (Mathf.Abs(num11 - num7) <= 0.01f && sqrMagnitude < num8))
					{
						result = val3;
						num7 = num11;
						num9 = num10;
						num8 = sqrMagnitude;
					}
					break;
				}
				}
			}
			_candidateBuffer.Clear();
			return result;
		}
	}
	public static class TargetPrediction
	{
		public static Vector3 GetTargetVelocity(Creature target, Vector3 aimPoint)
		{
			//IL_0015: 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_0022: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)target) || !Object.op_Implicit((Object)(object)((Item)target).Rig))
			{
				return Vector3.zero;
			}
			return ((Item)target).Rig.GetPointVelocity(aimPoint);
		}

		public static Vector3 PredictInterceptPoint(Vector3 origin, Creature target, float projectileSpeed, float gravityForce, out float flightTime)
		{
			//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_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: 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_0060: 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_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: 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)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: 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_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: 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)
			flightTime = 0f;
			if (!Object.op_Implicit((Object)(object)target))
			{
				return origin;
			}
			Vector3 val = HeadResolver.ResolveAimPoint(target);
			Vector3 targetVelocity = GetTargetVelocity(target, val);
			float num = ((ModConfig.MaxPredictionTime != null) ? ModConfig.MaxPredictionTime.Value : 2f);
			if (projectileSpeed <= 0.001f)
			{
				return val;
			}
			Vector3 val2 = val - origin;
			float magnitude = ((Vector3)(ref val2)).magnitude;
			float num2 = magnitude / projectileSpeed;
			for (int i = 0; i < 3; i++)
			{
				val2 = val + targetVelocity * num2 - origin;
				float num3 = ((Vector3)(ref val2)).magnitude / projectileSpeed;
				if (float.IsNaN(num3) || float.IsInfinity(num3) || num3 < 0f)
				{
					num2 = magnitude / projectileSpeed;
					break;
				}
				if (Mathf.Abs(num3 - num2) < 0.001f)
				{
					num2 = num3;
					break;
				}
				num2 = num3;
			}
			num2 = (flightTime = Mathf.Clamp(num2, 0f, num));
			Vector3 val3 = val + targetVelocity * num2;
			if (gravityForce > 0f)
			{
				val3 += Vector3.up * (0.5f * gravityForce * num2 * num2);
			}
			return val3;
		}

		public static Vector3 CalculateRedirectedVelocity(Vector3 origin, Vector3 originalVelocity, Creature target, WeaponInfo weaponInfo)
		{
			//IL_001a: 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_004e: 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_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: 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_0096: 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_0081: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)target))
			{
				return originalVelocity;
			}
			float speed = ((Vector3)(ref originalVelocity)).magnitude;
			if (speed <= 0.001f)
			{
				return originalVelocity;
			}
			float gravity = ((weaponInfo != null) ? weaponInfo.ProjectileGravity : 0f);
			float travelTime;
			Vector3 val = PredictInterceptPoint(origin, target, speed, gravity, out travelTime) - origin;
			if (((Vector3)(ref val)).sqrMagnitude <= 0.0001f)
			{
				return originalVelocity;
			}
			DebugLogger.Debug(() => $"[TargetPrediction] Redirected velocity toward {((Object)target).name} | Speed: {speed:0.#} | Gravity: {gravity:0.#} | Time: {travelTime:0.###}s");
			return ((Vector3)(ref val)).normalized * speed;
		}
	}
}