Decompiled source of Chatter v1.0.0

BepInEx/plugins/Chatter.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using Fusion;
using HarmonyLib;
using Il2CppInterop.Runtime.Injection;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppSystem.Collections.Generic;
using Microsoft.CodeAnalysis;
using Steamworks;
using TMPro;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.Rendering;
using UnityEngine.SceneManagement;
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(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("Chatter")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("Chatter")]
[assembly: AssemblyTitle("Chatter")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[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 ShiftAtMidnightChatter
{
	internal sealed class BubbleField
	{
		private readonly Dictionary<ulong, ChatBubble> _bubbles = new Dictionary<ulong, ChatBubble>();

		private readonly List<ulong> _finished = new List<ulong>();

		public void Say(ulong owner, string message)
		{
			For(owner).Say(message);
		}

		public void Typing(ulong owner, bool typing)
		{
			if (typing || _bubbles.ContainsKey(owner))
			{
				For(owner).Typing(typing);
			}
		}

		public void LateTick()
		{
			if (_bubbles.Count == 0)
			{
				return;
			}
			Camera localCamera = NetworkContext.LocalCamera;
			_finished.Clear();
			foreach (KeyValuePair<ulong, ChatBubble> bubble in _bubbles)
			{
				PlayerManager body = PlayerRoster.Body(bubble.Key);
				bubble.Value.LateTick(PlayerRoster.Head(body), localCamera);
				if (bubble.Value.Idle)
				{
					_finished.Add(bubble.Key);
				}
			}
			foreach (ulong item in _finished)
			{
				_bubbles[item].Destroy();
				_bubbles.Remove(item);
			}
		}

		public void Clear()
		{
			foreach (KeyValuePair<ulong, ChatBubble> bubble in _bubbles)
			{
				bubble.Value.Destroy();
			}
			_bubbles.Clear();
		}

		private ChatBubble For(ulong owner)
		{
			if (_bubbles.TryGetValue(owner, out var value) && value != null)
			{
				return value;
			}
			value = new ChatBubble(owner);
			_bubbles[owner] = value;
			return value;
		}
	}
	internal sealed class ChatBox
	{
		private const float Width = 760f;

		private const float MinHeight = 108f;

		private const float BottomMargin = 190f;

		private const float BorderThickness = 3f;

		private const float TextInset = 24f;

		private const float VerticalPadding = 34f;

		private const float FontSize = 40f;

		private const float CaretWidth = 3f;

		private const float CaretGap = 5f;

		private const float CaretBlinkPeriod = 1.06f;

		private static readonly Color Border = new Color(1f, 1f, 1f, 0.92f);

		private static readonly Color Backing = new Color(0f, 0f, 0f, 0.35f);

		private readonly GameObject _root;

		private readonly RectTransform _panel;

		private readonly TextMeshProUGUI _text;

		private readonly RectTransform _caret;

		private readonly Image _caretFill;

		public ChatBox()
		{
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: 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)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: 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_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_011b: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: Unknown result type (might be due to invalid IL or missing references)
			//IL_014a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0159: Unknown result type (might be due to invalid IL or missing references)
			//IL_0174: Unknown result type (might be due to invalid IL or missing references)
			//IL_0179: Unknown result type (might be due to invalid IL or missing references)
			//IL_0188: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0267: Unknown result type (might be due to invalid IL or missing references)
			//IL_0297: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cd: Unknown result type (might be due to invalid IL or missing references)
			_panel = ChatCanvas.Panel("ChatterBox", ChatCanvas.Root);
			_root = ((Component)_panel).gameObject;
			_panel.anchorMin = new Vector2(0.5f, 0f);
			_panel.anchorMax = new Vector2(0.5f, 0f);
			_panel.pivot = new Vector2(0.5f, 0f);
			_panel.anchoredPosition = new Vector2(0f, 190f);
			_panel.sizeDelta = new Vector2(760f, 108f);
			Image val = ChatCanvas.Fill("Backing", (Transform)(object)_panel, Backing);
			ChatCanvas.Stretch(((Graphic)val).rectTransform);
			Edge((Transform)(object)_panel, new Vector2(0f, 1f), Vector2.one, new Vector2(0f, 3f));
			Edge((Transform)(object)_panel, Vector2.zero, new Vector2(1f, 0f), new Vector2(0f, 3f));
			Edge((Transform)(object)_panel, Vector2.zero, new Vector2(0f, 1f), new Vector2(3f, 0f));
			Edge((Transform)(object)_panel, new Vector2(1f, 0f), Vector2.one, new Vector2(3f, 0f));
			RectTransform val2 = ChatCanvas.Panel("Text", (Transform)(object)_panel);
			val2.anchorMin = Vector2.zero;
			val2.anchorMax = Vector2.one;
			val2.offsetMin = new Vector2(24f, 0f);
			val2.offsetMax = new Vector2(-24f, 0f);
			_text = ((Component)val2).gameObject.AddComponent<TextMeshProUGUI>();
			((TMP_Text)_text).font = GameFont.Asset;
			((TMP_Text)_text).fontSize = 40f;
			((TMP_Text)_text).alignment = (TextAlignmentOptions)514;
			((TMP_Text)_text).textWrappingMode = (TextWrappingModes)1;
			((TMP_Text)_text).overflowMode = (TextOverflowModes)0;
			((Graphic)_text).raycastTarget = false;
			((TMP_Text)_text).richText = false;
			_caretFill = ChatCanvas.Fill("Caret", (Transform)(object)val2, Border);
			_caret = ((Graphic)_caretFill).rectTransform;
			_caret.anchorMin = new Vector2(0.5f, 0.5f);
			_caret.anchorMax = new Vector2(0.5f, 0.5f);
			_caret.pivot = new Vector2(0f, 0.5f);
			_root.SetActive(false);
		}

		public void Show(string typed)
		{
			//IL_005e: 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)
			_root.SetActive(true);
			((TMP_Text)_text).text = typed;
			((TMP_Text)_text).ForceMeshUpdate(false, false);
			Grow();
			PlaceCaret();
			bool flag = Mathf.Repeat(Time.unscaledTime, 1.06f) < 0.53f;
			((Graphic)_caretFill).color = (flag ? Border : Color.clear);
		}

		public void Hide()
		{
			_root.SetActive(false);
		}

		public void Destroy()
		{
			if ((Object)(object)_root != (Object)null)
			{
				Object.Destroy((Object)(object)_root);
			}
		}

		private void Grow()
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			float num = Mathf.Max(108f, ((TMP_Text)_text).preferredHeight + 34f);
			_panel.sizeDelta = new Vector2(760f, num);
		}

		private void PlaceCaret()
		{
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: 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_0054: Unknown result type (might be due to invalid IL or missing references)
			TMP_TextInfo textInfo = ((TMP_Text)_text).textInfo;
			int num = ((textInfo != null) ? textInfo.characterCount : 0);
			if (num == 0)
			{
				_caret.sizeDelta = new Vector2(3f, ((TMP_Text)_text).fontSize);
				_caret.anchoredPosition = new Vector2(5f, 0f);
			}
			else
			{
				TMP_CharacterInfo val = ((Il2CppArrayBase<TMP_CharacterInfo>)(object)textInfo.characterInfo)[num - 1];
				_caret.sizeDelta = new Vector2(3f, val.ascender - val.descender);
				_caret.anchoredPosition = new Vector2(val.xAdvance + 5f, (val.ascender + val.descender) * 0.5f);
			}
		}

		private static void Edge(Transform parent, Vector2 anchorMin, Vector2 anchorMax, Vector2 size)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			Image val = ChatCanvas.Fill("Edge", parent, Border);
			RectTransform rectTransform = ((Graphic)val).rectTransform;
			rectTransform.anchorMin = anchorMin;
			rectTransform.anchorMax = anchorMax;
			rectTransform.pivot = new Vector2(0.5f, 0.5f);
			rectTransform.sizeDelta = size;
			rectTransform.anchoredPosition = Vector2.zero;
		}
	}
	internal sealed class ChatBubble
	{
		private const float TagClearance = 0.06f;

		private const float LeastTagHeight = 0.05f;

		private const float MostTagHeight = 0.3f;

		private static readonly Color Ink = Color.white;

		private const float WorldScale = 1f;

		private const float PointSize = 2f;

		private const float LineWidth = 4f;

		private const float SolidDistance = 8f;

		private const float FaintDistance = 40f;

		private const float FaintestAlpha = 0.3f;

		private const float OccludedAlpha = 0.5f;

		private const float OccludedDim = 0.75f;

		private const float ArrivalDuration = 0.12f;

		private const float FadeDuration = 0.6f;

		private const int OccludedQueue = 2999;

		private const string TypingText = "...";

		private const float TypingPulseSpeed = 3.5f;

		private const float TypingFaintest = 0.35f;

		private readonly GameObject _root;

		private readonly Transform _transform;

		private readonly TextMeshPro _front;

		private readonly TextMeshPro _behind;

		private string _message = string.Empty;

		private float _shownAt;

		private float _expiresAt;

		private bool _typing;

		public bool Idle => !_typing && Time.unscaledTime >= _expiresAt;

		public ChatBubble(ulong owner)
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Expected O, but got Unknown
			_root = new GameObject($"ChatterBubble_{owner}");
			Object.DontDestroyOnLoad((Object)(object)_root);
			_transform = _root.transform;
			_front = Build("Front", _transform, overlay: false);
			_behind = Build("Behind", _transform, overlay: true);
			_root.SetActive(false);
		}

		public void Say(string message)
		{
			_message = message;
			_shownAt = Time.unscaledTime;
			_expiresAt = Time.unscaledTime + 8f;
		}

		public void Typing(bool typing)
		{
			_typing = typing;
		}

		public void LateTick(Transform head, Camera eye)
		{
			//IL_0060: 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_0076: 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_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			bool flag = Time.unscaledTime < _expiresAt;
			if ((Object)(object)head == (Object)null || (Object)(object)eye == (Object)null || (!flag && !_typing))
			{
				_root.SetActive(false);
				return;
			}
			_root.SetActive(true);
			_transform.position = head.position + Vector3.up * (TagHeight(head) + 0.06f);
			_transform.rotation = ((Component)eye).transform.rotation;
			float distance = Vector3.Distance(((Component)eye).transform.position, _transform.position);
			float num = Falloff(distance);
			if (flag)
			{
				Set(_message, num * Arriving() * Leaving());
				return;
			}
			float num2 = Mathf.Sin(Time.unscaledTime * 3.5f) * 0.5f + 0.5f;
			Set("...", num * Mathf.Lerp(0.35f, 1f, num2));
		}

		private static float TagHeight(Transform tag)
		{
			//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_002b: Unknown result type (might be due to invalid IL or missing references)
			RectTransform val = ((Il2CppObjectBase)tag).TryCast<RectTransform>();
			if ((Object)(object)val == (Object)null)
			{
				return 0.3f;
			}
			Rect rect = val.rect;
			float num = ((Rect)(ref rect)).height * Mathf.Abs(((Transform)val).lossyScale.y);
			return Mathf.Clamp(num, 0.05f, 0.3f);
		}

		public void Destroy()
		{
			if ((Object)(object)_root != (Object)null)
			{
				Object.Destroy((Object)(object)_root);
			}
		}

		private void Set(string text, float alpha)
		{
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			((TMP_Text)_front).text = text;
			((TMP_Text)_behind).text = text;
			((Graphic)_front).color = new Color(Ink.r, Ink.g, Ink.b, alpha);
			((Graphic)_behind).color = new Color(Ink.r * 0.75f, Ink.g * 0.75f, Ink.b * 0.75f, alpha * 0.5f);
		}

		private static float Falloff(float distance)
		{
			return Mathf.Lerp(1f, 0.3f, Mathf.SmoothStep(0f, 1f, Mathf.InverseLerp(8f, 40f, distance)));
		}

		private float Arriving()
		{
			return Mathf.Clamp01((Time.unscaledTime - _shownAt) / 0.12f);
		}

		private float Leaving()
		{
			return Mathf.Clamp01((_expiresAt - Time.unscaledTime) / 0.6f);
		}

		private static TextMeshPro Build(string name, Transform parent, bool overlay)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Expected O, but got Unknown
			//IL_001c: 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)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject(name);
			val.transform.SetParent(parent, false);
			val.transform.localScale = Vector3.one * 1f;
			TextMeshPro val2 = val.AddComponent<TextMeshPro>();
			((TMP_Text)val2).font = GameFont.Asset;
			((TMP_Text)val2).fontSize = 2f;
			((TMP_Text)val2).alignment = (TextAlignmentOptions)1026;
			((TMP_Text)val2).textWrappingMode = (TextWrappingModes)1;
			((TMP_Text)val2).overflowMode = (TextOverflowModes)0;
			((TMP_Text)val2).richText = false;
			((TMP_Text)val2).rectTransform.sizeDelta = new Vector2(4f, 1f);
			((TMP_Text)val2).rectTransform.pivot = new Vector2(0.5f, 0f);
			Material fontMaterial = ((TMP_Text)val2).fontMaterial;
			if (overlay)
			{
				((TMP_Text)val2).isOverlay = true;
				if ((Object)(object)fontMaterial != (Object)null)
				{
					fontMaterial.renderQueue = 2999;
				}
			}
			Renderer component = val.GetComponent<Renderer>();
			if ((Object)(object)component != (Object)null)
			{
				component.shadowCastingMode = (ShadowCastingMode)0;
				component.receiveShadows = false;
			}
			return val2;
		}
	}
	internal static class ChatCanvas
	{
		private static readonly Vector2 Reference = new Vector2(1920f, 1080f);

		private const int SortingOrder = 1000;

		private static GameObject _root;

		public static Transform Root
		{
			get
			{
				//IL_0022: Unknown result type (might be due to invalid IL or missing references)
				//IL_002c: Expected O, but got Unknown
				//IL_006a: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)_root != (Object)null)
				{
					return _root.transform;
				}
				_root = new GameObject("ChatterCanvas");
				Object.DontDestroyOnLoad((Object)(object)_root);
				Canvas val = _root.AddComponent<Canvas>();
				val.renderMode = (RenderMode)0;
				val.sortingOrder = 1000;
				CanvasScaler val2 = _root.AddComponent<CanvasScaler>();
				val2.uiScaleMode = (ScaleMode)1;
				val2.referenceResolution = Reference;
				val2.screenMatchMode = (ScreenMatchMode)0;
				val2.matchWidthOrHeight = 0.5f;
				return _root.transform;
			}
		}

		public static void Destroy()
		{
			if ((Object)(object)_root != (Object)null)
			{
				Object.Destroy((Object)(object)_root);
			}
			_root = null;
		}

		public static RectTransform Panel(string name, Transform parent)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Expected O, but got Unknown
			GameObject val = new GameObject(name);
			val.transform.SetParent(parent, false);
			return val.AddComponent<RectTransform>();
		}

		public static Image Fill(string name, Transform parent, Color colour)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			Image val = ((Component)Panel(name, parent)).gameObject.AddComponent<Image>();
			((Graphic)val).color = colour;
			((Graphic)val).raycastTarget = false;
			return val;
		}

		public static void Stretch(RectTransform rect)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: 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)
			rect.anchorMin = Vector2.zero;
			rect.anchorMax = Vector2.one;
			rect.offsetMin = Vector2.zero;
			rect.offsetMax = Vector2.zero;
		}
	}
	internal sealed class ChatComposer
	{
		private const int MostCharacters = 67;

		private const float SilentTimeout = 20f;

		private const char Backspace = '\b';

		private const char Return = '\r';

		private const char Newline = '\n';

		private const char FirstPrintable = ' ';

		private readonly List<PlayerInput> _held = new List<PlayerInput>();

		private readonly StringBuilder _typed = new StringBuilder(67);

		private readonly ChatSync _sync;

		private readonly ChatBox _box;

		private bool _open;

		private bool _ourMove;

		private bool _ourCam;

		private bool _ourInventory;

		private bool _ourHotbar;

		private bool _ourKeyboard;

		private int _openedFrame;

		private float _lastActivity;

		public bool Open => _open;

		public event Action<string> Sent;

		public ChatComposer(ChatSync sync, ChatBox box)
		{
			_sync = sync;
			_box = box;
		}

		public void Tick()
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			if (!_open)
			{
				if (Input.GetKeyDown(ChatterPlugin.ChatKey.Value) && CanOpen())
				{
					Begin();
				}
				return;
			}
			if (!CanStayOpen())
			{
				End(send: false);
				return;
			}
			if (Input.GetKeyDown((KeyCode)27))
			{
				End(send: false);
				return;
			}
			if (Time.unscaledTime - _lastActivity > 20f)
			{
				ModLog.Warning("Nothing typed for a while, so the chat box closed itself.");
				End(send: false);
				return;
			}
			Reassert();
			if (Time.frameCount > _openedFrame + 1)
			{
				Consume();
			}
			if (_open)
			{
				_box.Show(_typed.ToString());
			}
		}

		public void Cancel()
		{
			if (_open)
			{
				End(send: false);
			}
		}

		private void Begin()
		{
			_typed.Clear();
			_open = true;
			_openedFrame = Time.frameCount;
			_lastActivity = Time.unscaledTime;
			Suppress(on: true);
			_box.Show(string.Empty);
			_sync.SetTyping(typing: true);
		}

		private void Consume()
		{
			string inputString = Input.inputString;
			if (inputString.Length > 0)
			{
				_lastActivity = Time.unscaledTime;
			}
			foreach (char c in inputString)
			{
				switch (c)
				{
				case '\b':
					if (_typed.Length > 0)
					{
						_typed.Length--;
					}
					break;
				default:
					if (c != '\n')
					{
						if (c >= ' ' && _typed.Length < 67)
						{
							_typed.Append(c);
						}
						break;
					}
					goto case '\r';
				case '\r':
					End(send: true);
					return;
				}
			}
			if (Input.GetKeyDown((KeyCode)13) || Input.GetKeyDown((KeyCode)271))
			{
				End(send: true);
			}
		}

		private void End(bool send)
		{
			if (!_open)
			{
				return;
			}
			_open = false;
			Suppress(on: false);
			_box.Hide();
			_sync.SetTyping(typing: false);
			if (send)
			{
				string text = _typed.ToString().Trim();
				_typed.Clear();
				if (text.Length != 0)
				{
					this.Sent?.Invoke(text);
				}
			}
		}

		private void Suppress(bool on)
		{
			PlayerManager localPlayerManager = NetworkContext.LocalPlayerManager;
			if ((Object)(object)localPlayerManager == (Object)null)
			{
				return;
			}
			FPSController fpsScript = localPlayerManager.fpsScript;
			InventoryManager inventoryMan = localPlayerManager.inventoryMan;
			if (on)
			{
				_ourMove = (Object)(object)fpsScript != (Object)null && !fpsScript.lockMove;
				_ourCam = (Object)(object)fpsScript != (Object)null && !fpsScript.lockCam;
				_ourInventory = (Object)(object)inventoryMan != (Object)null;
				_ourHotbar = _ourInventory && (Object)(object)inventoryMan.inventoryUIHolder != (Object)null && inventoryMan.inventoryUIHolder.activeSelf;
				if (_ourInventory)
				{
					inventoryMan.PauseInventory();
				}
				InputBlock.FreezeHotbar = true;
				InputBlock.FreezeHistory = true;
				Gather();
				Reassert();
				return;
			}
			InputBlock.FreezeHotbar = false;
			InputBlock.FreezeHistory = false;
			Restore();
			foreach (PlayerInput item in _held)
			{
				Activate(item);
			}
			_held.Clear();
			if ((Object)(object)fpsScript != (Object)null)
			{
				if (_ourMove)
				{
					fpsScript.lockMove = false;
				}
				if (_ourCam)
				{
					fpsScript.lockCam = false;
				}
			}
			if (_ourInventory && (Object)(object)inventoryMan != (Object)null)
			{
				inventoryMan.canControlItem = true;
				inventoryMan.UnpauseInventory();
				if (_ourHotbar && (Object)(object)inventoryMan.inventoryUIHolder != (Object)null)
				{
					inventoryMan.inventoryUIHolder.SetActive(true);
				}
			}
			_ourMove = false;
			_ourCam = false;
			_ourInventory = false;
			_ourHotbar = false;
		}

		private void Gather()
		{
			_held.Clear();
			Il2CppArrayBase<PlayerInput> val = Object.FindObjectsOfType<PlayerInput>();
			if (val == null)
			{
				return;
			}
			for (int i = 0; i < val.Length; i++)
			{
				PlayerInput val2 = val[i];
				if (!((Object)(object)val2 == (Object)null) && val2.inputIsActive)
				{
					_held.Add(val2);
				}
			}
		}

		private void Reassert()
		{
			PlayerManager localPlayerManager = NetworkContext.LocalPlayerManager;
			if ((Object)(object)localPlayerManager == (Object)null)
			{
				return;
			}
			FPSController fpsScript = localPlayerManager.fpsScript;
			InventoryManager inventoryMan = localPlayerManager.inventoryMan;
			foreach (PlayerInput item in _held)
			{
				Deactivate(item);
			}
			Silence();
			if ((Object)(object)fpsScript != (Object)null)
			{
				if (_ourMove && !fpsScript.lockMove)
				{
					fpsScript.lockMove = true;
				}
				if (_ourCam && !fpsScript.lockCam)
				{
					fpsScript.lockCam = true;
				}
			}
			if (_ourInventory && !((Object)(object)inventoryMan == (Object)null))
			{
				if (inventoryMan.canControlItem)
				{
					inventoryMan.canControlItem = false;
				}
				if (_ourHotbar && (Object)(object)inventoryMan.inventoryUIHolder != (Object)null && inventoryMan.inventoryUIHolder.activeSelf)
				{
					inventoryMan.inventoryUIHolder.SetActive(false);
				}
			}
		}

		private void Silence()
		{
			Keyboard current = Keyboard.current;
			if (current != null && ((InputDevice)current).enabled)
			{
				InputSystem.DisableDevice((InputDevice)(object)current, false);
				_ourKeyboard = true;
			}
		}

		private void Restore()
		{
			if (_ourKeyboard)
			{
				_ourKeyboard = false;
				Keyboard current = Keyboard.current;
				if (current != null && !((InputDevice)current).enabled)
				{
					InputSystem.EnableDevice((InputDevice)(object)current);
				}
			}
		}

		private static void Deactivate(PlayerInput input)
		{
			if (!((Object)(object)input == (Object)null) && input.inputIsActive)
			{
				input.DeactivateInput();
			}
		}

		private static void Activate(PlayerInput input)
		{
			if (!((Object)(object)input == (Object)null) && !input.inputIsActive)
			{
				input.ActivateInput();
			}
		}

		private static bool CanOpen()
		{
			PlayerManager localPlayerManager = NetworkContext.LocalPlayerManager;
			if ((Object)(object)localPlayerManager == (Object)null)
			{
				return false;
			}
			return !localPlayerManager.paused && !localPlayerManager.dead && !localPlayerManager.customizablesMenuOpen && !localPlayerManager.dontAllowLockCursor;
		}

		private static bool CanStayOpen()
		{
			PlayerManager localPlayerManager = NetworkContext.LocalPlayerManager;
			if ((Object)(object)localPlayerManager == (Object)null)
			{
				return false;
			}
			return !localPlayerManager.paused && !localPlayerManager.dead;
		}
	}
	internal sealed class ChatSync
	{
		private struct Incoming
		{
			public int Seq;

			public bool Typing;
		}

		private const string Key = "chatter";

		private const string Version = "2";

		private const char Separator = '|';

		private const float PollInterval = 0.2f;

		private const float PublishInterval = 0.25f;

		private const int Fields = 4;

		private static readonly Encoding Wire = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false);

		private readonly Dictionary<ulong, Incoming> _seen = new Dictionary<ulong, Incoming>();

		private string _published;

		private string _text = string.Empty;

		private int _seq;

		private bool _typing;

		private bool _changed;

		private float _nextPoll;

		private float _nextPublish;

		private float _textExpiresAt;

		public event Action<ulong, string> MessageArrived;

		public event Action<ulong, bool> TypingChanged;

		public void Send(string text)
		{
			_text = text;
			_seq++;
			_textExpiresAt = Time.unscaledTime + 8f;
			_changed = true;
		}

		public void SetTyping(bool typing)
		{
			if (_typing != typing)
			{
				_typing = typing;
				_changed = true;
			}
		}

		public void Tick()
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				CSteamID lobby = NetworkContext.Lobby;
				if (lobby.m_SteamID != 0)
				{
					Expire();
					Publish(lobby);
					if (!(Time.unscaledTime < _nextPoll))
					{
						_nextPoll = Time.unscaledTime + 0.2f;
						Poll(lobby);
					}
				}
			}
			catch (Exception value)
			{
				ModLog.Error($"Sync: {value}");
			}
		}

		public void Clear()
		{
			_seen.Clear();
			_published = null;
			_text = string.Empty;
			_typing = false;
			_changed = false;
		}

		private void Expire()
		{
			if (_text.Length != 0 && !(Time.unscaledTime < _textExpiresAt))
			{
				_text = string.Empty;
				_changed = true;
			}
		}

		private void Publish(CSteamID lobby)
		{
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			if (_changed && !(Time.unscaledTime < _nextPublish))
			{
				string text = Serialise();
				_changed = false;
				if (!(text == _published))
				{
					SteamMatchmaking.SetLobbyMemberData(lobby, "chatter", text);
					_published = text;
					_nextPublish = Time.unscaledTime + 0.25f;
				}
			}
		}

		private string Serialise()
		{
			if (_text.Length == 0 && !_typing)
			{
				return string.Empty;
			}
			return string.Join('|'.ToString(), "2", _typing ? "1" : "0", _seq.ToString(CultureInfo.InvariantCulture), Convert.ToBase64String(Wire.GetBytes(_text)));
		}

		private void Poll(CSteamID lobby)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: 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_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			ulong localSteamId = NetworkContext.LocalSteamId;
			int numLobbyMembers = SteamMatchmaking.GetNumLobbyMembers(lobby);
			for (int i = 0; i < numLobbyMembers; i++)
			{
				CSteamID lobbyMemberByIndex = SteamMatchmaking.GetLobbyMemberByIndex(lobby, i);
				if (lobbyMemberByIndex.m_SteamID != localSteamId)
				{
					string lobbyMemberData = SteamMatchmaking.GetLobbyMemberData(lobby, lobbyMemberByIndex, "chatter");
					if (string.IsNullOrEmpty(lobbyMemberData))
					{
						Quiet(lobbyMemberByIndex.m_SteamID);
					}
					else
					{
						Read(lobbyMemberByIndex.m_SteamID, lobbyMemberData);
					}
				}
			}
		}

		private void Read(ulong owner, string raw)
		{
			string[] array = raw.Split('|');
			if (array.Length != 4 || array[0] != "2" || !int.TryParse(array[2], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result))
			{
				return;
			}
			bool flag = array[1] == "1";
			if (Decode(array[3], out var text))
			{
				Incoming value;
				bool flag2 = _seen.TryGetValue(owner, out value);
				if (!flag2 || value.Typing != flag)
				{
					this.TypingChanged?.Invoke(owner, flag);
				}
				bool flag3 = text.Length > 0 && (!flag2 || result > value.Seq);
				_seen[owner] = new Incoming
				{
					Seq = result,
					Typing = flag
				};
				if (flag3)
				{
					this.MessageArrived?.Invoke(owner, text);
				}
			}
		}

		private void Quiet(ulong owner)
		{
			if (_seen.TryGetValue(owner, out var value) && value.Typing)
			{
				value.Typing = false;
				_seen[owner] = value;
				this.TypingChanged?.Invoke(owner, arg2: false);
			}
		}

		private static bool Decode(string encoded, out string text)
		{
			text = string.Empty;
			if (encoded.Length == 0)
			{
				return true;
			}
			try
			{
				text = Wire.GetString(Convert.FromBase64String(encoded));
				return true;
			}
			catch
			{
				return false;
			}
		}
	}
	[BepInPlugin("clementinise.shiftatmidnight.chatter", "Chatter", "1.0.0")]
	public class ChatterPlugin : BasePlugin
	{
		public const string Guid = "clementinise.shiftatmidnight.chatter";

		internal static ConfigEntry<KeyCode> ChatKey;

		public const float BubbleLifetime = 8f;

		public override void Load()
		{
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			ModLog.Source = ((BasePlugin)this).Log;
			ChatKey = ((BasePlugin)this).Config.Bind<KeyCode>("Chat", "ChatKey", (KeyCode)13, "Opens the chat box. Enter sends, Escape cancels.");
			InputBlock.Install();
			ClassInjector.RegisterTypeInIl2Cpp<ChatterBehaviour>();
			((BasePlugin)this).AddComponent<ChatterBehaviour>();
			ModLog.Msg($"Chatter ready. {ChatKey.Value} opens the chat box, {ChatKey.Value} again sends.");
		}
	}
	public class ChatterBehaviour : MonoBehaviour
	{
		private ChatSync _sync;

		private BubbleField _bubbles;

		private ChatBox _box;

		private DialogueHistory _log;

		private ChatComposer _composer;

		private int _lastSceneHandle;

		private bool _built;

		public ChatterBehaviour(IntPtr handle)
			: base(handle)
		{
		}

		private void Awake()
		{
			//IL_0001: 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)
			Scene activeScene = SceneManager.GetActiveScene();
			_lastSceneHandle = ((Scene)(ref activeScene)).handle;
		}

		private void Update()
		{
			try
			{
				DetectSceneChange();
				if (Build())
				{
					_composer.Tick();
					_sync.Tick();
					_log.Tick();
				}
			}
			catch (Exception value)
			{
				ModLog.Error($"Update: {value}");
			}
		}

		private void LateUpdate()
		{
			try
			{
				if (_built)
				{
					_bubbles.LateTick();
					_log.LateTick();
				}
			}
			catch (Exception value)
			{
				ModLog.Error($"LateUpdate: {value}");
			}
		}

		private bool Build()
		{
			if (_built)
			{
				return true;
			}
			if ((Object)(object)NetworkContext.LocalPlayerManager == (Object)null)
			{
				return false;
			}
			_sync = new ChatSync();
			_bubbles = new BubbleField();
			_box = new ChatBox();
			_log = new DialogueHistory();
			_composer = new ChatComposer(_sync, _box);
			_composer.Sent += Send;
			_sync.MessageArrived += Receive;
			_sync.TypingChanged += delegate(ulong owner, bool typing)
			{
				_bubbles.Typing(owner, typing);
			};
			_built = true;
			return true;
		}

		private void Send(string message)
		{
			_sync.Send(message);
			_log.Add(PlayerRoster.Name(NetworkContext.LocalSteamId), message);
		}

		private void Receive(ulong owner, string message)
		{
			_bubbles.Say(owner, message);
			_log.Add(PlayerRoster.Name(owner), message);
		}

		private void DetectSceneChange()
		{
			//IL_0001: 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)
			Scene activeScene = SceneManager.GetActiveScene();
			int handle = ((Scene)(ref activeScene)).handle;
			if (handle != _lastSceneHandle)
			{
				_lastSceneHandle = handle;
				Teardown();
			}
		}

		private void OnDestroy()
		{
			try
			{
				Teardown();
			}
			catch
			{
			}
		}

		private void Teardown()
		{
			if (_built)
			{
				_composer.Cancel();
				_bubbles.Clear();
				_sync.Clear();
				_log.Close();
				_box.Destroy();
			}
			ChatCanvas.Destroy();
			PlayerRoster.Clear();
			GameFont.Rescan();
			_sync = null;
			_bubbles = null;
			_box = null;
			_log = null;
			_composer = null;
			_built = false;
		}
	}
	internal sealed class DialogueHistory
	{
		private sealed class Line
		{
			public GameObject Object;

			public ChatLogNode Node;

			public string Who;

			public string What;

			public float ForwardUntil;

			public bool Forward;
		}

		private const int MostLines = 20;

		private const string ForwardParameter = "Show";

		private readonly List<Line> _mine = new List<Line>();

		private bool _warned;

		public void Add(string who, string what)
		{
			SpeakingManager instance = SpeakingManager.Instance;
			if ((Object)(object)instance == (Object)null || (Object)(object)instance.chatLogNode == (Object)null || (Object)(object)instance.chatLogNodeHolder == (Object)null)
			{
				WarnOnce();
				return;
			}
			GameObject val = Object.Instantiate<GameObject>(instance.chatLogNode, instance.chatLogNodeHolder, false);
			((Object)val).name = "ChatterLine";
			ChatLogNode component = val.GetComponent<ChatLogNode>();
			if ((Object)(object)component != (Object)null)
			{
				if ((Object)(object)component.correct != (Object)null)
				{
					component.correct.SetActive(false);
				}
				if ((Object)(object)component.incorrect != (Object)null)
				{
					component.incorrect.SetActive(false);
				}
				if (instance.chatQueue != null)
				{
					instance.chatQueue.Enqueue(component);
				}
			}
			Line line = new Line
			{
				Object = val,
				Node = component,
				Who = who,
				What = what
			};
			val.SetActive(true);
			line.Forward = Forward(component, forward: true);
			line.ForwardUntil = Time.unscaledTime + 8f;
			Write(line);
			_mine.Add(line);
			while (_mine.Count > 20)
			{
				Object.Destroy((Object)(object)_mine[0].Object);
				_mine.RemoveAt(0);
			}
			RectTransform chatContent = instance.chatContent;
			if ((Object)(object)chatContent != (Object)null)
			{
				LayoutRebuilder.ForceRebuildLayoutImmediate(chatContent);
			}
		}

		public void Tick()
		{
			SpeakingManager instance = SpeakingManager.Instance;
			if ((Object)(object)instance == (Object)null)
			{
				return;
			}
			for (int i = 0; i < _mine.Count; i++)
			{
				Line line = _mine[i];
				if (line.Forward && !(Time.unscaledTime < line.ForwardUntil))
				{
					line.Forward = Forward(line.Node, forward: false);
				}
			}
		}

		private static bool Forward(ChatLogNode node, bool forward)
		{
			if ((Object)(object)node == (Object)null || (Object)(object)node.anim == (Object)null)
			{
				return false;
			}
			node.anim.SetBool("Show", forward);
			return forward;
		}

		public void LateTick()
		{
			for (int i = 0; i < _mine.Count; i++)
			{
				Write(_mine[i]);
			}
		}

		private static void Write(Line line)
		{
			ChatLogNode node = line.Node;
			if ((Object)(object)node == (Object)null)
			{
				return;
			}
			if ((Object)(object)node.nameText != (Object)null && ((TMP_Text)node.nameText).text != line.Who)
			{
				((TMP_Text)node.nameText).text = line.Who;
			}
			TextMeshProUGUI subtitleText = node.subtitleText;
			if (!((Object)(object)subtitleText == (Object)null))
			{
				if (((TMP_Text)subtitleText).text != line.What)
				{
					((TMP_Text)subtitleText).text = line.What;
					((TMP_Text)subtitleText).richText = false;
				}
				if (((TMP_Text)subtitleText).maxVisibleCharacters != int.MaxValue)
				{
					((TMP_Text)subtitleText).maxVisibleCharacters = int.MaxValue;
				}
			}
		}

		private void Forget()
		{
			foreach (Line item in _mine)
			{
				Object.Destroy((Object)(object)item.Object);
			}
			_mine.Clear();
		}

		public void Close()
		{
			Forget();
		}

		private void WarnOnce()
		{
			if (!_warned)
			{
				_warned = true;
				ModLog.Warning("SpeakingManager has no chat log to write into, so messages will only appear over people's heads.");
			}
		}
	}
	internal static class GameFont
	{
		private static TMP_FontAsset _asset;

		public static TMP_FontAsset Asset
		{
			get
			{
				if ((Object)(object)_asset != (Object)null)
				{
					return _asset;
				}
				SpeakingManager instance = SpeakingManager.Instance;
				if ((Object)(object)instance != (Object)null && (Object)(object)instance.subtitleText != (Object)null)
				{
					_asset = ((TMP_Text)instance.subtitleText).font;
				}
				if ((Object)(object)_asset == (Object)null)
				{
					PlayerManager localPlayerManager = NetworkContext.LocalPlayerManager;
					if ((Object)(object)localPlayerManager != (Object)null && (Object)(object)localPlayerManager.nameText != (Object)null)
					{
						_asset = ((TMP_Text)localPlayerManager.nameText).font;
					}
				}
				if ((Object)(object)_asset == (Object)null)
				{
					_asset = AnyLoaded();
				}
				if ((Object)(object)_asset == (Object)null)
				{
					ModLog.Warning("No TMP font found, so text will fall back to TMP's default.");
				}
				return _asset;
			}
		}

		public static void Rescan()
		{
			_asset = null;
		}

		private static TMP_FontAsset AnyLoaded()
		{
			Il2CppArrayBase<TextMeshProUGUI> val = Object.FindObjectsOfType<TextMeshProUGUI>();
			if (val == null)
			{
				return null;
			}
			for (int i = 0; i < val.Length; i++)
			{
				TextMeshProUGUI val2 = val[i];
				if ((Object)(object)val2 != (Object)null && (Object)(object)((TMP_Text)val2).font != (Object)null)
				{
					return ((TMP_Text)val2).font;
				}
			}
			return null;
		}
	}
	internal static class InputBlock
	{
		private const string Id = "clementinise.shiftatmidnight.chatter.input";

		public static bool FreezeHotbar;

		public static bool FreezeHistory;

		private static Harmony _harmony;

		public static void Install()
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Expected O, but got Unknown
			if (_harmony != null)
			{
				return;
			}
			try
			{
				_harmony = new Harmony("clementinise.shiftatmidnight.chatter.input");
				Refuse(AccessTools.Method(typeof(InventoryManager), "ChangeInventorySlot", (Type[])null, (Type[])null), "BeforeChangeSlot", "InventoryManager.ChangeInventorySlot", "the hotbar will stay live while typing");
				Refuse(AccessTools.Method(typeof(SpeakingManager), "Update", (Type[])null, (Type[])null), "BeforeSpeakingUpdate", "SpeakingManager.Update", "T will keep opening the dialogue history while typing");
			}
			catch (Exception ex)
			{
				ModLog.Warning("Could not install the input patches: " + ex.Message);
				_harmony = null;
			}
		}

		private static void Refuse(MethodBase target, string prefix, string what, string consequence)
		{
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Expected O, but got Unknown
			if (target == null)
			{
				ModLog.Warning(what + " not found - " + consequence + ".");
			}
			else
			{
				_harmony.Patch(target, new HarmonyMethod(AccessTools.Method(typeof(InputBlock), prefix, (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
		}

		public static void Remove()
		{
			FreezeHotbar = false;
			FreezeHistory = false;
			try
			{
				Harmony harmony = _harmony;
				if (harmony != null)
				{
					harmony.UnpatchSelf();
				}
			}
			catch (Exception ex)
			{
				ModLog.Warning("Could not unpatch the hotbar: " + ex.Message);
			}
			_harmony = null;
		}

		private static bool BeforeChangeSlot()
		{
			return !FreezeHotbar;
		}

		private static bool BeforeSpeakingUpdate()
		{
			return !FreezeHistory;
		}
	}
	internal static class ModLog
	{
		public static ManualLogSource Source;

		[Conditional("DEVTOOLS")]
		public static void Debug(string message)
		{
			ManualLogSource source = Source;
			if (source != null)
			{
				source.LogInfo((object)message);
			}
		}

		public static void Msg(string message)
		{
			ManualLogSource source = Source;
			if (source != null)
			{
				source.LogInfo((object)message);
			}
		}

		public static void Warning(string message)
		{
			ManualLogSource source = Source;
			if (source != null)
			{
				source.LogWarning((object)message);
			}
		}

		public static void Error(string message)
		{
			ManualLogSource source = Source;
			if (source != null)
			{
				source.LogError((object)message);
			}
		}
	}
	internal static class NetworkContext
	{
		public static NetworkRunner Runner
		{
			get
			{
				FusionNetworkManager instance = FusionNetworkManager.Instance;
				if ((Object)(object)instance == (Object)null)
				{
					return null;
				}
				NetworkRunner runner = instance._runner;
				if ((Object)(object)runner == (Object)null || !runner.IsRunning)
				{
					return null;
				}
				return runner;
			}
		}

		public static PlayerManager LocalPlayerManager
		{
			get
			{
				ClientPlayer instance = ClientPlayer.Instance;
				return ((Object)(object)instance == (Object)null) ? null : instance.playerMan;
			}
		}

		public static ThirdPersonManager LocalBody
		{
			get
			{
				PlayerManager localPlayerManager = LocalPlayerManager;
				return ((Object)(object)localPlayerManager == (Object)null) ? null : localPlayerManager.thirdPersonMan;
			}
		}

		public static Camera LocalCamera
		{
			get
			{
				PlayerManager localPlayerManager = LocalPlayerManager;
				if ((Object)(object)localPlayerManager != (Object)null)
				{
					FPSController fpsScript = localPlayerManager.fpsScript;
					if ((Object)(object)fpsScript != (Object)null && (Object)(object)fpsScript.playerCamera != (Object)null)
					{
						return fpsScript.playerCamera;
					}
					InteractManager interactMan = localPlayerManager.interactMan;
					if ((Object)(object)interactMan != (Object)null && (Object)(object)interactMan.mainCamera != (Object)null)
					{
						return interactMan.mainCamera;
					}
				}
				return Camera.main;
			}
		}

		public static ulong LocalSteamId
		{
			get
			{
				//IL_0002: Unknown result type (might be due to invalid IL or missing references)
				try
				{
					return SteamUser.GetSteamID().m_SteamID;
				}
				catch
				{
					return 0uL;
				}
			}
		}

		public static CSteamID Lobby
		{
			get
			{
				//IL_0020: Unknown result type (might be due to invalid IL or missing references)
				//IL_0033: Unknown result type (might be due to invalid IL or missing references)
				//IL_0034: 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_001a: Unknown result type (might be due to invalid IL or missing references)
				//IL_001b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0037: Unknown result type (might be due to invalid IL or missing references)
				PlatformManager instance = PlatformManager.Instance;
				if ((Object)(object)instance == (Object)null)
				{
					return default(CSteamID);
				}
				return new CSteamID
				{
					m_SteamID = instance._lobbyID
				};
			}
		}
	}
	internal static class PlayerRoster
	{
		private const float ScanInterval = 1f;

		private static readonly Dictionary<ulong, PlayerManager> _bodies = new Dictionary<ulong, PlayerManager>();

		private static readonly Dictionary<ulong, string> _names = new Dictionary<ulong, string>();

		private static float _nextScan;

		private static string _lastShape;

		public static PlayerManager Body(ulong steamId)
		{
			Scan();
			if (!_bodies.TryGetValue(steamId, out var value))
			{
				return null;
			}
			return ((Object)(object)value == (Object)null) ? null : value;
		}

		public static string Name(ulong steamId)
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			Scan();
			if (_names.TryGetValue(steamId, out var value) && !string.IsNullOrEmpty(value))
			{
				return value;
			}
			try
			{
				string friendPersonaName = SteamFriends.GetFriendPersonaName(new CSteamID
				{
					m_SteamID = steamId
				});
				if (!string.IsNullOrEmpty(friendPersonaName))
				{
					return friendPersonaName;
				}
			}
			catch
			{
			}
			return "Player";
		}

		public static Transform Head(PlayerManager body)
		{
			if ((Object)(object)body == (Object)null)
			{
				return null;
			}
			ThirdPersonManager thirdPersonMan = body.thirdPersonMan;
			if ((Object)(object)thirdPersonMan != (Object)null && (Object)(object)thirdPersonMan.nameCanvas != (Object)null)
			{
				return thirdPersonMan.nameCanvas.transform;
			}
			return ((Component)body).transform;
		}

		public static void Clear()
		{
			_bodies.Clear();
			_names.Clear();
			_nextScan = 0f;
			_lastShape = null;
		}

		private static void Scan()
		{
			if (Time.unscaledTime < _nextScan)
			{
				return;
			}
			_nextScan = Time.unscaledTime + 1f;
			_bodies.Clear();
			PlatformManager instance = PlatformManager.Instance;
			if ((Object)(object)instance == (Object)null)
			{
				return;
			}
			ReadNames(instance);
			Il2CppArrayBase<PlayerManager> val = Object.FindObjectsOfType<PlayerManager>();
			if (val == null)
			{
				return;
			}
			PlayerManager localPlayerManager = NetworkContext.LocalPlayerManager;
			for (int i = 0; i < val.Length; i++)
			{
				PlayerManager val2 = val[i];
				if (!((Object)(object)val2 == (Object)null) && Identify(instance, val2, localPlayerManager, out var steamId))
				{
					_bodies[steamId] = val2;
				}
			}
			string text = $"{val.Length}/{_bodies.Count}/{_names.Count}";
			if (!(text == _lastShape))
			{
				_lastShape = text;
			}
		}

		private static bool Identify(PlatformManager platform, PlayerManager body, PlayerManager local, out ulong steamId)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			NetworkObject val = ((SimulationBehaviour)body).Object;
			if ((Object)(object)val != (Object)null)
			{
				PlayerRef inputAuthority = val.InputAuthority;
				if (Parse(platform.GetPlayerUIDForFusionPlayerId(((PlayerRef)(ref inputAuthority)).PlayerId), out steamId))
				{
					return true;
				}
			}
			if ((Object)(object)body == (Object)(object)local && Parse(platform.GetPlayerUID(), out steamId))
			{
				return true;
			}
			return ByName(body.playerName, out steamId);
		}

		private static bool ByName(string playerName, out ulong steamId)
		{
			steamId = 0uL;
			if (string.IsNullOrEmpty(playerName))
			{
				return false;
			}
			foreach (KeyValuePair<ulong, string> name in _names)
			{
				if (name.Value != playerName)
				{
					continue;
				}
				steamId = name.Key;
				return true;
			}
			return false;
		}

		private static bool Parse(string uid, out ulong steamId)
		{
			steamId = 0uL;
			if (string.IsNullOrEmpty(uid))
			{
				return false;
			}
			return ulong.TryParse(uid, NumberStyles.Integer, CultureInfo.InvariantCulture, out steamId);
		}

		private static void ReadNames(PlatformManager platform)
		{
			List<NetPlayerData> lobbyMembers = platform.GetLobbyMembers();
			if (lobbyMembers == null)
			{
				return;
			}
			for (int i = 0; i < lobbyMembers.Count; i++)
			{
				NetPlayerData val = lobbyMembers[i];
				if (val != null && !string.IsNullOrEmpty(val._UID) && ulong.TryParse(val._UID, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result))
				{
					_names[result] = val._Gamertag;
				}
			}
		}
	}
}