Decompiled source of TextChat v1.1.5

BepInEx/plugins/TextChat/GWYF.TextChat.dll

Decompiled 5 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Mirror;
using Steamworks;
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.InputSystem.LowLevel;
using UnityEngine.InputSystem.UI;
using UnityEngine.SceneManagement;
using UnityEngine.TextCore.LowLevel;
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("GWYF.TextChat")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.1.5.0")]
[assembly: AssemblyInformationalVersion("1.1.5+9c38cd31e5d0e83a33a4100444e82cdbf0d65f79")]
[assembly: AssemblyProduct("GWYF.TextChat")]
[assembly: AssemblyTitle("GWYF.TextChat")]
[assembly: AssemblyVersion("1.1.5.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 GWYF.TextChat
{
	public sealed class ChatImeInput : BaseInput
	{
		private Keyboard keyboard;

		internal readonly Queue<char> PendingText = new Queue<char>();

		internal string Composition = "";

		internal int LastCompositionFrame = -100;

		internal int LastTextFrame = -100;

		private IMECompositionMode mode;

		private Vector2 position;

		internal bool IsComposing
		{
			get
			{
				if (Composition.Length <= 0)
				{
					return Time.frameCount <= LastCompositionFrame + 1;
				}
				return true;
			}
		}

		public override string compositionString => Composition;

		public override IMECompositionMode imeCompositionMode
		{
			get
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				return mode;
			}
			set
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_0002: Unknown result type (might be due to invalid IL or missing references)
				//IL_0012: Unknown result type (might be due to invalid IL or missing references)
				//IL_0014: Invalid comparison between Unknown and I4
				//IL_002a: Unknown result type (might be due to invalid IL or missing references)
				//IL_002c: Invalid comparison between Unknown and I4
				//IL_001f: Unknown result type (might be due to invalid IL or missing references)
				mode = value;
				Keyboard current = Keyboard.current;
				if (current != null)
				{
					current.SetIMEEnabled((int)value != 2);
				}
				try
				{
					Input.imeCompositionMode = value;
				}
				catch (InvalidOperationException)
				{
				}
				if ((int)value == 1)
				{
					WindowsIme.Begin();
				}
			}
		}

		public override Vector2 compositionCursorPos
		{
			get
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				return position;
			}
			set
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_0002: 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)
				position = value;
				Keyboard current = Keyboard.current;
				if (current != null)
				{
					current.SetIMECursorPosition(value);
				}
			}
		}

		internal void ResetComposition()
		{
			PendingText.Clear();
			Composition = "";
			LastCompositionFrame = (LastTextFrame = -100);
		}

		private void Update()
		{
			if (keyboard != Keyboard.current)
			{
				if (keyboard != null)
				{
					keyboard.onIMECompositionChange -= OnComposition;
					keyboard.onTextInput -= OnText;
				}
				keyboard = Keyboard.current;
				if (keyboard != null)
				{
					keyboard.onIMECompositionChange += OnComposition;
					keyboard.onTextInput += OnText;
				}
			}
		}

		private void OnText(char character)
		{
			if (Plugin.IsTyping && !char.IsControl(character))
			{
				PendingText.Enqueue(character);
				LastTextFrame = Time.frameCount;
			}
		}

		private unsafe void OnComposition(IMECompositionString value)
		{
			if (Plugin.IsTyping)
			{
				Composition = ((object)(*(IMECompositionString*)(&value))/*cast due to .constrained prefix*/).ToString();
				LastCompositionFrame = Time.frameCount;
			}
		}

		protected override void OnDestroy()
		{
			if (keyboard != null)
			{
				keyboard.onIMECompositionChange -= OnComposition;
				keyboard.onTextInput -= OnText;
			}
			((UIBehaviour)this).OnDestroy();
		}
	}
	public sealed class ChatInputField : TMP_InputField
	{
		internal ChatImeInput Ime;

		internal Action SubmitChat;

		internal Action CancelChat;

		internal int OpenedFrame;

		private readonly Event keyEvent = new Event();

		private bool submitPending;

		private int submitFrame;

		private float submitTime;

		internal void ResetSubmission()
		{
			submitPending = false;
		}

		protected override void LateUpdate()
		{
			((TMP_InputField)this).LateUpdate();
			if (!Plugin.IsTyping || !((TMP_InputField)this).isFocused || Time.frameCount <= OpenedFrame + 1)
			{
				return;
			}
			Keyboard current = Keyboard.current;
			if (current == null)
			{
				return;
			}
			while (Ime.PendingText.Count > 0)
			{
				((TMP_InputField)this).Append(Ime.PendingText.Dequeue());
			}
			if (!submitPending && (((ButtonControl)current.enterKey).wasPressedThisFrame || ((ButtonControl)current.numpadEnterKey).wasPressedThisFrame))
			{
				submitPending = true;
				submitFrame = Time.frameCount;
				submitTime = Time.unscaledTime;
			}
			if (submitPending)
			{
				if (!Ime.IsComposing && Time.frameCount > Math.Max(submitFrame, Ime.LastTextFrame) + 1)
				{
					submitPending = false;
					SubmitChat?.Invoke();
				}
				else if (Time.unscaledTime - submitTime > 1f)
				{
					submitPending = false;
				}
			}
		}

		public override void OnUpdateSelected(BaseEventData data)
		{
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Invalid comparison between Unknown and I4
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Invalid comparison between Unknown and I4
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Invalid comparison between Unknown and I4
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Invalid comparison between Unknown and I4
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			if (!((TMP_InputField)this).isFocused)
			{
				return;
			}
			while (Ime.PendingText.Count > 0)
			{
				((TMP_InputField)this).Append(Ime.PendingText.Dequeue());
			}
			while (Event.PopEvent(keyEvent))
			{
				if ((int)keyEvent.rawType == 4)
				{
					if ((int)keyEvent.keyCode != 13 && (int)keyEvent.keyCode != 271)
					{
						if ((int)keyEvent.keyCode == 27)
						{
							CancelChat?.Invoke();
							((AbstractEventData)data).Use();
							return;
						}
						keyEvent.character = '\0';
						((TMP_InputField)this).KeyPressed(keyEvent);
					}
				}
				else if (keyEvent.commandName == "SelectAll")
				{
					((TMP_InputField)this).SelectAll();
				}
			}
			((TMP_InputField)this).UpdateLabel();
			((AbstractEventData)data).Use();
		}
	}
	internal static class ChatProtocol
	{
		internal const int MaxCharacters = 256;

		internal const int MaxPacketBytes = 2048;

		private static readonly byte[] Marker = Encoding.ASCII.GetBytes("GWYF.TextChat/1\n");

		private static readonly UTF8Encoding Utf8 = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true);

		internal static string Clean(string value, int limit = 256)
		{
			StringBuilder stringBuilder = new StringBuilder();
			if (value == null)
			{
				return "";
			}
			foreach (char c in value)
			{
				if (stringBuilder.Length >= limit)
				{
					break;
				}
				if (char.IsControl(c))
				{
					continue;
				}
				switch (c)
				{
				case '\u2028':
				case '\u2029':
				case '\u202a':
				case '\u202b':
				case '\u202c':
				case '\u202d':
				case '\u202e':
					continue;
				}
				if (c < '\u2066' || c > '\u2069')
				{
					stringBuilder.Append(c);
				}
			}
			if (stringBuilder.Length > 0 && char.IsHighSurrogate(stringBuilder[stringBuilder.Length - 1]))
			{
				stringBuilder.Length--;
			}
			return stringBuilder.ToString().Trim();
		}

		internal static byte[] Encode(string text)
		{
			byte[] bytes = Utf8.GetBytes(Clean(text));
			byte[] array = new byte[Marker.Length + bytes.Length];
			Buffer.BlockCopy(Marker, 0, array, 0, Marker.Length);
			Buffer.BlockCopy(bytes, 0, array, Marker.Length, bytes.Length);
			return array;
		}

		internal static bool TryDecode(byte[] packet, int length, out string text)
		{
			text = "";
			if (packet == null || length <= Marker.Length || length > 2048 || length > packet.Length)
			{
				return false;
			}
			for (int i = 0; i < Marker.Length; i++)
			{
				if (packet[i] != Marker[i])
				{
					return false;
				}
			}
			try
			{
				text = Clean(Utf8.GetString(packet, Marker.Length, length - Marker.Length));
			}
			catch (DecoderFallbackException)
			{
				return false;
			}
			return text.Length > 0;
		}
	}
	internal static class GameChatTheme
	{
		internal static readonly Color Paper = Color32.op_Implicit(new Color32((byte)247, (byte)242, (byte)226, byte.MaxValue));

		internal static readonly Color Gold = Color32.op_Implicit(new Color32(byte.MaxValue, (byte)219, (byte)82, byte.MaxValue));

		internal static TMP_FontAsset FindFont()
		{
			return (from t in Resources.FindObjectsOfTypeAll<TextMeshProUGUI>().Where(delegate(TextMeshProUGUI t)
				{
					//IL_0014: Unknown result type (might be due to invalid IL or missing references)
					//IL_0019: Unknown result type (might be due to invalid IL or missing references)
					if ((Object)(object)((TMP_Text)t).font != (Object)null)
					{
						Scene scene = ((Component)t).gameObject.scene;
						if (((Scene)(ref scene)).IsValid())
						{
							return ((Object)((TMP_Text)t).transform.root).name != "TextChatCanvas";
						}
					}
					return false;
				})
				group t by ((TMP_Text)t).font into g
				orderby g.Sum((TextMeshProUGUI t) => ((!((Behaviour)t).isActiveAndEnabled) ? 1 : 10) + ((((TMP_Text)t).text ?? "").Any((char c) => c >= '가' && c <= '힣') ? 25 : 0)) descending
				select g.Key).FirstOrDefault() ?? TMP_Settings.defaultFontAsset;
		}
	}
	public struct ChatWireV2 : NetworkMessage
	{
		public byte Kind;

		public string Name;

		public byte[] Body;
	}
	internal sealed class NetworkChat
	{
		private const string CapabilityKey = "gwyf.textchat.protocol";

		private const string Version = "2";

		private readonly Action<string, string> receive;

		private readonly Dictionary<int, NetworkConnectionToClient> peers = new Dictionary<int, NetworkConnectionToClient>();

		private readonly Dictionary<int, float> lastSend = new Dictionary<int, float>();

		private NetworkConnectionToServer clientConnection;

		private bool serverWasActive;

		private float nextHello;

		private float nextMetadata;

		private CSteamID advertisedLobby;

		private LobbySettings lobby;

		private static readonly UTF8Encoding Utf8 = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true);

		internal bool HostReady { get; private set; }

		internal static bool InSession
		{
			get
			{
				//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)
				if (NetworkClient.isConnected && NetworkClient.ready && (Object)(object)NetworkClient.localPlayer != (Object)null)
				{
					Scene activeScene = SceneManager.GetActiveScene();
					return IsPlayScene(((Scene)(ref activeScene)).name);
				}
				return false;
			}
		}

		internal NetworkChat(Action<string, string> receive)
		{
			this.receive = receive;
			Writer<ChatWireV2>.write = Write;
			Reader<ChatWireV2>.read = Read;
			RegisterServer();
			RegisterClient();
		}

		internal static bool IsPlayScene(string scene)
		{
			switch (scene)
			{
			default:
				return scene == "GameTest";
			case "HomeScene":
			case "CasinoScene":
			case "LoseStateScene":
			case "WinStateScene":
			case "SummaryScene":
				return true;
			}
		}

		internal void RegisterServer()
		{
			NetworkServer.ReplaceHandler<ChatWireV2>((Action<NetworkConnectionToClient, ChatWireV2>)OnServerMessage, true);
		}

		internal void RegisterClient()
		{
			NetworkClient.ReplaceHandler<ChatWireV2>((Action<ChatWireV2>)OnClientMessage, true);
		}

		internal void ResetServer()
		{
			peers.Clear();
			lastSend.Clear();
		}

		internal void ResetClient()
		{
			clientConnection = null;
			HostReady = false;
			nextHello = 0f;
		}

		internal void Tick()
		{
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_0132: Unknown result type (might be due to invalid IL or missing references)
			//IL_0138: Unknown result type (might be due to invalid IL or missing references)
			//IL_013d: 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_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: 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_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: 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_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			if (!NetworkServer.active && serverWasActive)
			{
				ResetServer();
			}
			serverWasActive = NetworkServer.active;
			if (clientConnection != NetworkClient.connection)
			{
				ResetClient();
				clientConnection = NetworkClient.connection;
			}
			if (!NetworkClient.isConnected)
			{
				HostReady = false;
			}
			if (SteamManager.Initialized && Time.unscaledTime >= nextMetadata)
			{
				nextMetadata = Time.unscaledTime + 1f;
				if ((Object)(object)lobby == (Object)null)
				{
					lobby = Resources.Load<LobbySettings>("LobbySettings");
				}
				CSteamID val = (((Object)(object)lobby != (Object)null) ? lobby.steamLobbyID : CSteamID.Nil);
				if (val != advertisedLobby)
				{
					if (advertisedLobby != CSteamID.Nil)
					{
						SteamMatchmaking.SetLobbyMemberData(advertisedLobby, "gwyf.textchat.protocol", "");
					}
					advertisedLobby = val;
				}
				if (val != CSteamID.Nil)
				{
					SteamMatchmaking.SetLobbyMemberData(val, "gwyf.textchat.protocol", "2");
				}
			}
			bool flag = NetworkClient.activeHost;
			if (!flag && SteamManager.Initialized && advertisedLobby != CSteamID.Nil)
			{
				flag = SteamMatchmaking.GetLobbyMemberData(advertisedLobby, SteamMatchmaking.GetLobbyOwner(advertisedLobby), "gwyf.textchat.protocol") == "2";
			}
			if (!HostReady && NetworkClient.isConnected && NetworkClient.ready && flag && Time.unscaledTime >= nextHello)
			{
				nextHello = Time.unscaledTime + 2f;
				NetworkClient.Send<ChatWireV2>(new ChatWireV2
				{
					Kind = 1,
					Name = "2"
				}, 0);
			}
		}

		internal bool Send(string text)
		{
			if (!InSession || !HostReady)
			{
				return false;
			}
			NetworkClient.Send<ChatWireV2>(new ChatWireV2
			{
				Kind = 3,
				Body = ChatProtocol.Encode(text)
			}, 0);
			return true;
		}

		private void OnServerMessage(NetworkConnectionToClient connection, ChatWireV2 message)
		{
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			if (!((NetworkConnection)connection).isAuthenticated || !((NetworkConnection)connection).isReady)
			{
				return;
			}
			if (message.Kind == 1 && message.Name == "2")
			{
				peers[connection.connectionId] = connection;
				((NetworkConnection)connection).Send<ChatWireV2>(new ChatWireV2
				{
					Kind = 2,
					Name = "2"
				}, 0);
			}
			else
			{
				if (message.Kind != 3)
				{
					return;
				}
				Scene activeScene = SceneManager.GetActiveScene();
				if (!IsPlayScene(((Scene)(ref activeScene)).name) || !peers.TryGetValue(connection.connectionId, out var value) || value != connection)
				{
					return;
				}
				byte[] body = message.Body;
				if (!ChatProtocol.TryDecode(body, (body != null) ? body.Length : 0, out var text) || (lastSend.TryGetValue(connection.connectionId, out var value2) && Time.unscaledTime - value2 < 0.65f))
				{
					return;
				}
				lastSend[connection.connectionId] = Time.unscaledTime;
				ChatWireV2 chatWireV = new ChatWireV2
				{
					Kind = 4,
					Name = SenderName(connection),
					Body = ChatProtocol.Encode(text)
				};
				foreach (KeyValuePair<int, NetworkConnectionToClient> item in new List<KeyValuePair<int, NetworkConnectionToClient>>(peers))
				{
					if (!NetworkServer.connections.TryGetValue(item.Key, out var value3) || value3 != item.Value)
					{
						peers.Remove(item.Key);
						lastSend.Remove(item.Key);
					}
					else if (((NetworkConnection)value3).isAuthenticated && ((NetworkConnection)value3).isReady)
					{
						((NetworkConnection)value3).Send<ChatWireV2>(chatWireV, 0);
					}
				}
			}
		}

		private void OnClientMessage(ChatWireV2 message)
		{
			if (message.Kind == 2 && message.Name == "2")
			{
				HostReady = true;
				return;
			}
			byte[] body = message.Body;
			if (message.Kind == 4 && HostReady && InSession && ChatProtocol.TryDecode(body, (body != null) ? body.Length : 0, out var text))
			{
				receive(ChatProtocol.Clean(message.Name, 48), text);
			}
		}

		private static string SenderName(NetworkConnectionToClient connection)
		{
			//IL_0012: 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)
			ulong result = 0uL;
			if (connection is LocalConnectionToClient && SteamManager.Initialized)
			{
				result = SteamUser.GetSteamID().m_SteamID;
			}
			if (result == 0L)
			{
				ulong.TryParse(connection.address, out result);
			}
			if (result == 0L && (Object)(object)((NetworkConnection)connection).identity != (Object)null)
			{
				SteamIdComponent componentInChildren = ((Component)((NetworkConnection)connection).identity).GetComponentInChildren<SteamIdComponent>();
				if ((Object)(object)componentInChildren != (Object)null)
				{
					result = componentInChildren.SteamId;
				}
			}
			if (result != 0L && SteamManager.Initialized)
			{
				string text = ChatProtocol.Clean(SteamFriends.GetFriendPersonaName(new CSteamID(result)), 48);
				if (text.Length > 0)
				{
					return text;
				}
			}
			return "Player " + connection.connectionId;
		}

		private static void Write(NetworkWriter writer, ChatWireV2 value)
		{
			writer.WriteByte(value.Kind);
			byte[] bytes = Utf8.GetBytes(ChatProtocol.Clean(value.Name, 48));
			WriteBlock(writer, bytes, 192);
			WriteBlock(writer, value.Body ?? Array.Empty<byte>(), 2048);
		}

		private static void WriteBlock(NetworkWriter writer, byte[] bytes, int maximum)
		{
			if (bytes.Length > maximum)
			{
				throw new InvalidDataException("Chat packet exceeds limit.");
			}
			NetworkWriterExtensions.WriteUShort(writer, (ushort)bytes.Length);
			writer.WriteBytes(bytes, 0, bytes.Length);
		}

		private static byte[] ReadBlock(NetworkReader reader, int maximum)
		{
			int num = NetworkReaderExtensions.ReadUShort(reader);
			if (num > maximum)
			{
				throw new InvalidDataException("Chat packet exceeds limit.");
			}
			return reader.ReadBytes(new byte[num], num);
		}

		private static ChatWireV2 Read(NetworkReader reader)
		{
			return new ChatWireV2
			{
				Kind = reader.ReadByte(),
				Name = Utf8.GetString(ReadBlock(reader, 192)),
				Body = ReadBlock(reader, 2048)
			};
		}

		internal void Dispose()
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			NetworkServer.UnregisterHandler<ChatWireV2>();
			NetworkClient.UnregisterHandler<ChatWireV2>();
			if (SteamManager.Initialized && advertisedLobby != CSteamID.Nil)
			{
				SteamMatchmaking.SetLobbyMemberData(advertisedLobby, "gwyf.textchat.protocol", "");
			}
			ResetServer();
			ResetClient();
		}
	}
	[HarmonyPatch(typeof(CustomNetworkManager), "OnStartServer")]
	internal static class RegisterChatServer
	{
		private static void Prefix()
		{
			Plugin.Instance?.Chat?.RegisterServer();
		}
	}
	[HarmonyPatch(typeof(CustomNetworkManager), "OnClientConnect")]
	internal static class RegisterChatClient
	{
		private static void Prefix()
		{
			Plugin.Instance?.Chat?.RegisterClient();
		}
	}
	[HarmonyPatch(typeof(CustomNetworkManager), "OnStopServer")]
	internal static class StopChatServer
	{
		private static void Postfix()
		{
			Plugin.Instance?.Chat?.ResetServer();
		}
	}
	[HarmonyPatch(typeof(CustomNetworkManager), "OnStopClient")]
	internal static class StopChatClient
	{
		private static void Postfix()
		{
			Plugin.Instance?.Chat?.ResetClient();
		}
	}
	[BepInPlugin("gwyf.textchat", "Text Chat", "1.1.5")]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string Id = "gwyf.textchat";

		internal static Plugin Instance;

		private Harmony harmony;

		internal NetworkChat Chat;

		private bool sessionActive;

		private GameObject canvasObject;

		private GameObject panel;

		private GameObject inputObject;

		private GameObject ownEventSystem;

		private CanvasGroup panelGroup;

		private TextMeshProUGUI history;

		private TextMeshProUGUI hint;

		private ChatInputField field;

		private ChatImeInput ime;

		private TMP_FontAsset font;

		private TMP_FontAsset hangulFont;

		private bool ownsFont;

		private bool open;

		private InputLayer oldLayer;

		private CursorLockMode oldLock;

		private bool oldCursorVisible;

		private bool oldNavigation;

		private EventSystem editingSystem;

		private BaseInputModule editingModule;

		private BaseInput oldInput;

		private GameObject oldSelection;

		private float lastMessage = -100f;

		private float lastSend = -100f;

		private readonly Queue<string> lines = new Queue<string>();

		private ConfigEntry<float> displaySeconds;

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

		private void Awake()
		{
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Expected O, but got Unknown
			Instance = this;
			Chat = new NetworkChat(Receive);
			displaySeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Display", "VisibleSeconds", 12f, "Seconds to show recent messages when chat is closed.");
			harmony = new Harmony("gwyf.textchat");
			harmony.PatchAll();
			SceneManager.activeSceneChanged += SceneChanged;
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Text Chat 1.1.5 loaded (Mirror). Enter: chat, Enter: send, Escape: cancel.");
		}

		private void Update()
		{
			Chat.Tick();
			bool inSession = NetworkChat.InSession;
			if (inSession != sessionActive)
			{
				Close();
				sessionActive = inSession;
				((BaseUnityPlugin)this).Logger.LogInfo((object)(inSession ? "Gameplay chat enabled." : "Gameplay chat disabled."));
				lines.Clear();
				if ((Object)(object)history != (Object)null)
				{
					((TMP_Text)history).text = "";
				}
			}
			if (!inSession)
			{
				Close();
				if ((Object)(object)canvasObject != (Object)null)
				{
					canvasObject.SetActive(false);
				}
				return;
			}
			if ((Object)(object)canvasObject == (Object)null)
			{
				BuildUi();
			}
			canvasObject.SetActive(true);
			Keyboard current = Keyboard.current;
			if (!open && current != null && (((ButtonControl)current.enterKey).wasPressedThisFrame || ((ButtonControl)current.numpadEnterKey).wasPressedThisFrame))
			{
				EventSystem current2 = EventSystem.current;
				GameObject val = ((current2 != null) ? current2.currentSelectedGameObject : null);
				if ((Object)(object)val == (Object)null || ((Object)(object)val.GetComponent<TMP_InputField>() == (Object)null && (Object)(object)val.GetComponent<InputField>() == (Object)null))
				{
					Open();
				}
			}
			if (open && current != null && ((ButtonControl)current.escapeKey).wasPressedThisFrame)
			{
				Close();
			}
			panelGroup.alpha = ((open || Time.unscaledTime - lastMessage < Mathf.Clamp(displaySeconds.Value, 1f, 120f)) ? 1 : 0);
		}

		private void LateUpdate()
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Invalid comparison between Unknown and I4
			if (open)
			{
				if ((Object)(object)EventSystem.current != (Object)(object)editingSystem || (int)InputEvents.ActiveLayer != 3)
				{
					Close();
					return;
				}
				Cursor.lockState = (CursorLockMode)0;
				Cursor.visible = true;
			}
		}

		private void Open()
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Invalid comparison between Unknown and I4
			//IL_00a1: 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_00ac: 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_00c7: Unknown result type (might be due to invalid IL or missing references)
			if (NetworkChat.InSession && (int)InputEvents.ActiveLayer != 1)
			{
				EnsureEventSystem();
				editingSystem = EventSystem.current;
				editingModule = editingSystem.currentInputModule ?? ((Component)editingSystem).GetComponent<BaseInputModule>();
				if (!((Object)(object)editingModule == (Object)null))
				{
					oldInput = editingModule.inputOverride;
					editingModule.inputOverride = (BaseInput)(object)ime;
					oldSelection = editingSystem.currentSelectedGameObject;
					oldNavigation = editingSystem.sendNavigationEvents;
					editingSystem.sendNavigationEvents = false;
					oldLayer = InputEvents.ActiveLayer;
					oldLock = Cursor.lockState;
					oldCursorVisible = Cursor.visible;
					ResetGameplayInput();
					InputEvents.ActiveLayer = (InputLayer)3;
					open = true;
					inputObject.SetActive(true);
					((TMP_Text)hint).text = "ENTER  Send       ESC  Cancel";
					((TMP_InputField)field).text = "";
					field.ResetSubmission();
					ime.ResetComposition();
					field.OpenedFrame = Time.frameCount;
					editingSystem.SetSelectedGameObject(inputObject);
					((TMP_InputField)field).ActivateInputField();
					((BaseInput)ime).imeCompositionMode = (IMECompositionMode)1;
					((BaseUnityPlugin)this).Logger.LogInfo((object)"Chat input opened.");
					Cursor.lockState = (CursorLockMode)0;
					Cursor.visible = true;
				}
			}
		}

		private void Close()
		{
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Invalid comparison between Unknown and I4
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: 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)
			if (!open)
			{
				return;
			}
			open = false;
			field.ResetSubmission();
			((TMP_InputField)field).DeactivateInputField(false);
			ime.ResetComposition();
			((BaseInput)ime).imeCompositionMode = (IMECompositionMode)0;
			WindowsIme.End();
			if ((Object)(object)editingModule != (Object)null && (Object)(object)editingModule.inputOverride == (Object)(object)ime)
			{
				editingModule.inputOverride = oldInput;
			}
			if ((Object)(object)editingSystem != (Object)null)
			{
				editingSystem.sendNavigationEvents = oldNavigation;
				if ((Object)(object)editingSystem.currentSelectedGameObject == (Object)(object)inputObject)
				{
					editingSystem.SetSelectedGameObject(oldSelection);
				}
			}
			if ((int)InputEvents.ActiveLayer == 3)
			{
				InputEvents.ActiveLayer = oldLayer;
			}
			Cursor.lockState = oldLock;
			Cursor.visible = oldCursorVisible;
			inputObject.SetActive(false);
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Chat input closed.");
			((TMP_Text)hint).text = "ENTER  Chat";
		}

		private static void ResetGameplayInput()
		{
			//IL_000b: 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)
			InputEvents.OnMoveEvent?.Invoke(Vector2.zero);
			InputEvents.OnAimEvent?.Invoke(Vector2.zero);
			InputEvents.UpdateJump(false);
			InputEvents.UpdateCrouch(false);
			InputEvents.UpdateSprint(false);
			InputEvents.UpdateInteract(false);
			InputEvents.UpdateUseItem(false);
			InputEvents.UpdateThrowItem(false);
			InputEvents.UpdateZoom(false);
			InputEvents.UpdateEmoteWheel(false);
		}

		private void Send()
		{
			string text = ChatProtocol.Clean(((TMP_InputField)field).text);
			if (text.Length == 0)
			{
				Close();
				return;
			}
			if (Time.unscaledTime - lastSend < 0.8f)
			{
				((TMP_Text)hint).text = "Please wait a moment";
				return;
			}
			try
			{
				if (!Chat.Send(text))
				{
					((TMP_Text)hint).text = "The host needs Text Chat 1.1 or newer";
					return;
				}
			}
			catch (EncoderFallbackException)
			{
				((TMP_Text)hint).text = "Please check your input";
				return;
			}
			lastSend = Time.unscaledTime;
			((BaseUnityPlugin)this).Logger.LogInfo((object)("Chat message queued via Mirror (" + text.Length + " characters)."));
			Close();
		}

		private void Receive(string name, string text)
		{
			if (NetworkChat.InSession)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)("Chat broadcast received (" + text.Length + " characters)."));
				AddLine(((name.Length == 0) ? "Player" : name) + ": " + text);
			}
		}

		private void AddLine(string line)
		{
			if ((Object)(object)canvasObject == (Object)null)
			{
				BuildUi();
			}
			lines.Enqueue(line);
			while (lines.Count > 30)
			{
				lines.Dequeue();
			}
			((TMP_Text)history).text = string.Join("\n", lines);
			((TMP_Text)history).ForceMeshUpdate(false, false);
			lastMessage = Time.unscaledTime;
			panelGroup.alpha = 1f;
		}

		private void BuildUi()
		{
			//IL_020e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0218: Expected O, but got Unknown
			//IL_025c: Unknown result type (might be due to invalid IL or missing references)
			//IL_02aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0336: Unknown result type (might be due to invalid IL or missing references)
			//IL_033c: Expected O, but got Unknown
			//IL_035c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0361: Unknown result type (might be due to invalid IL or missing references)
			//IL_0362: Unknown result type (might be due to invalid IL or missing references)
			//IL_0369: Unknown result type (might be due to invalid IL or missing references)
			//IL_036b: Unknown result type (might be due to invalid IL or missing references)
			//IL_036c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0373: Unknown result type (might be due to invalid IL or missing references)
			//IL_0385: Unknown result type (might be due to invalid IL or missing references)
			//IL_0399: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_03bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_0408: Unknown result type (might be due to invalid IL or missing references)
			//IL_0417: Unknown result type (might be due to invalid IL or missing references)
			//IL_042e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0471: Unknown result type (might be due to invalid IL or missing references)
			//IL_0476: Unknown result type (might be due to invalid IL or missing references)
			//IL_0477: Unknown result type (might be due to invalid IL or missing references)
			//IL_047e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0480: Unknown result type (might be due to invalid IL or missing references)
			//IL_0481: Unknown result type (might be due to invalid IL or missing references)
			//IL_0488: Unknown result type (might be due to invalid IL or missing references)
			//IL_049a: Unknown result type (might be due to invalid IL or missing references)
			//IL_04ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_04c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_04fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0504: Expected O, but got Unknown
			//IL_0523: Unknown result type (might be due to invalid IL or missing references)
			//IL_052e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0543: Unknown result type (might be due to invalid IL or missing references)
			//IL_0558: Unknown result type (might be due to invalid IL or missing references)
			//IL_056e: Unknown result type (might be due to invalid IL or missing references)
			//IL_057d: Unknown result type (might be due to invalid IL or missing references)
			//IL_05a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_05ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_05c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_05ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_05d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_05d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_05db: Unknown result type (might be due to invalid IL or missing references)
			//IL_0661: Unknown result type (might be due to invalid IL or missing references)
			//IL_0685: Unknown result type (might be due to invalid IL or missing references)
			//IL_06fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0701: Unknown result type (might be due to invalid IL or missing references)
			//IL_0711: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)font == (Object)null)
			{
				TMP_FontAsset val = GameChatTheme.FindFont();
				string text = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Fonts), "malgun.ttf");
				if (File.Exists(text))
				{
					hangulFont = TMP_FontAsset.CreateFontAsset(text, 0, 32, 6, (GlyphRenderMode)4165, 1024, 1024);
				}
				if ((Object)(object)hangulFont != (Object)null)
				{
					hangulFont.isMultiAtlasTexturesEnabled = true;
				}
				if ((Object)(object)val != (Object)null)
				{
					font = Object.Instantiate<TMP_FontAsset>(val);
					((Object)font).name = "TextChat_" + ((Object)val).name;
					font.atlasPopulationMode = (AtlasPopulationMode)0;
					font.atlasTextures = val.atlasTextures.Select((Texture2D t) => (!((Object)(object)t != (Object)null)) ? null : Object.Instantiate<Texture2D>(t)).ToArray();
					((TMP_Asset)font).material = Object.Instantiate<Material>(((TMP_Asset)val).material);
					((TMP_Asset)font).material.mainTexture = (Texture)(object)font.atlasTextures[0];
					font.fallbackFontAssetTable = new List<TMP_FontAsset>(val.fallbackFontAssetTable ?? new List<TMP_FontAsset>());
					if ((Object)(object)hangulFont != (Object)null)
					{
						font.fallbackFontAssetTable.Add(hangulFont);
					}
					font.ReadFontAssetDefinition();
					ownsFont = true;
				}
				else
				{
					font = hangulFont;
				}
				if ((Object)(object)font == (Object)null)
				{
					throw new InvalidOperationException("No usable TextMeshPro font found.");
				}
				((BaseUnityPlugin)this).Logger.LogInfo((object)("Chat theme: game font=" + (((Object)(object)val != (Object)null) ? ((Object)val).name : "unavailable") + ", plain panel geometry"));
			}
			canvasObject = new GameObject("TextChatCanvas", new Type[4]
			{
				typeof(RectTransform),
				typeof(Canvas),
				typeof(CanvasScaler),
				typeof(GraphicRaycaster)
			});
			Object.DontDestroyOnLoad((Object)(object)canvasObject);
			Canvas component = canvasObject.GetComponent<Canvas>();
			component.renderMode = (RenderMode)0;
			component.sortingOrder = 32000;
			CanvasScaler component2 = canvasObject.GetComponent<CanvasScaler>();
			component2.uiScaleMode = (ScaleMode)1;
			component2.referenceResolution = new Vector2(1920f, 1080f);
			component2.matchWidthOrHeight = 0.5f;
			panel = Rect("ChatPanel", canvasObject.transform);
			RectTransform component3 = panel.GetComponent<RectTransform>();
			Vector2 val2 = default(Vector2);
			((Vector2)(ref val2))..ctor(0f, 0f);
			component3.pivot = val2;
			Vector2 anchorMin = (component3.anchorMax = val2);
			component3.anchorMin = anchorMin;
			component3.anchoredPosition = new Vector2(32f, 92f);
			component3.sizeDelta = new Vector2(540f, 280f);
			((Graphic)panel.GetComponent<Image>()).color = Color.clear;
			panelGroup = panel.AddComponent<CanvasGroup>();
			GameObject val4 = new GameObject("HistoryViewport", new Type[2]
			{
				typeof(RectTransform),
				typeof(RectMask2D)
			});
			val4.transform.SetParent(panel.transform, false);
			RectTransform component4 = val4.GetComponent<RectTransform>();
			val2 = (component4.pivot = Vector2.zero);
			anchorMin = (component4.anchorMax = val2);
			component4.anchorMin = anchorMin;
			component4.anchoredPosition = new Vector2(18f, 76f);
			component4.sizeDelta = new Vector2(504f, 190f);
			history = Text("History", val4.transform, Vector2.zero, new Vector2(504f, 190f), 20);
			((TMP_Text)history).alignment = (TextAlignmentOptions)1025;
			((TMP_Text)history).overflowMode = (TextOverflowModes)0;
			hint = Text("Hint", panel.transform, new Vector2(18f, 12f), new Vector2(504f, 22f), 14);
			((Graphic)hint).color = GameChatTheme.Paper;
			((TMP_Text)hint).text = "ENTER  Chat";
			inputObject = Rect("Input", panel.transform);
			RectTransform component5 = inputObject.GetComponent<RectTransform>();
			val2 = (component5.pivot = Vector2.zero);
			anchorMin = (component5.anchorMax = val2);
			component5.anchorMin = anchorMin;
			component5.anchoredPosition = new Vector2(16f, 37f);
			component5.sizeDelta = new Vector2(508f, 34f);
			((Graphic)inputObject.GetComponent<Image>()).color = Color.clear;
			inputObject.SetActive(false);
			GameObject val7 = new GameObject("Viewport", new Type[2]
			{
				typeof(RectTransform),
				typeof(RectMask2D)
			});
			val7.transform.SetParent(inputObject.transform, false);
			RectTransform component6 = val7.GetComponent<RectTransform>();
			component6.anchorMin = Vector2.zero;
			component6.anchorMax = Vector2.one;
			component6.offsetMin = new Vector2(10f, 0f);
			component6.offsetMax = new Vector2(-10f, 0f);
			TextMeshProUGUI val8 = Text("Text", val7.transform, Vector2.zero, new Vector2(488f, 34f), 20);
			((TMP_Text)val8).alignment = (TextAlignmentOptions)513;
			((TMP_Text)val8).textWrappingMode = (TextWrappingModes)0;
			RectTransform rectTransform = ((TMP_Text)val8).rectTransform;
			rectTransform.anchorMin = Vector2.zero;
			rectTransform.anchorMax = Vector2.one;
			rectTransform.pivot = new Vector2(0.5f, 0.5f);
			anchorMin = (rectTransform.offsetMax = Vector2.zero);
			rectTransform.offsetMin = anchorMin;
			field = inputObject.AddComponent<ChatInputField>();
			ime = canvasObject.AddComponent<ChatImeInput>();
			((TMP_InputField)field).textViewport = component6;
			((TMP_InputField)field).textComponent = (TMP_Text)(object)val8;
			((Selectable)field).targetGraphic = (Graphic)(object)inputObject.GetComponent<Image>();
			((TMP_InputField)field).fontAsset = font;
			((TMP_InputField)field).richText = false;
			((TMP_InputField)field).customCaretColor = true;
			((TMP_InputField)field).caretColor = GameChatTheme.Gold;
			((TMP_InputField)field).selectionColor = new Color(1f, 0.86f, 0.32f, 0.3f);
			((Selectable)field).transition = (Transition)0;
			((TMP_InputField)field).characterLimit = 256;
			((TMP_InputField)field).lineType = (LineType)0;
			field.Ime = ime;
			field.SubmitChat = Send;
			field.CancelChat = Close;
			Navigation navigation = ((Selectable)field).navigation;
			((Navigation)(ref navigation)).mode = (Mode)0;
			((Selectable)field).navigation = navigation;
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Chat UI created.");
		}

		private static GameObject Rect(string name, Transform parent)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Expected O, but got Unknown
			GameObject val = new GameObject(name, new Type[2]
			{
				typeof(RectTransform),
				typeof(Image)
			});
			val.transform.SetParent(parent, false);
			((Graphic)val.GetComponent<Image>()).raycastTarget = false;
			return val;
		}

		private TextMeshProUGUI Text(string name, Transform parent, Vector2 position, Vector2 size, int fontSize)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: 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_0035: 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)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: 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: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject(name, new Type[1] { typeof(RectTransform) });
			val.transform.SetParent(parent, false);
			RectTransform component = val.GetComponent<RectTransform>();
			Vector2 val2 = (component.pivot = Vector2.zero);
			Vector2 anchorMin = (component.anchorMax = val2);
			component.anchorMin = anchorMin;
			component.anchoredPosition = position;
			component.sizeDelta = size;
			TextMeshProUGUI obj = val.AddComponent<TextMeshProUGUI>();
			((TMP_Text)obj).font = font;
			((TMP_Text)obj).fontSize = fontSize;
			((Graphic)obj).color = GameChatTheme.Paper;
			((TMP_Text)obj).richText = false;
			((Graphic)obj).raycastTarget = false;
			((TMP_Text)obj).textWrappingMode = (TextWrappingModes)1;
			return obj;
		}

		private void EnsureEventSystem()
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Expected O, but got Unknown
			if (!((Object)(object)EventSystem.current != (Object)null))
			{
				ownEventSystem = new GameObject("TextChatEventSystem", new Type[2]
				{
					typeof(EventSystem),
					typeof(InputSystemUIInputModule)
				});
				Object.DontDestroyOnLoad((Object)(object)ownEventSystem);
				ownEventSystem.GetComponent<InputSystemUIInputModule>().AssignDefaultActions();
			}
		}

		private void SceneChanged(Scene before, Scene after)
		{
			Close();
			if ((Object)(object)canvasObject != (Object)null)
			{
				canvasObject.SetActive(false);
			}
			if ((Object)(object)ownEventSystem != (Object)null)
			{
				Object.Destroy((Object)(object)ownEventSystem);
			}
		}

		private void OnApplicationFocus(bool focused)
		{
			if (!focused)
			{
				Close();
			}
		}

		private void OnDisable()
		{
			Close();
		}

		private void OnDestroy()
		{
			Close();
			SceneManager.activeSceneChanged -= SceneChanged;
			Chat?.Dispose();
			Harmony obj = harmony;
			if (obj != null)
			{
				obj.UnpatchSelf();
			}
			if ((Object)(object)canvasObject != (Object)null)
			{
				Object.Destroy((Object)(object)canvasObject);
			}
			if ((Object)(object)ownEventSystem != (Object)null)
			{
				Object.Destroy((Object)(object)ownEventSystem);
			}
			if (ownsFont && (Object)(object)font != (Object)null)
			{
				Object.Destroy((Object)(object)font);
			}
			if ((Object)(object)hangulFont != (Object)null)
			{
				Object.Destroy((Object)(object)hangulFont);
			}
			Instance = null;
		}
	}
	[HarmonyPatch]
	internal static class BlockGameplayWhileTyping
	{
		private static IEnumerable<MethodBase> TargetMethods()
		{
			return from method in typeof(InputReader).GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public)
				where method.Name.StartsWith("On") && method.GetParameters().Length == 1 && method.GetParameters()[0].ParameterType == typeof(CallbackContext)
				select method;
		}

		private static bool Prefix()
		{
			return !Plugin.IsTyping;
		}
	}
	internal static class WindowsIme
	{
		private static IntPtr window;

		private static bool savedOpen;

		private static bool saved;

		[DllImport("user32.dll")]
		private static extern IntPtr GetForegroundWindow();

		[DllImport("user32.dll")]
		private static extern uint GetWindowThreadProcessId(IntPtr hwnd, out uint processId);

		[DllImport("kernel32.dll")]
		private static extern uint GetCurrentProcessId();

		[DllImport("imm32.dll")]
		private static extern IntPtr ImmGetContext(IntPtr hwnd);

		[DllImport("imm32.dll")]
		private static extern bool ImmReleaseContext(IntPtr hwnd, IntPtr context);

		[DllImport("imm32.dll")]
		private static extern bool ImmAssociateContextEx(IntPtr hwnd, IntPtr context, uint flags);

		[DllImport("imm32.dll")]
		private static extern bool ImmGetOpenStatus(IntPtr context);

		[DllImport("imm32.dll")]
		private static extern bool ImmSetOpenStatus(IntPtr context, bool open);

		internal static void Begin()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Invalid comparison between Unknown and I4
			if ((int)Application.platform != 2)
			{
				return;
			}
			IntPtr foregroundWindow = GetForegroundWindow();
			GetWindowThreadProcessId(foregroundWindow, out var processId);
			if (foregroundWindow == IntPtr.Zero || processId != GetCurrentProcessId())
			{
				return;
			}
			window = foregroundWindow;
			IntPtr intPtr = ImmGetContext(window);
			if (intPtr == IntPtr.Zero)
			{
				ImmAssociateContextEx(window, IntPtr.Zero, 16u);
				intPtr = ImmGetContext(window);
			}
			if (!(intPtr == IntPtr.Zero))
			{
				if (!saved)
				{
					savedOpen = ImmGetOpenStatus(intPtr);
					saved = true;
				}
				ImmReleaseContext(window, intPtr);
			}
		}

		internal static void End()
		{
			if (saved && !(window == IntPtr.Zero))
			{
				IntPtr intPtr = ImmGetContext(window);
				if (intPtr != IntPtr.Zero)
				{
					ImmSetOpenStatus(intPtr, savedOpen);
					ImmReleaseContext(window, intPtr);
				}
				saved = false;
				window = IntPtr.Zero;
			}
		}
	}
}