Decompiled source of MixedCaseMapMarkers v1.1.0

plugins/MixedCaseMapMarkers/MixedCaseMapMarkers.dll

Decompiled a day ago
using System;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using MixedCaseMapMarkers.Patches;
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("LexPy")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Displays Valheim map marker names using their stored lowercase and mixed-case text.")]
[assembly: AssemblyFileVersion("1.1.0.0")]
[assembly: AssemblyInformationalVersion("1.1.0")]
[assembly: AssemblyProduct("MixedCaseMapMarkers")]
[assembly: AssemblyTitle("MixedCaseMapMarkers")]
[assembly: AssemblyVersion("1.1.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 MixedCaseMapMarkers
{
	[BepInPlugin("com.lexpy.mixedcasemapmarkers", "MixedCaseMapMarkers", "1.1.0")]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "com.lexpy.mixedcasemapmarkers";

		public const string PluginName = "MixedCaseMapMarkers";

		public const string PluginVersion = "1.1.0";

		private Harmony? _harmony;

		internal static ManualLogSource? Log { get; private set; }

		private void Awake()
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			_harmony = new Harmony("com.lexpy.mixedcasemapmarkers");
			_harmony.PatchAll(typeof(Plugin).Assembly);
			((BaseUnityPlugin)this).Logger.LogInfo((object)"MixedCaseMapMarkers 1.1.0 loaded.");
		}

		private void OnDestroy()
		{
			Harmony? harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
			MapMarkerText.Dispose();
			_harmony = null;
			Log = null;
		}
	}
}
namespace MixedCaseMapMarkers.Patches
{
	internal static class MapMarkerText
	{
		private const float FontSizeMultiplier = 0.86f;

		private const float CharacterSpacingAdjustment = -3.25f;

		private const float WordSpacingAdjustment = -2f;

		private const float CharacterWidthAdjustment = 18f;

		private const float OutlineWidth = 0.12f;

		private const string UnderlayKeyword = "UNDERLAY_ON";

		private static readonly Color OutlineColor = new Color(0f, 0f, 0f, 1f);

		private static readonly Color UnderlayColor = new Color(0f, 0f, 0f, 0.85f);

		private static readonly int OutlineColorId = Shader.PropertyToID("_OutlineColor");

		private static readonly int OutlineWidthId = Shader.PropertyToID("_OutlineWidth");

		private static readonly int UnderlayColorId = Shader.PropertyToID("_UnderlayColor");

		private static readonly int UnderlayOffsetXId = Shader.PropertyToID("_UnderlayOffsetX");

		private static readonly int UnderlayOffsetYId = Shader.PropertyToID("_UnderlayOffsetY");

		private static readonly int UnderlayDilateId = Shader.PropertyToID("_UnderlayDilate");

		private static readonly int UnderlaySoftnessId = Shader.PropertyToID("_UnderlaySoftness");

		private static readonly FieldInfo? ChatInputField = AccessTools.Field(typeof(Terminal), "m_input");

		private static readonly FieldInfo? NameInputField = AccessTools.Field(typeof(Minimap), "m_nameInput");

		private static TMP_FontAsset? _chatFont;

		private static Material? _markerMaterial;

		private static FieldInfo? _pinSaveField;

		private static Type? _pinDataType;

		private static bool _fontLogged;

		private static bool _missingInputWarningLogged;

		private static bool _missingSaveFieldWarningLogged;

		public static void CaptureChatFont(Chat chat)
		{
			if (_chatFont != null || chat == null)
			{
				return;
			}
			_chatFont = FindFont(ChatInputField?.GetValue(chat));
			if (_chatFont == null)
			{
				return;
			}
			_markerMaterial = CreateMarkerMaterial(_chatFont);
			if (!_fontLogged)
			{
				ManualLogSource? log = Plugin.Log;
				if (log != null)
				{
					log.LogInfo((object)("Using Valheim chat font '" + ((Object)_chatFont).name + "' for persistent map markers."));
				}
				_fontLogged = true;
			}
		}

