using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; 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 AdvancedCompany.Cosmetics; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using GameNetcodeStuff; using HarmonyLib; using LCVR.Managers; using LethalCompanyInputUtils.Api; using MoreCompany.Cosmetics; using TMPro; using TooManyEmotes.Audio; using TooManyEmotes.Compatibility; using TooManyEmotes.Config; using TooManyEmotes.Input; using TooManyEmotes.Networking; using TooManyEmotes.Patches; using TooManyEmotes.Props; using TooManyEmotes.UI; using Unity.Collections; using Unity.Netcode; using UnityEngine; using UnityEngine.AI; using UnityEngine.Animations.Rigging; using UnityEngine.EventSystems; using UnityEngine.Events; using UnityEngine.Experimental.Rendering; using UnityEngine.InputSystem; using UnityEngine.Rendering; 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: InternalsVisibleTo("TooManyEmotesScrap")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyVersion("1.0.0.0")] namespace TooManyEmotes { [HarmonyPatch] public static class AdditionalEmoteData { public static void SetAdditionalEmoteData() { } public static void SetAdditionalPropData() { if (EmotesManager.allUnlockableEmotesDict != null) { AssignPropToEmote("jug_prop", "jug_band.jug"); AssignPropToEmote("guitar_prop", "jug_band.guitar"); AssignPropToEmote("banjo_prop", "jug_band.banjo"); AssignPropToEmote("fiddle_prop", "jug_band.fiddle"); AssignPropToEmote("sexy_saxophone.sexy_sax.prop", "sexy_saxophone.sexy_sax"); AssignPropToEmote("sexy_saxophone.epic_sax.prop", "sexy_saxophone.epic_sax"); AssignPropToEmote("trombone.prop", "sad_trombone"); AssignPropToEmote("old_chair.prop", "ma-ya-hi"); AssignPropToEmote("baseball_bat.prop", "miracle_trickshot"); AssignPropToEmote("dumbbell.prop", "pumping_iron"); AssignPropToEmote("paddle.prop", "paddle_royale"); AssignPropToEmote("gamepad.prop", "controller_crew"); AssignPropToEmote("jar_of_dirt.prop", "jar_of_dirt"); AssignPropToEmote("travelers.banjo.prop", "travelers.banjo"); AssignPropToEmote("travelers.harmonica.prop", "travelers.harmonica"); AssignPropToEmote("travelers.drums.prop", "travelers.drums"); AssignPropToEmote("travelers.flute.prop", "travelers.flute"); AssignPropToEmote("travelers.whistle.prop", "travelers.whistle"); AssignPropToEmote("travelers.piano.prop", "travelers.piano"); AssignPropToEmote("travelers.bow.prop", "travelers.bow"); } } public static void SetAdditionalMusicData() { if (EmotesManager.allUnlockableEmotesDict == null) { return; } SetEmoteDoesNotUseBoombox("jug_band.jug"); SetEmoteDoesNotUseBoombox("jug_band.guitar"); SetEmoteDoesNotUseBoombox("jug_band.banjo"); SetEmoteDoesNotUseBoombox("jug_band.fiddle"); SetEmoteDoesNotUseBoombox("hand_signals"); SetEmoteDoesNotUseBoombox("red_card"); SetEmoteDoesNotUseBoombox("sexy_saxophone.sexy_sax"); SetEmoteDoesNotUseBoombox("sexy_saxophone.epic_sax"); SetEmoteDoesNotUseBoombox("sad_trombone"); SetEmoteDoesNotUseBoombox("snake_summoner"); SetEmoteDoesNotUseBoombox("miracle_trickshot"); SetEmoteDoesNotUseBoombox("junk_food"); SetEmoteDoesNotUseBoombox("pumping_iron"); SetEmoteDoesNotUseBoombox("paddle_royale"); SetEmoteDoesNotUseBoombox("wolf_howl"); SetEmoteDoesNotUseBoombox("jar_of_dirt"); SetEmoteDoesNotUseBoombox("squeaky_step"); SetEmoteDoesNotUseBoombox("travelers.banjo"); SetEmoteDoesNotUseBoombox("travelers.harmonica"); SetEmoteDoesNotUseBoombox("travelers.drums"); SetEmoteDoesNotUseBoombox("travelers.flute"); SetEmoteDoesNotUseBoombox("travelers.whistle"); SetEmoteDoesNotUseBoombox("travelers.piano"); SetEmoteDoesNotUseBoombox("travelers.bow"); AssignMusicToEmote("jug_band.jug", "jug_band.jug"); AssignMusicToEmote("jug_band.guitar", "jug_band.guitar"); AssignMusicToEmote("jug_band.banjo", "jug_band.banjo"); AssignMusicToEmote("jug_band.fiddle", "jug_band.fiddle"); AssignMusicToEmote("travelers.banjo", "travelers.banjo"); AssignMusicToEmote("travelers.harmonica", "travelers.harmonica"); AssignMusicToEmote("travelers.drums", "travelers.drums"); AssignMusicToEmote("travelers.flute", "travelers.flute"); AssignMusicToEmote("travelers.whistle", "travelers.whistle"); AssignMusicToEmote("travelers.piano", "travelers.piano"); AssignMusicToEmote("travelers.bow", "travelers.bow"); if (EmotesManager.allUnlockableEmotesDict.TryGetValue("jug_band.banjo", out var value) && value.inEmoteSyncGroup) { foreach (UnlockableEmote item in value.emoteSyncGroup) { item.recordSongLoopValue = 1f; } } if (!EmotesManager.allUnlockableEmotesDict.TryGetValue("travelers.banjo", out value) || !value.inEmoteSyncGroup) { return; } foreach (UnlockableEmote item2 in value.emoteSyncGroup) { item2.recordSongLoopValue = 0.5f; } } public static void AssignPropToEmote(string propName, string emoteName) { if (!EmotePropManager.emotePropsDataDict.TryGetValue(propName, out var _)) { CustomLogging.LogWarning("Failed to assign prop: " + propName + " to emote. Prop does not exist!"); return; } if (!EmotesManager.allUnlockableEmotesDict.TryGetValue(emoteName, out var value2)) { CustomLogging.LogWarning("Failed to assign prop: " + propName + " to emote: " + emoteName + ". Emote does not exist!"); return; } if (!EmotePropManager.emotePropsDataDict.TryGetValue(propName, out var value3)) { CustomLogging.LogWarning("Failed to assign prop: " + propName + " to emote: " + emoteName + ". Prop data does not exist for: " + propName); return; } if (value2.propNamesInEmote == null) { value2.propNamesInEmote = new List(); } value2.propNamesInEmote.Add(propName); if (value3.parentEmotes == null) { value3.parentEmotes = new List(); } if (!value3.parentEmotes.Contains(value2)) { value3.parentEmotes.Add(value2); } } public static void SetEmoteDoesNotUseBoombox(string emoteName) { if (EmotesManager.allUnlockableEmotesDict.TryGetValue(emoteName, out var value)) { value.isBoomboxAudio = false; } } public static void SetCanMoveWhileEmoting(string emoteName) { if (EmotesManager.allUnlockableEmotesDict.TryGetValue(emoteName, out var value)) { value.canMoveWhileEmoting = true; } } public static void AssignMusicToEmote(string emoteName, string audioName, string audioLoopName = "") { if (EmotesManager.allUnlockableEmotesDict.TryGetValue(emoteName, out var value) && AudioManager.AudioExists(audioName)) { value.overrideAudioClipName = audioName; value.overrideAudioLoopClipName = audioLoopName; } } } public static class QuickEmotes { public static UnlockableEmote GetQuickEmote(int index) { if (index < 0 || index >= 8) { CustomLogging.LogError("Failed to get quick emote name at index: " + index + ". Index must be within range: 0 and 8"); return null; } string key = ES3.Load("QuickEmote" + index, SaveManager.TooManyEmotesSaveFileName, string.Empty); UnlockableEmote value = null; EmotesManager.allUnlockableEmotesDict.TryGetValue(key, out value); return value; } } public static class BoneMapper { public static Dictionary CreateBoneMap(Transform sourceSkeleton, Transform targetSkeleton, List sourceBoneNames, List 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) { CustomLogging.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 dictionary = new Dictionary(); 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 boneNames, Transform[] boneArray) { if ((Object)(object)((Component)bone).GetComponent() != (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); } } } internal static class CustomLogging { private static ManualLogSource logger; public static void InitLogger() { try { logger = Logger.CreateLogSource($"{((BaseUnityPlugin)Plugin.instance).Info.Metadata.Name}-{((BaseUnityPlugin)Plugin.instance).Info.Metadata.Version}"); } catch { logger = Plugin.defaultLogger; } } 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 void LogVerbose(string message) { if (ConfigSettings.verboseLogs.Value) { logger.LogInfo((object)("[VERBOSE] " + message)); } } public static void LogErrorVerbose(string message) { if (ConfigSettings.verboseLogs.Value) { logger.LogError((object)("[VERBOSE] " + message)); } } public static void LogWarningVerbose(string message) { if (ConfigSettings.verboseLogs.Value) { logger.LogWarning((object)("[VERBOSE] " + message)); } } public static bool Assert(bool condition, string failMessage) { if (!condition) { LogWarning(failMessage); } return condition; } } public class OnAnimatorIKHandler : MonoBehaviour { private EmoteController emoteController; private Animator animator; public float handIKWeight = 0.8f; private void Awake() { animator = ((Component)this).GetComponent(); if ((Object)(object)animator == (Object)null) { CustomLogging.LogWarning("OnIKHandler must be attached to a gameobject with an animator component."); } } public void SetParentEmoteController(EmoteController emoteController) { this.emoteController = emoteController; } protected void OnAnimatorIK(int layerIndex) { //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Unknown result type (might be due to invalid IL or missing references) //IL_0178: Unknown result type (might be due to invalid IL or missing references) //IL_017d: Unknown result type (might be due to invalid IL or missing references) //IL_01bb: Unknown result type (might be due to invalid IL or missing references) if (Object.op_Implicit((Object)(object)emoteController) && emoteController.initialized && emoteController.IsPerformingCustomEmote()) { if (Object.op_Implicit((Object)(object)emoteController.ikLeftHand) && emoteController.ikLeftHand.localPosition != Vector3.zero) { animator.SetIKPositionWeight((AvatarIKGoal)2, handIKWeight); animator.SetIKRotationWeight((AvatarIKGoal)2, handIKWeight); animator.SetIKPosition((AvatarIKGoal)2, emoteController.ikLeftHand.position); animator.SetIKRotation((AvatarIKGoal)2, emoteController.ikLeftHand.rotation); } if (Object.op_Implicit((Object)(object)emoteController.ikRightHand) && emoteController.ikRightHand.localPosition != Vector3.zero) { animator.SetIKPositionWeight((AvatarIKGoal)3, handIKWeight); animator.SetIKRotationWeight((AvatarIKGoal)3, handIKWeight); animator.SetIKPosition((AvatarIKGoal)3, emoteController.ikRightHand.position); animator.SetIKRotation((AvatarIKGoal)3, emoteController.ikRightHand.rotation); } if (Object.op_Implicit((Object)(object)emoteController.ikHead) && emoteController.ikHead.localPosition != Vector3.zero) { animator.SetLookAtWeight(1f, 0.25f, 0.5f); animator.SetLookAtPosition(emoteController.ikHead.position); } } } } [HarmonyPatch] public class EmoteSyncGroup { public static int currentEmoteSyncId = 0; public static Dictionary allEmoteSyncGroups = new Dictionary(); public int syncId = -1; public List syncGroup; public Dictionary leadEmoteControllerByEmote = new Dictionary(); public Dictionary currentEmoteAudioSources; public float timeStartedEmote; public UnlockableEmote performingEmote; public bool useAudio = true; public EmoteAudioPlayer currentAudioPlayer; public EmoteController leadEmoteController => (syncGroup != null && syncGroup.Count > 0) ? syncGroup[0] : null; public EmoteAudioSource leadEmoteAudioSource { get { if (currentEmoteAudioSources != null && currentEmoteAudioSources.Count > 0) { foreach (EmoteController item in syncGroup) { if ((Object)(object)item?.personalEmoteAudioSource != (Object)null && currentEmoteAudioSources.ContainsValue(item.personalEmoteAudioSource)) { return item.personalEmoteAudioSource; } } } return null; } } [HarmonyPatch(typeof(StartOfRound), "Awake")] [HarmonyPrefix] public static void Init() { currentEmoteSyncId = 0; allEmoteSyncGroups?.Clear(); } public static EmoteSyncGroup CreateEmoteSyncGroup(EmoteController emoteController, bool useAudio = true) { return new EmoteSyncGroup(emoteController, useAudio); } public EmoteSyncGroup(EmoteController emoteController, bool useAudio = true) { syncGroup = new List { emoteController }; syncId = currentEmoteSyncId++; performingEmote = emoteController.performingEmote; leadEmoteControllerByEmote.Add(performingEmote, emoteController); this.useAudio = useAudio; if (useAudio && performingEmote.hasAudio) { if (!performingEmote.isBoomboxAudio) { currentEmoteAudioSources = new Dictionary(); if ((Object)(object)emoteController.personalEmoteAudioSource == (Object)null) { CustomLogging.LogError("Attempted to perform emote with personal audio source, which is null."); this.useAudio = false; } else { currentEmoteAudioSources[performingEmote] = emoteController.personalEmoteAudioSource; emoteController.personalEmoteAudioSource.SyncWithEmoteControllerAudio(emoteController); emoteController.personalEmoteAudioSource.AddToEmoteSyncGroup(this); } } else { EmoteAudioPlayer nearestEmoteAudioPlayer = EmoteAudioPlayerManager.GetNearestEmoteAudioPlayer(((Component)emoteController).transform); if ((Object)(object)nearestEmoteAudioPlayer != (Object)null && nearestEmoteAudioPlayer.CanPlayMusic()) { AssignExternalAudioPlayer(nearestEmoteAudioPlayer); } else { CustomLogging.LogWarning("Performing emote with no music. No available boomboxes found nearby. Don't worry. Everything will be okay."); } } UpdateAudioVolume(); } allEmoteSyncGroups[syncId] = this; timeStartedEmote = Time.time; } public void AddToEmoteSyncGroup(EmoteController emoteController) { if (syncGroup == null || syncGroup.Contains(emoteController)) { return; } syncGroup.Add(emoteController); if (!leadEmoteControllerByEmote.ContainsKey(emoteController.performingEmote) || (Object)(object)leadEmoteControllerByEmote[emoteController.performingEmote] == (Object)null) { leadEmoteControllerByEmote[emoteController.performingEmote] = emoteController; } if (!useAudio || !performingEmote.hasAudio) { return; } if (!performingEmote.isBoomboxAudio) { if (currentEmoteAudioSources != null && (!currentEmoteAudioSources.ContainsKey(emoteController.performingEmote) || (Object)(object)currentEmoteAudioSources[emoteController.performingEmote] == (Object)null)) { currentEmoteAudioSources[emoteController.performingEmote] = emoteController.personalEmoteAudioSource; emoteController.personalEmoteAudioSource.SyncWithEmoteSyncGroup(this, emoteController); emoteController.personalEmoteAudioSource.AddToEmoteSyncGroup(this); } } else if ((Object)(object)currentAudioPlayer == (Object)null) { EmoteAudioPlayer nearestEmoteAudioPlayer = EmoteAudioPlayerManager.GetNearestEmoteAudioPlayer(((Component)emoteController).transform); if ((Object)(object)nearestEmoteAudioPlayer != (Object)null && nearestEmoteAudioPlayer.CanPlayMusic()) { AssignExternalAudioPlayer(nearestEmoteAudioPlayer); } } UpdateAudioVolume(); } public void RemoveFromEmoteSyncGroup(EmoteController emoteController) { if (syncGroup == null) { return; } syncGroup.Remove(emoteController); if (syncGroup.Count <= 0) { DestroyEmoteSyncGroup(); return; } if (leadEmoteControllerByEmote.ContainsValue(emoteController)) { UnlockableEmote key = leadEmoteControllerByEmote.FirstOrDefault((KeyValuePair x) => (Object)(object)x.Value == (Object)(object)emoteController).Key; leadEmoteControllerByEmote.Remove(key); foreach (EmoteController item in syncGroup) { if ((Object)(object)item == (Object)null || item.performingEmote == null || item.performingEmote != key) { continue; } leadEmoteControllerByEmote[key] = item; break; } } if (currentEmoteAudioSources == null) { return; } if (currentEmoteAudioSources.ContainsValue(emoteController.personalEmoteAudioSource)) { emoteController.personalEmoteAudioSource.StopAudio(); emoteController.personalEmoteAudioSource.RemoveFromEmoteSyncGroup(); UnlockableEmote key2 = currentEmoteAudioSources.FirstOrDefault((KeyValuePair x) => (Object)(object)x.Value == (Object)(object)emoteController.personalEmoteAudioSource).Key; currentEmoteAudioSources.Remove(key2); if (useAudio && key2.hasAudio && !key2.isBoomboxAudio) { foreach (EmoteController item2 in syncGroup) { if (!((Object)(object)item2 == (Object)null) && item2.performingEmote != null && !((Object)(object)item2 == (Object)(object)emoteController)) { EmoteAudioSource personalEmoteAudioSource = item2.personalEmoteAudioSource; if (item2.performingEmote == key2 && (Object)(object)personalEmoteAudioSource != (Object)null && personalEmoteAudioSource.CanPlayMusic()) { currentEmoteAudioSources[key2] = personalEmoteAudioSource; personalEmoteAudioSource.SyncWithEmoteControllerAudio(item2); break; } } } } } UpdateAudioVolume(); } public void DestroyEmoteSyncGroup() { CustomLogging.LogVerbose("Cleaning up emote sync group with id: " + syncId); if (currentEmoteAudioSources != null) { foreach (EmoteAudioSource value in currentEmoteAudioSources.Values) { if ((Object)(object)value != (Object)null) { value.StopAudio(); value.RemoveFromEmoteSyncGroup(); } } currentEmoteAudioSources = null; } if ((Object)(object)currentAudioPlayer != (Object)null) { currentAudioPlayer.StopAudio(); currentAudioPlayer.RemoveFromEmoteSyncGroup(); } allEmoteSyncGroups.Remove(syncId); syncGroup = null; syncId = -1; } public void UpdateAudioVolume() { if (currentEmoteAudioSources != null) { foreach (EmoteAudioSource value in currentEmoteAudioSources.Values) { if ((Object)(object)value != (Object)null) { value.UpdateVolume(); } } } if ((Object)(object)currentAudioPlayer != (Object)null) { currentAudioPlayer.UpdateVolume(); } } public void AssignExternalAudioPlayer(EmoteAudioPlayer audioPlayer) { if ((Object)(object)currentAudioPlayer != (Object)null) { currentAudioPlayer.StopAudio(); currentAudioPlayer.RemoveFromEmoteSyncGroup(); currentAudioPlayer = null; } if (useAudio && performingEmote.hasAudio && performingEmote.isBoomboxAudio) { currentAudioPlayer = audioPlayer; if ((Object)(object)currentAudioPlayer != (Object)null) { currentAudioPlayer.SyncWithEmoteControllerAudio(leadEmoteController); currentAudioPlayer.AddToEmoteSyncGroup(this); currentAudioPlayer.UpdateVolume(); } } } } internal static class HelperTools { public static NetworkManager networkManager => NetworkManager.Singleton; public static bool isClient => networkManager.IsClient; public static bool isServer => networkManager.IsServer; public static bool isHost => networkManager.IsHost; public static PlayerControllerB localPlayerController => StartOfRound.Instance?.localPlayerController; public static QuickMenuManager quickMenuManager => localPlayerController?.quickMenuManager; public static TextMeshProUGUI[] controlTipLines => HUDManager.Instance?.controlTipLines; public static List allItems => StartOfRound.Instance?.allItemsList?.itemsList; public static SelectableLevel[] selectableLevels => StartOfRound.Instance?.levels; public static string currentSaveFileName => GameNetworkManager.Instance?.currentSaveFileName; public static int groupCredits => ((Object)(object)TerminalPatcher.terminalInstance != (Object)null) ? groupCredits : (-1); public static int currentEmoteCredits => TerminalPatcher.currentEmoteCredits; public static EmoteControllerPlayer emoteControllerLocal => EmoteControllerPlayer.emoteControllerLocal; 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 static EmoteController GetEmoteControllerById(ulong id) { foreach (EmoteController value in EmoteController.allEmoteControllers.Values) { if (value.emoteControllerId == id) { return value; } } return null; } public static GrabbableObject GetHeldGrabbable(this PlayerControllerB playerController) { int currentItemSlot = playerController.currentItemSlot; return (currentItemSlot == 50) ? playerController.ItemOnlySlot : playerController.ItemSlots[currentItemSlot]; } } [HarmonyPatch] public class EmoteControllerMaskedEnemy : EmoteController { public static Dictionary allMaskedEnemyEmoteControllers = new Dictionary(); 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() : 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"); public override void Initialize(string sourceRootBoneName = "metarig") { base.Initialize(); if (initialized) { maskedEnemy = ((Component)this).GetComponentInParent(); if ((Object)(object)maskedEnemy == (Object)null) { CustomLogging.LogError("Failed to find MaskedPlayerEnemy component in parent of EmoteControllerMaskedEnemy."); } else { allMaskedEnemyEmoteControllers.Add(maskedEnemy, this); } } } 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 bool PerformEmote(UnlockableEmote emote, int overrideEmoteId = -1, bool doNotTriggerAudio = false) { //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) bool result = base.PerformEmote(emote, overrideEmoteId, doNotTriggerAudio); if (isPerformingEmote) { emoteCount++; emotedAtPosition = ((Component)maskedEnemy).transform.position; } return result; } 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(); } } [DefaultExecutionOrder(-2)] public class EmoteControllerPlayer : EmoteController { public static Dictionary allPlayerEmoteControllers = new Dictionary(); public PlayerControllerB playerController; public Animator originalAnimator; private Dictionary boneMapLocalPlayerArms; internal Transform humanoidHead; private Transform cameraContainerTarget; private Transform cameraContainerLerp; public static List sourceBoneNames = new List { "spine", "spine.001", "spine.002", "spine.003", "spine.004", "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 GrabbablePropObject sourceGrabbableEmoteProp; internal static float timeLastPeformedEmoteLocalPlayer = 0f; public static EmoteControllerPlayer emoteControllerLocal => ((Object)(object)HelperTools.localPlayerController != (Object)null && allPlayerEmoteControllers.ContainsKey(HelperTools.localPlayerController)) ? allPlayerEmoteControllers[HelperTools.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); } } public override void Initialize(string sourceRootBoneName = "metarig") { base.Initialize(); if (initialized) { originalAnimator = ((Component)metarig).GetComponentInChildren(); playerController = ((Component)this).GetComponentInParent(); if ((Object)(object)playerController == (Object)null) { CustomLogging.LogError("Failed to find PlayerControllerB component in parent of EmoteControllerPlayer."); } else { allPlayerEmoteControllers.Add(playerController, this); } } } protected override void Start() { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) base.Start(); if (initialized) { Transform val = FindChildRecursive("spine.004", metarig); if ((Object)(object)val != (Object)null) { cameraContainerTarget = new GameObject("CameraContainer_Target").transform; cameraContainerTarget.SetParent(val); cameraContainerTarget.localPosition = new Vector3(0f, 0.22f, 0f); cameraContainerTarget.localEulerAngles = new Vector3(-3f, 0f, 0f); cameraContainerLerp = new GameObject("CameraContainer_Lerp").transform; cameraContainerLerp.SetParent(humanoidSkeleton); cameraContainerLerp.SetLocalPositionAndRotation(Vector3.zero, Quaternion.identity); } humanoidHead = FindChildRecursive("head", humanoidSkeleton); if (!Object.op_Implicit((Object)(object)humanoidHead)) { CustomLogging.LogError("Failed to find Head on: " + base.emoteControllerName); } } } 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)HelperTools.localPlayerController) || (!ConfigSettings.disableEmotesForSelf.Value && !LCVR_Compat.LoadedAndEnabled))) { 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)HelperTools.localPlayerController && (ConfigSettings.disableEmotesForSelf.Value || LCVR_Compat.LoadedAndEnabled))) { 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() { //IL_006c: 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) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_0194: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_0209: Unknown result type (might be due to invalid IL or missing references) //IL_0222: Unknown result type (might be due to invalid IL or missing references) if (!initialized || !isPerformingEmote || (Object)(object)playerController == (Object)null) { return; } base.TranslateAnimation(); if (Object.op_Implicit((Object)(object)humanoidHead) && Object.op_Implicit((Object)(object)cameraContainerLerp) && Object.op_Implicit((Object)(object)cameraContainerTarget)) { cameraContainerLerp.position = Vector3.Lerp(cameraContainerLerp.position, cameraContainerTarget.position, 25f * Time.deltaTime); cameraContainerLerp.rotation = Quaternion.Lerp(cameraContainerLerp.rotation, cameraContainerTarget.rotation, 25f * Time.deltaTime); if (!isLocalPlayer || !ThirdPersonEmoteController.firstPersonEmotesEnabled || !ThirdPersonEmoteController.isMovingWhileEmoting) { playerController.cameraContainerTransform.position = cameraContainerLerp.position; playerController.cameraContainerTransform.rotation = cameraContainerLerp.rotation; } if (isLocalPlayer) { playerController.localVisor.position = playerController.localVisorTargetPoint.position; playerController.localVisor.rotation = playerController.localVisorTargetPoint.rotation; } } if (!isLocalPlayer) { return; } playerController.playerModelArmsMetarig.rotation = playerController.localArmsRotationTarget.rotation; if (boneMapLocalPlayerArms == null) { return; } foreach (KeyValuePair boneMapLocalPlayerArm in boneMapLocalPlayerArms) { Transform key = boneMapLocalPlayerArm.Key; Transform value = boneMapLocalPlayerArm.Value; if (!((Object)(object)key == (Object)null) && !((Object)(object)value == (Object)null)) { ((Component)value).transform.position = ((Component)key).transform.position; ((Component)value).transform.rotation = ((Component)key).transform.rotation; } } } protected override bool CheckIfShouldStopEmoting() { if ((Object)(object)playerController == (Object)null || !isPerformingEmote) { return false; } if (base.CheckIfShouldStopEmoting() || !playerController.performingEmote || performingEmote == null) { return true; } GrabbableObject heldGrabbable = playerController.GetHeldGrabbable(); if ((Object)(object)sourceGrabbableEmoteProp != (Object)null && (Object)(object)sourceGrabbableEmoteProp != (Object)(object)heldGrabbable) { return true; } return false; } public override bool IsPerformingCustomEmote() { return base.IsPerformingCustomEmote(); } public bool TryPerformingEmoteLocal(UnlockableEmote emote, int overrideEmoteId = -1, GrabbablePropObject sourcePropObject = null) { if (!initialized || ConfigSettings.disableEmotesForSelf.Value || LCVR_Compat.LoadedAndEnabled) { return false; } if (!isLocalPlayer) { CustomLogging.LogWarning("Cannot run TryPerformEmoteLocal on a character who does not belong to the local player. This is not allowed."); return false; } if (Time.time - timeLastPeformedEmoteLocalPlayer < 0.25f) { return false; } CustomLogging.Log("Attempting to perform emote on local player."); if (!CanPerformEmote()) { return false; } if (overrideEmoteId >= 0 && (emote.emoteSyncGroup == null || emote.emoteSyncGroup.Count <= 1 || overrideEmoteId < 0 || overrideEmoteId >= emote.emoteSyncGroup.Count)) { overrideEmoteId = -1; } if (emote.emoteSyncGroup != null && emote.emoteSyncGroup.Count > 1) { if (emote.randomEmote) { if (overrideEmoteId < 0) { overrideEmoteId = Random.Range(0, emote.emoteSyncGroup.Count); } } else { emote = emote.emoteSyncGroup[0]; } } if (overrideEmoteId >= 0 && emote.emoteSyncGroup != null && overrideEmoteId < emote.emoteSyncGroup.Count) { emote = emote.emoteSyncGroup[overrideEmoteId]; } else { overrideEmoteId = -1; } EmoteController emoteController = null; if (isPerformingEmote && performingEmote.IsEmoteInEmoteGroup(emote) && (!performingEmote.randomEmote || performingEmote.loopable)) { if (performingEmote.emoteSyncGroup != null && performingEmote.emoteSyncGroup.Count > 1) { overrideEmoteId = (performingEmote.emoteSyncGroup.IndexOf(performingEmote) + 1) % performingEmote.emoteSyncGroup.Count; if (performingEmote.emoteSyncGroup[overrideEmoteId] != null) { emote = performingEmote.emoteSyncGroup[overrideEmoteId]; } } if (emoteSyncGroup?.syncGroup != null && emoteSyncGroup.syncGroup.Count > 1) { if (emoteSyncGroup.syncGroup.Count > 1 && (performingEmote?.emoteSyncGroup == null || performingEmote.emoteSyncGroup.Count <= 1)) { timeLastPeformedEmoteLocalPlayer = Time.time; return true; } foreach (EmoteController item in emoteSyncGroup.syncGroup) { if ((Object)(object)item != (Object)(object)this) { emoteController = item; break; } } } } if ((Object)(object)emoteController != (Object)null) { return TrySyncingEmoteWithEmoteController(emoteController, overrideEmoteId); } CustomLogging.LogWarningVerbose("Trying to perform emote on local player. Emote: " + emote.emoteName + " | Emote id: " + emote.emoteId); bool result = ((!((Object)(object)sourcePropObject != (Object)null) || !((Object)(object)sourcePropObject == (Object)(object)HelperTools.localPlayerController.GetHeldGrabbable())) ? PerformEmote(emote, overrideEmoteId, AudioManager.emoteOnlyMode) : PerformEmote(emote, sourcePropObject, overrideEmoteId, AudioManager.emoteOnlyMode)); playerController.StartPerformingEmoteServerRpc(); SyncPerformingEmoteManager.SendPerformingEmoteUpdateToServer(emote, AudioManager.emoteOnlyMode); timeSinceStartingEmote = 0f; playerController.performingEmote = true; return result; } public bool TrySyncingEmoteWithEmoteController(EmoteController emoteController, int overrideEmoteId = -1) { if (!initialized || (Object)(object)emoteController == (Object)null || ConfigSettings.disableEmotesForSelf.Value || LCVR_Compat.LoadedAndEnabled) { return false; } if (!isLocalPlayer) { CustomLogging.LogWarning("Cannot run TrySyncingEmoteWithEmoteController on a character who does not belong to the local player. This is not allowed."); return false; } if (Time.time - timeLastPeformedEmoteLocalPlayer < 0.25f) { return false; } CustomLogging.Log("Attempting to sync emote for player: " + ((Object)playerController).name + " with emote controller with id: " + emoteController.emoteControllerId); if (!CanPerformEmote() || !emoteController.IsPerformingCustomEmote()) { return false; } if (overrideEmoteId >= 0 && (emoteController.performingEmote?.emoteSyncGroup == null || overrideEmoteId >= emoteController.performingEmote.emoteSyncGroup.Count || emoteController.performingEmote.emoteSyncGroup[overrideEmoteId] == null)) { overrideEmoteId = -1; } SyncWithEmoteController(emoteController, overrideEmoteId); if (performingEmote != null) { if (performingEmote.inEmoteSyncGroup) { overrideEmoteId = performingEmote.emoteSyncGroup.IndexOf(performingEmote); } playerController.StartPerformingEmoteServerRpc(); SyncPerformingEmoteManager.SendSyncEmoteUpdateToServer(emoteController, overrideEmoteId); timeSinceStartingEmote = 0f; playerController.performingEmote = true; timeLastPeformedEmoteLocalPlayer = Time.time; return true; } return false; } public override bool CanPerformEmote() { if (!isLocalPlayer) { return true; } if (!initialized || ConfigSettings.disableEmotesForSelf.Value || LCVR_Compat.LoadedAndEnabled) { 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; } [HarmonyPatch(typeof(PlayerControllerB), "SwitchToItemSlot")] [HarmonyPostfix] private static void OnSwapItem(int slot, PlayerControllerB __instance) { if (allPlayerEmoteControllers.TryGetValue(__instance, out var value) && value.IsPerformingCustomEmote()) { GrabbableObject heldGrabbable = __instance.GetHeldGrabbable(); if ((Object)(object)value.sourceGrabbableEmoteProp != (Object)null && (Object)(object)value.sourceGrabbableEmoteProp != (Object)(object)heldGrabbable) { value.StopPerformingEmote(); } else if (Object.op_Implicit((Object)(object)heldGrabbable) && value.emotingProps.Count > 0) { heldGrabbable.EnableItemMeshes(false); } } } public bool PerformEmote(UnlockableEmote emote, GrabbablePropObject sourcePropObject, int overrideEmoteId = -1, bool doNotTriggerAudio = false) { if ((Object)(object)sourcePropObject != (Object)null && (Object)(object)sourcePropObject == (Object)(object)playerController.GetHeldGrabbable()) { sourceGrabbableEmoteProp = sourcePropObject; } bool result = PerformEmote(emote, overrideEmoteId, doNotTriggerAudio); if (isPerformingEmote) { if (!isLocalPlayer && SyncManager.isSynced && ConfigSync.instance.syncPersistentUnlocksGlobal && !SessionManager.unlockedEmotesByPlayer.TryGetValue(playerController.playerUsername, out var value) && !value.Contains(performingEmote)) { SessionManager.UnlockEmoteLocal(emote.emoteId, purchased: false, playerController.playerUsername); } } else { StopPerformingEmote(); } return result; } public override bool PerformEmote(UnlockableEmote emote, int overrideEmoteId = -1, bool doNotTriggerAudio = false) { //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)playerController == (Object)null || (isLocalPlayer && (ConfigSettings.disableEmotesForSelf.Value || LCVR_Compat.LoadedAndEnabled))) { return false; } bool result = base.PerformEmote(emote, overrideEmoteId, doNotTriggerAudio); if (isPerformingEmote) { cameraContainerLerp.SetPositionAndRotation(cameraContainerTarget.position, cameraContainerTarget.rotation); playerController.performingEmote = true; originalAnimator.SetInteger("emoteNumber", 1); GrabbableObject heldGrabbable = playerController.GetHeldGrabbable(); if (Object.op_Implicit((Object)(object)heldGrabbable) && emotingProps.Count > 0) { heldGrabbable.EnableItemMeshes(false); } if (isLocalPlayer) { ThirdPersonEmoteController.OnStartCustomEmoteLocal(); playerController.StartPerformingEmoteServerRpc(); } } return result; } public override bool SyncWithEmoteController(EmoteController emoteController, int overrideEmoteId = -1) { //IL_0059: 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) if ((Object)(object)playerController == (Object)null || (isLocalPlayer && (ConfigSettings.disableEmotesForSelf.Value || LCVR_Compat.LoadedAndEnabled))) { return false; } bool result = base.SyncWithEmoteController(emoteController, overrideEmoteId); if (isPerformingEmote) { cameraContainerLerp.SetPositionAndRotation(cameraContainerTarget.position, cameraContainerTarget.rotation); playerController.performingEmote = true; originalAnimator.SetInteger("emoteNumber", 1); if (isLocalPlayer) { ThirdPersonEmoteController.OnStartCustomEmoteLocal(); playerController.StartPerformingEmoteServerRpc(); } } return result; } public override void StopPerformingEmote() { //IL_0043: 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_0109: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)playerController == (Object)null || (isLocalPlayer && ConfigSettings.disableEmotesForSelf.Value)) { return; } base.StopPerformingEmote(); cameraContainerLerp.SetPositionAndRotation(cameraContainerTarget.position, cameraContainerTarget.rotation); GrabbableObject heldGrabbable = playerController.GetHeldGrabbable(); if (Object.op_Implicit((Object)(object)heldGrabbable)) { heldGrabbable.EnableItemMeshes(true); } if ((Object)(object)sourceGrabbableEmoteProp != (Object)null) { if (sourceGrabbableEmoteProp.isPerformingEmote) { sourceGrabbableEmoteProp.StopEmote(); } sourceGrabbableEmoteProp = null; } playerController.playerBodyAnimator.SetInteger("emote_number", 0); playerController.performingEmote = false; playerController.playerBodyAnimator.Update(0f); if (isLocalPlayer) { ThirdPersonEmoteController.OnStopCustomEmoteLocal(); ((Component)playerController.gameplayCamera).transform.SetLocalPositionAndRotation(Vector3.zero, Quaternion.identity); playerController.StopPerformingEmoteServerRpc(); } } public override void ResetPerformingEmote() { if ((Object)(object)playerController == (Object)null || (isLocalPlayer && ConfigSettings.disableEmotesForSelf.Value)) { return; } base.ResetPerformingEmote(); if ((Object)(object)sourceGrabbableEmoteProp != (Object)null) { if (sourceGrabbableEmoteProp.isPerformingEmote) { sourceGrabbableEmoteProp.StopEmote(); } sourceGrabbableEmoteProp = null; } GrabbableObject heldGrabbable = playerController.GetHeldGrabbable(); if (Object.op_Implicit((Object)(object)heldGrabbable)) { heldGrabbable.EnableItemMeshes(true); } } protected override void CreateBoneMap() { boneMap = BoneMapper.CreateBoneMap(humanoidSkeleton, metarig, sourceBoneNames); List list = new List { "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", "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" }; boneMapLocalPlayerArms = BoneMapper.CreateBoneMap(humanoidSkeleton, playerController.localArmsTransform, list); } 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] [DefaultExecutionOrder(-2)] public class EmoteController : MonoBehaviour { public static Dictionary allEmoteControllers = new Dictionary(); public bool initialized = false; public Transform metarig; public Transform humanoidSkeleton; public Animator animator; public AnimatorOverrideController animatorController; public bool isPerformingEmote = false; public UnlockableEmote performingEmote; protected Dictionary boneMap; public List groundContactPoints = new List(); public Transform propsParent; public List emotingProps = new List(); public Transform ikLeftHand; public Transform ikRightHand; public Transform ikLeftFoot; public Transform ikRightFoot; public Transform ikHead; public EmoteSyncGroup emoteSyncGroup; public EmoteAudioSource personalEmoteAudioSource; private float timePerformedEmote = 0f; public bool smoothTransitionToEmote = false; public ulong emoteControllerId => GetEmoteControllerId(); public string emoteControllerName => GetEmoteControllerName(); public float currentAnimationTimeNormalized { 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 float currentAnimationTime { get { AnimationClip currentAnimationClip = GetCurrentAnimationClip(); return ((Object)(object)currentAnimationClip != (Object)null) ? (currentAnimationClip.length * (currentAnimationTimeNormalized % 1f)) : 0f; } } public int currentStateHash { 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)).shortNameHash; } } public bool isLooping { get { return animator.GetBool("loop"); } set { animator.SetBool("loop", value); } } public bool isAnimatorInLoopingState { 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)).IsName("emote_loop"); } } public bool isSimpleEmoteController => ((object)this).GetType() == typeof(EmoteController); public int emoteSyncId => (emoteSyncGroup != null) ? emoteSyncGroup.syncId : (-1); protected virtual void Awake() { if (!initialized) { Initialize(); } } public virtual void Initialize(string sourceRootBoneName = "metarig") { //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Expected O, but got Unknown //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_0151: Unknown result type (might be due to invalid IL or missing references) //IL_0157: Expected O, but got Unknown //IL_016f: Unknown result type (might be due to invalid IL or missing references) //IL_0174: Unknown result type (might be due to invalid IL or missing references) //IL_0185: Unknown result type (might be due to invalid IL or missing references) //IL_01df: Unknown result type (might be due to invalid IL or missing references) //IL_0206: Unknown result type (might be due to invalid IL or missing references) //IL_020b: Unknown result type (might be due to invalid IL or missing references) //IL_021c: Unknown result type (might be due to invalid IL or missing references) if (initialized || (Object)(object)Plugin.humanoidSkeletonPrefab == (Object)null || (Object)(object)Plugin.humanoidAnimatorController == (Object)null || (Object)(object)Plugin.humanoidAvatar == (Object)null) { return; } try { metarig = FindChildRecursive(sourceRootBoneName, ((Component)this).transform); humanoidSkeleton = Object.Instantiate(Plugin.humanoidSkeletonPrefab, metarig.parent).transform; ((Object)humanoidSkeleton).name = "HumanoidSkeleton"; humanoidSkeleton.SetSiblingIndex(metarig.GetSiblingIndex() + 1); animator = ((Component)humanoidSkeleton).GetComponent(); OnAnimatorIKHandler onAnimatorIKHandler = ((Component)animator).gameObject.AddComponent(); onAnimatorIKHandler.SetParentEmoteController(this); animatorController = new AnimatorOverrideController(Plugin.humanoidAnimatorController); animator.runtimeAnimatorController = (RuntimeAnimatorController)(object)animatorController; humanoidSkeleton.SetLocalPositionAndRotation(metarig.localPosition + Vector3.down * 0.025f, Quaternion.identity); humanoidSkeleton.localScale = metarig.localScale; if (!isSimpleEmoteController) { allEmoteControllers.Add(((Component)this).gameObject, this); GameObject val = new GameObject("PersonalEmoteAudioSource"); val.transform.SetParent(humanoidSkeleton); val.transform.SetLocalPositionAndRotation(Vector3.zero, Quaternion.identity); val.transform.localScale = Vector3.one; personalEmoteAudioSource = val.AddComponent(); } if ((Object)(object)propsParent == (Object)null) { propsParent = ((Component)this).transform.Find("EmoteProps"); if ((Object)(object)propsParent == (Object)null) { propsParent = new GameObject("EmoteProps").transform; propsParent.SetParent(humanoidSkeleton); propsParent.SetLocalPositionAndRotation(Vector3.zero, Quaternion.identity); propsParent.localScale = Vector3.one; } } initialized = true; } catch (Exception ex) { Debug.LogError((object)("Failed to initialize EmoteController. Error: " + ex)); } } protected virtual void Start() { if (!initialized) { return; } if (boneMap == null) { 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."); } } FindIkBones(); } protected virtual void OnEnable() { } protected virtual void OnDisable() { if (isPerformingEmote) { StopPerformingEmote(); } } protected virtual void OnDestroy() { if (isPerformingEmote) { StopPerformingEmote(); } allEmoteControllers?.Remove(((Component)this).gameObject); if (SyncPerformingEmoteManager.doNotTriggerAudioDict.ContainsKey(this)) { SyncPerformingEmoteManager.doNotTriggerAudioDict.Remove(this); } } protected virtual void Update() { if (initialized) { } } protected virtual void LateUpdate() { if (initialized) { if (isPerformingEmote && CheckIfShouldStopEmoting()) { StopPerformingEmote(); } if (!((Object)(object)animator == (Object)null) && !((Object)(object)animatorController == (Object)null) && boneMap != null && isPerformingEmote) { TranslateAnimation(); } } } protected virtual void TranslateAnimation() { //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00be: 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_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) if (performingEmote == null || boneMap == null || boneMap.Count <= 0) { return; } foreach (KeyValuePair item in boneMap) { Transform key = item.Key; Transform value = item.Value; if (!((Object)(object)key == (Object)null) && !((Object)(object)value == (Object)null)) { float num = Time.time - timePerformedEmote; float num2 = (smoothTransitionToEmote ? Mathf.Clamp01(num / 0.2f) : 1f); ((Component)value).transform.position = Vector3.Lerp(((Component)value).transform.position, ((Component)key).transform.position, num2); ((Component)value).transform.rotation = Quaternion.Slerp(((Component)value).transform.rotation, ((Component)key).transform.rotation, num2); } } } protected virtual bool CheckIfShouldStopEmoting() { if (isPerformingEmote) { return performingEmote == null || (!performingEmote.loopable && !performingEmote.isPose && currentAnimationTimeNormalized >= 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 initialized && (Object)(object)animator != (Object)null && ((Behaviour)animator).enabled; } public virtual bool PerformEmote(UnlockableEmote emote, int overrideEmoteId = -1, bool doNotTriggerAudio = false) { if (!initialized || !CanPerformEmote()) { return false; } if (!isSimpleEmoteController) { CustomLogging.Log("[" + emoteControllerName + "] Performing emote: " + emote.emoteName); } if (isPerformingEmote) { ResetPerformingEmote(); } if (emote.emoteSyncGroup != null) { if (overrideEmoteId >= 0 && overrideEmoteId < emote.emoteSyncGroup.Count && emote.emoteSyncGroup[overrideEmoteId] != null) { emote = emote.emoteSyncGroup[overrideEmoteId]; } else if (emote.randomEmote) { int index = Random.Range(0, emote.emoteSyncGroup.Count); UnlockableEmote unlockableEmote = emote.emoteSyncGroup[index]; if (unlockableEmote != null) { emote = unlockableEmote; } } } 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("emote", 0, 0f); animator.Update(0f); performingEmote = emote; isPerformingEmote = true; timePerformedEmote = Time.time; RecordStartingBonePositions(); PerformEmoteProps(); if (!isSimpleEmoteController) { CreateEmoteSyncGroup(doNotTriggerAudio); } DiscoBallPatcher.OnPerformEmote(this); return true; } public virtual bool SyncWithEmoteController(EmoteController emoteController, int overrideEmoteId = -1) { if (!initialized || !CanPerformEmote() || (Object)(object)emoteController == (Object)null || !emoteController.IsPerformingCustomEmote()) { return false; } if (!isSimpleEmoteController) { CustomLogging.Log("[" + emoteControllerName + "] Attempting to sync with emote controller: " + ((Object)emoteController).name + " Emote: " + emoteController.performingEmote.emoteName + " PlayEmoteAtTimeNormalized: " + emoteController.currentAnimationTimeNormalized % 1f); } if (isPerformingEmote) { ResetPerformingEmote(); } EmoteSyncGroup emoteSyncGroup = emoteController.emoteSyncGroup; if (emoteSyncGroup == null) { CustomLogging.LogWarning("[" + emoteControllerName + "] Attempted to sync with emote controller who is not a part of an emote sync group. Continuing anyways."); } UnlockableEmote unlockableEmote = emoteController.performingEmote; if (unlockableEmote.emoteSyncGroup != null) { if (overrideEmoteId >= 0 && overrideEmoteId < unlockableEmote.emoteSyncGroup.Count && unlockableEmote.emoteSyncGroup[overrideEmoteId] != null) { unlockableEmote = unlockableEmote.emoteSyncGroup[overrideEmoteId]; } else if (unlockableEmote.randomEmote) { if (unlockableEmote.hasAudio && !unlockableEmote.isBoomboxAudio) { unlockableEmote = emoteController.performingEmote; } else { int index = Random.Range(0, unlockableEmote.emoteSyncGroup.Count); UnlockableEmote unlockableEmote2 = unlockableEmote.emoteSyncGroup[index]; if (unlockableEmote2 != null) { unlockableEmote = unlockableEmote2; } } } else { bool flag = false; foreach (UnlockableEmote item in unlockableEmote.emoteSyncGroup) { if (!emoteSyncGroup.leadEmoteControllerByEmote.ContainsKey(item) || (Object)(object)emoteSyncGroup.leadEmoteControllerByEmote[unlockableEmote] == (Object)null) { unlockableEmote = item; flag = true; break; } } if (!flag) { int num = unlockableEmote.emoteSyncGroup.IndexOf(unlockableEmote); if (num >= 0) { num = (num + 1) % unlockableEmote.emoteSyncGroup.Count; unlockableEmote = unlockableEmote.emoteSyncGroup[num]; } } } } AnimationClip currentAnimationClip = emoteController.GetCurrentAnimationClip(); if (!unlockableEmote.ClipIsInEmote(currentAnimationClip)) { CustomLogging.LogError("[" + emoteControllerName + "] Attempted to sync with emote controller whose animation clip is not a part of their performing emote? Emote: " + emoteController.performingEmote?.ToString() + " AnimationClip: " + ((Object)currentAnimationClip).name); return false; } animatorController["emote"] = unlockableEmote.animationClip; if ((Object)(object)unlockableEmote.transitionsToClip != (Object)null) { animatorController["emote_loop"] = unlockableEmote.transitionsToClip; } float num2 = emoteController.currentAnimationTimeNormalized % 1f; animator.SetBool("loop", (Object)(object)unlockableEmote.transitionsToClip != (Object)null); animator.Play(((Object)(object)currentAnimationClip == (Object)(object)unlockableEmote.transitionsToClip) ? "emote_loop" : "emote", 0, num2); animator.Update(0f); performingEmote = unlockableEmote; isPerformingEmote = true; PerformEmoteProps(); if (!isSimpleEmoteController && emoteController.emoteSyncGroup != null) { AddToEmoteSyncGroup(emoteController.emoteSyncGroup); } DiscoBallPatcher.OnPerformEmote(this); return true; } protected void PerformEmoteProps() { if ((Object)(object)propsParent != (Object)null && performingEmote.propNamesInEmote != null) { LoadEmoteProps(); } if (emotingProps == null) { return; } foreach (PropObject emotingProp in emotingProps) { emotingProp.SyncWithEmoteController(this); } } protected void LoadEmoteProps() { //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) UnloadEmoteProps(); if (performingEmote.propNamesInEmote == null) { return; } foreach (string item in performingEmote.propNamesInEmote) { PropObject propObject = EmotePropManager.LoadEmoteProp(item); propObject.SetPropLayer(6); emotingProps.Add(propObject); ((Component)propObject).transform.SetParent(propsParent); ((Component)propObject).transform.localPosition = Vector3.zero; ((Component)propObject).transform.localRotation = Quaternion.identity; } } protected void UnloadEmoteProps() { if (emotingProps == null) { return; } foreach (PropObject emotingProp in emotingProps) { ((Component)emotingProp).transform.SetParent(EmotePropManager.propPoolParent); emotingProp.active = false; } emotingProps.Clear(); } public virtual void StopPerformingEmote() { //IL_0094: 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_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) if (initialized) { isPerformingEmote = false; if (!isSimpleEmoteController) { CustomLogging.Log(string.Format("[" + emoteControllerName + "] Stopping emote.")); } animatorController["emote"] = null; animatorController["emote_loop"] = null; RemoveFromEmoteSyncGroup(); UnloadEmoteProps(); if ((Object)(object)ikLeftHand != (Object)null) { ikLeftHand.localPosition = Vector3.zero; } if ((Object)(object)ikRightHand != (Object)null) { ikRightHand.localPosition = Vector3.zero; } if ((Object)(object)ikLeftFoot != (Object)null) { ikLeftFoot.localPosition = Vector3.zero; } if ((Object)(object)ikRightFoot != (Object)null) { ikRightFoot.localPosition = Vector3.zero; } if ((Object)(object)ikHead != (Object)null) { ikHead.localPosition = Vector3.zero; } DiscoBallPatcher.OnStopPerformingEmote(this); } } public virtual void ResetPerformingEmote() { //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) if (initialized) { isPerformingEmote = false; animatorController["emote"] = null; animatorController["emote_loop"] = null; RemoveFromEmoteSyncGroup(); UnloadEmoteProps(); if ((Object)(object)ikLeftHand != (Object)null) { ikLeftHand.localPosition = Vector3.zero; } if ((Object)(object)ikRightHand != (Object)null) { ikRightHand.localPosition = Vector3.zero; } if ((Object)(object)ikLeftFoot != (Object)null) { ikLeftFoot.localPosition = Vector3.zero; } if ((Object)(object)ikRightFoot != (Object)null) { ikRightFoot.localPosition = Vector3.zero; } if ((Object)(object)ikHead != (Object)null) { ikHead.localPosition = Vector3.zero; } } } 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() { } public void CreateBoneMap(List sourceBoneNames, List targetBoneNames = null) { boneMap = BoneMapper.CreateBoneMap(humanoidSkeleton, metarig, sourceBoneNames, targetBoneNames); } protected virtual void FindIkBones() { Transform val = FindChildRecursive("root_ik"); if ((Object)(object)val == (Object)null) { CustomLogging.LogError("Failed to find root ik bone called \"root_ik\" in humanoid skeleton: " + emoteControllerName); return; } ikLeftHand = val.Find("hand_ik_l"); ikRightHand = val.Find("hand_ik_r"); ikLeftFoot = val.Find("foot_ik_l"); ikRightFoot = val.Find("foot_ik_r"); ikHead = val.Find("head_ik"); } protected virtual Transform FindChildRecursive(string objectName, Transform root = null) { if ((Object)(object)root == (Object)null) { root = humanoidSkeleton; } if (((Object)root).name == objectName) { return root; } for (int i = 0; i < root.childCount; i++) { Transform child = root.GetChild(i); Transform val = FindChildRecursive(objectName, child); if ((Object)(object)val != (Object)null) { return val; } } return null; } protected virtual ulong GetEmoteControllerId() { return 0uL; } protected virtual string GetEmoteControllerName() { return ((Object)this).name; } protected void CreateEmoteSyncGroup(bool doNotTriggerAudio = false) { emoteSyncGroup = EmoteSyncGroup.CreateEmoteSyncGroup(this, !doNotTriggerAudio); } protected void AddToEmoteSyncGroup(EmoteSyncGroup emoteSyncGroup) { CustomLogging.Log("Adding to emote sync group with id: " + emoteSyncGroup.syncId); emoteSyncGroup.AddToEmoteSyncGroup(this); this.emoteSyncGroup = emoteSyncGroup; } protected void RemoveFromEmoteSyncGroup() { if (emoteSyncGroup != null) { emoteSyncGroup.RemoveFromEmoteSyncGroup(this); } emoteSyncGroup = null; } protected void RecordStartingBonePositions() { } } [HarmonyPatch] public static class EmotesManager { public static List allUnlockableEmotes; public static Dictionary allUnlockableEmotesDict; public static List complementaryEmotes; internal static List complementaryEmotesDefault; public static List allFavoriteEmotes; public static List allQuickEmotes; public static List allEmotesTier0; public static List allEmotesTier1; public static List allEmotesTier2; public static List allEmotesTier3; public static HashSet blacklistedEmoteIds = new HashSet(); internal static CultureInfo defaultSortCulture = CultureInfo.CreateSpecificCulture("en-US"); public static void BuildEmotesList() { allUnlockableEmotes = new List(); allUnlockableEmotesDict = new Dictionary(); complementaryEmotesDefault = new List(); allFavoriteEmotes = new List(); allQuickEmotes = new List(8); while (allQuickEmotes.Count < allQuickEmotes.Capacity) { allQuickEmotes.Add(""); } allEmotesTier0 = new List(); allEmotesTier1 = new List(); allEmotesTier2 = new List(); allEmotesTier3 = new List(); Dictionary> dictionary = new Dictionary>(); 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 (Plugin.complementaryAnimationClips.Contains(val)) { unlockableEmote.complementary = true; } if (unlockableEmote.emoteName.Contains("_start") && !unlockableEmote.emoteName.Contains("_start_")) { string key = unlockableEmote.emoteName.Replace("_start", "_loop"); AnimationClip val2 = Plugin.customAnimationClipsLoopDict[key]; if ((Object)(object)val2 != (Object)null) { unlockableEmote.transitionsToClip = val2; unlockableEmote.emoteName = unlockableEmote.emoteName.Replace("_start", ""); ((Object)unlockableEmote.animationClip).name = unlockableEmote.emoteName + "_start"; ((Object)unlockableEmote.transitionsToClip).name = unlockableEmote.emoteName + "_loop"; } } else if (unlockableEmote.emoteName.Contains("_pose")) { unlockableEmote.isPose = true; unlockableEmote.emoteName = unlockableEmote.emoteName.Replace("_pose", ""); ((Object)unlockableEmote.animationClip).name = unlockableEmote.emoteName; } if (unlockableEmote.emoteName.Contains(".")) { string[] array = unlockableEmote.emoteName.Split(new char[1] { '.' }); if (array.Length != 0 && array[0].Length > 0) { if (array.Length > 3) { CustomLogging.LogError("Error parsing emote name: " + unlockableEmote.emoteName + ". Correct format: \"emote_group.optional_arg.emote_name\""); continue; } unlockableEmote.emoteSyncGroupName = array[0]; unlockableEmote.emoteName = unlockableEmote.emoteSyncGroupName + "." + array[^1]; unlockableEmote.displayName = unlockableEmote.emoteSyncGroupName; if ((Object)(object)unlockableEmote.transitionsToClip == (Object)null) { ((Object)unlockableEmote.animationClip).name = unlockableEmote.emoteName; } else { ((Object)unlockableEmote.animationClip).name = unlockableEmote.emoteName + "_start"; ((Object)unlockableEmote.transitionsToClip).name = unlockableEmote.emoteName + "_loop"; } if (!dictionary.TryGetValue(unlockableEmote.emoteSyncGroupName, out unlockableEmote.emoteSyncGroup)) { unlockableEmote.emoteSyncGroup = new List(); dictionary.Add(unlockableEmote.emoteSyncGroupName, unlockableEmote.emoteSyncGroup); } if (array.Length == 3 && array[1].ToLower().Contains("layer_")) { ((Object)val).name = ((Object)val).name.Replace("." + array[1], ""); if ((Object)(object)unlockableEmote.transitionsToClip != (Object)null) { ((Object)unlockableEmote.transitionsToClip).name = ((Object)unlockableEmote.transitionsToClip).name.Replace("." + array[1], ""); } if (!int.TryParse(array[1].Substring(6), out var result)) { CustomLogging.LogError("Failed to parse emote layer number in arg: " + array[1] + ". Emote will not be added."); continue; } unlockableEmote.purchasable = result == 0; while (unlockableEmote.emoteSyncGroup.Count <= result) { unlockableEmote.emoteSyncGroup.Add(null); } unlockableEmote.emoteSyncGroup[result] = unlockableEmote; } else { unlockableEmote.emoteSyncGroup.Add(unlockableEmote); unlockableEmote.purchasable = unlockableEmote.emoteSyncGroup.Count == 1; if (array.Length == 3 && array[1].ToLower() == "random") { unlockableEmote.randomEmote = true; ((Object)val).name = ((Object)val).name.Replace("." + array[1], ""); if ((Object)(object)unlockableEmote.transitionsToClip != (Object)null) { ((Object)unlockableEmote.transitionsToClip).name = ((Object)unlockableEmote.transitionsToClip).name.Replace("." + array[1], ""); } } } } } if (unlockableEmote.emoteName.Contains("_start") && !unlockableEmote.emoteName.Contains("_start_")) { string key2 = unlockableEmote.emoteName.Replace("_start", "_loop"); AnimationClip val3 = Plugin.customAnimationClipsLoopDict[key2]; if ((Object)(object)val3 != (Object)null) { unlockableEmote.transitionsToClip = val3; unlockableEmote.emoteName = unlockableEmote.emoteName.Replace("_start", ""); ((Object)unlockableEmote.animationClip).name = unlockableEmote.emoteName + "_start"; ((Object)unlockableEmote.transitionsToClip).name = unlockableEmote.emoteName + "_loop"; } } else if (unlockableEmote.emoteName.Contains("_pose")) { unlockableEmote.isPose = true; unlockableEmote.emoteName = unlockableEmote.emoteName.Replace("_pose", ""); ((Object)unlockableEmote.animationClip).name = unlockableEmote.emoteName; } if ((!((Object)(object)unlockableEmote.transitionsToClip != (Object)null) && !((Motion)unlockableEmote.animationClip).isLooping && !unlockableEmote.isPose && unlockableEmote.emoteSyncGroup == null) || true) { 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 (ConfigSettings.blacklistedEmoteNames.Contains(unlockableEmote.displayName)) { blacklistedEmoteIds.Add(unlockableEmote.emoteId); } } if (Plugin.complementaryAnimationClips.Contains(val) && unlockableEmote.purchasable) { unlockableEmote.complementary = true; complementaryEmotesDefault.Add(unlockableEmote); } } try { allUnlockableEmotes.Sort((UnlockableEmote item1, UnlockableEmote item2) => string.Compare(item1.displayName, item2.displayName, ignoreCase: true, defaultSortCulture)); } catch (Exception) { if (ConfigSettings.verboseLogs.Value) { CustomLogging.LogWarningVerbose("Failed to apply default emote sort. Reverting to original sort method."); } allUnlockableEmotes = allUnlockableEmotes.OrderBy((UnlockableEmote item) => item.emoteName).ToList(); } int num = 0; foreach (UnlockableEmote allUnlockableEmote in allUnlockableEmotes) { allUnlockableEmote.emoteId = num++; 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); } } } complementaryEmotes = new List(complementaryEmotesDefault); SaveManager.LoadFavoritedEmotes(); SaveManager.LoadQuickEmotes(); } } [HarmonyPatch] public static class SessionManager { public static List unlockedEmotes = new List(); public static List unlockedEmotesTier0 = new List(); public static List unlockedEmotesTier1 = new List(); public static List unlockedEmotesTier2 = new List(); public static List unlockedEmotesTier3 = new List(); internal static List emotesUnlockedThisSession = new List(); public static Dictionary> unlockedEmotesByPlayer = new Dictionary>(); public static List unlockedFavoriteEmotes = new List(); public static string localPlayerUsername => GameNetworkManager.Instance?.username; [HarmonyPatch(typeof(StartOfRound), "Awake")] [HarmonyPrefix] public static void ResetGameValues() { EmoteController.allEmoteControllers?.Clear(); EmoteControllerPlayer.allPlayerEmoteControllers?.Clear(); EmoteControllerMaskedEnemy.allMaskedEnemyEmoteControllers?.Clear(); EmoteAudioSource.allEmoteAudioSources?.Clear(); EmotesManager.complementaryEmotes = new List(EmotesManager.complementaryEmotesDefault); } [HarmonyPatch(typeof(PlayerControllerB), "ConnectClientToPlayerObject")] [HarmonyPostfix] public static void OnHostConnected(PlayerControllerB __instance) { if (!HelperTools.isServer) { return; } if (!unlockedEmotesByPlayer.ContainsKey(HelperTools.localPlayerController.playerUsername)) { unlockedEmotesByPlayer.Add(HelperTools.localPlayerController.playerUsername, unlockedEmotes); TerminalPatcher.currentEmoteCreditsByPlayer.Add(HelperTools.localPlayerController.playerUsername, TerminalPatcher.currentEmoteCredits); return; } foreach (UnlockableEmote item in unlockedEmotesByPlayer[HelperTools.localPlayerController.playerUsername]) { if (!IsEmoteUnlocked(item)) { unlockedEmotes.Add(item); } } unlockedEmotesByPlayer[HelperTools.localPlayerController.playerUsername] = unlockedEmotes; TerminalPatcher.currentEmoteCreditsByPlayer[HelperTools.localPlayerController.playerUsername] = TerminalPatcher.currentEmoteCredits; } [HarmonyPatch(typeof(StartOfRound), "Start")] [HarmonyPostfix] public static void OnServerStart(StartOfRound __instance) { if (HelperTools.isServer) { } SyncManager.RotateEmoteSelectionServer(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 (HelperTools.isServer) { SyncManager.RotateEmoteSelectionServer(); } } public static void ResetProgressLocal(bool forceResetAll = false) { CustomLogging.Log("Resetting progress."); if (!ConfigSync.instance.syncPersistentUnlocks || forceResetAll) { ResetEmotesLocal(); } if (!ConfigSync.instance.syncPersistentEmoteCredits || forceResetAll) { TerminalPatcher.currentEmoteCredits = ConfigSync.instance.syncStartingEmoteCredits; List list = new List(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 (!HelperTools.isServer || ConfigSync.instance.syncUnlockEverything || ConfigSync.instance.syncPersistentUnlocksGlobal) { return; } if (ConfigSync.instance.syncShareEverything) { CustomLogging.Log("Syncing unlocked emotes with clients."); SyncManager.SendOnUnlockEmoteUpdateMulti(TerminalPatcher.currentEmoteCredits); return; } HashSet hashSet = new HashSet(); 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 bool IsEmoteUnlocked(string emoteName, string playerUsername = "") { if (EmotesManager.allUnlockableEmotesDict.TryGetValue(emoteName, out var value)) { return IsEmoteUnlocked(value, playerUsername); } return false; } public static bool IsEmoteUnlocked(UnlockableEmote emote, string playerUsername = "") { if (emote == null) { return false; } List value = unlockedEmotes; if (playerUsername != "" && !unlockedEmotesByPlayer.TryGetValue(playerUsername, out value)) { return false; } if (emote.emoteSyncGroup != null && emote.emoteSyncGroup.Count > 0) { foreach (UnlockableEmote item in emote.emoteSyncGroup) { if (value.Contains(item)) { return true; } } } return value.Contains(emote); } public static List GetUnlockedEmotes(PlayerControllerB playerController) { return GetUnlockedEmotes(((Object)(object)playerController != (Object)null) ? playerController.playerUsername : ""); } public static List GetUnlockedEmotes(string playerUsername) { if (unlockedEmotesByPlayer.TryGetValue(playerUsername, out var value)) { return value; } return null; } public static void UnlockEmotesLocal(IEnumerable emotes, bool purchased = false, string playerUsername = "") { foreach (UnlockableEmote emote in emotes) { UnlockEmoteLocal(emote, purchased, playerUsername); } } public static void UnlockEmoteLocal(int emoteId, bool purchased = false, string playerUsername = "") { UnlockEmoteLocal((emoteId >= 0 && emoteId < EmotesManager.allUnlockableEmotes.Count) ? EmotesManager.allUnlockableEmotes[emoteId] : null, purchased, playerUsername); } public static void UnlockEmoteLocal(UnlockableEmote emote, bool purchased = false, string playerUsername = "") { if (emote == null || (emote.requiresHeldProp && ConfigSync.instance.syncRemoveGrabbableEmotesPartyPooperMode)) { return; } List list = unlockedEmotes; if (playerUsername != "" && playerUsername != localPlayerUsername) { if (!unlockedEmotesByPlayer.TryGetValue(playerUsername, out var value) && !ConfigSync.instance.syncShareEverything) { return; } if (value != null) { list = value; } } if (IsEmoteUnlocked(emote, playerUsername)) { return; } if (emote.emoteSyncGroup != null) { foreach (UnlockableEmote item in emote.emoteSyncGroup) { if (list.Contains(item)) { return; } } if (emote.emoteSyncGroup.Count > 0) { emote = emote.emoteSyncGroup[0]; } } if (!list.Contains(emote)) { list.Add(emote); } if (list != 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); } if (ConfigSync.instance.syncPersistentUnlocksGlobal && purchased && !emotesUnlockedThisSession.Contains(emote)) { emotesUnlockedThisSession.Add(emote); } } public static void RemoveEmoteLocal(UnlockableEmote emote) { unlockedEmotes.Remove(emote); unlockedEmotesTier0.Remove(emote); unlockedEmotesTier1.Remove(emote); unlockedEmotesTier2.Remove(emote); unlockedEmotesTier3.Remove(emote); unlockedFavoriteEmotes.Remove(emote); emotesUnlockedThisSession.Remove(emote); foreach (List value in unlockedEmotesByPlayer.Values) { value.Remove(emote); } } public static void ResetEmotesLocal() { CustomLogging.Log("Resetting unlocked emotes."); unlockedEmotes.Clear(); unlockedEmotesTier0.Clear(); unlockedEmotesTier1.Clear(); unlockedEmotesTier2.Clear(); unlockedEmotesTier3.Clear(); emotesUnlockedThisSession.Clear(); unlockedEmotesByPlayer.Clear(); PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts; foreach (PlayerControllerB val in allPlayerScripts) { if (val.playerSteamId != 0L && !unlockedEmotesByPlayer.ContainsKey(val.playerUsername)) { unlockedEmotesByPlayer.Add(val.playerUsername, ((Object)(object)val == (Object)(object)HelperTools.localPlayerController || ConfigSync.instance.syncShareEverything) ? unlockedEmotes : new List()); } } UnlockEmotesLocal(ConfigSync.instance.syncUnlockEverything ? EmotesManager.allUnlockableEmotes : EmotesManager.complementaryEmotes); UpdateUnlockedFavoriteEmotes(); } public static void UpdateUnlockedFavoriteEmotes() { unlockedFavoriteEmotes?.Clear(); if (EmotesManager.allFavoriteEmotes == null || EmotesManager.allUnlockableEmotesDict == null || unlockedFavoriteEmotes == null) { return; } foreach (string allFavoriteEmote in EmotesManager.allFavoriteEmotes) { if (EmotesManager.allUnlockableEmotesDict.TryGetValue(allFavoriteEmote, out var value)) { if (value.emoteSyncGroup != null && value.emoteSyncGroup.Count > 0) { value = value.emoteSyncGroup[0]; } if (IsEmoteUnlocked(value)) { unlockedFavoriteEmotes.Add(value); } } } } internal static void UpdateBlacklistedEmotes() { } } public class UnlockableEmote { public int emoteId; public string emoteName; public string displayName = ""; public AnimationClip animationClip; public AnimationClip transitionsToClip = null; public bool purchasable = true; public bool requiresHeldProp = false; public GameObject requiredHeldPropPrefab = null; public bool complementary = false; public bool isPose = false; public bool canMoveWhileEmoting = false; private bool _isBoomboxAudio = true; public string overrideAudioClipName = ""; public string overrideAudioLoopClipName = ""; public string emoteSyncGroupName = ""; public List emoteSyncGroup; public float recordSongLoopValue = 0f; public bool randomEmote = false; public List propNamesInEmote; public bool canSyncEmote = 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 => $"{displayName}"; public bool humanoidAnimation => ((Motion)animationClip).isHumanMotion; public bool loopable => ((Motion)animationClip).isLooping || ((Object)(object)transitionsToClip != (Object)null && ((Motion)transitionsToClip).isLooping); public bool hasAudio => audioClipName != "" || audioLoopClipName != ""; public bool isBoomboxAudio { get { return _isBoomboxAudio && !ConfigSettings.disableBoomboxRequirement.Value; } set { _isBoomboxAudio = value; } } public string audioClipName => ((Object)(object)animationClip != (Object)null && AudioManager.AudioExists(((Object)animationClip).name)) ? ((Object)animationClip).name : ((overrideAudioClipName != "" && AudioManager.AudioExists(overrideAudioClipName)) ? overrideAudioClipName : ""); public string audioLoopClipName => ((Object)(object)transitionsToClip != (Object)null && AudioManager.AudioExists(((Object)transitionsToClip).name)) ? ((Object)transitionsToClip).name : ((overrideAudioLoopClipName != "" && AudioManager.AudioExists(overrideAudioLoopClipName)) ? overrideAudioLoopClipName : ""); public bool inEmoteSyncGroup => emoteSyncGroup != null && !randomEmote; public bool favorite => EmotesManager.allFavoriteEmotes.Contains(emoteName); 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 IsEmoteInEmoteGroup(UnlockableEmote emote) { return this == emote || (emoteSyncGroup != null && emoteSyncGroup.Contains(emote)); } public bool ClipIsInEmote(AnimationClip clip) { if ((Object)(object)clip == (Object)null) { return false; } if ((Object)(object)clip == (Object)(object)animationClip || (Object)(object)clip == (Object)(object)transitionsToClip) { return true; } if (emoteSyncGroup != null) { foreach (UnlockableEmote item in emoteSyncGroup) { if ((Object)(object)clip == (Object)(object)item.animationClip || (Object)(object)clip == (Object)(object)item.transitionsToClip) { return true; } } } return false; } public AudioClip LoadAudioClip() { if (hasAudio && audioClipName.Length > 0) { return AudioManager.LoadAudioClip(audioClipName); } return null; } public AudioClip LoadAudioLoopClip() { if (hasAudio && (Object)(object)transitionsToClip != (Object)null && audioLoopClipName.Length > 0) { return AudioManager.LoadAudioClip(audioLoopClipName); } return null; } } [HarmonyPatch] public static class SaveManager { public static string TooManyEmotesSaveFileName = "TooManyEmotes_LocalSaveData"; private static List globallyUnlockedEmoteNames = new List(); [HarmonyPatch(typeof(PlayerControllerB), "ConnectClientToPlayerObject")] [HarmonyPrefix] public static void CheckIfShouldResetLocalSettings() { if (ConfigSettings.resetGloballyUnlockedEmotes) { ResetGloballyUnlockedEmotes(); } if (ConfigSettings.resetFavoriteEmotes) { ResetFavoritedEmotes(); } ConfigSettings.resetGloballyUnlockedEmotes = false; ConfigSettings.resetFavoriteEmotes = false; } [HarmonyPatch(typeof(GameNetworkManager), "SaveGameValues")] [HarmonyPostfix] public static void SaveUnlockedEmotes(GameNetworkManager __instance) { if (!__instance.isHostingGame || !StartOfRound.Instance.inShipPhase || ConfigSync.instance.syncUnlockEverything) { return; } CustomLogging.Log("Saving game values."); try { HashSet hashSet; try { hashSet = new HashSet(ES3.Load("TooManyEmotes.UnlockedEmotes.PlayersList", HelperTools.currentSaveFileName, new string[0])); } catch (Exception ex) { CustomLogging.LogErrorVerbose("Error loading previous users list. Deleting key: TooManyEmotes.UnlockedEmotes.PlayersList from file: " + HelperTools.currentSaveFileName); CustomLogging.LogErrorVerbose(ex.ToString()); ES3.DeleteKey("TooManyEmotes.UnlockedEmotes.PlayersList", HelperTools.currentSaveFileName); hashSet = new HashSet(); } foreach (string key in SessionManager.unlockedEmotesByPlayer.Keys) { hashSet.Add(key); } ES3.Save("TooManyEmotes.UnlockedEmotes.PlayersList", hashSet.ToArray(), HelperTools.currentSaveFileName); foreach (string item in hashSet) { if (!ConfigSync.instance.syncPersistentUnlocksGlobal) { if (!SessionManager.unlockedEmotesByPlayer.ContainsKey(item)) { continue; } if (SessionManager.unlockedEmotesByPlayer.TryGetValue(item, out var value)) { CustomLogging.Log("Saving " + value.Count + " unlocked emotes for player: " + item); string[] array = new string[value.Count]; for (int i = 0; i < value.Count; i++) { array[i] = value[i].emoteName; } if (value == SessionManager.unlockedEmotes) { ES3.Save("TooManyEmotes.UnlockedEmotes", array, HelperTools.currentSaveFileName); } else { ES3.Save("TooManyEmotes.UnlockedEmotes.Player_" + item, array, HelperTools.currentSaveFileName); } } } if (TerminalPatcher.currentEmoteCreditsByPlayer.ContainsKey(item)) { CustomLogging.Log("Saving " + TerminalPatcher.currentEmoteCreditsByPlayer[item] + " emote credits for player: " + item); string text = "TooManyEmotes.CurrentEmoteCredits" + (ConfigSync.instance.syncPersistentUnlocks ? ".Persistent" : ""); if ((Object)(object)HelperTools.localPlayerController != (Object)null && HelperTools.localPlayerController.playerSteamId != 0L && item == HelperTools.localPlayerController.playerUsername) { ES3.Save(text, TerminalPatcher.currentEmoteCredits, __instance.currentSaveFileName); } else { ES3.Save(text + ".Player_" + item, TerminalPatcher.currentEmoteCreditsByPlayer[item], __instance.currentSaveFileName); } } } ES3.Save("TooManyEmotes.EmoteStoreSeed", TerminalPatcher.emoteStoreSeed, __instance.currentSaveFileName); CustomLogging.Log("Saved Seed: " + TerminalPatcher.emoteStoreSeed); } catch (Exception ex2) { CustomLogging.LogError("Error while trying to save TooManyEmotes values when disconnecting as host."); CustomLogging.LogError(ex2.ToString()); } } [HarmonyPatch(typeof(StartOfRound), "LoadUnlockables")] [HarmonyPostfix] public static void LoadUnlockedEmotes(StartOfRound __instance) { if (!GameNetworkManager.Instance.isHostingGame || ConfigSync.instance.syncUnlockEverything) { return; } CustomLogging.Log("Loading game values."); try { if (!ConfigSync.instance.syncPersistentUnlocksGlobal) { SessionManager.ResetEmotesLocal(); string[] array = ES3.Load("TooManyEmotes.UnlockedEmotes", HelperTools.currentSaveFileName, new string[0]); string[] array2 = array; foreach (string key in array2) { if (EmotesManager.allUnlockableEmotesDict.TryGetValue(key, out var value)) { SessionManager.UnlockEmoteLocal(value); } } } string text = "TooManyEmotes.CurrentEmoteCredits" + (ConfigSync.instance.syncPersistentUnlocks ? ".Persistent" : ""); TerminalPatcher.currentEmoteCredits = ES3.Load(text, HelperTools.currentSaveFileName, ConfigSync.instance.syncStartingEmoteCredits); string[] array3 = ES3.Load("TooManyEmotes.UnlockedEmotes.PlayersList", HelperTools.currentSaveFileName, new string[0]); string[] array4 = array3; foreach (string text2 in array4) { if ((Object)(object)HelperTools.localPlayerController != (Object)null && HelperTools.localPlayerController.playerSteamId != 0L && text2 == HelperTools.localPlayerController.playerUsername) { continue; } if (!SessionManager.unlockedEmotesByPlayer.ContainsKey(text2)) { SessionManager.unlockedEmotesByPlayer.Add(text2, new List()); } text = "TooManyEmotes.UnlockedEmotes.Player_" + text2; if (!ConfigSync.instance.syncPersistentUnlocksGlobal) { string[] array5 = ES3.Load(text, HelperTools.currentSaveFileName, new string[0]); CustomLogging.Log("Loading " + array5.Length + " unlocked emotes for player: " + text2); string[] array6 = array5; foreach (string key2 in array6) { if (EmotesManager.allUnlockableEmotesDict.TryGetValue(key2, out var value2)) { SessionManager.UnlockEmoteLocal(value2, purchased: false, text2); } } } text = "TooManyEmotes.CurrentEmoteCredits.Player_" + text2; if (ConfigSync.instance.syncPersistentUnlocks) { text = text.Replace("CurrentEmoteCredits", "CurrentEmoteCredits.Persistent"); } int value3 = ES3.Load(text, HelperTools.currentSaveFileName, ConfigSync.instance.syncStartingEmoteCredits); CustomLogging.Log("Loading " + value3 + " emote credits for player: " + text2); TerminalPatcher.currentEmoteCreditsByPlayer[text2] = value3; } TerminalPatcher.emoteStoreSeed = ES3.Load("TooManyEmotes.EmoteStoreSeed", HelperTools.currentSaveFileName, 0); CustomLogging.Log("Loaded Seed: " + TerminalPatcher.emoteStoreSeed); } catch (Exception ex) { CustomLogging.LogError("Error while trying to load TooManyEmotes values: " + ex); } } [HarmonyPatch(typeof(GameNetworkManager), "ResetSavedGameValues")] [HarmonyPrefix] public static void ResetUnlockedEmotesList(GameNetworkManager __instance) { if (!__instance.isHostingGame || (Object)(object)StartOfRound.Instance == (Object)null || SessionManager.unlockedEmotes == null) { return; } CustomLogging.Log("Resetting saved game values."); if (!ConfigSync.instance.syncPersistentUnlocks) { ES3.DeleteKey("TooManyEmotes.UnlockedEmotes", __instance.currentSaveFileName); ES3.DeleteKey("TooManyEmotes.CurrentEmoteCredits.Persistent", __instance.currentSaveFileName); } ES3.DeleteKey("TooManyEmotes.CurrentEmoteCredits", __instance.currentSaveFileName); ES3.DeleteKey("TooManyEmotes.EmoteStoreSeed", __instance.currentSaveFileName); HashSet hashSet = new HashSet(ES3.Load("TooManyEmotes.UnlockedEmotes.PlayersList", __instance.currentSaveFileName, new string[0])); foreach (string key in SessionManager.unlockedEmotesByPlayer.Keys) { hashSet.Add(key); } foreach (string item in hashSet) { if (!ConfigSync.instance.syncPersistentUnlocks) { ES3.DeleteKey("TooManyEmotes.UnlockedEmotes.Player_" + item, __instance.currentSaveFileName); ES3.DeleteKey("TooManyEmotes.CurrentEmoteCredits.Persistent.Player_" + item, __instance.currentSaveFileName); } ES3.DeleteKey("TooManyEmotes.CurrentEmoteCredits.Player_" + item, __instance.currentSaveFileName); } SessionManager.ResetProgressLocal(); } [HarmonyPatch(typeof(GameNetworkManager), "SaveLocalPlayerValues")] [HarmonyPrefix] public static void SaveLocalPlayerValues() { if (!HelperTools.isClient || !SyncManager.isSynced || ConfigSync.instance == null || !ConfigSync.instance.syncPersistentUnlocksGlobal || globallyUnlockedEmoteNames == null || SessionManager.emotesUnlockedThisSession == null) { return; } try { foreach (UnlockableEmote item in SessionManager.emotesUnlockedThisSession) { if (item != null && !item.complementary && !item.requiresHeldProp && !globallyUnlockedEmoteNames.Contains(item.emoteName)) { globallyUnlockedEmoteNames.Add(item.emoteName); } } ES3.Save("UnlockedEmotes", globallyUnlockedEmoteNames.ToArray(), TooManyEmotesSaveFileName); CustomLogging.Log("Saved " + globallyUnlockedEmoteNames.Count + " globally unlocked emotes for local player."); } catch (Exception ex) { CustomLogging.LogErrorVerbose("Error while trying to save TooManyEmotes local player data.\n" + ex); } } internal static void LoadLocalPlayerValues() { if (!HelperTools.isClient || !SyncManager.isSynced || !ConfigSync.instance.syncPersistentUnlocksGlobal || globallyUnlockedEmoteNames == null || EmotesManager.allUnlockableEmotesDict == null) { return; } try { string[] array = ES3.Load("UnlockedEmotes", TooManyEmotesSaveFileName, new string[0]); string[] array2 = array; foreach (string key in array2) { if (EmotesManager.allUnlockableEmotesDict.TryGetValue(key, out var value) && !value.complementary && !value.requiresHeldProp) { SessionManager.UnlockEmoteLocal(value); } } globallyUnlockedEmoteNames.Clear(); globallyUnlockedEmoteNames.AddRange(array); CustomLogging.Log("Loaded " + array.Length + " globally unlocked emotes for local player."); } catch (Exception ex) { CustomLogging.LogErrorVerbose("Error while trying to load TooManyEmotes local player data.\n" + ex); } } internal static void ResetGloballyUnlockedEmotes() { CustomLogging.LogWarning("Resetting globally unlocked emotes for local player."); try { globallyUnlockedEmoteNames?.Clear(); SessionManager.emotesUnlockedThisSession?.Clear(); ES3.DeleteKey("UnlockedEmotes", TooManyEmotesSaveFileName); } catch (Exception ex) { CustomLogging.LogErrorVerbose("Error resetting globally unlocked emotes?\n" + ex); } } public static void SaveFavoritedEmotes() { if (EmotesManager.allFavoriteEmotes != null) { try { ES3.Save("TooManyEmotes.FavoriteEmotes", EmotesManager.allFavoriteEmotes.ToArray(), TooManyEmotesSaveFileName); } catch (Exception ex) { CustomLogging.LogErrorVerbose("Error saving favorited emotes?\n" + ex); } } } public static void LoadFavoritedEmotes() { if (EmotesManager.allFavoriteEmotes == null) { return; } EmotesManager.allFavoriteEmotes?.Clear(); try { string[] collection = ES3.Load("TooManyEmotes.FavoriteEmotes", TooManyEmotesSaveFileName, new string[0]); EmotesManager.allFavoriteEmotes.AddRange(collection); } catch (Exception ex) { CustomLogging.LogError("Error while trying to load favorited emotes due to possible save corruption? Your favorited emotes will likely be reset.\n" + ex); try { ES3.DeleteKey("TooManyEmotes.FavoriteEmotes", TooManyEmotesSaveFileName); CustomLogging.LogErrorVerbose("Deleted key: \"TooManyEmotes.FavoriteEmotes\" from file: \"" + TooManyEmotesSaveFileName + "\""); } catch { CustomLogging.LogErrorVerbose("Could not delete key: \"TooManyEmotes.FavoriteEmotes\" from file: \"" + TooManyEmotesSaveFileName + "\""); } } SessionManager.UpdateUnlockedFavoriteEmotes(); } internal static void ResetFavoritedEmotes() { CustomLogging.LogWarning("Resetting favorited emotes for local player."); try { ES3.DeleteKey("TooManyEmotes.FavoriteEmotes", TooManyEmotesSaveFileName); SessionManager.unlockedFavoriteEmotes?.Clear(); SessionManager.UpdateUnlockedFavoriteEmotes(); } catch (Exception ex) { CustomLogging.LogErrorVerbose("Error resetting favorite emotes?\n" + ex); } } public static void SaveQuickEmotes() { if (EmotesManager.allQuickEmotes == null) { return; } try { for (int i = 0; i < EmotesManager.allQuickEmotes.Count; i++) { string text = EmotesManager.allQuickEmotes[i] ?? ""; ES3.Save("TooManyEmotes.QuickEmote" + i, text, TooManyEmotesSaveFileName); } } catch (Exception ex) { CustomLogging.LogErrorVerbose("Error saving quick emotes?\n" + ex); } } public static void LoadQuickEmotes() { if (EmotesManager.allQuickEmotes == null) { return; } try { for (int i = 0; i < EmotesManager.allQuickEmotes.Count; i++) { string value = ES3.Load("TooManyEmotes.QuickEmote" + i, TooManyEmotesSaveFileName, ""); EmotesManager.allQuickEmotes[i] = value; } } catch (Exception ex) { CustomLogging.LogError("Error while trying to load quick emotes due to possible save corruption? Your quick emotes will likely be reset.\n" + ex); for (int j = 0; j < EmotesManager.allQuickEmotes.Count; j++) { string text = "TooManyEmotes.QuickEmote" + j; try { ES3.DeleteKey(text, TooManyEmotesSaveFileName); CustomLogging.LogErrorVerbose("Deleted key: \"" + text + "\" from file: \"" + TooManyEmotesSaveFileName + "\""); } catch { CustomLogging.LogErrorVerbose("Could not delete key: \"" + text + "\" from file: \"" + TooManyEmotesSaveFileName + "\""); } } } } internal static void ResetQuickEmotes() { CustomLogging.LogWarning("Resetting quick emotes."); try { for (int i = 0; i < EmotesManager.allQuickEmotes.Count; i++) { string text = "TooManyEmotes.QuickEmote" + i; ES3.DeleteKey(text, TooManyEmotesSaveFileName); EmotesManager.allQuickEmotes[i] = ""; } } catch (Exception ex) { CustomLogging.LogErrorVerbose("Error resetting quick emotes?\n" + ex); } } } [BepInPlugin("FlipMods.TooManyEmotes", "TooManyEmotes", "2.3.16")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { private Harmony _harmony; public static Plugin instance; public static List customAnimationClips; public static HashSet customAnimationClipsHash; public static Dictionary customAnimationClipsLoopDict; public static List complementaryAnimationClips; public static List animationClipsTier0; public static List animationClipsTier1; public static List animationClipsTier2; public static List animationClipsTier3; public static List animationClipsSpecial; public static GameObject radialMenuPrefab; public static RuntimeAnimatorController humanoidAnimatorController; public static Avatar humanoidAvatar; public static GameObject humanoidSkeletonPrefab; public static ManualLogSource defaultLogger => ((BaseUnityPlugin)instance).Logger; private void Awake() { //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Expected O, but got Unknown instance = this; CustomLogging.InitLogger(); ConfigSettings.BindConfigSettings(); Keybinds.InitKeybinds(); LoadEmoteAssets(); LoadMiscAnimationAssets(); LoadRadialMenuAsset(); AudioManager.LoadAudioAssets(); EmotePropManager.LoadPropAssets(); EmotesManager.BuildEmotesList(); AudioManager.BuildAudioClipList(); EmotePropManager.BuildEmotePropList(); AdditionalEmoteData.SetAdditionalEmoteData(); AdditionalEmoteData.SetAdditionalPropData(); AdditionalEmoteData.SetAdditionalMusicData(); _harmony = new Harmony("TooManyEmotes"); PatchAll(); CustomLogging.Log("TooManyEmotes finished loading!"); } private static void LoadEmoteAssets() { customAnimationClips = new List(); customAnimationClipsHash = new HashSet(); customAnimationClipsLoopDict = new Dictionary(); if (complementaryAnimationClips != null && complementaryAnimationClips.Count() > 0) { customAnimationClipsHash.UnionWith(complementaryAnimationClips); animationClipsTier0 = new List(); animationClipsTier1 = new List(); animationClipsTier2 = new List(); animationClipsTier3 = new List(); animationClipsSpecial = new List(); } else { complementaryAnimationClips = new List(LoadEmoteAssetBundle("Assets/emotes_complementary")); animationClipsTier0 = new List(LoadEmoteAssetBundle("Assets/emotes_0")); animationClipsTier1 = new List(LoadEmoteAssetBundle("Assets/emotes_1")); animationClipsTier2 = new List(LoadEmoteAssetBundle("Assets/emotes_2")); animationClipsTier3 = new List(LoadEmoteAssetBundle("Assets/emotes_3")); animationClipsSpecial = new List(LoadEmoteAssetBundle("Assets/emotes_special")); complementaryAnimationClips.AddRange(animationClipsSpecial); customAnimationClipsHash.UnionWith(complementaryAnimationClips); customAnimationClipsHash.UnionWith(animationClipsTier0); customAnimationClipsHash.UnionWith(animationClipsTier1); customAnimationClipsHash.UnionWith(animationClipsTier2); customAnimationClipsHash.UnionWith(animationClipsTier3); } foreach (AnimationClip item in customAnimationClipsHash) { if (((Object)item).name.EndsWith("_loop")) { if (customAnimationClipsLoopDict.ContainsKey(((Object)item).name)) { CustomLogging.LogWarning("Attempted to add duplicate emote in CustomAnimationClipsLoopDict. AnimationClip: " + ((Object)item).name); } else { customAnimationClipsLoopDict.Add(((Object)item).name, item); } } } customAnimationClips = new List(customAnimationClipsHash); 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(); CustomLogging.Log($"Successfully loaded {array.Length} animation clips from asset bundle: {assetBundleName}"); return array; } catch { CustomLogging.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("humanoid_animator_controller"); humanoidAvatar = val.LoadAsset("humanoid_avatar"); humanoidSkeletonPrefab = val.LoadAsset("humanoid_skeleton"); Animator val2 = humanoidSkeletonPrefab.GetComponentInChildren(); if ((Object)(object)val2 == (Object)null) { val2 = humanoidSkeletonPrefab.AddComponent(); } if (Object.op_Implicit((Object)(object)humanoidAvatar)) { val2.avatar = humanoidAvatar; } if (!Object.op_Implicit((Object)(object)humanoidAnimatorController)) { CustomLogging.LogError("Failed to load humanoid animator controller from asset bundle: misc"); } if (!Object.op_Implicit((Object)(object)humanoidAvatar)) { CustomLogging.LogError("Failed to load humanoid avatar from asset bundle: misc"); } if (!Object.op_Implicit((Object)(object)humanoidSkeletonPrefab)) { CustomLogging.LogError("Failed to load humanoid skeleton prefab from asset bundle: misc"); } } catch { CustomLogging.LogError("Failed to load misc 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("RadialMenu"); CustomLogging.Log("Successfully loaded radial menu asset."); } catch { CustomLogging.LogError("Failed to load radial menu asset."); } } private void PatchAll() { IEnumerable enumerable; try { enumerable = Assembly.GetExecutingAssembly().GetTypes(); } catch (ReflectionTypeLoadException ex) { enumerable = ex.Types.Where((Type t) => t != null); } foreach (Type item in enumerable) { try { _harmony.PatchAll(item); } catch { } } } 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 = "2.3.16"; } } namespace TooManyEmotes.Config { public static class ConfigSettings { public static ConfigEntry unlockEverything; public static ConfigEntry shareEverything; public static ConfigEntry persistentUnlocks; public static ConfigEntry persistentUnlocksGlobal; public static ConfigEntry persistentEmoteCredits; public static ConfigEntry syncUnsharedEmotes; public static ConfigEntry forceDisableMovingWhileEmoting; public static ConfigEntry disableEmotesForSelf; public static ConfigEntry disableChatLogRandomEmote; public static ConfigEntry toggleRotateCharacterInEmote; public static ConfigEntry blacklistEmotes; public static ConfigEntry removeGrabbableEmotesPartyPooperMode; public static ConfigEntry disableRaritySystem; public static ConfigEntry basePriceEmoteRaritySystemDisabled; public static ConfigEntry startingEmoteCredits; public static ConfigEntry addEmoteCreditsMultiplier; public static ConfigEntry purchaseEmotesWithDefaultCurrency; public static ConfigEntry priceMultiplierEmotesStore; public static ConfigEntry basePriceEmoteTier0; public static ConfigEntry basePriceEmoteTier1; public static ConfigEntry basePriceEmoteTier2; public static ConfigEntry basePriceEmoteTier3; public static ConfigEntry numEmotesStoreRotation; public static ConfigEntry rotationChanceEmoteTier0; public static ConfigEntry rotationChanceEmoteTier1; public static ConfigEntry rotationChanceEmoteTier2; public static ConfigEntry rotationChanceEmoteTier3; public static ConfigEntry enableMaskedEnemiesEmoting; public static ConfigEntry maskedEnemiesEmoteChanceOnEncounter; public static ConfigEntry maskedEnemiesAlwaysEmoteOnFirstEncounter; public static ConfigEntry enableSyncingEmotesWithMaskedEnemies; public static ConfigEntry overrideStopAndStareDuration; public static ConfigEntry maskedEnemyEmoteRandomDelay; public static ConfigEntry maskedEnemyEmoteRandomDuration; public static ConfigEntry openEmoteMenuKeybind; public static ConfigEntry toggleEmoteMenu; public static ConfigEntry reverseEmoteWheelScrollDirection; public static ConfigEntry colorCodeEmoteNamesInRadialMenu; public static ConfigEntry colorCodeEmoteBackgroundInRadialMenu; public static ConfigEntry disableBoomboxRequirement; public static ConfigEntry disableAudioShipSpeaker; public static ConfigEntry baseEmoteAudioVolume; public static ConfigEntry emoteAudioMaxVolume; public static ConfigEntry emoteAudioIncreasePerPlayerSyncing; public static ConfigEntry emoteAudioMinDistance; public static ConfigEntry emoteAudioMaxDistance; public static ConfigEntry emoteNameColorTier0; public static ConfigEntry emoteNameColorTier1; public static ConfigEntry emoteNameColorTier2; public static ConfigEntry emoteNameColorTier3; public static ConfigEntry verboseLogs; public static ConfigEntry resetFavoritesOnNextStart; public static ConfigEntry resetGlobalUnlocksOnNextStart; public static Dictionary currentConfigEntries = new Dictionary(); public static List configSections = new List(); internal static bool resetFavoriteEmotes = false; internal static bool resetGloballyUnlockedEmotes = false; public static List blacklistedEmoteNames = new List(); public static ConfigFile config => ((BaseUnityPlugin)Plugin.instance).Config; public static void BindConfigSettings() { CustomLogging.Log("BindingConfigs"); unlockEverything = AddConfigEntry("Emote Settings", "I am a Party Pooper", defaultValue: false, "[Host only] If true, every emote will be unlocked at the start of the game. (You're not really a party pooper)"); shareEverything = AddConfigEntry("Emote Settings", "ShareEverything", defaultValue: false, "[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."); persistentUnlocks = AddConfigEntry("Emote Settings", "PersistentUnlocks", defaultValue: false, "[Host only] If enabled, emotes will be unlocked per save, and will not reset upon ship resets, unless a new save is created.\nNOTE: This setting (as well as the other persistent settings) will be disabled if UnlockEverything (I am a Party Pooper) is enabled."); persistentUnlocksGlobal = AddConfigEntry("Emote Settings", "PersistentUnlocksGlobal", defaultValue: false, "[Host only] If enabled, emotes will be permanently unlocked for your character, and will be available when playing on any save. Only applies if PersistentUnlocks is set to true.\nIf ShareEverything is enabled, emotes that the host already has unlocked will NOT unlock for you upon joining the game, unless you also have them unlocked.\nIf ShareEverything is enabled, emotes unlocked by other players DURING the session will still permanently unlock for your character.\nNOTE: At this time, if enabled, many config settings are subject to be limited, or forced to their default values, in order to prevent unlocking emotes globally too fast. These settings may include starting emote credits, emote credits earned, number of emotes in store rotation, etc.\nIf you want persistent emotes, but with more freedom, please disable this global persistent emotes mode."); persistentEmoteCredits = AddConfigEntry("Emote Settings", "PersistentEmoteCredits", defaultValue: false, "[Host only] If enabled, emote credits will not reset upon ship resets. Only applies if PersistentUnlocks is enabled.\nThis setting will be disabled if PersistentUnlocksGlobal is enabled."); 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."); forceDisableMovingWhileEmoting = AddConfigEntry("Emote Settings", "ForceDisableMovingWhileEmoting", defaultValue: false, "[Host only] If true, this will prevent all players from moving while emoting, and the option to enable this will be removed from the emote menu.\nIf false, all players will be able to turn this on or off again."); removeGrabbableEmotesPartyPooperMode = AddConfigEntry("Emote Settings", "DoNotUnlockPropEmotes PartyPooperMode", defaultValue: true, "[Host only] If true, and if I am a Party Pooper is enabled, emotes from props will NOT be unlocked in the radial menu.\nThis only applies if the TooManyEmotesScrap mod is installed."); 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."); disableChatLogRandomEmote = AddConfigEntry("Emote Settings", "DisableChatLogRandomEmote", defaultValue: false, "If true, chat will no longer display what emote you are performing when performing a random emote. This could save memory if using mods that cache all chat messages."); toggleRotateCharacterInEmote = AddConfigEntry("Emote Settings", "ToggleRotateCharacterInEmote", defaultValue: false, "If true, rotating character while emoting will be toggled, instead of rotating while holding the hotkey."); blacklistEmotes = AddConfigEntry("Emote Settings", "Blacklist Emotes", "", "[Host only] Enter emote names, separated by a comma. Case-insensitive.\nBlacklisted emotes will not appear in game for any players."); 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.3333f, "[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. NOTE: 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.5f, "[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.135f, "[Host only] The likelyhood of [epic] emotes appearing (per slot) in the store rotation."); rotationChanceEmoteTier3 = AddConfigEntry("Emote Store", "RotationWeightLegendaryEmote", 0.015f, "[Host only] The likelyhood of [legendary] emotes appearing (per slot) in the store rotation."); enableMaskedEnemiesEmoting = AddConfigEntry("Masked Enemy Emotes", "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("Masked Enemy Emotes", "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("Masked Enemy Emotes", "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("Masked Enemy Emotes", "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("Masked Enemy Emotes", "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("Masked Enemy Emotes", "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("Masked Enemy Emotes", "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", "/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."); colorCodeEmoteNamesInRadialMenu = AddConfigEntry("Emote Radial Menu", "ColorCodeEmoteNamesInRadialMenuByRarity", defaultValue: false, "If true, emote names in the radial menu will be colored based on their rarity."); colorCodeEmoteBackgroundInRadialMenu = AddConfigEntry("Emote Radial Menu", "ColorCodeEmoteBackgroundInRadialMenu", defaultValue: false, "If true, the background UI element for each element in the radial menu will be colored based on their rarity.\nNOTE: Enabling this will force the emote names in the radial menu to have their default color."); disableBoomboxRequirement = AddConfigEntry("Emote Audio", "DisableBoomboxRequirement", defaultValue: false, "If set to true, emote audio that normally requires a nearby boombox will be played from your character instead."); disableAudioShipSpeaker = AddConfigEntry("Emote Audio", "DisableAudioOnShipSpeaker", defaultValue: false, "[Host only] This does nothing if DisableBoomboxRequirement is true. This setting is host only to ensure no de-synced audio sources."); baseEmoteAudioVolume = AddConfigEntry("Emote Audio", "BaseEmoteAudioVolume", 0.25f, "The base emote audio volume. The volume slider in the emote menu will be based off of this value."); emoteAudioMaxVolume = AddConfigEntry("Emote Audio", "MaxEmoteAudioVolume", 0.8f, "The max volume that emote audio will reach. Emote audio volume may dynamically change by increasing the number of players syncing an emote, or adjusting the volume slider in the emote menu. This setting will not affect emote audio volume, aside from preventing the volume from going higher than this value."); emoteAudioIncreasePerPlayerSyncing = AddConfigEntry("Emote Audio", "VolumeGainPerPlayerSyncingEmote", 0.05f, "By how much emote audio volume will increase by per player syncing with that emote."); emoteAudioMinDistance = AddConfigEntry("Emote Audio", "MinAudioDistance", 10f, "The range from an emote audio source at which the volume will start to fade."); emoteAudioMaxDistance = AddConfigEntry("Emote Audio", "MaxAudioDistance", 40f, "The range from an emote audio source at which the audio can no longer be heard."); 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."); verboseLogs = AddConfigEntry("Other", "VerboseLogs", defaultValue: false, "Set to true if you want to receive ALL logs. Most of the time, you will want to keep this disabled unless troubleshooting a specific issue."); resetFavoritesOnNextStart = AddConfigEntry("Other", "ResetFavoritedEmotesOnNextStart", defaultValue: false, "Set this to true to force remove all emotes from your favorites when the game starts up next.\nThis may resolve any issues that might be related to having favorited emotes that don't exist.\nThis setting will reset back to false once reset."); resetGlobalUnlocksOnNextStart = AddConfigEntry("Other", "ResetGlobalUnlocksOnNextStart", defaultValue: false, "Set this to true to force reset all globally unlocked emotes for your local player. These emotes are only usable when the host has PersistentUnlocksGlobal enabled in the config.\nThis setting will reset back to false once reset."); bool flag = false; if (resetFavoritesOnNextStart.Value) { resetFavoritesOnNextStart.Value = false; resetFavoriteEmotes = true; flag = true; } if (resetGlobalUnlocksOnNextStart.Value) { resetGlobalUnlocksOnNextStart.Value = false; resetGloballyUnlockedEmotes = true; flag = true; } float value = rotationChanceEmoteTier0.Value; value += rotationChanceEmoteTier1.Value; value += rotationChanceEmoteTier2.Value; value += rotationChanceEmoteTier3.Value; if (value != 1f && value != 0f) { ConfigEntry obj = rotationChanceEmoteTier0; obj.Value /= value; ConfigEntry obj2 = rotationChanceEmoteTier1; obj2.Value /= value; ConfigEntry obj3 = rotationChanceEmoteTier2; obj3.Value /= value; ConfigEntry obj4 = rotationChanceEmoteTier3; obj4.Value /= value; flag = true; } if (flag) { config.Save(); } TryRemoveOldConfigSettings(); try { if (blacklistEmotes.Value.Length > 0) { string text = blacklistEmotes.Value.Replace("\n", " ").Replace("\t", " ").Trim(); while (text.Contains(", ")) { text = text.Replace(", ", ","); } blacklistedEmoteNames = blacklistEmotes.Value.Split(new char[1] { ',' }).ToList(); for (int i = 0; i < blacklistedEmoteNames.Count; i++) { blacklistedEmoteNames[i] = char.ToUpper(blacklistedEmoteNames[i][0]) + blacklistedEmoteNames[i].Substring(1).ToLower(); } CustomLogging.Log("Added " + blacklistedEmoteNames.Count + " emotes to the blacklist."); } } catch (Exception ex) { CustomLogging.LogError("Error parsing emote blacklist. If you are the host, the blacklist will not be used.\n" + ex); } } public static ConfigEntry AddConfigEntry(string section, string name, T defaultValue, string description) { ConfigEntry val = config.Bind(section, name, defaultValue, description); currentConfigEntries.Add(((ConfigEntryBase)val).Definition.Key, (ConfigEntryBase)(object)val); return val; } public static void TryRemoveOldConfigSettings() { HashSet hashSet = new HashSet(); HashSet hashSet2 = new HashSet(); foreach (ConfigEntryBase value in currentConfigEntries.Values) { hashSet.Add(value.Definition.Section); hashSet2.Add(value.Definition.Key); } try { 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 (Exception ex) { CustomLogging.LogErrorVerbose("Error in TryRemoveOldConfigSettings?"); CustomLogging.LogErrorVerbose(ex.ToString()); } } } } namespace TooManyEmotes.Input { internal class IngameKeybinds : LcInputActions { internal static IngameKeybinds Instance = new IngameKeybinds(); [InputAction("/backquote", GamepadPath = "/leftStickPress", Name = "Open Emote Menu")] public InputAction OpenEmoteMenuHotkey { get; set; } [InputAction("/leftAlt", GamepadPath = "", Name = "Rotate Character in Emote")] public InputAction RotateCharacterEmoteHotkey { get; set; } [InputAction("/scroll/up", GamepadPath = "", Name = "Zoom In While Emoting")] public InputAction ZoomInEmoteHotkey { get; set; } [InputAction("/scroll/down", GamepadPath = "", Name = "Zoom Out While Emoting")] public InputAction ZoomOutEmoteHotkey { get; set; } [InputAction("/middleButton", GamepadPath = "/rightStickPress", Name = "Favorite/Unfavorite Emote")] public InputAction FavoriteEmoteHotkey { get; set; } [InputAction("", GamepadPath = "/dpad/left", Name = "Prev Emote Page")] public InputAction PrevEmotePageHotkey { get; set; } [InputAction("", GamepadPath = "/dpad/right", Name = "Next Emote Page")] public InputAction NextEmotePageHotkey { get; set; } [InputAction("", GamepadPath = "/dpad/up", Name = "Swap Emote Loadout Up")] public InputAction NextEmoteLoadoutUpHotkey { get; set; } [InputAction("", GamepadPath = "/dpad/down", Name = "Swap Emote Loadout Down")] public InputAction NextEmoteLoadoutDownHotkey { get; set; } [InputAction("/n", GamepadPath = "/dpad/right", Name = "Play Next Instrument")] public InputAction PerformNextInstrumentHotkey { get; set; } [InputAction("/m", GamepadPath = "", Name = "Perform Random Emote")] public InputAction PerformRandomEmoteHotkey { get; set; } [InputAction("", GamepadPath = "", Name = "Set/Perform Quick Emote 1")] public InputAction QuickEmoteHotkey1 { get; set; } [InputAction("", GamepadPath = "", Name = "Set/Perform Quick Emote 2")] public InputAction QuickEmoteHotkey2 { get; set; } [InputAction("", GamepadPath = "", Name = "Set/Perform Quick Emote 3")] public InputAction QuickEmoteHotkey3 { get; set; } [InputAction("", GamepadPath = "", Name = "Set/Perform Quick Emote 4")] public InputAction QuickEmoteHotkey4 { get; set; } [InputAction("", GamepadPath = "", Name = "Set/Perform Quick Emote 5")] public InputAction QuickEmoteHotkey5 { get; set; } [InputAction("", GamepadPath = "", Name = "Set/Perform Quick Emote 6")] public InputAction QuickEmoteHotkey6 { get; set; } [InputAction("", GamepadPath = "", Name = "Set/Perform Quick Emote 7")] public InputAction QuickEmoteHotkey7 { get; set; } [InputAction("", GamepadPath = "", Name = "Set/Perform Quick Emote 8")] public InputAction QuickEmoteHotkey8 { get; set; } internal static InputActionAsset GetAsset() { return ((LcInputActions)Instance).Asset; } } [HarmonyPatch] internal static class Keybinds { public static InputActionAsset Asset; public static InputActionMap ActionMap; public static InputAction OpenEmoteMenuAction; public static InputAction RotatePlayerEmoteAction; public static InputAction ZoomOutEmoteAction; public static InputAction ZoomInEmoteAction; public static InputAction FavoriteEmoteAction; public static InputAction PrevEmotePageAction; public static InputAction NextEmotePageAction; public static InputAction NextEmoteLoadoutUpAction; public static InputAction NextEmoteLoadoutDownAction; public static InputAction PerformNextInstrumentAction; public static InputAction PerformRandomEmoteAction; public static InputAction QuickEmote1Action; public static InputAction QuickEmote2Action; public static InputAction QuickEmote3Action; public static InputAction QuickEmote4Action; public static InputAction QuickEmote5Action; public static InputAction QuickEmote6Action; public static InputAction QuickEmote7Action; public static InputAction QuickEmote8Action; public static InputAction PerformSelectedEmoteAction; public static InputAction ThumbStickAction; public static InputAction RawScrollAction; public static bool holdingRotatePlayerModifier; public static bool toggledRotating; public static void InitKeybinds() { //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_0165: Expected O, but got Unknown //IL_01a9: Unknown result type (might be due to invalid IL or missing references) //IL_01de: Unknown result type (might be due to invalid IL or missing references) //IL_0213: Unknown result type (might be due to invalid IL or missing references) //IL_0248: Unknown result type (might be due to invalid IL or missing references) //IL_027d: Unknown result type (might be due to invalid IL or missing references) //IL_02b2: Unknown result type (might be due to invalid IL or missing references) //IL_02e7: Unknown result type (might be due to invalid IL or missing references) //IL_031c: Unknown result type (might be due to invalid IL or missing references) //IL_0351: Unknown result type (might be due to invalid IL or missing references) //IL_0386: Unknown result type (might be due to invalid IL or missing references) //IL_0399: Unknown result type (might be due to invalid IL or missing references) //IL_03b1: Unknown result type (might be due to invalid IL or missing references) //IL_03bb: Expected O, but got Unknown //IL_03c9: Unknown result type (might be due to invalid IL or missing references) //IL_03d3: Expected O, but got Unknown //IL_03e1: Unknown result type (might be due to invalid IL or missing references) //IL_03eb: Expected O, but got Unknown //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Expected O, but got Unknown //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Expected O, but got Unknown //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Expected O, but got Unknown CustomLogging.Log("Initializing custom emote hotkeys."); if (InputUtils_Compat.Enabled) { Asset = InputUtils_Compat.Asset; ActionMap = Asset.actionMaps[0]; OpenEmoteMenuAction = InputUtils_Compat.OpenEmoteMenuHotkey; FavoriteEmoteAction = InputUtils_Compat.FavoriteEmoteHotkey; PrevEmotePageAction = InputUtils_Compat.PrevEmotePageHotkey; NextEmotePageAction = InputUtils_Compat.NextEmotePageHotkey; NextEmoteLoadoutUpAction = InputUtils_Compat.NextEmoteLoadoutUpHotkey; NextEmoteLoadoutDownAction = InputUtils_Compat.NextEmoteLoadoutDownHotkey; RotatePlayerEmoteAction = InputUtils_Compat.RotateCharacterEmoteHotkey; ZoomInEmoteAction = InputUtils_Compat.ZoomInEmoteHotkey; ZoomOutEmoteAction = InputUtils_Compat.ZoomOutEmoteHotkey; PerformNextInstrumentAction = InputUtils_Compat.PerformNextInstrumentHotkey; PerformRandomEmoteAction = InputUtils_Compat.PerformRandomEmoteHotkey; QuickEmote1Action = InputUtils_Compat.QuickEmote1; QuickEmote2Action = InputUtils_Compat.QuickEmote2; QuickEmote3Action = InputUtils_Compat.QuickEmote3; QuickEmote4Action = InputUtils_Compat.QuickEmote4; QuickEmote5Action = InputUtils_Compat.QuickEmote5; QuickEmote6Action = InputUtils_Compat.QuickEmote6; QuickEmote7Action = InputUtils_Compat.QuickEmote7; QuickEmote8Action = InputUtils_Compat.QuickEmote8; PerformSelectedEmoteAction = new InputAction("TooManyEmotes.PerformSelectedEmote", (InputActionType)0, "/leftButton", "Press", (string)null, (string)null); ThumbStickAction = new InputAction("TooManyEmotes.ThumbStick", (InputActionType)0, "/rightStick", (string)null, (string)null, (string)null); RawScrollAction = new InputAction("TooManyEmotes.ScrollEmoteMenu", (InputActionType)0, "/scroll", (string)null, (string)null, (string)null); } else { Asset = ScriptableObject.CreateInstance(); ActionMap = new InputActionMap("TooManyEmotes"); InputActionSetupExtensions.AddActionMap(Asset, ActionMap); OpenEmoteMenuAction = InputActionSetupExtensions.AddAction(ActionMap, "TooManyEmotes.OpenEmoteMenu", (InputActionType)0, ConfigSettings.openEmoteMenuKeybind.Value, "Press", (string)null, (string)null, (string)null); InputActionSetupExtensions.AddBinding(OpenEmoteMenuAction, "/leftStickPress", (string)null, (string)null, (string)null); FavoriteEmoteAction = InputActionSetupExtensions.AddAction(ActionMap, "TooManyEmotes.FavoriteEmote", (InputActionType)0, "/middleButton", "Press", (string)null, (string)null, (string)null); InputActionSetupExtensions.AddBinding(FavoriteEmoteAction, "/rightStickPress", (string)null, (string)null, (string)null); PrevEmotePageAction = InputActionSetupExtensions.AddAction(ActionMap, "TooManyEmotes.PrevEmotePage", (InputActionType)0, "/ ", "Press", (string)null, (string)null, (string)null); InputActionSetupExtensions.AddBinding(PrevEmotePageAction, "/dpad/left", (string)null, (string)null, (string)null); NextEmotePageAction = InputActionSetupExtensions.AddAction(ActionMap, "TooManyEmotes.NextEmotePage", (InputActionType)0, "/ ", "Press", (string)null, (string)null, (string)null); InputActionSetupExtensions.AddBinding(NextEmotePageAction, "/dpad/right", (string)null, (string)null, (string)null); NextEmoteLoadoutUpAction = InputActionSetupExtensions.AddAction(ActionMap, "TooManyEmotes.EmoteLoadoutUp", (InputActionType)0, "/ ", "Press", (string)null, (string)null, (string)null); InputActionSetupExtensions.AddBinding(NextEmoteLoadoutUpAction, "/dpad/up", (string)null, (string)null, (string)null); NextEmoteLoadoutDownAction = InputActionSetupExtensions.AddAction(ActionMap, "TooManyEmotes.EmoteLoadoutDown", (InputActionType)0, "/ ", "Press", (string)null, (string)null, (string)null); InputActionSetupExtensions.AddBinding(NextEmoteLoadoutDownAction, "/dpad/down", (string)null, (string)null, (string)null); RotatePlayerEmoteAction = InputActionSetupExtensions.AddAction(ActionMap, "TooManyEmotes.RotatePlayerEmote", (InputActionType)0, "/leftAlt", "Press", (string)null, (string)null, (string)null); InputActionSetupExtensions.AddBinding(RotatePlayerEmoteAction, "/ ", (string)null, (string)null, (string)null); ZoomInEmoteAction = InputActionSetupExtensions.AddAction(ActionMap, "TooManyEmotes.ZoomInEmote", (InputActionType)0, "/scroll/up", "Press", (string)null, (string)null, (string)null); InputActionSetupExtensions.AddBinding(ZoomInEmoteAction, "/ ", (string)null, (string)null, (string)null); ZoomOutEmoteAction = InputActionSetupExtensions.AddAction(ActionMap, "TooManyEmotes.ZoomOutEmote", (InputActionType)0, "/scroll/down", "Press", (string)null, (string)null, (string)null); InputActionSetupExtensions.AddBinding(ZoomOutEmoteAction, "/ ", (string)null, (string)null, (string)null); PerformNextInstrumentAction = InputActionSetupExtensions.AddAction(ActionMap, "TooManyEmotes.PlayNextInstrument", (InputActionType)0, "/n", "Press", (string)null, (string)null, (string)null); InputActionSetupExtensions.AddBinding(PerformNextInstrumentAction, "/dpad/right", (string)null, (string)null, (string)null); InputActionSetupExtensions.AddBinding(PerformRandomEmoteAction, "/ ", (string)null, (string)null, (string)null); PerformSelectedEmoteAction = new InputAction("TooManyEmotes.PerformSelectedEmote", (InputActionType)0, "/leftButton", "Press", (string)null, (string)null); ThumbStickAction = new InputAction("TooManyEmotes.ThumbStick", (InputActionType)0, "/rightStick", (string)null, (string)null, (string)null); RawScrollAction = new InputAction("TooManyEmotes.ScrollEmoteMenu", (InputActionType)0, "/scroll", (string)null, (string)null, (string)null); } } [HarmonyPatch(typeof(StartOfRound), "OnEnable")] [HarmonyPostfix] public static void OnEnable() { Asset.Enable(); OpenEmoteMenuAction.performed += OnPressOpenEmoteMenu; OpenEmoteMenuAction.canceled += OnPressOpenEmoteMenu; FavoriteEmoteAction.performed += OnFavoriteEmote; PrevEmotePageAction.performed += OnPrevEmotePage; NextEmotePageAction.performed += OnNextEmotePage; NextEmoteLoadoutUpAction.performed += OnEmoteLoadoutUp; NextEmoteLoadoutDownAction.performed += OnEmoteLoadoutDown; RotatePlayerEmoteAction.performed += OnUpdateRotatePlayerEmoteModifier; RotatePlayerEmoteAction.canceled += OnUpdateRotatePlayerEmoteModifier; ZoomInEmoteAction.performed += ThirdPersonEmoteController.OnZoomInEmote; ZoomOutEmoteAction.performed += ThirdPersonEmoteController.OnZoomOutEmote; PerformNextInstrumentAction.performed += PlayNextInstrument; PerformRandomEmoteAction.performed += PerformRandomEmote; if (InputUtils_Compat.Enabled) { QuickEmote1Action.performed += OnQuickEmote1; QuickEmote2Action.performed += OnQuickEmote2; QuickEmote3Action.performed += OnQuickEmote3; QuickEmote4Action.performed += OnQuickEmote4; QuickEmote5Action.performed += OnQuickEmote5; QuickEmote6Action.performed += OnQuickEmote6; QuickEmote7Action.performed += OnQuickEmote7; QuickEmote8Action.performed += OnQuickEmote8; } PerformSelectedEmoteAction.Enable(); PerformSelectedEmoteAction.performed += OnSelectEmoteUI; ThumbStickAction.Enable(); ThumbStickAction.performed += EmoteMenu.OnUpdateThumbStickAngle; RawScrollAction.Enable(); } [HarmonyPatch(typeof(StartOfRound), "OnDisable")] [HarmonyPostfix] public static void OnDisable() { Asset.Disable(); OpenEmoteMenuAction.performed -= OnPressOpenEmoteMenu; OpenEmoteMenuAction.canceled -= OnPressOpenEmoteMenu; FavoriteEmoteAction.performed -= OnFavoriteEmote; PrevEmotePageAction.performed -= OnPrevEmotePage; NextEmotePageAction.performed -= OnNextEmotePage; NextEmoteLoadoutUpAction.performed -= OnEmoteLoadoutUp; NextEmoteLoadoutDownAction.performed -= OnEmoteLoadoutDown; RotatePlayerEmoteAction.performed -= OnUpdateRotatePlayerEmoteModifier; RotatePlayerEmoteAction.canceled -= OnUpdateRotatePlayerEmoteModifier; ZoomInEmoteAction.performed -= ThirdPersonEmoteController.OnZoomInEmote; ZoomOutEmoteAction.performed -= ThirdPersonEmoteController.OnZoomOutEmote; PerformNextInstrumentAction.performed -= PlayNextInstrument; PerformRandomEmoteAction.performed -= PerformRandomEmote; if (InputUtils_Compat.Enabled) { QuickEmote1Action.performed -= OnQuickEmote1; QuickEmote2Action.performed -= OnQuickEmote2; QuickEmote3Action.performed -= OnQuickEmote3; QuickEmote4Action.performed -= OnQuickEmote4; QuickEmote5Action.performed -= OnQuickEmote5; QuickEmote6Action.performed -= OnQuickEmote6; QuickEmote7Action.performed -= OnQuickEmote7; QuickEmote8Action.performed -= OnQuickEmote8; } PerformSelectedEmoteAction.Disable(); PerformSelectedEmoteAction.performed -= OnSelectEmoteUI; ThumbStickAction.Disable(); ThumbStickAction.performed -= EmoteMenu.OnUpdateThumbStickAngle; RawScrollAction.Disable(); } public static void OnPrevEmotePage(CallbackContext context) { if (!((Object)(object)HelperTools.localPlayerController == (Object)null) && !ConfigSettings.disableEmotesForSelf.Value && EmoteMenu.isMenuOpen && ((CallbackContext)(ref context)).performed) { EmoteMenu.SwapPrevPage(); } } public static void OnNextEmotePage(CallbackContext context) { if (!((Object)(object)HelperTools.localPlayerController == (Object)null) && !ConfigSettings.disableEmotesForSelf.Value && EmoteMenu.isMenuOpen && ((CallbackContext)(ref context)).performed) { EmoteMenu.SwapNextPage(); } } public static void OnEmoteLoadoutUp(CallbackContext context) { if (!((Object)(object)HelperTools.localPlayerController == (Object)null) && !ConfigSettings.disableEmotesForSelf.Value && EmoteMenu.isMenuOpen && ((CallbackContext)(ref context)).performed) { EmoteMenu.SetCurrentEmoteLoadout((EmoteMenu.currentLoadoutIndex != 0) ? (EmoteMenu.currentLoadoutIndex - 1) : (EmoteMenu.numLoadouts - 1)); } } public static void OnEmoteLoadoutDown(CallbackContext context) { if (!((Object)(object)HelperTools.localPlayerController == (Object)null) && !ConfigSettings.disableEmotesForSelf.Value && EmoteMenu.isMenuOpen && ((CallbackContext)(ref context)).performed) { EmoteMenu.SetCurrentEmoteLoadout((EmoteMenu.currentLoadoutIndex + 1) % EmoteMenu.numLoadouts); } } private static void OnPressOpenEmoteMenu(CallbackContext context) { //IL_00aa: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)HelperTools.localPlayerController == (Object)null || ConfigSettings.disableEmotesForSelf.Value || LCVR_Compat.LoadedAndEnabled) { return; } if (!EmoteMenu.isMenuOpen) { if (((CallbackContext)(ref context)).performed && EmoteMenu.CanOpenEmoteMenu()) { EmoteMenu.OpenEmoteMenu(); } } else if (ConfigSettings.toggleEmoteMenu.Value || StartOfRound.Instance.localPlayerUsingController) { if (((CallbackContext)(ref context)).performed) { EmoteMenu.CloseEmoteMenu(); } } else if (((CallbackContext)(ref context)).canceled) { if (EmoteMenu.hoveredEmoteIndex != -1) { PerformEmoteLocal(context); } EmoteMenu.CloseEmoteMenu(); } } private static void OnSelectEmoteUI(CallbackContext context) { //IL_007b: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)HelperTools.localPlayerController == (Object)null) && ((CallbackContext)(ref context)).performed && EmoteMenu.isMenuOpen) { if (EmoteMenu.hoveredLoadoutUIIndex != -1 && EmoteMenu.hoveredLoadoutUIIndex != EmoteMenu.currentLoadoutIndex) { EmoteMenu.SetCurrentEmoteLoadout(EmoteMenu.hoveredLoadoutUIIndex); } else if (EmoteMenu.hoveredEmoteIndex >= 0 && EmoteMenu.hoveredEmoteIndex < EmoteMenu.currentLoadoutEmotesList.Count) { PerformEmoteLocal(context); EmoteMenu.CloseEmoteMenu(); } } } public static void PerformEmoteLocal(CallbackContext context) { if (!ConfigSettings.disableEmotesForSelf.Value && !LCVR_Compat.LoadedAndEnabled && EmoteMenu.hoveredEmoteIndex >= 0 && EmoteMenu.hoveredEmoteIndex < EmoteMenu.currentLoadoutEmotesList.Count && !((Object)(object)EmoteControllerPlayer.emoteControllerLocal == (Object)null)) { UnlockableEmote unlockableEmote = EmoteMenu.currentLoadoutEmotesList[EmoteMenu.hoveredEmoteIndex]; if (unlockableEmote != null) { HelperTools.emoteControllerLocal.TryPerformingEmoteLocal(unlockableEmote); } } } public static void OnFavoriteEmote(CallbackContext context) { if (!((Object)(object)HelperTools.localPlayerController == (Object)null) && ((CallbackContext)(ref context)).performed && EmoteMenu.isMenuOpen && EmoteMenu.hoveredEmoteUIIndex != -1 && EmoteMenu.previewingEmote != null) { EmoteMenu.ToggleFavoriteHoveredEmote(); } } private static void OnQuickEmote1(CallbackContext context) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) OnQuickEmote(context, 0); } private static void OnQuickEmote2(CallbackContext context) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) OnQuickEmote(context, 1); } private static void OnQuickEmote3(CallbackContext context) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) OnQuickEmote(context, 2); } private static void OnQuickEmote4(CallbackContext context) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) OnQuickEmote(context, 3); } private static void OnQuickEmote5(CallbackContext context) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) OnQuickEmote(context, 4); } private static void OnQuickEmote6(CallbackContext context) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) OnQuickEmote(context, 5); } private static void OnQuickEmote7(CallbackContext context) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) OnQuickEmote(context, 6); } private static void OnQuickEmote8(CallbackContext context) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) OnQuickEmote(context, 7); } public static void OnQuickEmote(CallbackContext context, int quickEmoteIndex) { if ((Object)(object)HelperTools.localPlayerController == (Object)null || !((CallbackContext)(ref context)).performed || (HelperTools.quickMenuManager.isMenuOpen && !EmoteMenu.isMenuOpen) || ConfigSettings.disableEmotesForSelf.Value || LCVR_Compat.LoadedAndEnabled) { return; } if (EmoteMenu.isMenuOpen) { try { string text = ""; if (EmotesManager.allQuickEmotes != null && quickEmoteIndex >= 0 && quickEmoteIndex < EmotesManager.allQuickEmotes.Count()) { text = EmotesManager.allQuickEmotes[quickEmoteIndex]; } CustomLogging.LogWarningVerbose("HoveredEmoteIndex: " + EmoteMenu.hoveredEmoteIndex + " LoadoutSize: " + EmoteMenu.currentLoadoutEmotesList.Count); if (EmoteMenu.hoveredEmoteIndex >= 0 && EmoteMenu.hoveredEmoteIndex < EmoteMenu.currentLoadoutEmotesList.Count) { UnlockableEmote unlockableEmote = EmoteMenu.currentLoadoutEmotesList[EmoteMenu.hoveredEmoteIndex]; if (unlockableEmote != null) { CustomLogging.LogWarningVerbose("QuickEmote: " + unlockableEmote); if (unlockableEmote.emoteName != text) { while (EmotesManager.allQuickEmotes.Contains(unlockableEmote.emoteName)) { EmotesManager.allQuickEmotes[EmotesManager.allQuickEmotes.IndexOf(unlockableEmote.emoteName)] = ""; } if (unlockableEmote.inEmoteSyncGroup) { EmotesManager.allQuickEmotes[quickEmoteIndex] = unlockableEmote.emoteSyncGroup[0].emoteName; } else { EmotesManager.allQuickEmotes[quickEmoteIndex] = unlockableEmote.emoteName; } EmoteMenu.UpdateEmoteWheel(); SaveManager.SaveQuickEmotes(); CustomLogging.LogVerbose("Assigned quick emote " + (quickEmoteIndex + 1) + ". Emote: " + unlockableEmote.emoteName + ((!string.IsNullOrEmpty(text)) ? (". Previous emote: " + text) : "")); } else { EmotesManager.allQuickEmotes[quickEmoteIndex] = ""; EmoteMenu.UpdateEmoteWheel(); SaveManager.SaveQuickEmotes(); CustomLogging.LogVerbose("Unassigned quick emote " + (quickEmoteIndex + 1) + ". Emote: " + text); } } } return; } catch (Exception ex) { CustomLogging.LogErrorVerbose("Could not assign quick emote " + (quickEmoteIndex + 1) + "\n" + ex); return; } } try { string text2 = EmotesManager.allQuickEmotes[quickEmoteIndex]; UnlockableEmote value; if (string.IsNullOrEmpty(text2)) { CustomLogging.LogWarningVerbose("Could not perform quick emote " + (quickEmoteIndex + 1) + ". Emote has not been assigned."); } else if (!EmotesManager.allUnlockableEmotesDict.TryGetValue(text2, out value)) { CustomLogging.LogWarningVerbose("Could not perform quick emote " + (quickEmoteIndex + 1) + ". Emote is invalid: " + text2); } else if (!SessionManager.unlockedEmotes.Contains(value) && !value.complementary) { CustomLogging.LogWarningVerbose("Could not perform quick emote " + (quickEmoteIndex + 1) + ". Emote is not unlocked: " + text2); } else if (!(Time.time - EmoteControllerPlayer.timeLastPeformedEmoteLocalPlayer < 0.25f)) { CustomLogging.LogVerbose("Attempting to perform quick emote " + (quickEmoteIndex + 1) + ". Emote: " + value); HelperTools.emoteControllerLocal.TryPerformingEmoteLocal(value); } } catch (Exception ex2) { CustomLogging.LogErrorVerbose("Could not perform quick emote " + (quickEmoteIndex + 1) + "\n" + ex2); } } public static void OnUpdateRotatePlayerEmoteModifier(CallbackContext context) { if ((Object)(object)HelperTools.localPlayerController == (Object)null || !HelperTools.emoteControllerLocal.IsPerformingCustomEmote() || ThirdPersonEmoteController.firstPersonEmotesEnabled || HelperTools.quickMenuManager.isMenuOpen) { return; } if (((CallbackContext)(ref context)).performed) { if (ConfigSettings.toggleRotateCharacterInEmote.Value) { toggledRotating = !toggledRotating; holdingRotatePlayerModifier = false; } else { holdingRotatePlayerModifier = true; toggledRotating = false; } } else if (((CallbackContext)(ref context)).canceled && !ConfigSettings.toggleRotateCharacterInEmote.Value) { holdingRotatePlayerModifier = false; } } public static void PlayNextInstrument(CallbackContext context) { if (!((Object)(object)HelperTools.localPlayerController == (Object)null) && !ConfigSettings.disableEmotesForSelf.Value && !LCVR_Compat.LoadedAndEnabled && (!HelperTools.quickMenuManager.isMenuOpen || EmoteMenu.isMenuOpen) && HelperTools.emoteControllerLocal.isPerformingEmote && HelperTools.emoteControllerLocal.performingEmote.inEmoteSyncGroup && HelperTools.emoteControllerLocal.performingEmote.emoteSyncGroup.Count > 1) { HelperTools.emoteControllerLocal.TryPerformingEmoteLocal(HelperTools.emoteControllerLocal.performingEmote); } } public static void PerformRandomEmote(CallbackContext context) { if (!ConfigSettings.disableEmotesForSelf.Value && !LCVR_Compat.LoadedAndEnabled && !EmoteMenu.isMenuOpen && SessionManager.unlockedEmotes != null && SessionManager.unlockedEmotes.Count > 0 && (!HelperTools.quickMenuManager.isMenuOpen || EmoteMenu.isMenuOpen)) { int index = Random.Range(0, SessionManager.unlockedEmotes.Count); UnlockableEmote emote = SessionManager.unlockedEmotes[index]; if (HelperTools.emoteControllerLocal.TryPerformingEmoteLocal(emote) && !ConfigSettings.disableChatLogRandomEmote.Value) { MethodInfo method = ((object)HUDManager.Instance).GetType().GetMethod("AddChatMessage", BindingFlags.Instance | BindingFlags.NonPublic); method.Invoke(HUDManager.Instance, new object[4] { $"Perform Random Emote\n[{HelperTools.emoteControllerLocal.performingEmote.displayNameColorCoded}]", "", -1, false }); } } } } [HarmonyPatch] public static class KeybindDisplayNames { public static bool usingControllerPrevious = false; public static string[] keyboardKeywords = new string[2] { "keyboard", "mouse" }; public static string[] controllerKeywords = new string[2] { "gamepad", "controller" }; public static bool usingController => StartOfRound.Instance.localPlayerUsingController; [HarmonyPatch(typeof(HUDManager), "Update")] [HarmonyPostfix] public static void CheckForInputSourceUpdate() { if (usingController != usingControllerPrevious) { usingControllerPrevious = usingController; UpdateControlTipLines(); } } [HarmonyPatch(typeof(KepRemapPanel), "OnDisable")] [HarmonyPostfix] public static void OnCloseRemapPanel() { UpdateControlTipLines(); } public static void UpdateControlTipLines() { if (EmoteMenu.isMenuOpen) { EmoteMenu.UpdateControlTipLines(); } if (HUDManager.Instance?.controlTipLines != null) { for (int i = 0; i < HUDManager.Instance.controlTipLines.Length; i++) { TextMeshProUGUI val = HUDManager.Instance.controlTipLines[i]; if (!((Object)(object)val != (Object)null) || !((Component)val).gameObject.activeSelf || !((Behaviour)val).enabled || !((TMP_Text)val).text.Contains("Emote Radial Menu")) { continue; } string keybindDisplayName = GetKeybindDisplayName(Keybinds.OpenEmoteMenuAction); string keybindDisplayName2 = GetKeybindDisplayName(Keybinds.PerformRandomEmoteAction); if (keybindDisplayName != "") { ((TMP_Text)HUDManager.Instance.controlTipLines[i]).text = $"Emote Menu : [{keybindDisplayName}]"; if (i == HUDManager.Instance.controlTipLines.Length - 1 && keybindDisplayName2 != "") { TextMeshProUGUI obj = HUDManager.Instance.controlTipLines[i]; ((TMP_Text)obj).text = ((TMP_Text)obj).text + $"\nRandom Emote : [{keybindDisplayName2}]"; } } break; } } ThirdPersonEmoteController.UpdateControlTip(); } public static string GetKeybindDisplayName(InputAction inputAction) { //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_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) if (inputAction == null || !inputAction.enabled) { return ""; } int num = (usingController ? 1 : 0); InputBinding val = inputAction.bindings[num]; string effectivePath = ((InputBinding)(ref val)).effectivePath; return GetKeybindDisplayName(effectivePath); } public static string GetKeybindDisplayName(string controlPath) { if (string.IsNullOrEmpty(controlPath) || controlPath.Length <= 1) { return ""; } string text = controlPath.ToLower(); int num = text.IndexOf(">/"); text = ((num >= 0) ? text.Substring(num + 2) : text); if (string.IsNullOrWhiteSpace(text) || text.Contains("not-bound")) { return ""; } text = text.Replace("leftalt", "Alt"); text = text.Replace("rightalt", "Alt"); text = text.Replace("leftctrl", "Ctrl"); text = text.Replace("rightctrl", "Ctrl"); text = text.Replace("leftshift", "Shift"); text = text.Replace("rightshift", "Shift"); text = text.Replace("leftbutton", "LMB"); text = text.Replace("rightbutton", "RMB"); text = text.Replace("middlebutton", "MMB"); text = text.Replace("lefttrigger", "LT"); text = text.Replace("righttrigger", "RT"); text = text.Replace("leftshoulder", "LB"); text = text.Replace("rightshoulder", "RB"); text = text.Replace("leftstickpress", "LS"); text = text.Replace("rightstickpress", "RS"); text = text.Replace("dpad/", "DPad-"); text = text.Replace("scroll/up", "Scroll Up"); text = text.Replace("scroll/down", "Scroll Down"); text = text.Replace("backquote", "`"); try { text = char.ToUpper(text[0]) + text.Substring(1); } catch { } return text; } } } namespace TooManyEmotes.UI { [HarmonyPatch] public static class AnimationPreviewer { [CompilerGenerated] private sealed class <g__DisableRenderCameraNextFrameCoroutine|13_0>d : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <g__DisableRenderCameraNextFrameCoroutine|13_0>d(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = null; <>1__state = 1; return true; case 1: <>1__state = -1; ((Behaviour)renderingCamera).enabled = false; return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <>c__DisplayClass10_0 { public PlayerControllerB __instance; } public static bool enabled = false; public static Camera renderingCamera; public static GameObject previewPlayerObject; public static SkinnedMeshRenderer previewPlayerMesh; public static EmoteController simpleEmoteController; public static int renderLayer = 23; public static GameObject previewBoombox; public static int renderLayerMask => 1 << renderLayer; public static void InitializeAnimationRenderer() { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Unknown result type (might be due to invalid IL or missing references) if (!ConfigSettings.disableEmotesForSelf.Value && !LCVR_Compat.LoadedAndEnabled) { CustomLogging.Log("Initializing animation renderer"); renderingCamera = new GameObject("AnimationRenderingCamera").AddComponent(); Object.Destroy((Object)(object)((Component)renderingCamera).GetComponent()); renderingCamera.cullingMask = renderLayerMask; 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; renderingCamera.targetTexture = EmoteMenu.renderTexture; ((Component)renderingCamera).transform.position = Vector3.down * 1000f; EmoteMenu.renderTextureImageUI.texture = (Texture)(object)EmoteMenu.renderTexture; Light val = new GameObject("Spotlight").AddComponent(); val.type = (LightType)0; ((Component)val).transform.SetParent(((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 = renderLayer; DisableRenderCameraNextFrame(); enabled = true; } } [HarmonyPatch(typeof(PlayerControllerB), "ConnectClientToPlayerObject")] [HarmonyPostfix] public static void InitializePlayerCloneRenderObject(PlayerControllerB __instance) { <>c__DisplayClass10_0 CS$<>8__locals0 = new <>c__DisplayClass10_0(); CS$<>8__locals0.__instance = __instance; if (enabled && !ConfigSettings.disableEmotesForSelf.Value && !LCVR_Compat.LoadedAndEnabled && Object.op_Implicit((Object)(object)Plugin.radialMenuPrefab)) { ((MonoBehaviour)CS$<>8__locals0.__instance).StartCoroutine(InitPlayerCloneAfterSpawnAnimation()); } [IteratorStateMachine(typeof(<>c__DisplayClass10_0.<g__InitPlayerCloneAfterSpawnAnimation|0>d))] IEnumerator InitPlayerCloneAfterSpawnAnimation() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <>c__DisplayClass10_0.<g__InitPlayerCloneAfterSpawnAnimation|0>d(0) { <>4__this = CS$<>8__locals0 }; } } public static void UpdatePlayerSuit() { if ((Object)(object)previewPlayerMesh != (Object)null && (Object)(object)HelperTools.localPlayerController?.thisPlayerModel != (Object)null) { ((Renderer)previewPlayerMesh).material = ((Renderer)HelperTools.localPlayerController.thisPlayerModel).material; } } public static void SetPreviewAnimation(UnlockableEmote emote) { if (!enabled || !Object.op_Implicit((Object)(object)previewPlayerObject) || !Object.op_Implicit((Object)(object)simpleEmoteController)) { return; } if (enabled && emote != null) { previewPlayerObject.SetActive(true); ((Behaviour)renderingCamera).enabled = true; if (Object.op_Implicit((Object)(object)previewBoombox)) { previewBoombox.SetActive(emote.hasAudio && emote.isBoomboxAudio); } simpleEmoteController.PerformEmote(emote); if (simpleEmoteController.emotingProps == null) { return; } { foreach (PropObject emotingProp in simpleEmoteController.emotingProps) { emotingProp.SetPropLayer(renderLayer); } return; } } simpleEmoteController.StopPerformingEmote(); previewPlayerObject.SetActive(false); if (Object.op_Implicit((Object)(object)previewBoombox)) { previewBoombox.SetActive(false); } DisableRenderCameraNextFrame(); } private static void DisableRenderCameraNextFrame() { ((MonoBehaviour)HUDManager.Instance).StartCoroutine(DisableRenderCameraNextFrameCoroutine()); [IteratorStateMachine(typeof(<g__DisableRenderCameraNextFrameCoroutine|13_0>d))] static IEnumerator DisableRenderCameraNextFrameCoroutine() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <g__DisableRenderCameraNextFrameCoroutine|13_0>d(0); } } private static void SetObjectLayerRecursive(GameObject obj, int layer) { if (Object.op_Implicit((Object)(object)obj)) { 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] public static class EmoteMenu { public static GameObject menuGameObject; public static RectTransform menuTransform; public static CanvasGroup canvasGroup; public static RawImage renderTextureImageUI; public static RenderTexture renderTexture; public static TextMeshPro swapPageText; public static TextMeshPro currentEmoteText; 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 emoteUIElementsList; public static int hoveredEmoteUIIndex = -1; public static int currentPage = 0; public static List emoteLoadoutUIElementsList = new List(); public static List> emoteLoadouts = new List>(); 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; private static Transform customControlTipLinesParent; public static TextMeshProUGUI[] customControlTipLines; private static bool firstTimeOpeningMenu; private static Slider emoteVolumeSlider; private static Toggle muteEmoteToggle; private static Toggle emoteOnlyModeToggle; private static Toggle enableDmcaFreeToggle; private static GameObject allowMovingWhileEmotingGameObject; private static Toggle enableFirstPersonEmoteToggle; private static Toggle allowMovingWhileEmotingToggle; private static float currentVolumeSetting = 1f; private static bool currentMuteSetting = false; private static bool currentEmoteOnlyMode = false; private static bool currentDmcaFreeSetting = false; private static bool currentFirstPersonEmotes = false; private static bool currentAllowMovingWhileEmoting = false; private static List allUnlockedEmotesFiltered = new List(); private static GameObject togglePanelComplementary; private static GameObject togglePanel0; private static GameObject togglePanel1; private static GameObject togglePanel2; private static GameObject togglePanel3; private static Toggle hideEmotesComplementaryToggle; private static Toggle hideEmotes0Toggle; private static Toggle hideEmotes1Toggle; private static Toggle hideEmotes2Toggle; private static Toggle hideEmotes3Toggle; private static Camera currentCameraInSettings; 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) ? null : (currentLoadoutEmotesList[hoveredEmoteIndex].inEmoteSyncGroup ? currentLoadoutEmotesList[hoveredEmoteIndex].emoteSyncGroup[0] : currentLoadoutEmotesList[hoveredEmoteIndex]); public static List 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), "Awake")] [HarmonyPostfix] public static void InitializeUI(HUDManager __instance) { //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) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Expected O, but got Unknown //IL_01cb: Unknown result type (might be due to invalid IL or missing references) //IL_01d1: Unknown result type (might be due to invalid IL or missing references) //IL_01e2: Unknown result type (might be due to invalid IL or missing references) //IL_0291: Unknown result type (might be due to invalid IL or missing references) //IL_02a0: Unknown result type (might be due to invalid IL or missing references) //IL_02af: Unknown result type (might be due to invalid IL or missing references) if (!CustomLogging.Assert((Object)(object)Plugin.radialMenuPrefab != (Object)null, "Radial menu prefab is null??") || ConfigSettings.disableEmotesForSelf.Value || LCVR_Compat.LoadedAndEnabled) { return; } CustomLogging.Log("Initializing emote menu"); AnimationPreviewer.enabled = false; firstTimeOpeningMenu = true; hoveredEmoteUIIndex = -1; currentPage = 0; currentLoadoutIndex = -1; hoveredLoadoutUIIndex = -1; currentThumbstickPosition = Vector2.zero; menuGameObject = Object.Instantiate(Plugin.radialMenuPrefab, __instance.HUDContainer.transform.parent); menuGameObject.transform.SetAsLastSibling(); ((Object)menuGameObject).name = "EmotesRadialMenu"; menuTransform = menuGameObject.GetComponent(); renderTextureImageUI = menuGameObject.GetComponentInChildren(); renderTexture = new RenderTexture(1024, 1024, 24); renderTexture.format = (RenderTextureFormat)0; renderTexture.graphicsFormat = (GraphicsFormat)8; renderTexture.depthStencilFormat = (GraphicsFormat)92; Transform transform = ((Component)((Transform)menuTransform).Find("MenuUI/RadialMenu/RadialElements")).transform; swapPageText = ((Component)((Transform)menuTransform).Find("MenuUI/RadialMenu/RadialBase/SwapPageText")).GetComponent(); currentEmoteText = ((Component)((Transform)menuTransform).Find("MenuUI/RadialMenu/RadialBase/CurrentEmoteText")).GetComponent(); ((TMP_Text)currentEmoteText).text = ""; emoteUIElementsList = new List(); RectTransform component = ((Component)((TMP_Text)HUDManager.Instance.controlTipLines[0]).transform.parent).GetComponent(); customControlTipLinesParent = (Transform)(object)Object.Instantiate(component, ((Transform)component).parent); ((Object)customControlTipLinesParent).name = "EmoteMenuControlTips"; customControlTipLinesParent.SetSiblingIndex(((Transform)component).GetSiblingIndex() + 1); customControlTipLinesParent.SetPositionAndRotation(((Transform)component).position, ((Transform)component).rotation); customControlTipLinesParent.localScale = ((Transform)component).localScale; customControlTipLines = (TextMeshProUGUI[])(object)new TextMeshProUGUI[HUDManager.Instance.controlTipLines.Length]; int num = 0; TextMeshProUGUI[] componentsInChildren = ((Component)customControlTipLinesParent).GetComponentsInChildren(); foreach (TextMeshProUGUI val in componentsInChildren) { if ((Object)(object)val != (Object)null) { if (((Object)val).name.ToLower().Contains("controltip")) { customControlTipLines[num++] = val; } else { Object.Destroy((Object)(object)((Component)val).gameObject); } } } customControlTipLinesParent.SetParent((Transform)(object)menuTransform, true); customControlTipLinesParent.localPosition = new Vector3(customControlTipLinesParent.localPosition.x, customControlTipLinesParent.localPosition.y, 0f); customControlTipLinesParent.SetSiblingIndex(1); currentPage = 0; hoveredEmoteUIIndex = -1; for (int j = 0; j < transform.childCount; j++) { Transform child = transform.GetChild(j); EmoteUIElement emoteUIElement = new EmoteUIElement(); emoteUIElement.uiGameObject = ((Component)child).gameObject; emoteUIElement.uiRectTransform = (RectTransform)(object)((child is RectTransform) ? child : null); emoteUIElement.id = j; emoteUIElement.backgroundImage = ((Component)child).GetComponentInChildren(); emoteUIElement.textContainer = ((Component)child).GetComponentInChildren(); EmoteUIElement item = emoteUIElement; emoteUIElementsList.Add(item); } Transform transform2 = ((Component)((Transform)menuTransform).Find("MenuUI/EmoteLoadouts")).transform; ((Component)transform2).gameObject.AddComponent(); EmoteLoadoutUIElement.uiCount = 0; emoteLoadoutUIElementsList.Clear(); emoteLoadoutUIElementsList.Add(((Component)transform2.GetChild(0)).gameObject.AddComponent()); emoteLoadoutUIElementsList.AddRange(new EmoteLoadoutUIElement[6] { Object.Instantiate(emoteLoadoutUIElementsList[0], transform2), Object.Instantiate(emoteLoadoutUIElementsList[0], transform2), Object.Instantiate(emoteLoadoutUIElementsList[0], transform2), Object.Instantiate(emoteLoadoutUIElementsList[0], transform2), Object.Instantiate(emoteLoadoutUIElementsList[0], transform2), Object.Instantiate(emoteLoadoutUIElementsList[0], transform2) }); for (int k = 0; k < emoteLoadoutUIElementsList.Count; k++) { ((Object)emoteLoadoutUIElementsList[k]).name = "EmoteLoadout_" + k; } emoteLoadoutUIElementsList[0].loadoutName = "Favorites"; emoteLoadoutUIElementsList[1].loadoutName = $"Legendary"; emoteLoadoutUIElementsList[2].loadoutName = $"Epic"; emoteLoadoutUIElementsList[3].loadoutName = $"Rare"; emoteLoadoutUIElementsList[4].loadoutName = $"Common"; emoteLoadoutUIElementsList[5].loadoutName = "Complementary"; emoteLoadoutUIElementsList[6].loadoutName = "All"; emoteLoadouts.Clear(); emoteLoadouts.AddRange(new List[7] { SessionManager.unlockedFavoriteEmotes, SessionManager.unlockedEmotesTier3, SessionManager.unlockedEmotesTier2, SessionManager.unlockedEmotesTier1, SessionManager.unlockedEmotesTier0, EmotesManager.complementaryEmotes, allUnlockedEmotesFiltered }); if (currentLoadoutIndex < 0 || currentLoadoutIndex >= emoteLoadouts.Count) { currentLoadoutIndex = emoteLoadouts.Count - 1; } Transform val2 = ((Transform)menuTransform).Find("MenuUI/AdditionalUI"); ((Component)val2).gameObject.AddComponent(); AudioManager.LoadPreferences(); ThirdPersonEmoteController.LoadPreferences(); Transform obj = val2.Find("AudioVolumePanel"); emoteVolumeSlider = ((obj != null) ? ((Component)obj).GetComponentInChildren() : null); emoteVolumeSlider.value = Mathf.Clamp(AudioManager.emoteVolumeMultiplier, 0f, emoteVolumeSlider.maxValue); ((UnityEvent)(object)emoteVolumeSlider.onValueChanged).AddListener((UnityAction)delegate { OnUpdateEmoteVolume(emoteVolumeSlider); }); currentVolumeSetting = emoteVolumeSlider.value; Transform obj2 = val2.Find("MasterMutePanel"); muteEmoteToggle = ((obj2 != null) ? ((Component)obj2).GetComponentInChildren() : null); muteEmoteToggle.isOn = AudioManager.muteEmoteAudio; ((UnityEvent)(object)muteEmoteToggle.onValueChanged).AddListener((UnityAction)delegate { OnUpdateToggleMuteEmote(muteEmoteToggle); }); currentMuteSetting = muteEmoteToggle.isOn; Transform obj3 = val2.Find("EmoteOnlyModePanel"); emoteOnlyModeToggle = ((obj3 != null) ? ((Component)obj3).GetComponentInChildren() : null); emoteOnlyModeToggle.isOn = AudioManager.emoteOnlyMode; ((UnityEvent)(object)emoteOnlyModeToggle.onValueChanged).AddListener((UnityAction)delegate { OnUpdateToggleEmoteOnlyMode(emoteOnlyModeToggle); }); currentEmoteOnlyMode = emoteOnlyModeToggle.isOn; Transform obj4 = val2.Find("DmcaFreePanel"); enableDmcaFreeToggle = ((obj4 != null) ? ((Component)obj4).GetComponentInChildren() : null); enableDmcaFreeToggle.isOn = AudioManager.dmcaFreeMode; ((UnityEvent)(object)enableDmcaFreeToggle.onValueChanged).AddListener((UnityAction)delegate { OnUpdateToggleDmcaFreeMode(enableDmcaFreeToggle); }); currentDmcaFreeSetting = enableDmcaFreeToggle.isOn; Transform obj5 = val2.Find("FirstPersonEmotesPanel"); enableFirstPersonEmoteToggle = ((obj5 != null) ? ((Component)obj5).GetComponentInChildren() : null); enableFirstPersonEmoteToggle.isOn = ThirdPersonEmoteController.firstPersonEmotesEnabled; ((UnityEvent)(object)enableFirstPersonEmoteToggle.onValueChanged).AddListener((UnityAction)delegate { OnUpdateToggleFirstPerson(enableFirstPersonEmoteToggle); }); currentFirstPersonEmotes = enableFirstPersonEmoteToggle.isOn; Transform obj6 = val2.Find("MoveWhileEmotingPanel"); allowMovingWhileEmotingGameObject = ((obj6 != null) ? ((Component)obj6).gameObject : null); GameObject obj7 = allowMovingWhileEmotingGameObject; allowMovingWhileEmotingToggle = ((obj7 != null) ? obj7.GetComponentInChildren() : null); allowMovingWhileEmotingToggle.isOn = ThirdPersonEmoteController.allowMovingWhileEmoting; ((UnityEvent)(object)allowMovingWhileEmotingToggle.onValueChanged).AddListener((UnityAction)delegate { OnUpdateToggleAllowMovingWhileEmoting(allowMovingWhileEmotingToggle); }); currentAllowMovingWhileEmoting = allowMovingWhileEmotingToggle.isOn; togglePanelComplementary = ((Component)val2.Find("HideEmotesComplementary")).gameObject; togglePanel0 = ((Component)val2.Find("HideEmotes0")).gameObject; togglePanel1 = ((Component)val2.Find("HideEmotes1")).gameObject; togglePanel2 = ((Component)val2.Find("HideEmotes2")).gameObject; togglePanel3 = ((Component)val2.Find("HideEmotes3")).gameObject; GameObject obj8 = togglePanelComplementary; hideEmotesComplementaryToggle = ((obj8 != null) ? obj8.GetComponentInChildren() : null); GameObject obj9 = togglePanel0; hideEmotes0Toggle = ((obj9 != null) ? obj9.GetComponentInChildren() : null); GameObject obj10 = togglePanel1; hideEmotes1Toggle = ((obj10 != null) ? obj10.GetComponentInChildren() : null); GameObject obj11 = togglePanel2; hideEmotes2Toggle = ((obj11 != null) ? obj11.GetComponentInChildren() : null); GameObject obj12 = togglePanel3; hideEmotes3Toggle = ((obj12 != null) ? obj12.GetComponentInChildren() : null); ((UnityEvent)(object)hideEmotesComplementaryToggle?.onValueChanged).AddListener((UnityAction)delegate { OnUpdateFilteredEmotes(); }); ((UnityEvent)(object)hideEmotes0Toggle?.onValueChanged).AddListener((UnityAction)delegate { OnUpdateFilteredEmotes(); }); ((UnityEvent)(object)hideEmotes1Toggle?.onValueChanged).AddListener((UnityAction)delegate { OnUpdateFilteredEmotes(); }); ((UnityEvent)(object)hideEmotes2Toggle?.onValueChanged).AddListener((UnityAction)delegate { OnUpdateFilteredEmotes(); }); ((UnityEvent)(object)hideEmotes3Toggle?.onValueChanged).AddListener((UnityAction)delegate { OnUpdateFilteredEmotes(); }); LoadFilterPreferences(); AnimationPreviewer.InitializeAnimationRenderer(); menuGameObject.SetActive(false); } [HarmonyPatch(typeof(HUDManager), "Update")] [HarmonyPostfix] public static void GetInput() { //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Unknown result type (might be due to invalid IL or missing references) //IL_014b: 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_0168: Unknown result type (might be due to invalid IL or missing references) if (!isMenuOpen || ConfigSettings.disableEmotesForSelf.Value || LCVR_Compat.LoadedAndEnabled) { return; } if (AdditionalPanelUI.hovered || hoveredLoadoutUIIndex != -1) { if (hoveredEmoteUIIndex != -1) { OnHoveredNewElement(-1); } return; } RectTransform uiRectTransform = emoteUIElementsList[0].uiRectTransform; float num = Vector2.Distance(Vector2.op_Implicit(menuGameObject.transform.position), Vector2.op_Implicit(((Transform)uiRectTransform).position)) * 0.815f; Vector2 val2; if (!usingController) { Vector3 val = Vector2.op_Implicit(((InputControl)(object)((Pointer)Mouse.current).position).ReadValue()); Camera worldCamera = HUDManager.Instance.HUDContainer.GetComponentInParent().worldCamera; val.z = Mathf.Abs(((Component)worldCamera).transform.position.z - ((Transform)menuTransform).position.z); val2 = Vector2.op_Implicit(worldCamera.ScreenToWorldPoint(val) - ((Transform)menuTransform).position); } else { val2 = currentThumbstickPosition; } int num2 = -1; if ((!usingController && ((Vector2)(ref val2)).magnitude >= num) || (usingController && currentThumbstickPosition != Vector2.zero)) { float num3 = Mathf.Atan2(val2.y, 0f - val2.x) * 57.29578f - 67.5f; if (num3 < 0f) { num3 += 360f; } num2 = Mathf.FloorToInt(num3 / 45f); } if (num2 != hoveredEmoteUIIndex) { OnHoveredNewElement(num2); } } public static void OnUpdateThumbStickAngle(CallbackContext context) { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)HelperTools.localPlayerController == (Object)null) && !ConfigSettings.disableEmotesForSelf.Value && !LCVR_Compat.LoadedAndEnabled && ((CallbackContext)(ref context)).performed && isMenuOpen) { currentThumbstickPosition = ((CallbackContext)(ref context)).ReadValue(); currentThumbstickPosition = ((((Vector2)(ref currentThumbstickPosition)).magnitude > 0.75f) ? currentThumbstickPosition : Vector2.zero); StartOfRound.Instance.localPlayerUsingController = true; if (currentThumbstickPosition == Vector2.zero && previewingEmote != null) { HelperTools.emoteControllerLocal.TryPerformingEmoteLocal(previewingEmote); 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; AnimationPreviewer.SetPreviewAnimation(previewingEmote); if (previewingEmote != null) { ((TMP_Text)currentEmoteText).text = previewingEmote.displayNameColorCoded + (EmotesManager.allFavoriteEmotes.Contains(previewingEmote.emoteName) ? " *" : ""); } else { ((TMP_Text)currentEmoteText).text = ""; } } 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() { if (customControlTipLines != null) { 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)customControlTipLines[i++]).text = "Swap Page: [Scroll Mouse]"; } else if (keybindDisplayName != "" || keybindDisplayName2 != "") { ((TMP_Text)customControlTipLines[i++]).text = $"Swap Page: [{keybindDisplayName}/{keybindDisplayName2}]"; } if (usingController || keybindDisplayName3 != "" || keybindDisplayName4 != "") { ((TMP_Text)customControlTipLines[i++]).text = $"Swap Loadout: [{keybindDisplayName3}/{keybindDisplayName4}]"; } ((TMP_Text)customControlTipLines[i++]).text = $"Favorite Emote: [{keybindDisplayName5}]"; if (InputUtils_Compat.Enabled && i < customControlTipLines.Length) { ((TMP_Text)customControlTipLines[i++]).text = "Set Quick Emote : [Keybind #]"; } for (; i < customControlTipLines.Length; i++) { ((TMP_Text)customControlTipLines[i]).text = ""; } } } public static void UpdateEmoteWheel() { //IL_01bf: Unknown result type (might be due to invalid IL or missing references) //IL_01c4: Unknown result type (might be due to invalid IL or missing references) //IL_01c6: Unknown result type (might be due to invalid IL or missing references) //IL_01cb: Unknown result type (might be due to invalid IL or missing references) //IL_02d3: Unknown result type (might be due to invalid IL or missing references) //IL_02d5: Unknown result type (might be due to invalid IL or missing references) //IL_02e1: Unknown result type (might be due to invalid IL or missing references) //IL_02b4: Unknown result type (might be due to invalid IL or missing references) //IL_02b6: Unknown result type (might be due to invalid IL or missing references) //IL_02ca: Unknown result type (might be due to invalid IL or missing references) //IL_02cc: Unknown result type (might be due to invalid IL or missing references) if (currentLoadoutEmotesList == allUnlockedEmotesFiltered) { SortFilteredEmotes(); togglePanelComplementary.SetActive(true); togglePanel0.SetActive(true); togglePanel1.SetActive(true); togglePanel2.SetActive(true); togglePanel3.SetActive(true); } else { togglePanelComplementary.SetActive(false); togglePanel0.SetActive(false); togglePanel1.SetActive(false); togglePanel2.SetActive(false); togglePanel3.SetActive(false); } 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 list = emoteLoadouts[j]; EmoteLoadoutUIElement emoteLoadoutUIElement2 = emoteLoadoutUIElementsList[j]; ((TMP_Text)emoteLoadoutUIElement2.textContainer).text = emoteLoadoutUIElement2.loadoutName + " [" + list.Count + "]"; } Color val = default(Color); 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; Color color = Color.white; if (num < currentLoadoutEmotesList.Count) { UnlockableEmote unlockableEmote = currentLoadoutEmotesList[num]; if (unlockableEmote != null) { emoteUIElement.emote = unlockableEmote; ((TMP_Text)emoteUIElement.textContainer).text = unlockableEmote.displayName; int num2 = EmotesManager.allQuickEmotes.IndexOf(unlockableEmote.emoteName); if (num2 >= 0 && num2 < EmotesManager.allQuickEmotes.Count) { TextMeshPro textContainer = emoteUIElement.textContainer; ((TMP_Text)textContainer).text = ((TMP_Text)textContainer).text + " [" + (num2 + 1) + "]"; } if (!unlockableEmote.complementary && ColorUtility.TryParseHtmlString(UnlockableEmote.rarityColorCodes[unlockableEmote.rarity], ref val)) { if (ConfigSettings.colorCodeEmoteBackgroundInRadialMenu.Value) { baseColor = val; } else if (ConfigSettings.colorCodeEmoteNamesInRadialMenu.Value) { color = val; } } } } emoteUIElement.baseColor = baseColor; ((Graphic)emoteUIElement.textContainer).color = color; emoteUIElement.OnHover(hovered: false); } if (hoveredEmoteUIIndex >= 0 && hoveredEmoteUIIndex < 8) { OnHoveredNewElement(hoveredEmoteUIIndex); } } private static void SortFilteredEmotes() { allUnlockedEmotesFiltered.Clear(); if (!hideEmotesComplementaryToggle.isOn) { allUnlockedEmotesFiltered.AddRange(EmotesManager.complementaryEmotes); } if (!hideEmotes0Toggle.isOn) { allUnlockedEmotesFiltered.AddRange(SessionManager.unlockedEmotesTier0); } if (!hideEmotes1Toggle.isOn) { allUnlockedEmotesFiltered.AddRange(SessionManager.unlockedEmotesTier1); } if (!hideEmotes2Toggle.isOn) { allUnlockedEmotesFiltered.AddRange(SessionManager.unlockedEmotesTier2); } if (!hideEmotes3Toggle.isOn) { allUnlockedEmotesFiltered.AddRange(SessionManager.unlockedEmotesTier3); } for (int num = SessionManager.unlockedFavoriteEmotes.Count - 1; num >= 0; num--) { if (!allUnlockedEmotesFiltered.Contains(SessionManager.unlockedFavoriteEmotes[num])) { allUnlockedEmotesFiltered.Add(SessionManager.unlockedFavoriteEmotes[num]); } } try { allUnlockedEmotesFiltered.Sort((UnlockableEmote item1, UnlockableEmote item2) => string.Compare(item1.displayName, item2.displayName, ignoreCase: true, EmotesManager.defaultSortCulture)); } catch (Exception) { if (ConfigSettings.verboseLogs.Value) { CustomLogging.LogWarningVerbose("Failed to apply default emote sort in emote menu. Reverting to original sort method."); } allUnlockedEmotesFiltered.Sort((UnlockableEmote item1, UnlockableEmote item2) => item1.displayName.CompareTo(item2.displayName)); } } public static void SetCurrentEmoteLoadout(int loadoutIndex) { if (currentLoadoutIndex != loadoutIndex) { currentPage = 0; currentLoadoutIndex = loadoutIndex; UpdateEmoteWheel(); } } public static void ToggleFavoriteHoveredEmote() { if (isMenuOpen && previewingEmote != null) { UnlockableEmote unlockableEmote = previewingEmote; if (previewingEmote.emoteSyncGroup != null && previewingEmote.emoteSyncGroup.Count > 0) { unlockableEmote = previewingEmote.emoteSyncGroup[0]; } string emoteName = unlockableEmote.emoteName; if (EmotesManager.allFavoriteEmotes.Contains(emoteName)) { EmotesManager.allFavoriteEmotes.Remove(emoteName); } else { EmotesManager.allFavoriteEmotes.Add(emoteName); } SessionManager.UpdateUnlockedFavoriteEmotes(); SaveManager.SaveFavoritedEmotes(); UpdateEmoteWheel(); } } public static void OpenEmoteMenu() { //IL_019c: Unknown result type (might be due to invalid IL or missing references) //IL_01a1: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)HelperTools.localPlayerController) || ConfigSettings.disableEmotesForSelf.Value || LCVR_Compat.LoadedAndEnabled) { return; } if (firstTimeOpeningMenu) { CustomLogging.Assert(emoteLoadouts != null && emoteLoadouts.Count > 0, "Error opening emote menu. Emote loadouts are null or empty!"); int currentEmoteLoadout = ((emoteLoadouts[0].Count <= 0) ? currentLoadoutIndex : 0); SetCurrentEmoteLoadout(currentEmoteLoadout); if (currentLoadoutIndex < emoteLoadouts.Count - 1) { SortFilteredEmotes(); } customControlTipLinesParent.position = ((TMP_Text)HUDManager.Instance.controlTipLines[0]).transform.parent.position; firstTimeOpeningMenu = false; } currentMuteSetting = AudioManager.muteEmoteAudio; currentEmoteOnlyMode = AudioManager.emoteOnlyMode; currentDmcaFreeSetting = AudioManager.dmcaFreeMode; currentVolumeSetting = AudioManager.emoteVolumeMultiplier; currentFirstPersonEmotes = ThirdPersonEmoteController.firstPersonEmotesEnabled; currentAllowMovingWhileEmoting = ThirdPersonEmoteController.allowMovingWhileEmoting; if (ConfigSync.instance.syncForceDisableMovingWhileEmoting && Object.op_Implicit((Object)(object)allowMovingWhileEmotingGameObject)) { allowMovingWhileEmotingGameObject.SetActive(false); } if (CustomLogging.Assert((Object)(object)menuGameObject != (Object)null, "Error opening emote menu. Menu gameobject is null!")) { menuGameObject.SetActive(true); } if (CustomLogging.Assert((Object)(object)HelperTools.quickMenuManager != (Object)null, "Error opening emote menu. Quick menu manager gameobject is null!")) { HelperTools.quickMenuManager.isMenuOpen = true; } Cursor.lockState = (CursorLockMode)0; Cursor.visible = true; AnimationPreviewer.UpdatePlayerSuit(); currentThumbstickPosition = Vector2.zero; TextMeshProUGUI[] array = HUDManager.Instance?.controlTipLines; if (array != null) { TextMeshProUGUI[] array2 = array; foreach (TextMeshProUGUI val in array2) { if ((Object)(object)val != (Object)null) { ((Behaviour)val).enabled = false; } } } TextMeshProUGUI[] array3 = ThirdPersonEmoteController.customControlTipLines; foreach (TextMeshProUGUI val2 in array3) { if ((Object)(object)val2 != (Object)null) { ((Behaviour)val2).enabled = false; } } UpdateControlTipLines(); UpdateEmoteWheel(); if (currentLoadoutEmotesList != allUnlockedEmotesFiltered) { SortFilteredEmotes(); } } public static void CloseEmoteMenu() { Cursor.lockState = (CursorLockMode)1; Cursor.visible = false; if (Object.op_Implicit((Object)(object)HelperTools.localPlayerController)) { HelperTools.localPlayerController.isFreeCamera = false; } if (Object.op_Implicit((Object)(object)menuGameObject)) { menuGameObject.SetActive(false); } if (Object.op_Implicit((Object)(object)HelperTools.quickMenuManager) && HelperTools.quickMenuManager.isMenuOpen) { if (HelperTools.quickMenuManager.settingsPanel.activeSelf) { IngamePlayerSettings.Instance.DiscardChangedSettings(); } HelperTools.quickMenuManager.CloseQuickMenuPanels(); HelperTools.quickMenuManager.menuContainer.SetActive(false); Cursor.lockState = (CursorLockMode)1; Cursor.visible = false; HelperTools.quickMenuManager.isMenuOpen = false; } OnHoveredNewLoadoutElement(-1); AnimationPreviewer.SetPreviewAnimation(null); AdditionalPanelUI.hovered = false; SaveFilterPreferences(); if (ThirdPersonEmoteController.firstPersonEmotesEnabled != currentFirstPersonEmotes || ThirdPersonEmoteController.allowMovingWhileEmoting != currentAllowMovingWhileEmoting) { ThirdPersonEmoteController.SavePreferences(); } if (AudioManager.muteEmoteAudio != currentMuteSetting || AudioManager.emoteOnlyMode != currentEmoteOnlyMode || AudioManager.dmcaFreeMode != currentDmcaFreeSetting || AudioManager.emoteVolumeMultiplier != currentVolumeSetting) { AudioManager.SavePreferences(); } TextMeshProUGUI[] array = HUDManager.Instance?.controlTipLines; if (array != null) { TextMeshProUGUI[] array2 = array; foreach (TextMeshProUGUI val in array2) { if ((Object)(object)val != (Object)null) { ((Behaviour)val).enabled = true; } } } TextMeshProUGUI[] array3 = ThirdPersonEmoteController.customControlTipLines; foreach (TextMeshProUGUI val2 in array3) { if ((Object)(object)val2 != (Object)null) { ((Behaviour)val2).enabled = true; } } } public static bool CanOpenEmoteMenu() { if (HelperTools.quickMenuManager.isMenuOpen && !isMenuOpen) { return false; } if (ConfigSettings.disableEmotesForSelf.Value || LCVR_Compat.LoadedAndEnabled) { return false; } if (HelperTools.localPlayerController.isPlayerDead || HelperTools.localPlayerController.inSpecialInteractAnimation || HelperTools.localPlayerController.inTerminalMenu || HelperTools.localPlayerController.isTypingChat || HelperTools.localPlayerController.inSpecialInteractAnimation || HelperTools.localPlayerController.isGrabbingObjectAnimation || HelperTools.localPlayerController.inShockingMinigame || HelperTools.localPlayerController.isClimbingLadder || HelperTools.localPlayerController.isSinking) { return false; } if ((Object)(object)HelperTools.localPlayerController.inAnimationWithEnemy != (Object)null || CentipedePatcher.IsCentipedeLatchedOntoLocalPlayer()) { return false; } return true; } public static void OnUpdateToggleMuteEmote(Toggle toggle) { AudioManager.muteEmoteAudio = toggle.isOn; CustomLogging.Log("Toggling mute emote audio: " + AudioManager.muteEmoteAudio); foreach (EmoteAudioSource allEmoteAudioSource in EmoteAudioSource.allEmoteAudioSources) { allEmoteAudioSource.UpdateVolume(); } DiscoBallPatcher.OnUpdateMuteEmotes(); } public static void OnUpdateToggleEmoteOnlyMode(Toggle toggle) { AudioManager.emoteOnlyMode = toggle.isOn; CustomLogging.Log("Toggling emote only mode: " + AudioManager.emoteOnlyMode); } public static void OnUpdateToggleDmcaFreeMode(Toggle toggle) { AudioManager.dmcaFreeMode = toggle.isOn; CustomLogging.Log("Toggling DMCA free mode: " + AudioManager.dmcaFreeMode); foreach (EmoteAudioSource allEmoteAudioSource in EmoteAudioSource.allEmoteAudioSources) { allEmoteAudioSource.RefreshAudio(); } } public static void OnUpdateToggleFirstPerson(Toggle toggle) { ThirdPersonEmoteController.UpdateFirstPersonEmoteMode(toggle.isOn); CustomLogging.Log("Toggling first person emotes: " + ThirdPersonEmoteController.firstPersonEmotesEnabled); } public static void OnUpdateToggleAllowMovingWhileEmoting(Toggle toggle) { ThirdPersonEmoteController.SetCanMoveWhileEmoting(toggle.isOn); CustomLogging.Log("Toggling allow moving while emoting: " + ThirdPersonEmoteController.allowMovingWhileEmoting); } public static void OnUpdateEmoteVolume(Slider volumeSlider) { AudioManager.emoteVolumeMultiplier = Mathf.Clamp(volumeSlider.value, 0f, 2f); foreach (EmoteAudioSource allEmoteAudioSource in EmoteAudioSource.allEmoteAudioSources) { allEmoteAudioSource.UpdateVolume(); } } public static void OnUpdateFilteredEmotes() { if (currentLoadoutEmotesList == allUnlockedEmotesFiltered) { UpdateEmoteWheel(); } } public static void SaveFilterPreferences() { try { CustomLogging.Log("Saving TooManyEmotes emote menu preferences."); ES3.Save("TooManyEmotes.HideEmotesComplementary", hideEmotesComplementaryToggle.isOn, SaveManager.TooManyEmotesSaveFileName); ES3.Save("TooManyEmotes.HideEmotes0", hideEmotes0Toggle.isOn, SaveManager.TooManyEmotesSaveFileName); ES3.Save("TooManyEmotes.HideEmotes1", hideEmotes1Toggle.isOn, SaveManager.TooManyEmotesSaveFileName); ES3.Save("TooManyEmotes.HideEmotes2", hideEmotes2Toggle.isOn, SaveManager.TooManyEmotesSaveFileName); ES3.Save("TooManyEmotes.HideEmotes3", hideEmotes3Toggle.isOn, SaveManager.TooManyEmotesSaveFileName); } catch (Exception ex) { CustomLogging.LogErrorVerbose("Error while trying to save TooManyEmotes emote menu data.\n" + ex); } } public static void LoadFilterPreferences() { try { ES3.DeleteKey("TooManyEmotes.HideEmotesComplementary"); ES3.DeleteKey("TooManyEmotes.HideEmotes0"); ES3.DeleteKey("TooManyEmotes.HideEmotes1"); ES3.DeleteKey("TooManyEmotes.HideEmotes2"); ES3.DeleteKey("TooManyEmotes.HideEmotes3"); } catch { } try { hideEmotesComplementaryToggle.isOn = ES3.Load("TooManyEmotes.HideEmotesComplementary", SaveManager.TooManyEmotesSaveFileName, false); hideEmotes0Toggle.isOn = ES3.Load("TooManyEmotes.HideEmotes0", SaveManager.TooManyEmotesSaveFileName, false); hideEmotes1Toggle.isOn = ES3.Load("TooManyEmotes.HideEmotes1", SaveManager.TooManyEmotesSaveFileName, false); hideEmotes2Toggle.isOn = ES3.Load("TooManyEmotes.HideEmotes2", SaveManager.TooManyEmotesSaveFileName, false); hideEmotes3Toggle.isOn = ES3.Load("TooManyEmotes.HideEmotes3", SaveManager.TooManyEmotesSaveFileName, false); } catch { try { ES3.DeleteKey("TooManyEmotes.HideEmotesComplementary", SaveManager.TooManyEmotesSaveFileName); ES3.DeleteKey("TooManyEmotes.HideEmotes0", SaveManager.TooManyEmotesSaveFileName); ES3.DeleteKey("TooManyEmotes.HideEmotes1", SaveManager.TooManyEmotesSaveFileName); ES3.DeleteKey("TooManyEmotes.HideEmotes2", SaveManager.TooManyEmotesSaveFileName); ES3.DeleteKey("TooManyEmotes.HideEmotes3", SaveManager.TooManyEmotesSaveFileName); } catch { } } } [HarmonyPatch(typeof(PlayerControllerB), "ScrollMouse_performed")] [HarmonyPrefix] public static bool OnScrollMouse(CallbackContext context, PlayerControllerB __instance) { if (!((CallbackContext)(ref context)).performed || (Object)(object)__instance != (Object)(object)HelperTools.localPlayerController || ConfigSettings.disableEmotesForSelf.Value || LCVR_Compat.LoadedAndEnabled || !isMenuOpen || usingController) { return true; } if (isMenuOpen) { if (numPages == 0 || (numPages == 1 && currentPage == 0)) { return false; } float num = ((CallbackContext)(ref context)).ReadValue(); 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, PlayerControllerB __instance) { if ((Object)(object)__instance != (Object)(object)HelperTools.localPlayerController || ConfigSettings.disableEmotesForSelf.Value || LCVR_Compat.LoadedAndEnabled) { return true; } return !isMenuOpen; } [HarmonyPatch(typeof(PlayerControllerB), "ItemTertiaryUse_performed")] [HarmonyPrefix] public static bool PreventItemTertiaryUseInMenu(CallbackContext context, PlayerControllerB __instance) { if ((Object)(object)__instance != (Object)(object)HelperTools.localPlayerController || ConfigSettings.disableEmotesForSelf.Value || LCVR_Compat.LoadedAndEnabled) { return true; } return !isMenuOpen; } [HarmonyPatch(typeof(PlayerControllerB), "Interact_performed")] [HarmonyPrefix] public static bool PreventItemInteractInMenu(CallbackContext context, PlayerControllerB __instance) { if ((Object)(object)__instance != (Object)(object)HelperTools.localPlayerController || ConfigSettings.disableEmotesForSelf.Value || LCVR_Compat.LoadedAndEnabled) { return true; } return !isMenuOpen; } [HarmonyPatch(typeof(QuickMenuManager), "OpenQuickMenu")] [HarmonyPrefix] public static bool OnOpenQuickMenu() { if (isMenuOpen) { CloseEmoteMenu(); return false; } return true; } [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)HelperTools.localPlayerController && __instance.isPlayerDead) { CloseEmoteMenu(); } } [HarmonyPatch(typeof(IngamePlayerSettings), "UpdateCameraMotionVectorsSetting")] [HarmonyPrefix] public static void OnUpdateCameraMotionVectorsSettingPrefix() { currentCameraInSettings = null; if ((Object)(object)StartOfRound.Instance != (Object)null && (Object)(object)StartOfRound.Instance.activeCamera != (Object)null) { currentCameraInSettings = StartOfRound.Instance.activeCamera; if (HelperTools.emoteControllerLocal.isPerformingEmote && (Object)(object)StartOfRound.Instance.activeCamera != (Object)(object)ThirdPersonEmoteController.gameplayCamera) { currentCameraInSettings = StartOfRound.Instance.activeCamera; StartOfRound.Instance.activeCamera = ThirdPersonEmoteController.gameplayCamera; } } } [HarmonyPatch(typeof(IngamePlayerSettings), "UpdateCameraMotionVectorsSetting")] [HarmonyPostfix] public static void OnUpdateCameraMotionVectorsSettingPostfix() { if ((Object)(object)StartOfRound.Instance != (Object)null && (Object)(object)currentCameraInSettings != (Object)null) { StartOfRound.Instance.activeCamera = currentCameraInSettings; } } } public class EmoteUIElement { public GameObject uiGameObject; public RectTransform uiRectTransform; 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 ? EmoteMenu.hoveredAlpha : EmoteMenu.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(); textContainer = ((Component)this).GetComponentInChildren(); ((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 = ((EmoteMenu.currentLoadoutIndex == id) ? EmoteMenu.selectedLoadoutUIColor : EmoteMenu.defaultUIColor) * (hovered ? 1f : 0.5f); color.a = (hovered ? EmoteMenu.hoveredAlpha : EmoteMenu.unhoveredAlpha); ((Graphic)backgroundImage).color = color; } public void OnPointerEnter(PointerEventData eventData) { EmoteMenu.OnHoveredNewLoadoutElement(id); OnHover(); } public void OnPointerExit(PointerEventData eventData) { EmoteMenu.OnHoveredNewLoadoutElement(-1); OnHover(hovered: false); } } public class AdditionalPanelUI : MonoBehaviour, IPointerEnterHandler, IEventSystemHandler, IPointerExitHandler { public static bool hovered; public void OnPointerEnter(PointerEventData eventData) { hovered = true; } public void OnPointerExit(PointerEventData eventData) { hovered = false; } } } namespace TooManyEmotes.Props { public class EmotePropData { public GameObject propPrefab; public string propName; public List parentEmotes = new List(); public bool isGrabbableObject = false; public bool registered = false; public Item itemData; public SpawnableItemWithRarity itemRarityData; public string itemName = ""; public GrabbablePropObject grabbablePropObject = null; public bool isScrap = true; public int rarity = 10; public bool twoHanded = false; public int minValue = 0; public int maxValue = 0; public float weight = 0f; public Vector3 positionOffset = default(Vector3); public Vector3 rotationOffset = default(Vector3); public Vector3 restingRotation = default(Vector3); public float verticalOffset = 0f; } public class GrabbablePropObject : PhysicsProp { public EmotePropData emotePropData; public UnlockableEmote emote; public ScanNodeProperties scanNodeProperties; public AudioSource sfxAudioSource; public EmoteControllerPlayer heldByPlayerEmoteController { get { EmoteControllerPlayer value; return ((Object)(object)((GrabbableObject)this).playerHeldBy != (Object)null && EmoteControllerPlayer.allPlayerEmoteControllers.TryGetValue(((GrabbableObject)this).playerHeldBy, out value)) ? value : null; } } public bool isPerformingEmote { get; private set; } public void Awake() { Animator componentInChildren = ((Component)this).GetComponentInChildren(); if ((Object)(object)componentInChildren != (Object)null) { ((Behaviour)componentInChildren).enabled = false; } if (emotePropData == null) { if ((Object)(object)((GrabbableObject)this).itemProperties.spawnPrefab == (Object)null) { CustomLogging.LogError("Failed to initialize grabbable emote prop object. Prefab reference is missing!"); return; } if (!EmotePropManager.emotePropsDataDict.TryGetValue(((Object)((GrabbableObject)this).itemProperties.spawnPrefab).name, out emotePropData)) { CustomLogging.LogError("Failed to initialize grabbable emote prop object. Failed to find EmotePropData for object: " + ((Object)((GrabbableObject)this).itemProperties.spawnPrefab).name); return; } } if (emotePropData.parentEmotes != null && emotePropData.parentEmotes.Count > 0) { if (emote == null) { emote = emotePropData.parentEmotes[0]; } } else { CustomLogging.LogError("Failed to assign emote to grabbable emote prop: " + ((Object)this).name + ". Emote is null."); } BoxCollider component = ((Component)this).GetComponent(); ((Collider)component).isTrigger = false; } public override void Start() { ((GrabbableObject)this).Start(); Animator componentInChildren = ((Component)this).GetComponentInChildren(); if ((Object)(object)componentInChildren != (Object)null) { Object.DestroyImmediate((Object)(object)componentInChildren); } StopEmote(); } public override void ItemActivate(bool used, bool buttonDown = true) { if (buttonDown) { if (emote == null) { CustomLogging.LogWarning("Failed to interact with prop: " + ((GrabbableObject)this).itemProperties.itemName + ". Emote is null!"); } else if ((Object)(object)heldByPlayerEmoteController == (Object)null) { CustomLogging.LogWarning("Failed to interact with prop: " + ((GrabbableObject)this).itemProperties.itemName + ". Parent player emote controller is null!"); } else if (heldByPlayerEmoteController.IsPerformingCustomEmote()) { StopEmote(); } else { PerformEmote(); } } } public override void Update() { ((GrabbableObject)this).Update(); } internal void PerformEmote() { if (emote == null || (Object)(object)heldByPlayerEmoteController == (Object)null || heldByPlayerEmoteController.IsPerformingCustomEmote()) { return; } isPerformingEmote = true; heldByPlayerEmoteController.TryPerformingEmoteLocal(emote, -1, this); if (heldByPlayerEmoteController.IsPerformingCustomEmote()) { SkinnedMeshRenderer[] componentsInChildren = ((Component)this).GetComponentsInChildren(); foreach (SkinnedMeshRenderer val in componentsInChildren) { val.updateWhenOffscreen = true; } } } internal void StopEmote() { if (Object.op_Implicit((Object)(object)heldByPlayerEmoteController)) { isPerformingEmote = false; if (heldByPlayerEmoteController.IsPerformingCustomEmote()) { heldByPlayerEmoteController.StopPerformingEmote(); } ((GrabbableObject)this).parentObject = (heldByPlayerEmoteController.isLocalPlayer ? heldByPlayerEmoteController.playerController.localItemHolder : heldByPlayerEmoteController.playerController.serverItemHolder); } SkinnedMeshRenderer[] componentsInChildren = ((Component)this).GetComponentsInChildren(); foreach (SkinnedMeshRenderer val in componentsInChildren) { val.updateWhenOffscreen = false; } } } [HarmonyPatch] internal static class EmotePropManager { public static AssetBundle propAssetBundle; public static List emotePropsData = new List(); public static Dictionary emotePropsDataDict = new Dictionary(); public static bool registeredGrabbableEmoteProps = false; public static Transform propPoolParent; public static Dictionary> propPoolsDict = new Dictionary>(); [HarmonyPatch(typeof(StartOfRound), "Awake")] [HarmonyPrefix] private static void Init(StartOfRound __instance) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) CleanPropPools(); propPoolParent = new GameObject("EmotePropPool").transform; } public static void LoadPropAssets() { try { string text = Path.Combine(Path.GetDirectoryName(((BaseUnityPlugin)Plugin.instance).Info.Location), "Assets/emote_props"); propAssetBundle = AssetBundle.LoadFromFile(text); GameObject[] array = propAssetBundle.LoadAllAssets(); GameObject[] array2 = array; foreach (GameObject val in array2) { if (!emotePropsDataDict.ContainsKey(((Object)val).name)) { EmotePropData emotePropData = new EmotePropData { propPrefab = val, propName = ((Object)val).name }; if (!Object.op_Implicit((Object)(object)val.GetComponent())) { val.AddComponent(); } emotePropsData.Add(emotePropData); emotePropsDataDict.Add(emotePropData.propName, emotePropData); } } CustomLogging.Log("Loaded " + emotePropsData.Count + " emote props."); } catch { CustomLogging.LogError("Failed to load emotes props asset bundle: emote_props."); } } public static void BuildEmotePropList() { if (emotePropsData == null) { return; } CleanPropPools(); propPoolsDict.Clear(); if (EmotesManager.allUnlockableEmotes == null || EmotesManager.allUnlockableEmotes.Count <= 0) { CustomLogging.LogError("Failed to build emote prop list. Make sure you build the emote prop list after building the unlockable emotes list."); return; } foreach (EmotePropData emotePropsDatum in emotePropsData) { if (emotePropsDatum == null) { continue; } string text = emotePropsDatum.propName; if (text.Contains(".")) { string[] array = text.Split(new char[1] { '.' }); if (array.Length != 0 && array[0].Length > 0) { text = array[0]; } } if (EmotesManager.allUnlockableEmotesDict.TryGetValue(text, out var value)) { if (value.propNamesInEmote == null) { value.propNamesInEmote = new List(); } value.propNamesInEmote.Add(emotePropsDatum.propName); if (emotePropsDatum.parentEmotes == null) { emotePropsDatum.parentEmotes = new List(); } emotePropsDatum.parentEmotes.Add(value); } } } public static PropObject LoadEmoteProp(string propName) { if (!emotePropsDataDict.TryGetValue(propName, out var value)) { CustomLogging.LogError("Failed to instantiate emote prop: " + propName + ". Prop does not exist!"); return null; } if (!propPoolsDict.TryGetValue(propName, out var value2)) { value2 = new HashSet(); propPoolsDict.Add(propName, value2); } foreach (PropObject item in value2) { if (!item.active) { item.active = true; return item; } } GameObject val = Object.Instantiate(value.propPrefab); ((Object)val).name = ((Object)value.propPrefab).name + ".animation_prop"; GrabbablePropObject component = val.GetComponent(); if ((Object)(object)component != (Object)null && Object.op_Implicit((Object)(object)component.sfxAudioSource)) { Object.Destroy((Object)(object)component.sfxAudioSource); } Object.DestroyImmediate((Object)(object)val.GetComponent()); Object.DestroyImmediate((Object)(object)val.GetComponent()); Object.Destroy((Object)(object)val.GetComponent()); Collider[] componentsInChildren = val.GetComponentsInChildren(); foreach (Collider val2 in componentsInChildren) { Object.Destroy((Object)(object)val2); } PropObject propObject = val.GetComponentInChildren(); if ((Object)(object)propObject == (Object)null) { propObject = val.AddComponent(); } propObject.active = true; value2.Add(propObject); propObject.InitializeEmoteProp(); return propObject; } internal static void CleanPropPools() { foreach (HashSet value in propPoolsDict.Values) { value.RemoveWhere((PropObject prop) => (Object)(object)prop == (Object)null); } } internal static void DestroyAllProps() { foreach (HashSet value in propPoolsDict.Values) { foreach (PropObject item in value) { Object.DestroyImmediate((Object)(object)item); } value.Clear(); } } } public class PropObject : MonoBehaviour { private bool initialized = false; public Animator animator; public bool active { get { return ((Component)this).gameObject.activeSelf; } set { ((Component)this).gameObject.SetActive(value); } } public RuntimeAnimatorController animatorController => ((Object)(object)animator != (Object)null) ? animator.runtimeAnimatorController : null; private void Awake() { if (!initialized) { InitializeEmoteProp(); } Collider[] componentsInChildren = ((Component)this).GetComponentsInChildren(); foreach (Collider val in componentsInChildren) { Object.Destroy((Object)(object)val); } Object.Destroy((Object)(object)((Component)this).GetComponentInChildren()); } public void InitializeEmoteProp() { if (!initialized) { animator = ((Component)this).GetComponentInChildren(); initialized = true; } } public void SyncWithEmoteController(EmoteController emoteController) { if ((Object)(object)animator != (Object)null) { ((Behaviour)animator).enabled = true; animator.SetBool("loop", emoteController.isLooping); animator.Play(emoteController.currentStateHash, 0, emoteController.currentAnimationTimeNormalized % 1f); } } public void SetPropLayer(int layer) { SetPropLayerRecursive(((Component)this).gameObject, layer); } private void SetPropLayerRecursive(GameObject obj, int layer) { if (obj.layer != 22) { obj.layer = layer; } for (int i = 0; i < obj.transform.childCount; i++) { SetPropLayerRecursive(((Component)obj.transform.GetChild(i)).gameObject, layer); } } } } namespace TooManyEmotes.Patches { [HarmonyPatch] public static class DiscoBallPatcher { public static Transform discoBallTransform; public static AudioSource audioSource; private static bool prevIsMuted = false; private static bool isMuted = false; private static float muteEmoteDistance = 20f; private static HashSet nearbyPerformingEmoteControllers = new HashSet(); [HarmonyPatch(typeof(AutoParentToShip), "Awake")] [HarmonyPostfix] private static void InitDiscoBall(AutoParentToShip __instance) { if (((Object)__instance).name.ToLower().StartsWith("discoball") && (!((Object)(object)discoBallTransform != (Object)null) || !((Object)(object)audioSource != (Object)null))) { GameObject val = (Object.op_Implicit((Object)(object)discoBallTransform) ? ((Component)discoBallTransform).gameObject : ((Component)__instance).gameObject); discoBallTransform = null; audioSource = null; isMuted = false; nearbyPerformingEmoteControllers.Clear(); audioSource = val.GetComponentInChildren(); if (Object.op_Implicit((Object)(object)audioSource)) { discoBallTransform = val.transform; CustomLogging.Log("Found disco ball."); } } } [HarmonyPatch(typeof(StartOfRound), "LateUpdate")] [HarmonyPostfix] private static void CheckForStateUpdates(StartOfRound __instance) { //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_0151: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)discoBallTransform)) { return; } foreach (EmoteSyncGroup value in EmoteSyncGroup.allEmoteSyncGroups.Values) { if (!value.useAudio || value.performingEmote == null || !value.performingEmote.hasAudio || value.syncGroup == null || value.syncGroup.Count <= 0) { continue; } foreach (EmoteController item in value.syncGroup) { if (!nearbyPerformingEmoteControllers.Contains(item)) { float num = Vector3.Distance(((Component)item).transform.position, discoBallTransform.position); if (num < muteEmoteDistance) { OnPerformEmote(item); } } } } if (nearbyPerformingEmoteControllers.Count <= 0) { return; } HashSet hashSet = null; foreach (EmoteController nearbyPerformingEmoteController in nearbyPerformingEmoteControllers) { float num2 = Vector3.Distance(((Component)nearbyPerformingEmoteController).transform.position, discoBallTransform.position); if (num2 >= muteEmoteDistance) { if (hashSet == null) { hashSet = new HashSet(); } hashSet.Add(nearbyPerformingEmoteController); } } if (hashSet == null) { return; } foreach (EmoteController item2 in hashSet) { OnStopPerformingEmote(item2); } } internal static void OnPerformEmote(EmoteController emoteController) { //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) if (Object.op_Implicit((Object)(object)discoBallTransform) && Object.op_Implicit((Object)(object)emoteController) && emoteController.IsPerformingCustomEmote() && emoteController.performingEmote.hasAudio && emoteController.emoteSyncGroup != null && emoteController.emoteSyncGroup.useAudio && Vector3.Distance(((Component)emoteController).transform.position, discoBallTransform.position) < muteEmoteDistance) { nearbyPerformingEmoteControllers.Add(emoteController); if (!isMuted && nearbyPerformingEmoteControllers.Count > 0) { MuteDiscoBall(); } } } internal static void OnStopPerformingEmote(EmoteController emoteController) { if (nearbyPerformingEmoteControllers.Contains(emoteController)) { nearbyPerformingEmoteControllers.Remove(emoteController); if (Object.op_Implicit((Object)(object)discoBallTransform) && nearbyPerformingEmoteControllers.Count <= 0 && isMuted) { UnmuteDiscoBall(); } } } internal static void OnUpdateMuteEmotes() { if (Object.op_Implicit((Object)(object)audioSource) && isMuted && AudioManager.muteEmoteAudio == audioSource.mute) { audioSource.mute = !AudioManager.muteEmoteAudio || prevIsMuted; } } private static void MuteDiscoBall(bool mute = true) { if (!Object.op_Implicit((Object)(object)discoBallTransform) || !Object.op_Implicit((Object)(object)audioSource) || isMuted == mute) { return; } if (mute) { prevIsMuted = audioSource.mute; if (!AudioManager.muteEmoteAudio) { audioSource.mute = true; } } else { audioSource.mute = prevIsMuted; } isMuted = mute; CustomLogging.Log("Updating disco ball mute value to: " + mute); } private static void UnmuteDiscoBall() { MuteDiscoBall(mute: false); } } [HarmonyPatch] public static class CentipedePatcher { public static HashSet latchedOnCentipedesLocalPlayer = new HashSet(); [HarmonyPatch(typeof(StartOfRound), "Awake")] [HarmonyPostfix] public static void Init() { latchedOnCentipedesLocalPlayer.Clear(); } [HarmonyPatch(typeof(CentipedeAI), "ClingToPlayer")] [HarmonyPostfix] public static void OnCentipedeLatchOntoLocalPlayer(PlayerControllerB playerScript, CentipedeAI __instance) { if ((Object)(object)__instance.clingingToPlayer == (Object)(object)HelperTools.localPlayerController) { latchedOnCentipedesLocalPlayer.Add(__instance); if (HelperTools.emoteControllerLocal.IsPerformingCustomEmote()) { CustomLogging.LogWarning("Centipede latched onto local player while emoting. Canceling emote."); HelperTools.localPlayerController.performingEmote = false; HelperTools.emoteControllerLocal.StopPerformingEmote(); HelperTools.localPlayerController.StopPerformingEmoteServerRpc(); } } } [HarmonyPatch(typeof(CentipedeAI), "OnDisable")] [HarmonyPostfix] public static void RemoveCentipedeFromList(CentipedeAI __instance) { if (latchedOnCentipedesLocalPlayer.Contains(__instance)) { latchedOnCentipedesLocalPlayer.Remove(__instance); } } public static bool IsCentipedeLatchedOntoLocalPlayer() { if ((Object)(object)HelperTools.localPlayerController == (Object)null) { return false; } foreach (CentipedeAI item in latchedOnCentipedesLocalPlayer) { if ((Object)(object)HelperTools.localPlayerController == (Object)(object)item?.clingingToPlayer) { return true; } } return false; } } [HarmonyPatch] public class DressGirlVisibilityPatcher { [HarmonyPatch(typeof(EnemyAI), "EnableEnemyMesh")] [HarmonyPostfix] public static void HideGirlMesh(bool enable, EnemyAI __instance, bool overrideDoNotSet = false) { if (LethalVRM_Compat.Enabled && __instance is DressGirlAI) { SkinnedMeshRenderer[] skinnedMeshRenderers = __instance.skinnedMeshRenderers; foreach (SkinnedMeshRenderer val in skinnedMeshRenderers) { ((Renderer)val).enabled = ((Component)val).gameObject.layer != 23; } MeshRenderer[] meshRenderers = __instance.meshRenderers; foreach (MeshRenderer val2 in meshRenderers) { ((Renderer)val2).enabled = ((Component)val2).gameObject.layer != 23; } } } } [HarmonyPatch] public static class LocomotionEmotePatcher { [HarmonyPatch(typeof(PlayerControllerB), "CheckConditionsForEmote")] [HarmonyPostfix] public static void AllowMovingInEmoteConditions(ref bool __result, PlayerControllerB __instance) { if (!__result && EmoteController.allEmoteControllers.TryGetValue(((Component)__instance).gameObject, out var value) && value.IsPerformingCustomEmote() && ThirdPersonEmoteController.isMovingWhileEmoting && !Keybinds.toggledRotating && !Keybinds.holdingRotatePlayerModifier && !__instance.inSpecialInteractAnimation && !__instance.isPlayerDead && !__instance.isCrouching && !__instance.isClimbingLadder && !__instance.isGrabbingObjectAnimation && !__instance.inTerminalMenu && !__instance.isTypingChat) { __result = true; } } [HarmonyPatch(typeof(QuickMenuManager), "OpenQuickMenu")] [HarmonyPrefix] public static bool CancelMovingEmote() { if ((Object)(object)HelperTools.localPlayerController == (Object)null || (Object)(object)HelperTools.emoteControllerLocal == (Object)null) { return true; } if (HelperTools.emoteControllerLocal.IsPerformingCustomEmote() && ThirdPersonEmoteController.isMovingWhileEmoting) { HelperTools.emoteControllerLocal.StopPerformingEmote(); return false; } return true; } } [HarmonyPatch] public class MaskedEnemyPatcher { [CompilerGenerated] private sealed class <>c__DisplayClass15_0 { public float delay; public EmoteControllerMaskedEnemy emoteController; public UnlockableEmote emote; } public static AnimationClip defaultIdleClip; public static HashSet playersEmotedWithThisRound = new HashSet(); public static int currentLevelSeed => StartOfRound.Instance.randomMapSeed; [HarmonyPatch(typeof(PlayerControllerB), "ConnectClientToPlayerObject")] [HarmonyPostfix] public static void Init(StartOfRound __instance) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Expected O, but got Unknown if (!HelperTools.isServer) { NetworkManager.Singleton.CustomMessagingManager.RegisterNamedMessageHandler("TooManyEmotes.OnMaskedEnemyEmoteClientRpc", new HandleNamedMessageDelegate(OnMaskedEnemyEmoteClientRpc)); } } [HarmonyPatch(typeof(StartOfRound), "Awake")] [HarmonyPostfix] public static void ResetValues(StartOfRound __instance) { if (ConfigSync.instance.syncEnableMaskedEnemiesEmoting) { } } [HarmonyPatch(typeof(MaskedPlayerEnemy), "Start")] [HarmonyPostfix] public static void InitMaskedEnemy(MaskedPlayerEnemy __instance) { if (ConfigSync.instance.syncEnableMaskedEnemiesEmoting) { ((Component)__instance).gameObject.AddComponent(); } } [HarmonyPatch(typeof(RoundManager), "LoadNewLevel")] [HarmonyPrefix] public static void OnLoadNewLevel() { if (ConfigSync.instance.syncEnableMaskedEnemiesEmoting) { playersEmotedWithThisRound.Clear(); } } [HarmonyPatch(typeof(MaskedPlayerEnemy), "Update")] [HarmonyPostfix] public static void OnUpdate(MaskedPlayerEnemy __instance) { if (!ConfigSync.instance.syncEnableMaskedEnemiesEmoting || ((EnemyAI)__instance).isEnemyDead || !EmoteControllerMaskedEnemy.allMaskedEnemyEmoteControllers.TryGetValue(__instance, out var value)) { return; } if (HelperTools.isServer && !value.stoppedAndStaring && value.CanPerformEmote()) { value.stoppedAndStaring = true; if (!CalculateShouldEmoteChance(value)) { value.emoteCount++; return; } playersEmotedWithThisRound.Add(value.lookingAtPlayer); UnlockableEmote randomUnlockedEmote = GetRandomUnlockedEmote(value); float randomEmoteDelay = GetRandomEmoteDelay(value); float randomEmoteDuration = GetRandomEmoteDuration(value); CustomLogging.Log("Pre-performing emote on MaskedEnemy. Delay: " + randomEmoteDelay + " ExtendedStopAndStareDuration: " + randomEmoteDuration); value.stopAndStareTimer += randomEmoteDuration; PerformEmoteAfterDelay(randomUnlockedEmote, value, randomEmoteDelay); } else if (value.stopAndStareTimer <= 0f && value.stoppedAndStaring) { value.stoppedAndStaring = false; } } public static bool CalculateShouldEmoteChance(EmoteControllerMaskedEnemy emoteController) { bool flag = ConfigSync.instance.syncMaskedEnemiesAlwaysEmoteOnFirstEncounter && !playersEmotedWithThisRound.Contains(emoteController.lookingAtPlayer); if (!flag) { Random random = new Random(currentLevelSeed + 1550 + 100 * emoteController.id + emoteController.emoteCount); float num = (float)random.NextDouble(); flag = num <= ConfigSync.instance.syncMaskedEnemiesEmoteChanceOnEncounter; } CustomLogging.Log("Calculating if the masked enemy (" + ((Object)emoteController.maskedEnemy).name + ") should emote: " + flag); return flag; } public static float GetRandomEmoteDelay(EmoteControllerMaskedEnemy emoteController) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) Random random = new Random(currentLevelSeed - 550 + 100 * emoteController.id + emoteController.emoteCount); Vector2 syncMaskedEnemyEmoteRandomDelay = ConfigSync.syncMaskedEnemyEmoteRandomDelay; ((Vector2)(ref syncMaskedEnemyEmoteRandomDelay))..ctor(Mathf.Min(Mathf.Abs(syncMaskedEnemyEmoteRandomDelay.x), Mathf.Abs(syncMaskedEnemyEmoteRandomDelay.y)), Mathf.Max(Mathf.Abs(syncMaskedEnemyEmoteRandomDelay.x), Mathf.Abs(syncMaskedEnemyEmoteRandomDelay.y))); return (float)(random.NextDouble() * (double)(syncMaskedEnemyEmoteRandomDelay.y - syncMaskedEnemyEmoteRandomDelay.x) + (double)syncMaskedEnemyEmoteRandomDelay.x); } public static float GetRandomEmoteDuration(EmoteControllerMaskedEnemy emoteController) { //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) if (!ConfigSync.instance.syncOverrideStopAndStareDuration) { return 0f; } Random random = new Random(currentLevelSeed + 550 + 100 * emoteController.id + emoteController.emoteCount); Vector2 syncMaskedEnemyEmoteRandomDuration = ConfigSync.syncMaskedEnemyEmoteRandomDuration; ((Vector2)(ref syncMaskedEnemyEmoteRandomDuration))..ctor(Mathf.Min(Mathf.Abs(syncMaskedEnemyEmoteRandomDuration.x), Mathf.Abs(syncMaskedEnemyEmoteRandomDuration.y)), Mathf.Max(Mathf.Abs(syncMaskedEnemyEmoteRandomDuration.x), Mathf.Abs(syncMaskedEnemyEmoteRandomDuration.y))); return (float)random.NextDouble() * (syncMaskedEnemyEmoteRandomDuration.y - syncMaskedEnemyEmoteRandomDuration.x) + syncMaskedEnemyEmoteRandomDuration.x; } public static UnlockableEmote GetRandomUnlockedEmote(EmoteControllerMaskedEnemy emoteController) { PlayerControllerB val = emoteController.maskedEnemy.mimickingPlayer; if ((Object)(object)val == (Object)null) { val = emoteController.lookingAtPlayer; } if ((Object)(object)val == (Object)null) { return null; } List value = SessionManager.unlockedEmotes; if (!ConfigSync.instance.syncShareEverything && (Object)(object)val != (Object)(object)HelperTools.localPlayerController) { SessionManager.unlockedEmotesByPlayer.TryGetValue(val.playerUsername, out value); } if (value == null) { value = SessionManager.unlockedEmotes; } Random random = new Random(currentLevelSeed + 100 * emoteController.id + emoteController.emoteCount); UnlockableEmote unlockableEmote = value[random.Next(value.Count)]; if (unlockableEmote.randomEmote && unlockableEmote.emoteSyncGroup != null && unlockableEmote.emoteSyncGroup.Count > 0) { unlockableEmote = unlockableEmote.emoteSyncGroup[random.Next(unlockableEmote.emoteSyncGroup.Count)]; } return unlockableEmote; } private static void SendUpdateMaskedEnemyEmoteToClients(EmoteControllerMaskedEnemy emoteController, int emoteId) { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) if (HelperTools.isServer) { FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(10, (Allocator)2, -1); ulong networkObjectId = ((NetworkBehaviour)emoteController.maskedEnemy).NetworkObjectId; ((FastBufferWriter)(ref val)).WriteValueSafe(ref networkObjectId, default(ForPrimitives)); short num = (short)emoteId; ((FastBufferWriter)(ref val)).WriteValueSafe(ref num, default(ForPrimitives)); NetworkManager.Singleton.CustomMessagingManager.SendNamedMessageToAll("TooManyEmotes.OnMaskedEnemyEmoteClientRpc", val, (NetworkDelivery)3); } } private static void OnMaskedEnemyEmoteClientRpc(ulong clientId, FastBufferReader reader) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0032: 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) if (!HelperTools.isClient || HelperTools.isServer) { return; } ulong num = default(ulong); ((FastBufferReader)(ref reader)).ReadValue(ref num, default(ForPrimitives)); short index = default(short); ((FastBufferReader)(ref reader)).ReadValue(ref index, default(ForPrimitives)); CustomLogging.Log("Receiving update for masked enemy emote from server. Masked enemy id: " + num + " EmoteId: " + index); foreach (EmoteControllerMaskedEnemy value in EmoteControllerMaskedEnemy.allMaskedEnemyEmoteControllers.Values) { if (((NetworkBehaviour)value.maskedEnemy).NetworkObjectId == num) { value.PerformEmote(EmotesManager.allUnlockableEmotes[index]); return; } } CustomLogging.LogError("Failed to find masked enemy with id: " + num); } public static void PerformEmoteAfterDelay(UnlockableEmote emote, EmoteControllerMaskedEnemy emoteController, float delay) { <>c__DisplayClass15_0 CS$<>8__locals0 = new <>c__DisplayClass15_0(); CS$<>8__locals0.delay = delay; CS$<>8__locals0.emoteController = emoteController; CS$<>8__locals0.emote = emote; if (CS$<>8__locals0.emote != null) { ((MonoBehaviour)CS$<>8__locals0.emoteController.maskedEnemy).StartCoroutine(PerformEmote()); } [IteratorStateMachine(typeof(<>c__DisplayClass15_0.<g__PerformEmote|0>d))] IEnumerator PerformEmote() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <>c__DisplayClass15_0.<g__PerformEmote|0>d(0) { <>4__this = CS$<>8__locals0 }; } } } [HarmonyPatch] public static class SyncWithEmoteControllerManager { public static int syncableEmoteLayerMask = (1 << LayerMask.NameToLayer("Player")) | (1 << LayerMask.NameToLayer("Enemies")); public static EmoteController lookingAtSyncableEmoteController = null; [HarmonyPatch(typeof(PlayerControllerB), "LateUpdate")] [HarmonyPostfix] public static void CheckIfLookingAtSyncableEmoteController(PlayerControllerB __instance) { //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)__instance != (Object)(object)HelperTools.localPlayerController || (Object)(object)HelperTools.emoteControllerLocal == (Object)null || ConfigSettings.disableEmotesForSelf.Value || LCVR_Compat.LoadedAndEnabled) { return; } if (((TMP_Text)HelperTools.localPlayerController.cursorTip).text.Contains("Sync emote")) { ((TMP_Text)HelperTools.localPlayerController.cursorTip).text = ""; } RaycastHit val = default(RaycastHit); if (!HelperTools.emoteControllerLocal.IsPerformingCustomEmote() && !__instance.isPlayerDead && Physics.Raycast(((Component)HelperTools.localPlayerController.gameplayCamera).transform.position + ((Component)HelperTools.localPlayerController.gameplayCamera).transform.forward * 0.5f, ((Component)HelperTools.localPlayerController.gameplayCamera).transform.forward * 4.5f, ref val, 4.5f, syncableEmoteLayerMask)) { try { EmoteController emoteController = ((Component)((RaycastHit)(ref val)).collider).GetComponentInChildren() ?? ((Component)((RaycastHit)(ref val)).collider).GetComponentInParent(); if (CanSyncWithEmoteController(HelperTools.emoteControllerLocal, emoteController) && (!(emoteController is EmoteControllerMaskedEnemy) || ConfigSettings.enableSyncingEmotesWithMaskedEnemies.Value)) { lookingAtSyncableEmoteController = emoteController; ((TMP_Text)HelperTools.localPlayerController.cursorTip).text = "[E] Sync emote"; return; } } catch { } } ResetState(); } [HarmonyPatch(typeof(PlayerControllerB), "Interact_performed")] [HarmonyPrefix] public static bool SyncWithEmoteController_performed(CallbackContext context, PlayerControllerB __instance) { if ((Object)(object)__instance != (Object)(object)HelperTools.localPlayerController || !((CallbackContext)(ref context)).performed) { return true; } if ((Object)(object)HelperTools.emoteControllerLocal != (Object)null && (Object)(object)lookingAtSyncableEmoteController != (Object)null && !ConfigSettings.disableEmotesForSelf.Value && !LCVR_Compat.LoadedAndEnabled && !__instance.isPlayerDead && CanSyncWithEmoteController(HelperTools.emoteControllerLocal, lookingAtSyncableEmoteController)) { CustomLogging.Log("[SyncWithEmoteController_performed] Attempting to sync with emote controller: " + (object)lookingAtSyncableEmoteController); HelperTools.emoteControllerLocal.TrySyncingEmoteWithEmoteController(lookingAtSyncableEmoteController); ResetState(); return false; } ResetState(); return true; } public static bool CanSyncWithEmoteController(EmoteController sourceEmoteController, EmoteController syncWithEmoteController) { if ((Object)(object)sourceEmoteController == (Object)(object)HelperTools.emoteControllerLocal && (ConfigSettings.disableEmotesForSelf.Value || LCVR_Compat.LoadedAndEnabled)) { return false; } if ((Object)(object)sourceEmoteController == (Object)null || (Object)(object)syncWithEmoteController == (Object)null || (Object)(object)sourceEmoteController == (Object)(object)syncWithEmoteController) { return false; } return !sourceEmoteController.IsPerformingCustomEmote() && syncWithEmoteController.IsPerformingCustomEmote() && syncWithEmoteController.performingEmote.canSyncEmote; } public static void ResetState() { lookingAtSyncableEmoteController = null; } } [HarmonyPatch] public static class ThirdPersonEmoteController { internal static GameObject playerHUDHelmetModel; internal static GameObject scannedObjectsUI; internal static Camera gameplayCamera; internal static Camera emoteCamera; internal static Transform emoteCameraPivot; internal static int cameraCollideLayerMask = (1 << LayerMask.NameToLayer("Room")) | (1 << LayerMask.NameToLayer("PlaceableShipObject")) | (1 << LayerMask.NameToLayer("Terrain")) | (1 << LayerMask.NameToLayer("MiscLevelGeometry")); internal static Vector2 clampCameraDistance = new Vector2(1.5f, 5f); internal static float targetCameraDistance = 3f; internal static ShadowCastingMode defaultShadowCastingMode = (ShadowCastingMode)1; internal static RectTransform defaultControlTipLinesParent; internal static RectTransform customControlTipLinesParent; internal static TextMeshProUGUI[] customControlTipLines; private static Vector3 defaultControlTipLinesScale = Vector3.one; internal static Vector3 firstPersonCameraLocalPosition; internal static Quaternion firstPersonCameraLocalRotation; private static bool isPerformingEmote = false; internal static Transform localPlayerCameraContainer => HelperTools.localPlayerController?.cameraContainerTransform; public static bool firstPersonEmotesEnabled { get; internal set; } = false; public static bool allowMovingWhileEmoting { get; internal set; } = false; internal static bool isMovingWhileEmoting => !ConfigSync.instance.syncForceDisableMovingWhileEmoting && HelperTools.emoteControllerLocal.IsPerformingCustomEmote() && (allowMovingWhileEmoting || HelperTools.emoteControllerLocal.performingEmote.canMoveWhileEmoting); [HarmonyPatch(typeof(PlayerControllerB), "ConnectClientToPlayerObject")] [HarmonyPostfix] public static void InitLocalPlayerController(PlayerControllerB __instance) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Unknown result type (might be due to invalid IL or missing references) gameplayCamera = __instance.gameplayCamera; if (!Object.op_Implicit((Object)(object)emoteCamera)) { emoteCameraPivot = new GameObject("EmoteCameraPivot").transform; emoteCamera = new GameObject("EmoteCamera").AddComponent(); emoteCamera.CopyFrom(gameplayCamera); } scannedObjectsUI = GameObject.Find("Systems/UI/Canvas/ObjectScanner"); if (!Object.op_Implicit((Object)(object)scannedObjectsUI)) { Animator scanInfoAnimator = HUDManager.Instance.scanInfoAnimator; scannedObjectsUI = ((scanInfoAnimator != null) ? ((Component)((Component)scanInfoAnimator).transform.parent.parent).gameObject : null); } defaultControlTipLinesParent = ((Component)((TMP_Text)HUDManager.Instance.controlTipLines[0]).transform.parent).GetComponent(); defaultControlTipLinesScale = ((Transform)defaultControlTipLinesParent).localScale; customControlTipLinesParent = Object.Instantiate(defaultControlTipLinesParent, ((Transform)defaultControlTipLinesParent).parent); ((Object)customControlTipLinesParent).name = "ThirdPersonEmotesControlTips"; ((Transform)customControlTipLinesParent).SetSiblingIndex(((Transform)defaultControlTipLinesParent).GetSiblingIndex() + 1); ((Transform)customControlTipLinesParent).SetPositionAndRotation(((Transform)defaultControlTipLinesParent).position, ((Transform)defaultControlTipLinesParent).rotation); ((Transform)customControlTipLinesParent).localScale = Vector3.zero; customControlTipLines = (TextMeshProUGUI[])(object)new TextMeshProUGUI[HUDManager.Instance.controlTipLines.Length]; int num = 0; TextMeshProUGUI[] componentsInChildren = ((Component)customControlTipLinesParent).GetComponentsInChildren(); foreach (TextMeshProUGUI val in componentsInChildren) { if ((Object)(object)val != (Object)null) { if (((Object)val).name.ToLower().Contains("controltip")) { customControlTipLines[num++] = val; } else { Object.Destroy((Object)(object)((Component)val).gameObject); } } } LoadPreferences(); ResetCamera(); } [HarmonyPatch(typeof(PlayerControllerB), "SpawnPlayerAnimation")] [HarmonyPostfix] public static void OnPlayerSpawn(PlayerControllerB __instance) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) firstPersonCameraLocalPosition = ((Component)localPlayerCameraContainer).transform.localPosition; firstPersonCameraLocalRotation = ((Component)localPlayerCameraContainer).transform.localRotation; ResetCamera(); } internal static void SavePreferences() { try { CustomLogging.Log("Saving ThirdPersonEmoteController preferences."); ES3.Save("TooManyEmotes.EnableFirstPersonEmotes", firstPersonEmotesEnabled, SaveManager.TooManyEmotesSaveFileName); ES3.Save("TooManyEmotes.AllowMovingWhileEmoting", allowMovingWhileEmoting, SaveManager.TooManyEmotesSaveFileName); } catch (Exception ex) { CustomLogging.LogErrorVerbose("Error while trying to save TooManyEmotes ThirdPersonEmoteController preferences.\n" + ex); } } internal static void LoadPreferences() { CustomLogging.Log("Loading ThirdPersonEmoteController preferences."); try { if (ES3.KeyExists("TooManyEmotes.EnableFirstPersonEmotes")) { ES3.DeleteKey("TooManyEmotes.EnableFirstPersonEmotes"); } if (ES3.KeyExists("TooManyEmotes.AllowMovingWhileEmoting")) { ES3.DeleteKey("TooManyEmotes.AllowMovingWhileEmoting"); } } catch { try { ES3.DeleteKey("TooManyEmotes.EnableFirstPersonEmotes"); ES3.DeleteKey("TooManyEmotes.AllowMovingWhileEmoting"); } catch { } } try { firstPersonEmotesEnabled = ES3.Load("TooManyEmotes.EnableFirstPersonEmotes", SaveManager.TooManyEmotesSaveFileName, false); allowMovingWhileEmoting = ES3.Load("TooManyEmotes.AllowMovingWhileEmoting", SaveManager.TooManyEmotesSaveFileName, false); } catch (Exception ex) { CustomLogging.LogErrorVerbose("Failed to load third person emote preferences. Preferences will be reset.\n" + ex); firstPersonEmotesEnabled = false; allowMovingWhileEmoting = false; try { ES3.DeleteKey("TooManyEmotes.EnableFirstPersonEmotes", SaveManager.TooManyEmotesSaveFileName); ES3.DeleteKey("TooManyEmotes.AllowMovingWhileEmoting", SaveManager.TooManyEmotesSaveFileName); } catch { CustomLogging.LogErrorVerbose("Failed to reset third person emote preferences. I recommend deleting this file: \"" + SaveManager.TooManyEmotesSaveFileName + "\" located at this path: \"C:\\Users\\YOUR_USER\\AppData\\LocalLow\\ZeekerssRBLX\\Lethal Company\""); } } } public static void ResetCamera() { //IL_0126: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_015f: Unknown result type (might be due to invalid IL or missing references) //IL_0169: Unknown result type (might be due to invalid IL or missing references) //IL_016e: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)StartOfRound.Instance == (Object)null || (Object)(object)HelperTools.localPlayerController == (Object)null || !Object.op_Implicit((Object)(object)gameplayCamera) || !Object.op_Implicit((Object)(object)emoteCamera) || !Object.op_Implicit((Object)(object)emoteCameraPivot)) { return; } ((Behaviour)emoteCamera).enabled = false; Camera val = ((firstPersonEmotesEnabled || ConfigSettings.disableEmotesForSelf.Value || LCVR_Compat.LoadedAndEnabled) ? gameplayCamera : StartOfRound.Instance.activeCamera); if ((Object)(object)val == (Object)null) { val = gameplayCamera; } StartOfRound.Instance.SwitchCamera(val); CallChangeAudioListenerToObject(((Component)val).gameObject); ReloadPlayerModel(HelperTools.localPlayerController); Camera obj = gameplayCamera; obj.cullingMask &= -8388609; emoteCamera.cullingMask = gameplayCamera.cullingMask; Camera obj2 = emoteCamera; obj2.cullingMask &= -161; ((Component)emoteCameraPivot).transform.SetParent(((Component)HelperTools.localPlayerController).transform); emoteCameraPivot.SetLocalPositionAndRotation(Vector3.up * 1.8f, Quaternion.identity); ((Component)emoteCamera).transform.SetParent(emoteCameraPivot); ((Component)emoteCamera).transform.SetLocalPositionAndRotation(Vector3.back * targetCameraDistance, Quaternion.identity); PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts; foreach (PlayerControllerB val2 in allPlayerScripts) { if ((Object)(object)val2 != (Object)null && (Object)(object)val2 != (Object)(object)HelperTools.localPlayerController && (Object)(object)val2.gameplayCamera != (Object)null) { Camera obj3 = val2.gameplayCamera; obj3.cullingMask |= 0x800000; } } GameObject obj4 = GameObject.Find("Environment/HangarShip/Cameras/ShipCamera"); Camera val3 = ((obj4 != null) ? obj4.GetComponent() : null); if (Object.op_Implicit((Object)(object)val3)) { val3.cullingMask |= 0x800000; } } public static void ReloadPlayerModel(PlayerControllerB playerController) { if (ConfigSettings.disableEmotesForSelf.Value || LCVR_Compat.LoadedAndEnabled) { return; } try { ((Component)playerController).GetComponentInChildren().enabled = false; ((Component)playerController.thisPlayerModelLOD1).gameObject.layer = 5; ((Renderer)playerController.thisPlayerModelLOD1).shadowCastingMode = (ShadowCastingMode)3; ((Renderer)playerController.thisPlayerModelLOD2).shadowCastingMode = (ShadowCastingMode)0; ((Renderer)playerController.thisPlayerModelLOD2).enabled = false; ((Component)playerController.playerBetaBadgeMesh).gameObject.layer = 5; ((Component)playerController.thisPlayerModel).gameObject.layer = 23; ((Renderer)playerController.thisPlayerModel).shadowCastingMode = (ShadowCastingMode)1; } catch (Exception ex) { CustomLogging.LogError("Error while trying to reset player model for player: " + ((Object)playerController).name + " Error: " + ex); } } [HarmonyPatch(typeof(PlayerControllerB), "PlayerLookInput")] [HarmonyPrefix] private static bool UseFreeCamWhileEmoting(PlayerControllerB __instance) { //IL_0189: Unknown result type (might be due to invalid IL or missing references) //IL_01ac: Unknown result type (might be due to invalid IL or missing references) //IL_01b1: Unknown result type (might be due to invalid IL or missing references) //IL_01c7: Unknown result type (might be due to invalid IL or missing references) //IL_01cc: Unknown result type (might be due to invalid IL or missing references) //IL_01d9: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_023f: Unknown result type (might be due to invalid IL or missing references) //IL_03e1: Unknown result type (might be due to invalid IL or missing references) //IL_0307: Unknown result type (might be due to invalid IL or missing references) //IL_030c: Unknown result type (might be due to invalid IL or missing references) //IL_0315: Unknown result type (might be due to invalid IL or missing references) //IL_031f: Unknown result type (might be due to invalid IL or missing references) //IL_0334: Unknown result type (might be due to invalid IL or missing references) //IL_0339: Unknown result type (might be due to invalid IL or missing references) //IL_0345: Unknown result type (might be due to invalid IL or missing references) //IL_0351: Unknown result type (might be due to invalid IL or missing references) //IL_0361: Unknown result type (might be due to invalid IL or missing references) //IL_036b: Unknown result type (might be due to invalid IL or missing references) //IL_0271: Unknown result type (might be due to invalid IL or missing references) //IL_0285: Unknown result type (might be due to invalid IL or missing references) //IL_0299: Unknown result type (might be due to invalid IL or missing references) //IL_02a3: Unknown result type (might be due to invalid IL or missing references) //IL_02bd: Unknown result type (might be due to invalid IL or missing references) //IL_02d1: Unknown result type (might be due to invalid IL or missing references) //IL_02db: Unknown result type (might be due to invalid IL or missing references) //IL_03f1: Unknown result type (might be due to invalid IL or missing references) //IL_03fb: Unknown result type (might be due to invalid IL or missing references) //IL_0400: Unknown result type (might be due to invalid IL or missing references) //IL_040a: Unknown result type (might be due to invalid IL or missing references) //IL_0430: Unknown result type (might be due to invalid IL or missing references) //IL_0451: Unknown result type (might be due to invalid IL or missing references) //IL_03b0: Unknown result type (might be due to invalid IL or missing references) //IL_03bf: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)__instance != (Object)(object)HelperTools.localPlayerController || (Object)(object)HelperTools.emoteControllerLocal == (Object)null) { return true; } if (ConfigSettings.disableEmotesForSelf.Value || LCVR_Compat.LoadedAndEnabled) { return true; } if (HelperTools.emoteControllerLocal.IsPerformingCustomEmote()) { if (firstPersonEmotesEnabled) { if ((Object)(object)StartOfRound.Instance.activeCamera != (Object)(object)gameplayCamera) { StartOfRound.Instance.SwitchCamera(gameplayCamera); CallChangeAudioListenerToObject(((Component)gameplayCamera).gameObject); ((Behaviour)emoteCamera).enabled = false; if ((Object)(object)HelperTools.localPlayerController.currentlyHeldObjectServer != (Object)null) { HelperTools.localPlayerController.currentlyHeldObjectServer.parentObject = HelperTools.localPlayerController.localItemHolder; } } localPlayerCameraContainer.SetPositionAndRotation(HelperTools.localPlayerController.playerGlobalHead.position, ((Component)HelperTools.localPlayerController).transform.rotation); return isMovingWhileEmoting; } if ((Object)(object)StartOfRound.Instance.activeCamera != (Object)(object)emoteCamera) { ((Behaviour)emoteCamera).enabled = true; StartOfRound.Instance.SwitchCamera(emoteCamera); CallChangeAudioListenerToObject(((Component)emoteCamera).gameObject); if ((Object)(object)HelperTools.localPlayerController.currentlyHeldObjectServer != (Object)null) { HelperTools.localPlayerController.currentlyHeldObjectServer.parentObject = HelperTools.localPlayerController.serverItemHolder; } } Vector3 val = Vector3.back * Mathf.Clamp(targetCameraDistance, clampCameraDistance.x, clampCameraDistance.y); ((Component)emoteCamera).transform.localPosition = Vector3.Lerp(((Component)emoteCamera).transform.localPosition, val, 10f * Time.deltaTime); if (!HelperTools.localPlayerController.quickMenuManager.isMenuOpen && !EmoteMenu.isMenuOpen) { bool flag = (ConfigSettings.toggleRotateCharacterInEmote.Value ? Keybinds.toggledRotating : Keybinds.holdingRotatePlayerModifier); if (flag != isMovingWhileEmoting && emoteCameraPivot.localEulerAngles.y != 0f) { ((Component)HelperTools.localPlayerController).transform.localEulerAngles = new Vector3(((Component)HelperTools.localPlayerController).transform.localEulerAngles.x, ((Component)emoteCameraPivot).transform.eulerAngles.y, ((Component)HelperTools.localPlayerController).transform.localEulerAngles.z); ((Component)emoteCameraPivot).transform.localEulerAngles = new Vector3(emoteCameraPivot.localEulerAngles.x, 0f, emoteCameraPivot.localEulerAngles.z); } if (!isMovingWhileEmoting || flag) { MovementActions movement = HelperTools.localPlayerController.playerActions.Movement; Vector2 val2 = ((MovementActions)(ref movement)).Look.ReadValue() * 0.008f * (float)IngamePlayerSettings.Instance.settings.lookSensitivity; emoteCameraPivot.Rotate(new Vector3(0f, val2.x, 0f)); float num = emoteCameraPivot.localEulerAngles.x - val2.y; num = ((num > 180f) ? (num - 360f) : num); num = Mathf.Clamp(num, -45f, 45f); ((Component)emoteCameraPivot).transform.localEulerAngles = new Vector3(num, emoteCameraPivot.localEulerAngles.y, 0f); } else { ((Component)emoteCameraPivot).transform.localEulerAngles = ((Component)gameplayCamera).transform.localEulerAngles; } RaycastHit val3 = default(RaycastHit); if (Physics.Raycast(emoteCameraPivot.position, -emoteCameraPivot.forward * targetCameraDistance, ref val3, targetCameraDistance, cameraCollideLayerMask)) { ((Component)emoteCamera).transform.localPosition = Vector3.back * Mathf.Clamp(((RaycastHit)(ref val3)).distance - 0.2f, 0f, targetCameraDistance); } if (!isMovingWhileEmoting || flag) { return false; } } } return true; } internal static void OnZoomInEmote(CallbackContext context) { if (!((Object)(object)HelperTools.localPlayerController == (Object)null) && HelperTools.emoteControllerLocal.IsPerformingCustomEmote() && !EmoteMenu.isMenuOpen && !HelperTools.quickMenuManager.isMenuOpen && !firstPersonEmotesEnabled && !ConfigSettings.disableEmotesForSelf.Value && !LCVR_Compat.LoadedAndEnabled) { bool flag = (ConfigSettings.toggleRotateCharacterInEmote.Value ? Keybinds.toggledRotating : Keybinds.holdingRotatePlayerModifier); if (!isMovingWhileEmoting || flag) { targetCameraDistance = Mathf.Clamp(targetCameraDistance - 0.25f, ((Vector2)(ref clampCameraDistance))[0], ((Vector2)(ref clampCameraDistance))[1]); } } } internal static void OnZoomOutEmote(CallbackContext context) { if (!((Object)(object)HelperTools.localPlayerController == (Object)null) && HelperTools.emoteControllerLocal.IsPerformingCustomEmote() && !EmoteMenu.isMenuOpen && !HelperTools.quickMenuManager.isMenuOpen && !firstPersonEmotesEnabled && !ConfigSettings.disableEmotesForSelf.Value && !LCVR_Compat.LoadedAndEnabled) { bool flag = (ConfigSettings.toggleRotateCharacterInEmote.Value ? Keybinds.toggledRotating : Keybinds.holdingRotatePlayerModifier); if (!isMovingWhileEmoting || flag) { targetCameraDistance = Mathf.Clamp(targetCameraDistance + 0.25f, ((Vector2)(ref clampCameraDistance))[0], ((Vector2)(ref clampCameraDistance))[1]); } } } public static void OnStartCustomEmoteLocal() { //IL_0073: Unknown result type (might be due to invalid IL or missing references) Keybinds.toggledRotating = false; if (!firstPersonEmotesEnabled) { if (Object.op_Implicit((Object)(object)emoteCamera) && !((Behaviour)emoteCamera).enabled) { StartOfRound.Instance.SwitchCamera(emoteCamera); CallChangeAudioListenerToObject(((Component)emoteCamera).gameObject); if (!isPerformingEmote) { emoteCameraPivot.eulerAngles = ((Component)gameplayCamera).transform.eulerAngles; } } ((Component)HelperTools.localPlayerController.thisPlayerModelLOD1).gameObject.layer = 5; ((Renderer)HelperTools.localPlayerController.thisPlayerModelLOD1).shadowCastingMode = (ShadowCastingMode)3; ((Renderer)HelperTools.localPlayerController.thisPlayerModelLOD2).shadowCastingMode = (ShadowCastingMode)0; ((Renderer)HelperTools.localPlayerController.thisPlayerModelLOD2).enabled = false; ((Component)HelperTools.localPlayerController.playerBetaBadgeMesh).gameObject.layer = 5; ((Component)HelperTools.localPlayerController.thisPlayerModel).gameObject.layer = 3; ((Renderer)HelperTools.localPlayerController.thisPlayerModel).shadowCastingMode = (ShadowCastingMode)1; ((Renderer)HelperTools.localPlayerController.thisPlayerModelArms).enabled = false; if (Object.op_Implicit((Object)(object)scannedObjectsUI)) { scannedObjectsUI.SetActive(false); } if ((Object)(object)HelperTools.localPlayerController.localItemHolder == (Object)(object)HelperTools.localPlayerController.currentlyHeldObjectServer?.parentObject) { HelperTools.localPlayerController.currentlyHeldObjectServer.parentObject = HelperTools.localPlayerController.serverItemHolder; } if (AdvancedCompany_Compat.Enabled) { AdvancedCompany_Compat.ShowLocalCosmetics(); } else if (MoreCompany_Compat.Enabled) { MoreCompany_Compat.ShowLocalCosmetics(); } if (LethalVRM_Compat.Enabled) { LethalVRM_Compat.DisplayVRMModel(); } } UpdateControlTip(); ShowCustomControlTips(!firstPersonEmotesEnabled); isPerformingEmote = true; } public static void OnStopCustomEmoteLocal() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_018a: Unknown result type (might be due to invalid IL or missing references) localPlayerCameraContainer.SetLocalPositionAndRotation(firstPersonCameraLocalPosition, firstPersonCameraLocalRotation); Keybinds.toggledRotating = false; if (Object.op_Implicit((Object)(object)emoteCamera)) { ((Behaviour)emoteCamera).enabled = false; } if ((Object)(object)StartOfRound.Instance.activeCamera != (Object)(object)gameplayCamera) { StartOfRound.Instance.SwitchCamera(gameplayCamera); } if ((Object)(object)HelperTools.localPlayerController.activeAudioListener != (Object)(object)((Component)gameplayCamera).gameObject) { CallChangeAudioListenerToObject(((Component)gameplayCamera).gameObject); } ((Component)HelperTools.localPlayerController.thisPlayerModel).gameObject.layer = 23; ((Renderer)HelperTools.localPlayerController.thisPlayerModel).shadowCastingMode = defaultShadowCastingMode; ((Renderer)HelperTools.localPlayerController.thisPlayerModelArms).enabled = true; if (Object.op_Implicit((Object)(object)scannedObjectsUI)) { scannedObjectsUI.SetActive(true); } if (AdvancedCompany_Compat.Enabled) { AdvancedCompany_Compat.HideLocalCosmetics(); } else if (MoreCompany_Compat.Enabled) { MoreCompany_Compat.HideLocalCosmetics(); } if (LethalVRM_Compat.Enabled) { LethalVRM_Compat.HideVRMModel(); } ShowCustomControlTips(show: false); GrabbableObject[] itemSlots = HelperTools.localPlayerController.ItemSlots; foreach (GrabbableObject val in itemSlots) { if (Object.op_Implicit((Object)(object)val) && (Object)(object)val.parentObject == (Object)(object)HelperTools.localPlayerController.serverItemHolder) { val.parentObject = HelperTools.localPlayerController.localItemHolder; } } emoteCameraPivot.eulerAngles = localPlayerCameraContainer.eulerAngles; isPerformingEmote = false; } internal static void UpdateFirstPersonEmoteMode(bool value) { if (firstPersonEmotesEnabled == value) { return; } firstPersonEmotesEnabled = value; if (!HelperTools.emoteControllerLocal.IsPerformingCustomEmote()) { return; } ((Renderer)HelperTools.localPlayerController.thisPlayerModelArms).enabled = firstPersonEmotesEnabled; ((Component)HelperTools.localPlayerController.thisPlayerModel).gameObject.layer = (firstPersonEmotesEnabled ? 23 : 3); if (firstPersonEmotesEnabled) { Keybinds.holdingRotatePlayerModifier = false; Keybinds.toggledRotating = false; if (AdvancedCompany_Compat.Enabled) { AdvancedCompany_Compat.HideLocalCosmetics(); } else if (MoreCompany_Compat.Enabled) { MoreCompany_Compat.HideLocalCosmetics(); } if (LethalVRM_Compat.Enabled) { LethalVRM_Compat.HideVRMModel(); } if (Object.op_Implicit((Object)(object)scannedObjectsUI)) { scannedObjectsUI.SetActive(false); } } else { if (AdvancedCompany_Compat.Enabled) { AdvancedCompany_Compat.ShowLocalCosmetics(); } else if (MoreCompany_Compat.Enabled) { MoreCompany_Compat.ShowLocalCosmetics(); } if (LethalVRM_Compat.Enabled) { LethalVRM_Compat.DisplayVRMModel(); } if (Object.op_Implicit((Object)(object)scannedObjectsUI)) { scannedObjectsUI.SetActive(true); } } UpdateControlTip(); ShowCustomControlTips(!firstPersonEmotesEnabled); } internal static void SetCanMoveWhileEmoting(bool value) { //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) if (allowMovingWhileEmoting == value) { return; } allowMovingWhileEmoting = value; if (HelperTools.emoteControllerLocal.IsPerformingCustomEmote()) { if (allowMovingWhileEmoting) { emoteCameraPivot.localEulerAngles = new Vector3(emoteCameraPivot.localEulerAngles.x, 0f, emoteCameraPivot.localEulerAngles.z); } UpdateControlTip(); } } [HarmonyPatch(typeof(PlayerControllerB), "ScrollMouse_performed")] [HarmonyPrefix] private static bool PreventSwappingItemsWhileEmoting(CallbackContext context, PlayerControllerB __instance) { if (!Object.op_Implicit((Object)(object)emoteCamera) || !((Behaviour)emoteCamera).enabled) { return true; } if (ConfigSettings.disableEmotesForSelf.Value || LCVR_Compat.LoadedAndEnabled) { return true; } bool flag = (ConfigSettings.toggleRotateCharacterInEmote.Value ? Keybinds.toggledRotating : Keybinds.holdingRotatePlayerModifier); if ((Object)(object)__instance == (Object)(object)HelperTools.localPlayerController && ((CallbackContext)(ref context)).performed && (Object)(object)HelperTools.emoteControllerLocal != (Object)null && HelperTools.emoteControllerLocal.IsPerformingCustomEmote() && (!isMovingWhileEmoting || flag)) { return false; } return true; } [HarmonyPatch(typeof(PlayerControllerB), "SwitchToItemSlot")] [HarmonyPostfix] private static void FixedNewHeldItemParent(int slot, PlayerControllerB __instance) { if ((Object)(object)__instance != (Object)(object)HelperTools.localPlayerController || !HelperTools.emoteControllerLocal.IsPerformingCustomEmote()) { return; } GrabbableObject heldGrabbable = HelperTools.localPlayerController.GetHeldGrabbable(); if (Object.op_Implicit((Object)(object)heldGrabbable)) { heldGrabbable.parentObject = (firstPersonEmotesEnabled ? HelperTools.localPlayerController.localItemHolder : HelperTools.localPlayerController.serverItemHolder); if (EmoteControllerPlayer.emoteControllerLocal.emotingProps.Count > 0) { heldGrabbable.EnableItemMeshes(false); } } } internal static void ShowCustomControlTips(bool show) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)customControlTipLinesParent == (Object)null) && !((Object)(object)defaultControlTipLinesParent == (Object)null)) { ((Transform)customControlTipLinesParent).localScale = (show ? defaultControlTipLinesScale : Vector3.zero); ((Transform)defaultControlTipLinesParent).localScale = (show ? Vector3.zero : defaultControlTipLinesScale); } } public static void UpdateControlTip(int appendToIndex = 0) { if (HelperTools.emoteControllerLocal.IsPerformingCustomEmote() && HelperTools.controlTipLines != null && customControlTipLines != null && customControlTipLines.Length >= 4) { if (appendToIndex < 0 || appendToIndex >= HelperTools.controlTipLines.Length - 1) { appendToIndex = 0; } string text = KeybindDisplayNames.GetKeybindDisplayName(Keybinds.ZoomInEmoteAction); string text2 = KeybindDisplayNames.GetKeybindDisplayName(Keybinds.ZoomOutEmoteAction); string text3 = KeybindDisplayNames.GetKeybindDisplayName(Keybinds.RotatePlayerEmoteAction); string keybindDisplayName = KeybindDisplayNames.GetKeybindDisplayName(Keybinds.PerformNextInstrumentAction); if (text == "") { text = "Unbound"; } if (text2 == "") { text2 = "Unbound"; } if (text3 == "") { text3 = "Unbound"; } int i = appendToIndex; string text4 = (((text == "Scroll Up" || text == "Scroll Down") && (text2 == "Scroll Up" || text2 == "Scroll Down") && text != text2) ? "[Scroll Mouse]" : ((!(text != "Unbound") && !(text2 != "Unbound")) ? "Unbound" : (text + "/" + text2))); ((TMP_Text)customControlTipLines[i]).text = "Zoom : "; if (isMovingWhileEmoting) { TextMeshProUGUI obj = customControlTipLines[i]; ((TMP_Text)obj).text = ((TMP_Text)obj).text + "[" + text3 + "] + "; } TextMeshProUGUI obj2 = customControlTipLines[i++]; ((TMP_Text)obj2).text = ((TMP_Text)obj2).text + text4; ((TMP_Text)customControlTipLines[i++]).text = string.Format((isMovingWhileEmoting ? "Freeze" : "Rotate") + " : " + (ConfigSettings.toggleRotateCharacterInEmote.Value ? "Toggle" : "Hold") + " [{0}]", text3); if (HelperTools.emoteControllerLocal.isPerformingEmote && HelperTools.emoteControllerLocal.performingEmote.inEmoteSyncGroup && HelperTools.emoteControllerLocal.performingEmote.emoteSyncGroup.Count > 1) { ((TMP_Text)customControlTipLines[i++]).text = $"Play Next Instrument: [{keybindDisplayName}]"; } for (; i < customControlTipLines.Length; i++) { ((TMP_Text)customControlTipLines[i]).text = ""; } } } public static void CallChangeAudioListenerToObject(GameObject gameObject) { if (!firstPersonEmotesEnabled || !((Object)(object)gameObject != (Object)(object)HelperTools.localPlayerController.gameplayCamera)) { MethodInfo method = ((object)HelperTools.localPlayerController).GetType().GetMethod("ChangeAudioListenerToObject", BindingFlags.Instance | BindingFlags.Public); method.Invoke(HelperTools.localPlayerController, new object[1] { gameObject }); } } } [HarmonyPatch] public static class TerminalPatcher { public static Terminal terminalInstance; public static List emoteSelection; public static List mysteryEmoteSelection; public static int currentEmoteCredits; public static Dictionary currentEmoteCreditsByPlayer; private static string confirmEmoteOpeningText = "You have requested to order a new emote."; private static string[] ignoreTerminalKeywords = new string[12] { "company", "moons", "help", "switch", "transmit", "store", "beastiary", "storage", "other", "scan", "ping", "view monitor" }; public static UnlockableEmote purchasingEmote; public static bool initializedTerminalNodes = false; public static int emoteStoreSeed = 0; [HarmonyPatch(typeof(Terminal), "Awake")] [HarmonyPostfix] private static void InitializeTerminal(Terminal __instance) { terminalInstance = __instance; initializedTerminalNodes = false; emoteSelection = new List(); mysteryEmoteSelection = new List(); currentEmoteCreditsByPlayer = new Dictionary(); EditExistingTerminalNodes(); } [HarmonyPatch(typeof(Terminal), "BeginUsingTerminal")] [HarmonyPostfix] private static void OnBeginUsingTerminal(Terminal __instance) { if (!initializedTerminalNodes && ConfigSync.isSynced) { EditExistingTerminalNodes(); } purchasingEmote = null; } private static void EditExistingTerminalNodes() { initializedTerminalNodes = true; if (ConfigSync.instance.syncUnlockEverything) { return; } foreach (TerminalNode specialNode in terminalInstance.terminalNodes.specialNodes) { if (((Object)specialNode).name == "Start" && !specialNode.displayText.Contains("[TooManyEmotes]")) { string text = "Type \"Help\" for a list of commands."; int num = specialNode.displayText.IndexOf(text); if (num != -1) { num += text.Length; string value = "\n\n[TooManyEmotes]\nType \"Emotes\" for a list of commands."; specialNode.displayText = specialNode.displayText.Insert(num, value); } else { Debug.LogError((object)"Failed to add emotes tip to terminal. Maybe an update broke it?"); } } else if (((Object)specialNode).name == "HelpCommands" && !specialNode.displayText.Contains(">EMOTES")) { string value2 = "[numberOfItemsOnRoute]"; int num2 = specialNode.displayText.IndexOf(value2); if (num2 != -1) { string value3 = ">EMOTES\nFor a list of Emote commands.\n\n"; specialNode.displayText = specialNode.displayText.Insert(num2, value3); } } } } [HarmonyPatch(typeof(Terminal), "TextPostProcess")] [HarmonyPrefix] private static void TextPostProcess(ref string modifiedDisplayText, TerminalNode node) { if (modifiedDisplayText.Length <= 0) { return; } string text = "[[[emoteUnlockablesSelectionList]]]"; if (!modifiedDisplayText.Contains(text)) { return; } int num = modifiedDisplayText.IndexOf(text); int num2 = num + text.Length; string oldValue = modifiedDisplayText.Substring(num, num2 - num); string text2 = ""; if (ConfigSync.instance.syncUnlockEverything) { text2 += "Every emote is already unlocked!\n\n"; } else { text2 = text2 + "Remaining emote credit balance: $" + currentEmoteCredits + ".\n"; if (ConfigSync.instance.syncPurchaseEmotesWithDefaultCurrency) { text2 = text2 + "Remaining group credit balance: $" + terminalInstance.groupCredits + ".\n"; } text2 += "\n"; int num3 = 0; foreach (UnlockableEmote item in emoteSelection) { num3 = Mathf.Max(num3, item.displayName.Length); } foreach (UnlockableEmote item2 in emoteSelection) { string arg = (SessionManager.IsEmoteUnlocked(item2) ? "[Purchased]" : ("$" + item2.price)); text2 += $"* {item2.displayNameColorCoded}{new string(' ', num3 - item2.displayName.Length)} // {arg}\n"; } } modifiedDisplayText = modifiedDisplayText.Replace(oldValue, text2); } [HarmonyPatch(typeof(Terminal), "ParsePlayerSentence")] [HarmonyPrefix] private static bool ParsePlayerSentence(ref TerminalNode __result, Terminal __instance) { if (__instance.screenText.text.Length <= 0) { return true; } if ((ConfigSettings.disableEmotesForSelf.Value || LCVR_Compat.LoadedAndEnabled) && !ConfigSync.instance.syncShareEverything) { return true; } string text = __instance.screenText.text.Substring(__instance.screenText.text.Length - __instance.textAdded).ToLower(); string[] array = text.Split(new char[1] { ' ' }); UnlockableEmote value = null; if (array.Length == 0) { return true; } if (!ConfigSync.isSynced) { if (text.StartsWith("emote")) { __result = BuildTerminalNodeNotSynced(); return false; } return true; } if (purchasingEmote != null) { if ("confirm".StartsWith(text)) { if (SessionManager.IsEmoteUnlocked(purchasingEmote)) { Debug.Log((object)("Attempted to confirm purchase on emote that was already unlocked. Emote: " + purchasingEmote.displayName)); __result = BuildTerminalNodeAlreadyUnlocked(purchasingEmote); } else if (Mathf.Max(currentEmoteCredits, 0) + (ConfigSync.instance.syncPurchaseEmotesWithDefaultCurrency ? Mathf.Max(terminalInstance.groupCredits, 0) : 0) < purchasingEmote.price) { Debug.Log((object)("Attempted to confirm purchase with insufficient emote credits. Current credits: " + currentEmoteCredits + ". " + (ConfigSync.instance.syncPurchaseEmotesWithDefaultCurrency ? ("Group credits: " + terminalInstance.groupCredits + ". ") : "") + "Emote price: " + purchasingEmote.price)); __result = BuildTerminalNodeInsufficientFunds(purchasingEmote); } else { int num = currentEmoteCredits; int groupCredits = terminalInstance.groupCredits; int num2 = -Mathf.Min(Mathf.Max(currentEmoteCredits, 0), purchasingEmote.price); int num3 = (ConfigSync.instance.syncPurchaseEmotesWithDefaultCurrency ? (-Mathf.Min(Mathf.Max(terminalInstance.groupCredits, 0), purchasingEmote.price + num2)) : 0); currentEmoteCredits += num2; Terminal obj = terminalInstance; obj.groupCredits += num3; if (!ConfigSync.instance.syncShareEverything) { SessionManager.UnlockEmoteLocal(purchasingEmote, purchased: true); } SyncManager.SendOnUnlockEmoteUpdate(purchasingEmote.emoteId, currentEmoteCredits); if (num3 > 0) { terminalInstance.SyncGroupCreditsServerRpc(terminalInstance.groupCredits, terminalInstance.numberOfItemsInDropship); } Debug.Log((object)("Purchasing emote: " + purchasingEmote.displayName + ". Price: " + purchasingEmote.price)); __result = BuildTerminalNodeOnPurchased(purchasingEmote, (num2 != 0) ? currentEmoteCredits : (-1), (num3 != 0) ? terminalInstance.groupCredits : (-1)); } } else { CustomLogging.Log("Canceling emote order."); __result = BuildCustomTerminalNode("Canceled order.\n\n"); } purchasingEmote = null; return false; } if (text.StartsWith("emotes")) { text = text.Replace("emotes", "emote"); } purchasingEmote = null; if (text.StartsWith("emote cheat ") && GameNetworkManager.Instance.localPlayerController.playerUsername == "Flip" && ((NetworkBehaviour)GameNetworkManager.Instance.localPlayerController).IsServer) { text = text.Replace("emote cheat ", ""); if (text.StartsWith("rotate")) { SyncManager.RotateEmoteSelectionServer(); __result = BuildCustomTerminalNode("Rotated emotes.\n------------------------------\n[[[emoteUnlockablesSelectionList]]]\n\n", clearPreviousText: true); } else if (text.StartsWith("resetship")) { SessionManager.ResetProgressLocal(); __result = BuildCustomTerminalNode("Reset ship emotes.\n\n", clearPreviousText: true); } else if (text.StartsWith("morecredits")) { currentEmoteCredits = 10000; __result = BuildCustomTerminalNode("New emote credit balance: " + currentEmoteCredits + "\n\n", clearPreviousText: true); } else if (EmotesManager.allUnlockableEmotesDict.TryGetValue(text, out value) && !SessionManager.IsEmoteUnlocked(value)) { SyncManager.SendOnUnlockEmoteUpdate(value.emoteId); } return false; } if (text.StartsWith("emote")) { if (text == "emote") { __result = BuildTerminalNodeHome(); return false; } text = text.Substring(6); value = TryGetEmoteCurrentSelection(text); } else { if (text.StartsWith("buy ")) { text = text.Replace("buy ", ""); } value = TryGetEmoteCurrentSelection(text, reliable: true); if (value == null) { return true; } } if (value != null) { if (SessionManager.IsEmoteUnlocked(value)) { CustomLogging.Log("Attempted to start purchase on emote that was already unlocked. Emote: " + value.displayName); __result = BuildTerminalNodeAlreadyUnlocked(value); } else if (Mathf.Max(currentEmoteCredits, 0) + (ConfigSync.instance.syncPurchaseEmotesWithDefaultCurrency ? Mathf.Max(terminalInstance.groupCredits, 0) : 0) < value.price) { CustomLogging.Log("Attempted to start purchase with insufficient emote credits. Current credits: " + currentEmoteCredits + ". " + (ConfigSync.instance.syncPurchaseEmotesWithDefaultCurrency ? ("Group credits: " + terminalInstance.groupCredits + ". ") : "") + "Emote price: " + value.price); __result = BuildTerminalNodeInsufficientFunds(value); } else { CustomLogging.Log("Started purchasing emote: " + value.emoteName); purchasingEmote = value; __result = BuildTerminalNodeConfirmDenyPurchase(value); } return false; } CustomLogging.Log("Attempted to start purchase on invalid emote, or emote was not in current rotation. Input emote: " + text); __result = BuildTerminalNodeInvalidEmote(); return false; } [HarmonyPatch(typeof(DepositItemsDesk), "SellAndDisplayItemProfits")] [HarmonyPrefix] private static void OnGainGroupCredits(int profit, int newGroupCredits, DepositItemsDesk __instance) { profit = Mathf.Max(profit, 0); if (profit > 0) { int num = (int)((float)profit * ConfigSync.instance.syncAddEmoteCreditsMultiplier); CustomLogging.Log("Gained " + profit + " group credits. (GainEmoteCreditsMultiplier: " + ConfigSync.instance.syncAddEmoteCreditsMultiplier + ")"); currentEmoteCredits += num; for (int i = 0; i < currentEmoteCreditsByPlayer.Count; i++) { string key = currentEmoteCreditsByPlayer.ElementAt(i).Key; currentEmoteCreditsByPlayer[key] += num; } } } [HarmonyPatch(typeof(TimeOfDay), "SetNewProfitQuota")] [HarmonyPostfix] private static void RotateEmoteSelectionPerQuota() { if (HelperTools.isServer) { SyncManager.RotateEmoteSelectionServer(); } } public static void RotateNewEmoteSelection() { int num = emoteStoreSeed + (ConfigSync.instance.syncPersistentUnlocks ? 1000 : 0); if (!ConfigSync.instance.syncShareEverything) { int num2 = (int)(((Object)(object)StartOfRound.Instance.localPlayerController != (Object)null) ? HelperTools.localPlayerController.playerClientId : 0); num += num2; } CustomLogging.Log("Rotating emote selection in store. Seed: " + num); Random random = new Random(num); emoteSelection.Clear(); for (int i = 0; i < ConfigSync.instance.syncNumEmotesStoreRotation; i++) { UnlockableEmote unlockableEmote = null; if (ConfigSync.instance.syncDisableRaritySystem) { unlockableEmote = GetRandomEmoteNotUnlocked(EmotesManager.allUnlockableEmotes, random); } else { double num3 = random.NextDouble(); float num4 = 1f - ConfigSync.instance.syncRotationChanceEmoteTier3; if (num3 >= (double)num4) { unlockableEmote = GetRandomEmoteNotUnlocked(EmotesManager.allEmotesTier3, random); } if (unlockableEmote == null) { num4 -= ConfigSync.instance.syncRotationChanceEmoteTier2; if (num3 >= (double)num4) { unlockableEmote = GetRandomEmoteNotUnlocked(EmotesManager.allEmotesTier2, random); } } if (unlockableEmote == null) { num4 -= ConfigSync.instance.syncRotationChanceEmoteTier1; if (num3 >= (double)num4) { unlockableEmote = GetRandomEmoteNotUnlocked(EmotesManager.allEmotesTier1, random); } } if (unlockableEmote == null) { unlockableEmote = GetRandomEmoteNotUnlocked(EmotesManager.allEmotesTier0, random); } } if (unlockableEmote != null) { emoteSelection.Add(unlockableEmote); } } emoteSelection.Sort((UnlockableEmote item1, UnlockableEmote item2) => item1.rarity.CompareTo(item2.rarity)); } public static UnlockableEmote GetRandomEmoteNotUnlocked(List emoteList, Random random) { List list = new List(); foreach (UnlockableEmote emote in emoteList) { if (!SessionManager.IsEmoteUnlocked(emote) && !emoteSelection.Contains(emote) && emote.purchasable && !emote.requiresHeldProp) { list.Add(emote); } } if (list.Count > 0) { int index = random.Next(list.Count); return list[index]; } return null; } private static TerminalNode BuildTerminalNodeHome() { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Expected O, but got Unknown return new TerminalNode { displayText = "[TooManyEmotes]\n\nStore\n------------------------------\n[[[emoteUnlockablesSelectionList]]]\n\n", clearPreviousText = true, acceptAnything = false }; } private static TerminalNode BuildTerminalNodeConfirmDenyPurchase(UnlockableEmote emote) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Expected O, but got Unknown TerminalNode val = new TerminalNode { displayText = confirmEmoteOpeningText + "\n> [" + emote.displayNameColorCoded + "]\n\n", isConfirmationNode = true, acceptAnything = false, clearPreviousText = true }; val.displayText = val.displayText + "Emote credit balance: $" + currentEmoteCredits + "\n"; if (ConfigSync.instance.syncPurchaseEmotesWithDefaultCurrency) { val.displayText = val.displayText + "Group credit balance: $" + terminalInstance.groupCredits + "\n"; } val.displayText += "\n"; val.displayText += "Please CONFIRM or DENY.\n\n"; return val; } private static TerminalNode BuildTerminalNodeOnPurchased(UnlockableEmote emote, int newEmoteCredits, int newGroupCredits) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Expected O, but got Unknown TerminalNode val = new TerminalNode { displayText = "You have successfully purchased a new emote!\n> [" + emote.displayNameColorCoded + "]\n\n", buyUnlockable = true, clearPreviousText = true, acceptAnything = false, playSyncedClip = 0 }; if (newEmoteCredits != -1) { val.displayText = val.displayText + "New emote credit balance: $" + newEmoteCredits + "\n"; } if (ConfigSync.instance.syncPurchaseEmotesWithDefaultCurrency && newGroupCredits != -1) { val.displayText = val.displayText + "New group credit balance: $" + newGroupCredits + "\n"; } val.displayText += "\n"; int num = Mathf.Max(new int[1] { (SessionManager.unlockedEmotes.Count - 1) / 8 }) + 1; int num2 = SessionManager.unlockedEmotes.Count % 8; val.displayText += "Your new emote has been added to the emote menu!\n\n"; return val; } private static TerminalNode BuildTerminalNodeAlreadyUnlocked(UnlockableEmote emote) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Expected O, but got Unknown return new TerminalNode { displayText = "You have already purchased this emote!\n> [" + emote.displayNameColorCoded + "]\n\n", clearPreviousText = false, acceptAnything = false }; } private static TerminalNode BuildTerminalNodeInsufficientFunds(UnlockableEmote emote) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Expected O, but got Unknown TerminalNode val = new TerminalNode(); val.displayText = "You could not afford this emote!\n> [" + emote.displayNameColorCoded + "]\n\nEmote credit balance is $" + currentEmoteCredits + "\n"; val.clearPreviousText = true; val.acceptAnything = false; TerminalNode val2 = val; if (ConfigSync.instance.syncPurchaseEmotesWithDefaultCurrency) { val2.displayText = val2.displayText + "Group credit balance is $" + terminalInstance.groupCredits + "\n"; } val2.displayText = val2.displayText + "Cost of emote is $" + emote.price + "\n\n"; return val2; } private static TerminalNode BuildTerminalNodeInvalidEmote(string emoteName = "") { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Expected O, but got Unknown TerminalNode val = new TerminalNode { displayText = "Emote does not exist, or is not available in the current rotation.", clearPreviousText = false, acceptAnything = false }; if (emoteName != "") { val.displayText = val.displayText + "\n\"" + emoteName + "\""; } val.displayText += "\n"; return val; } private static TerminalNode BuildTerminalNodeNotSynced(string emoteName = "") { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Expected O, but got Unknown TerminalNode val = new TerminalNode { displayText = "You cannot use the emote commands menu until you are synced with the host.\n\nYou may also be seeing this because the host does not have this mod.\nIf this is the case, you will already have access to every emote in your emote wheel. Enjoy!\n\n", clearPreviousText = true, acceptAnything = false }; if (emoteName != "") { val.displayText = val.displayText + "\n\"" + emoteName + "\""; } val.displayText += "\n"; return val; } private static TerminalNode BuildCustomTerminalNode(string displayText, bool clearPreviousText = false, bool acceptAnything = false, bool isConfirmationNode = false) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Expected O, but got Unknown return new TerminalNode { displayText = displayText, clearPreviousText = clearPreviousText, acceptAnything = false, isConfirmationNode = isConfirmationNode }; } private static bool IsAmbiguousKeyword(string keyword) { keyword = keyword.ToLower(); string[] array = ignoreTerminalKeywords; foreach (string text in array) { if (keyword.StartsWith(text) || text.StartsWith(keyword)) { return true; } } return false; } private static UnlockableEmote TryGetEmote(string emoteNameInput, IEnumerable emoteList = null, bool reliable = false) { if (emoteList == null) { emoteList = EmotesManager.allUnlockableEmotes; } UnlockableEmote unlockableEmote = null; foreach (UnlockableEmote emote in emoteList) { string text = emote.displayName.ToLower(); bool flag = IsAmbiguousKeyword(text); if (reliable || flag) { if ((emoteNameInput == text || (!flag && emoteNameInput.Length >= 4 && text.StartsWith(emoteNameInput))) && (unlockableEmote == null || text.Length < unlockableEmote.displayName.Length) && !"the company".StartsWith(emoteNameInput) && !"company".StartsWith(emoteNameInput)) { unlockableEmote = emote; } } else if (text.StartsWith(emoteNameInput) && (unlockableEmote == null || text.Length < unlockableEmote.displayName.Length)) { unlockableEmote = emote; } } return unlockableEmote; } private static UnlockableEmote TryGetEmoteCurrentSelection(string emoteNameInput, bool reliable = false) { return TryGetEmote(emoteNameInput, emoteSelection, reliable); } private static UnlockableEmote TryGetEmoteUnlockedEmotes(string emoteNameInput, bool reliable = false) { return TryGetEmote(emoteNameInput, SessionManager.unlockedEmotes, reliable); } } [HarmonyPatch] public class PlayerPatcher { [HarmonyPatch(typeof(PlayerControllerB), "Start")] [HarmonyPostfix] private static void InitializeEmoteController(PlayerControllerB __instance) { ((Component)__instance).gameObject.AddComponent(); } [HarmonyPatch(typeof(PlayerControllerB), "ConnectClientToPlayerObject")] [HarmonyPostfix] private static void OnLocalClientReady(PlayerControllerB __instance) { CustomLogging.Log("Initializing local player."); for (int i = 0; i < HUDManager.Instance.controlTipLines.Length; i++) { TextMeshProUGUI val = HUDManager.Instance.controlTipLines[i]; if (((TMP_Text)val).text == "") { ((TMP_Text)HUDManager.Instance.controlTipLines[i]).text = $"[{KeybindDisplayNames.GetKeybindDisplayName(Keybinds.OpenEmoteMenuAction)}]: Open Emote Radial Menu"; break; } } KeybindDisplayNames.UpdateControlTipLines(); } [HarmonyPatch(typeof(StartOfRound), "OnPlayerDC")] [HarmonyPrefix] private static void OnPlayerDC(int playerObjectNumber, ulong clientId, StartOfRound __instance) { PlayerControllerB component = __instance.allPlayerObjects[playerObjectNumber].GetComponent(); if ((Object)(object)component != (Object)null && EmoteControllerPlayer.allPlayerEmoteControllers.TryGetValue(component, out var value) && value.IsPerformingCustomEmote()) { value.StopPerformingEmote(); } } [HarmonyPatch(typeof(PlayerControllerB), "KillPlayer")] [HarmonyPrefix] private static void OnPlayerDeath(Vector3 bodyVelocity, PlayerControllerB __instance) { if ((Object)(object)__instance != (Object)null && EmoteControllerPlayer.allPlayerEmoteControllers.TryGetValue(__instance, out var value) && value.IsPerformingCustomEmote()) { CustomLogging.LogWarning("Player died while emoting. Heh... I mean, I hope this handles smoothly."); value.StopPerformingEmote(); } } [HarmonyPatch(typeof(PlayerControllerB), "StopPerformingEmoteClientRpc")] [HarmonyPrefix] private static void OnStopPerformingEmote(PlayerControllerB __instance) { if (!((Object)(object)__instance == (Object)(object)HelperTools.localPlayerController) && EmoteControllerPlayer.allPlayerEmoteControllers.TryGetValue(__instance, out var value) && value.IsPerformingCustomEmote()) { value.StopPerformingEmote(); } } public static UnlockableEmote GetCurrentlyPlayingEmote(PlayerControllerB playerController) { if (EmoteControllerPlayer.allPlayerEmoteControllers.TryGetValue(playerController, out var value)) { return value.performingEmote; } return null; } [HarmonyPatch(typeof(PlayerControllerB), "PerformEmote")] [HarmonyPrefix] private static void OnPerformDefaultEmote(CallbackContext context, int emoteID) { if (((CallbackContext)(ref context)).performed && HelperTools.emoteControllerLocal.IsPerformingCustomEmote()) { CustomLogging.LogWarningVerbose("[PerformEmote] On perform vanilla emote on local player. Stopping custom emote."); HelperTools.emoteControllerLocal.StopPerformingEmote(); } } } } namespace TooManyEmotes.Networking { [HarmonyPatch] public static class SyncPerformingEmoteManager { internal static Dictionary doNotTriggerAudioDict = new Dictionary(); private static HashSet sentLastAudioUpdateToPlayers = new HashSet(); [HarmonyPatch(typeof(PlayerControllerB), "ConnectClientToPlayerObject")] [HarmonyPostfix] public static void Init() { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Expected O, but got Unknown //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Expected O, but got Unknown //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Expected O, but got Unknown //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Expected O, but got Unknown doNotTriggerAudioDict.Clear(); sentLastAudioUpdateToPlayers.Clear(); if (HelperTools.isServer) { NetworkManager.Singleton.CustomMessagingManager.RegisterNamedMessageHandler("TooManyEmotes.PerformEmoteServerRpc", new HandleNamedMessageDelegate(PerformEmoteServerRpc)); NetworkManager.Singleton.CustomMessagingManager.RegisterNamedMessageHandler("TooManyEmotes.SyncEmoteServerRpc", new HandleNamedMessageDelegate(SyncEmoteServerRpc)); } else if (HelperTools.isClient) { NetworkManager.Singleton.CustomMessagingManager.RegisterNamedMessageHandler("TooManyEmotes.PerformEmoteClientRpc", new HandleNamedMessageDelegate(PerformEmoteClientRpc)); NetworkManager.Singleton.CustomMessagingManager.RegisterNamedMessageHandler("TooManyEmotes.SyncEmoteClientRpc", new HandleNamedMessageDelegate(SyncEmoteClientRpc)); } } public static void SendPerformingEmoteUpdateToServer(UnlockableEmote emote, bool doNotTriggerAudio = false) { //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) if (!HelperTools.isClient || emote == null) { return; } if (!doNotTriggerAudioDict.ContainsKey(HelperTools.emoteControllerLocal)) { doNotTriggerAudioDict[HelperTools.emoteControllerLocal] = !doNotTriggerAudio; } if (HelperTools.isServer) { ServerSendPerformingEmoteUpdateToClients(HelperTools.emoteControllerLocal, emote, doNotTriggerAudio); return; } bool flag = doNotTriggerAudioDict[HelperTools.emoteControllerLocal] != doNotTriggerAudio; int num = 2 + (flag ? 1 : 0); FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(num, (Allocator)2, -1); short num2 = (short)emote.emoteId; ((FastBufferWriter)(ref val)).WriteValue(ref num2, default(ForPrimitives)); CustomLogging.Log("Sending performing emote update to server. Emote: " + emote.emoteName + " EmoteId: " + emote.emoteId); if (flag) { ((FastBufferWriter)(ref val)).WriteValue(ref doNotTriggerAudio, default(ForPrimitives)); doNotTriggerAudioDict[HelperTools.emoteControllerLocal] = doNotTriggerAudio; } NetworkManager.Singleton.CustomMessagingManager.SendNamedMessage("TooManyEmotes.PerformEmoteServerRpc", 0uL, val, (NetworkDelivery)3); } private static void PerformEmoteServerRpc(ulong clientId, FastBufferReader reader) { //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) if (!HelperTools.isServer) { return; } if (!HelperTools.TryGetPlayerByClientId(clientId, out var playerController) || !EmoteControllerPlayer.allPlayerEmoteControllers.TryGetValue(playerController, out var value)) { CustomLogging.LogWarning("Could not handle performing emote request. Could not find emote controller for player with id: " + clientId); return; } short num = default(short); ((FastBufferReader)(ref reader)).ReadValue(ref num, default(ForPrimitives)); if (num < 0 || num >= EmotesManager.allUnlockableEmotes.Count) { CustomLogging.LogWarning("Could not handle performing emote request from client with id: " + clientId + ". Invalid emote id: " + num + " AllUnlockableEmoteListSize: " + EmotesManager.allUnlockableEmotes.Count); return; } bool doNotTriggerAudio = false; if (((FastBufferReader)(ref reader)).TryBeginRead(1)) { ((FastBufferReader)(ref reader)).ReadValue(ref doNotTriggerAudio, default(ForPrimitives)); } else if (doNotTriggerAudioDict.ContainsKey(value)) { doNotTriggerAudio = doNotTriggerAudioDict[value]; } UnlockableEmote unlockableEmote = EmotesManager.allUnlockableEmotes[num]; int overrideEmoteId = -1; if (unlockableEmote.emoteSyncGroup != null) { overrideEmoteId = unlockableEmote.emoteSyncGroup.IndexOf(unlockableEmote); } CustomLogging.Log("Receiving performing emote update from client: " + clientId + " Emote: " + unlockableEmote.emoteName); if (HelperTools.isClient && !value.isLocalPlayer) { value.PerformEmote(unlockableEmote, overrideEmoteId, doNotTriggerAudio); } ServerSendPerformingEmoteUpdateToClients(value, unlockableEmote, doNotTriggerAudio); } public static void ServerSendPerformingEmoteUpdateToClients(EmoteController emoteController, UnlockableEmote emote, bool doNotTriggerAudio = false) { //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00af: 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_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) if (!HelperTools.isServer) { CustomLogging.LogWarning("[ServerSendPerformingEmoteUpdateToClients] Only the server can call this method!"); } else if (!((Object)(object)emoteController == (Object)null) && emote != null) { if (!doNotTriggerAudioDict.ContainsKey(emoteController)) { doNotTriggerAudioDict[emoteController] = !doNotTriggerAudio; } bool flag = doNotTriggerAudioDict[emoteController] != doNotTriggerAudio; int num = 6 + (flag ? 1 : 0); FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(num, (Allocator)2, -1); uint num2 = (uint)emoteController.emoteControllerId; ((FastBufferWriter)(ref val)).WriteValue(ref num2, default(ForPrimitives)); short num3 = (short)emote.emoteId; ((FastBufferWriter)(ref val)).WriteValue(ref num3, default(ForPrimitives)); if (flag) { ((FastBufferWriter)(ref val)).WriteValue(ref doNotTriggerAudio, default(ForPrimitives)); doNotTriggerAudioDict[emoteController] = doNotTriggerAudio; } NetworkManager.Singleton.CustomMessagingManager.SendNamedMessageToAll("TooManyEmotes.PerformEmoteClientRpc", val, (NetworkDelivery)3); } } private static void PerformEmoteClientRpc(ulong clientId, FastBufferReader reader) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0096: 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_0130: Unknown result type (might be due to invalid IL or missing references) if (!HelperTools.isClient || HelperTools.isServer) { return; } uint num = default(uint); ((FastBufferReader)(ref reader)).ReadValue(ref num, default(ForPrimitives)); if ((Object)(object)HelperTools.emoteControllerLocal != (Object)null && num == HelperTools.emoteControllerLocal.emoteControllerId) { return; } EmoteController emoteControllerById = HelperTools.GetEmoteControllerById(num); if ((Object)(object)emoteControllerById == (Object)null) { CustomLogging.LogWarning("Could not handle performing emote request from server. Failed to find emote controller with id: " + num); return; } short num2 = default(short); ((FastBufferReader)(ref reader)).ReadValue(ref num2, default(ForPrimitives)); if (num2 < 0 || num2 >= EmotesManager.allUnlockableEmotes.Count) { CustomLogging.LogWarning("Could not handle performing emote request from server for emote controller with id: " + num + ". Invalid emote id: " + num2 + " AllUnlockableEmoteListSize: " + EmotesManager.allUnlockableEmotes.Count); return; } bool flag = false; if (((FastBufferReader)(ref reader)).TryBeginRead(1)) { ((FastBufferReader)(ref reader)).ReadValue(ref flag, default(ForPrimitives)); } else if (doNotTriggerAudioDict.ContainsKey(emoteControllerById)) { flag = doNotTriggerAudioDict[emoteControllerById]; } doNotTriggerAudioDict[emoteControllerById] = flag; UnlockableEmote unlockableEmote = EmotesManager.allUnlockableEmotes[num2]; int overrideEmoteId = -1; if (unlockableEmote.emoteSyncGroup != null) { overrideEmoteId = unlockableEmote.emoteSyncGroup.IndexOf(unlockableEmote); } CustomLogging.Log("Receiving performing emote update from server for emote controller with id: " + num + " Emote: " + unlockableEmote.emoteName); emoteControllerById.PerformEmote(unlockableEmote, overrideEmoteId, flag); } public static void SendSyncEmoteUpdateToServer(EmoteController emoteController, int overrideEmoteId = -1) { //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) if (HelperTools.isClient && !((Object)(object)emoteController == (Object)null)) { if (HelperTools.isServer) { ServerSendSyncEmoteUpdateToClients(HelperTools.emoteControllerLocal, emoteController, overrideEmoteId); return; } CustomLogging.Log("Sending sync emote update to server. Sync with emote controller id: " + (object)emoteController); FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(6, (Allocator)2, -1); uint num = (uint)emoteController.emoteControllerId; ((FastBufferWriter)(ref val)).WriteValue(ref num, default(ForPrimitives)); short num2 = (short)overrideEmoteId; ((FastBufferWriter)(ref val)).WriteValue(ref num2, default(ForPrimitives)); NetworkManager.Singleton.CustomMessagingManager.SendNamedMessage("TooManyEmotes.SyncEmoteServerRpc", 0uL, val, (NetworkDelivery)3); } } private static void SyncEmoteServerRpc(ulong clientId, FastBufferReader reader) { //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) if (!HelperTools.isServer) { return; } if (!HelperTools.TryGetPlayerByClientId(clientId, out var playerController) || !EmoteControllerPlayer.allPlayerEmoteControllers.TryGetValue(playerController, out var value)) { CustomLogging.LogWarning("Could not handle sync emote request. Could not find emote controller for player with id: " + clientId); return; } uint num = default(uint); ((FastBufferReader)(ref reader)).ReadValue(ref num, default(ForPrimitives)); short overrideEmoteId = default(short); ((FastBufferReader)(ref reader)).ReadValue(ref overrideEmoteId, default(ForPrimitives)); EmoteController emoteControllerById = HelperTools.GetEmoteControllerById(num); if ((Object)(object)emoteControllerById == (Object)null) { CustomLogging.LogWarning("Could not handle sync emote request from client with id: " + clientId + ". Failed to find emote controller with id: " + num); return; } if (emoteControllerById.performingEmote == null) { CustomLogging.LogWarning("Could not handle sync emote request from client with id: " + clientId + ". Emote controller is not performing any emote."); return; } CustomLogging.Log("Receiving sync emote update from client with id: " + clientId + " Sync with emote controller id: " + num); if (HelperTools.isClient && !value.isLocalPlayer) { value.SyncWithEmoteController(emoteControllerById, overrideEmoteId); } ServerSendSyncEmoteUpdateToClients(value, emoteControllerById, overrideEmoteId); } public static void ServerSendSyncEmoteUpdateToClients(EmoteController emoteController, EmoteController syncWithEmoteController, int overrideEmoteId = -1) { //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0084: 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_00a1: Unknown result type (might be due to invalid IL or missing references) if (!HelperTools.isServer) { CustomLogging.LogWarning("[ServerSendSyncEmoteUpdateToClients] Only the server can call this method!"); } else if (!((Object)(object)emoteController == (Object)null) && !((Object)(object)syncWithEmoteController == (Object)null)) { FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(10, (Allocator)2, -1); uint num = (uint)emoteController.emoteControllerId; ((FastBufferWriter)(ref val)).WriteValue(ref num, default(ForPrimitives)); num = (uint)syncWithEmoteController.emoteControllerId; ((FastBufferWriter)(ref val)).WriteValue(ref num, default(ForPrimitives)); short num2 = (short)overrideEmoteId; ((FastBufferWriter)(ref val)).WriteValue(ref num2, default(ForPrimitives)); NetworkManager.Singleton.CustomMessagingManager.SendNamedMessageToAll("TooManyEmotes.SyncEmoteClientRpc", val, (NetworkDelivery)3); } } private static void SyncEmoteClientRpc(ulong clientId, FastBufferReader reader) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) if (!HelperTools.isClient || HelperTools.isServer) { return; } uint num = default(uint); ((FastBufferReader)(ref reader)).ReadValue(ref num, default(ForPrimitives)); if ((Object)(object)HelperTools.emoteControllerLocal != (Object)null && num == HelperTools.emoteControllerLocal.emoteControllerId) { return; } EmoteController emoteControllerById = HelperTools.GetEmoteControllerById(num); if ((Object)(object)emoteControllerById == (Object)null) { CustomLogging.LogWarning("Could not handle sync emote request from server. Failed to find emote controller with id: " + num); return; } uint num2 = default(uint); ((FastBufferReader)(ref reader)).ReadValue(ref num2, default(ForPrimitives)); short overrideEmoteId = default(short); ((FastBufferReader)(ref reader)).ReadValue(ref overrideEmoteId, default(ForPrimitives)); EmoteController emoteControllerById2 = HelperTools.GetEmoteControllerById(num2); if ((Object)(object)emoteControllerById2 == (Object)null) { CustomLogging.LogWarning("Could not handle sync emote request from server for emote controller with id: " + num + ". Failed to find emote controller with id: " + num + " to sync with."); } else if (emoteControllerById2.performingEmote == null) { CustomLogging.LogWarning("Could not handle sync emote request from server for emote controller with id: " + clientId + ". Emote controller is not performing any emote."); } else { CustomLogging.Log("Receiving sync emote update from server for emote controller with id: " + num + " SyncWithEmoteControllerId: " + num2); emoteControllerById.SyncWithEmoteController(emoteControllerById2, overrideEmoteId); } } } [Serializable] [HarmonyPatch] public class ConfigSync { public static bool isSynced; public static ConfigSync defaultConfig; public static ConfigSync instance; public bool syncUnlockEverything; public bool syncShareEverything; public bool syncPersistentUnlocks; public bool syncPersistentUnlocksGlobal; public bool syncPersistentEmoteCredits; public bool syncSyncUnsharedEmotes; public bool syncForceDisableMovingWhileEmoting; public bool syncDisableRaritySystem; public bool syncRemoveGrabbableEmotesPartyPooperMode; public int syncStartingEmoteCredits; public float syncAddEmoteCreditsMultiplier; public bool syncPurchaseEmotesWithDefaultCurrency; public float syncPriceMultiplierEmotesStore; public int syncBasePriceEmoteTier0; public int syncBasePriceEmoteTier1; public int syncBasePriceEmoteTier2; public int syncBasePriceEmoteTier3; public int syncNumEmotesStoreRotation; public float syncRotationChanceEmoteTier0; public float syncRotationChanceEmoteTier1; public float syncRotationChanceEmoteTier2; public float syncRotationChanceEmoteTier3; public bool syncEnableMaskedEnemiesEmoting; public float syncMaskedEnemiesEmoteChanceOnEncounter; public bool syncMaskedEnemiesAlwaysEmoteOnFirstEncounter; public bool syncOverrideStopAndStareDuration; public float syncMaskedEnemyEmoteRandomDelayMin; public float syncMaskedEnemyEmoteRandomDelayMax; public float syncMaskedEnemyEmoteRandomDurationMin; public float syncMaskedEnemyEmoteRandomDurationMax; public bool syncDisableAudioShipSpeaker; public static Vector2 syncMaskedEnemyEmoteRandomDelay; public static Vector2 syncMaskedEnemyEmoteRandomDuration; public static HashSet syncedClients; public ConfigSync() { //IL_0381: Unknown result type (might be due to invalid IL or missing references) //IL_0386: Unknown result type (might be due to invalid IL or missing references) //IL_03b6: Unknown result type (might be due to invalid IL or missing references) //IL_03bb: Unknown result type (might be due to invalid IL or missing references) syncUnlockEverything = ConfigSettings.unlockEverything.Value; syncShareEverything = syncUnlockEverything || ConfigSettings.shareEverything.Value; syncPersistentUnlocks = !syncUnlockEverything && ConfigSettings.persistentUnlocks.Value; syncPersistentUnlocksGlobal = syncPersistentUnlocks && ConfigSettings.persistentUnlocksGlobal.Value; syncPersistentEmoteCredits = syncPersistentUnlocks && !syncPersistentUnlocksGlobal && ConfigSettings.persistentEmoteCredits.Value; if (!syncPersistentUnlocksGlobal) { syncDisableRaritySystem = ConfigSettings.disableRaritySystem.Value; syncStartingEmoteCredits = ConfigSettings.startingEmoteCredits.Value; syncAddEmoteCreditsMultiplier = ConfigSettings.addEmoteCreditsMultiplier.Value; syncPriceMultiplierEmotesStore = ConfigSettings.priceMultiplierEmotesStore.Value; syncNumEmotesStoreRotation = ConfigSettings.numEmotesStoreRotation.Value; syncRotationChanceEmoteTier0 = ConfigSettings.rotationChanceEmoteTier0.Value; syncRotationChanceEmoteTier1 = ConfigSettings.rotationChanceEmoteTier1.Value; syncRotationChanceEmoteTier2 = ConfigSettings.rotationChanceEmoteTier2.Value; syncRotationChanceEmoteTier3 = ConfigSettings.rotationChanceEmoteTier3.Value; syncPurchaseEmotesWithDefaultCurrency = ConfigSettings.purchaseEmotesWithDefaultCurrency.Value && syncShareEverything; syncBasePriceEmoteTier0 = (syncDisableRaritySystem ? ConfigSettings.basePriceEmoteRaritySystemDisabled.Value : ConfigSettings.basePriceEmoteTier0.Value); syncBasePriceEmoteTier1 = (syncDisableRaritySystem ? ConfigSettings.basePriceEmoteRaritySystemDisabled.Value : ConfigSettings.basePriceEmoteTier1.Value); syncBasePriceEmoteTier2 = (syncDisableRaritySystem ? ConfigSettings.basePriceEmoteRaritySystemDisabled.Value : ConfigSettings.basePriceEmoteTier2.Value); syncBasePriceEmoteTier3 = (syncDisableRaritySystem ? ConfigSettings.basePriceEmoteRaritySystemDisabled.Value : ConfigSettings.basePriceEmoteTier3.Value); } else { syncDisableRaritySystem = false; syncStartingEmoteCredits = (int)((ConfigEntryBase)ConfigSettings.basePriceEmoteTier0).DefaultValue - 1; syncAddEmoteCreditsMultiplier = (float)((ConfigEntryBase)ConfigSettings.addEmoteCreditsMultiplier).DefaultValue; syncPriceMultiplierEmotesStore = Mathf.Max(syncPriceMultiplierEmotesStore, (float)((ConfigEntryBase)ConfigSettings.priceMultiplierEmotesStore).DefaultValue); syncNumEmotesStoreRotation = Mathf.Min(ConfigSettings.numEmotesStoreRotation.Value, (int)((ConfigEntryBase)ConfigSettings.numEmotesStoreRotation).DefaultValue); syncRotationChanceEmoteTier0 = (float)((ConfigEntryBase)ConfigSettings.rotationChanceEmoteTier0).DefaultValue; syncRotationChanceEmoteTier1 = (float)((ConfigEntryBase)ConfigSettings.rotationChanceEmoteTier1).DefaultValue; syncRotationChanceEmoteTier2 = (float)((ConfigEntryBase)ConfigSettings.rotationChanceEmoteTier2).DefaultValue; syncRotationChanceEmoteTier3 = (float)((ConfigEntryBase)ConfigSettings.rotationChanceEmoteTier3).DefaultValue; syncPurchaseEmotesWithDefaultCurrency = false; syncBasePriceEmoteTier0 = (int)((ConfigEntryBase)ConfigSettings.basePriceEmoteTier0).DefaultValue; syncBasePriceEmoteTier1 = (int)((ConfigEntryBase)ConfigSettings.basePriceEmoteTier1).DefaultValue; syncBasePriceEmoteTier2 = (int)((ConfigEntryBase)ConfigSettings.basePriceEmoteTier2).DefaultValue; syncBasePriceEmoteTier3 = (int)((ConfigEntryBase)ConfigSettings.basePriceEmoteTier3).DefaultValue; } syncSyncUnsharedEmotes = ConfigSettings.syncUnsharedEmotes.Value; syncForceDisableMovingWhileEmoting = ConfigSettings.forceDisableMovingWhileEmoting.Value; syncRemoveGrabbableEmotesPartyPooperMode = ConfigSettings.removeGrabbableEmotesPartyPooperMode.Value; syncEnableMaskedEnemiesEmoting = ConfigSettings.enableMaskedEnemiesEmoting.Value; syncMaskedEnemiesEmoteChanceOnEncounter = ConfigSettings.maskedEnemiesEmoteChanceOnEncounter.Value; syncMaskedEnemiesAlwaysEmoteOnFirstEncounter = ConfigSettings.maskedEnemiesAlwaysEmoteOnFirstEncounter.Value; syncOverrideStopAndStareDuration = ConfigSettings.overrideStopAndStareDuration.Value; syncMaskedEnemyEmoteRandomDelay = ParseVector2FromString(ConfigSettings.maskedEnemyEmoteRandomDelay.Value); syncMaskedEnemyEmoteRandomDelayMin = syncMaskedEnemyEmoteRandomDelay.x; syncMaskedEnemyEmoteRandomDelayMax = syncMaskedEnemyEmoteRandomDelay.y; syncMaskedEnemyEmoteRandomDuration = ParseVector2FromString(ConfigSettings.maskedEnemyEmoteRandomDuration.Value); syncMaskedEnemyEmoteRandomDurationMin = syncMaskedEnemyEmoteRandomDuration.x; syncMaskedEnemyEmoteRandomDurationMax = syncMaskedEnemyEmoteRandomDuration.y; syncDisableAudioShipSpeaker = ConfigSettings.disableAudioShipSpeaker.Value; } public Vector2 ParseVector2FromString(string str) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0089: 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_008e: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) Vector2 result = Vector2.zero; try { string[] array = str.Split(new char[1] { ',' }); if (float.TryParse(array[0].Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out var result2) && float.TryParse(array[1].Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out var result3)) { result = new Vector2(Mathf.Min(Mathf.Abs(result2), Mathf.Abs(result3)), Mathf.Max(Mathf.Abs(result2), Mathf.Abs(result3))); } } catch { } return result; } [HarmonyPatch(typeof(StartOfRound), "Awake")] [HarmonyPrefix] public static void ResetValues() { isSynced = false; BuildDefaultConfigSync(); } public static void BuildDefaultConfigSync() { defaultConfig = new ConfigSync(); instance = new ConfigSync(); } [HarmonyPatch(typeof(PlayerControllerB), "ConnectClientToPlayerObject")] [HarmonyPostfix] public static void Init(PlayerControllerB __instance) { //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Expected O, but got Unknown //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Expected O, but got Unknown if (isSynced) { return; } isSynced = HelperTools.isServer; SyncManager.isSynced = false; SyncManager.requestedSync = false; if (HelperTools.isServer) { syncedClients = new HashSet(); NetworkManager.Singleton.CustomMessagingManager.RegisterNamedMessageHandler("TooManyEmotes.OnRequestConfigSyncServerRpc", new HandleNamedMessageDelegate(OnRequestConfigSyncServerRpc)); if (instance.syncUnlockEverything) { foreach (UnlockableEmote allUnlockableEmote in EmotesManager.allUnlockableEmotes) { SessionManager.UnlockEmoteLocal(allUnlockableEmote); } } OnSynced(); return; } foreach (UnlockableEmote allUnlockableEmote2 in EmotesManager.allUnlockableEmotes) { SessionManager.UnlockEmoteLocal(allUnlockableEmote2); } NetworkManager.Singleton.CustomMessagingManager.RegisterNamedMessageHandler("TooManyEmotes.OnRequestConfigSyncClientRpc", new HandleNamedMessageDelegate(OnRequestConfigSyncClientRpc)); RequestConfigSync(); } public static void RequestConfigSync() { //IL_0031: Unknown result type (might be due to invalid IL or missing references) if (HelperTools.isClient) { CustomLogging.Log("Requesting config sync from server"); FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(0, (Allocator)2, -1); NetworkManager.Singleton.CustomMessagingManager.SendNamedMessage("TooManyEmotes.OnRequestConfigSyncServerRpc", 0uL, val, (NetworkDelivery)3); } else { CustomLogging.LogError("Failed to send unlocked emote update to server."); } } private static void OnRequestConfigSyncServerRpc(ulong clientId, FastBufferReader reader) { //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) if (HelperTools.isServer) { CustomLogging.Log("Receiving config sync request from client: " + clientId); syncedClients.Add(clientId); SyncManager.syncedClients.Remove(clientId); byte[] array = SerializeConfigToByteArray(instance); FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(4 + array.Length, (Allocator)2, -1); int num = array.Length; ((FastBufferWriter)(ref val)).WriteValueSafe(ref num, default(ForPrimitives)); ((FastBufferWriter)(ref val)).WriteBytesSafe(array, -1, 0); NetworkManager.Singleton.CustomMessagingManager.SendNamedMessage("TooManyEmotes.OnRequestConfigSyncClientRpc", clientId, val, (NetworkDelivery)3); } } private static void OnRequestConfigSyncClientRpc(ulong clientId, FastBufferReader reader) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) if (!HelperTools.isClient) { return; } int num = default(int); ((FastBufferReader)(ref reader)).ReadValueSafe(ref num, default(ForPrimitives)); if (((FastBufferReader)(ref reader)).TryBeginRead(num)) { CustomLogging.Log("Receiving config sync from server."); byte[] data = new byte[num]; ((FastBufferReader)(ref reader)).ReadBytesSafe(ref data, num, 0); instance = DeserializeFromByteArray(data); syncMaskedEnemyEmoteRandomDelay = new Vector2(instance.syncMaskedEnemyEmoteRandomDelayMin, instance.syncMaskedEnemyEmoteRandomDelayMax); syncMaskedEnemyEmoteRandomDuration = new Vector2(instance.syncMaskedEnemyEmoteRandomDurationMin, instance.syncMaskedEnemyEmoteRandomDurationMax); isSynced = true; OnSynced(); if (EmotesManager.allUnlockableEmotes != null && SessionManager.unlockedEmotes != null) { SessionManager.ResetProgressLocal(forceResetAll: true); if (instance.syncUnlockEverything) { SessionManager.UnlockEmotesLocal(EmotesManager.allUnlockableEmotes); } else { SessionManager.UnlockEmotesLocal(EmotesManager.complementaryEmotes); } SessionManager.UpdateUnlockedFavoriteEmotes(); } } else { CustomLogging.LogError("Error receiving sync from server."); } } private static void OnSynced() { isSynced = true; if (!instance.syncDisableAudioShipSpeaker) { EmoteAudioPlayerManager.InitializeShipSpeakerAudioPlayer(); } } public static byte[] SerializeConfigToByteArray(ConfigSync config) { BinaryFormatter binaryFormatter = new BinaryFormatter(); MemoryStream memoryStream = new MemoryStream(); binaryFormatter.Serialize(memoryStream, config); return memoryStream.ToArray(); } public static ConfigSync DeserializeFromByteArray(byte[] data) { MemoryStream serializationStream = new MemoryStream(data); BinaryFormatter binaryFormatter = new BinaryFormatter(); return (ConfigSync)binaryFormatter.Deserialize(serializationStream); } } [HarmonyPatch] public static class SyncManager { [CompilerGenerated] private sealed class d__11 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__11(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = (object)new WaitForEndOfFrame(); <>1__state = 1; return true; case 1: <>1__state = -1; TerminalPatcher.RotateNewEmoteSelection(); return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } public static bool requestedSync = false; public static bool isSynced = false; public static HashSet syncedClients = new HashSet(); [HarmonyPatch(typeof(StartOfRound), "Awake")] [HarmonyPostfix] public static void ResetValues() { isSynced = false; requestedSync = false; } [HarmonyPatch(typeof(PlayerControllerB), "ConnectClientToPlayerObject")] [HarmonyPostfix] public static void Init() { //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Expected O, but got Unknown //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Expected O, but got Unknown //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Expected O, but got Unknown //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Expected O, but got Unknown //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Expected O, but got Unknown isSynced = false; requestedSync = false; if (HelperTools.isServer) { syncedClients?.Clear(); OnSynced(); NetworkManager.Singleton.CustomMessagingManager.RegisterNamedMessageHandler("TooManyEmotes.OnRequestSyncServerRpc", new HandleNamedMessageDelegate(OnRequestSyncServerRpc)); NetworkManager.Singleton.CustomMessagingManager.RegisterNamedMessageHandler("TooManyEmotes.OnUnlockEmoteServerRpc", new HandleNamedMessageDelegate(OnUnlockEmoteServerRpc)); } else if (HelperTools.isClient) { NetworkManager.Singleton.CustomMessagingManager.RegisterNamedMessageHandler("TooManyEmotes.OnRequestSyncClientRpc", new HandleNamedMessageDelegate(OnRequestSyncClientRpc)); NetworkManager.Singleton.CustomMessagingManager.RegisterNamedMessageHandler("TooManyEmotes.OnUnlockEmoteClientRpc", new HandleNamedMessageDelegate(OnUnlockEmoteClientRpc)); NetworkManager.Singleton.CustomMessagingManager.RegisterNamedMessageHandler("TooManyEmotes.OnRotateEmotesClientRpc", new HandleNamedMessageDelegate(RotateEmoteSelectionClientRpc)); } } [HarmonyPatch(typeof(PlayerControllerB), "Update")] [HarmonyPostfix] public static void RequestSyncAfterConfigUpdate(PlayerControllerB __instance) { if (HelperTools.isClient && !HelperTools.isServer && !isSynced && !requestedSync && ConfigSync.isSynced && (Object)(object)__instance == (Object)(object)HelperTools.localPlayerController) { requestedSync = true; SendSyncRequest(); } } public static void SendSyncRequest() { //IL_003c: Unknown result type (might be due to invalid IL or missing references) if (HelperTools.isClient && !HelperTools.isServer) { CustomLogging.Log("Sending sync request to server."); FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(0, (Allocator)2, -1); NetworkManager.Singleton.CustomMessagingManager.SendNamedMessage("TooManyEmotes.OnRequestSyncServerRpc", 0uL, val, (NetworkDelivery)3); } } private static void OnRequestSyncServerRpc(ulong clientId, FastBufferReader reader) { if (HelperTools.isServer) { CustomLogging.Log("Receiving sync request from client: " + clientId); ServerSendSyncToClient(clientId); SyncPerformingEmoteManager.doNotTriggerAudioDict?.Clear(); } } public static void ServerSendSyncToClient(ulong clientId) { //IL_01dc: Unknown result type (might be due to invalid IL or missing references) //IL_01e2: Unknown result type (might be due to invalid IL or missing references) //IL_01fe: Unknown result type (might be due to invalid IL or missing references) //IL_0204: Unknown result type (might be due to invalid IL or missing references) //IL_0216: Unknown result type (might be due to invalid IL or missing references) //IL_021c: Unknown result type (might be due to invalid IL or missing references) //IL_023f: Unknown result type (might be due to invalid IL or missing references) //IL_0245: Unknown result type (might be due to invalid IL or missing references) //IL_0269: Unknown result type (might be due to invalid IL or missing references) //IL_026f: Unknown result type (might be due to invalid IL or missing references) //IL_029a: Unknown result type (might be due to invalid IL or missing references) //IL_02a0: Unknown result type (might be due to invalid IL or missing references) //IL_02de: Unknown result type (might be due to invalid IL or missing references) if (!HelperTools.isServer || !ConfigSync.syncedClients.Contains(clientId)) { return; } if (HelperTools.TryGetPlayerByClientId(clientId, out var playerController)) { if (!SessionManager.unlockedEmotesByPlayer.ContainsKey(playerController.playerUsername)) { SessionManager.unlockedEmotesByPlayer.Add(playerController.playerUsername, new List()); } if (!TerminalPatcher.currentEmoteCreditsByPlayer.ContainsKey(playerController.playerUsername)) { TerminalPatcher.currentEmoteCreditsByPlayer.Add(playerController.playerUsername, ConfigSync.instance.syncStartingEmoteCredits); } } List list = SessionManager.unlockedEmotes; int num = TerminalPatcher.currentEmoteCredits; if (!ConfigSync.instance.syncUnlockEverything && !ConfigSync.instance.syncShareEverything) { if ((Object)(object)playerController != (Object)null) { if (SessionManager.unlockedEmotesByPlayer.TryGetValue(playerController.playerUsername, out var value)) { CustomLogging.Log("Loading " + value.Count + " unlocked emotes for player: " + playerController.playerUsername); list = value; } if (TerminalPatcher.currentEmoteCreditsByPlayer.TryGetValue(playerController.playerUsername, out var value2)) { CustomLogging.Log("Loading " + value2 + " emote credits for player: " + playerController.playerUsername); num = value2; } } else { CustomLogging.LogError("Error loading custom emotes for player. Player with id: " + clientId + " does not exist?"); list = EmotesManager.complementaryEmotes; num = ConfigSync.instance.syncStartingEmoteCredits; } } int num2 = ((!ConfigSync.instance.syncPersistentUnlocksGlobal) ? list.Count : 0); int num3 = 8 + 2 * num2; int count = EmotesManager.blacklistedEmoteIds.Count; num3 += 2 + 2 * count; FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(num3, (Allocator)2, -1); ((FastBufferWriter)(ref val)).WriteValue(ref TerminalPatcher.emoteStoreSeed, default(ForPrimitives)); short num4 = (short)Mathf.Min(num, 32767); ((FastBufferWriter)(ref val)).WriteValue(ref num4, default(ForPrimitives)); num4 = (short)num2; ((FastBufferWriter)(ref val)).WriteValue(ref num4, default(ForPrimitives)); for (int i = 0; i < num2; i++) { num4 = (short)list[i].emoteId; ((FastBufferWriter)(ref val)).WriteValue(ref num4, default(ForPrimitives)); } num4 = (short)count; ((FastBufferWriter)(ref val)).WriteValue(ref num4, default(ForPrimitives)); foreach (int blacklistedEmoteId in EmotesManager.blacklistedEmoteIds) { num4 = (short)blacklistedEmoteId; ((FastBufferWriter)(ref val)).WriteValue(ref num4, default(ForPrimitives)); } syncedClients.Add(clientId); NetworkManager.Singleton.CustomMessagingManager.SendNamedMessage("TooManyEmotes.OnRequestSyncClientRpc", clientId, val, (NetworkDelivery)3); } private static void OnRequestSyncClientRpc(ulong clientId, FastBufferReader reader) { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Unknown result type (might be due to invalid IL or missing references) if (!HelperTools.isClient || !ConfigSync.isSynced) { return; } SessionManager.ResetProgressLocal(); ((FastBufferReader)(ref reader)).ReadValue(ref TerminalPatcher.emoteStoreSeed, default(ForPrimitives)); short currentEmoteCredits = default(short); ((FastBufferReader)(ref reader)).ReadValue(ref currentEmoteCredits, default(ForPrimitives)); short num = default(short); ((FastBufferReader)(ref reader)).ReadValue(ref num, default(ForPrimitives)); TerminalPatcher.currentEmoteCredits = currentEmoteCredits; if (num <= 0) { if (num < 0) { SessionManager.ResetEmotesLocal(); } } else { if (!((FastBufferReader)(ref reader)).TryBeginRead(2 * num)) { CustomLogging.LogError("Error receiving emotes sync from server."); OnSynced(); return; } short emoteId = default(short); for (int i = 0; i < num; i++) { ((FastBufferReader)(ref reader)).ReadValue(ref emoteId, default(ForPrimitives)); SessionManager.UnlockEmoteLocal(emoteId); } } EmotesManager.blacklistedEmoteIds = new HashSet(); short num2 = default(short); ((FastBufferReader)(ref reader)).ReadValue(ref num2, default(ForPrimitives)); if (num2 > 0 && ((FastBufferReader)(ref reader)).TryBeginRead(2 * num2)) { short item = default(short); for (int j = 0; j < num2; j++) { ((FastBufferReader)(ref reader)).ReadValue(ref item, default(ForPrimitives)); EmotesManager.blacklistedEmoteIds.Add(item); } } CustomLogging.Log("Received sync from server. CurrentEmoteCredits: " + TerminalPatcher.currentEmoteCredits + " EmoteStoreSeed: " + TerminalPatcher.emoteStoreSeed + " NumEmotes: " + num); OnSynced(); } internal static void OnSynced() { isSynced = true; requestedSync = true; if (ConfigSync.instance.syncPersistentUnlocksGlobal) { SessionManager.ResetEmotesLocal(); } SaveManager.LoadLocalPlayerValues(); ((MonoBehaviour)StartOfRound.Instance).StartCoroutine(OnSyncedEndOfFrame()); } [IteratorStateMachine(typeof(d__11))] private static IEnumerator OnSyncedEndOfFrame() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__11(0); } public static void SendOnUnlockEmoteUpdate(int emoteId, int newEmoteCredits = -1) { //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0060: 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_007e: Unknown result type (might be due to invalid IL or missing references) FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(6, (Allocator)2, -1); CustomLogging.Log("Sending unlocked emote update to server. Emote id: " + emoteId); short num = (short)Mathf.Min(newEmoteCredits, 32767); ((FastBufferWriter)(ref val)).WriteValue(ref num, default(ForPrimitives)); num = 1; ((FastBufferWriter)(ref val)).WriteValue(ref num, default(ForPrimitives)); num = (short)emoteId; ((FastBufferWriter)(ref val)).WriteValue(ref num, default(ForPrimitives)); NetworkManager.Singleton.CustomMessagingManager.SendNamedMessage("TooManyEmotes.OnUnlockEmoteServerRpc", 0uL, val, (NetworkDelivery)3); } public static void SendOnUnlockEmoteUpdateMulti(int newEmoteCredits = -1) { //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0055: 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_0088: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(4 + 2 * SessionManager.unlockedEmotes.Count, (Allocator)2, -1); CustomLogging.Log("Sending all unlocked emotes update to server."); short num = (short)Mathf.Min(newEmoteCredits, 32767); ((FastBufferWriter)(ref val)).WriteValue(ref num, default(ForPrimitives)); num = (short)SessionManager.unlockedEmotes.Count; ((FastBufferWriter)(ref val)).WriteValue(ref num, default(ForPrimitives)); foreach (UnlockableEmote unlockedEmote in SessionManager.unlockedEmotes) { num = (short)unlockedEmote.emoteId; ((FastBufferWriter)(ref val)).WriteValue(ref num, default(ForPrimitives)); } NetworkManager.Singleton.CustomMessagingManager.SendNamedMessage("TooManyEmotes.OnUnlockEmoteServerRpc", 0uL, val, (NetworkDelivery)3); } private static void OnUnlockEmoteServerRpc(ulong clientId, FastBufferReader reader) { //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_0148: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_0176: 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_018e: Unknown result type (might be due to invalid IL or missing references) //IL_0194: Unknown result type (might be due to invalid IL or missing references) //IL_01f6: Unknown result type (might be due to invalid IL or missing references) if (!HelperTools.isServer) { return; } if (ConfigSync.instance.syncUnlockEverything) { CustomLogging.LogWarning("Received unlocked emote update from client when UnlockEverything is enabled. This will be ignored."); } short num = default(short); ((FastBufferReader)(ref reader)).ReadValue(ref num, default(ForPrimitives)); short num2 = default(short); ((FastBufferReader)(ref reader)).ReadValue(ref num2, default(ForPrimitives)); if (!HelperTools.TryGetPlayerByClientId(clientId, out var playerController) && !ConfigSync.instance.syncShareEverything) { CustomLogging.LogError("Failed to receive unlocked emote update from client. Could not find player with client id: " + clientId); return; } if (num != -1) { if (!ConfigSync.instance.syncShareEverything && clientId != 0) { TerminalPatcher.currentEmoteCreditsByPlayer[playerController.playerUsername] = num; } else { TerminalPatcher.currentEmoteCredits = num; } } CustomLogging.Log("Receiving unlocked emote update from client for " + num2 + " emotes."); FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(8 + 2 * num2, (Allocator)2, -1); uint num3 = (uint)clientId; ((FastBufferWriter)(ref val)).WriteValue(ref num3, default(ForPrimitives)); short num4 = (short)Mathf.Min(TerminalPatcher.currentEmoteCredits, 32767); ((FastBufferWriter)(ref val)).WriteValue(ref num4, default(ForPrimitives)); num4 = num2; ((FastBufferWriter)(ref val)).WriteValue(ref num4, default(ForPrimitives)); if (((FastBufferReader)(ref reader)).TryBeginRead(2 * num2)) { short num5 = default(short); for (int i = 0; i < num2; i++) { ((FastBufferReader)(ref reader)).ReadValue(ref num5, default(ForPrimitives)); num4 = num5; ((FastBufferWriter)(ref val)).WriteValue(ref num4, default(ForPrimitives)); if (!ConfigSync.instance.syncShareEverything && clientId != 0) { SessionManager.UnlockEmoteLocal(num5, purchased: true, playerController.playerUsername); } else { SessionManager.UnlockEmoteLocal(num5, purchased: true); } } NetworkManager.Singleton.CustomMessagingManager.SendNamedMessageToAll("TooManyEmotes.OnUnlockEmoteClientRpc", val, (NetworkDelivery)3); } else { CustomLogging.LogError("Failed to receive unlocked emote updates from client. Expected updates: " + num2); } } private static void OnUnlockEmoteClientRpc(ulong clientId, FastBufferReader reader) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: 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) if (!HelperTools.isClient || HelperTools.isServer) { return; } uint num = default(uint); ((FastBufferReader)(ref reader)).ReadValue(ref num, default(ForPrimitives)); short num2 = default(short); ((FastBufferReader)(ref reader)).ReadValue(ref num2, default(ForPrimitives)); short num3 = default(short); ((FastBufferReader)(ref reader)).ReadValue(ref num3, default(ForPrimitives)); if (!HelperTools.TryGetPlayerByClientId(num, out var playerController) && !ConfigSync.instance.syncShareEverything) { return; } if (num2 != -1) { if (!ConfigSync.instance.syncShareEverything) { TerminalPatcher.currentEmoteCreditsByPlayer[playerController.playerUsername] = num2; } else { TerminalPatcher.currentEmoteCredits = num2; } } if (((FastBufferReader)(ref reader)).TryBeginRead(2 * num3)) { short emoteId = default(short); for (int i = 0; i < num3; i++) { ((FastBufferReader)(ref reader)).ReadValue(ref emoteId, default(ForPrimitives)); CustomLogging.Log("Receiving unlocked emote update from server. Emote id: " + emoteId); if (ConfigSync.instance.syncShareEverything) { SessionManager.UnlockEmoteLocal(emoteId, purchased: true); } else { SessionManager.UnlockEmoteLocal(emoteId, purchased: true, playerController.playerUsername); } } } else { CustomLogging.LogError("Failed to receive unlocked emote updates from client. Expected updates: " + num3); } } public static void RotateEmoteSelectionServer(int overrideSeed = 0) { //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) if (HelperTools.isServer) { TerminalPatcher.emoteStoreSeed = ((overrideSeed == 0) ? Random.Range(0, 1000000000) : overrideSeed); TerminalPatcher.RotateNewEmoteSelection(); FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(4, (Allocator)2, -1); ((FastBufferWriter)(ref val)).WriteValue(ref TerminalPatcher.emoteStoreSeed, default(ForPrimitives)); NetworkManager.Singleton.CustomMessagingManager.SendNamedMessageToAll("TooManyEmotes.OnRotateEmotesClientRpc", val, (NetworkDelivery)3); } } private static void RotateEmoteSelectionClientRpc(ulong clientId, FastBufferReader reader) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) if (HelperTools.isClient && !HelperTools.isServer) { ((FastBufferReader)(ref reader)).ReadValue(ref TerminalPatcher.emoteStoreSeed, default(ForPrimitives)); TerminalPatcher.RotateNewEmoteSelection(); } } } } namespace TooManyEmotes.Compatibility { [HarmonyPatch] internal static class HelmetCameras_Compat { [CompilerGenerated] private sealed class d__3 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; private Camera 5__1; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__3(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { 5__1 = null; <>1__state = -2; } private bool MoveNext() { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = (object)new WaitForSeconds(6f); <>1__state = 1; return true; case 1: { <>1__state = -1; GameObject obj = GameObject.Find("HelmetCamera"); 5__1 = ((obj != null) ? obj.GetComponent() : null); if (Object.op_Implicit((Object)(object)5__1)) { Camera obj2 = 5__1; obj2.cullingMask |= 0x800000; Camera obj3 = 5__1; obj3.cullingMask &= -33; } return false; } } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } public static bool Enabled => Chainloader.PluginInfos.ContainsKey("RickArg.lethalcompany.helmetcameras"); [HarmonyPatch(typeof(StartOfRound), "Start")] [HarmonyPrefix] private static void ApplyPatch(StartOfRound __instance) { if (Enabled) { ((MonoBehaviour)__instance).StartCoroutine(ApplyPatchDelayed()); } } [IteratorStateMachine(typeof(d__3))] private static IEnumerator ApplyPatchDelayed() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__3(0); } } [HarmonyPatch] internal static class AdvancedCompany_Compat { private static PlayerControllerB localPlayerController; private static List acCosmetics = new List(); internal static bool Enabled => Chainloader.PluginInfos.ContainsKey("com.potatoepet.AdvancedCompany"); [MethodImpl(MethodImplOptions.NoInlining)] internal static void ShowLocalCosmetics() { try { if ((Object)(object)localPlayerController != (Object)(object)StartOfRound.Instance.localPlayerController) { localPlayerController = StartOfRound.Instance.localPlayerController; acCosmetics.Clear(); CosmeticInstance[] componentsInChildren = ((Component)localPlayerController).GetComponentsInChildren(); CosmeticInstance[] array = componentsInChildren; foreach (CosmeticInstance val in array) { acCosmetics.Add(((Component)val).gameObject); } } foreach (GameObject acCosmetic in acCosmetics) { SetAllChildrenLayer(acCosmetic.transform, 0); acCosmetic.SetActive(true); } } catch { } } [MethodImpl(MethodImplOptions.NoInlining)] internal static void HideLocalCosmetics() { try { if ((Object)(object)localPlayerController != (Object)(object)StartOfRound.Instance.localPlayerController) { return; } foreach (GameObject acCosmetic in acCosmetics) { SetAllChildrenLayer(acCosmetic.transform, 23); } } catch { } } private static void SetAllChildrenLayer(Transform transform, int layer) { //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Expected O, but got Unknown try { ((Component)transform).gameObject.layer = layer; Light[] components = ((Component)transform).gameObject.GetComponents(); foreach (Light val in components) { val.cullingMask = 1 << layer; } foreach (Transform item in transform) { Transform transform2 = item; SetAllChildrenLayer(transform2, layer); } } catch { } } } [HarmonyPatch] internal static class LethalVRM_Compat { internal static bool Enabled => Plugin.IsModLoaded("Ooseykins.LethalVRM") || Plugin.IsModLoaded("OomJan.BetterLethalVRM"); internal static void DisplayVRMModel() { Camera emoteCamera = ThirdPersonEmoteController.emoteCamera; emoteCamera.cullingMask |= 0x800000; } internal static void HideVRMModel() { Camera emoteCamera = ThirdPersonEmoteController.emoteCamera; emoteCamera.cullingMask &= -8388609; } } [HarmonyPatch] internal static class TooManyEmotesScrap_Compat { internal static bool Enabled => Plugin.IsModLoaded("FlipMods.TooManyEmotesScrap"); [HarmonyPatch(typeof(StartOfRound), "LoadShipGrabbableItems")] [HarmonyPrefix] private static void FixGhostEmotePropsIfModDisabled(StartOfRound __instance) { if (Enabled || !ES3.KeyExists("shipGrabbableItemIDs", HelperTools.currentSaveFileName)) { return; } try { if (!ES3.KeyExists("TooManyEmotes.GrabbablePropIndexes", HelperTools.currentSaveFileName)) { return; } } catch (Exception ex) { CustomLogging.LogErrorVerbose("Failed to load existing TooManyEmotesScrap.GrabbablePropIndexes from file: " + HelperTools.currentSaveFileName + ". Deleting key."); CustomLogging.LogErrorVerbose(ex.ToString()); ES3.DeleteKey("TooManyEmotes.GrabbablePropIndexes", HelperTools.currentSaveFileName); return; } int[] array = null; int[] array2 = null; int num = 0; int num2 = 0; try { array = ES3.Load("shipGrabbableItemIDs", HelperTools.currentSaveFileName); array2 = ES3.Load("TooManyEmotes.GrabbablePropIndexes", HelperTools.currentSaveFileName); num = ES3.Load("TooManyEmotes.StartGrabbablePropItemId", HelperTools.currentSaveFileName); num2 = ES3.Load("TooManyEmotes.NumGrabbableProps", HelperTools.currentSaveFileName); } catch (Exception ex2) { CustomLogging.LogErrorVerbose("Failed to load existing TooManyEmotesScrap data from file: " + HelperTools.currentSaveFileName + ". Deleting keys."); CustomLogging.LogErrorVerbose(ex2.ToString()); ES3.DeleteKey("TooManyEmotes.GrabbablePropIndexes", HelperTools.currentSaveFileName); ES3.DeleteKey("TooManyEmotes.StartGrabbablePropItemId", HelperTools.currentSaveFileName); ES3.DeleteKey("TooManyEmotes.NumGrabbableProps", HelperTools.currentSaveFileName); return; } CustomLogging.LogWarningVerbose("Fixing TooManyEmotes ghost emote props. NumProps: " + array2.Length + " StartId: " + num + " NumPropsVar: " + num2 + " ItemListSize: " + HelperTools.allItems.Count); int num3 = 0; int[] array3 = array2; foreach (int num4 in array3) { if (num4 >= 0 && num4 < array.Length) { int num5 = array[num4]; if (num5 < Mathf.Max(num, 0) || num5 >= Mathf.Min(num + num2, HelperTools.allItems.Count)) { num3++; array[num4] = 19; } } } if (num3 > 0) { ES3.Save("shipGrabbableItemIDs", array, HelperTools.currentSaveFileName); CustomLogging.LogWarningVerbose("Removed " + num3 + " ghost emote props."); } ES3.DeleteKey("TooManyEmotes.GrabbablePropIndexes", HelperTools.currentSaveFileName); ES3.DeleteKey("TooManyEmotes.StartGrabbablePropItemId", HelperTools.currentSaveFileName); ES3.DeleteKey("TooManyEmotes.NumGrabbableProps", HelperTools.currentSaveFileName); } } public static class TooManyEmotesCompat { public static bool IsEnabled => Chainloader.PluginInfos.ContainsKey("FlipMods.TooManyEmotes"); public static bool IsPlayerEmoting(PlayerControllerB playerController) { EmoteControllerPlayer value; return EmoteControllerPlayer.allPlayerEmoteControllers.TryGetValue(playerController, out value) && value.IsPerformingCustomEmote(); } } [HarmonyPatch] internal static class LCVR_Compat { internal static bool Loaded => Plugin.IsModLoaded("io.daxcess.lcvr"); internal static bool VRModeEnabled => VRSession.InVR; public static bool LoadedAndEnabled => Loaded && VRModeEnabled; } [HarmonyPatch] internal static class MoreCompany_Compat { internal static bool Enabled => Chainloader.PluginInfos.ContainsKey("me.swipez.melonloader.morecompany"); [MethodImpl(MethodImplOptions.NoInlining)] internal static void ShowLocalCosmetics(Transform playerRoot = null) { //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Unknown result type (might be due to invalid IL or missing references) try { if (CosmeticRegistry.locallySelectedCosmetics.Count <= 0) { return; } Transform val = (((Object)(object)playerRoot != (Object)null) ? playerRoot : ((Component)StartOfRound.Instance.localPlayerController).transform); CosmeticApplication val2 = ((val != null) ? ((Component)val).GetComponentInChildren() : null); if (Object.op_Implicit((Object)(object)val2) && val2.spawnedCosmetics.Count != 0) { foreach (CosmeticInstance spawnedCosmetic in val2.spawnedCosmetics) { SetAllChildrenLayer(((Component)spawnedCosmetic).transform, 0); ((Component)spawnedCosmetic).gameObject.SetActive(true); } return; } if (!Object.op_Implicit((Object)(object)val2)) { val2 = ((Component)val).gameObject.AddComponent(); } foreach (string locallySelectedCosmetic in CosmeticRegistry.locallySelectedCosmetics) { val2.ApplyCosmetic(locallySelectedCosmetic, true); } foreach (CosmeticInstance spawnedCosmetic2 in val2.spawnedCosmetics) { Transform transform = ((Component)spawnedCosmetic2).transform; transform.localScale *= 0.38f; } } catch { } } [MethodImpl(MethodImplOptions.NoInlining)] internal static void HideLocalCosmetics() { try { Transform transform = ((Component)StartOfRound.Instance.localPlayerController).transform; CosmeticApplication val = ((transform != null) ? ((Component)transform).GetComponentInChildren() : null); if (!Object.op_Implicit((Object)(object)val) || val.spawnedCosmetics.Count == 0) { return; } foreach (CosmeticInstance spawnedCosmetic in val.spawnedCosmetics) { SetAllChildrenLayer(((Component)spawnedCosmetic).transform, 23); } } catch { } } private static void SetAllChildrenLayer(Transform transform, int layer) { //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Expected O, but got Unknown try { ((Component)transform).gameObject.layer = layer; Light[] components = ((Component)transform).gameObject.GetComponents(); foreach (Light val in components) { val.cullingMask = 1 << layer; } foreach (Transform item in transform) { Transform transform2 = item; SetAllChildrenLayer(transform2, layer); } } catch { } } } public static class InputUtils_Compat { internal static InputActionAsset Asset => IngameKeybinds.GetAsset(); internal static bool Enabled => Plugin.IsModLoaded("com.rune580.LethalCompanyInputUtils"); public static InputAction OpenEmoteMenuHotkey => IngameKeybinds.Instance.OpenEmoteMenuHotkey; public static InputAction RotateCharacterEmoteHotkey => IngameKeybinds.Instance.RotateCharacterEmoteHotkey; public static InputAction ZoomInEmoteHotkey => IngameKeybinds.Instance.ZoomInEmoteHotkey; public static InputAction ZoomOutEmoteHotkey => IngameKeybinds.Instance.ZoomOutEmoteHotkey; public static InputAction FavoriteEmoteHotkey => IngameKeybinds.Instance.FavoriteEmoteHotkey; public static InputAction PrevEmotePageHotkey => IngameKeybinds.Instance.PrevEmotePageHotkey; public static InputAction NextEmotePageHotkey => IngameKeybinds.Instance.NextEmotePageHotkey; public static InputAction NextEmoteLoadoutUpHotkey => IngameKeybinds.Instance.NextEmoteLoadoutUpHotkey; public static InputAction NextEmoteLoadoutDownHotkey => IngameKeybinds.Instance.NextEmoteLoadoutDownHotkey; public static InputAction PerformNextInstrumentHotkey => IngameKeybinds.Instance.PerformNextInstrumentHotkey; public static InputAction PerformRandomEmoteHotkey => IngameKeybinds.Instance.PerformRandomEmoteHotkey; public static InputAction QuickEmote1 => IngameKeybinds.Instance.QuickEmoteHotkey1; public static InputAction QuickEmote2 => IngameKeybinds.Instance.QuickEmoteHotkey2; public static InputAction QuickEmote3 => IngameKeybinds.Instance.QuickEmoteHotkey3; public static InputAction QuickEmote4 => IngameKeybinds.Instance.QuickEmoteHotkey4; public static InputAction QuickEmote5 => IngameKeybinds.Instance.QuickEmoteHotkey5; public static InputAction QuickEmote6 => IngameKeybinds.Instance.QuickEmoteHotkey6; public static InputAction QuickEmote7 => IngameKeybinds.Instance.QuickEmoteHotkey7; public static InputAction QuickEmote8 => IngameKeybinds.Instance.QuickEmoteHotkey8; } } namespace TooManyEmotes.Audio { [HarmonyPatch] public static class AudioManager { public static AssetBundle audioAssetBundle; public static AssetBundle dmcaAudioAssetBundle; private static HashSet loadedAudioClips = new HashSet(); private static HashSet loadedAudioClipsDmca = new HashSet(); private static HashSet loadedAudioClipsDmcaFree = new HashSet(); private static Dictionary audioClipsDictDmcaFree = new Dictionary(); private static Dictionary audioClipsDictDmca = new Dictionary(); public static bool muteEmoteAudio = false; public static bool emoteOnlyMode = false; public static bool dmcaFreeMode = false; public static float emoteVolumeMultiplier = 1f; public static bool AudioExists(string audioName) { return (audioClipsDictDmcaFree != null && audioClipsDictDmcaFree.ContainsKey(audioName)) || (audioClipsDictDmca != null && audioClipsDictDmca.ContainsKey(audioName)); } [HarmonyPatch(typeof(StartOfRound), "Awake")] [HarmonyPostfix] public static void Init() { LoadPreferences(); } public static void SavePreferences() { CustomLogging.Log("Saving AudioManager preferences."); ES3.Save("TooManyEmotes.EmoteAudioVolume", emoteVolumeMultiplier, SaveManager.TooManyEmotesSaveFileName); ES3.Save("TooManyEmotes.MuteEmoteAudio", muteEmoteAudio, SaveManager.TooManyEmotesSaveFileName); ES3.Save("TooManyEmotes.EmoteOnlyMode", emoteOnlyMode, SaveManager.TooManyEmotesSaveFileName); ES3.Save("TooManyEmotes.DmcaFreeMode", dmcaFreeMode, SaveManager.TooManyEmotesSaveFileName); } public static void LoadPreferences() { CustomLogging.Log("Loading AudioManager preferences."); try { if (ES3.KeyExists("TooManyEmotes.EmoteAudioVolume")) { ES3.DeleteKey("TooManyEmotes.EmoteAudioVolume"); } if (ES3.KeyExists("TooManyEmotes.MuteEmoteAudio")) { ES3.DeleteKey("TooManyEmotes.MuteEmoteAudio"); } if (ES3.KeyExists("TooManyEmotes.EmoteOnlyMode")) { ES3.DeleteKey("TooManyEmotes.EmoteOnlyMode"); } if (ES3.KeyExists("TooManyEmotes.DmcaFreeMode")) { ES3.DeleteKey("TooManyEmotes.DmcaFreeMode"); } } catch { try { ES3.DeleteKey("TooManyEmotes.EmoteAudioVolume"); ES3.DeleteKey("TooManyEmotes.MuteEmoteAudio"); ES3.DeleteKey("TooManyEmotes.EmoteOnlyMode"); ES3.DeleteKey("TooManyEmotes.DmcaFreeMode"); } catch { } } try { emoteVolumeMultiplier = ES3.Load("TooManyEmotes.EmoteAudioVolume", SaveManager.TooManyEmotesSaveFileName, 1f); muteEmoteAudio = ES3.Load("TooManyEmotes.MuteEmoteAudio", SaveManager.TooManyEmotesSaveFileName, false); emoteOnlyMode = ES3.Load("TooManyEmotes.EmoteOnlyMode", SaveManager.TooManyEmotesSaveFileName, false); dmcaFreeMode = ES3.Load("TooManyEmotes.DmcaFreeMode", SaveManager.TooManyEmotesSaveFileName, dmcaFreeMode); } catch (Exception ex) { CustomLogging.LogErrorVerbose("Failed to load audio preferences. Preferences will be reset.\n" + ex); emoteVolumeMultiplier = 1f; muteEmoteAudio = false; emoteOnlyMode = false; dmcaFreeMode = false; try { ES3.DeleteKey("TooManyEmotes.EmoteAudioVolume", SaveManager.TooManyEmotesSaveFileName); ES3.DeleteKey("TooManyEmotes.MuteEmoteAudio", SaveManager.TooManyEmotesSaveFileName); ES3.DeleteKey("TooManyEmotes.EmoteOnlyMode", SaveManager.TooManyEmotesSaveFileName); ES3.DeleteKey("TooManyEmotes.DmcaFreeMode", SaveManager.TooManyEmotesSaveFileName); } catch { CustomLogging.LogErrorVerbose("Failed to reset audio preferences. I recommend deleting this file: \"" + SaveManager.TooManyEmotesSaveFileName + "\" located at this path: \"C:\\Users\\YOUR_USER\\AppData\\LocalLow\\ZeekerssRBLX\\Lethal Company\""); } } } public static void BuildAudioClipList() { LoadAllAudioClips(); } public static void LoadAudioAssets() { try { string text = Path.Combine(Path.GetDirectoryName(((BaseUnityPlugin)Plugin.instance).Info.Location), "Assets/compressed_audio"); audioAssetBundle = AssetBundle.LoadFromFile(text); } catch { CustomLogging.LogWarning("Failed to load emotes audio asset bundle: compressed_audio."); } try { string text2 = Path.Combine(Path.GetDirectoryName(((BaseUnityPlugin)Plugin.instance).Info.Location), "Assets/compressed_audio_dmca"); dmcaAudioAssetBundle = AssetBundle.LoadFromFile(text2); } catch { CustomLogging.LogWarning("Failed to load emotes audio asset bundle: compressed_audio_dmca."); } } public static void LoadAllAudioClips() { if ((Object)(object)audioAssetBundle == (Object)null) { CustomLogging.LogError("Cannot load audio clips with a null Asset Bundle. Did the Asset Bundle fail to load?"); } else { try { loadedAudioClipsDmcaFree = new HashSet(audioAssetBundle.LoadAllAssets()); loadedAudioClips.UnionWith(loadedAudioClipsDmcaFree); CustomLogging.Log("Loading " + loadedAudioClipsDmcaFree.Count + " dmca-free audio clips."); foreach (AudioClip item in loadedAudioClipsDmcaFree) { if (!audioClipsDictDmcaFree.ContainsKey(((Object)item).name)) { audioClipsDictDmcaFree[((Object)item).name] = item; } } } catch { CustomLogging.LogError("Failed to load dmca-free emote audio clips from asset bundle."); } } if ((Object)(object)dmcaAudioAssetBundle == (Object)null) { CustomLogging.LogError("Cannot load dmca audio clips with a null Asset Bundle. Did the Asset Bundle fail to load?"); return; } try { loadedAudioClipsDmca = new HashSet(dmcaAudioAssetBundle.LoadAllAssets()); loadedAudioClips.UnionWith(loadedAudioClipsDmca); CustomLogging.Log("Loading " + loadedAudioClipsDmca.Count + " dmca audio clips."); foreach (AudioClip item2 in loadedAudioClipsDmca) { if (!audioClipsDictDmca.ContainsKey(((Object)item2).name)) { audioClipsDictDmca[((Object)item2).name] = item2; } } } catch { CustomLogging.LogError("Failed to load dmca emote audio clips from asset bundle."); } } public static AudioClip LoadAudioClip(string clipName) { if ((Object)(object)audioAssetBundle == (Object)null) { CustomLogging.LogError("Cannot load audio clip: " + clipName + " with a null Asset Bundle. Did the Asset Bundle fail to load?"); return null; } if (!dmcaFreeMode) { if (audioClipsDictDmca.TryGetValue(clipName, out var value)) { return value; } value = dmcaAudioAssetBundle.LoadAsset(clipName); if ((Object)(object)value != (Object)null) { loadedAudioClips.Add(value); loadedAudioClipsDmca.Add(value); audioClipsDictDmca.Add(clipName, value); return value; } } if (audioClipsDictDmcaFree.TryGetValue(clipName, out var value2)) { return value2; } value2 = audioAssetBundle.LoadAsset(clipName); if ((Object)(object)value2 != (Object)null) { loadedAudioClips.Add(value2); loadedAudioClipsDmcaFree.Add(value2); audioClipsDictDmcaFree.Add(clipName, value2); return value2; } return null; } public static bool IsClipDMCA(AudioClip audioClip) { return loadedAudioClipsDmca.Contains(audioClip); } public static void ClearAudioClipCache() { loadedAudioClips?.Clear(); audioClipsDictDmca?.Clear(); audioClipsDictDmcaFree?.Clear(); if (EmotesManager.allUnlockableEmotes != null) { try { } catch { } } } } public static class EmoteAudioPlayerManager { public static List allEmoteAudioPlayers = new List(); private static EmoteAudioPlayer shipSpeakerAudioPlayer = null; public static float requiredEmoteRange = 10f; public static float maxEmoteRange = 20f; [HarmonyPatch(typeof(BoomboxItem), "Start")] [HarmonyPrefix] public static void AttachCustomScript(BoomboxItem __instance) { allEmoteAudioPlayers.Add(((Component)__instance).gameObject.AddComponent()); } [HarmonyPatch(typeof(StartOfRound), "Start")] [HarmonyPrefix] public static void AttachCustomScript(StartOfRound __instance) { if (ConfigSync.isSynced && (Object)(object)shipSpeakerAudioPlayer == (Object)null && !ConfigSync.instance.syncDisableAudioShipSpeaker) { InitializeShipSpeakerAudioPlayer(); } } public static void InitializeShipSpeakerAudioPlayer() { shipSpeakerAudioPlayer = ((Component)StartOfRound.Instance.speakerAudioSource).gameObject.AddComponent(); allEmoteAudioPlayers.Add(shipSpeakerAudioPlayer); } public static EmoteAudioPlayer GetNearestEmoteAudioPlayer(Transform transform, bool onlyAvailableEmoteAudioPlayers = false) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) float num = requiredEmoteRange; EmoteAudioPlayer result = null; foreach (EmoteAudioPlayer allEmoteAudioPlayer in allEmoteAudioPlayers) { float num2 = Vector3.Distance(transform.position, ((Component)allEmoteAudioPlayer).transform.position); if (num2 < num && (!onlyAvailableEmoteAudioPlayers || allEmoteAudioPlayer.CanPlayMusic())) { num = num2; result = allEmoteAudioPlayer; } } return result; } } public class EmoteAudioSource : MonoBehaviour { public static HashSet allEmoteAudioSources = new HashSet(); public static HashSet playingAudioSources = new HashSet(); public AudioSource audioSource; public AudioSource audioLoopSource; private float playAudioLoopSourceAtTime = 0f; public EmoteSyncGroup currentEmoteSyncGroup; public bool isPlayingAudio { get { return playingAudioSources.Contains(this); } set { if (value) { playingAudioSources.Add(this); } else { playingAudioSources.Remove(this); } } } public UnlockableEmote currentEmote => currentEmoteSyncGroup?.performingEmote; protected virtual void Awake() { allEmoteAudioSources.Add(this); audioSource = ((Component)this).gameObject.AddComponent(); audioLoopSource = ((Component)this).gameObject.AddComponent(); ResetAudioSettings(); } protected virtual void ResetAudioSettings() { audioSource.volume = ConfigSettings.baseEmoteAudioVolume.Value; audioSource.dopplerLevel = 0f; audioSource.spatialBlend = 1f; audioSource.minDistance = ConfigSettings.emoteAudioMinDistance.Value; audioSource.maxDistance = ConfigSettings.emoteAudioMaxDistance.Value; audioSource.rolloffMode = (AudioRolloffMode)1; audioSource.loop = false; audioSource.playOnAwake = false; audioLoopSource.volume = ConfigSettings.baseEmoteAudioVolume.Value; audioLoopSource.dopplerLevel = 0f; audioLoopSource.spatialBlend = 1f; audioLoopSource.minDistance = ConfigSettings.emoteAudioMinDistance.Value; audioLoopSource.maxDistance = ConfigSettings.emoteAudioMaxDistance.Value; audioLoopSource.rolloffMode = (AudioRolloffMode)1; audioLoopSource.loop = true; audioLoopSource.playOnAwake = false; UpdateVolume(); } [HarmonyPatch(typeof(QuickMenuManager), "CloseQuickMenu")] [HarmonyPostfix] private static void OnCloseQuickMenu() { foreach (EmoteAudioSource allEmoteAudioSource in allEmoteAudioSources) { allEmoteAudioSource.ResetAudioSettings(); } } protected virtual void OnDestroy() { StopAudio(); allEmoteAudioSources.Remove(this); if (currentEmoteSyncGroup != null) { RemoveFromEmoteSyncGroup(); } } protected virtual void OnEnable() { } protected virtual void OnDisable() { StopAudio(); if (currentEmoteSyncGroup != null) { RemoveFromEmoteSyncGroup(); } } protected virtual void Update() { if (isPlayingAudio && CheckIfShouldStopAudio()) { StopAudio(); } } public virtual bool CanPlayMusic() { return !isPlayingAudio; } public virtual bool CheckIfShouldStopAudio() { return false; } public virtual bool SyncWithEmoteControllerAudio(EmoteController emoteController) { if ((Object)(object)emoteController == (Object)null || !emoteController.IsPerformingCustomEmote()) { return false; } isPlayingAudio = false; audioSource.Stop(); audioLoopSource.Stop(); audioSource.mute = false; audioLoopSource.mute = false; UnlockableEmote performingEmote = emoteController.performingEmote; if (SetAudioFromEmote(performingEmote)) { AnimationClip currentAnimationClip = emoteController.GetCurrentAnimationClip(); float currentAnimationTime = emoteController.currentAnimationTime; if ((Object)(object)currentAnimationClip == (Object)(object)performingEmote.transitionsToClip || ((Motion)currentAnimationClip).isLooping) { if ((Object)(object)audioLoopSource.clip != (Object)null) { audioLoopSource.time = currentAnimationTime; playAudioLoopSourceAtTime = Time.time - audioLoopSource.time; audioLoopSource.Play(); } } else { if ((Object)(object)audioSource.clip != (Object)null) { float num = 0f; if ((Object)(object)performingEmote.transitionsToClip != (Object)null) { num = currentAnimationClip.length - currentAnimationTime - audioSource.clip.length; } if (num > 0f) { audioSource.time = 0f; audioSource.PlayScheduled(AudioSettings.dspTime + (double)num); } else { audioSource.time = 0f - num; audioSource.Play(); } } if ((Object)(object)performingEmote.transitionsToClip != (Object)null) { audioLoopSource.time = 0f; float num2 = (((Object)(object)audioSource.clip != (Object)null) ? (currentAnimationClip.length - emoteController.currentAnimationTime) : (currentAnimationClip.length - emoteController.currentAnimationTime)); playAudioLoopSourceAtTime = Time.time + num2; audioLoopSource.PlayScheduled(AudioSettings.dspTime + (double)num2); } } isPlayingAudio = true; return true; } return false; } public virtual bool SyncWithEmoteSyncGroup(EmoteSyncGroup emoteSyncGroup, EmoteController playAudioFromEmoteController = null) { if (emoteSyncGroup == null || emoteSyncGroup.performingEmote == null || (Object)(object)emoteSyncGroup.leadEmoteController == (Object)null || !emoteSyncGroup.leadEmoteController.IsPerformingCustomEmote()) { return false; } EmoteController leadEmoteController = emoteSyncGroup.leadEmoteController; UnlockableEmote audioFromEmote = (((Object)(object)playAudioFromEmoteController != (Object)null) ? playAudioFromEmoteController.performingEmote : leadEmoteController.performingEmote); EmoteAudioSource leadEmoteAudioSource = emoteSyncGroup.leadEmoteAudioSource; if ((Object)(object)leadEmoteAudioSource != (Object)null) { bool isPlaying = leadEmoteAudioSource.audioSource.isPlaying; bool isPlaying2 = leadEmoteAudioSource.audioLoopSource.isPlaying; float time = leadEmoteAudioSource.audioSource.time; float time2 = leadEmoteAudioSource.audioLoopSource.time; isPlayingAudio = false; audioSource.Stop(); audioLoopSource.Stop(); audioSource.mute = false; audioLoopSource.mute = false; if (SetAudioFromEmote(audioFromEmote)) { audioSource.time = time; audioLoopSource.time = time2; if ((Object)(object)audioSource.clip != (Object)null && isPlaying) { audioSource.Play(); if ((Object)(object)audioLoopSource.clip != (Object)null && leadEmoteAudioSource.playAudioLoopSourceAtTime > Time.time) { playAudioLoopSourceAtTime = leadEmoteAudioSource.playAudioLoopSourceAtTime; audioLoopSource.PlayScheduled(AudioSettings.dspTime + (double)(audioSource.clip.length - audioSource.time)); } } else if ((Object)(object)audioLoopSource.clip != (Object)null && isPlaying2) { audioLoopSource.Play(); } isPlayingAudio = true; return true; } } return false; } public virtual bool SyncWithEmoteController(UnlockableEmote emote, EmoteController playAudioFromEmoteController) { if (emote == null || (Object)(object)playAudioFromEmoteController == (Object)null || !playAudioFromEmoteController.IsPerformingCustomEmote()) { return false; } isPlayingAudio = false; audioSource.Stop(); audioLoopSource.Stop(); audioSource.mute = false; audioLoopSource.mute = false; if (SetAudioFromEmote(emote)) { AnimationClip currentAnimationClip = playAudioFromEmoteController.GetCurrentAnimationClip(); float currentAnimationTime = playAudioFromEmoteController.currentAnimationTime; if ((Object)(object)currentAnimationClip == (Object)(object)emote.transitionsToClip || ((Motion)currentAnimationClip).isLooping) { if ((Object)(object)audioLoopSource.clip != (Object)null) { audioLoopSource.time = currentAnimationTime; playAudioLoopSourceAtTime = Time.time - audioLoopSource.time; audioLoopSource.Play(); } } else { if ((Object)(object)audioSource.clip != (Object)null) { float num = 0f; if ((Object)(object)emote.transitionsToClip != (Object)null) { num = currentAnimationClip.length - currentAnimationTime - audioSource.clip.length; } if (num > 0f) { audioSource.time = 0f; audioSource.PlayScheduled(AudioSettings.dspTime + (double)num); } else { audioSource.time = 0f - num; audioSource.Play(); } } if ((Object)(object)emote.transitionsToClip != (Object)null) { audioLoopSource.time = 0f; float num2 = (((Object)(object)audioSource.clip != (Object)null) ? (currentAnimationClip.length - playAudioFromEmoteController.currentAnimationTime) : (currentAnimationClip.length - playAudioFromEmoteController.currentAnimationTime)); playAudioLoopSourceAtTime = Time.time + num2; audioLoopSource.PlayScheduled(AudioSettings.dspTime + (double)num2); } } isPlayingAudio = true; return true; } return false; } public virtual void RefreshAudio() { if (currentEmoteSyncGroup != null && currentEmote != null) { SetAudioFromEmote(currentEmote); SyncWithEmoteControllerAudio(currentEmoteSyncGroup.leadEmoteController); } } protected virtual bool SetAudioFromEmote(UnlockableEmote emote) { audioSource.clip = null; audioSource.mute = AudioManager.muteEmoteAudio || (AudioManager.dmcaFreeMode && (Object)(object)audioSource.clip != (Object)null && AudioManager.IsClipDMCA(audioSource.clip)); audioSource.time = 0f; audioLoopSource.loop = false; audioLoopSource.clip = null; audioLoopSource.mute = audioSource.mute; audioLoopSource.time = 0f; audioLoopSource.loop = true; if (emote != null && emote.hasAudio) { AudioClip val = emote.LoadAudioClip(); AudioClip val2 = emote.LoadAudioLoopClip(); if ((Object)(object)val2 != (Object)null) { audioSource.clip = val; audioLoopSource.clip = val2; } else { if (!((Object)(object)val != (Object)null)) { return false; } if (((Motion)emote.animationClip).isLooping) { audioLoopSource.clip = val; } else { audioSource.clip = val; } } return true; } return false; } public virtual void StopAudio() { if ((Object)(object)audioSource != (Object)null) { audioSource.Stop(); audioSource.clip = null; } if ((Object)(object)audioLoopSource != (Object)null) { audioLoopSource.Stop(); audioLoopSource.clip = null; } isPlayingAudio = false; } public void UpdateVolume() { float emoteVolumeMultiplier = AudioManager.emoteVolumeMultiplier; float value = ConfigSettings.baseEmoteAudioVolume.Value; float num; if (currentEmoteSyncGroup?.syncGroup != null) { EmoteSyncGroup emoteSyncGroup = currentEmoteSyncGroup; if (emoteSyncGroup != null && emoteSyncGroup.syncGroup.Count > 0) { num = ConfigSettings.emoteAudioIncreasePerPlayerSyncing.Value * (float)(currentEmoteSyncGroup.syncGroup.Count - 1); goto IL_0065; } } num = 0f; goto IL_0065; IL_0065: float num2 = emoteVolumeMultiplier * (value + num); num2 = Mathf.Min(num2, ConfigSettings.emoteAudioMaxVolume.Value); if ((Object)(object)audioSource != (Object)null) { audioSource.volume = num2; } if ((Object)(object)audioLoopSource != (Object)null) { audioLoopSource.volume = num2; } audioSource.mute = AudioManager.muteEmoteAudio; audioLoopSource.mute = AudioManager.muteEmoteAudio; } public virtual void AddToEmoteSyncGroup(int emoteSyncId) { if (EmoteSyncGroup.allEmoteSyncGroups.TryGetValue(emoteSyncId, out var value)) { currentEmoteSyncGroup = value; } } public virtual void AddToEmoteSyncGroup(EmoteSyncGroup emoteSyncGroup) { currentEmoteSyncGroup = emoteSyncGroup; } public virtual void RemoveFromEmoteSyncGroup() { currentEmoteSyncGroup = null; } } public class EmoteAudioPlayer : EmoteAudioSource { public GrabbableObject grabbableAudioPlayer; public AudioSource[] existingAudioSources; public Dictionary previouslyMutedAudioSources = new Dictionary(); public int emoteSyncId => currentEmoteSyncGroup.syncId; protected override void Awake() { grabbableAudioPlayer = ((Component)this).GetComponent(); existingAudioSources = ((Component)this).GetComponentsInChildren(); AudioSource[] array = existingAudioSources; foreach (AudioSource val in array) { previouslyMutedAudioSources[val] = val.mute; } base.Awake(); } protected override void OnDestroy() { EmoteAudioPlayerManager.allEmoteAudioPlayers.Remove(this); base.OnDestroy(); } protected override void OnEnable() { base.OnEnable(); } protected override void OnDisable() { base.OnDisable(); } protected override void Update() { base.Update(); } public override bool CanPlayMusic() { if (!base.CanPlayMusic()) { return false; } if (grabbableAudioPlayer is BoomboxItem) { GrabbableObject obj = grabbableAudioPlayer; BoomboxItem val = (BoomboxItem)(object)((obj is BoomboxItem) ? obj : null); if (val.isPlayingMusic) { return false; } } return true; } public override bool CheckIfShouldStopAudio() { if (base.CheckIfShouldStopAudio()) { return true; } if ((Object)(object)grabbableAudioPlayer != (Object)null) { if (grabbableAudioPlayer is BoomboxItem) { GrabbableObject obj = grabbableAudioPlayer; BoomboxItem val = (BoomboxItem)(object)((obj is BoomboxItem) ? obj : null); if (val.isPlayingMusic) { return true; } } if (grabbableAudioPlayer.itemProperties.requiresBattery && grabbableAudioPlayer.insertedBattery != null && grabbableAudioPlayer.insertedBattery.empty) { return true; } } if ((Object)(object)GetNearestEmoteControllerWithinRange() == (Object)null) { return true; } return false; } public EmoteController GetNearestEmoteControllerWithinRange() { //IL_003f: 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) if (currentEmoteSyncGroup == null) { return null; } float num = EmoteAudioPlayerManager.maxEmoteRange; EmoteController result = null; foreach (EmoteController item in currentEmoteSyncGroup.syncGroup) { float num2 = Vector3.Distance(((Component)this).transform.position, ((Component)item).transform.position); if (num2 < num) { result = item; num = num2; } } return result; } public override bool SyncWithEmoteControllerAudio(EmoteController emoteController) { if (!base.isPlayingAudio) { AudioSource[] array = existingAudioSources; foreach (AudioSource val in array) { val.mute = previouslyMutedAudioSources[val]; } } bool flag = base.SyncWithEmoteControllerAudio(emoteController); if (flag && (Object)(object)grabbableAudioPlayer != (Object)null && grabbableAudioPlayer is BoomboxItem) { AudioSource[] array2 = existingAudioSources; foreach (AudioSource val2 in array2) { val2.mute = true; } } return flag; } protected override bool SetAudioFromEmote(UnlockableEmote emote) { return base.SetAudioFromEmote(emote); } public override void StopAudio() { base.StopAudio(); AudioSource[] array = existingAudioSources; foreach (AudioSource val in array) { val.mute = previouslyMutedAudioSources[val]; } } public override void AddToEmoteSyncGroup(int emoteSyncId) { base.AddToEmoteSyncGroup(emoteSyncId); } public override void AddToEmoteSyncGroup(EmoteSyncGroup emoteSyncGroup) { base.AddToEmoteSyncGroup(emoteSyncGroup); } public override void RemoveFromEmoteSyncGroup() { base.RemoveFromEmoteSyncGroup(); } } }