Decompiled source of TooManyEmotesAddonFix v0.1.0

TooManyEmotesAddonFix.dll

Decompiled 8 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using TooManyEmotes;
using TooManyEmotes.Props;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("TooManyEmotesAddonFix")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Fixes TooManyEmotes addons: their emotes get a rarity tier and must be bought, and the base emotes they break work again.")]
[assembly: AssemblyFileVersion("0.1.0.0")]
[assembly: AssemblyInformationalVersion("0.1.0")]
[assembly: AssemblyProduct("TooManyEmotesAddonFix")]
[assembly: AssemblyTitle("TooManyEmotesAddonFix")]
[assembly: AssemblyVersion("0.1.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace TooManyEmotesAddonFix
{
	internal static class AddonTiers
	{
		private static readonly float[] tierFloors = new float[3] { 7f, 14f, 28f };

		private static readonly FieldRef<List<UnlockableEmote>> complementaryEmotesDefault = AccessTools.StaticFieldRefAccess<List<UnlockableEmote>>(AccessTools.Field(typeof(EmotesManager), "complementaryEmotesDefault"));

		internal static void Apply()
		{
			if (EmotesManager.allUnlockableEmotes == null || !BaseBundles.Found)
			{
				return;
			}
			int[] array = new int[4];
			foreach (UnlockableEmote allUnlockableEmote in EmotesManager.allUnlockableEmotes)
			{
				if (allUnlockableEmote.complementary && !((Object)(object)allUnlockableEmote.animationClip == (Object)null) && !BaseBundles.FreeClips.Contains(allUnlockableEmote.animationClip))
				{
					allUnlockableEmote.complementary = false;
					allUnlockableEmote.rarity = TierFor(allUnlockableEmote);
					allUnlockableEmote.displayName = OriginalCaseName(allUnlockableEmote);
					TierList(allUnlockableEmote.rarity).Add(allUnlockableEmote);
					complementaryEmotesDefault.Invoke()?.Remove(allUnlockableEmote);
					EmotesManager.complementaryEmotes?.Remove(allUnlockableEmote);
					array[allUnlockableEmote.rarity]++;
				}
			}
			int num = array[0] + array[1] + array[2] + array[3];
			if (num > 0)
			{
				Plugin.mlg.LogInfo((object)$"Tiered {num} addon emotes: {array[0]} Common, {array[1]} Rare, {array[2]} Epic, {array[3]} Legendary.");
			}
		}

		private static int TierFor(UnlockableEmote emote)
		{
			float num = emote.animationClip.length;
			if ((Object)(object)emote.transitionsToClip != (Object)null)
			{
				num += emote.transitionsToClip.length;
			}
			int i;
			for (i = 0; i < tierFloors.Length && num >= tierFloors[i]; i++)
			{
			}
			return i;
		}

		private static string OriginalCaseName(UnlockableEmote emote)
		{
			string text = ((emote.emoteSyncGroupName != "") ? emote.emoteSyncGroupName : emote.emoteName);
			text = text.Replace('_', ' ').Trim(' ');
			if (!(text != ""))
			{
				return emote.displayName;
			}
			return text;
		}

		private static List<UnlockableEmote> TierList(int rarity)
		{
			return rarity switch
			{
				1 => EmotesManager.allEmotesTier1, 
				2 => EmotesManager.allEmotesTier2, 
				3 => EmotesManager.allEmotesTier3, 
				_ => EmotesManager.allEmotesTier0, 
			};
		}
	}
	internal static class BaseBundles
	{
		private static readonly string[] emoteBundles = new string[6] { "emotes_0", "emotes_1", "emotes_2", "emotes_3", "emotes_complementary", "emotes_special" };

		private static readonly string[] freeBundles = new string[2] { "emotes_complementary", "emotes_special" };

		internal static List<(AnimationClip clip, string originalName)> Clips { get; private set; }

		internal static HashSet<AnimationClip> AllClips { get; private set; }

		internal static HashSet<AnimationClip> FreeClips { get; private set; }

		internal static bool Found => Clips != null;

		internal static void Find()
		{
			if (Found)
			{
				return;
			}
			List<(AnimationClip, string)> list = new List<(AnimationClip, string)>();
			HashSet<AnimationClip> hashSet = new HashSet<AnimationClip>();
			HashSet<AnimationClip> hashSet2 = new HashSet<AnimationClip>();
			int num = 0;
			foreach (AssetBundle allLoadedAssetBundle in AssetBundle.GetAllLoadedAssetBundles())
			{
				if (Array.IndexOf(emoteBundles, ((Object)allLoadedAssetBundle).name) < 0)
				{
					continue;
				}
				num++;
				bool flag = Array.IndexOf(freeBundles, ((Object)allLoadedAssetBundle).name) >= 0;
				string[] allAssetNames = allLoadedAssetBundle.GetAllAssetNames();
				foreach (string text in allAssetNames)
				{
					if (!text.EndsWith(".anim", StringComparison.OrdinalIgnoreCase))
					{
						continue;
					}
					AnimationClip val = allLoadedAssetBundle.LoadAsset<AnimationClip>(text);
					if (!((Object)(object)val == (Object)null))
					{
						list.Add((val, Path.GetFileNameWithoutExtension(text)));
						hashSet.Add(val);
						if (flag)
						{
							hashSet2.Add(val);
						}
					}
				}
			}
			if (num < emoteBundles.Length)
			{
				Plugin.mlg.LogError((object)$"Found {num} of TooManyEmotes' {emoteBundles.Length} emote bundles, emotes are left as they are.");
				return;
			}
			Clips = list;
			AllClips = hashSet;
			FreeClips = hashSet2;
		}
	}
	[HarmonyPatch]
	internal static class EmoteListRepair
	{
		private readonly struct AddonEmoteSettings
		{
			private readonly bool boomboxAudio;

			private readonly bool canMoveWhileEmoting;

			private readonly string overrideAudioClipName;

			private readonly string overrideAudioLoopClipName;

			private readonly float recordSongLoopValue;

			private readonly bool requiresHeldProp;

			private readonly GameObject requiredHeldPropPrefab;

			private readonly List<string> propNamesInEmote;

			internal AddonEmoteSettings(UnlockableEmote emote)
			{
				boomboxAudio = isBoomboxAudio.Invoke(emote);
				canMoveWhileEmoting = emote.canMoveWhileEmoting;
				overrideAudioClipName = emote.overrideAudioClipName;
				overrideAudioLoopClipName = emote.overrideAudioLoopClipName;
				recordSongLoopValue = emote.recordSongLoopValue;
				requiresHeldProp = emote.requiresHeldProp;
				requiredHeldPropPrefab = emote.requiredHeldPropPrefab;
				propNamesInEmote = emote.propNamesInEmote;
			}

			internal void ApplyTo(UnlockableEmote emote)
			{
				isBoomboxAudio.Invoke(emote) = boomboxAudio;
				emote.canMoveWhileEmoting = canMoveWhileEmoting;
				emote.overrideAudioClipName = overrideAudioClipName;
				emote.overrideAudioLoopClipName = overrideAudioLoopClipName;
				emote.recordSongLoopValue = recordSongLoopValue;
				emote.requiresHeldProp = requiresHeldProp;
				emote.requiredHeldPropPrefab = requiredHeldPropPrefab;
				if (emote.propNamesInEmote == null)
				{
					emote.propNamesInEmote = propNamesInEmote;
				}
			}
		}

		private static bool ready;

		private static bool rebuilding;

		private static Dictionary<AnimationClip, AddonEmoteSettings> addonSettings;

		private static readonly FieldRef<UnlockableEmote, bool> isBoomboxAudio = AccessTools.FieldRefAccess<UnlockableEmote, bool>("_isBoomboxAudio");

		private static readonly FieldInfo emotePropsData = AccessTools.Field(AccessTools.TypeByName("TooManyEmotes.Props.EmotePropManager"), "emotePropsData");

		private static readonly MethodInfo buildEmotePropList = AccessTools.Method(AccessTools.TypeByName("TooManyEmotes.Props.EmotePropManager"), "BuildEmotePropList", (Type[])null, (Type[])null);

		internal static void AtStartup()
		{
			Stopwatch stopwatch = Stopwatch.StartNew();
			BaseBundles.Find();
			ready = BaseBundles.Found;
			if (ready)
			{
				addonSettings = SaveAddonSettings();
				Repair();
				Plugin.mlg.LogInfo((object)$"Emote list repaired and tiered in {stopwatch.ElapsedMilliseconds} ms.");
			}
		}

		[HarmonyPatch(typeof(EmotesManager), "BuildEmotesList")]
		[HarmonyPrefix]
		private static void BeforeBuild()
		{
			if (ready && !rebuilding)
			{
				addonSettings = SaveAddonSettings();
			}
		}

		[HarmonyPatch(typeof(EmotesManager), "BuildEmotesList")]
		[HarmonyPostfix]
		private static void AfterBuild()
		{
			if (ready && !rebuilding)
			{
				Repair();
			}
		}

		private static void Repair()
		{
			try
			{
				RestoreClipNames();
				rebuilding = true;
				try
				{
					EmotesManager.BuildEmotesList();
				}
				finally
				{
					rebuilding = false;
				}
				RerunBaseSetup();
				RestoreAddonSettings();
			}
			catch (Exception arg)
			{
				Plugin.mlg.LogError((object)$"Could not repair the emote list: {arg}");
			}
			AddonTiers.Apply();
		}

		private static void RestoreClipNames()
		{
			foreach (var (val, text) in BaseBundles.Clips)
			{
				if ((Object)(object)val != (Object)null && !string.Equals(((Object)val).name, text, StringComparison.OrdinalIgnoreCase))
				{
					((Object)val).name = text;
				}
			}
		}

		private static void RerunBaseSetup()
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			if (emotePropsData?.GetValue(null) is IEnumerable enumerable)
			{
				foreach (EmotePropData item in enumerable)
				{
					if ((int)item != 0)
					{
						item.parentEmotes?.Clear();
					}
				}
			}
			buildEmotePropList?.Invoke(null, null);
			AdditionalEmoteData.SetAdditionalEmoteData();
			AdditionalEmoteData.SetAdditionalPropData();
			AdditionalEmoteData.SetAdditionalMusicData();
		}

		private static Dictionary<AnimationClip, AddonEmoteSettings> SaveAddonSettings()
		{
			Dictionary<AnimationClip, AddonEmoteSettings> dictionary = new Dictionary<AnimationClip, AddonEmoteSettings>();
			if (EmotesManager.allUnlockableEmotes == null)
			{
				return dictionary;
			}
			foreach (UnlockableEmote allUnlockableEmote in EmotesManager.allUnlockableEmotes)
			{
				if ((Object)(object)allUnlockableEmote.animationClip != (Object)null && !BaseBundles.AllClips.Contains(allUnlockableEmote.animationClip))
				{
					dictionary[allUnlockableEmote.animationClip] = new AddonEmoteSettings(allUnlockableEmote);
				}
			}
			return dictionary;
		}

		private static void RestoreAddonSettings()
		{
			if (addonSettings == null)
			{
				return;
			}
			foreach (UnlockableEmote allUnlockableEmote in EmotesManager.allUnlockableEmotes)
			{
				if ((Object)(object)allUnlockableEmote.animationClip != (Object)null && addonSettings.TryGetValue(allUnlockableEmote.animationClip, out var value))
				{
					value.ApplyTo(allUnlockableEmote);
				}
			}
		}
	}
	[BepInPlugin("dev.davesco.TooManyEmotesAddonFix", "TooManyEmotesAddonFix", "0.1.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		public const string modGUID = "dev.davesco.TooManyEmotesAddonFix";

		public const string modName = "TooManyEmotesAddonFix";

		public const string modVersion = "0.1.0";

		private Harmony _harmony = new Harmony("dev.davesco.TooManyEmotesAddonFix");

		internal static ManualLogSource mlg = Logger.CreateLogSource("dev.davesco.TooManyEmotesAddonFix");

		private void Awake()
		{
			_harmony.PatchAll();
			EmoteListRepair.AtStartup();
			mlg.LogInfo((object)"Plugin TooManyEmotesAddonFix is loaded!");
		}
	}
	public static class PluginInfo
	{
		public const string PLUGIN_GUID = "TooManyEmotesAddonFix";

		public const string PLUGIN_NAME = "TooManyEmotesAddonFix";

		public const string PLUGIN_VERSION = "0.1.0";
	}
}