Decompiled source of BetterTextChat v0.3.1

BetterTextChat.dll

Decompiled 2 months 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.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using CellMenu;
using HarmonyLib;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppSystem.Collections.Generic;
using Microsoft.CodeAnalysis;
using Player;
using TMPro;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("BetterTextChat")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("BetterTextChat")]
[assembly: AssemblyTitle("BetterTextChat")]
[assembly: AssemblyVersion("1.0.0.0")]
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;
		}
	}
}
namespace BetterTextChat
{
	internal static class BetterChatComposition
	{
		private static string rawCurrentValue = "";

		[HarmonyPatch(typeof(PlayerChatManager), "UpdateTextChatInput")]
		[HarmonyPrefix]
		private static void PlayerChatManager__UpdateTextChatInput__Prefix(PlayerChatManager __instance, ref bool __runOriginal)
		{
			__runOriginal = false;
			if (!PlayerChatManager.TextChatInputEnabled)
			{
				return;
			}
			if ((Object)(object)PlayerChatManager.Current != (Object)null && !PlayerChatManager.InChatMode && InputMapper.GetButtonDownKeyMouseGamepad((InputAction)56, (eFocusState)0))
			{
				PlayerChatManager.Log("Open chat window");
				__instance.EnterChatMode();
			}
			else
			{
				if (!((Object)(object)PlayerChatManager.Current != (Object)null) || !PlayerChatManager.InChatMode)
				{
					return;
				}
				if (InputMapper.GetButtonDownKeyMouseGamepad((InputAction)57, (eFocusState)0))
				{
					__instance.ExitChatMode();
					return;
				}
				string inputString = Input.inputString;
				for (int i = 0; i < inputString.Length; i++)
				{
					char c = inputString[i];
					if (!ConfigManager.allowForbiddenChars.Value && ((Il2CppArrayBase<int>)(object)__instance.m_forbiddenChars).Contains((int)c))
					{
						continue;
					}
					switch (c)
					{
					case '\b':
						if (rawCurrentValue.Length > 0)
						{
							rawCurrentValue = rawCurrentValue.Substring(0, rawCurrentValue.Length - 1);
						}
						break;
					default:
						if (c != '\r')
						{
							rawCurrentValue += c;
							break;
						}
						goto case '\n';
					case '\n':
						if (Input.GetKey((KeyCode)304) || Input.GetKey((KeyCode)303))
						{
							rawCurrentValue += "\n";
							break;
						}
						__instance.m_currentValue = Utils.WordWrap(rawCurrentValue, __instance.m_maxLen);
						__instance.m_currentImeCompositionString = "";
						__instance.PostMessage();
						break;
					}
				}
				if ((Input.GetKey((KeyCode)306) || Input.GetKey((KeyCode)305)) && Input.GetKeyDown((KeyCode)118))
				{
					rawCurrentValue += GUIUtility.systemCopyBuffer.ReplaceLineEndings("\n");
				}
				__instance.m_currentValue = Utils.WordWrap(rawCurrentValue, __instance.m_maxLen);
				__instance.m_currentImeCompositionString = Input.compositionString;
				__instance.UpdateMessage();
			}
		}

		[HarmonyPatch(typeof(PlayerChatManager), "ExitChatMode")]
		[HarmonyPostfix]
		private static void PlayerChatManager__ExitChatMode__Postfix(PlayerChatManager __instance)
		{
			if (ConfigManager.discardDraftMessage.Value)
			{
				rawCurrentValue = "";
				__instance.m_currentValue = "";
				__instance.m_currentImeCompositionString = "";
				__instance.UpdateMessage();
			}
		}

		[HarmonyPatch(typeof(PlayerChatManager), "PostMessage")]
		[HarmonyPrefix]
		private static void PlayerChatManager__PostMessage__Prefix(ref bool __runOriginal)
		{
			__runOriginal = false;
		}

		[HarmonyPatch(typeof(PlayerChatManager), "PostMessage")]
		[HarmonyPostfix]
		private static void PlayerChatManager__PostMessage__Postfix(PlayerChatManager __instance)
		{
			if (rawCurrentValue.Trim('\n').Length > 0 && __instance.m_currentValue.Length > 0)
			{
				string[] array = __instance.m_currentValue.Split('\n');
				foreach (string text in array)
				{
					PlayerChatManager.WantToSentTextMessage(PlayerManager.GetLocalPlayerAgent(), text, (PlayerAgent)null);
				}
			}
			rawCurrentValue = "";
			__instance.m_currentValue = "";
			__instance.ExitChatMode();
		}

