Decompiled source of ChatPlus v1.0.0

ChatPlus.dll

Decompiled 2 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using I2.Loc;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace ChatPlus;

public enum QuickChatMenu
{
	Automatic,
	Treehouse,
	BuildMode,
	PlayMode
}
public enum PlusButtonMode
{
	WhenChatOpen,
	Always
}
[BepInPlugin("com.chatplus.uch", "Chat+", "1.1.2")]
public class ChatPlusPlugin : BaseUnityPlugin
{
	public const string PluginGuid = "com.chatplus.uch";

	public const string PluginName = "Chat+";

	public const string PluginVersion = "1.1.2";

	internal static ChatPlusPlugin Instance;

	internal static ManualLogSource Log;

	internal static ConfigEntry<bool> AutoHello;

	internal static ConfigEntry<bool> AutoGoodbye;

	internal static ConfigEntry<bool> AutoWellDone;

	internal static ConfigEntry<bool> AutoSoClose;

	internal static ConfigEntry<QuickChatMenu> QuickChat;

	internal static ConfigEntry<PlusButtonMode> PlusMode;

	internal static string HookStatus = "no hooks applied";

	internal static bool HooksAllOk;

	private int errUi;

	private int errNet;

	private int errAuto;

	private int errMenu;

	private static EmoteContext lastAutomatic = (EmoteContext)2;

	private static EmoteContext lastApplied = (EmoteContext)2;

	private static bool appliedOnce;

	private void Awake()
	{
		Instance = this;
		Log = ((BaseUnityPlugin)this).Logger;
		AutoHello = ((BaseUnityPlugin)this).Config.Bind<bool>("1. Auto Chat", "Hello when someone joins treehouse", true, "Automatically say \"Hello!\" 0.5s after another player joins the treehouse.");
		AutoGoodbye = ((BaseUnityPlugin)this).Config.Bind<bool>("1. Auto Chat", "Goodbye when someone leaves treehouse", true, "Automatically say \"Goodbye\" 0.5s after another player leaves the treehouse.");
		AutoWellDone = ((BaseUnityPlugin)this).Config.Bind<bool>("1. Auto Chat", "Well done when someone finishes", true, "Automatically say \"Well done!\" when another player finishes.");
		AutoSoClose = ((BaseUnityPlugin)this).Config.Bind<bool>("1. Auto Chat", "So close when someone dies on last life", true, "Automatically say \"So close!\" when another player dies on their last life.");
		QuickChat = ((BaseUnityPlugin)this).Config.Bind<QuickChatMenu>("2. Quick Chat", "Quick chat menu", QuickChatMenu.Automatic, "Which quick chat (emote) menu is active: Automatic (switches by itself: treehouse, build mode, play mode), Treehouse, BuildMode or PlayMode.");
		QuickChat.SettingChanged += delegate
		{
			ApplyQuickChatNow();
		};
		PlusMode = ((BaseUnityPlugin)this).Config.Bind<PlusButtonMode>("3. Misc", "Plus buttons", PlusButtonMode.WhenChatOpen, "WhenChatOpen: the + buttons only show while the chat box is open. Always: the + buttons are always visible.");
		ApplyHooks();
		Log.LogInfo((object)"Chat+ 1.1.2 loaded.");
	}

	private void ApplyHooks()
	{
		//IL_0005: Unknown result type (might be due to invalid IL or missing references)
		//IL_000b: Expected O, but got Unknown
		Harmony val = new Harmony("com.chatplus.uch");
		string[] array = new string[6] { "QuickChat", "ChatLines", "Death", "Finish", "PlusButton", "SelfJoin" };
		Type[] array2 = new Type[6]
		{
			typeof(Patch_SetEmoteContext),
			typeof(Patch_DisplayNewMessage),
			typeof(Patch_SetupDeath),
			typeof(Patch_PlayerSuccess),
			typeof(Patch_SetChatUnitMessage),
			typeof(Patch_SelfJoin)
		};
		Type[] array3 = new Type[6]
		{
			typeof(EmoteSystem),
			typeof(ChatDisplay),
			typeof(Character),
			typeof(Character),
			typeof(ChatUnit),
			typeof(LobbyPlayer)
		};
		string[] array4 = new string[6] { "SetEmoteContext", "DisplayNewMessage", "setupDeath", "RpcSendPlayerSuccessEvent", "SetChatUnitMessage", "CallCmdSendJoinMessage" };
		int num = 0;
		List<string> list = new List<string>();
		for (int i = 0; i < array2.Length; i++)
		{
			bool flag = false;
			try
			{
				val.CreateClassProcessor(array2[i]).Patch();
				MethodBase methodBase = AccessTools.Method(array3[i], array4[i], (Type[])null, (Type[])null);
				if (methodBase == null)
				{
					Log.LogError((object)("Chat+ hook " + array[i] + ": game method " + array3[i].Name + "." + array4[i] + " was not found"));
				}
				else
				{
					Patches patchInfo = Harmony.GetPatchInfo(methodBase);
					flag = patchInfo != null && (patchInfo.Prefixes.Any((Patch x) => x.owner == "com.chatplus.uch") || patchInfo.Postfixes.Any((Patch x) => x.owner == "com.chatplus.uch"));
					if (!flag)
					{
						Log.LogError((object)("Chat+ hook " + array[i] + ": patch did not attach to " + array3[i].Name + "." + array4[i]));
					}
				}
			}
			catch (Exception ex)
			{
				Log.LogError((object)("Chat+ hook " + array[i] + " failed: " + ex));
			}
			if (flag)
			{
				num++;
				Log.LogInfo((object)("Chat+ hook OK: " + array[i]));
			}
			else
			{
				list.Add(array[i]);
			}
		}
		HooksAllOk = list.Count == 0;
		HookStatus = ((!HooksAllOk) ? (num + "/" + array2.Length + " hooks OK, FAILED: " + string.Join(", ", list.ToArray())) : ("all " + array2.Length + " hooks OK"));
		Log.LogInfo((object)("Chat+ status: " + HookStatus));
	}

	private void Update()
	{
		try
		{
			ChatPlusNet.Poll();
		}
		catch (Exception ex)
		{
			if (errNet++ < 5)
			{
				Log.LogError((object)("Chat+ network update error: " + ex));
			}
		}
		try
		{
			ChatPlusUI.Tick();
		}
		catch (Exception ex2)
		{
			if (errUi++ < 5)
			{
				Log.LogError((object)("Chat+ UI update error: " + ex2));
			}
		}
		try
		{
			AutoChat.Poll();
		}
		catch (Exception ex3)
		{
			if (errAuto++ < 5)
			{
				Log.LogError((object)("Chat+ auto chat update error: " + ex3));
			}
		}
		try
		{
			TickAutomaticMenu();
		}
		catch (Exception ex4)
		{
			if (errMenu++ < 5)
			{
				Log.LogError((object)("Chat+ quick chat update error: " + ex4));
			}
		}
	}

	private static EmoteContext AutomaticContext()
	{
		//IL_0012: Unknown result type (might be due to invalid IL or missing references)
		//IL_0038: Unknown result type (might be due to invalid IL or missing references)
		//IL_003d: Unknown result type (might be due to invalid IL or missing references)
		//IL_003e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0040: Invalid comparison between Unknown and I4
		//IL_002c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0031: Unknown result type (might be due to invalid IL or missing references)
		//IL_0059: Unknown result type (might be due to invalid IL or missing references)
		//IL_0045: Unknown result type (might be due to invalid IL or missing references)
		//IL_0047: Invalid comparison between Unknown and I4
		//IL_006e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0064: Unknown result type (might be due to invalid IL or missing references)
		//IL_004c: Unknown result type (might be due to invalid IL or missing references)
		//IL_004e: Invalid comparison between Unknown and I4
		LobbyManager instance = LobbyManager.instance;
		if ((Object)(object)instance == (Object)null)
		{
			return lastAutomatic;
		}
		GameControl currentGameController = instance.CurrentGameController;
		if ((Object)(object)currentGameController == (Object)null)
		{
			lastAutomatic = (EmoteContext)2;
			return lastAutomatic;
		}
		GamePhase phase = currentGameController.Phase;
		if ((int)phase != 3)
		{
			if ((int)phase == 2 || (int)phase == 4)
			{
				lastAutomatic = (EmoteContext)0;
			}
		}
		else
		{
			lastAutomatic = (EmoteContext)1;
		}
		return lastAutomatic;
	}

