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