The current BepInExPack is broken due to the Oakveil update, and mods installed through a mod manager may not work. Join the modding Discord for more information.
Decompiled source of CrimsonFAQ v1.2.1
CrimsonFAQ.dll
Decompiled a week agousing 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.Json.Serialization; using BepInEx; using BepInEx.Configuration; using BepInEx.Core.Logging.Interpolation; using BepInEx.Logging; using BepInEx.Unity.IL2CPP; using CrimsonFAQ.Structs; using CrimsonFAQ.Systems; using HarmonyLib; using Microsoft.CodeAnalysis; using ProjectM; using ProjectM.Network; using Unity.Collections; using Unity.Entities; using VAMP; using VAMP.Services; using VAMP.Structs; using VAMP.Utilities; using VampireCommandFramework; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")] [assembly: AssemblyCompany("CrimsonFAQ")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("AutoResponder System")] [assembly: AssemblyFileVersion("1.2.1.0")] [assembly: AssemblyInformationalVersion("1.2.1+Branch.master.Sha.574951c59ab741ac2283e21a7196958540eada38.574951c59ab741ac2283e21a7196958540eada38")] [assembly: AssemblyProduct("CrimsonFAQ")] [assembly: AssemblyTitle("CrimsonFAQ")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.2.1.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 CrimsonFAQ { [BepInPlugin("CrimsonFAQ", "CrimsonFAQ", "1.2.1")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] public class Plugin : BasePlugin { private Harmony _harmony; internal static Plugin Instance { get; private set; } public static Settings Settings { get; private set; } public static Harmony Harmony => Instance._harmony; public static ManualLogSource LogInstance => ((BasePlugin)Instance).Log; public static Database DB { get; internal set; } public static string ConfigFiles => Path.Combine(Paths.ConfigPath, "CrimsonFAQ"); public override void Load() { //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Expected O, but got Unknown Instance = this; Settings = default(Settings); Settings.InitConfig(); _harmony = Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), (string)null); CommandRegistry.RegisterAll(); 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>("CrimsonFAQ"); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" version "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("1.2.1"); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" is loaded!"); } log.LogInfo(val); DB = new Database(); } public override bool Unload() { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } return true; } } public static class MyPluginInfo { public const string PLUGIN_GUID = "CrimsonFAQ"; public const string PLUGIN_NAME = "CrimsonFAQ"; public const string PLUGIN_VERSION = "1.2.1"; } } namespace CrimsonFAQ.Systems { public class Database { public static string ResponsesFile = Path.Combine(Plugin.ConfigFiles, "responses.json"); public static string TrustedFile = Path.Combine(Plugin.ConfigFiles, "trusted.json"); public List<KeyResponse> Responses { get; set; } public List<string> Trusted { get; set; } public Database() { CreateDatabaseFiles(); LoadDatabase(); } public bool LoadDatabase() { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Expected O, but got Unknown //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Expected O, but got Unknown try { string json = File.ReadAllText(ResponsesFile); Responses = JsonSerializer.Deserialize<List<KeyResponse>>(json); ManualLogSource logInstance = Plugin.LogInstance; bool flag = default(bool); BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(36, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Loaded Responses Database: "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(Responses.Count); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" entries."); } logInstance.LogInfo(val); string json2 = File.ReadAllText(TrustedFile); Trusted = JsonSerializer.Deserialize<List<string>>(json2); ManualLogSource logInstance2 = Plugin.LogInstance; val = new BepInExInfoLogInterpolatedStringHandler(34, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Loaded Trusted Database: "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(Trusted.Count); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" entries."); } logInstance2.LogInfo(val); return true; } catch (Exception ex) { Plugin.LogInstance.LogError((object)ex); return false; } } public void SaveDatabase() { string contents = JsonSerializer.Serialize(Trusted); File.WriteAllText(TrustedFile, contents); } public static void CreateDatabaseFiles() { if (!File.Exists(ResponsesFile)) { List<KeyResponse> list = new List<KeyResponse>(); KeyResponse item = new KeyResponse("discord", "Join our discord at discord.gg/RBPesMj", "discord link", isGlobal: true, 0, 30); list.Add(item); string contents = JsonSerializer.Serialize(list, new JsonSerializerOptions { WriteIndented = true }); File.WriteAllText(ResponsesFile, contents); } if (!File.Exists(TrustedFile)) { string contents2 = JsonSerializer.Serialize(new List<string>(), new JsonSerializerOptions { WriteIndented = true }); File.WriteAllText(TrustedFile, contents2); } } public bool GetResponse(string key, out KeyResponse response) { response = null; if (Responses.Exists((KeyResponse x) => string.Equals(x.Key, key, StringComparison.OrdinalIgnoreCase))) { response = Responses.Find((KeyResponse x) => string.Equals(x.Key, key, StringComparison.OrdinalIgnoreCase)); return true; } return false; } public bool IsTrusted(User user, int keyLevel) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) if (keyLevel == 1 && (user.IsAdmin || Trusted.Contains(user.PlatformId.ToString()))) { return true; } if (keyLevel == 2 && user.IsAdmin) { return true; } return false; } public bool AddTrusted(User user) { if (Trusted.Contains(user.PlatformId.ToString())) { return false; } Trusted.Add(user.PlatformId.ToString()); SaveDatabase(); return true; } public bool RemoveTrusted(User user) { if (!Trusted.Contains(user.PlatformId.ToString())) { return false; } Trusted.Remove(user.PlatformId.ToString()); SaveDatabase(); return true; } } public static class Responder { public static void Respond(ChatMessageEvent message, User user, Entity chatEntity) { //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_01cd: Unknown result type (might be due to invalid IL or missing references) //IL_0226: Unknown result type (might be due to invalid IL or missing references) //IL_022b: Unknown result type (might be due to invalid IL or missing references) //IL_022f: Unknown result type (might be due to invalid IL or missing references) //IL_0164: Unknown result type (might be due to invalid IL or missing references) //IL_01bd: Unknown result type (might be due to invalid IL or missing references) //IL_01c2: Unknown result type (might be due to invalid IL or missing references) //IL_01c6: Unknown result type (might be due to invalid IL or missing references) if (!((FixedString512Bytes)(ref message.MessageText)).Value.StartsWith(Settings.Prefix.Value)) { return; } string key = ((FixedString512Bytes)(ref message.MessageText)).Value.TrimStart(Settings.Prefix.Value[0]); if (!Plugin.DB.GetResponse(key, out var response)) { return; } EntityManager entityManager; if (response.PermissionLevel > 0) { if (Plugin.DB.IsTrusted(user, response.PermissionLevel)) { ChatUtil.SystemSendAll($"<color={Settings.HexResponse.Value}>{response.Response}</color>"); response.GlobalLastUsed = DateTime.Now; } } else if (response.IsGlobal) { if ((DateTime.Now - response.GlobalLastUsed).TotalSeconds > (double)response.GlobalCooldownSeconds) { ChatUtil.SystemSendAll($"<color={Settings.HexResponse.Value}>{response.Response}</color>"); response.GlobalLastUsed = DateTime.Now; } else { ChatUtil.SystemSendUser(user, $"<color={Settings.HexResponse.Value}>{response.Response}</color>"); entityManager = Core.EntityManager; ((EntityManager)(ref entityManager)).DestroyEntity(chatEntity); } } else { ChatUtil.SystemSendUser(user, $"<color={Settings.HexResponse.Value}>{response.Response}</color>"); entityManager = Core.EntityManager; ((EntityManager)(ref entityManager)).DestroyEntity(chatEntity); } } } } namespace CrimsonFAQ.Structs { public class KeyResponse { [JsonPropertyName("Key")] public string Key { get; set; } [JsonPropertyName("Response")] public string Response { get; set; } [JsonPropertyName("Description")] public string Description { get; set; } [JsonPropertyName("IsGlobal")] public bool IsGlobal { get; set; } [JsonPropertyName("PermissionLevel")] public int PermissionLevel { get; set; } [JsonPropertyName("GlobalCooldownSeconds")] public int GlobalCooldownSeconds { get; set; } [JsonIgnore] public DateTime GlobalLastUsed { get; set; } public KeyResponse() { GlobalLastUsed = DateTime.MinValue; } [JsonConstructor] public KeyResponse(string key, string response, string description, bool isGlobal = false, int permissionLevel = 0, int globalCooldownSeconds = 0) { Key = key; Response = response; Description = description; IsGlobal = isGlobal; PermissionLevel = permissionLevel; GlobalCooldownSeconds = globalCooldownSeconds; GlobalLastUsed = DateTime.MinValue; } } [StructLayout(LayoutKind.Sequential, Size = 1)] public readonly struct Settings { private static readonly List<string> directoryPaths = new List<string> { Plugin.ConfigFiles }; public static ConfigEntry<bool> FAQ { get; private set; } public static ConfigEntry<string> Prefix { get; private set; } public static ConfigEntry<string> HexKey { get; private set; } public static ConfigEntry<string> HexDescription { get; private set; } public static ConfigEntry<string> HexMisc { get; private set; } public static ConfigEntry<string> HexResponse { get; private set; } public static void InitConfig() { foreach (string directoryPath in directoryPaths) { CreateDirectories(directoryPath); } FAQ = InitConfigEntry("_Config", "FAQEnable", defaultValue: true, "Enable or disable the mod."); Prefix = InitConfigEntry("_Config", "Prefix", "?", "The prefix before information requests i.e. \"?discord\""); HexKey = InitConfigEntry("Response Colors", "KeyColor", "#9cb730", "The hex value color that will be displayed for keys in .faq list"); HexDescription = InitConfigEntry("Response Colors", "DescriptionColor", "#309CB7", "The hex value color that will be displayed for descriptions in .faq list"); HexMisc = InitConfigEntry("Response Colors", "MiscColor", "#b7309c", "The hex value color that will be used for formatting elements like the dash in .faq list"); HexResponse = InitConfigEntry("Response Colors", "ResponseColor", "#9cb730", "The hex value color that will be used for responding to user key queries"); } 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, "CrimsonFAQ.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 CreateDirectories(string path) { if (!Directory.Exists(path)) { Directory.CreateDirectory(path); } } } } namespace CrimsonFAQ.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_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Invalid comparison between Unknown and I4 //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) if (!Settings.FAQ.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); if ((int)componentData3.MessageType != 5) { Responder.Respond(componentData3, componentData2, current); } } val.Dispose(); return true; } } } namespace CrimsonFAQ.Commands { [CommandGroup("faq", null)] internal class Basic { private const int MESSAGE_LIMIT = 460; private const int MESSAGES_PER_PAGE = 2; [Command("list", "l", null, "shows the list of FAQ requests that can be queried", null, false)] public static void ListFAQs(ChatCommandContext ctx, int page = 1) { //IL_0075: Unknown result type (might be due to invalid IL or missing references) List<string> list = new List<string> { "\n" }; int num = 0; if (Plugin.DB.Responses.Count == 0) { list[0] += "There are no FAQs setup on the server."; } else { foreach (KeyResponse response in Plugin.DB.Responses) { if (response.PermissionLevel <= 0 || Plugin.DB.IsTrusted(ctx.User, response.PermissionLevel)) { string value = ((!string.IsNullOrEmpty(response.Description)) ? $"<color={Settings.HexMisc.Value}>-</color> <color={Settings.HexDescription.Value}>{response.Description}</color>" : ""); string text = $"<color={Settings.HexKey.Value}>{Settings.Prefix.Value}{response.Key}</color> {value}\n"; if (list[num].Length + text.Length > 460) { num++; list.Add(text); } else { list[num] += text; } } } } int num2 = (int)Math.Ceiling((double)list.Count / 2.0); if (page < 1 || page > num2) { page = 1; } int num3 = (page - 1) * 2; int num4 = Math.Min(num3 + 2, list.Count); if (num2 > 1) { ctx.Reply($"Page {page} of {num2}:"); } for (int i = num3; i < num4; i++) { ctx.Reply(list[i]); } } [Command("trust", "t", null, "adds a player to the list of trusted users", null, true)] public static void AddTrusted(ChatCommandContext ctx, string playerName = "") { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0036: 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_0047: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) if (string.IsNullOrEmpty(playerName)) { ctx.Reply("Must input a player name."); } PlayerData val = default(PlayerData); if (!PlayerService.TryFindByName(playerName, ref val)) { ctx.Reply("Unable to find player named " + playerName); return; } Entity userEntity = ((PlayerData)(ref val)).UserEntity; if (!((Entity)(ref userEntity)).Equals(Entity.Null) && EntityUtil.Has<User>(((PlayerData)(ref val)).UserEntity)) { if (Plugin.DB.AddTrusted(EntityUtil.Read<User>(((PlayerData)(ref val)).UserEntity))) { ctx.Reply(playerName + " added to trusted FAQ users."); } else { ctx.Reply(playerName + " is already a trusted user."); } } else { ctx.Reply("Unable to find player named " + playerName); } } [Command("untrust", "ut", null, "removes a player from the list of trusted users", null, true)] public static void RemoveTrusted(ChatCommandContext ctx, string playerName = "") { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0036: 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_0047: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) if (string.IsNullOrEmpty(playerName)) { ctx.Reply("Must input a player name."); } PlayerData val = default(PlayerData); if (!PlayerService.TryFindByName(playerName, ref val)) { ctx.Reply("Unable to find player named " + playerName); return; } Entity userEntity = ((PlayerData)(ref val)).UserEntity; if (!((Entity)(ref userEntity)).Equals(Entity.Null) && EntityUtil.Has<User>(((PlayerData)(ref val)).UserEntity)) { if (Plugin.DB.RemoveTrusted(EntityUtil.Read<User>(((PlayerData)(ref val)).UserEntity))) { ctx.Reply(playerName + " removed from trusted FAQ users."); } else { ctx.Reply(playerName + " is not in the trusted list"); } } else { ctx.Reply("Unable to find player named " + playerName); } } [Command("reload", "r", null, "reloads the FAQ KeyResponse entries from json", null, true)] public static void ReloadJSON(ChatCommandContext ctx) { KeyResponse[] source = Plugin.DB.Responses.ToArray(); if (Plugin.DB.LoadDatabase()) { List<KeyResponse> responses = Plugin.DB.Responses; int num = 0; foreach (KeyResponse newResponse in responses) { KeyResponse keyResponse = source.FirstOrDefault((KeyResponse r) => r.Key == newResponse.Key); if (keyResponse == null || !keyResponse.Equals(newResponse)) { num++; } } ctx.Reply($"{num} responses loaded."); } else { ctx.Reply("Failed to retreive a valid collection from the responses.json file, please validate your formatting and values"); } } } }