Decompiled source of SlopChat v0.1.2

SlopChat.dll

Decompiled 6 months ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Reptile;
using SlopChat.Packets;
using SlopChat.Patches;
using SlopCrew.API;
using TMPro;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.6.2", FrameworkDisplayName = ".NET Framework 4.6.2")]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: AssemblyCompany("SlopChat")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Chat Plugin for SlopCrew")]
[assembly: AssemblyFileVersion("0.1.2.0")]
[assembly: AssemblyInformationalVersion("0.1.2+78d037bae8c8544f95718e346625513ca0759f34")]
[assembly: AssemblyProduct("SlopChat")]
[assembly: AssemblyTitle("SlopChat")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.1.2.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.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 SlopChat
{
	public class ChatAssets
	{
		public AssetBundle Bundle { get; private set; }

		public ChatAssets(string path)
		{
			Bundle = AssetBundle.LoadFromFile(Path.Combine(path, "slopchat"));
		}
	}
	public static class ChatCommands
	{
		public static void Initialize()
		{
			ChatController.OnSendMessage = (Action<SendMessageEventArgs>)Delegate.Combine(ChatController.OnSendMessage, new Action<SendMessageEventArgs>(OnSendMessage));
		}

		public static void OnSendMessage(SendMessageEventArgs e)
		{
			string text = e.Message.Trim();
			string text2 = e.Message.Trim().ToLowerInvariant();
			if (text2[0] != '/')
			{
				return;
			}
			e.Cancel = true;
			text2 = text2.Substring(1);
			string[] array = text2.Split(new char[1] { ' ' });
			ISlopCrewAPI aPI = APIManager.API;
			UIManager uIManager = Core.Instance.UIManager;
			string text3 = array[0];
			if (text3 == null)
			{
				return;
			}
			switch (text3.Length)
			{
			case 4:
				switch (text3[0])
				{
				case 'h':
					if (text3 == "hide")
					{
						ChatController.HideWhileNotTyping = true;
					}
					break;
				case 's':
					if (!(text3 == "show"))
					{
						if (text3 == "side")
						{
							ChatController.LeftSide = !ChatController.LeftSide;
							ChatController.Instance.SwitchChatHistorySide();
						}
					}
					else
					{
						ChatController.HideWhileNotTyping = false;
					}
					break;
				case 'm':
				{
					if (!(text3 == "mute"))
					{
						break;
					}
					if (array.Length < 2)
					{
						uIManager.ShowNotification("Please provide a player ID to mute", Array.Empty<string>());
					}
					if (uint.TryParse(array[1], out var result))
					{
						if (aPI.PlayerIDExists(result) == true)
						{
							string text4 = TMPFilter.RemoveAllTags(aPI.GetPlayerName(result));
							ChatController.MutedPlayers.Add(text4);
							uIManager.ShowNotification("Muted player " + text4, Array.Empty<string>());
						}
						else
						{
							uIManager.ShowNotification("A player with that ID doesn't exist", Array.Empty<string>());
						}
					}
					else
					{
						uIManager.ShowNotification("Invalid ID", Array.Empty<string>());
					}
					break;
				}
				}
				break;
			case 6:
				switch (text3[0])
				{
				case 'u':
				{
					if (!(text3 == "unmute"))
					{
						break;
					}
					if (array.Length < 2)
					{
						uIManager.ShowNotification("Please provide a player ID to unmute", Array.Empty<string>());
					}
					if (uint.TryParse(array[1], out var result2))
					{
						if (aPI.PlayerIDExists(result2) == true)
						{
							string text6 = TMPFilter.RemoveAllTags(aPI.GetPlayerName(result2));
							ChatController.MutedPlayers.Remove(text6);
							uIManager.ShowNotification("Unmuted player " + text6, Array.Empty<string>());
						}
						else
						{
							uIManager.ShowNotification("A player with that ID doesn't exist", Array.Empty<string>());
						}
					}
					else
					{
						uIManager.ShowNotification("Invalid ID", Array.Empty<string>());
					}
					break;
				}
				case 's':
				{
					if (!(text3 == "status"))
					{
						break;
					}
					if (array.Length < 2)
					{
						ChatController.Instance.SetStatus("");
						break;
					}
					string text5 = text.Substring(7).Trim();
					if (!SlopChatPlugin.Instance.ValidMessage(text5))
					{
						ChatController.Instance.SetStatus("");
						break;
					}
					if (ProfanityFilter.TMPContainsProfanity(text5))
					{
						uIManager.ShowNotification("Your status contains banned words.", Array.Empty<string>());
						break;
					}
					if (text5.Length > SlopChatPlugin.Instance.ChatConfig.MaxStatusCharacters)
					{
						text5 = text5.Substring(0, SlopChatPlugin.Instance.ChatConfig.MaxStatusCharacters);
					}
					string status = SlopChatPlugin.Instance.SanitizeMessage(text5, "Saying Slurs");
					ChatController.Instance.SetStatus(status);
					break;
				}
				}
				break;
			case 9:
				if (text3 == "unmuteall")
				{
					ChatController.MutedPlayers.Clear();
					uIManager.ShowNotification("Unmuted all players", Array.Empty<string>());
				}
				break;
			}
		}
	}
	public class ChatConfig
	{
		public int MaxMessages = 10;

		public int MaxStatusCharacters = 16;

		public int MaxCharacters = 200;

		public bool PhoneOutWhileTyping = true;

		public TMPFilter.Criteria ChatCriteria = new TMPFilter.Criteria(new string[9] { "b", "color", "i", "mark", "sprite", "s", "sub", "sup", "u" }, TMPFilter.Criteria.Kinds.Whitelist);

		public bool FilterProfanity = true;
	}
	public class ChatController : MonoBehaviour
	{
		public enum ChatStates
		{
			None,
			Default,
			Typing
		}

		public enum NetworkStates
		{
			None,
			Server,
			Client,
			LookingForHost
		}

		public static bool LeftSide = false;

		public static string Status = "";

		public static HashSet<string> MutedPlayers = new HashSet<string>();

		public static bool HideWhileNotTyping = false;

		public static Action<SendMessageEventArgs> OnSendMessage;

		public string CurrentInput = "";

		public ChatStates CurrentChatState;

		public NetworkStates CurrentNetworkState;

		public Dictionary<uint, ChatPlayer> ChatPlayersById = new Dictionary<uint, ChatPlayer>();

		private ChatAssets _assets;

		private ChatConfig _config;

		private GameObject _chatUI;

		private TextMeshProUGUI _inputLabel;

		private TextMeshProUGUI _playersLabel;

		private ChatHistory _history;

		private GameObject _historyLeft;

		private GameObject _historyRight;

		private float _caretTimer;

		private float _caretTime = 0.5f;

		private float _heartBeatTimer;

		private float _heartBeatTime = 0.2f;

		private float _heartBeatTimeout = 5f;

		private ISlopCrewAPI _slopAPI;

		private uint _hostId = uint.MaxValue;

		private float _hostTimer;

		private float _hostTimeout = 5f;

		private float _chatHistoryTimer;

		private float _chatHistoryTime = 1f;

		private float _chatFadeTimer;

		private float _chatFadeTime = 30f;

		private DateTime _hostDate;

		public static ChatController Instance { get; private set; }

		private void Awake()
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Expected O, but got Unknown
			_slopAPI = APIManager.API;
			_slopAPI.OnCustomPacketReceived += OnPacketReceived;
			Core.OnUpdate += new OnUpdateHandler(CoreUpdate);
			_assets = SlopChatPlugin.Instance.Assets;
			_config = SlopChatPlugin.Instance.ChatConfig;
			Instance = this;
			GameObject val = _assets.Bundle.LoadAsset<GameObject>("Chat UI");
			_chatUI = Object.Instantiate<GameObject>(val);
			Transform val2 = _chatUI.transform.Find("Canvas");
			_inputLabel = ((Component)((Component)val2).transform.Find("Chat Input")).GetComponent<TextMeshProUGUI>();
			_playersLabel = ((Component)((Component)val2).transform.Find("Chat Players")).GetComponent<TextMeshProUGUI>();
			_history = ((Component)((Component)val2).transform.Find("Chat History")).gameObject.AddComponent<ChatHistory>();
			_historyRight = ((Component)_history).gameObject;
			_historyLeft = ((Component)((Component)val2).transform.Find("Chat History Left")).gameObject;
			_historyLeft.AddComponent<ChatHistory>();
			_historyLeft.SetActive(false);
			_chatUI.transform.SetParent(((Component)Core.Instance.UIManager.gameplay).transform.parent);
			((TMP_Text)_playersLabel).text = "";
			EnterChatState(ChatStates.Default);
			CurrentNetworkState = NetworkStates.LookingForHost;
			if (LeftSide)
			{
				SwitchChatHistorySide();
			}
		}

		public void SetStatus(string status)
		{
			Status = status;
			_history.UpdateLabel();
		}

		public void SwitchChatHistorySide()
		{
			if (_historyLeft.activeSelf)
			{
				_historyLeft.SetActive(false);
				_historyRight.SetActive(true);
				ChatHistory component = _historyRight.GetComponent<ChatHistory>();
				component.Entries = _history.Entries;
				_history = component;
				_history.UpdateLabel();
			}
			else
			{
				_historyLeft.SetActive(true);
				_historyRight.SetActive(false);
				ChatHistory component2 = _historyLeft.GetComponent<ChatHistory>();
				component2.Entries = _history.Entries;
				_history = component2;
				_history.UpdateLabel();
			}
		}

		private void OnPacketReceived(uint playerId, string guid, byte[] data)
		{
			Packet packet = PacketFactory.DeserializePacket(guid, data, playerId);
			if (packet == null)
			{
				return;
			}
			switch (packet.GUID)
			{
			case "SlopChat-Heartbeat":
				if (_slopAPI.PlayerIDExists(playerId) != false)
				{
					HeartbeatPacket heartbeatPacket = packet as HeartbeatPacket;
					if (!ChatPlayersById.TryGetValue(playerId, out var value3))
					{
						value3 = new ChatPlayer();
						ChatPlayersById[playerId] = value3;
					}
					value3.NetworkState = heartbeatPacket.NetworkState;
					value3.LastHeartBeat = DateTime.UtcNow;
					value3.Name = _slopAPI.GetPlayerName(playerId);
					value3.Id = playerId;
					value3.HostId = heartbeatPacket.HostId;
					value3.HostDate = heartbeatPacket.HostStartTime;
					value3.Status = SlopChatPlugin.Instance.SanitizeMessage(heartbeatPacket.Status, "Saying Slurs");
				}
				break;
			case "SlopChat-ChatHistory":
			{
				if (_slopAPI.PlayerIDExists(playerId) != false && CurrentNetworkState == NetworkStates.Client && _hostId == playerId && ChatPlayersById.TryGetValue(playerId, out var value2) && value2.NetworkState == NetworkStates.Server)
				{
					ChatHistoryPacket chatHistoryPacket = packet as ChatHistoryPacket;
					if (chatHistoryPacket.Entry != null && chatHistoryPacket.Entry.PlayerId == uint.MaxValue)
					{
						chatHistoryPacket.Entry.PlayerId = playerId;
					}
					_history.Set(chatHistoryPacket.Entry, chatHistoryPacket.Index);
					if (_history.UpdateLabel())
					{
						PingChat();
					}
				}
				break;
			}
			case "SlopChat-Message":
			{
				if (_slopAPI.PlayerIDExists(playerId) != false && CurrentNetworkState == NetworkStates.Server && ChatPlayersById.TryGetValue(playerId, out var value) && _slopAPI.PlayerIDExists(value.HostId) != true && value.NetworkState == NetworkStates.Client)
				{
					MessagePacket messagePacket = packet as MessagePacket;
					if (SlopChatPlugin.Instance.ValidMessage(messagePacket.Message))
					{
						ChatHistory.Entry entry = new ChatHistory.Entry
						{
							PlayerName = _slopAPI.GetPlayerName(playerId),
							PlayerId = playerId,
							Message = messagePacket.Message
						};
						entry.Sanitize();
						_history.Append(entry);
						PingChat();
						SendChatHistory();
					}
				}
				break;
			}
			}
		}

		private void UpdatePlayers()
		{
			Dictionary<uint, ChatPlayer> dictionary = new Dictionary<uint, ChatPlayer>();
			foreach (KeyValuePair<uint, ChatPlayer> item in ChatPlayersById)
			{
				if ((DateTime.UtcNow - item.Value.LastHeartBeat).TotalSeconds <= (double)_heartBeatTimeout && _slopAPI.PlayerIDExists(item.Key) == true)
				{
					dictionary[item.Key] = item.Value;
				}
			}
			ChatPlayersById = dictionary;
			string text = "Players in Text Chat:\n";
			if (CurrentNetworkState == NetworkStates.Server)
			{
				text += "<color=red>[HOST] ";
			}
			else if (CurrentNetworkState != NetworkStates.Client)
			{
				text += "<color=red>[CONNECTING] ";
			}
			if (!string.IsNullOrWhiteSpace(Status))
			{
				text = text + "<color=yellow>[" + Status + "] </color>";
			}
			text = text + "<color=white>" + SlopChatPlugin.Instance.SanitizeName(_slopAPI.PlayerName) + "\n";
			foreach (KeyValuePair<uint, ChatPlayer> item2 in ChatPlayersById)
			{
				if (item2.Value.NetworkState == NetworkStates.Client || item2.Value.NetworkState == NetworkStates.Server)
				{
					text += $"<color=white>{item2.Key} - ";
					if (CurrentNetworkState == NetworkStates.Client && _hostId == item2.Key)
					{
						text += "<color=red>[HOST] ";
					}
					if (!string.IsNullOrWhiteSpace(item2.Value.Status) && !MutedPlayers.Contains(TMPFilter.RemoveAllTags(item2.Value.Name)))
					{
						text = text + "<color=yellow>[" + item2.Value.Status + "] </color>";
					}
					text = text + "<color=white>" + SlopChatPlugin.Instance.SanitizeName(item2.Value.Name) + "\n";
				}
			}
			((TMP_Text)_playersLabel).text = text;
		}

		private void SendChatHistory()
		{
			for (int i = 0; i < _history.Entries.Count; i++)
			{
				PacketFactory.SendPacket(new ChatHistoryPacket
				{
					Index = i,
					Entry = _history.Entries[i]
				}, _slopAPI);
			}
		}

		private void Heartbeat()
		{
			UpdatePlayers();
			PacketFactory.SendPacket(new HeartbeatPacket
			{
				NetworkState = CurrentNetworkState,
				HostId = _hostId,
				HostStartTime = _hostDate,
				Status = Status
			}, _slopAPI);
		}

		private void NetworkUpdate()
		{
			if (!_slopAPI.Connected)
			{
				CurrentNetworkState = NetworkStates.LookingForHost;
				_hostId = uint.MaxValue;
				_hostTimer = 0f;
			}
			_heartBeatTimer += Core.dt;
			if (_heartBeatTimer >= _heartBeatTime)
			{
				_heartBeatTimer = 0f;
				Heartbeat();
			}
			switch (CurrentNetworkState)
			{
			case NetworkStates.LookingForHost:
				NetworkLookingForHostUpdate();
				break;
			case NetworkStates.Server:
				NetworkServerUpdate();
				break;
			case NetworkStates.Client:
				NetworkClientUpdate();
				break;
			}
		}

		private void NetworkClientUpdate()
		{
			ChatPlayer value;
			if (_slopAPI.PlayerIDExists(_hostId) == false)
			{
				LookForHost();
			}
			else if (!ChatPlayersById.TryGetValue(_hostId, out value))
			{
				LookForHost();
			}
			else if (value.NetworkState != NetworkStates.Server)
			{
				LookForHost();
			}
		}

		private void NetworkServerUpdate()
		{
			_chatHistoryTimer += Core.dt;
			if (_chatHistoryTimer > _chatHistoryTime)
			{
				_chatHistoryTimer = 0f;
				SendChatHistory();
				NetworkServerCheckForOtherServers();
			}
		}

		private void NetworkServerCheckForOtherServers()
		{
			double totalSeconds = (DateTime.UtcNow - _hostDate).TotalSeconds;
			ChatPlayer chatPlayer = null;
			double num = 0.0;
			foreach (KeyValuePair<uint, ChatPlayer> item in ChatPlayersById)
			{
				if (_slopAPI.PlayerIDExists(item.Key) != false && item.Value.NetworkState == NetworkStates.Server)
				{
					double totalSeconds2 = (DateTime.UtcNow - item.Value.HostDate).TotalSeconds;
					if (chatPlayer == null)
					{
						chatPlayer = item.Value;
						num = totalSeconds2;
					}
					else if (totalSeconds2 > num)
					{
						chatPlayer = item.Value;
						num = totalSeconds2;
					}
				}
			}
			if (chatPlayer != null && num > totalSeconds)
			{
				ConnectToHost(chatPlayer.Id);
			}
		}

		private void NetworkLookingForHostUpdate()
		{
			_hostId = uint.MaxValue;
			_hostTimer += Core.dt;
			ChatPlayer chatPlayer = null;
			foreach (KeyValuePair<uint, ChatPlayer> item in ChatPlayersById)
			{
				if (_slopAPI.PlayerIDExists(item.Key) != false && item.Value.NetworkState == NetworkStates.Server)
				{
					if (chatPlayer == null)
					{
						chatPlayer = item.Value;
					}
					else if (item.Key < chatPlayer.Id)
					{
						chatPlayer = item.Value;
					}
				}
			}
			if (chatPlayer != null)
			{
				ConnectToHost(chatPlayer.Id);
			}
			if (_hostTimer > _hostTimeout)
			{
				HostChat();
			}
		}

		private void LookForHost()
		{
			_hostTimer = 0f;
			CurrentNetworkState = NetworkStates.LookingForHost;
		}

		private void ConnectToHost(uint playerId)
		{
			PingChat();
			_hostId = playerId;
			CurrentNetworkState = NetworkStates.Client;
		}

		private void HostChat()
		{
			PingChat();
			_hostDate = DateTime.UtcNow;
			_chatHistoryTimer = 0f;
			_hostId = uint.MaxValue;
			CurrentNetworkState = NetworkStates.Server;
		}

		private bool CanEnterTypingState()
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: 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_002e: Unknown result type (might be due to invalid IL or missing references)
			if (!_chatUI.activeInHierarchy)
			{
				return false;
			}
			PlayerControllerMapIDCollection allCurrentEnabledControllerMapCategoryIDs = Core.Instance.gameInput.GetAllCurrentEnabledControllerMapCategoryIDs(0);
			if (allCurrentEnabledControllerMapCategoryIDs.controllerMapCategoryIDs.Contains(0))
			{
				return allCurrentEnabledControllerMapCategoryIDs.controllerMapCategoryIDs.Contains(6);
			}
			return false;
		}

		private void EnableInputs()
		{
			GameInput gameInput = Core.Instance.gameInput;
			gameInput.DisableAllControllerMaps(0);
			gameInput.EnableControllerMaps(BaseModule.IN_GAME_INPUT_MAPS, 0);
		}

		private void DisableInputs()
		{
			Core.Instance.gameInput.DisableAllControllerMaps(0);
		}

		public void EnterChatState(ChatStates newState)
		{
			if (CurrentChatState != newState)
			{
				_caretTimer = 0f;
				CurrentInput = "";
				((TMP_Text)_inputLabel).text = "";
				((Component)((TMP_Text)_playersLabel).transform).gameObject.SetActive(false);
				if (CurrentChatState == ChatStates.Typing)
				{
					InputUtils.PopInputBlocker();
					EnableInputs();
				}
				if (newState != ChatStates.Default && newState == ChatStates.Typing)
				{
					((Component)((TMP_Text)_playersLabel).transform).gameObject.SetActive(true);
					InputUtils.PushInputBlocker();
					DisableInputs();
				}
				CurrentChatState = newState;
			}
		}

		private void SendChatMessage(string text)
		{
			EnterChatState(ChatStates.Default);
			if (!SlopChatPlugin.Instance.ValidMessage(text))
			{
				return;
			}
			SendMessageEventArgs sendMessageEventArgs = new SendMessageEventArgs(text);
			OnSendMessage?.Invoke(sendMessageEventArgs);
			if (!sendMessageEventArgs.Cancel)
			{
				if (CurrentNetworkState == NetworkStates.Server)
				{
					ChatHistory.Entry entry = new ChatHistory.Entry
					{
						PlayerName = _slopAPI.PlayerName,
						PlayerId = uint.MaxValue,
						Message = text
					};
					entry.Sanitize();
					_history.Append(entry);
					PingChat();
					SendChatHistory();
				}
				else if (CurrentNetworkState == NetworkStates.Client)
				{
					PacketFactory.SendPacket(new MessagePacket
					{
						Message = text
					}, _slopAPI);
				}
			}
		}

		private void DefaultUpdate()
		{
			if (Input.GetKeyDown((KeyCode)9) && CanEnterTypingState())
			{
				EnterChatState(ChatStates.Typing);
			}
		}

		private void TypingUpdate()
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: 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)
			PingChat();
			GameInput gameInput = Core.Instance.GameInput;
			PlayerControllerMapIDCollection allCurrentEnabledControllerMapCategoryIDs = gameInput.GetAllCurrentEnabledControllerMapCategoryIDs(0);
			if (allCurrentEnabledControllerMapCategoryIDs.controllerMapCategoryIDs.Length != 0 || !_chatUI.activeInHierarchy)
			{
				EnterChatState(ChatStates.Default);
				gameInput.DisableAllControllerMaps(0);
				gameInput.EnableControllerMaps(allCurrentEnabledControllerMapCategoryIDs.controllerMapCategoryIDs, 0);
				return;
			}
			_caretTimer += Core.dt;
			InputUtils.PopInputBlocker();
			try
			{
				string inputString = Input.inputString;
				if (Input.GetKeyDown((KeyCode)27) || Input.GetKeyDown((KeyCode)9))
				{
					EnterChatState(ChatStates.Default);
					return;
				}
				if (Input.GetKey((KeyCode)306))
				{
					if (Input.GetKeyDown((KeyCode)118))
					{
						CurrentInput += GUIUtility.systemCopyBuffer;
					}
				}
				else
				{
					string text = inputString;
					for (int i = 0; i < text.Length; i++)
					{
						char c = text[i];
						switch (c)
						{
						case '\b':
							if (CurrentInput.Length > 0)
							{
								CurrentInput = CurrentInput.Substring(0, CurrentInput.Length - 1);
							}
							break;
						case '\n':
						case '\r':
							if (CurrentNetworkState == NetworkStates.Server || CurrentNetworkState == NetworkStates.Client)
							{
								if (SlopChatPlugin.Instance.ChatConfig.FilterProfanity && ProfanityFilter.TMPContainsProfanity(CurrentInput))
								{
									EnterChatState(ChatStates.Default);
									Core.Instance.UIManager.ShowNotification("Your message contains banned words.", Array.Empty<string>());
								}
								else
								{
									SendChatMessage(CurrentInput);
								}
							}
							return;
						default:
							CurrentInput += c;
							break;
						}
					}
				}
				CurrentInput = SlopChatPlugin.Instance.SanitizeInput(CurrentInput);
				((TMP_Text)_inputLabel).text = "<color=#87e5e5>Say</color> : " + TMPFilter.FilterTags(CurrentInput, SlopChatPlugin.Instance.ChatConfig.ChatCriteria);
				if (_caretTimer >= _caretTime)
				{
					TextMeshProUGUI inputLabel = _inputLabel;
					((TMP_Text)inputLabel).text = ((TMP_Text)inputLabel).text + "|";
					if (_caretTimer >= _caretTime * 2f)
					{
						_caretTimer = 0f;
					}
				}
			}
			finally
			{
				InputUtils.PushInputBlocker();
			}
		}

		private void ChatUpdate()
		{
			switch (CurrentChatState)
			{
			case ChatStates.Default:
				DefaultUpdate();
				break;
			case ChatStates.Typing:
				TypingUpdate();
				break;
			}
		}

		private void CoreUpdate()
		{
			ChatUpdate();
			NetworkUpdate();
			_chatFadeTimer += Core.dt;
			if (HideWhileNotTyping)
			{
				if (CurrentChatState == ChatStates.Typing)
				{
					_chatFadeTimer = 0f;
				}
				else
				{
					_chatFadeTimer = _chatFadeTime;
				}
			}
			if (_chatFadeTimer >= _chatFadeTime)
			{
				_chatFadeTimer = _chatFadeTime;
				if (((Component)_history).gameObject.activeSelf)
				{
					((Component)_history).gameObject.SetActive(false);
				}
			}
			else if (!((Component)_history).gameObject.activeSelf)
			{
				((Component)_history).gameObject.SetActive(true);
			}
		}

		private void PingChat()
		{
			_chatFadeTimer = 0f;
		}

		private void OnDestroy()
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Expected O, but got Unknown
			_slopAPI.OnCustomPacketReceived -= OnPacketReceived;
			Core.OnUpdate -= new OnUpdateHandler(CoreUpdate);
			EnterChatState(ChatStates.Default);
		}
	}
	public class ChatHistory : MonoBehaviour
	{
		public class Entry
		{
			public string PlayerName;

			public uint PlayerId;

			public string Message;

			public void Sanitize()
			{
				PlayerName = SlopChatPlugin.Instance.SanitizeName(PlayerName);
				Message = SlopChatPlugin.Instance.SanitizeMessage(Message, "I said a naughty word!");
			}
		}

		public List<Entry> Entries;

		private TextMeshProUGUI _label;

		private ChatConfig _config;

		private void Awake()
		{
			_config = SlopChatPlugin.Instance.ChatConfig;
			Entries = new List<Entry>();
			for (int i = 0; i < SlopChatPlugin.Instance.ChatConfig.MaxMessages; i++)
			{
				Entries.Add(null);
			}
			_label = ((Component)this).GetComponent<TextMeshProUGUI>();
			UpdateLabel();
		}

		public bool UpdateLabel()
		{
			string text = "";
			for (int i = 0; i < Entries.Count; i++)
			{
				Entry entry = Entries[i];
				if (entry == null)
				{
					continue;
				}
				string text2 = entry.Message;
				ChatPlayer value;
				if (ChatController.MutedPlayers.Contains(TMPFilter.RemoveAllTags(entry.PlayerName)))
				{
					text2 = "Muted message.";
				}
				else if (ChatController.Instance.ChatPlayersById.TryGetValue(entry.PlayerId, out value))
				{
					if (!string.IsNullOrWhiteSpace(value.Status))
					{
						text = text + "<color=yellow>[" + value.Status + "]</color> ";
					}
				}
				else if (APIManager.API.PlayerIDExists(entry.PlayerId) == false && TMPFilter.RemoveAllTags(entry.PlayerName) == TMPFilter.RemoveAllTags(APIManager.API.PlayerName) && !string.IsNullOrWhiteSpace(ChatController.Status))
				{
					text = text + "<color=yellow>[" + ChatController.Status + "]</color> ";
				}
				text = text + "<color=yellow>" + entry.PlayerName + "<color=white> : " + text2;
				if (i != Entries.Count - 1)
				{
					text += "\n";
				}
			}
			if (text != ((TMP_Text)_label).text)
			{
				((TMP_Text)_label).text = text;
				return true;
			}
			((TMP_Text)_label).text = text;
			return false;
		}

		public void Append(Entry message)
		{
			Entries.Add(message);
			if (Entries.Count > _config.MaxMessages)
			{
				Entries.RemoveAt(0);
			}
			UpdateLabel();
		}

		public void Set(Entry message, int position)
		{
			Entries[position] = message;
		}
	}
	public class ChatPlayer
	{
		public string Name;

		public uint Id;

		public ChatController.NetworkStates NetworkState;

		public uint HostId;

		public DateTime LastHeartBeat;

		public DateTime HostDate;

		public string Status;
	}
	public static class InputUtils
	{
		public static int InputBlockers { get; private set; }

		public static bool InputBlocked => InputBlockers > 0;

		public static void PushInputBlocker()
		{
			InputBlockers++;
		}

		public static void PopInputBlocker()
		{
			InputBlockers--;
		}
	}
	public static class ProfanityFilter
	{
		public const string CensoredMessage = "I said a naughty word!";

		public const string ProfanityError = "Your message contains banned words.";

		public const string CensoredStatus = "Saying Slurs";

		public const string StatusProfanityError = "Your status contains banned words.";

		private static List<string> BannedContent = LoadBannedContent();

		private static List<string> SafeWords = LoadSafeWords();

		private static List<string> BadWords = LoadBadWords();

		private static List<string> LoadBadWords()
		{
			List<string> list = new List<string>();
			string[] array = new StreamReader(Assembly.GetExecutingAssembly().GetManifestResourceStream("SlopChat.res.badwords.txt") ?? throw new Exception("Could not load bad words for profanity filter")).ReadToEnd().Split(new char[1] { '\n' });
			for (int i = 0; i < array.Length; i++)
			{
				string text = array[i].Trim();
				if (!text.StartsWith("#"))
				{
					text = RemoveSpecialCharacters(text);
					text = SpecialCharactersToLetters(text);
					list.Add(text);
				}
			}
			return list;
		}

		private static List<string> LoadSafeWords()
		{
			List<string> list = new List<string>();
			string[] array = new StreamReader(Assembly.GetExecutingAssembly().GetManifestResourceStream("SlopChat.res.safewords.txt") ?? throw new Exception("Could not load safe words for profanity filter")).ReadToEnd().Split(new char[1] { '\n' });
			for (int i = 0; i < array.Length; i++)
			{
				string text = array[i].Trim();
				if (!text.StartsWith("#"))
				{
					text = RemoveSpecialCharacters(text);
					text = SpecialCharactersToLetters(text);
					list.Add(text);
				}
			}
			return list;
		}

		private static List<string> LoadBannedContent()
		{
			List<string> list = new List<string>();
			string[] array = new StreamReader(Assembly.GetExecutingAssembly().GetManifestResourceStream("SlopChat.res.profanity.txt") ?? throw new Exception("Could not load profanity filter")).ReadToEnd().Split(new char[1] { '\n' });
			for (int i = 0; i < array.Length; i++)
			{
				string text = array[i].Trim();
				if (!text.StartsWith("#"))
				{
					text = RemoveSpecialCharacters(text);
					text = SpecialCharactersToLetters(text);
					list.Add(text);
				}
			}
			return list;
		}

		public static bool ContainsBadWords(string text)
		{
			text = text.ToLower();
			foreach (string badWord in BadWords)
			{
				if (text == badWord)
				{
					return true;
				}
				if (text.StartsWith(badWord + " "))
				{
					return true;
				}
				if (text.EndsWith(" " + badWord))
				{
					return true;
				}
				if (text.Contains(" " + badWord + " "))
				{
					return true;
				}
			}
			return false;
		}

		public static string RemoveSafeWords(string text)
		{
			text = text.ToLower();
			foreach (string safeWord in SafeWords)
			{
				if (text == safeWord)
				{
					return "";
				}
				text = text.Replace(" " + safeWord + " ", "");
				if (text.StartsWith(safeWord + " "))
				{
					text = text.Substring(safeWord.Length + 1);
				}
				if (text.EndsWith(" " + safeWord))
				{
					text = text.Substring(0, text.Length - safeWord.Length - 1);
				}
			}
			return text;
		}

		public static bool ContainsProfanity(string text)
		{
			foreach (string item in BannedContent)
			{
				if (text.Contains(item.ToLower()))
				{
					return true;
				}
			}
			return false;
		}

		public static bool TMPContainsProfanity(string tmpText)
		{
			tmpText = RemoveSafeWords(tmpText);
			string text = TMPFilter.RemoveAllTags(tmpText);
			text = SpecialCharactersToLetters(text);
			text = RemoveSpecialCharacters(text);
			string text2 = tmpText;
			text2 = SpecialCharactersToLetters(text2);
			text2 = RemoveSpecialCharacters(text2);
			string text3 = RemoveRepeatedLetters(text2);
			string text4 = RemoveRepeatedLetters(text);
			if (ContainsBadWords(text2) || ContainsBadWords(text) || ContainsBadWords(text3) || ContainsBadWords(text4))
			{
				return true;
			}
			text2 = RemoveSpaces(text2);
			text = RemoveSpaces(text);
			text3 = RemoveSpaces(text3);
			text4 = RemoveSpaces(text4);
			if (ContainsProfanity(text2) || ContainsProfanity(text) || ContainsProfanity(text3) || ContainsProfanity(text4))
			{
				return true;
			}
			return false;
		}

		public static string RemoveRepeatedLetters(string text)
		{
			string text2 = "";
			char c = '\0';
			for (int i = 0; i < text.Length; i++)
			{
				char c2 = text[i];
				if (c2 != c)
				{
					c = c2;
					text2 += c2;
				}
			}
			return text2;
		}

		public static string RemoveSpecialCharacters(string text)
		{
			text = new Regex("[^A-Za-z0-9 ]").Replace(text, string.Empty);
			return text;
		}

		public static string RemoveSpaces(string text)
		{
			return text.Replace(" ", string.Empty);
		}

		public static string SpecialCharactersToLetters(string text)
		{
			text = text.Replace("0", "o");
			text = text.Replace("1", "i");
			text = text.Replace("3", "e");
			text = text.Replace("4", "a");
			text = text.Replace("5", "s");
			text = text.Replace("6", "g");
			text = text.Replace("7", "t");
			text = text.Replace("0", "o");
			text = text.Replace("@", "a");
			return text;
		}
	}
	public class SendMessageEventArgs
	{
		public string Message;

		public bool Cancel;

		public SendMessageEventArgs(string message)
		{
			Message = message;
		}
	}
	[BepInPlugin("SlopChat", "SlopChat", "0.1.2")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class SlopChatPlugin : BaseUnityPlugin
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static OnStageInitializedDelegate <0>__StageManager_OnStagePostInitialization;
		}

		public static SlopChatPlugin Instance { get; private set; }

		public ChatAssets Assets { get; private set; }

		public ChatConfig ChatConfig { get; private set; }

		private void Awake()
		{
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Expected O, but got Unknown
			KeyValuePair<ConfigDefinition, ConfigEntryBase> keyValuePair = ((IEnumerable<KeyValuePair<ConfigDefinition, ConfigEntryBase>>)Chainloader.PluginInfos["SlopCrew.Plugin"].Instance.Config).First((KeyValuePair<ConfigDefinition, ConfigEntryBase> x) => x.Key.Section == "Server" && x.Key.Key == "Host");
			if (keyValuePair.Value.BoxedValue == keyValuePair.Value.DefaultValue)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)"SlopChat is not allowed on the official SlopCrew server.");
				return;
			}
			try
			{
				Instance = this;
				Assets = new ChatAssets(Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location));
				ChatConfig = new ChatConfig();
				Patch();
				object obj = <>O.<0>__StageManager_OnStagePostInitialization;
				if (obj == null)
				{
					OnStageInitializedDelegate val = StageManager_OnStagePostInitialization;
					<>O.<0>__StageManager_OnStagePostInitialization = val;
					obj = (object)val;
				}
				StageManager.OnStagePostInitialization += (OnStageInitializedDelegate)obj;
				ChatCommands.Initialize();
				((BaseUnityPlugin)this).Logger.LogInfo((object)"Plugin SlopChat 0.1.2 is loaded!");
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)string.Format("Failed to load {0} {1}!{2}{3}", "SlopChat", "0.1.2", Environment.NewLine, ex));
			}
		}

		private void Patch()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Expected O, but got Unknown
			Harmony val = new Harmony("SlopChat");
			val.PatchAll();
			InputPatch.Patch(val);
		}

		private static void StageManager_OnStagePostInitialization()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			new GameObject("Chat Controller").AddComponent<ChatController>();
		}

		public string SanitizeInput(string text)
		{
			text = text.Replace("\n", "");
			text = text.Replace("\t", "");
			text = text.Replace("\r", "");
			if (text.Length > ChatConfig.MaxCharacters)
			{
				text = text.Substring(0, ChatConfig.MaxCharacters);
			}
			return text;
		}

		public string SanitizeName(string text)
		{
			text = SanitizeInput(text);
			text = text.Trim();
			text = TMPFilter.CloseAllTags(TMPFilter.FilterTags(text, ChatConfig.ChatCriteria));
			return text;
		}

		public string SanitizeMessage(string text, string censor)
		{
			text = SanitizeInput(text);
			text = text.Trim();
			text = TMPFilter.CloseAllTags(TMPFilter.FilterTags(text, ChatConfig.ChatCriteria));
			if (ChatConfig.FilterProfanity && ProfanityFilter.TMPContainsProfanity(text))
			{
				return censor;
			}
			return text;
		}

		public bool ValidMessage(string text)
		{
			text = SanitizeMessage(text, "I said a naughty word!");
			if (Utility.IsNullOrWhiteSpace(text))
			{
				return false;
			}
			return true;
		}
	}
	public static class TMPFilter
	{
		public class Criteria
		{
			public enum Kinds
			{
				Whitelist,
				Blacklist
			}

			public Kinds ListKind;

			public string[] List;

			public Criteria(string[] list, Kinds listKind)
			{
				List = list;
				ListKind = listKind;
			}

			internal bool CheckTag(string tag)
			{
				if (List.Contains(tag.ToLowerInvariant()))
				{
					return ListKind == Kinds.Whitelist;
				}
				return ListKind == Kinds.Blacklist;
			}
		}

		public static string[] EnclosingTags = new string[30]
		{
			"align", "allcaps", "b", "color", "cspace", "font", "font-weight", "gradient", "i", "indent",
			"line-height", "link", "lowercase", "margin", "mark", "mspace", "nobr", "noparse", "pos", "rotate",
			"s", "size", "smallcaps", "style", "sub", "sup", "u", "uppercase", "voffset", "width"
		};

		public static string RemoveAllTags(string text)
		{
			text = new Regex("<[^>]*>").Replace(text, string.Empty);
			return text;
		}

		public static string EscapeAllTags(string text)
		{
			return FilterTags(text, new Criteria(Array.Empty<string>(), Criteria.Kinds.Whitelist));
		}

		public static string FilterTags(string text, Criteria criteria)
		{
			bool flag = false;
			int num = 0;
			string text2 = "";
			StringBuilder stringBuilder = new StringBuilder(text);
			int num2 = 0;
			for (int i = 0; i < text.Length; i++)
			{
				char c = text[i];
				if (!flag)
				{
					if (c == '<')
					{
						flag = true;
						text2 = "";
						num = i;
					}
				}
				else if (c == '>')
				{
					flag = false;
					if (text2[0] == '/')
					{
						text2 = text2.Substring(1);
					}
					if (text2[0] == '#')
					{
						text2 = "color";
					}
					text2 = text2.ToLowerInvariant();
					if (text2.Contains("="))
					{
						text2 = text2.Split(new char[1] { '=' })[0];
					}
					if (!criteria.CheckTag(text2))
					{
						stringBuilder.Insert(num + 1 + num2, "\u200b");
						num2++;
					}
				}
				else
				{
					text2 += c;
				}
			}
			return stringBuilder.ToString();
		}

		public static string CloseAllTags(string text)
		{
			bool flag = false;
			string text2 = "";
			List<string> list = new List<string>();
			string text3 = text;
			for (int i = 0; i < text3.Length; i++)
			{
				char c = text3[i];
				if (!flag)
				{
					if (c == '<')
					{
						flag = true;
						text2 = "";
					}
				}
				else if (c == '>')
				{
					flag = false;
					if (text2[0] == '/')
					{
						if (list.Count > 0)
						{
							text2 = text2.Substring(1);
							if (text2 == list[0])
							{
								list.RemoveAt(0);
							}
						}
						continue;
					}
					if (text2[0] == '#')
					{
						text2 = "color";
					}
					text2 = text2.ToLowerInvariant();
					if (text2.Contains("="))
					{
						text2 = text2.Split(new char[1] { '=' })[0];
					}
					if (EnclosingTags.Contains(text2))
					{
						list.Insert(0, text2);
					}
				}
				else
				{
					text2 += c;
				}
			}
			string text4 = "";
			foreach (string item in list)
			{
				text4 = text4 + "</" + item + ">";
			}
			text += text4;
			return text;
		}
	}
	public static class PluginInfo
	{
		public const string PLUGIN_GUID = "SlopChat";

		public const string PLUGIN_NAME = "SlopChat";

		public const string PLUGIN_VERSION = "0.1.2";
	}
}
namespace SlopChat.Patches
{
	internal static class InputPatch
	{
		private static MethodInfo GetKeyDown_Base_KeyCodeOverload = AccessTools.Method(typeof(Input), "GetKeyDown", new Type[1] { typeof(KeyCode) }, (Type[])null);

