Decompiled source of Emote Sync v0.3.1

EmoteSync.dll

Decompiled 6 hours ago
using System;
using System.Collections;
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 System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using OnTogetherMods.Shared;
using PurrNet;
using PurrNet.Modules;
using Steamworks;
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("EmoteSync")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.3.1.0")]
[assembly: AssemblyInformationalVersion("0.3.1+622bd7ccbb267719684ff770ce18e1834dc51b45")]
[assembly: AssemblyProduct("EmoteSync")]
[assembly: AssemblyTitle("EmoteSync")]
[assembly: AssemblyVersion("0.3.1.0")]
[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 OnTogetherMods.Shared
{
	internal static class PanelStack
	{
		private const string TableKey = "OnTogetherMods.PanelStack.Panels";

		private const string HiddenKey = "OnTogetherMods.PanelStack.Hidden";

		private const string IconBarKey = "OnTogetherMods.IconBar.Rect";

		private const float Margin = 20f;

		private const float FromRight = 0.15f;

		private const float Gap = 10f;

		private const int WorldScene = 2;

		public const int PhotoModeOrder = 0;

		public const int EmoteSyncOrder = 10;

		public const int TeleportSpotsOrder = 20;

		public const int SongPlayerOrder = 30;

		public const int TraceOverlayOrder = 40;

		public const int NameDesignerOrder = 50;

		public const string CanvasPrefix = "OnTogetherMods ";

		private static int _deskFrame = -1;

		private static bool _desk;

		public static float Width => (float)Screen.width * 1080f / (float)Screen.height;

		public static bool Hidden
		{
			get
			{
				if (!(AppDomain.CurrentDomain.GetData("OnTogetherMods.PanelStack.Hidden") is int num) || Time.frameCount > num)
				{
					return InDeskMode;
				}
				return true;
			}
		}

		public static bool InDeskMode
		{
			get
			{
				//IL_001a: Unknown result type (might be due to invalid IL or missing references)
				//IL_001f: Unknown result type (might be due to invalid IL or missing references)
				//IL_003a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0040: Invalid comparison between Unknown and I4
				int frameCount = Time.frameCount;
				if (_deskFrame != frameCount)
				{
					_deskFrame = frameCount;
					_desk = false;
					Scene activeScene = SceneManager.GetActiveScene();
					if (((Scene)(ref activeScene)).buildIndex == 2)
					{
						OverlayManager i = MonoSingleton<OverlayManager>.I;
						_desk = (Object)(object)i != (Object)null && (int)i.ResolutionMode == 3;
					}
				}
				return _desk;
			}
		}

		public static bool IsModCanvas(Canvas canvas)
		{
			Canvas val = canvas;
			Transform parent = ((Component)canvas).transform.parent;
			while ((Object)(object)parent != (Object)null)
			{
				Canvas component = ((Component)parent).GetComponent<Canvas>();
				val = (((Object)(object)component != (Object)null) ? component : val);
				parent = parent.parent;
			}
			return ((Object)((Component)val).gameObject).name.StartsWith("OnTogetherMods ", StringComparison.Ordinal);
		}

		public static void HideForCapture()
		{
			AppDomain.CurrentDomain.SetData("OnTogetherMods.PanelStack.Hidden", Time.frameCount + 1);
		}

		public static Rect Place(string id, int order, Vector2 size)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: 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_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: 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)
			Hashtable hashtable = Panels();
			int frameCount = Time.frameCount;
			hashtable[id] = new double[3] { order, size.y, frameCount };
			float width = Width;
			float num = Mathf.Max(20f, width * 0.85f - size.x);
			float num2 = Bottom(num + size.x, frameCount) - size.y;
			foreach (DictionaryEntry item in hashtable)
			{
				string text = (string)item.Key;
				double[] array = (double[])item.Value;
				bool flag = (double)frameCount - array[2] <= 2.0;
				bool flag2 = array[0] < (double)order || (array[0] == (double)order && string.CompareOrdinal(text, id) < 0);
				if (text != id && flag && flag2)
				{
					num2 -= (float)array[1] + 10f;
				}
			}
			return new Rect(num, num2, size.x, size.y);
		}

		private static float Bottom(float windowRight, int frame)
		{
			float num = 1060f;
			if (AppDomain.CurrentDomain.GetData("OnTogetherMods.IconBar.Rect") is double[] array && (double)frame - array[4] <= 2.0)
			{
				float num2 = 1080f / (float)Screen.height;
				if (array[0] * (double)num2 < (double)(windowRight + 10f))
				{
					num = Mathf.Min(num, (float)array[1] * num2 - 10f);
				}
			}
			return num;
		}

		public static Matrix4x4 Begin(out float width)
		{
			//IL_000d: 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_001e: Unknown result type (might be due to invalid IL or missing references)
			float num = (float)Screen.height / 1080f;
			Matrix4x4 matrix = GUI.matrix;
			GUI.matrix = Matrix4x4.Scale(new Vector3(num, num, 1f));
			width = (float)Screen.width / num;
			return matrix;
		}

		public static void End(Matrix4x4 previous)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			GUI.matrix = previous;
		}

		public static GUIStyle MakeStyle(TextAnchor alignment)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//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)
			//IL_0016: 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_0025: 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_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Expected O, but got Unknown
			//IL_003f: 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_0050: Expected O, but got Unknown
			GUIStyle val = new GUIStyle(GUI.skin.box)
			{
				alignment = alignment,
				fontSize = 15,
				richText = true,
				wordWrap = false,
				padding = new RectOffset(12, 12, 10, 10)
			};
			val.normal.textColor = Color.white;
			return val;
		}

		private static Hashtable Panels()
		{
			Hashtable hashtable = AppDomain.CurrentDomain.GetData("OnTogetherMods.PanelStack.Panels") as Hashtable;
			if (hashtable == null)
			{
				hashtable = new Hashtable();
				AppDomain.CurrentDomain.SetData("OnTogetherMods.PanelStack.Panels", hashtable);
			}
			return hashtable;
		}
	}
	internal static class IconBar
	{
		public enum State
		{
			Plain,
			Open,
			On,
			Off
		}

		public enum Click
		{
			None,
			Left,
			Right
		}

		private struct Metrics
		{
			public float Unit;

			public int Art;

			public int Button;

			public int Gap;

			public int Margin;
		}

		private static class Patches
		{
			private static Action<InputManager, bool> _setMouse0Down;

			private static Action<InputManager, bool> _setMouse1;

			private static Action<InputManager, bool> _setMouse1Up;

			private static FieldRef<QuadPainterGPU, Vector2> _previousUV;

			private static bool _leftOnBar;

			private static bool _rightOnBar;

			public static void Apply(Harmony harmony)
			{
				//IL_0055: Unknown result type (might be due to invalid IL or missing references)
				//IL_0062: Expected O, but got Unknown
				//IL_0099: Unknown result type (might be due to invalid IL or missing references)
				//IL_00a7: Expected O, but got Unknown
				_setMouse0Down = Setter("IsMouseButton0Down");
				_setMouse1 = Setter("IsMouseButton1");
				_setMouse1Up = Setter("IsMouseButton1Up");
				harmony.Patch((MethodBase)AccessTools.Method(typeof(InputManager), "Update", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(Patches), "InputPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				_previousUV = AccessTools.FieldRefAccess<QuadPainterGPU, Vector2>("previousUV");
				harmony.Patch((MethodBase)AccessTools.Method(typeof(QuadPainterGPU), "Update", (Type[])null, (Type[])null), new HarmonyMethod(typeof(Patches), "PaintPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}

			private static void InputPostfix(InputManager __instance)
			{
				bool mouseOver = MouseOver;
				if (Input.GetMouseButtonDown(0))
				{
					_leftOnBar = mouseOver;
				}
				if (Input.GetMouseButtonDown(1))
				{
					_rightOnBar = mouseOver;
				}
				if (mouseOver)
				{
					_setMouse0Down(__instance, arg2: false);
				}
				if (_rightOnBar)
				{
					_setMouse1(__instance, arg2: false);
					_setMouse1Up(__instance, arg2: false);
				}
				if (!Input.GetMouseButton(0))
				{
					_leftOnBar = false;
				}
				if (!Input.GetMouseButton(1))
				{
					_rightOnBar = false;
				}
			}

			private static bool PaintPrefix(QuadPainterGPU __instance)
			{
				if (__instance.IsActive && (_leftOnBar || MouseOver))
				{
					_previousUV.Invoke(__instance).x = -1f;
					return false;
				}
				return true;
			}

			private static Action<InputManager, bool> Setter(string property)
			{
				return (Action<InputManager, bool>)Delegate.CreateDelegate(typeof(Action<InputManager, bool>), AccessTools.PropertySetter(typeof(InputManager), property));
			}
		}

		public const int PhotoModeOrder = 0;

		public const int EmoteSyncOrder = 10;

		public const int TeleportSpotsOrder = 20;

		public const int NameDesignerOrder = 30;

		public const int DeskSnapOrder = 40;

		public const int FocusAnywhereOrder = 50;

		public const int SongPlayerOrder = 60;

		public const int TraceOverlayOrder = 70;

		public const int ChatRangeOrder = 80;

		private const string RectKey = "OnTogetherMods.IconBar.Rect";

		private const string TableKey = "OnTogetherMods.IconBar.Icons";

		private const string PatchedKey = "OnTogetherMods.IconBar.Patched";

		private const string BlockerKey = "OnTogetherMods.IconBar.Blocker";

		private const string BlockerFrameKey = "OnTogetherMods.IconBar.BlockerFrame";

		private const string HiddenKey = "OnTogetherMods.IconBar.HiddenUntil";

		private const int WorldScene = 2;

		private const int TooltipDepth = -100;

		private static readonly Dictionary<char, Color32> Palette = new Dictionary<char, Color32>
		{
			{
				'K',
				new Color32((byte)42, (byte)36, (byte)51, byte.MaxValue)
			},
			{
				'W',
				new Color32((byte)247, (byte)243, (byte)234, byte.MaxValue)
			},
			{
				'G',
				new Color32((byte)201, (byte)198, (byte)207, byte.MaxValue)
			},
			{
				'g',
				new Color32((byte)143, (byte)138, (byte)153, byte.MaxValue)
			},
			{
				'D',
				new Color32((byte)87, (byte)82, (byte)95, byte.MaxValue)
			},
			{
				'B',
				new Color32((byte)168, (byte)107, (byte)60, byte.MaxValue)
			},
			{
				'b',
				new Color32((byte)217, (byte)160, (byte)102, byte.MaxValue)
			},
			{
				'd',
				new Color32((byte)110, (byte)67, (byte)37, byte.MaxValue)
			},
			{
				'R',
				new Color32((byte)224, (byte)90, (byte)90, byte.MaxValue)
			},
			{
				'r',
				new Color32((byte)168, (byte)58, (byte)70, byte.MaxValue)
			},
			{
				'p',
				new Color32((byte)246, (byte)165, (byte)165, byte.MaxValue)
			},
			{
				'Y',
				new Color32((byte)245, (byte)208, (byte)97, byte.MaxValue)
			},
			{
				'y',
				new Color32((byte)201, (byte)150, (byte)50, byte.MaxValue)
			},
			{
				'O',
				new Color32((byte)232, (byte)146, (byte)74, byte.MaxValue)
			},
			{
				'L',
				new Color32((byte)159, (byte)214, (byte)245, byte.MaxValue)
			},
			{
				'U',
				new Color32((byte)74, (byte)143, (byte)217, byte.MaxValue)
			},
			{
				'u',
				new Color32((byte)47, (byte)90, (byte)158, byte.MaxValue)
			},
			{
				'N',
				new Color32((byte)116, (byte)192, (byte)105, byte.MaxValue)
			},
			{
				'n',
				new Color32((byte)63, (byte)138, (byte)74, byte.MaxValue)
			},
			{
				'P',
				new Color32((byte)246, (byte)207, (byte)174, byte.MaxValue)
			},
			{
				'V',
				new Color32((byte)154, (byte)114, (byte)214, byte.MaxValue)
			},
			{
				'v',
				new Color32((byte)105, (byte)72, (byte)160, byte.MaxValue)
			},
			{
				'S',
				new Color32((byte)233, (byte)139, (byte)181, byte.MaxValue)
			},
			{
				'H',
				new Color32((byte)60, (byte)48, (byte)56, byte.MaxValue)
			}
		};

		private static readonly Color32 ButtonFill = new Color32((byte)28, (byte)26, (byte)34, (byte)200);

		private static readonly Color32 ButtonEdge = new Color32(byte.MaxValue, byte.MaxValue, byte.MaxValue, (byte)30);

		private static readonly Color32 HoverFill = new Color32((byte)48, (byte)45, (byte)58, (byte)225);

		private static readonly Color32 HoverEdge = new Color32(byte.MaxValue, byte.MaxValue, byte.MaxValue, (byte)80);

		private static readonly Color32 OpenFill = new Color32((byte)70, (byte)64, (byte)88, (byte)235);

		private static readonly Color32 OpenEdge = new Color32(byte.MaxValue, byte.MaxValue, byte.MaxValue, (byte)150);

		private static readonly Color32 DotFill = new Color32((byte)140, (byte)220, (byte)120, byte.MaxValue);

		private static readonly Color32 DotEdge = new Color32((byte)20, (byte)40, (byte)20, byte.MaxValue);

		private static readonly Dictionary<string[], Texture2D[]> Icons = new Dictionary<string[], Texture2D[]>();

		private static Texture2D _buttonTexture;

		private static Texture2D _hoverTexture;

		private static Texture2D _openTexture;

		private static Texture2D _dotTexture;

		private static GUIStyle _buttonStyle;

		private static GUIStyle _tipStyle;

		private static int _builtFor;

		private static int _cachedFrame = -1;

		private static bool _inWorld;

		private static bool _visible;

		private static int _pressedButton;

		private static bool RowHidden
		{
			get
			{
				if (AppDomain.CurrentDomain.GetData("OnTogetherMods.IconBar.HiddenUntil") is int num)
				{
					return Time.frameCount <= num;
				}
				return false;
			}
		}

		public static bool MouseOver
		{
			get
			{
				//IL_003d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0042: 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_0068: 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)
				if (!(AppDomain.CurrentDomain.GetData("OnTogetherMods.IconBar.Rect") is double[] array) || array[5] < 0.5 || (double)Time.frameCount - array[4] > 2.0)
				{
					return false;
				}
				Vector3 mousePosition = Input.mousePosition;
				Rect val = default(Rect);
				((Rect)(ref val))..ctor((float)array[0], (float)array[1], (float)array[2], (float)array[3]);
				return ((Rect)(ref val)).Contains(new Vector2(mousePosition.x, (float)Screen.height - mousePosition.y));
			}
		}

		public static Click Draw(string id, int order, string[] pixels, State state, string name, KeyCode key, string hint = null)
		{
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: 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_0049: 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_0029: 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_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			int controlID = GUIUtility.GetControlID((FocusType)2);
			Event current = Event.current;
			Refresh();
			if (!_inWorld)
			{
				Hide(controlID, current);
				UpdateBlocker(shown: false, default(Rect));
				return Click.None;
			}
			Rect bar;
			Metrics m;
			Rect icon = Place(id, order, out bar, out m);
			Share(bar);
			UpdateBlocker(_visible, bar);
			if (!_visible)
			{
				Hide(controlID, current);
				return Click.None;
			}
			Matrix4x4 matrix = GUI.matrix;
			GUI.matrix = Matrix4x4.identity;
			try
			{
				return Handle(controlID, current, icon, m, pixels, state, name, key, hint);
			}
			finally
			{
				GUI.matrix = matrix;
			}
		}

		public static void HideRow()
		{
			AppDomain.CurrentDomain.SetData("OnTogetherMods.IconBar.HiddenUntil", Time.frameCount + 1);
		}

		public static string KeyText(KeyCode key)
		{
			//IL_0000: 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)
			if ((int)key != 0)
			{
				return $" ({key})";
			}
			return "";
		}

		private static Click Handle(int control, Event e, Rect icon, Metrics m, string[] pixels, State state, string name, KeyCode key, string hint)
		{
			//IL_0003: 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_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Expected I4, but got Unknown
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Invalid comparison between Unknown and I4
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_015a: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bb: 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_01e3: Unknown result type (might be due to invalid IL or missing references)
			bool flag = ((Rect)(ref icon)).Contains(e.mousePosition);
			EventType typeForControl = e.GetTypeForControl(control);
			switch ((int)typeForControl)
			{
			default:
			{
				if ((int)typeForControl != 7)
				{
					break;
				}
				BuildStyles(m);
				bool flag2 = GUIUtility.hotControl == control;
				_buttonStyle.normal.background = ((state == State.Open || (flag2 && flag)) ? _openTexture : (flag ? _hoverTexture : _buttonTexture));
				_buttonStyle.Draw(icon, false, false, false, false);
				Texture2D[] array = IconTextures(pixels);
				GUI.DrawTexture(new Rect(((Rect)(ref icon)).x + (((Rect)(ref icon)).width - (float)m.Art) / 2f, ((Rect)(ref icon)).y + (((Rect)(ref icon)).height - (float)m.Art) / 2f, (float)m.Art, (float)m.Art), (Texture)(object)((state == State.Off) ? array[1] : array[0]));
				if (state == State.On)
				{
					float num = Mathf.Max(1, Mathf.RoundToInt(2f * m.Unit));
					float num2 = ((Texture)_dotTexture).width;
					GUI.DrawTexture(new Rect(((Rect)(ref icon)).xMax - num - num2, ((Rect)(ref icon)).yMax - num - num2, num2, num2), (Texture)(object)_dotTexture);
				}
				int num3;
				if (flag)
				{
					num3 = ((GUIUtility.hotControl == 0 || flag2) ? 1 : 0);
					if (num3 != 0)
					{
						DrawTooltip(icon, m, Tooltip(state, name, key, hint));
					}
				}
				else
				{
					num3 = 0;
				}
				GUI.depth = ((num3 != 0) ? (-100) : 0);
				break;
			}
			case 0:
				if (flag && (e.button == 0 || e.button == 1))
				{
					GUIUtility.hotControl = control;
					_pressedButton = e.button;
					e.Use();
				}
				break;
			case 3:
				if (GUIUtility.hotControl == control)
				{
					e.Use();
				}
				break;
			case 1:
				if (GUIUtility.hotControl != control)
				{
					break;
				}
				GUIUtility.hotControl = 0;
				e.Use();
				if (flag && e.button == _pressedButton)
				{
					if (e.button != 0)
					{
						return Click.Right;
					}
					return Click.Left;
				}
				break;
			case 2:
				break;
			}
			return Click.None;
		}

		private static string Tooltip(State state, string name, KeyCode key, string hint)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			string text = name + KeyText(key);
			switch (state)
			{
			case State.On:
				text += ": on";
				break;
			case State.Off:
				text += ": off";
				break;
			}
			if (hint == null)
			{
				return text;
			}
			return text + "\n" + hint;
		}

		private static void DrawTooltip(Rect icon, Metrics m, string text)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Expected O, but got Unknown
			//IL_000d: 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_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: 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)
			GUIContent val = new GUIContent(text);
			Vector2 val2 = _tipStyle.CalcSize(val);
			float num = Mathf.Clamp(((Rect)(ref icon)).center.x - val2.x / 2f, (float)m.Margin, Mathf.Max((float)m.Margin, (float)(Screen.width - m.Margin) - val2.x));
			float num2 = ((Rect)(ref icon)).y - (float)m.Gap - val2.y;
			_tipStyle.Draw(new Rect(Mathf.Round(num), Mathf.Round(num2), val2.x, val2.y), val, false, false, false, false);
		}

		private static void Hide(int control, Event e)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Invalid comparison between Unknown and I4
			if (GUIUtility.hotControl == control)
			{
				GUIUtility.hotControl = 0;
			}
			if ((int)e.type == 7)
			{
				GUI.depth = 0;
			}
		}

		private static Metrics Measure()
		{
			float num = (float)Screen.height / 1080f;
			int num2 = Mathf.Max(1, Mathf.RoundToInt(2f * num));
			int num3 = Mathf.Max(2, Mathf.RoundToInt(4f * num));
			return new Metrics
			{
				Unit = num,
				Art = 16 * num2,
				Button = 16 * num2 + 2 * num3,
				Gap = Mathf.Max(2, Mathf.RoundToInt(6f * num)),
				Margin = Mathf.RoundToInt(20f * num)
			};
		}

		private static Rect Place(string id, int order, out Rect bar, out Metrics m)
		{
			//IL_0132: Unknown result type (might be due to invalid IL or missing references)
			//IL_0137: Unknown result type (might be due to invalid IL or missing references)
			//IL_0160: Unknown result type (might be due to invalid IL or missing references)
			Hashtable hashtable = Table();
			int frameCount = Time.frameCount;
			if (hashtable[id] is double[] array)
			{
				array[0] = order;
				array[1] = frameCount;
			}
			else
			{
				hashtable[id] = new double[2] { order, frameCount };
			}
			int num = 0;
			int num2 = 0;
			foreach (DictionaryEntry item in hashtable)
			{
				string text = (string)item.Key;
				double[] array2 = (double[])item.Value;
				if (!((double)frameCount - array2[1] > 2.0))
				{
					num2++;
					if (text != id && (array2[0] < (double)order || (array2[0] == (double)order && string.CompareOrdinal(text, id) < 0)))
					{
						num++;
					}
				}
			}
			m = Measure();
			int num3 = num2 * m.Button + (num2 - 1) * m.Gap;
			int num4 = Screen.width - m.Margin - num3;
			int num5 = Screen.height - m.Margin - m.Button;
			bar = new Rect((float)num4, (float)num5, (float)num3, (float)m.Button);
			return new Rect((float)(num4 + num * (m.Button + m.Gap)), (float)num5, (float)m.Button, (float)m.Button);
		}

		private static void Share(Rect bar)
		{
			AppDomain currentDomain = AppDomain.CurrentDomain;
			int frameCount = Time.frameCount;
			if (!(currentDomain.GetData("OnTogetherMods.IconBar.Rect") is double[] array) || (int)array[4] != frameCount || !(array[2] >= (double)((Rect)(ref bar)).width))
			{
				currentDomain.SetData("OnTogetherMods.IconBar.Rect", new double[6]
				{
					((Rect)(ref bar)).x,
					((Rect)(ref bar)).y,
					((Rect)(ref bar)).width,
					((Rect)(ref bar)).height,
					frameCount,
					_visible ? 1 : 0
				});
			}
		}

		private static Hashtable Table()
		{
			Hashtable hashtable = AppDomain.CurrentDomain.GetData("OnTogetherMods.IconBar.Icons") as Hashtable;
			if (hashtable == null)
			{
				hashtable = new Hashtable();
				AppDomain.CurrentDomain.SetData("OnTogetherMods.IconBar.Icons", hashtable);
			}
			return hashtable;
		}

		private static void Refresh()
		{
			//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_0055: 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_0063: Invalid comparison between Unknown and I4
			int frameCount = Time.frameCount;
			if (_cachedFrame != frameCount)
			{
				_cachedFrame = frameCount;
				Scene activeScene = SceneManager.GetActiveScene();
				_inWorld = ((Scene)(ref activeScene)).buildIndex == 2;
				_visible = false;
				if (_inWorld && !PanelStack.Hidden && !RowHidden)
				{
					TaskManager i = MonoSingleton<TaskManager>.I;
					_visible = (Object)(object)i != (Object)null && ((int)i.LockState == 0 || (int)i.LockState == 5);
				}
			}
		}

		private static void UpdateBlocker(bool shown, Rect bar)
		{
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Expected O, but got Unknown
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			AppDomain currentDomain = AppDomain.CurrentDomain;
			int frameCount = Time.frameCount;
			if (currentDomain.GetData("OnTogetherMods.IconBar.BlockerFrame") is int num && num == frameCount)
			{
				return;
			}
			currentDomain.SetData("OnTogetherMods.IconBar.BlockerFrame", frameCount);
			object? data = currentDomain.GetData("OnTogetherMods.IconBar.Blocker");
			GameObject val = (GameObject)((data is GameObject) ? data : null);
			if ((Object)(object)val == (Object)null)
			{
				if (!shown)
				{
					return;
				}
				val = CreateBlocker();
				currentDomain.SetData("OnTogetherMods.IconBar.Blocker", val);
			}
			if (shown)
			{
				RectTransform val2 = (RectTransform)val.transform.GetChild(0);
				Vector2 val3 = default(Vector2);
				((Vector2)(ref val3))..ctor(((Rect)(ref bar)).x, (float)Screen.height - ((Rect)(ref bar)).yMax);
				if (val2.anchoredPosition != val3)
				{
					val2.anchoredPosition = val3;
				}
				if (val2.sizeDelta != ((Rect)(ref bar)).size)
				{
					val2.sizeDelta = ((Rect)(ref bar)).size;
				}
			}
			if (val.activeSelf != shown)
			{
				val.SetActive(shown);
			}
		}

		private static GameObject CreateBlocker()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Expected O, but got Unknown
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: 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)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("OnTogetherMods IconBar ClickBlocker");
			Object.DontDestroyOnLoad((Object)(object)val);
			Canvas obj = val.AddComponent<Canvas>();
			obj.renderMode = (RenderMode)0;
			obj.sortingOrder = 32767;
			val.AddComponent<GraphicRaycaster>();
			GameObject val2 = new GameObject("Area", new Type[3]
			{
				typeof(RectTransform),
				typeof(CanvasRenderer),
				typeof(Image)
			});
			val2.transform.SetParent(val.transform, false);
			((Graphic)val2.GetComponent<Image>()).color = Color.clear;
			RectTransform val3 = (RectTransform)val2.transform;
			val3.anchorMin = Vector2.zero;
			val3.anchorMax = Vector2.zero;
			val3.pivot = Vector2.zero;
			val.SetActive(false);
			return val;
		}

		public static void Patch()
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Expected O, but got Unknown
			AppDomain currentDomain = AppDomain.CurrentDomain;
			if (currentDomain.GetData("OnTogetherMods.IconBar.Patched") != null)
			{
				return;
			}
			currentDomain.SetData("OnTogetherMods.IconBar.Patched", true);
			try
			{
				Patches.Apply(new Harmony("nelphei.ontogether.iconbar"));
			}
			catch (Exception arg)
			{
				Debug.LogError((object)$"[OnTogetherMods] Icon bar patches failed, so clicks on it may reach the game: {arg}");
			}
		}

		private static Texture2D[] IconTextures(string[] pixels)
		{
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: 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_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			if (Icons.TryGetValue(pixels, out var value) && (Object)(object)value[0] != (Object)null && (Object)(object)value[1] != (Object)null)
			{
				return value;
			}
			Color32[] array = (Color32[])(object)new Color32[256];
			Color32[] array2 = (Color32[])(object)new Color32[256];
			for (int i = 0; i < 16; i++)
			{
				string text = ((i < pixels.Length) ? pixels[i] : "");
				for (int j = 0; j < 16; j++)
				{
					char key = ((j < text.Length) ? text[j] : '.');
					Color32 value2;
					Color32 val = (Color32)(Palette.TryGetValue(key, out value2) ? value2 : new Color32((byte)0, (byte)0, (byte)0, (byte)0));
					int num = (15 - i) * 16 + j;
					array[num] = val;
					byte b = (byte)Mathf.RoundToInt(0.3f * (float)(int)val.r + 0.59f * (float)(int)val.g + 0.11f * (float)(int)val.b);
					array2[num] = new Color32(b, b, b, (byte)((float)(int)val.a * 0.45f));
				}
			}
			value = (Texture2D[])(object)new Texture2D[2]
			{
				NewTexture(16, 16, array, (FilterMode)0),
				NewTexture(16, 16, array2, (FilterMode)0)
			};
			Icons[pixels] = value;
			return value;
		}

		private static void BuildStyles(Metrics m)
		{
			//IL_0078: 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)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: 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_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Expected O, but got Unknown
			//IL_0105: Expected O, but got Unknown
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: Expected O, but got Unknown
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_015e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0168: Expected O, but got Unknown
			//IL_0168: Unknown result type (might be due to invalid IL or missing references)
			//IL_0185: 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_0193: Unknown result type (might be due to invalid IL or missing references)
			//IL_019f: Expected O, but got Unknown
			//IL_01bd: Unknown result type (might be due to invalid IL or missing references)
			if (_builtFor != Screen.height || _buttonStyle == null || !((Object)(object)_buttonTexture != (Object)null) || !((Object)(object)_dotTexture != (Object)null))
			{
				_builtFor = Screen.height;
				int num = Mathf.Max(2, Mathf.RoundToInt(6f * m.Unit));
				Destroy(_buttonTexture);
				Destroy(_hoverTexture);
				Destroy(_openTexture);
				Destroy(_dotTexture);
				_buttonTexture = RoundedBox(num, ButtonFill, ButtonEdge);
				_hoverTexture = RoundedBox(num, HoverFill, HoverEdge);
				_openTexture = RoundedBox(num, OpenFill, OpenEdge);
				int num2 = Mathf.Max(2, Mathf.RoundToInt(3f * m.Unit));
				_dotTexture = RoundedBox(num2, DotFill, DotEdge, 2 * num2);
				int num3 = num + 1;
				_buttonStyle = new GUIStyle
				{
					border = new RectOffset(num3, num3, num3, num3)
				};
				_tipStyle = new GUIStyle
				{
					border = new RectOffset(num3, num3, num3, num3),
					padding = new RectOffset(Mathf.RoundToInt(10f * m.Unit), Mathf.RoundToInt(10f * m.Unit), Mathf.RoundToInt(6f * m.Unit), Mathf.RoundToInt(6f * m.Unit)),
					fontSize = Mathf.Max(8, Mathf.RoundToInt(15f * m.Unit)),
					alignment = (TextAnchor)3,
					wordWrap = false,
					richText = false
				};
				_tipStyle.normal.background = _hoverTexture;
				_tipStyle.normal.textColor = Color.white;
			}
		}

		private static Texture2D RoundedBox(int radius, Color32 fill, Color32 edge, int size = 0)
		{
			//IL_008c: 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)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: 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_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: 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)
			if (size <= 0)
			{
				size = 2 * radius + 4;
			}
			Color32[] array = (Color32[])(object)new Color32[size * size];
			for (int i = 0; i < size; i++)
			{
				for (int j = 0; j < size; j++)
				{
					float num = (float)j + 0.5f;
					float num2 = (float)i + 0.5f;
					float num3 = Mathf.Max(Mathf.Max((float)radius - num, num - (float)(size - radius)), 0f);
					float num4 = Mathf.Max(Mathf.Max((float)radius - num2, num2 - (float)(size - radius)), 0f);
					float num5 = Mathf.Sqrt(num3 * num3 + num4 * num4) - (float)radius;
					float num6 = Mathf.Clamp01(0.5f - num5);
					Color val = Color.Lerp(Color32.op_Implicit(fill), Color32.op_Implicit(edge), Mathf.Clamp01(num5 + 1.5f));
					val.a *= num6;
					array[i * size + j] = Color32.op_Implicit(val);
				}
			}
			return NewTexture(size, size, array, (FilterMode)1);
		}

		private static Texture2D NewTexture(int width, int height, Color32[] pixels, FilterMode filter)
		{
			//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_000a: 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_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: 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_002f: Expected O, but got Unknown
			Texture2D val = new Texture2D(width, height, (TextureFormat)4, false)
			{
				filterMode = filter,
				wrapMode = (TextureWrapMode)1,
				hideFlags = (HideFlags)61
			};
			val.SetPixels32(pixels);
			val.Apply(false, true);
			return val;
		}

		private static void Destroy(Texture2D texture)
		{
			if ((Object)(object)texture != (Object)null)
			{
				Object.Destroy((Object)(object)texture);
			}
		}
	}
	internal sealed class ClickBlocker
	{
		private readonly GameObject _root;

		private readonly RectTransform _area;

		public ClickBlocker(string name)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Expected O, but got Unknown
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Expected O, but got Unknown
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Expected O, but got Unknown
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			_root = new GameObject(name);
			Object.DontDestroyOnLoad((Object)(object)_root);
			Canvas obj = _root.AddComponent<Canvas>();
			obj.renderMode = (RenderMode)0;
			obj.sortingOrder = 32767;
			_root.AddComponent<GraphicRaycaster>();
			GameObject val = new GameObject("Area", new Type[3]
			{
				typeof(RectTransform),
				typeof(CanvasRenderer),
				typeof(Image)
			});
			val.transform.SetParent(_root.transform, false);
			((Graphic)val.GetComponent<Image>()).color = Color.clear;
			_area = (RectTransform)val.transform;
			_area.anchorMin = Vector2.zero;
			_area.anchorMax = Vector2.zero;
			_area.pivot = Vector2.zero;
			_root.SetActive(false);
		}

		public void Update(bool shown, Rect screenRect)
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_root == (Object)null))
			{
				if (shown)
				{
					_area.anchoredPosition = new Vector2(((Rect)(ref screenRect)).x, (float)Screen.height - ((Rect)(ref screenRect)).yMax);
					_area.sizeDelta = ((Rect)(ref screenRect)).size;
				}
				if (_root.activeSelf != shown)
				{
					_root.SetActive(shown);
				}
			}
		}

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

		public static bool MouseIn(Rect screenRect)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: 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_0014: 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)
			Vector3 mousePosition = Input.mousePosition;
			return ((Rect)(ref screenRect)).Contains(new Vector2(mousePosition.x, (float)Screen.height - mousePosition.y));
		}
	}
	internal sealed class TextBox
	{
		public const float FontSize = 18f;

		private static readonly RectOffset Padding = new RectOffset(12, 12, 10, 10);

		private static Sprite _boxSprite;

		private static bool _lookedForBox;

		private readonly string _name;

		private readonly TextAlignmentOptions _alignment;

		private GameObject _root;

		private RectTransform _box;

		private TextMeshProUGUI _text;

		private int _drawnFrame = -100;

		private string _measured;

		private TMP_FontAsset _measuredFont;

		private Vector2 _measuredSize;

		public TMP_FontAsset Font { get; set; }

		public TextBox(string name, TextAlignmentOptions alignment)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			_name = name;
			_alignment = alignment;
		}

		public Vector2 Measure(string text)
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: 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_008b: Unknown result type (might be due to invalid IL or missing references)
			Prepare();
			if (text != _measured || (Object)(object)((TMP_Text)_text).font != (Object)(object)_measuredFont)
			{
				Vector2 preferredValues = ((TMP_Text)_text).GetPreferredValues(text);
				_measuredSize = new Vector2(Mathf.Ceil(preferredValues.x) + (float)Padding.horizontal, Mathf.Ceil(preferredValues.y) + (float)Padding.vertical);
				_measured = text;
				_measuredFont = ((TMP_Text)_text).font;
			}
			return _measuredSize;
		}

		public void Draw(Rect rect, string text)
		{
			//IL_003a: 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)
			Prepare();
			if (((TMP_Text)_text).text != text)
			{
				((TMP_Text)_text).text = text;
			}
			_box.anchoredPosition = new Vector2(((Rect)(ref rect)).x, 0f - ((Rect)(ref rect)).y);
			_box.sizeDelta = ((Rect)(ref rect)).size;
			_drawnFrame = Time.frameCount;
		}

		public void LateUpdate()
		{
			if (!((Object)(object)_root == (Object)null))
			{
				bool flag = Time.frameCount - _drawnFrame <= 1 && !PanelStack.Hidden;
				if (_root.activeSelf != flag)
				{
					_root.SetActive(flag);
				}
			}
		}

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

		private void Prepare()
		{
			if ((Object)(object)_root == (Object)null)
			{
				Build();
			}
			TMP_FontAsset val = (((Object)(object)Font != (Object)null) ? Font : PlayerNames.NameTagFont());
			if ((Object)(object)val != (Object)null && (Object)(object)((TMP_Text)_text).font != (Object)(object)val)
			{
				((TMP_Text)_text).font = val;
			}
			if (!_root.activeSelf && !PanelStack.Hidden)
			{
				_root.SetActive(true);
			}
		}

		private void Build()
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Expected O, but got Unknown
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Expected O, but got Unknown
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0157: Unknown result type (might be due to invalid IL or missing references)
			//IL_0186: Unknown result type (might be due to invalid IL or missing references)
			//IL_018c: Expected O, but got Unknown
			//IL_01a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_023c: Unknown result type (might be due to invalid IL or missing references)
			//IL_024d: Unknown result type (might be due to invalid IL or missing references)
			_root = new GameObject("OnTogetherMods " + _name);
			Object.DontDestroyOnLoad((Object)(object)_root);
			Canvas obj = _root.AddComponent<Canvas>();
			obj.renderMode = (RenderMode)0;
			obj.sortingOrder = 32766;
			CanvasScaler obj2 = _root.AddComponent<CanvasScaler>();
			obj2.uiScaleMode = (ScaleMode)1;
			obj2.referenceResolution = new Vector2(1920f, 1080f);
			obj2.screenMatchMode = (ScreenMatchMode)0;
			obj2.matchWidthOrHeight = 1f;
			GameObject val = new GameObject("Box", new Type[3]
			{
				typeof(RectTransform),
				typeof(CanvasRenderer),
				typeof(Image)
			});
			val.transform.SetParent(_root.transform, false);
			_box = (RectTransform)val.transform;
			RectTransform box = _box;
			RectTransform box2 = _box;
			RectTransform box3 = _box;
			Vector2 val2 = default(Vector2);
			((Vector2)(ref val2))..ctor(0f, 1f);
			box3.pivot = val2;
			Vector2 anchorMin = (box2.anchorMax = val2);
			box.anchorMin = anchorMin;
			Image component = val.GetComponent<Image>();
			((Graphic)component).raycastTarget = false;
			Sprite val4 = BoxSprite();
			if ((Object)(object)val4 != (Object)null)
			{
				component.sprite = val4;
				component.type = (Type)1;
			}
			else
			{
				((Graphic)component).color = new Color(0f, 0f, 0f, 0.65f);
			}
			GameObject val5 = new GameObject("Text", new Type[2]
			{
				typeof(RectTransform),
				typeof(CanvasRenderer)
			});
			val5.transform.SetParent(val.transform, false);
			RectTransform val6 = (RectTransform)val5.transform;
			val6.anchorMin = Vector2.zero;
			val6.anchorMax = Vector2.one;
			val6.offsetMin = new Vector2((float)Padding.left, (float)Padding.bottom);
			val6.offsetMax = new Vector2((float)(-Padding.right), (float)(-Padding.top));
			_text = val5.AddComponent<TextMeshProUGUI>();
			((Graphic)_text).raycastTarget = false;
			((TMP_Text)_text).richText = true;
			((TMP_Text)_text).fontSize = 18f;
			((Graphic)_text).color = Color.white;
			((TMP_Text)_text).alignment = _alignment;
			((TMP_Text)_text).textWrappingMode = (TextWrappingModes)0;
			((TMP_Text)_text).overflowMode = (TextOverflowModes)0;
			_root.SetActive(false);
		}

		private static Sprite BoxSprite()
		{
			//IL_0050: 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_0087: Unknown result type (might be due to invalid IL or missing references)
			if (!_lookedForBox)
			{
				_lookedForBox = true;
				GUIStyle box = GUI.skin.box;
				Texture2D background = box.normal.background;
				if ((Object)(object)background != (Object)null)
				{
					RectOffset border = box.border;
					_boxSprite = Sprite.Create(background, new Rect(0f, 0f, (float)((Texture)background).width, (float)((Texture)background).height), new Vector2(0.5f, 0.5f), 100f, 0u, (SpriteMeshType)0, new Vector4((float)border.left, (float)border.bottom, (float)border.right, (float)border.top));
				}
			}
			return _boxSprite;
		}
	}
	internal static class PlayerNames
	{
		private static readonly HashSet<string> Closable = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
		{
			"color", "b", "i", "u", "s", "size", "font", "font-weight", "material", "mark",
			"gradient", "cspace", "mspace", "voffset", "alpha", "indent", "line-height", "line-indent", "align", "rotate",
			"lowercase", "uppercase", "allcaps", "smallcaps", "sup", "sub", "width", "margin", "nobr", "link",
			"style", "noparse"
		};

		private static readonly Regex Tag = new Regex("<(/?)(#|[A-Za-z][\\w-]*)[^<>]*>");

		private static TMP_FontAsset _font;

		private static float _nextFontLookup;

		public static string Of(PlayerController player)
		{
			string text = (((Object)(object)player != (Object)null && (Object)(object)player.PlayerNameText != (Object)null) ? ((TMP_Text)player.PlayerNameText).text : null);
			if (!string.IsNullOrWhiteSpace(text))
			{
				return ForText(text.Trim());
			}
			return null;
		}

		public static string Plain(string name)
		{
			return name.Replace("<", "‹");
		}

		public static string WithoutTags(string name)
		{
			return Tag.Replace(name, "");
		}

		public static string ForText(string name)
		{
			List<string> list = new List<string>();
			bool flag = false;
			foreach (Match item in Tag.Matches(name))
			{
				string text = ((item.Groups[2].Value == "#") ? "color" : item.Groups[2].Value.ToLowerInvariant());
				bool flag2 = item.Groups[1].Value == "/";
				if (!Closable.Contains(text) || (flag && (!flag2 || !(text == "noparse"))))
				{
					continue;
				}
				if (flag2)
				{
					int num = list.LastIndexOf(text);
					if (num >= 0)
					{
						list.RemoveAt(num);
					}
				}
				else
				{
					list.Add(text);
				}
				flag = list.Contains("noparse");
			}
			StringBuilder stringBuilder = new StringBuilder(name);
			for (int num2 = list.Count - 1; num2 >= 0; num2--)
			{
				stringBuilder.Append("</").Append(list[num2]).Append('>');
			}
			return stringBuilder.ToString();
		}

		public static TMP_FontAsset NameTagFont()
		{
			if ((Object)(object)_font == (Object)null && Time.unscaledTime >= _nextFontLookup)
			{
				_nextFontLookup = Time.unscaledTime + 1f;
				PlayerController val = Object.FindAnyObjectByType<PlayerController>();
				if ((Object)(object)val != (Object)null && (Object)(object)val.PlayerNameText != (Object)null)
				{
					_font = ((TMP_Text)val.PlayerNameText).font;
				}
			}
			return _font;
		}
	}
}
namespace EmoteSync
{
	internal enum JoinResult
	{
		Joined,
		Wait,
		Skip
	}
	internal static class FocusJoin
	{
		private const string FocusAnywhereGuid = "nelphei.ontogether.focusanywhere";