	private static void TickAutomaticMenu()
	{
		//IL_0010: Unknown result type (might be due to invalid IL or missing references)
		//IL_0015: Unknown result type (might be due to invalid IL or missing references)
		//IL_0020: Unknown result type (might be due to invalid IL or missing references)
		//IL_0021: Unknown result type (might be due to invalid IL or missing references)
		if (QuickChat.Value == QuickChatMenu.Automatic)
		{
			EmoteContext val = AutomaticContext();
			if (!appliedOnce || val != lastApplied)
			{
				ApplyQuickChatNow();
			}
		}
	}

	internal static EmoteContext MappedContext()
	{
		//IL_0026: Unknown result type (might be due to invalid IL or missing references)
		return (EmoteContext)(QuickChat.Value switch
		{
			QuickChatMenu.Automatic => AutomaticContext(), 
			QuickChatMenu.BuildMode => 1, 
			QuickChatMenu.PlayMode => 0, 
			_ => 2, 
		});
	}

	private static void ApplyQuickChatNow()
	{
		//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)
		//IL_0006: 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_0022: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			EmoteContext emoteContext = (lastApplied = MappedContext());
			appliedOnce = true;
			EmoteSystem[] array = Object.FindObjectsOfType<EmoteSystem>();
			for (int i = 0; i < array.Length; i++)
			{
				array[i].SetEmoteContext(emoteContext);
			}
		}
		catch (Exception ex)
		{
			Log.LogError((object)("Chat+ could not apply quick chat menu: " + ex));
		}
	}
}
[HarmonyPatch(typeof(EmoteSystem), "SetEmoteContext")]
internal static class Patch_SetEmoteContext
{
	private static void Prefix(ref EmoteContext __0)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0007: Expected I4, but got Unknown
		try
		{
			__0 = (EmoteContext)(int)ChatPlusPlugin.MappedContext();
		}
		catch (Exception ex)
		{
			ChatPlusPlugin.Log.LogError((object)("Chat+ SetEmoteContext patch: " + ex));
		}
	}
}
[HarmonyPatch(typeof(LobbyPlayer), "CallCmdSendJoinMessage")]
internal static class Patch_SelfJoin
{
	private static void Postfix()
	{
		try
		{
			AutoChat.OnSelfJoined();
		}
		catch (Exception ex)
		{
			ChatPlusPlugin.Log.LogError((object)("Chat+ self join patch: " + ex));
		}
	}
}
[HarmonyPatch(typeof(ChatDisplay), "DisplayNewMessage")]
internal static class Patch_DisplayNewMessage
{
	private static void Postfix(ChatMessageDetails chatMessageDetails)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			AutoChat.OnChatLine(chatMessageDetails);
		}
		catch (Exception ex)
		{
			ChatPlusPlugin.Log.LogError((object)("Chat+ DisplayNewMessage patch: " + ex));
		}
	}
}
[HarmonyPatch(typeof(Character), "setupDeath")]
internal static class Patch_SetupDeath
{
	private static void Postfix(Character __instance)
	{
		try
		{
			AutoChat.OnCharacterDied(__instance);
		}
		catch (Exception ex)
		{
			ChatPlusPlugin.Log.LogError((object)("Chat+ setupDeath patch: " + ex));
		}
	}
}
[HarmonyPatch(typeof(Character), "RpcSendPlayerSuccessEvent")]
internal static class Patch_PlayerSuccess
{
	private static void Postfix(Character __instance)
	{
		try
		{
			AutoChat.OnCharacterFinished(__instance);
		}
		catch (Exception ex)
		{
			ChatPlusPlugin.Log.LogError((object)("Chat+ success patch: " + ex));
		}
	}
}
[HarmonyPatch(typeof(ChatUnit), "SetChatUnitMessage")]
internal static class Patch_SetChatUnitMessage
{
	private static void Postfix(ChatUnit __instance, ChatMessageDetails chatMessage)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			ChatPlusUI.DecorateUnit(__instance, chatMessage);
		}
		catch (Exception ex)
		{
			ChatPlusPlugin.Log.LogError((object)("Chat+ SetChatUnitMessage patch: " + ex));
		}
	}
}
internal static class AutoChat
{
	private const string TreehouseScene = "TreeHouseLobby";

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

	private static bool inLobby;

	private static float settleUntil;

	private static HashSet<int> known = new HashSet<int>();

	private static readonly Dictionary<string, float> recentlySaid = new Dictionary<string, float>();

	internal static bool InTreehouse()
	{
		//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)).name == "TreeHouseLobby" || LobbyManagerManager.LastSceneLoaded == "TreeHouseLobby")
		{
			return true;
		}
		LobbyManager instance = LobbyManager.instance;
		return (Object)(object)instance != (Object)null && (Object)(object)instance.CurrentLevelSelectController != (Object)null;
	}

	internal static bool IsLocal(int networkNumber)
	{
		return (Object)(object)LobbyManager.instance != (Object)null && LobbyManager.instance.IsLocalNetworkNumber(networkNumber);
	}

	internal static LobbyPlayer LocalLobbyPlayer()
	{
		if ((Object)(object)LobbyManager.instance == (Object)null)
		{
			return null;
		}
		foreach (LobbyPlayer lobbyPlayer in LobbyManager.instance.GetLobbyPlayers())
		{
			if ((Object)(object)lobbyPlayer != (Object)null && lobbyPlayer.Initialized && lobbyPlayer.IsLocalPlayer)
			{
				return lobbyPlayer;
			}
		}
		return null;
	}

	internal static void Poll()
	{
		LobbyManager instance = LobbyManager.instance;
		LobbyPlayer val = ((!((Object)(object)instance != (Object)null)) ? null : LocalLobbyPlayer());
		if ((Object)(object)val == (Object)null)
		{
			inLobby = false;
			known.Clear();
			return;
		}
		if (!inLobby)
		{
			inLobby = true;
			settleUntil = Time.unscaledTime + 3f;
			known.Clear();
			OnSelfJoined();
		}
		HashSet<int> hashSet = new HashSet<int>();
		foreach (LobbyPlayer lobbyPlayer in instance.GetLobbyPlayers())
		{
			if ((Object)(object)lobbyPlayer != (Object)null && lobbyPlayer.Initialized && lobbyPlayer.LocalPlayer == null && !lobbyPlayer.IsLocalPlayer)
			{
				hashSet.Add(lobbyPlayer.networkNumber);
			}
		}
		if (Time.unscaledTime >= settleUntil)
		{
			foreach (int item in hashSet)
			{
				if (!known.Contains(item) && ChatPlusPlugin.AutoHello.Value && InTreehouse())
				{
					ChatPlusPlugin.Log.LogInfo((object)("Chat+: player " + item + " joined (lobby watch), saying hello"));
					Say((EmoteMeanings)17, 0.5f, treehouseOnly: true, item);
				}
			}
		}
		known = hashSet;
	}

	internal static void OnSelfJoined()
	{
		LobbyManager instance = LobbyManager.instance;
		if (!((Object)(object)instance == (Object)null) && !instance.IsHost && ChatPlusPlugin.AutoHello.Value)
		{
			ChatPlusPlugin.Log.LogInfo((object)"Chat+: you joined a lobby, saying hello");
			Say((EmoteMeanings)17, 0.5f, treehouseOnly: false, -1);
		}
	}

	internal static void OnChatLine(ChatMessageDetails d)
	{
		if (!d.isChatMessage && !string.IsNullOrEmpty(d.Message))
		{
			bool flag = d.Message == Network.SomeoneJoined_lobby;
			bool flag2 = d.Message == Network.Someone_left_lobby;
			if ((flag || flag2) && !InTreehouse())
			{
				ChatPlusPlugin.Log.LogInfo((object)"Chat+: join/leave seen but not in the treehouse, ignoring");
			}
			else if (ChatPlusPlugin.AutoHello.Value && d.Message == Network.SomeoneJoined_lobby)
			{
				ChatPlusPlugin.Log.LogInfo((object)"Chat+: someone joined, saying hello");
				Say((EmoteMeanings)17, 0.5f, treehouseOnly: true, d.NetworkNumber);
			}
			else if (ChatPlusPlugin.AutoGoodbye.Value && d.Message == Network.Someone_left_lobby)
			{
				ChatPlusPlugin.Log.LogInfo((object)"Chat+: someone left, saying goodbye");
				Say((EmoteMeanings)12, 0.5f, treehouseOnly: true, d.NetworkNumber);
			}
		}
	}

