Decompiled source of Bragi v0.2.0

plugins\Bragi\Bragi.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 Jotunn.Configs;
using Jotunn.Entities;
using Jotunn.Managers;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using Splatform;
using UnityEngine;
using UnityEngine.Audio;
using UnityEngine.Networking;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.0.0.0")]
[module: UnverifiableCode]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
}
namespace Bragi
{
	public static class BardBuff
	{
		private static Coroutine? _buffLoop;

		private const float RESTED_EXTENSION_PER_PULSE = 10f;

		private const float RESTED_MAX_EXTENSION = 1200f;

		public static void StartBuff()
		{
			if (BragiConfig.BuffEnabled.Value)
			{
				Player localPlayer = Player.m_localPlayer;
				_buffLoop = ((localPlayer != null) ? ((MonoBehaviour)localPlayer).StartCoroutine(BuffLoop()) : null);
			}
		}

		public static void EndBuff()
		{
			if (_buffLoop != null && (Object)(object)Player.m_localPlayer != (Object)null)
			{
				((MonoBehaviour)Player.m_localPlayer).StopCoroutine(_buffLoop);
			}
			_buffLoop = null;
		}

		private static IEnumerator BuffLoop()
		{
			while (true)
			{
				ApplyToNearbyPlayers();
				yield return (object)new WaitForSeconds(5f);
			}
		}

