Decompiled source of TextUpgradesUIScale v1.4.1

TextUpgradesUIScale.dll

Decompiled a week ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using TMPro;
using TextUpgradesUIScale.Patches;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("TextUpgradesUIScale")]
[assembly: AssemblyDescription("Resizes the R.E.P.O. upgrades UI text for large upgrade lists.")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("DarkSpider90")]
[assembly: AssemblyProduct("TextUpgradesUIScale")]
[assembly: AssemblyCopyright("")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("a27adabc-310b-43d6-8584-f2e1ec7a34cb")]
[assembly: AssemblyFileVersion("1.2.1.0")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyVersion("1.2.1.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 TextUpgradesUIScale
{
	[BepInPlugin("DarkSpider90.TextUpgradesUIScale", "TextUpgradesUIScale", "1.4.1")]
	public class Plugin : BaseUnityPlugin
	{
		private const string ModGuid = "DarkSpider90.TextUpgradesUIScale";

		private const string ModName = "TextUpgradesUIScale";

		private const string ModVersion = "1.4.1";

		private readonly Harmony harmony = new Harmony("DarkSpider90.TextUpgradesUIScale");

		internal static ManualLogSource Log { get; private set; }

		internal static ConfigEntry<bool> ModEnabled { get; private set; }

		internal static ConfigEntry<int> StartShrinkingAfterUpgradesCount { get; private set; }

		internal static ConfigEntry<int> ShrinkEveryUpgrades { get; private set; }

		internal static ConfigEntry<float> ShrinkStep { get; private set; }

		internal static ConfigEntry<float> LineSpacing { get; private set; }

		internal static ConfigEntry<float> MaxTextWidthBeforeShrinking { get; private set; }

		internal static ConfigEntry<float> MinimumTextScale { get; private set; }

		internal static ConfigEntry<bool> AlignColumns { get; private set; }

		internal static ConfigEntry<float> NameColumnOffset { get; private set; }

		private void Awake()
		{
			Log = ((BaseUnityPlugin)this).Logger;
			BindConfig();
			Log.LogInfo((object)"Loaded TextUpgradesUIScale 1.4.1 for R.E.P.O. v0.5.0 UI.");
			harmony.PatchAll(typeof(StatsUIPatch));
		}

		private void BindConfig()
		{
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Expected O, but got Unknown
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Expected O, but got Unknown
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Expected O, but got Unknown
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Expected O, but got Unknown
			//IL_014d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0157: Expected O, but got Unknown
			//IL_018a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0194: Expected O, but got Unknown
			//IL_01c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d1: Expected O, but got Unknown
			ModEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "EnableMod", true, "Enable or disable the mod.");
			StartShrinkingAfterUpgradesCount = ((BaseUnityPlugin)this).Config.Bind<int>("Text fitting", "StartShrinkingAfterUpgradesCount", 10, new ConfigDescription("Start shrinking text after this many active upgrades.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>()));
			ShrinkEveryUpgrades = ((BaseUnityPlugin)this).Config.Bind<int>("Text fitting", "ShrinkEveryUpgrades", 2, new ConfigDescription("Shrink text once per this many additional upgrades.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 20), Array.Empty<object>()));
			ShrinkStep = ((BaseUnityPlugin)this).Config.Bind<float>("Text fitting", "ShrinkStep", 0.07f, new ConfigDescription("Text scale removed per shrink step. 0.07 means 7%.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.01f, 0.5f), Array.Empty<object>()));
			MinimumTextScale = ((BaseUnityPlugin)this).Config.Bind<float>("Text fitting", "MinimumTextScale", 0.45f, new ConfigDescription("The smallest the text is allowed to get, as a share of its normal size.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.05f, 1f), Array.Empty<object>()));
			AlignColumns = ((BaseUnityPlugin)this).Config.Bind<bool>("Layout", "AlignColumns", true, "Draw each upgrade's level and name on one line so they always line up. The game draws them as two separate columns, which drift apart when a language uses a taller font than the digits do.");
			NameColumnOffset = ((BaseUnityPlugin)this).Config.Bind<float>("Layout", "NameColumnOffset", 1.5f, new ConfigDescription("How far from the left the upgrade names start, in character widths. Only used when AlignColumns is on.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 10f), Array.Empty<object>()));
			LineSpacing = ((BaseUnityPlugin)this).Config.Bind<float>("Layout", "LineSpacing", -4f, new ConfigDescription("Extra vertical spacing between upgrade rows while scaled. Negative values make the list tighter.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-30f, 30f), Array.Empty<object>()));
			MaxTextWidthBeforeShrinking = ((BaseUnityPlugin)this).Config.Bind<float>("Layout", "MaxTextWidthBeforeShrinking", 0f, new ConfigDescription("Shrink text if the upgrade names become wider than this value. Set to 0 to disable width-based shrinking.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 2000f), Array.Empty<object>()));
		}
	}
}
namespace TextUpgradesUIScale.Patches
{
	[HarmonyPatch(typeof(StatsUI), "Fetch")]
	public static class StatsUIPatch
	{
		private const float TechnicalMinimumScale = 0.05f;

		private static readonly FieldInfo TextField = AccessTools.Field(typeof(StatsUI), "Text");

		private static readonly FieldInfo NumbersTextField = AccessTools.Field(typeof(StatsUI), "textNumbers");

		private static readonly FieldInfo PlayerUpgradesField = AccessTools.Field(typeof(StatsUI), "playerUpgrades");

		private static TextMeshProUGUI _cachedMainText;

		private static TextMeshProUGUI _cachedNumbersText;

		private static float _defaultFontSize;

		private static float _defaultNumbersFontSize;

		private static bool _defaultAutoSizing;

		private static bool _defaultNumbersAutoSizing;

		private static TextWrappingModes _defaultWrappingMode;

		private static TextWrappingModes _defaultNumbersWrappingMode;

		private static TextOverflowModes _defaultOverflowMode;

		private static TextOverflowModes _defaultNumbersOverflowMode;

		private static VerticalAlignmentOptions _defaultVerticalAlignment;

		private static VerticalAlignmentOptions _defaultNumbersVerticalAlignment;

		private static float _defaultLineSpacing;

		private static float _defaultNumbersLineSpacing;

		private static bool _defaultFontSizeInitialized;

		private static bool _loggedMissingFields;

		private static bool _loggedException;

		private static bool _loggedFittingNumbers;

		private const char LineBreak = '\n';

		public static void Postfix(StatsUI __instance)
		{
			try
			{
				TextMeshProUGUI val = (TextMeshProUGUI)((TextField == null) ? null : /*isinst with value type is only supported in some contexts*/);
				TextMeshProUGUI val2 = (TextMeshProUGUI)((NumbersTextField == null) ? null : /*isinst with value type is only supported in some contexts*/);
				Dictionary<string, int> dictionary = ((PlayerUpgradesField == null) ? null : (PlayerUpgradesField.GetValue(__instance) as Dictionary<string, int>));
				if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null || dictionary == null)
				{
					LogMissingFieldsOnce();
					return;
				}
				CaptureDefaultsIfNeeded(val, val2);
				if (!Plugin.ModEnabled.Value)
				{
					RestoreTextColumns(val, val2);
					return;
				}
				if (Plugin.AlignColumns.Value)
				{
					MergeColumns(val, val2);
				}
				float scaleForUpgradeCount = GetScaleForUpgradeCount(CountActiveUpgrades(dictionary));
				scaleForUpgradeCount = ApplyWidthLimit(val, scaleForUpgradeCount);
				ReportFittingNumbersOnce(val, scaleForUpgradeCount);
				if (scaleForUpgradeCount >= 0.999f)
				{
					RestoreTextColumns(val, val2);
					return;
				}
				ConfigureTextColumn(val, _defaultLineSpacing);
				ConfigureTextColumn(val2, _defaultNumbersLineSpacing);
				((TMP_Text)val).fontSize = _defaultFontSize * scaleForUpgradeCount;
				((TMP_Text)val2).fontSize = _defaultNumbersFontSize * scaleForUpgradeCount;
			}
			catch (Exception ex)
			{
				if (!_loggedException)
				{
					_loggedException = true;
					if (Plugin.Log != null)
					{
						Plugin.Log.LogWarning((object)("[TextUpgradesUIScale] Failed to resize StatsUI text: " + ex.Message));
					}
				}
			}
		}

		private static void CaptureDefaultsIfNeeded(TextMeshProUGUI mainText, TextMeshProUGUI numbersText)
		{
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: 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_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: 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_007c: 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_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: 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)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			if (!_defaultFontSizeInitialized || !((Object)(object)_cachedMainText == (Object)(object)mainText) || !((Object)(object)_cachedNumbersText == (Object)(object)numbersText))
			{
				_cachedMainText = mainText;
				_cachedNumbersText = numbersText;
				_defaultFontSize = ((TMP_Text)mainText).fontSize;
				_defaultNumbersFontSize = ((TMP_Text)numbersText).fontSize;
				_defaultAutoSizing = ((TMP_Text)mainText).enableAutoSizing;
				_defaultNumbersAutoSizing = ((TMP_Text)numbersText).enableAutoSizing;
				_defaultWrappingMode = ((TMP_Text)mainText).textWrappingMode;
				_defaultNumbersWrappingMode = ((TMP_Text)numbersText).textWrappingMode;
				_defaultOverflowMode = ((TMP_Text)mainText).overflowMode;
				_defaultNumbersOverflowMode = ((TMP_Text)numbersText).overflowMode;
				_defaultVerticalAlignment = ((TMP_Text)mainText).verticalAlignment;
				_defaultNumbersVerticalAlignment = ((TMP_Text)numbersText).verticalAlignment;
				_defaultLineSpacing = ((TMP_Text)mainText).lineSpacing;
				_defaultNumbersLineSpacing = ((TMP_Text)numbersText).lineSpacing;
				_defaultFontSizeInitialized = true;
			}
		}

		private static void MergeColumns(TextMeshProUGUI mainText, TextMeshProUGUI numbersText)
		{
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			string text = ((TMP_Text)mainText).text;
			string text2 = ((TMP_Text)numbersText).text;
			if (string.IsNullOrEmpty(text) || string.IsNullOrEmpty(text2))
			{
				return;
			}
			string[] array = text.Split('\n');
			string[] array2 = text2.Split('\n');
			int num = Mathf.Min(array.Length, array2.Length);
			StringBuilder stringBuilder = new StringBuilder(text.Length + text2.Length + num * 32);
			float num2 = Mathf.Max(0.5f, Plugin.NameColumnOffset.Value);
			string value = ColorUtility.ToHtmlStringRGB(((Graphic)numbersText).color);
			for (int i = 0; i < num; i++)
			{
				string value2 = array[i];
				if (!string.IsNullOrEmpty(value2))
				{
					if (stringBuilder.Length > 0)
					{
						stringBuilder.Append('\n');
					}
					stringBuilder.Append("<color=#").Append(value).Append('>')
						.Append(array2[i])
						.Append("</color>")
						.Append("<pos=")
						.Append(num2.ToString("0.##", CultureInfo.InvariantCulture))
						.Append("em>")
						.Append(value2);
				}
			}
			((TMP_Text)mainText).text = stringBuilder.ToString();
			((TMP_Text)numbersText).text = string.Empty;
		}

		private static int CountActiveUpgrades(Dictionary<string, int> playerUpgrades)
		{
			int num = 0;
			foreach (KeyValuePair<string, int> playerUpgrade in playerUpgrades)
			{
				if (playerUpgrade.Value > 0)
				{
					num++;
				}
			}
			return num;
		}

		private static void ConfigureTextColumn(TextMeshProUGUI text, float defaultLineSpacing)
		{
			((TMP_Text)text).enableAutoSizing = false;
			((TMP_Text)text).textWrappingMode = (TextWrappingModes)0;
			((TMP_Text)text).overflowMode = (TextOverflowModes)0;
			((TMP_Text)text).verticalAlignment = (VerticalAlignmentOptions)256;
			((TMP_Text)text).lineSpacing = defaultLineSpacing + Plugin.LineSpacing.Value;
		}

		private static void RestoreTextColumns(TextMeshProUGUI mainText, TextMeshProUGUI numbersText)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//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_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			RestoreTextColumn(mainText, _defaultFontSize, _defaultAutoSizing, _defaultWrappingMode, _defaultOverflowMode, _defaultVerticalAlignment, _defaultLineSpacing);
			RestoreTextColumn(numbersText, _defaultNumbersFontSize, _defaultNumbersAutoSizing, _defaultNumbersWrappingMode, _defaultNumbersOverflowMode, _defaultNumbersVerticalAlignment, _defaultNumbersLineSpacing);
		}

		private static void RestoreTextColumn(TextMeshProUGUI text, float fontSize, bool autoSizing, TextWrappingModes wrappingMode, TextOverflowModes overflowMode, VerticalAlignmentOptions verticalAlignment, float lineSpacing)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			((TMP_Text)text).fontSize = fontSize;
			((TMP_Text)text).enableAutoSizing = autoSizing;
			((TMP_Text)text).textWrappingMode = wrappingMode;
			((TMP_Text)text).overflowMode = overflowMode;
			((TMP_Text)text).verticalAlignment = verticalAlignment;
			((TMP_Text)text).lineSpacing = lineSpacing;
		}

		private static float GetScaleForUpgradeCount(int activeUpgradesCount)
		{
			int num = Mathf.Max(0, Plugin.StartShrinkingAfterUpgradesCount.Value);
			if (activeUpgradesCount <= num)
			{
				return 1f;
			}
			int num2 = Mathf.Max(1, Plugin.ShrinkEveryUpgrades.Value);
			float num3 = Mathf.Clamp(Plugin.ShrinkStep.Value, 0.01f, 0.5f);
			int num4 = Mathf.CeilToInt((float)Mathf.Max(0, activeUpgradesCount - num) / (float)num2);
			return ClampScale(1f - (float)num4 * num3);
		}

		private static float ApplyWidthLimit(TextMeshProUGUI mainText, float currentScale)
		{
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			float value = Plugin.MaxTextWidthBeforeShrinking.Value;
			if (value <= 1f)
			{
				return currentScale;
			}
			ConfigureTextColumn(mainText, _defaultLineSpacing);
			((TMP_Text)mainText).fontSize = _defaultFontSize * currentScale;
			if (((TMP_Text)mainText).GetPreferredValues(((TMP_Text)mainText).text, float.PositiveInfinity, float.PositiveInfinity).x <= value)
			{
				return currentScale;
			}
			float num = MinimumScale();
			float num2 = currentScale;
			for (int i = 0; i < 8; i++)
			{
				float num3 = (num + num2) * 0.5f;
				((TMP_Text)mainText).fontSize = _defaultFontSize * num3;
				if (((TMP_Text)mainText).GetPreferredValues(((TMP_Text)mainText).text, float.PositiveInfinity, float.PositiveInfinity).x <= value)
				{
					num = num3;
				}
				else
				{
					num2 = num3;
				}
			}
			return ClampScale(num);
		}

		private static void ReportFittingNumbersOnce(TextMeshProUGUI mainText, float scale)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: 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)
			if (!_loggedFittingNumbers && Plugin.Log != null)
			{
				_loggedFittingNumbers = true;
				Rect rect = ((TMP_Text)mainText).rectTransform.rect;
				float height = ((Rect)(ref rect)).height;
				Transform parent = ((Transform)((TMP_Text)mainText).rectTransform).parent;
				RectTransform val = (RectTransform)(object)((parent is RectTransform) ? parent : null);
				float num;
				if (!((Object)(object)val != (Object)null))
				{
					num = -1f;
				}
				else
				{
					rect = val.rect;
					num = ((Rect)(ref rect)).height;
				}
				float num2 = num;
				float num3 = MeasuredHeight(mainText, scale);
				((TMP_Text)mainText).fontSize = _defaultFontSize * scale;
				Plugin.Log.LogInfo((object)($"[TextUpgradesUIScale] Column rect={height:F1}, parent rect={num2:F1}, " + $"rendered={num3:F1} at scale {scale:F2}, lines={CountLines(((TMP_Text)mainText).text)}."));
			}
		}

		private static int CountLines(string text)
		{
			if (string.IsNullOrEmpty(text))
			{
				return 0;
			}
			int num = 1;
			for (int i = 0; i < text.Length; i++)
			{
				if (text[i] == '\n')
				{
					num++;
				}
			}
			return num;
		}

		private static float MeasuredHeight(TextMeshProUGUI text, float scale)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			((TMP_Text)text).fontSize = _defaultFontSize * scale;
			return ((TMP_Text)text).GetPreferredValues(((TMP_Text)text).text, float.PositiveInfinity, float.PositiveInfinity).y;
		}

		private static float MinimumScale()
		{
			return Mathf.Clamp(Plugin.MinimumTextScale.Value, 0.05f, 1f);
		}

		private static float ClampScale(float scale)
		{
			return Mathf.Clamp(scale, MinimumScale(), 1f);
		}

		private static void LogMissingFieldsOnce()
		{
			if (!_loggedMissingFields)
			{
				_loggedMissingFields = true;
				if (Plugin.Log != null)
				{
					Plugin.Log.LogWarning((object)"[TextUpgradesUIScale] Could not access StatsUI text fields. The game UI may have changed.");
				}
			}
		}
	}
}