		private static MethodInfo GetKeyDown_Base_StringOverload = AccessTools.Method(typeof(Input), "GetKeyDown", new Type[1] { typeof(string) }, (Type[])null);

		private static MethodInfo GetKeyDown_Prefix_Method = AccessTools.Method(typeof(InputPatch), "GetKeyDown_Prefix", (Type[])null, (Type[])null);

		internal static void Patch(Harmony harmony)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Expected O, but got Unknown
			HarmonyMethod val = new HarmonyMethod(GetKeyDown_Prefix_Method);
			harmony.Patch((MethodBase)GetKeyDown_Base_KeyCodeOverload, val, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			harmony.Patch((MethodBase)GetKeyDown_Base_StringOverload, val, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		}

		private static bool GetKeyDown_Prefix(ref bool __result)
		{
			if (InputUtils.InputBlocked)
			{
				__result = false;
				return false;
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(KeyboardShortcut))]
	internal class KeyboardShortcutPatch
	{
		[HarmonyPrefix]
		[HarmonyPatch("IsDown")]
		private static bool IsDown_Prefix(ref bool __result)
		{
			if (InputUtils.InputBlocked)
			{
				__result = false;
				return false;
			}
			return true;
		}

		[HarmonyPrefix]
		[HarmonyPatch("IsPressed")]
		private static bool IsPressed_Prefix(ref bool __result)
		{
			if (InputUtils.InputBlocked)
			{
				__result = false;
				return false;
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(Player))]
	internal static class PlayerPatch
	{
		[HarmonyPatch("LateUpdateAnimation")]
		[HarmonyPostfix]
		private static void LateUpdateAnimation_Postfix(Player __instance)
		{
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			if (SlopChatPlugin.Instance.ChatConfig.PhoneOutWhileTyping && ((Component)__instance).gameObject.activeSelf && !__instance.isAI && !__instance.phone.IsOn)
			{
				ChatController instance = ChatController.Instance;
				if (!((Object)(object)instance == (Object)null) && instance.CurrentChatState == ChatController.ChatStates.Typing && (int)__instance.spraycanState == 0)
				{
					__instance.anim.speed = 0f;
					__instance.anim.SetFloat(__instance.phoneDirectionXHash, (0f - __instance.phoneDirBone.localRotation.x) * 2.5f + __instance.customPhoneHandValue.x);
					__instance.anim.SetFloat(__instance.phoneDirectionYHash, (0f - __instance.phoneDirBone.localRotation.y) * 2.5f + __instance.customPhoneHandValue.y);
					__instance.anim.Update(Core.dt);
					__instance.anim.speed = 1f;
				}
			}
		}

		[HarmonyPatch("UpdateLookAt")]
		[HarmonyPostfix]
		private static void UpdateLookAt_Postfix(Player __instance)
		{
			if (SlopChatPlugin.Instance.ChatConfig.PhoneOutWhileTyping && !__instance.isAI)
			{
				ChatController instance = ChatController.Instance;
				if (!((Object)(object)instance == (Object)null) && instance.CurrentChatState == ChatController.ChatStates.Typing)
				{
					__instance.characterVisual.phoneActive = __instance.phoneLayerWeight >= 1f;
				}
			}
		}

		[HarmonyPatch("UpdateHoldProps")]
		[HarmonyPrefix]
		private static bool UpdateHoldProps_Prefix(Player __instance)
		{
			if (!SlopChatPlugin.Instance.ChatConfig.PhoneOutWhileTyping)
			{
				return true;
			}
			ChatController instance = ChatController.Instance;
			if ((Object)(object)instance == (Object)null)
			{
				return true;
			}
			if (__instance.isAI)
			{
				return true;
			}
			if (instance.CurrentChatState != ChatController.ChatStates.Typing)
			{
				return true;
			}
			__instance.UpdateSprayCanShake();
			__instance.characterVisual.SetPhone(true);
			__instance.phoneLayerWeight += __instance.grabPhoneSpeed * Core.dt;
			if (__instance.phoneLayerWeight >= 1f)
			{
				__instance.phoneLayerWeight = 1f;
			}
			__instance.anim.SetLayerWeight(3, __instance.phoneLayerWeight);
			return false;
		}
	}
}
namespace SlopChat.Packets
{
	public class ChatHistoryPacket : Packet
	{
		public const string kGUID = "SlopChat-ChatHistory";

		public int Index;

		public ChatHistory.Entry Entry;

		private const byte Version = 0;

		public override string GUID => "SlopChat-ChatHistory";

		public override void Write(BinaryWriter writer)
		{
			writer.Write((byte)0);
			writer.Write(Index);
			writer.Write(Entry != null);
			if (Entry != null)
			{
				writer.Write(Entry.PlayerId);
				writer.Write(Entry.PlayerName);
				writer.Write(Entry.Message);
			}
		}

		public override void Read(BinaryReader reader)
		{
			reader.ReadByte();
			Index = reader.ReadInt32();
			if (reader.ReadBoolean())
			{
				ChatHistory.Entry entry = new ChatHistory.Entry();
				entry.PlayerId = reader.ReadUInt32();
				entry.PlayerName = reader.ReadString();
				entry.Message = reader.ReadString();
				ISlopCrewAPI aPI = APIManager.API;
				if (aPI.PlayerIDExists(entry.PlayerId) == true)
				{
					entry.PlayerName = aPI.GetPlayerName(entry.PlayerId);
				}
				entry.Sanitize();
				Entry = entry;
			}
		}
	}
	internal class HeartbeatPacket : Packet
	{
		public const string kGUID = "SlopChat-Heartbeat";

		private const byte Version = 1;

		public ChatController.NetworkStates NetworkState;

		public uint HostId = uint.MaxValue;

		public DateTime HostStartTime;

		public string Status = "";

		public override string GUID => "SlopChat-Heartbeat";

		public override void Write(BinaryWriter writer)
		{
			writer.Write((byte)1);
			writer.Write((int)NetworkState);
			writer.Write(HostId);
			writer.Write(HostStartTime.ToBinary());
			writer.Write(Status);
		}

		public override void Read(BinaryReader reader)
		{
			byte num = reader.ReadByte();
			NetworkState = (ChatController.NetworkStates)reader.ReadInt32();
			HostId = reader.ReadUInt32();
			HostStartTime = DateTime.FromBinary(reader.ReadInt64());
			if (num > 0)
			{
				Status = reader.ReadString();
			}
		}
	}
	public class MessagePacket : Packet
	{
		public const string kGUID = "SlopChat-Message";

		public string Message = "";

		private const byte Version = 0;

		public override string GUID => "SlopChat-Message";

		public override void Write(BinaryWriter writer)
		{
			writer.Write((byte)0);
			writer.Write(Message);
		}

		public override void Read(BinaryReader reader)
		{
			reader.ReadByte();
			Message = reader.ReadString();
		}
	}
	public abstract class Packet
	{
		public uint PlayerId = uint.MaxValue;

		public abstract string GUID { get; }

		public virtual void Write(BinaryWriter writer)
		{
		}

		public virtual void Read(BinaryReader reader)
		{
		}
	}
	public static class PacketFactory
	{
		public static void SendPacket(Packet packet, ISlopCrewAPI slopAPI)
		{
			byte[] array = SerializePacket(packet);
			slopAPI.SendCustomPacket(packet.GUID, array);
		}

		public static byte[] SerializePacket(Packet packet)
		{
			MemoryStream memoryStream = new MemoryStream();
			BinaryWriter binaryWriter = new BinaryWriter(memoryStream);
			packet.Write(binaryWriter);
			binaryWriter.Flush();
			byte[] result = memoryStream.ToArray();
			binaryWriter.Close();
			memoryStream.Close();
			return result;
		}

		public static T DeserializePacket<T>(string guid, byte[] data, uint playerId) where T : Packet
		{
			return DeserializePacket(guid, data, playerId) as T;
		}

		public static Packet DeserializePacket(string guid, byte[] data, uint playerId)
		{
			MemoryStream memoryStream = new MemoryStream(data);
			BinaryReader binaryReader = new BinaryReader(memoryStream);
			Packet packet = null;
			switch (guid)
			{
			case "SlopChat-Heartbeat":
				packet = new HeartbeatPacket();
				break;
			case "SlopChat-Message":
				packet = new MessagePacket();
				break;
			case "SlopChat-ChatHistory":
				packet = new ChatHistoryPacket();
				break;
			}
			if (packet != null)
			{
				packet.PlayerId = playerId;
				packet.Read(binaryReader);
			}
			binaryReader.Close();
			memoryStream.Close();
			return packet;
		}
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
}