	internal static void OnCharacterFinished(Character c)
	{
		if (!((Object)(object)c == (Object)null) && ChatPlusPlugin.AutoWellDone.Value && !IsLocal(c.networkNumber))
		{
			ChatPlusPlugin.Log.LogInfo((object)"Chat+: someone finished, saying well done");
			Say((EmoteMeanings)38, 0f, treehouseOnly: false, c.networkNumber);
		}
	}

	internal static void OnCharacterDied(Character c)
	{
		if (!((Object)(object)c == (Object)null) && ChatPlusPlugin.AutoSoClose.Value && !IsLocal(c.networkNumber))
		{
			GamePlayer associatedGamePlayer = c.AssociatedGamePlayer;
			if (!((Object)(object)associatedGamePlayer == (Object)null) && associatedGamePlayer.lives <= 0 && (!lastDeathSaid.TryGetValue(c.networkNumber, out var value) || !(Time.unscaledTime - value < 2f)))
			{
				lastDeathSaid[c.networkNumber] = Time.unscaledTime;
				ChatPlusPlugin.Log.LogInfo((object)"Chat+: someone died on their last life, saying so close");
				Say((EmoteMeanings)31, 0f, treehouseOnly: false, c.networkNumber);
			}
		}
	}

	private static void Say(EmoteMeanings emote, float delay, bool treehouseOnly, int subject)
	{
		//IL_0028: 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)
		ChatPlusPlugin instance = ChatPlusPlugin.Instance;
		if (!((Object)(object)instance == (Object)null))
		{
			if (delay <= 0f)
			{
				TrySend(emote, treehouseOnly, subject);
			}
			else
			{
				((MonoBehaviour)instance).StartCoroutine(SayLater(emote, delay, treehouseOnly, subject));
			}
		}
	}

	private static IEnumerator SayLater(EmoteMeanings emote, float delay, bool treehouseOnly, int subject)
	{
		//IL_000e: Unknown result type (might be due to invalid IL or missing references)
		//IL_000f: Unknown result type (might be due to invalid IL or missing references)
		yield return (object)new WaitForSecondsRealtime(delay);
		TrySend(emote, treehouseOnly, subject);
	}

	private static void TrySend(EmoteMeanings emote, bool treehouseOnly, int subject)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_009e: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a4: Invalid comparison between Unknown and I4
		//IL_012c: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			string key = string.Concat(emote, ":", subject);
			if (recentlySaid.TryGetValue(key, out var value) && Time.unscaledTime - value < 3f)
			{
				return;
			}
			if ((Object)(object)LobbyManager.instance == (Object)null)
			{
				ChatPlusPlugin.Log.LogInfo((object)"Chat+: auto chat skipped (no lobby manager)");
				return;
			}
			if (treehouseOnly && !InTreehouse())
			{
				ChatPlusPlugin.Log.LogInfo((object)"Chat+: auto chat skipped (left the treehouse)");
				return;
			}
			ChatDisplay chatSystem = GameState.ChatSystem;
			if ((Object)(object)chatSystem == (Object)null || (int)GameSettings.GetInstance().OnlineChatEmotes == 2)
			{
				ChatPlusPlugin.Log.LogInfo((object)"Chat+: auto chat skipped (chat is off)");
				return;
			}
			NetworkManager singleton = NetworkManager.singleton;
			if ((Object)(object)singleton == (Object)null || singleton.client == null)
			{
				ChatPlusPlugin.Log.LogInfo((object)"Chat+: auto chat skipped (no network client)");
				return;
			}
			LobbyPlayer val = LocalLobbyPlayer();
			if ((Object)(object)val == (Object)null)
			{
				ChatPlusPlugin.Log.LogInfo((object)"Chat+: auto chat skipped (local player not found)");
				return;
			}
			recentlySaid[key] = Time.unscaledTime;
			chatSystem.NewChatMessage(string.Empty, emote, val.networkNumber);
		}
		catch (Exception ex)
		{
			ChatPlusPlugin.Log.LogError((object)("Chat+ auto chat failed: " + ex));
		}
	}
}
public class MsgChatPlusReaction : MessageBase
{
	public int ReactorNumber;

	public int TargetSpeaker;

	public int Occurrence;

	public int EmojiIndex;

	public string TargetKey;

	public override void Serialize(NetworkWriter writer)
	{
		writer.Write(ReactorNumber);
		writer.Write(TargetSpeaker);
		writer.Write(Occurrence);
		writer.Write(EmojiIndex);
		writer.Write(TargetKey ?? string.Empty);
	}

	public override void Deserialize(NetworkReader reader)
	{
		ReactorNumber = reader.ReadInt32();
		TargetSpeaker = reader.ReadInt32();
		Occurrence = reader.ReadInt32();
		EmojiIndex = reader.ReadInt32();
		TargetKey = reader.ReadString();
	}
}
internal static class ChatPlusNet
{
	internal const short ReactionMsgType = 3100;

	private static NetworkClient registeredClient;

	private static bool serverRegistered;

	internal static void Poll()
	{
		//IL_0027: Unknown result type (might be due to invalid IL or missing references)
		//IL_0031: Expected O, but got Unknown
		//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00aa: Expected O, but got Unknown
		if (NetworkServer.active)
		{
			if (!serverRegistered)
			{
				NetworkServer.RegisterHandler((short)3100, new NetworkMessageDelegate(OnServerMessage));
				serverRegistered = true;
			}
		}
		else
		{
			serverRegistered = false;
		}
		NetworkManager singleton = NetworkManager.singleton;
		NetworkClient val = ((!((Object)(object)singleton != (Object)null)) ? null : singleton.client);
		if (val != null && val.connection != null)
		{
			if (!object.ReferenceEquals(val, registeredClient))
			{
				val.RegisterHandler((short)3100, new NetworkMessageDelegate(OnClientMessage));
				registeredClient = val;
			}
		}
		else
		{
			registeredClient = null;
		}
	}

	private static void OnServerMessage(NetworkMessage netMsg)
	{
		MsgChatPlusReaction msgChatPlusReaction = netMsg.ReadMessage<MsgChatPlusReaction>();
		NetworkServer.SendToAll((short)3100, (MessageBase)(object)msgChatPlusReaction);
	}

	private static void OnClientMessage(NetworkMessage netMsg)
	{
		MsgChatPlusReaction msg = netMsg.ReadMessage<MsgChatPlusReaction>();
		try
		{
			ChatPlusUI.ApplyReaction(msg);
		}
		catch (Exception ex)
		{
			ChatPlusPlugin.Log.LogError((object)("Chat+ could not show reaction: " + ex));
		}
	}

	internal static void SendReaction(MsgChatPlusReaction msg)
	{
		NetworkManager singleton = NetworkManager.singleton;
		if (!((Object)(object)singleton == (Object)null) && singleton.client != null && singleton.client.connection != null)
		{
			singleton.client.Send((short)3100, (MessageBase)(object)msg);
		}
	}
}
internal sealed class ChatPlusUnit : MonoBehaviour
{
	internal ChatUnit Unit;

	internal int Speaker;

	internal string Key;

	internal RectTransform Plus;

	internal Image PlusImage;

	internal CanvasGroup PlusGroup;

	internal readonly Dictionary<int, GameObject> Reactions = new Dictionary<int, GameObject>();

	private void OnDestroy()
	{
		ChatPlusUI.Live.Remove(this);
		if ((Object)(object)ChatPlusUI.Selected == (Object)(object)this)
		{
			ChatPlusUI.Selected = null;
			ChatPlusUI.NoteSelectionLost();
		}
		if ((Object)(object)ChatPlusUI.OpenFor == (Object)(object)this)
		{
			ChatPlusUI.ClosePicker();
		}
	}
}
internal static class ChatPlusUI
{
	internal static readonly List<ChatPlusUnit> Live = new List<ChatPlusUnit>();

	internal static ChatPlusUnit OpenFor;

	internal static ChatPlusUnit Selected;

	private static bool wasChatMode;

	private static bool selectionLost;

	private static int hoverIndex = -1;

	private static Vector2 lastMouse;

	private static string savedText = string.Empty;

	private static int enforceFrames;

	private static GameObject pickerRoot;

	private static RectTransform pickerRect;

	private static readonly List<RectTransform> cellRects = new List<RectTransform>();

	private static readonly List<Image> cellImages = new List<Image>();