		[HarmonyPatch(typeof(PUI_GameEventLog), "Update")]
		[HarmonyPostfix]
		private static void PUI_GameEventLog__Update__Postfix(PUI_GameEventLog __instance)
		{
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			((TMP_Text)__instance.m_txtInput).enableWordWrapping = false;
			((TMP_Text)__instance.m_txtInput).overflowMode = (TextOverflowModes)0;
			__instance.m_blinkSuffix = (__instance.m_blink ? "_" : " ");
			((TMP_Text)__instance.m_txtInput).text = __instance.m_textInputString + __instance.m_blinkSuffix;
			((TMP_Text)__instance.m_txtInput).alignment = (TextAlignmentOptions)1025;
			float num = ((TMP_Text)__instance.m_txtInput).preferredHeight + 5.1f;
			Transform val = __instance.m_chatActiveRoot.transform.FindChild("Input Background Active");
			SpriteRenderer component = ((Component)val).GetComponent<SpriteRenderer>();
			component.size = new Vector2(component.size.x, num);
			RectTransform component2 = ((Component)val).GetComponent<RectTransform>();
			((Transform)component2).localPosition = new Vector3(0f, num / 2f - 1f, 0f);
			__instance.ShowAndUpdateItemPositions();
		}

		[HarmonyPatch(typeof(PUI_GameEventLog), "ShowAndUpdateItemPositions")]
		[HarmonyPrefix]
		private static void PUI_GameEventLog__ShowAndUpdateItemPositions__Prefix(PUI_GameEventLog __instance, ref bool __runOriginal)
		{
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			__runOriginal = false;
			float num = ((TMP_Text)__instance.m_txtInput).preferredHeight + 5.1f;
			float num2 = (((TMP_Text)__instance.m_txtInput).text.Contains('\n') ? (num - __instance.m_logItemHeight) : 0f);
			for (int i = 0; i < __instance.m_logItems.Count; i++)
			{
				((Component)__instance.m_logItems[i]).transform.localPosition = new Vector3(0f, num2 + (float)(__instance.m_logItems.Count - i - 1) * __instance.m_logItemHeight);
			}
		}
	}
	internal static class ScrollableGameEventLog
	{
		private static Dictionary<int, PUI_GameEventLog_ExtensionData> extensionDataForEachInstance = new Dictionary<int, PUI_GameEventLog_ExtensionData>();

		private static PUI_GameEventLog_ExtensionData GetInstanceData(PUI_GameEventLog __instance)
		{
			int instanceID = ((Object)__instance).GetInstanceID();
			if (!extensionDataForEachInstance.ContainsKey(instanceID))
			{
				extensionDataForEachInstance[instanceID] = new PUI_GameEventLog_ExtensionData(instanceID);
			}
			return extensionDataForEachInstance[instanceID];
		}

		[HarmonyPatch(typeof(PUI_GameEventLog), "AddLogItem")]
		[HarmonyPrefix]
		private static void PUI_GameEventLog__AddLogItem__Prefix(PUI_GameEventLog __instance, ref bool __runOriginal, string log, eGameEventChatLogType type)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			__runOriginal = false;
			PUI_GameEventLog_ExtensionData instanceData = GetInstanceData(__instance);
			instanceData.rawEventLog.Add((log, type));
		}

		[HarmonyPatch(typeof(PUI_GameEventLog), "OnLevelCleanup")]
		[HarmonyPrefix]
		private static void PUI_GameEventLog__OnLevelCleanup__Prefix(PUI_GameEventLog __instance, ref bool __runOriginal)
		{
			__runOriginal = false;
			if ((Object)(object)__instance != (Object)(object)CM_PageLoadout.Current.m_gameEventLog)
			{
				PUI_GameEventLog_ExtensionData instanceData = GetInstanceData(GuiManager.PlayerLayer.m_gameEventLog);
				instanceData.rawEventLog.Clear();
			}
		}

		[HarmonyPatch(typeof(PlayerChatManager), "EnterChatMode")]
		[HarmonyPatch(typeof(PlayerChatManager), "ExitChatMode")]
		[HarmonyPostfix]
		private static void PlayerChatManager__EnterExitChatMode__Postfix()
		{
			foreach (PUI_GameEventLog_ExtensionData value in extensionDataForEachInstance.Values)
			{
				value.scrollPosition = null;
			}
		}