		public static void ConfigureNameInput(Minimap minimap)
		{
			if (minimap == null || _chatFont == null)
			{
				return;
			}
			object obj = NameInputField?.GetValue(minimap);
			if (obj == null)
			{
				LogMissingInputWarning();
				return;
			}
			GameObject root = GetRoot(obj);
			if (root != null)
			{
				TMP_InputField[] componentsInChildren = root.GetComponentsInChildren<TMP_InputField>(true);
				foreach (TMP_InputField obj2 in componentsInChildren)
				{
					obj2.contentType = (ContentType)0;
					obj2.characterValidation = (CharacterValidation)0;
					obj2.inputValidator = null;
					obj2.onValidateInput = null;
				}
				TMP_Text[] componentsInChildren2 = root.GetComponentsInChildren<TMP_Text>(true);
				for (int i = 0; i < componentsInChildren2.Length; i++)
				{
					ApplyText(componentsInChildren2[i]);
				}
			}
		}

		public static int CaptureChildCount(RectTransform? root)
		{
			if (root == null)
			{
				return -1;
			}
			return ((Transform)root).childCount;
		}

		public static void ApplyCreatedPersistentMarker(object? pinData, RectTransform? root, int previousChildCount)
		{
			if (_chatFont == null || root == null || previousChildCount < 0 || !IsPersistentPin(pinData))
			{
				return;
			}
			for (int i = Mathf.Clamp(previousChildCount, 0, ((Transform)root).childCount); i < ((Transform)root).childCount; i++)
			{
				TMP_Text[] componentsInChildren = ((Component)((Transform)root).GetChild(i)).GetComponentsInChildren<TMP_Text>(true);
				for (int j = 0; j < componentsInChildren.Length; j++)
				{
					ApplyText(componentsInChildren[j]);
				}
			}
		}

		public static void Dispose()
		{
			if (_markerMaterial != null)
			{
				Object.Destroy((Object)(object)_markerMaterial);
			}
			_chatFont = null;
			_markerMaterial = null;
			_pinSaveField = null;
			_pinDataType = null;
		}

		private static bool IsPersistentPin(object? pinData)
		{
			if (pinData == null)
			{
				return false;
			}
			Type type = pinData.GetType();
			if (_pinDataType != type)
			{
				_pinDataType = type;
				_pinSaveField = AccessTools.Field(type, "m_save");
			}
			if ((object)_pinSaveField == null)
			{
				if (!_missingSaveFieldWarningLogged)
				{
					ManualLogSource? log = Plugin.Log;
					if (log != null)
					{
						log.LogWarning((object)"Valheim's PinData.m_save field was not found. Persistent marker labels will not be modified.");
					}
					_missingSaveFieldWarningLogged = true;
				}
				return false;
			}
			object value = _pinSaveField.GetValue(pinData);
			if (value is bool)
			{
				return (bool)value;
			}
			return false;
		}

		private static void ApplyText(TMP_Text text)
		{
			if (!((Object)(object)text.font == (Object)(object)_chatFont) || (_markerMaterial != null && !((Object)(object)text.fontSharedMaterial == (Object)(object)_markerMaterial)))
			{
				RemoveCaseStyle(text);
				text.font = _chatFont;
				if (_markerMaterial != null)
				{
					text.fontSharedMaterial = _markerMaterial;
				}
				text.fontSize *= 0.86f;
				text.fontSizeMin *= 0.86f;
				text.fontSizeMax *= 0.86f;
				text.characterSpacing += -3.25f;
				text.wordSpacing += -2f;
				text.characterWidthAdjustment = Mathf.Max(text.characterWidthAdjustment, 18f);
				((Graphic)text).SetVerticesDirty();
				((Graphic)text).SetLayoutDirty();
			}
		}

		private static Material? CreateMarkerMaterial(TMP_FontAsset font)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Expected O, but got Unknown
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Expected O, but got Unknown
			//IL_0052: 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_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Expected O, but got Unknown
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Expected O, but got Unknown
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Expected O, but got Unknown
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Expected O, but got Unknown
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Expected O, but got Unknown
			//IL_00ae: Expected O, but got Unknown
			Material material = ((TMP_Asset)font).material;
			if (material == null)
			{
				ManualLogSource? log = Plugin.Log;
				if (log != null)
				{
					log.LogWarning((object)"Valheim's chat font has no material. The custom outline will not be applied.");
				}
				return null;
			}
			Material val = new Material(material)
			{
				name = "MixedCaseMapMarkers-Material"
			};
			SetColor(val, OutlineColorId, OutlineColor);
			SetFloat(val, OutlineWidthId, 0.12f);
			val.EnableKeyword("UNDERLAY_ON");
			SetColor(val, UnderlayColorId, UnderlayColor);
			SetFloat(val, UnderlayOffsetXId, 0.1f);
			SetFloat(val, UnderlayOffsetYId, -0.1f);
			SetFloat(val, UnderlayDilateId, 0.15f);
			SetFloat(val, UnderlaySoftnessId, 0.05f);
			return val;
		}

