Decompiled source of YoshiCarry v1.2.1

plugins/Xuaun.YoshiSounds.dll

Decompiled 4 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.Audio;
using UnityEngine.Networking;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("Xuaun.YoshiSounds")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Sons do Yoshi por ação (pulo, pulo duplo, dano) enquanto o cosmético está equipado.")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("Yoshi Sounds")]
[assembly: AssemblyTitle("Xuaun.YoshiSounds")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[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 YoshiSounds
{
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "Xuaun.YoshiSounds";

		public const string PLUGIN_NAME = "Yoshi Sounds";

		public const string PLUGIN_VERSION = "1.0.0";
	}
}
namespace Xuaun.YoshiSounds
{
	internal static class Config
	{
		public static readonly string[] TargetCosmeticAssetIds = new string[5] { "yoshicarry:bbmblueyoshi", "yoshicarry:bbmgreenyoshi", "yoshicarry:bbmredyoshi", "yoshicarry:bbmyellowyoshi", "yoshicarry:bbmcustomyoshi" };

		public static readonly string[] TargetCosmeticAssetNames = new string[10] { "Blue Yoshi Carrying", "Blue Yoshi Carrying Body", "Green Yoshi Carrying", "Green Yoshi Carrying Body", "Red Yoshi Carrying", "Red Yoshi Carrying Body", "Yellow Yoshi Carrying", "Yellow Yoshi Carrying Body", "Custom Yoshi Carrying", "Custom Yoshi Carrying Body" };

		public static readonly string[] SoundJump = new string[2] { "jump1.wav", "jump6.wav" };

		public static readonly string[] SoundDoubleJump = new string[1] { "flutter.wav" };

		public static readonly string[] SoundHurtMinor = new string[1] { "pain_minor.wav" };

		public static readonly string[] SoundHurtMajor = new string[1] { "pain_major.wav" };

		public const int HurtMajorThreshold = 25;

		public static readonly string[] SoundDeath = new string[1] { "death.wav" };

		public static readonly string[] SoundEquip = new string[1] { "yoshi1.wav" };

		public static readonly string[] SoundExtract = new string[2] { "celebrate1.wav", "celebrate2.wav" };

		public static readonly string[] SoundGrab = new string[1] { "tongue.wav" };

		private const string SGeneral = "General";

		private const string SToggles = "Sound Toggles";

		private const string SChances = "Sound Chances (%)";

		private const string SCompat = "Compatibility";

		public static ConfigEntry<bool> Enabled;

		public static ConfigEntry<int> Volume;

		public static ConfigEntry<float> SoundCooldownSeconds;

		public static ConfigEntry<bool> Debug;

		public static ConfigEntry<bool> PlayHurt;

		public static ConfigEntry<bool> PlayDeath;

		public static ConfigEntry<bool> PlayEquip;

		public static ConfigEntry<bool> PlayExtract;

		public static ConfigEntry<bool> PlayGrab;

		public static ConfigEntry<int> ChanceJump;

		public static ConfigEntry<int> ChanceDoubleJump;

		public static ConfigEntry<int> ChanceHurt;

		public static ConfigEntry<int> ChanceDeath;

		public static ConfigEntry<int> ChanceEquip;

		public static ConfigEntry<int> ChanceExtract;

		public static ConfigEntry<int> ChanceGrab;

		public static ConfigEntry<bool> HideBridgedDuplicates;

		public static float VolumeNormalized => Mathf.Clamp01((float)Volume.Value / 100f);

		public static void Init(ConfigFile cfg)
		{
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Expected O, but got Unknown
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Expected O, but got Unknown
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			//IL_014c: Expected O, but got Unknown
			//IL_0170: Unknown result type (might be due to invalid IL or missing references)
			//IL_017a: Expected O, but got Unknown
			//IL_019e: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a8: Expected O, but got Unknown
			//IL_01cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d6: Expected O, but got Unknown
			//IL_01fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0204: Expected O, but got Unknown
			//IL_0228: Unknown result type (might be due to invalid IL or missing references)
			//IL_0232: Expected O, but got Unknown
			//IL_0256: Unknown result type (might be due to invalid IL or missing references)
			//IL_0260: Expected O, but got Unknown
			Enabled = cfg.Bind<bool>("General", "YoshiSoundsEnabled", true, "Master switch for all Yoshi Carrying sounds.");
			Volume = cfg.Bind<int>("General", "YoshiSoundVolume", 100, new ConfigDescription("Volume of the Yoshi sounds, in % (100 = full clip volume). Routed through the game's SFX mixer, so the in-game Sound Effects slider applies on top.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>()));
			SoundCooldownSeconds = cfg.Bind<float>("General", "MinSecondsBetweenSounds", 0.2f, new ConfigDescription("Minimum time between any two Yoshi sounds, in seconds.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 5f), Array.Empty<object>()));
			Debug = cfg.Bind<bool>("General", "Debug", false, "Log Yoshi sounds/events to the console (verbose). Keep off for normal play.");
			PlayHurt = cfg.Bind<bool>("Sound Toggles", "PlayHurtSound", true, "Play a sound when the Yoshi wearer takes damage.");
			PlayDeath = cfg.Bind<bool>("Sound Toggles", "PlayDeathSound", true, "Play a sound when the Yoshi wearer dies.");
			PlayEquip = cfg.Bind<bool>("Sound Toggles", "PlayEquipSound", true, "Play a sound when equipping the Yoshi cosmetic.");
			PlayExtract = cfg.Bind<bool>("Sound Toggles", "PlayExtractSound", true, "Play a sound when the final extraction completes.");
			PlayGrab = cfg.Bind<bool>("Sound Toggles", "PlayGrabSound", true, "Play the tongue sound when grabbing an object.");
			ChanceJump = cfg.Bind<int>("Sound Chances (%)", "JumpSoundChance", 60, new ConfigDescription("Chance (%) to play a sound on each normal jump.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>()));
			ChanceDoubleJump = cfg.Bind<int>("Sound Chances (%)", "DoubleJumpSoundChance", 75, new ConfigDescription("Chance (%) to play a sound on each double/extra jump.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>()));
			ChanceHurt = cfg.Bind<int>("Sound Chances (%)", "HurtSoundChance", 70, new ConfigDescription("Chance (%) to play a sound on each hit.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>()));
			ChanceDeath = cfg.Bind<int>("Sound Chances (%)", "DeathSoundChance", 100, new ConfigDescription("Chance (%) to play a sound on death.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>()));
			ChanceEquip = cfg.Bind<int>("Sound Chances (%)", "EquipSoundChance", 40, new ConfigDescription("Chance (%) to play a sound when equipping.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>()));
			ChanceExtract = cfg.Bind<int>("Sound Chances (%)", "ExtractSoundChance", 100, new ConfigDescription("Chance (%) to play a sound when extraction completes.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>()));
			ChanceGrab = cfg.Bind<int>("Sound Chances (%)", "GrabSoundChance", 30, new ConfigDescription("Chance (%) to play a sound when grabbing an object.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>()));
			HideBridgedDuplicates = cfg.Bind<bool>("Compatibility", "HideBridgedYoshiDuplicates", true, "When another mod (e.g. XuaunCosmetics via MoreHeadBridge) provides its own 'Yoshi Carrying' outfit, hide THOSE bridged copies from the menu and keep this pack's YoshiCarry version.");
		}
	}
	internal static class CosmeticUtil
	{
		private static readonly HashSet<int> _targetAvatarIds = new HashSet<int>();

		public static bool IsWearingTarget(PlayerAvatar avatar)
		{
			if ((Object)(object)avatar == (Object)null)
			{
				return false;
			}
			if ((Object)(object)avatar.playerCosmetics != (Object)null && avatar.playerCosmetics.cosmeticEquipped != null)
			{
				foreach (Cosmetic item in avatar.playerCosmetics.cosmeticEquipped)
				{
					if (IsTarget(item))
					{
						RegisterTargetAvatar(avatar);
						return true;
					}
				}
				UnregisterTargetAvatar(avatar);
				return false;
			}
			if (_targetAvatarIds.Contains(((Object)avatar).GetInstanceID()))
			{
				return true;
			}
			Cosmetic[] componentsInChildren = ((Component)avatar).GetComponentsInChildren<Cosmetic>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				if (IsTarget(componentsInChildren[i]))
				{
					RegisterTargetAvatar(avatar);
					return true;
				}
			}
			return false;
		}

		public static void RegisterTargetAvatar(PlayerAvatar avatar)
		{
			if (!((Object)(object)avatar == (Object)null))
			{
				_targetAvatarIds.Add(((Object)avatar).GetInstanceID());
			}
		}

		public static void UnregisterTargetAvatar(PlayerAvatar avatar)
		{
			if (!((Object)(object)avatar == (Object)null))
			{
				_targetAvatarIds.Remove(((Object)avatar).GetInstanceID());
			}
		}

		public static PlayerAvatar FindAvatar(Cosmetic cosmetic)
		{
			if ((Object)(object)cosmetic == (Object)null)
			{
				return null;
			}
			PlayerAvatar componentInParent = ((Component)cosmetic).GetComponentInParent<PlayerAvatar>();
			if ((Object)(object)componentInParent != (Object)null)
			{
				return componentInParent;
			}
			if ((Object)(object)cosmetic.playerCosmetics != (Object)null && (Object)(object)cosmetic.playerCosmetics.playerAvatarVisuals != (Object)null)
			{
				return cosmetic.playerCosmetics.playerAvatarVisuals.playerAvatar;
			}
			return null;
		}

		public static bool IsTarget(Cosmetic cosmetic)
		{
			return IsTargetAsset(cosmetic?.cosmeticAsset);
		}

		public static bool IsTargetAsset(CosmeticAsset asset)
		{
			if ((Object)(object)asset == (Object)null)
			{
				return false;
			}
			if (!ContainsExact(Config.TargetCosmeticAssetIds, asset.assetId) && !ContainsExact(Config.TargetCosmeticAssetNames, asset.assetName))
			{
				return ContainsExact(Config.TargetCosmeticAssetNames, ((Object)asset).name);
			}
			return true;
		}

		private static bool ContainsExact(string[] values, string value)
		{
			if (values == null || string.IsNullOrWhiteSpace(value))
			{
				return false;
			}
			for (int i = 0; i < values.Length; i++)
			{
				if (string.Equals(values[i], value, StringComparison.OrdinalIgnoreCase))
				{
					return true;
				}
			}
			return false;
		}
	}
	[BepInPlugin("com.xuaun.yoshicarry", "YoshiCarry", "1.1.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		public const string Guid = "com.xuaun.yoshicarry";

		public const string Name = "YoshiCarry";

		public const string Version = "1.1.0";

		internal static ManualLogSource Log;

		private void Awake()
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			Log = ((BaseUnityPlugin)this).Logger;
			Config.Init(((BaseUnityPlugin)this).Config);
			SoundManager.Init(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location));
			new Harmony("com.xuaun.yoshicarry").PatchAll(Assembly.GetExecutingAssembly());
			Log.LogInfo((object)string.Format("{0} {1} loaded. Target cosmetics: {2} IDs", "YoshiCarry", "1.1.0", Config.TargetCosmeticAssetIds.Length));
		}
	}
	internal static class SoundManager
	{
		private class CoroutineRunner : MonoBehaviour
		{
		}

		private static readonly Dictionary<string, AudioClip> _clips = new Dictionary<string, AudioClip>();

		private static string _soundsDir;

		private static CoroutineRunner _runner;

		private static float _lastSoundTime = -999f;

		private static readonly Dictionary<int, AudioSource> _activeDoubleJump = new Dictionary<int, AudioSource>();

		public static string[] JumpSounds { get; private set; }

		public static string[] DoubleJumpSounds { get; private set; }

		public static string[] HurtMinorSounds { get; private set; }

		public static string[] HurtMajorSounds { get; private set; }

		public static string[] DeathSounds { get; private set; }

		public static string[] EquipSounds { get; private set; }

		public static string[] ExtractSounds { get; private set; }

		public static string[] GrabSounds { get; private set; }

		public static void Init(string pluginDir)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Expected O, but got Unknown
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			_soundsDir = Path.Combine(pluginDir, "sounds");
			GameObject val = new GameObject("YoshiSounds_Runner");
			Object.DontDestroyOnLoad((Object)val);
			((Object)val).hideFlags = (HideFlags)61;
			_runner = val.AddComponent<CoroutineRunner>();
			JumpSounds = Discover(Config.SoundJump, "jump");
			DoubleJumpSounds = Discover(Config.SoundDoubleJump, "flutter");
			HurtMinorSounds = Discover(Config.SoundHurtMinor, "pain_minor");
			HurtMajorSounds = Discover(Config.SoundHurtMajor, "pain_major");
			DeathSounds = Discover(Config.SoundDeath, "death");
			EquipSounds = Discover(Config.SoundEquip, "yoshi");
			ExtractSounds = Discover(Config.SoundExtract, "celebrate");
			GrabSounds = Discover(Config.SoundGrab, "tongue");
			PreloadAll(JumpSounds);
			PreloadAll(DoubleJumpSounds);
			PreloadAll(HurtMinorSounds);
			PreloadAll(HurtMajorSounds);
			PreloadAll(DeathSounds);
			PreloadAll(EquipSounds);
			PreloadAll(ExtractSounds);
			PreloadAll(GrabSounds);
			if (Config.Debug.Value)
			{
				Plugin.Log.LogInfo((object)$"Yoshi sound pools: jump={JumpSounds.Length}, double={DoubleJumpSounds.Length}, hurtMinor={HurtMinorSounds.Length}, hurtMajor={HurtMajorSounds.Length}, equip={EquipSounds.Length}, death={DeathSounds.Length}, extract={ExtractSounds.Length}, grab={GrabSounds.Length}");
			}
		}

		private static string[] Discover(string[] defaults, params string[] prefixes)
		{
			List<string> list = new List<string>();
			AddUnique(list, defaults);
			if (Directory.Exists(_soundsDir))
			{
				string[] files = Directory.GetFiles(_soundsDir);
				for (int i = 0; i < files.Length; i++)
				{
					string fileName = Path.GetFileName(files[i]);
					if (!IsSupportedAudio(fileName))
					{
						continue;
					}
					foreach (string value in prefixes)
					{
						if (fileName.StartsWith(value, StringComparison.OrdinalIgnoreCase))
						{
							AddUnique(list, fileName);
							break;
						}
					}
				}
			}
			return list.ToArray();
		}

		private static bool IsSupportedAudio(string fileName)
		{
			if (!fileName.EndsWith(".wav", StringComparison.OrdinalIgnoreCase))
			{
				return fileName.EndsWith(".ogg", StringComparison.OrdinalIgnoreCase);
			}
			return true;
		}

		private static void AddUnique(List<string> target, string[] files)
		{
			if (files != null)
			{
				foreach (string file in files)
				{
					AddUnique(target, file);
				}
			}
		}

		private static void AddUnique(List<string> target, string file)
		{
			if (string.IsNullOrWhiteSpace(file))
			{
				return;
			}
			foreach (string item in target)
			{
				if (string.Equals(item, file, StringComparison.OrdinalIgnoreCase))
				{
					return;
				}
			}
			target.Add(file);
		}

		private static void PreloadAll(string[] fileNames)
		{
			if (fileNames != null)
			{
				for (int i = 0; i < fileNames.Length; i++)
				{
					Preload(fileNames[i]);
				}
			}
		}

		private static void Preload(string fileName)
		{
			if (!string.IsNullOrEmpty(fileName) && !_clips.ContainsKey(fileName))
			{
				((MonoBehaviour)_runner).StartCoroutine(LoadClip(fileName));
			}
		}

		private static IEnumerator LoadClip(string fileName)
		{
			string text = Path.Combine(_soundsDir, fileName);
			if (!File.Exists(text))
			{
				Plugin.Log.LogWarning((object)("Sound file not found: " + text));
				yield break;
			}
			AudioType val = (AudioType)(fileName.EndsWith(".ogg", StringComparison.OrdinalIgnoreCase) ? 14 : 20);
			string absoluteUri = new Uri(text).AbsoluteUri;
			UnityWebRequest req = UnityWebRequestMultimedia.GetAudioClip(absoluteUri, val);
			try
			{
				yield return req.SendWebRequest();
				if ((int)req.result != 1)
				{
					Plugin.Log.LogWarning((object)("Failed to load " + fileName + ": " + req.error));
					yield break;
				}
				AudioClip content = DownloadHandlerAudioClip.GetContent(req);
				if ((Object)(object)content != (Object)null && content.length > 0f)
				{
					((Object)content).name = fileName;
					_clips[fileName] = content;
					if (Config.Debug.Value)
					{
						Plugin.Log.LogInfo((object)$"Loaded sound: {fileName} ({content.length:0.00}s)");
					}
				}
				else
				{
					Plugin.Log.LogWarning((object)("Empty/invalid clip: " + fileName));
				}
			}
			finally
			{
				((IDisposable)req)?.Dispose();
			}
		}

		public static AudioSource PlayAt(string fileName, Vector3 position)
		{
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: Expected O, but got Unknown
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			if (!Config.Enabled.Value)
			{
				return null;
			}
			if (Time.time - _lastSoundTime < Config.SoundCooldownSeconds.Value)
			{
				return null;
			}
			if (!_clips.TryGetValue(fileName, out var value) || (Object)(object)value == (Object)null)
			{
				Plugin.Log.LogWarning((object)("Sound requested but not loaded: " + fileName));
				return null;
			}
			GameObject val = new GameObject("YoshiSound_OneShot");
			val.transform.position = position;
			AudioSource val2 = val.AddComponent<AudioSource>();
			val2.clip = value;
			val2.volume = Config.VolumeNormalized;
			val2.spatialBlend = 0.75f;
			val2.minDistance = 3f;
			val2.maxDistance = 50f;
			val2.rolloffMode = (AudioRolloffMode)1;
			val2.priority = 64;
			val2.dopplerLevel = 0f;
			AudioMixerGroup val3 = (((Object)(object)AudioManager.instance != (Object)null) ? AudioManager.instance.SoundMasterGroup : null);
			if ((Object)(object)val3 != (Object)null)
			{
				val2.outputAudioMixerGroup = val3;
			}
			val2.Play();
			_lastSoundTime = Time.time;
			if (Config.Debug.Value)
			{
				Plugin.Log.LogInfo((object)$"Playing Yoshi sound: {fileName} at {position}");
			}
			Object.Destroy((Object)val, value.length + 0.2f);
			return val2;
		}

		public static AudioSource PlayRandomAt(string[] fileNames, Vector3 position)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			if (fileNames == null || fileNames.Length == 0)
			{
				return null;
			}
			return PlayAt((fileNames.Length == 1) ? fileNames[0] : fileNames[Random.Range(0, fileNames.Length)], position);
		}

		public static AudioSource PlayRandomAtChance(string[] fileNames, Vector3 position, float percent)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			if (!Roll(percent))
			{
				return null;
			}
			return PlayRandomAt(fileNames, position);
		}

		public static void PlayHurt(PlayerAvatar avatar, int damage)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)avatar == (Object)null) && damage > 0)
			{
				PlayRandomAtChance((damage >= 25) ? HurtMajorSounds : HurtMinorSounds, ((Component)avatar).transform.position, Config.ChanceHurt.Value);
			}
		}

		public static void PlayDoubleJump(PlayerAvatar avatar)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)avatar == (Object)null))
			{
				AudioSource val = PlayRandomAtChance(DoubleJumpSounds, ((Component)avatar).transform.position, Config.ChanceDoubleJump.Value);
				if ((Object)(object)val != (Object)null)
				{
					_activeDoubleJump[((Object)avatar).GetInstanceID()] = val;
				}
			}
		}

		public static void StopDoubleJump(PlayerAvatar avatar)
		{
			if ((Object)(object)avatar == (Object)null)
			{
				return;
			}
			int instanceID = ((Object)avatar).GetInstanceID();
			if (_activeDoubleJump.TryGetValue(instanceID, out var value))
			{
				if ((Object)(object)value != (Object)null && value.isPlaying)
				{
					value.Stop();
				}
				_activeDoubleJump.Remove(instanceID);
			}
		}

		private static bool Roll(float percent)
		{
			if (percent <= 0f)
			{
				return false;
			}
			if (percent >= 100f)
			{
				return true;
			}
			return Random.Range(0f, 100f) < percent;
		}
	}
}
namespace Xuaun.YoshiSounds.Patches
{
	[HarmonyPatch(typeof(MenuElementCosmeticButton), "Start")]
	internal static class BundleDedupPatch
	{
		private const string OwnPrefix = "yoshicarry:";

		private const string BridgedPrefix = "morehead-bridge:";

		private const string CarryingTag = "yoshi carrying";

		private static int _hideActiveCache = -1;

		private static bool _hideLogged;

		[HarmonyPrefix]
		private static bool Prefix(MenuElementCosmeticButton __instance)
		{
			if (!Config.HideBridgedDuplicates.Value)
			{
				return true;
			}
			CosmeticAsset val = (((Object)(object)__instance != (Object)null) ? __instance.cosmeticAsset : null);
			if ((Object)(object)val == (Object)null)
			{
				return true;
			}
			if (!StartsWith(val.assetId, "morehead-bridge:"))
			{
				return true;
			}
			if (!Contains(val.assetName, "yoshi carrying") && !Contains(((Object)val).name, "yoshi carrying"))
			{
				return true;
			}
			if (!OwnCarryingPresent())
			{
				return true;
			}
			((Component)__instance).gameObject.SetActive(false);
			return false;
		}

		private static bool OwnCarryingPresent()
		{
			if (_hideActiveCache != -1)
			{
				return _hideActiveCache == 1;
			}
			if ((Object)(object)MetaManager.instance == (Object)null)
			{
				return false;
			}
			bool num = MetaManager.instance.cosmeticAssets.Any((CosmeticAsset a) => (Object)(object)a != (Object)null && StartsWith(a.assetId, "yoshicarry:") && Contains(a.assetName, "yoshi carrying"));
			_hideActiveCache = (num ? 1 : 0);
			if (num && !_hideLogged)
			{
				_hideLogged = true;
				Plugin.Log.LogInfo((object)"Hiding bridged 'Yoshi Carrying' duplicates — keeping this pack's YoshiCarry version.");
			}
			return num;
		}

		private static bool StartsWith(string value, string prefix)
		{
			if (!string.IsNullOrEmpty(value))
			{
				return value.StartsWith(prefix, StringComparison.OrdinalIgnoreCase);
			}
			return false;
		}

		private static bool Contains(string value, string fragment)
		{
			if (!string.IsNullOrEmpty(value))
			{
				return value.IndexOf(fragment, StringComparison.OrdinalIgnoreCase) >= 0;
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(Cosmetic), "Remove")]
	internal static class CosmeticRemovePatch
	{
		[HarmonyPrefix]
		private static void Prefix(Cosmetic __instance)
		{
			if (CosmeticUtil.IsTarget(__instance))
			{
				PlayerAvatar val = CosmeticUtil.FindAvatar(__instance);
				if (!((Object)(object)val == (Object)null))
				{
					CosmeticUtil.UnregisterTargetAvatar(val);
				}
			}
		}
	}
	[HarmonyPatch(typeof(PlayerAvatar), "PlayerDeathRPC")]
	internal static class DeathPatch
	{
		[HarmonyPostfix]
		private static void Postfix(PlayerAvatar __instance)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			if (Config.PlayDeath.Value && !((Object)(object)__instance == (Object)null) && CosmeticUtil.IsWearingTarget(__instance))
			{
				SoundManager.PlayRandomAtChance(SoundManager.DeathSounds, ((Component)__instance).transform.position, Config.ChanceDeath.Value);
			}
		}
	}
	[HarmonyPatch(typeof(MetaManager), "CosmeticEquip")]
	internal static class EquipPatch
	{
		[HarmonyPostfix]
		private static void Postfix(CosmeticAsset _cosmeticAssetNew, bool _isPreview, bool __result)
		{
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			if (Config.PlayEquip.Value && !_isPreview && __result && CosmeticUtil.IsTargetAsset(_cosmeticAssetNew))
			{
				PlayerAvatar instance = PlayerAvatar.instance;
				Vector3 position = (((Object)(object)instance != (Object)null) ? ((Component)instance).transform.position : (((Object)(object)Camera.main != (Object)null) ? ((Component)Camera.main).transform.position : Vector3.zero));
				SoundManager.PlayRandomAtChance(SoundManager.EquipSounds, position, Config.ChanceEquip.Value);
			}
		}
	}
	[HarmonyPatch(typeof(RoundDirector), "ExtractionCompletedAllRPC")]
	internal static class ExtractPatch
	{
		[HarmonyPostfix]
		private static void Postfix()
		{
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			if (!Config.PlayExtract.Value)
			{
				return;
			}
			foreach (PlayerAvatar item in SemiFunc.PlayerGetAll())
			{
				if (!((Object)(object)item == (Object)null) && CosmeticUtil.IsWearingTarget(item))
				{
					SoundManager.PlayRandomAtChance(SoundManager.ExtractSounds, ((Component)item).transform.position, Config.ChanceExtract.Value);
				}
			}
		}
	}
	[HarmonyPatch(typeof(PhysGrabber), "PhysGrabStartEffects")]
	internal static class GrabPatch
	{
		private const float GrabCooldown = 1f;

		private static readonly Dictionary<int, float> _lastGrabTime = new Dictionary<int, float>();

		[HarmonyPostfix]
		private static void Postfix(PhysGrabber __instance)
		{
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			if (!Config.PlayGrab.Value || (Object)(object)__instance == (Object)null)
			{
				return;
			}
			PlayerAvatar playerAvatar = __instance.playerAvatar;
			if (!((Object)(object)playerAvatar == (Object)null) && CosmeticUtil.IsWearingTarget(playerAvatar))
			{
				int instanceID = ((Object)__instance).GetInstanceID();
				if (!_lastGrabTime.TryGetValue(instanceID, out var value) || !(Time.time - value < 1f))
				{
					_lastGrabTime[instanceID] = Time.time;
					SoundManager.PlayRandomAtChance(SoundManager.GrabSounds, ((Component)playerAvatar).transform.position, Config.ChanceGrab.Value);
				}
			}
		}
	}
	[HarmonyPatch(typeof(PlayerHealth), "Hurt", new Type[]
	{
		typeof(int),
		typeof(bool),
		typeof(int),
		typeof(bool)
	})]
	internal static class HurtPatch
	{
		[HarmonyPostfix]
		private static void Postfix(PlayerHealth __instance, int damage)
		{
			if (Config.PlayHurt.Value && !((Object)(object)__instance == (Object)null) && damage > 0 && __instance.health > 0)
			{
				PlayerAvatar val = __instance.playerAvatar;
				if ((Object)(object)val == (Object)null)
				{
					val = ((Component)__instance).GetComponent<PlayerAvatar>();
				}
				if ((Object)(object)val == (Object)null)
				{
					val = PlayerAvatar.instance;
				}
				if (!((Object)(object)val == (Object)null) && CosmeticUtil.IsWearingTarget(val))
				{
					SoundManager.PlayHurt(val, damage);
				}
			}
		}
	}
	[HarmonyPatch(typeof(PlayerHealth), "UpdateHealthRPC")]
	internal static class HurtRemotePatch
	{
		[HarmonyPrefix]
		private static void Prefix(PlayerHealth __instance, out int __state)
		{
			__state = (((Object)(object)__instance != (Object)null) ? __instance.health : 0);
		}

		[HarmonyPostfix]
		private static void Postfix(PlayerHealth __instance, int healthNew, bool effect, int __state)
		{
			if (!Config.PlayHurt.Value || (Object)(object)__instance == (Object)null || !effect || healthNew <= 0 || __instance.health != healthNew)
			{
				return;
			}
			int num = __state - healthNew;
			if (num > 0)
			{
				PlayerAvatar val = __instance.playerAvatar;
				if ((Object)(object)val == (Object)null)
				{
					val = ((Component)__instance).GetComponent<PlayerAvatar>();
				}
				if (!((Object)(object)val == (Object)null) && CosmeticUtil.IsWearingTarget(val))
				{
					SoundManager.PlayHurt(val, num);
				}
			}
		}
	}
	[HarmonyPatch(typeof(PlayerAvatar), "JumpRPC")]
	internal static class JumpPatch
	{
		[HarmonyPostfix]
		private static void Postfix(PlayerAvatar __instance, bool _powerupEffect)
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)__instance == (Object)null) && CosmeticUtil.IsWearingTarget(__instance))
			{
				if (_powerupEffect)
				{
					SoundManager.PlayDoubleJump(__instance);
				}
				else
				{
					SoundManager.PlayRandomAtChance(SoundManager.JumpSounds, ((Component)__instance).transform.position, Config.ChanceJump.Value);
				}
			}
		}
	}
	[HarmonyPatch(typeof(PlayerAvatar), "LandRPC")]
	internal static class LandPatch
	{
		[HarmonyPostfix]
		private static void Postfix(PlayerAvatar __instance)
		{
			if (!((Object)(object)__instance == (Object)null))
			{
				SoundManager.StopDoubleJump(__instance);
			}
		}
	}
	[HarmonyPatch(typeof(PlayerCosmetics), "SetupCosmeticsLogic")]
	internal static class PlayerCosmeticsPatch
	{
		[HarmonyPostfix]
		private static void Postfix(PlayerCosmetics __instance)
		{
			if ((Object)(object)__instance == (Object)null || (Object)(object)__instance.playerAvatarVisuals == (Object)null)
			{
				return;
			}
			PlayerAvatar playerAvatar = __instance.playerAvatarVisuals.playerAvatar;
			if ((Object)(object)playerAvatar == (Object)null)
			{
				return;
			}
			bool flag = false;
			foreach (Cosmetic item in __instance.cosmeticEquipped)
			{
				if (CosmeticUtil.IsTarget(item))
				{
					flag = true;
					break;
				}
			}
			if (flag)
			{
				CosmeticUtil.RegisterTargetAvatar(playerAvatar);
			}
			else
			{
				CosmeticUtil.UnregisterTargetAvatar(playerAvatar);
			}
		}
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
}