		private static bool? _anyGround;

		public static bool Joining { get; private set; }

		public static JoinResult TryJoin(int animState, FocusType focusType, out string why, out bool canClear)
		{
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: 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_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_016f: 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_0178: Unknown result type (might be due to invalid IL or missing references)
			//IL_0183: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d3: Unknown result type (might be due to invalid IL or missing references)
			why = null;
			canClear = false;
			TextChannelManager i = NetworkSingleton<TextChannelManager>.I;
			TaskManager i2 = MonoSingleton<TaskManager>.I;
			if ((Object)(object)i == (Object)null || (Object)(object)i2 == (Object)null || (Object)(object)i.MainFocusController == (Object)null || (Object)(object)i.MainMovementController == (Object)null || (Object)(object)i.MainAnimationController == (Object)null)
			{
				why = "the game is ready";
				return JoinResult.Wait;
			}
			PlayerFocusController mainFocusController = i.MainFocusController;
			PlayerMovementController mainMovementController = i.MainMovementController;
			bool isFocus = mainFocusController.IsFocus;
			if (isFocus && (Object)(object)Game.ActiveFocusArea.Invoke(mainFocusController) != (Object)null)
			{
				why = "you're at a seat spot";
				return JoinResult.Skip;
			}
			why = WaitingFor(i2, mainFocusController, mainMovementController, isFocus, out canClear);
			if (why != null)
			{
				return JoinResult.Wait;
			}
			if (isFocus && i.MainAnimationController.GetState() == animState)
			{
				return JoinResult.Joined;
			}
			GameSettings i3 = ScriptableSingleton<GameSettings>.I;
			List<FocusType> focusTypes = i3.FocusTypes;
			List<int> animationStates = i3.AnimationStates;
			int num = Find(focusTypes, animationStates, animState, focusType, mainMovementController, i3, sameType: true);
			if (num < 0)
			{
				num = Find(focusTypes, animationStates, animState, focusType, mainMovementController, i3, sameType: false);
			}
			if (num < 0)
			{
				why = "that activity isn't in your menu here";
				return JoinResult.Skip;
			}
			FocusType val = focusTypes[num];
			int num2 = 0;
			for (int j = 0; j < num; j++)
			{
				if (focusTypes[j] == val && IsAllowed(j, mainMovementController, i3))
				{
					num2++;
				}
			}
			if (!isFocus && NetworkSingleton<BasketBallManager>.I.IsBallOnMyHand)
			{
				NetworkSingleton<BasketBallManager>.I.DropBall();
			}
			List<FocusType> list = new List<FocusType>();
			foreach (FocusType item in focusTypes)
			{
				if (!list.Contains(item))
				{
					list.Add(item);
				}
			}
			Game.SetCurrentFocusArea(mainFocusController, null);
			Game.IsFocusChange.Invoke(mainFocusController) = isFocus;
			Game.SimpledFocusTypes.Invoke(mainFocusController) = list;
			Game.FocusMainIndex.Invoke(mainFocusController) = list.IndexOf(val);
			Joining = true;
			try
			{
				mainFocusController.SetFocus(num2);
			}
			finally
			{
				Joining = false;
			}
			if (!mainFocusController.IsFocus)
			{
				why = "the game didn't start it";
				return JoinResult.Skip;
			}
			return JoinResult.Joined;
		}

