Decompiled source of Punkalyn PunkEmotes v1.0.0

PunkEmotes.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.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Mirror;
using UnityEngine;
using UnityEngine.Animations;
using UnityEngine.Playables;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("PunkEmotes")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("0.0.1.0")]
[assembly: AssemblyInformationalVersion("0.0.1")]
[assembly: AssemblyProduct("PunkEmotes")]
[assembly: AssemblyTitle("PunkEmotes")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.0.1.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace PunkEmotes
{
	[BepInPlugin("punkalyn.punkemotes", "PunkEmotes", "0.1.0")]
	[BepInProcess("ATLYSS.exe")]
	public class Plugin : BaseUnityPlugin
	{
		public class AnimationConstructor
		{
			[HarmonyPatch(typeof(CharacterSelectManager), "Select_CharacterFile")]
			private class ResetCache
			{
				private static void Postfix()
				{
					raceAnimatorReset = true;
					PlayerRegistry.ClearRegistry();
				}
			}

			[HarmonyPatch(typeof(PlayerVisual), "Iterate_AnimationCallback")]
			public class LoadFBX
			{
				private static void Postfix(PlayerVisual __instance, ref string _animName, ref float _animLayer)
				{
					if (raceAnimatorReset)
					{
						LoadRaceFBXs();
					}
				}
			}

			public class AnimationLibrary
			{
				private static AnimationLibrary _instance;

				private Dictionary<string, Dictionary<string, AnimationClip>> animationClips = new Dictionary<string, Dictionary<string, AnimationClip>>
				{
					{
						"dance",
						new Dictionary<string, AnimationClip>()
					},
					{
						"general",
						new Dictionary<string, AnimationClip>()
					},
					{
						"override",
						new Dictionary<string, AnimationClip>()
					},
					{
						"sit",
						new Dictionary<string, AnimationClip>()
					}
				};

				public static AnimationLibrary Instance
				{
					get
					{
						if (_instance == null)
						{
							_instance = new AnimationLibrary();
						}
						return _instance;
					}
				}

				private AnimationLibrary()
				{
				}

				public void PopulateDefaultAnimations()
				{
					foreach (KeyValuePair<string, Animator> raceAnimator in raceAnimators)
					{
						string key = raceAnimator.Key;
						Animator value = raceAnimator.Value;
						AnimationClip[] array = ExtractAnimationsFromAnimator(value);
						AnimationClip[] array2 = array;
						foreach (AnimationClip val in array2)
						{
							if (!((Object)(object)val != (Object)null))
							{
								continue;
							}
							if (((Object)val).name.Contains("dance"))
							{
								if (((Object)val).name == "Kobold_dance")
								{
									((Object)val).name = "kubold_dance";
								}
								animationClips["dance"][key + "_dance"] = val;
								LogInfo("Added " + ((Object)val).name + " as " + key + "_dance to animation library!");
							}
							if (((Object)val).name.Contains("sitInit") && !((Object)val).name.Contains("02"))
							{
								if (((Object)val).name == "Kobold_sitInit")
								{
									((Object)val).name = "kubold_sitInit";
								}
								animationClips["override"][key + "_sitInit"] = val;
								animationClips["sit"][key + "_sitInit"] = val;
								LogInfo("Added " + ((Object)val).name + " as " + key + "_sitInit to animation library!");
							}
							if (((Object)val).name.Contains("sitLoop") && !((Object)val).name.Contains("02"))
							{
								if (((Object)val).name == "Kobold_sitLoop")
								{
									((Object)val).name = "kubold_sitLoop";
								}
								animationClips["override"][key + "_sitLoop"] = val;
								LogInfo("Added " + ((Object)val).name + " as " + key + "_sitLoop to animation library!");
							}
							if (((Object)val).name.Contains("sitInit02"))
							{
								if (((Object)val).name == "Kobold_sitInit02")
								{
									((Object)val).name = "kubold_sitInit02";
								}
								animationClips["override"][key + "_sitInit02"] = val;
								LogInfo("Added " + ((Object)val).name + " as " + key + "_sitInit02 to animation library!");
							}
							if (((Object)val).name.Contains("sitLoop02"))
							{
								if (((Object)val).name == "Kobold_sitLoop")
								{
									((Object)val).name = "kubold_sitLoop";
								}
								animationClips["override"][key + "_sitLoop02"] = val;
								LogInfo("Added " + ((Object)val).name + " as " + key + "_sitLoop02 to animation library!");
							}
						}
					}
				}

				private AnimationClip[] ExtractAnimationsFromAnimator(Animator animator)
				{
					List<AnimationClip> list = new List<AnimationClip>();
					AnimationClip[] array = animator.runtimeAnimatorController.animationClips;
					foreach (AnimationClip item in array)
					{
						list.Add(item);
					}
					return list.ToArray();
				}

				public void LoadAnimations()
				{
					AnimationClip[] array = Resources.LoadAll<AnimationClip>("Animations/");
					AnimationClip[] array2 = array;
					foreach (AnimationClip val in array2)
					{
					}
				}

				public AnimationClip GetAnimation(string name, string category)
				{
					name = name.ToLowerInvariant();
					if (!string.IsNullOrEmpty(category) && animationClips.ContainsKey(category))
					{
						Dictionary<string, AnimationClip> dictionary = animationClips[category];
						if (dictionary.ContainsKey(name))
						{
							return dictionary[name];
						}
						foreach (AnimationClip value in dictionary.Values)
						{
							if (((Object)value).name.Equals(name, StringComparison.OrdinalIgnoreCase))
							{
								return value;
							}
						}
						foreach (string key in dictionary.Keys)
						{
							if (key.Contains(name))
							{
								return dictionary[key];
							}
						}
						foreach (AnimationClip value2 in dictionary.Values)
						{
							if (((Object)value2).name.IndexOf(name, StringComparison.OrdinalIgnoreCase) >= 0)
							{
								return value2;
							}
						}
						LogInfo("No animation named: " + name + " in category: " + category);
					}
					if (animationClips.ContainsKey("general") && category == null)
					{
						Dictionary<string, AnimationClip> dictionary2 = animationClips["general"];
						if (dictionary2.ContainsKey(name))
						{
							return dictionary2[name];
						}
						foreach (AnimationClip value3 in dictionary2.Values)
						{
							if (((Object)value3).name.Equals(name, StringComparison.OrdinalIgnoreCase))
							{
								return value3;
							}
						}
						foreach (string key2 in dictionary2.Keys)
						{
							if (key2.Contains(name))
							{
								return dictionary2[key2];
							}
						}
						foreach (AnimationClip value4 in dictionary2.Values)
						{
							if (((Object)value4).name.IndexOf(name, StringComparison.OrdinalIgnoreCase) >= 0)
							{
								return value4;
							}
						}
					}
					if (category == null)
					{
						foreach (Dictionary<string, AnimationClip> value5 in animationClips.Values)
						{
							if (value5.ContainsKey(name))
							{
								return value5[name];
							}
							foreach (AnimationClip value6 in value5.Values)
							{
								if (((Object)value6).name.Equals(name, StringComparison.OrdinalIgnoreCase))
								{
									return value6;
								}
							}
							foreach (string key3 in value5.Keys)
							{
								if (key3.Contains(name))
								{
									return value5[key3];
								}
							}
							foreach (AnimationClip value7 in value5.Values)
							{
								if (((Object)value7).name.IndexOf(name, StringComparison.OrdinalIgnoreCase) >= 0)
								{
									return value7;
								}
							}
						}
					}
					LogWarning("No animation found with the name: " + name);
					return null;
				}
			}

			private static Dictionary<string, Animator> raceAnimators = new Dictionary<string, Animator>();

			private static bool raceAnimatorReset = true;

			private static void LoadRaceFBXs()
			{
				string[] array = new string[5] { "byrdle", "chang", "imp", "Kobold", "poon" };
				string[] array2 = array;
				foreach (string text in array2)
				{
					GameObject val = GameObject.Find(text + "FBX");
					if ((Object)(object)val != (Object)null)
					{
						Animator component = val.GetComponent<Animator>();
						raceAnimators[text] = component;
						LogInfo(text + " loaded into animation memory");
					}
				}
				AnimationLibrary.Instance.PopulateDefaultAnimations();
				raceAnimatorReset = false;
			}
		}

		public class PunkEmotesManager : MonoBehaviour
		{
			private PlayableGraph _playableGraph;

			public Animator _animator;

			private AnimationClipPlayable _currentClipPlayable;

			private AnimationLayerMixerPlayable _layerMixerPlayable;

			private AnimatorOverrideController newOverrideController;

			public Dictionary<string, List<string>> overrideAliases = new Dictionary<string, List<string>>();

			private string _currentAnimation;

			private string _currentCategory;

			private List<string> playerOverrides = new List<string>();

			private Player _player;

			public bool _isAnimationPlaying;

			private void Awake()
			{
				//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)
				//IL_0033: Unknown result type (might be due to invalid IL or missing references)
				//IL_0039: Unknown result type (might be due to invalid IL or missing references)
				//IL_003e: Unknown result type (might be due to invalid IL or missing references)
				((MonoBehaviour)this).StartCoroutine(WaitForAnimator());
				_animator = ((Component)this).GetComponent<Animator>();
				_playableGraph = PlayableGraph.Create();
				_player = ((Component)this).GetComponent<Player>();
				_currentClipPlayable = AnimationClipPlayable.Create(_playableGraph, (AnimationClip)null);
				overrideAliases["sit"] = new List<string> { "_playeremote_sitinit", "_playeremote_sitloop", "_sitInit", "_sitLoop" };
				overrideAliases["sit2"] = new List<string> { "_playeremote_sitinit02", "_playeremote_sitloop02", "_sitInit02", "_sitLoop02" };
			}

			private IEnumerator WaitForAnimator()
			{
				_player = ((Component)this).GetComponent<Player>();
				if ((Object)(object)_player == (Object)null)
				{
					LogError("PunkEmotesManager must be attached to a Player object.");
					yield break;
				}
				while ((Object)(object)_player._pVisual == (Object)null || (Object)(object)_player._pVisual._visualAnimator == (Object)null)
				{
					yield return null;
				}
				_animator = ((Component)_player._pVisual._visualAnimator).GetComponent<Animator>();
				if ((Object)(object)_animator != (Object)null)
				{
					newOverrideController = new AnimatorOverrideController(_animator.runtimeAnimatorController);
					InitializeGraph(_animator);
					LogInfo("Attached PunkEmotesManager to player: " + _player._nickname);
					SendSyncRequest();
				}
				else
				{
					LogError("Animator component not found on PlayerVisual.");
				}
			}

			public void InitializeGraph(Animator animator)
			{
				//IL_0029: Unknown result type (might be due to invalid IL or missing references)
				//IL_002e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0035: Unknown result type (might be due to invalid IL or missing references)
				//IL_003b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0040: Unknown result type (might be due to invalid IL or missing references)
				//IL_0046: 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_0056: Unknown result type (might be due to invalid IL or missing references)
				//IL_0057: Unknown result type (might be due to invalid IL or missing references)
				//IL_0059: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)animator == (Object)null)
				{
					LogError("Animator is null.");
					return;
				}
				_playableGraph = PlayableGraph.Create("AnimationGraph");
				_layerMixerPlayable = AnimationLayerMixerPlayable.Create(_playableGraph, 2);
				AnimationPlayableOutput val = AnimationPlayableOutput.Create(_playableGraph, "AnimationOutput", animator);
				PlayableOutputExtensions.SetSourcePlayable<AnimationPlayableOutput, AnimationLayerMixerPlayable>(val, _layerMixerPlayable);
			}

			private void SendSyncRequest()
			{
				string text = $"<>#PUNKEMOTES#{((NetworkBehaviour)_player).netId}#ALL#SYNCREQUEST#";
				((Component)_player).GetComponent<ChatBehaviour>().Cmd_SendChatMessage(text, (ChatChannel)3);
			}

			private void SendSyncResponse(string target)
			{
				if (_isAnimationPlaying)
				{
					LogInfo("We're sending the animation to " + target);
					SendAnimationCommand(target, "START", _currentAnimation, this, _currentCategory);
				}
				else
				{
					LogInfo("No animation playing, is this correct?");
				}
				if (playerOverrides != null)
				{
					LogInfo("We're sending override info to " + target);
					{
						foreach (string playerOverride in playerOverrides)
						{
							LogInfo(playerOverride ?? "");
							string[] array = playerOverride.Split('_');
							string animationName = array[0];
							string originOverride = array[1];
							ApplyPunkOverrides(target, this, animationName, originOverride);
						}
						return;
					}
				}
				LogInfo("No override info to send, is this correct?");
			}

			public void ApplyPunkOverrides(string target, PunkEmotesManager emotesManager, string animationName, string originOverride)
			{
				AnimationClip animation = AnimationConstructor.AnimationLibrary.Instance.GetAnimation(animationName, "override");
				if ((Object)(object)animation == (Object)null)
				{
					return;
				}
				RuntimeAnimatorController runtimeAnimatorController = _animator.runtimeAnimatorController;
				AnimatorOverrideController val = (AnimatorOverrideController)(object)((runtimeAnimatorController is AnimatorOverrideController) ? runtimeAnimatorController : null);
				List<KeyValuePair<AnimationClip, AnimationClip>> list = new List<KeyValuePair<AnimationClip, AnimationClip>>();
				val.GetOverrides(list);
				foreach (KeyValuePair<AnimationClip, AnimationClip> item2 in list)
				{
					newOverrideController[item2.Key] = item2.Value;
				}
				bool flag = false;
				foreach (KeyValuePair<AnimationClip, AnimationClip> item3 in list)
				{
					AnimationClip key = item3.Key;
					if (((key != null) ? ((Object)key).name.ToLowerInvariant() : null) == originOverride)
					{
						newOverrideController[item3.Key] = animation;
						flag = true;
						break;
					}
				}
				if (!flag)
				{
					LogError(originOverride + " not found in override mappings.");
					return;
				}
				_animator.runtimeAnimatorController = (RuntimeAnimatorController)(object)newOverrideController;
				LogInfo("Applied override: '" + originOverride + "' -> '" + animationName + "'.");
				string item = animationName + "_" + originOverride;
				if (!playerOverrides.Contains(item))
				{
					playerOverrides.Add(item);
				}
				SendAnimationCommand("ALL", "Override", animationName, emotesManager, originOverride);
			}

			public void PlayAnimationClip(string target, PunkEmotesManager emotesManager, string animationName, string animationCategory = null)
			{
				//IL_0065: 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)
				//IL_0070: 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_0078: 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_0093: Unknown result type (might be due to invalid IL or missing references)
				//IL_00b1: 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)
				AnimationClip animation = AnimationConstructor.AnimationLibrary.Instance.GetAnimation(animationName, animationCategory);
				if (!((PlayableGraph)(ref emotesManager._playableGraph)).IsValid())
				{
					emotesManager.InitializeGraph(emotesManager._animator);
				}
				if ((Object)(object)animation == (Object)null)
				{
					LogError("AnimationClip is null.");
					return;
				}
				emotesManager.CrossfadeToCustomAnimation(emotesManager, animation);
				AnimationClipPlayable val = AnimationClipPlayable.Create(emotesManager._playableGraph, animation);
				PlayableExtensions.ConnectInput<AnimationLayerMixerPlayable, AnimationClipPlayable>(_layerMixerPlayable, 1, val, 0);
				PlayableExtensions.SetInputWeight<AnimationLayerMixerPlayable>(_layerMixerPlayable, 1, 1f);
				PlayableExtensions.SetInputWeight<AnimationLayerMixerPlayable>(_layerMixerPlayable, 0, 0f);
				((PlayableGraph)(ref emotesManager._playableGraph)).Play();
				emotesManager._currentClipPlayable = val;
				emotesManager._isAnimationPlaying = true;
				emotesManager._currentAnimation = animationName;
				emotesManager._currentCategory = animationCategory;
				if (((NetworkBehaviour)Player._mainPlayer).netId == ((NetworkBehaviour)_player).netId)
				{
					SendAnimationCommand("ALL", "START", animationName, emotesManager, animationCategory);
				}
				LogInfo($"Playing animation clip: {animationName} for player with netId {((NetworkBehaviour)emotesManager._player).netId}");
			}

			public void StopAnimation(PunkEmotesManager emotesManager)
			{
				//IL_0022: Unknown result type (might be due to invalid IL or missing references)
				//IL_0034: Unknown result type (might be due to invalid IL or missing references)
				//IL_0052: Unknown result type (might be due to invalid IL or missing references)
				if (emotesManager._isAnimationPlaying && ((PlayableGraph)(ref emotesManager._playableGraph)).IsValid())
				{
					string animationName = null;
					PlayableExtensions.SetInputWeight<AnimationLayerMixerPlayable>(_layerMixerPlayable, 1, 0f);
					PlayableExtensions.SetInputWeight<AnimationLayerMixerPlayable>(_layerMixerPlayable, 0, 1f);
					((PlayableGraph)(ref emotesManager._playableGraph)).Stop();
					PlayableExtensions.Destroy<AnimationClipPlayable>(_currentClipPlayable);
					emotesManager._currentAnimation = null;
					emotesManager._isAnimationPlaying = false;
					SendAnimationCommand("ALL", "STOP", animationName, emotesManager);
					LogInfo($"Stopped custom animation for player with netId {((NetworkBehaviour)emotesManager._player).netId}.");
				}
			}

			private void CrossfadeToCustomAnimation(PunkEmotesManager emotesManager, AnimationClip animationClip, float crossfadeDuration = 0.3f)
			{
				//IL_0037: 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)
				RuntimeAnimatorController runtimeAnimatorController = emotesManager._animator.runtimeAnimatorController;
				AnimatorOverrideController val = (AnimatorOverrideController)(object)((runtimeAnimatorController is AnimatorOverrideController) ? runtimeAnimatorController : null);
				if (val != null)
				{
					int num = 0;
					if (emotesManager._animator.layerCount > num)
					{
						AnimatorStateInfo currentAnimatorStateInfo = emotesManager._animator.GetCurrentAnimatorStateInfo(num);
						string text = (((AnimatorStateInfo)(ref currentAnimatorStateInfo)).IsName("Idle") ? "Idle" : "Default");
						val[text] = animationClip;
						emotesManager._animator.CrossFade(text, crossfadeDuration, num);
					}
					else
					{
						LogError("Base layer not found in animator.");
					}
				}
				LogInfo($"Crossfaded to custom animation: {((Object)animationClip).name} with a {crossfadeDuration}s transition.");
			}

			public void CrossfadeToDefaultState()
			{
				//IL_0008: 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)
				AnimatorStateInfo currentAnimatorStateInfo = _animator.GetCurrentAnimatorStateInfo(0);
				if (((AnimatorStateInfo)(ref currentAnimatorStateInfo)).IsName("Walk") || ((AnimatorStateInfo)(ref currentAnimatorStateInfo)).IsName("Run") || ((AnimatorStateInfo)(ref currentAnimatorStateInfo)).IsName("Jump") || ((AnimatorStateInfo)(ref currentAnimatorStateInfo)).IsName("Dash"))
				{
					_animator.CrossFade(((AnimatorStateInfo)(ref currentAnimatorStateInfo)).fullPathHash, 0.2f);
				}
				else
				{
					_animator.CrossFade("Idle", 0.2f);
				}
				LogInfo("Crossfaded back to default state (Idle/Walk/Run) after custom animation.");
			}

			public void Dispose(PunkEmotesManager emotesManager)
			{
				if (((PlayableGraph)(ref emotesManager._playableGraph)).IsValid())
				{
					((PlayableGraph)(ref emotesManager._playableGraph)).Destroy();
					LogInfo("PlayableGraph destroyed.");
				}
			}

			public void SendAnimationCommand(string target, string command, string animationName, PunkEmotesManager emotesManager, string categoryOrOrigin = null)
			{
				string text = $"<>#PUNKEMOTES#{((NetworkBehaviour)emotesManager._player).netId}#{target}#{command}#{animationName}#{categoryOrOrigin}";
				((Component)_player).GetComponent<ChatBehaviour>().Cmd_SendChatMessage(text, (ChatChannel)3);
			}

			public void HandleChatAnimationMessage(string message)
			{
				if (string.IsNullOrEmpty(message))
				{
					return;
				}
				string[] array = message.ToLower().Split(new string[1] { "#" }, StringSplitOptions.None);
				if (array.Length >= 5)
				{
					if (uint.TryParse(array[2], out var result))
					{
						string text = array[3];
						string text2 = array[4];
						string text3 = array[5];
						string text4 = ((array.Length > 6) ? array[6] : null);
						if (result == ((NetworkBehaviour)Player._mainPlayer).netId)
						{
							LogInfo("Skipping local player animation reprocessing to prevent infinite loop.");
						}
						else
						{
							if (!(text == "all") && (!uint.TryParse(text, out var result2) || result2 != ((NetworkBehaviour)Player._mainPlayer).netId))
							{
								return;
							}
							Player playerByNetId = PlayerRegistry.GetPlayerByNetId(result);
							if ((Object)(object)playerByNetId != (Object)null)
							{
								PunkEmotesManager component = ((Component)playerByNetId).GetComponent<PunkEmotesManager>();
								if ((Object)(object)component != (Object)null)
								{
									switch (text2)
									{
									case "syncrequest":
										LogInfo("Sync requested, sending response:");
										SendSyncResponse(result.ToString());
										break;
									case "start":
										if (!string.IsNullOrEmpty(text4))
										{
											component.PlayAnimationClip(null, component, text3, text4);
										}
										else
										{
											component.PlayAnimationClip(null, component, text3);
										}
										break;
									case "override":
										if (!string.IsNullOrEmpty(text4))
										{
											if (overrideAliases.ContainsKey(text4))
											{
												List<string> list = overrideAliases[text4];
												string animationName = text3 + list[2];
												string animationName2 = text3 + list[3];
												component.ApplyPunkOverrides(null, component, animationName, list[0]);
												component.ApplyPunkOverrides(null, component, animationName2, list[1]);
											}
											else
											{
												component.ApplyPunkOverrides(null, component, text3, text4);
											}
										}
										else
										{
											LogWarning("Override command missing originOverride for animation '" + text3 + "'.");
										}
										break;
									case "stop":
										component.StopAnimation(component);
										break;
									default:
										LogWarning("Unknown command '" + text2 + "' received in PUNKEMOTES message.");
										break;
									}
								}
								else
								{
									LogWarning($"PunkEmotesManager not found for sender player with netId '{result}'.");
								}
							}
							else
							{
								LogWarning($"Sender player with netId '{result}' not found.");
							}
						}
					}
					else
					{
						LogWarning("Failed to parse sender's netId from message: " + array[2]);
					}
				}
				else
				{
					LogWarning("Invalid PUNKEMOTES message format. Insufficient parts.");
				}
			}
		}

		public static class PlayerRegistry
		{
			private class PlayerEntry
			{
				public string Nickname { get; set; }

				public Player PlayerInstance { get; set; }

				public PunkEmotesManager EmotesManager { get; set; }
			}

			private static Dictionary<uint, PlayerEntry> _playersByNetId = new Dictionary<uint, PlayerEntry>();

			public static void RegisterPlayer(Player player, PunkEmotesManager emotesManager)
			{
				if ((Object)(object)player != (Object)null && (Object)(object)emotesManager != (Object)null)
				{
					uint netId = ((NetworkBehaviour)player).netId;
					if (!_playersByNetId.ContainsKey(netId))
					{
						_playersByNetId[netId] = new PlayerEntry
						{
							Nickname = player.Network_nickname,
							PlayerInstance = player,
							EmotesManager = emotesManager
						};
					}
				}
			}

			public static void UnregisterPlayer(Player player)
			{
				if ((Object)(object)player != (Object)null)
				{
					uint netId = ((NetworkBehaviour)player).netId;
					_playersByNetId.Remove(netId);
				}
			}

			public static void ClearRegistry()
			{
				_playersByNetId.Clear();
			}

			public static PunkEmotesManager GetEmotesManagerByNetId(uint netId)
			{
				PlayerEntry value;
				return _playersByNetId.TryGetValue(netId, out value) ? value.EmotesManager : null;
			}

			public static Player GetPlayerByNetId(uint netId)
			{
				PlayerEntry value;
				return _playersByNetId.TryGetValue(netId, out value) ? value.PlayerInstance : null;
			}

			public static Player GetPlayerByNickname(string nickname)
			{
				foreach (PlayerEntry value in _playersByNetId.Values)
				{
					if (value.Nickname == nickname)
					{
						return value.PlayerInstance;
					}
				}
				return null;
			}
		}

		[HarmonyPatch]
		public static class PatchWrapper
		{
			[HarmonyPatch(typeof(ChatBehaviour), "Send_ChatMessage")]
			public class PlayPunkEmote
			{
				private static bool Prefix(ref string _message, ChatBehaviour __instance)
				{
					if (string.IsNullOrEmpty(_message))
					{
						return true;
					}
					if (!_message.StartsWith("/em ", StringComparison.OrdinalIgnoreCase))
					{
						return true;
					}
					PunkEmotesManager emotesManagerByNetId = PlayerRegistry.GetEmotesManagerByNetId(((NetworkBehaviour)Player._mainPlayer).netId);
					string text = _message.Substring(4).Trim();
					string[] array = text.Split(' ');
					string text2 = array[0].ToLower();
					string text3 = text2;
					if (!(text3 == "overrides"))
					{
						if (text3 == "help")
						{
							SendChatMessage("Commands: '/em animation_name (or race)'");
							SendChatMessage("Commands: '/em category animation_name (or race)'");
							SendChatMessage("Categories: 'sit', 'dance'");
							SendChatMessage("Test animation: '/em 02'");
							LogInfo("Available commands: overrides, help");
							return false;
						}
						if (array.Length == 3 && array[0].ToLower() == "override")
						{
							string text4 = array[1].ToLower();
							string text5 = array[2].ToLower();
							if ((Object)(object)AnimationConstructor.AnimationLibrary.Instance.GetAnimation(text5, "override") == (Object)null)
							{
								LogError("Override animation '" + text5 + "' not found.");
								return false;
							}
							if (emotesManagerByNetId.overrideAliases.ContainsKey(text4))
							{
								List<string> list = emotesManagerByNetId.overrideAliases[text4];
								string animationName = text5 + list[2];
								string animationName2 = text5 + list[3];
								emotesManagerByNetId.ApplyPunkOverrides("ALL", emotesManagerByNetId, animationName, list[0]);
								emotesManagerByNetId.ApplyPunkOverrides("ALL", emotesManagerByNetId, animationName2, list[1]);
							}
							else
							{
								emotesManagerByNetId.ApplyPunkOverrides("ALL", emotesManagerByNetId, text5, text4);
							}
							return false;
						}
						if (array.Length == 2)
						{
							string animationCategory = array[0].ToLower();
							string animationName3 = array[1].ToLower();
							emotesManagerByNetId.PlayAnimationClip("ALL", emotesManagerByNetId, animationName3, animationCategory);
							return false;
						}
						if (array.Length == 1)
						{
							string animationName4 = array[0].ToLower();
							emotesManagerByNetId.PlayAnimationClip("ALL", emotesManagerByNetId, animationName4);
							return false;
						}
						LogWarning("Invalid emotes format. Expected '/em [category] [name]', '/em [name]', or '/em override [originOverride] [newOverride]'.");
						return false;
					}
					AnimationClip[] animationClips = emotesManagerByNetId._animator.runtimeAnimatorController.animationClips;
					if (animationClips != null && animationClips.Length != 0)
					{
						AnimationClip[] array2 = animationClips;
						foreach (AnimationClip val in array2)
						{
							LogInfo("Overridable animation: " + ((Object)val).name);
						}
					}
					else
					{
						LogWarning("No animation clips found in the Animator.");
					}
					return false;
				}
			}

			[HarmonyPatch(typeof(PlayerMove), "Set_MovementAction")]
			public class SetMovementActionPatch
			{
				private static void Postfix(PlayerMove __instance, MovementAction _mA)
				{
					//IL_0030: Unknown result type (might be due to invalid IL or missing references)
					Player component = ((Component)__instance).gameObject.GetComponent<Player>();
					if (!((Object)(object)component == (Object)null))
					{
						PunkEmotesManager component2 = ((Component)component).GetComponent<PunkEmotesManager>();
						if (!((Object)(object)component2 == (Object)null) && (int)_mA != 0 && component2._isAnimationPlaying)
						{
							component2.StopAnimation(component2);
						}
					}
				}
			}

			private static MethodInfo rpcMethod = typeof(ChatBehaviour).GetMethod("Rpc_RecieveChatMessage", BindingFlags.Instance | BindingFlags.NonPublic);

			[HarmonyPatch(typeof(ChatBehaviour), "UserCode_Rpc_RecieveChatMessage__String__Boolean__ChatChannel")]
			[HarmonyPrefix]
			public static bool UserCode_Rpc_RecieveChatMessage__String__Boolean__ChatChannel_Prefix(string message, bool _isEmoteMessage, ChatChannel _chatChannel)
			{
				LogInfo(message);
				if (message.Contains("<>#PUNKEMOTES#"))
				{
					LogInfo("PUNKEMOTES detected in RPC!");
					string[] array = message.Split(new string[1] { "#" }, StringSplitOptions.None);
					if (array.Length >= 4)
					{
						if (!uint.TryParse(array[2], out var result))
						{
							LogWarning("Failed to parse netId from message: " + array[2]);
							return false;
						}
						Player playerByNetId = PlayerRegistry.GetPlayerByNetId(result);
						if (!((Object)(object)playerByNetId != (Object)null))
						{
							LogWarning($"Player with netId '{result}' not found.");
							return false;
						}
						PunkEmotesManager component = ((Component)playerByNetId).GetComponent<PunkEmotesManager>();
						if ((Object)(object)component != (Object)null)
						{
							component.HandleChatAnimationMessage(message);
							return false;
						}
					}
					return false;
				}
				return true;
			}

			[HarmonyPatch(typeof(ChatBehaviour), "UserCode_Cmd_SendChatMessage__String__ChatChannel")]
			[HarmonyPrefix]
			public static bool UserCode_Cmd_SendChatMessage__String__ChatChannel_Prefix(ChatBehaviour __instance, string _message, ChatChannel _chatChannel)
			{
				if (_message.Contains("<>#PUNKEMOTES#"))
				{
					if (rpcMethod != null)
					{
						rpcMethod.Invoke(__instance, new object[3]
						{
							_message,
							true,
							(object)(ChatChannel)3
						});
						LogInfo("Caught <>#PUNKEMOTES#, sent to RPC");
						return false;
					}
					return false;
				}
				return true;
			}

			[HarmonyPatch(typeof(Player), "Start")]
			private static void Postfix(Player __instance)
			{
				PunkEmotesManager punkEmotesManager = ((Component)__instance).gameObject.GetComponent<PunkEmotesManager>();
				if ((Object)(object)punkEmotesManager == (Object)null)
				{
					punkEmotesManager = ((Component)__instance).gameObject.AddComponent<PunkEmotesManager>();
				}
				PlayerRegistry.RegisterPlayer(__instance, punkEmotesManager);
			}
		}

		internal static ManualLogSource Logger;

		public static bool logInfoEnabled = false;

		public static bool logWarningEnabled = true;

		public static bool logErrorEnabled = true;

		private static bool logMethod = true;

		private void Awake()
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Expected O, but got Unknown
			Logger = ((BaseUnityPlugin)this).Logger;
			LogInfo("Punk Emotes is rockin'!");
			Harmony val = new Harmony("punkalyn.punkemotes");
			int num = 7;
			try
			{
				val.PatchAll();
				if (num != val.GetPatchedMethods().Count())
				{
					LogError($"Punk Emotes patched {val.GetPatchedMethods().Count()} methods out of {num} intended patches!");
				}
			}
			catch (Exception ex)
			{
				LogError("Exception caught while patching: " + ex.Message);
			}
		}

		public static void LogMethod(bool enable)
		{
			logMethod = enable;
		}

		public static void LogInfo(string message, bool? shouldLog = null)
		{
			if ((shouldLog ?? logInfoEnabled) && logMethod)
			{
				Logger.LogInfo((object)message);
			}
		}

		public static void LogWarning(string message, bool? shouldLog = null)
		{
			if ((shouldLog ?? logWarningEnabled) && logMethod)
			{
				Logger.LogWarning((object)message);
			}
		}

		public static void LogError(string message, bool? shouldLog = null)
		{
			if ((shouldLog ?? logErrorEnabled) && logMethod)
			{
				Logger.LogError((object)message);
			}
		}

		private static void SendChatMessage(string message)
		{
			if (Object.op_Implicit((Object)(object)Player._mainPlayer))
			{
				Player._mainPlayer._cB.New_ChatMessage(message);
			}
		}
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "PunkEmotes";

		public const string PLUGIN_NAME = "PunkEmotes";

		public const string PLUGIN_VERSION = "0.0.1";
	}
}