Decompiled source of MimesisTextChat v0.1.1

MimesisTextChat.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using HarmonyLib;
using MelonLoader;
using Microsoft.CodeAnalysis;
using MimesisTextChat;
using Steamworks;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: MelonInfo(typeof(TextChatMod), "MimesisTextChat", "0.1.0", "Codex local build", null)]
[assembly: MelonGame("ReLUGames", "MIMESIS")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("MimesisTextChat")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("MimesisTextChat")]
[assembly: AssemblyTitle("MimesisTextChat")]
[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 MimesisTextChat
{
	public sealed class TextChatMod : MelonMod
	{
		private readonly struct ChatMessage
		{
			public string SenderName { get; }

			public string Body { get; }

			public Color NameColor { get; }

			public ChatMessage(string senderName, string body, Color nameColor)
			{
				//IL_000f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0010: Unknown result type (might be due to invalid IL or missing references)
				SenderName = senderName;
				Body = body;
				NameColor = nameColor;
			}
		}

		private readonly struct ChatLayout
		{
			public int VisibleMessages { get; }

			private float X { get; }

			private float Y { get; }

			private float Width { get; }

			private float LineHeight { get; }

			public ChatLayout(float x, float y, float width, float lineHeight, int visibleMessages)
			{
				X = x;
				Y = y;
				Width = width;
				LineHeight = lineHeight;
				VisibleMessages = visibleMessages;
			}

			public Rect GetLineRect(int line)
			{
				//IL_0022: Unknown result type (might be due to invalid IL or missing references)
				return new Rect(X, Y + (float)line * LineHeight, Width, LineHeight);
			}
		}

		private const string PacketPrefix = "MIMESIS_TEXT_CHAT_V1|";

		private const int MaxMessageCharacters = 180;

		private const int MaxVisibleMessages = 6;

		private const int MaxStoredMessages = 40;

		private const float VisibleSeconds = 7f;

		private const float FadeSeconds = 1.5f;

		private readonly List<ChatMessage> _messages = new List<ChatMessage>();

		private Callback<LobbyChatMsg_t>? _chatCallback;

		private GUIStyle? _labelStyle;

		private GUIStyle? _inputStyle;

		private string _draft = string.Empty;

		private bool _typing;

		private int _firstVisibleMessageIndex;

		private Keyboard? _subscribedKeyboard;

		private float _lastActivityTime = -999f;

		private float _nextCallbackAttempt;

		internal static bool IsTyping { get; private set; }

		public override void OnInitializeMelon()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			new Harmony("local.codex.mimesistextchat").PatchAll(typeof(TextChatMod).Assembly);
			MelonLogger.Msg("Loaded. Press Enter to open chat, Enter to send, and Escape to close.");
		}

		public override void OnUpdate()
		{
			EnsureCallback();
			EnsureKeyboardSubscription();
			HandleKeyboardShortcuts();
			HandleMouseWheel();
		}

		public override void OnGUI()
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			EnsureStyles();
			float overlayAlpha = GetOverlayAlpha();
			if (_typing || !(overlayAlpha <= 0.01f))
			{
				Color color = GUI.color;
				GUI.color = new Color(color.r, color.g, color.b, color.a * overlayAlpha);
				_firstVisibleMessageIndex = Mathf.Clamp(_firstVisibleMessageIndex, 0, GetNewestWindowStart());
				DrawChatFeed();
				if (_typing)
				{
					DrawDraft();
				}
				GUI.color = color;
			}
		}

		public override void OnDeinitializeMelon()
		{
			if (_subscribedKeyboard != null)
			{
				_subscribedKeyboard.onTextInput -= OnTextInput;
			}
		}

		private void EnsureKeyboardSubscription()
		{
			Keyboard current = Keyboard.current;
			if (current != _subscribedKeyboard)
			{
				if (_subscribedKeyboard != null)
				{
					_subscribedKeyboard.onTextInput -= OnTextInput;
				}
				_subscribedKeyboard = current;
				if (_subscribedKeyboard != null)
				{
					_subscribedKeyboard.onTextInput += OnTextInput;
				}
			}
		}

		private void HandleKeyboardShortcuts()
		{
			Keyboard current = Keyboard.current;
			if (current == null)
			{
				return;
			}
			if (!_typing && (((ButtonControl)current.enterKey).wasPressedThisFrame || ((ButtonControl)current.numpadEnterKey).wasPressedThisFrame))
			{
				OpenChat();
			}
			else
			{
				if (!_typing)
				{
					return;
				}
				if (((ButtonControl)current.escapeKey).wasPressedThisFrame)
				{
					CloseChat(clearDraft: true);
					return;
				}
				if (((ButtonControl)current.enterKey).wasPressedThisFrame || ((ButtonControl)current.numpadEnterKey).wasPressedThisFrame)
				{
					SubmitDraft();
					return;
				}
				if (((ButtonControl)current.backspaceKey).wasPressedThisFrame && _draft.Length > 0)
				{
					_draft = _draft.Substring(0, _draft.Length - 1);
				}
				if (((ButtonControl)current.deleteKey).wasPressedThisFrame)
				{
					_draft = string.Empty;
				}
			}
		}

		private void OnTextInput(char character)
		{
			if (_typing && _draft.Length < 180 && character != '\r' && character != '\n' && character != '\b' && !char.IsControl(character) && character != '<' && character != '>')
			{
				_draft += character;
				_lastActivityTime = Time.unscaledTime;
			}
		}

		private void OpenChat()
		{
			_typing = true;
			IsTyping = true;
			_lastActivityTime = Time.unscaledTime;
		}

		private void CloseChat(bool clearDraft)
		{
			_typing = false;
			IsTyping = false;
			if (clearDraft)
			{
				_draft = string.Empty;
			}
			_lastActivityTime = Time.unscaledTime;
		}

		private void EnsureCallback()
		{
			if (_chatCallback != null || Time.unscaledTime < _nextCallbackAttempt)
			{
				return;
			}
			_nextCallbackAttempt = Time.unscaledTime + 5f;
			try
			{
				_chatCallback = Callback<LobbyChatMsg_t>.Create((DispatchDelegate<LobbyChatMsg_t>)OnLobbyChatMessage);
				MelonLogger.Msg("Steam lobby-chat receiver is ready.");
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("Steam lobby-chat receiver is not ready yet: " + ex.Message);
			}
		}

		private void SubmitDraft()
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			string text = Sanitize(_draft);
			_draft = string.Empty;
			CloseChat(clearDraft: false);
			if (string.IsNullOrWhiteSpace(text))
			{
				return;
			}
			CSteamID currentLobby = GetCurrentLobby();
			if (currentLobby == CSteamID.Nil)
			{
				AddSystemMessage("Join or host a Steam lobby before sending chat.");
				return;
			}
			byte[] bytes = Encoding.UTF8.GetBytes("MIMESIS_TEXT_CHAT_V1|" + text);
			if (!SteamMatchmaking.SendLobbyChatMsg(currentLobby, bytes, bytes.Length))
			{
				AddSystemMessage("Steam did not accept the chat message.");
			}
			else
			{
				AddMessage("Me", text, GetNameColor(SteamUser.GetSteamID()));
			}
		}

		private void OnLobbyChatMessage(LobbyChatMsg_t callback)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: 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_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				CSteamID val = new CSteamID(callback.m_ulSteamIDLobby);
				CSteamID nil = CSteamID.Nil;
				EChatEntryType val2 = (EChatEntryType)0;
				byte[] array = new byte[2048];
				int lobbyChatEntry = SteamMatchmaking.GetLobbyChatEntry(val, (int)callback.m_iChatID, ref nil, array, array.Length, ref val2);
				if (lobbyChatEntry <= 0)
				{
					return;
				}
				string text = Encoding.UTF8.GetString(array, 0, lobbyChatEntry).TrimEnd('\0');
				if (text.StartsWith("MIMESIS_TEXT_CHAT_V1|", StringComparison.Ordinal) && !(nil == SteamUser.GetSteamID()))
				{
					string text2 = Sanitize(SteamFriends.GetFriendPersonaName(nil));
					if (string.IsNullOrWhiteSpace(text2))
					{
						text2 = ((object)(CSteamID)(ref nil)).ToString();
					}
					string text3 = Sanitize(text.Substring("MIMESIS_TEXT_CHAT_V1|".Length));
					if (!string.IsNullOrWhiteSpace(text3))
					{
						AddMessage(text2, text3, GetNameColor(nil));
					}
				}
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("Could not read a Steam lobby-chat message: " + ex.Message);
			}
		}

		private void AddSystemMessage(string message)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			AddMessage("System", message, new Color(1f, 0.86f, 0.35f));
		}

		private void AddMessage(string senderName, string body, Color nameColor)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			_messages.Add(new ChatMessage(senderName, body, nameColor));
			_lastActivityTime = Time.unscaledTime;
			while (_messages.Count > 40)
			{
				_messages.RemoveAt(0);
			}
			ScrollToBottom();
		}

		private void HandleMouseWheel()
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			if (!_typing)
			{
				return;
			}
			Mouse current = Mouse.current;
			if (current == null)
			{
				return;
			}
			float y = ((InputControl<Vector2>)(object)current.scroll).ReadValue().y;
			if (!(Math.Abs(y) < 0.01f))
			{
				if (y > 0f)
				{
					_firstVisibleMessageIndex = Math.Max(0, _firstVisibleMessageIndex - 1);
				}
				else
				{
					_firstVisibleMessageIndex = Math.Min(GetNewestWindowStart(), _firstVisibleMessageIndex + 1);
				}
				_lastActivityTime = Time.unscaledTime;
			}
		}

		private void DrawChatFeed()
		{
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			ChatLayout chatLayout = GetChatLayout(_typing);
			if (chatLayout.VisibleMessages == 0)
			{
				return;
			}
			int num = 0;
			foreach (ChatMessage item in _messages.Skip(_firstVisibleMessageIndex).Take(6))
			{
				DrawChatLine(chatLayout.GetLineRect(num), item);
				num++;
			}
		}

		private void DrawDraft()
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			ChatLayout chatLayout = GetChatLayout(includeDraft: true);
			DrawShadowedLabel(chatLayout.GetLineRect(chatLayout.VisibleMessages), "> " + _draft, _inputStyle);
		}

		private ChatLayout GetChatLayout(bool includeDraft)
		{
			int num = Math.Min(6, Math.Max(0, _messages.Count - _firstVisibleMessageIndex));
			int num2 = num + (includeDraft ? 1 : 0);
			float y = (float)Screen.height * 0.5f - (float)num2 * 34f * 0.5f;
			return new ChatLayout(48f, y, 840f, 34f, num);
		}

		private void DrawChatLine(Rect rect, ChatMessage message)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Expected O, but got Unknown
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			string text = message.SenderName + ": ";
			GUIStyle? labelStyle = _labelStyle;
			Vector2 val = ((labelStyle != null) ? labelStyle.CalcSize(new GUIContent(text)) : Vector2.zero);
			DrawShadowedLabel(rect, text, _labelStyle, message.NameColor);
			DrawShadowedLabel(new Rect(((Rect)(ref rect)).x + val.x, ((Rect)(ref rect)).y, ((Rect)(ref rect)).width - val.x, ((Rect)(ref rect)).height), message.Body, _labelStyle, Color.white);
		}

		private static void DrawShadowedLabel(Rect rect, string text, GUIStyle? style)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			DrawShadowedLabel(rect, text, style, Color.white);
		}

		private static void DrawShadowedLabel(Rect rect, string text, GUIStyle? style, Color textColor)
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			if (style != null)
			{
				Color color = GUI.color;
				GUI.color = new Color(0f, 0f, 0f, color.a * 0.85f);
				GUI.Label(new Rect(((Rect)(ref rect)).x + 2f, ((Rect)(ref rect)).y + 2f, ((Rect)(ref rect)).width, ((Rect)(ref rect)).height), text, style);
				GUI.color = new Color(textColor.r, textColor.g, textColor.b, color.a);
				GUI.Label(rect, text, style);
				GUI.color = color;
			}
		}

		private static Color GetNameColor(CSteamID steamId)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			return Color.HSVToRGB((float)((ulong)steamId * 2654435761u % 360) / 360f, 0.62f, 1f);
		}

		private int GetNewestWindowStart()
		{
			return Math.Max(0, _messages.Count - 6);
		}

		private void ScrollToBottom()
		{
			_firstVisibleMessageIndex = GetNewestWindowStart();
		}

		private float GetOverlayAlpha()
		{
			if (_typing)
			{
				return 1f;
			}
			float num = Time.unscaledTime - _lastActivityTime;
			if (num <= 7f)
			{
				return 1f;
			}
			return Mathf.Clamp01(1f - (num - 7f) / 1.5f);
		}

		private void EnsureStyles()
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Expected O, but got Unknown
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Expected O, but got Unknown
			if (_labelStyle == null || _inputStyle == null)
			{
				_labelStyle = new GUIStyle(GUI.skin.label)
				{
					fontSize = 26,
					wordWrap = true
				};
				_inputStyle = new GUIStyle(GUI.skin.label)
				{
					fontSize = 28,
					wordWrap = true
				};
			}
		}

		private static string Sanitize(string value)
		{
			if (string.IsNullOrEmpty(value))
			{
				return string.Empty;
			}
			StringBuilder stringBuilder = new StringBuilder(Math.Min(value.Length, 180));
			foreach (char c in value)
			{
				if (stringBuilder.Length >= 180)
				{
					break;
				}
				if (!char.IsControl(c) && c != '<' && c != '>')
				{
					stringBuilder.Append(c);
				}
			}
			return stringBuilder.ToString().Trim();
		}

		private static CSteamID GetCurrentLobby()
		{
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				Type type = Type.GetType("SteamInviteDispatcher, Assembly-CSharp");
				if (type == null)
				{
					return CSteamID.Nil;
				}
				Object val = Object.FindObjectOfType(type);
				FieldInfo field = type.GetField("joinedLobbyID", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				return (val != (Object)null && field?.GetValue(val) is CSteamID val2) ? val2 : CSteamID.Nil;
			}
			catch
			{
				return CSteamID.Nil;
			}
		}
	}
	[HarmonyPatch]
	public static class GameInputBlockPatch
	{
		private static MethodBase? TargetMethod()
		{
			return Type.GetType("Mimic.InputSystem.InputManager, Assembly-CSharp")?.GetMethod("Update", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		}

		private static bool Prefix()
		{
			return !TextChatMod.IsTyping;
		}
	}
}