using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Globalization;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using CrossHair.Utilities;
using GameNetcodeStuff;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("com.ctnoriginals.crosshair")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Adds a CrossHair to the center of your screen to indicate where you are aiming.")]
[assembly: AssemblyFileVersion("1.1.1.0")]
[assembly: AssemblyInformationalVersion("1.1.1")]
[assembly: AssemblyProduct("CrossHair")]
[assembly: AssemblyTitle("com.ctnoriginals.crosshair")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.1.1.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.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 CrossHair
{
[BepInPlugin("com.ctnoriginals.crosshair", "CrossHair", "1.1.1")]
public class Plugin : BaseUnityPlugin
{
private readonly Harmony harmony = new Harmony("com.ctnoriginals.crosshair");
public static ConfigFile Config = new ConfigFile(Paths.ConfigPath + "\\com.ctnoriginals.crosshair.cfg", true);
public static ConfigEntry<string> CrossHairText;
public static ConfigEntry<float> CrossHairSize;
public static ConfigEntry<bool> CrossHairShadow;
public static ConfigEntry<string> CrossHairColor;
public static ConfigEntry<int> CrossHairOpacity;
public static ConfigEntry<bool> CrossHairFading;
public static ManualLogSource CLog;
public static bool DebugMode = false;
private void Awake()
{
CLog = ((BaseUnityPlugin)this).Logger;
CLog.LogInfo((object)("Plugin com.ctnoriginals.crosshair is loaded! Version: 1.1.1 (" + (DebugMode ? "Debug" : "Release") + ")"));
ConfigFile();
harmony.PatchAll();
}
private void ConfigFile()
{
CrossHairText = Config.Bind<string>("!General", "CrossHairText", "- + -", "Text to display as crosshair (use \\n for new line)");
CrossHairSize = Config.Bind<float>("!General", "CrossHairSize", 50f, "Size of the crosshair");
CrossHairShadow = Config.Bind<bool>("!General", "CrossHairShadow", true, "Whether to display a shadow behind the crosshair");
CrossHairColor = Config.Bind<string>("Appearance", "CrossHairColor", "ffffff", "Color of the crosshair in hexadecimal (Do not include the #)");
CrossHairOpacity = Config.Bind<int>("Appearance", "CrossHairOpacity", 80, "Opacity of the crosshair (0 to 100)%");
CrossHairFading = Config.Bind<bool>("Appearance", "CrossHairFading", true, "Whether the crosshair should fade in and out in specific situations");
CrossHair.Utilities.Console.LogMessage("CrossHairText: " + CrossHairText.Value);
CrossHair.Utilities.Console.LogMessage($"CrossHairSize: {CrossHairSize.Value}");
CrossHair.Utilities.Console.LogMessage($"CrossHairShadow: {CrossHairShadow.Value}");
CrossHair.Utilities.Console.LogMessage("CrossHairColor: " + CrossHairColor.Value);
CrossHair.Utilities.Console.LogMessage($"CrossHairOpacity: {CrossHairOpacity.Value}");
CrossHair.Utilities.Console.LogMessage($"CrossHairFading: {CrossHairFading.Value}");
Config.Save();
}
}
public static class PluginInfo
{
public const string PLUGIN_GUID = "com.ctnoriginals.crosshair";
public const string PLUGIN_NAME = "CrossHair";
public const string PLUGIN_VERSION = "1.1.1";
}
}
namespace CrossHair.Utilities
{
public static class Console
{
public static void Log(string message)
{
SendLog(message, "Log");
}
public static void LogInfo(string message)
{
SendLog(message, "LogInfo");
}
public static void LogError(string message)
{
SendLog(message, "LogError");
}
public static void LogWarning(string message)
{
SendLog(message, "LogWarning");
}
public static void LogDebug(string message)
{
SendLog(message, "LogDebug");
}
public static void LogFatal(string message)
{
SendLog(message, "LogFatal");
}
public static void LogMessage(string message)
{
SendLog(message, "LogMessage");
}
private static void SendLog(string message, string level = null)
{
if (!Plugin.DebugMode && (level == "LogDebug" || level == "LogInfo"))
{
return;
}
switch (level)
{
case "LogInfo":
Plugin.CLog.LogInfo((object)message);
return;
case "LogError":
Plugin.CLog.LogError((object)message);
return;
case "LogWarning":
Plugin.CLog.LogWarning((object)message);
return;
case "LogDebug":
Plugin.CLog.LogDebug((object)message);
return;
case "LogFatal":
Plugin.CLog.LogFatal((object)message);
return;
case "LogMessage":
Plugin.CLog.LogMessage((object)message);
return;
}
if (level != "Log")
{
Debug.Log((object)("[" + level + "]: " + message));
}
else
{
Debug.Log((object)message);
}
}
}
public class PrivateFieldAccessor<InstanceType>
{
private FieldInfo _field;
private object _instance;
public PrivateFieldAccessor(object instance, string fieldname)
{
_field = typeof(InstanceType).GetField(fieldname, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
_instance = instance;
}
public T Get<T>()
{
return Utils.GetInstanceField<T>(_instance, _field.Name);
}
public void Set<T>(T value)
{
_field.SetValue(_instance, value);
}
}
internal static class Utils
{
public static T GetInstanceField<T>(object instance, string fieldName)
{
BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
return (T)instance.GetType().GetField(fieldName, bindingAttr).GetValue(instance);
}
}
}
namespace CrossHair.Patches
{
[HarmonyPatch(typeof(HUDManager))]
internal class HUDManagerPatch
{
public static Transform CrossHair;
public static TextMeshProUGUI CrossHairTMP;
public static float CrossHairAlpha = 200f;
public static Transform CrossHairShadow;
public static float CrossHairShadowAlpha = 100f;
[HarmonyPatch("Start")]
[HarmonyPostfix]
private static void Start(ref HUDManager __instance)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
//IL_01e7: Unknown result type (might be due to invalid IL or missing references)
//IL_01ec: Unknown result type (might be due to invalid IL or missing references)
//IL_02c7: Unknown result type (might be due to invalid IL or missing references)
//IL_02cc: Unknown result type (might be due to invalid IL or missing references)
//IL_02ea: Unknown result type (might be due to invalid IL or missing references)
CrossHair = ((TMP_Text)Object.Instantiate<TextMeshProUGUI>(new GameObject().AddComponent<TextMeshProUGUI>())).transform;
global::CrossHair.Utilities.Console.LogDebug(((Object)CrossHair).name ?? "");
((Object)CrossHair).name = "CrossHair";
Transform transform = ((Component)((Component)__instance.PTTIcon).transform.parent.parent.parent.Find("PlayerCursor").Find("Cursor")).transform;
CrossHairTMP = ((Component)CrossHair).GetComponent<TextMeshProUGUI>();
RectTransform rectTransform = ((TMP_Text)CrossHairTMP).rectTransform;
((Transform)rectTransform).SetParent(transform, false);
rectTransform.anchoredPosition = new Vector2(0f, 0f);
((Transform)rectTransform).localPosition = new Vector3(0f, 0f, 0f);
rectTransform.offsetMin = new Vector2(-500f, -500f);
rectTransform.offsetMax = new Vector2(500f, 500f);
string text = Plugin.CrossHairColor.Value;
if (text.Length != 6)
{
text = HexFormatException("character amount: \"" + text + "\"");
}
int num = 16777215;
try
{
num = int.Parse(text.Replace("#", ""), NumberStyles.HexNumber);
}
catch (FormatException)
{
num = int.Parse(HexFormatException("color: \"" + text + "\""), NumberStyles.HexNumber);
}
Color color = Color.FromArgb(num);
CrossHairAlpha = (int)(byte)(Plugin.CrossHairOpacity.Value * 255 / 100);
CrossHairShadowAlpha = (int)(byte)(CrossHairAlpha * 50f / 100f);
((TMP_Text)CrossHairTMP).text = Plugin.CrossHairText.Value;
((TMP_Text)CrossHairTMP).fontSize = Plugin.CrossHairSize.Value;
((Graphic)CrossHairTMP).color = Color32.op_Implicit(new Color32(color.R, color.G, color.B, (byte)Mathf.RoundToInt(CrossHairAlpha)));
global::CrossHair.Utilities.Console.LogDebug($"CrossHairColor: ({color.R}, {color.G}, {color.B}, {CrossHairAlpha})");
((TMP_Text)CrossHairTMP).alignment = (TextAlignmentOptions)514;
((TMP_Text)CrossHairTMP).font = ((TMP_Text)__instance.controlTipLines[0]).font;
((Behaviour)CrossHairTMP).enabled = true;
if (Plugin.CrossHairShadow.Value)
{
CrossHairShadow = Object.Instantiate<Transform>(CrossHair, transform);
TextMeshProUGUI component = ((Component)CrossHairShadow).GetComponent<TextMeshProUGUI>();
((Object)CrossHairShadow).name = "CrossHairShadow";
((TMP_Text)component).fontSize = Plugin.CrossHairSize.Value;
((Graphic)component).color = Color32.op_Implicit(new Color32((byte)0, (byte)0, (byte)0, (byte)CrossHairShadowAlpha));
((Transform)((TMP_Text)component).rectTransform).localPosition = new Vector3(2f, -2f, 0f);
((Transform)rectTransform).SetAsLastSibling();
}
}
public static void SetCrossHairAlphaPercent(float target)
{
if (Object.op_Implicit((Object)(object)CrossHair))
{
((TMP_Text)((Component)CrossHair).GetComponent<TextMeshProUGUI>()).alpha = target * (CrossHairAlpha / 255f);
if (Object.op_Implicit((Object)(object)CrossHairShadow))
{
((TMP_Text)((Component)CrossHairShadow).GetComponent<TextMeshProUGUI>()).alpha = target * (CrossHairShadowAlpha / 255f);
}
}
}
private static string HexFormatException(string message = "color")
{
global::CrossHair.Utilities.Console.LogMessage("Invalid hex " + message + ", using default color (ffffff)");
Plugin.CrossHairColor.Value = "ffffff";
Plugin.Config.Save();
return "ffffff";
}
}
public class TargetFieldHook
{
public string fieldName;
public object targetValue;
private float fadeValue;
private float fadeOutDuration;
private float fadeInDuration;
public PrivateFieldAccessor<PlayerControllerB> field;
private bool isFading;
public float currentFade = 1f;
private float fadeTimer;
public TargetFieldHook(PlayerControllerB playerInstance, string fieldName, object targetValue, float fadeValue = 0.2f, float fadeOutDuration = 0.2f, float fadeInDuration = 0.5f)
{
this.fieldName = fieldName;
this.targetValue = targetValue;
this.fadeValue = fadeValue;
this.fadeOutDuration = fadeOutDuration;
this.fadeInDuration = fadeInDuration;
field = new PrivateFieldAccessor<PlayerControllerB>(playerInstance, fieldName);
}
public bool GetState()
{
object obj = field.Get<object>();
try
{
object obj2 = targetValue;
InteractTrigger val = (InteractTrigger)((obj2 is InteractTrigger) ? obj2 : null);
if (val == null)
{
if (!(obj2 is bool flag))
{
if (!(obj2 is float num))
{
if (!(obj2 is int num2))
{
if (obj2 is string text)
{
return (string)obj == text;
}
throw new TypeAccessException($"TargetFieldHook.GetState() - Unknown type: {targetValue.GetType()}");
}
return (int)obj == num2;
}
return (float)obj == num;
}
return (bool)obj == flag;
}
return obj != null == Object.op_Implicit((Object)(object)val);
}
catch (TypeAccessException ex)
{
CrossHair.Utilities.Console.LogError(ex.ToString());
}
CrossHair.Utilities.Console.LogDebug($"{fieldName} - Unknown type: {targetValue.GetType()}");
return false;
}
public void Update()
{
if (isFading)
{
if (!GetState())
{
isFading = false;
fadeTimer = currentFade;
}
else if (currentFade > fadeValue)
{
currentFade = Mathf.Lerp(1f, fadeValue, fadeTimer);
fadeTimer += Time.deltaTime / fadeOutDuration;
}
}
else if (GetState())
{
isFading = true;
fadeTimer = 1f - currentFade;
}
else if (currentFade < 1f)
{
currentFade = Mathf.Lerp(fadeValue, 1f, fadeTimer);
fadeTimer += Time.deltaTime / fadeInDuration;
}
currentFade = Mathf.Clamp(currentFade, 0f, 1f);
fadeTimer = Mathf.Clamp(fadeTimer, 0f, 1f);
}
public void LogValues()
{
CrossHair.Utilities.Console.LogDebug($"{fieldName}\nValue: {field.Get<object>()} - Target: {targetValue}\nFade: {fadeValue} - Duration: {fadeOutDuration} - {fadeInDuration}");
}
}
[HarmonyPatch(typeof(PlayerControllerB))]
internal static class PlayerControllerBPatch
{
private static List<TargetFieldHook> targetFields = new List<TargetFieldHook>();
[HarmonyPatch("ConnectClientToPlayerObject")]
[HarmonyPostfix]
private static void ConnectClientToPlayerObject(ref PlayerControllerB __instance)
{
PlayerControllerB localPlayerController = GameNetworkManager.Instance.localPlayerController;
if (!((Object)(object)__instance != (Object)(object)localPlayerController))
{
CrossHair.Utilities.Console.LogInfo("PlayerControllerB.ConnectClientToPlayerObject() called");
if (Plugin.CrossHairFading.Value)
{
targetFields = new List<TargetFieldHook>
{
new TargetFieldHook(__instance, "isWalking", true, 0.5f, 1f, 0.25f),
new TargetFieldHook(__instance, "isSprinting", true, 0.25f, 0.5f, 0.25f),
new TargetFieldHook(__instance, "isJumping", true, 0.1f, 0.05f, 1f),
new TargetFieldHook(__instance, "isFallingFromJump", true, 0.1f, 0.01f, 1f),
new TargetFieldHook(__instance, "isFallingNoJump", true, 0.1f, 0.01f, 1f),
new TargetFieldHook(__instance, "isCrouching", true, 0.5f, 0.5f, 1f),
new TargetFieldHook(__instance, "isClimbingLadder", true, 0.01f, 0.25f, 2f),
new TargetFieldHook(__instance, "twoHanded", true, 0.1f, 0.01f),
new TargetFieldHook(__instance, "performingEmote", true, 0.05f, 0.2f, 2f),
new TargetFieldHook(__instance, "isUnderwater", true, 0.025f, 0.1f, 1f),
new TargetFieldHook(__instance, "inTerminalMenu", true, 0f, 0.2f, 1.5f),
new TargetFieldHook(__instance, "isPlayerDead", true, 0.05f, 2.5f, 1f),
new TargetFieldHook(__instance, "hasBegunSpectating", true, 0f, 5f, 50f),
new TargetFieldHook(__instance, "isHoldingInteract", true, 0.1f, 0.5f)
};
CrossHair.Utilities.Console.LogDebug($"PlayerControllerB.targetFields.Count: {targetFields.Count}");
}
}
}
[HarmonyPatch("Update")]
[HarmonyPostfix]
private static void Update(ref PlayerControllerB __instance)
{
if ((Object)(object)__instance != (Object)(object)GameNetworkManager.Instance.localPlayerController)
{
return;
}
float num = 1f;
foreach (TargetFieldHook targetField in targetFields)
{
targetField.Update();
if (targetField.currentFade < num)
{
num = targetField.currentFade;
_ = targetField.fieldName;
}
}
if (Mathf.Abs(((TMP_Text)HUDManagerPatch.CrossHairTMP).alpha - num * (HUDManagerPatch.CrossHairAlpha / 255f)) > 0.0001f)
{
HUDManagerPatch.SetCrossHairAlphaPercent(num);
}
}
}
}