Decompiled source of TooManyEmotes v1.9.5
plugins/TooManyEmotes.dll
Decompiled a day ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Serialization.Formatters.Binary; using System.Runtime.Versioning; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using Dissonance.Integrations.Unity_NFGO; using GameNetcodeStuff; using HarmonyLib; using LCVR; using LethalCompanyInputUtils.Api; using MoreCompany.Cosmetics; using TMPro; using TooManyEmotes.Compatibility; using TooManyEmotes.Config; using TooManyEmotes.Input; using TooManyEmotes.Networking; using TooManyEmotes.Patches; using TooManyEmotes.Props; using Unity.Collections; using Unity.Netcode; using UnityEngine; using UnityEngine.AI; using UnityEngine.Animations.Rigging; using UnityEngine.EventSystems; using UnityEngine.Experimental.Rendering; using UnityEngine.InputSystem; using UnityEngine.Rendering; using UnityEngine.Rendering.HighDefinition; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("TooManyEmotes")] [assembly: AssemblyDescription("Mod made by flipf17")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("TooManyEmotes")] [assembly: AssemblyCopyright("Copyright © 2023")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("d6950625-e3a1-4896-a183-87110491bf18")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyVersion("1.0.0.0")] namespace TooManyEmotes { public class AdditionalEmoteData { } public static class BoneMapper { public static Dictionary<Transform, Transform> CreateBoneMap(Transform sourceSkeleton, Transform targetSkeleton, List<string> sourceBoneNames, List<string> targetBoneNames = null) { if ((Object)(object)sourceSkeleton == (Object)null || (Object)(object)targetSkeleton == (Object)null || sourceBoneNames == null) { return null; } if (targetBoneNames == null) { targetBoneNames = sourceBoneNames; } if (sourceBoneNames.Count != targetBoneNames.Count) { Plugin.LogError("Attempted to map humanoid skeleton, but passed two sets of bone names with differing sizes."); return null; } int count = sourceBoneNames.Count; Transform[] array = (Transform[])(object)new Transform[count]; Transform[] array2 = (Transform[])(object)new Transform[count]; FindBones(sourceSkeleton, sourceBoneNames, array); FindBones(targetSkeleton, targetBoneNames, array2); Dictionary<Transform, Transform> dictionary = new Dictionary<Transform, Transform>(); for (int i = 0; i < count; i++) { if ((Object)(object)array[i] != (Object)null && !dictionary.ContainsKey(array[i])) { dictionary.Add(array[i], array2[i]); } } return dictionary; } private static void FindBones(Transform bone, List<string> boneNames, Transform[] boneArray) { if ((Object)(object)((Component)bone).GetComponent<Rig>() != (Object)null || ((Object)bone).name == "ScavengerModelArmsOnly") { return; } if (boneNames.Contains(((Object)bone).name)) { int num = boneNames.IndexOf(((Object)bone).name); if (!((Object)(object)boneArray[num] != (Object)null)) { boneArray[num] = bone; } } for (int i = 0; i < bone.childCount; i++) { FindBones(bone.GetChild(i), boneNames, boneArray); } } } [HarmonyPatch] public class EmoteControllerMaskedEnemy : EmoteController { public static Dictionary<MaskedPlayerEnemy, EmoteControllerMaskedEnemy> allMaskedEnemyEmoteControllers = new Dictionary<MaskedPlayerEnemy, EmoteControllerMaskedEnemy>(); public MaskedPlayerEnemy maskedEnemy; public int emoteCount = 0; public bool stoppedAndStaring = false; public bool behaviour1 = false; public Vector3 emotedAtPosition; public int id => (int)((NetworkBehaviour)maskedEnemy).NetworkObjectId; public float stopAndStareTimer { get { return (float)Traverse.Create((object)maskedEnemy).Field("stopAndStareTimer").GetValue(); } set { Traverse.Create((object)maskedEnemy).Field("stopAndStareTimer").SetValue((object)value); } } public NavMeshAgent agent => ((EnemyAI)maskedEnemy).agent; public PlayerControllerB lookingAtPlayer { get { Transform stareAtTransform = maskedEnemy.stareAtTransform; return (stareAtTransform != null) ? ((Component)stareAtTransform).GetComponentInParent<PlayerControllerB>() : null; } } public bool inKillAnimation => (bool)Traverse.Create((object)maskedEnemy).Field("inKillAnimation").GetValue(); public bool handsOut => (bool)Traverse.Create((object)maskedEnemy).Field("handsOut").GetValue(); public float localSpeed { get { //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) Vector3 val = (Vector3)Traverse.Create((object)maskedEnemy).Field("agentLocalVelocity").GetValue(); return ((Vector3)(ref val)).magnitude; } } public bool isMoving => animator.GetBool("IsMoving"); protected override void Awake() { base.Awake(); if (!initialized) { return; } try { maskedEnemy = ((Component)this).GetComponentInParent<MaskedPlayerEnemy>(); if ((Object)(object)maskedEnemy == (Object)null) { Plugin.LogError("Failed to find MaskedPlayerEnemy component in parent of EmoteControllerMaskedEnemy."); } else { allMaskedEnemyEmoteControllers.Add(maskedEnemy, this); } } catch (Exception ex) { Debug.LogError((object)("Failed to initialize EmoteControllerMaskedEnemy. Error: " + ex)); } } protected override void OnDestroy() { base.OnDestroy(); allMaskedEnemyEmoteControllers?.Remove(maskedEnemy); } protected override bool CheckIfShouldStopEmoting() { //IL_0068: 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) if (!isPerformingEmote) { return false; } if (base.CheckIfShouldStopEmoting()) { return true; } return ((EnemyAI)maskedEnemy).isEnemyDead || (NetworkManager.Singleton.IsServer && (agent.speed > 0f || stopAndStareTimer <= 0f)) || (!NetworkManager.Singleton.IsServer && Vector3.Distance(emotedAtPosition, ((Component)maskedEnemy).transform.position) > 0.01f) || inKillAnimation; } public override bool IsPerformingCustomEmote() { return base.IsPerformingCustomEmote(); } public override bool CanPerformEmote() { return base.CanPerformEmote() && (Object)(object)lookingAtPlayer != (Object)null && (!NetworkManager.Singleton.IsServer || stopAndStareTimer >= 2f) && !inKillAnimation && ((NetworkManager.Singleton.IsServer && agent.speed == 0f) || (!NetworkManager.Singleton.IsServer && !isMoving)) && !((EnemyAI)maskedEnemy).isEnemyDead; } public override void PerformEmote(UnlockableEmote emote, AnimationClip overrideAnimationClip = null, float playAtTimeNormalized = 0f) { //IL_0030: 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) base.PerformEmote(emote, overrideAnimationClip, playAtTimeNormalized); if (isPerformingEmote) { emoteCount++; emotedAtPosition = ((Component)maskedEnemy).transform.position; } } public override void StopPerformingEmote() { base.StopPerformingEmote(); stoppedAndStaring = false; } protected override void CreateBoneMap() { boneMap = BoneMapper.CreateBoneMap(humanoidSkeleton, metarig, EmoteControllerPlayer.sourceBoneNames); } protected override ulong GetEmoteControllerId() { return ((Object)(object)maskedEnemy != (Object)null) ? ((NetworkBehaviour)maskedEnemy).NetworkObjectId : 0; } protected override string GetEmoteControllerName() { return ((Object)(object)maskedEnemy != (Object)null) ? ((Object)maskedEnemy).name : base.GetEmoteControllerName(); } } public class EmoteControllerPlayer : EmoteController { public static Dictionary<PlayerControllerB, EmoteControllerPlayer> allPlayerEmoteControllers = new Dictionary<PlayerControllerB, EmoteControllerPlayer>(); public PlayerControllerB playerController; public static List<string> sourceBoneNames = new List<string> { "spine", "spine.001", "spine.002", "spine.003", "spine.004", "CameraContainer", "shoulder.L", "arm.L_upper", "arm.L_lower", "hand.L", "finger1.L", "finger1.L.001", "finger2.L", "finger2.L.001", "finger3.L", "finger3.L.001", "finger4.L", "finger4.L.001", "finger5.L", "finger5.L.001", "shoulder.R", "arm.R_upper", "arm.R_lower", "hand.R", "finger1.R", "finger1.R.001", "finger2.R", "finger2.R.001", "finger3.R", "finger3.R.001", "finger4.R", "finger4.R.001", "finger5.R", "finger5.R.001", "thigh.L", "shin.L", "foot.L", "heel.02.L", "toe.L", "thigh.R", "shin.R", "foot.R", "heel.02.R", "toe.R" }; public static PlayerControllerB localPlayerController => StartOfRound.Instance?.localPlayerController; public static EmoteControllerPlayer emoteControllerLocal => ((Object)(object)localPlayerController != (Object)null && allPlayerEmoteControllers.ContainsKey(localPlayerController)) ? allPlayerEmoteControllers[localPlayerController] : null; public bool isLocalPlayer => (Object)(object)playerController == (Object)(object)StartOfRound.Instance?.localPlayerController; public ulong clientId => playerController.actualClientId; public ulong playerId => playerController.playerClientId; public ulong steamId => playerController.playerSteamId; public string username => playerController.playerUsername; public float timeSinceStartingEmote { get { return (float)Traverse.Create((object)playerController).Field("timeSinceStartingEmote").GetValue(); } set { Traverse.Create((object)playerController).Field("timeSinceStartingEmote").SetValue((object)value); } } protected override void Awake() { base.Awake(); if (!initialized) { return; } try { playerController = ((Component)this).GetComponentInParent<PlayerControllerB>(); if ((Object)(object)playerController == (Object)null) { Plugin.LogError("Failed to find PlayerControllerB component in parent of EmoteControllerPlayer."); } else { allPlayerEmoteControllers.Add(playerController, this); } } catch (Exception ex) { Debug.LogError((object)("Failed to initialize EmoteControllerPlayer: " + ((Object)playerController).name + ". Error: " + ex)); } } protected override void Start() { base.Start(); } protected override void OnDestroy() { base.OnDestroy(); allPlayerEmoteControllers?.Remove(playerController); } protected override void Update() { if (initialized && !((Object)(object)playerController == (Object)null) && (!((Object)(object)playerController == (Object)(object)localPlayerController) || (!ConfigSettings.disableEmotesForSelf.Value && !LCVR_Patcher.Enabled))) { base.Update(); } } protected override void LateUpdate() { //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) if (!initialized || (Object)(object)playerController == (Object)null || ((Object)(object)playerController == (Object)(object)localPlayerController && (ConfigSettings.disableEmotesForSelf.Value || LCVR_Patcher.Enabled))) { return; } bool flag = isPerformingEmote; base.LateUpdate(); if (flag && !isPerformingEmote && playerController.performingEmote) { playerController.performingEmote = false; originalAnimator.SetInteger("emoteNumber", 0); AnimatorStateInfo currentAnimatorStateInfo = originalAnimator.GetCurrentAnimatorStateInfo(0); animator.Play(((AnimatorStateInfo)(ref currentAnimatorStateInfo)).fullPathHash, 0, 0f); if (isLocalPlayer) { timeSinceStartingEmote = 0f; playerController.StopPerformingEmoteServerRpc(); } } } protected override void TranslateAnimation() { if (initialized && !((Object)(object)playerController == (Object)null)) { base.TranslateAnimation(); } } protected override bool CheckIfShouldStopEmoting() { if ((Object)(object)playerController == (Object)null || !isPerformingEmote) { return false; } return base.CheckIfShouldStopEmoting() || !playerController.performingEmote || performingEmote == null; } public override bool IsPerformingCustomEmote() { return base.IsPerformingCustomEmote() && playerController.performingEmote; } public void TryPerformingEmoteLocal(UnlockableEmote emote) { if (!initialized || ConfigSettings.disableEmotesForSelf.Value || LCVR_Patcher.Enabled) { return; } if (!isLocalPlayer) { Plugin.LogWarning("Cannot run TryPerformEmoteLocal on a character who does not belong to the local player. This is not allowed."); return; } Plugin.Log("Attempting to emote for player: " + ((Object)playerController).name); if (CanPerformEmote()) { if (emote.randomEmotePool != null && emote.randomEmotePool.Count > 0) { emote = emote.randomEmotePool[Random.Range(0, emote.randomEmotePool.Count)]; } PerformEmote(emote); playerController.StartPerformingEmoteServerRpc(); SyncPerformingEmoteManager.SendPerformingEmoteUpdateToServer(emote); timeSinceStartingEmote = 0f; playerController.performingEmote = true; originalAnimator.SetInteger("emoteNumber", 1); } } public void TrySyncingEmoteWithEmoteController(EmoteController emoteController) { if (!initialized || (Object)(object)emoteController == (Object)null || ConfigSettings.disableEmotesForSelf.Value || LCVR_Patcher.Enabled) { return; } if (!isLocalPlayer) { Plugin.LogWarning("Cannot run TrySyncingEmoteWithEmoteController on a character who does not belong to the local player. This is not allowed."); return; } Plugin.Log("Attempting to sync emote for player: " + ((Object)playerController).name + " with emote controller with id: " + emoteController.emoteControllerId); if (CanPerformEmote() && emoteController.IsPerformingCustomEmote()) { SyncWithEmoteController(emoteController); playerController.StartPerformingEmoteServerRpc(); SyncPerformingEmoteManager.SendSyncEmoteUpdateToServer(emoteController); timeSinceStartingEmote = 0f; playerController.performingEmote = true; originalAnimator.SetInteger("emoteNumber", 1); } } public override bool CanPerformEmote() { if (!isLocalPlayer) { return true; } if (!initialized || ConfigSettings.disableEmotesForSelf.Value || LCVR_Patcher.Enabled) { return false; } bool flag = base.CanPerformEmote(); MethodInfo method = ((object)playerController).GetType().GetMethod("CheckConditionsForEmote", BindingFlags.Instance | BindingFlags.NonPublic); flag &= (bool)method.Invoke(playerController, new object[0]); bool flag2 = (Object)(object)playerController.inAnimationWithEnemy == (Object)null && (!isLocalPlayer || !CentipedePatcher.IsCentipedeLatchedOntoLocalPlayer()); return flag && flag2; } public override void PerformEmote(UnlockableEmote emote, AnimationClip overrideAnimationClip = null, float playAtTimeNormalized = 0f) { if ((Object)(object)playerController == (Object)null || (isLocalPlayer && (ConfigSettings.disableEmotesForSelf.Value || LCVR_Patcher.Enabled))) { return; } base.PerformEmote(emote, overrideAnimationClip, playAtTimeNormalized); if (isPerformingEmote) { playerController.performingEmote = true; originalAnimator.SetInteger("emoteNumber", 0); if (isLocalPlayer) { ThirdPersonEmoteController.OnStartCustomEmoteLocal(); } } } public override void StopPerformingEmote() { if (!((Object)(object)playerController == (Object)null) && (!isLocalPlayer || (!ConfigSettings.disableEmotesForSelf.Value && !LCVR_Patcher.Enabled))) { base.StopPerformingEmote(); if (isLocalPlayer) { ThirdPersonEmoteController.OnStopCustomEmoteLocal(); } } } protected override void CreateBoneMap() { boneMap = BoneMapper.CreateBoneMap(humanoidSkeleton, metarig, sourceBoneNames); } protected override ulong GetEmoteControllerId() { return ((Object)(object)playerController != (Object)null) ? ((NetworkBehaviour)playerController).NetworkObjectId : 0; } protected override string GetEmoteControllerName() { return ((Object)(object)playerController != (Object)null) ? playerController.playerUsername : base.GetEmoteControllerName(); } } [HarmonyPatch] public class EmoteController : MonoBehaviour { public static Dictionary<GameObject, EmoteController> allEmoteControllers = new Dictionary<GameObject, EmoteController>(); public bool initialized = false; public Transform metarig; protected Vector3 originalMetarigLocalPosition = Vector3.zero; public Animator originalAnimator; public Transform humanoidSkeleton; public Animator animator; public AnimatorOverrideController animatorController; protected bool isPerformingEmote = false; public UnlockableEmote performingEmote; public List<Transform> groundContactPoints = new List<Transform>(); protected Dictionary<Transform, Transform> boneMap; public ulong emoteControllerId => GetEmoteControllerId(); public string emoteControllerName => GetEmoteControllerName(); public float normalizedTimeAnimation { get { //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); return ((AnimatorStateInfo)(ref currentAnimatorStateInfo)).normalizedTime; } } public bool isSimpleEmoteController => ((object)this).GetType() == typeof(EmoteController); protected virtual void Awake() { //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Expected O, but got Unknown //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) //IL_0162: Unknown result type (might be due to invalid IL or missing references) //IL_0167: Unknown result type (might be due to invalid IL or missing references) //IL_016c: 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) if ((Object)(object)Plugin.humanoidSkeletonPrefab == (Object)null || (Object)(object)Plugin.humanoidAnimatorController == (Object)null || (Object)(object)Plugin.humanoidAvatar == (Object)null) { return; } try { if ((Object)(object)originalAnimator == (Object)null) { Animator[] componentsInChildren = ((Component)this).GetComponentsInChildren<Animator>(); foreach (Animator val in componentsInChildren) { if (((Object)val).name == "metarig") { originalAnimator = val; break; } } } if ((Object)(object)originalAnimator == (Object)null) { Debug.LogError((object)"Failed to find animator component in children. Make sure you place this component on one of the parents of this character's metarig."); return; } metarig = ((Component)originalAnimator).transform; originalMetarigLocalPosition = metarig.localPosition; humanoidSkeleton = Object.Instantiate<GameObject>(Plugin.humanoidSkeletonPrefab, metarig.parent).transform; ((Object)humanoidSkeleton).name = "HumanoidSkeleton"; humanoidSkeleton.SetSiblingIndex(metarig.GetSiblingIndex() + 1); animator = ((Component)humanoidSkeleton).GetComponentInChildren<Animator>(); animatorController = new AnimatorOverrideController(Plugin.humanoidAnimatorController); animator.runtimeAnimatorController = (RuntimeAnimatorController)(object)animatorController; humanoidSkeleton.SetLocalPositionAndRotation(metarig.localPosition + Vector3.down * 0.025f, Quaternion.identity); humanoidSkeleton.localScale = metarig.localScale; allEmoteControllers.Add(((Component)this).gameObject, this); initialized = true; } catch (Exception ex) { Debug.LogError((object)("Failed to initialize EmoteController. Error: " + ex)); } } protected virtual void Start() { if (initialized) { if (!isSimpleEmoteController) { CreateBoneMap(); } else { Debug.LogWarning((object)"Using the base emote controller. Remember that when doing this, the bonemap will need to be built manually."); } } } protected virtual void OnEnable() { } protected virtual void OnDisable() { if (initialized && isPerformingEmote) { StopPerformingEmote(); } } protected virtual void OnDestroy() { allEmoteControllers?.Remove(((Component)this).gameObject); } protected virtual void Update() { if (initialized) { } } protected virtual void LateUpdate() { if (initialized) { if (isPerformingEmote && CheckIfShouldStopEmoting()) { Plugin.LogWarning("OnCheckIfShouldStopEmoting. Stopping emote. " + ((Object)this).name + " NormTime: " + normalizedTimeAnimation); StopPerformingEmote(); } if (!((Object)(object)animator == (Object)null) && !((Object)(object)animatorController == (Object)null) && boneMap != null && isPerformingEmote) { TranslateAnimation(); } } } protected virtual void TranslateAnimation() { //IL_0061: 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) if (boneMap == null || performingEmote == null || boneMap.Count <= 0) { return; } foreach (KeyValuePair<Transform, Transform> item in boneMap) { Transform key = item.Key; Transform value = item.Value; ((Component)value).transform.position = ((Component)key).transform.position; ((Component)value).transform.rotation = ((Component)key).transform.rotation; } } protected virtual bool CheckIfShouldStopEmoting() { if (isPerformingEmote) { return performingEmote == null || (!performingEmote.loopable && !performingEmote.isPose && normalizedTimeAnimation >= 1f); } return false; } protected virtual void CorrectVerticalPosition() { //IL_0037: 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_008c: 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_00ae: 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) if (groundContactPoints == null) { return; } float num = 0f; foreach (Transform groundContactPoint in groundContactPoints) { num = Mathf.Min(num, ((Component)groundContactPoint).transform.position.y - metarig.position.y); } if (num < 0f) { metarig.position = new Vector3(metarig.position.x, metarig.position.y - num, metarig.position.z); } } public virtual bool IsPerformingCustomEmote() { return isPerformingEmote && performingEmote != null; } public virtual bool CanPerformEmote() { return (Object)(object)animator != (Object)null && ((Behaviour)animator).enabled; } public virtual void PerformEmote(UnlockableEmote emote, AnimationClip overrideAnimationClip = null, float playAtTimeNormalized = 0f) { if (!initialized || !CanPerformEmote()) { return; } AnimationClip val = emote.animationClip; if ((Object)(object)overrideAnimationClip != (Object)null) { if (emote == null) { Debug.LogError((object)"Failed to perform emote with overrideAnimationClip while passed emote is null."); return; } if (!emote.ClipIsInEmote(overrideAnimationClip)) { Debug.LogError((object)("Failed to perform emote where overrideAnimationClip is not the start or loop clip of the passed emote. Clip: " + ((Object)overrideAnimationClip).name + " Emote: " + emote.emoteName)); return; } val = overrideAnimationClip; } playAtTimeNormalized %= 1f; if (!isSimpleEmoteController) { Plugin.Log("[" + ((Object)this).name + "] Performing emote: " + emote.emoteName + (((Object)(object)val == (Object)(object)overrideAnimationClip) ? (" OverrideClip: " + ((Object)val).name) : "") + ((playAtTimeNormalized > 0f) ? (" PlayAtTime: " + playAtTimeNormalized) : "")); } animator.avatar = (emote.humanoidAnimation ? Plugin.humanoidAvatar : null); animatorController["emote"] = emote.animationClip; if ((Object)(object)emote.transitionsToClip != (Object)null) { animatorController["emote_loop"] = emote.transitionsToClip; } animator.SetBool("loop", (Object)(object)emote.transitionsToClip != (Object)null); animator.Play(((Object)(object)val == (Object)(object)emote.transitionsToClip) ? "emote_loop" : "emote", 0, playAtTimeNormalized); performingEmote = emote; isPerformingEmote = true; } public void PerformEmoteDelayed(UnlockableEmote emote, float delayForSeconds, AnimationClip overrideAnimationClip = null, float playAtTimeNormalized = 0f) { ((MonoBehaviour)this).StartCoroutine(PerformAfterDelay()); IEnumerator PerformAfterDelay() { yield return (object)new WaitForSeconds(delayForSeconds); if (CanPerformEmote()) { PerformEmote(emote, overrideAnimationClip, playAtTimeNormalized); } } } public void SyncWithEmoteController(EmoteController emoteController) { if (!((Object)(object)emoteController == (Object)null) && emoteController.IsPerformingCustomEmote()) { if (!isSimpleEmoteController) { Plugin.Log("[" + ((Object)this).name + "] Attempting to sync with emote controller: " + ((Object)emoteController).name + " Emote: " + emoteController.performingEmote.emoteName + " PlayEmoteAtTimeNormalized: " + emoteController.normalizedTimeAnimation % 1f); } PerformEmote(emoteController.performingEmote, emoteController.GetCurrentAnimationClip(), emoteController.normalizedTimeAnimation); } } public virtual void StopPerformingEmote() { //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_005b: 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) if (!isSimpleEmoteController) { Plugin.Log(string.Format("[" + ((Object)this).name + "] Stopping emote.")); } isPerformingEmote = false; metarig.localPosition = new Vector3(metarig.localPosition.x, 0f, metarig.localPosition.z); } public AnimationClip GetCurrentAnimationClip() { //IL_0043: 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) if (!IsPerformingCustomEmote()) { return null; } if (!animator.GetBool("loop")) { return animatorController["emote"]; } AnimatorStateInfo currentAnimatorStateInfo = animator.GetCurrentAnimatorStateInfo(0); return animatorController[((AnimatorStateInfo)(ref currentAnimatorStateInfo)).IsName("emote_loop") ? "emote_loop" : "emote"]; } protected virtual void CreateBoneMap() { } protected virtual ulong GetEmoteControllerId() { return 0uL; } protected virtual string GetEmoteControllerName() { return ((Object)this).name; } } [HarmonyPatch] public static class EmoteMenuManager { public static GameObject menuGameObject; public static RectTransform menuTransform; public static CanvasGroup canvasGroup; public static RawImage renderTextureImageUI; public static TextMeshPro swapPageText; public static TextMeshPro currentEmoteText; public static RenderTexture renderTexture; public static Camera renderingCamera; public static GameObject previewPlayerObject; public static SkinnedMeshRenderer previewPlayerMesh; public static Animator previewPlayerAnimator; public static AnimatorOverrideController previewPlayerAnimatorController; public static int playerLayer = LayerMask.NameToLayer("Player"); public static float hoveredAlpha = 0.75f; public static float unhoveredAlpha = 0.75f; public static Color defaultUIColor = new Color(0.3f, 0.3f, 0.3f); public static List<EmoteUIElement> emoteUIElementsList; public static int hoveredEmoteUIIndex = -1; public static int currentPage = 0; public static List<EmoteLoadoutUIElement> emoteLoadoutUIElementsList; public static List<List<UnlockableEmote>> emoteLoadouts; public static Color selectedLoadoutUIColor = new Color(0.2f, 0.2f, 1f); public static int currentLoadoutIndex = -1; public static int hoveredLoadoutUIIndex = -1; public static Vector2 currentThumbstickPosition = Vector2.zero; public static TextMeshProUGUI[] controlTipLines; private static bool firstTimeOpeningMenu; public static QuickMenuManager quickMenuManager => StartOfRound.Instance?.localPlayerController?.quickMenuManager; public static PlayerControllerB localPlayerController => StartOfRound.Instance?.localPlayerController; public static int playerLayerMask => 1 << playerLayer; public static int hoveredEmoteIndex => (hoveredEmoteUIIndex >= 0) ? (hoveredEmoteUIIndex + 8 * currentPage) : (-1); public static int numPages => (currentLoadoutEmotesList != null) ? (Mathf.Max((currentLoadoutEmotesList.Count - 1) / emoteUIElementsList.Count, 0) + 1) : 0; public static UnlockableEmote previewingEmote => (currentLoadoutEmotesList != null && hoveredEmoteIndex >= 0 && hoveredEmoteIndex < currentLoadoutEmotesList.Count) ? currentLoadoutEmotesList[hoveredEmoteIndex] : null; public static List<UnlockableEmote> currentLoadoutEmotesList => (emoteLoadouts != null && currentLoadoutIndex >= 0 && currentLoadoutIndex < emoteLoadouts.Count) ? emoteLoadouts[currentLoadoutIndex] : null; public static int numLoadouts => emoteLoadouts.Count; public static bool usingController => StartOfRound.Instance.localPlayerUsingController; public static bool isMenuOpen => (Object)(object)menuGameObject != (Object)null && menuGameObject.activeSelf; [HarmonyPatch(typeof(HUDManager), "Start")] [HarmonyPostfix] public static void InitializeUI(HUDManager __instance) { //IL_014e: 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_0199: Unknown result type (might be due to invalid IL or missing references) if (!ConfigSettings.disableEmotesForSelf.Value && !LCVR_Patcher.Enabled && !((Object)(object)Plugin.radialMenuPrefab == (Object)null)) { firstTimeOpeningMenu = true; menuGameObject = Object.Instantiate<GameObject>(Plugin.radialMenuPrefab, __instance.HUDContainer.transform.parent); menuGameObject.transform.SetAsLastSibling(); ((Object)menuGameObject).name = "EmotesRadialMenu"; menuTransform = menuGameObject.GetComponent<RectTransform>(); renderTextureImageUI = menuGameObject.GetComponentInChildren<RawImage>(); Transform transform = ((Component)((Transform)menuTransform).Find("RadialMenuUI/RadialElements")).transform; swapPageText = ((Component)((Transform)menuTransform).Find("RadialMenuUI/RadialBase/SwapPageText")).GetComponent<TextMeshPro>(); currentEmoteText = ((Component)((Transform)menuTransform).Find("RadialMenuUI/RadialBase/CurrentEmoteText")).GetComponent<TextMeshPro>(); ((TMP_Text)currentEmoteText).text = ""; emoteUIElementsList = new List<EmoteUIElement>(); controlTipLines = (TextMeshProUGUI[])(object)new TextMeshProUGUI[HUDManager.Instance.controlTipLines.Length]; for (int i = 0; i < HUDManager.Instance.controlTipLines.Length; i++) { TextMeshProUGUI val = Object.Instantiate<TextMeshProUGUI>(HUDManager.Instance.controlTipLines[i], ((TMP_Text)HUDManager.Instance.controlTipLines[0]).transform.parent); ((TMP_Text)val).transform.localScale = ((TMP_Text)HUDManager.Instance.controlTipLines[0]).transform.localScale; ((TMP_Text)val).transform.parent = (Transform)(object)menuTransform; ((TMP_Text)val).transform.SetPositionAndRotation(((TMP_Text)HUDManager.Instance.controlTipLines[i]).transform.position, ((TMP_Text)HUDManager.Instance.controlTipLines[i]).transform.rotation); ((TMP_Text)val).text = ""; ((TMP_Text)val).overflowMode = (TextOverflowModes)0; ((TMP_Text)val).enableWordWrapping = false; controlTipLines[i] = val; } currentPage = 0; hoveredEmoteUIIndex = -1; for (int j = 0; j < transform.childCount; j++) { Transform child = transform.GetChild(j); EmoteUIElement item = new EmoteUIElement { uiGameObject = ((Component)child).gameObject, id = j, backgroundImage = ((Component)child).GetComponentInChildren<Image>(), textContainer = ((Component)child).GetComponentInChildren<TextMeshPro>() }; emoteUIElementsList.Add(item); } EmoteLoadoutUIElement.uiCount = 0; Transform transform2 = ((Component)((Transform)menuTransform).Find("RadialMenuUI/EmoteLoadouts")).transform; ((Component)transform2).gameObject.AddComponent<EmoteLoadoutUIContainer>(); emoteLoadoutUIElementsList = new List<EmoteLoadoutUIElement>(); emoteLoadoutUIElementsList.Add(((Component)transform2.GetChild(0)).gameObject.AddComponent<EmoteLoadoutUIElement>()); emoteLoadoutUIElementsList.Add(Object.Instantiate<EmoteLoadoutUIElement>(emoteLoadoutUIElementsList[0], transform2)); emoteLoadoutUIElementsList.Add(Object.Instantiate<EmoteLoadoutUIElement>(emoteLoadoutUIElementsList[0], transform2)); emoteLoadoutUIElementsList.Add(Object.Instantiate<EmoteLoadoutUIElement>(emoteLoadoutUIElementsList[0], transform2)); emoteLoadoutUIElementsList.Add(Object.Instantiate<EmoteLoadoutUIElement>(emoteLoadoutUIElementsList[0], transform2)); emoteLoadoutUIElementsList.Add(Object.Instantiate<EmoteLoadoutUIElement>(emoteLoadoutUIElementsList[0], transform2)); emoteLoadoutUIElementsList.Add(Object.Instantiate<EmoteLoadoutUIElement>(emoteLoadoutUIElementsList[0], transform2)); for (int k = 0; k < emoteLoadoutUIElementsList.Count; k++) { ((Object)emoteLoadoutUIElementsList[k]).name = "EmoteLoadout_" + k; } emoteLoadoutUIElementsList[0].loadoutName = "Favorites"; emoteLoadoutUIElementsList[1].loadoutName = $"<color={UnlockableEmote.rarityColorCodes[3]}>Legendary</color>"; emoteLoadoutUIElementsList[2].loadoutName = $"<color={UnlockableEmote.rarityColorCodes[2]}>Epic</color>"; emoteLoadoutUIElementsList[3].loadoutName = $"<color={UnlockableEmote.rarityColorCodes[1]}>Rare</color>"; emoteLoadoutUIElementsList[4].loadoutName = $"<color={UnlockableEmote.rarityColorCodes[0]}>Common</color>"; emoteLoadoutUIElementsList[5].loadoutName = "Complementary"; emoteLoadoutUIElementsList[6].loadoutName = "All"; SaveManager.LoadFavoritedEmotes(); emoteLoadouts = new List<List<UnlockableEmote>> { SessionManager.unlockedFavoriteEmotes, SessionManager.unlockedEmotesTier3, SessionManager.unlockedEmotesTier2, SessionManager.unlockedEmotesTier1, SessionManager.unlockedEmotesTier0, EmotesManager.complementaryEmotes, SessionManager.unlockedEmotes }; if (currentLoadoutIndex < 0 || currentLoadoutIndex >= emoteLoadouts.Count) { currentLoadoutIndex = emoteLoadouts.Count - 1; } InitializeAnimationRenderer(); menuGameObject.SetActive(false); } } [HarmonyPatch(typeof(HUDManager), "Update")] [HarmonyPostfix] public static void GetInput() { //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: 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_008a: 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_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: 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_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: 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 (ConfigSettings.disableEmotesForSelf.Value || LCVR_Patcher.Enabled || (Object)(object)previewPlayerAnimatorController == (Object)null || !isMenuOpen) { return; } if (EmoteLoadoutUIContainer.hovered || hoveredLoadoutUIIndex != -1) { if (hoveredEmoteUIIndex != -1) { OnHoveredNewElement(-1); } return; } Vector2 val3; if (!usingController) { Vector2 val = ((InputControl<Vector2>)(object)((Pointer)Mouse.current).position).ReadValue(); Vector2 val2 = default(Vector2); ((Vector2)(ref val2))..ctor((float)(Screen.width / 2), (float)(Screen.height / 2)); val3 = val - val2; } else { val3 = currentThumbstickPosition; } int num = -1; if ((!usingController && ((Vector2)(ref val3)).magnitude / (float)Screen.height >= 0.17f) || (usingController && currentThumbstickPosition != Vector2.zero)) { float num2 = Mathf.Atan2(val3.y, 0f - val3.x) * 57.29578f - 67.5f; if (num2 < 0f) { num2 += 360f; } num = Mathf.FloorToInt(num2 / 45f); } if (num != hoveredEmoteUIIndex) { OnHoveredNewElement(num); } } public static void OnUpdateThumbStickAngle(CallbackContext context) { //IL_0049: 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_006b: 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_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0085: 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) if (!((Object)(object)localPlayerController == (Object)null) && !ConfigSettings.disableEmotesForSelf.Value && !LCVR_Patcher.Enabled && ((CallbackContext)(ref context)).performed && !ConfigSync.instance.syncEnableMovingWhileEmoting && isMenuOpen) { currentThumbstickPosition = ((CallbackContext)(ref context)).ReadValue<Vector2>(); currentThumbstickPosition = ((((Vector2)(ref currentThumbstickPosition)).magnitude > 0.75f) ? currentThumbstickPosition : Vector2.zero); StartOfRound.Instance.localPlayerUsingController = true; if (currentThumbstickPosition == Vector2.zero && previewingEmote != null) { localPlayerController.PerformEmote(context, -(previewingEmote.emoteId + 1)); CloseEmoteMenu(); } } } public static void OnHoveredNewLoadoutElement(int index) { if (hoveredLoadoutUIIndex == index) { return; } hoveredLoadoutUIIndex = index; foreach (EmoteLoadoutUIElement emoteLoadoutUIElements in emoteLoadoutUIElementsList) { emoteLoadoutUIElements.OnHover(emoteLoadoutUIElements.id == index); } } public static void OnHoveredNewElement(int index) { if (hoveredEmoteUIIndex != -1 && hoveredEmoteUIIndex != index) { emoteUIElementsList[hoveredEmoteUIIndex].OnHover(hovered: false); } if (index != -1) { emoteUIElementsList[index].OnHover(); } hoveredEmoteUIIndex = index; SetPreviewAnimation(hoveredEmoteIndex); } public static void SwapPrevPage() { hoveredEmoteUIIndex = -1; currentPage--; currentPage = ((currentPage < 0) ? (numPages - 1) : currentPage); UpdateEmoteWheel(); } public static void SwapNextPage() { hoveredEmoteUIIndex = -1; currentPage = (currentPage + 1) % numPages; UpdateEmoteWheel(); } public static void UpdateControlTipLines() { int num = (usingController ? 1 : 0); string keybindDisplayName = KeybindDisplayNames.GetKeybindDisplayName(Keybinds.PrevEmotePageAction); string keybindDisplayName2 = KeybindDisplayNames.GetKeybindDisplayName(Keybinds.NextEmotePageAction); string keybindDisplayName3 = KeybindDisplayNames.GetKeybindDisplayName(Keybinds.NextEmoteLoadoutUpAction); string keybindDisplayName4 = KeybindDisplayNames.GetKeybindDisplayName(Keybinds.NextEmoteLoadoutDownAction); string keybindDisplayName5 = KeybindDisplayNames.GetKeybindDisplayName(Keybinds.FavoriteEmoteAction); int i = 0; if (!usingController) { ((TMP_Text)controlTipLines[i++]).text = "Swap Page: [Scroll Mouse]"; } else if (keybindDisplayName != "" || keybindDisplayName2 != "") { ((TMP_Text)controlTipLines[i++]).text = $"Swap Page: [{keybindDisplayName}/{keybindDisplayName2}]"; } if (usingController || keybindDisplayName3 != "" || keybindDisplayName4 != "") { ((TMP_Text)controlTipLines[i++]).text = $"Swap Loadout: [{keybindDisplayName3}/{keybindDisplayName4}]"; } ((TMP_Text)controlTipLines[i++]).text = $"Favorite Emote: [{keybindDisplayName5}]"; for (; i < controlTipLines.Length; i++) { ((TMP_Text)controlTipLines[i]).text = ""; } } public static void UpdateEmoteWheel() { //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_017c: Unknown result type (might be due to invalid IL or missing references) //IL_017e: Unknown result type (might be due to invalid IL or missing references) currentPage = Mathf.Clamp(currentPage, 0, numPages - 1); ((TMP_Text)swapPageText).text = $"Page [{currentPage + 1} / {numPages}]"; for (int i = 0; i < emoteLoadoutUIElementsList.Count; i++) { EmoteLoadoutUIElement emoteLoadoutUIElement = emoteLoadoutUIElementsList[i]; emoteLoadoutUIElement.OnHover(hoveredLoadoutUIIndex == emoteLoadoutUIElement.id); } for (int j = 0; j < emoteLoadouts.Count; j++) { List<UnlockableEmote> list = emoteLoadouts[j]; EmoteLoadoutUIElement emoteLoadoutUIElement2 = emoteLoadoutUIElementsList[j]; ((TMP_Text)emoteLoadoutUIElement2.textContainer).text = emoteLoadoutUIElement2.loadoutName + " [" + list.Count + "]"; } for (int k = 0; k < emoteUIElementsList.Count; k++) { EmoteUIElement emoteUIElement = emoteUIElementsList[k]; int num = k + 8 * currentPage; ((TMP_Text)emoteUIElement.textContainer).text = ""; emoteUIElement.emote = null; Color baseColor = defaultUIColor; if (num < currentLoadoutEmotesList.Count) { UnlockableEmote unlockableEmote = currentLoadoutEmotesList[num]; if (unlockableEmote != null) { emoteUIElement.emote = unlockableEmote; ((TMP_Text)emoteUIElement.textContainer).text = unlockableEmote.displayName; } } emoteUIElement.baseColor = baseColor; emoteUIElement.OnHover(hovered: false); } if (hoveredEmoteUIIndex >= 0 && hoveredEmoteUIIndex < 8) { OnHoveredNewElement(hoveredEmoteUIIndex); } } public static void SetPreviewAnimation(int emoteIndex) { if (emoteIndex >= 0 && emoteIndex < currentLoadoutEmotesList.Count && currentLoadoutEmotesList[emoteIndex] != null) { UnlockableEmote unlockableEmote = currentLoadoutEmotesList[emoteIndex]; previewPlayerObject.SetActive(true); ((Behaviour)renderingCamera).enabled = true; previewPlayerAnimatorController["emote"] = unlockableEmote.animationClip; if ((Object)(object)unlockableEmote.transitionsToClip != (Object)null) { previewPlayerAnimatorController["emote_loop"] = unlockableEmote.transitionsToClip; } previewPlayerAnimator.SetBool("loop", (Object)(object)unlockableEmote.transitionsToClip != (Object)null); previewPlayerAnimator.Play("emote", 0, 0f); ((TMP_Text)currentEmoteText).text = unlockableEmote.displayNameColorCoded + (EmotesManager.allFavoriteEmotes.Contains(unlockableEmote.emoteName) ? " *" : ""); } else { previewPlayerAnimatorController["emote"] = null; previewPlayerAnimatorController["emote_loop"] = null; previewPlayerObject.SetActive(false); ((TMP_Text)currentEmoteText).text = ""; DisableRenderCameraNextFrame(); } } public static void DisableRenderCameraNextFrame() { ((MonoBehaviour)HUDManager.Instance).StartCoroutine(DisableRenderCameraNextFrameCoroutine()); static IEnumerator DisableRenderCameraNextFrameCoroutine() { yield return null; ((Behaviour)renderingCamera).enabled = false; } } public static void SetCurrentEmoteLoadout(int loadoutIndex) { if (currentLoadoutIndex != loadoutIndex) { currentPage = 0; currentLoadoutIndex = loadoutIndex; UpdateEmoteWheel(); } } public static void ToggleFavoriteHoveredEmote() { if (isMenuOpen && previewingEmote != null) { string emoteName = previewingEmote.emoteName; if (EmotesManager.allFavoriteEmotes.Contains(emoteName)) { EmotesManager.allFavoriteEmotes.Remove(emoteName); } else { EmotesManager.allFavoriteEmotes.Add(emoteName); } SessionManager.UpdateUnlockedFavoriteEmotes(); SaveManager.SaveFavoritedEmotes(); UpdateEmoteWheel(); } } public static void ToggleEmoteMenu() { if (!isMenuOpen) { OpenEmoteMenu(); } else { CloseEmoteMenu(); } } public static void OpenEmoteMenu() { //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) if (firstTimeOpeningMenu) { SetCurrentEmoteLoadout((emoteLoadouts[0].Count <= 0) ? currentLoadoutIndex : 0); firstTimeOpeningMenu = false; } menuGameObject.SetActive(true); Cursor.lockState = (CursorLockMode)0; Cursor.visible = true; quickMenuManager.isMenuOpen = true; ((Renderer)previewPlayerMesh).material = ((Renderer)localPlayerController.thisPlayerModel).material; currentThumbstickPosition = Vector2.zero; TextMeshProUGUI[] array = HUDManager.Instance.controlTipLines; foreach (TextMeshProUGUI val in array) { ((Behaviour)val).enabled = false; } UpdateControlTipLines(); UpdateEmoteWheel(); } public static void CloseEmoteMenu() { Cursor.lockState = (CursorLockMode)1; Cursor.visible = false; localPlayerController.isFreeCamera = false; menuGameObject.SetActive(false); quickMenuManager.CloseQuickMenu(); OnHoveredNewLoadoutElement(-1); TextMeshProUGUI[] array = HUDManager.Instance.controlTipLines; foreach (TextMeshProUGUI val in array) { ((Behaviour)val).enabled = true; } } public static bool CanOpenEmoteMenu() { if ((quickMenuManager.isMenuOpen && !isMenuOpen) || (Object)(object)previewPlayerObject == (Object)null) { return false; } if (localPlayerController.isPlayerDead || localPlayerController.inTerminalMenu || localPlayerController.isTypingChat || localPlayerController.isPlayerDead || localPlayerController.inSpecialInteractAnimation || localPlayerController.isGrabbingObjectAnimation || localPlayerController.inShockingMinigame || localPlayerController.isClimbingLadder || localPlayerController.isSinking || (Object)(object)localPlayerController.inAnimationWithEnemy != (Object)null || CentipedePatcher.IsCentipedeLatchedOntoLocalPlayer()) { return false; } return true; } private static void InitializeAnimationRenderer() { //IL_0006: 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_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Expected O, but got Unknown //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: 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_013b: Unknown result type (might be due to invalid IL or missing references) //IL_0162: Unknown result type (might be due to invalid IL or missing references) //IL_0167: Unknown result type (might be due to invalid IL or missing references) renderingCamera = new GameObject("AnimationRenderingCamera").AddComponent<Camera>(); Object.Destroy((Object)(object)((Component)renderingCamera).GetComponent<AudioListener>()); renderingCamera.cullingMask = playerLayerMask; renderingCamera.clearFlags = (CameraClearFlags)2; renderingCamera.cameraType = (CameraType)4; renderingCamera.backgroundColor = new Color(0.1f, 0.1f, 0.1f, 0f); renderingCamera.allowHDR = false; renderingCamera.allowMSAA = false; renderingCamera.farClipPlane = 5f; renderTexture = new RenderTexture(1024, 1024, 24); renderTexture.format = (RenderTextureFormat)0; renderTexture.graphicsFormat = (GraphicsFormat)8; renderTexture.depthStencilFormat = (GraphicsFormat)92; renderingCamera.targetTexture = renderTexture; ((Component)renderingCamera).transform.position = Vector3.down * 1000f; renderTextureImageUI.texture = (Texture)(object)renderTexture; Light val = new GameObject("Spotlight").AddComponent<Light>(); val.type = (LightType)0; ((Component)val).transform.position = ((Component)renderingCamera).transform.position; ((Component)val).transform.parent = ((Component)renderingCamera).transform; ((Component)val).transform.SetLocalPositionAndRotation(Vector3.zero, Quaternion.identity); val.intensity = 50f; val.range = 40f; val.innerSpotAngle = 100f; val.spotAngle = 120f; ((Component)val).gameObject.layer = playerLayer; DisableRenderCameraNextFrame(); } [HarmonyPatch(typeof(PlayerControllerB), "ConnectClientToPlayerObject")] [HarmonyPostfix] public static void InitializePlayerCloneRenderObject(PlayerControllerB __instance) { if (!ConfigSettings.disableEmotesForSelf.Value && !LCVR_Patcher.Enabled && !((Object)(object)Plugin.radialMenuPrefab == (Object)null)) { ((MonoBehaviour)__instance).StartCoroutine(InitPlayerCloneAfterSpawnAnimation()); } IEnumerator InitPlayerCloneAfterSpawnAnimation() { yield return (object)new WaitForSeconds(2f); previewPlayerObject = Object.Instantiate<GameObject>(((Component)__instance).gameObject, ((Component)renderingCamera).transform); ((Object)previewPlayerObject).name = "PreviewPlayerAnimationObject"; GameObject modelGameObject = ((Component)previewPlayerObject.transform.Find("ScavengerModel")).gameObject; GameObject metarigGameObject = ((Component)modelGameObject.transform.Find("metarig")).gameObject; metarigGameObject.transform.localRotation = Quaternion.identity; PlayerControllerB copyPlayerController = previewPlayerObject.GetComponentInChildren<PlayerControllerB>(); ((Renderer)copyPlayerController.thisPlayerModel).shadowCastingMode = (ShadowCastingMode)1; previewPlayerMesh = copyPlayerController.thisPlayerModel; Object.DestroyImmediate((Object)(object)modelGameObject.GetComponentInChildren<LODGroup>()); Object.DestroyImmediate((Object)(object)metarigGameObject.GetComponentInChildren<RigBuilder>()); Object.DestroyImmediate((Object)(object)metarigGameObject.GetComponentInChildren<GraphicRaycaster>()); Object.DestroyImmediate((Object)(object)metarigGameObject.GetComponentInChildren<TMP_Text>()); Object.DestroyImmediate((Object)(object)copyPlayerController.playerBodyAnimator); Object.DestroyImmediate((Object)(object)previewPlayerObject.GetComponent<NfgoPlayer>()); foreach (Transform item in previewPlayerObject.transform) { Transform child2 = item; if (((Object)child2).name != "ScavengerModel") { Object.Destroy((Object)(object)((Component)child2).gameObject); } } foreach (Transform item2 in modelGameObject.transform) { Transform child3 = item2; if (((Object)child3).name != "LOD1" && ((Object)child3).name != "metarig") { Object.Destroy((Object)(object)((Component)child3).gameObject); } } foreach (Transform item3 in metarigGameObject.transform) { Transform child = item3; if (((Object)child).name != "spine") { Object.Destroy((Object)(object)((Component)child).gameObject); } } List<Component> destroyComponents = new List<Component>((IEnumerable<Component>)(object)previewPlayerObject.GetComponentsInChildren<HDAdditionalLightData>()); destroyComponents.AddRange((IEnumerable<Component>)(object)previewPlayerObject.GetComponentsInChildren<HDAdditionalCameraData>()); destroyComponents.AddRange((IEnumerable<Component>)(object)previewPlayerObject.GetComponentsInChildren<AudioReverbFilter>()); destroyComponents.AddRange((IEnumerable<Component>)(object)previewPlayerObject.GetComponentsInChildren<OccludeAudio>()); destroyComponents.AddRange((IEnumerable<Component>)(object)previewPlayerObject.GetComponentsInChildren<AudioLowPassFilter>()); destroyComponents.AddRange((IEnumerable<Component>)(object)previewPlayerObject.GetComponentsInChildren<AudioHighPassFilter>()); destroyComponents.AddRange((IEnumerable<Component>)(object)previewPlayerObject.GetComponentsInChildren<AudioChorusFilter>()); foreach (Component component2 in destroyComponents) { Object.DestroyImmediate((Object)(object)component2); } Component[] componentsInChildren = previewPlayerObject.GetComponentsInChildren<Component>(); foreach (Component component in componentsInChildren) { if (!(component is Transform) && !(component is SkinnedMeshRenderer) && !(component is MeshFilter) && !(component is Animator)) { try { Object.DestroyImmediate((Object)(object)component); } catch { Plugin.LogError("Failed to destroy component of type: " + ((object)component).GetType().ToString() + " on animation previewer object."); } } } previewPlayerAnimator = modelGameObject.AddComponent<Animator>(); previewPlayerAnimatorController = new AnimatorOverrideController(Plugin.humanoidAnimatorController); previewPlayerAnimator.runtimeAnimatorController = (RuntimeAnimatorController)(object)previewPlayerAnimatorController; previewPlayerAnimator.avatar = Plugin.humanoidAvatar; previewPlayerObject.transform.position = ((Component)renderingCamera).transform.position + ((Component)renderingCamera).transform.forward * 2.8f + Vector3.down * 1.35f; previewPlayerObject.transform.LookAt(new Vector3(((Component)renderingCamera).transform.position.x, previewPlayerObject.transform.position.y, ((Component)renderingCamera).transform.position.z)); SetObjectLayerRecursive(previewPlayerObject, playerLayer); } } private static void SetObjectLayerRecursive(GameObject obj, int layer) { if (!((Object)(object)obj == (Object)null)) { obj.layer = layer; for (int i = 0; i < obj.transform.childCount; i++) { Transform child = obj.transform.GetChild(i); SetObjectLayerRecursive((child != null) ? ((Component)child).gameObject : null, layer); } } } [HarmonyPatch(typeof(PlayerControllerB), "ScrollMouse_performed")] [HarmonyPrefix] public static bool OnScrollMouse(CallbackContext context, PlayerControllerB __instance) { if (!((CallbackContext)(ref context)).performed || (Object)(object)__instance != (Object)(object)localPlayerController || ConfigSettings.disableEmotesForSelf.Value || LCVR_Patcher.Enabled || !isMenuOpen || usingController) { return true; } if (isMenuOpen) { if (numPages == 0 || (numPages == 1 && currentPage == 0)) { return false; } float num = ((CallbackContext)(ref context)).ReadValue<float>(); if (num == 0f) { return false; } if (num < 0f == !ConfigSettings.reverseEmoteWheelScrollDirection.Value) { SwapPrevPage(); } else { SwapNextPage(); } return false; } return true; } [HarmonyPatch(typeof(PlayerControllerB), "ItemSecondaryUse_performed")] [HarmonyPrefix] public static bool PreventItemSecondaryUseInMenu(CallbackContext context) { if (ConfigSettings.disableEmotesForSelf.Value || LCVR_Patcher.Enabled) { return true; } return !isMenuOpen; } [HarmonyPatch(typeof(PlayerControllerB), "ItemTertiaryUse_performed")] [HarmonyPrefix] public static bool PreventItemTertiaryUseInMenu(CallbackContext context) { if (ConfigSettings.disableEmotesForSelf.Value || LCVR_Patcher.Enabled) { return true; } return !isMenuOpen; } [HarmonyPatch(typeof(PlayerControllerB), "Interact_performed")] [HarmonyPrefix] public static bool PreventInteractInMenu(CallbackContext context) { if (ConfigSettings.disableEmotesForSelf.Value || LCVR_Patcher.Enabled) { return true; } return !isMenuOpen; } [HarmonyPatch(typeof(QuickMenuManager), "OpenQuickMenu")] [HarmonyPrefix] public static bool OnOpenQuickMenu() { if (!isMenuOpen) { return true; } CloseEmoteMenu(); return false; } [HarmonyPatch(typeof(QuickMenuManager), "CloseQuickMenu")] [HarmonyPostfix] public static void OnCloseQuickMenu() { if (isMenuOpen) { CloseEmoteMenu(); } } [HarmonyPatch(typeof(PlayerControllerB), "KillPlayer")] [HarmonyPostfix] public static void OnLocalPlayerDeath(Vector3 bodyVelocity, PlayerControllerB __instance) { if (isMenuOpen && (Object)(object)__instance == (Object)(object)localPlayerController && __instance.isPlayerDead) { CloseEmoteMenu(); } } } public class EmoteUIElement { public GameObject uiGameObject; public int id; public Image backgroundImage; public TextMeshPro textContainer; public Color baseColor; public UnlockableEmote emote; public void OnHover(bool hovered = true) { //IL_0002: 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_001b: 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) Color color = baseColor * (hovered ? 1f : 0.5f); color.a = (hovered ? EmoteMenuManager.hoveredAlpha : EmoteMenuManager.unhoveredAlpha); ((Graphic)backgroundImage).color = color; } } public class EmoteLoadoutUIElement : MonoBehaviour, IPointerEnterHandler, IEventSystemHandler, IPointerExitHandler { public static int uiCount; public int id; public string loadoutName; public Image backgroundImage; public TextMeshPro textContainer; private void Awake() { id = uiCount++; backgroundImage = ((Component)this).GetComponentInChildren<Image>(); textContainer = ((Component)this).GetComponentInChildren<TextMeshPro>(); ((TMP_Text)textContainer).text = loadoutName; } private void Start() { } public void OnHover(bool hovered = true) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_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_004b: Unknown result type (might be due to invalid IL or missing references) Color color = ((EmoteMenuManager.currentLoadoutIndex == id) ? EmoteMenuManager.selectedLoadoutUIColor : EmoteMenuManager.defaultUIColor) * (hovered ? 1f : 0.5f); color.a = (hovered ? EmoteMenuManager.hoveredAlpha : EmoteMenuManager.unhoveredAlpha); ((Graphic)backgroundImage).color = color; } public void OnPointerEnter(PointerEventData eventData) { EmoteMenuManager.OnHoveredNewLoadoutElement(id); OnHover(); } public void OnPointerExit(PointerEventData eventData) { EmoteMenuManager.OnHoveredNewLoadoutElement(-1); OnHover(hovered: false); } } public class EmoteLoadoutUIContainer : MonoBehaviour, IPointerEnterHandler, IEventSystemHandler, IPointerExitHandler { public static bool hovered; public void OnPointerEnter(PointerEventData eventData) { hovered = true; } public void OnPointerExit(PointerEventData eventData) { hovered = false; } } [HarmonyPatch] public static class EmotesManager { public static List<UnlockableEmote> allUnlockableEmotes; public static Dictionary<string, UnlockableEmote> allUnlockableEmotesDict; public static List<UnlockableEmote> complementaryEmotes; public static List<string> allFavoriteEmotes; public static List<UnlockableEmote> allEmotesTier0; public static List<UnlockableEmote> allEmotesTier1; public static List<UnlockableEmote> allEmotesTier2; public static List<UnlockableEmote> allEmotesTier3; public static void BuildEmotesList() { allUnlockableEmotes = new List<UnlockableEmote>(); allUnlockableEmotesDict = new Dictionary<string, UnlockableEmote>(); complementaryEmotes = new List<UnlockableEmote>(); allFavoriteEmotes = new List<string>(); allEmotesTier0 = new List<UnlockableEmote>(); allEmotesTier1 = new List<UnlockableEmote>(); allEmotesTier2 = new List<UnlockableEmote>(); allEmotesTier3 = new List<UnlockableEmote>(); Dictionary<string, List<UnlockableEmote>> dictionary = new Dictionary<string, List<UnlockableEmote>>(); Dictionary<string, List<UnlockableEmote>> dictionary2 = new Dictionary<string, List<UnlockableEmote>>(); for (int i = 0; i < Plugin.customAnimationClips.Count; i++) { AnimationClip val = Plugin.customAnimationClips[i]; UnlockableEmote unlockableEmote = new UnlockableEmote { emoteId = i, emoteName = ((Object)val).name, displayName = "", animationClip = val, rarity = 0 }; unlockableEmote.rarity = (Plugin.animationClipsTier1.Contains(val) ? 1 : (Plugin.animationClipsTier2.Contains(val) ? 2 : (Plugin.animationClipsTier3.Contains(val) ? 3 : 0))); if (unlockableEmote.emoteName.Contains("_start") && !unlockableEmote.emoteName.Contains("_start_")) { string key = unlockableEmote.emoteName.Replace("_start", "_loop"); AnimationClip transitionsToClip = Plugin.customAnimationClipsLoopDict[key]; unlockableEmote.transitionsToClip = transitionsToClip; unlockableEmote.emoteName = unlockableEmote.emoteName.Replace("_start", ""); } if (unlockableEmote.emoteName.Contains("_pose")) { unlockableEmote.emoteName = unlockableEmote.emoteName.Replace("_pose", ""); unlockableEmote.isPose = true; } if (unlockableEmote.emoteName.Contains("_sync")) { unlockableEmote.emoteSyncGroupName = unlockableEmote.emoteName.Substring(0, unlockableEmote.emoteName.IndexOf("_sync")); unlockableEmote.emoteName = unlockableEmote.emoteName.Replace("_sync", ""); int num = unlockableEmote.emoteSyncGroupName.IndexOf("_"); if (num >= 0) { unlockableEmote.emoteSyncGroupName = unlockableEmote.emoteSyncGroupName.Substring(num + 1, unlockableEmote.emoteSyncGroupName.Length - num - 1); } if (dictionary2.TryGetValue(unlockableEmote.emoteSyncGroupName, out var value)) { if (!value.Contains(unlockableEmote)) { value.Add(unlockableEmote); } } else { value = new List<UnlockableEmote> { unlockableEmote }; dictionary2.Add(unlockableEmote.emoteSyncGroupName, value); } unlockableEmote.emoteSyncGroup = value; } if (unlockableEmote.emoteName.Contains("_random")) { unlockableEmote.randomEmotePoolName = unlockableEmote.emoteName.Substring(0, unlockableEmote.emoteName.IndexOf("_random")); if (!dictionary.ContainsKey(unlockableEmote.randomEmotePoolName)) { dictionary.Add(unlockableEmote.randomEmotePoolName, new List<UnlockableEmote> { unlockableEmote }); } else { unlockableEmote.purchasable = false; dictionary[unlockableEmote.randomEmotePoolName].Add(unlockableEmote); } unlockableEmote.randomEmotePool = dictionary[unlockableEmote.randomEmotePoolName]; unlockableEmote.emoteName = unlockableEmote.emoteName.Replace("_random", ""); unlockableEmote.displayName = unlockableEmote.randomEmotePoolName; } if ((Object)(object)unlockableEmote.transitionsToClip != (Object)null || ((Motion)unlockableEmote.animationClip).isLooping || unlockableEmote.isPose || unlockableEmote.emoteSyncGroup != null) { unlockableEmote.canSyncEmote = true; } if (unlockableEmote.displayName == "") { unlockableEmote.displayName = unlockableEmote.emoteName; } unlockableEmote.displayName = unlockableEmote.displayName.Replace('_', ' ').Trim(new char[1] { ' ' }); unlockableEmote.displayName = char.ToUpper(unlockableEmote.displayName[0]) + unlockableEmote.displayName.Substring(1).ToLower(); if (!allUnlockableEmotes.Contains(unlockableEmote)) { allUnlockableEmotes.Add(unlockableEmote); allUnlockableEmotesDict.Add(unlockableEmote.emoteName, unlockableEmote); } if (Plugin.complementaryAnimationClips.Contains(val) && unlockableEmote.purchasable) { unlockableEmote.complementary = true; complementaryEmotes.Add(unlockableEmote); } } allUnlockableEmotes = (from item in allUnlockableEmotes orderby item.rarity, item.emoteName select item).ToList(); int num2 = 0; foreach (UnlockableEmote allUnlockableEmote in allUnlockableEmotes) { allUnlockableEmote.emoteId = num2++; if (!allUnlockableEmote.complementary) { if (allUnlockableEmote.rarity == 0) { allEmotesTier0.Add(allUnlockableEmote); } else if (allUnlockableEmote.rarity == 1) { allEmotesTier1.Add(allUnlockableEmote); } else if (allUnlockableEmote.rarity == 2) { allEmotesTier2.Add(allUnlockableEmote); } else if (allUnlockableEmote.rarity == 3) { allEmotesTier3.Add(allUnlockableEmote); } } } SaveManager.LoadFavoritedEmotes(); } } [HarmonyPatch] public static class SessionManager { public static List<UnlockableEmote> unlockedEmotes = new List<UnlockableEmote>(); public static List<UnlockableEmote> unlockedEmotesTier0 = new List<UnlockableEmote>(); public static List<UnlockableEmote> unlockedEmotesTier1 = new List<UnlockableEmote>(); public static List<UnlockableEmote> unlockedEmotesTier2 = new List<UnlockableEmote>(); public static List<UnlockableEmote> unlockedEmotesTier3 = new List<UnlockableEmote>(); public static Dictionary<string, List<UnlockableEmote>> unlockedEmotesByPlayer = new Dictionary<string, List<UnlockableEmote>>(); public static List<UnlockableEmote> unlockedFavoriteEmotes = new List<UnlockableEmote>(); public static PlayerControllerB localPlayerController => StartOfRound.Instance?.localPlayerController; public static string localPlayerUsername => GameNetworkManager.Instance.username; [HarmonyPatch(typeof(StartOfRound), "Awake")] [HarmonyPostfix] public static void ResetGameValues() { EmoteController.allEmoteControllers.Clear(); EmoteControllerPlayer.allPlayerEmoteControllers.Clear(); EmoteControllerMaskedEnemy.allMaskedEnemyEmoteControllers.Clear(); } [HarmonyPatch(typeof(PlayerControllerB), "ConnectClientToPlayerObject")] [HarmonyPostfix] public static void OnHostConnected(PlayerControllerB __instance) { if (!NetworkManager.Singleton.IsServer) { return; } if (!unlockedEmotesByPlayer.ContainsKey(StartOfRound.Instance.localPlayerController.playerUsername)) { unlockedEmotesByPlayer.Add(StartOfRound.Instance.localPlayerController.playerUsername, unlockedEmotes); TerminalPatcher.currentEmoteCreditsByPlayer.Add(StartOfRound.Instance.localPlayerController.playerUsername, TerminalPatcher.currentEmoteCredits); return; } foreach (UnlockableEmote item in unlockedEmotesByPlayer[StartOfRound.Instance.localPlayerController.playerUsername]) { if (!unlockedEmotes.Contains(item)) { unlockedEmotes.Add(item); } } unlockedEmotesByPlayer[StartOfRound.Instance.localPlayerController.playerUsername] = unlockedEmotes; TerminalPatcher.currentEmoteCreditsByPlayer[StartOfRound.Instance.localPlayerController.playerUsername] = TerminalPatcher.currentEmoteCredits; } [HarmonyPatch(typeof(StartOfRound), "Start")] [HarmonyPostfix] public static void OnServerStart(StartOfRound __instance) { if (((NetworkBehaviour)__instance).IsServer) { UnlockEmotesLocal(ConfigSync.instance.syncUnlockEverything ? EmotesManager.allUnlockableEmotes : EmotesManager.complementaryEmotes); SyncManager.RotateEmoteSelectionServerRpc(TerminalPatcher.emoteStoreSeed); } } [HarmonyPatch(typeof(StartOfRound), "StartGame")] [HarmonyPostfix] public static void ResetOverrideSeedFlag(StartOfRound __instance) { __instance.overrideRandomSeed = false; } [HarmonyPatch(typeof(StartOfRound), "ResetShip")] [HarmonyPostfix] public static void ResetEmotesOnShipReset(StartOfRound __instance) { if (!ConfigSync.instance.syncUnlockEverything) { ResetProgressLocal(); } if (NetworkManager.Singleton.IsServer) { SyncManager.RotateEmoteSelectionServerRpc(); } } public static void ResetProgressLocal() { Plugin.Log("Resetting progression."); ResetEmotesLocal(); TerminalPatcher.currentEmoteCredits = ConfigSync.instance.syncStartingEmoteCredits; List<string> list = new List<string>(TerminalPatcher.currentEmoteCreditsByPlayer.Keys); foreach (string item in list) { TerminalPatcher.currentEmoteCreditsByPlayer[item] = ConfigSync.instance.syncStartingEmoteCredits; } TerminalPatcher.emoteStoreSeed = 0; } [HarmonyPatch(typeof(StartOfRound), "SyncShipUnlockablesServerRpc")] [HarmonyPostfix] public static void SyncUnlockedEmotesWithClients(StartOfRound __instance) { if (!NetworkManager.Singleton.IsServer || ConfigSync.instance.syncUnlockEverything) { return; } if (ConfigSync.instance.syncShareEverything) { Plugin.Log("Syncing unlocked emotes with clients."); SyncManager.SendOnUnlockEmoteUpdateMulti(TerminalPatcher.currentEmoteCredits); return; } HashSet<ulong> hashSet = new HashSet<ulong>(); PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts; foreach (PlayerControllerB val in allPlayerScripts) { if (val.actualClientId != 0L && val.playerSteamId != 0) { hashSet.Add(val.actualClientId); } } foreach (ulong item in hashSet) { SyncManager.ServerSendSyncToClient(item); } } public static List<UnlockableEmote> GetUnlockedEmotes(PlayerControllerB playerController) { return GetUnlockedEmotes(((Object)(object)playerController != (Object)null) ? playerController.playerUsername : ""); } public static List<UnlockableEmote> GetUnlockedEmotes(string playerUsername) { if (unlockedEmotesByPlayer.TryGetValue(playerUsername, out var value)) { return value; } return null; } public static void UnlockEmotesLocal(IEnumerable<UnlockableEmote> emotes, string playerUsername = "") { foreach (UnlockableEmote emote in emotes) { UnlockEmoteLocal(emote, playerUsername); } } public static void UnlockEmoteLocal(int emoteId, string playerUsername = "") { UnlockEmoteLocal((emoteId >= 0 && emoteId < EmotesManager.allUnlockableEmotes.Count) ? EmotesManager.allUnlockableEmotes[emoteId] : null, playerUsername); } public static void UnlockEmoteLocal(UnlockableEmote emote, string playerUsername = "") { if (emote == null) { return; } List<UnlockableEmote> value = unlockedEmotes; if (playerUsername != "" && !ConfigSync.instance.syncShareEverything && playerUsername != localPlayerUsername && !unlockedEmotesByPlayer.TryGetValue(playerUsername, out value)) { return; } if (emote.randomEmotePool != null) { foreach (UnlockableEmote item in emote.randomEmotePool) { if (value.Contains(item)) { return; } } } if (!value.Contains(emote)) { value.Add(emote); } if (value != unlockedEmotes) { return; } if (!emote.complementary) { if (emote.rarity == 3 && !unlockedEmotesTier3.Contains(emote)) { unlockedEmotesTier3.Add(emote); } else if (emote.rarity == 2 && !unlockedEmotesTier2.Contains(emote)) { unlockedEmotesTier2.Add(emote); } else if (emote.rarity == 1 && !unlockedEmotesTier1.Contains(emote)) { unlockedEmotesTier1.Add(emote); } else if (emote.rarity == 0 && !unlockedEmotesTier0.Contains(emote)) { unlockedEmotesTier0.Add(emote); } } if (EmotesManager.allFavoriteEmotes.Contains(emote.emoteName) && !unlockedFavoriteEmotes.Contains(emote)) { unlockedFavoriteEmotes.Add(emote); } } public static void ResetEmotesLocal() { Plugin.Log("Resetting unlocked emotes."); unlockedEmotes.Clear(); unlockedEmotesTier0.Clear(); unlockedEmotesTier1.Clear(); unlockedEmotesTier2.Clear(); unlockedEmotesTier3.Clear(); unlockedEmotesByPlayer.Clear(); PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts; foreach (PlayerControllerB val in allPlayerScripts) { if (val.playerSteamId != 0) { unlockedEmotesByPlayer.Add(val.playerUsername, ((Object)(object)val == (Object)(object)StartOfRound.Instance.localPlayerController || ConfigSync.instance.syncShareEverything) ? unlockedEmotes : new List<UnlockableEmote>()); } } UnlockEmotesLocal(ConfigSync.instance.syncUnlockEverything ? EmotesManager.allUnlockableEmotes : EmotesManager.complementaryEmotes); UpdateUnlockedFavoriteEmotes(); } public static void UpdateUnlockedFavoriteEmotes() { unlockedFavoriteEmotes.Clear(); foreach (string allFavoriteEmote in EmotesManager.allFavoriteEmotes) { if (EmotesManager.allUnlockableEmotesDict.ContainsKey(allFavoriteEmote)) { UnlockableEmote unlockableEmote = EmotesManager.allUnlockableEmotesDict[allFavoriteEmote]; if (unlockableEmote != null && unlockedEmotes.Contains(unlockableEmote)) { unlockedFavoriteEmotes.Add(unlockableEmote); } } else { Plugin.LogWarning("Error loading favorited emote. Emote does not exist. The emote has likely been temporarily removed in this update."); } } } public static void SortUnlockedEmotes() { unlockedEmotes = (from item in unlockedEmotes orderby item.rarity, item.emoteName select item).ToList(); } public static bool TryGetPlayerByClientId(ulong clientId, out PlayerControllerB playerController) { playerController = null; PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts; foreach (PlayerControllerB val in allPlayerScripts) { if (val.actualClientId == clientId) { playerController = val; break; } } return (Object)(object)playerController != (Object)null; } public static bool TryGetPlayerByUsername(string username, out PlayerControllerB playerController) { playerController = null; PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts; foreach (PlayerControllerB val in allPlayerScripts) { if (val.playerUsername == username) { playerController = val; break; } } return (Object)(object)playerController != (Object)null; } } public class UnlockableEmote { public int emoteId; public string emoteName; public string displayName = ""; public AnimationClip animationClip; public AnimationClip transitionsToClip = null; public string randomEmotePoolName = ""; public List<UnlockableEmote> randomEmotePool; public bool purchasable = true; public bool complementary = false; public bool isPose = false; public string emoteSyncGroupName = ""; public List<UnlockableEmote> emoteSyncGroup; public List<PropAnimationData> propAnimationsData; public bool canSyncEmote = false; public bool favorite = false; public int rarity = 0; public static string[] rarityColorCodes = new string[4] { ConfigSettings.emoteNameColorTier0.Value, ConfigSettings.emoteNameColorTier1.Value, ConfigSettings.emoteNameColorTier2.Value, ConfigSettings.emoteNameColorTier3.Value }; public string displayNameColorCoded => $"<color={nameColor}>{displayName}</color>"; public bool humanoidAnimation => ((Motion)animationClip).isHumanMotion; public bool loopable => ((Motion)animationClip).isLooping || ((Object)(object)transitionsToClip != (Object)null && ((Motion)transitionsToClip).isLooping); public string rarityText { get { if (rarity == 0) { return "Common"; } if (rarity == 1) { return "Rare"; } if (rarity == 2) { return "Epic"; } if (rarity == 3) { return "Legendary"; } return "Invalid"; } } public int price { get { int num = -1; if (complementary) { num = 0; } else if (rarity == 0) { num = ConfigSync.instance.syncBasePriceEmoteTier0; } else if (rarity == 1) { num = ConfigSync.instance.syncBasePriceEmoteTier1; } else if (rarity == 2) { num = ConfigSync.instance.syncBasePriceEmoteTier2; } else if (rarity == 3) { num = ConfigSync.instance.syncBasePriceEmoteTier3; } return (int)Mathf.Max((float)num * ConfigSync.instance.syncPriceMultiplierEmotesStore, 0f); } } public string nameColor => rarityColorCodes[rarity]; public bool ClipIsInEmote(AnimationClip clip) { return (Object)(object)clip != (Object)null && ((Object)(object)clip == (Object)(object)animationClip || (Object)(object)clip == (Object)(object)transitionsToClip); } } [BepInPlugin("FlipMods.TooManyEmotes", "TooManyEmotes", "1.9.5")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { private Harmony _harmony; public static Plugin instance; private static ManualLogSource logger; public static List<AnimationClip> customAnimationClips; public static HashSet<AnimationClip> customAnimationClipsHash; public static Dictionary<string, AnimationClip> customAnimationClipsLoopDict; public static List<AnimationClip> complementaryAnimationClips; public static List<AnimationClip> animationClipsTier0; public static List<AnimationClip> animationClipsTier1; public static List<AnimationClip> animationClipsTier2; public static List<AnimationClip> animationClipsTier3; public static GameObject radialMenuPrefab; public static RuntimeAnimatorController humanoidAnimatorController; public static Avatar humanoidAvatar; public static GameObject humanoidSkeletonPrefab; public static HashSet<AudioClip> emoteAudioClips; public static HashSet<GameObject> emotePropPrefabs; public static HashSet<RuntimeAnimatorController> emotePropAnimatorControllers; private void Awake() { //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Expected O, but got Unknown instance = this; CreateCustomLogger(); ConfigSettings.BindConfigSettings(); Keybinds.InitKeybinds(); if (IsModLoaded("io.daxcess.lcvr")) { LCVR_Patcher.CheckIfVRIsEnabled(); } LoadEmoteAssets(); LoadMiscAnimationAssets(); LoadRadialMenuAsset(); EmotesManager.BuildEmotesList(); _harmony = new Harmony("TooManyEmotes"); PatchAll(); Log("TooManyEmotes loaded"); } private static void LoadEmoteAssets() { customAnimationClips = new List<AnimationClip>(); customAnimationClipsHash = new HashSet<AnimationClip>(); customAnimationClipsLoopDict = new Dictionary<string, AnimationClip>(); complementaryAnimationClips = new List<AnimationClip>(LoadEmoteAssetBundle("Assets/emotes_complementary")); animationClipsTier0 = new List<AnimationClip>(LoadEmoteAssetBundle("Assets/emotes_0")); animationClipsTier1 = new List<AnimationClip>(LoadEmoteAssetBundle("Assets/emotes_1")); animationClipsTier2 = new List<AnimationClip>(LoadEmoteAssetBundle("Assets/emotes_2")); animationClipsTier3 = new List<AnimationClip>(LoadEmoteAssetBundle("Assets/emotes_3")); customAnimationClipsHash.UnionWith(complementaryAnimationClips); customAnimationClipsHash.UnionWith(animationClipsTier0); customAnimationClipsHash.UnionWith(animationClipsTier1); customAnimationClipsHash.UnionWith(animationClipsTier2); customAnimationClipsHash.UnionWith(animationClipsTier3); foreach (AnimationClip item in customAnimationClipsHash) { if (((Object)item).name.StartsWith("fn_")) { ((Object)item).name = ((Object)item).name.Replace("fn_", ""); } if (((Object)item).name.EndsWith("_loop")) { if (customAnimationClipsLoopDict.ContainsKey(((Object)item).name)) { LogWarning("Attempted to add duplicate emote in CustomAnimationClipsLoopDict. AnimationClip: " + ((Object)item).name); } else { customAnimationClipsLoopDict.Add(((Object)item).name, item); } } } customAnimationClips = new List<AnimationClip>(customAnimationClipsHash); customAnimationClipsHash = new HashSet<AnimationClip>(customAnimationClips); foreach (AnimationClip value in customAnimationClipsLoopDict.Values) { customAnimationClips.Remove(value); } } private static AnimationClip[] LoadEmoteAssetBundle(string assetBundleName) { try { string text = Path.Combine(Path.GetDirectoryName(((BaseUnityPlugin)instance).Info.Location), assetBundleName); AssetBundle val = AssetBundle.LoadFromFile(text); AnimationClip[] array = val.LoadAllAssets<AnimationClip>(); Log($"Successfully loaded {array.Length} animation clips from asset bundle: {assetBundleName}"); return array; } catch { LogError("Failed to load emotes Asset Bundle."); return (AnimationClip[])(object)new AnimationClip[0]; } } private static void LoadMiscAnimationAssets() { try { string text = Path.Combine(Path.GetDirectoryName(((BaseUnityPlugin)instance).Info.Location), "Assets/misc"); AssetBundle val = AssetBundle.LoadFromFile(text); humanoidAnimatorController = val.LoadAsset<RuntimeAnimatorController>("humanoid_animator_controller"); humanoidAvatar = val.LoadAsset<Avatar>("humanoid_avatar"); humanoidSkeletonPrefab = val.LoadAsset<GameObject>("humanoid_skeleton"); Animator componentInChildren = humanoidSkeletonPrefab.GetComponentInChildren<Animator>(); if ((Object)(object)componentInChildren == (Object)null) { componentInChildren = humanoidSkeletonPrefab.AddComponent<Animator>(); } if ((Object)(object)humanoidAnimatorController == (Object)null) { LogError("Failed to load humanoid animator controller from asset bundle: misc"); } if ((Object)(object)humanoidAvatar == (Object)null) { LogError("Failed to load humanoid avatar from asset bundle: misc"); } if ((Object)(object)humanoidSkeletonPrefab == (Object)null) { LogError("Failed to load humanoid skeleton prefab from asset bundle: misc"); } } catch { LogError("Failed to load misc Asset Bundle."); } } private static void LoadEmotePropAssets() { try { string text = Path.Combine(Path.GetDirectoryName(((BaseUnityPlugin)instance).Info.Location), "Assets/props"); AssetBundle val = AssetBundle.LoadFromFile(text); GameObject[] array = val.LoadAllAssets<GameObject>(); GameObject[] array2 = array; foreach (GameObject item in array2) { emotePropPrefabs.Add(item); } } catch { LogError("Failed to load emote props Asset Bundle."); } } public static void LoadRadialMenuAsset() { try { string text = Path.Combine(Path.GetDirectoryName(((BaseUnityPlugin)instance).Info.Location), "Assets/radial_menu"); AssetBundle val = AssetBundle.LoadFromFile(text); radialMenuPrefab = val.LoadAsset<GameObject>("RadialMenu"); Log("Successfully loaded radial menu asset."); } catch { LogError("Failed to load radial menu asset."); } } private void PatchAll() { IEnumerable<Type> enumerable; try { enumerable = Assembly.GetExecutingAssembly().GetTypes(); } catch (ReflectionTypeLoadException ex) { enumerable = ex.Types.Where((Type t) => t != null); } foreach (Type item in enumerable) { _harmony.PatchAll(item); } } private void CreateCustomLogger() { try { logger = Logger.CreateLogSource($"{((BaseUnityPlugin)this).Info.Metadata.Name}-{((BaseUnityPlugin)this).Info.Metadata.Version}"); } catch { logger = ((BaseUnityPlugin)this).Logger; } } public static void Log(string message) { logger.LogInfo((object)message); } public static void LogError(string message) { logger.LogError((object)message); } public static void LogWarning(string message) { logger.LogWarning((object)message); } public static bool IsModLoaded(string guid) { return Chainloader.PluginInfos.ContainsKey(guid); } } public static class PluginInfo { public const string PLUGIN_GUID = "FlipMods.TooManyEmotes"; public const string PLUGIN_NAME = "TooManyEmotes"; public const string PLUGIN_VERSION = "1.9.5"; } } namespace TooManyEmotes.Config { public static class ConfigSettings { public static ConfigEntry<bool> unlockEverything; public static ConfigEntry<bool> shareEverything; public static ConfigEntry<bool> syncUnsharedEmotes; public static ConfigEntry<bool> enableMovingWhileEmoting; public static ConfigEntry<bool> disableEmotesForSelf; public static ConfigEntry<string> rotateCharacterInEmoteKeybind; public static ConfigEntry<bool> toggleRotateCharacterInEmote; public static ConfigEntry<bool> disableRaritySystem; public static ConfigEntry<int> basePriceEmoteRaritySystemDisabled; public static ConfigEntry<int> startingEmoteCredits; public static ConfigEntry<float> addEmoteCreditsMultiplier; public static ConfigEntry<bool> purchaseEmotesWithDefaultCurrency; public static ConfigEntry<float> priceMultiplierEmotesStore; public static ConfigEntry<int> basePriceEmoteTier0; public static ConfigEntry<int> basePriceEmoteTier1; public static ConfigEntry<int> basePriceEmoteTier2; public static ConfigEntry<int> basePriceEmoteTier3; public static ConfigEntry<int> numEmotesStoreRotation; public static ConfigEntry<float> rotationChanceEmoteTier0; public static ConfigEntry<float> rotationChanceEmoteTier1; public static ConfigEntry<float> rotationChanceEmoteTier2; public static ConfigEntry<float> rotationChanceEmoteTier3; public static ConfigEntry<bool> enableMaskedEnemiesEmoting; public static ConfigEntry<float> maskedEnemiesEmoteChanceOnEncounter; public static ConfigEntry<bool> maskedEnemiesAlwaysEmoteOnFirstEncounter; public static ConfigEntry<bool> enableSyncingEmotesWithMaskedEnemies; public static ConfigEntry<bool> overrideStopAndStareDuration; public static ConfigEntry<string> maskedEnemyEmoteRandomDelay; public static ConfigEntry<string> maskedEnemyEmoteRandomDuration; public static ConfigEntry<string> openEmoteMenuKeybind; public static ConfigEntry<bool> toggleEmoteMenu; public static ConfigEntry<bool> reverseEmoteWheelScrollDirection; public static ConfigEntry<string> quickEmoteFavorite1Keybind; public static ConfigEntry<string> quickEmoteFavorite2Keybind; public static ConfigEntry<string> quickEmoteFavorite3Keybind; public static ConfigEntry<string> quickEmoteFavorite4Keybind; public static ConfigEntry<string> quickEmoteFavorite5Keybind; public static ConfigEntry<string> quickEmoteFavorite6Keybind; public static ConfigEntry<string> quickEmoteFavorite7Keybind; public static ConfigEntry<string> quickEmoteFavorite8Keybind; public static ConfigEntry<string> emoteNameColorTier0; public static ConfigEntry<string> emoteNameColorTier1; public static ConfigEntry<string> emoteNameColorTier2; public static ConfigEntry<string> emoteNameColorTier3; public static Dictionary<string, ConfigEntryBase> currentConfigEntries = new Dictionary<string, ConfigEntryBase>(); public static List<string> configSections = new List<string>(); public static void BindConfigSettings() { Plugin.Log("BindingConfigs"); unlockEverything = AddConfigEntry("Emote Settings", "I am a Party Pooper", defaultValue: false, "[Host only] If true, every emote will be unlocked in your emote wheel at the start of the game. Also, you're not really a party pooper."); shareEverything = AddConfigEntry("Emote Settings", "ShareEverything", defaultValue: true, "[Host only] This setting will be ignored if \"I am a Party Pooper\" is enabled. If this setting is set to false, emotes in the store will be different for each player. Unlocking emotes will only unlock for the player that purchased the emote. Each player will have their own emote credits. The amount of emote credits that each player will receive will NOT be reduced."); syncUnsharedEmotes = AddConfigEntry("Emote Settings", "CanSyncUnsharedEmotes", defaultValue: true, "[Host only] Only applies if ShareEverything is false. If set to true, players will be able to sync emotes with other players, even if they do not have the emote being performed unlocked."); enableMovingWhileEmoting = AddConfigEntry("Emote Settings", "CanMoveWhileEmoting", defaultValue: false, "[Host only] If set to true, rotating while emoting will be automatic. To cancel an emote, you will press the vanilla menu button."); disableEmotesForSelf = AddConfigEntry("Emote Settings", "DisableEmotingForSelf", defaultValue: false, "Disabling this will not convert your player's animator controller to an AnimatorOverrideController, and you will not be able to perform custom emotes. Disable this in case of specific mod conflicts. You will still be able to see other players emoting."); rotateCharacterInEmoteKeybind = AddConfigEntry("Emote Settings", "RotateCharacterInEmoteKeybind", "<Keyboard>/leftAlt", "Keybind to hold to rotate character while performing a custom emote. NOTE: This setting will be ignored if InputUtils is installed and enabled. (I recommend running InputUtils to edit keybinds in the in-game settings)"); toggleRotateCharacterInEmote = AddConfigEntry("Emote Settings", "ToggleRotateCharacterInEmote", defaultValue: false, "If true, rotating character while emoting will be toggled, instead of rotating while holding the hotkey."); disableRaritySystem = AddConfigEntry("Emote Store", "DisableRaritySystem", defaultValue: false, "[Host only] If true, every emote will have the same likelyhood of appearing in the emote store."); basePriceEmoteRaritySystemDisabled = AddConfigEntry("Emote Store", "BasePriceEmote - Rarity System Disabled", 100, "[Host only] Base price of emotes if the rarity system is disabled."); startingEmoteCredits = AddConfigEntry("Emote Store", "StartingEmoteCredits", 100, "[Host only] The number of emote credits you start each game with."); addEmoteCreditsMultiplier = AddConfigEntry("Emote Store", "AddEmoteCreditsMultiplier", 0.4f, "[Host only] You gain emote credits based off this multiplier of normal group credits earned. Example: If set to the default, 0.25, and you earn 200 group credits, you will also gain 50 emote credits."); purchaseEmotesWithDefaultCurrency = AddConfigEntry("Emote Store", "PurchaseEmotesWithDefaultCredits", defaultValue: true, "[Host only] Setting this to true will allow you to purchase emotes with normal group credits once you run out of emote credits. This setting will automatically be disabled if ShareEverything is false."); priceMultiplierEmotesStore = AddConfigEntry("Emote Store", "PriceMultiplierEmotesStore", 1f, "[Host only] Price multiplier for emotes in the store. Only applies if UnlockEverythingAtStart is false."); basePriceEmoteTier0 = AddConfigEntry("Emote Store", "PriceCommonEmote", 50, "[Host only] The base price of [common]emotes in the store."); basePriceEmoteTier1 = AddConfigEntry("Emote Store", "PriceRareEmote", 100, "[Host only] The base price of [rare] emotes in the store."); basePriceEmoteTier2 = AddConfigEntry("Emote Store", "PriceEpicEmote", 200, "[Host only] The base price of [epic] emotes in the store."); basePriceEmoteTier3 = AddConfigEntry("Emote Store", "PriceLegendaryEmote", 300, "[Host only] The base price of [legendary] emotes in the store."); numEmotesStoreRotation = AddConfigEntry("Emote Store", "EmotesInStoreRotation", 6, "[Host only] The number of emotes that will be available at a time in the store. Only applies if UnlockEverythingAtStart is false."); rotationChanceEmoteTier0 = AddConfigEntry("Emote Store", "RotationWeightCommonEmote", 0.55f, "[Host only] The likelyhood of [common] emotes appearing (per slot) in the store rotation."); rotationChanceEmoteTier1 = AddConfigEntry("Emote Store", "RotationWeightRareEmote", 0.35f, "[Host only] The likelyhood of [rare] emotes appearing (per slot) in the store rotation."); rotationChanceEmoteTier2 = AddConfigEntry("Emote Store", "RotationWeightEpicEmote", 0.08f, "[Host only] The likelyhood of [epic] emotes appearing (per slot) in the store rotation."); rotationChanceEmoteTier3 = AddConfigEntry("Emote Store", "RotationWeightLegendaryEmote", 0.02f, "[Host only] The likelyhood of [legendary] emotes appearing (per slot) in the store rotation."); enableMaskedEnemiesEmoting = AddConfigEntry("MaskedEnemyEmotes - Beta", "EnableMaskedEnemiesEmoting", defaultValue: true, "[Host only] Enabling this alone does not change the behaviour of the Masked Enemies, and shouldn't conflict with other mods."); maskedEnemiesEmoteChanceOnEncounter = AddConfigEntry("MaskedEnemyEmotes - Beta", "EmoteChanceOnEncounter", 0.25f, "[Host only] Chance per encounter with a Masked Enemy, for them to perform an emote. Use values between 0 and 1."); maskedEnemiesAlwaysEmoteOnFirstEncounter = AddConfigEntry("MaskedEnemyEmotes - Beta", "AlwaysEmoteOnFirstEncounter", defaultValue: true, "[Host only] This will force the first encounter (for each player) with a Masked Enemy to trigger an emote, regardless of EmoteChanceOnEncounter."); enableSyncingEmotesWithMaskedEnemies = AddConfigEntry("MaskedEnemyEmotes - Beta", "EnableSyncingEmotesWithMaskedEnemies", defaultValue: true, "[Client-side] Enabling this will allow you to sync emotes with Masked Enemies. This config is mainly here to disable in case of strange issues."); maskedEnemyEmoteRandomDelay = AddConfigEntry("MaskedEnemyEmotes - Beta", "RandomEmoteDelay", "1.5,2.0", "[Host only] Random range at which Masked Enemies will delay before performing an emote. These values could be raised a bit if OverrideStopAndStareDuration is enabled, otherwise, you may run into emotes ending quickly."); overrideStopAndStareDuration = AddConfigEntry("MaskedEnemyEmotes - Beta", "OverrideStopAndStareDuration", defaultValue: true, "[Host only] Enabling this will allow this mod to extend the stop and stare duration for longer emotes. If disabled, emotes may end very quickly. Disable this setting if you run into mod conflicts."); maskedEnemyEmoteRandomDuration = AddConfigEntry("MaskedEnemyEmotes - Beta", "RandomEmoteDuration", "2.0,4.0", "[Host only] Random range on how long Masked Enemies will emote for. This will extend the Masked Enemies' stop and stare duration by this amount. Only applies if OverrideStopAndStareDuration is true."); openEmoteMenuKeybind = AddConfigEntry("Emote Radial Menu", "OpenEmoteMenuKeybind", "<Keyboard>/backquote", "NOTE: This setting will be ignored if InputUtils is installed and enabled. (I recommend running InputUtils to edit keybinds in the in-game settings)"); toggleEmoteMenu = AddConfigEntry("Emote Radial Menu", "ToggleEmoteMenu", defaultValue: false, "If set to false, the emote menu will open upon pressing the related keybind, and close upon releasing, and will play the currently hovered emote."); reverseEmoteWheelScrollDirection = AddConfigEntry("Emote Radial Menu", "ReverseEmoteWheelScrollDirection", defaultValue: false, "Reverses the page swapping direction in your emote when scrolling."); emoteNameColorTier0 = AddConfigEntry("Accessibility", "EmoteNameColorCommon", "#00FF00", "The color of the [common] emote name in the terminal."); emoteNameColorTier1 = AddConfigEntry("Accessibility", "EmoteNameColorRare", "#2828FF", "The color of the [rare] emote name in the terminal."); emoteNameColorTier2 = AddConfigEntry("Accessibility", "EmoteNameColorEpic", "#AA00EE", "The color of the [epic] emote name in the terminal."); emoteNameColorTier3 = AddConfigEntry("Accessibility", "EmoteNameColorLegendary", "#FF2222", "The color of the [legendary] emote name in the terminal."); float value = rotationChanceEmoteTier0.Value; value += rotationChanceEmoteTier1.Value; value += rotationChanceEmoteTier2.Value; value += rotationChanceEmoteTier3.Value; if (value != 1f && value != 0f) { ConfigEntry<float> obj = rotationChanceEmoteTier0; obj.Value /= value; ConfigEntry<float> obj2 = rotationChanceEmoteTier1; obj2.Value /= value; ConfigEntry<float> obj3 = rotationChanceEmoteTier2; obj3.Value /= value; ConfigEntry<float> obj4 = rotationChanceEmoteTier3; obj4.Value /= value; ((BaseUnityPlugin)Plugin.instance).Config.Save(); } TryRemoveOldConfigSettings(); ConfigSync.BuildDefaultConfigSync(); } public static ConfigEntry<T> AddConfigEntry<T>(string section, string name, T defaultValue, string description) { ConfigEntry<T> val = ((BaseUnityPlugin)Plugin.instance).Config.Bind<T>(section, name, defaultValue, description); currentConfigEntries.Add(((ConfigEntryBase)val).Definition.Key, (ConfigEntryBase)(object)val); return val; } public static void TryRemoveOldConfigSettings() { HashSet<string> hashSet = new HashSet<string>(); HashSet<string> hashSet2 = new HashSet<string>(); foreach (ConfigEntryBase value in currentConfigEntries.Values) { hashSet.Add(value.Definition.Section); hashSet2.Add(value.Definition.Key); } try { Plugin.Log("Cleaning old config entries"); ConfigFile config = ((BaseUnityPlugin)Plugin.instance).Config; string configFilePath = config.ConfigFilePath; if (!File.Exists(configFilePath)) { return; } string text = File.ReadAllText(configFilePath); string[] array = File.ReadAllLines(configFilePath); string text2 = ""; for (int i = 0; i < array.Length; i++) { array[i] = array[i].Replace("\n", ""); if (array[i].Length <= 0) { continue; } if (array[i].StartsWith("[")) { if (text2 != "" && !hashSet.Contains(text2)) { text2 = "[" + text2 + "]"; int num = text.IndexOf(text2); int num2 = text.IndexOf(array[i]); text = text.Remove(num, num2 - num); } text2 = array[i].Replace("[", "").Replace("]", "").Trim(); } else { if (!(text2 != "")) { continue; } if (i <= array.Length - 4 && array[i].StartsWith("##")) { int j; for (j = 1; i + j < array.Length && array[i + j].Length > 3; j++) { } if (hashSet.Contains(text2)) { int num3 = array[i + j - 1].IndexOf("="); string item = array[i + j - 1].Substring(0, num3 - 1); if (!hashSet2.Contains(item)) { int num4 = text.IndexOf(array[i]); int num5 = text.IndexOf(array[i + j - 1]) + array[i + j - 1].Length; text = text.Remove(num4, num5 - num4); } } i += j - 1; } else if (array[i].Length > 3) { text = text.Replace(array[i], ""); } } } if (!hashSet.Contains(text2)) { text2 = "[" + text2 + "]"; int num6 = text.IndexOf(text2); text = text.Remove(num6, text.Length - num6); } while (text.Contains("\n\n\n")) { text = text.Replace("\n\n\n", "\n\n"); } File.WriteAllText(configFilePath, text); config.Reload(); } catch { } } } } namespace TooManyEmotes.Input { internal class IngameKeybinds : LcInputActions { internal static IngameKeybinds Instance = new IngameKeybinds(); [InputAction("<Keyboard>/backquote", GamepadPath = "<Gamepad>/leftStickPress", Name = "Open Emote Menu")] public InputAction OpenEmoteMenuHotkey { get; set; } [InputAction("<Key