Decompiled source of Buff Timers v1.2.2

Buff_Timers/Buff_Timers.dll

Decompiled 12 hours 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 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("Buff_Timers")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+a0d73d031984068578c6541d86bc307c982e9d87")]
[assembly: AssemblyProduct("Buff_Timers")]
[assembly: AssemblyTitle("Buff_Timers")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[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 Ocewen.BuffTimers
{
	public enum AnchorPreset
	{
		BottomCenter,
		BottomLeft,
		BottomRight,
		Center,
		TopCenter,
		TopLeft,
		TopRight
	}
	internal static class ModConfig
	{
		internal static float CachedFontSize = 8f;

		internal static Color CachedColor = Color.white;

		internal static AnchorPreset CachedPosition = AnchorPreset.BottomCenter;

		internal static float CachedOverlayOpacity = 0f;

		private static readonly List<WeakReference<TextMeshProUGUI>> _labels = new List<WeakReference<TextMeshProUGUI>>();

		internal static ConfigEntry<float> FontSize { get; private set; } = null;

		internal static ConfigEntry<string> TextColor { get; private set; } = null;

		internal static ConfigEntry<AnchorPreset> Position { get; private set; } = null;

		internal static ConfigEntry<bool> ShowOnPlayer { get; private set; } = null;

		internal static ConfigEntry<bool> ShowOnTarget { get; private set; } = null;

		internal static ConfigEntry<float> OverlayOpacity { get; private set; } = null;

		internal static void Bind(ConfigFile config)
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Expected O, but got Unknown
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Expected O, but got Unknown
			FontSize = config.Bind<float>("Appearance", "FontSize", 8f, new ConfigDescription("Timer text size", (AcceptableValueBase)(object)new AcceptableValueRange<float>(4f, 24f), Array.Empty<object>()));
			TextColor = config.Bind<string>("Appearance", "TextColor", "#FFFFFF", "Timer text color as HTML hex (e.g. #FFFFFF, #FFD700)");
			Position = config.Bind<AnchorPreset>("Appearance", "Position", AnchorPreset.BottomCenter, "Where to display the timer within the icon");
			ShowOnPlayer = config.Bind<bool>("Visibility", "ShowOnPlayer", true, "Show timers on your own buff/debuff icons");
			ShowOnTarget = config.Bind<bool>("Visibility", "ShowOnTarget", true, "Show timers on target buff/debuff icons");
			OverlayOpacity = config.Bind<float>("Appearance", "OverlayOpacity", 0f, new ConfigDescription("Darkness of the shadow behind the timer (0 = none, 1 = fully black)", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
			ParseColor();
			CachedFontSize = FontSize.Value;
			CachedPosition = Position.Value;
			CachedOverlayOpacity = OverlayOpacity.Value;
			FontSize.SettingChanged += delegate
			{
				CachedFontSize = FontSize.Value;
				RefreshAll();
			};
			TextColor.SettingChanged += delegate
			{
				ParseColor();
				RefreshAll();
			};
			Position.SettingChanged += delegate
			{
				CachedPosition = Position.Value;
				RefreshAll();
			};
			OverlayOpacity.SettingChanged += delegate
			{
				CachedOverlayOpacity = OverlayOpacity.Value;
			};
		}

		internal static void TrackLabel(TextMeshProUGUI label)
		{
			_labels.Add(new WeakReference<TextMeshProUGUI>(label));
		}

		internal static void ApplyStyle(TextMeshProUGUI label)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			((TMP_Text)label).fontSize = CachedFontSize;
			((Graphic)label).color = CachedColor;
			ApplyAnchor(((TMP_Text)label).rectTransform, label, CachedPosition);
		}

		private static void RefreshAll()
		{
			_labels.RemoveAll((WeakReference<TextMeshProUGUI> wr) => !wr.TryGetTarget(out TextMeshProUGUI _));
			foreach (WeakReference<TextMeshProUGUI> label in _labels)
			{
				if (label.TryGetTarget(out var target) && (Object)(object)target != (Object)null)
				{
					ApplyStyle(target);
				}
			}
		}

		private static void ParseColor()
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: 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)
			Color white = default(Color);
			if (!ColorUtility.TryParseHtmlString(TextColor.Value, ref white))
			{
				white = Color.white;
			}
			CachedColor = white;
		}

		private static void ApplyAnchor(RectTransform rect, TextMeshProUGUI label, AnchorPreset preset)
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: 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_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_015b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0160: Unknown result type (might be due to invalid IL or missing references)
			//IL_0162: Unknown result type (might be due to invalid IL or missing references)
			//IL_0167: Unknown result type (might be due to invalid IL or missing references)
			//IL_0168: Unknown result type (might be due to invalid IL or missing references)
			//IL_016d: Unknown result type (might be due to invalid IL or missing references)
			//IL_016f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0176: Unknown result type (might be due to invalid IL or missing references)
			//IL_017d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0188: Unknown result type (might be due to invalid IL or missing references)
			//IL_0193: Unknown result type (might be due to invalid IL or missing references)
			//IL_013a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0149: Unknown result type (might be due to invalid IL or missing references)
			var (anchorMin, anchorMax, alignment) = preset switch
			{
				AnchorPreset.BottomLeft => (new Vector2(0f, 0f), new Vector2(0.5f, 0.5f), (TextAlignmentOptions)1025), 
				AnchorPreset.BottomRight => (new Vector2(0.5f, 0f), new Vector2(1f, 0.5f), (TextAlignmentOptions)1028), 
				AnchorPreset.Center => (new Vector2(0f, 0.25f), new Vector2(1f, 0.75f), (TextAlignmentOptions)514), 
				AnchorPreset.TopLeft => (new Vector2(0f, 0.5f), new Vector2(0.5f, 1f), (TextAlignmentOptions)257), 
				AnchorPreset.TopCenter => (new Vector2(0f, 0.5f), new Vector2(1f, 1f), (TextAlignmentOptions)258), 
				AnchorPreset.TopRight => (new Vector2(0.5f, 0.5f), new Vector2(1f, 1f), (TextAlignmentOptions)260), 
				_ => (new Vector2(0f, 0f), new Vector2(1f, 0.5f), (TextAlignmentOptions)1026), 
			};
			rect.anchorMin = anchorMin;
			rect.anchorMax = anchorMax;
			rect.offsetMin = Vector2.zero;
			rect.offsetMax = Vector2.zero;
			((TMP_Text)label).alignment = alignment;
		}
	}
	[BepInPlugin("Ocewen.Buff_Timers", "Buff Timers", "1.2.1")]
	public class Plugin : BaseUnityPlugin
	{
		private void Awake()
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			ModConfig.Bind(((BaseUnityPlugin)this).Config);
			new Harmony("Ocewen.Buff_Timers").PatchAll();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Buff Timers 1.2.1 loaded.");
		}
	}
	internal static class TimerFormatter
	{
		internal static string FormatTime(float seconds)
		{
			if (seconds <= 0f)
			{
				return "";
			}
			if (seconds < 60f)
			{
				return $"{(int)Math.Ceiling(seconds)}s";
			}
			if (seconds < 3600f)
			{
				return $"{(int)(seconds / 60f)}m";
			}
			return $"{(int)(seconds / 3600f)}h";
		}
	}
	internal static class TimerLabel
	{
		private sealed class TickRecord
		{
			internal float LastSeenDuration;

			internal float RecordedAt;
		}

		internal const string LabelName = "BuffTimerLabel";

		internal const string OverlayName = "BuffTimerOverlay";

		private static readonly ConditionalWeakTable<StatusEffect, TickRecord> _tickRecords = new ConditionalWeakTable<StatusEffect, TickRecord>();

		internal static TextMeshProUGUI CreateLabel(GameObject parent)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: 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_0051: 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_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("BuffTimerOverlay");
			val.transform.SetParent(parent.transform, false);
			((Graphic)val.AddComponent<Image>()).color = new Color(0f, 0f, 0f, 0f);
			RectTransform component = val.GetComponent<RectTransform>();
			component.anchorMin = Vector2.zero;
			component.anchorMax = Vector2.one;
			component.offsetMin = Vector2.zero;
			component.offsetMax = Vector2.zero;
			GameObject val2 = new GameObject("BuffTimerLabel");
			val2.transform.SetParent(parent.transform, false);
			TextMeshProUGUI obj = val2.AddComponent<TextMeshProUGUI>();
			((TMP_Text)obj).outlineWidth = 0.2f;
			((TMP_Text)obj).outlineColor = new Color32((byte)0, (byte)0, (byte)0, byte.MaxValue);
			ModConfig.ApplyStyle(obj);
			ModConfig.TrackLabel(obj);
			return obj;
		}

		internal static void ClearLabel(TextMeshProUGUI label)
		{
			((TMP_Text)label).text = "";
			SetOverlayAlpha(label, 0f);
		}

		internal static void UpdateLabel(TextMeshProUGUI label, StatusEffect? effect)
		{
			if ((Object)(object)effect?.Effect == (Object)null || effect.Effect.SpellDurationInTicks == 0 || ((object)Unsafe.As<SpellLine, SpellLine>(ref effect.Effect.Line)/*cast due to .constrained prefix*/).ToString().StartsWith("Aura_"))
			{
				ClearLabel(label);
				return;
			}
			((TMP_Text)label).text = TimerFormatter.FormatTime(GetInterpolatedSeconds(effect));
			SetOverlayAlpha(label, ModConfig.CachedOverlayOpacity);
		}

		private static void SetOverlayAlpha(TextMeshProUGUI label, float alpha)
		{
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			Transform parent = ((TMP_Text)label).transform.parent;
			Transform val = ((parent != null) ? parent.Find("BuffTimerOverlay") : null);
			if (!((Object)(object)val == (Object)null))
			{
				Image component = ((Component)val).GetComponent<Image>();
				if ((Object)(object)component != (Object)null)
				{
					((Graphic)component).color = new Color(0f, 0f, 0f, alpha);
				}
			}
		}

		private static float GetInterpolatedSeconds(StatusEffect effect)
		{
			float duration = effect.Duration;
			float unscaledTime = Time.unscaledTime;
			if (!_tickRecords.TryGetValue(effect, out TickRecord value))
			{
				value = new TickRecord
				{
					LastSeenDuration = duration,
					RecordedAt = unscaledTime
				};
				_tickRecords.Add(effect, value);
			}
			else if (value.LastSeenDuration != duration)
			{
				value.LastSeenDuration = duration;
				value.RecordedAt = unscaledTime;
			}
			return Math.Max(0f, duration * 3f - (unscaledTime - value.RecordedAt));
		}
	}
}
namespace Ocewen.BuffTimers.Patches
{
	[HarmonyPatch(typeof(StatusEffectIcon), "Start")]
	internal static class StatusEffectIcon_Start_Patch
	{
		[HarmonyPostfix]
		private static void Postfix(StatusEffectIcon __instance)
		{
			TimerLabel.CreateLabel(((Component)__instance).gameObject);
		}
	}
	[HarmonyPatch(typeof(StatusEffectIcon), "Update")]
	internal static class StatusEffectIcon_Update_Patch
	{
		[HarmonyPostfix]
		private static void Postfix(StatusEffectIcon __instance)
		{
			Transform val = ((Component)__instance).transform.Find("BuffTimerLabel");
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			TextMeshProUGUI component = ((Component)val).GetComponent<TextMeshProUGUI>();
			if ((Object)(object)component == (Object)null)
			{
				return;
			}
			if (!ModConfig.ShowOnPlayer.Value || !((Behaviour)__instance.Icon).enabled)
			{
				TimerLabel.ClearLabel(component);
				return;
			}
			Stats readStats = __instance.ReadStats;
			object obj;
			if (readStats == null)
			{
				obj = null;
			}
			else
			{
				StatusEffect[] statusEffects = readStats.StatusEffects;
				obj = ((statusEffects != null) ? statusEffects[__instance.SlotIndex] : null);
			}
			StatusEffect effect = (StatusEffect)obj;
			TimerLabel.UpdateLabel(component, effect);
		}
	}
	internal static class TargetStatusIconState
	{
		internal static readonly ConditionalWeakTable<TargetStatusIcon, StatusEffect> LiveEffects = new ConditionalWeakTable<TargetStatusIcon, StatusEffect>();
	}
	[HarmonyPatch(typeof(TargetStatusIcon), "Awake")]
	internal static class TargetStatusIcon_Awake_Patch
	{
		[HarmonyPostfix]
		private static void Postfix(TargetStatusIcon __instance)
		{
			TimerLabel.CreateLabel(((Component)__instance).gameObject);
		}
	}
	[HarmonyPatch(typeof(TargetStatusIcon), "PopulateData")]
	internal static class TargetStatusIcon_PopulateData_Patch
	{
		[HarmonyPostfix]
		private static void Postfix(TargetStatusIcon __instance, StatusEffect _SE)
		{
			TargetStatusIconState.LiveEffects.Remove(__instance);
			TargetStatusIconState.LiveEffects.Add(__instance, _SE);
		}
	}
	[HarmonyPatch(typeof(TargetStatusIcon), "Update")]
	internal static class TargetStatusIcon_Update_Patch
	{
		[HarmonyPostfix]
		private static void Postfix(TargetStatusIcon __instance)
		{
			Transform val = ((Component)__instance).transform.Find("BuffTimerLabel");
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			TextMeshProUGUI component = ((Component)val).GetComponent<TextMeshProUGUI>();
			if (!((Object)(object)component == (Object)null))
			{
				if (!ModConfig.ShowOnTarget.Value || __instance.IsEmpty() || !TargetStatusIconState.LiveEffects.TryGetValue(__instance, out StatusEffect value))
				{
					TimerLabel.ClearLabel(component);
				}
				else
				{
					TimerLabel.UpdateLabel(component, value);
				}
			}
		}
	}
}