Decompiled source of RiskUIFixes v1.0.3

RiskUIFix.dll

Decompiled 9 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using MaterialHud;
using RoR2;
using RoR2.UI;
using TMPro;
using UnityEngine;
using ZioConfigFile;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace RiskUIFix;

[BepInPlugin("com.RiskUIFix.RiskUIFix", "RiskUIFixes", "1.0.3")]
public class RiskUIFixPlugin : BaseUnityPlugin
{
	public const string GUID = "com.RiskUIFix.RiskUIFix";

	public const string NAME = "RiskUIFixes";

	public const string VERSION = "1.0.3";

	internal static ManualLogSource Log;

	internal static Func<bool> TimerCentisecondsValue;

	internal static Func<float> ObjectiveSizeValue;

	private void Awake()
	{
		//IL_0010: Unknown result type (might be due to invalid IL or missing references)
		//IL_0016: Expected O, but got Unknown
		Log = ((BaseUnityPlugin)this).Logger;
		try
		{
			Harmony harmony = new Harmony("com.RiskUIFix.RiskUIFix");
			PatchDirect(harmony, AccessTools.Method(typeof(TooltipProvider), "SetTooltip", (Type[])null, (Type[])null), "SetTooltipPrefix", null);
			PatchDirect(harmony, FindExplicitInterfaceMethod(typeof(TooltipProvider), "OnPointerEnter"), "PointerEnterPrefix", null);
			PatchDirect(harmony, FindExplicitInterfaceMethod(typeof(TooltipProvider), "OnPointerExit"), null, "PointerExitPostfix");
			PatchDirect(harmony, AccessTools.Method(typeof(TooltipProvider), "OnSelect", (Type[])null, (Type[])null), "SelectPrefix", null);
			Type type = AccessTools.TypeByName("MaterialHud.DifficultyTextController");
			if (type != null)
			{
				PatchDirect(harmony, AccessTools.Method(type, "Awake", (Type[])null, (Type[])null), null, "DifficultyAwakePostfix");
				PatchDirect(harmony, AccessTools.Method(type, "OnDestroy", (Type[])null, (Type[])null), null, "DifficultyDestroyPostfix");
			}
			else
			{
				Log.LogWarning((object)"MaterialHud.DifficultyTextController not found (centiseconds toggle will not apply).");
			}
			PatchDirect(harmony, AccessTools.Method(typeof(ObjectivePanelController), "Update", (Type[])null, (Type[])null), null, "ObjectivePanelUpdatePostfix");
			RoR2Application.onLoad = (Action)Delegate.Combine(RoR2Application.onLoad, new Action(OnGameLoaded));
			Log.LogInfo((object)"RiskUIFixes 1.0.3 loaded.");
		}
		catch (Exception ex)
		{
			Log.LogError((object)("Failed to apply patches: " + ex));
		}
	}

	private void OnGameLoaded()
	{
		try
		{
			BindConfig();
		}
		catch (Exception ex)
		{
			Log.LogWarning((object)("Failed to integrate with RiskUI settings: " + ex));
		}
	}