		[HarmonyPatch(typeof(PUI_GameEventLog), "Update")]
		[HarmonyPostfix]
		private static void PUI_GameEventLog__Update__Postfix(PUI_GameEventLog __instance)
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_0249: Unknown result type (might be due to invalid IL or missing references)
			//IL_024e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0278: Unknown result type (might be due to invalid IL or missing references)
			PUI_GameEventLog_ExtensionData instanceData = GetInstanceData(__instance);
			int num = Math.Min(__instance.m_limitNRLines, PUI_GameEventLog.s_logItemsMax);
			if (PlayerChatManager.TextChatInputEnabled && PlayerChatManager.InChatMode && Input.mouseScrollDelta.y != 0f)
			{
				int? scrollPosition = instanceData.scrollPosition;
				if (!scrollPosition.HasValue)
				{
					instanceData.scrollPosition = instanceData.rawEventLog.Count - num;
				}
				instanceData.scrollPosition -= (int)Input.mouseScrollDelta.y;
				if (instanceData.scrollPosition < 0)
				{
					instanceData.scrollPosition = 0;
				}
				if (instanceData.scrollPosition >= instanceData.rawEventLog.Count - num)
				{
					instanceData.scrollPosition = null;
				}
			}
			int sequenceHashCode = instanceData.rawEventLog.GetSequenceHashCode();
			if (instanceData.scrollPosition == instanceData.previousScrollPosition && sequenceHashCode == instanceData.previousRawEventLogHash)
			{
				return;
			}
			instanceData.previousScrollPosition = instanceData.scrollPosition;
			instanceData.previousRawEventLogHash = sequenceHashCode;
			Enumerator<PUI_GameEventLog_Item> enumerator = __instance.m_logItems.GetEnumerator();
			while (enumerator.MoveNext())
			{
				PUI_GameEventLog_Item current = enumerator.Current;
				Object.Destroy((Object)(object)((Component)current).gameObject);
			}
			__instance.m_logItems.Clear();
			int num2 = instanceData.scrollPosition ?? Mathf.Max(instanceData.rawEventLog.Count - num, 0);
			int count = Mathf.Min(num, instanceData.rawEventLog.Count - num2);
			foreach (var item3 in instanceData.rawEventLog.GetRange(num2, count))
			{
				string item = item3.Item1;
				eGameEventChatLogType item2 = item3.Item2;
				PUI_GameEventLog_Item val = GOUtil.SpawnChildAndGetComp<PUI_GameEventLog_Item>(__instance.m_logItemPrefab, __instance.m_itemAlign);
				((RectTransformComp)val).Setup();
				val.SetText(item);
				val.SetType(item2);
				__instance.m_logItems.Add(val);
			}
			__instance.ShowAndUpdateItemPositions();
			__instance.ResetHideTimer();
		}
	}
	internal class PUI_GameEventLog_ExtensionData
	{
		public int instanceID;

		public List<(string, eGameEventChatLogType)> rawEventLog = new List<(string, eGameEventChatLogType)>();

		public int previousRawEventLogHash = 0;

		public int? scrollPosition = null;

		public int? previousScrollPosition = null;

		public PUI_GameEventLog_ExtensionData(int instanceID)
		{
			this.instanceID = instanceID;
		}
	}
	internal static class Extensions
	{
		public static int GetSequenceHashCode<T>(this List<T> sequence)
		{
			return sequence.Aggregate(487, (int current, T item) => current * 31 + (item?.GetHashCode() ?? 0));
		}
	}
	internal static class Utils
	{
		private static ManualLogSource logger = Logger.CreateLogSource("Andocas.BetterTextChat");

		public static void LogInfo(string text)
		{
			logger.LogInfo((object)text);
		}

		public static void LogError(string text)
		{
			logger.LogError((object)text);
		}

		public static void SendChatMessage(string text)
		{
			LogInfo("SendChatMessage: " + text);
			string text2 = "<color=yellow>";
			int num = 50 - text2.Length;
			while (text.Length > num)
			{
				PlayerChatManager.WantToSentTextMessage(PlayerManager.GetLocalPlayerAgent(), text2 + text.Substring(0, num).Trim(), (PlayerAgent)null);
				text = text.Substring(num).Trim();
			}
			PlayerChatManager.WantToSentTextMessage(PlayerManager.GetLocalPlayerAgent(), text2 + text, (PlayerAgent)null);
		}

		public static void SendLocalMessage(string text)
		{
			LogInfo("SendLocalMessage: " + text);
			GuiManager.PlayerLayer.m_gameEventLog.AddLogItem("<color=yellow>" + text, (eGameEventChatLogType)2);
			CM_PageLoadout.Current.m_gameEventLog.AddLogItem("<color=yellow>" + text, (eGameEventChatLogType)2);
		}

		public static string WordWrap(string original_text, int width)
		{
			StringBuilder stringBuilder = new StringBuilder();
			StringBuilder stringBuilder2 = new StringBuilder();
			StringBuilder stringBuilder3 = new StringBuilder();
			foreach (char c in original_text)
			{
				switch (c)
				{
				case '\n':
					if (stringBuilder2.Length + stringBuilder3.Length > width)
					{
						stringBuilder.Append(stringBuilder2);
						stringBuilder.Append('\n');
						stringBuilder2.Clear();
					}
					stringBuilder2.Append(stringBuilder3);
					stringBuilder3.Clear();
					stringBuilder.Append(stringBuilder2);
					stringBuilder.Append('\n');
					stringBuilder2.Clear();
					break;
				case ' ':
					if (stringBuilder2.Length + stringBuilder3.Length > width)
					{
						stringBuilder.Append(stringBuilder2);
						stringBuilder.Append('\n');
						stringBuilder2.Clear();
					}
					stringBuilder2.Append(stringBuilder3);
					stringBuilder2.Append(' ');
					stringBuilder3.Clear();
					break;
				default:
					stringBuilder3.Append(c);
					if (stringBuilder3.Length > width)
					{
						int num = width - stringBuilder2.Length;
						stringBuilder2.Append(stringBuilder3.ToString(0, num));
						stringBuilder3.Remove(0, num);
						stringBuilder.Append(stringBuilder2);
						stringBuilder.Append('\n');
						stringBuilder2.Clear();
					}
					break;
				}
			}
			if (stringBuilder2.Length + stringBuilder3.Length > width)
			{
				stringBuilder.Append(stringBuilder2);
				stringBuilder.Append('\n');
				stringBuilder2.Clear();
			}
			stringBuilder2.Append(stringBuilder3);
			stringBuilder3.Clear();
			stringBuilder.Append(stringBuilder2);
			stringBuilder2.Clear();
			if (stringBuilder.Length > 0 && stringBuilder[stringBuilder.Length - 1] == '\n' && original_text[original_text.Length - 1] != '\n')
			{
				stringBuilder.Remove(stringBuilder.Length - 1, 1);
			}
			return stringBuilder.ToString();
		}
	}
	[BepInPlugin("Andocas.BetterTextChat", "Andocas.BetterTextChat", "0.3.1")]
	internal class Plugin : BasePlugin
	{
		public override void Load()
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Expected O, but got Unknown
			Utils.LogInfo("BetterTextChat is loading...");
			PUI_GameEventLog.s_logItemsMax = ConfigManager.chatHistoryLength.Value;
			Harmony val = new Harmony("BetterTextChat");
			val.PatchAll(typeof(BetterChatComposition));
			val.PatchAll(typeof(ScrollableGameEventLog));
			Utils.LogInfo("BetterTextChat is loaded");
		}
	}
	internal static class ConfigManager
	{
		public static readonly ConfigEntry<bool> allowForbiddenChars;

		public static readonly ConfigEntry<bool> discardDraftMessage;

		public static readonly ConfigEntry<int> chatHistoryLength;

		static ConfigManager()
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Expected O, but got Unknown
			ConfigFile val = new ConfigFile(Path.Combine(Paths.ConfigPath, "BetterTextChat.cfg"), true);
			allowForbiddenChars = val.Bind<bool>("General", "Allow special characters", true, "Makes it possible to type <, >, and = in chat. (Beware: Things can get weird if you use formatting tags, especially across multiple lines.)");
			discardDraftMessage = val.Bind<bool>("General", "Discard draft message", false, "In vanilla, when you close the chat box, your message will still be there next time you open it. This option clears the chat box when it's closed.");
			chatHistoryLength = val.Bind<int>("General", "Chat history length", 15, "Number of messages to show at once in the chat history.");
		}
	}
}