Decompiled source of CRACK TextChat v1.0.0

BepInEx/plugins/CRACK_TextChat/CRACK.TextChat.dll

Decompiled 16 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
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.Events;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.InputSystem.LowLevel;
using UnityEngine.InputSystem.UI;
using UnityEngine.InputSystem.Utilities;
using UnityEngine.SceneManagement;
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("CRACK.TextChat")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("CRACK.TextChat")]
[assembly: AssemblyTitle("CRACK.TextChat")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace CrackTextChat
{
	public struct HelloV1 : NetworkMessage
	{
		public int Protocol;
	}
	public struct WelcomeV1 : NetworkMessage
	{
		public int Protocol;
	}
	public struct SayV1 : NetworkMessage
	{
		public string Text;
	}
	public struct LineV1 : NetworkMessage
	{
		public string Name;

		public string Text;
	}
	public sealed class ChatNetwork
	{
		public const int Protocol = 1;

		private const string CapabilityKey = "crack.textchat.protocol";

		private readonly Plugin plugin;

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

		private NetworkConnectionToServer clientConnection;

		private float retryAt;

		private float advertiseAt;

		private bool welcomed;

		private static readonly IDictionary ServerHandlers = (IDictionary)AccessTools.Field(typeof(NetworkServer), "handlers").GetValue(null);

		private static readonly IDictionary ClientHandlers = (IDictionary)AccessTools.Field(typeof(NetworkClient), "handlers").GetValue(null);

		public bool Ready
		{
			get
			{
				if (NetworkClient.isConnected)
				{
					return welcomed;
				}
				return false;
			}
		}

		public string Status
		{
			get
			{
				if (NetworkClient.isConnected)
				{
					if (!Ready)
					{
						return "Waiting for TextChat host";
					}
					return "Crew chat";
				}
				return "Join a game to chat";
			}
		}

		public ChatNetwork(Plugin plugin)
		{
			this.plugin = plugin;
			RegisterCodecs();
		}

		public static void RegisterCodecs()
		{
			Writer<HelloV1>.write = delegate(NetworkWriter w, HelloV1 m)
			{
				NetworkWriterExtensions.WriteInt(w, m.Protocol);
			};
			Reader<HelloV1>.read = (NetworkReader r) => new HelloV1
			{
				Protocol = NetworkReaderExtensions.ReadInt(r)
			};
			Writer<WelcomeV1>.write = delegate(NetworkWriter w, WelcomeV1 m)
			{
				NetworkWriterExtensions.WriteInt(w, m.Protocol);
			};
			Reader<WelcomeV1>.read = (NetworkReader r) => new WelcomeV1
			{
				Protocol = NetworkReaderExtensions.ReadInt(r)
			};
			Writer<SayV1>.write = delegate(NetworkWriter w, SayV1 m)
			{
				NetworkWriterExtensions.WriteString(w, m.Text);
			};
			Reader<SayV1>.read = (NetworkReader r) => new SayV1
			{
				Text = ReadBounded(r, 1200)
			};
			Writer<LineV1>.write = delegate(NetworkWriter w, LineV1 m)
			{
				NetworkWriterExtensions.WriteString(w, m.Name);
				NetworkWriterExtensions.WriteString(w, m.Text);
			};
			Reader<LineV1>.read = (NetworkReader r) => new LineV1
			{
				Name = ReadBounded(r, 256),
				Text = ReadBounded(r, 1200)
			};
		}

		private static string ReadBounded(NetworkReader reader, int maxBytes)
		{
			ushort num = NetworkReaderExtensions.ReadUShort(reader);
			if (num == 0)
			{
				return "";
			}
			int num2 = num - 1;
			if (num2 > maxBytes)
			{
				throw new InvalidDataException("TextChat message exceeds protocol limit.");
			}
			ArraySegment<byte> arraySegment = reader.ReadBytesSegment(num2);
			return new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true).GetString(arraySegment.Array, arraySegment.Offset, arraySegment.Count);
		}

		public void Tick()
		{
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_013a: Unknown result type (might be due to invalid IL or missing references)
			if (NetworkServer.active)
			{
				if (!ServerHandlers.Contains(NetworkMessageId<HelloV1>.Id))
				{
					NetworkServer.RegisterHandler<HelloV1>((Action<NetworkConnectionToClient, HelloV1>)OnHello, true);
				}
				if (!ServerHandlers.Contains(NetworkMessageId<SayV1>.Id))
				{
					NetworkServer.RegisterHandler<SayV1>((Action<NetworkConnectionToClient, SayV1>)OnSay, true);
				}
				List<NetworkConnectionToClient> list = new List<NetworkConnectionToClient>();
				foreach (NetworkConnectionToClient key in peers.Keys)
				{
					if (!NetworkServer.connections.TryGetValue(key.connectionId, out var value) || value != key)
					{
						list.Add(key);
					}
				}
				foreach (NetworkConnectionToClient item in list)
				{
					peers.Remove(item);
				}
				if (Time.unscaledTime >= advertiseAt)
				{
					advertiseAt = Time.unscaledTime + 1f;
					if ((Object)(object)SteamLobby.instance != (Object)null && SteamLobby.instance.currentLobbyID != CSteamID.Nil && SteamManager.Initialized)
					{
						SteamMatchmaking.SetLobbyData(SteamLobby.instance.currentLobbyID, "crack.textchat.protocol", 1.ToString());
					}
				}
			}
			else
			{
				peers.Clear();
			}
			if (NetworkClient.active)
			{
				if (!ClientHandlers.Contains(NetworkMessageId<WelcomeV1>.Id))
				{
					NetworkClient.RegisterHandler<WelcomeV1>((Action<WelcomeV1>)OnWelcome, true);
				}
				if (!ClientHandlers.Contains(NetworkMessageId<LineV1>.Id))
				{
					NetworkClient.RegisterHandler<LineV1>((Action<LineV1>)OnLine, true);
				}
			}
			if (clientConnection != NetworkClient.connection)
			{
				clientConnection = NetworkClient.connection;
				welcomed = false;
				retryAt = 0f;
				plugin.View?.ResetSession();
			}
			if (!NetworkClient.isConnected)
			{
				welcomed = false;
			}
			else if (!welcomed && clientConnection != null && ((NetworkConnection)clientConnection).isAuthenticated && NetworkClient.ready && (Object)(object)NetworkClient.localPlayer != (Object)null && Time.unscaledTime >= retryAt && HostSupportsChat())
			{
				retryAt = Time.unscaledTime + 3f;
				NetworkClient.Send<HelloV1>(new HelloV1
				{
					Protocol = 1
				}, 0);
			}
		}

		private bool HostSupportsChat()
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			if (NetworkServer.active)
			{
				return true;
			}
			if ((Object)(object)SteamLobby.instance != (Object)null && SteamLobby.instance.currentLobbyID != CSteamID.Nil && SteamManager.Initialized)
			{
				return SteamMatchmaking.GetLobbyData(SteamLobby.instance.currentLobbyID, "crack.textchat.protocol") == 1.ToString();
			}
			return plugin.AssumeLanHost.Value;
		}

		private void OnHello(NetworkConnectionToClient connection, HelloV1 message)
		{
			if (message.Protocol == 1 && !((Object)(object)((NetworkConnection)connection).identity == (Object)null))
			{
				if (!peers.ContainsKey(connection))
				{
					peers.Add(connection, new MessageGate());
				}
				((NetworkConnection)connection).Send<WelcomeV1>(new WelcomeV1
				{
					Protocol = 1
				}, 0);
			}
		}

		private void OnWelcome(WelcomeV1 message)
		{
			if (message.Protocol == 1 && !welcomed)
			{
				welcomed = true;
				plugin.View?.Add("TextChat", "Connected. Enter to chat · Esc to close", system: true);
			}
		}

		private void OnSay(NetworkConnectionToClient connection, SayV1 message)
		{
			if (!peers.TryGetValue(connection, out var value) || (Object)(object)((NetworkConnection)connection).identity == (Object)null)
			{
				return;
			}
			PlayerController component = ((Component)((NetworkConnection)connection).identity).GetComponent<PlayerController>();
			if ((Object)(object)component == (Object)null)
			{
				return;
			}
			string text = ChatRules.Clean(message.Text);
			if (text.Length == 0 || !value.TryAccept(Time.unscaledTimeAsDouble, plugin.MessageInterval.Value))
			{
				return;
			}
			string text2 = ChatRules.Clean(component.steamName, 48);
			if (text2.Length == 0)
			{
				text2 = "Player " + (component.index + 1);
			}
			LineV1 lineV = new LineV1
			{
				Name = text2,
				Text = text
			};
			foreach (NetworkConnectionToClient key in peers.Keys)
			{
				if (((NetworkConnection)key).isAuthenticated && ((NetworkConnection)key).isReady)
				{
					((NetworkConnection)key).Send<LineV1>(lineV, 0);
				}
			}
		}

		private void OnLine(LineV1 line)
		{
			plugin.View?.Add(ChatRules.Clean(line.Name, 48), ChatRules.Clean(line.Text), system: false);
		}

		public bool Send(string text)
		{
			if (!Ready)
			{
				plugin.View?.Add("TextChat", "The host needs TextChat. For LAN, enable AssumeLanHostHasMod only when the host has it.", system: true);
				return false;
			}
			text = ChatRules.Clean(text);
			if (text.Length == 0)
			{
				return false;
			}
			NetworkClient.Send<SayV1>(new SayV1
			{
				Text = text
			}, 0);
			return true;
		}

		public void Dispose()
		{
			//IL_0019: 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)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			if (NetworkServer.active && (Object)(object)SteamLobby.instance != (Object)null && SteamLobby.instance.currentLobbyID != CSteamID.Nil && SteamManager.Initialized)
			{
				SteamMatchmaking.DeleteLobbyData(SteamLobby.instance.currentLobbyID, "crack.textchat.protocol");
			}
			NetworkServer.UnregisterHandler<HelloV1>();
			NetworkServer.UnregisterHandler<SayV1>();
			NetworkClient.UnregisterHandler<WelcomeV1>();
			NetworkClient.UnregisterHandler<LineV1>();
			peers.Clear();
		}
	}
	public static class ChatRules
	{
		public const int MaxLength = 300;

		public static string Clean(string value, int limit = 300)
		{
			if (string.IsNullOrEmpty(value))
			{
				return "";
			}
			StringBuilder stringBuilder = new StringBuilder();
			for (int i = 0; i < value.Length; i++)
			{
				if (stringBuilder.Length >= limit)
				{
					break;
				}
				char c = value[i];
				if (char.IsControl(c))
				{
					if (c == '\n' || c == '\r' || c == '\t')
					{
						stringBuilder.Append(' ');
					}
				}
				else
				{
					if (char.GetUnicodeCategory(c) == UnicodeCategory.Format)
					{
						continue;
					}
					if (char.IsHighSurrogate(c))
					{
						if (i + 1 < value.Length && char.IsLowSurrogate(value[i + 1]) && stringBuilder.Length + 2 <= limit)
						{
							stringBuilder.Append(c).Append(value[++i]);
						}
					}
					else if (!char.IsLowSurrogate(c))
					{
						stringBuilder.Append(c);
					}
				}
			}
			return stringBuilder.ToString().Trim();
		}
	}
	public sealed class MessageGate
	{
		private double next;

		public bool TryAccept(double now, double interval)
		{
			if (now < next)
			{
				return false;
			}
			next = now + interval;
			return true;
		}
	}
	public sealed class ChatView : MonoBehaviour
	{
		private Plugin plugin;

		private GameObject canvasObject;

		private RectTransform panel;

		private CanvasGroup group;

		private RectTransform content;

		private ScrollRect scroll;

		private ChatInputField input;

		private TMP_Text count;

		private TMP_FontAsset font;

		private TMP_FontAsset fallbackFont;

		private float fontRefreshAt;

		private RectTransform viewport;

		private RectTransform inputRect;

		private TMP_Text hint;

		private readonly Queue<GameObject> rows = new Queue<GameObject>();

		private readonly List<InputAction> restoreActions = new List<InputAction>();

		private Player capturedPlayer;

		private CursorLockMode savedLock;

		private bool savedVisible;

		private bool restorePending;

		private BaseInputModule module;

		private BaseInput savedOverride;

		private ChatBaseInput bridge;

		private GameObject savedSelection;

		private float lastMessage = -1000f;

		private float lastSent = -1000f;

		private int openFrame;

		internal int CompositionFrame = -10;

		internal string Composition = "";

		private Keyboard keyboard;

		private IMECompositionMode savedImeMode;

		private WindowsImeContext nativeIme;

		private GameObject ownEventSystem;

		private bool submitPending;

		private int submitFrame;

		private int committedFrame = -10;

		public bool IsOpen { get; private set; }

		internal bool IsComposing
		{
			get
			{
				if (Composition.Length <= 0 && string.IsNullOrEmpty(Input.compositionString))
				{
					return CompositionFrame >= Time.frameCount - 1;
				}
				return true;
			}
		}

		public void Initialize(Plugin owner)
		{
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Expected O, but got Unknown
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: Unknown result type (might be due to invalid IL or missing references)
			//IL_013a: Unknown result type (might be due to invalid IL or missing references)
			//IL_015f: 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_01d1: 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)
			//IL_01ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0214: Unknown result type (might be due to invalid IL or missing references)
			//IL_028b: 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_02ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e4: 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_037c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0381: Unknown result type (might be due to invalid IL or missing references)
			//IL_0382: Unknown result type (might be due to invalid IL or missing references)
			//IL_0388: Unknown result type (might be due to invalid IL or missing references)
			//IL_0394: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d2: 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_0423: Unknown result type (might be due to invalid IL or missing references)
			//IL_0432: Unknown result type (might be due to invalid IL or missing references)
			//IL_0472: Unknown result type (might be due to invalid IL or missing references)
			//IL_048d: Unknown result type (might be due to invalid IL or missing references)
			//IL_049c: Unknown result type (might be due to invalid IL or missing references)
			//IL_055d: Unknown result type (might be due to invalid IL or missing references)
			//IL_05a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_05f2: Unknown result type (might be due to invalid IL or missing references)
			plugin = owner;
			fallbackFont = TMP_FontAsset.CreateFontAsset(plugin.FontName.Value, "Regular", 90);
			font = TMP_Settings.defaultFontAsset ?? fallbackFont;
			canvasObject = new GameObject("TextChat Canvas", new Type[4]
			{
				typeof(RectTransform),
				typeof(Canvas),
				typeof(CanvasScaler),
				typeof(GraphicRaycaster)
			});
			canvasObject.transform.SetParent(((Component)this).transform, false);
			Canvas component = canvasObject.GetComponent<Canvas>();
			component.renderMode = (RenderMode)0;
			component.sortingOrder = 31000;
			CanvasScaler component2 = canvasObject.GetComponent<CanvasScaler>();
			component2.uiScaleMode = (ScaleMode)1;
			component2.referenceResolution = new Vector2(1920f, 1080f);
			component2.matchWidthOrHeight = 0.5f;
			panel = Rect("Crew chat", canvasObject.transform, new Vector2(560f, 300f));
			RectTransform obj = panel;
			Vector2 anchorMin = (panel.anchorMax = Vector2.zero);
			obj.anchorMin = anchorMin;
			panel.pivot = Vector2.zero;
			panel.anchoredPosition = new Vector2(24f, plugin.BottomOffset.Value);
			Background(((Component)panel).gameObject, new Color(0.055f, 0.05f, 0.04f, 0.84f));
			group = ((Component)panel).gameObject.AddComponent<CanvasGroup>();
			group.alpha = 0f;
			group.blocksRaycasts = false;
			viewport = Rect("Messages", (Transform)(object)panel, Vector2.zero);
			Stretch(viewport, new Vector2(14f, 66f), new Vector2(-14f, -12f));
			Background(((Component)viewport).gameObject, Color.clear);
			((Component)viewport).gameObject.AddComponent<RectMask2D>();
			scroll = ((Component)viewport).gameObject.AddComponent<ScrollRect>();
			scroll.horizontal = false;
			scroll.movementType = (MovementType)2;
			scroll.scrollSensitivity = 32f;
			scroll.viewport = viewport;
			content = Rect("History", (Transform)(object)viewport, Vector2.zero);
			content.anchorMin = new Vector2(0f, 1f);
			content.anchorMax = Vector2.one;
			content.pivot = new Vector2(0.5f, 1f);
			content.sizeDelta = Vector2.zero;
			VerticalLayoutGroup obj2 = ((Component)content).gameObject.AddComponent<VerticalLayoutGroup>();
			((HorizontalOrVerticalLayoutGroup)obj2).childControlWidth = true;
			((HorizontalOrVerticalLayoutGroup)obj2).childControlHeight = true;
			((HorizontalOrVerticalLayoutGroup)obj2).childForceExpandWidth = true;
			((HorizontalOrVerticalLayoutGroup)obj2).childForceExpandHeight = false;
			((HorizontalOrVerticalLayoutGroup)obj2).spacing = 5f;
			((Component)content).gameObject.AddComponent<ContentSizeFitter>().verticalFit = (FitMode)2;
			scroll.content = content;
			inputRect = Rect("Message input", (Transform)(object)panel, new Vector2(532f, 36f));
			RectTransform obj3 = inputRect;
			anchorMin = (inputRect.anchorMax = Vector2.zero);
			obj3.anchorMin = anchorMin;
			inputRect.pivot = Vector2.zero;
			inputRect.anchoredPosition = new Vector2(14f, 26f);
			Image targetGraphic = Background(((Component)inputRect).gameObject, new Color(0.94f, 0.93f, 0.89f));
			TextMeshProUGUI val = Label("", (Transform)(object)inputRect, plugin.FontSize.Value, new Color(0.1f, 0.09f, 0.07f));
			Stretch(((TMP_Text)val).rectTransform, new Vector2(10f, 2f), new Vector2(-10f, -2f));
			((TMP_Text)val).alignment = (TextAlignmentOptions)4097;
			((TMP_Text)val).richText = false;
			((TMP_Text)val).textWrappingMode = (TextWrappingModes)0;
			TextMeshProUGUI val2 = Label("Type a message...", (Transform)(object)inputRect, 18, new Color(0.4f, 0.37f, 0.32f));
			Stretch(((TMP_Text)val2).rectTransform, new Vector2(10f, 2f), new Vector2(-10f, -2f));
			((TMP_Text)val2).alignment = (TextAlignmentOptions)4097;
			input = ((Component)inputRect).gameObject.AddComponent<ChatInputField>();
			input.Owner = this;
			((Selectable)input).targetGraphic = (Graphic)(object)targetGraphic;
			((TMP_InputField)input).textComponent = (TMP_Text)(object)val;
			((TMP_InputField)input).textViewport = inputRect;
			((TMP_InputField)input).richText = false;
			((TMP_InputField)input).onFocusSelectAll = false;
			((TMP_InputField)input).placeholder = (Graphic)(object)val2;
			((TMP_InputField)input).characterLimit = 300;
			((TMP_InputField)input).lineType = (LineType)0;
			((TMP_InputField)input).customCaretColor = true;
			((TMP_InputField)input).caretColor = new Color(0.12f, 0.1f, 0.08f);
			((UnityEvent<string>)(object)((TMP_InputField)input).onValueChanged).AddListener((UnityAction<string>)delegate(string value)
			{
				count.text = value.Length + "/300";
			});
			hint = (TMP_Text)(object)Label("ENTER send   /   ESC close   /   Scroll history", (Transform)(object)panel, 12, new Color(0.6f, 0.66f, 0.71f));
			Place(hint.rectTransform, 14f, -278f, 460f, 20f);
			count = (TMP_Text)(object)Label("0/300", (Transform)(object)panel, 12, new Color(0.6f, 0.66f, 0.71f));
			Place(count.rectTransform, 480f, -278f, 66f, 20f);
			count.alignment = (TextAlignmentOptions)4100;
			((Selectable)input).interactable = false;
			((Behaviour)scroll).enabled = false;
		}

		private Player LocalPlayer()
		{
			if (!((Object)(object)NetworkClient.localPlayer == (Object)null))
			{
				return ((Component)NetworkClient.localPlayer).GetComponent<PlayerController>()?.player;
			}
			return null;
		}

		private bool InGameplayScene()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			Scene activeScene = SceneManager.GetActiveScene();
			if (((Scene)(ref activeScene)).IsValid() && ((Scene)(ref activeScene)).isLoaded)
			{
				return !string.Equals(((Scene)(ref activeScene)).name, "Menu", StringComparison.OrdinalIgnoreCase);
			}
			return false;
		}

		public void Tick()
		{
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0162: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ff: Unknown result type (might be due to invalid IL or missing references)
			RefreshGameFont();
			if (restorePending && plugin.ClosedFrame != Time.frameCount)
			{
				RestoreInput();
			}
			Player val = LocalPlayer();
			if (!InGameplayScene() || !NetworkClient.isConnected || !NetworkClient.ready || NetworkClient.isLoadingScene || !((Object)(object)val != (Object)null) || !((Behaviour)val).isActiveAndEnabled || !val.IsInputReady)
			{
				if (IsOpen || rows.Count > 0)
				{
					ResetSession();
				}
				group.alpha = 0f;
				group.blocksRaycasts = false;
				canvasObject.SetActive(false);
				return;
			}
			canvasObject.SetActive(true);
			panel.anchoredPosition = new Vector2(24f, plugin.BottomOffset.Value);
			panel.sizeDelta = new Vector2(560f, (float)(IsOpen ? 300 : 180));
			((Component)inputRect).gameObject.SetActive(IsOpen);
			((Component)hint).gameObject.SetActive(IsOpen);
			((Component)count).gameObject.SetActive(IsOpen);
			viewport.offsetMin = new Vector2(14f, (float)(IsOpen ? 66 : 10));
			Keyboard current = Keyboard.current;
			if (IsOpen)
			{
				if (!NetworkClient.isConnected || (Object)(object)LocalPlayer() != (Object)(object)capturedPlayer || !Application.isFocused || ((Object)(object)GameMenu.instance != (Object)null && GameMenu.instance.IsOpen) || (Object)(object)module == (Object)null || (Object)(object)EventSystem.current == (Object)null || (Object)(object)EventSystem.current.currentInputModule != (Object)(object)module)
				{
					Close();
				}
				else
				{
					GameplayActions gameplayInput = capturedPlayer.GameplayInput;
					((GameplayActions)(ref gameplayInput)).Disable();
					Cursor.lockState = (CursorLockMode)0;
					Cursor.visible = true;
					if (current != null && Time.frameCount > openFrame && (((ButtonControl)current.enterKey).wasPressedThisFrame || ((ButtonControl)current.numpadEnterKey).wasPressedThisFrame))
					{
						RequestSubmit();
					}
					if (current != null && ((ButtonControl)current.escapeKey).wasPressedThisFrame && Time.frameCount > openFrame)
					{
						Close();
					}
				}
			}
			else if (current != null && plugin.ClosedFrame != Time.frameCount && NetworkClient.isConnected && Application.isFocused && (int)plugin.OpenKey.Value != 0 && ((ButtonControl)current[plugin.OpenKey.Value]).wasPressedThisFrame && ((Object)(object)GameMenu.instance == (Object)null || !GameMenu.instance.IsOpen) && !KeybindPanel.IsRebinding && (Object)(object)LocalPlayer() != (Object)null && !OtherTextFieldSelected())
			{
				Open();
			}
			float alpha = ((!NetworkClient.isConnected) ? 0f : (IsOpen ? 1f : Mathf.Clamp01(plugin.FadeSeconds.Value + 1f - (Time.unscaledTime - lastMessage))));
			group.alpha = alpha;
		}

		private bool OtherTextFieldSelected()
		{
			GameObject val = (((Object)(object)EventSystem.current == (Object)null) ? null : EventSystem.current.currentSelectedGameObject);
			if ((Object)(object)val != (Object)null)
			{
				if (!((Object)(object)val.GetComponent<InputField>() != (Object)null))
				{
					return (Object)(object)val.GetComponent<TMP_InputField>() != (Object)null;
				}
				return true;
			}
			return false;
		}

		private void Open()
		{
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Expected O, but got Unknown
			//IL_01a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01de: Unknown result type (might be due to invalid IL or missing references)
			//IL_021c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0221: Unknown result type (might be due to invalid IL or missing references)
			//IL_022a: Unknown result type (might be due to invalid IL or missing references)
			//IL_022f: Unknown result type (might be due to invalid IL or missing references)
			if (!InGameplayScene() || !NetworkClient.isConnected || !NetworkClient.ready || NetworkClient.isLoadingScene)
			{
				return;
			}
			capturedPlayer = LocalPlayer();
			if ((Object)(object)capturedPlayer == (Object)null || !capturedPlayer.IsInputReady)
			{
				return;
			}
			RestoreInput();
			if ((Object)(object)EventSystem.current == (Object)null)
			{
				ownEventSystem = new GameObject("TextChat EventSystem", new Type[2]
				{
					typeof(EventSystem),
					typeof(InputSystemUIInputModule)
				});
				ownEventSystem.transform.SetParent(((Component)this).transform, false);
				ownEventSystem.GetComponent<InputSystemUIInputModule>().AssignDefaultActions();
			}
			module = EventSystem.current.currentInputModule;
			if ((Object)(object)module == (Object)null)
			{
				return;
			}
			savedSelection = EventSystem.current.currentSelectedGameObject;
			savedOverride = module.inputOverride;
			bridge = ((Component)module).gameObject.AddComponent<ChatBaseInput>();
			bridge.Owner = this;
			module.inputOverride = (BaseInput)(object)bridge;
			keyboard = Keyboard.current;
			Composition = "";
			CompositionFrame = -10;
			submitPending = false;
			committedFrame = -10;
			hint.text = "ENTER send   /   ESC close   /   Scroll history";
			if (keyboard != null)
			{
				keyboard.onIMECompositionChange += OnComposition;
				keyboard.onTextInput += OnTextInput;
				keyboard.SetIMEEnabled(true);
			}
			savedImeMode = Input.imeCompositionMode;
			Input.imeCompositionMode = (IMECompositionMode)1;
			nativeIme = WindowsImeContext.Acquire();
			GameplayActions gameplayInput = capturedPlayer.GameplayInput;
			Enumerator<InputAction> enumerator = ((GameplayActions)(ref gameplayInput)).Get().actions.GetEnumerator();
			try
			{
				while (enumerator.MoveNext())
				{
					InputAction current = enumerator.Current;
					if (current.enabled)
					{
						restoreActions.Add(current);
					}
				}
			}
			finally
			{
				((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose();
			}
			gameplayInput = capturedPlayer.GameplayInput;
			((GameplayActions)(ref gameplayInput)).Disable();
			savedLock = Cursor.lockState;
			savedVisible = Cursor.visible;
			IsOpen = true;
			openFrame = Time.frameCount;
			Cursor.lockState = (CursorLockMode)0;
			Cursor.visible = true;
			group.blocksRaycasts = true;
			((Component)inputRect).gameObject.SetActive(true);
			((Component)hint).gameObject.SetActive(true);
			((Component)count).gameObject.SetActive(true);
			((Selectable)input).interactable = true;
			((Behaviour)scroll).enabled = true;
			((TMP_InputField)input).text = "";
			EventSystem.current.SetSelectedGameObject(((Component)input).gameObject);
			((TMP_InputField)input).ActivateInputField();
			ScrollToBottom();
		}

		private unsafe void OnComposition(IMECompositionString value)
		{
			Composition = ((object)(*(IMECompositionString*)(&value))/*cast due to .constrained prefix*/).ToString();
			CompositionFrame = Time.frameCount;
			input.RefreshComposition();
		}

		private void OnTextInput(char value)
		{
			if (IsOpen && Time.frameCount > openFrame)
			{
				if (value == '\r' || value == '\n')
				{
					RequestSubmit();
				}
				else if (!char.IsControl(value))
				{
					Composition = "";
					input.ReceiveCharacter(value);
					committedFrame = Time.frameCount;
				}
			}
		}

		internal void RequestSubmit()
		{
			if (IsOpen && !submitPending)
			{
				submitPending = true;
				submitFrame = Time.frameCount;
				if (IsComposing)
				{
					nativeIme?.CompleteComposition();
				}
			}
		}

		private void LateUpdate()
		{
			ProcessPendingSubmit();
		}

		private void ProcessPendingSubmit()
		{
			if (submitPending && IsOpen && Time.frameCount > submitFrame && Time.frameCount > committedFrame && Time.frameCount > CompositionFrame && Composition.Length <= 0 && string.IsNullOrEmpty(Input.compositionString))
			{
				submitPending = false;
				TrySubmit();
			}
		}

		private void RefreshGameFont()
		{
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			if (Time.unscaledTime < fontRefreshAt)
			{
				return;
			}
			fontRefreshAt = Time.unscaledTime + 2f;
			Dictionary<TMP_FontAsset, int> dictionary = new Dictionary<TMP_FontAsset, int>();
			TextMeshProUGUI[] array = Resources.FindObjectsOfTypeAll<TextMeshProUGUI>();
			foreach (TextMeshProUGUI val in array)
			{
				if ((Object)(object)((TMP_Text)val).font == (Object)null || ((TMP_Text)val).transform.IsChildOf(canvasObject.transform))
				{
					continue;
				}
				Scene scene = ((Component)val).gameObject.scene;
				if (((Scene)(ref scene)).IsValid())
				{
					if (!dictionary.ContainsKey(((TMP_Text)val).font))
					{
						dictionary[((TMP_Text)val).font] = 0;
					}
					dictionary[((TMP_Text)val).font]++;
				}
			}
			int num = 0;
			TMP_FontAsset key = font;
			foreach (KeyValuePair<TMP_FontAsset, int> item in dictionary)
			{
				if (item.Value > num)
				{
					key = item.Key;
					num = item.Value;
				}
			}
			if (!((Object)(object)key == (Object)null) && !((Object)(object)key == (Object)(object)font))
			{
				font = key;
				TMP_Text[] componentsInChildren = canvasObject.GetComponentsInChildren<TMP_Text>(true);
				for (int i = 0; i < componentsInChildren.Length; i++)
				{
					componentsInChildren[i].font = font;
				}
			}
		}

		internal void ProcessInput(BaseEventData data)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Expected O, but got Unknown
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Invalid comparison between Unknown and I4
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Invalid comparison between Unknown and I4
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Invalid comparison between Unknown and I4
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Invalid comparison between Unknown and I4
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Invalid comparison between Unknown and I4
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Invalid comparison between Unknown and I4
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Invalid comparison between Unknown and I4
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Invalid comparison between Unknown and I4
			Event val = new Event();
			while (Event.PopEvent(val))
			{
				if (!IsOpen || Time.frameCount <= openFrame)
				{
					continue;
				}
				if ((int)val.rawType == 4)
				{
					if ((int)val.keyCode == 13 || (int)val.keyCode == 271)
					{
						RequestSubmit();
					}
					else if ((int)val.keyCode == 27)
					{
						Close();
					}
					else if (!IsComposing || ((int)val.keyCode != 8 && (int)val.keyCode != 127))
					{
						val.character = '\0';
						((TMP_InputField)input).ProcessEvent(val);
					}
				}
				else if (((int)val.type == 13 || (int)val.type == 14) && val.commandName == "SelectAll")
				{
					input.SelectAllText();
				}
			}
			input.RefreshComposition();
			((AbstractEventData)data).Use();
		}

		internal void TrySubmit()
		{
			string text = ChatRules.Clean(((TMP_InputField)input).text);
			if (text.Length == 0)
			{
				Close();
			}
			else if (Time.unscaledTime - lastSent < plugin.MessageInterval.Value)
			{
				hint.text = "Please wait before sending another message";
			}
			else if (plugin.Network.Send(text))
			{
				lastSent = Time.unscaledTime;
				Close();
			}
		}

		public void Close()
		{
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0192: Unknown result type (might be due to invalid IL or missing references)
			if (IsOpen)
			{
				IsOpen = false;
				submitPending = false;
				plugin.ClosedFrame = Time.frameCount;
				((TMP_InputField)input).DeactivateInputField(false);
				((Selectable)input).interactable = false;
				((TMP_InputField)input).text = "";
				group.blocksRaycasts = false;
				((Behaviour)scroll).enabled = false;
				if ((Object)(object)module != (Object)null && (Object)(object)module.inputOverride == (Object)(object)bridge)
				{
					module.inputOverride = savedOverride;
				}
				if ((Object)(object)bridge != (Object)null)
				{
					Object.Destroy((Object)(object)bridge);
				}
				if (keyboard != null)
				{
					keyboard.onIMECompositionChange -= OnComposition;
					keyboard.onTextInput -= OnTextInput;
					keyboard.SetIMEEnabled(false);
				}
				Input.imeCompositionMode = savedImeMode;
				nativeIme?.Dispose();
				nativeIme = null;
				Composition = "";
				if ((Object)(object)EventSystem.current != (Object)null && (Object)(object)EventSystem.current.currentSelectedGameObject == (Object)(object)((Component)input).gameObject)
				{
					EventSystem.current.SetSelectedGameObject(savedSelection);
				}
				if ((!((Object)(object)GameMenu.instance != (Object)null) || !GameMenu.instance.IsOpen) && NetworkClient.isConnected && (Object)(object)capturedPlayer != (Object)null)
				{
					Cursor.lockState = savedLock;
					Cursor.visible = savedVisible;
				}
				restorePending = true;
				ScrollToBottom();
			}
		}

		private void RestoreInput()
		{
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//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_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			if (restorePending && (Object)(object)capturedPlayer != (Object)null && NetworkClient.isConnected && ((Object)(object)GameMenu.instance == (Object)null || !GameMenu.instance.IsOpen))
			{
				capturedPlayer.RestoreGameplayInput();
				GameplayActions gameplayInput = capturedPlayer.GameplayInput;
				Enumerator<InputAction> enumerator = ((GameplayActions)(ref gameplayInput)).Get().actions.GetEnumerator();
				try
				{
					while (enumerator.MoveNext())
					{
						InputAction current = enumerator.Current;
						if (!restoreActions.Contains(current))
						{
							current.Disable();
						}
					}
				}
				finally
				{
					((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose();
				}
			}
			restoreActions.Clear();
			restorePending = false;
		}

		public void Add(string name, string text, bool system)
		{
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			bool flag = !IsOpen || scroll.verticalNormalizedPosition <= 0.05f;
			TextMeshProUGUI val = Label(DateTime.Now.ToString("HH:mm") + "  " + name + ": " + text, (Transform)(object)content, plugin.FontSize.Value, system ? new Color(0.84f, 0.8f, 0.68f) : new Color(0.94f, 0.95f, 0.96f));
			((TMP_Text)val).richText = false;
			((TMP_Text)val).textWrappingMode = (TextWrappingModes)1;
			((TMP_Text)val).overflowMode = (TextOverflowModes)0;
			((Component)val).gameObject.AddComponent<LayoutElement>().minHeight = plugin.FontSize.Value + 5;
			rows.Enqueue(((Component)val).gameObject);
			while (rows.Count > plugin.HistoryLimit.Value)
			{
				GameObject obj = rows.Dequeue();
				obj.SetActive(false);
				Object.Destroy((Object)(object)obj);
			}
			lastMessage = Time.unscaledTime;
			if (flag)
			{
				ScrollToBottom();
			}
		}

		private void ScrollToBottom()
		{
			Canvas.ForceUpdateCanvases();
			LayoutRebuilder.ForceRebuildLayoutImmediate(content);
			scroll.verticalNormalizedPosition = 0f;
		}

		public void ResetSession()
		{
			Close();
			while (rows.Count > 0)
			{
				GameObject obj = rows.Dequeue();
				obj.SetActive(false);
				Object.Destroy((Object)(object)obj);
			}
			lastMessage = -1000f;
			lastSent = -1000f;
		}

		private void OnDestroy()
		{
			Close();
			RestoreInput();
			if ((Object)(object)canvasObject != (Object)null)
			{
				Object.Destroy((Object)(object)canvasObject);
			}
			if ((Object)(object)ownEventSystem != (Object)null)
			{
				Object.Destroy((Object)(object)ownEventSystem);
			}
			if ((Object)(object)fallbackFont != (Object)null)
			{
				Object.Destroy((Object)(object)fallbackFont);
			}
		}

		private static RectTransform Rect(string name, Transform parent, Vector2 size)
		{
			//IL_0014: 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)
			RectTransform component = new GameObject(name, new Type[1] { typeof(RectTransform) }).GetComponent<RectTransform>();
			((Transform)component).SetParent(parent, false);
			component.sizeDelta = size;
			return component;
		}

		private TextMeshProUGUI Label(string value, Transform parent, int size, Color color)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			TextMeshProUGUI obj = ((Component)Rect("Text", parent, Vector2.zero)).gameObject.AddComponent<TextMeshProUGUI>();
			((TMP_Text)obj).font = font;
			((TMP_Text)obj).fontSharedMaterial = ((TMP_Asset)font).material;
			((TMP_Text)obj).text = value;
			((TMP_Text)obj).fontSize = size;
			((Graphic)obj).color = color;
			((Graphic)obj).raycastTarget = false;
			((TMP_Text)obj).richText = false;
			return obj;
		}

		private static Image Background(GameObject obj, Color color)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			Image obj2 = obj.AddComponent<Image>();
			((Graphic)obj2).color = color;
			return obj2;
		}

		private static void Place(RectTransform rect, float x, float y, float width, float height)
		{
			//IL_0013: 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_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: 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)
			Vector2 val = default(Vector2);
			((Vector2)(ref val))..ctor(0f, 1f);
			rect.anchorMax = val;
			rect.anchorMin = val;
			rect.pivot = new Vector2(0f, 1f);
			rect.anchoredPosition = new Vector2(x, y);
			rect.sizeDelta = new Vector2(width, height);
		}

		private static void Stretch(RectTransform rect, Vector2 min, Vector2 max)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: 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)
			rect.anchorMin = Vector2.zero;
			rect.anchorMax = Vector2.one;
			rect.offsetMin = min;
			rect.offsetMax = max;
		}
	}
	public sealed class ChatInputField : TMP_InputField
	{
		internal ChatView Owner;

		public override void OnUpdateSelected(BaseEventData eventData)
		{
			if (((TMP_InputField)this).isFocused && (Object)(object)Owner != (Object)null)
			{
				Owner.ProcessInput(eventData);
			}
		}

		internal void RefreshComposition()
		{
			((TMP_InputField)this).UpdateLabel();
		}

		internal void SelectAllText()
		{
			((TMP_InputField)this).SelectAll();
		}

		internal void ReceiveCharacter(char value)
		{
			((TMP_InputField)this).Append(value);
			((TMP_InputField)this).UpdateLabel();
		}
	}
	public sealed class ChatBaseInput : BaseInput
	{
		internal ChatView Owner;

		private Vector2 cursor;

		public override string compositionString
		{
			get
			{
				if (!((Object)(object)Owner == (Object)null))
				{
					if (Owner.Composition.Length <= 0)
					{
						return Input.compositionString;
					}
					return Owner.Composition;
				}
				return "";
			}
		}

		public override IMECompositionMode imeCompositionMode
		{
			get
			{
				//IL_0000: Unknown result type (might be due to invalid IL or missing references)
				return Input.imeCompositionMode;
			}
			set
			{
				//IL_0000: Unknown result type (might be due to invalid IL or missing references)
				Input.imeCompositionMode = value;
			}
		}

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

		public override bool touchSupported => false;

		public override bool mousePresent => Mouse.current != null;

		public override Vector2 mousePosition
		{
			get
			{
				//IL_0017: 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)
				if (Mouse.current != null)
				{
					return ((InputControl<Vector2>)(object)((Pointer)Mouse.current).position).ReadValue();
				}
				return Vector2.zero;
			}
		}

		public override Vector2 mouseScrollDelta
		{
			get
			{
				//IL_0017: 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)
				if (Mouse.current != null)
				{
					return ((InputControl<Vector2>)(object)Mouse.current.scroll).ReadValue();
				}
				return Vector2.zero;
			}
		}
	}
	[BepInPlugin("crack.textchat", "CRACK TextChat", "1.0.0")]
	[BepInProcess("CRACK.exe")]
	[DefaultExecutionOrder(-10000)]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string Guid = "crack.textchat";

		internal static Plugin Instance;

		internal ConfigEntry<bool> AssumeLanHost;

		internal ConfigEntry<float> MessageInterval;

		internal ConfigEntry<int> FontSize;

		internal ConfigEntry<float> FadeSeconds;

		internal ConfigEntry<int> HistoryLimit;

		internal ConfigEntry<Key> OpenKey;

		internal ConfigEntry<string> FontName;

		internal ConfigEntry<float> BottomOffset;

		internal ChatView View;

		internal ChatNetwork Network;

		private Harmony harmony;

		internal int ClosedFrame = -1;

		internal bool BlocksInput
		{
			get
			{
				if (!((Object)(object)View != (Object)null) || !View.IsOpen)
				{
					return ClosedFrame == Time.frameCount;
				}
				return true;
			}
		}

		private void Awake()
		{
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Expected O, but got Unknown
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Expected O, but got Unknown
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Expected O, but got Unknown
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Expected O, but got Unknown
			//IL_0164: Unknown result type (might be due to invalid IL or missing references)
			//IL_016e: Expected O, but got Unknown
			//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cd: Expected O, but got Unknown
			Instance = this;
			AssumeLanHost = ((BaseUnityPlugin)this).Config.Bind<bool>("Network", "AssumeLanHostHasMod", false, "LAN clients only: enable only if the host also has TextChat 1.x. Steam lobbies discover support automatically.");
			MessageInterval = ((BaseUnityPlugin)this).Config.Bind<float>("Network", "MessageIntervalSeconds", 0.75f, new ConfigDescription("Host-enforced minimum time between messages.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.25f, 10f), Array.Empty<object>()));
			FontSize = ((BaseUnityPlugin)this).Config.Bind<int>("UI", "FontSize", 20, new ConfigDescription("Chat font size. Restart to apply.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(14, 32), Array.Empty<object>()));
			FadeSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("UI", "VisibleSeconds", 12f, new ConfigDescription("Time before closed chat fades out.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(3f, 120f), Array.Empty<object>()));
			HistoryLimit = ((BaseUnityPlugin)this).Config.Bind<int>("UI", "HistoryLimit", 100, new ConfigDescription("Maximum messages retained for this session.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(20, 300), Array.Empty<object>()));
			FontName = ((BaseUnityPlugin)this).Config.Bind<string>("UI", "FontName", "Malgun Gothic", "Temporary OS fallback before the game's TextMeshPro font is loaded. The game's font and localized fallbacks are preferred.");
			BottomOffset = ((BaseUnityPlugin)this).Config.Bind<float>("UI", "BottomOffset", 200f, new ConfigDescription("Chat bottom margin at 1080p. Keeps chat above the hotbar.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(100f, 500f), Array.Empty<object>()));
			OpenKey = ((BaseUnityPlugin)this).Config.Bind<Key>("Controls", "OpenKey", (Key)2, "Key used to open chat. Enter always sends while chat is open.");
			Network = new ChatNetwork(this);
			View = ((Component)this).gameObject.AddComponent<ChatView>();
			View.Initialize(this);
			harmony = new Harmony("crack.textchat");
			harmony.PatchAll(typeof(Plugin).Assembly);
			((BaseUnityPlugin)this).Logger.LogInfo((object)"CRACK TextChat 1.0.0 loaded. Press Enter in a game to chat.");
		}

		private void Update()
		{
			Network.Tick();
			View.Tick();
		}

		private void OnDestroy()
		{
			Harmony obj = harmony;
			if (obj != null)
			{
				obj.UnpatchSelf();
			}
			View?.Close();
			Network?.Dispose();
			if ((Object)(object)View != (Object)null)
			{
				Object.Destroy((Object)(object)View);
			}
			Instance = null;
		}

		[HarmonyPatch(typeof(GameMenu), "Update")]
		[HarmonyPrefix]
		private static bool MenuInput()
		{
			if (!((Object)(object)Instance == (Object)null))
			{
				return !Instance.BlocksInput;
			}
			return true;
		}

		[HarmonyPatch(typeof(Player), "RestoreGameplayInput")]
		[HarmonyPostfix]
		private static void RestoredInput(Player __instance)
		{
			//IL_002a: 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)
			if ((Object)(object)Instance != (Object)null && Instance.BlocksInput && ((NetworkBehaviour)__instance).isOwned && __instance.IsInputReady)
			{
				GameplayActions gameplayInput = __instance.GameplayInput;
				((GameplayActions)(ref gameplayInput)).Disable();
			}
		}

		[HarmonyPatch(typeof(Player), "Update")]
		[HarmonyPrefix]
		private static void PlayerInput(Player __instance)
		{
			//IL_002a: 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)
			if ((Object)(object)Instance != (Object)null && Instance.BlocksInput && ((NetworkBehaviour)__instance).isOwned && __instance.IsInputReady)
			{
				GameplayActions gameplayInput = __instance.GameplayInput;
				((GameplayActions)(ref gameplayInput)).Disable();
			}
		}
	}
	internal sealed class WindowsImeContext : IDisposable
	{
		private IntPtr window;

		private IntPtr created;

		private IntPtr previous;

		private bool changed;

		internal static WindowsImeContext Acquire()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Invalid comparison between Unknown and I4
			WindowsImeContext windowsImeContext = new WindowsImeContext();
			if ((int)Application.platform != 2)
			{
				return windowsImeContext;
			}
			try
			{
				using (Process process = Process.GetCurrentProcess())
				{
					windowsImeContext.window = process.MainWindowHandle;
				}
				if (windowsImeContext.window == IntPtr.Zero)
				{
					return windowsImeContext;
				}
				IntPtr intPtr = ImmGetContext(windowsImeContext.window);
				if (intPtr != IntPtr.Zero)
				{
					ImmReleaseContext(windowsImeContext.window, intPtr);
					return windowsImeContext;
				}
				windowsImeContext.changed = ImmAssociateContextEx(windowsImeContext.window, IntPtr.Zero, 16u);
				intPtr = ImmGetContext(windowsImeContext.window);
				if (intPtr != IntPtr.Zero)
				{
					ImmReleaseContext(windowsImeContext.window, intPtr);
					return windowsImeContext;
				}
				windowsImeContext.created = ImmCreateContext();
				if (windowsImeContext.created != IntPtr.Zero)
				{
					windowsImeContext.previous = ImmAssociateContext(windowsImeContext.window, windowsImeContext.created);
					windowsImeContext.changed = true;
				}
			}
			catch (DllNotFoundException)
			{
			}
			catch (EntryPointNotFoundException)
			{
			}
			return windowsImeContext;
		}

		public void Dispose()
		{
			if (changed && window != IntPtr.Zero)
			{
				ImmAssociateContext(window, previous);
			}
			if (created != IntPtr.Zero)
			{
				ImmDestroyContext(created);
			}
			window = (created = IntPtr.Zero);
			changed = false;
		}

		internal void CompleteComposition()
		{
			if (window == IntPtr.Zero)
			{
				return;
			}
			IntPtr intPtr = ImmGetContext(window);
			if (intPtr == IntPtr.Zero)
			{
				return;
			}
			try
			{
				ImmNotifyIME(intPtr, 21u, 1u, 0u);
			}
			finally
			{
				ImmReleaseContext(window, intPtr);
			}
		}

		[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 IntPtr ImmAssociateContext(IntPtr hwnd, IntPtr context);

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

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

		[DllImport("imm32.dll")]
		private static extern bool ImmNotifyIME(IntPtr context, uint action, uint index, uint value);
	}
}