	private void BindConfig()
	{
		//IL_009a: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a4: Expected O, but got Unknown
		ReadLegacyConfig(out var centiseconds, out var size);
		if (ConfigHelper.ActiveConfigFile == null)
		{
			Log.LogWarning((object)"RiskUI config system not initialized; falling back to a plain BepInEx config (RiskUIFixes.cfg).");
			ConfigEntry<bool> plainTimer = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Show Timer Centiseconds", centiseconds, "Show the centiseconds on the difficulty timer.");
			plainTimer.SettingChanged += OnTimerCentisecondsChanged;
			ConfigEntry<float> plainSize = ((BaseUnityPlugin)this).Config.Bind<float>("Rescaling", "Objective Text Size", size, new ConfigDescription("Size of the objective text (top right), in percent of the default.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 300f), new object[0]));
			TimerCentisecondsValue = () => plainTimer.Value;
			ObjectiveSizeValue = () => plainSize.Value;
		}
		else
		{
			ZioConfigEntry<bool> timer = ConfigHelper.Bind<bool>("General", "Show Timer Centiseconds", centiseconds, "Show the centiseconds on the difficulty timer.", (Action<ZioConfigEntry<bool>>)null, (object)null);
			((ZioConfigEntryBase)timer).SettingChanged += OnTimerSettingChanged;
			ZioConfigEntry<float> size2 = ConfigHelper.Bind<float>("Rescaling", "Objective Text Size", size, "Size of the objective text (top right), in percent of the default.", (Action<ZioConfigEntry<float>>)null, (object)300f);
			TimerCentisecondsValue = () => timer.Value;
			ObjectiveSizeValue = () => size2.Value;
			Log.LogInfo((object)"Settings integrated into RiskUI's menu (Zio config).");
		}
	}

	private static void OnTimerSettingChanged(ZioConfigEntryBase entry, object oldValue, bool ignored)
	{
		Patches.ApplyTimerCentisecondsToAll();
	}

	private void OnTimerCentisecondsChanged(object sender, EventArgs e)
	{
		Patches.ApplyTimerCentisecondsToAll();
	}

	private void ReadLegacyConfig(out bool centiseconds, out float size)
	{
		centiseconds = true;
		size = 100f;
		try
		{
			string path = Path.Combine(Paths.ConfigPath, "com.RiskUIFix.RiskUIFix.cfg");
			if (!File.Exists(path))
			{
				return;
			}
			string[] array = File.ReadAllLines(path);
			foreach (string text in array)
			{
				string text2 = text.Trim();
				int num = text2.IndexOf('=');
				if (num <= 0)
				{
					continue;
				}
				string text3 = text2.Substring(0, num).Trim();
				string text4 = text2.Substring(num + 1).Trim();
				float result2;
				if (text3 == "Show Timer Centiseconds")
				{
					if (bool.TryParse(text4, out var result))
					{
						centiseconds = result;
					}
				}
				else if (text3 == "Objective Text Size" && float.TryParse(text4, out result2))
				{
					size = result2;
				}
			}
		}
		catch (Exception ex)
		{
			Log.LogWarning((object)("Legacy config migration failed: " + ex));
		}
	}

	private static MethodInfo FindExplicitInterfaceMethod(Type type, string methodName)
	{
		MethodInfo[] methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		MethodInfo result = null;
		for (int i = 0; i < methods.Length; i++)
		{
			if (methods[i].Name.EndsWith("." + methodName, StringComparison.Ordinal))
			{
				result = methods[i];
				break;
			}
		}
		return result;
	}

	private void PatchDirect(Harmony harmony, MethodInfo target, string prefix, string postfix)
	{
		//IL_003d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0043: Expected O, but got Unknown
		//IL_0065: Unknown result type (might be due to invalid IL or missing references)
		//IL_006b: Expected O, but got Unknown
		if (target == null)
		{
			Log.LogWarning((object)"Patch target is null (skipped).");
			return;
		}
		HarmonyMethod val = null;
		HarmonyMethod val2 = null;
		if (prefix != null)
		{
			MethodInfo method = typeof(Patches).GetMethod(prefix, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
			if (method != null)
			{
				val = new HarmonyMethod(method);
			}
		}
		if (postfix != null)
		{
			MethodInfo method2 = typeof(Patches).GetMethod(postfix, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
			if (method2 != null)
			{
				val2 = new HarmonyMethod(method2);
			}
		}
		harmony.Patch((MethodBase)target, val, val2, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
	}
}
internal static class Patches
{
	internal static readonly ConditionalWeakTable<TooltipProvider, object> _suppressed = new ConditionalWeakTable<TooltipProvider, object>();

	private static readonly object _marker = new object();

	private static readonly List<object> _liveDifficultyControllers = new List<object>();

	private static readonly ConditionalWeakTable<TMP_Text, object> _originalObjectiveFontSizes = new ConditionalWeakTable<TMP_Text, object>();

	private static FieldInfo _dtcTimerCentiRecolorer;

	private static FieldInfo _recolorerTarget;

	private static bool _difficultyResolved;

	private static bool _objectiveResolved;

	private static bool _objectiveFailureLogged;

	private static FieldInfo _objectiveTrackersField;

	private static FieldInfo _trackerLabelField;

	private static bool ResolveDifficultyFields()
	{
		if (_difficultyResolved)
		{
			return true;
		}
		try
		{
			Type type = AccessTools.TypeByName("MaterialHud.DifficultyTextController");
			Type type2 = AccessTools.TypeByName("MaterialHud.RedToColorRemapperIndividual");
			if (type == null || type2 == null)
			{
				RiskUIFixPlugin.Log.LogWarning((object)"Difficulty widget types not found.");
				return false;
			}
			_dtcTimerCentiRecolorer = AccessTools.Field(type, "timerCentiTextRecolorer");
			_recolorerTarget = AccessTools.Field(type2, "target");
			_difficultyResolved = _dtcTimerCentiRecolorer != null && _recolorerTarget != null;
			if (!_difficultyResolved)
			{
				RiskUIFixPlugin.Log.LogWarning((object)("Some difficulty widget fields were not found; timerCentiTextRecolorer=" + (_dtcTimerCentiRecolorer != null) + " target=" + (_recolorerTarget != null)));
			}
		}
		catch (Exception ex)
		{
			RiskUIFixPlugin.Log.LogError((object)("Difficulty widget reflection resolution failed: " + ex));
			_difficultyResolved = false;
		}
		return _difficultyResolved;
	}

	private static bool ResolveObjectiveFields()
	{
		if (_objectiveResolved)
		{
			return true;
		}
		try
		{
			_objectiveTrackersField = AccessTools.Field(typeof(ObjectivePanelController), "objectiveTrackers");
			Type nestedType = typeof(ObjectivePanelController).GetNestedType("ObjectiveTracker", BindingFlags.Public | BindingFlags.NonPublic);
			_trackerLabelField = ((nestedType != null) ? AccessTools.Field(nestedType, "label") : null);
			_objectiveResolved = _objectiveTrackersField != null && _trackerLabelField != null;
			if (!_objectiveResolved)
			{
				RiskUIFixPlugin.Log.LogWarning((object)("Objective fields not found: objectiveTrackers=" + (_objectiveTrackersField != null) + " label=" + (_trackerLabelField != null)));
			}
		}
		catch (Exception ex)
		{
			RiskUIFixPlugin.Log.LogError((object)("Objective reflection resolution failed: " + ex));
			_objectiveResolved = false;
		}
		return _objectiveResolved;
	}

	private static void ObjectivePanelUpdatePostfix(object __instance)
	{
		try
		{
			if (__instance == null || RiskUIFixPlugin.ObjectiveSizeValue == null || !ResolveObjectiveFields() || !(_objectiveTrackersField.GetValue(__instance) is IList list))
			{
				return;
			}
			float percent = RiskUIFixPlugin.ObjectiveSizeValue();
			for (int i = 0; i < list.Count; i++)
			{
				object obj = list[i];
				if (obj != null)
				{
					ApplyObjectiveSize(obj, percent);
				}
			}
		}
		catch (Exception ex)
		{
			if (!_objectiveFailureLogged)
			{
				_objectiveFailureLogged = true;
				RiskUIFixPlugin.Log.LogWarning((object)("ObjectivePanelUpdatePostfix failed: " + ex));
			}
		}
	}

	private static void ApplyObjectiveSize(object tracker, float percent)
	{
		object? value = _trackerLabelField.GetValue(tracker);
		TMP_Text val = (TMP_Text)((value is TMP_Text) ? value : null);
		if (!((Object)(object)val == (Object)null))
		{
			float num;
			if (!_originalObjectiveFontSizes.TryGetValue(val, out var value2))
			{
				num = val.fontSize;
				_originalObjectiveFontSizes.Add(val, num);
			}
			else
			{
				num = (float)value2;
			}
			float num2 = num * percent / 100f;
			if (val.fontSize != num2)
			{
				val.fontSize = num2;
			}
		}
	}

	private static bool SetTooltipPrefix(TooltipProvider __instance)
	{
		object value;
		return !_suppressed.TryGetValue(__instance, out value);
	}

	private static void PointerEnterPrefix(TooltipProvider __instance)
	{
		_suppressed.Remove(__instance);
	}

	private static void SelectPrefix(TooltipProvider __instance)
	{
		_suppressed.Remove(__instance);
	}

	private static void PointerExitPostfix(TooltipProvider __instance)
	{
		_suppressed.Remove(__instance);
		_suppressed.Add(__instance, _marker);
	}

	private static void DifficultyAwakePostfix(object __instance)
	{
		try
		{
			if (__instance != null && !_liveDifficultyControllers.Contains(__instance))
			{
				_liveDifficultyControllers.Add(__instance);
				ApplyTimerCentiseconds(__instance);
			}
		}
		catch (Exception ex)
		{
			RiskUIFixPlugin.Log.LogWarning((object)("DifficultyAwakePostfix failed: " + ex));
		}
	}

	private static void DifficultyDestroyPostfix(object __instance)
	{
		try
		{
			if (__instance != null)
			{
				_liveDifficultyControllers.Remove(__instance);
			}
		}
		catch (Exception ex)
		{
			RiskUIFixPlugin.Log.LogWarning((object)("DifficultyDestroyPostfix failed: " + ex));
		}
	}

	internal static void ApplyTimerCentisecondsToAll()
	{
		object[] array = _liveDifficultyControllers.ToArray();
		for (int i = 0; i < array.Length; i++)
		{
			ApplyTimerCentiseconds(array[i]);
		}
	}

	private static void ApplyTimerCentiseconds(object instance)
	{
		if (instance == null || !ResolveDifficultyFields() || RiskUIFixPlugin.TimerCentisecondsValue == null)
		{
			return;
		}
		object value = _dtcTimerCentiRecolorer.GetValue(instance);
		if (value == null)
		{
			return;
		}
		object? value2 = _recolorerTarget.GetValue(value);
		Behaviour val = (Behaviour)((value2 is Behaviour) ? value2 : null);
		if (!((Object)(object)val == (Object)null))
		{
			bool flag = RiskUIFixPlugin.TimerCentisecondsValue();
			if (((Component)val).gameObject.activeSelf != flag)
			{
				((Component)val).gameObject.SetActive(flag);
			}
		}
	}
}