using 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.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+89ef4a342e5b0a073074124718e6399010a34357")]
[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.2")]
public class BetterChatBox : BaseUnityPlugin
{
internal const string CursorString = "<b>|</b>";
internal const string EmptyCursorString = "<b> </b>";
internal const int MaxChars = 50;
internal static BetterChatBox Instance { get; private set; }
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; }
public static ConfigEntry<float> DeleteRepeatSpeed { get; private set; }
public static ConfigEntry<float> InputHoldDelay { get; private set; }
public static ConfigEntry<bool> SavePreviousChatMessage { get; private set; }
public static ConfigEntry<bool> SaveCursorPosition { get; private set; }
public static ConfigEntry<bool> CutToSystemClipboard { get; private set; }
private void Awake()
{
Instance = this;
((Component)this).gameObject.transform.parent = null;
((Object)((Component)this).gameObject).hideFlags = (HideFlags)61;
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) ? "<b>|</b>" : "<b> </b>");
((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("<b>|</b>", string.Empty).Replace("<b> </b>", 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_0249: 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 (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_0065: 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) || 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;
}
}
}