		public static void ClearWay()
		{
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Invalid comparison between Unknown and I4
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			TextChannelManager i = NetworkSingleton<TextChannelManager>.I;
			TaskManager i2 = MonoSingleton<TaskManager>.I;
			InputManager i3 = MonoSingleton<InputManager>.I;
			if ((Object)(object)i == (Object)null || (Object)(object)i2 == (Object)null || (Object)(object)i3 == (Object)null)
			{
				return;
			}
			if (i2.IsWriting && (Object)(object)EventSystem.current != (Object)null)
			{
				EventSystem.current.SetSelectedGameObject((GameObject)null);
			}
			if (IsClosableWindow(i2.LockState) && i2.CloseUIAction != null)
			{
				i3.CloseOnWriting();
			}
			PlayerMovementController mainMovementController = i.MainMovementController;
			if ((Object)(object)mainMovementController != (Object)null && mainMovementController.IsAnimation && CanStopAnimation(mainMovementController))
			{
				if ((int)mainMovementController.PlayerAnimationState == 2)
				{
					i.MainAnimationController.StopEmote();
				}
				else if (mainMovementController.GetUpRoutine != null)
				{
					((MonoBehaviour)mainMovementController).StopCoroutine(mainMovementController.GetUpRoutine);
				}
				mainMovementController.IsAnimation = false;
				mainMovementController.PlayerAnimationState = (AnimationState)0;
			}
		}

