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<string>();
}
value2.propNamesInEmote.Add(propName);
if (value3.parentEmotes == null)
{
value3.parentEmotes = new List<UnlockableEmote>();
}
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<string>("QuickEmote" + index, SaveManager.TooManyEmotesSaveFileName, string.Empty);
UnlockableEmote value = null;
EmotesManager.allUnlockableEmotesDict.TryGetValue(key, out value);
return value;
}
}
public static class BoneMapper
{
public static Dictionary<Transform, Transform> CreateBoneMap(Transform sourceSkeleton, Transform targetSkeleton, List<string> sourceBoneNames, List<string> targetBoneNames = null)
{
if ((Object)(object)sourceSkeleton == (Object)null || (Object)(object)targetSkeleton == (Object)null || sourceBoneNames == null)
{
return null;
}
if (targetBoneNames == null)
{
targetBoneNames = sourceBoneNames;
}
if (sourceBoneNames.Count != targetBoneNames.Count)
{
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<Transform, Transform> dictionary = new Dictionary<Transform, Transform>();
for (int i = 0; i < count; i++)
{
if ((Object)(object)array[i] != (Object)null && !dictionary.ContainsKey(array[i]))
{
dictionary.Add(array[i], array2[i]);
}
}
return dictionary;
}
private static void FindBones(Transform bone, List<string> boneNames, Transform[] boneArray)
{
if ((Object)(object)((Component)bone).GetComponent<Rig>() != (Object)null || ((Object)bone).name == "ScavengerModelArmsOnly")
{
return;
}
if (boneNames.Contains(((Object)bone).name))
{
int num = boneNames.IndexOf(((Object)bone).name);
if (!((Object)(object)boneArray[num] != (Object)null))
{
boneArray[num] = bone;
}
}
for (int i = 0; i < bone.childCount; i++)
{
FindBones(bone.GetChild(i), boneNames, boneArray);
}
}
}
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<Animator>();
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<int, EmoteSyncGroup> allEmoteSyncGroups = new Dictionary<int, EmoteSyncGroup>();
public int syncId = -1;
public List<EmoteController> syncGroup;
public Dictionary<UnlockableEmote, EmoteController> leadEmoteControllerByEmote = new Dictionary<UnlockableEmote, EmoteController>();
public Dictionary<UnlockableEmote, EmoteAudioSource> 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> { emoteController };
syncId = currentEmoteSyncId++;
performingEmote = emoteController.performingEmote;
leadEmoteControllerByEmote.Add(performingEmote, emoteController);
this.useAudio = useAudio;
if (useAudio && performingEmote.hasAudio)
{
if (!performingEmote.isBoomboxAudio)
{
currentEmoteAudioSources = new Dictionary<UnlockableEmote, EmoteAudioSource>();
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<UnlockableEmote, EmoteController> 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<UnlockableEmote, EmoteAudioSource> 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<Item> 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<MaskedPlayerEnemy, EmoteControllerMaskedEnemy> allMaskedEnemyEmoteControllers = new Dictionary<MaskedPlayerEnemy, EmoteControllerMaskedEnemy>();
public MaskedPlayerEnemy maskedEnemy;
public int emoteCount = 0;
public bool stoppedAndStaring = false;
public bool behaviour1 = false;
public Vector3 emotedAtPosition;
public int id => (int)((NetworkBehaviour)maskedEnemy).NetworkObjectId;
public float stopAndStareTimer
{
get
{
return (float)Traverse.Create((object)maskedEnemy).Field("stopAndStareTimer").GetValue();
}
set
{
Traverse.Create((object)maskedEnemy).Field("stopAndStareTimer").SetValue((object)value);
}
}
public NavMeshAgent agent => ((EnemyAI)maskedEnemy).agent;
public PlayerControllerB lookingAtPlayer
{
get
{
Transform stareAtTransform = maskedEnemy.stareAtTransform;
return (stareAtTransform != null) ? ((Component)stareAtTransform).GetComponentInParent<PlayerControllerB>() : null;
}
}
public bool inKillAnimation => (bool)Traverse.Create((object)maskedEnemy).Field("inKillAnimation").GetValue();
public bool handsOut => (bool)Traverse.Create((object)maskedEnemy).Field("handsOut").GetValue();
public float localSpeed
{
get
{
//IL_001b: Unknown result type (might be due to invalid IL or missing references)
//IL_0020: Unknown result type (might be due to invalid IL or missing references)
Vector3 val = (Vector3)Traverse.Create((object)maskedEnemy).Field("agentLocalVelocity").GetValue();
return ((Vector3)(ref val)).magnitude;
}
}
public bool isMoving => animator.GetBool("IsMoving");
public override void Initialize(string sourceRootBoneName = "metarig")
{
base.Initialize();
if (initialized)
{
maskedEnemy = ((Component)this).GetComponentInParent<MaskedPlayerEnemy>();
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<PlayerControllerB, EmoteControllerPlayer> allPlayerEmoteControllers = new Dictionary<PlayerControllerB, EmoteControllerPlayer>();
public PlayerControllerB playerController;
public Animator originalAnimator;
private Dictionary<Transform, Transform> boneMapLocalPlayerArms;
internal Transform humanoidHead;
private Transform cameraContainerTarget;
private Transform cameraContainerLerp;
public static List<string> sourceBoneNames = new List<string>
{
"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<Animator>();
playerController = ((Component)this).GetComponentInParent<PlayerControllerB>();
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<Transform, Transform> 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<string> list = new List<string>
{
"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<GameObject, EmoteController> allEmoteControllers = new Dictionary<GameObject, EmoteController>();
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<Transform, Transform> boneMap;
public List<Transform> groundContactPoints = new List<Transform>();
public Transform propsParent;
public List<PropObject> emotingProps = new List<PropObject>();
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<GameObject>(Plugin.humanoidSkeletonPrefab, metarig.parent).transform;
((Object)humanoidSkeleton).name = "HumanoidSkeleton";
humanoidSkeleton.SetSiblingIndex(metarig.GetSiblingIndex() + 1);
animator = ((Component)humanoidSkeleton).GetComponent<Animator>();
OnAnimatorIKHandler onAnimatorIKHandler = ((Component)animator).gameObject.AddComponent<OnAnimatorIKHandler>();
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<EmoteAudioSource>();
}
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<Transform, Transform> 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<string> sourceBoneNames, List<string> 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<UnlockableEmote> allUnlockableEmotes;
public static Dictionary<string, UnlockableEmote> allUnlockableEmotesDict;
public static List<UnlockableEmote> complementaryEmotes;
internal static List<UnlockableEmote> complementaryEmotesDefault;
public static List<string> allFavoriteEmotes;
public static List<string> allQuickEmotes;
public static List<UnlockableEmote> allEmotesTier0;
public static List<UnlockableEmote> allEmotesTier1;
public static List<UnlockableEmote> allEmotesTier2;
public static List<UnlockableEmote> allEmotesTier3;
public static HashSet<int> blacklistedEmoteIds = new HashSet<int>();
internal static CultureInfo defaultSortCulture = CultureInfo.CreateSpecificCulture("en-US");
public static void BuildEmotesList()
{
allUnlockableEmotes = new List<UnlockableEmote>();
allUnlockableEmotesDict = new Dictionary<string, UnlockableEmote>();
complementaryEmotesDefault = new List<UnlockableEmote>();
allFavoriteEmotes = new List<string>();
allQuickEmotes = new List<string>(8);
while (allQuickEmotes.Count < allQuickEmotes.Capacity)
{
allQuickEmotes.Add("");
}
allEmotesTier0 = new List<UnlockableEmote>();
allEmotesTier1 = new List<UnlockableEmote>();
allEmotesTier2 = new List<UnlockableEmote>();
allEmotesTier3 = new List<UnlockableEmote>();
Dictionary<string, List<UnlockableEmote>> dictionary = new Dictionary<string, List<UnlockableEmote>>();
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<UnlockableEmote>();
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<UnlockableEmote>(complementaryEmotesDefault);
SaveManager.LoadFavoritedEmotes();
SaveManager.LoadQuickEmotes();
}
}
[HarmonyPatch]
public static class SessionManager
{
public static List<UnlockableEmote> unlockedEmotes = new List<UnlockableEmote>();
public static List<UnlockableEmote> unlockedEmotesTier0 = new List<UnlockableEmote>();
public static List<UnlockableEmote> unlockedEmotesTier1 = new List<UnlockableEmote>();
public static List<UnlockableEmote> unlockedEmotesTier2 = new List<UnlockableEmote>();
public static List<UnlockableEmote> unlockedEmotesTier3 = new List<UnlockableEmote>();
internal static List<UnlockableEmote> emotesUnlockedThisSession = new List<UnlockableEmote>();
public static Dictionary<string, List<UnlockableEmote>> unlockedEmotesByPlayer = new Dictionary<string, List<UnlockableEmote>>();
public static List<UnlockableEmote> unlockedFavoriteEmotes = new List<UnlockableEmote>();
public static 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<UnlockableEmote>(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<string> list = new List<string>(TerminalPatcher.currentEmoteCreditsByPlayer.Keys);
foreach (string item in list)
{
TerminalPatcher.currentEmoteCreditsByPlayer[item] = ConfigSync.instance.syncStartingEmoteCredits;
}
}
TerminalPatcher.emoteStoreSeed = 0;
}
[HarmonyPatch(typeof(StartOfRound), "SyncShipUnlockablesServerRpc")]
[HarmonyPostfix]
public static void SyncUnlockedEmotesWithClients(StartOfRound __instance)
{
if (!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<ulong> hashSet = new HashSet<ulong>();
PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts;
foreach (PlayerControllerB val in allPlayerScripts)
{
if (val.actualClientId != 0L && val.playerSteamId != 0)
{
hashSet.Add(val.actualClientId);
}
}
foreach (ulong item in hashSet)
{
SyncManager.ServerSendSyncToClient(item);
}
}
public static 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<UnlockableEmote> 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<UnlockableEmote> GetUnlockedEmotes(PlayerControllerB playerController)
{
return GetUnlockedEmotes(((Object)(object)playerController != (Object)null) ? playerController.playerUsername : "");
}
public static List<UnlockableEmote> GetUnlockedEmotes(string playerUsername)
{
if (unlockedEmotesByPlayer.TryGetValue(playerUsername, out var value))
{
return value;
}
return null;
}
public static void UnlockEmotesLocal(IEnumerable<UnlockableEmote> emotes, 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<UnlockableEmote> 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<UnlockableEmote> 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<UnlockableEmote>());
}
}
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<UnlockableEmote> emoteSyncGroup;
public float recordSongLoopValue = 0f;
public bool randomEmote = false;
public List<string> 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 => $"<color={nameColor}>{displayName}</color>";
public bool humanoidAnimation => ((Motion)animationClip).isHumanMotion;
public bool loopable => ((Motion)animationClip).isLooping || ((Object)(object)transitionsToClip != (Object)null && ((Motion)transitionsToClip).isLooping);
public 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<string> globallyUnlockedEmoteNames = new List<string>();
[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<string> hashSet;
try
{
hashSet = new HashSet<string>(ES3.Load<string[]>("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<string>();
}
foreach (string key in SessionManager.unlockedEmotesByPlayer.Keys)
{
hashSet.Add(key);
}
ES3.Save<string[]>("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<string[]>("TooManyEmotes.UnlockedEmotes", array, HelperTools.currentSaveFileName);
}
else
{
ES3.Save<string[]>("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<int>(text, TerminalPatcher.currentEmoteCredits, __instance.currentSaveFileName);
}
else
{
ES3.Save<int>(text + ".Player_" + item, TerminalPatcher.currentEmoteCreditsByPlayer[item], __instance.currentSaveFileName);
}
}
}
ES3.Save<int>("TooManyEmotes.EmoteStoreSeed", TerminalPatcher.emoteStoreSeed, __instance.currentSaveFileName);
CustomLogging.Log("Saved Seed: " + TerminalPatcher.emoteStoreSeed);
}
catch (Exception ex2)
{
CustomLoggin