		private static void RemoveCaseStyle(TMP_Text text)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			text.fontStyle = (FontStyles)(text.fontStyle & -57);
			TMP_Style textStyle = text.textStyle;
			if (textStyle != null && (ContainsCaseTag(textStyle.styleOpeningDefinition) || ContainsCaseTag(textStyle.styleClosingDefinition)))
			{
				text.textStyle = TMP_Style.NormalStyle;
			}
		}

		private static bool ContainsCaseTag(string? definition)
		{
			if (string.IsNullOrWhiteSpace(definition))
			{
				return false;
			}
			if (definition.IndexOf("<uppercase>", StringComparison.OrdinalIgnoreCase) < 0 && definition.IndexOf("<allcaps>", StringComparison.OrdinalIgnoreCase) < 0 && definition.IndexOf("<lowercase>", StringComparison.OrdinalIgnoreCase) < 0)
			{
				return definition.IndexOf("<smallcaps>", StringComparison.OrdinalIgnoreCase) >= 0;
			}
			return true;
		}

		private static TMP_FontAsset? FindFont(object? value)
		{
			TMP_InputField val = (TMP_InputField)((value is TMP_InputField) ? value : null);
			if (val != null)
			{
				TMP_Text textComponent = val.textComponent;
				object obj = ((textComponent != null) ? textComponent.font : null);
				if (obj == null)
				{
					Graphic placeholder = val.placeholder;
					Graphic obj2 = ((placeholder is TMP_Text) ? placeholder : null);
					if (obj2 == null)
					{
						return null;
					}
					obj = ((TMP_Text)obj2).font;
				}
				return (TMP_FontAsset?)obj;
			}
			TMP_Text val2 = (TMP_Text)((value is TMP_Text) ? value : null);
			if (val2 != null)
			{
				return val2.font;
			}
			GameObject root = GetRoot(value);
			if (root == null)
			{
				return null;
			}
			TMP_Text[] componentsInChildren = root.GetComponentsInChildren<TMP_Text>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				TMP_FontAsset font = componentsInChildren[i].font;
				if (font != null)
				{
					return font;
				}
			}
			return null;
		}

		private static GameObject? GetRoot(object? value)
		{
			GameObject val = (GameObject)((value is GameObject) ? value : null);
			if (val == null)
			{
				Component val2 = (Component)((value is Component) ? value : null);
				if (val2 != null)
				{
					return val2.gameObject;
				}
				return null;
			}
			return val;
		}

		private static void LogMissingInputWarning()
		{
			if (!_missingInputWarningLogged)
			{
				ManualLogSource? log = Plugin.Log;
				if (log != null)
				{
					log.LogWarning((object)"Valheim's map-marker name input field was not found. A game update may have changed the map UI.");
				}
				_missingInputWarningLogged = true;
			}
		}

		private static void SetColor(Material material, int propertyId, Color value)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			if (material.HasProperty(propertyId))
			{
				material.SetColor(propertyId, value);
			}
		}

		private static void SetFloat(Material material, int propertyId, float value)
		{
			if (material.HasProperty(propertyId))
			{
				material.SetFloat(propertyId, value);
			}
		}
	}
	[HarmonyPatch(typeof(Chat), "Awake")]
	internal static class ChatAwakePatch
	{
		[HarmonyPostfix]
		private static void Postfix(Chat __instance)
		{
			MapMarkerText.CaptureChatFont(__instance);
		}
	}
	[HarmonyPatch(typeof(Minimap), "ShowPinNameInput")]
	internal static class MinimapShowPinNameInputPatch
	{
		[HarmonyPostfix]
		private static void Postfix(Minimap __instance)
		{
			MapMarkerText.ConfigureNameInput(__instance);
		}
	}
	[HarmonyPatch(typeof(Minimap), "CreateMapNamePin")]
	internal static class MinimapCreateMapNamePinPatch
	{
		[HarmonyPrefix]
		private static void Prefix(RectTransform __1, out int __state)
		{
			__state = MapMarkerText.CaptureChildCount(__1);
		}

		[HarmonyPostfix]
		private static void Postfix(object __0, RectTransform __1, int __state)
		{
			MapMarkerText.ApplyCreatedPersistentMarker(__0, __1, __state);
		}
	}
}