Decompiled source of Hitmarker v1.2.3

com.github.zehsteam.Hitmarker.dll

Decompiled 6 months ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
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 GameNetcodeStuff;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using TMPro;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.UI;
using com.github.zehsteam.Hitmarker.MonoBehaviours;
using com.github.zehsteam.Hitmarker.Patches;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("com.github.zehsteam.Hitmarker")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyDescription("Shows a hitmarker when you successfully hit an enemy. With additional features. (Client-side)")]
[assembly: AssemblyFileVersion("1.2.3.0")]
[assembly: AssemblyInformationalVersion("1.2.3+9f550c00a965039c6c13c3bda8cf3750925b11f7")]
[assembly: AssemblyProduct("Hitmarker")]
[assembly: AssemblyTitle("com.github.zehsteam.Hitmarker")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.2.3.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 com.github.zehsteam.Hitmarker
{
	internal class ConfigManager
	{
		public ConfigEntry<bool> ExtendedLogging { get; private set; }

		public ConfigEntry<bool> ShowHitmarkerImage { get; private set; }

		public ConfigEntry<int> HitmarkerImageSize { get; private set; }

		public ConfigEntry<bool> PlayHitmarkerSound { get; private set; }

		public ConfigEntry<float> MessageDuration { get; private set; }

		public ConfigEntry<int> MessageFontSize { get; private set; }

		public ConfigEntry<bool> ShowDamageMessage { get; private set; }

		public ConfigEntry<bool> ShowKillMessage { get; private set; }

		public ConfigEntry<bool> OnlyShowLocalKillMessage { get; private set; }

		public ConfigManager()
		{
			BindConfigs();
			ClearUnusedEntries();
		}

		private void BindConfigs()
		{
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Expected O, but got Unknown
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Expected O, but got Unknown
			ConfigFile config = ((BaseUnityPlugin)Plugin.Instance).Config;
			ExtendedLogging = config.Bind<bool>("General Settings", "ExtendedLogging", false, "Enable extended logging.");
			ShowHitmarkerImage = config.Bind<bool>("Hitmarker Settings", "ShowHitmarkerImage", true, "Do you want to show the hitmarker image?");
			HitmarkerImageSize = config.Bind<int>("Hitmarker Settings", "HitmarkerImageSize", 40, new ConfigDescription("The size of the hitmarker image in pixels.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(10, 100), Array.Empty<object>()));
			PlayHitmarkerSound = config.Bind<bool>("Hitmarker Settings", "PlayHitmarkerSound", true, "Do you want to play the hitmarker sound?");
			MessageDuration = config.Bind<float>("Message Settings", "MessageDuration", 4f, "The message duration in seconds.");
			MessageFontSize = config.Bind<int>("Message Settings", "MessageFontSize", 35, new ConfigDescription("The message font size in pixels.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(10, 100), Array.Empty<object>()));
			ShowDamageMessage = config.Bind<bool>("Message Settings", "ShowDamageMessage", true, "Shows a message of how much damage you did to an enemy.");
			ShowKillMessage = config.Bind<bool>("Message Settings", "ShowKillMessage", true, "Shows a message when an enemy is killed.");
			OnlyShowLocalKillMessage = config.Bind<bool>("Message Settings", "OnlyShowLocalKillMessage", true, "Will only show your kill messages.");
		}

		private void ClearUnusedEntries()
		{
			ConfigFile config = ((BaseUnityPlugin)Plugin.Instance).Config;
			PropertyInfo property = ((object)config).GetType().GetProperty("OrphanedEntries", BindingFlags.Instance | BindingFlags.NonPublic);
			Dictionary<ConfigDefinition, string> dictionary = (Dictionary<ConfigDefinition, string>)property.GetValue(config, null);
			dictionary.Clear();
			config.Save();
		}
	}
	internal class Content
	{
		public static GameObject HitmarkerCanvasPrefab;

		public static void Load()
		{
			LoadAssetsFromAssetBundle();
		}

		private static void LoadAssetsFromAssetBundle()
		{
			try
			{
				string directoryName = Path.GetDirectoryName(((BaseUnityPlugin)Plugin.Instance).Info.Location);
				string text = Path.Combine(directoryName, "hitmarker_assets");
				AssetBundle val = AssetBundle.LoadFromFile(text);
				HitmarkerCanvasPrefab = val.LoadAsset<GameObject>("HitmarkerCanvas");
				Plugin.logger.LogInfo((object)"Successfully loaded assets from AssetBundle!");
			}
			catch (Exception arg)
			{
				Plugin.logger.LogError((object)$"Error: failed to load assets from AssetBundle.\n\n{arg}");
			}
		}
	}
	[BepInPlugin("com.github.zehsteam.Hitmarker", "Hitmarker", "1.2.3")]
	internal class Plugin : BaseUnityPlugin
	{
		private readonly Harmony harmony = new Harmony("com.github.zehsteam.Hitmarker");

		internal static Plugin Instance;

		internal static ManualLogSource logger;

		internal static ConfigManager ConfigManager;

		internal static bool IsHostOrServer => NetworkManager.Singleton.IsHost || NetworkManager.Singleton.IsServer;

		private void Awake()
		{
			if ((Object)(object)Instance == (Object)null)
			{
				Instance = this;
			}
			logger = Logger.CreateLogSource("com.github.zehsteam.Hitmarker");
			logger.LogInfo((object)"Hitmarker has awoken!");
			harmony.PatchAll(typeof(HUDManagerPatch));
			harmony.PatchAll(typeof(EnemyAIPatch));
			ConfigManager = new ConfigManager();
			Content.Load();
		}

		public void CreateHitmarkerCanvas()
		{
			if (!((Object)(object)HitmarkerCanvasBehaviour.Instance != (Object)null))
			{
				Object.Instantiate<GameObject>(Content.HitmarkerCanvasPrefab);
				logger.LogInfo((object)"Instantiated Hitmarker canvas.");
			}
		}

		public void LogInfoExtended(object data)
		{
			if (ConfigManager.ExtendedLogging.Value)
			{
				logger.LogInfo(data);
			}
		}
	}
	internal class Utils
	{
		public static bool IsLocalPlayer(PlayerControllerB playerScript)
		{
			return (Object)(object)StartOfRound.Instance.localPlayerController == (Object)(object)playerScript;
		}

		public static PlayerControllerB GetPlayerScript(int playerWhoHit)
		{
			if (playerWhoHit < 0 || playerWhoHit > StartOfRound.Instance.allPlayerScripts.Length - 1)
			{
				return null;
			}
			return StartOfRound.Instance.allPlayerScripts[playerWhoHit];
		}
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "com.github.zehsteam.Hitmarker";

		public const string PLUGIN_NAME = "Hitmarker";

		public const string PLUGIN_VERSION = "1.2.3";
	}
}
namespace com.github.zehsteam.Hitmarker.Patches
{
	[HarmonyPatch(typeof(EnemyAI))]
	internal class EnemyAIPatch
	{
		[HarmonyPatch("HitEnemyOnLocalClient")]
		[HarmonyPrefix]
		private static void HitEnemyOnLocalClientPatch(ref EnemyAI __instance, int force, PlayerControllerB playerWhoHit = null)
		{
			if (!((Object)(object)playerWhoHit == (Object)null) && Utils.IsLocalPlayer(playerWhoHit))
			{
				HitEnemy(__instance, force, playerWhoHit);
			}
		}

		[HarmonyPatch("HitEnemyServerRpc")]
		[HarmonyPrefix]
		private static void HitEnemyServerRpcPatch(ref EnemyAI __instance, int force, int playerWhoHit)
		{
			if (playerWhoHit != -1)
			{
				PlayerControllerB playerScript = Utils.GetPlayerScript(playerWhoHit);
				if (!Utils.IsLocalPlayer(playerScript))
				{
					HitEnemy(__instance, force, playerScript);
				}
			}
		}

		[HarmonyPatch("HitEnemyClientRpc")]
		[HarmonyPrefix]
		private static void HitEnemyClientRpcPatch(ref EnemyAI __instance, int force, int playerWhoHit)
		{
			if (playerWhoHit != -1 && !Plugin.IsHostOrServer)
			{
				PlayerControllerB playerScript = Utils.GetPlayerScript(playerWhoHit);
				if (!Utils.IsLocalPlayer(playerScript))
				{
					HitEnemy(__instance, force, playerScript);
				}
			}
		}

		private static void HitEnemy(EnemyAI enemyAI, int force, PlayerControllerB playerWhoHit)
		{
			if (enemyAI.enemyType.canDie && !enemyAI.isEnemyDead && enemyAI.enemyHP > 0)
			{
				bool flag = Utils.IsLocalPlayer(playerWhoHit);
				string enemyName = enemyAI.enemyType.enemyName;
				bool flag2 = enemyAI.enemyHP - force <= 0;
				if (flag)
				{
					HitmarkerCanvasBehaviour.Instance.ShowHitmarker(flag2);
					HitmarkerCanvasBehaviour.Instance.ShowDamageMessage(enemyName, force);
				}
				if (flag2)
				{
					HitmarkerCanvasBehaviour.Instance.ShowKillMessage(enemyName, flag, playerWhoHit.playerUsername);
				}
				LogInfoExtended("HitEnemy();", enemyAI, force, playerWhoHit);
			}
		}

		private static void LogInfoExtended(string functionName, EnemyAI enemyAI, int force, PlayerControllerB playerWhoHit)
		{
			NetworkObject component = ((Component)enemyAI).gameObject.GetComponent<NetworkObject>();
			string text = (Utils.IsLocalPlayer(playerWhoHit) ? " (LOCAL)" : "");
			string text2 = $"{functionName} NetworkObjectId: {component.NetworkObjectId}\n\n";
			text2 += $"Player \"{playerWhoHit.playerUsername}\"{text} hit \"{enemyAI.enemyType.enemyName}\" for {force} force.\n";
			text2 += $"isEnemyDead: {enemyAI.isEnemyDead}, enemyHP: {enemyAI.enemyHP}, (new enemyHP should be {enemyAI.enemyHP - force})\n";
			Plugin.Instance.LogInfoExtended("\n\n" + text2.Trim() + "\n");
		}
	}
	[HarmonyPatch(typeof(HUDManager))]
	internal class HUDManagerPatch
	{
		[HarmonyPatch("Start")]
		[HarmonyPostfix]
		private static void StartPatch()
		{
			Plugin.Instance.CreateHitmarkerCanvas();
		}
	}
}
namespace com.github.zehsteam.Hitmarker.MonoBehaviours
{
	public class HitmarkerCanvasBehaviour : MonoBehaviour
	{
		public static HitmarkerCanvasBehaviour Instance;

		public HitmarkerImageBehaviour HitmarkerImageBehaviour;

		public AudioClip HitSFX;

		public RectTransform MessageListTransform;

		public RectTransform MessageItemPrefab;

		private Queue<RectTransform> _messageItemPool = new Queue<RectTransform>();

		private void Awake()
		{
			if ((Object)(object)Instance == (Object)null)
			{
				Instance = this;
			}
		}

		private void Start()
		{
			InitializeMessageItemPool();
		}

		private void InitializeMessageItemPool()
		{
			_messageItemPool = new Queue<RectTransform>();
			for (int i = 0; i < 20; i++)
			{
				RectTransform val = Object.Instantiate<RectTransform>(MessageItemPrefab, (Transform)(object)MessageListTransform);
				((Component)val).gameObject.SetActive(false);
				_messageItemPool.Enqueue(val);
			}
		}

		public void ShowHitmarker(bool killed = false)
		{
			ShowHitmarkerImage(killed);
			PlayHitSFX();
		}

		private void ShowHitmarkerImage(bool killed = false)
		{
			if (Plugin.ConfigManager.ShowHitmarkerImage.Value)
			{
				HitmarkerImageBehaviour.ShowImage(killed);
			}
		}

		private void PlayHitSFX()
		{
			if (Plugin.ConfigManager.PlayHitmarkerSound.Value)
			{
				HUDManager.Instance.UIAudio.PlayOneShot(HitSFX);
			}
		}

		public void ShowDamageMessage(string enemyName, int damage = 1)
		{
			if (Plugin.ConfigManager.ShowDamageMessage.Value)
			{
				ShowMessage($"{enemyName} -{damage} HP");
			}
		}

		public void ShowKillMessage(string enemyName, bool fromLocalPlayer = true, string fromPlayerName = "")
		{
			//IL_0063: 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)
			if (Plugin.ConfigManager.ShowKillMessage.Value && (fromLocalPlayer || !Plugin.ConfigManager.OnlyShowLocalKillMessage.Value))
			{
				if (!fromLocalPlayer)
				{
					ShowMessage(fromPlayerName + " Killed " + enemyName, Color.red);
				}
				else
				{
					ShowMessage("Killed " + enemyName, Color.red);
				}
			}
		}

		private void ShowMessage(string text)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			ShowMessage(text, Color.white);
		}

		private void ShowMessage(string text, Color color)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			SpawnMessageItemFromPool(text, color);
		}

		private RectTransform SpawnMessageItemFromPool(string text, Color color)
		{
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			if (_messageItemPool == null || _messageItemPool.Count == 0)
			{
				Plugin.logger.LogError((object)"Error: Failed to spawn message item from pool. Message item pool is either null or empty.");
				return null;
			}
			RectTransform val = _messageItemPool.Dequeue();
			((Component)val).gameObject.SetActive(true);
			((Transform)val).SetAsLastSibling();
			MessageItemBehaviour messageItemBehaviour = default(MessageItemBehaviour);
			if (((Component)val).TryGetComponent<MessageItemBehaviour>(ref messageItemBehaviour))
			{
				messageItemBehaviour.SetText(text, color);
			}
			_messageItemPool.Enqueue(val);
			return val;
		}
	}
	public class HitmarkerImageBehaviour : MonoBehaviour
	{
		public Image Image;

		public Color32 DefaultColor;

		public Color32 KilledColor;

		private Coroutine _fadeOutCoroutine;

		private void Start()
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			int value = Plugin.ConfigManager.HitmarkerImageSize.Value;
			((Graphic)Image).rectTransform.sizeDelta = new Vector2((float)value, (float)value);
			SetAlpha(0f);
		}

		public void ShowImage(bool killed = false)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			((Graphic)Image).color = Color32.op_Implicit(killed ? KilledColor : DefaultColor);
			if (_fadeOutCoroutine != null)
			{
				((MonoBehaviour)this).StopCoroutine(_fadeOutCoroutine);
			}
			_fadeOutCoroutine = ((MonoBehaviour)this).StartCoroutine(FadeOut(0.25f));
		}

		private IEnumerator FadeOut(float duration)
		{
			SetAlpha(255f);
			for (float timer = 0f; timer < duration; timer += Time.deltaTime)
			{
				float percent = 1f / duration * timer;
				float alpha = 255f + -255f * percent;
				SetAlpha(alpha);
				yield return null;
			}
			SetAlpha(0f);
		}

		private void SetAlpha(float a)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			a = Mathf.Clamp(a, 0f, 255f);
			Color32 val = Color32.op_Implicit(((Graphic)Image).color);
			val.a = (byte)a;
			((Graphic)Image).color = Color32.op_Implicit(val);
		}
	}
	public class MessageItemBehaviour : MonoBehaviour
	{
		public TextMeshProUGUI TextUGUI;

		private Coroutine _animationCoroutine;

		private void Start()
		{
			((TMP_Text)TextUGUI).fontSize = Plugin.ConfigManager.MessageFontSize.Value;
		}

		private void OnEnable()
		{
			if (_animationCoroutine != null)
			{
				((MonoBehaviour)this).StopCoroutine(_animationCoroutine);
			}
			_animationCoroutine = ((MonoBehaviour)this).StartCoroutine(PlayAnimation());
		}

		private void OnDisable()
		{
			if (_animationCoroutine != null)
			{
				((MonoBehaviour)this).StopCoroutine(_animationCoroutine);
			}
		}

		private IEnumerator PlayAnimation()
		{
			yield return (object)new WaitForSeconds(Plugin.ConfigManager.MessageDuration.Value);
			float fadeOutDuration = 1f;
			SetAlpha(255f);
			for (float timer = 0f; timer < fadeOutDuration; timer += Time.deltaTime)
			{
				float percent = 1f / fadeOutDuration * timer;
				float alpha = 255f + -255f * percent;
				SetAlpha(alpha);
				yield return null;
			}
			SetAlpha(0f);
			yield return null;
			((Component)this).gameObject.SetActive(false);
		}

		public void SetText(string text)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			SetText(text, Color.white);
		}

		public void SetText(string text, Color color)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			((TMP_Text)TextUGUI).text = text;
			((Graphic)TextUGUI).color = color;
		}

		private void SetAlpha(float a)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			a = Mathf.Clamp(a, 0f, 255f);
			Color32 val = Color32.op_Implicit(((Graphic)TextUGUI).color);
			val.a = (byte)a;
			((Graphic)TextUGUI).color = Color32.op_Implicit(val);
		}
	}
}