Decompiled source of CrimsonChatFilter v1.1.3

CrimsonChatFilter.dll

Decompiled a week ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text.Json;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Core.Logging.Interpolation;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using CrimsonChatFilter.Structs;
using CrimsonChatFilter.Utils;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using ProjectM;
using ProjectM.Network;
using Unity.Collections;
using Unity.Entities;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("CrimsonChatFilter")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Filter server chat!")]
[assembly: AssemblyFileVersion("1.1.3.0")]
[assembly: AssemblyInformationalVersion("1.1.3+1.Branch.master.Sha.0bf85cee523e58d1dc8041d4c261b282b442b8a9.0bf85cee523e58d1dc8041d4c261b282b442b8a9")]
[assembly: AssemblyProduct("CrimsonChatFilter")]
[assembly: AssemblyTitle("CrimsonChatFilter")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.1.3.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 CrimsonChatFilter
{
	[BepInPlugin("CrimsonChatFilter", "CrimsonChatFilter", "1.1.3")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Plugin : BasePlugin
	{
		private Harmony _harmony;

		public static readonly string ConfigFiles = Path.Combine(Paths.ConfigPath, "CrimsonChatFilter");

		public static bool LogLoaded = false;

		public static bool BanLoaded = false;

		public static Plugin Instance { get; private set; }

		public static Harmony Harmony => Instance._harmony;

		public static Settings Settings { get; private set; }

		public static ManualLogSource LogInstance => ((BasePlugin)Instance).Log;

		public static Database Database { get; private set; }

		public override void Load()
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Expected O, but got Unknown
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Expected O, but got Unknown
			Instance = this;
			Settings = default(Settings);
			Settings.InitConfig();
			Database = new Database();
			_harmony = new Harmony("CrimsonChatFilter");
			_harmony.PatchAll(Assembly.GetExecutingAssembly());
			foreach (KeyValuePair<string, PluginInfo> plugin in ((BaseChainloader<BasePlugin>)(object)IL2CPPChainloader.Instance).Plugins)
			{
				BepInPlugin metadata = plugin.Value.Metadata;
				if (metadata.GUID.Equals("CrimsonLog"))
				{
					LogLoaded = true;
				}
				else if (metadata.GUID.Equals("CrimsonBanned"))
				{
					BanLoaded = true;
				}
			}
			ManualLogSource log = ((BasePlugin)this).Log;
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(27, 2, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Plugin ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("CrimsonChatFilter");
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" version ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("1.1.3");
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" is loaded!");
			}
			log.LogInfo(val);
		}

		public static void AddLog(string message, bool console = false)
		{
			if (LogLoaded && !console)
			{
				Type type = Type.GetType("CrimsonLog.Systems.Logger, CrimsonLog");
				if (type != null)
				{
					type.GetMethod("Record").Invoke(null, new object[3]
					{
						"Chat/Filter",
						"filter",
						message + "\n"
					});
					return;
				}
			}
			LogInstance.LogInfo((object)message);
		}

		public override bool Unload()
		{
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
			return true;
		}
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "CrimsonChatFilter";

		public const string PLUGIN_NAME = "CrimsonChatFilter";

		public const string PLUGIN_VERSION = "1.1.3";
	}
}
namespace CrimsonChatFilter.Utils
{
	internal static class FilterString
	{
		private static string addressFilter = ".[0-9]+[0-9][0-9].[0-9]+[0-9][0-9].[0-9]+[0-9][0-9].[0-9]+[0-9][0-9]*";

		private static string domainFilter = "\\bhttp:\\/\\/([^\\/]*)\\/([^\\s]*)";

		public static string Filter(this string input)
		{
			if (Settings.FILTER_URLS.Value)
			{
				input = Regex.Replace(input, addressFilter, "****", RegexOptions.IgnoreCase);
				input = Regex.Replace(input, domainFilter, "****", RegexOptions.IgnoreCase);
			}
			foreach (string item in Database.Filtered)
			{
				string pattern = CreateRegexPattern(item);
				input = Regex.Replace(input, pattern, "****", RegexOptions.IgnoreCase);
			}
			return input;
		}

		public static bool ContainsFiltered(this string input)
		{
			if (Settings.FILTER_URLS.Value)
			{
				if (Regex.IsMatch(input, addressFilter))
				{
					return true;
				}
				if (Regex.IsMatch(input, domainFilter))
				{
					return true;
				}
			}
			foreach (string item in Database.Filtered)
			{
				string pattern = CreateRegexPattern(item);
				if (Regex.IsMatch(input, pattern, RegexOptions.IgnoreCase))
				{
					return true;
				}
			}
			return false;
		}

		private static string CreateRegexPattern(string word)
		{
			string text = Regex.Escape(word).Replace("\\*", ".*");
			return "\\b" + text + "\\b";
		}
	}
}
namespace CrimsonChatFilter.Structs
{
	public class Database
	{
		public static string FilteredFile = Path.Combine(Plugin.ConfigFiles, "filtered_words.json");

		public static List<string> Filtered;

		public Database()
		{
			Load();
		}

