Decompiled source of RichEmoji v1.0.0

BepInEx/plugins/RichEmoji.dll

Decompiled 2 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using GUIFramework;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.TextCore;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("gui_framework")]
[assembly: IgnoresAccessChecksTo("Unity.TextMeshPro")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("Ron4242")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCopyright("Copyright © Ron4242 2026")]
[assembly: AssemblyDescription("Enhances emojis all across Valheim, adds new ones, and even lets you add your own!")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+475f0a3a4f8aa8d92d5ec050f7d3a417f59853ff")]
[assembly: AssemblyProduct("RichEmoji")]
[assembly: AssemblyTitle("RichEmoji")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[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 RichEmoji
{
	public class EmojiAutocomplete : MonoBehaviour
	{
		private class SuggestionRow
		{
			public readonly GameObject Root;

			private const float UnselectedBgAlpha = 0.45f;

			private readonly Image _bg;

			private readonly Color _bgColor;

			private readonly TextMeshProUGUI _preview;

			private readonly TextMeshProUGUI _label;

			public SuggestionRow(GameObject root, Image bg, TextMeshProUGUI preview, TextMeshProUGUI label)
			{
				//IL_0016: Unknown result type (might be due to invalid IL or missing references)
				//IL_001b: Unknown result type (might be due to invalid IL or missing references)
				Root = root;
				_bg = bg;
				_bgColor = ((Graphic)bg).color;
				_preview = preview;
				_label = label;
			}

			public void SetContent(string emojiName, string partial, string fakeChar)
			{
				((TMP_Text)_preview).text = fakeChar ?? "?";
				string text = emojiName.Substring(0, Mathf.Min(partial.Length, emojiName.Length));
				string text2 = emojiName.Substring(text.Length);
				((TMP_Text)_label).text = ":<color=#FFA13C>" + text + "</color>" + text2 + ":";
			}

			public void SetSelected(bool selected)
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_0006: 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_0036: 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)
				Color bgColor = _bgColor;
				if (!selected)
				{
					bgColor.a *= 0.45f;
				}
				((Graphic)_bg).color = bgColor;
				((Graphic)_label).color = (selected ? Color.white : GameAssets.ValheimBeige);
			}
		}

		private const int MaxSuggestions = 8;

		private const int MinQueryLength = 2;

		private const float RowHeight = 28f;

		private const float HeaderHeight = 20f;

		private const float Padding = 10f;

		private const float PopupWidth = 280f;

		private GuiInputField _field;

		private GameObject _popup;

		private RectTransform _rowContainer;

		private readonly List<SuggestionRow> _rows = new List<SuggestionRow>();

		private List<string> _currentMatches = new List<string>();

		private int _selectedIndex = -1;

		private int _triggerPos = -1;

		private int _consumedFrame = -1;

		private static EmojiAutocomplete _lastOpened;

		public bool IsOpen
		{
			get
			{
				if (Object.op_Implicit((Object)(object)_popup))
				{
					return _popup.activeSelf;
				}
				return false;
			}
		}

		public bool BlocksGameInput
		{
			get
			{
				if (!IsOpen)
				{
					return _consumedFrame == Time.frameCount;
				}
				return true;
			}
		}

		public static bool AnyBlocksGameInput
		{
			get
			{
				if (Object.op_Implicit((Object)(object)_lastOpened))
				{
					return _lastOpened.BlocksGameInput;
				}
				return false;
			}
		}

		private TMP_FontAsset FieldFont
		{
			get
			{
				if (!Object.op_Implicit((Object)(object)((TMP_InputField)_field).textComponent))
				{
					return TMP_Settings.defaultFontAsset;
				}
				return ((TMP_InputField)_field).textComponent.font;
			}
		}

		private TMP_FontAsset BodyFont => GameAssets.GetFont("Valheim-AveriaSerifLibre") ?? FieldFont;

		private TMP_FontAsset HeaderFont => GameAssets.GetFont("Valheim-Norsebold") ?? GameAssets.GetFont("Valheim-Norse") ?? BodyFont;

		private void Awake()
		{
			_field = ((Component)this).GetComponent<GuiInputField>();
		}

		private void OnDisable()
		{
			Hide();
		}

		private void OnDestroy()
		{
			if (Object.op_Implicit((Object)(object)_popup))
			{
				Object.Destroy((Object)(object)_popup);
			}
		}

		public void OnTextChanged(string text)
		{
			if (!RichEmoji.AutocompleteEnabled.Value || !Object.op_Implicit((Object)(object)_field) || !((TMP_InputField)_field).isFocused || RichEmoji.EmojiNameLookup.Count == 0)
			{
				Hide();
				return;
			}
			int caretPos = Mathf.Clamp(((TMP_InputField)_field).stringPosition, 0, text.Length);
			if (!TryGetPartialShortcode(text, caretPos, out var partial, out var triggerPos))
			{
				Hide();
				return;
			}
			List<string> list = (from k in RichEmoji.EmojiNameLookup.Keys
				where k.StartsWith(partial, StringComparison.OrdinalIgnoreCase)
				orderby k.Length, k
				select k).Take(8).ToList();
			if (list.Count == 0)
			{
				Hide();
				return;
			}
			_triggerPos = triggerPos;
			_currentMatches = list;
			_selectedIndex = 0;
			EnsurePopup();
			_popup.SetActive(true);
			_lastOpened = this;
			Populate(list, partial);
		}

		public bool HandleKey(Event evt)
		{
			//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_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Invalid comparison between Unknown and I4
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Invalid comparison between Unknown and I4
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Invalid comparison between Unknown and I4
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Expected I4, but got Unknown
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Invalid comparison between Unknown and I4
			if (!IsOpen)
			{
				return false;
			}
			KeyCode keyCode = evt.keyCode;
			if ((int)keyCode <= 13)
			{
				if ((int)keyCode == 9 || (int)keyCode == 13)
				{
					goto IL_0057;
				}
				goto IL_0067;
			}
			if ((int)keyCode != 27)
			{
				switch (keyCode - 271)
				{
				case 3:
					break;
				case 2:
					goto IL_004e;
				case 0:
					goto IL_0057;
				default:
					goto IL_0067;
				}
				MoveSelection(1);
			}
			else
			{
				Hide();
			}
			goto IL_0069;
			IL_004e:
			MoveSelection(-1);
			goto IL_0069;
			IL_0057:
			Commit();
			goto IL_0069;
			IL_0067:
			return false;
			IL_0069:
			_consumedFrame = Time.frameCount;
			return true;
		}

		private void MoveSelection(int delta)
		{
			if (_currentMatches.Count != 0)
			{
				_selectedIndex = (_selectedIndex + delta + _currentMatches.Count) % _currentMatches.Count;
				for (int i = 0; i < _rows.Count; i++)
				{
					_rows[i].SetSelected(i == _selectedIndex);
				}
			}
		}

		private void Commit()
		{
			if (_selectedIndex < 0 || _selectedIndex >= _currentMatches.Count || _triggerPos < 0)
			{
				Hide();
				return;
			}
			string key = _currentMatches[_selectedIndex];
			string text = ((TMP_InputField)_field).text;
			int num = Mathf.Clamp(((TMP_InputField)_field).stringPosition, 0, text.Length);
			if (_triggerPos < num && RichEmoji.EmojiNameLookup.TryGetValue(key, out var value))
			{
				string text2 = value + " ";
				string text3 = text.Substring(0, _triggerPos) + text2 + text.Substring(num);
				int stringPosition = _triggerPos + text2.Length;
				((TMP_InputField)_field).SetTextWithoutNotify(text3);
				((TMP_InputField)_field).stringPosition = stringPosition;
				((UnityEvent<string>)(object)((TMP_InputField)_field).onValueChanged).Invoke(text3);
			}
			Hide();
		}

		private void Hide()
		{
			if (Object.op_Implicit((Object)(object)_popup))
			{
				_popup.SetActive(false);
			}
			_currentMatches.Clear();
			_selectedIndex = -1;
			_triggerPos = -1;
		}

		private void Populate(List<string> names, string partial)
		{
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			while (_rows.Count < names.Count)
			{
				_rows.Add(CreateRow());
			}
			for (int i = 0; i < _rows.Count; i++)
			{
				bool flag = i < names.Count;
				_rows[i].Root.SetActive(flag);
				if (flag)
				{
					string text = names[i];
					_rows[i].SetContent(text, partial, RichEmoji.EmojiNameLookup.TryGetValue(text, out var value) ? value : null);
					_rows[i].SetSelected(i == _selectedIndex);
				}
			}
			((RectTransform)_popup.transform).sizeDelta = new Vector2(280f, (float)names.Count * 29f + 20f + 20f);
		}

		private static void ApplySprite(Image image, string spriteName, Color fallback)
		{
			//IL_002a: 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)
			Sprite sprite = GameAssets.GetSprite(spriteName);
			if (Object.op_Implicit((Object)(object)sprite))
			{
				image.sprite = sprite;
				image.type = (Type)1;
				((Graphic)image).color = Color.white;
			}
			else
			{
				((Graphic)image).color = fallback;
			}
		}

		private void EnsurePopup()
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Expected O, but got Unknown
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: 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_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_0136: Unknown result type (might be due to invalid IL or missing references)
			//IL_014d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0153: Unknown result type (might be due to invalid IL or missing references)
			//IL_0158: Unknown result type (might be due to invalid IL or missing references)
			//IL_0163: 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_0178: Unknown result type (might be due to invalid IL or missing references)
			//IL_0182: Unknown result type (might be due to invalid IL or missing references)
			//IL_018d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0197: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_021b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0221: Expected O, but got Unknown
			//IL_023f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0249: Expected O, but got Unknown
			//IL_024f: Unknown result type (might be due to invalid IL or missing references)
			//IL_025f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0279: Unknown result type (might be due to invalid IL or missing references)
			//IL_0293: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b2: Expected O, but got Unknown
			if (!Object.op_Implicit((Object)(object)_popup))
			{
				_popup = new GameObject("EmojiAutocomplete", new Type[1] { typeof(RectTransform) });
				_popup.SetActive(false);
				_popup.transform.SetParent(((Component)this).transform, false);
				_popup.AddComponent<LayoutElement>().ignoreLayout = true;
				Canvas obj = _popup.AddComponent<Canvas>();
				obj.overrideSorting = true;
				obj.sortingOrder = 30000;
				RectTransform val = (RectTransform)_popup.transform;
				val.anchorMin = new Vector2(0f, 1f);
				val.anchorMax = new Vector2(0f, 1f);
				val.pivot = new Vector2(0f, 0f);
				val.anchoredPosition = new Vector2(0f, 6f);
				Image obj2 = _popup.AddComponent<Image>();
				ApplySprite(obj2, "woodpanel_trophys", new Color(0.18f, 0.13f, 0.09f, 0.95f));
				((Graphic)obj2).raycastTarget = false;
				GameObject val2 = new GameObject("Header", new Type[1] { typeof(RectTransform) });
				val2.transform.SetParent(_popup.transform, false);
				RectTransform val3 = (RectTransform)val2.transform;
				val3.anchorMin = new Vector2(0f, 1f);
				val3.anchorMax = new Vector2(1f, 1f);
				val3.pivot = new Vector2(0f, 1f);
				val3.offsetMin = new Vector2(14f, -30f);
				val3.offsetMax = new Vector2(-10f, -10f);
				TextMeshProUGUI obj3 = val2.AddComponent<TextMeshProUGUI>();
				((TMP_Text)obj3).font = HeaderFont;
				((TMP_Text)obj3).text = "Emoji";
				((TMP_Text)obj3).fontSize = 16f;
				((Graphic)obj3).color = GameAssets.ValheimOrange;
				((TMP_Text)obj3).alignment = (TextAlignmentOptions)4097;
				((Graphic)obj3).raycastTarget = false;
				GameObject val4 = new GameObject("Rows", new Type[1] { typeof(RectTransform) });
				val4.transform.SetParent(_popup.transform, false);
				_rowContainer = (RectTransform)val4.transform;
				_rowContainer.anchorMin = Vector2.zero;
				_rowContainer.anchorMax = Vector2.one;
				_rowContainer.offsetMin = new Vector2(10f, 10f);
				_rowContainer.offsetMax = new Vector2(-10f, -30f);
				VerticalLayoutGroup obj4 = val4.AddComponent<VerticalLayoutGroup>();
				((LayoutGroup)obj4).padding = new RectOffset(0, 0, 0, 0);
				((HorizontalOrVerticalLayoutGroup)obj4).spacing = 1f;
				((HorizontalOrVerticalLayoutGroup)obj4).childControlHeight = false;
				((HorizontalOrVerticalLayoutGroup)obj4).childControlWidth = true;
				((HorizontalOrVerticalLayoutGroup)obj4).childForceExpandWidth = true;
				((HorizontalOrVerticalLayoutGroup)obj4).childForceExpandHeight = false;
			}
		}

		private SuggestionRow CreateRow()
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Expected O, but got Unknown
			//IL_0036: 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_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: 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_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_0171: 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_0188: Unknown result type (might be due to invalid IL or missing references)
			//IL_018e: 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_0194: Unknown result type (might be due to invalid IL or missing references)
			//IL_019e: Unknown result type (might be due to invalid IL or missing references)
			//IL_019f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f0: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("Row", new Type[1] { typeof(RectTransform) });
			val.transform.SetParent((Transform)(object)_rowContainer, false);
			((RectTransform)val.transform).sizeDelta = new Vector2(0f, 28f);
			Image val2 = val.AddComponent<Image>();
			ApplySprite(val2, "item_background_sunken", new Color(0f, 0f, 0f, 0.5f));
			((Graphic)val2).raycastTarget = false;
			GameObject val3 = new GameObject("Preview", new Type[1] { typeof(RectTransform) });
			val3.transform.SetParent(val.transform, false);
			RectTransform val4 = (RectTransform)val3.transform;
			val4.anchorMin = new Vector2(0f, 0f);
			val4.anchorMax = new Vector2(0f, 1f);
			val4.pivot = new Vector2(0f, 0.5f);
			val4.anchoredPosition = new Vector2(6f, 0f);
			val4.sizeDelta = new Vector2(22f, 0f);
			TextMeshProUGUI val5 = val3.AddComponent<TextMeshProUGUI>();
			((TMP_Text)val5).font = FieldFont;
			((TMP_Text)val5).fontSize = 18f;
			((TMP_Text)val5).alignment = (TextAlignmentOptions)4098;
			((TMP_Text)val5).overflowMode = (TextOverflowModes)0;
			((Graphic)val5).raycastTarget = false;
			GameObject val6 = new GameObject("Label", new Type[1] { typeof(RectTransform) });
			val6.transform.SetParent(val.transform, false);
			RectTransform val7 = (RectTransform)val6.transform;
			val7.anchorMin = Vector2.zero;
			val7.anchorMax = Vector2.one;
			val7.offsetMin = new Vector2(32f, 0f);
			val7.offsetMax = new Vector2(-6f, 0f);
			TextMeshProUGUI val8 = val6.AddComponent<TextMeshProUGUI>();
			((TMP_Text)val8).font = BodyFont;
			((TMP_Text)val8).fontSize = 16f;
			((Graphic)val8).color = GameAssets.ValheimBeige;
			((TMP_Text)val8).alignment = (TextAlignmentOptions)4097;
			((TMP_Text)val8).overflowMode = (TextOverflowModes)1;
			((TMP_Text)val8).textWrappingMode = (TextWrappingModes)0;
			((Graphic)val8).raycastTarget = false;
			((TMP_Text)val8).textPreprocessor = null;
			return new SuggestionRow(val, val2, val5, val8);
		}

		private static bool TryGetPartialShortcode(string text, int caretPos, out string partial, out int triggerPos)
		{
			partial = null;
			triggerPos = -1;
			int num = caretPos - 1;
			while (num >= 0 && caretPos - num <= 40)
			{
				char c = text[num];
				if (c == ':')
				{
					string text2 = text.Substring(num + 1, caretPos - num - 1);
					if (text2.Length < 2)
					{
						return false;
					}
					partial = text2;
					triggerPos = num;
					return true;
				}
				if (!IsShortcodeChar(c))
				{
					return false;
				}
				num--;
			}
			return false;
		}

		private static bool IsShortcodeChar(char c)
		{
			switch (c)
			{
			case '-':
			case '0':
			case '1':
			case '2':
			case '3':
			case '4':
			case '5':
			case '6':
			case '7':
			case '8':
			case '9':
			case 'A':
			case 'B':
			case 'C':
			case 'D':
			case 'E':
			case 'F':
			case 'G':
			case 'H':
			case 'I':
			case 'J':
			case 'K':
			case 'L':
			case 'M':
			case 'N':
			case 'O':
			case 'P':
			case 'Q':
			case 'R':
			case 'S':
			case 'T':
			case 'U':
			case 'V':
			case 'W':
			case 'X':
			case 'Y':
			case 'Z':
			case '_':
			case 'a':
			case 'b':
			case 'c':
			case 'd':
			case 'e':
			case 'f':
			case 'g':
			case 'h':
			case 'i':
			case 'j':
			case 'k':
			case 'l':
			case 'm':
			case 'n':
			case 'o':
			case 'p':
			case 'q':
			case 'r':
			case 's':
			case 't':
			case 'u':
			case 'v':
			case 'w':
			case 'x':
			case 'y':
			case 'z':
				return true;
			default:
				return false;
			}
		}
	}
	public static class EmojiConverter
	{
		public class EmojiTextPreprocessor : ITextPreprocessor
		{
			public static readonly EmojiTextPreprocessor Instance = new EmojiTextPreprocessor();

			public string PreprocessText(string text)
			{
				return ToFakeUnicode(text);
			}
		}

		private const string BaseEmoji = "(?:(?:\\uD83C[\\uDDE6-\\uDDFF]){2}|[\\uD83C-\\uD83F][\\uDC00-\\uDFFF]|[\\u2000-\\u3299]|[\\u00A9\\u00AE]|[0-9#*]\\uFE0F?\\u20E3)(?:\\uD83C[\\uDFFB-\\uDFFF])?\\uFE0F?";

		public static readonly Regex EmojiNamePattern = new Regex(":([a-zA-Z0-9-_]+):", RegexOptions.Compiled);

		public static readonly Regex EmojiUnicodePattern = new Regex("(?:(?:\\uD83C[\\uDDE6-\\uDDFF]){2}|[\\uD83C-\\uD83F][\\uDC00-\\uDFFF]|[\\u2000-\\u3299]|[\\u00A9\\u00AE]|[0-9#*]\\uFE0F?\\u20E3)(?:\\uD83C[\\uDFFB-\\uDFFF])?\\uFE0F?(?:\\u200D(?:(?:\\uD83C[\\uDDE6-\\uDDFF]){2}|[\\uD83C-\\uD83F][\\uDC00-\\uDFFF]|[\\u2000-\\u3299]|[\\u00A9\\u00AE]|[0-9#*]\\uFE0F?\\u20E3)(?:\\uD83C[\\uDFFB-\\uDFFF])?\\uFE0F?)*", RegexOptions.Compiled);

		public static string ToFakeUnicode(string text)
		{
			if (string.IsNullOrEmpty(text))
			{
				return text;
			}
			string text2 = text;
			string value;
			if (text2.Contains(":"))
			{
				text2 = EmojiNamePattern.Replace(text2, (Match match) => (!RichEmoji.EmojiNameLookup.TryGetValue(match.Groups[1].Value, out value)) ? match.Value : value);
			}
			return EmojiUnicodePattern.Replace(text2, (Match match) => (!RichEmoji.EmojiUnicodeLookup.TryGetValue(match.Value, out value)) ? match.Value : value);
		}

		public static string ToShortcodes(string text)
		{
			if (string.IsNullOrEmpty(text))
			{
				return text;
			}
			StringBuilder stringBuilder = new StringBuilder();
			foreach (char c in text)
			{
				if (RichEmoji.EmojiFakeUnicodeLookup.TryGetValue(c, out var value))
				{
					stringBuilder.Append(value);
				}
				else
				{
					stringBuilder.Append(c);
				}
			}
			return stringBuilder.ToString();
		}
	}
	public static class GameAssets
	{
		public static readonly Color ValheimOrange = new Color(1f, 0.631f, 0.235f, 1f);

		public static readonly Color ValheimBeige = new Color(0.95f, 0.87f, 0.72f, 1f);

		private static readonly Dictionary<string, Sprite> Sprites = new Dictionary<string, Sprite>();

		private static readonly Dictionary<string, TMP_FontAsset> Fonts = new Dictionary<string, TMP_FontAsset>();

		public static Sprite GetSprite(string name)
		{
			if (Sprites.TryGetValue(name, out var value) && Object.op_Implicit((Object)(object)value))
			{
				return value;
			}
			Sprite val = ((IEnumerable<Sprite>)Resources.FindObjectsOfTypeAll<Sprite>()).FirstOrDefault((Func<Sprite, bool>)((Sprite s) => ((Object)s).name == name));
			if (Object.op_Implicit((Object)(object)val))
			{
				Sprites[name] = val;
			}
			else
			{
				RichEmoji.Log.LogDebug((object)("Game sprite '" + name + "' not found, using fallback"));
			}
			return val;
		}

		public static TMP_FontAsset GetFont(string name)
		{
			if (Fonts.TryGetValue(name, out var value) && Object.op_Implicit((Object)(object)value))
			{
				return value;
			}
			TMP_FontAsset val = ((IEnumerable<TMP_FontAsset>)Resources.FindObjectsOfTypeAll<TMP_FontAsset>()).FirstOrDefault((Func<TMP_FontAsset, bool>)((TMP_FontAsset f) => ((Object)f).name == name));
			if (Object.op_Implicit((Object)(object)val))
			{
				Fonts[name] = val;
			}
			else
			{
				RichEmoji.Log.LogDebug((object)("Game font '" + name + "' not found, using fallback"));
			}
			return val;
		}
	}
	public static class Patches
	{
		[HarmonyPatch(typeof(GuiInputField), "ActivateInputField")]
		public static class GuiInputFieldActivatePatch
		{
			private static void Postfix(GuiInputField __instance)
			{
				if (!string.IsNullOrEmpty(((TMP_InputField)__instance).text))
				{
					string text = EmojiConverter.ToFakeUnicode(((TMP_InputField)__instance).text);
					if (!(text == ((TMP_InputField)__instance).text))
					{
						((TMP_InputField)__instance).SetTextWithoutNotify(text);
						((TMP_InputField)__instance).m_OriginalText = text;
					}
				}
			}
		}

		[HarmonyPatch(typeof(GuiInputField), "Awake")]
		public static class GuiInputFieldAwakePatch
		{
			private static void Postfix(GuiInputField __instance)
			{
				EmojiAutocomplete autocomplete = ((Component)__instance).gameObject.AddComponent<EmojiAutocomplete>();
				Coroutine pending = null;
				((UnityEvent<string>)(object)((TMP_InputField)__instance).onValueChanged).AddListener((UnityAction<string>)delegate(string text)
				{
					if (pending != null)
					{
						((MonoBehaviour)__instance).StopCoroutine(pending);
					}
					string captured = text;
					pending = ((MonoBehaviour)__instance).StartCoroutine(Routine());
					IEnumerator Routine()
					{
						yield return null;
						pending = null;
						string text2 = EmojiConverter.ToFakeUnicode(captured);
						if (text2 != captured)
						{
							int length = Mathf.Clamp(((TMP_InputField)__instance).stringPosition, 0, captured.Length);
							int length2 = EmojiConverter.ToFakeUnicode(captured.Substring(0, length)).Length;
							((TMP_InputField)__instance).SetTextWithoutNotify(text2);
							((TMP_InputField)__instance).stringPosition = length2;
						}
						autocomplete.OnTextChanged(((TMP_InputField)__instance).text);
					}
				});
			}
		}

		[HarmonyPatch(typeof(TMP_InputField), "KeyPressed")]
		public static class TMPInputFieldKeyPressedPatch
		{
			private static bool Prefix(TMP_InputField __instance, Event evt, ref EditState __result)
			{
				EmojiAutocomplete emojiAutocomplete = default(EmojiAutocomplete);
				if (!((Component)__instance).TryGetComponent<EmojiAutocomplete>(ref emojiAutocomplete) || !emojiAutocomplete.HandleKey(evt))
				{
					return true;
				}
				__result = (EditState)0;
				return false;
			}
		}

		[HarmonyPatch(typeof(Terminal), "UpdateInput")]
		public static class TerminalUpdateInputPatch
		{
			private static bool Prefix(Terminal __instance)
			{
				EmojiAutocomplete emojiAutocomplete = default(EmojiAutocomplete);
				if (Object.op_Implicit((Object)(object)__instance.m_input) && ((Component)__instance.m_input).TryGetComponent<EmojiAutocomplete>(ref emojiAutocomplete))
				{
					return !emojiAutocomplete.BlocksGameInput;
				}
				return true;
			}
		}

		[HarmonyPatch(typeof(InventoryGui), "Update")]
		public static class InventoryGuiUpdatePatch
		{
			private static void Prefix()
			{
				if (EmojiAutocomplete.AnyBlocksGameInput)
				{
					ZInput.ResetButtonStatus("Inventory");
				}
			}
		}

		[HarmonyPatch(typeof(GuiInputField), "onInputSubmit")]
		public static class GuiInputFieldSubmitPatch
		{
			private static void Prefix(GuiInputField __instance, ref string text)
			{
				string text2 = EmojiConverter.ToShortcodes(text);
				if (!(text2 == text))
				{
					((TMP_InputField)__instance).SetTextWithoutNotify(text2);
					text = text2;
				}
			}
		}

		[HarmonyPatch(typeof(TextInput), "setText")]
		public static class TextInputSetTextPatch
		{
			private static void Prefix(ref string text)
			{
				text = EmojiConverter.ToShortcodes(text);
			}
		}

		[HarmonyPatch(typeof(Minimap), "OnPinTextEntered")]
		public static class MinimapPinTextPatch
		{
			private static void Prefix(Minimap __instance)
			{
				ToShortcodesInPlace(__instance.m_nameInput);
			}
		}

		[HarmonyPatch(typeof(Terminal), "SendInput")]
		public static class TerminalSendInputPatch
		{
			private static void Prefix(Terminal __instance)
			{
				ToShortcodesInPlace(__instance.m_input);
			}
		}

		[HarmonyPatch(typeof(TextMeshProUGUI), "Awake")]
		public static class TMPTextAwakePatch
		{
			private static void Postfix(TextMeshProUGUI __instance)
			{
				if (((TMP_Text)__instance).textPreprocessor == null)
				{
					ITextPreprocessor val = (((TMP_Text)__instance).textPreprocessor = (ITextPreprocessor)(object)EmojiConverter.EmojiTextPreprocessor.Instance);
				}
			}
		}

		private static void ToShortcodesInPlace(GuiInputField field)
		{
			if (Object.op_Implicit((Object)(object)field))
			{
				string text = EmojiConverter.ToShortcodes(((TMP_InputField)field).text);
				if (text != ((TMP_InputField)field).text)
				{
					((TMP_InputField)field).SetTextWithoutNotify(text);
				}
			}
		}
	}
	[BepInPlugin("Ron4242.github.RichEmoji", "RichEmoji", "1.0.0")]
	public sealed class RichEmoji : BaseUnityPlugin
	{
		private const int MaxEmojis = 6400;

		private const int EmojiMaxWidth = 64;

		private const int EmojiMaxHeight = 64;

		public static readonly ManualLogSource Log = Logger.CreateLogSource("RichEmoji");

		public static TMP_SpriteAsset CustomEmojiAsset;

		public static ConfigEntry<bool> AutocompleteEnabled;

		private static readonly List<(Texture2D texture, string emojiName, string unicode)> PendingEmojis = new List<(Texture2D, string, string)>();

		public static readonly Dictionary<string, string> EmojiNameLookup = new Dictionary<string, string>();

		public static readonly Dictionary<char, string> EmojiFakeUnicodeLookup = new Dictionary<char, string>();

		public static readonly Dictionary<string, string> EmojiUnicodeLookup = new Dictionary<string, string>();

		private static MethodInfo LoadImageMethod { get; } = AccessTools.Method(typeof(ImageConversion), "LoadImage", new Type[2]
		{
			typeof(Texture2D),
			typeof(byte[])
		}, (Type[])null);

		private void Awake()
		{
			AutocompleteEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Autocomplete", true, "Show a list of matching emojis while typing a shortcode (e.g. :wa)");
			Harmony.CreateAndPatchAll(typeof(Patches).Assembly, (string)null);
			LoadEmojis();
		}

		private void Start()
		{
			BuildEmojis();
		}

		private void LoadEmojis()
		{
			string source = Path.Combine(Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location), "emojis");
			string text = Path.Combine(Paths.ConfigPath, "RichEmoji", "emojis");
			if (!Directory.Exists(text))
			{
				SeedEmojiFolder(source, text);
			}
			int num = AddEmojiFiles(Directory.GetFiles(text, "*.png", SearchOption.TopDirectoryOnly));
			if (num > 0)
			{
				Log.LogInfo((object)$"Loaded {num} custom emojis");
			}
			string[] directories = Directory.GetDirectories(text);
			Array.Sort(directories, (IComparer<string>?)StringComparer.OrdinalIgnoreCase);
			string[] array = directories;
			foreach (string text2 in array)
			{
				int num2 = AddEmojis(text2);
				if (num2 > 0)
				{
					Log.LogInfo((object)$"Loaded {num2} emojis from {Path.GetFileName(text2)}");
				}
			}
		}

		private static void SeedEmojiFolder(string source, string destination)
		{
			Directory.CreateDirectory(destination);
			if (Directory.Exists(source))
			{
				int num = 0;
				string[] files = Directory.GetFiles(source, "*", SearchOption.AllDirectories);
				foreach (string text in files)
				{
					string text2 = Path.Combine(destination, text.Substring(source.Length).TrimStart(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar));
					Directory.CreateDirectory(Path.GetDirectoryName(text2));
					File.Copy(text, text2, overwrite: false);
					num++;
				}
				Log.LogInfo((object)$"First launch: copied {num} bundled emoji files to {destination}");
			}
		}

		public static int AddEmojis(string folder)
		{
			if (!Directory.Exists(folder))
			{
				return 0;
			}
			return AddEmojiFiles(Directory.GetFiles(folder, "*.png", SearchOption.AllDirectories));
		}

		private static int AddEmojiFiles(string[] files)
		{
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Expected O, but got Unknown
			if (files.Length == 0)
			{
				return 0;
			}
			Array.Sort(files, (IComparer<string>?)StringComparer.OrdinalIgnoreCase);
			byte[][] bytes = new byte[files.Length][];
			Parallel.For(0, files.Length, delegate(int i)
			{
				bytes[i] = File.ReadAllBytes(files[i]);
			});
			int num = 0;
			for (int num2 = 0; num2 < files.Length; num2++)
			{
				Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false);
				if (!(bool)LoadImageMethod.Invoke(null, new object[2]
				{
					val,
					bytes[num2]
				}))
				{
					Log.LogWarning((object)("Couldn't load " + files[num2] + ", skipping"));
					Object.Destroy((Object)(object)val);
					continue;
				}
				string[] array = Path.GetFileNameWithoutExtension(files[num2]).Split(new string[1] { "__" }, StringSplitOptions.None);
				string emojiName = array[0];
				string unicode = ((array.Length > 1) ? array[1] : null);
				AddEmoji(val, emojiName, unicode);
				num++;
			}
			return num;
		}

		public static void AddEmoji(Texture2D source, string emojiName, string unicode = null)
		{
			Texture2D val = ResizeTexture(source, 64, 64);
			if ((Object)(object)val != (Object)(object)source)
			{
				Object.Destroy((Object)(object)source);
			}
			PendingEmojis.Add((val, emojiName, unicode));
		}

		public static void BuildEmojis()
		{
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: Expected O, but got Unknown
			//IL_01b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c4: Expected O, but got Unknown
			//IL_0208: Unknown result type (might be due to invalid IL or missing references)
			//IL_020d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0253: Unknown result type (might be due to invalid IL or missing references)
			//IL_0258: Unknown result type (might be due to invalid IL or missing references)
			//IL_0260: Unknown result type (might be due to invalid IL or missing references)
			//IL_026e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0278: Unknown result type (might be due to invalid IL or missing references)
			//IL_0285: Unknown result type (might be due to invalid IL or missing references)
			//IL_028f: Unknown result type (might be due to invalid IL or missing references)
			//IL_029c: Expected O, but got Unknown
			//IL_0349: Unknown result type (might be due to invalid IL or missing references)
			//IL_034e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0358: Expected O, but got Unknown
			if (PendingEmojis.Count == 0)
			{
				return;
			}
			if (Object.op_Implicit((Object)(object)CustomEmojiAsset))
			{
				TMP_Settings.defaultSpriteAsset.fallbackSpriteAssets?.Remove(CustomEmojiAsset);
				if (Object.op_Implicit((Object)(object)((TMP_Asset)CustomEmojiAsset).material))
				{
					Object.Destroy((Object)(object)((TMP_Asset)CustomEmojiAsset).material);
				}
				if (Object.op_Implicit((Object)(object)CustomEmojiAsset.spriteSheet))
				{
					Object.Destroy((Object)(object)CustomEmojiAsset.spriteSheet);
					Object.Destroy((Object)(object)CustomEmojiAsset);
					EmojiNameLookup.Clear();
					EmojiFakeUnicodeLookup.Clear();
					EmojiUnicodeLookup.Clear();
				}
			}
			if (PendingEmojis.Count > 6400)
			{
				Log.LogWarning((object)$"Emoji limit exceeded! Found {PendingEmojis.Count}, but only {6400} are supported. Not all emojis will be loaded.");
			}
			int num = Math.Min(PendingEmojis.Count, 6400);
			List<Texture2D> list = new List<Texture2D>(num);
			for (int i = 0; i < num; i++)
			{
				list.Add(PendingEmojis[i].texture);
			}
			Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false);
			Rect[] array = val.PackTextures(list.ToArray(), 2, 8192, true);
			foreach (Texture2D item4 in list)
			{
				Object.Destroy((Object)(object)item4);
			}
			CustomEmojiAsset = ScriptableObject.CreateInstance<TMP_SpriteAsset>();
			((Object)CustomEmojiAsset).name = "RichEmojiAtlas";
			CustomEmojiAsset.spriteSheet = (Texture)(object)val;
			((TMP_Asset)CustomEmojiAsset).m_Version = "1.1.0";
			TMP_SpriteAsset defaultSpriteAsset = TMP_Settings.defaultSpriteAsset;
			((TMP_Asset)CustomEmojiAsset).material = new Material(((TMP_Asset)defaultSpriteAsset).material)
			{
				mainTexture = (Texture)(object)val
			};
			CustomEmojiAsset.spriteCharacterTable = new List<TMP_SpriteCharacter>();
			CustomEmojiAsset.spriteGlyphTable = new List<TMP_SpriteGlyph>();
			for (int j = 0; j < num; j++)
			{
				(Texture2D texture, string emojiName, string unicode) tuple = PendingEmojis[j];
				string item = tuple.emojiName;
				string item2 = tuple.unicode;
				Rect val2 = array[j];
				float num2 = ((Rect)(ref val2)).x * (float)((Texture)val).width;
				float num3 = ((Rect)(ref val2)).y * (float)((Texture)val).height;
				float num4 = ((Rect)(ref val2)).width * (float)((Texture)val).width;
				float num5 = ((Rect)(ref val2)).height * (float)((Texture)val).height;
				TMP_SpriteGlyph val3 = new TMP_SpriteGlyph
				{
					index = (uint)j,
					metrics = new GlyphMetrics(num4, num5, 0f, num5, num4),
					glyphRect = new GlyphRect((int)num2, (int)num3, (int)num4, (int)num5),
					scale = 1f
				};
				CustomEmojiAsset.spriteGlyphTable.Add(val3);
				uint num6 = (uint)(57344 + j);
				string text = char.ConvertFromUtf32((int)num6);
				if (!string.IsNullOrWhiteSpace(item2))
				{
					StringBuilder stringBuilder = new StringBuilder();
					string[] array2 = item2.Split(new char[1] { '-' });
					bool flag = true;
					for (int k = 0; k < array2.Length; k++)
					{
						if (uint.TryParse(array2[k], NumberStyles.HexNumber, null, out var result))
						{
							stringBuilder.Append(char.ConvertFromUtf32((int)result));
							continue;
						}
						flag = false;
						break;
					}
					if (flag && stringBuilder.Length > 0)
					{
						EmojiUnicodeLookup[stringBuilder.ToString()] = text;
					}
				}
				TMP_SpriteCharacter item3 = new TMP_SpriteCharacter(num6, val3)
				{
					name = item
				};
				CustomEmojiAsset.spriteCharacterTable.Add(item3);
				if (EmojiNameLookup.ContainsKey(item))
				{
					Log.LogWarning((object)("Duplicate emoji :" + item + ":, the one loaded last wins"));
				}
				EmojiNameLookup[item] = text;
				EmojiFakeUnicodeLookup[text[0]] = ":" + item + ":";
			}
			CustomEmojiAsset.UpdateLookupTables();
			TMP_SpriteAsset val4 = defaultSpriteAsset;
			if (val4.fallbackSpriteAssets == null)
			{
				val4.fallbackSpriteAssets = new List<TMP_SpriteAsset>();
			}
			defaultSpriteAsset.fallbackSpriteAssets.Add(CustomEmojiAsset);
			Log.LogInfo((object)$"Built emoji atlas with {num} emojis ({((Texture)val).width}x{((Texture)val).height})");
			PendingEmojis.Clear();
		}

		private static Texture2D ResizeTexture(Texture2D source, int maxWidth, int maxHeight)
		{
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: 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_008d: Expected O, but got Unknown
			int width = ((Texture)source).width;
			int height = ((Texture)source).height;
			if (width > maxWidth || height > maxHeight)
			{
				float num = (float)width / (float)height;
				if (width > height)
				{
					width = maxWidth;
					height = Mathf.RoundToInt((float)width / num);
				}
				else
				{
					height = maxHeight;
					width = Mathf.RoundToInt((float)height * num);
				}
				RenderTexture val = (RenderTexture.active = RenderTexture.GetTemporary(width, height, 0, (RenderTextureFormat)0, (RenderTextureReadWrite)0));
				Graphics.Blit((Texture)(object)source, val);
				Texture2D val2 = new Texture2D(width, height, (TextureFormat)4, false);
				val2.ReadPixels(new Rect(0f, 0f, (float)width, (float)height), 0, 0);
				val2.Apply();
				RenderTexture.active = null;
				RenderTexture.ReleaseTemporary(val);
				return val2;
			}
			return source;
		}
	}
	internal static class ThisPluginInfo
	{
		public const string PLUGIN_GUID = "Ron4242.github.RichEmoji";

		public const string PLUGIN_NAME = "RichEmoji";

		public const string PLUGIN_VERSION = "1.0.0";
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
}