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