	private static readonly Color PlusNormal = new Color(1f, 1f, 1f, 0.2f);

	private static readonly Color PlusSelected = new Color(1f, 0.85f, 0.15f, 0.95f);

	private const int Columns = 5;

	private const int Rows = 2;

	internal static void NoteSelectionLost()
	{
		selectionLost = true;
	}

	private static GameObject NewUI(string name, Transform parent, int layer, params Type[] components)
	{
		//IL_0026: Unknown result type (might be due to invalid IL or missing references)
		//IL_002c: Expected O, but got Unknown
		Type[] array = new Type[components.Length + 1];
		array[0] = typeof(RectTransform);
		Array.Copy(components, 0, array, 1, components.Length);
		GameObject val = new GameObject(name, array);
		val.layer = layer;
		val.transform.SetParent(parent, false);
		return val;
	}

	private static string MakeKey(ChatMessageDetails d)
	{
		//IL_0002: Unknown result type (might be due to invalid IL or missing references)
		//IL_000e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0015: Invalid comparison between Unknown and I4
		//IL_001d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0027: Expected I4, but got Unknown
		bool flag = (int)d.EmoteType == 0 || (int)d.EmoteType == 10;
		return (int)d.EmoteType + "|" + ((!flag) ? string.Empty : d.Message);
	}

	private static bool Contains(RectTransform rt, Vector2 screenPoint)
	{
		//IL_004a: Unknown result type (might be due to invalid IL or missing references)
		//IL_001d: Unknown result type (might be due to invalid IL or missing references)
		Camera val = null;
		Canvas componentInParent = ((Component)rt).GetComponentInParent<Canvas>();
		if ((Object)(object)componentInParent != (Object)null)
		{
			componentInParent = componentInParent.rootCanvas;
			if ((int)componentInParent.renderMode != 0)
			{
				val = ((!((Object)(object)componentInParent.worldCamera != (Object)null)) ? Camera.main : componentInParent.worldCamera);
			}
		}
		return RectTransformUtility.RectangleContainsScreenPoint(rt, screenPoint, val);
	}

	private static void SetHighlight(ChatPlusUnit u, bool on)
	{
		//IL_0034: 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_0063: Unknown result type (might be due to invalid IL or missing references)
		//IL_0059: Unknown result type (might be due to invalid IL or missing references)
		if (!((Object)(object)u == (Object)null) && !((Object)(object)u.PlusImage == (Object)null))
		{
			((Graphic)u.PlusImage).color = ((!on) ? PlusNormal : PlusSelected);
			((Transform)u.Plus).localScale = (Vector3)((!on) ? Vector3.one : new Vector3(1.25f, 1.25f, 1f));
		}
	}

	private static void SelectUnit(ChatPlusUnit u)
	{
		if ((Object)(object)Selected != (Object)null && (Object)(object)Selected != (Object)(object)u)
		{
			SetHighlight(Selected, on: false);
		}
		Selected = u;
		SetHighlight(u, on: true);
	}

	private static List<ChatPlusUnit> Ordered(ChatDisplay chat)
	{
		List<ChatPlusUnit> list = new List<ChatPlusUnit>();
		List<ChatUnit> currentMessages = chat.currentMessages;
		for (int i = 0; i < currentMessages.Count; i++)
		{
			ChatUnit val = currentMessages[i];
			if (!((Object)(object)val == (Object)null))
			{
				ChatPlusUnit component = ((Component)val).GetComponent<ChatPlusUnit>();
				if ((Object)(object)component != (Object)null && (Object)(object)component.Plus != (Object)null)
				{
					list.Add(component);
				}
			}
		}
		return list;
	}

	internal static void DecorateUnit(ChatUnit unit, ChatMessageDetails d)
	{
		//IL_0070: 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_0144: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ae: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ba: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c6: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d2: Unknown result type (might be due to invalid IL or missing references)
		//IL_022c: Unknown result type (might be due to invalid IL or missing references)
		if (!((Object)(object)unit == (Object)null) && d.isChatMessage && !string.IsNullOrEmpty(d.UserName))
		{
			ChatPlusUnit chatPlusUnit = ((Component)unit).GetComponent<ChatPlusUnit>();
			if ((Object)(object)chatPlusUnit == (Object)null)
			{
				chatPlusUnit = ((Component)unit).gameObject.AddComponent<ChatPlusUnit>();
			}
			if (!((Object)(object)chatPlusUnit.Plus != (Object)null))
			{
				chatPlusUnit.Unit = unit;
				chatPlusUnit.Speaker = d.NetworkNumber;
				chatPlusUnit.Key = MakeKey(d);
				int chatMessageFontSize = GameSettings.GetInstance().ChatMessageFontSize;
				int num = Mathf.Max(14, Mathf.RoundToInt((float)chatMessageFontSize * 1.6f));
				int layer = ((Component)unit).gameObject.layer;
				GameObject val = NewUI("ChatPlusButton", ((Component)unit).transform, layer, typeof(Image), typeof(LayoutElement), typeof(CanvasGroup));
				Image component = val.GetComponent<Image>();
				((Graphic)component).color = PlusNormal;
				LayoutElement component2 = val.GetComponent<LayoutElement>();
				component2.minWidth = num;
				component2.preferredWidth = num;
				component2.minHeight = num;
				component2.preferredHeight = num;
				component2.flexibleWidth = 0f;
				RectTransform component3 = val.GetComponent<RectTransform>();
				component3.sizeDelta = new Vector2((float)num, (float)num);
				CanvasGroup component4 = val.GetComponent<CanvasGroup>();
				component4.alpha = ((!PlusVisible(ChatIsOpen())) ? 0f : 1f);
				GameObject val2 = NewUI("Plus", val.transform, layer, typeof(Text));
				RectTransform component5 = val2.GetComponent<RectTransform>();
				component5.anchorMin = Vector2.zero;
				component5.anchorMax = Vector2.one;
				component5.offsetMin = Vector2.zero;
				component5.offsetMax = Vector2.zero;
				Text component6 = val2.GetComponent<Text>();
				component6.text = "+";
				component6.font = ((!((Object)(object)unit.chatText != (Object)null)) ? null : unit.chatText.font);
				component6.fontSize = chatMessageFontSize;
				component6.alignment = (TextAnchor)4;
				((Graphic)component6).color = Color.white;
				((Graphic)component6).raycastTarget = false;
				component6.horizontalOverflow = (HorizontalWrapMode)1;
				component6.verticalOverflow = (VerticalWrapMode)1;
				val.transform.SetAsLastSibling();
				chatPlusUnit.Plus = component3;
				chatPlusUnit.PlusImage = component;
				chatPlusUnit.PlusGroup = component4;
				Live.Add(chatPlusUnit);
			}
		}
	}

	private static bool PlusVisible(bool chatOpen)
	{
		return chatOpen || ChatPlusPlugin.PlusMode.Value == PlusButtonMode.Always;
	}

	private static bool ChatIsOpen()
	{
		ChatDisplay chatSystem = GameState.ChatSystem;
		return (Object)(object)chatSystem != (Object)null && chatSystem.ChatMode;
	}

	private static void BuildPicker(Canvas rootCanvas, int layer)
	{
		//IL_0061: Unknown result type (might be due to invalid IL or missing references)
		//IL_0089: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
		//IL_0171: Unknown result type (might be due to invalid IL or missing references)
		//IL_0190: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a6: Unknown result type (might be due to invalid IL or missing references)
		//IL_01bc: Unknown result type (might be due to invalid IL or missing references)
		//IL_01cc: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f7: Unknown result type (might be due to invalid IL or missing references)
		int chatMessageFontSize = GameSettings.GetInstance().ChatMessageFontSize;
		int num = Mathf.Max(36, chatMessageFontSize * 2);
		int num2 = 6;
		int num3 = 4;
		pickerRoot = NewUI("ChatPlusPicker", ((Component)rootCanvas).transform, layer, typeof(Image));
		((Graphic)pickerRoot.GetComponent<Image>()).color = new Color(0.07f, 0.07f, 0.1f, 0.93f);
		pickerRect = pickerRoot.GetComponent<RectTransform>();
		pickerRect.anchorMin = new Vector2(0.5f, 0.5f);
		pickerRect.anchorMax = new Vector2(0.5f, 0.5f);
		pickerRect.pivot = new Vector2(0f, 1f);
		pickerRect.sizeDelta = new Vector2((float)(num2 * 2 + 5 * num + 4 * num3), (float)(num2 * 2 + 2 * num + num3));
		cellRects.Clear();
		cellImages.Clear();
		for (int i = 0; i < 10; i++)
		{
			GameObject val = NewUI("Face" + i, pickerRoot.transform, layer, typeof(Image));
			Image component = val.GetComponent<Image>();
			component.sprite = Faces.Get(i);
			component.preserveAspect = true;
			((Graphic)component).color = new Color(0.7f, 0.7f, 0.7f, 1f);
			RectTransform component2 = val.GetComponent<RectTransform>();
			component2.anchorMin = new Vector2(0f, 1f);
			component2.anchorMax = new Vector2(0f, 1f);
			component2.pivot = new Vector2(0f, 1f);
			component2.sizeDelta = new Vector2((float)num, (float)num);
			int num4 = i % 5;
			int num5 = i / 5;
			component2.anchoredPosition = new Vector2((float)(num2 + num4 * (num + num3)), (float)(-(num2 + num5 * (num + num3))));
			cellRects.Add(component2);
			cellImages.Add(component);
		}
	}