		private static string WaitingFor(TaskManager tasks, PlayerFocusController focus, PlayerMovementController movement, bool switching, out bool canClear)
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Invalid comparison between Unknown and I4
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Invalid comparison between Unknown and I4
			//IL_0134: Unknown result type (might be due to invalid IL or missing references)
			//IL_013a: Invalid comparison between Unknown and I4
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Invalid comparison between Unknown and I4
			//IL_014c: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0154: Unknown result type (might be due to invalid IL or missing references)
			//IL_015a: Invalid comparison between Unknown and I4
			//IL_01b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ca: Unknown result type (might be due to invalid IL or missing references)
			string first = null;
			bool stuck = false;
			if (tasks.IsWriting)
			{
				Add("you finish typing", clearable: true);
			}
			if (focus.IsSelectorOpened)
			{
				Add("you close the focus menu", clearable: true);
			}
			if ((int)tasks.LockState == 5)
			{
				DrawingManager i = MonoSingleton<DrawingManager>.I;
				Add(((Object)(object)i != (Object)null && i.IsActive) ? "you stop drawing" : "you leave the instrument", clearable: false);
			}
			else if ((int)tasks.LockState != 0)
			{
				Add("you close the window you have open", IsClosableWindow(tasks.LockState) && tasks.CloseUIAction != null);
			}
			if (!switching)
			{
				if (NetworkSingleton<BasketBallManager>.I.IsInBasketBallCourtColorful)
				{
					Add("you leave the basketball court", clearable: false);
				}
				if ((int)MonoSingleton<FishingManager>.I.FishingState != 0)
				{
					Add("you stop fishing", clearable: false);
				}
				if (movement.IsAnimation)
				{
					AnimationState playerAnimationState = movement.PlayerAnimationState;
					if ((int)playerAnimationState != 2)
					{
						if ((int)playerAnimationState == 3)
						{
							Add("you finish using the item", clearable: false);
						}
						else
						{
							Add("you're back on your feet", CanStopAnimation(movement));
						}
					}
					else
					{
						Add("your emote finishes", clearable: true);
					}
				}
				if (movement.IsStair)
				{
					Add("you're off the stairs", clearable: false);
				}
				if ((int)movement.MovementState == 2)
				{
					Add("you're out of the bubble", clearable: false);
				}
				else if (((int)movement.MovementState != 0 && (int)movement.MovementState != 1) || (int)movement.GroundState != 0)
				{
					Add("you land", clearable: false);
				}
				if (!AnyGround())
				{
					MainSceneManager i2 = MonoSingleton<MainSceneManager>.I;
					if (focus.FocusAreaControllers.Count > 0 && !movement.IsLake)
					{
						Add("you step away from the seat spot", clearable: false);
					}
					else
					{
						if ((Object)(object)i2 != (Object)null)
						{
							Vector3 val = i2.MusicHillTransform.position - ((Component)focus).transform.position;
							if (((Vector3)(ref val)).sqrMagnitude < 12.53f)
							{
								Add("you move away from the music hill", clearable: false);
								goto IL_01fe;
							}
						}
						if (!Game.IsFocusable(focus))
						{
							Add("you stand somewhere you can focus", clearable: false);
						}
					}
				}
			}
			goto IL_01fe;
			IL_01fe:
			canClear = first != null && !stuck;
			return first;
			void Add(string why, bool clearable)
			{
				first = first ?? why;
				stuck |= !clearable;
			}
		}

