using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using System.Text.RegularExpressions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using Mirror; using Nessie.ATLYSS.EasySettings; using TMPro; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.Events; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("ChatX")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("3.1.0.0")] [assembly: AssemblyInformationalVersion("3.1.0+4c913a7c0d55f8366ddcb3969839b76de08d1c83")] [assembly: AssemblyProduct("ChatX")] [assembly: AssemblyTitle("ChatX")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("3.1.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 ChatX { internal sealed class ChatLinkClickHandler : MonoBehaviour, IPointerClickHandler, IEventSystemHandler, IPointerDownHandler, IPointerUpHandler, IInitializePotentialDragHandler, IBeginDragHandler, IDragHandler, IEndDragHandler, IScrollHandler { private ChatBehaviourAssets _assets; private ScrollRect _scrollRect; private TextMeshProUGUI _chatText; private bool _dragInProgress; internal void Bind(ChatBehaviourAssets assets, ScrollRect scrollRect, TextMeshProUGUI chatText) { _assets = assets; _scrollRect = scrollRect; _chatText = chatText; } public void OnPointerClick(PointerEventData eventData) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) if (eventData == null || (int)eventData.button != 0 || _dragInProgress || (Object)(object)_chatText == (Object)null || ChatX.IsChatLinkPromptOpen) { return; } Camera val = eventData.pressEventCamera ?? eventData.enterEventCamera; int num = TMP_TextUtilities.FindIntersectingLink((TMP_Text)(object)_chatText, Vector2.op_Implicit(eventData.position), val); if (num >= 0 && num < ((TMP_Text)_chatText).textInfo.linkCount) { string linkID = ((TMP_LinkInfo)(ref ((TMP_Text)_chatText).textInfo.linkInfo[num])).GetLinkID(); if (!string.IsNullOrWhiteSpace(linkID)) { ChatX.ShowChatLinkPrompt(_assets, linkID); } } } public void OnPointerDown(PointerEventData eventData) { _dragInProgress = false; } public void OnPointerUp(PointerEventData eventData) { _dragInProgress = false; } public void OnInitializePotentialDrag(PointerEventData eventData) { ForwardToScrollRect((BaseEventData)(object)eventData, ExecuteEvents.initializePotentialDrag); } public void OnBeginDrag(PointerEventData eventData) { _dragInProgress = true; ForwardToScrollRect((BaseEventData)(object)eventData, ExecuteEvents.beginDragHandler); } public void OnDrag(PointerEventData eventData) { _dragInProgress = true; ForwardToScrollRect((BaseEventData)(object)eventData, ExecuteEvents.dragHandler); } public void OnEndDrag(PointerEventData eventData) { ForwardToScrollRect((BaseEventData)(object)eventData, ExecuteEvents.endDragHandler); _dragInProgress = false; } public void OnScroll(PointerEventData eventData) { ForwardToScrollRect((BaseEventData)(object)eventData, ExecuteEvents.scrollHandler); } private void ForwardToScrollRect(BaseEventData eventData, EventFunction handler) where T : IEventSystemHandler { if (!((Object)(object)_scrollRect == (Object)null) && eventData != null) { ExecuteEvents.Execute(((Component)_scrollRect).gameObject, eventData, handler); } } } [BepInPlugin("ChatX", "ChatX", "3.1.0")] public class ChatX : BaseUnityPlugin { private enum PromptButtonIconKind { Confirm, Copy, Cancel } private sealed class ProtectedChatLink { public string Token; public string DisplayText; public string CanonicalUrl; } internal sealed class ChatScrollbarState { public CanvasGroup Scrollbar; public GameObject ScrollbarObject; public Scrollbar ScrollbarComponent; public ScrollRect ScrollRect; public GameObject ChatContainer; public bool? CachedChatContainerActive; public bool? CachedChannelDockActive; } [HarmonyPatch(typeof(ChatBehaviour), "New_ChatMessage")] private static class ChatBehaviour_New_ChatMessage_PrefixAndBlock { [HarmonyPrefix] [HarmonyPriority(800)] private static bool Prefix(ref string __0) { //IL_0087: Unknown result type (might be due to invalid IL or missing references) ConfigEntry blockChat = ChatX.blockChat; if (blockChat != null && blockChat.Value) { return false; } __0 = ProtectChatLinks(__0, out var protectedLinks); string badge = ExtractRenderedOocBadge(ref __0); ConfigEntry asteriskItalic = ChatX.asteriskItalic; if (asteriskItalic != null && asteriskItalic.Value) { __0 = ApplyAsteriskFormatting(__0); } string prefix = string.Empty; ConfigEntry chatPrefix = ChatX.chatPrefix; if (chatPrefix != null && chatPrefix.Value && !LooksPrefixed(__0) && TryExtractChatChannel(__0, out var channel)) { prefix = BuildMessagePrefix(channel); } string text = CombinePrefixSegments(prefix, badge); if (!string.IsNullOrEmpty(text)) { __0 = InsertPrefix(__0, text); } ApplyMentionEffects(ref __0); __0 = RestoreProtectedChatLinks(__0, protectedLinks); return true; } [HarmonyPostfix] [HarmonyPriority(0)] private static void Postfix(ChatBehaviour __instance) { if (Object.op_Implicit((Object)(object)__instance)) { EnsureChatLinkUi(__instance._chatAssets); ApplyOpacityCap(__instance._chatAssets); } } } [HarmonyPatch(typeof(ChatBehaviour), "Init_GameLogicMessage")] private static class ChatBehaviour_Init_GameLogicMessage_Block { [HarmonyPrefix] [HarmonyPriority(800)] private static bool Prefix() { ConfigEntry blockGameFeed = ChatX.blockGameFeed; return blockGameFeed == null || !blockGameFeed.Value; } } [HarmonyPatch(typeof(PatternInstanceManager), "On_DungeonKeyChange")] private static class PatternInstanceManager_OnDungeonKeyChange_Reroute { private static readonly MethodInfo NewChatMessage = AccessTools.Method(typeof(ChatBehaviour), "New_ChatMessage", (Type[])null, (Type[])null); private static readonly MethodInfo PushGameFeed = AccessTools.Method(typeof(ChatX), "PushGameFeedMessage", (Type[])null, (Type[])null); private static IEnumerable Transpiler(IEnumerable instructions) { return ReplaceMethodCalls(instructions, NewChatMessage, PushGameFeed, 2, "PatternInstanceManager.On_DungeonKeyChange reroute"); } } [HarmonyPatch(typeof(PlayerQuesting), "Accept_Quest")] private static class PlayerQuesting_AcceptQuest_RerouteObjectivePickup { private static readonly MethodInfo NewChatMessage = AccessTools.Method(typeof(ChatBehaviour), "New_ChatMessage", (Type[])null, (Type[])null); private static readonly MethodInfo PushGameFeed = AccessTools.Method(typeof(ChatX), "PushGameFeedMessage", (Type[])null, (Type[])null); private static IEnumerable Transpiler(IEnumerable instructions) { return ReplaceMethodCalls(instructions, NewChatMessage, PushGameFeed, 1, "PlayerQuesting.Accept_Quest reroute"); } } [HarmonyPatch(typeof(WorldPortalWaypoint), "OnTriggerEnter")] private static class WorldPortalWaypoint_OnTriggerEnter_RerouteAttuneChat { private static readonly MethodInfo NewChatMessage = AccessTools.Method(typeof(ChatBehaviour), "New_ChatMessage", (Type[])null, (Type[])null); private static readonly MethodInfo RouteAttune = AccessTools.Method(typeof(ChatX), "RouteWaypointAttuneMessage", (Type[])null, (Type[])null); private static IEnumerable Transpiler(IEnumerable instructions) { return ReplaceMethodCalls(instructions, NewChatMessage, RouteAttune, 1, "WorldPortalWaypoint.OnTriggerEnter reroute"); } } [HarmonyPatch(typeof(NetTrigger))] private static class NetTrigger_OnTriggerStay_RerouteDungeonKeyMessage { private static readonly MethodInfo TargetReceive = AccessTools.Method(typeof(ChatBehaviour), "Target_RecieveMessage", (Type[])null, (Type[])null); private static readonly MethodInfo RouteTarget = AccessTools.Method(typeof(ChatX), "PushTargetedGameFeedMessage", (Type[])null, (Type[])null); private static MethodBase TargetMethod() { return AccessTools.Method(typeof(NetTrigger), "OnTriggerStay", (Type[])null, (Type[])null); } private static IEnumerable Transpiler(IEnumerable instructions) { return ReplaceMethodCalls(instructions, TargetReceive, RouteTarget, 1, "NetTrigger.OnTriggerStay reroute"); } } [HarmonyPatch(typeof(ChatBehaviour), "UserCode_Target_RecieveMessage__String")] private static class ChatBehaviour_TargetReceiveMessage_RerouteDungeonKey { private const string DoorLockedMessage = "The door is locked. It requires a Dungeon Key."; private static bool Prefix(ChatBehaviour __instance, string _message) { if (!ShouldPushGameFeed()) { return true; } if (!Object.op_Implicit((Object)(object)__instance) || string.IsNullOrEmpty(_message)) { return true; } if (!string.Equals(_message, "The door is locked. It requires a Dungeon Key.", StringComparison.Ordinal)) { return true; } PushGameFeedMessage(__instance, _message); return false; } } [HarmonyPatch(typeof(ChatBehaviour), "Display_Chat")] private static class ChatBehaviourDisplayPatch { private static void Postfix(ChatBehaviour __instance) { if (Object.op_Implicit((Object)(object)__instance)) { ApplyOpacityCap(__instance._chatAssets); } } } [HarmonyPatch(typeof(ChatBehaviour), "Client_HandleChatboxUpdate")] private static class ChatBehaviour_CapOpacity_Postfix { [HarmonyPostfix] private static void Postfix(ChatBehaviour __instance) { if (Object.op_Implicit((Object)(object)__instance)) { ApplyOpacityCap(__instance._chatAssets); } } } [HarmonyPatch(typeof(ChatBehaviour), "Client_HandleChatboxUpdate")] private static class ChatBehaviour_HandleChatControls_PreOpen { [HarmonyPrefix] [HarmonyPriority(800)] private static void Prefix(ChatBehaviour __instance) { if (Object.op_Implicit((Object)(object)__instance) && ((NetworkBehaviour)__instance).isLocalPlayer && ChatBehaviour._current == __instance && IsChatSubmitKeyPressed()) { ChatBehaviourAssets chatAssets = __instance._chatAssets; bool flag = ChatInputResolver.TryGet(chatAssets)?.IsFocused ?? false; CanvasGroup val = (Object.op_Implicit((Object)(object)chatAssets) ? chatAssets._generalCanvasGroup : null); bool flag2 = Object.op_Implicit((Object)(object)val) && val.blocksRaycasts && val.interactable; bool flag3 = Object.op_Implicit((Object)(object)val) && val.alpha <= 0.001f && !flag2; if (!(__instance._focusedInChat || flag) && flag3) { pendingRestore = true; ResetChatFocus(); } } } } [HarmonyPatch(typeof(SettingsManager), "Load_SettingsData")] private static class ChatInputLimit_OnLoad { private static void Postfix() { ChatInputCharacterLimiter.ApplyCharacterLimit(); ChatWindowResizer.ApplyAll(); } } [HarmonyPatch(typeof(SettingsManager), "Save_SettingsData")] private static class ChatInputLimit_OnSave { private static void Postfix() { ChatInputCharacterLimiter.ApplyCharacterLimit(); ChatWindowResizer.ApplyAll(); } } [HarmonyPatch(typeof(ChatBehaviourAssets), "Start")] private static class ChatInputLimit_OnChatAssetsStart { private static void Postfix(ChatBehaviourAssets __instance) { ChatWindowResizer.Register(__instance); EnsureChatLinkUi(__instance); ChatInputHandle chatInputHandle = ChatInputResolver.TryGet(__instance); if (chatInputHandle != null) { chatInputHandle.CharacterLimit = GetMaxMessageLength(); } } } [HarmonyPatch(typeof(ChatBehaviour), "OnStartAuthority")] private static class ChatBehaviour_OnStartAuthority_Patch { private static void Postfix(ChatBehaviour __instance) { ((MonoBehaviour)__instance).StartCoroutine(ChatInputCharacterLimiter.ApplyWhenReady(__instance)); } } [HarmonyPatch(typeof(InGameUI), "RefreshParams_LocatePlayer")] private static class ApplyLimit_AfterPlayerLocated { private static void Postfix() { ChatInputCharacterLimiter.ApplyCharacterLimit(); ChatWindowResizer.ApplyAll(); EnsureChatLinkUi(ChatBehaviourAssets._current); } } [HarmonyPatch(typeof(ChatBehaviour), "Send_ChatMessage")] private static class ChatBehaviour_SendMessage_Ooc { [HarmonyPrefix] [HarmonyPriority(800)] private static bool Prefix(ChatBehaviour __instance, ref string __0, out string __state) { __state = null; if (!ShouldInterceptOutgoingChat(__0)) { return true; } if (TryHandleLocalOocToggle(__instance, __0)) { return false; } string transformedMessage; string errorPrompt; switch (PrepareOutgoingChatMessage(__0, out transformedMessage, out errorPrompt)) { case OutgoingChatPreparationStatus.Suppressed: FinalizeLocalChatCommand(__instance); return false; case OutgoingChatPreparationStatus.Invalid: ShowOutgoingChatValidationError(__instance, errorPrompt, __0); return false; case OutgoingChatPreparationStatus.Transformed: __state = __0; __0 = transformedMessage; break; } return true; } [HarmonyPostfix] private static void Postfix(ChatBehaviour __instance, string __state) { if (!string.IsNullOrEmpty(__state)) { RestoreLastTypedChatMessage(__instance, __state); } } } [HarmonyPatch(typeof(ChatBehaviour), "Send_ChatMessage")] private static class ChatBehaviour_SendMessage_Transpiler { private static IEnumerable Transpiler(IEnumerable instrs) { return ReplaceMaxLengthGuards(instrs, 1, "ChatBehaviour.Send_ChatMessage max length"); } } [HarmonyPatch(typeof(ChatBehaviour), "UserCode_Cmd_SendChatMessage__String__ChatChannel")] private static class ChatBehaviour_CmdSendMessage_Transpiler { private static IEnumerable Transpiler(IEnumerable instrs) { return ReplaceMaxLengthGuards(instrs, 1, "ChatBehaviour.UserCode_Cmd_SendChatMessage__String__ChatChannel max length"); } } private enum OutgoingChatPreparationStatus { Unchanged, Transformed, Suppressed, Invalid } public enum MentionClip { LexiconBell, UIClick01, UIHover, Lockout } [CompilerGenerated] private static class <>O { public static UnityAction <0>__OpenPendingChatLink; public static UnityAction <1>__CopyPendingChatLink; public static UnityAction <2>__CancelPendingChatLink; public static EventHandler <3>__OnChatTallWindowChanged; public static EventHandler <4>__OnTransparentScrollbarChanged; public static EventHandler <5>__OnMentionPingChanged; public static EventHandler <6>__OnMentionPingClipChanged; public static EventHandler <7>__OnMentionPingVolumeChanged; public static EventHandler <8>__OnOocEnabledChanged; } private static readonly Type PartyUiManagerType = typeof(Player).Assembly.GetType("PartyUIManager"); private static readonly FieldInfo PartyUiCurrentField = AccessTools.Field(PartyUiManagerType, "_current"); private static readonly FieldInfo PartyInviteElementField = AccessTools.Field(PartyUiManagerType, "_partyInviteElement"); private static readonly FieldInfo PartyAcceptInviteButtonField = AccessTools.Field(PartyUiManagerType, "_acceptInviteButton"); private static readonly FieldInfo PartyDeclineInviteButtonField = AccessTools.Field(PartyUiManagerType, "_declineInviteButton"); private static readonly FieldInfo PartyInvitePromptField = AccessTools.Field(PartyUiManagerType, "_invitedByPrompt"); private static readonly FieldInfo PartyPanelGroupField = AccessTools.Field(PartyUiManagerType, "_partyPanelGroup"); private static readonly FieldInfo MenuElementRectField = AccessTools.Field(typeof(MenuElement), "menuRect"); private static readonly FieldInfo MenuElementCanvasGroupField = AccessTools.Field(typeof(MenuElement), "_canvasGroup"); private static GameObject _chatLinkPromptRoot; private static MenuElement _chatLinkPromptElement; private static CanvasGroup _chatLinkPromptCanvasGroup; private static TextMeshProUGUI _chatLinkPromptText; private static Text _chatLinkPromptTextLegacy; private static Button _chatLinkOpenButton; private static Button _chatLinkCopyButton; private static Button _chatLinkCancelButton; private static string _pendingChatLinkUrl; private static bool _chatLinkPromptOpen; private const string ChatLinkOverlayName = "ChatX_LinkClickOverlay"; private static readonly Regex UrlRegex = new Regex("\\b(?:https?://|www\\.)[^\\s<]+", RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.CultureInvariant); internal static readonly ConditionalWeakTable _scrollbarStates = new ConditionalWeakTable(); private static bool _dialogSuppressed; private static bool pendingRestore; private static bool _chatWasHidden; internal static readonly FieldInfo ChatInputBufferField = typeof(ChatBehaviour).GetField("_inputBuffer", BindingFlags.Instance | BindingFlags.NonPublic); private static bool _loggedMissingInputBufferField; private static bool _chatHidden; internal static ManualLogSource Log; private static readonly MethodInfo GetMaxMessageLengthMethod = AccessTools.Method(typeof(ChatX), "GetMaxMessageLength", (Type[])null, (Type[])null); private static readonly MethodInfo StringLengthGetter = AccessTools.PropertyGetter(typeof(string), "Length"); internal static AudioClip _mentionAudioClip; private static float _nextMentionPingAllowedAt; private static readonly Dictionary _mentionClipCache = new Dictionary(StringComparer.OrdinalIgnoreCase); private static Type _cachedPlayerSoundType; private static FieldInfo[] _cachedPlayerSoundClipFields; private static Type _cachedButtonSoundType; private static FieldInfo _cachedButtonSoundHoverField; private static FieldInfo _cachedButtonSoundClickField; private static string _lastMissingMentionClipName; private const string OocToken = "[OOC]"; private const string OocPrefix = "[OOC] "; private const string OocToggleCommand = "/ooc"; private static readonly FieldInfo ChatLastMessageField = AccessTools.Field(typeof(ChatBehaviour), "_lastMessage"); private static readonly Type ErrorPromptManagerType = typeof(Player).Assembly.GetType("ErrorPromptTextManager"); private static readonly FieldInfo ErrorPromptCurrentField = AccessTools.Field(ErrorPromptManagerType, "current"); private static readonly MethodInfo ErrorPromptInitMethod = AccessTools.Method(ErrorPromptManagerType, "Init_ErrorPrompt", (Type[])null, (Type[])null); private static bool _oocModeEnabled; internal static ConfigEntry chatOpacity; internal static ConfigEntry blockChat; internal static ConfigEntry blockGameFeed; internal static ConfigEntry chatPrefix; internal static ConfigEntry chatTimestamp; internal static ConfigEntry timestampFormat; internal static ConfigEntry asteriskItalic; internal static ConfigEntry oocEnabled; internal static ConfigEntry chatTallWindow; internal static ConfigEntry clearChatKey; internal static ConfigEntry toggleChatVisibilityKey; internal static ConfigEntry messageLimit; internal static ConfigEntry pushGameMessage; internal static ConfigEntry mentionUnderline; internal static ConfigEntry mentionPing; internal static ConfigEntry mentionPingClip; internal static ConfigEntry mentionPingClipEnum; internal static ConfigEntry mentionPingVolume; internal static ConfigEntry transparentScrollbar; private static bool _settingsRegistered; private const string SettingsTabName = "Chat"; private static readonly MethodInfo GetOrAddCustomTabMethod = typeof(Settings).GetMethod("GetOrAddCustomTab", BindingFlags.Static | BindingFlags.Public, null, new Type[1] { typeof(string) }, null); private static bool _loggedMissingCustomTabApi; private static readonly string[] ClipNames = new string[4] { "_lexiconBell", "_uiClick01", "_uiHover", "lockout" }; internal static bool IsChatLinkPromptOpen => _chatLinkPromptOpen; private static string NormalizeChannelColorToken(string token) { if (string.IsNullOrWhiteSpace(token)) { return string.Empty; } token = token.Trim(); if (token.StartsWith("#", StringComparison.Ordinal) && token.Length >= 7) { token = token.Substring(0, 7); } return token.ToUpperInvariant(); } private static bool TryExtractChatChannel(string message, out ChatChannel channel) { channel = (ChatChannel)0; if (string.IsNullOrEmpty(message)) { return false; } int num = message.IndexOf(": : = message.Length) { return false; } int num3 = message.IndexOf('>', num2); if (num3 < 0) { return false; } int num4 = num2; string token = message.Substring(num4, num3 - num4); string text = NormalizeChannelColorToken(token); if (string.IsNullOrEmpty(text)) { return false; } switch (text) { case "YELLOW": case "#FFFF00": case "#FFD700": channel = (ChatChannel)0; return true; case "#B2EC5D": channel = (ChatChannel)1; return true; case "#FF8A90": channel = (ChatChannel)2; return true; default: return false; } } private static int SkipTimestampPrefix(string msg, int startIndex = 0) { if (string.IsNullOrEmpty(msg) || startIndex >= msg.Length) { return startIndex; } if (msg[startIndex] != '[') { return startIndex; } int num = startIndex + 1; if (num >= msg.Length || !char.IsDigit(msg[num])) { return startIndex; } num++; if (num < msg.Length && char.IsDigit(msg[num])) { num++; } if (num >= msg.Length || msg[num] != ':') { return startIndex; } num++; if (num + 1 >= msg.Length || !char.IsDigit(msg[num]) || !char.IsDigit(msg[num + 1])) { return startIndex; } num += 2; if (num < msg.Length && msg[num] == ' ') { if (num + 2 >= msg.Length || (msg[num + 1] != 'A' && msg[num + 1] != 'a' && msg[num + 1] != 'P' && msg[num + 1] != 'p') || (msg[num + 2] != 'M' && msg[num + 2] != 'm')) { return startIndex; } num += 3; } if (num >= msg.Length || msg[num] != ']') { return startIndex; } num++; if (num < msg.Length && msg[num] == ' ') { num++; } return num; } public static string BuildColoredPrefixFromEnum(ChatChannel ch) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Expected I4, but got Unknown if (1 == 0) { } string result = (int)ch switch { 0 => "(G)", 1 => "(P)", 2 => "(Z)", _ => string.Empty, }; if (1 == 0) { } return result; } public static string BuildMessagePrefix(ChatChannel ch) { //IL_0057: Unknown result type (might be due to invalid IL or missing references) string text = null; ConfigEntry obj = chatTimestamp; if (obj != null && obj.Value) { string text2 = (timestampFormat.Value ? "HH:mm" : "h:mm tt"); text = "[" + DateTime.Now.ToString(text2, CultureInfo.InvariantCulture) + "]"; } string text3 = BuildColoredPrefixFromEnum(ch); if (string.IsNullOrEmpty(text3)) { text3 = null; } if (text == null && text3 == null) { return string.Empty; } if (text != null && text3 != null) { return text + " " + text3 + " "; } return (text ?? text3) + " "; } public static string BuildOocBadge() { return "[OOC]"; } public static string ExtractRenderedOocBadge(ref string message) { if (!IsOocFeatureEnabled() || string.IsNullOrEmpty(message)) { return string.Empty; } int num = message.IndexOf(": : ', startIndex); if (num2 < 0) { return string.Empty; } int startIndex2 = num2 + 1; if (!TryFindLeadingOocToken(message, startIndex2, out var tokenStart, out var tokenLength, out var trailingSpaceStart, out var trailingSpaceLength)) { return string.Empty; } if (trailingSpaceLength > 0) { message = message.Remove(trailingSpaceStart, trailingSpaceLength); } message = message.Remove(tokenStart, tokenLength); return BuildOocBadge(); } public static string CombinePrefixSegments(string prefix, string badge) { bool flag = !string.IsNullOrWhiteSpace(prefix); bool flag2 = !string.IsNullOrWhiteSpace(badge); if (!flag && !flag2) { return string.Empty; } prefix = (flag ? prefix.TrimEnd() : string.Empty); badge = (flag2 ? badge.Trim() : string.Empty); if (!flag) { return badge + " "; } if (!flag2) { return prefix.EndsWith(" ", StringComparison.Ordinal) ? prefix : (prefix + " "); } return prefix + " " + badge + " "; } public static bool LooksPrefixed(string msg) { if (string.IsNullOrEmpty(msg)) { return false; } int num = SkipTimestampPrefix(msg); if (msg.Length - num >= 4 && msg[num] == '(' && (msg[num + 1] == 'G' || msg[num + 1] == 'P' || msg[num + 1] == 'Z') && msg[num + 2] == ')' && msg[num + 3] == ' ') { return true; } if (num < msg.Length && msg.IndexOf("', num); if (num2 >= 0) { int num3 = msg.IndexOf("", num2 + 1, StringComparison.OrdinalIgnoreCase); if (num3 > num2 + 1) { int num4 = num2 + 1; string text = msg.Substring(num4, num3 - num4); if (text.StartsWith("(G)") || text.StartsWith("(P)") || text.StartsWith("(Z)")) { return true; } } } } return false; } public static string InsertPrefix(string line, string prefix) { if (string.IsNullOrEmpty(prefix) || string.IsNullOrEmpty(line)) { return line; } return prefix + line; } public static string ApplyAsteriskFormatting(string s) { ConfigEntry obj = asteriskItalic; if (obj == null || !obj.Value || string.IsNullOrEmpty(s) || s.IndexOf('*') < 0) { return s; } StringBuilder stringBuilder = new StringBuilder(s.Length + 16); ReadOnlySpan readOnlySpan = s.AsSpan(); bool flag = false; bool flag2 = false; bool flag3 = false; int num = -1; int num2 = -1; for (int i = 0; i < readOnlySpan.Length; i++) { char c = readOnlySpan[i]; if (c == '<') { flag3 = true; stringBuilder.Append(c); } else if (c == '>' && flag3) { flag3 = false; stringBuilder.Append(c); } else if (c == '\\' && i + 1 < readOnlySpan.Length && readOnlySpan[i + 1] == '*') { stringBuilder.Append('*'); i++; } else if (c == '*' && !flag3) { int j; for (j = i + 1; j < readOnlySpan.Length && readOnlySpan[j] == '*'; j++) { } int num3 = j - i; if (num3 >= 2) { int num4; for (num4 = num3; num4 >= 2; num4 -= 2) { if (flag2) { stringBuilder.Append(""); flag2 = false; num2 = -1; } else { num2 = stringBuilder.Length; stringBuilder.Append(""); flag2 = true; } } if (num4 == 1) { if (flag) { stringBuilder.Append(""); flag = false; num = -1; } else { num = stringBuilder.Length; stringBuilder.Append(""); flag = true; } } } else if (flag) { stringBuilder.Append(""); flag = false; num = -1; } else { num = stringBuilder.Length; stringBuilder.Append(""); flag = true; } i = j - 1; } else { stringBuilder.Append(c); } } if (flag2 && num2 >= 0) { stringBuilder.Remove(num2, 3).Insert(num2, "**"); if (num > num2) { num += -1; } } if (flag && num >= 0) { stringBuilder.Remove(num, 3).Insert(num, "*"); } return stringBuilder.ToString(); } private static bool IsChatSubmitKeyPressed() { return Input.GetKeyDown((KeyCode)13) || Input.GetKeyDown((KeyCode)271); } internal static Transform FindDescendantTransformByName(Transform root, string name) { if ((Object)(object)root == (Object)null || string.IsNullOrEmpty(name)) { return null; } Queue queue = new Queue(); queue.Enqueue(root); while (queue.Count > 0) { Transform val = queue.Dequeue(); if (!((Object)(object)val == (Object)null)) { if (((Object)val).name == name) { return val; } for (int i = 0; i < val.childCount; i++) { queue.Enqueue(val.GetChild(i)); } } } return null; } internal static T FindDescendantComponentByName(Transform root, string name) where T : Component { Transform val = FindDescendantTransformByName(root, name); return ((Object)(object)val != (Object)null) ? ((Component)val).GetComponent() : default(T); } internal static void ResetLinkPromptRuntimeState() { _pendingChatLinkUrl = null; _chatLinkPromptOpen = false; _chatLinkPromptElement = null; _chatLinkPromptText = null; _chatLinkPromptTextLegacy = null; _chatLinkOpenButton = null; _chatLinkCopyButton = null; _chatLinkCancelButton = null; _chatLinkPromptCanvasGroup = null; if ((Object)(object)_chatLinkPromptRoot != (Object)null && !((object)_chatLinkPromptRoot).Equals((object?)null)) { Object.Destroy((Object)(object)_chatLinkPromptRoot); } _chatLinkPromptRoot = null; } internal static bool PollLinkPromptHotkeys() { if (!_chatLinkPromptOpen) { return false; } if (Input.GetKeyDown((KeyCode)27)) { CancelPendingChatLink(); return true; } if (IsChatSubmitKeyPressed()) { OpenPendingChatLink(); return true; } return false; } internal static void ShowChatLinkPrompt(ChatBehaviourAssets assets, string url) { if (_chatLinkPromptOpen) { return; } if (!TryCanonicalizeUrl(url, out var canonicalUrl)) { ShowErrorPrompt("That link is invalid."); return; } EnsureChatLinkPrompt(assets ?? ChatBehaviourAssets._current); if ((Object)(object)_chatLinkPromptRoot == (Object)null || ((object)_chatLinkPromptRoot).Equals((object?)null)) { ShowErrorPrompt("Chat link prompts are unavailable right now."); return; } _pendingChatLinkUrl = canonicalUrl; SetChatLinkPromptText(canonicalUrl); SetChatLinkPromptVisible(visible: true); EventSystem current = EventSystem.current; if (current != null) { current.SetSelectedGameObject(((Object)(object)_chatLinkOpenButton != (Object)null) ? ((Component)_chatLinkOpenButton).gameObject : null); } } private static void OpenPendingChatLink() { string pendingChatLinkUrl = _pendingChatLinkUrl; HideChatLinkPrompt(); if (!TryCanonicalizeUrl(pendingChatLinkUrl, out var canonicalUrl)) { ShowErrorPrompt("That link is invalid."); } else { Application.OpenURL(canonicalUrl); } } private static void CopyPendingChatLink() { string pendingChatLinkUrl = _pendingChatLinkUrl; HideChatLinkPrompt(); if (!TryCanonicalizeUrl(pendingChatLinkUrl, out var canonicalUrl)) { ShowErrorPrompt("That link is invalid."); return; } try { GUIUtility.systemCopyBuffer = canonicalUrl; PushLocalChatStatus(ChatBehaviour._current, "Link copied to clipboard."); } catch (Exception ex) { ManualLogSource log = Log; if (log != null) { log.LogDebug((object)("ChatX could not copy the pending link: " + ex.Message)); } ShowErrorPrompt("Could not copy that link."); } } private static void CancelPendingChatLink() { HideChatLinkPrompt(); } private static void HideChatLinkPrompt() { _pendingChatLinkUrl = null; SetChatLinkPromptVisible(visible: false); EventSystem current = EventSystem.current; if (current != null) { current.SetSelectedGameObject((GameObject)null); } } private static void SetChatLinkPromptVisible(bool visible) { //IL_0060: Unknown result type (might be due to invalid IL or missing references) _chatLinkPromptOpen = visible; if ((Object)(object)_chatLinkPromptRoot == (Object)null || ((object)_chatLinkPromptRoot).Equals((object?)null)) { return; } if ((Object)(object)_chatLinkPromptElement != (Object)null) { _chatLinkPromptRoot.SetActive(true); RectTransform menuElementRect = GetMenuElementRect(_chatLinkPromptElement); if ((Object)(object)menuElementRect != (Object)null) { menuElementRect.anchoredPosition = Vector2.zero; } _chatLinkPromptElement.isEnabled = visible; } if ((Object)(object)_chatLinkPromptCanvasGroup != (Object)null) { _chatLinkPromptCanvasGroup.alpha = (visible ? 1f : 0f); _chatLinkPromptCanvasGroup.blocksRaycasts = visible; _chatLinkPromptCanvasGroup.interactable = visible; } if ((Object)(object)_chatLinkPromptElement == (Object)null) { _chatLinkPromptRoot.SetActive(visible); } if (visible) { Transform transform = _chatLinkPromptRoot.transform; RectTransform val = (RectTransform)(object)((transform is RectTransform) ? transform : null); if (val != null) { ((Transform)val).SetAsLastSibling(); LayoutRebuilder.ForceRebuildLayoutImmediate(val); } } } private static void SetChatLinkPromptText(string canonicalUrl) { string text = "Open this link in your browser?\n" + canonicalUrl; if ((Object)(object)_chatLinkPromptText != (Object)null) { ((TMP_Text)_chatLinkPromptText).text = text; } if ((Object)(object)_chatLinkPromptTextLegacy != (Object)null) { _chatLinkPromptTextLegacy.text = text; } } private static void EnsureChatLinkPrompt(ChatBehaviourAssets assets) { if (!((Object)(object)_chatLinkPromptRoot != (Object)null) || ((object)_chatLinkPromptRoot).Equals((object?)null)) { Transform val = ResolveChatLinkPromptParent(assets); if (!((Object)(object)val == (Object)null)) { int layer = (((Object)(object)assets != (Object)null) ? ((Component)assets).gameObject.layer : ((Component)val).gameObject.layer); TryCreatePromptFromPartyInvite(val, layer); } } } private static bool TryCreatePromptFromPartyInvite(Transform parent, int layer) { //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_0126: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_029d: Unknown result type (might be due to invalid IL or missing references) //IL_0220: Unknown result type (might be due to invalid IL or missing references) //IL_0225: Unknown result type (might be due to invalid IL or missing references) //IL_0229: Unknown result type (might be due to invalid IL or missing references) //IL_022e: Unknown result type (might be due to invalid IL or missing references) //IL_0230: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Unknown result type (might be due to invalid IL or missing references) //IL_0165: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Unknown result type (might be due to invalid IL or missing references) //IL_0142: 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) //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_023e: 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_0184: Unknown result type (might be due to invalid IL or missing references) //IL_0198: Unknown result type (might be due to invalid IL or missing references) //IL_019f: Unknown result type (might be due to invalid IL or missing references) //IL_01ab: Unknown result type (might be due to invalid IL or missing references) //IL_01b7: Unknown result type (might be due to invalid IL or missing references) //IL_01c3: Unknown result type (might be due to invalid IL or missing references) //IL_0261: Unknown result type (might be due to invalid IL or missing references) //IL_025a: Unknown result type (might be due to invalid IL or missing references) //IL_025f: Unknown result type (might be due to invalid IL or missing references) //IL_026f: Unknown result type (might be due to invalid IL or missing references) //IL_0288: Unknown result type (might be due to invalid IL or missing references) //IL_028f: Unknown result type (might be due to invalid IL or missing references) //IL_0401: Unknown result type (might be due to invalid IL or missing references) //IL_040b: Expected O, but got Unknown //IL_043c: Unknown result type (might be due to invalid IL or missing references) //IL_0446: Expected O, but got Unknown //IL_0426: Unknown result type (might be due to invalid IL or missing references) //IL_042b: Unknown result type (might be due to invalid IL or missing references) //IL_0431: Expected O, but got Unknown //IL_0477: Unknown result type (might be due to invalid IL or missing references) //IL_0481: Expected O, but got Unknown //IL_0461: Unknown result type (might be due to invalid IL or missing references) //IL_0466: Unknown result type (might be due to invalid IL or missing references) //IL_046c: Expected O, but got Unknown //IL_049c: Unknown result type (might be due to invalid IL or missing references) //IL_04a1: Unknown result type (might be due to invalid IL or missing references) //IL_04a7: Expected O, but got Unknown try { object obj = PartyUiCurrentField?.GetValue(null); object? obj2 = PartyInviteElementField?.GetValue(obj); MenuElement val = (MenuElement)((obj2 is MenuElement) ? obj2 : null); if (obj == null || (Object)(object)val == (Object)null || (Object)(object)((Component)val).gameObject == (Object)null) { return false; } _chatLinkPromptRoot = Object.Instantiate(((Component)val).gameObject, parent, false); ((Object)_chatLinkPromptRoot).name = "ChatX_LinkPrompt"; _chatLinkPromptRoot.SetActive(true); SetLayerRecursive(_chatLinkPromptRoot, layer); RectTransform component = ((Component)val).GetComponent(); RectTransform component2 = _chatLinkPromptRoot.GetComponent(); Rect rect; if ((Object)(object)component2 != (Object)null) { Vector2 val2 = default(Vector2); ((Vector2)(ref val2))..ctor(720f, 230f); Vector2 val3 = val2; if ((Object)(object)component != (Object)null) { rect = component.rect; val3 = ((Rect)(ref rect)).size; if (val3.x <= 1f || val3.y <= 1f) { val3 = component.sizeDelta; } } if (val3.x <= 1f || val3.y <= 1f) { val3 = val2; } component2.anchorMin = new Vector2(0.5f, 0.5f); component2.anchorMax = new Vector2(0.5f, 0.5f); component2.pivot = (Vector2)(((Object)(object)component != (Object)null) ? component.pivot : new Vector2(0.5f, 0.5f)); component2.sizeDelta = val3 * 2f; component2.anchoredPosition = Vector2.zero; ((Transform)component2).localScale = Vector3.one; ((Transform)component2).localRotation = Quaternion.identity; ((Transform)component2).SetAsLastSibling(); } _chatLinkPromptElement = _chatLinkPromptRoot.GetComponent(); RectTransform menuElementRect = GetMenuElementRect(_chatLinkPromptElement); if ((Object)(object)menuElementRect != (Object)null) { if ((Object)(object)component2 == (Object)null || menuElementRect != component2) { rect = menuElementRect.rect; Vector2 val4 = ((Rect)(ref rect)).size; if (val4.x <= 1f || val4.y <= 1f) { val4 = menuElementRect.sizeDelta; } if (val4.x > 1f && val4.y > 1f) { menuElementRect.sizeDelta = val4 * 2f; } } menuElementRect.anchoredPosition = Vector2.zero; } _chatLinkPromptCanvasGroup = GetMenuElementCanvasGroup(_chatLinkPromptElement) ?? _chatLinkPromptRoot.GetComponentInChildren(true) ?? _chatLinkPromptRoot.GetComponent(); object? obj3 = PartyInvitePromptField?.GetValue(obj); Component originalComponent = (Component)((obj3 is Component) ? obj3 : null); object? obj4 = PartyAcceptInviteButtonField?.GetValue(obj); Component originalComponent2 = (Component)((obj4 is Component) ? obj4 : null); object? obj5 = PartyDeclineInviteButtonField?.GetValue(obj); Component originalComponent3 = (Component)((obj5 is Component) ? obj5 : null); _chatLinkPromptText = FindClonedComponent(((Component)val).transform, originalComponent, _chatLinkPromptRoot.transform); _chatLinkPromptTextLegacy = FindClonedComponent(((Component)val).transform, originalComponent, _chatLinkPromptRoot.transform) ?? _chatLinkPromptRoot.GetComponentInChildren(true); _chatLinkOpenButton = FindClonedComponent