Decompiled source of TrajectoryVisualizer v2.5.3

BepInEx/plugins/TrajectoryVisualizer.dll

Decompiled a day ago
using System;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyVersion("0.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 TrajectoryVisualizer
{
	[BepInPlugin("com.syntx.stonewards.trajectoryvisualizer", "Trajectory Visualizer", "2.5.2")]
	public class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "com.syntx.stonewards.trajectoryvisualizer";

		public const string PluginName = "Trajectory Visualizer";

		public const string PluginVersion = "2.5.2";

		internal static Plugin Instance;

		internal static ManualLogSource Log;

		internal static ConfigEntry<bool> ShowBombTrajectory;

		internal static ConfigEntry<bool> ShowArrowTrajectory;

		internal static ConfigEntry<float> Gravity;

		internal static ConfigEntry<float> LineWidth;

		internal static ConfigEntry<float> RightOffset;

		internal static ConfigEntry<float> DownOffset;

		internal static ConfigEntry<float> MarkerSize;

		internal static ConfigEntry<float> DashLength;

		internal static ConfigEntry<float> DashGap;

		private Harmony _harmony;

		private void Awake()
		{
			//IL_0194: Unknown result type (might be due to invalid IL or missing references)
			//IL_019e: Expected O, but got Unknown
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			ShowBombTrajectory = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ShowBombTrajectory", true, "Show bomb arc while LMB is held.");
			ShowArrowTrajectory = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ShowArrowTrajectory", true, "Show arrow arc while LMB is held.");
			Gravity = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Gravity", 9.81f, "Same gravity as projectiles: v += down * g * dt.");
			LineWidth = ((BaseUnityPlugin)this).Config.Bind<float>("General", "LineWidth", 0.025f, "Dash thickness.");
			RightOffset = ((BaseUnityPlugin)this).Config.Bind<float>("General", "RightOffset", 0.22f, "Start slightly right of the crosshair.");
			DownOffset = ((BaseUnityPlugin)this).Config.Bind<float>("General", "DownOffset", 0.22f, "Start slightly below the camera.");
			MarkerSize = ((BaseUnityPlugin)this).Config.Bind<float>("General", "MarkerSize", 0.16f, "Impact marker size.");
			DashLength = ((BaseUnityPlugin)this).Config.Bind<float>("General", "DashLength", 0.55f, "Length of each dash.");
			DashGap = ((BaseUnityPlugin)this).Config.Bind<float>("General", "DashGap", 0.38f, "Gap between dashes.");
			Log.LogInfo((object)"====================================================");
			Log.LogInfo((object)"Trajectory Visualizer v2.5.2 loaded");
			Log.LogInfo((object)"Dashed arc. Thin ray only (no fat overlap). Archer force at any charge.");
			Log.LogInfo((object)"====================================================");
			UnityCache.Init();
			_harmony = new Harmony("com.syntx.stonewards.trajectoryvisualizer");
			int num = 0;
			num += Patch("FirstPersonController", "Update", "OnPlayerUpdate");
			num += Patch("ThrowableTool", "OnPrimaryAction", "OnThrowPrimary");
			num += Patch("BowTool", "OnPrimaryAction", "OnBowPrimary");
			Log.LogInfo((object)("Patches applied: " + num));
		}

		private int Patch(string typeName, string methodName, string postfixName)
		{
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Expected O, but got Unknown
			Type type = AccessTools.TypeByName(typeName);
			if (type == null)
			{
				Log.LogError((object)("Type not found: " + typeName));
				return 0;
			}
			MethodInfo methodInfo = null;
			MethodInfo[] methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (MethodInfo methodInfo2 in methods)
			{
				if (methodInfo2.Name == methodName)
				{
					methodInfo = methodInfo2;
					break;
				}
			}
			if (methodInfo == null)
			{
				Log.LogError((object)("Method not found: " + typeName + "." + methodName));
				return 0;
			}
			try
			{
				MethodInfo method = typeof(Patches).GetMethod(postfixName, BindingFlags.Static | BindingFlags.Public);
				_harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(method), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				Log.LogInfo((object)("OK  " + typeName + "." + methodInfo.Name));
				return 1;
			}
			catch (Exception ex)
			{
				Log.LogError((object)("FAIL " + typeName + "." + methodName + ": " + ex.Message));
				return 0;
			}
		}
	}
	internal static class UnityCache
	{
		private const BindingFlags Inst = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;

		private const BindingFlags Stat = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;

		private const int MaxDashes = 28;

		internal static Type Vector3Type;

		internal static Type ColorType;

		internal static Type LineRendererType;

		internal static Type GameObjectType;

		internal static Type ObjectType;

		internal static Type ShaderType;

		internal static Type MaterialType;

		internal static Type PhysicsType;

		internal static Type TransformType;

		internal static Type RendererType;

		internal static PropertyInfo CameraMain;

		internal static PropertyInfo TransformProp;

		internal static PropertyInfo PositionProp;

		internal static PropertyInfo ForwardProp;

		internal static PropertyInfo RightProp;

		internal static PropertyInfo LocalScaleProp;

		internal static PropertyInfo TimeSinceLevelLoad;

		internal static MethodInfo InputGetMouseButton;

		internal static MethodInfo ShaderFind;

		internal static MethodInfo DontDestroyOnLoad;

		internal static MethodInfo DestroyImmediate;

		internal static MethodInfo AddComponentGeneric;

		internal static MethodInfo AddComponentTyped;

		internal static MethodInfo CreatePrimitive;

		internal static MethodInfo GetComponentType;

		internal static MethodInfo RaycastAll;

		internal static MethodInfo OverlapSphere;

		internal static MethodInfo MaterialSetColor;

		internal static ConstructorInfo Vector3Ctor;

		internal static ConstructorInfo ColorCtor;

		internal static ConstructorInfo GameObjectCtor;

		internal static ConstructorInfo MaterialCtor;

		internal static FieldInfo VecX;

		internal static FieldInfo VecY;

		internal static FieldInfo VecZ;

		internal static PropertyInfo HitCollider;

		internal static PropertyInfo HitDistance;

		internal static PropertyInfo HitPoint;

		internal static PropertyInfo ColliderGameObject;

		internal static PropertyInfo GameObjectName;

		internal static PropertyInfo GameObjectTag;

		internal static PropertyInfo GameObjectTransform;

		internal static MethodInfo GetComponentInParentTyped;

		internal static object QueryCollide;

		internal static object PrimitiveSphere;

		internal static Type EnemyHitboxType;

		internal static Type EnemyControllerType;

		internal static Type HitboxType;

		internal static Type PlayerHitboxType;

		internal static PropertyInfo HitboxTypeProp;

		internal static object WhiteColor;

		internal static object RedColor;

		internal static object SharedMaterial;

		internal static object[] DashLines = new object[28];

		internal static object[] DashGos = new object[28];

		internal static MethodInfo[] DashSetPositions = new MethodInfo[28];

		internal static Array[] DashBuffers = new Array[28];

		internal static object MarkerGo;

		internal static object MarkerRenderer;

		internal static object MarkerMaterial;

		internal static bool Ready;

		internal static bool DashesReady;

		internal static bool LoggedFail;

		internal static void Init()
		{
			try
			{
				Type type = AccessTools.TypeByName("UnityEngine.Camera");
				TransformType = AccessTools.TypeByName("UnityEngine.Transform");
				Type type2 = AccessTools.TypeByName("UnityEngine.Input");
				Type type3 = AccessTools.TypeByName("UnityEngine.Time");
				Vector3Type = AccessTools.TypeByName("UnityEngine.Vector3");
				ColorType = AccessTools.TypeByName("UnityEngine.Color");
				LineRendererType = AccessTools.TypeByName("UnityEngine.LineRenderer");
				GameObjectType = AccessTools.TypeByName("UnityEngine.GameObject");
				ObjectType = AccessTools.TypeByName("UnityEngine.Object");
				ShaderType = AccessTools.TypeByName("UnityEngine.Shader");
				MaterialType = AccessTools.TypeByName("UnityEngine.Material");
				PhysicsType = AccessTools.TypeByName("UnityEngine.Physics");
				RendererType = AccessTools.TypeByName("UnityEngine.Renderer");
				Type type4 = AccessTools.TypeByName("UnityEngine.RaycastHit");
				Type type5 = AccessTools.TypeByName("UnityEngine.Collider");
				Type type6 = AccessTools.TypeByName("UnityEngine.QueryTriggerInteraction");
				Type type7 = AccessTools.TypeByName("UnityEngine.PrimitiveType");
				EnemyHitboxType = AccessTools.TypeByName("EnemyHitbox");
				EnemyControllerType = AccessTools.TypeByName("EnemyController");
				HitboxType = AccessTools.TypeByName("Hitbox");
				PlayerHitboxType = AccessTools.TypeByName("PlayerHitbox");
				if (HitboxType != null)
				{
					HitboxTypeProp = HitboxType.GetProperty("Type", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				}
				if (type != null)
				{
					CameraMain = type.GetProperty("main", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
					TransformProp = type.GetProperty("transform", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				}
				if (TransformType != null)
				{
					PositionProp = TransformType.GetProperty("position", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
					ForwardProp = TransformType.GetProperty("forward", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
					RightProp = TransformType.GetProperty("right", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
					LocalScaleProp = TransformType.GetProperty("localScale", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				}
				if (type3 != null)
				{
					TimeSinceLevelLoad = type3.GetProperty("timeSinceLevelLoad", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
					if (TimeSinceLevelLoad == null)
					{
						TimeSinceLevelLoad = type3.GetProperty("time", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
					}
				}
				if (type2 != null)
				{
					InputGetMouseButton = type2.GetMethod("GetMouseButton", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { typeof(int) }, null);
				}
				if (ShaderType != null)
				{
					ShaderFind = ShaderType.GetMethod("Find", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { typeof(string) }, null);
				}
				if (ObjectType != null)
				{
					DontDestroyOnLoad = ObjectType.GetMethod("DontDestroyOnLoad", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { ObjectType }, null);
					DestroyImmediate = ObjectType.GetMethod("DestroyImmediate", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { ObjectType }, null);
					if (DestroyImmediate == null)
					{
						DestroyImmediate = ObjectType.GetMethod("Destroy", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { ObjectType }, null);
					}
				}
				if (GameObjectType != null)
				{
					GameObjectCtor = GameObjectType.GetConstructor(new Type[1] { typeof(string) });
					AddComponentTyped = GameObjectType.GetMethod("AddComponent", new Type[1] { typeof(Type) });
					GetComponentType = GameObjectType.GetMethod("GetComponent", new Type[1] { typeof(Type) });
					GameObjectName = GameObjectType.GetProperty("name", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
					GameObjectTag = GameObjectType.GetProperty("tag", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
					GameObjectTransform = GameObjectType.GetProperty("transform", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
					MethodInfo[] methods = GameObjectType.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
					foreach (MethodInfo methodInfo in methods)
					{
						if (methodInfo.Name == "AddComponent" && methodInfo.IsGenericMethodDefinition && methodInfo.GetParameters().Length == 0)
						{
							AddComponentGeneric = methodInfo;
						}
					}
					if (type7 != null)
					{
						PrimitiveSphere = Enum.ToObject(type7, 0);
						CreatePrimitive = GameObjectType.GetMethod("CreatePrimitive", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { type7 }, null);
					}
				}
				if (Vector3Type != null)
				{
					Vector3Ctor = Vector3Type.GetConstructor(new Type[3]
					{
						typeof(float),
						typeof(float),
						typeof(float)
					});
					VecX = Vector3Type.GetField("x");
					VecY = Vector3Type.GetField("y");
					VecZ = Vector3Type.GetField("z");
				}
				if (ColorType != null)
				{
					ColorCtor = ColorType.GetConstructor(new Type[4]
					{
						typeof(float),
						typeof(float),
						typeof(float),
						typeof(float)
					});
				}
				if (MaterialType != null && ShaderType != null)
				{
					MaterialCtor = MaterialType.GetConstructor(new Type[1] { ShaderType });
					MaterialSetColor = MaterialType.GetMethod("SetColor", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[2]
					{
						typeof(string),
						ColorType
					}, null);
				}
				if (type6 != null)
				{
					QueryCollide = Enum.ToObject(type6, 2);
				}
				if (PhysicsType != null && Vector3Type != null)
				{
					MethodInfo[] methods = PhysicsType.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
					foreach (MethodInfo methodInfo2 in methods)
					{
						ParameterInfo[] parameters = methodInfo2.GetParameters();
						if (methodInfo2.Name == "RaycastAll" && parameters.Length >= 3 && RaycastAll == null)
						{
							RaycastAll = methodInfo2;
						}
						if (methodInfo2.Name == "OverlapSphere" && parameters.Length >= 2 && OverlapSphere == null)
						{
							OverlapSphere = methodInfo2;
						}
					}
					methods = PhysicsType.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
					foreach (MethodInfo methodInfo3 in methods)
					{
						ParameterInfo[] parameters2 = methodInfo3.GetParameters();
						if (methodInfo3.Name == "RaycastAll" && parameters2.Length == 5)
						{
							RaycastAll = methodInfo3;
						}
						if (methodInfo3.Name == "OverlapSphere" && parameters2.Length == 4)
						{
							OverlapSphere = methodInfo3;
						}
					}
				}
				if (type4 != null)
				{
					HitCollider = type4.GetProperty("collider", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
					HitDistance = type4.GetProperty("distance", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
					HitPoint = type4.GetProperty("point", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				}
				if (type5 != null)
				{
					ColliderGameObject = type5.GetProperty("gameObject", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
					MethodInfo[] methods = type5.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
					foreach (MethodInfo methodInfo4 in methods)
					{
						if (methodInfo4.Name == "GetComponentInParent" && methodInfo4.GetParameters().Length == 1 && methodInfo4.GetParameters()[0].ParameterType == typeof(Type))
						{
							GetComponentInParentTyped = methodInfo4;
						}
					}
				}
				Ready = type != null && Vector3Type != null && GameObjectType != null && LineRendererType != null;
				Plugin.Log.LogInfo((object)("Unity cache ready. timeSinceLevelLoad=" + (TimeSinceLevelLoad != null) + " RaycastAll=" + (RaycastAll != null)));
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("UnityCache.Init failed: " + ex));
			}
		}

		internal static float Now()
		{
			try
			{
				if (TimeSinceLevelLoad != null)
				{
					return Convert.ToSingle(TimeSinceLevelLoad.GetValue(null));
				}
			}
			catch
			{
			}
			return 0f;
		}

		internal static bool IsLmbHeld()
		{
			try
			{
				if (InputGetMouseButton != null)
				{
					return Convert.ToBoolean(InputGetMouseButton.Invoke(null, new object[1] { 0 }));
				}
			}
			catch
			{
			}
			if (!Patches.ThrowHeld)
			{
				return Patches.BowHeld;
			}
			return true;
		}

		internal static bool TryGetCamVectors(out Vec3 pos, out Vec3 forward, out Vec3 right)
		{
			pos = default(Vec3);
			forward = default(Vec3);
			right = default(Vec3);
			try
			{
				object obj = ((CameraMain != null) ? CameraMain.GetValue(null) : null);
				if (obj == null)
				{
					return false;
				}
				object obj2 = ((TransformProp != null) ? TransformProp.GetValue(obj) : null);
				if (obj2 == null)
				{
					return false;
				}
				object value = PositionProp.GetValue(obj2);
				object value2 = ForwardProp.GetValue(obj2);
				object value3 = RightProp.GetValue(obj2);
				if (value == null || value2 == null || value3 == null)
				{
					return false;
				}
				pos = Vec3.From(value);
				forward = Vec3.From(value2);
				right = Vec3.From(value3);
				return true;
			}
			catch
			{
				return false;
			}
		}

		internal static object MakeV3(float x, float y, float z)
		{
			return Vector3Ctor.Invoke(new object[3] { x, y, z });
		}

		internal static object MakeColor(float r, float g, float b, float a)
		{
			return ColorCtor.Invoke(new object[4] { r, g, b, a });
		}

		private static object FindShader()
		{
			if (ShaderFind == null)
			{
				return null;
			}
			string[] array = new string[4] { "Sprites/Default", "Hidden/Internal-Colored", "Unlit/Color", "Universal Render Pipeline/Unlit" };
			foreach (string text in array)
			{
				object obj = ShaderFind.Invoke(null, new object[1] { text });
				if (obj != null)
				{
					return obj;
				}
			}
			return null;
		}

		private static object MakeMaterial()
		{
			object obj = FindShader();
			if (MaterialCtor == null || obj == null)
			{
				return null;
			}
			return MaterialCtor.Invoke(new object[1] { obj });
		}

		internal static void EnsureVisuals()
		{
			if (DashesReady || !Ready)
			{
				return;
			}
			try
			{
				SharedMaterial = MakeMaterial();
				WhiteColor = MakeColor(1f, 1f, 1f, 1f);
				RedColor = MakeColor(1f, 0.08f, 0.08f, 1f);
				for (int i = 0; i < 28; i++)
				{
					object obj = GameObjectCtor.Invoke(new object[1] { "SW_Dash_" + i });
					object obj2 = ((!(AddComponentGeneric != null)) ? AddComponentTyped.Invoke(obj, new object[1] { LineRendererType }) : AddComponentGeneric.MakeGenericMethod(LineRendererType).Invoke(obj, null));
					DashGos[i] = obj;
					DashLines[i] = obj2;
					DashBuffers[i] = Array.CreateInstance(Vector3Type, 2);
					SetProp(obj2, "useWorldSpace", true);
					SetProp(obj2, "shadowCastingMode", 0);
					SetProp(obj2, "receiveShadows", false);
					SetProp(obj2, "positionCount", 2);
					SetProp(obj2, "enabled", false);
					if (SharedMaterial != null)
					{
						SetProp(obj2, "material", SharedMaterial);
					}
					MethodInfo[] methods = obj2.GetType().GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
					foreach (MethodInfo methodInfo in methods)
					{
						if (methodInfo.Name == "SetPositions" && methodInfo.GetParameters().Length == 1)
						{
							DashSetPositions[i] = methodInfo;
							break;
						}
					}
					if (DontDestroyOnLoad != null)
					{
						DontDestroyOnLoad.Invoke(null, new object[1] { obj });
					}
				}
				EnsureMarker();
				DashesReady = true;
				Plugin.Log.LogInfo((object)"Dashed trajectory ready.");
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("EnsureVisuals failed: " + ex));
			}
		}

		private static void EnsureMarker()
		{
			if (MarkerGo != null)
			{
				return;
			}
			try
			{
				if (CreatePrimitive != null && PrimitiveSphere != null)
				{
					MarkerGo = CreatePrimitive.Invoke(null, new object[1] { PrimitiveSphere });
					SetProp(MarkerGo, "name", "SW_ImpactMarker");
					object obj = ((GetComponentType != null) ? GetComponentType.Invoke(MarkerGo, new object[1] { AccessTools.TypeByName("UnityEngine.Collider") }) : null);
					if (obj != null && DestroyImmediate != null)
					{
						DestroyImmediate.Invoke(null, new object[1] { obj });
					}
					MarkerRenderer = ((GetComponentType != null) ? GetComponentType.Invoke(MarkerGo, new object[1] { RendererType }) : null);
					MarkerMaterial = MakeMaterial();
					if (MarkerRenderer != null && MarkerMaterial != null)
					{
						SetProp(MarkerRenderer, "material", MarkerMaterial);
					}
					if (DontDestroyOnLoad != null)
					{
						DontDestroyOnLoad.Invoke(null, new object[1] { MarkerGo });
					}
					SetActive(MarkerGo, on: false);
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Marker failed: " + ex.Message));
			}
		}

		private static void SetProp(object obj, string name, object value)
		{
			if (obj == null)
			{
				return;
			}
			try
			{
				PropertyInfo property = obj.GetType().GetProperty(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (property != null && property.CanWrite)
				{
					property.SetValue(obj, value, null);
				}
			}
			catch
			{
			}
		}

		private static void SetActive(object go, bool on)
		{
			if (go == null)
			{
				return;
			}
			try
			{
				MethodInfo method = go.GetType().GetMethod("SetActive", new Type[1] { typeof(bool) });
				if (method != null)
				{
					method.Invoke(go, new object[1] { on });
				}
			}
			catch
			{
			}
		}

		internal static void HideLine()
		{
			if (DashesReady)
			{
				for (int i = 0; i < 28; i++)
				{
					SetProp(DashLines[i], "enabled", false);
				}
				SetActive(MarkerGo, on: false);
			}
		}

		internal static void DrawArc(Vec3 origin, Vec3 dir, float speed, out bool hitsEnemy)
		{
			hitsEnemy = false;
			EnsureVisuals();
			if (!DashesReady)
			{
				return;
			}
			float value = Plugin.Gravity.Value;
			float num = 0.03f;
			int num2 = 70;
			Vec3 vec = origin;
			Vec3 p = origin;
			bool flag = false;
			Vec3[] array = new Vec3[num2];
			int count = 0;
			array[count++] = origin;
			for (int i = 1; i < num2; i++)
			{
				if (flag)
				{
					break;
				}
				float num3 = (float)i * num;
				Vec3 vec2 = new Vec3(origin.x + dir.x * speed * num3, origin.y + dir.y * speed * num3 - 0.5f * value * num3 * num3, origin.z + dir.z * speed * num3);
				try
				{
					if (TryHit(vec, vec2, out var enemy, out var hitPoint))
					{
						vec2 = hitPoint;
						hitsEnemy = enemy;
						flag = true;
					}
				}
				catch
				{
				}
				if (i > 4 && vec2.y < origin.y - 80f)
				{
					flag = true;
				}
				array[count++] = vec2;
				vec = vec2;
				p = vec2;
			}
			object color = (hitsEnemy ? RedColor : WhiteColor);
			ApplyColor(SharedMaterial, color);
			DrawDashes(array, count, color);
			DrawImpactMarker(p, color);
		}

		private static void DrawDashes(Vec3[] pts, int count, object color)
		{
			float num = Plugin.DashLength.Value;
			float num2 = Plugin.DashGap.Value;
			if (num < 0.08f)
			{
				num = 0.08f;
			}
			if (num2 < 0.05f)
			{
				num2 = 0.05f;
			}
			float num3 = num + num2;
			int num4 = 0;
			float num5 = 0f;
			for (int i = 1; i < count; i++)
			{
				if (num4 >= 28)
				{
					break;
				}
				Vec3 a = pts[i - 1];
				Vec3 b = pts[i];
				float num6 = Dist(a, b);
				if (num6 < 0.0001f)
				{
					continue;
				}
				float num7 = num5;
				float num8 = num5 + num6;
				int num9 = (int)Math.Floor(num7 / num3);
				int num10 = (int)Math.Floor(num8 / num3);
				for (int j = num9; j <= num10; j++)
				{
					if (num4 >= 28)
					{
						break;
					}
					float num11 = (float)j * num3;
					float num12 = num11 + num;
					float num13 = ((num7 > num11) ? num7 : num11);
					float num14 = ((num8 < num12) ? num8 : num12);
					if (num14 > num13 + 0.001f)
					{
						float t = (num13 - num7) / num6;
						float t2 = (num14 - num7) / num6;
						SetDash(num4++, Lerp(a, b, t), Lerp(a, b, t2), color);
					}
				}
				num5 = num8;
			}
			for (int k = num4; k < 28; k++)
			{
				SetProp(DashLines[k], "enabled", false);
			}
		}

		private static void SetDash(int i, Vec3 a, Vec3 b, object color)
		{
			object obj = DashLines[i];
			if (obj != null)
			{
				SetProp(obj, "enabled", true);
				SetProp(obj, "positionCount", 2);
				float value = Plugin.LineWidth.Value;
				SetProp(obj, "startWidth", value);
				SetProp(obj, "endWidth", value);
				SetProp(obj, "startColor", color);
				SetProp(obj, "endColor", color);
				Array array = DashBuffers[i];
				array.SetValue(MakeV3(a.x, a.y, a.z), 0);
				array.SetValue(MakeV3(b.x, b.y, b.z), 1);
				if (DashSetPositions[i] != null)
				{
					DashSetPositions[i].Invoke(obj, new object[1] { array });
				}
			}
		}

		private static float Dist(Vec3 a, Vec3 b)
		{
			float num = a.x - b.x;
			float num2 = a.y - b.y;
			float num3 = a.z - b.z;
			return (float)Math.Sqrt(num * num + num2 * num2 + num3 * num3);
		}

		private static Vec3 Lerp(Vec3 a, Vec3 b, float t)
		{
			return new Vec3(a.x + (b.x - a.x) * t, a.y + (b.y - a.y) * t, a.z + (b.z - a.z) * t);
		}

		private static void ApplyColor(object mat, object color)
		{
			if (mat == null || color == null)
			{
				return;
			}
			SetProp(mat, "color", color);
			if (!(MaterialSetColor != null))
			{
				return;
			}
			try
			{
				MaterialSetColor.Invoke(mat, new object[2] { "_Color", color });
			}
			catch
			{
			}
			try
			{
				MaterialSetColor.Invoke(mat, new object[2] { "_BaseColor", color });
			}
			catch
			{
			}
		}

		private static void DrawImpactMarker(Vec3 p, object color)
		{
			if (MarkerGo == null)
			{
				return;
			}
			SetActive(MarkerGo, on: true);
			object obj = ((GameObjectTransform != null) ? GameObjectTransform.GetValue(MarkerGo) : null);
			if (obj != null)
			{
				if (PositionProp != null)
				{
					PositionProp.SetValue(obj, MakeV3(p.x, p.y, p.z), null);
				}
				float value = Plugin.MarkerSize.Value;
				if (LocalScaleProp != null)
				{
					LocalScaleProp.SetValue(obj, MakeV3(value, value, value), null);
				}
			}
			ApplyColor(MarkerMaterial, color);
			if (MarkerRenderer != null)
			{
				SetProp(MarkerRenderer, "enabled", true);
			}
		}

		private static object InvokeRaycastAll(object origin, object direction, float dist)
		{
			if (RaycastAll == null)
			{
				return null;
			}
			ParameterInfo[] parameters = RaycastAll.GetParameters();
			if (parameters.Length >= 5)
			{
				return RaycastAll.Invoke(null, new object[5]
				{
					origin,
					direction,
					dist,
					-1,
					QueryCollide ?? ((object)2)
				});
			}
			if (parameters.Length == 4)
			{
				return RaycastAll.Invoke(null, new object[4] { origin, direction, dist, -1 });
			}
			return RaycastAll.Invoke(null, new object[3] { origin, direction, dist });
		}

		private static object InvokeOverlap(object pos, float radius)
		{
			if (OverlapSphere == null)
			{
				return null;
			}
			ParameterInfo[] parameters = OverlapSphere.GetParameters();
			if (parameters.Length >= 4)
			{
				return OverlapSphere.Invoke(null, new object[4]
				{
					pos,
					radius,
					-1,
					QueryCollide ?? ((object)2)
				});
			}
			if (parameters.Length == 3)
			{
				return OverlapSphere.Invoke(null, new object[3] { pos, radius, -1 });
			}
			return OverlapSphere.Invoke(null, new object[2] { pos, radius });
		}

		private static bool TryHit(Vec3 from, Vec3 to, out bool enemy, out Vec3 hitPoint)
		{
			enemy = false;
			hitPoint = to;
			Vec3 vec = new Vec3(to.x - from.x, to.y - from.y, to.z - from.z);
			float num = (float)Math.Sqrt(vec.SqrMag());
			if (num < 0.001f)
			{
				return false;
			}
			Vec3 vec2 = vec.Mul(1f / num);
			try
			{
				object origin = MakeV3(from.x, from.y, from.z);
				object direction = MakeV3(vec2.x, vec2.y, vec2.z);
				Array array = InvokeRaycastAll(origin, direction, num + 0.01f) as Array;
				object obj = null;
				float num2 = float.MaxValue;
				bool flag = false;
				if (array != null)
				{
					for (int i = 0; i < array.Length; i++)
					{
						object value = array.GetValue(i);
						if (value == null)
						{
							continue;
						}
						float num3 = ((HitDistance != null) ? Convert.ToSingle(HitDistance.GetValue(value)) : ((float)i));
						if (!(num3 < 0.04f) && !IsPlayerHit(value))
						{
							bool flag2 = IsEnemyHitObject((HitCollider != null) ? HitCollider.GetValue(value) : null);
							if (obj == null || (flag2 && !flag) || (!flag && num3 < num2))
							{
								obj = value;
								num2 = num3;
								flag = flag2;
							}
							if (flag2)
							{
								break;
							}
						}
					}
				}
				if (obj == null)
				{
					return false;
				}
				enemy = flag;
				object obj2 = ((HitPoint != null) ? HitPoint.GetValue(obj) : null);
				if (obj2 != null)
				{
					hitPoint = Vec3.From(obj2);
				}
				return true;
			}
			catch
			{
				return false;
			}
		}

		private static bool IsPlayerHit(object hit)
		{
			return IsPlayerHitCollider((HitCollider != null) ? HitCollider.GetValue(hit) : null);
		}

		private static bool IsPlayerHitCollider(object col)
		{
			if (col == null)
			{
				return false;
			}
			if (PlayerHitboxType != null && FindComponent(col, PlayerHitboxType) != null)
			{
				return true;
			}
			object obj = ((ColliderGameObject != null) ? ColliderGameObject.GetValue(col) : null);
			string text = ((obj != null && GameObjectName != null) ? Convert.ToString(GameObjectName.GetValue(obj)) : "");
			if (!string.IsNullOrEmpty(text))
			{
				return text.IndexOf("Player", StringComparison.OrdinalIgnoreCase) >= 0;
			}
			return false;
		}

		private static bool IsEnemyHitObject(object obj)
		{
			if (obj == null)
			{
				return false;
			}
			if (PlayerHitboxType != null && FindComponent(obj, PlayerHitboxType) != null)
			{
				return false;
			}
			if (EnemyHitboxType != null && FindComponent(obj, EnemyHitboxType) != null)
			{
				return true;
			}
			if (EnemyControllerType != null && FindComponent(obj, EnemyControllerType) != null)
			{
				return true;
			}
			object obj2 = ((HitboxType != null) ? FindComponent(obj, HitboxType) : null);
			if (obj2 != null && HitboxTypeProp != null)
			{
				object value = HitboxTypeProp.GetValue(obj2);
				string text = ((value != null) ? Convert.ToString(value) : "");
				if (text.IndexOf("PLAYER", StringComparison.OrdinalIgnoreCase) >= 0)
				{
					return false;
				}
				if (text.IndexOf("NORMAL", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("ELITE", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("BOSS", StringComparison.OrdinalIgnoreCase) >= 0)
				{
					return true;
				}
			}
			return false;
		}

		private static object FindComponent(object obj, Type type)
		{
			if (obj == null || type == null)
			{
				return null;
			}
			try
			{
				if (type.IsInstanceOfType(obj))
				{
					return obj;
				}
				MethodInfo method = obj.GetType().GetMethod("GetComponent", new Type[1] { typeof(Type) });
				if (method != null)
				{
					object obj2 = method.Invoke(obj, new object[1] { type });
					if (obj2 != null)
					{
						return obj2;
					}
				}
				if (GetComponentInParentTyped != null)
				{
					object obj3 = GetComponentInParentTyped.Invoke(obj, new object[1] { type });
					if (obj3 != null)
					{
						return obj3;
					}
				}
			}
			catch
			{
			}
			return null;
		}
	}
	public static class Patches
	{
		internal static bool ThrowHeld;

		internal static bool BowHeld;

		private static bool _wasLmb;

		private static float _holdStart;

		private static object _cachedItem;

		private static int _equipTick;

		private static int _hideFrames;

		private static float _lastLoggedCharge = -1f;

		public static void OnThrowPrimary(bool _B)
		{
			ThrowHeld = _B;
			if (_B)
			{
				_holdStart = UnityCache.Now();
			}
			else
			{
				UnityCache.HideLine();
			}
		}

		public static void OnBowPrimary(bool _B)
		{
			BowHeld = _B;
			if (_B)
			{
				_holdStart = UnityCache.Now();
			}
			else
			{
				UnityCache.HideLine();
			}
		}

		public static void OnPlayerUpdate(object __instance)
		{
			if (!IsLocalPlayer(__instance))
			{
				return;
			}
			bool num = UnityCache.IsLmbHeld();
			if (num && !_wasLmb)
			{
				_holdStart = UnityCache.Now();
			}
			_wasLmb = num;
			if (!num)
			{
				if (_hideFrames < 2)
				{
					UnityCache.HideLine();
					_hideFrames++;
				}
				ThrowHeld = false;
				BowHeld = false;
				return;
			}
			_hideFrames = 0;
			if ((_equipTick++ & 3) == 0 || _cachedItem == null)
			{
				_cachedItem = GetEquippedItem(__instance);
			}
			object cachedItem = _cachedItem;
			string name = cachedItem?.GetType().Name;
			bool flag = Plugin.ShowBombTrajectory.Value && IsBombTool(name);
			bool flag2 = Plugin.ShowArrowTrajectory.Value && IsBowTool(name);
			if (!flag && !flag2)
			{
				UnityCache.HideLine();
				return;
			}
			if (!UnityCache.TryGetCamVectors(out var pos, out var forward, out var right))
			{
				UnityCache.HideLine();
				return;
			}
			float charge = GetCharge01(cachedItem);
			float speed = GetSpeed(cachedItem, __instance, flag, charge);
			UnityCache.DrawArc(GetStart(cachedItem, pos, forward, right), forward.Normalized(), speed, out var _);
			if (Math.Abs(charge - _lastLoggedCharge) > 0.24f)
			{
				_lastLoggedCharge = charge;
				Plugin.Log.LogInfo((object)((flag ? "bomb" : "arrow") + " charge=" + charge.ToString("0.00") + " speed=" + speed.ToString("0.0") + " hold=" + (UnityCache.Now() - _holdStart).ToString("0.00")));
			}
		}

		private static Vec3 GetStart(object item, Vec3 camPos, Vec3 forward, Vec3 right)
		{
			Vec3 result = camPos.Add(forward.Mul(0.35f)).Add(right.Mul(Plugin.RightOffset.Value)).Add(new Vec3(0f, 0f - Plugin.DownOffset.Value, 0f));
			if (item == null)
			{
				return result;
			}
			try
			{
				object member = GetMember(item, "bowPosition");
				if (member != null && UnityCache.PositionProp != null)
				{
					object value = UnityCache.PositionProp.GetValue(member);
					if (value != null)
					{
						return Vec3.From(value).Add(forward.Mul(0.12f));
					}
				}
			}
			catch
			{
			}
			return result;
		}

		private static float GetCharge01(object tool)
		{
			float num = UnityCache.Now();
			float num2 = 0.75f;
			float num3 = _holdStart;
			bool flag = false;
			if (tool != null)
			{
				float num4 = ToFloat(GetMember(tool, "aimingDuration"), 0f);
				if (num4 > 0.05f)
				{
					num2 = num4;
				}
				if (GetMember(tool, "isFullyCharged") is bool flag2)
				{
					flag = flag2;
				}
				float num5 = ToFloat(GetMember(tool, "aimingStartTime"), 0f);
				if (num5 > 0.05f)
				{
					num3 = num5;
				}
			}
			if (flag)
			{
				return 1f;
			}
			float num6 = (num - num3) / num2;
			if (num6 < 0f)
			{
				num6 = 0f;
			}
			if (num6 > 1f)
			{
				num6 = 1f;
			}
			return num6;
		}

		private static float GetSpeed(object item, object player, bool bomb, float charge)
		{
			float num = (bomb ? 8f : 18f);
			float num2 = (bomb ? 22f : 42f);
			if (bomb && item != null)
			{
				object member = GetMember(item, "forceRange");
				if (member != null)
				{
					float num3 = ToFloat(GetMember(member, "x"), 0f);
					float num4 = ToFloat(GetMember(member, "y"), 0f);
					if (num3 > 0.1f)
					{
						num = num3;
					}
					if (num4 > 0.1f)
					{
						num2 = num4;
					}
				}
			}
			if (!bomb && player != null)
			{
				try
				{
					object obj = GetMember(player, "FPSSettingsSO") ?? GetMember(player, "fpsSettingsSo");
					object obj2 = GetMember(obj, "BowForce") ?? GetMember(obj, "bowForce");
					if (obj2 != null)
					{
						float num5 = ToFloat(GetMember(obj2, "x"), 0f);
						float num6 = ToFloat(GetMember(obj2, "y"), 0f);
						if (num5 > 0.1f)
						{
							num = num5;
						}
						if (num6 > 0.1f)
						{
							num2 = num6;
						}
					}
				}
				catch
				{
				}
			}
			float num7 = num + (num2 - num) * charge;
			if (!bomb && player != null)
			{
				try
				{
					object obj4 = GetMember(player, "playerClass") ?? GetMember(player, "NetworkplayerClass");
					int num8 = ((obj4 != null) ? Convert.ToInt32(obj4) : (-1));
					object obj5 = GetMember(player, "PlayerArchetypeSO") ?? GetMember(player, "playerArchetypeSO");
					object obj6 = GetMember(obj5, "ArcherStats") ?? GetMember(obj5, "archerStats");
					float num9 = ToFloat(GetMember(obj6, "ArrowForceMultiplayer") ?? GetMember(obj6, "arrowForceMultiplayer"), 1f);
					if (num9 > 0.05f && (num8 == 1 || obj6 != null))
					{
						num7 *= num9;
					}
				}
				catch
				{
				}
			}
			float num10 = ToFloat(GetMember((player != null) ? (GetMember(player, "PlayerStats") ?? GetMember(player, "playerStats")) : null, "ProjectileSpeed"), 1f);
			if (!bomb && num10 > 0.05f && num10 < 10f)
			{
				num7 *= num10;
			}
			return num7;
		}

		private static float ToFloat(object v, float fallback)
		{
			if (v == null)
			{
				return fallback;
			}
			try
			{
				return Convert.ToSingle(v);
			}
			catch
			{
				return fallback;
			}
		}

		private static bool IsBombTool(string name)
		{
			if (!string.IsNullOrEmpty(name))
			{
				if (name.IndexOf("Throwable", StringComparison.OrdinalIgnoreCase) < 0)
				{
					return name.IndexOf("Bomb", StringComparison.OrdinalIgnoreCase) >= 0;
				}
				return true;
			}
			return false;
		}

		private static bool IsBowTool(string name)
		{
			if (!string.IsNullOrEmpty(name))
			{
				return name.IndexOf("Bow", StringComparison.OrdinalIgnoreCase) >= 0;
			}
			return false;
		}

		private static bool IsLocalPlayer(object player)
		{
			if (player == null)
			{
				return false;
			}
			try
			{
				PropertyInfo property = player.GetType().GetProperty("isLocalPlayer", BindingFlags.Instance | BindingFlags.Public);
				if (property != null)
				{
					return Convert.ToBoolean(property.GetValue(player));
				}
			}
			catch
			{
			}
			return true;
		}

		private static object GetEquippedItem(object player)
		{
			try
			{
				object obj = GetMember(player, "PlayerEquipment") ?? GetMember(player, "playerEquipment");
				if (obj == null)
				{
					return null;
				}
				return GetMember(obj, "CurrentEquippedItem") ?? GetMember(obj, "currentEquippedItem");
			}
			catch
			{
				return null;
			}
		}

		private static object GetMember(object obj, string name)
		{
			if (obj == null)
			{
				return null;
			}
			PropertyInfo property = obj.GetType().GetProperty(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (property != null)
			{
				return property.GetValue(obj);
			}
			FieldInfo fieldInfo = AccessTools.Field(obj.GetType(), name);
			if (!(fieldInfo != null))
			{
				return null;
			}
			return fieldInfo.GetValue(obj);
		}
	}
	internal struct Vec3
	{
		public float x;

		public float y;

		public float z;

		public Vec3(float x, float y, float z)
		{
			this.x = x;
			this.y = y;
			this.z = z;
		}

		public static Vec3 From(object obj)
		{
			return new Vec3(Convert.ToSingle(UnityCache.VecX.GetValue(obj)), Convert.ToSingle(UnityCache.VecY.GetValue(obj)), Convert.ToSingle(UnityCache.VecZ.GetValue(obj)));
		}

		public Vec3 Add(Vec3 o)
		{
			return new Vec3(x + o.x, y + o.y, z + o.z);
		}

		public Vec3 Mul(float s)
		{
			return new Vec3(x * s, y * s, z * s);
		}

		public float SqrMag()
		{
			return x * x + y * y + z * z;
		}

		public Vec3 Normalized()
		{
			float num = (float)Math.Sqrt(SqrMag());
			if (num < 0.0001f)
			{
				return new Vec3(0f, 0f, 1f);
			}
			return new Vec3(x / num, y / num, z / num);
		}
	}
}