Decompiled source of HudControl v1.0.0

BepInEx/plugins/HudControl/HudControl.dll

Decompiled 2 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyVersion("0.0.0.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 LocalHudControl
{
	[BepInPlugin("local.howtofish.hudcontrol", "HUD Control", "1.0.0")]
	[DefaultExecutionOrder(30000)]
	public sealed class HudControl : BaseUnityPlugin
	{
		public const string Id = "local.howtofish.hudcontrol";

		public static HudControl Instance;

		private static readonly FieldInfo UiInstance = AccessTools.Field(typeof(PlayerUI), "_instance");

		private static readonly string[] GroupNames = new string[3] { "_mainCanvas", "_fxCanvas", "_bossCanvas" };

		private readonly List<HudGroup> groups = new List<HudGroup>();

		private ConfigEntry<float> scaleSetting;

		private ConfigEntry<float> opacitySetting;

		private ConfigEntry<bool> hideSetting;

		private Harmony harmony;

		private PlayerUI boundUi;

		private bool open;

		private bool dirty;

		private float nextScan;

		private float saveAt;

		private Rect window = new Rect(32f, 80f, 400f, 300f);

		private CursorLockMode oldLock;

		private bool oldVisible;

		private GUIStyle heading;

		private GUIStyle label;

		private GUIStyle button;

		private GUIStyle checkbox;

		public static bool IsOpen
		{
			get
			{
				if ((Object)(object)Instance != (Object)null)
				{
					return Instance.open;
				}
				return false;
			}
		}

		private void Awake()
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Expected O, but got Unknown
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Expected O, but got Unknown
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Expected O, but got Unknown
			Instance = this;
			((BaseUnityPlugin)this).Config.SaveOnConfigSet = false;
			scaleSetting = ((BaseUnityPlugin)this).Config.Bind<float>("HUD", "Scale", 1f, new ConfigDescription("Base HUD scale: 0.5 (50%) to 1 (default).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 1f), Array.Empty<object>()));
			opacitySetting = ((BaseUnityPlugin)this).Config.Bind<float>("HUD", "Opacity", 1f, new ConfigDescription("Base HUD opacity: 0 (transparent) to 1 (opaque).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
			hideSetting = ((BaseUnityPlugin)this).Config.Bind<bool>("HUD", "HideHUD", false, "Hide the base HUD. The F1 settings panel remains accessible.");
			scaleSetting.Value = HudValues.Clamp(scaleSetting.Value, 0.5f, 1f, 1f);
			opacitySetting.Value = HudValues.Clamp(opacitySetting.Value, 0f, 1f, 1f);
			harmony = new Harmony("local.howtofish.hudcontrol");
			harmony.PatchAll(typeof(HudControl).Assembly);
			((BaseUnityPlugin)this).Config.Save();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"HUD Control loaded. F1 opens scale, visibility and opacity settings.");
		}

		private void Update()
		{
			Keyboard current = Keyboard.current;
			if (current != null && ((ButtonControl)current.f1Key).wasPressedThisFrame)
			{
				SetOpen(!open);
			}
			if (Time.unscaledTime >= nextScan)
			{
				nextScan = Time.unscaledTime + 0.5f;
				object? value = UiInstance.GetValue(null);
				PlayerUI val = (PlayerUI)((value is PlayerUI) ? value : null);
				if ((Object)(object)val != (Object)(object)boundUi || ((Object)(object)val != (Object)null && groups.Count == 0) || ((Object)(object)val == (Object)null && groups.Count > 0))
				{
					Bind(val);
				}
			}
		}

		private void Bind(PlayerUI ui)
		{
			foreach (HudGroup group in groups)
			{
				group.Restore();
			}
			groups.Clear();
			boundUi = ui;
			if ((Object)(object)ui == (Object)null)
			{
				return;
			}
			List<CanvasGroup> list = new List<CanvasGroup>();
			string[] groupNames = GroupNames;
			foreach (string text in groupNames)
			{
				object? value = AccessTools.Field(typeof(PlayerUI), text).GetValue(ui);
				CanvasGroup val = (CanvasGroup)((value is CanvasGroup) ? value : null);
				if ((Object)(object)val != (Object)null && !list.Contains(val))
				{
					list.Add(val);
				}
			}
			foreach (CanvasGroup item in list)
			{
				bool flag = false;
				foreach (CanvasGroup item2 in list)
				{
					if ((Object)(object)item2 != (Object)(object)item && ((Component)item).transform.IsChildOf(((Component)item2).transform))
					{
						flag = true;
					}
				}
				if (!flag)
				{
					groups.Add(new HudGroup(item));
					((BaseUnityPlugin)this).Logger.LogInfo((object)("Controlling base HUD group: " + ((Object)item).name));
				}
			}
		}

		private void LateUpdate()
		{
			foreach (HudGroup group in groups)
			{
				group.Apply(scaleSetting.Value, hideSetting.Value ? 0f : opacitySetting.Value);
			}
			if (open)
			{
				Cursor.lockState = (CursorLockMode)0;
				Cursor.visible = true;
			}
			if (dirty && Time.unscaledTime >= saveAt)
			{
				Save();
			}
		}

		public void CaptureGameAlpha(MethodBase method)
		{
			string text = ((method.Name == "ToggleMainCanvas") ? "_mainCanvas" : ((method.Name == "ToggleFXCanvas") ? "_fxCanvas" : "_bossCanvas"));
			object? value = UiInstance.GetValue(null);
			PlayerUI val = (PlayerUI)((value is PlayerUI) ? value : null);
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			object? value2 = AccessTools.Field(typeof(PlayerUI), text).GetValue(val);
			CanvasGroup val2 = (CanvasGroup)((value2 is CanvasGroup) ? value2 : null);
			foreach (HudGroup group in groups)
			{
				if ((Object)(object)group.Group == (Object)(object)val2)
				{
					group.CaptureAlpha();
				}
			}
		}

		public void CaptureCanvasScale(CanvasScaler scaler, float value)
		{
			foreach (HudGroup group in groups)
			{
				group.CaptureCanvasScale(scaler, value);
			}
		}

		public void SetOpen(bool value)
		{
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: 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_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Invalid comparison between Unknown and I4
			if (open == value)
			{
				return;
			}
			if (value)
			{
				oldLock = Cursor.lockState;
				oldVisible = Cursor.visible;
				open = true;
				try
				{
					PlayerCamera.ToggleMouse(true);
				}
				catch
				{
				}
				Cursor.lockState = (CursorLockMode)0;
				Cursor.visible = true;
			}
			else
			{
				open = false;
				try
				{
					PlayerCamera.ToggleMouse((int)oldLock != 1);
				}
				catch
				{
					Cursor.lockState = oldLock;
					Cursor.visible = oldVisible;
				}
				Save();
			}
		}

		private void Changed()
		{
			dirty = true;
			saveAt = Time.unscaledTime + 0.4f;
		}

		private void Save()
		{
			if (dirty)
			{
				((BaseUnityPlugin)this).Config.Save();
				dirty = false;
			}
		}

		private void OnGUI()
		{
			//IL_014b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0157: Unknown result type (might be due to invalid IL or missing references)
			//IL_0166: Expected O, but got Unknown
			//IL_0161: 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_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Expected O, but got Unknown
			//IL_0040: 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)
			//IL_0052: Expected O, but got Unknown
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Expected O, but got Unknown
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Expected O, but got Unknown
			if (open)
			{
				if (heading == null)
				{
					heading = new GUIStyle(GUI.skin.label)
					{
						fontSize = 21,
						fontStyle = (FontStyle)1
					};
					label = new GUIStyle(GUI.skin.label)
					{
						fontSize = 15
					};
					button = new GUIStyle(GUI.skin.button)
					{
						fontSize = 14
					};
					checkbox = new GUIStyle(GUI.skin.toggle)
					{
						fontSize = 16
					};
				}
				GUI.depth = -10000;
				((Rect)(ref window)).width = Mathf.Min(400, Screen.width);
				((Rect)(ref window)).height = Mathf.Min(300, Screen.height);
				((Rect)(ref window)).x = Mathf.Clamp(((Rect)(ref window)).x, 0f, Mathf.Max(0f, (float)Screen.width - ((Rect)(ref window)).width));
				((Rect)(ref window)).y = Mathf.Clamp(((Rect)(ref window)).y, 0f, Mathf.Max(0f, (float)Screen.height - ((Rect)(ref window)).height));
				window = GUI.Window(4740420, window, new WindowFunction(DrawWindow), "");
			}
		}

		private void DrawWindow(int id)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: 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_0135: Unknown result type (might be due to invalid IL or missing references)
			//IL_016a: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_0208: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_030a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0353: Unknown result type (might be due to invalid IL or missing references)
			GUI.Label(new Rect(18f, 12f, 290f, 32f), "HUD settings", heading);
			if (GUI.Button(new Rect(((Rect)(ref window)).width - 45f, 12f, 28f, 27f), "X", button))
			{
				SetOpen(value: false);
			}
			GUI.Label(new Rect(18f, 51f, ((Rect)(ref window)).width - 36f, 24f), "Scale                         " + Mathf.RoundToInt(scaleSetting.Value * 100f) + "%", label);
			float num = Mathf.Round(GUI.HorizontalSlider(new Rect(20f, 81f, ((Rect)(ref window)).width - 40f, 22f), scaleSetting.Value, 0.5f, 1f) * 100f) / 100f;
			GUI.Label(new Rect(18f, 101f, ((Rect)(ref window)).width - 36f, 23f), "50%                                                 100% (default)", label);
			bool flag = GUI.Toggle(new Rect(20f, 133f, ((Rect)(ref window)).width - 40f, 26f), hideSetting.Value, " Hide HUD", checkbox);
			GUI.Label(new Rect(18f, 171f, ((Rect)(ref window)).width - 36f, 24f), "Opacity                      " + Mathf.RoundToInt(opacitySetting.Value * 100f) + "%", label);
			float num2 = Mathf.Round(GUI.HorizontalSlider(new Rect(20f, 202f, ((Rect)(ref window)).width - 40f, 22f), opacitySetting.Value, 0f, 1f) * 100f) / 100f;
			if (num != scaleSetting.Value || num2 != opacitySetting.Value || flag != hideSetting.Value)
			{
				scaleSetting.Value = num;
				opacitySetting.Value = num2;
				hideSetting.Value = flag;
				Changed();
			}
			if (GUI.Button(new Rect(18f, 246f, 128f, 30f), "Reset defaults", button))
			{
				ConfigEntry<float> obj = scaleSetting;
				float value = (opacitySetting.Value = 1f);
				obj.Value = value;
				hideSetting.Value = false;
				Changed();
			}
			GUI.Label(new Rect(163f, 249f, ((Rect)(ref window)).width - 170f, 25f), (groups.Count == 0) ? "Load a game to preview" : "F1 / Esc to close", label);
			GUI.DragWindow(new Rect(0f, 0f, ((Rect)(ref window)).width - 52f, 45f));
		}

		private void OnDestroy()
		{
			SetOpen(value: false);
			Save();
			foreach (HudGroup group in groups)
			{
				group.Restore();
			}
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
			Instance = null;
		}
	}
	public sealed class HudGroup
	{
		private readonly RectTransform rect;

		private readonly Canvas rootCanvas;

		private readonly Vector3 originalScale;

		private readonly Vector2 originalSize;

		private readonly bool originalRaycasts;

		private readonly bool originalInteractable;

		private readonly MultiplierState alpha;

		private readonly MultiplierState canvasScale;

		public CanvasGroup Group { get; private set; }

		public HudGroup(CanvasGroup group)
		{
			//IL_0025: 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_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			Group = group;
			ref RectTransform reference = ref rect;
			Transform transform = ((Component)group).transform;
			reference = (RectTransform)(object)((transform is RectTransform) ? transform : null);
			originalScale = ((Transform)rect).localScale;
			originalSize = rect.sizeDelta;
			originalRaycasts = group.blocksRaycasts;
			originalInteractable = group.interactable;
			alpha = new MultiplierState(group.alpha);
			Canvas component = ((Component)group).GetComponent<Canvas>();
			if ((Object)(object)component != (Object)null && component.isRootCanvas)
			{
				rootCanvas = component;
				canvasScale = new MultiplierState(component.scaleFactor);
			}
		}

		public void CaptureAlpha()
		{
			if ((Object)(object)Group != (Object)null)
			{
				alpha.SetBaseline(Group.alpha);
			}
		}

		public void CaptureCanvasScale(CanvasScaler scaler, float value)
		{
			if ((Object)(object)rootCanvas != (Object)null && (Object)(object)((Component)scaler).gameObject == (Object)(object)((Component)rootCanvas).gameObject)
			{
				canvasScale.SetBaseline(value);
			}
		}

		public void Apply(float scale, float opacity)
		{
			//IL_014f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0155: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: 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_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: 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)
			if ((Object)(object)Group == (Object)null)
			{
				return;
			}
			alpha.Observe(Group.alpha);
			Group.alpha = alpha.Apply(opacity);
			Group.blocksRaycasts = opacity > 0f && originalRaycasts;
			Group.interactable = opacity > 0f && originalInteractable;
			if ((Object)(object)rootCanvas != (Object)null)
			{
				canvasScale.Observe(rootCanvas.scaleFactor);
				rootCanvas.scaleFactor = canvasScale.Apply(scale);
			}
			else if ((Object)(object)rect != (Object)null)
			{
				Transform parent = ((Transform)rect).parent;
				RectTransform val = (RectTransform)(object)((parent is RectTransform) ? parent : null);
				if ((Object)(object)val != (Object)null)
				{
					Rect val2 = val.rect;
					Vector2 val3 = Vector2.Scale(((Rect)(ref val2)).size, rect.anchorMax - rect.anchorMin);
					rect.sizeDelta = new Vector2(HudValues.CompensatedSize(val3.x, originalSize.x, scale), HudValues.CompensatedSize(val3.y, originalSize.y, scale));
				}
				((Transform)rect).localScale = originalScale * scale;
			}
		}

		public void Restore()
		{
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)Group == (Object)null))
			{
				Group.alpha = alpha.Baseline;
				Group.blocksRaycasts = originalRaycasts;
				Group.interactable = originalInteractable;
				if ((Object)(object)rootCanvas != (Object)null)
				{
					rootCanvas.scaleFactor = canvasScale.Baseline;
				}
				else if ((Object)(object)rect != (Object)null)
				{
					((Transform)rect).localScale = originalScale;
					rect.sizeDelta = originalSize;
				}
			}
		}
	}
	[HarmonyPatch(typeof(Player), "get_BlockInputs")]
	internal static class BlockPlayerInput
	{
		private static void Postfix(Player __instance, ref bool __result)
		{
			if (HudControl.IsOpen && (Object)(object)__instance == (Object)(object)Player.LocalPlayer)
			{
				__result = true;
			}
		}
	}
	[HarmonyPatch]
	internal static class BlockCameraInput
	{
		private static IEnumerable<MethodBase> TargetMethods()
		{
			string[] array = new string[4] { "MouseClick", "MouseInput", "ControllerRotation", "ApplyAimAssist" };
			foreach (string text in array)
			{
				yield return AccessTools.Method(typeof(PlayerCamera), text, (Type[])null, (Type[])null);
			}
		}

		private static bool Prefix()
		{
			return !HudControl.IsOpen;
		}
	}
	[HarmonyPatch(typeof(PauseManager), "PauseInput")]
	internal static class CloseOnEscape
	{
		private static bool Prefix(CallbackContext context)
		{
			if (!HudControl.IsOpen)
			{
				return true;
			}
			if (((CallbackContext)(ref context)).performed)
			{
				HudControl.Instance.SetOpen(value: false);
			}
			return false;
		}
	}
	[HarmonyPatch]
	internal static class RespectGameVisibility
	{
		private static IEnumerable<MethodBase> TargetMethods()
		{
			string[] array = new string[3] { "ToggleMainCanvas", "ToggleFXCanvas", "ToggleBossCanvas" };
			foreach (string text in array)
			{
				yield return AccessTools.Method(typeof(PlayerUI), text, (Type[])null, (Type[])null);
			}
		}

		private static void Postfix(MethodBase __originalMethod)
		{
			if ((Object)(object)HudControl.Instance != (Object)null)
			{
				HudControl.Instance.CaptureGameAlpha(__originalMethod);
			}
		}
	}
	[HarmonyPatch(typeof(CanvasScaler), "SetScaleFactor")]
	internal static class RespectResolutionScale
	{
		private static void Postfix(CanvasScaler __instance, float __0)
		{
			if ((Object)(object)HudControl.Instance != (Object)null)
			{
				HudControl.Instance.CaptureCanvasScale(__instance, __0);
			}
		}
	}
	public static class HudValues
	{
		public static float Clamp(float value, float minimum, float maximum, float fallback)
		{
			if (float.IsNaN(value) || float.IsInfinity(value))
			{
				return fallback;
			}
			return Math.Max(minimum, Math.Min(maximum, value));
		}

		public static float CompensatedSize(float parentSpan, float originalDelta, float scale)
		{
			return (parentSpan + originalDelta) / scale - parentSpan;
		}
	}
	public sealed class MultiplierState
	{
		private float applied;

		private bool hasApplied;

		public float Baseline { get; private set; }

		public MultiplierState(float initial)
		{
			Baseline = initial;
		}

		public void Observe(float current)
		{
			if (!hasApplied || Math.Abs(current - applied) > 1E-05f)
			{
				Baseline = current;
			}
		}

		public void SetBaseline(float value)
		{
			Baseline = value;
		}

		public float Apply(float multiplier)
		{
			hasApplied = true;
			return applied = Baseline * multiplier;
		}
	}
}