Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of BetterChatBox v1.0.3
BetterChatBox.dll
Decompiled 11 months agousing System; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using TMPro; using UnityEngine; using UnityEngine.InputSystem.Utilities; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: IgnoresAccessChecksTo("Assembly-CSharp-firstpass")] [assembly: IgnoresAccessChecksTo("Assembly-CSharp")] [assembly: IgnoresAccessChecksTo("Autodesk.Fbx")] [assembly: IgnoresAccessChecksTo("Facepunch.Steamworks.Win64")] [assembly: IgnoresAccessChecksTo("FbxBuildTestAssets")] [assembly: IgnoresAccessChecksTo("Klattersynth")] [assembly: IgnoresAccessChecksTo("Photon3Unity3D")] [assembly: IgnoresAccessChecksTo("PhotonChat")] [assembly: IgnoresAccessChecksTo("PhotonRealtime")] [assembly: IgnoresAccessChecksTo("PhotonUnityNetworking")] [assembly: IgnoresAccessChecksTo("PhotonUnityNetworking.Utilities")] [assembly: IgnoresAccessChecksTo("PhotonVoice.API")] [assembly: IgnoresAccessChecksTo("PhotonVoice")] [assembly: IgnoresAccessChecksTo("PhotonVoice.PUN")] [assembly: IgnoresAccessChecksTo("SingularityGroup.HotReload.Runtime")] [assembly: IgnoresAccessChecksTo("SingularityGroup.HotReload.Runtime.Public")] [assembly: IgnoresAccessChecksTo("Sirenix.OdinInspector.Attributes")] [assembly: IgnoresAccessChecksTo("Sirenix.Serialization.Config")] [assembly: IgnoresAccessChecksTo("Sirenix.Serialization")] [assembly: IgnoresAccessChecksTo("Sirenix.Utilities")] [assembly: IgnoresAccessChecksTo("Unity.AI.Navigation")] [assembly: IgnoresAccessChecksTo("Unity.Formats.Fbx.Runtime")] [assembly: IgnoresAccessChecksTo("Unity.InputSystem")] [assembly: IgnoresAccessChecksTo("Unity.InputSystem.ForUI")] [assembly: IgnoresAccessChecksTo("Unity.Postprocessing.Runtime")] [assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.Core.Runtime")] [assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.Core.ShaderLibrary")] [assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.ShaderGraph.ShaderGraphLibrary")] [assembly: IgnoresAccessChecksTo("Unity.TextMeshPro")] [assembly: IgnoresAccessChecksTo("Unity.Timeline")] [assembly: IgnoresAccessChecksTo("Unity.VisualScripting.Antlr3.Runtime")] [assembly: IgnoresAccessChecksTo("Unity.VisualScripting.Core")] [assembly: IgnoresAccessChecksTo("Unity.VisualScripting.Flow")] [assembly: IgnoresAccessChecksTo("Unity.VisualScripting.State")] [assembly: IgnoresAccessChecksTo("UnityEngine.ARModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.NVIDIAModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.UI")] [assembly: IgnoresAccessChecksTo("websocket-sharp")] [assembly: AssemblyCompany("NoSpawnn")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+a192c3892fe365bfc1c0f1cb86941879560ca844")] [assembly: AssemblyProduct("BetterChatBox")] [assembly: AssemblyTitle("BetterChatBox")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.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.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [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 BetterChatBox { [BepInPlugin("NoSpawnn.BetterChatBox", "BetterChatBox", "1.0.3")] public class BetterChatBox : BaseUnityPlugin { internal const string CursorString = "|"; internal const string EmptyCursorString = " "; internal const int MaxChars = 50; internal static bool ShouldLimitChatLength = true; internal static BetterChatBox Instance { get; private set; } = null; internal static ManualLogSource Logger => Instance._logger; private ManualLogSource _logger => ((BaseUnityPlugin)this).Logger; internal Harmony? Harmony { get; set; } internal int CursorPos { get; set; } internal float DeleteTimer { get; set; } internal bool BackspaceHeld { get; set; } internal bool DeleteHeld { get; set; } internal bool LeftArrowHeld { get; set; } internal bool RightArrowHeld { get; set; } internal float CursorMoveTimer { get; set; } public static ConfigEntry<float> CursorMoveSpeed { get; private set; } = null; public static ConfigEntry<float> DeleteRepeatSpeed { get; private set; } = null; public static ConfigEntry<float> InputHoldDelay { get; private set; } = null; public static ConfigEntry<bool> SavePreviousChatMessage { get; private set; } = null; public static ConfigEntry<bool> SaveCursorPosition { get; private set; } = null; public static ConfigEntry<bool> CutToSystemClipboard { get; private set; } = null; private void Awake() { Instance = this; ((Component)this).gameObject.transform.parent = null; ((Object)((Component)this).gameObject).hideFlags = (HideFlags)61; if (Chainloader.PluginInfos.ContainsKey("nickklmao.nolimitchatbox")) { Logger.LogInfo((object)"nolimitchatbox is installed, removing chat length limit"); ShouldLimitChatLength = false; } Patch(); BindConfigs(); Logger.LogInfo((object)$"{((BaseUnityPlugin)this).Info.Metadata.GUID} v{((BaseUnityPlugin)this).Info.Metadata.Version} has loaded!"); } internal void Patch() { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Expected O, but got Unknown //IL_0025: Expected O, but got Unknown if (Harmony == null) { Harmony val = new Harmony(((BaseUnityPlugin)this).Info.Metadata.GUID); Harmony val2 = val; Harmony = val; } Harmony.PatchAll(); } internal void Unpatch() { Harmony? harmony = Harmony; if (harmony != null) { harmony.UnpatchSelf(); } } internal void ResetButtonsHeldState() { BackspaceHeld = false; DeleteHeld = false; LeftArrowHeld = false; RightArrowHeld = false; } private void BindConfigs() { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Expected O, but got Unknown //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Expected O, but got Unknown //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Expected O, but got Unknown CursorMoveSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("Input", "Cursor Tick Speed", 0.05f, new ConfigDescription("Cursor move speed when holding an arrow key", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.01f, 0.1f), Array.Empty<object>())); DeleteRepeatSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("Input", "Delete Tick Speed", 0.05f, new ConfigDescription("Character delete speed when holding backspace or delete", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.01f, 0.1f), Array.Empty<object>())); InputHoldDelay = ((BaseUnityPlugin)this).Config.Bind<float>("Input", "Input Hold Delay", 0.5f, new ConfigDescription("How long you need to hold a key before it starts repeating", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 1f), Array.Empty<object>())); SavePreviousChatMessage = ((BaseUnityPlugin)this).Config.Bind<bool>("Behavior", "Save Last Chat Message", true, "Should the chat box save your unsent message on close"); SaveCursorPosition = ((BaseUnityPlugin)this).Config.Bind<bool>("Behavior", "Save Cursor Position", true, "Should the chat box save the cursor's position on close (this has no effect if the above is disabled)"); CutToSystemClipboard = ((BaseUnityPlugin)this).Config.Bind<bool>("Behavior", "Cut to system clipboard", false, "Should cutting (Ctrl + X) text be placed onto the system clipboard"); } } [HarmonyPatch(typeof(ChatManager))] public class ChatPatch { [HarmonyPrefix] [HarmonyPatch("StateActive")] public static bool StateActivePrefix(ChatManager __instance) { int cursorPos = BetterChatBox.Instance.CursorPos; string chatMessage = __instance.chatMessage; SemiFunc.InputDisableMovement(); InputHandlers.HandleCursorNavigation(ref __instance, ref cursorPos, ref chatMessage); InputHandlers.HandleClipboardOperation(ref __instance, ref cursorPos, ref chatMessage); InputHandlers.HandleHistoryNavigation(ref __instance, ref cursorPos, ref chatMessage); InputHandlers.HandleTextManip(ref __instance, ref cursorPos, ref chatMessage); string value = ((Mathf.Sin(Time.time * 10f) > 0f) ? "|" : " "); ((TMP_Text)__instance.chatText).text = chatMessage.Insert(cursorPos, value); __instance.chatMessage = chatMessage; if (SemiFunc.InputDown((InputKey)9)) { __instance.StateSet((ChatState)((!Utility.IsNullOrWhiteSpace(chatMessage)) ? 3 : 0)); } if (SemiFunc.InputDown((InputKey)18)) { __instance.StateSet((ChatState)0); ((SemiUI)ChatUI.instance).SemiUISpringShakeX(10f, 10f, 0.3f); ((SemiUI)ChatUI.instance).SemiUISpringScale(0.05f, 5f, 0.2f); MenuManager.instance.MenuEffectClick((MenuClickEffectType)2, (MenuPage)null, 1f, 1f, true); __instance.StateSet((ChatState)0); } BetterChatBox.Instance.CursorPos = cursorPos; return false; } [HarmonyPrefix] [HarmonyPatch("StateInactive")] public static bool StateInactivePrefix(ChatManager __instance) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Invalid comparison between Unknown and I4 //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Invalid comparison between Unknown and I4 ((SemiUI)ChatUI.instance).Hide(); __instance.chatActive = false; MenuManager instance = MenuManager.instance; MenuPage currentMenuPage = instance.currentMenuPage; if ((currentMenuPage == null || ((int)currentMenuPage.menuPageIndex != 1 && (int)currentMenuPage.menuPageIndex != 2)) && SemiFunc.InputDown((InputKey)7)) { TutorialDirector.instance.playerChatted = true; instance.MenuEffectClick((MenuClickEffectType)0, (MenuPage)null, 1f, 1f, true); __instance.chatActive = !__instance.chatActive; __instance.StateSet((ChatState)1); } return false; } [HarmonyPostfix] [HarmonyPatch("ChatReset")] private static void ChatResetPostfix(ChatManager __instance) { BetterChatBox.Instance.CursorPos = 0; } [HarmonyPostfix] [HarmonyPatch("StateSet")] public static void StateSetPostfix(ChatManager __instance, ChatState state) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Invalid comparison between Unknown and I4 if (__instance != null && __instance.chatText != null && (int)state == 1) { BetterChatBox.Instance.ResetButtonsHeldState(); if (BetterChatBox.SavePreviousChatMessage.Value) { __instance.chatMessage = ((TMP_Text)__instance.chatText).text.Replace("|", string.Empty).Replace(" ", string.Empty); } else { __instance.chatMessage = string.Empty; ((TMP_Text)__instance.chatText).text = string.Empty; } if (!BetterChatBox.SaveCursorPosition.Value || __instance.chatMessage.Length == 0) { BetterChatBox.Instance.CursorPos = __instance.chatMessage.Length; } } } internal static void ChatHistoryChangeEffect() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) ((SemiUI)ChatUI.instance).SemiUITextFlashColor(Color.cyan, 0.2f); ((SemiUI)ChatUI.instance).SemiUISpringShakeY(2f, 5f, 0.2f); MenuManager.instance.MenuEffectClick((MenuClickEffectType)4, (MenuPage)null, 1f, 0.2f, true); } internal static void ChatFailInputEffect() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) ((SemiUI)ChatUI.instance).SemiUITextFlashColor(Color.red, 0.2f); ((SemiUI)ChatUI.instance).SemiUISpringShakeX(10f, 10f, 0.3f); ((SemiUI)ChatUI.instance).SemiUISpringScale(0.05f, 5f, 0.2f); MenuManager.instance.MenuEffectClick((MenuClickEffectType)2, (MenuPage)null, 1f, 1f, true); } } internal static class InputHandlers { internal static void HandleTextManip(ref ChatManager chatManagerInstance, ref int cursorPos, ref string chatMessage) { //IL_0250: Unknown result type (might be due to invalid IL or missing references) if (Input.GetKeyUp((KeyCode)8)) { BetterChatBox.Instance.BackspaceHeld = false; } if (Input.GetKeyUp((KeyCode)127)) { BetterChatBox.Instance.DeleteHeld = false; } if (chatMessage.Length > 0) { if (Input.GetKeyDown((KeyCode)8) && cursorPos > 0) { if (Input.GetKey((KeyCode)306)) { int previousWordIdxFromIdx = GetPreviousWordIdxFromIdx(cursorPos, chatMessage, keepWhitespace: true); chatMessage = chatMessage.Remove(previousWordIdxFromIdx, cursorPos - previousWordIdxFromIdx); cursorPos = previousWordIdxFromIdx; } else { BetterChatBox.Instance.BackspaceHeld = true; BetterChatBox.Instance.DeleteTimer = BetterChatBox.InputHoldDelay.Value; chatMessage = chatMessage.Remove(cursorPos - 1, 1); cursorPos--; } chatManagerInstance.CharRemoveEffect(); } else if (BetterChatBox.Instance.BackspaceHeld && cursorPos > 0) { BetterChatBox.Instance.DeleteTimer -= Time.deltaTime; if (BetterChatBox.Instance.DeleteTimer <= 0f) { BetterChatBox.Instance.DeleteTimer = BetterChatBox.DeleteRepeatSpeed.Value; chatMessage = chatMessage.Remove(cursorPos - 1, 1); chatManagerInstance.CharRemoveEffect(); cursorPos--; } } if (Input.GetKeyDown((KeyCode)127) && cursorPos < chatMessage.Length) { if (Input.GetKey((KeyCode)306)) { int nextWordIdxFromIdx = GetNextWordIdxFromIdx(cursorPos, chatMessage, keepWhitespace: true); chatMessage = chatMessage.Remove(cursorPos, nextWordIdxFromIdx - cursorPos); } else { BetterChatBox.Instance.DeleteHeld = true; BetterChatBox.Instance.DeleteTimer = BetterChatBox.InputHoldDelay.Value; chatMessage = chatMessage.Remove(cursorPos, 1); } chatManagerInstance.CharRemoveEffect(); } else if (BetterChatBox.Instance.DeleteHeld && cursorPos < chatMessage.Length) { BetterChatBox.Instance.DeleteTimer -= Time.deltaTime; if (BetterChatBox.Instance.DeleteTimer <= 0f) { BetterChatBox.Instance.DeleteTimer = BetterChatBox.DeleteRepeatSpeed.Value; chatMessage = chatMessage.Remove(cursorPos, 1); chatManagerInstance.CharRemoveEffect(); } } } foreach (char item in Input.inputString.Where((char c) => !char.IsControl(c))) { if (!BetterChatBox.ShouldLimitChatLength || chatMessage.Length < 50) { chatManagerInstance.prevChatMessage = chatMessage; chatMessage = chatMessage.Insert(cursorPos, item.ToString()); cursorPos++; chatManagerInstance.TypeEffect(Color.yellow); } else { ChatPatch.ChatFailInputEffect(); } } } internal static void HandleHistoryNavigation(ref ChatManager chatManagerInstance, ref int cursorPos, ref string chatMessage) { if (chatManagerInstance.chatHistory.Count <= 0) { return; } if (Input.GetKeyDown((KeyCode)273)) { if (chatManagerInstance.chatHistoryIndex > 0) { ChatManager obj = chatManagerInstance; obj.chatHistoryIndex--; } else { chatManagerInstance.chatHistoryIndex = chatManagerInstance.chatHistory.Count - 1; } chatMessage = chatManagerInstance.chatHistory[chatManagerInstance.chatHistoryIndex]; ChatPatch.ChatHistoryChangeEffect(); cursorPos = chatMessage.Length; } if (Input.GetKeyDown((KeyCode)274)) { if (chatManagerInstance.chatHistoryIndex < chatManagerInstance.chatHistory.Count - 1) { ChatManager obj2 = chatManagerInstance; obj2.chatHistoryIndex++; } else { chatManagerInstance.chatHistoryIndex = 0; } chatMessage = chatManagerInstance.chatHistory[chatManagerInstance.chatHistoryIndex]; ChatPatch.ChatHistoryChangeEffect(); cursorPos = chatMessage.Length; } } internal static void HandleCursorNavigation(ref ChatManager chatManagerInstance, ref int cursorPos, ref string chatMessage) { if (Input.GetKeyUp((KeyCode)275)) { BetterChatBox.Instance.RightArrowHeld = false; } if (Input.GetKeyUp((KeyCode)276)) { BetterChatBox.Instance.LeftArrowHeld = false; } if (Input.GetKeyDown((KeyCode)276) && cursorPos > 0) { if (Input.GetKey((KeyCode)306)) { cursorPos = GetPreviousWordIdxFromIdx(cursorPos, chatMessage, keepWhitespace: false); } else { BetterChatBox.Instance.LeftArrowHeld = true; BetterChatBox.Instance.CursorMoveTimer = BetterChatBox.InputHoldDelay.Value; cursorPos--; } } else if (BetterChatBox.Instance.LeftArrowHeld && cursorPos > 0) { BetterChatBox.Instance.CursorMoveTimer -= Time.deltaTime; if (BetterChatBox.Instance.CursorMoveTimer <= 0f) { BetterChatBox.Instance.CursorMoveTimer = BetterChatBox.CursorMoveSpeed.Value; cursorPos--; } } if (Input.GetKeyDown((KeyCode)275) && cursorPos < chatMessage.Length) { if (Input.GetKey((KeyCode)306)) { cursorPos = GetNextWordIdxFromIdx(cursorPos, chatMessage, keepWhitespace: false); return; } BetterChatBox.Instance.RightArrowHeld = true; BetterChatBox.Instance.CursorMoveTimer = BetterChatBox.InputHoldDelay.Value; cursorPos++; } else if (BetterChatBox.Instance.RightArrowHeld && cursorPos < chatMessage.Length) { BetterChatBox.Instance.CursorMoveTimer -= Time.deltaTime; if (BetterChatBox.Instance.CursorMoveTimer <= 0f) { BetterChatBox.Instance.CursorMoveTimer = BetterChatBox.CursorMoveSpeed.Value; cursorPos++; } } } internal static void HandleClipboardOperation(ref ChatManager chatManagerInstance, ref int cursorPos, ref string chatMessage) { //IL_006c: Unknown result type (might be due to invalid IL or missing references) if (!Input.GetKey((KeyCode)306)) { return; } if (Input.GetKeyDown((KeyCode)99)) { GUIUtility.systemCopyBuffer = chatMessage; } else if (Input.GetKeyDown((KeyCode)118)) { string text = StringHelpers.WithAllWhitespaceStripped(GUIUtility.systemCopyBuffer); string text2 = chatMessage.Insert(cursorPos, text); if (Utility.IsNullOrWhiteSpace(text) || (BetterChatBox.ShouldLimitChatLength && text2.Length >= 50)) { ChatPatch.ChatFailInputEffect(); return; } chatMessage = text2; cursorPos += text.Length; chatManagerInstance.TypeEffect(Color.yellow); } else if (Input.GetKeyDown((KeyCode)120)) { if (BetterChatBox.CutToSystemClipboard.Value) { GUIUtility.systemCopyBuffer = chatMessage; } chatMessage = string.Empty; cursorPos = 0; chatManagerInstance.CharRemoveEffect(); } } private static int GetNextWordIdxFromIdx(int from, string str, bool keepWhitespace) { int i; for (i = from; i < str.Length && char.IsWhiteSpace(str[i]); i++) { } if (!char.IsWhiteSpace(str[from])) { for (; i < str.Length && !char.IsWhiteSpace(str[i]); i++) { } } if (!keepWhitespace) { for (; i < str.Length && !char.IsWhiteSpace(str[i]); i++) { } } return i; } private static int GetPreviousWordIdxFromIdx(int from, string str, bool keepWhitespace) { int num = from - 1; while (num >= 0 && char.IsWhiteSpace(str[num])) { num--; } if (!char.IsWhiteSpace(str[from - 1])) { while (num >= 0 && !char.IsWhiteSpace(str[num])) { num--; } } if (!keepWhitespace) { while (num >= 0 && !char.IsWhiteSpace(str[num])) { num--; } } return num + 1; } } }