		private static bool IsClosableWindow(LockState state)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Invalid comparison between Unknown and I4
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Invalid comparison between Unknown and I4
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Invalid comparison between Unknown and I4
			if ((int)state != 3 && (int)state != 4)
			{
				return (int)state == 2;
			}
			return true;
		}

		private static bool CanStopAnimation(PlayerMovementController movement)
		{
			//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)
			//IL_0007: 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_001f: Expected I4, but got Unknown
			AnimationState playerAnimationState = movement.PlayerAnimationState;
			switch (playerAnimationState - 1)
			{
			case 1:
			case 3:
				return true;
			case 0:
				return movement.AnimationTimer >= 0.5f;
			default:
				return false;
			}
		}

		private static bool AnyGround()
		{
			if (!_anyGround.HasValue)
			{
				_anyGround = false;
				if (Chainloader.PluginInfos.TryGetValue("nelphei.ontogether.focusanywhere", out var value) && (Object)(object)value.Instance != (Object)null)
				{
					ConfigEntry<bool> val = default(ConfigEntry<bool>);
					_anyGround = !value.Instance.Config.TryGetEntry<bool>("Focus", "AnyGround", ref val) || val.Value;
				}
				Plugin.Log.LogInfo((object)(_anyGround.Value ? "Focus Anywhere is installed, so you can join focus on any ground." : "Joining focus follows the game's ground rules (Focus Anywhere isn't installed or its AnyGround is off)."));
			}
			return _anyGround.Value;
		}

		private static int Find(List<FocusType> types, List<int> anims, int animState, FocusType focusType, PlayerMovementController movement, GameSettings settings, bool sameType)
		{
			//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)
			for (int i = 0; i < types.Count && i < anims.Count; i++)
			{
				if (anims[i] == animState && (!sameType || types[i] == focusType) && IsAllowed(i, movement, settings))
				{
					return i;
				}
			}
			return -1;
		}

		private static bool IsAllowed(int i, PlayerMovementController movement, GameSettings settings)
		{
			if (movement.IsInWater && settings.FocusIsSummerDLC[i])
			{
				return MonoSingleton<DataManager>.I.IsHaveSummerDLC;
			}
			return true;
		}
	}
	internal sealed class FocusLocker
	{
		private sealed class Entry
		{
			public PlayerFocusController Focus;

			public PlayerAnimationController Player;

			public Animator Animator;

			public int Hash;

			public int Fixes;
		}

		private const double Tolerance = 0.08;

		private const int MaxFixes = 3;

		private readonly Dictionary<PlayerFocusController, Entry> _entries = new Dictionary<PlayerFocusController, Entry>();

		private readonly HashSet<int> _focusAnims = new HashSet<int>();

		private readonly List<PlayerFocusController> _gone = new List<PlayerFocusController>();

		private float _nextScan;

		public void Reset()
		{
			_entries.Clear();
			_nextScan = 0f;
		}

		public void Update(TickManager ticks)
		{
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			if (ticks == null)
			{
				return;
			}
			if (Time.unscaledTime >= _nextScan)
			{
				_nextScan = Time.unscaledTime + 2f;
				Scan();
			}
			PlayerAnimationController val = NetworkSingleton<TextChannelManager>.I?.MainAnimationController;
			double num = ticks.syncedPreciseTick * ticks.tickDeltaDouble;
			foreach (Entry value in _entries.Values)
			{
				if ((Object)(object)value.Focus == (Object)null || (Object)(object)value.Player == (Object)null || (Object)(object)value.Animator == (Object)null || !((Behaviour)value.Animator).isActiveAndEnabled)
				{
					continue;
				}
				bool num2;
				if (!((Object)(object)value.Player == (Object)(object)val))
				{
					if (value.Focus.IsFocus)
					{
						goto IL_00f1;
					}
					num2 = _focusAnims.Contains(value.Animator.GetInteger(Game.AnimStateParam));
				}
				else
				{
					num2 = value.Focus.IsFocus;
				}
				if (num2)
				{
					goto IL_00f1;
				}
				goto IL_00ff;
				IL_00ff:
				value.Hash = 0;
				continue;
				IL_00f1:
				if (!value.Animator.IsInTransition(0))
				{
					AnimatorStateInfo currentAnimatorStateInfo = value.Animator.GetCurrentAnimatorStateInfo(0);
					if (((AnimatorStateInfo)(ref currentAnimatorStateInfo)).fullPathHash != value.Hash)
					{
						value.Hash = ((AnimatorStateInfo)(ref currentAnimatorStateInfo)).fullPathHash;
						value.Fixes = 0;
					}
					if (!((AnimatorStateInfo)(ref currentAnimatorStateInfo)).loop || ((AnimatorStateInfo)(ref currentAnimatorStateInfo)).length < 0.2f || value.Fixes >= 3)
					{
						continue;
					}
					double num3 = Fraction(num / (double)((AnimatorStateInfo)(ref currentAnimatorStateInfo)).length);
					double num4 = num3 - Fraction(((AnimatorStateInfo)(ref currentAnimatorStateInfo)).normalizedTime);
					if (num4 > 0.5)
					{
						num4 -= 1.0;
					}
					else if (num4 < -0.5)
					{
						num4 += 1.0;
					}
					if (!(Math.Abs(num4) * (double)((AnimatorStateInfo)(ref currentAnimatorStateInfo)).length < 0.08))
					{
						value.Fixes++;
						value.Animator.Play(((AnimatorStateInfo)(ref currentAnimatorStateInfo)).fullPathHash, 0, (float)num3);
						MoveProps(value, ((AnimatorStateInfo)(ref currentAnimatorStateInfo)).length, (float)num3);
						if (Plugin.Settings.DebugLog.Value)
						{
							Plugin.Log.LogInfo((object)($"Focus loop of {((Object)value.Player).name} moved {num4 * (double)((AnimatorStateInfo)(ref currentAnimatorStateInfo)).length:+0.000;-0.000}s " + $"to stay in step ({((AnimatorStateInfo)(ref currentAnimatorStateInfo)).length:0.00}s loop)."));
						}
					}
					continue;
				}
				goto IL_00ff;
			}
		}

		private void Scan()
		{
			_focusAnims.Clear();
			foreach (int item in Game.FreeFocusAnimStates())
			{
				_focusAnims.Add(item);
			}
			FocusAreaController[] array = Object.FindObjectsByType<FocusAreaController>((FindObjectsSortMode)0);
			foreach (FocusAreaController val in array)
			{
				if ((Object)(object)val.FocusAreaSettings != (Object)null && val.FocusAreaSettings.AnimationStates != null)
				{
					_focusAnims.UnionWith(val.FocusAreaSettings.AnimationStates);
				}
			}
			_gone.Clear();
			foreach (PlayerFocusController key in _entries.Keys)
			{
				if ((Object)(object)key == (Object)null)
				{
					_gone.Add(key);
				}
			}
			foreach (PlayerFocusController item2 in _gone)
			{
				_entries.Remove(item2);
			}
			PlayerFocusController[] array2 = Object.FindObjectsByType<PlayerFocusController>((FindObjectsSortMode)0);
			foreach (PlayerFocusController val2 in array2)
			{
				if (!_entries.ContainsKey(val2))
				{
					PlayerAnimationController val3 = ((Component)val2).GetComponent<PlayerAnimationController>() ?? ((Component)val2).GetComponentInParent<PlayerAnimationController>() ?? ((Component)val2).GetComponentInChildren<PlayerAnimationController>();
					Animator val4 = (((Object)(object)val3 != (Object)null) ? Game.GetAnimator(val3) : null);
					if ((Object)(object)val4 != (Object)null)
					{
						_entries[val2] = new Entry
						{
							Focus = val2,
							Player = val3,
							Animator = val4
						};
					}
				}
			}
		}

		private static void MoveProps(Entry entry, float length, float target)
		{
			//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)
			Animator[] componentsInChildren = ((Component)entry.Player).GetComponentsInChildren<Animator>();
			foreach (Animator val in componentsInChildren)
			{
				if (!((Object)(object)val == (Object)(object)entry.Animator) && ((Behaviour)val).isActiveAndEnabled && !((Object)(object)val.runtimeAnimatorController == (Object)null) && val.layerCount != 0 && !val.IsInTransition(0))
				{
					AnimatorStateInfo currentAnimatorStateInfo = val.GetCurrentAnimatorStateInfo(0);
					if (((AnimatorStateInfo)(ref currentAnimatorStateInfo)).loop && Mathf.Abs(((AnimatorStateInfo)(ref currentAnimatorStateInfo)).length - length) < length * 0.05f)
					{
						val.Play(((AnimatorStateInfo)(ref currentAnimatorStateInfo)).fullPathHash, 0, target);
					}
				}
			}
		}

		private static double Fraction(double value)
		{
			return value - Math.Floor(value);
		}
	}
	internal static class Game
	{
		public static readonly int AnimStateParam = Animator.StringToHash("AnimState");

		private static readonly FieldRef<PlayerAnimationController, Animator> AnimatorField = AccessTools.FieldRefAccess<PlayerAnimationController, Animator>("_animator");

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

		private static readonly FieldRef<PlayerAnimationController, NetworkAnimator> NetAnimatorField = AccessTools.FieldRefAccess<PlayerAnimationController, NetworkAnimator>("_networkAnimator");

		private static readonly FieldRef<PlayerAnimationController, EmoteController> EmoteControllerField = AccessTools.FieldRefAccess<PlayerAnimationController, EmoteController>("_emoteController");

		private static readonly Action<EmoteController, int> SetEmoteAnimMethod = AccessTools.MethodDelegate<Action<EmoteController, int>>(AccessTools.Method(typeof(EmoteController), "SetEmoteAnim", (Type[])null, (Type[])null), (object)null, true);

		public static readonly FieldRef<PlayerFocusController, bool> IsFocusChange = AccessTools.FieldRefAccess<PlayerFocusController, bool>("_isFocusChange");

		public static readonly FieldRef<PlayerFocusController, List<FocusType>> SimpledFocusTypes = AccessTools.FieldRefAccess<PlayerFocusController, List<FocusType>>("_simpledFocusTypes");

		public static readonly FieldRef<PlayerFocusController, int> FocusMainIndex = AccessTools.FieldRefAccess<PlayerFocusController, int>("_currentFocusMainIndex");

		public static readonly FieldRef<PlayerFocusController, FocusAreaController> ActiveFocusArea = AccessTools.FieldRefAccess<PlayerFocusController, FocusAreaController>("_activeFocusAreaController");

		private static readonly Action<PlayerFocusController, FocusAreaController> SetCurrentFocusAreaMethod = AccessTools.MethodDelegate<Action<PlayerFocusController, FocusAreaController>>(AccessTools.PropertySetter(typeof(PlayerFocusController), "CurrentFocusAreaController"), (object)null, true);

		private static readonly Func<PlayerFocusController, bool> IsFocusableMethod = AccessTools.MethodDelegate<Func<PlayerFocusController, bool>>(AccessTools.Method(typeof(PlayerFocusController), "IsFocusable", (Type[])null, (Type[])null), (object)null, true);

		private static readonly FieldRef<GameSettings, List<int>> LandFocusAnims = AccessTools.FieldRefAccess<GameSettings, List<int>>("_animationStates");

		private static readonly FieldRef<GameSettings, List<int>> WaterFocusAnims = AccessTools.FieldRefAccess<GameSettings, List<int>>("_animationStatesWater");

		public static int EmoteCount => ScriptableSingleton<GameSettings>.I.EmoteAnimStates.Count;

		public static TickManager Ticks
		{
			get
			{
				NetworkManager main = NetworkManager.main;
				if ((Object)(object)main == (Object)null || (!main.isClient && !main.isServer))
				{
					return null;
				}
				return main.tickModule;
			}
		}

		public unsafe static string PlayerName(CSteamID id)
		{
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				PlayerPanelController i = NetworkSingleton<PlayerPanelController>.I;
				if ((Object)(object)i != (Object)null && i.PlayerSteamIDs != null && i.PlayerControllers != null)
				{
					int num = i.PlayerSteamIDs.IndexOf(((object)(*(CSteamID*)(&id))/*cast due to .constrained prefix*/).ToString());
					string text = ((num >= 0 && num < i.PlayerControllers.Count) ? PlayerNames.Of(i.PlayerControllers[num]) : null);
					if (text != null)
					{
						NameTags[id.m_SteamID] = text;
						return text;
					}
				}
			}
			catch (Exception)
			{
			}
			if (!NameTags.TryGetValue(id.m_SteamID, out var value))
			{
				return PlayerNames.Plain(LobbyChannel.NameOf(id));
			}
			return value;
		}

		public static void SetCurrentFocusArea(PlayerFocusController focus, FocusAreaController area)
		{
			SetCurrentFocusAreaMethod(focus, area);
		}

		public static bool IsFocusable(PlayerFocusController focus)
		{
			return IsFocusableMethod(focus);
		}

		public static IEnumerable<int> FreeFocusAnimStates()
		{
			GameSettings i = ScriptableSingleton<GameSettings>.I;
			return (LandFocusAnims.Invoke(i) ?? new List<int>()).Concat(WaterFocusAnims.Invoke(i) ?? new List<int>());
		}

		public static Animator GetAnimator(PlayerAnimationController player)
		{
			return AnimatorField.Invoke(player);
		}

		public static NetworkAnimator GetNetAnimator(PlayerAnimationController player)
		{
			return NetAnimatorField.Invoke(player);
		}

		public static EmoteController GetEmoteController(PlayerAnimationController player)
		{
			return EmoteControllerField.Invoke(player);
		}

		public static void SetEmoteAnim(EmoteController controller, int emoteIndex)
		{
			SetEmoteAnimMethod(controller, emoteIndex);
		}

		public unsafe static string FocusName(FocusType type)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				int num = ScriptableSingleton<GameSettings>.I.FocusTypesForNames.IndexOf(type);
				List<string> focusNamesStrings = MonoSingleton<SettingsController>.I.FocusNamesStrings;
				if (num >= 0 && num < focusNamesStrings.Count && !string.IsNullOrEmpty(focusNamesStrings[num]))
				{
					return focusNamesStrings[num];
				}
			}
			catch (Exception)
			{
			}
			return ((object)(*(FocusType*)(&type))/*cast due to .constrained prefix*/).ToString();
		}

		public static int EmoteAnimState(int emoteIndex)
		{
			return ScriptableSingleton<GameSettings>.I.EmoteAnimStates[emoteIndex];
		}
	}
	internal static class Icon
	{
		public static readonly string[] Pixels = new string[16]
		{
			"................", "................", "..KKKK....KKKK..", "PKHHHHKPPKddddKP", "PKPPPPKPPKPPPPKP", "PKPPPPKPPKPPPPKP", ".PKKKKP..PKKKKP.", ".PUUUUP..PSSSSP.", "..UUUU....SSSS..", "..UUUU....SSSS..",
			"..uuuu....vvvv..", "..u..u....v..v..", "..K..K....K..K..", "................", "................", "................"
		};
	}
	internal sealed class LobbyChannel
	{
		private const string Tag = "OTES1";

		private Callback<LobbyChatMsg_t> _chatMsg;

		private Callback<LobbyChatUpdate_t> _chatUpdate;

		private readonly byte[] _buffer = new byte[512];

		private float _nextPoll;

		public CSteamID Lobby { get; private set; } = CSteamID.Nil;

		public CSteamID Me { get; private set; } = CSteamID.Nil;

		public bool InLobby => Lobby != CSteamID.Nil;

		public event Action<CSteamID, string[]> MessageReceived;

		public event Action<CSteamID> MemberLeft;

		public event Action LobbyChanged;

		public void Poll()
		{
			//IL_001f: 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_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			if (Time.unscaledTime < _nextPoll)
			{
				return;
			}
			_nextPoll = Time.unscaledTime + 1f;
			CSteamID val = ReadLobby();
			if (val == Lobby)
			{
				return;
			}
			Lobby = val;
			if (InLobby)
			{
				Me = SteamUser.GetSteamID();
				if (_chatMsg == null)
				{
					_chatMsg = Callback<LobbyChatMsg_t>.Create((DispatchDelegate<LobbyChatMsg_t>)OnChatMsg);
					_chatUpdate = Callback<LobbyChatUpdate_t>.Create((DispatchDelegate<LobbyChatUpdate_t>)OnChatUpdate);
				}
			}
			Plugin.Log.LogInfo((object)(InLobby ? $"In lobby {Lobby}." : "Left the lobby."));
			this.LobbyChanged?.Invoke();
		}

		public bool Send(string message)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			if (!InLobby)
			{
				return false;
			}
			byte[] bytes = Encoding.ASCII.GetBytes("OTES1 " + message);
			bool num = SteamMatchmaking.SendLobbyChatMsg(Lobby, bytes, bytes.Length);
			if (!num)
			{
				Plugin.Log.LogWarning((object)("Steam didn't send \"" + message + "\"."));
			}
			return num;
		}

		public unsafe static string NameOf(CSteamID id)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				return SteamFriends.GetFriendPersonaName(id);
			}
			catch (Exception)
			{
				return ((object)(*(CSteamID*)(&id))/*cast due to .constrained prefix*/).ToString();
			}
		}

		private static CSteamID ReadLobby()
		{
			//IL_0046: 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_0021: 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_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				MultiplayerManager i = MonoSingleton<MultiplayerManager>.I;
				if ((Object)(object)i == (Object)null || !ulong.TryParse(i.LobbyCode, out var result) || result == 0L)
				{
					return CSteamID.Nil;
				}
				CSteamID val = default(CSteamID);
				((CSteamID)(ref val))..ctor(result);
				return (SteamMatchmaking.GetNumLobbyMembers(val) > 0) ? val : CSteamID.Nil;
			}
			catch (Exception)
			{
				return CSteamID.Nil;
			}
		}

		private void OnChatMsg(LobbyChatMsg_t msg)
		{
			//IL_0000: 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_00b6: 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_003c: 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_0091: Unknown result type (might be due to invalid IL or missing references)
			if (msg.m_ulSteamIDLobby != Lobby.m_SteamID)
			{
				return;
			}
			CSteamID val = default(CSteamID);
			EChatEntryType val2 = default(EChatEntryType);
			int lobbyChatEntry = SteamMatchmaking.GetLobbyChatEntry(Lobby, (int)msg.m_iChatID, ref val, _buffer, _buffer.Length, ref val2);
			if (lobbyChatEntry <= 0 || val == Me)
			{
				return;
			}
			string text = Encoding.ASCII.GetString(_buffer, 0, lobbyChatEntry).TrimEnd('\0');
			string[] array = text.Split(' ');
			if (array.Length < 2 || array[0] != "OTES1")
			{
				return;
			}
			try
			{
				this.MessageReceived?.Invoke(val, array.AsSpan(1).ToArray());
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"Failed to handle \"{text}\" from {NameOf(val)}: {arg}");
			}
		}

		private void OnChatUpdate(LobbyChatUpdate_t update)
		{
			//IL_0000: 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_0013: 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_002f: Unknown result type (might be due to invalid IL or missing references)
			if (update.m_ulSteamIDLobby == Lobby.m_SteamID && (update.m_rgfChatMemberStateChange & 0x1E) != 0)
			{
				this.MemberLeft?.Invoke(new CSteamID(update.m_ulSteamIDUserChanged));
			}
		}
	}
	[HarmonyPatch(typeof(InputManager), "Update")]
	internal static class InputPatch
	{
		private static readonly Action<InputManager, bool> SetMouse0Down = (Action<InputManager, bool>)Delegate.CreateDelegate(typeof(Action<InputManager, bool>), AccessTools.PropertySetter(typeof(InputManager), "IsMouseButton0Down"));

		private static void Postfix(InputManager __instance)
		{
			if (SyncController.IsMouseOverPrompt)
			{
				SetMouse0Down(__instance, arg2: false);
			}
		}
	}
	[HarmonyPatch(typeof(EmoteController), "SetEmoteAnim")]
	internal static class SetEmoteAnimPatch
	{
		private static bool Prefix(int emoteIndex)
		{
			try
			{
				SyncController instance = SyncController.Instance;
				return (Object)(object)instance == (Object)null || !instance.TryTakeOver(emoteIndex);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)ex);
				return true;
			}
		}
	}
	[HarmonyPatch(typeof(PlayerFocusController), "SetFocus")]
	internal static class SetFocusPatch
	{
		private static void Postfix(PlayerFocusController __instance)
		{
			try
			{
				if (!FocusJoin.Joining)
				{
					SyncController.Instance?.OnLocalFocusPicked(__instance);
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)ex);
			}
		}
	}
	internal sealed class PhaseAligner
	{
		private sealed class Watch
		{
			public PlayerAnimationController Player;

			public Animator Animator;

			public int Hash;

			public float Time;

			public bool Done;
		}

		private const float WatchSeconds = 4f;

		private readonly List<Watch> _watches = new List<Watch>();

		private int _animState;

		private uint _startTick;

		private double _endTick;

		private bool _active;

		public void Begin(int animState, uint startTick, TickManager ticks)
		{
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			_watches.Clear();
			_active = false;
			if (!Plugin.Settings.AlignOthers.Value || ticks == null)
			{
				return;
			}
			PlayerAnimationController val = NetworkSingleton<TextChannelManager>.I?.MainAnimationController;
			PlayerAnimationController[] array = Object.FindObjectsByType<PlayerAnimationController>((FindObjectsSortMode)0);
			foreach (PlayerAnimationController val2 in array)
			{
				Animator val3 = (((Object)(object)val2 == (Object)(object)val) ? null : Game.GetAnimator(val2));
				if (!((Object)(object)val3 == (Object)null))
				{
					Watch watch = new Watch
					{
						Player = val2,
						Animator = val3
					};
					Read(val3, out watch.Hash, out watch.Time);
					_watches.Add(watch);
				}
			}
			_animState = animState;
			_startTick = startTick;
			_endTick = (float)startTick + 4f * (float)ticks.tickRate;
			_active = _watches.Count > 0;
		}

		public void Stop()
		{
			_watches.Clear();
			_active = false;
		}

		public void Update(TickManager ticks)
		{
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			if (!_active)
			{
				return;
			}
			if (ticks == null || ticks.syncedPreciseTick > _endTick)
			{
				Stop();
				return;
			}
			double num = (ticks.syncedPreciseTick - (double)_startTick) * ticks.tickDeltaDouble;
			foreach (Watch watch in _watches)
			{
				if (watch.Done || (Object)(object)watch.Player == (Object)null || (Object)(object)watch.Animator == (Object)null || !((Behaviour)watch.Animator).isActiveAndEnabled)
				{
					continue;
				}
				int hash;
				float time;
				AnimatorStateInfo val = Read(watch.Animator, out hash, out time);
				bool num2 = hash != watch.Hash || time + 0.1f < watch.Time;
				watch.Hash = hash;
				watch.Time = time;
				if (!num2 || watch.Animator.GetInteger(Game.AnimStateParam) != _animState)
				{
					continue;
				}
				watch.Done = true;
				if (num < 0.05 || ((AnimatorStateInfo)(ref val)).length <= 0f)
				{
					continue;
				}
				float num3 = (float)(num / (double)((AnimatorStateInfo)(ref val)).length);
				if (num3 >= 1f)
				{
					if (!((AnimatorStateInfo)(ref val)).loop)
					{
						continue;
					}
					num3 -= Mathf.Floor(num3);
				}
				watch.Animator.Play(hash, 0, num3);
				if (Plugin.Settings.DebugLog.Value)
				{
					Plugin.Log.LogInfo((object)$"Aligned {((Object)watch.Player).name}: {num:0.000}s late, jumped to {num3:0.000} of {((AnimatorStateInfo)(ref val)).length:0.00}s.");
				}
			}
		}

		private static AnimatorStateInfo Read(Animator animator, out int hash, out float time)
		{
			//IL_0014: 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_0019: 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)
			AnimatorStateInfo result = (animator.IsInTransition(0) ? animator.GetNextAnimatorStateInfo(0) : animator.GetCurrentAnimatorStateInfo(0));
			hash = ((AnimatorStateInfo)(ref result)).fullPathHash;
			time = ((AnimatorStateInfo)(ref result)).normalizedTime;
			return result;
		}
	}
	[BepInPlugin("nelphei.ontogether.emotesync", "Emote Sync", "0.3.1")]
	public class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "nelphei.ontogether.emotesync";

		public const string PluginName = "Emote Sync";

		public const string PluginVersion = "0.3.1";

		internal static ManualLogSource Log;

		internal static Settings Settings;

		private GameObject _host;

		private void Awake()
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Expected O, but got Unknown
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			Log = ((BaseUnityPlugin)this).Logger;
			Settings = new Settings(((BaseUnityPlugin)this).Config);
			new Harmony("nelphei.ontogether.emotesync").PatchAll();
			IconBar.Patch();
			_host = new GameObject("EmoteSync");
			((Object)_host).hideFlags = (HideFlags)61;
			Object.DontDestroyOnLoad((Object)(object)_host);
			_host.AddComponent<SyncController>();
			Log.LogInfo((object)string.Format("{0} {1} loaded. Press {2} to turn emote sync on or off.", "Emote Sync", "0.3.1", Settings.ToggleKey.Value));
		}

		private void OnDestroy()
		{
			if ((Object)(object)_host != (Object)null)
			{
				Object.Destroy((Object)(object)_host);
			}
		}
	}
	internal sealed class Settings
	{
		public readonly ConfigEntry<KeyCode> ToggleKey;

		public readonly ConfigEntry<KeyCode> PanelKey;

		public readonly ConfigEntry<bool> ShowPanel;

		public readonly ConfigEntry<float> LeadTime;

		public readonly ConfigEntry<bool> AlignOthers;

		public readonly ConfigEntry<bool> SyncFocus;

		public readonly ConfigEntry<float> JoinWaitSeconds;

		public readonly ConfigEntry<bool> ShowNotices;

		public readonly ConfigEntry<bool> ShowIcon;

		public readonly ConfigEntry<bool> DebugLog;

		public Settings(ConfigFile config)
		{
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Expected O, but got Unknown
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Expected O, but got Unknown
			ToggleKey = config.Bind<KeyCode>("Keys", "ToggleKey", (KeyCode)288, "Turns sync on and off.");
			PanelKey = config.Bind<KeyCode>("Keys", "PanelKey", (KeyCode)287, "Shows or hides the sync window while sync is on.");
			LeadTime = config.Bind<float>("Sync", "LeadTime", 1f, new ConfigDescription("Seconds between picking an emote and everyone starting it. It gives the message time to reach everyone. Raise it if friends' emotes start late.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.3f, 3f), Array.Empty<object>()));
			AlignOthers = config.Bind<bool>("Sync", "AlignOthers", true, "Line up other players' synced emotes on your screen, so their ping doesn't put them slightly behind you. Only changes what you see.");
			SyncFocus = config.Bind<bool>("Sync", "SyncFocus", true, "Focus together while emote sync is on. When someone in the group picks a focus activity, you start or switch to the same one if you can, and yours are shared with them. Focus loops are also kept in step, so everyone doing the same activity moves together. Set to false to only sync emotes.");
			JoinWaitSeconds = config.Bind<float>("Sync", "JoinWaitSeconds", 30f, new ConfigDescription("When someone in the group picks a focus activity while you're busy (typing, a window open, mid-emote, in the air...), you join it as soon as you're free, if that's within this many seconds. Nothing is closed or stopped for you, but a \"Join now\" button does that when you click it. Set to 0 to only join when you're free right away.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 120f), Array.Empty<object>()));
			ShowPanel = config.Bind<bool>("Display", "ShowPanelByDefault", true, "Show the sync window (who's in your group, and the keys) when you turn sync on. Toggle with PanelKey. It sits at the bottom of the screen, above Photo Mode's controls when both are open, and is never in photos.");
			ShowNotices = config.Bind<bool>("Display", "ShowNotices", true, "Show short messages at the top of the screen, like who has emote sync on.");
			ShowIcon = config.Bind<bool>("Display", "ShowIcon", true, "Show an icon in the row of mod icons at the bottom-right. Clicking it does what ToggleKey does, and right-clicking it while sync is on does what PanelKey does.");
			DebugLog = config.Bind<bool>("Debug", "DebugLog", false, "Write extra details about each synced emote to the BepInEx log.");
		}
	}
	internal sealed class SyncController : MonoBehaviour
	{
		private struct Pending
		{
			public int Emote;

			public uint Tick;

			public bool Mine;

			public ulong Sender;
		}

		private struct WaitingFocus
		{
			public ulong Sender;

			public string Name;

			public string Activity;

			public int Anim;

			public FocusType Type;

			public float Until;

			public string WaitingFor;

			public bool CanClear;
		}

		private const float MaxLateSeconds = 1f;

		private readonly LobbyChannel _lobby = new LobbyChannel();

		private readonly PhaseAligner _aligner = new PhaseAligner();

		private readonly FocusLocker _focusLocker = new FocusLocker();

		private readonly HashSet<ulong> _group = new HashSet<ulong>();

		private Pending? _pending;

		private WaitingFocus? _waitingFocus;

		private bool _wasFocusing;

		private bool _on;

		private bool _firing;

		private readonly TextBox _panelBox = new TextBox("EmoteSync Panel", (TextAlignmentOptions)257);

		private readonly TextBox _promptBox = new TextBox("EmoteSync Prompt", (TextAlignmentOptions)514);

		private readonly TextBox _noticeBox = new TextBox("EmoteSync Notice", (TextAlignmentOptions)514);

		private GUIStyle _buttonStyle;

		private ClickBlocker _blocker;

		private Rect _promptScreenRect;

		private int _promptDrawnFrame = -100;

		private bool _joinNowClicked;

		private IconBar.Click _iconClick;

		private string _notice;

		private float _noticeUntil;

		private bool _showPanel;

		private string _groupNames;

		private float _groupNamesAt;

		public static SyncController Instance { get; private set; }

		public static bool IsMouseOverPrompt { get; private set; }

		private static Settings S => Plugin.Settings;

		private void Awake()
		{
			Instance = this;
			_blocker = new ClickBlocker("EmoteSync ClickBlocker");
			_lobby.MessageReceived += OnMessage;
			_lobby.MemberLeft += OnMemberLeft;
			_lobby.LobbyChanged += OnLobbyChanged;
		}

		private void OnDestroy()
		{
			if ((Object)(object)Instance == (Object)(object)this)
			{
				Instance = null;
				IsMouseOverPrompt = false;
			}
			_blocker?.Destroy();
			_panelBox.Destroy();
			_promptBox.Destroy();
			_noticeBox.Destroy();
		}

		private void Update()
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				IconBar.Click iconClick = _iconClick;
				_iconClick = IconBar.Click.None;
				if ((Input.GetKeyDown(S.ToggleKey.Value) && !IsTyping()) || iconClick == IconBar.Click.Left)
				{
					Toggle();
				}
				if (_on && ((Input.GetKeyDown(S.PanelKey.Value) && !IsTyping()) || iconClick == IconBar.Click.Right))
				{
					_showPanel = !_showPanel;
				}
				_lobby.Poll();
				UpdatePending();
				UpdateFocus();
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)ex);
				_pending = null;
				_waitingFocus = null;
			}
			bool flag = _waitingFocus.HasValue && Time.frameCount - _promptDrawnFrame <= 2;
			IsMouseOverPrompt = flag && ClickBlocker.MouseIn(_promptScreenRect);
			_blocker?.Update(flag, _promptScreenRect);
		}

		private void LateUpdate()
		{
			_panelBox.LateUpdate();
			_promptBox.LateUpdate();
			_noticeBox.LateUpdate();
			try
			{
				_aligner.Update(Game.Ticks);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)ex);
				_aligner.Stop();
			}
			try
			{
				if (_on && S.SyncFocus.Value && _lobby.InLobby)
				{
					_focusLocker.Update(Game.Ticks);
				}
			}
			catch (Exception ex2)
			{
				Plugin.Log.LogError((object)ex2);
				_focusLocker.Reset();
			}
		}

		public bool TryTakeOver(int emoteIndex)
		{
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			if (_firing || !_on || _group.Count == 0 || !_lobby.InLobby)
			{
				return false;
			}
			TickManager ticks = Game.Ticks;
			if (ticks == null)
			{
				return false;
			}
			uint num = (uint)Math.Ceiling(ticks.syncedPreciseTick + (double)(S.LeadTime.Value * (float)ticks.tickRate));
			if (!_lobby.Send($"GO {emoteIndex} {num}"))
			{
				return false;
			}
			MonoSingleton<TaskManager>.I.SetLockState((LockState)0);
			Schedule(emoteIndex, num, mine: true, _lobby.Me.m_SteamID, ticks);
			Notice((_group.Count == 1) ? "Syncing emote with 1 player" : $"Syncing emote with {_group.Count} players");
			if (S.DebugLog.Value)
			{
				Plugin.Log.LogInfo((object)($"Sent emote {emoteIndex} for tick {num} (now {ticks.syncedPreciseTick:0.0}, " + $"{ticks.tickRate} ticks/s, ping to host {ticks.rtt * 1000.0:0}ms)."));
			}
			return true;
		}

		private void Toggle()
		{
			_on = !_on;
			if (_on)
			{
				_showPanel = S.ShowPanel.Value;
				_lobby.Send("ON");
				string text = (S.SyncFocus.Value ? "Sync ON for emotes and focus." : "Sync ON for emotes.");
				Notice((!_lobby.InLobby) ? (text + " It starts when you join a lobby.") : (text + " " + GroupText()));
			}
			else
			{
				_lobby.Send("OFF");
				_pending = null;
				_waitingFocus = null;
				_aligner.Stop();
				_focusLocker.Reset();
				Notice("Sync OFF");
			}
			Plugin.Log.LogInfo((object)(_on ? "Emote sync on." : "Emote sync off."));
		}

		private void OnLobbyChanged()
		{
			_group.Clear();
			_pending = null;
			_waitingFocus = null;
			_wasFocusing = false;
			_aligner.Stop();
			_focusLocker.Reset();
			if (_on && _lobby.InLobby)
			{
				_lobby.Send("ON");
			}
		}

		private void OnMemberLeft(CSteamID id)
		{
			//IL_0006: 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)
			if (_group.Remove(id.m_SteamID) && _on)
			{
				Notice(Game.PlayerName(id) + " left. " + GroupText());
			}
		}

		private void OnMessage(CSteamID sender, string[] words)
		{
			//IL_001b: 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_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_015b: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_0151: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bc: Unknown result type (might be due to invalid IL or missing references)
			if (S.DebugLog.Value)
			{
				Plugin.Log.LogInfo((object)("From " + LobbyChannel.NameOf(sender) + ": " + string.Join(" ", words)));
			}
			switch (words[0])
			{
			case "ON":
				if (_on)
				{
					_lobby.Send("HI");
				}
				AddToGroup(sender);
				break;
			case "HI":
				AddToGroup(sender);
				break;
			case "OFF":
				if (_group.Remove(sender.m_SteamID) && _on)
				{
					Notice(Game.PlayerName(sender) + " turned emote sync off. " + GroupText());
				}
				break;
			case "GO":
			{
				AddToGroup(sender);
				if (_on && words.Length >= 3 && int.TryParse(words[1], out var result) && result >= 0 && result < Game.EmoteCount && uint.TryParse(words[2], out var result2))
				{
					ReceiveGo(sender, result, result2);
				}
				break;
			}
			case "FOCUS":
			{
				AddToGroup(sender);
				if (_on && S.SyncFocus.Value && words.Length >= 3 && int.TryParse(words[1], out var result3) && int.TryParse(words[2], out var result4) && Enum.IsDefined(typeof(FocusType), result4))
				{
					ReceiveFocus(sender, result3, (FocusType)result4);
				}
				break;
			}
			case "UNFOCUS":
			{
				AddToGroup(sender);
				WaitingFocus? waitingFocus = _waitingFocus;
				if (waitingFocus.HasValue)
				{
					WaitingFocus valueOrDefault = waitingFocus.GetValueOrDefault();