	private static void OpenPicker(ChatPlusUnit unit, bool byKeyboard)
	{
		//IL_0094: Unknown result type (might be due to invalid IL or missing references)
		//IL_0099: Unknown result type (might be due to invalid IL or missing references)
		//IL_009e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0103: Unknown result type (might be due to invalid IL or missing references)
		//IL_012f: Unknown result type (might be due to invalid IL or missing references)
		//IL_013b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0140: Unknown result type (might be due to invalid IL or missing references)
		//IL_024c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0251: Unknown result type (might be due to invalid IL or missing references)
		//IL_0253: Unknown result type (might be due to invalid IL or missing references)
		ChatDisplay chatSystem = GameState.ChatSystem;
		Canvas componentInParent = ((Component)chatSystem.ChatHolder).GetComponentInParent<Canvas>();
		if (!((Object)(object)componentInParent == (Object)null))
		{
			componentInParent = componentInParent.rootCanvas;
			if ((Object)(object)pickerRoot == (Object)null)
			{
				BuildPicker(componentInParent, ((Component)chatSystem.ChatHolder).gameObject.layer);
			}
			pickerRoot.transform.SetParent(((Component)componentInParent).transform, false);
			pickerRoot.SetActive(true);
			pickerRoot.transform.SetAsLastSibling();
			OpenFor = unit;
			hoverIndex = ((!byKeyboard) ? (-1) : 0);
			lastMouse = Vector2.op_Implicit(Input.mousePosition);
			InputField val = InputBox();
			string text = ((!((Object)(object)val != (Object)null)) ? string.Empty : val.text);
			savedText = ((!string.IsNullOrWhiteSpace(text)) ? text : string.Empty);
			Vector3[] array = (Vector3[])(object)new Vector3[4];
			unit.Plus.GetWorldCorners(array);
			((Transform)pickerRect).position = array[0];
			Vector3[] array2 = (Vector3[])(object)new Vector3[4];
			Vector3[] array3 = (Vector3[])(object)new Vector3[4];
			pickerRect.GetWorldCorners(array2);
			((RectTransform)((Component)componentInParent).transform).GetWorldCorners(array3);
			Vector3 zero = Vector3.zero;
			if (array2[2].x > array3[2].x)
			{
				zero.x = array3[2].x - array2[2].x;
			}
			if (array2[0].x < array3[0].x)
			{
				zero.x = array3[0].x - array2[0].x;
			}
			if (array2[0].y < array3[0].y)
			{
				zero.y = array3[0].y - array2[0].y;
			}
			if (array2[1].y > array3[1].y)
			{
				zero.y = array3[1].y - array2[1].y;
			}
			RectTransform obj = pickerRect;
			((Transform)obj).position = ((Transform)obj).position + zero;
			ApplyHover();
		}
	}

	internal static void ClosePicker()
	{
		bool flag = (Object)(object)pickerRoot != (Object)null && pickerRoot.activeSelf;
		if ((Object)(object)pickerRoot != (Object)null)
		{
			pickerRoot.SetActive(false);
		}
		OpenFor = null;
		hoverIndex = -1;
		if (flag)
		{
			enforceFrames = 3;
		}
	}

	private static InputField InputBox()
	{
		ChatDisplay chatSystem = GameState.ChatSystem;
		if ((Object)(object)chatSystem == (Object)null || (Object)(object)chatSystem.currentChatInputField == (Object)null)
		{
			return null;
		}
		return chatSystem.currentChatInputField.inputField;
	}

	private static int HitCell(Vector2 mp)
	{
		//IL_0028: Unknown result type (might be due to invalid IL or missing references)
		for (int i = 0; i < cellRects.Count; i++)
		{
			if ((Object)(object)cellRects[i] != (Object)null && Contains(cellRects[i], mp))
			{
				return i;
			}
		}
		return -1;
	}

	private static void ApplyHover()
	{
		//IL_0039: 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)
		//IL_0063: Unknown result type (might be due to invalid IL or missing references)
		for (int i = 0; i < cellImages.Count; i++)
		{
			bool flag = i == hoverIndex;
			float num = ((!flag) ? 0.7f : 1f);
			((Graphic)cellImages[i]).color = new Color(num, num, num, 1f);
			((Transform)cellRects[i]).localScale = (Vector3)((!flag) ? Vector3.one : new Vector3(1.2f, 1.2f, 1f));
		}
	}

	internal static void Tick()
	{
		//IL_020a: Unknown result type (might be due to invalid IL or missing references)
		//IL_020f: 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_021d: Unknown result type (might be due to invalid IL or missing references)
		//IL_021f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0224: Unknown result type (might be due to invalid IL or missing references)
		//IL_0229: Unknown result type (might be due to invalid IL or missing references)
		//IL_023b: Unknown result type (might be due to invalid IL or missing references)
		//IL_023d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0249: Unknown result type (might be due to invalid IL or missing references)
		//IL_0468: Unknown result type (might be due to invalid IL or missing references)
		//IL_0486: Unknown result type (might be due to invalid IL or missing references)
		//IL_0525: Unknown result type (might be due to invalid IL or missing references)
		ChatDisplay chatSystem = GameState.ChatSystem;
		if ((Object)(object)chatSystem == (Object)null || (Object)(object)chatSystem.ChatHolder == (Object)null)
		{
			return;
		}
		bool chatMode = chatSystem.ChatMode;
		if (chatMode != wasChatMode)
		{
			wasChatMode = chatMode;
			if (chatMode)
			{
				List<ChatPlusUnit> list = Ordered(chatSystem);
				selectionLost = false;
				SelectUnit((list.Count <= 0) ? null : list[list.Count - 1]);
			}
			else
			{
				ClosePicker();
				SelectUnit(null);
			}
		}
		for (int num = Live.Count - 1; num >= 0; num--)
		{
			ChatPlusUnit chatPlusUnit = Live[num];
			if ((Object)(object)chatPlusUnit == (Object)null)
			{
				Live.RemoveAt(num);
			}
			else if ((Object)(object)chatPlusUnit.PlusGroup != (Object)null)
			{
				chatPlusUnit.PlusGroup.alpha = ((!PlusVisible(chatMode)) ? 0f : 1f);
			}
		}
		InputField val = InputBox();
		bool flag = (Object)(object)pickerRoot != (Object)null && pickerRoot.activeSelf;
		if ((Object)(object)val != (Object)null && (flag || enforceFrames > 0))
		{
			if (val.text != savedText)
			{
				val.text = savedText;
				val.caretPosition = savedText.Length;
			}
			if (!flag)
			{
				enforceFrames--;
			}
		}
		if (!chatMode)
		{
			return;
		}
		List<ChatPlusUnit> list2 = Ordered(chatSystem);
		if ((Object)(object)Selected == (Object)null && list2.Count > 0)
		{
			SelectUnit((!selectionLost) ? list2[list2.Count - 1] : list2[0]);
			selectionLost = false;
		}
		bool flag2 = Input.GetKey((KeyCode)304) || Input.GetKey((KeyCode)303);
		Vector2 val2 = Vector2.op_Implicit(Input.mousePosition);
		if (flag)
		{
			Vector2 val3 = val2 - lastMouse;
			bool flag3 = ((Vector2)(ref val3)).sqrMagnitude > 1f;
			lastMouse = val2;
			if (flag3)
			{
				int num2 = HitCell(val2);
				if (num2 >= 0)
				{
					hoverIndex = num2;
				}
			}
			int num3 = ((hoverIndex >= 0) ? hoverIndex : 0);
			if (Input.GetKeyDown((KeyCode)9))
			{
				hoverIndex = (num3 + ((!flag2) ? 1 : 9)) % 10;
			}
			else if (Input.GetKeyDown((KeyCode)275))
			{
				hoverIndex = Mathf.Min(num3 + 1, 9);
			}
			else if (Input.GetKeyDown((KeyCode)276))
			{
				hoverIndex = Mathf.Max(num3 - 1, 0);
			}
			else if (Input.GetKeyDown((KeyCode)274))
			{
				hoverIndex = ((num3 + 5 >= 10) ? num3 : (num3 + 5));
			}
			else if (Input.GetKeyDown((KeyCode)273))
			{
				hoverIndex = ((num3 - 5 < 0) ? num3 : (num3 - 5));
			}
			else
			{
				if (Input.GetKeyDown((KeyCode)32))
				{
					Choose(num3);
					return;
				}
				if (Input.GetKeyDown((KeyCode)8))
				{
					ClosePicker();
					return;
				}
			}
			ApplyHover();
		}
		else if (Input.GetKeyDown((KeyCode)9) && list2.Count > 0)
		{
			int num4 = ((!((Object)(object)Selected != (Object)null)) ? (-1) : list2.IndexOf(Selected));
			int index = ((num4 < 0) ? (list2.Count - 1) : ((!flag2) ? ((num4 + 1) % list2.Count) : ((num4 - 1 + list2.Count) % list2.Count)));
			SelectUnit(list2[index]);
		}
		else if (Input.GetKeyDown((KeyCode)32) && (Object)(object)Selected != (Object)null && (Object)(object)val != (Object)null && string.IsNullOrWhiteSpace(val.text))
		{
			OpenPicker(Selected, byKeyboard: true);
			return;
		}
		if (!Input.GetMouseButtonDown(0))
		{
			return;
		}
		if (flag)
		{
			int num5 = HitCell(val2);
			if (num5 >= 0)
			{
				Choose(num5);
				return;
			}
			bool flag4 = Contains(pickerRect, val2);
			ClosePicker();
			if (flag4)
			{
				return;
			}
		}
		if ((Object)(object)chatSystem.ChatCanvasGroup != (Object)null && chatSystem.ChatCanvasGroup.alpha < 0.4f)
		{
			return;
		}
		for (int num6 = Live.Count - 1; num6 >= 0; num6--)
		{
			ChatPlusUnit chatPlusUnit2 = Live[num6];
			if (!((Object)(object)chatPlusUnit2 == (Object)null) && !((Object)(object)chatPlusUnit2.Plus == (Object)null) && ((Component)chatPlusUnit2.Plus).gameObject.activeInHierarchy && Contains(chatPlusUnit2.Plus, val2))
			{
				SelectUnit(chatPlusUnit2);
				OpenPicker(chatPlusUnit2, byKeyboard: false);
				break;
			}
		}
	}

