Decompiled source of MobThreat v1.0.2

plugins/Jarki-MobThreat/MobThreat.dll

Decompiled 5 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
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("MobThreat")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.2.0")]
[assembly: AssemblyInformationalVersion("1.0.2+4290106b332b8be71230f3163086c278272a925e")]
[assembly: AssemblyProduct("MobThreat")]
[assembly: AssemblyTitle("MobThreat")]
[assembly: AssemblyVersion("1.0.2.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 MobThreat
{
	[DefaultExecutionOrder(10000)]
	[BepInPlugin("local.mobthreat", "MobThreat", "1.0.2")]
	public sealed class Plugin : BaseUnityPlugin
	{
		private sealed class Label
		{
			internal Character Mob;

			internal int Hits = -1;

			internal TextMeshProUGUI Text;

			internal string Caption;

			internal Vector2 Screen;

			internal bool Visible;

			internal void Set(Character mob, int hits)
			{
				Mob = mob;
				if (Hits != hits)
				{
					Hits = hits;
					Caption = ((hits == 1) ? "~1 hit" : ("~" + hits + " hits"));
					if (Object.op_Implicit((Object)(object)Text))
					{
						((TMP_Text)Text).text = Caption;
					}
				}
			}
		}

		private readonly List<Character> nearby = new List<Character>();

		private readonly List<Label> labels = new List<Label>();

		private readonly ThreatEstimator estimator = new ThreatEstimator();

		private ConfigEntry<bool> displayEnabled;

		private ConfigEntry<float> distance;

		private GameObject overlay;

		private TMP_FontAsset font;

		private float nextSample;

		private int active;

		private int wallMask;

		private void Awake()
		{
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Expected O, but got Unknown
			displayEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Display", "Enabled", true, "Show estimated unblocked hits to death above hostile mobs.");
			distance = ((BaseUnityPlugin)this).Config.Bind<float>("Display", "MaxDistance", 35f, new ConfigDescription("Maximum label distance in metres.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(5f, 100f), Array.Empty<object>()));
			wallMask = LayerMask.GetMask(new string[5] { "Default", "static_solid", "Default_small", "piece", "terrain" });
		}

		private bool CanDisplay()
		{
			Player localPlayer = Player.m_localPlayer;
			if (displayEnabled != null && displayEnabled.Value && Object.op_Implicit((Object)(object)localPlayer) && !((Character)localPlayer).IsDead() && !((Character)localPlayer).IsTeleporting() && !((Character)localPlayer).InCutscene() && Object.op_Implicit((Object)(object)Game.instance))
			{
				return !Hud.IsUserHidden();
			}
			return false;
		}

		private void LateUpdate()
		{
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_0137: Unknown result type (might be due to invalid IL or missing references)
			//IL_013e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0143: Unknown result type (might be due to invalid IL or missing references)
			if (!CanDisplay())
			{
				Clear();
				nextSample = 0f;
				return;
			}
			Player localPlayer = Player.m_localPlayer;
			if (Time.unscaledTime >= nextSample)
			{
				nextSample = Time.unscaledTime + 0.25f;
				Sample(localPlayer);
			}
			Camera mainCamera = Utils.GetMainCamera();
			for (int i = 0; i < active; i++)
			{
				Label label = labels[i];
				label.Visible = false;
				if (Object.op_Implicit((Object)(object)mainCamera) && Object.op_Implicit((Object)(object)label.Mob) && !label.Mob.IsDead() && !label.Mob.m_hideHud)
				{
					Vector3 val = label.Mob.GetTopPoint() + Vector3.up * 0.45f;
					Vector3 val2 = Utils.WorldToScreenPointScaled(mainCamera, val);
					if (!(val2.z <= 0f) && !(val2.x < 0f) && !(val2.x > (float)Screen.width) && !(val2.y < 0f) && !(val2.y > (float)Screen.height) && !Physics.Linecast(((Component)mainCamera).transform.position, val, wallMask, (QueryTriggerInteraction)1))
					{
						label.Screen = new Vector2(val2.x, val2.y);
						label.Visible = true;
					}
				}
			}
			DrawLabels();
		}

		private void Sample(Player player)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: 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_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			nearby.Clear();
			Character.GetCharactersInRange(((Component)player).transform.position, distance.Value, nearby);
			DamageModifiers damageModifiers = ((Character)player).GetDamageModifiers((WeakSpot)null);
			float bodyArmor = ((Character)player).GetBodyArmor();
			float difficultyDamageScalePlayer = Game.instance.GetDifficultyDamageScalePlayer(((Component)player).transform.position);
			int num = 0;
			for (int i = 0; i < nearby.Count; i++)
			{
				Character val = nearby[i];
				if (!Object.op_Implicit((Object)(object)val) || val.IsPlayer() || val.IsDead() || val.m_hideHud || !Object.op_Implicit((Object)(object)val.GetBaseAI()) || !BaseAI.IsEnemy((Character)(object)player, val))
				{
					continue;
				}
				Humanoid val2 = (Humanoid)(object)((val is Humanoid) ? val : null);
				int num2 = ((val2 != null) ? ThreatMath.HitsToDie(((Character)player).GetHealth(), estimator.Estimate(val2, damageModifiers, bodyArmor, difficultyDamageScalePlayer)) : 0);
				if (num2 > 0)
				{
					if (num == labels.Count)
					{
						labels.Add(new Label());
					}
					labels[num++].Set(val, num2);
				}
			}
			for (int j = num; j < active; j++)
			{
				labels[j].Mob = null;
				labels[j].Visible = false;
				if (Object.op_Implicit((Object)(object)labels[j].Text))
				{
					((Component)labels[j].Text).gameObject.SetActive(false);
				}
			}
			active = num;
			nearby.Clear();
		}

		private void DrawLabels()
		{
			//IL_0156: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: Expected O, but got Unknown
			//IL_0216: Unknown result type (might be due to invalid IL or missing references)
			//IL_021b: Unknown result type (might be due to invalid IL or missing references)
			//IL_021c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0223: Unknown result type (might be due to invalid IL or missing references)
			//IL_0235: Unknown result type (might be due to invalid IL or missing references)
			//IL_0249: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Expected O, but got Unknown
			if (active == 0)
			{
				if (Object.op_Implicit((Object)(object)overlay))
				{
					overlay.SetActive(false);
				}
				return;
			}
			if (!Object.op_Implicit((Object)(object)overlay))
			{
				GameObject val = (Object.op_Implicit((Object)(object)EnemyHud.instance) ? EnemyHud.instance.m_baseHud : null);
				Transform val2 = (Object.op_Implicit((Object)(object)val) ? val.transform.Find("Name") : null);
				TextMeshProUGUI val3 = (Object.op_Implicit((Object)(object)val2) ? ((Component)val2).GetComponent<TextMeshProUGUI>() : null);
				if (!Object.op_Implicit((Object)(object)val3) || !Object.op_Implicit((Object)(object)((TMP_Text)val3).font))
				{
					return;
				}
				font = ((TMP_Text)val3).font;
				overlay = new GameObject("MobThreatOverlay", new Type[2]
				{
					typeof(RectTransform),
					typeof(Canvas)
				});
				overlay.transform.SetParent(((Component)this).transform, false);
				Canvas component = overlay.GetComponent<Canvas>();
				component.renderMode = (RenderMode)0;
				component.sortingOrder = 30000;
			}
			overlay.SetActive(true);
			for (int i = 0; i < active; i++)
			{
				Label label = labels[i];
				if (!Object.op_Implicit((Object)(object)label.Text))
				{
					GameObject val4 = new GameObject("Threat", new Type[2]
					{
						typeof(RectTransform),
						typeof(TextMeshProUGUI)
					});
					val4.transform.SetParent(overlay.transform, false);
					label.Text = val4.GetComponent<TextMeshProUGUI>();
					((TMP_Text)label.Text).font = font;
					((TMP_Text)label.Text).fontSharedMaterial = ((TMP_Asset)font).material;
					((TMP_Text)label.Text).fontSize = 20f;
					((TMP_Text)label.Text).fontStyle = (FontStyles)1;
					((TMP_Text)label.Text).alignment = (TextAlignmentOptions)514;
					((Graphic)label.Text).raycastTarget = false;
					((TMP_Text)label.Text).richText = false;
					((TMP_Text)label.Text).text = label.Caption;
					RectTransform rectTransform = ((TMP_Text)label.Text).rectTransform;
					Vector2 anchorMin = (rectTransform.anchorMax = Vector2.zero);
					rectTransform.anchorMin = anchorMin;
					rectTransform.pivot = new Vector2(0.5f, 0f);
					rectTransform.sizeDelta = new Vector2(180f, 32f);
				}
				bool flag = label.Visible && Object.op_Implicit((Object)(object)label.Mob) && !label.Mob.IsDead();
				((Component)label.Text).gameObject.SetActive(flag);
				if (flag)
				{
					((TMP_Text)label.Text).rectTransform.anchoredPosition = label.Screen;
					((Graphic)label.Text).color = ((label.Hits > 0 && label.Hits <= 2) ? Color.red : Color.white);
				}
			}
		}

		private void Clear()
		{
			for (int i = 0; i < active; i++)
			{
				labels[i].Mob = null;
				labels[i].Visible = false;
				if (Object.op_Implicit((Object)(object)labels[i].Text))
				{
					((Component)labels[i].Text).gameObject.SetActive(false);
				}
			}
			active = 0;
			nearby.Clear();
			if (Object.op_Implicit((Object)(object)overlay))
			{
				overlay.SetActive(false);
			}
		}

		private void OnDisable()
		{
			Clear();
		}

		private void OnDestroy()
		{
			Clear();
			if (Object.op_Implicit((Object)(object)overlay))
			{
				Object.Destroy((Object)(object)overlay);
			}
		}
	}
	internal sealed class ThreatEstimator
	{
		private readonly HitData hit = new HitData();

		internal float Estimate(Humanoid mob, DamageModifiers resistance, float armor, float difficulty)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			float num = 0f;
			List<ItemData> allItems = mob.GetInventory().GetAllItems();
			for (int i = 0; i < allItems.Count; i++)
			{
				num = Mathf.Max(num, EstimateWeapon(mob, allItems[i], resistance, armor, difficulty));
			}
			return Mathf.Max(num, EstimateWeapon(mob, mob.GetCurrentWeapon(), resistance, armor, difficulty));
		}

		private float EstimateWeapon(Humanoid mob, ItemData weapon, DamageModifiers resistance, float armor, float difficulty)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			if (weapon == null || !weapon.IsWeapon() || (int)weapon.m_shared.m_aiTargetType != 0)
			{
				return 0f;
			}
			float num = EstimateAttack(mob, weapon, weapon.m_shared.m_attack, resistance, armor, difficulty);
			if (weapon.HaveSecondaryAttack())
			{
				num = Mathf.Max(num, EstimateAttack(mob, weapon, weapon.m_shared.m_secondaryAttack, resistance, armor, difficulty));
			}
			return num;
		}

		private float EstimateAttack(Humanoid mob, ItemData weapon, Attack attack, DamageModifiers resistance, float armor, float difficulty)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			if (attack == null)
			{
				return 0f;
			}
			hit.m_damage = weapon.GetDamage();
			float num = attack.m_damageMultiplier * (1f + (float)Mathf.Max(0, ((Character)mob).GetLevel() - 1) * 0.5f);
			num *= 0.935f;
			if (attack.m_damageMultiplierPerMissingHP > 0f)
			{
				num *= 1f + (((Character)mob).GetMaxHealth() - ((Character)mob).GetHealth()) * attack.m_damageMultiplierPerMissingHP;
			}
			if (attack.m_damageMultiplierByTotalHealthMissing > 0f)
			{
				num *= 1f + (1f - ((Character)mob).GetHealthPercentage()) * attack.m_damageMultiplierByTotalHealthMissing;
			}
			((DamageTypes)(ref hit.m_damage)).Modify(num);
			hit.m_damage.m_chop = (hit.m_damage.m_pickaxe = 0f);
			float extraDamage = ((Game.m_worldLevel > 0) ? ((float)(Game.m_worldLevel * Game.instance.m_worldLevelEnemyBaseDamage)) : 0f);
			return Mitigate(hit, resistance, armor, difficulty * Game.m_enemyDamageRate, Game.m_localDamgeTakenRate, extraDamage);
		}

		internal static float Mitigate(HitData incoming, DamageModifiers resistance, float armor, float difficultyAndEnemyRate, float localDamageRate, float extraDamage)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			incoming.ApplyModifier(difficultyAndEnemyRate);
			DamageModifier val = default(DamageModifier);
			incoming.ApplyResistance(resistance, ref val);
			incoming.ApplyArmor(armor);
			incoming.ApplyModifier(localDamageRate);
			float num = ((DamageTypes)(ref incoming.m_damage)).GetTotalDamage() + extraDamage;
			if (!(num > 0.1f))
			{
				return 0f;
			}
			return num;
		}
	}
	internal static class ThreatMath
	{
		internal static int HitsToDie(float health, float damage)
		{
			if (float.IsNaN(health) || float.IsInfinity(health) || health <= 0f || float.IsNaN(damage) || float.IsInfinity(damage) || damage <= 0f)
			{
				return 0;
			}
			double num = Math.Ceiling((double)health / (double)damage);
			if (!(num > 2147483647.0))
			{
				return (int)num;
			}
			return int.MaxValue;
		}
	}
}