Decompiled source of Projectile Aim Indicator v0.2.20

plugins/ProjectileAimIndicator.dll

Decompiled 2 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using AzNean.SotfCommon;
using Ballistics;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Core.Logging.Interpolation;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using HarmonyLib;
using Il2CppInterop.Runtime.Attributes;
using Il2CppInterop.Runtime.Injection;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppSystem;
using Il2CppSystem.Collections.Generic;
using Il2CppSystem.Reflection;
using Microsoft.CodeAnalysis;
using ProjectileAimIndicator.Logic;
using ProjectileAimIndicator.Patches;
using Sons.Gui;
using Sons.Inventory;
using Sons.Items.Core;
using Sons.Weapon;
using TheForest.Utils;
using UnityEngine;
using UnityEngine.Rendering;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("ProjectileAimIndicator")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.2.20.0")]
[assembly: AssemblyInformationalVersion("0.2.20+e032234f27f1f72f2aff98afdebb24baaeee0ef9")]
[assembly: AssemblyProduct("ProjectileAimIndicator")]
[assembly: AssemblyTitle("ProjectileAimIndicator")]
[assembly: AssemblyVersion("0.2.20.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[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 AzNean.SotfCommon
{
	internal static class ModLog
	{
		private static ManualLogSource _log;

		private static ConfigEntry<bool> _full;

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

		private static readonly Dictionary<(int, string), int> _state = new Dictionary<(int, string), int>();

		internal static bool Full => _full.Value;

		internal static void Init(ManualLogSource log, ConfigEntry<bool> full)
		{
			_log = log;
			_full = full;
		}

		internal static void Trace(string message)
		{
			if (_full.Value)
			{
				_log.LogInfo((object)message);
			}
		}

		internal static bool Changed(int id, string what, int state)
		{
			if (!_full.Value || (_state.TryGetValue((id, what), out var value) && value == state))
			{
				return false;
			}
			_state[(id, what)] = state;
			return true;
		}

		internal static void Once(string key, string message, LogLevel level = (LogLevel)16)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			if (_once.Add(key))
			{
				_log.Log(level, (object)message);
			}
		}
	}
}
namespace ProjectileAimIndicator
{
	public class AimWatcher : MonoBehaviour
	{
		internal static AimWatcher Instance;

		private GameObject _linePrefab;

		private GameObject _targetPrefab;

		private LineRenderer _line;

		private GameObject _target;

		private float _targetMetres = 0.5f;

		private bool _failed;

		private int _heldId;

		private RangedWeapon _weapon;

		private RangedWeaponController _controller;

		private WeaponKind _kind;

		private bool _chosen;

		private bool _shown;

		private bool _gameOwn;

		private GameObject _gameTarget;

		private Vector3 _gameTargetScale;

		private float _gameTargetMetres;

		private float _nextLookup;

		private float _nextPath;

		private bool _hit;

		private Vector3 _shownImpact;

		private Vector3 _shownPos;

		private Vector3 _shownDir;

		private float _lastDraw = -1f;

		private int _shotFrame = -1;

		private IntPtr _pendingWeapon;

		private Vector3 _pendingShown;

		private Vector3 _pendingReplay;

		private bool _pendingShownHit;

		private bool _pendingReplayHit;

		private float _pendingTime;

		private WeaponKind _pendingKind;

		private readonly HashSet<(int, bool)> _sizedCameras = new HashSet<(int, bool)>();

		public AimWatcher(IntPtr ptr)
			: base(ptr)
		{
		}

		internal void Refresh()
		{
			_heldId = 0;
		}

		private void Awake()
		{
			Instance = this;
		}

		private void LateUpdate()
		{
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Invalid comparison between Unknown and I4
			if (_failed)
			{
				return;
			}
			RangedWeapon val = HeldWeapon();
			if ((Object)(object)val != (Object)null && _gameOwn)
			{
				Hide();
				if (_chosen)
				{
					TakeGameTarget(val);
				}
				return;
			}
			bool midAttack = (Object)(object)val != (Object)null && _controller._isCharging && (int)_controller._attackState == 2;
			if (!((Object)(object)val != (Object)null) || !Decision.ShouldShow(_kind, _chosen, midAttack, _controller.IsAiming))
			{
				Hide();
				return;
			}
			if (!_shown)
			{
				_nextPath = 0f;
			}
			_shown = true;
			if (Time.unscaledTime >= _nextPath)
			{
				DrawPath(val);
			}
		}

		private void Hide()
		{
			if (_shown)
			{
				_shown = false;
				if ((Object)(object)_line != (Object)null)
				{
					((Component)_line).gameObject.SetActive(false);
				}
				if ((Object)(object)_target != (Object)null)
				{
					_target.SetActive(false);
				}
			}
		}

		private RangedWeapon HeldWeapon()
		{
			//IL_03cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_03df: Unknown result type (might be due to invalid IL or missing references)
			if (!LocalPlayer.IsInWorld || PauseMenu.IsActive)
			{
				return null;
			}
			ItemInstance rightHandItem = LocalPlayer.Inventory.RightHandItem;
			GameObject val = ((rightHandItem != null) ? rightHandItem.ItemObject : null);
			int num = ((!((Object)(object)val == (Object)null)) ? ((Object)val).GetInstanceID() : 0);
			bool flag = num != _heldId;
			if (flag)
			{
				Hide();
				ReleaseGameTarget();
			}
			if ((Object)(object)val == (Object)null)
			{
				_heldId = 0;
				_weapon = null;
				return null;
			}
			if (flag || (((Object)(object)_weapon == (Object)null || ((Object)(object)_controller == (Object)null && _kind == WeaponKind.Other)) && Time.unscaledTime >= _nextLookup))
			{
				_heldId = num;
				_nextLookup = Time.unscaledTime + Plugin.LookupSeconds.Value;
				_weapon = val.GetComponentInChildren<RangedWeapon>(true);
				_controller = val.GetComponentInChildren<RangedWeaponController>(true);
				_kind = KindOf(_controller, val);
				_gameOwn = (Object)(object)_weapon != (Object)null && (Decision.GameDrawsOwn(_kind) || ((Object)(object)_controller != (Object)null && (Object)(object)_weapon._trajectoryPathPrefab != (Object)null && _weapon._showImpactLocation));
				bool flag2 = (Object)(object)_weapon != (Object)null && ((Object)(object)_controller != (Object)null || _gameOwn);
				_chosen = flag2 && Plugin.IsChosen(_kind) && (_gameOwn || Ready());
				if (ModLog.Changed(num, "weapon", flag2 ? (1 + (_chosen ? 2 : 0) + (_gameOwn ? 4 : 0)) : 0))
				{
					ModLog.Trace("Held " + ((Object)val).name + ": " + (flag2 ? $"{_kind} ({(((Object)(object)_controller != (Object)null) ? ((MemberInfo)((Object)_controller).GetIl2CppType()).Name : "no ranged controller")}), {(_gameOwn ? $"the game draws its own target, sized by the mod={_chosen}" : $"indicator={_chosen}")} (game line={(Object)(object)_weapon._trajectoryPathPrefab != (Object)null}, game option={_weapon._showImpactLocation}), spawn point {(((Object)(object)((Weapon)_weapon).physicalSpawnPoint != (Object)null) ? ((Object)((Weapon)_weapon).physicalSpawnPoint).name : "none")} ({(((Object)(object)((Weapon)_weapon).physicalSpawnPoint == (Object)null || (Object)(object)_weapon.GetProjectileTransform() == (Object)null) ? "n/a" : $"{Vector3.Angle(((Weapon)_weapon).physicalSpawnPoint.forward, _weapon.GetProjectileTransform().forward):F2}")}° from the projectile axis), laser sight={_weapon.HasLaserSight()}, spawn is laser copy={(Object)(object)((Weapon)_weapon).physicalSpawnPoint != (Object)null && (Object)(object)((Weapon)_weapon).physicalSpawnPoint == (Object)(object)_weapon._projectilePhysicalSpawnPoint}, modified screen position={_weapon._useModifiedScreenPostion}, ammo {AmmoName(_weapon)}" : $"no ranged weapon yet (weapon={(Object)(object)_weapon != (Object)null}, controller={(Object)(object)_controller != (Object)null})"));
				}
			}
			if (!((Object)(object)_weapon != (Object)null) || (!((Object)(object)_controller != (Object)null) && !_gameOwn))
			{
				return null;
			}
			return _weapon;
		}

		private static WeaponKind KindOf(RangedWeaponController c, GameObject held)
		{
			if ((Object)(object)c == (Object)null)
			{
				if ((Object)(object)held.GetComponentInChildren<SeveredLimbController>(true) != (Object)null)
				{
					return WeaponKind.Thrown;
				}
				if (!((Object)(object)held.GetComponentInChildren<SpearWeaponController>(true) != (Object)null))
				{
					return WeaponKind.Other;
				}
				return WeaponKind.Spear;
			}
			if ((Object)(object)((Il2CppObjectBase)c).TryCast<BowWeaponController>() != (Object)null)
			{
				return WeaponKind.Bow;
			}
			if ((Object)(object)((Il2CppObjectBase)c).TryCast<CrossbowWeaponController>() != (Object)null)
			{
				return WeaponKind.Crossbow;
			}
			if ((Object)(object)((Il2CppObjectBase)c).TryCast<SlingshotWeaponController>() != (Object)null)
			{
				return WeaponKind.Slingshot;
			}
			if ((Object)(object)((Il2CppObjectBase)c).TryCast<FlareWeaponController>() != (Object)null)
			{
				return WeaponKind.FlareGun;
			}
			if ((Object)(object)((Il2CppObjectBase)c).TryCast<RopeGunController>() != (Object)null)
			{
				return WeaponKind.RopeGun;
			}
			if ((Object)(object)((Il2CppObjectBase)c).TryCast<StunGunWeaponController>() != (Object)null)
			{
				return WeaponKind.StunGun;
			}
			if ((Object)(object)((Il2CppObjectBase)c).TryCast<GrenadeWeaponController>() != (Object)null || (Object)(object)((Il2CppObjectBase)c).TryCast<MolotovWeaponController>() != (Object)null || (Object)(object)((Il2CppObjectBase)c).TryCast<TimeBombWeaponController>() != (Object)null || (Object)(object)((Il2CppObjectBase)c).TryCast<SmallRockWeaponController>() != (Object)null)
			{
				return WeaponKind.Thrown;
			}
			return WeaponKind.Firearm;
		}

		private void TakeGameTarget(RangedWeapon weapon)
		{
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_gameTarget != (Object)null)
			{
				return;
			}
			GameObject impactTargetInstance = weapon._impactTargetInstance;
			if ((Object)(object)impactTargetInstance == (Object)null)
			{
				if (ModLog.Changed(_heldId, "game target", 0))
				{
					ModLog.Trace($"{_kind}: the game's own landing target does not exist yet (made the first time the game shows its indicator), sized then");
				}
				return;
			}
			_gameTarget = impactTargetInstance;
			_gameTargetScale = impactTargetInstance.transform.localScale;
			_gameTargetMetres = VisibleWidth(impactTargetInstance);
			ModLog.Once($"game target {((Object)impactTargetInstance).GetInstanceID()}", $"{_kind}: the game's own landing target {((Object)impactTargetInstance).name} taken, {_gameTargetMetres:F2} m wide at its own scale", (LogLevel)16);
		}

		private void ReleaseGameTarget()
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_gameTarget != (Object)null)
			{
				_gameTarget.transform.localScale = _gameTargetScale;
			}
			_gameTarget = null;
		}

		private static float VisibleWidth(GameObject target)
		{
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: 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_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: 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)
			foreach (MeshFilter componentsInChild in target.GetComponentsInChildren<MeshFilter>(true))
			{
				if (((Component)componentsInChild).gameObject.activeSelf && !((Object)(object)componentsInChild.sharedMesh == (Object)null))
				{
					Bounds bounds = componentsInChild.sharedMesh.bounds;
					Vector3 val = Vector3.Scale(((Bounds)(ref bounds)).size, ((Component)componentsInChild).transform.lossyScale);
					return Mathf.Max(val.x, Mathf.Max(val.y, val.z));
				}
			}
			return 0f;
		}

		private bool Ready()
		{
			if ((Object)(object)_linePrefab == (Object)null && !FindSpear())
			{
				return false;
			}
			if ((Object)(object)_line == (Object)null)
			{
				_line = Hidden(_linePrefab).GetComponent<LineRenderer>();
			}
			if ((Object)(object)_target == (Object)null && (Object)(object)_targetPrefab != (Object)null)
			{
				_target = Hidden(_targetPrefab);
			}
			return (Object)(object)_line != (Object)null;
		}

		private static string AmmoName(RangedWeapon weapon)
		{
			Ammo ammo = weapon.GetAmmo();
			AmmoProperties val = ((ammo != null) ? ammo._properties : null);
			ProjectileInfo val2 = ((val != null) ? val.ProjectileInfo : null);
			if (!((Object)(object)val == (Object)null))
			{
				return ((Object)val).name + " (" + ((val2 == null) ? "no flight data" : $"speed {((BulletInfo)val2).maxSpeed:F1} m/s, drag {((BulletInfo)val2).dragCoefficient:F2}, weight {((BulletInfo)val2).weight:F3}") + ")";
			}
			return "none";
		}

		private static GameObject Hidden(GameObject prefab)
		{
			GameObject obj = Object.Instantiate<GameObject>(prefab);
			obj.SetActive(false);
			return obj;
		}

		private void DrawPath(RangedWeapon weapon)
		{
			//IL_00c5: 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_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_0154: Unknown result type (might be due to invalid IL or missing references)
			//IL_0159: Unknown result type (might be due to invalid IL or missing references)
			//IL_015e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0163: 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_0190: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a6: Unknown result type (might be due to invalid IL or missing references)
			_nextPath = Time.unscaledTime + Plugin.PathUpdateSeconds.Value;
			int num = ((!Ready()) ? 1 : ((!RefreshBulletInfo(weapon)) ? 2 : ((!Launch(weapon, out _shownPos, out _shownDir)) ? 3 : 0)));
			if (ModLog.Changed(_heldId, "path", num))
			{
				ModLog.Trace($"{_kind}: {num switch
				{
					2 => "no aim path, no ammo with flight data loaded", 
					1 => "no aim path, the spear's line could not be copied", 
					0 => "aim path drawn", 
					_ => "no aim path, the weapon has no spawn point", 
				}}");
			}
			if (num != 0)
			{
				Hide();
				_shown = true;
				return;
			}
			TrajectoryData val = weapon.SimulateTrajectory(_shownPos, _shownDir);
			List<Vector3> arcPoints = val.arcPoints;
			int num2 = arcPoints?.Count ?? 0;
			_line.positionCount = num2;
			for (int i = 0; i < num2; i++)
			{
				_line.SetPosition(i, arcPoints[i]);
			}
			((Component)_line).gameObject.SetActive(num2 > 1);
			_hit = val.surfaceImpactDetected;
			_lastDraw = Time.unscaledTime;
			if (_hit)
			{
				RaycastHit rayHit = val.resultingSurfaceImpactInfo.rayHit;
				_shownImpact = ((RaycastHit)(ref rayHit)).point;
				if ((Object)(object)_target != (Object)null)
				{
					Transform transform = _target.transform;
					transform.position = ((RaycastHit)(ref rayHit)).point;
					transform.up = ((RaycastHit)(ref rayHit)).normal;
					SizeFor(Camera.main, _target, Vector3.one, _targetMetres);
				}
			}
			if ((Object)(object)_target != (Object)null)
			{
				_target.SetActive(_hit);
			}
		}

		private void SizeFor(Camera cam, GameObject target, Vector3 baseScale, float metres)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: 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_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Expected O, but got Unknown
			if ((Object)(object)cam == (Object)null || (Object)(object)target == (Object)null)
			{
				return;
			}
			Transform transform = target.transform;
			float num = Vector3.Distance(((Component)cam).transform.position, transform.position);
			float num2 = Decision.MarkerScale(num, cam.fieldOfView, Plugin.MarkerScreenSize.Value, Plugin.MarkerMaxMetres.Value, metres);
			transform.localScale = baseScale * num2;
			bool flag = (Object)(object)target == (Object)(object)_target;
			if (_sizedCameras.Add((((Object)cam).GetInstanceID(), flag)))
			{
				ManualLogSource logger = Plugin.Logger;
				bool flag2 = default(bool);
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(56, 5, ref flag2);
				if (flag2)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Landing target");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(flag ? "" : $" (game's own, {_kind})");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" sized for camera ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(((Object)cam).name);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(": ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<float>(num2 * metres, "F2");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" m wide at ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<float>(num, "F1");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" m (");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<float>(cam.fieldOfView, "F0");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("° view)");
				}
				logger.LogInfo(val);
			}
		}

		internal static void BeforeCamera(ScriptableRenderContext context, Camera cam)
		{
			//IL_0033: 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)
			AimWatcher instance = Instance;
			if (!((Object)(object)instance == (Object)null))
			{
				if ((Object)(object)instance._target != (Object)null && instance._target.activeSelf)
				{
					instance.SizeFor(cam, instance._target, Vector3.one, instance._targetMetres);
				}
				if ((Object)(object)instance._gameTarget != (Object)null && instance._gameTarget.activeInHierarchy)
				{
					instance.SizeFor(cam, instance._gameTarget, instance._gameTargetScale, instance._gameTargetMetres);
				}
			}
		}

		[HideFromIl2Cpp]
		private static bool Launch(RangedWeapon weapon, out Vector3 pos, out Vector3 dir)
		{
			//IL_001b: 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_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: 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)
			Transform val = SpawnPoint(weapon);
			pos = (Vector3)(((Object)(object)val == (Object)null) ? default(Vector3) : val.position);
			dir = (Vector3)(((Object)(object)val == (Object)null) ? default(Vector3) : val.forward);
			return (Object)(object)val != (Object)null;
		}

		private static Transform SpawnPoint(RangedWeapon weapon)
		{
			Transform physicalSpawnPoint = ((Weapon)weapon).physicalSpawnPoint;
			if (!((Object)(object)physicalSpawnPoint != (Object)null) || !weapon.HasLaserSight() || !((Object)(object)physicalSpawnPoint == (Object)(object)weapon._projectilePhysicalSpawnPoint))
			{
				return physicalSpawnPoint;
			}
			return weapon.GetProjectileTransform();
		}

		private static bool RefreshBulletInfo(RangedWeapon weapon)
		{
			Ammo ammo = weapon.GetAmmo();
			object obj;
			if (ammo == null)
			{
				obj = null;
			}
			else
			{
				AmmoProperties properties = ammo._properties;
				obj = ((properties != null) ? properties.ProjectileInfo : null);
			}
			ProjectileInfo val = (ProjectileInfo)obj;
			if (val == null)
			{
				return false;
			}
			weapon._simulatedBulletInfo = (BulletInfo)(object)val;
			if ((Object)(object)weapon._simulatedBullet == (Object)null)
			{
				weapon.SimulateTrajectory();
			}
			return true;
		}

		internal void Fired(RangedWeapon weapon, Vector3 direction, float zeroAngle)
		{
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: Unknown result type (might be due to invalid IL or missing references)
			//IL_012f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0151: Unknown result type (might be due to invalid IL or missing references)
			//IL_0156: Unknown result type (might be due to invalid IL or missing references)
			//IL_018c: 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_0195: Unknown result type (might be due to invalid IL or missing references)
			//IL_017b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0181: 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_020e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0237: Unknown result type (might be due to invalid IL or missing references)
			//IL_0250: Unknown result type (might be due to invalid IL or missing references)
			//IL_0252: Unknown result type (might be due to invalid IL or missing references)
			//IL_0274: Unknown result type (might be due to invalid IL or missing references)
			//IL_0276: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d3: Unknown result type (might be due to invalid IL or missing references)
			if (!ModLog.Full || (Object)(object)_weapon == (Object)null || ((Il2CppObjectBase)weapon).Pointer != ((Il2CppObjectBase)_weapon).Pointer || !_chosen || _gameOwn || Time.frameCount == _shotFrame)
			{
				return;
			}
			_shotFrame = Time.frameCount;
			Transform val = SpawnPoint(weapon);
			if ((Object)(object)val == (Object)null)
			{
				ModLog.Trace($"Shot {_kind}: the weapon has no spawn point, not compared with the indicator");
				return;
			}
			Vector3 position = val.position;
			Vector3 normalized = ((Vector3)(ref direction)).normalized;
			Transform projectileTransform = weapon.GetProjectileTransform();
			if (_pendingWeapon != IntPtr.Zero)
			{
				ModLog.Trace($"{_pendingKind}: previous shot's impact never reported (lost or out of range)");
			}
			bool flag = _lastDraw >= 0f && Time.unscaledTime - _lastDraw < 1f;
			bool flag2 = flag && _hit;
			TrajectoryData val2 = weapon.SimulateTrajectory(position, normalized);
			_pendingWeapon = ((Il2CppObjectBase)weapon).Pointer;
			_pendingKind = _kind;
			_pendingShown = _shownImpact;
			_pendingShownHit = flag2;
			_pendingReplayHit = val2.surfaceImpactDetected;
			? pendingReplay;
			if (!_pendingReplayHit)
			{
				pendingReplay = default(Vector3);
			}
			else
			{
				RaycastHit rayHit = val2.resultingSurfaceImpactInfo.rayHit;
				pendingReplay = ((RaycastHit)(ref rayHit)).point;
			}
			_pendingReplay = (Vector3)pendingReplay;
			_pendingTime = Time.time;
			ModLog.Trace($"Shot {_kind}: indicator {((!flag) ? "not shown" : (flag2 ? $"showed impact {_shownImpact:F1}" : "showed no impact"))}; real launch {position:F2} differs by {Vector3.Distance(position, _shownPos):F2} m and {Vector3.Angle(normalized, _shownDir):F2}° (at this instant: spawn point axis {Vector3.Angle(normalized, val.forward):F2}°, projectile axis {(((Object)(object)projectileTransform == (Object)null) ? "n/a" : Vector3.Angle(normalized, projectileTransform.forward).ToString("F2"))}°) (zero angle {zeroAngle:F2}, ammo {AmmoName(weapon)}); replay from real launch: {(_pendingReplayHit ? ((Vector3)(ref _pendingReplay)).ToString("F1") : "no impact")}");
		}

		internal void Landed(Weapon weapon, Vector3 point)
		{
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			if (!(_pendingWeapon == IntPtr.Zero) && !((Object)(object)weapon == (Object)null) && !(((Il2CppObjectBase)weapon).Pointer != _pendingWeapon))
			{
				_pendingWeapon = IntPtr.Zero;
				string value = (_pendingShownHit ? $"{Vector3.Distance(_pendingShown, point):F2} m" : "n/a (no impact shown)");
				string value2 = (_pendingReplayHit ? $"{Vector3.Distance(_pendingReplay, point):F2} m" : "n/a");
				ModLog.Trace($"Impact {_pendingKind}: real {point:F1} after {Time.time - _pendingTime:F2} s; indicator off by {value}, replay from real launch off by {value2}");
			}
		}

		private bool FindSpear()
		{
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Expected O, but got Unknown
			ItemData obj = ItemDatabaseManager.ItemById(ItemDatabase.CraftedSpearId);
			object obj2;
			if (obj == null)
			{
				obj2 = null;
			}
			else
			{
				Transform heldPrefab = obj.HeldPrefab;
				obj2 = ((heldPrefab != null) ? ((Component)heldPrefab).GetComponentInChildren<RangedWeapon>(true) : null);
			}
			RangedWeapon val = (RangedWeapon)obj2;
			if ((Object)(object)val == (Object)null || (Object)(object)val._trajectoryPathPrefab == (Object)null)
			{
				_failed = true;
				ManualLogSource logger = Plugin.Logger;
				bool flag = default(bool);
				BepInExErrorLogInterpolatedStringHandler val2 = new BepInExErrorLogInterpolatedStringHandler(71, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("The spear's aim indicator was not found (ranged part=");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<bool>((Object)(object)val != (Object)null);
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("); the mod is off.");
				}
				logger.LogError(val2);
				return false;
			}
			_linePrefab = val._trajectoryPathPrefab;
			_targetPrefab = val._impactTargetPrefab;
			float num = (((Object)(object)_targetPrefab != (Object)null) ? VisibleWidth(_targetPrefab) : 0f);
			if (num > 0f)
			{
				_targetMetres = num;
			}
			DefaultInterpolatedStringHandler defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(60, 4);
			defaultInterpolatedStringHandler.AppendLiteral("Spear indicator found: path=");
			defaultInterpolatedStringHandler.AppendFormatted(((Object)_linePrefab).name);
			defaultInterpolatedStringHandler.AppendLiteral(", target=");
			GameObject targetPrefab = _targetPrefab;
			defaultInterpolatedStringHandler.AppendFormatted((targetPrefab != null) ? ((Object)targetPrefab).name : null);
			defaultInterpolatedStringHandler.AppendLiteral(", ");
			defaultInterpolatedStringHandler.AppendFormatted(_targetMetres, "F2");
			defaultInterpolatedStringHandler.AppendLiteral(" m wide at scale 1 (");
			defaultInterpolatedStringHandler.AppendFormatted((num > 0f) ? "measured" : "not measurable, default kept");
			defaultInterpolatedStringHandler.AppendLiteral(")");
			ModLog.Trace(defaultInterpolatedStringHandler.ToStringAndClear());
			return true;
		}
	}
	[BepInPlugin("aznan.sotf.projectileaimindicator", "ProjectileAimIndicator", "0.2.20")]
	public class Plugin : BasePlugin
	{
		internal const string Version = "0.2.20";

		internal static ManualLogSource Logger;

		internal static ConfigEntry<bool> FullLogging;

		private static readonly Dictionary<WeaponKind, ConfigEntry<bool>> Chosen = new Dictionary<WeaponKind, ConfigEntry<bool>>();

		internal static ConfigEntry<float> LookupSeconds;

		internal static ConfigEntry<float> PathUpdateSeconds;

		internal static ConfigEntry<float> MarkerScreenSize;

		internal static ConfigEntry<float> MarkerMaxMetres;

		internal static ConfigEntry<bool> Enabled;

		private static Action<ScriptableRenderContext, Camera> _beforeCamera;

		private static string Describe(WeaponKind kind)
		{
			return kind switch
			{
				WeaponKind.FlareGun => "flare gun", 
				WeaponKind.Spear => "thrown spear", 
				WeaponKind.Thrown => "thrown items (grenade, molotov, time bomb, rocks, severed limbs)", 
				WeaponKind.RopeGun => "rope gun", 
				WeaponKind.StunGun => "stun gun", 
				WeaponKind.Firearm => "firearms (pistol, revolver, shotgun, rifle)", 
				_ => kind.ToString().ToLowerInvariant(), 
			};
		}

		internal static bool IsChosen(WeaponKind kind)
		{
			if (Enabled.Value && Chosen.TryGetValue(kind, out var value))
			{
				return value.Value;
			}
			return false;
		}

		public override void Load()
		{
			//IL_0270: Unknown result type (might be due to invalid IL or missing references)
			//IL_0277: Expected O, but got Unknown
			//IL_02dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e3: Expected O, but got Unknown
			//IL_0314: Unknown result type (might be due to invalid IL or missing references)
			//IL_031b: Expected O, but got Unknown
			//IL_020d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0213: Expected O, but got Unknown
			//IL_0249: Unknown result type (might be due to invalid IL or missing references)
			Logger = ((BasePlugin)this).Log;
			Decision.SelfCheck();
			Enabled = ((BasePlugin)this).Config.Bind<bool>("General", "Enabled", true, "True = the weapons ticked in [Weapons] show the aim indicator, and the game's own landing target of the items ticked there keeps the same size on screen. False = nothing from this mod (the game's own indicators stay as the game draws them).");
			bool flag = default(bool);
			foreach (WeaponKind value in Enum.GetValues(typeof(WeaponKind)))
			{
				if (value != WeaponKind.Other)
				{
					Dictionary<WeaponKind, ConfigEntry<bool>> chosen = Chosen;
					WeaponKind key = value;
					ConfigFile config = ((BasePlugin)this).Config;
					string text = value.ToString();
					bool num = Decision.OnByDefault(value);
					string text2;
					if (!Decision.GameDrawsOwn(value))
					{
						DefaultInterpolatedStringHandler defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(92, 3);
						defaultInterpolatedStringHandler.AppendLiteral("Show the thrown spear's aim indicator (path and landing target) while aiming the ");
						defaultInterpolatedStringHandler.AppendFormatted(Describe(value));
						defaultInterpolatedStringHandler.AppendFormatted((value == WeaponKind.FlareGun) ? " (if the game already draws its own, only its target is sized)" : "");
						defaultInterpolatedStringHandler.AppendLiteral(". Default ");
						flag = Decision.OnByDefault(value);
						defaultInterpolatedStringHandler.AppendFormatted(flag.ToString().ToLowerInvariant());
						defaultInterpolatedStringHandler.AppendLiteral(".");
						text2 = defaultInterpolatedStringHandler.ToStringAndClear();
					}
					else
					{
						text2 = "The game draws its own aim indicator for the " + Describe(value) + ". True = its landing target keeps the size set in [Marker] in every view (yours and ProjectileCam's preview); false = the game's own size. Default true.";
					}
					chosen[key] = config.Bind<bool>("Weapons", text, num, text2);
				}
			}
			MarkerScreenSize = ((BasePlugin)this).Config.Bind<float>("Marker", "ScreenSize", 0.02f, "Size of the landing target on your screen, as a share of the screen height: it keeps that size near or far. 0.02 = 2 % (default); the game's spear target is about 5 % at 10 m. Advised: 0.005 to 0.1.");
			MarkerMaxMetres = ((BasePlugin)this).Config.Bind<float>("Marker", "MaxMetres", 1f, "Largest size of the landing target on the ground, in metres, so a far target never hides what you aim at (the game's spear target is 0.5 m). Default 1. Advised: 0.2 to 5.");
			LookupSeconds = ((BasePlugin)this).Config.Bind<float>("Performance", "LookupSeconds", 0.5f, "While the item in your hand shows no ranged weapon yet (just equipped, or not a ranged weapon), seconds between two new looks. Advised: 0.1 to 5.");
			PathUpdateSeconds = ((BasePlugin)this).Config.Bind<float>("Performance", "PathUpdateSeconds", 0f, "While aiming, seconds between two path calculations. 0 = every frame, like the game's spear indicator (smoothest). Raise it (advised up to 0.1) if aiming costs too much on your PC; the line then follows your aim in small steps. Default 0.");
			FullLogging = ((BasePlugin)this).Config.Bind<bool>("Debug", "FullLogging", false, "True = the BepInEx log gets every step useful to diagnose a problem (decisions, values read, object aimed at, failures with their cause). False = only loading, version and errors.");
			ModLog.Init(Logger, FullLogging);
			ClassInjector.RegisterTypeInIl2Cpp<AimWatcher>();
			GameObject val = new GameObject("ProjectileAimIndicator");
			Object.DontDestroyOnLoad((Object)(object)val);
			((Object)val).hideFlags = (HideFlags)61;
			AimWatcher watcher = val.AddComponent<AimWatcher>();
			((BasePlugin)this).Config.SettingChanged += delegate
			{
				watcher.Refresh();
			};
			try
			{
				new Harmony("aznan.sotf.projectileaimindicator").PatchAll(typeof(ShotPatches).Assembly);
			}
			catch (Exception ex)
			{
				ManualLogSource logger = Logger;
				BepInExErrorLogInterpolatedStringHandler val2 = new BepInExErrorLogInterpolatedStringHandler(68, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Shot patches not installed, no shot is compared with the indicator: ");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(ex.Message);
				}
				logger.LogError(val2);
			}
			try
			{
				_beforeCamera = Action<ScriptableRenderContext, Camera>.op_Implicit((Action<ScriptableRenderContext, Camera>)AimWatcher.BeforeCamera);
				RenderPipelineManager.beginCameraRendering += _beforeCamera;
			}
			catch (Exception ex2)
			{
				ManualLogSource logger2 = Logger;
				BepInExErrorLogInterpolatedStringHandler val2 = new BepInExErrorLogInterpolatedStringHandler(82, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Per-camera target size not installed, the target is sized for your own view only: ");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(ex2.Message);
				}
				logger2.LogError(val2);
			}
			ManualLogSource logger3 = Logger;
			BepInExInfoLogInterpolatedStringHandler val3 = new BepInExInfoLogInterpolatedStringHandler(30, 1, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("ProjectileAimIndicator ");
				((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<string>("0.2.20");
				((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(" loaded");
			}
			logger3.LogInfo(val3);
		}
	}
}
namespace ProjectileAimIndicator.Patches
{
	public static class ShotPatches
	{
		[HarmonyPatch(typeof(RangedWeapon), "Shoot", new Type[]
		{
			typeof(Vector3),
			typeof(float),
			typeof(int)
		})]
		public static class Shoot
		{
			private static void Prefix(RangedWeapon __instance, Vector3 direction, float zeroAngle)
			{
				//IL_000b: Unknown result type (might be due to invalid IL or missing references)
				AimWatcher.Instance?.Fired(__instance, direction, zeroAngle);
			}
		}

		[HarmonyPatch(typeof(ProjectileImpactObject), "Impact")]
		public static class Impact
		{
			private static void Prefix(SurfaceImpactInfo surfaceImpactInfo)
			{
				//IL_0011: Unknown result type (might be due to invalid IL or missing references)
				//IL_0016: Unknown result type (might be due to invalid IL or missing references)
				//IL_0019: Unknown result type (might be due to invalid IL or missing references)
				AimWatcher instance = AimWatcher.Instance;
				if (instance != null)
				{
					Weapon weapon = surfaceImpactInfo.weapon;
					RaycastHit rayHit = surfaceImpactInfo.rayHit;
					instance.Landed(weapon, ((RaycastHit)(ref rayHit)).point);
				}
			}
		}
	}
}
namespace ProjectileAimIndicator.Logic
{
	public enum WeaponKind
	{
		Other,
		Bow,
		Crossbow,
		Slingshot,
		FlareGun,
		Spear,
		Thrown,
		RopeGun,
		StunGun,
		Firearm
	}
	public static class Decision
	{
		public static bool OnByDefault(WeaponKind kind)
		{
			if (kind != WeaponKind.Other && kind != WeaponKind.Firearm)
			{
				return kind != WeaponKind.StunGun;
			}
			return false;
		}

		public static bool GameDrawsOwn(WeaponKind kind)
		{
			if (kind != WeaponKind.Spear && kind != WeaponKind.Thrown)
			{
				return kind == WeaponKind.RopeGun;
			}
			return true;
		}

		public static bool ShouldShow(WeaponKind kind, bool chosen, bool midAttack, bool aiming)
		{
			if (chosen)
			{
				switch (kind)
				{
				case WeaponKind.Other:
					break;
				default:
					return midAttack || aiming;
				case WeaponKind.Bow:
					return midAttack;
				}
			}
			return false;
		}

		public static float MarkerScale(float distance, float fovDegrees, float screenShare, float maxMetres, float targetMetres)
		{
			float val = Math.Min(2f * distance * (float)Math.Tan((double)fovDegrees * Math.PI / 360.0) * screenShare, maxMetres);
			if (!(targetMetres > 0f))
			{
				return 1f;
			}
			return Math.Max(val, 0f) / targetMetres;
		}

		public static void SelfCheck()
		{
			if (!OnByDefault(WeaponKind.Bow) || !OnByDefault(WeaponKind.FlareGun) || OnByDefault(WeaponKind.Other) || !OnByDefault(WeaponKind.RopeGun) || !OnByDefault(WeaponKind.Thrown) || OnByDefault(WeaponKind.Firearm) || OnByDefault(WeaponKind.StunGun) || !GameDrawsOwn(WeaponKind.RopeGun) || !GameDrawsOwn(WeaponKind.Spear) || GameDrawsOwn(WeaponKind.Bow) || GameDrawsOwn(WeaponKind.Firearm))
			{
				throw new InvalidOperationException("Decision defaults are wrong.");
			}
			if (ShouldShow(WeaponKind.Bow, chosen: true, midAttack: false, aiming: true) || !ShouldShow(WeaponKind.Bow, chosen: true, midAttack: true, aiming: false) || !ShouldShow(WeaponKind.Slingshot, chosen: true, midAttack: false, aiming: true) || ShouldShow(WeaponKind.Slingshot, chosen: false, midAttack: true, aiming: true) || ShouldShow(WeaponKind.Other, chosen: true, midAttack: true, aiming: true))
			{
				throw new InvalidOperationException("Decision rules are wrong.");
			}
			if (Math.Abs(MarkerScale(10f, 90f, 0.02f, 1f, 0.5f) - 0.8f) > 0.0001f || Math.Abs(MarkerScale(100f, 90f, 0.02f, 1f, 0.5f) - 2f) > 0.0001f || MarkerScale(10f, 90f, 0.02f, 1f, 0f) != 1f || MarkerScale(10f, 90f, -1f, 1f, 0.5f) != 0f)
			{
				throw new InvalidOperationException("Decision.MarkerScale is wrong.");
			}
		}
	}
}