	private static void Choose(int emojiIndex)
	{
		ChatPlusUnit openFor = OpenFor;
		ClosePicker();
		if ((Object)(object)openFor == (Object)null || (Object)(object)openFor.Unit == (Object)null)
		{
			return;
		}
		LobbyPlayer val = AutoChat.LocalLobbyPlayer();
		ChatDisplay chatSystem = GameState.ChatSystem;
		if ((Object)(object)val == (Object)null || (Object)(object)chatSystem == (Object)null)
		{
			return;
		}
		int num = 0;
		List<ChatUnit> currentMessages = chatSystem.currentMessages;
		for (int num2 = currentMessages.Count - 1; num2 >= 0; num2--)
		{
			ChatUnit val2 = currentMessages[num2];
			if (!((Object)(object)val2 == (Object)null))
			{
				if ((Object)(object)val2 == (Object)(object)openFor.Unit)
				{
					break;
				}
				ChatPlusUnit component = ((Component)val2).GetComponent<ChatPlusUnit>();
				if ((Object)(object)component != (Object)null && component.Speaker == openFor.Speaker && component.Key == openFor.Key)
				{
					num++;
				}
			}
		}
		MsgChatPlusReaction msgChatPlusReaction = new MsgChatPlusReaction();
		msgChatPlusReaction.ReactorNumber = val.networkNumber;
		msgChatPlusReaction.TargetSpeaker = openFor.Speaker;
		msgChatPlusReaction.Occurrence = num;
		msgChatPlusReaction.EmojiIndex = emojiIndex;
		msgChatPlusReaction.TargetKey = openFor.Key;
		ChatPlusNet.SendReaction(msgChatPlusReaction);
	}

	internal static void ApplyReaction(MsgChatPlusReaction msg)
	{
		//IL_0025: Unknown result type (might be due to invalid IL or missing references)
		//IL_002b: Invalid comparison between Unknown and I4
		//IL_013d: Unknown result type (might be due to invalid IL or missing references)
		if (msg == null || msg.EmojiIndex < 0 || msg.EmojiIndex >= 10 || (int)GameSettings.GetInstance().OnlineChatEmotes == 2)
		{
			return;
		}
		LobbyManager instance = LobbyManager.instance;
		ChatDisplay chatSystem = GameState.ChatSystem;
		if ((Object)(object)instance == (Object)null || (Object)(object)chatSystem == (Object)null)
		{
			return;
		}
		LobbyPlayer lobbyPlayer = instance.GetLobbyPlayer(msg.ReactorNumber);
		if ((Object)(object)lobbyPlayer == (Object)null || lobbyPlayer.Muted)
		{
			return;
		}
		ChatPlusUnit chatPlusUnit = null;
		int num = 0;
		List<ChatUnit> currentMessages = chatSystem.currentMessages;
		for (int num2 = currentMessages.Count - 1; num2 >= 0; num2--)
		{
			ChatUnit val = currentMessages[num2];
			if (!((Object)(object)val == (Object)null))
			{
				ChatPlusUnit component = ((Component)val).GetComponent<ChatPlusUnit>();
				if (!((Object)(object)component == (Object)null) && component.Speaker == msg.TargetSpeaker && !(component.Key != msg.TargetKey))
				{
					if (num == msg.Occurrence)
					{
						chatPlusUnit = component;
						break;
					}
					num++;
				}
			}
		}
		if (!((Object)(object)chatPlusUnit == (Object)null))
		{
			AddReaction(chatPlusUnit, msg.ReactorNumber, lobbyPlayer.playerName, lobbyPlayer.PlayerColor, msg.EmojiIndex);
		}
	}

	private static void AddReaction(ChatPlusUnit cpu, int reactorNumber, string reactorName, Color reactorColor, int emojiIndex)
	{
		//IL_01d8: Unknown result type (might be due to invalid IL or missing references)
		//IL_023f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0249: Expected O, but got Unknown
		if (cpu.Reactions.TryGetValue(reactorNumber, out var value) && (Object)(object)value != (Object)null)
		{
			Object.Destroy((Object)(object)value);
		}
		ChatUnit unit = cpu.Unit;
		int chatMessageFontSize = GameSettings.GetInstance().ChatMessageFontSize;
		int num = Mathf.Max(14, Mathf.RoundToInt((float)chatMessageFontSize * 1.6f));
		int layer = ((Component)unit).gameObject.layer;
		GameObject val = NewUI("ChatPlusReaction", ((Component)unit).transform, layer, typeof(HorizontalLayoutGroup), typeof(ContentSizeFitter));
		HorizontalLayoutGroup component = val.GetComponent<HorizontalLayoutGroup>();
		((HorizontalOrVerticalLayoutGroup)component).spacing = 3f;
		((LayoutGroup)component).childAlignment = (TextAnchor)3;
		((HorizontalOrVerticalLayoutGroup)component).childControlWidth = true;
		((HorizontalOrVerticalLayoutGroup)component).childControlHeight = true;
		((HorizontalOrVerticalLayoutGroup)component).childForceExpandWidth = false;
		((HorizontalOrVerticalLayoutGroup)component).childForceExpandHeight = false;
		ContentSizeFitter component2 = val.GetComponent<ContentSizeFitter>();
		component2.horizontalFit = (FitMode)2;
		component2.verticalFit = (FitMode)2;
		GameObject val2 = NewUI("Face", val.transform, layer, typeof(Image), typeof(LayoutElement));
		Image component3 = val2.GetComponent<Image>();
		component3.sprite = Faces.Get(emojiIndex);
		component3.preserveAspect = true;
		((Graphic)component3).raycastTarget = false;
		LayoutElement component4 = val2.GetComponent<LayoutElement>();
		component4.minWidth = num;
		component4.preferredWidth = num;
		component4.minHeight = num;
		component4.preferredHeight = num;
		GameObject val3 = NewUI("Name", val.transform, layer, typeof(Text));
		Text component5 = val3.GetComponent<Text>();
		component5.text = reactorName;
		component5.font = ((!((Object)(object)unit.chatText != (Object)null)) ? null : unit.chatText.font);
		component5.fontSize = chatMessageFontSize;
		((Graphic)component5).color = reactorColor;
		component5.alignment = (TextAnchor)3;
		((Graphic)component5).raycastTarget = false;
		component5.horizontalOverflow = (HorizontalWrapMode)1;
		component5.verticalOverflow = (VerticalWrapMode)1;
		val.transform.SetAsLastSibling();
		cpu.Reactions[reactorNumber] = val;
		RectTransform component6 = ((Component)unit).GetComponent<RectTransform>();
		LayoutRebuilder.MarkLayoutForRebuild(component6);
		if (((Transform)component6).parent is RectTransform)
		{
			LayoutRebuilder.MarkLayoutForRebuild((RectTransform)((Transform)component6).parent);
		}
	}
}
internal static class Faces
{
	internal const int Count = 10;