		private static void ApplyToNearbyPlayers()
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				return;
			}
			float value = BragiConfig.BuffRadius.Value;
			foreach (Player allPlayer in Player.GetAllPlayers())
			{
				if (!(Vector3.Distance(((Component)allPlayer).transform.position, ((Component)localPlayer).transform.position) > value))
				{
					ExtendRestBuff(allPlayer);
				}
			}
		}

		private static void ExtendRestBuff(Player player)
		{
			SEMan sEMan = ((Character)player).GetSEMan();
			if (sEMan == null)
			{
				return;
			}
			int hashCode = "Rested".GetHashCode();
			if (sEMan.HaveStatusEffect(hashCode))
			{
				StatusEffect statusEffect = sEMan.GetStatusEffect(hashCode);
				if ((Object)(object)statusEffect != (Object)null)
				{
					float remaningTime = statusEffect.GetRemaningTime();
					float ttl = Mathf.Min(1200f, remaningTime + 10f + BragiConfig.StaminaRegenBonus.Value * 60f);
					statusEffect.m_ttl = ttl;
					statusEffect.ResetTime();
				}
			}
			else
			{
				ObjectDB instance = ObjectDB.instance;
				StatusEffect val = ((instance != null) ? instance.GetStatusEffect(hashCode) : null);
				if ((Object)(object)val != (Object)null)
				{
					sEMan.AddStatusEffect(val, false, 0, 0f, (short)(-1));
					((Character)player).Message((MessageType)1, "$se_rested_start", 0, (Sprite)null, false);
				}
			}
		}
	}
	[HarmonyPatch(typeof(Player), "OnSpawned")]
	internal static class PlayerSpawnPatch
	{
		[HarmonyPostfix]
		private static void Postfix(Player __instance)
		{
			if (((Character)__instance).IsOwner())
			{
				if ((Object)(object)((Component)__instance).GetComponent<SongPlayer>() == (Object)null)
				{
					((Component)__instance).gameObject.AddComponent<SongPlayer>();
				}
				if ((Object)(object)((Component)__instance).GetComponent<SongSelectUI>() == (Object)null)
				{
					((Component)__instance).gameObject.AddComponent<SongSelectUI>();
				}
				BragiPlugin.Log.LogInfo((object)"\ud83c\udfb5 Bragi components attached to local player.");
			}
		}
	}
	public static class BragiConfig
	{
		public static ConfigEntry<float> MasterVolume;

		public static ConfigEntry<float> MusicRange;

		public static ConfigEntry<bool> DuckGameMusic;

		public static ConfigEntry<bool> BuffEnabled;

		public static ConfigEntry<float> BuffRadius;

		public static ConfigEntry<float> BuffDuration;

		public static ConfigEntry<float> StaminaRegenBonus;

		public static ConfigEntry<string> OpenMenuKey;

		public static void Init(ConfigFile cfg)
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Expected O, but got Unknown
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Expected O, but got Unknown
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Expected O, but got Unknown
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Expected O, but got Unknown
			//IL_013f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0149: Expected O, but got Unknown
			MasterVolume = cfg.Bind<float>("Audio", "MasterVolume", 1f, new ConfigDescription("Global volume multiplier for instrument audio (0.0 – 1.0).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
			MusicRange = cfg.Bind<float>("Audio", "MusicRange", 30f, new ConfigDescription("Radius in metres within which other players hear your music.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(5f, 100f), Array.Empty<object>()));
			DuckGameMusic = cfg.Bind<bool>("Audio", "DuckGameMusic", true, "Reduce Valheim's background ambient music volume while instruments are playing, so it doesn't clash with the performed song.");
			BuffEnabled = cfg.Bind<bool>("BardBuff", "Enabled", true, "Enable the bard buff: playing music refreshes the vanilla Rested status effect for nearby players.");
			BuffRadius = cfg.Bind<float>("BardBuff", "Radius", 15f, new ConfigDescription("Radius in metres of the bard Rested-extension buff.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(2f, 50f), Array.Empty<object>()));
			BuffDuration = cfg.Bind<float>("BardBuff", "Duration", 60f, new ConfigDescription("How long (seconds) the Rested buff persists naturally after being granted.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(10f, 300f), Array.Empty<object>()));
			StaminaRegenBonus = cfg.Bind<float>("BardBuff", "StaminaRegenBonus", 0.15f, new ConfigDescription("Extra stamina regen percentage on top of the vanilla Rested buff (0.15 = +15%).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
			OpenMenuKey = cfg.Bind<string>("UI", "OpenMenuKey", "G", "Keyboard key to open the song selection menu while holding an instrument.");
		}
	}
	public static class ForagerConfig
	{
		public static ConfigEntry<float> ScanRadius;

		public static ConfigEntry<float> PulseInterval;

		public static ConfigEntry<bool> DetectBerries;

		public static ConfigEntry<bool> DetectMushrooms;

		public static ConfigEntry<int> MaxPins;

		public static void Init(ConfigFile cfg)
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Expected O, but got Unknown
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Expected O, but got Unknown
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Expected O, but got Unknown
			ScanRadius = cfg.Bind<float>("Forager", "ScanRadius", 40f, new ConfigDescription("Radius in metres that the Forager's Nose scans for pickables.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(10f, 200f), Array.Empty<object>()));
			PulseInterval = cfg.Bind<float>("Forager", "PulseInterval", 3f, new ConfigDescription("Seconds between each scan pulse (lower = more frequent, heavier on CPU).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 30f), Array.Empty<object>()));
			DetectBerries = cfg.Bind<bool>("Forager", "DetectBerries", true, "Detect blueberry, raspberry and cloudberry bushes.");
			DetectMushrooms = cfg.Bind<bool>("Forager", "DetectMushrooms", true, "Detect wild mushrooms (red, yellow, blue, jotun puffs, magecap).");
			MaxPins = cfg.Bind<int>("Forager", "MaxPins", 20, new ConfigDescription("Maximum number of minimap pins shown by the radar at once.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 100), Array.Empty<object>()));
		}
	}
	public static class ForagerItem
	{
		public const string ItemPrefabName = "ForagersNose";

		public static void Register()
		{
			PrefabManager.OnVanillaPrefabsAvailable += CreateItem;
			BragiPlugin.Log.LogInfo((object)"Forager's Nose queued for registration.");
		}

		private static void CreateItem()
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Expected O, but got Unknown
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Expected O, but got Unknown
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Expected O, but got Unknown
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Expected O, but got Unknown
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Expected O, but got Unknown
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Expected O, but got Unknown
			PrefabManager.OnVanillaPrefabsAvailable -= CreateItem;
			ItemConfig val = new ItemConfig();
			val.Name = "$item_foragersnose";
			val.Description = "$item_foragersnose_desc";
			val.CraftingStation = CraftingStations.Workbench;
			val.Requirements = (RequirementConfig[])(object)new RequirementConfig[4]
			{
				new RequirementConfig("Raspberry", 10, 0, true),
				new RequirementConfig("Blueberries", 10, 0, true),
				new RequirementConfig("Mushroom", 5, 0, true),
				new RequirementConfig("Dandelion", 2, 0, true)
			};
			ItemConfig val2 = val;
			CustomItem val3 = new CustomItem("ForagersNose", "Wishbone", val2);
			TweakSharedData(val3);
			ItemManager.Instance.AddItem(val3);
			BragiPlugin.Log.LogInfo((object)"Forager's Nose item registered.");
		}

		private static void TweakSharedData(CustomItem item)
		{
			GameObject itemPrefab = item.ItemPrefab;
			SharedData val = ((itemPrefab == null) ? null : itemPrefab.GetComponent<ItemDrop>()?.m_itemData?.m_shared);
			if (val == null)
			{
				BragiPlugin.Log.LogWarning((object)"Could not tweak Forager's Nose shared data — ItemDrop missing.");
				return;
			}
			val.m_name = "$item_foragersnose";
			val.m_description = "$item_foragersnose_desc";
			val.m_equipStatusEffect = null;
			val.m_setStatusEffect = null;
			BragiPlugin.Log.LogInfo((object)"Forager's Nose shared data tweaked.");
		}
	}
	[HarmonyPatch(typeof(Player), "OnSpawned")]
	internal static class ForagerSpawnPatch
	{
		[HarmonyPostfix]
		private static void Postfix(Player __instance)
		{
			if (((Character)__instance).IsOwner() && (Object)(object)((Component)__instance).GetComponent<ForagerRadar>() == (Object)null)
			{
				((Component)__instance).gameObject.AddComponent<ForagerRadar>();
				BragiPlugin.Log.LogInfo((object)"ForagerRadar attached to local player.");
			}
		}
	}
	public class ForagerRadar : MonoBehaviour
	{
		private static readonly HashSet<string> BerryPrefabs = new HashSet<string> { "BlueberryBush", "RaspberryBush", "CloudberryBush" };

		private static readonly HashSet<string> MushroomPrefabs = new HashSet<string> { "Pickable_Mushroom", "Pickable_Mushroom_blue", "Pickable_Mushroom_yellow", "Pickable_Mushroom_JotunPuffs", "Pickable_Mushroom_Magecap" };

		private static readonly Dictionary<string, string?> FoodCategoryCache = new Dictionary<string, string>();

		private static readonly int s_pickedKey = "picked".GetHashCode();

		private const PinType PIN_TYPE = (PinType)8;

		private readonly Dictionary<int, PinData> _pins = new Dictionary<int, PinData>();

		private Coroutine? _scanLoop;

		private static AudioClip? _pingSfx;

		private readonly Collider[] _colliderBuffer = (Collider[])(object)new Collider[256];

		private bool _sfxAttempted;

		private void OnEnable()
		{
			_scanLoop = ((MonoBehaviour)this).StartCoroutine(ScanLoop());
			BragiPlugin.Log.LogInfo((object)"ForagerRadar started.");
		}

		private void OnDisable()
		{
			if (_scanLoop != null)
			{
				((MonoBehaviour)this).StopCoroutine(_scanLoop);
			}
			_scanLoop = null;
			ClearAllPins();
			BragiPlugin.Log.LogInfo((object)"ForagerRadar stopped.");
		}

		private IEnumerator ScanLoop()
		{
			while (true)
			{
				yield return (object)new WaitForSeconds(ForagerConfig.PulseInterval.Value);
				Player localPlayer = Player.m_localPlayer;
				if ((Object)(object)localPlayer == (Object)null)
				{
					continue;
				}
				if (!IsForagersNoseEquipped(localPlayer))
				{
					if (_pins.Count > 0)
					{
						ClearAllPins();
					}
					continue;
				}
				List<(GameObject, string)> list = FindNearbyPickables(((Component)localPlayer).transform.position);
				BragiPlugin.Log.LogDebug((object)$"Radar scan: found {list.Count} harvestable food resource(s) within {ForagerConfig.ScanRadius.Value}m.");
				RefreshPins(list);
				if (list.Count > 0)
				{
					PlayPingSfx(localPlayer, list);
				}
			}
		}

		private static bool IsForagersNoseEquipped(Player player)
		{
			Inventory inventory = ((Humanoid)player).GetInventory();
			List<ItemData> list = ((inventory != null) ? inventory.GetEquippedItems() : null);
			if (list == null)
			{
				return false;
			}
			foreach (ItemData item in list)
			{
				if (item?.m_shared?.m_name == "$item_foragersnose")
				{
					return true;
				}
			}
			return false;
		}

		private List<(GameObject go, string category)> FindNearbyPickables(Vector3 origin)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			List<(GameObject, string)> list = new List<(GameObject, string)>();
			float value = ForagerConfig.ScanRadius.Value;
			int value2 = ForagerConfig.MaxPins.Value;
			int num = Physics.OverlapSphereNonAlloc(origin, value, _colliderBuffer, -1, (QueryTriggerInteraction)2);
			HashSet<int> hashSet = new HashSet<int>();
			for (int i = 0; i < num; i++)
			{
				if (list.Count >= value2)
				{
					break;
				}
				Collider val = _colliderBuffer[i];
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				ZNetView componentInParent = ((Component)val).gameObject.GetComponentInParent<ZNetView>();
				if ((Object)(object)componentInParent == (Object)null)
				{
					continue;
				}
				GameObject gameObject = ((Component)componentInParent).gameObject;
				int instanceID = ((Object)gameObject).GetInstanceID();
				if (hashSet.Contains(instanceID))
				{
					continue;
				}
				string name = ((Object)gameObject).name;
				int num2 = name.IndexOf('(');
				string prefabName = ((num2 >= 0) ? name.Substring(0, num2).TrimEnd(Array.Empty<char>()) : name);
				string category = GetCategory(gameObject, prefabName);
				if (category != null)
				{
					Pickable componentInChildren = gameObject.GetComponentInChildren<Pickable>();
					if ((!((Object)(object)componentInChildren != (Object)null) || (!componentInChildren.GetPicked() && componentInChildren.CanBePicked())) && (!componentInParent.IsValid() || !componentInParent.GetZDO().GetBool(s_pickedKey, false)))
					{
						hashSet.Add(instanceID);
						list.Add((gameObject, category));
					}
				}
			}
			return list;
		}

		private string? GetCategory(GameObject rootGo, string prefabName)
		{
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Invalid comparison between Unknown and I4
			if (!FoodCategoryCache.TryGetValue(prefabName, out string value))
			{
				if (BerryPrefabs.Contains(prefabName))
				{
					value = "$forager_berries";
				}
				else if (MushroomPrefabs.Contains(prefabName))
				{
					value = "$forager_mushrooms";
				}
				else
				{
					Pickable componentInChildren = rootGo.GetComponentInChildren<Pickable>();
					if ((Object)(object)componentInChildren != (Object)null && (Object)(object)componentInChildren.m_itemPrefab != (Object)null)
					{
						SharedData val = componentInChildren.m_itemPrefab.GetComponent<ItemDrop>()?.m_itemData?.m_shared;
						if (val != null && (val.m_food > 0f || val.m_foodStamina > 0f || val.m_foodEitr > 0f || ((int)val.m_itemType == 2 && !val.m_isDrink)))
						{
							value = (prefabName.ToLowerInvariant().Contains("mushroom") ? "$forager_mushrooms" : "$forager_berries");
						}
					}
				}
				FoodCategoryCache[prefabName] = value;
			}
			if (value == null)
			{
				return null;
			}
			if (value == "$forager_berries" && !ForagerConfig.DetectBerries.Value)
			{
				return null;
			}
			if (value == "$forager_mushrooms" && !ForagerConfig.DetectMushrooms.Value)
			{
				return null;
			}
			return value;
		}

		private void RefreshPins(List<(GameObject go, string category)> current)
		{
			//IL_0135: Unknown result type (might be due to invalid IL or missing references)
			//IL_0143: Unknown result type (might be due to invalid IL or missing references)
			//IL_0149: Unknown result type (might be due to invalid IL or missing references)
			//IL_0172: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)Minimap.instance == (Object)null)
			{
				return;
			}
			HashSet<int> hashSet = new HashSet<int>();
			foreach (var item4 in current)
			{
				GameObject item = item4.go;
				hashSet.Add(((Object)item).GetInstanceID());
			}
			List<int> list = new List<int>();
			foreach (int key in _pins.Keys)
			{
				if (!hashSet.Contains(key))
				{
					list.Add(key);
				}
			}
			foreach (int item5 in list)
			{
				Minimap.instance.RemovePin(_pins[item5]);
				_pins.Remove(item5);
			}
			foreach (var item6 in current)
			{
				GameObject item2 = item6.go;
				string item3 = item6.category;
				int instanceID = ((Object)item2).GetInstanceID();
				if (!_pins.ContainsKey(instanceID))
				{
					PinData value = Minimap.instance.AddPin(item2.transform.position, (PinType)8, item3, false, false, 0L, default(PlatformUserID));
					_pins[instanceID] = value;
					BragiPlugin.Log.LogDebug((object)$"Pin added at {item2.transform.position} [{item3}]");
				}
			}
		}

		private void ClearAllPins()
		{
			if ((Object)(object)Minimap.instance == (Object)null)
			{
				_pins.Clear();
				return;
			}
			foreach (PinData value in _pins.Values)
			{
				Minimap.instance.RemovePin(value);
			}
			_pins.Clear();
		}

		private void PlayPingSfx(Player player, List<(GameObject go, string category)> results)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			float num = float.MaxValue;
			foreach (var result in results)
			{
				GameObject item = result.go;
				float num2 = Vector3.Distance(((Component)player).transform.position, item.transform.position);
				if (num2 < num)
				{
					num = num2;
				}
			}
			float value = ForagerConfig.ScanRadius.Value;
			float num3 = 1f - Mathf.Clamp01(num / value);
			if ((Object)(object)_pingSfx == (Object)null && !_sfxAttempted)
			{
				_sfxAttempted = true;
				_pingSfx = LoadWishbonePingClip();
				BragiPlugin.Log.LogInfo((object)(((Object)(object)_pingSfx != (Object)null) ? "Wishbone SFX loaded successfully." : "Wishbone SFX not found — continuing without audio."));
			}
			if (!((Object)(object)_pingSfx == (Object)null))
			{
				float volume = Mathf.Lerp(0.15f, 0.7f, num3);
				float pitch = Mathf.Lerp(0.8f, 1.4f, num3);
				PlaySfxAtPoint(_pingSfx, ((Component)player).transform.position, volume, pitch);
			}
		}

		private static void PlaySfxAtPoint(AudioClip clip, Vector3 position, float volume, float pitch)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Expected O, but got Unknown
			GameObject val = new GameObject("_ForagerPing");
			val.transform.position = position;
			AudioSource obj = val.AddComponent<AudioSource>();
			obj.clip = clip;
			obj.volume = volume;
			obj.pitch = pitch;
			obj.spatialBlend = 1f;
			obj.maxDistance = 25f;
			obj.rolloffMode = (AudioRolloffMode)1;
			obj.Play();
			Object.Destroy((Object)val, clip.length + 0.5f);
		}

		private static AudioClip? LoadWishbonePingClip()
		{
			if ((Object)(object)ObjectDB.instance == (Object)null)
			{
				BragiPlugin.Log.LogInfo((object)"LoadWishbonePingClip: ObjectDB not ready.");
				return null;
			}
			SE_Finder val = null;
			foreach (StatusEffect statusEffect in ObjectDB.instance.m_StatusEffects)
			{
				SE_Finder val2 = (SE_Finder)(object)((statusEffect is SE_Finder) ? statusEffect : null);
				if (val2 != null && ((Object)statusEffect).name == "Wishbone")
				{
					val = val2;
					break;
				}
			}
			if ((Object)(object)val == (Object)null)
			{
				BragiPlugin.Log.LogInfo((object)"LoadWishbonePingClip: SE_Finder 'Wishbone' not found in ObjectDB.");
				return null;
			}
			EffectData[] array = val.m_pingEffectNear?.m_effectPrefabs;
			if (array == null)
			{
				return null;
			}
			EffectData[] array2 = array;
			foreach (EffectData val3 in array2)
			{
				if (!((Object)(object)val3.m_prefab == (Object)null))
				{
					AudioSource componentInChildren = val3.m_prefab.GetComponentInChildren<AudioSource>();
					if ((Object)(object)((componentInChildren != null) ? componentInChildren.clip : null) != (Object)null)
					{
						return componentInChildren.clip;
					}
				}
			}
			return null;
		}
	}
	public static class InstrumentDefinitions
	{
		public static readonly Dictionary<string, InstrumentType> ItemNameToType = new Dictionary<string, InstrumentType>
		{
			{
				"BragiLyre",
				InstrumentType.Lyre
			},
			{
				"BragiBoneFlute",
				InstrumentType.BoneFlute
			},
			{
				"BragiJawHarp",
				InstrumentType.JawHarp
			}
		};

		public static bool IsInstrument(string itemName)
		{
			return ItemNameToType.ContainsKey(itemName);
		}

		public static InstrumentType? GetType(string itemName)
		{
			if (!ItemNameToType.TryGetValue(itemName, out var value))
			{
				return null;
			}
			return value;
		}
	}
	public enum InstrumentType
	{
		Lyre,
		BoneFlute,
		JawHarp
	}
	public static class InstrumentRegistry
	{
		public static void Register()
		{
			PrefabManager.OnVanillaPrefabsAvailable += AddInstruments;
		}

		private static void AddInstruments()
		{
			RegisterLyre();
			RegisterBoneFlute();
			RegisterJawHarp();
			BragiPlugin.Log.LogInfo((object)"\ud83c\udfb5 Bragi instruments registered.");
			PrefabManager.OnVanillaPrefabsAvailable -= AddInstruments;
		}

		private static void RegisterLyre()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Expected O, but got Unknown
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Expected O, but got Unknown
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Expected O, but got Unknown
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Expected O, but got Unknown
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Expected O, but got Unknown
			ItemConfig val = new ItemConfig();
			val.Name = "$item_bragi_lyre";
			val.Description = "$item_bragi_lyre_desc";
			val.CraftingStation = CraftingStations.Workbench;
			val.MinStationLevel = 1;
			val.Requirements = (RequirementConfig[])(object)new RequirementConfig[3]
			{
				new RequirementConfig
				{
					Item = "FineWood",
					Amount = 8
				},
				new RequirementConfig
				{
					Item = "DeerHide",
					Amount = 2
				},
				new RequirementConfig
				{
					Item = "Resin",
					Amount = 4
				}
			};
			ItemConfig val2 = val;
			ItemManager.Instance.AddItem(new CustomItem("BragiLyre", "Club", val2));
		}

		private static void RegisterBoneFlute()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Expected O, but got Unknown
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Expected O, but got Unknown
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Expected O, but got Unknown
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Expected O, but got Unknown
			ItemConfig val = new ItemConfig();
			val.Name = "$item_bragi_boneflute";
			val.Description = "$item_bragi_boneflute_desc";
			val.CraftingStation = CraftingStations.Workbench;
			val.MinStationLevel = 1;
			val.Requirements = (RequirementConfig[])(object)new RequirementConfig[2]
			{
				new RequirementConfig
				{
					Item = "BoneFragments",
					Amount = 4
				},
				new RequirementConfig
				{
					Item = "Feathers",
					Amount = 2
				}
			};
			ItemConfig val2 = val;
			ItemManager.Instance.AddItem(new CustomItem("BragiBoneFlute", "Club", val2));
		}

		private static void RegisterJawHarp()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Expected O, but got Unknown
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Expected O, but got Unknown
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Expected O, but got Unknown
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Expected O, but got Unknown
			ItemConfig val = new ItemConfig();
			val.Name = "$item_bragi_jawharp";
			val.Description = "$item_bragi_jawharp_desc";
			val.CraftingStation = CraftingStations.Forge;
			val.MinStationLevel = 1;
			val.Requirements = (RequirementConfig[])(object)new RequirementConfig[2]
			{
				new RequirementConfig
				{
					Item = "Iron",
					Amount = 2
				},
				new RequirementConfig
				{
					Item = "LeatherScraps",
					Amount = 1
				}
			};
			ItemConfig val2 = val;
			ItemManager.Instance.AddItem(new CustomItem("BragiJawHarp", "Club", val2));
		}
	}
	[Serializable]
	public class SongData
	{
		[JsonProperty("id")]
		public string Id { get; set; } = "";

		[JsonProperty("name")]
		public string Name { get; set; } = "Unknown Song";

		[JsonProperty("author")]
		public string Author { get; set; } = "Traditional";

		[JsonProperty("description")]
		public string Description { get; set; } = "";

		[JsonProperty("audioFile")]
		public string AudioFile { get; set; } = "";

		[JsonProperty("tracks")]
		public Dictionary<string, string> Tracks { get; set; } = new Dictionary<string, string>();

		[JsonProperty("duration")]
		public float Duration { get; set; } = 60f;

		[JsonProperty("instruments")]
		public List<string> Instruments { get; set; } = new List<string>();

		[JsonProperty("mood")]
		public string Mood { get; set; } = "";

		[JsonIgnore]
		public Dictionary<string, AudioClip> StemClips { get; } = new Dictionary<string, AudioClip>();

		[JsonIgnore]
		public string SourcePath { get; set; } = "";

		public bool SupportsInstrument(InstrumentType type)
		{
			if (Instruments == null || Instruments.Count == 0)
			{
				return true;
			}
			return Instruments.Contains(type.ToString());
		}

		public string GetAudioFileForInstrument(InstrumentType? type)
		{
			if (type.HasValue && Tracks != null && Tracks.TryGetValue(type.Value.ToString(), out string value))
			{
				return value;
			}
			return AudioFile;
		}

		public bool HasStemFor(InstrumentType type)
		{
			if (Tracks != null)
			{
				return Tracks.ContainsKey(type.ToString());
			}
			return false;
		}

		public override string ToString()
		{
			return $"[{Id}] {Name} by {Author} ({Duration:0}s)";
		}
	}
	public static class SongLibrary
	{
		private static readonly List<SongData> _songs = new List<SongData>();

		public static IReadOnlyList<SongData> AllSongs => _songs;

		public static string SongsDirectory => Path.Combine(Paths.ConfigPath, "Bragi", "songs");

		public static void Init()
		{
			Directory.CreateDirectory(SongsDirectory);
			ExtractDefaultSongs();
			LoadSongs();
		}

		private static void ExtractDefaultSongs()
		{
			Assembly executingAssembly = Assembly.GetExecutingAssembly();
			foreach (string item in from n in executingAssembly.GetManifestResourceNames()
				where n.StartsWith("Bragi.songs.") && n.EndsWith(".json")
				select n)
			{
				string text = item.Replace("Bragi.songs.", "");
				string path = Path.Combine(SongsDirectory, text);
				if (File.Exists(path))
				{
					continue;
				}
				using Stream stream = executingAssembly.GetManifestResourceStream(item);
				if (stream != null)
				{
					using StreamReader streamReader = new StreamReader(stream);
					File.WriteAllText(path, streamReader.ReadToEnd());
					BragiPlugin.Log.LogInfo((object)("\ud83d\udcc4 Extracted default song: " + text));
				}
			}
		}

		private static void LoadSongs()
		{
			_songs.Clear();
			string[] files = Directory.GetFiles(SongsDirectory, "*.json");
			foreach (string text in files)
			{
				try
				{
					SongData songData = JsonConvert.DeserializeObject<SongData>(File.ReadAllText(text));
					if (songData != null)
					{
						songData.SourcePath = text;
						_songs.Add(songData);
						BragiPlugin.Log.LogInfo((object)$"\ud83c\udfb5 Loaded song: {songData}");
					}
				}
				catch (Exception ex)
				{
					BragiPlugin.Log.LogError((object)("Failed to load song JSON " + text + ": " + ex.Message));
				}
			}
			BragiPlugin.Log.LogInfo((object)$"\ud83c\udfb5 SongLibrary: {_songs.Count} songs loaded.");
		}

		public static IEnumerator LoadClip(SongData song, InstrumentType? instrument, Action<AudioClip?> onLoaded)
		{
			string audioFileName = song.GetAudioFileForInstrument(instrument);
			if (string.IsNullOrEmpty(audioFileName))
			{
				BragiPlugin.Log.LogWarning((object)("No audio file defined for song '" + song.Id + "'."));
				onLoaded(null);
				yield break;
			}
			if (song.StemClips.TryGetValue(audioFileName, out AudioClip value))
			{
				onLoaded(value);
				yield break;
			}
			string path = Path.GetDirectoryName(song.SourcePath) ?? SongsDirectory;
			string audioPath = Path.Combine(path, audioFileName);
			if (!File.Exists(audioPath))
			{
				BragiPlugin.Log.LogWarning((object)("Audio file not found: " + audioPath));
				onLoaded(null);
				yield break;
			}
			AudioType val = (AudioType)(audioPath.EndsWith(".ogg", StringComparison.OrdinalIgnoreCase) ? 14 : 20);
			UnityWebRequest request = UnityWebRequestMultimedia.GetAudioClip("file:///" + audioPath.Replace('\\', '/'), val);
			try
			{
				yield return request.SendWebRequest();
				if ((int)request.result != 1)
				{
					BragiPlugin.Log.LogError((object)("Failed to load audio '" + audioPath + "': " + request.error));
					onLoaded(null);
					yield break;
				}
				AudioClip content = DownloadHandlerAudioClip.GetContent(request);
				((Object)content).name = song.Id + "_" + audioFileName;
				song.StemClips[audioFileName] = content;
				onLoaded(content);
			}
			finally
			{
				((IDisposable)request)?.Dispose();
			}
		}

		public static List<SongData> GetSongsForInstrument(InstrumentType type)
		{
			return _songs.Where((SongData s) => s.SupportsInstrument(type)).ToList();
		}

		public static SongData? GetById(string id)
		{
			return _songs.FirstOrDefault((SongData s) => s.Id == id);
		}
	}
	public class SongPlayer : MonoBehaviour
	{
		private AudioSource? _audioSource;

		private Coroutine? _loadCoroutine;

		public static SongPlayer? Instance { get; private set; }

		public bool IsPlaying { get; private set; }

		public SongData? CurrentSong { get; private set; }

		private void Awake()
		{
			Instance = this;
			_audioSource = ((Component)this).gameObject.AddComponent<AudioSource>();
			Configure3DAudio(_audioSource);
		}

		private void OnDestroy()
		{
			if ((Object)(object)Instance == (Object)(object)this)
			{
				Instance = null;
			}
			StopPlaying();
		}

		public void StartNewSession(SongData song)
		{
			if (IsPlaying)
			{
				StopPlaying();
			}
			InstrumentType? equippedInstrumentType = GetEquippedInstrumentType();
			CurrentSong = song;
			_loadCoroutine = ((MonoBehaviour)this).StartCoroutine(LoadAndPlay(song, equippedInstrumentType, 0f, isNewSession: true));
		}

		public void JoinActiveSession()
		{
			MusicSync.EnsembleSession activeSession = MusicSync.ActiveSession;
			if (activeSession == null)
			{
				Player localPlayer = Player.m_localPlayer;
				if (localPlayer != null)
				{
					((Character)localPlayer).Message((MessageType)2, "⚠ No active ensemble session nearby.", 0, (Sprite)null, false);
				}
				return;
			}
			if (IsPlaying)
			{
				StopPlaying();
			}
			InstrumentType? equippedInstrumentType = GetEquippedInstrumentType();
			float seekSeconds = (((Object)(object)ZNet.instance != (Object)null) ? ((float)(ZNet.instance.GetTimeSeconds() - activeSession.StartNetworkTime)) : 0f);
			CurrentSong = activeSession.Song;
			_loadCoroutine = ((MonoBehaviour)this).StartCoroutine(LoadAndPlay(activeSession.Song, equippedInstrumentType, seekSeconds, isNewSession: false));
		}

		public void StopPlaying()
		{
			if (_loadCoroutine != null)
			{
				((MonoBehaviour)this).StopCoroutine(_loadCoroutine);
				_loadCoroutine = null;
			}
			if ((Object)(object)_audioSource != (Object)null)
			{
				_audioSource.Stop();
			}
			if (IsPlaying)
			{
				IsPlaying = false;
				MusicSync.SendStopSession();
				AudioRouting.RestoreGameMusic();
				BardBuff.EndBuff();
				BragiPlugin.Log.LogInfo((object)"\ud83c\udfb5 Stopped playing.");
			}
			CurrentSong = null;
		}

		private IEnumerator LoadAndPlay(SongData song, InstrumentType? instrType, float seekSeconds, bool isNewSession)
		{
			BragiPlugin.Log.LogInfo((object)("\ud83c\udfb5 Loading song: " + song.Name + (instrType.HasValue ? $" [{instrType.Value} stem]" : " [full mix]")));
			AudioClip clip = null;
			yield return SongLibrary.LoadClip(song, instrType, delegate(AudioClip? c)
			{
				clip = c;
			});
			if ((Object)(object)clip == (Object)null)
			{
				BragiPlugin.Log.LogError((object)("Could not load audio for '" + song.Name + "'. Aborting."));
				Player localPlayer = Player.m_localPlayer;
				if (localPlayer != null)
				{
					((Character)localPlayer).Message((MessageType)2, "⚠ Could not load audio file.", 0, (Sprite)null, false);
				}
				yield break;
			}
			_audioSource.clip = clip;
			_audioSource.volume = BragiConfig.MasterVolume.Value;
			_audioSource.maxDistance = BragiConfig.MusicRange.Value;
			AudioRouting.ApplyMixerGroup(_audioSource);
			float num = Mathf.Repeat(seekSeconds, clip.length);
			_audioSource.time = num;
			_audioSource.Play();
			IsPlaying = true;
			AudioRouting.DuckGameMusic();
			if (isNewSession)
			{
				MusicSync.SendStartSession(song.Id, instrType?.ToString() ?? "");
			}
			else
			{
				MusicSync.SendJoinSession(song.Id, instrType?.ToString() ?? "");
			}
			if (BragiConfig.BuffEnabled.Value)
			{
				BardBuff.StartBuff();
			}
			BragiPlugin.Log.LogInfo((object)("\ud83c\udfb5 Now playing: " + song.Name + ((num > 0f) ? $" (offset {num:0.0}s)" : "")));
			float num2 = clip.length - num;
			yield return (object)new WaitForSeconds(num2);
			StopPlaying();
		}

		private static InstrumentType? GetEquippedInstrumentType()
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				return null;
			}
			ItemData val = ((Humanoid)localPlayer).GetInventory().GetEquippedItems().Find(delegate(ItemData i)
			{
				GameObject dropPrefab2 = i.m_dropPrefab;
				return InstrumentDefinitions.IsInstrument(((dropPrefab2 != null) ? ((Object)dropPrefab2).name : null) ?? "");
			});
			if (val == null)
			{
				return null;
			}
			GameObject dropPrefab = val.m_dropPrefab;
			return InstrumentDefinitions.GetType(((dropPrefab != null) ? ((Object)dropPrefab).name : null) ?? "");
		}

		private static void Configure3DAudio(AudioSource src)
		{
			src.spatialBlend = 1f;
			src.rolloffMode = (AudioRolloffMode)1;
			src.minDistance = 2f;
			src.maxDistance = BragiConfig.MusicRange.Value;
			src.dopplerLevel = 0f;
			src.spread = 60f;
			src.loop = false;
			src.playOnAwake = false;
		}
	}
	public static class MusicSync
	{
		public class EnsembleSession
		{
			public SongData Song;

			public double StartNetworkTime;

			public long HostPeerId;
		}

		internal const string RPC_START_SESSION = "Bragi_StartSession";

		internal const string RPC_JOIN_SESSION = "Bragi_JoinSession";

		internal const string RPC_STOP_SESSION = "Bragi_StopSession";

		public static EnsembleSession? ActiveSession { get; private set; }

		public static void Init()
		{
			BragiPlugin.Log.LogInfo((object)"\ud83c\udfb5 MusicSync ready (RPCs will register on ZNet.Awake).");
		}

		public static void SendStartSession(string songId, string instrumentType)
		{
			if (ZRoutedRpc.instance != null)
			{
				double num = (((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetTimeSeconds() : 0.0);
				ZRoutedRpc.instance.InvokeRoutedRPC(0L, "Bragi_StartSession", new object[3] { songId, num, instrumentType });
			}
		}

		public static void SendJoinSession(string songId, string instrumentType)
		{
			if (ZRoutedRpc.instance != null)
			{
				double num = (((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetTimeSeconds() : 0.0);
				ZRoutedRpc.instance.InvokeRoutedRPC(0L, "Bragi_JoinSession", new object[3] { songId, num, instrumentType });
			}
		}

		public static void SendStopSession()
		{
			if (ZRoutedRpc.instance != null)
			{
				ZRoutedRpc.instance.InvokeRoutedRPC(0L, "Bragi_StopSession", Array.Empty<object>());
				if (ActiveSession?.HostPeerId == ZDOMan.GetSessionID())
				{
					ActiveSession = null;
				}
			}
		}

		internal static void OnRemoteStartSession(long senderPeerId, string songId, double startNetTime, string instrumentType)
		{
			if (senderPeerId == ZDOMan.GetSessionID())
			{
				return;
			}
			SongData byId = SongLibrary.GetById(songId);
			if (byId == null)
			{
				BragiPlugin.Log.LogWarning((object)("Received StartSession for unknown song: " + songId));
				return;
			}
			ActiveSession = new EnsembleSession
			{
				Song = byId,
				StartNetworkTime = startNetTime,
				HostPeerId = senderPeerId
			};
			Player playerByPeerId = GetPlayerByPeerId(senderPeerId);
			if (!((Object)(object)playerByPeerId == (Object)null))
			{
				double elapsedSeconds = (((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetTimeSeconds() : startNetTime) - startNetTime;
				RemoteAudioSource.PlayAt(playerByPeerId, byId, instrumentType, startNetTime, elapsedSeconds);
				BragiPlugin.Log.LogInfo((object)("\ud83c\udfb5 Remote session started: " + byId.Name + " by " + playerByPeerId.GetPlayerName()));
			}
		}

		internal static void OnRemoteJoinSession(long senderPeerId, string songId, double joinNetTime, string instrumentType)
		{
			if (senderPeerId == ZDOMan.GetSessionID())
			{
				return;
			}
			SongData byId = SongLibrary.GetById(songId);
			if (byId != null)
			{
				if (ActiveSession == null)
				{
					ActiveSession = new EnsembleSession
					{
						Song = byId,
						StartNetworkTime = joinNetTime,
						HostPeerId = senderPeerId
					};
				}
				Player playerByPeerId = GetPlayerByPeerId(senderPeerId);
				if (!((Object)(object)playerByPeerId == (Object)null))
				{
					double elapsedSeconds = (((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetTimeSeconds() : joinNetTime) - ActiveSession.StartNetworkTime;
					RemoteAudioSource.PlayAt(playerByPeerId, byId, instrumentType, ActiveSession.StartNetworkTime, elapsedSeconds);
					BragiPlugin.Log.LogInfo((object)("\ud83c\udfb5 Remote player joined session: " + playerByPeerId.GetPlayerName() + " (" + instrumentType + ")"));
				}
			}
		}

		internal static void OnRemoteStopSession(long senderPeerId)
		{
			if (senderPeerId != ZDOMan.GetSessionID())
			{
				Player playerByPeerId = GetPlayerByPeerId(senderPeerId);
				if ((Object)(object)playerByPeerId != (Object)null)
				{
					RemoteAudioSource.StopAt(playerByPeerId);
				}
				EnsembleSession? activeSession = ActiveSession;
				if (activeSession != null && activeSession.HostPeerId == senderPeerId)
				{
					ActiveSession = null;
					BragiPlugin.Log.LogInfo((object)"\ud83c\udfb5 Remote ensemble session ended.");
				}
			}
		}

		private static Player? GetPlayerByPeerId(long peerId)
		{
			foreach (Player allPlayer in Player.GetAllPlayers())
			{
				ZNetView component = ((Component)allPlayer).GetComponent<ZNetView>();
				if ((Object)(object)component != (Object)null)
				{
					ZDO zDO = component.GetZDO();
					if (zDO != null && zDO.GetOwner() == peerId)
					{
						return allPlayer;
					}
				}
			}
			return null;
		}
	}
	[HarmonyPatch(typeof(ZNet), "Awake")]
	internal static class ZNetAwakePatch
	{
		[HarmonyPostfix]
		private static void Postfix()
		{
			if (ZRoutedRpc.instance != null)
			{
				ZRoutedRpc.instance.Register<string, double, string>("Bragi_StartSession", (Action<long, string, double, string>)MusicSync.OnRemoteStartSession);
				ZRoutedRpc.instance.Register<string, double, string>("Bragi_JoinSession", (Action<long, string, double, string>)MusicSync.OnRemoteJoinSession);
				ZRoutedRpc.instance.Register("Bragi_StopSession", (Action<long>)MusicSync.OnRemoteStopSession);
				BragiPlugin.Log.LogInfo((object)"\ud83c\udfb5 MusicSync RPCs registered.");
			}
		}
	}
	public class RemoteAudioSource : MonoBehaviour
	{
		private AudioSource? _source;

		private static readonly Dictionary<Player, RemoteAudioSource> _active = new Dictionary<Player, RemoteAudioSource>();

		public static void PlayAt(Player player, SongData song, string instrumentType, double sessionStartTime, double elapsedSeconds)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			StopAt(player);
			GameObject val = new GameObject("BragiRemoteAudio");
			val.transform.SetParent(((Component)player).transform, false);
			val.transform.localPosition = new Vector3(0f, 1.5f, 0f);
			RemoteAudioSource remoteAudioSource = val.AddComponent<RemoteAudioSource>();
			((MonoBehaviour)remoteAudioSource).StartCoroutine(remoteAudioSource.LoadAndPlay(song, instrumentType, (float)elapsedSeconds));
			_active[player] = remoteAudioSource;
		}

		public static void StopAt(Player player)
		{
			if (_active.TryGetValue(player, out RemoteAudioSource value))
			{
				if ((Object)(object)value != (Object)null)
				{
					Object.Destroy((Object)(object)((Component)value).gameObject);
				}
				_active.Remove(player);
			}
		}

		private IEnumerator LoadAndPlay(SongData song, string instrumentType, float seekSeconds)
		{
			InstrumentType result;
			InstrumentType? instrument = (Enum.TryParse<InstrumentType>(instrumentType, out result) ? new InstrumentType?(result) : ((InstrumentType?)null));
			AudioClip clip = null;
			yield return SongLibrary.LoadClip(song, instrument, delegate(AudioClip? c)
			{
				clip = c;
			});
			if (!((Object)(object)clip == (Object)null) && !((Object)(object)this == (Object)null))
			{
				_source = ((Component)this).gameObject.AddComponent<AudioSource>();
				_source.clip = clip;
				_source.volume = BragiConfig.MasterVolume.Value;
				_source.spatialBlend = 1f;
				_source.rolloffMode = (AudioRolloffMode)1;
				_source.minDistance = 2f;
				_source.maxDistance = BragiConfig.MusicRange.Value;
				_source.dopplerLevel = 0f;
				_source.loop = false;
				AudioRouting.ApplyMixerGroup(_source);
				float num = Mathf.Repeat(seekSeconds, clip.length);
				_source.time = num;
				_source.Play();
				float num2 = clip.length - num;
				yield return (object)new WaitForSeconds(num2);
				if ((Object)(object)this != (Object)null)
				{
					Object.Destroy((Object)(object)((Component)this).gameObject);
				}
			}
		}
	}
	public static class AudioRouting
	{
		private static AudioMixerGroup? _cachedMixerGroup;

		public static void ApplyMixerGroup(AudioSource source)
		{
			if ((Object)(object)_cachedMixerGroup == (Object)null)
			{
				_cachedMixerGroup = ResolveMixerGroup();
			}
			if ((Object)(object)_cachedMixerGroup != (Object)null)
			{
				source.outputAudioMixerGroup = _cachedMixerGroup;
			}
		}

		private static AudioMixerGroup? ResolveMixerGroup()
		{
			try
			{
				if ((Object)(object)AudioMan.instance != (Object)null)
				{
					return AudioMan.instance.m_ambientMixer;
				}
			}
			catch
			{
			}
			return null;
		}

		public static void DuckGameMusic()
		{
			if (!BragiConfig.DuckGameMusic.Value)
			{
				return;
			}
			try
			{
				AudioMan instance = AudioMan.instance;
				if (instance != null)
				{
					AudioMixer masterMixer = instance.m_masterMixer;
					if (masterMixer != null)
					{
						masterMixer.SetFloat("MusicVolume", -80f);
					}
				}
			}
			catch
			{
			}
		}

		public static void RestoreGameMusic()
		{
			try
			{
				AudioMan instance = AudioMan.instance;
				if (instance != null)
				{
					AudioMixer masterMixer = instance.m_masterMixer;
					if (masterMixer != null)
					{
						masterMixer.SetFloat("MusicVolume", 0f);
					}
				}
			}
			catch
			{
			}
		}
	}
	[BepInPlugin("com.bragi.valheim", "Bragi", "0.2.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	public class BragiPlugin : BaseUnityPlugin
	{
		public const string PluginGUID = "com.bragi.valheim";

		public const string PluginName = "Bragi";

		public const string PluginVersion = "0.2.0";

		internal static ManualLogSource Log;

		private static Harmony _harmony;

		private void Awake()
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			Log.LogInfo((object)"\ud83c\udfb5 Bragi 0.2.0 loading...");
			BragiConfig.Init(((BaseUnityPlugin)this).Config);
			ForagerConfig.Init(((BaseUnityPlugin)this).Config);
			_harmony = new Harmony("com.bragi.valheim");
			_harmony.PatchAll(Assembly.GetExecutingAssembly());
			InstrumentRegistry.Register();
			ForagerItem.Register();
			SongLibrary.Init();
			MusicSync.Init();
			RegisterLocalization();
			Log.LogInfo((object)"\ud83c\udfb5 Bragi loaded successfully!");
		}

		private static void RegisterLocalization()
		{
			CustomLocalization localization = LocalizationManager.Instance.GetLocalization();
			using Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("Bragi.Localization.English.json");
			if (stream != null)
			{
				using (StreamReader streamReader = new StreamReader(stream))
				{
					localization.AddJsonFile("English", streamReader.ReadToEnd());
					Log.LogInfo((object)"\ud83c\udfb5 Localization loaded from embedded resource.");
					return;
				}
			}
			string path = Path.Combine(Paths.ConfigPath, "Bragi", "Localization", "English.json");
			if (File.Exists(path))
			{
				localization.AddJsonFile("English", File.ReadAllText(path));
				Log.LogInfo((object)"\ud83c\udfb5 Localization loaded from config folder.");
			}
			else
			{
				Log.LogWarning((object)"⚠ Localization file not found — item names may appear as raw tokens.");
			}
		}

		private void OnDestroy()
		{
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}
	}
	public class SongSelectUI : MonoBehaviour
	{
		private List<SongData> _availableSongs = new List<SongData>();

		private const int PanelW = 460;

		private const int PanelH = 560;

		private Rect _panelRect;

		private Vector2 _scrollPos;

		private int _selectedIndex = -1;

		private KeyCode _cachedMenuKey = (KeyCode)103;

		private string _cachedMenuKeyStr = "G";

		public static SongSelectUI? Instance { get; private set; }

		public static bool IsOpen { get; private set; }

		private void Awake()
		{
			Instance = this;
			CenterPanel();
		}

		private void OnDestroy()
		{
			if ((Object)(object)Instance == (Object)(object)this)
			{
				Instance = null;
			}
			ForceClose();
		}

		private void CenterPanel()
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			_panelRect = new Rect((float)(Screen.width - 460) / 2f, (float)(Screen.height - 560) / 2f, 460f, 560f);
		}

		private KeyCode GetMenuKey()
		{
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			string value = BragiConfig.OpenMenuKey.Value;
			if (value != _cachedMenuKeyStr)
			{
				_cachedMenuKeyStr = value;
				_cachedMenuKey = (KeyCode)((!Enum.TryParse<KeyCode>(value, ignoreCase: true, out KeyCode result)) ? 103 : ((int)result));
			}
			return _cachedMenuKey;
		}

		private void Update()
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			if (Input.GetKeyDown(GetMenuKey()) && IsInstrumentEquipped())
			{
				Toggle();
			}
			if (IsOpen && Input.GetKeyDown((KeyCode)27))
			{
				Close();
			}
			if (IsOpen && _selectedIndex >= 0 && Input.GetKeyDown((KeyCode)13))
			{
				PlaySelected();
			}
		}

		private void OnGUI()
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Invalid comparison between Unknown and I4
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			if (IsOpen)
			{
				if ((int)Event.current.type == 8)
				{
					CenterPanel();
				}
				GUI.color = new Color(0f, 0f, 0f, 0.55f);
				GUI.DrawTexture(new Rect(0f, 0f, (float)Screen.width, (float)Screen.height), (Texture)(object)Texture2D.whiteTexture);
				GUI.color = Color.white;
				GUI.Box(_panelRect, "");
				GUILayout.BeginArea(_panelRect);
				DrawHeader();
				DrawEnsembleBanner();
				DrawSongList();
				DrawFooter();
				GUILayout.EndArea();
			}
		}

		private void DrawHeader()
		{
			GUILayout.Space(10f);
			GUILayout.Label("♪  Choose a Song  ♪", LargeLabel(), Array.Empty<GUILayoutOption>());
			GUILayout.Label(GetInstrumentDisplayName(), SmallLabel(), Array.Empty<GUILayoutOption>());
			GUILayout.Space(6f);
			DrawHorizontalLine();
			GUILayout.Space(4f);
		}

		private void DrawEnsembleBanner()
		{
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_011b: Unknown result type (might be due to invalid IL or missing references)
			MusicSync.EnsembleSession activeSession = MusicSync.ActiveSession;
			if (activeSession == null)
			{
				return;
			}
			string text = "someone";
			foreach (Player allPlayer in Player.GetAllPlayers())
			{
				ZNetView component = ((Component)allPlayer).GetComponent<ZNetView>();
				if ((Object)(object)component != (Object)null)
				{
					ZDO zDO = component.GetZDO();
					if (((zDO != null) ? new long?(zDO.GetOwner()) : ((long?)null)) == activeSession.HostPeerId)
					{
						text = allPlayer.GetPlayerName();
						break;
					}
				}
			}
			GUILayout.Space(4f);
			GUI.backgroundColor = new Color(0.15f, 0.45f, 0.15f, 0.95f);
			if (GUILayout.Button("\ud83c\udfb5  Join  " + text + "'s  \"" + activeSession.Song.Name + "\"  →", JoinBannerStyle(), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(40f) }))
			{
				JoinSession();
			}
			GUI.backgroundColor = Color.white;
			GUILayout.Space(6f);
			DrawHorizontalLine();
			GUILayout.Space(4f);
		}

		private void DrawSongList()
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_016b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0186: Unknown result type (might be due to invalid IL or missing references)
			//IL_018c: Unknown result type (might be due to invalid IL or missing references)
			_scrollPos = GUILayout.BeginScrollView(_scrollPos, (GUILayoutOption[])(object)new GUILayoutOption[2]
			{
				GUILayout.Width(444f),
				GUILayout.Height(400f)
			});
			for (int i = 0; i < _availableSongs.Count; i++)
			{
				SongData songData = _availableSongs[i];
				GUI.backgroundColor = ((i == _selectedIndex) ? new Color(0.65f, 0.48f, 0.1f, 0.95f) : new Color(0.18f, 0.14f, 0.07f, 0.85f));
				if (GUILayout.Button("", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(54f) }))
				{
					_selectedIndex = i;
				}
				Rect lastRect = GUILayoutUtility.GetLastRect();
				GUI.Label(new Rect(((Rect)(ref lastRect)).x + 10f, ((Rect)(ref lastRect)).y + 5f, ((Rect)(ref lastRect)).width - 100f, 22f), songData.Name, SongNameStyle());
				GUI.Label(new Rect(((Rect)(ref lastRect)).x + 10f, ((Rect)(ref lastRect)).y + 28f, ((Rect)(ref lastRect)).width - 100f, 17f), songData.Author + "  ·  " + songData.Mood, SubtitleStyle());
				GUI.Label(new Rect(((Rect)(ref lastRect)).xMax - 90f, ((Rect)(ref lastRect)).y + 18f, 80f, 18f), FormatDuration(songData.Duration), DurationStyle());
				DrawStemDots(songData, lastRect);
				GUI.backgroundColor = Color.white;
				GUILayout.Space(2f);
			}
			if (_availableSongs.Count == 0)
			{
				GUILayout.Label("No songs found.\nAdd .json + .ogg files to:\nBepInEx/config/Bragi/songs/", SmallLabel(), Array.Empty<GUILayoutOption>());
			}
			GUILayout.EndScrollView();
		}

		private static void DrawStemDots(SongData song, Rect btnRect)
		{
			//IL_009f: 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_0087: 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_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: 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_00da: 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_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			if (song.Tracks == null || song.Tracks.Count == 0)
			{
				return;
			}
			float num = ((Rect)(ref btnRect)).x + 10f;
			float num2 = ((Rect)(ref btnRect)).yMax - 12f;
			foreach (InstrumentType value in Enum.GetValues(typeof(InstrumentType)))
			{
				if (song.HasStemFor(value))
				{
					GUI.color = (Color)(value switch
					{
						InstrumentType.BoneFlute => new Color(0.6f, 0.9f, 0.6f), 
						InstrumentType.Lyre => new Color(0.9f, 0.85f, 0.4f), 
						InstrumentType.JawHarp => new Color(0.7f, 0.5f, 0.9f), 
						_ => Color.white, 
					});
					GUI.DrawTexture(new Rect(num, num2, 8f, 8f), (Texture)(object)Texture2D.whiteTexture);
					GUI.color = Color.white;
					num += 12f;
				}
			}
		}

		private void DrawFooter()
		{
			DrawHorizontalLine();
			GUILayout.Space(6f);
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUI.enabled = _selectedIndex >= 0;
			if (GUILayout.Button("▶  Play", (GUILayoutOption[])(object)new GUILayoutOption[2]
			{
				GUILayout.Height(34f),
				GUILayout.Width(130f)
			}))
			{
				PlaySelected();
			}
			GUI.enabled = true;
			SongPlayer? instance = SongPlayer.Instance;
			if (instance != null && instance.IsPlaying && GUILayout.Button("■  Stop", (GUILayoutOption[])(object)new GUILayoutOption[2]
			{
				GUILayout.Height(34f),
				GUILayout.Width(90f)
			}))
			{
				SongPlayer.Instance.StopPlaying();
			}
			GUILayout.FlexibleSpace();
			if (GUILayout.Button("✕", (GUILayoutOption[])(object)new GUILayoutOption[2]
			{
				GUILayout.Height(34f),
				GUILayout.Width(34f)
			}))
			{
				Close();
			}
			GUILayout.EndHorizontal();
			GUILayout.Space(8f);
		}

		public void Open(InstrumentType instrumentType)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			_availableSongs = SongLibrary.GetSongsForInstrument(instrumentType);
			_selectedIndex = ((_availableSongs.Count <= 0) ? (-1) : 0);
			_scrollPos = Vector2.zero;
			IsOpen = true;
			Cursor.lockState = (CursorLockMode)0;
			Cursor.visible = true;
		}

		public void Close()
		{
			IsOpen = false;
			Cursor.lockState = (CursorLockMode)1;
			Cursor.visible = false;
		}

		private void ForceClose()
		{
			if (IsOpen)
			{
				Close();
			}
		}

		public void Toggle()
		{
			if (IsOpen)
			{
				Close();
				return;
			}
			InstrumentType? equippedInstrumentType = GetEquippedInstrumentType();
			if (equippedInstrumentType.HasValue)
			{
				Open(equippedInstrumentType.Value);
			}
		}

		private void PlaySelected()
		{
			if (_selectedIndex >= 0 && _selectedIndex < _availableSongs.Count)
			{
				SongData song = _availableSongs[_selectedIndex];
				SongPlayer instance = SongPlayer.Instance;
				if (!((Object)(object)instance == (Object)null))
				{
					instance.StartNewSession(song);
					Close();
				}
			}
		}

		private void JoinSession()
		{
			SongPlayer instance = SongPlayer.Instance;
			if (!((Object)(object)instance == (Object)null))
			{
				instance.JoinActiveSession();
				Close();
			}
		}

		private static bool IsInstrumentEquipped()
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				return false;
			}
			return ((Humanoid)localPlayer).GetInventory().GetEquippedItems().Exists(delegate(ItemData i)
			{
				GameObject dropPrefab = i.m_dropPrefab;
				return InstrumentDefinitions.IsInstrument(((dropPrefab != null) ? ((Object)dropPrefab).name : null) ?? "");
			});
		}

		private static InstrumentType? GetEquippedInstrumentType()
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				return null;
			}
			ItemData val = ((Humanoid)localPlayer).GetInventory().GetEquippedItems().Find(delegate(ItemData i)
			{
				GameObject dropPrefab2 = i.m_dropPrefab;
				return InstrumentDefinitions.IsInstrument(((dropPrefab2 != null) ? ((Object)dropPrefab2).name : null) ?? "");
			});
			if (val == null)
			{
				return null;
			}
			GameObject dropPrefab = val.m_dropPrefab;
			return InstrumentDefinitions.GetType(((dropPrefab != null) ? ((Object)dropPrefab).name : null) ?? "");
		}

		private static string GetInstrumentDisplayName()
		{
			return GetEquippedInstrumentType() switch
			{
				InstrumentType.Lyre => "Lyre", 
				InstrumentType.BoneFlute => "Bone Flute", 
				InstrumentType.JawHarp => "Jaw Harp", 
				_ => "Instrument", 
			};
		}

		private static string FormatDuration(float seconds)
		{
			TimeSpan timeSpan = TimeSpan.FromSeconds(seconds);
			if (timeSpan.Minutes <= 0)
			{
				return $"0:{timeSpan.Seconds:00}";
			}
			return $"{timeSpan.Minutes}:{timeSpan.Seconds:00}";
		}

		private static void DrawHorizontalLine()
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			Rect rect = GUILayoutUtility.GetRect(1f, 1f, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) });
			GUI.color = new Color(0.6f, 0.45f, 0.1f);
			GUI.DrawTexture(rect, (Texture)(object)Texture2D.whiteTexture);
			GUI.color = Color.white;
		}

		private static GUIStyle LargeLabel()
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Expected O, but got Unknown
			GUIStyle val = new GUIStyle(GUI.skin.label)
			{
				fontSize = 18,
				fontStyle = (FontStyle)1,
				alignment = (TextAnchor)4
			};
			val.normal.textColor = new Color(0.95f, 0.8f, 0.4f);
			return val;
		}

		private static GUIStyle SmallLabel()
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Expected O, but got Unknown
			GUIStyle val = new GUIStyle(GUI.skin.label)
			{
				fontSize = 11,
				alignment = (TextAnchor)4
			};
			val.normal.textColor = new Color(0.75f, 0.68f, 0.55f);
			return val;
		}

		private static GUIStyle JoinBannerStyle()
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Expected O, but got Unknown
			GUIStyle val = new GUIStyle(GUI.skin.button)
			{
				fontSize = 13,
				fontStyle = (FontStyle)1,
				alignment = (TextAnchor)4
			};
			val.normal.textColor = new Color(0.85f, 1f, 0.85f);
			val.hover.textColor = Color.white;
			return val;
		}

		private static GUIStyle SongNameStyle()
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Expected O, but got Unknown
			GUIStyle val = new GUIStyle(GUI.skin.label)
			{
				fontSize = 13,
				fontStyle = (FontStyle)1
			};
			val.normal.textColor = new Color(0.95f, 0.9f, 0.8f);
			return val;
		}

		private static GUIStyle SubtitleStyle()
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Expected O, but got Unknown
			GUIStyle val = new GUIStyle(GUI.skin.label)
			{
				fontSize = 10
			};
			val.normal.textColor = new Color(0.7f, 0.65f, 0.5f);
			return val;
		}

		private static GUIStyle DurationStyle()
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Expected O, but got Unknown
			GUIStyle val = new GUIStyle(GUI.skin.label)
			{
				fontSize = 11,
				alignment = (TextAnchor)5
			};
			val.normal.textColor = new Color(0.6f, 0.8f, 0.6f);
			return val;
		}
	}
	[HarmonyPatch(typeof(PlayerController), "InInventoryEtc")]
	internal static class BlockInputWhileUIOpenPatch
	{
		[HarmonyPostfix]
		private static void Postfix(ref bool __result)
		{
			if (SongSelectUI.IsOpen)
			{
				__result = true;
			}
		}
	}
}