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("2.0.0.0")]
[assembly: AssemblyInformationalVersion("2.0.0+Branch.master.Sha.720fbb9076cc27726a4be6f8ff34c51fdaf6ab83.720fbb9076cc27726a4be6f8ff34c51fdaf6ab83")]
[assembly: AssemblyProduct("CrimsonChatFilter")]
[assembly: AssemblyTitle("CrimsonChatFilter")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("2.0.0.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", "2.0.0")]
[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>("2.0.0");
((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 = "2.0.0";
}
}
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;
}
}
}