Decompiled source of Emotes v0.1.0

plugins/CrackEmotes.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using CrackMods.Shared;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Mirror;
using Steamworks;
using TMPro;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("CrackEmotes")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("CrackEmotes")]
[assembly: AssemblyTitle("CrackEmotes")]
[assembly: AssemblyVersion("1.0.0.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 CrackMods.Shared
{
	internal static class ModHandshake
	{
		[HarmonyPatch(typeof(SteamLobby), "OnLobbyCreated")]
		private static class PublishPatch
		{
			private static void Postfix(SteamLobby __instance)
			{
				Publish(__instance);
			}
		}

		[HarmonyPatch(typeof(SteamLobby), "RefreshModdedLobbyData")]
		private static class RefreshPatch
		{
			private static void Postfix(SteamLobby __instance)
			{
				Publish(__instance);
			}
		}

		[HarmonyPatch(typeof(SteamLobby), "HostIsInLobby")]
		private static class JoinCheckPatch
		{
			private static bool Prefix(CSteamID lobby, ref bool __result)
			{
				//IL_000e: Unknown result type (might be due to invalid IL or missing references)
				if (!IsLeader(_ownGuid))
				{
					return true;
				}
				string lobbyData = SteamMatchmaking.GetLobbyData(lobby, "cmods");
				string text = LocalToken();
				if (lobbyData == text)
				{
					return true;
				}
				_pendingReason = Describe(lobbyData, text);
				Debug.LogWarning((object)("[CrackMods] refusing to join: " + _pendingReason));
				__result = false;
				return false;
			}
		}

		[HarmonyPatch(typeof(SteamLobby), "FailConnect")]
		private static class FailMessagePatch
		{
			private static void Prefix(ref string messageKey)
			{
				if (_pendingReason != null && !(messageKey != "Error_JoinFailed"))
				{
					messageKey = _pendingReason;
					_pendingReason = null;
				}
			}
		}

		internal const string GuidPrefix = "com.altma.crack.";

		private const string LobbyKey = "cmods";

		private static string _ownGuid;

		private static string _pendingReason;

		internal static string LocalToken()
		{
			List<string> list = new List<string>();
			foreach (KeyValuePair<string, PluginInfo> item in Chainloader.PluginInfos.OrderBy((KeyValuePair<string, PluginInfo> k) => k.Key))
			{
				if (item.Key.StartsWith("com.altma.crack."))
				{
					string text = item.Key.Substring("com.altma.crack.".Length) + "=" + item.Value.Metadata.Version;
					object instance = item.Value.Instance;
					PropertyInfo propertyInfo = ((instance != null) ? AccessTools.Property(instance.GetType(), "HandshakeExtra") : null);
					if (propertyInfo != null && propertyInfo.GetGetMethod() != null && propertyInfo.GetGetMethod().IsStatic)
					{
						text = text + "+" + propertyInfo.GetValue(null, null);
					}
					list.Add(text);
				}
			}
			return string.Join(";", list.ToArray());
		}

		private static bool IsLeader(string ownGuid)
		{
			string text = (from k in Chainloader.PluginInfos.Keys
				where k.StartsWith("com.altma.crack.")
				orderby k
				select k).FirstOrDefault();
			if (text != null)
			{
				return text == ownGuid;
			}
			return true;
		}

		internal static void Install(string ownGuid)
		{
			_ownGuid = ownGuid;
		}

		private static void Publish(SteamLobby lobby)
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			if (IsLeader(_ownGuid) && !((Object)(object)lobby == (Object)null) && ((CSteamID)(ref lobby.currentLobbyID)).IsValid())
			{
				string text = LocalToken();
				SteamMatchmaking.SetLobbyData(lobby.currentLobbyID, "cmods", text);
				Debug.Log((object)("[CrackMods] lobby mods: " + text));
			}
		}

		internal static string Describe(string host, string local)
		{
			Dictionary<string, string> dictionary = Parse(host);
			Dictionary<string, string> dictionary2 = Parse(local);
			List<string> list = new List<string>();
			foreach (string item in from k in dictionary.Keys.Union(dictionary2.Keys)
				orderby k
				select k)
			{
				dictionary.TryGetValue(item, out var value);
				dictionary2.TryGetValue(item, out var value2);
				if (!(value == value2))
				{
					list.Add(item + ": host " + (value ?? "doesn't have it") + ", you " + (value2 ?? "don't have it"));
				}
			}
			return "CrackMods don't match the host. " + string.Join(". ", list.ToArray());
			static Dictionary<string, string> Parse(string s)
			{
				return (from p in (s ?? "").Split(new char[1] { ';' })
					where p.Contains("=")
					select p).ToDictionary((string p) => p.Substring(0, p.IndexOf('=')), (string p) => p.Substring(p.IndexOf('=') + 1));
			}
		}
	}
}
namespace CrackEmotes
{
	[Serializable]
	internal class EmoteFile
	{
		public string name;

		public float fps;

		public bool loop;

		public int frames;

		public string[] bones;

		public float[] rot;

		public float[] hips;
	}
	internal sealed class Emote
	{
		internal static readonly List<Emote> All = new List<Emote>();

		public readonly string Name;

		public readonly bool Loop;

		public readonly string[] Bones;

		public readonly float Length;

		private readonly float _fps;

		private readonly int _frames;

		private readonly Quaternion[] _rot;

		private readonly Vector3[] _hips;

		private Emote(EmoteFile f)
		{
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			Name = f.name;
			Loop = f.loop;
			Bones = f.bones;
			_fps = f.fps;
			_frames = f.frames;
			int num = Bones.Length;
			_rot = (Quaternion[])(object)new Quaternion[_frames * num];
			for (int i = 0; i < _rot.Length; i++)
			{
				_rot[i] = new Quaternion(f.rot[i * 4], f.rot[i * 4 + 1], f.rot[i * 4 + 2], f.rot[i * 4 + 3]);
			}
			_hips = (Vector3[])(object)new Vector3[_frames];
			for (int j = 0; j < _frames; j++)
			{
				_hips[j] = new Vector3(f.hips[j * 3], f.hips[j * 3 + 1], f.hips[j * 3 + 2]);
			}
			Length = (float)(Loop ? _frames : (_frames - 1)) / _fps;
		}

		public void Sample(float t, Quaternion[] rot, out Vector3 hips)
		{
			//IL_0082: 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_0099: 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_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: 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)
			float num = (Loop ? Mathf.Repeat(t * _fps, (float)_frames) : Mathf.Clamp(t * _fps, 0f, (float)(_frames - 1)));
			int num2 = (int)num;
			int num3 = (Loop ? ((num2 + 1) % _frames) : Mathf.Min(num2 + 1, _frames - 1));
			float num4 = num - (float)num2;
			int num5 = Bones.Length;
			for (int i = 0; i < num5; i++)
			{
				rot[i] = Quaternion.Slerp(_rot[num2 * num5 + i], _rot[num3 * num5 + i], num4);
			}
			hips = Vector3.Lerp(_hips[num2], _hips[num3], num4);
		}

		internal static Emote Find(string name)
		{
			return All.FirstOrDefault((Emote e) => e.Name == name);
		}

		internal static void Load(string dir)
		{
			Directory.CreateDirectory(dir);
			foreach (string item in Directory.GetFiles(dir, "*.json").OrderBy<string, string>((string p) => p, StringComparer.OrdinalIgnoreCase))
			{
				try
				{
					EmoteFile emoteFile = JsonUtility.FromJson<EmoteFile>(File.ReadAllText(item));
					if (emoteFile?.bones == null || emoteFile.frames < 1 || emoteFile.rot.Length != emoteFile.frames * emoteFile.bones.Length * 4)
					{
						throw new InvalidDataException("frame data doesn't match its bone list");
					}
					All.Add(new Emote(emoteFile));
				}
				catch (Exception ex)
				{
					Plugin.Log.LogWarning((object)("Skipped emote '" + Path.GetFileName(item) + "': " + ex.Message));
				}
			}
		}
	}
	internal sealed class Emoter : MonoBehaviour
	{
		private const string LobbyKey = "cme_emote";

		private const float BlendTime = 0.25f;

		private const float RemoteSpeedGrace = 0.5f;

		internal static readonly List<Emoter> All = new List<Emoter>();

		private static readonly Dictionary<PlayerCharacterModel, Emoter> byModel = new Dictionary<PlayerCharacterModel, Emoter>();

		private static readonly FieldRef<Player, PlayerCharacter> CharacterRef = AccessTools.FieldRefAccess<Player, PlayerCharacter>("playerCharacter");

		private static readonly FieldRef<Player, PlayerCamera> CameraRef = AccessTools.FieldRefAccess<Player, PlayerCamera>("playerCamera");

		private static readonly FieldRef<Player, PlayerItemHolder> HolderRef = AccessTools.FieldRefAccess<Player, PlayerItemHolder>("playerItemHolder");

		private static readonly FieldRef<Player, CharacterInput> InputRef = AccessTools.FieldRefAccess<Player, CharacterInput>("characterInput");

		private static readonly int Speed = Animator.StringToHash("Speed");

		private static readonly int Grounded = Animator.StringToHash("Grounded");

		private static readonly int Ladder = Animator.StringToHash("Climb_Ladder");

		private static readonly int Sitting = Animator.StringToHash("Sitting");

		private static readonly int Crouching = Animator.StringToHash("Crouching");

		private static readonly int UsingStation = Animator.StringToHash("UsingStation");

		private static int _seq;

		private Player _player;

		private PlayerCharacterModel _model;

		private Transform[] _bones;

		private Quaternion[] _pose;

		private Emote _current;

		private float _time;

		private float _weight;

		private float _yaw;

		private float _poll;

		private bool _stopping;

		private bool _dressed;

		private bool _cleared;

		private string _seen;

		private Renderer[] _hiddenItem;

		private static Transform _movedCamera;

		private static Vector3 _savedCamera;

		private static readonly Action<NameTag> NameTagFollow = AccessTools.MethodDelegate<Action<NameTag>>(AccessTools.Method(typeof(NameTag), "LateUpdate", (Type[])null, (Type[])null), (object)null, true);

		private static readonly Action<IdBadge> BadgeFollow = AccessTools.MethodDelegate<Action<IdBadge>>(AccessTools.Method(typeof(IdBadge), "ApplyPocketPose", (Type[])null, (Type[])null), (object)null, true);

		private static readonly FieldInfo BadgeState = AccessTools.Field(typeof(IdBadge), "currentState");

		private NameTag _nameTag;

		private IdBadge _badge;

		internal bool Emoting
		{
			get
			{
				if (_current != null)
				{
					return !_stopping;
				}
				return false;
			}
		}

		internal static float Smooth(float w)
		{
			return w * w * (3f - 2f * w);
		}

		internal static bool Frozen(PlayerCharacterModel model, out float yaw)
		{
			yaw = 0f;
			if ((Object)(object)model == (Object)null || !byModel.TryGetValue(model, out var value) || value._current == null)
			{
				return false;
			}
			yaw = value._yaw;
			return true;
		}

		private void Awake()
		{
			_player = ((Component)this).GetComponent<Player>();
			All.Add(this);
		}

		private void OnDestroy()
		{
			All.Remove(this);
			if ((Object)(object)_model != (Object)null)
			{
				byModel.Remove(_model);
			}
		}

		private bool Resolve()
		{
			if ((Object)(object)_model != (Object)null)
			{
				return true;
			}
			PlayerCharacter val = (((Object)(object)_player != (Object)null) ? CharacterRef.Invoke(_player) : null);
			_model = (((Object)(object)val != (Object)null) ? val.GetModel() : null);
			if ((Object)(object)_model == (Object)null || (Object)(object)_model.BodyMesh == (Object)null)
			{
				return false;
			}
			byModel[_model] = this;
			return true;
		}

		internal void PlayLocal(Emote emote)
		{
			Play(emote);
			Publish(emote.Name);
		}

		private void StopLocal()
		{
			Stop();
			Publish("");
		}

		private static void Publish(string name)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: 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_0030: Unknown result type (might be due to invalid IL or missing references)
			CSteamID val = (((Object)(object)SteamLobby.instance != (Object)null) ? SteamLobby.instance.currentLobbyID : CSteamID.Nil);
			if (SteamManager.Initialized && ((CSteamID)(ref val)).IsValid())
			{
				SteamMatchmaking.SetLobbyMemberData(val, "cme_emote", (name.Length == 0) ? "" : $"{++_seq}|{name}");
			}
		}

		private void Play(Emote emote)
		{
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			if (Resolve())
			{
				Dictionary<string, Transform> byName = (from b in _model.BodyMesh.bones
					where (Object)(object)b != (Object)null
					group b by ((Object)b).name).ToDictionary((IGrouping<string, Transform> g) => g.Key, (IGrouping<string, Transform> g) => g.First());
				_bones = emote.Bones.Select((string n) => (!byName.TryGetValue(n, out var value)) ? null : value).ToArray();
				_pose = (Quaternion[])(object)new Quaternion[_bones.Length];
				if (_current == null)
				{
					_yaw = ((Component)_model).transform.eulerAngles.y;
				}
				_current = emote;
				_time = 0f;
				_stopping = false;
				HideItem();
				if (((NetworkBehaviour)_player).isOwned && Plugin.ThirdPerson.Value && !_dressed)
				{
					_model.SetSpectatorLook(true);
					_dressed = true;
				}
			}
		}

		private void Stop()
		{
			_stopping = _current != null;
		}

		private void End()
		{
			_current = null;
			_weight = 0f;
			if (_hiddenItem != null)
			{
				Renderer[] hiddenItem = _hiddenItem;
				foreach (Renderer val in hiddenItem)
				{
					if ((Object)(object)val != (Object)null)
					{
						val.enabled = true;
					}
				}
			}
			_hiddenItem = null;
			if (_dressed && (Object)(object)_model != (Object)null)
			{
				_model.SetSpectatorLook(false);
			}
			_dressed = false;
		}

		private void HideItem()
		{
			if (_hiddenItem != null)
			{
				return;
			}
			PlayerItemHolder val = HolderRef.Invoke(_player);
			HeldItem val2 = (((Object)(object)val != (Object)null) ? val.CurrentItem : null);
			if (!((Object)(object)val2 == (Object)null))
			{
				_hiddenItem = (from r in ((Component)val2).GetComponentsInChildren<Renderer>()
					where r.enabled
					select r).ToArray();
				Renderer[] hiddenItem = _hiddenItem;
				for (int num = 0; num < hiddenItem.Length; num++)
				{
					hiddenItem[num].enabled = false;
				}
			}
		}

		private bool ShouldStop(bool local)
		{
			//IL_00b1: 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_00ca: 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_00da: Unknown result type (might be due to invalid IL or missing references)
			if (_player.IsRagdolled || (Object)(object)_player.CurrentStation != (Object)null)
			{
				return true;
			}
			Animator animator = _model.Animator;
			if ((Object)(object)animator != (Object)null && (!animator.GetBool(Grounded) || animator.GetBool(Ladder) || animator.GetBool(Sitting) || animator.GetBool(Crouching) || animator.GetBool(UsingStation) || (!local && _time > 0.5f && animator.GetFloat(Speed) > 0.5f)))
			{
				return true;
			}
			if (!local)
			{
				return false;
			}
			CharacterInput val = InputRef.Invoke(_player);
			if (!(((Vector2)(ref val.move)).sqrMagnitude > 0.04f) && !val.jump && !val.leftHandUse)
			{
				return val.rightHandUse;
			}
			return true;
		}

		private void PollRemote()
		{
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			if ((_poll -= Time.deltaTime) > 0f)
			{
				return;
			}
			_poll = 0.1f;
			CSteamID val = (((Object)(object)SteamLobby.instance != (Object)null) ? SteamLobby.instance.currentLobbyID : CSteamID.Nil);
			ulong num = (((Object)(object)_player.playerController != (Object)null) ? _player.playerController.steamId : 0);
			if (!SteamManager.Initialized || !((CSteamID)(ref val)).IsValid() || num == 0L)
			{
				return;
			}
			string text = SteamMatchmaking.GetLobbyMemberData(val, new CSteamID(num), "cme_emote") ?? "";
			if (!(text == _seen))
			{
				_seen = text;
				int num2 = text.IndexOf('|');
				Emote emote = ((num2 > 0) ? Emote.Find(text.Substring(num2 + 1)) : null);
				if (emote != null)
				{
					Play(emote);
				}
				else
				{
					Stop();
				}
			}
		}

		private void Update()
		{
			if ((Object)(object)_player == (Object)null || !Resolve())
			{
				return;
			}
			bool isOwned = ((NetworkBehaviour)_player).isOwned;
			if (isOwned && !_cleared)
			{
				_cleared = true;
				Publish("");
			}
			if (!isOwned)
			{
				PollRemote();
			}
			if (_current == null)
			{
				return;
			}
			_time += Time.deltaTime;
			bool flag = !_current.Loop && _time >= _current.Length - 0.25f;
			if (!_stopping && (flag || ShouldStop(isOwned)))
			{
				if (isOwned)
				{
					StopLocal();
				}
				else
				{
					Stop();
				}
			}
			_weight = Mathf.MoveTowards(_weight, _stopping ? 0f : 1f, Time.deltaTime / 0.25f);
			if (_stopping && _weight <= 0f)
			{
				End();
			}
		}

		private void ApplyPose()
		{
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: 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_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			if (_current == null || _weight <= 0f || _bones == null)
			{
				return;
			}
			_current.Sample(_time, _pose, out var hips);
			float num = Smooth(_weight);
			for (int i = 0; i < _bones.Length; i++)
			{
				if ((Object)(object)_bones[i] != (Object)null)
				{
					_bones[i].localRotation = Quaternion.Slerp(_bones[i].localRotation, _pose[i], num);
				}
			}
			if ((Object)(object)_bones[0] != (Object)null)
			{
				_bones[0].localPosition = Vector3.Lerp(_bones[0].localPosition, hips, num);
			}
		}

		internal void LateApply()
		{
			if (_current != null && !(_weight <= 0f))
			{
				ApplyPose();
				if ((Object)(object)_nameTag == (Object)null)
				{
					_nameTag = ((Component)_player).GetComponentInChildren<NameTag>(true);
				}
				if ((Object)(object)_badge == (Object)null)
				{
					_badge = ((Component)_player).GetComponentInChildren<IdBadge>(true);
				}
				if ((Object)(object)_nameTag != (Object)null)
				{
					NameTagFollow(_nameTag);
				}
				if ((Object)(object)_badge != (Object)null && BadgeState.GetValue(_badge).ToString() == "Pocketed")
				{
					BadgeFollow(_badge);
				}
				if (((NetworkBehaviour)_player).isOwned)
				{
					MoveCamera();
				}
			}
		}

		private void MoveCamera()
		{
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: 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_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: 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_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: 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)
			//IL_00f4: 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_0109: Unknown result type (might be due to invalid IL or missing references)
			if (!Plugin.ThirdPerson.Value || _current == null || _weight <= 0f)
			{
				return;
			}
			PlayerCamera val = CameraRef.Invoke(_player);
			if (!((Object)(object)val == (Object)null))
			{
				Transform transform = ((Component)val).transform;
				Vector3 val2 = _model.GetMotorPosition() + Vector3.up * 1.3f;
				Vector3 val3 = -transform.forward;
				float num = Plugin.CameraDistance.Value;
				PlayerCharacter val4 = CharacterRef.Invoke(_player);
				LayerMask val5 = (((Object)(object)val4 != (Object)null) ? val4.CollidableLayers : LayerMask.op_Implicit(-5));
				RaycastHit val6 = default(RaycastHit);
				if (Physics.SphereCast(val2, 0.2f, val3, ref val6, num, LayerMask.op_Implicit(val5), (QueryTriggerInteraction)1))
				{
					num = Mathf.Max(0.3f, ((RaycastHit)(ref val6)).distance - 0.05f);
				}
				_movedCamera = transform;
				_savedCamera = transform.position;
				transform.position = Vector3.Lerp(_savedCamera, val2 + val3 * num, Smooth(_weight));
			}
		}

		internal static void RestoreCamera()
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_movedCamera == (Object)null))
			{
				_movedCamera.position = _savedCamera;
				_movedCamera = null;
			}
		}
	}
	internal sealed class EmoteWheel : MonoBehaviour
	{
		internal static bool IsOpen;

		private const float Radius = 250f;

		private const float Inner = 0.4f;

		private const float Deadzone = 0.3f;

		private const float MouseScale = 0.004f;

		private static readonly Color Panel = new Color(0.07f, 0.08f, 0.1f, 0.82f);

		private static readonly Color Accent = new Color(1f, 0.8f, 0.22f, 0.95f);

		private GameObject _root;

		private RectTransform _highlight;

		private TMP_Text[] _labels;

		private TMP_Text _center;

		private Vector2 _cursor;

		private int _selected = -1;

		private static bool CanOpen(Player p)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Invalid comparison between Unknown and I4
			if ((Object)(object)p != (Object)null && Emote.All.Count > 0 && (int)Cursor.lockState == 1 && (Object)(object)p.CurrentStation == (Object)null)
			{
				return !p.IsRagdolled;
			}
			return false;
		}

		private void Update()
		{
			//IL_000f: 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_009b: 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_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			Player local = Player.Local;
			Keyboard current = Keyboard.current;
			bool flag = current != null && (int)Plugin.WheelKey != 0 && ((ButtonControl)current[Plugin.WheelKey]).isPressed;
			if (!IsOpen)
			{
				if (flag && CanOpen(local))
				{
					Open();
				}
			}
			else if (!flag || !CanOpen(local))
			{
				if (!flag && _selected >= 0 && CanOpen(local))
				{
					Emoter component = ((Component)local).GetComponent<Emoter>();
					if ((Object)(object)component != (Object)null)
					{
						component.PlayLocal(Emote.All[_selected]);
					}
				}
				Close();
			}
			else
			{
				if (Mouse.current != null)
				{
					_cursor = Vector2.ClampMagnitude(_cursor + ((InputControl<Vector2>)(object)((Pointer)Mouse.current).delta).ReadValue() * 0.004f, 1f);
				}
				int count = Emote.All.Count;
				float num = 360f / (float)count;
				float num2 = Mathf.Repeat(Mathf.Atan2(_cursor.x, _cursor.y) * 57.29578f + num / 2f, 360f);
				Select((((Vector2)(ref _cursor)).magnitude > 0.3f) ? ((int)(num2 / num) % count) : (-1));
			}
		}

		private void Open()
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_root == (Object)null)
			{
				Build();
			}
			IsOpen = true;
			_cursor = Vector2.zero;
			_selected = -2;
			Select(-1);
			_root.SetActive(true);
		}

		private void Close()
		{
			IsOpen = false;
			if ((Object)(object)_root != (Object)null)
			{
				_root.SetActive(false);
			}
		}

		private void Select(int i)
		{
			//IL_0051: 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_006b: Unknown result type (might be due to invalid IL or missing references)
			if (i != _selected)
			{
				_selected = i;
				((Component)_highlight).gameObject.SetActive(i >= 0);
				if (i >= 0)
				{
					((Transform)_highlight).localEulerAngles = new Vector3(0f, 0f, (float)(-i) * 360f / (float)Emote.All.Count);
				}
				for (int j = 0; j < _labels.Length; j++)
				{
					((Graphic)_labels[j]).color = (Color)((j == i) ? new Color(0.08f, 0.08f, 0.1f) : Color.white);
				}
				_center.text = ((i >= 0) ? Emote.All[i].Name : "EMOTES");
			}
		}

		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_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0136: Unknown result type (might be due to invalid IL or missing references)
			//IL_0165: Unknown result type (might be due to invalid IL or missing references)
			//IL_0199: 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)
			int count = Emote.All.Count;
			_root = new GameObject("CrackEmotes_Wheel");
			Object.DontDestroyOnLoad((Object)(object)_root);
			Canvas obj = _root.AddComponent<Canvas>();
			obj.renderMode = (RenderMode)0;
			obj.sortingOrder = 500;
			CanvasScaler obj2 = _root.AddComponent<CanvasScaler>();
			obj2.uiScaleMode = (ScaleMode)1;
			obj2.referenceResolution = new Vector2(1920f, 1080f);
			obj2.matchWidthOrHeight = 1f;
			TMP_FontAsset font = HudFont();
			Image(_root.transform, "Ring", Ring(count, wedge: false), Panel);
			_highlight = Image(_root.transform, "Highlight", Ring(count, wedge: true), Accent);
			_labels = (TMP_Text[])(object)new TMP_Text[count];
			for (int i = 0; i < count; i++)
			{
				float num = (float)i * 2f * (float)Math.PI / (float)count;
				_labels[i] = Text(_root.transform, Emote.All[i].Name, font, 22f, new Vector2(Mathf.Sin(num), Mathf.Cos(num)) * 250f * 1.4f / 2f, 150f);
			}
			_center = Text(_root.transform, "", font, 26f, Vector2.zero, 160f);
			((Graphic)Text(_root.transform, "Release to play", font, 16f, new Vector2(0f, -32f), 200f)).color = new Color(1f, 1f, 1f, 0.55f);
		}

		private static TMP_FontAsset HudFont()
		{
			PlayerHUD val = Object.FindFirstObjectByType<PlayerHUD>((FindObjectsInactive)1);
			TMP_Text val2 = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponentInChildren<TMP_Text>(true) : null);
			if (!((Object)(object)val2 != (Object)null))
			{
				return TMP_Settings.defaultFontAsset;
			}
			return val2.font;
		}

		private static RectTransform Image(Transform parent, string name, Sprite sprite, Color color)
		{
			//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_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Expected O, but got Unknown
			//IL_003b: 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_004f: 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)
			GameObject val = new GameObject(name, new Type[2]
			{
				typeof(RectTransform),
				typeof(Image)
			});
			RectTransform val2 = (RectTransform)val.transform;
			((Transform)val2).SetParent(parent, false);
			val2.sizeDelta = Vector2.one * 250f * 2f;
			Image component = val.GetComponent<Image>();
			component.sprite = sprite;
			((Graphic)component).color = color;
			((Graphic)component).raycastTarget = false;
			return val2;
		}

		private static TMP_Text Text(Transform parent, string s, TMP_FontAsset font, float size, Vector2 pos, float width)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: 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_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: 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)
			GameObject val = new GameObject("Label", new Type[1] { typeof(RectTransform) });
			RectTransform val2 = (RectTransform)val.transform;
			((Transform)val2).SetParent(parent, false);
			val2.anchoredPosition = pos;
			val2.sizeDelta = new Vector2(width, 80f);
			TextMeshProUGUI val3 = val.AddComponent<TextMeshProUGUI>();
			if ((Object)(object)font != (Object)null)
			{
				((TMP_Text)val3).font = font;
			}
			((TMP_Text)val3).text = s;
			((TMP_Text)val3).fontSize = size;
			((TMP_Text)val3).alignment = (TextAlignmentOptions)514;
			((TMP_Text)val3).textWrappingMode = (TextWrappingModes)1;
			((Graphic)val3).raycastTarget = false;
			return (TMP_Text)(object)val3;
		}

		private static Sprite Ring(int n, bool wedge)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Expected O, but got Unknown
			//IL_01a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_014e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0153: Unknown result type (might be due to invalid IL or missing references)
			//IL_0158: Unknown result type (might be due to invalid IL or missing references)
			Texture2D val = new Texture2D(512, 512, (TextureFormat)4, false)
			{
				wrapMode = (TextureWrapMode)1
			};
			Color32[] array = (Color32[])(object)new Color32[262144];
			float num = 360f / (float)n;
			float num2 = ((n > 1) ? 1.2f : 0f);
			for (int i = 0; i < 512; i++)
			{
				for (int j = 0; j < 512; j++)
				{
					float num3 = ((float)j + 0.5f) / 512f * 2f - 1f;
					float num4 = ((float)i + 0.5f) / 512f * 2f - 1f;
					float num5 = Mathf.Sqrt(num3 * num3 + num4 * num4);
					float num6 = Mathf.Clamp01((1f - num5) * 512f / 2f) * Mathf.Clamp01((num5 - 0.4f) * 512f / 2f);
					float num7 = Mathf.Repeat(Mathf.Atan2(num3, num4) * 57.29578f + num / 2f, 360f);
					float num8 = Mathf.Repeat(num7, num);
					float num9 = Mathf.Clamp01((Mathf.Min(num8, num - num8) - num2 / 2f) * num5 * 512f / 60f);
					if (wedge && num7 >= num)
					{
						num9 = 0f;
					}
					array[i * 512 + j] = Color32.op_Implicit(new Color(1f, 1f, 1f, num6 * num9));
				}
			}
			val.SetPixels32(array);
			val.Apply();
			return Sprite.Create(val, new Rect(0f, 0f, 512f, 512f), new Vector2(0.5f, 0.5f));
		}
	}
	[BepInPlugin("com.altma.crack.emotes", "CRACK Emotes", "0.1.0")]
	public class Plugin : BaseUnityPlugin
	{
		public const string Guid = "com.altma.crack.emotes";

		public const string Name = "CRACK Emotes";

		public const string Version = "0.1.0";

		internal static ManualLogSource Log;

		internal static ConfigEntry<bool> ThirdPerson;

		internal static ConfigEntry<float> CameraDistance;

		internal static Key WheelKey;

		private void Awake()
		{
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: 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_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Expected O, but got Unknown
			//IL_0141: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			Log = ((BaseUnityPlugin)this).Logger;
			ConfigEntry<string> val = ((BaseUnityPlugin)this).Config.Bind<string>("Emotes", "WheelKey", "B", "Hold to open the emote wheel (a key name, e.g. B, G, T).");
			ThirdPerson = ((BaseUnityPlugin)this).Config.Bind<bool>("Emotes", "ThirdPersonCamera", true, "Pull the camera back while you emote so you can see yourself.");
			CameraDistance = ((BaseUnityPlugin)this).Config.Bind<float>("Emotes", "CameraDistance", 2.5f, "How far back the emote camera sits (metres).");
			if (!Enum.TryParse<Key>(val.Value, ignoreCase: true, out WheelKey))
			{
				Log.LogWarning((object)("WheelKey '" + val.Value + "' isn't a key name, using B"));
				WheelKey = (Key)16;
			}
			ModHandshake.Install("com.altma.crack.emotes");
			Emote.Load(Path.Combine(Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location), "Emotes"));
			new Harmony("com.altma.crack.emotes").PatchAll(typeof(Plugin).Assembly);
			GameObject val2 = new GameObject("CrackEmotes")
			{
				hideFlags = (HideFlags)61
			};
			Object.DontDestroyOnLoad((Object)val2);
			val2.AddComponent<EmoteWheel>();
			Log.LogInfo((object)string.Format("{0} {1} loaded, {2} emotes, wheel key {3}", "CRACK Emotes", "0.1.0", Emote.All.Count, WheelKey));
		}
	}
	[HarmonyPatch]
	internal static class Patches
	{
		private static readonly FieldRef<PlayerCharacterModel, float> LowerBodyYaw = AccessTools.FieldRefAccess<PlayerCharacterModel, float>("_lowerBodyYaw");

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Player), "OnStartClient")]
		private static void AddEmoter(Player __instance)
		{
			if ((Object)(object)((Component)__instance).GetComponent<Emoter>() == (Object)null)
			{
				((Component)__instance).gameObject.AddComponent<Emoter>();
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Player), "LateUpdate")]
		private static void Pose(Player __instance)
		{
			Emoter component = ((Component)__instance).GetComponent<Emoter>();
			if ((Object)(object)component != (Object)null)
			{
				component.LateApply();
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Player), "Update")]
		private static void Unpose(Player __instance)
		{
			if (((NetworkBehaviour)__instance).isOwned)
			{
				Emoter.RestoreCamera();
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Player), "ReadLook")]
		private static bool BlockLook(ref Vector2 __result)
		{
			//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)
			if (!EmoteWheel.IsOpen)
			{
				return true;
			}
			__result = Vector2.zero;
			return false;
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(PlayerCharacterModel), "UpdateLowerBodyRotation")]
		private static bool FreezeYaw(PlayerCharacterModel __instance)
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			if (!Emoter.Frozen(__instance, out var yaw))
			{
				return true;
			}
			LowerBodyYaw.Invoke(__instance) = yaw;
			((Component)__instance).transform.rotation = Quaternion.Euler(0f, yaw, 0f);
			return false;
		}
	}
}