	private static Sprite[] sprites;

	internal static Sprite Get(int index)
	{
		if (sprites == null)
		{
			sprites = (Sprite[])(object)new Sprite[10];
			for (int i = 0; i < 10; i++)
			{
				sprites[i] = MakeFace(i);
			}
		}
		return sprites[Mathf.Clamp(index, 0, 9)];
	}

	private static Sprite MakeFace(int i)
	{
		//IL_004a: Unknown result type (might be due to invalid IL or missing references)
		//IL_004f: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f7: 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_0153: Unknown result type (might be due to invalid IL or missing references)
		//IL_0178: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c7: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e2: Unknown result type (might be due to invalid IL or missing references)
		//IL_020c: Unknown result type (might be due to invalid IL or missing references)
		//IL_022b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0247: Unknown result type (might be due to invalid IL or missing references)
		//IL_0263: Unknown result type (might be due to invalid IL or missing references)
		//IL_027a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0291: Unknown result type (might be due to invalid IL or missing references)
		//IL_02a7: Unknown result type (might be due to invalid IL or missing references)
		//IL_02c7: Unknown result type (might be due to invalid IL or missing references)
		//IL_02e7: Unknown result type (might be due to invalid IL or missing references)
		//IL_0302: Unknown result type (might be due to invalid IL or missing references)
		//IL_031d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0333: Unknown result type (might be due to invalid IL or missing references)
		//IL_0353: 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_0398: Unknown result type (might be due to invalid IL or missing references)
		//IL_03b3: Unknown result type (might be due to invalid IL or missing references)
		//IL_03d9: Unknown result type (might be due to invalid IL or missing references)
		//IL_03f9: Unknown result type (might be due to invalid IL or missing references)
		//IL_040f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0425: Unknown result type (might be due to invalid IL or missing references)
		//IL_044a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0465: Unknown result type (might be due to invalid IL or missing references)
		//IL_047c: Unknown result type (might be due to invalid IL or missing references)
		//IL_04a2: Unknown result type (might be due to invalid IL or missing references)
		//IL_04bd: Unknown result type (might be due to invalid IL or missing references)
		//IL_04d3: Unknown result type (might be due to invalid IL or missing references)
		//IL_04f3: Unknown result type (might be due to invalid IL or missing references)
		//IL_0513: Unknown result type (might be due to invalid IL or missing references)
		//IL_0533: Unknown result type (might be due to invalid IL or missing references)
		//IL_0549: 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_0592: 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_05cf: Unknown result type (might be due to invalid IL or missing references)
		//IL_0604: Unknown result type (might be due to invalid IL or missing references)
		//IL_062d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0657: Unknown result type (might be due to invalid IL or missing references)
		//IL_066d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0692: Unknown result type (might be due to invalid IL or missing references)
		//IL_0767: Unknown result type (might be due to invalid IL or missing references)
		//IL_0776: Unknown result type (might be due to invalid IL or missing references)
		//IL_06bc: Unknown result type (might be due to invalid IL or missing references)
		//IL_06e1: 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_0718: Unknown result type (might be due to invalid IL or missing references)
		//IL_073e: Unknown result type (might be due to invalid IL or missing references)
		Painter painter = new Painter(64);
		Color val = default(Color);
		((Color)(ref val))..ctor(1f, 0.83f, 0.22f);
		Color c = default(Color);
		((Color)(ref c))..ctor(0.35f, 0.2f, 0.05f);
		Color c2 = default(Color);
		((Color)(ref c2))..ctor(0.22f, 0.12f, 0.05f);
		Color white = Color.white;
		Color c3 = default(Color);
		((Color)(ref c3))..ctor(0.35f, 0.7f, 1f);
		Color c4 = default(Color);
		((Color)(ref c4))..ctor(0.9f, 0.1f, 0.2f);
		Color c5 = default(Color);
		((Color)(ref c5))..ctor(1f, 0.45f, 0.5f, 0.75f);
		Color c6 = default(Color);
		((Color)(ref c6))..ctor(0.06f, 0.06f, 0.08f);
		Color c7 = (Color)((i != 4) ? val : new Color(0.96f, 0.36f, 0.2f));
		painter.Circle(32f, 32f, 30.5f, c);
		painter.Circle(32f, 32f, 28f, c7);
		switch (i)
		{
		case 0:
			painter.Circle(22f, 40f, 3.6f, c2);
			painter.Circle(42f, 40f, 3.6f, c2);
			painter.Arc(32f, 36f, 16f, 205f, 335f, 3.2f, c2);
			break;
		case 1:
			painter.Arc(21f, 40f, 5.5f, 25f, 155f, 3f, c2);
			painter.Arc(43f, 40f, 5.5f, 25f, 155f, 3f, c2);
			painter.Ellipse(32f, 25f, 13f, 9f, c2);
			painter.Ellipse(32f, 19.5f, 7f, 4f, new Color(0.95f, 0.4f, 0.45f));
			painter.Ellipse(12f, 32f, 3f, 4.5f, c3);
			painter.Ellipse(52f, 32f, 3f, 4.5f, c3);
			break;
		case 2:
			painter.Circle(22f, 41f, 5.5f, white);
			painter.Circle(42f, 41f, 5.5f, white);
			painter.Circle(22f, 41f, 2.6f, c2);
			painter.Circle(42f, 41f, 2.6f, c2);
			painter.Line(15f, 51f, 28f, 53f, 2.6f, c2);
			painter.Line(36f, 53f, 49f, 51f, 2.6f, c2);
			painter.Ellipse(32f, 19f, 5.5f, 8f, c2);
			break;
		case 3:
			painter.Circle(22f, 38f, 3.3f, c2);
			painter.Circle(42f, 38f, 3.3f, c2);
			painter.Line(15f, 45f, 27f, 49f, 2.6f, c2);
			painter.Line(49f, 45f, 37f, 49f, 2.6f, c2);
			painter.Arc(32f, 14f, 13f, 45f, 135f, 3f, c2);
			painter.Ellipse(21f, 30f, 2.6f, 4f, c3);
			break;
		case 4:
			painter.Line(14f, 48f, 28f, 41f, 3.4f, c2);
			painter.Line(50f, 48f, 36f, 41f, 3.4f, c2);
			painter.Circle(22f, 36f, 3.3f, c2);
			painter.Circle(42f, 36f, 3.3f, c2);
			painter.Arc(32f, 12f, 13f, 50f, 130f, 3.2f, c2);
			break;
		case 5:
			painter.Heart(22f, 40f, 3.6f, c4);
			painter.Heart(42f, 40f, 3.6f, c4);
			painter.Arc(32f, 36f, 16f, 205f, 335f, 3.2f, c2);
			break;
		case 6:
			painter.Circle(22f, 39f, 3.2f, c2);
			painter.Circle(42f, 39f, 3.2f, c2);
			painter.Line(15f, 45f, 28f, 46.5f, 2.4f, c2);
			painter.Line(36f, 50f, 49f, 48f, 2.4f, c2);
			painter.Line(22f, 24f, 38f, 27f, 3f, c2);
			painter.Circle(44f, 14f, 8.5f, c);
			painter.Circle(44f, 14f, 7f, new Color(1f, 0.7f, 0.2f));
			break;
		case 7:
			painter.Ellipse(21f, 40f, 9f, 6.5f, c6);
			painter.Ellipse(43f, 40f, 9f, 6.5f, c6);
			painter.Line(29f, 41f, 35f, 41f, 2.4f, c6);
			painter.Line(17f, 43f, 21f, 43f, 1.6f, new Color(1f, 1f, 1f, 0.5f));
			painter.Arc(32f, 34f, 16f, 205f, 335f, 3.2f, c2);
			break;
		case 8:
			painter.Arc(21f, 40f, 5.5f, 25f, 155f, 3f, c2);
			painter.Circle(43f, 40f, 3.6f, c2);
			painter.Arc(32f, 36f, 16f, 205f, 335f, 3.2f, c2);
			break;
		default:
			painter.Arc(21f, 40f, 5.5f, 25f, 155f, 3f, c2);
			painter.Arc(43f, 40f, 5.5f, 25f, 155f, 3f, c2);
			painter.Ellipse(14f, 29f, 5.5f, 3.2f, c5);
			painter.Ellipse(50f, 29f, 5.5f, 3.2f, c5);
			painter.Arc(32f, 33f, 11f, 210f, 330f, 3f, c2);
			break;
		}
		Texture2D val2 = painter.ToTexture();
		return Sprite.Create(val2, new Rect(0f, 0f, 64f, 64f), new Vector2(0.5f, 0.5f), 100f);
	}
}
internal sealed class Painter
{
	private readonly int size;