		private void Load()
		{
			if (!Directory.Exists(Plugin.ConfigFiles))
			{
				Directory.CreateDirectory(Plugin.ConfigFiles);
			}
			if (!File.Exists(FilteredFile))
			{
				Filtered = new List<string> { "coon", "jim crow", "nigger", "gook", "chink", "towelhead", "honky", "beaner", "spic" };
				string contents = JsonSerializer.Serialize(Filtered, new JsonSerializerOptions
				{
					WriteIndented = true
				});
				File.WriteAllText(FilteredFile, contents);
			}
			else
			{
				Filtered = JsonSerializer.Deserialize<List<string>>(File.ReadAllText(FilteredFile));
			}
		}
	}
	[StructLayout(LayoutKind.Sequential, Size = 1)]
	public readonly struct Settings
	{
		public static readonly string CONFIG_PATH = Path.Combine(Paths.ConfigPath, "CrimsonChatFilter");

		private static readonly List<string> OrderedSections = new List<string> { "Config", "AutoMod" };

		public static ConfigEntry<bool> ENABLE_MOD { get; private set; }

		public static ConfigEntry<bool> FULL_REMOVE { get; private set; }

		public static ConfigEntry<bool> FILTER_URLS { get; private set; }

		public static void InitConfig()
		{
			ENABLE_MOD = InitConfigEntry(OrderedSections[0], "EnableMod", defaultValue: true, "Enable or disable chat filtering");
			FULL_REMOVE = InitConfigEntry(OrderedSections[0], "FullRemove", defaultValue: false, "If enabled, others won't see the message, otherwise replaces filtered words with ****");
			FILTER_URLS = InitConfigEntry(OrderedSections[0], "FilterURLs", defaultValue: true, "Includes .com and server addresses in filter list");
			ReorderConfigSections();
		}

		private static ConfigEntry<T> InitConfigEntry<T>(string section, string key, T defaultValue, string description)
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			ConfigEntry<T> val = ((BasePlugin)Plugin.Instance).Config.Bind<T>(section, key, defaultValue, description);
			string text = Path.Combine(Paths.ConfigPath, "CrimsonChatFilter.cfg");
			ConfigEntry<T> val2 = default(ConfigEntry<T>);
			if (File.Exists(text) && new ConfigFile(text, true).TryGetEntry<T>(section, key, ref val2))
			{
				val.Value = val2.Value;
			}
			return val;
		}

		private static void ReorderConfigSections()
		{
			string path = Path.Combine(Paths.ConfigPath, "CrimsonChatFilter.cfg");
			if (!File.Exists(path))
			{
				return;
			}
			List<string> list = File.ReadAllLines(path).ToList();
			Dictionary<string, List<string>> dictionary = new Dictionary<string, List<string>>();
			string text = "";
			foreach (string item in list)
			{
				if (item.StartsWith("["))
				{
					text = item.Trim('[', ']');
					dictionary[text] = new List<string> { item };
				}
				else if (!string.IsNullOrWhiteSpace(text))
				{
					dictionary[text].Add(item);
				}
			}
			using StreamWriter streamWriter = new StreamWriter(path, append: false);
			foreach (string orderedSection in OrderedSections)
			{
				if (!dictionary.ContainsKey(orderedSection))
				{
					continue;
				}
				foreach (string item2 in dictionary[orderedSection])
				{
					streamWriter.WriteLine(item2);
				}
				streamWriter.WriteLine();
			}
		}
	}
}
namespace CrimsonChatFilter.Hooks
{
	[HarmonyPatch]
	public static class ChatMessageSystem_Patch
	{
		[HarmonyPatch(typeof(ChatMessageSystem), "OnUpdate")]
		[HarmonyPrefix]
		public static bool OnUpdate(ChatMessageSystem __instance)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: 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_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//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_0039: 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: 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_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Invalid comparison between Unknown and I4
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_0132: Unknown result type (might be due to invalid IL or missing references)
			//IL_0177: Unknown result type (might be due to invalid IL or missing references)
			//IL_017c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0182: Unknown result type (might be due to invalid IL or missing references)
			//IL_0187: Unknown result type (might be due to invalid IL or missing references)
			//IL_018b: Unknown result type (might be due to invalid IL or missing references)
			//IL_018c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: 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_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			if (!Settings.ENABLE_MOD.Value)
			{
				return true;
			}
			_ = __instance.__query_661171423_0;
			EntityQuery _query_661171423_ = __instance.__query_661171423_0;
			NativeArray<Entity> val = ((EntityQuery)(ref _query_661171423_)).ToEntityArray(AllocatorHandle.op_Implicit((Allocator)2));
			Enumerator<Entity> enumerator = val.GetEnumerator();
			while (enumerator.MoveNext())
			{
				Entity current = enumerator.Current;
				EntityManager entityManager = ((ComponentSystemBase)__instance).EntityManager;
				FromCharacter componentData = ((EntityManager)(ref entityManager)).GetComponentData<FromCharacter>(current);
				entityManager = ((ComponentSystemBase)__instance).EntityManager;
				User componentData2 = ((EntityManager)(ref entityManager)).GetComponentData<User>(componentData.User);
				entityManager = ((ComponentSystemBase)__instance).EntityManager;
				ChatMessageEvent componentData3 = ((EntityManager)(ref entityManager)).GetComponentData<ChatMessageEvent>(current);
				string text = ((object)(FixedString512Bytes)(ref componentData3.MessageText)).ToString();
				if ((int)componentData3.MessageType != 5 && text.ContainsFiltered())
				{
					if (Settings.FULL_REMOVE.Value)
					{
						Plugin.AddLog($"REMOVED from {componentData2.CharacterName}: \"{text}\"");
						entityManager = ((ComponentSystemBase)__instance).EntityManager;
						((EntityManager)(ref entityManager)).DestroyEntity(current);
					}
					else
					{
						Plugin.AddLog($"CENSORED from {componentData2.CharacterName}: \"{text}\"");
						text = text.Filter();
						componentData3.MessageText = FixedString512Bytes.op_Implicit(text);
						entityManager = ((ComponentSystemBase)__instance).EntityManager;
						((EntityManager)(ref entityManager)).SetComponentData<ChatMessageEvent>(current, componentData3);
					}
				}
			}
			val.Dispose();
			return true;
		}
	}
}