Decompiled source of AbilityCooldown v0.2.2

plugins/MycopunkAbilityCooldown/MycopunkAbilityCooldown.dll

Decompiled 2 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
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 HarmonyLib;
using Microsoft.CodeAnalysis;
using MycopunkShared;
using Pigeon.UI;
using TMPro;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("MycopunkAbilityCooldown")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.2.2.0")]
[assembly: AssemblyInformationalVersion("0.2.2+fe8cef1291afd0a7f7ea8a9ddfd28d3607c4cdd5")]
[assembly: AssemblyProduct("MycopunkAbilityCooldown")]
[assembly: AssemblyTitle("MycopunkAbilityCooldown")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.2.2.0")]
[module: UnverifiableCode]
[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 MycopunkAbilityCooldown
{
	internal sealed class CooldownLabel : MonoBehaviour
	{
		private sealed class Tag
		{
			public GameObject Root;

			public TextMeshProUGUI Text;

			public string Shown = "";

			public void Show(string text)
			{
				if ((object)text != Shown && !(text == Shown))
				{
					Shown = text;
					((TMP_Text)Text).text = text;
					bool flag = text.Length > 0;
					if (Root.activeSelf != flag)
					{
						Root.SetActive(flag);
					}
				}
			}
		}

		[HarmonyPatch(typeof(AbilityRechargeUI), "Setup")]
		internal static class SetupPatch
		{
			[HarmonyPostfix]
			private static void Postfix(AbilityRechargeUI __instance)
			{
				Attach(__instance);
			}
		}

		private const string Prefix = "MycoCooldown";

		private AbilityRechargeUI _ui;

		private bool _built;

		private Graphic _shade;

		private TextMeshProUGUI _big;

		private Tag _timer;

		private Tag _count;

		private readonly RechargeEstimate _estimate = new RechargeEstimate();

		private readonly SecondsText _seconds = new SecondsText();

		private CooldownMode _mode;

		private string _shownSeconds = "";

		private int _shownCount = -1;

		public static void AttachExisting()
		{
			AbilityRechargeUI[] array = Object.FindObjectsByType<AbilityRechargeUI>((FindObjectsInactive)1);
			for (int i = 0; i < array.Length; i++)
			{
				Attach(array[i]);
			}
		}

		private void OnDestroy()
		{
			if ((Object)(object)_shade != (Object)null)
			{
				Object.Destroy((Object)(object)((Component)_shade).gameObject);
			}
			if ((Object)(object)_big != (Object)null)
			{
				Object.Destroy((Object)(object)((Component)_big).gameObject);
			}
			if ((Object)(object)_timer?.Root != (Object)null && (Object)(object)_timer.Root.transform.parent != (Object)null)
			{
				Object.Destroy((Object)(object)((Component)_timer.Root.transform.parent).gameObject);
			}
		}

		private static void Attach(AbilityRechargeUI ui)
		{
			try
			{
				CooldownLabel cooldownLabel = ((Component)ui).GetComponent<CooldownLabel>();
				if ((Object)(object)cooldownLabel == (Object)null)
				{
					cooldownLabel = ((Component)ui).gameObject.AddComponent<CooldownLabel>();
				}
				cooldownLabel._ui = ui;
				cooldownLabel._estimate.Reset();
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Cooldown label could not be added: " + ex));
			}
		}

		private void LateUpdate()
		{
			if ((Object)(object)_ui == (Object)null)
			{
				return;
			}
			try
			{
				IActivatedAbility ability = _ui.ability;
				if (ability == null || !Plugin.Enabled.Value)
				{
					if (_built)
					{
						Apply(CooldownView.Of(0f, 1, float.NaN), "", hideCount: true);
					}
					return;
				}
				float charge = ability.Charge;
				int maxCharges = ability.MaxCharges;
				float seconds = _estimate.Update(Time.time, charge, maxCharges);
				CooldownView view = CooldownView.Of(charge, maxCharges, seconds);
				if ((_built || (view.Mode == CooldownMode.None && !view.ShowCount) || Build()) && _built)
				{
					Apply(view, _seconds.Get(seconds), hideCount: false);
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Cooldown label failed and is turned off: " + ex));
				((Behaviour)this).enabled = false;
			}
		}

		private void Apply(CooldownView view, string seconds, bool hideCount)
		{
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			if (view.Mode != _mode || (object)seconds != _shownSeconds)
			{
				_mode = view.Mode;
				_shownSeconds = seconds;
				bool flag = view.Mode == CooldownMode.Empty;
				((Behaviour)_shade).enabled = flag;
				((TMP_Text)_big).text = (flag ? seconds : "");
				_timer.Show((view.Mode == CooldownMode.Recharging) ? seconds : "");
			}
			int num = ((hideCount || !view.ShowCount) ? (-1) : view.Count);
			if (num != _shownCount)
			{
				_shownCount = num;
				_count.Show((num < 0) ? "" : num.ToString());
			}
			Color val = default(Color);
			((Color)(ref val))..ctor(0f, 0f, 0f, Mathf.Clamp01(Plugin.ShadeAlpha.Value));
			if (_shade.color != val)
			{
				_shade.color = val;
			}
			float value = Plugin.FontSize.Value;
			if (((TMP_Text)_big).fontSize != value)
			{
				((TMP_Text)_big).fontSize = value;
			}
			float value2 = Plugin.SmallFontSize.Value;
			if (((TMP_Text)_timer.Text).fontSize != value2)
			{
				((TMP_Text)_timer.Text).fontSize = value2;
				((TMP_Text)_count.Text).fontSize = value2;
			}
		}

		private bool Build()
		{
			//IL_0163: Unknown result type (might be due to invalid IL or missing references)
			//IL_018b: Unknown result type (might be due to invalid IL or missing references)
			Image icon = _ui.icon;
			TextMeshProUGUI keybindText = _ui.keybindText;
			if ((Object)(object)icon == (Object)null || (Object)(object)keybindText == (Object)null || (Object)(object)((TMP_Text)keybindText).font == (Object)null)
			{
				((Behaviour)this).enabled = false;
				Plugin.Log.LogWarning((object)"AbilityRechargeUI has no icon or keybind text; no cooldown number for it.");
				return false;
			}
			Graphic chargedBackground = _ui.chargedBackground;
			BevelRect val = (((Object)(object)chargedBackground != (Object)null && (Object)(object)((Component)chargedBackground).transform.parent != (Object)null) ? ((Component)((Component)chargedBackground).transform.parent).GetComponent<BevelRect>() : null);
			RectTransform shape = (((Object)(object)val != (Object)null) ? ((Graphic)val).rectTransform : ((Graphic)icon).rectTransform);
			Transform parent = ((Component)icon).transform.parent;
			int num = ((Component)icon).transform.GetSiblingIndex() + 1;
			GameObject val2 = Sibling(parent, "MycoCooldownShade", shape, num);
			_shade = (Graphic)(((Object)(object)val != (Object)null) ? ((object)Bevel(val2, val)) : ((object)val2.AddComponent<Image>()));
			_shade.raycastTarget = false;
			((Behaviour)_shade).enabled = false;
			_big = Text(Sibling(parent, "MycoCooldown", shape, num + 1), keybindText, Plugin.FontSize.Value, (TextAlignmentOptions)514);
			GameObject val3 = Sibling(parent, "MycoCooldownTags", shape, num + 2);
			_timer = NewTag(val3.transform, "Timer", new Vector2(1f, 0f), val, keybindText);
			_count = NewTag(val3.transform, "Count", new Vector2(1f, 1f), val, keybindText);
			_mode = CooldownMode.None;
			_shownSeconds = "";
			_shownCount = -1;
			_built = true;
			return true;
		}

		private static Tag NewTag(Transform parent, string name, Vector2 corner, BevelRect bkg, TextMeshProUGUI font)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Expected O, but got Unknown
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Expected O, but got Unknown
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: 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)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Expected O, but got Unknown
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			//IL_0147: Unknown result type (might be due to invalid IL or missing references)
			//IL_0166: Unknown result type (might be due to invalid IL or missing references)
			//IL_016b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0177: Unknown result type (might be due to invalid IL or missing references)
			//IL_019a: Expected O, but got Unknown
			GameObject val = new GameObject("MycoCooldown" + name, new Type[1] { typeof(RectTransform) });
			val.layer = ((Component)parent).gameObject.layer;
			RectTransform val2 = (RectTransform)val.transform;
			((Transform)val2).SetParent(parent, false);
			Vector2 val3 = (val2.pivot = corner);
			Vector2 anchorMin = (val2.anchorMax = val3);
			val2.anchorMin = anchorMin;
			val2.anchoredPosition = new Vector2((corner.x > 0.5f) ? (-2f) : 2f, (corner.y > 0.5f) ? (-2f) : 2f);
			((Transform)val2).localScale = Vector3.one;
			Graphic val6;
			if ((Object)(object)bkg != (Object)null)
			{
				BevelRect obj = val.AddComponent<BevelRect>();
				obj.SetCorners(3f);
				val6 = (Graphic)(object)obj;
			}
			else
			{
				val6 = (Graphic)(object)val.AddComponent<Image>();
			}
			val6.color = new Color(0f, 0f, 0f, 0.8f);
			val6.raycastTarget = false;
			HorizontalLayoutGroup obj2 = val.AddComponent<HorizontalLayoutGroup>();
			((LayoutGroup)obj2).padding = new RectOffset(4, 4, 1, 1);
			((LayoutGroup)obj2).childAlignment = (TextAnchor)4;
			bool childControlWidth = (((HorizontalOrVerticalLayoutGroup)obj2).childControlHeight = true);
			((HorizontalOrVerticalLayoutGroup)obj2).childControlWidth = childControlWidth;
			childControlWidth = (((HorizontalOrVerticalLayoutGroup)obj2).childForceExpandHeight = false);
			((HorizontalOrVerticalLayoutGroup)obj2).childForceExpandWidth = childControlWidth;
			ContentSizeFitter obj3 = val.AddComponent<ContentSizeFitter>();
			FitMode horizontalFit = (FitMode)2;
			obj3.verticalFit = (FitMode)2;
			obj3.horizontalFit = horizontalFit;
			GameObject val7 = new GameObject("Text", new Type[1] { typeof(RectTransform) })
			{
				layer = val.layer
			};
			val7.transform.SetParent((Transform)(object)val2, false);
			TextMeshProUGUI text = Text(val7, font, Plugin.SmallFontSize.Value, (TextAlignmentOptions)514);
			val.SetActive(false);
			return new Tag
			{
				Root = val,
				Text = text
			};
		}

		private static BevelRect Bevel(GameObject go, BevelRect like)
		{
			BevelRect obj = go.AddComponent<BevelRect>();
			obj.TopLeft = like.TopLeft;
			obj.TopRight = like.TopRight;
			obj.BottomLeft = like.BottomLeft;
			obj.BottomRight = like.BottomRight;
			return obj;
		}

		private static TextMeshProUGUI Text(GameObject go, TextMeshProUGUI font, float size, TextAlignmentOptions align)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			TextMeshProUGUI obj = go.AddComponent<TextMeshProUGUI>();
			((TMP_Text)obj).font = ((TMP_Text)font).font;
			((TMP_Text)obj).fontSharedMaterial = ((TMP_Text)font).fontSharedMaterial;
			((TMP_Text)obj).fontSize = size;
			((Graphic)obj).color = Color.white;
			((TMP_Text)obj).alignment = align;
			((TMP_Text)obj).textWrappingMode = (TextWrappingModes)0;
			((TMP_Text)obj).overflowMode = (TextOverflowModes)0;
			((Graphic)obj).raycastTarget = false;
			((TMP_Text)obj).text = "";
			return obj;
		}

		private static GameObject Sibling(Transform parent, string name, RectTransform shape, int index)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: 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_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Expected O, but got Unknown
			GameObject val = new GameObject(name, new Type[1] { typeof(RectTransform) })
			{
				layer = ((Component)shape).gameObject.layer
			};
			RectTransform val2 = (RectTransform)val.transform;
			((Transform)val2).SetParent(parent, false);
			((Transform)val2).SetSiblingIndex(index);
			val2.anchorMin = shape.anchorMin;
			val2.anchorMax = shape.anchorMax;
			val2.pivot = shape.pivot;
			val2.sizeDelta = shape.sizeDelta;
			val2.anchoredPosition = shape.anchoredPosition;
			((Transform)val2).localRotation = Quaternion.identity;
			((Transform)val2).localScale = Vector3.one;
			return val;
		}
	}
	internal enum CooldownMode
	{
		None,
		Empty,
		Recharging
	}
	internal readonly struct CooldownView
	{
		public readonly CooldownMode Mode;

		public readonly int Count;

		public readonly bool ShowCount;

		private CooldownView(CooldownMode mode, int count, bool showCount)
		{
			Mode = mode;
			Count = count;
			ShowCount = showCount;
		}

		public static CooldownView Of(float charge, int maxCharges, float seconds)
		{
			int num = ((!(charge <= 0f)) ? ((int)Math.Floor(charge)) : 0);
			if (num > maxCharges)
			{
				num = maxCharges;
			}
			bool showCount = maxCharges > 1;
			if (float.IsNaN(seconds) || num >= maxCharges)
			{
				return new CooldownView(CooldownMode.None, num, showCount);
			}
			return new CooldownView((num == 0) ? CooldownMode.Empty : CooldownMode.Recharging, num, showCount);
		}
	}
	internal static class MenuText
	{
		private static readonly Dictionary<string, Dictionary<string, string>> Names = new Dictionary<string, Dictionary<string, string>>
		{
			["en"] = new Dictionary<string, string> { ["ability.cooldown"] = "Cooldown seconds on ability icons" },
			["ja"] = new Dictionary<string, string> { ["ability.cooldown"] = "アビリティの再使用時間を表示" }
		};

		private static readonly Dictionary<string, Dictionary<string, string>> Descriptions = new Dictionary<string, Dictionary<string, string>> { ["ja"] = new Dictionary<string, string> { ["ability.cooldown"] = "各アビリティのアイコンに次の使用までの秒数を表示します。この変更は即時に反映されます。" } };

		public static object[] Label(string key)
		{
			return ModsMenuTag.Label(key, (IDictionary<string, Dictionary<string, string>>)Names, (IDictionary<string, Dictionary<string, string>>)Descriptions);
		}
	}
	[BepInPlugin("t4t5u0.mycopunk.abilitycooldown", "Mycopunk Ability Cooldown", "0.2.2")]
	[BepInDependency("doku_macaron.mycopunk.macaroncore", "1.1.0")]
	[MycoMod(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		public const string Guid = "t4t5u0.mycopunk.abilitycooldown";

		public const string Name = "Mycopunk Ability Cooldown";

		public const string Version = "0.2.2";

		internal static ManualLogSource Log;

		internal static ConfigEntry<bool> Enabled;

		internal static ConfigEntry<float> FontSize;

		internal static ConfigEntry<float> ShadeAlpha;

		internal static ConfigEntry<float> SmallFontSize;

		private Harmony _harmony;

		private void Awake()
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Expected O, but got Unknown
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, new ConfigDescription("Show the seconds until the next charge over each ability icon (grenade, movement ability...). Takes effect at once.", (AcceptableValueBase)null, MenuText.Label("ability.cooldown")));
			FontSize = ((BaseUnityPlugin)this).Config.Bind<float>("General", "FontSize", 22f, "Font size of the seconds, in HUD units.");
			ShadeAlpha = ((BaseUnityPlugin)this).Config.Bind<float>("General", "ShadeAlpha", 0.8f, "How dark the shade over the icon is while it recharges (0 = none, 1 = black), so the number stays readable.");
			SmallFontSize = ((BaseUnityPlugin)this).Config.Bind<float>("General", "SmallFontSize", 13f, "Font size of the corner tags (the charge count, and the seconds while charges are left), in HUD units.");
			_harmony = new Harmony("t4t5u0.mycopunk.abilitycooldown");
			ModSetup.Try(Log, "cooldown labels", (Action)delegate
			{
				_harmony.CreateClassProcessor(typeof(CooldownLabel.SetupPatch)).Patch();
				CooldownLabel.AttachExisting();
			});
			ModSetup.Try(Log, "MODS tab", (Action)delegate
			{
				ModsMenu.Install(_harmony, (BaseUnityPlugin)(object)this);
			});
			ModSetup.Try(Log, "hotkey report", (Action)delegate
			{
				Hotkeys.ReportConflicts((BaseUnityPlugin)(object)this);
			});
			Log.LogInfo((object)("Mycopunk Ability Cooldown 0.2.2 loaded (enabled=" + Enabled.Value + ")."));
		}

		private void OnDestroy()
		{
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}
	}
	internal sealed class RechargeEstimate
	{
		public const float Window = 0.5f;

		private bool _started;

		private float _t0 = float.NaN;

		private float _c0;

		private float _lastT;

		private float _lastC;

		private float _prevT;

		private float _rate;

		public float Update(float time, float charge, int maxCharges)
		{
			if (maxCharges <= 0 || charge >= (float)maxCharges)
			{
				Reset();
				return float.NaN;
			}
			if (!_started || charge < _lastC)
			{
				Reset();
				_started = true;
				_lastT = (_prevT = time);
				_lastC = charge;
				return float.NaN;
			}
			if (charge > _lastC)
			{
				if (float.IsNaN(_t0))
				{
					_t0 = _prevT;
					_c0 = _lastC;
				}
				_lastT = time;
				_lastC = charge;
			}
			_prevT = time;
			if (time - _lastT > 0.5f)
			{
				_t0 = float.NaN;
				_rate = 0f;
				return float.NaN;
			}
			if (!float.IsNaN(_t0))
			{
				float num = _lastT - _t0;
				if (num >= 0.25f)
				{
					_rate = (_lastC - _c0) / num;
					if (num > 0.5f)
					{
						_t0 = _lastT;
						_c0 = _lastC;
					}
				}
			}
			if (_rate <= 0f)
			{
				return float.NaN;
			}
			return ((float)Math.Floor(charge) + 1f - charge) / _rate;
		}

		public void Reset()
		{
			_started = false;
			_t0 = float.NaN;
			_c0 = (_lastC = (_lastT = (_prevT = 0f)));
			_rate = 0f;
		}
	}
	internal sealed class SecondsText
	{
		private int _tenths = int.MinValue;

		private string _text = "";

		public string Get(float seconds)
		{
			int num = ((float.IsNaN(seconds) || seconds < 0f) ? (-1) : ((seconds >= 10f) ? ((int)Math.Ceiling(seconds) * 10) : ((int)Math.Ceiling(seconds * 10f))));
			if (num != _tenths)
			{
				_tenths = num;
				_text = ((num < 0) ? "" : ((num >= 100) ? (num / 10).ToString() : (num / 10 + "." + num % 10)));
			}
			return _text;
		}
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
}