	private readonly Color[] px;

	internal Painter(int size)
	{
		this.size = size;
		px = (Color[])(object)new Color[size * size];
	}

	internal Texture2D ToTexture()
	{
		//IL_000e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0014: Expected O, but got Unknown
		Texture2D val = new Texture2D(size, size, (TextureFormat)4, false);
		val.SetPixels(px);
		((Texture)val).filterMode = (FilterMode)1;
		((Texture)val).wrapMode = (TextureWrapMode)1;
		val.Apply();
		return val;
	}

	private void Blend(int x, int y, Color c, float coverage)
	{
		//IL_0035: Unknown result type (might be due to invalid IL or missing references)
		//IL_003a: 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)
		//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
		coverage = Mathf.Clamp01(coverage) * c.a;
		if (!(coverage <= 0f))
		{
			int num = y * size + x;
			Color val = px[num];
			float num2 = coverage + val.a * (1f - coverage);
			if (!(num2 <= 0f))
			{
				ref Color reference = ref px[num];
				reference = new Color((c.r * coverage + val.r * val.a * (1f - coverage)) / num2, (c.g * coverage + val.g * val.a * (1f - coverage)) / num2, (c.b * coverage + val.b * val.a * (1f - coverage)) / num2, num2);
			}
		}
	}

	private void Fill(float minX, float minY, float maxX, float maxY, Func<float, float, float> signedDistance, Color c)
	{
		//IL_007f: Unknown result type (might be due to invalid IL or missing references)
		int num = Mathf.Max(0, Mathf.FloorToInt(minX));
		int num2 = Mathf.Max(0, Mathf.FloorToInt(minY));
		int num3 = Mathf.Min(size - 1, Mathf.CeilToInt(maxX));
		int num4 = Mathf.Min(size - 1, Mathf.CeilToInt(maxY));
		for (int i = num2; i <= num4; i++)
		{
			for (int j = num; j <= num3; j++)
			{
				float num5 = signedDistance((float)j + 0.5f, (float)i + 0.5f);
				if (num5 > -0.5f)
				{
					Blend(j, i, c, num5 + 0.5f);
				}
			}
		}
	}

	internal void Circle(float cx, float cy, float r, Color c)
	{
		//IL_0074: Unknown result type (might be due to invalid IL or missing references)
		Fill(cx - r - 1f, cy - r - 1f, cx + r + 1f, cy + r + 1f, (float x, float y) => r - Mathf.Sqrt((x - cx) * (x - cx) + (y - cy) * (y - cy)), c);
	}

	internal void Ellipse(float cx, float cy, float rx, float ry, Color c)
	{
		//IL_0093: Unknown result type (might be due to invalid IL or missing references)
		float m = Mathf.Min(rx, ry);
		Fill(cx - rx - 1f, cy - ry - 1f, cx + rx + 1f, cy + ry + 1f, delegate(float x, float y)
		{
			float num = (x - cx) / rx;
			float num2 = (y - cy) / ry;
			return (1f - Mathf.Sqrt(num * num + num2 * num2)) * m;
		}, c);
	}

	internal void Line(float x0, float y0, float x1, float y1, float thickness, Color c)
	{
		//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
		float h = thickness * 0.5f;
		Fill(Mathf.Min(x0, x1) - h - 1f, Mathf.Min(y0, y1) - h - 1f, Mathf.Max(x0, x1) + h + 1f, Mathf.Max(y0, y1) + h + 1f, (float num, float py) => h - DistToSegment(num, py, x0, y0, x1, y1), c);
	}

	internal void Arc(float cx, float cy, float r, float a0, float a1, float thickness, Color c)
	{
		//IL_0142: Unknown result type (might be due to invalid IL or missing references)
		float h = thickness * 0.5f;
		float e0x = cx + r * Mathf.Cos(a0 * ((float)Math.PI / 180f));
		float e0y = cy + r * Mathf.Sin(a0 * ((float)Math.PI / 180f));
		float e1x = cx + r * Mathf.Cos(a1 * ((float)Math.PI / 180f));
		float e1y = cy + r * Mathf.Sin(a1 * ((float)Math.PI / 180f));
		Fill(cx - r - h - 1f, cy - r - h - 1f, cx + r + h + 1f, cy + r + h + 1f, delegate(float x, float y)
		{
			float num = x - cx;
			float num2 = y - cy;
			float num3 = Mathf.Atan2(num2, num) * 57.29578f;
			if (num3 < 0f)
			{
				num3 += 360f;
			}
			if (num3 >= a0 && num3 <= a1)
			{
				return h - Mathf.Abs(Mathf.Sqrt(num * num + num2 * num2) - r);
			}
			float num4 = Mathf.Sqrt((x - e0x) * (x - e0x) + (y - e0y) * (y - e0y));
			float num5 = Mathf.Sqrt((x - e1x) * (x - e1x) + (y - e1y) * (y - e1y));
			return h - Mathf.Min(num4, num5);
		}, c);
	}

	internal void Heart(float cx, float cy, float s, Color c)
	{
		//IL_011a: Unknown result type (might be due to invalid IL or missing references)
		int num = Mathf.Max(0, Mathf.FloorToInt(cx - s * 1.6f));
		int num2 = Mathf.Min(size - 1, Mathf.CeilToInt(cx + s * 1.6f));
		int num3 = Mathf.Max(0, Mathf.FloorToInt(cy - s * 1.4f));
		int num4 = Mathf.Min(size - 1, Mathf.CeilToInt(cy + s * 1.6f));
		for (int i = num3; i <= num4; i++)
		{
			for (int j = num; j <= num2; j++)
			{
				int num5 = 0;
				for (int k = 0; k < 3; k++)
				{
					for (int l = 0; l < 3; l++)
					{
						float num6 = ((float)j + ((float)l + 0.5f) / 3f - cx) / s;
						float num7 = ((float)i + ((float)k + 0.5f) / 3f - cy) / s;
						float num8 = num6 * num6 + num7 * num7 - 1f;
						if (num8 * num8 * num8 - num6 * num6 * num7 * num7 * num7 <= 0f)
						{
							num5++;
						}
					}
				}
				if (num5 > 0)
				{
					Blend(j, i, c, (float)num5 / 9f);
				}
			}
		}
	}

	private static float DistToSegment(float px, float py, float ax, float ay, float bx, float by)
	{
		float num = bx - ax;
		float num2 = by - ay;
		float num3 = num * num + num2 * num2;
		float num4 = ((!(num3 <= 0f)) ? Mathf.Clamp01(((px - ax) * num + (py - ay) * num2) / num3) : 0f);
		float num5 = ax + num * num4;
		float num6 = ay + num2 * num4;
		return Mathf.Sqrt((px - num5) * (px - num5) + (py - num6) * (py - num6));
	}
}