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)
{
}
}
}