Decompiled source of GlitnirSounds v0.1.2

GlitnirMusicZones.dll

Decompiled 2 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.Networking;
using YamlDotNet.Serialization;
using YamlDotNet.Serialization.NamingConventions;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("GlitnirMusicZones")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("GlitnirMusicZones")]
[assembly: AssemblyTitle("GlitnirMusicZones")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.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 GlitnirMusicZones
{
	internal static class DefaultConfig
	{
		public const string YAML = "# ╔══════════════════════════════════════════════════════════════════╗\r\n# ║           GLITNIR MUSIC ZONES — music_config.yaml               ║\r\n# ╚══════════════════════════════════════════════════════════════════╝\r\n# Use URLs diretas de MP3 (sem expiração). Recomendado: GitHub Releases\r\n# ou cdn.pixabay.com. Evite links do Discord (expiram em horas).\r\n#\r\n# Após salvar o arquivo, a config recarrega automaticamente no jogo.\r\n\r\n# ─── MENU PRINCIPAL ────────────────────────────────────────────────\r\nmenu:\r\n  enabled: true\r\n  volume: 0.3\r\n  url: \"https://cdn.pixabay.com/download/audio/2025/07/24/audio_9d4a9c72f8.mp3?filename=wesleysert-glitnir-valhhala-1-379314.mp3\"\r\n\r\n# ─── BIOMAS ────────────────────────────────────────────────────────\r\n# Biomas disponíveis: Meadows, BlackForest, Swamp, Mountain, Plains,\r\n#                     Mistlands, AshLands, DeepNorth, Ocean\r\nbiomes:\r\n  enabled: true\r\n  volume: 0.6\r\n  tracks:\r\n    Meadows:\r\n      enabled: true\r\n      url: \"\"\r\n    BlackForest:\r\n      enabled: true\r\n      url: \"\"\r\n    Swamp:\r\n      enabled: true\r\n      url: \"\"\r\n    Mountain:\r\n      enabled: true\r\n      url: \"\"\r\n    Plains:\r\n      enabled: true\r\n      url: \"\"\r\n    Mistlands:\r\n      enabled: true\r\n      url: \"\"\r\n    AshLands:\r\n      enabled: true\r\n      url: \"\"\r\n    DeepNorth:\r\n      enabled: true\r\n      url: \"\"\r\n    Ocean:\r\n      enabled: true\r\n      url: \"\"\r\n\r\n# ─── TERRITÓRIOS (Locations do ZoneSystem) ─────────────────────────\r\n# location:      nome exato da Location (ex: StartTemple, Crypt2)\r\n# radius:        raio em unidades (0 = usa o radius global abaixo)\r\n# dungeon_only:  true = só toca dentro da dungeon (faixa Y)\r\n# dungeon_y_min/max: faixa Y da dungeon (-1 = usa o global)\r\nterritories:\r\n  enabled: true\r\n  volume: 0.65\r\n  radius: 90.0\r\n  dungeon_y_min: 4500.0\r\n  dungeon_y_max: 5500.0\r\n  tracks:\r\n    - enabled: true\r\n      location: StartTemple\r\n      radius: 60.0\r\n      dungeon_only: false\r\n      dungeon_y_min: -1\r\n      dungeon_y_max: -1\r\n      url: \"\"\r\n\r\n    - enabled: false\r\n      location: Vendor_BlackForest\r\n      radius: 0.0\r\n      dungeon_only: false\r\n      dungeon_y_min: -1\r\n      dungeon_y_max: -1\r\n      url: \"\"\r\n\r\n    - enabled: true\r\n      location: Crypt2\r\n      radius: 90.0\r\n      dungeon_only: true\r\n      dungeon_y_min: 4500\r\n      dungeon_y_max: 5500\r\n      url: \"\"\r\n\r\n    - enabled: true\r\n      location: Crypt3\r\n      radius: 90.0\r\n      dungeon_only: true\r\n      dungeon_y_min: 4500\r\n      dungeon_y_max: 5500\r\n      url: \"\"\r\n\r\n    - enabled: true\r\n      location: Crypt4\r\n      radius: 90.0\r\n      dungeon_only: true\r\n      dungeon_y_min: 4500\r\n      dungeon_y_max: 5500\r\n      url: \"\"\r\n\r\n# ─── ZONAS POR COORDENADA ──────────────────────────────────────────\r\n# Use para vilas ou regiões sem Location no ZoneSystem.\r\n# x/z: coordenadas do centro no mapa do Valheim\r\nzones:\r\n  enabled: true\r\n  tracks:\r\n    - enabled: false\r\n      name: Exemplo Vila\r\n      x: 0.0\r\n      z: 0.0\r\n      radius: 80.0\r\n      volume: 0.65\r\n      url: \"\"\r\n\r\n# ─── BOSSES ────────────────────────────────────────────────────────\r\n# Prefab name do boss sem '(Clone)'. Toca enquanto o boss estiver vivo no raio.\r\n# Bosses vanilla: Eikthyr, gd_king, Bonemass, Dragon, GoblinKing, SeekerQueen, Fader\r\nbosses:\r\n  enabled: true\r\n  volume: 0.7\r\n  radius: 120.0\r\n  tracks:\r\n    Eikthyr:\r\n      enabled: true\r\n      url: \"\"\r\n    gd_king:\r\n      enabled: true\r\n      url: \"\"\r\n    Bonemass:\r\n      enabled: true\r\n      url: \"\"\r\n    Dragon:\r\n      enabled: true\r\n      url: \"\"\r\n    GoblinKing:\r\n      enabled: true\r\n      url: \"\"\r\n    SeekerQueen:\r\n      enabled: true\r\n      url: \"\"\r\n    Fader:\r\n      enabled: true\r\n      url: \"\"\r\n\r\n# ─── CRIATURAS ─────────────────────────────────────────────────────\r\n# Toca enquanto houver ao menos uma criatura viva no raio.\r\ncreatures:\r\n  enabled: true\r\n  volume: 0.55\r\n  radius: 30.0\r\n  tracks:\r\n    Troll:\r\n      enabled: false\r\n      url: \"\"\r\n    GoblinBrute:\r\n      enabled: false\r\n      url: \"\"\r\n    BlobTar:\r\n      enabled: false\r\n      url: \"\"\r\n    Seeker:\r\n      enabled: false\r\n      url: \"\"\r\n    Leech:\r\n      enabled: false\r\n      url: \"\"\r\n";
	}
	internal static class MusicManPatches
	{
		private static AudioSource _musicManSource = null;

		private static float _volCheckTimer = 0f;

		private static AudioSource MusicManSource
		{
			get
			{
				if ((Object)(object)_musicManSource == (Object)null && (Object)(object)MusicMan.instance != (Object)null)
				{
					_musicManSource = ((Component)MusicMan.instance).GetComponent<AudioSource>();
				}
				return _musicManSource;
			}
		}

		public static float RealMusicVolume { get; private set; } = PlayerPrefs.GetFloat("MusicVolume", 1f);


		public static void InvalidateSourceCache()
		{
			_musicManSource = null;
		}

		private static bool PrefixStartMusic()
		{
			if (!Plugin.VanillaMuted)
			{
				return true;
			}
			AudioSource musicManSource = MusicManSource;
			if (musicManSource != null)
			{
				musicManSource.Stop();
			}
			return false;
		}

		private static bool PrefixQueue()
		{
			return !Plugin.VanillaMuted;
		}

		private static void PrefixUpdate()
		{
			_volCheckTimer += Time.deltaTime;
			if (!(_volCheckTimer < 0.2f))
			{
				_volCheckTimer = 0f;
				float @float = PlayerPrefs.GetFloat("MusicVolume", 1f);
				if (@float >= 0f)
				{
					RealMusicVolume = @float;
				}
			}
		}

		private static void PostfixUpdate()
		{
			if (Plugin.VanillaMuted)
			{
				MusicMan.m_masterMusicVolume = 0f;
				AudioSource musicManSource = MusicManSource;
				if ((Object)(object)musicManSource != (Object)null && musicManSource.isPlaying)
				{
					musicManSource.Stop();
				}
			}
		}

		public static void ApplyAll(Harmony harmony)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Expected O, but got Unknown
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Expected O, but got Unknown
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Expected O, but got Unknown
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Expected O, but got Unknown
			Type typeFromHandle = typeof(MusicManPatches);
			HarmonyMethod val = new HarmonyMethod(typeFromHandle.GetMethod("PrefixStartMusic", BindingFlags.Static | BindingFlags.NonPublic));
			HarmonyMethod val2 = new HarmonyMethod(typeFromHandle.GetMethod("PrefixQueue", BindingFlags.Static | BindingFlags.NonPublic));
			HarmonyMethod val3 = new HarmonyMethod(typeFromHandle.GetMethod("PostfixUpdate", BindingFlags.Static | BindingFlags.NonPublic));
			MethodInfo[] methods = typeof(MusicMan).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (MethodInfo methodInfo in methods)
			{
				if (methodInfo.Name == "StartMusic")
				{
					harmony.Patch((MethodBase)methodInfo, val, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				}
				else if (methodInfo.Name == "Queue")
				{
					harmony.Patch((MethodBase)methodInfo, val2, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				}
			}
			HarmonyMethod val4 = new HarmonyMethod(typeFromHandle.GetMethod("PrefixUpdate", BindingFlags.Static | BindingFlags.NonPublic));
			MethodInfo method = typeof(MusicMan).GetMethod("Update", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (method != null)
			{
				harmony.Patch((MethodBase)method, val4, val3, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
		}
	}
	public class YamlConfig
	{
		public YamlMenu menu { get; set; } = new YamlMenu();


		public YamlBiomes biomes { get; set; } = new YamlBiomes();


		public YamlTerritories territories { get; set; } = new YamlTerritories();


		public YamlZones zones { get; set; } = new YamlZones();


		public YamlBosses bosses { get; set; } = new YamlBosses();


		public YamlCreatures creatures { get; set; } = new YamlCreatures();

	}
	public class YamlMenu
	{
		public bool enabled { get; set; } = true;


		public float volume { get; set; } = 0.3f;


		public string url { get; set; } = "";

	}
	public class YamlBiomes
	{
		public bool enabled { get; set; } = true;


		public float volume { get; set; } = 0.6f;


		public Dictionary<string, YamlTrack> tracks { get; set; } = new Dictionary<string, YamlTrack>();

	}
	public class YamlTerritories
	{
		public bool enabled { get; set; } = true;


		public float volume { get; set; } = 0.65f;


		public float radius { get; set; } = 90f;


		public float dungeon_y_min { get; set; } = 4500f;


		public float dungeon_y_max { get; set; } = 5500f;


		public List<YamlTerritoryTrack> tracks { get; set; } = new List<YamlTerritoryTrack>();

	}
	public class YamlZones
	{
		public bool enabled { get; set; } = true;


		public List<YamlZoneTrack> tracks { get; set; } = new List<YamlZoneTrack>();

	}
	public class YamlBosses
	{
		public bool enabled { get; set; } = true;


		public float volume { get; set; } = 0.7f;


		public float radius { get; set; } = 120f;


		public Dictionary<string, YamlTrack> tracks { get; set; } = new Dictionary<string, YamlTrack>();

	}
	public class YamlCreatures
	{
		public bool enabled { get; set; } = true;


		public float volume { get; set; } = 0.55f;


		public float radius { get; set; } = 30f;


		public Dictionary<string, YamlTrack> tracks { get; set; } = new Dictionary<string, YamlTrack>();

	}
	public class YamlTrack
	{
		public bool enabled { get; set; } = true;


		public string url { get; set; } = "";

	}
	public class YamlTerritoryTrack
	{
		public bool enabled { get; set; } = true;


		public string location { get; set; } = "";


		public float radius { get; set; } = 0f;


		public bool dungeon_only { get; set; } = false;


		public float dungeon_y_min { get; set; } = -1f;


		public float dungeon_y_max { get; set; } = -1f;


		public string url { get; set; } = "";

	}
	public class YamlZoneTrack
	{
		public bool enabled { get; set; } = true;


		public string name { get; set; } = "";


		public float x { get; set; } = 0f;


		public float z { get; set; } = 0f;


		public float radius { get; set; } = 60f;


		public float volume { get; set; } = 0.65f;


		public string url { get; set; } = "";

	}
	[BepInPlugin("glitnir.musiczones", "Glitnir Music Zones", "1.0.0")]
	public class Plugin : BaseUnityPlugin
	{
		private enum MusicState
		{
			None,
			Menu,
			Biome,
			Territory,
			Boss,
			Creature
		}

		internal class TerritoryEntry
		{
			public string location;

			public float radius;

			public float dungeonYMin;

			public float dungeonYMax;

			public bool dungeonOnly;

			public bool enabled;

			public string url;

			public bool IsActive => enabled && !string.IsNullOrWhiteSpace(url) && !string.IsNullOrWhiteSpace(location);
		}

		internal class ZoneEntry
		{
			public string name;

			public float x;

			public float z;

			public float radius;

			public float volume;

			public bool enabled;

			public string url;

			public bool IsActive => enabled && !string.IsNullOrWhiteSpace(url);
		}

		internal class MusicEntry
		{
			public bool enabled;

			public string url;

			public bool IsActive => enabled && !string.IsNullOrWhiteSpace(url);

			public MusicEntry(bool enabled, string url)
			{
				this.enabled = enabled;
				this.url = url ?? "";
			}
		}

		[CompilerGenerated]
		private sealed class <FadeOutAndStop>d__68 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			public bool andUnmute;

			public Plugin <>4__this;

			private float <startVol>5__1;

			private float <t>5__2;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <FadeOutAndStop>d__68(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<startVol>5__1 = audioSource.volume;
					<t>5__2 = 0f;
					break;
				case 1:
					<>1__state = -1;
					break;
				}
				if (<t>5__2 < <>4__this.fadeDuration)
				{
					<t>5__2 += Time.deltaTime;
					audioSource.volume = Mathf.Lerp(<startVol>5__1, 0f, <t>5__2 / <>4__this.fadeDuration);
					<>2__current = null;
					<>1__state = 1;
					return true;
				}
				audioSource.Stop();
				<>4__this.ReleaseCurrentClip();
				if (andUnmute)
				{
					<>4__this.UnmuteVanilla();
				}
				return false;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		[CompilerGenerated]
		private sealed class <FadeSwitch>d__67 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			public string url;

			public float cfgVolume;

			public Plugin <>4__this;

			private float <waitLimit>5__1;

			private float <waited>5__2;

			private float <startVol>5__3;

			private float <t>5__4;

			private AudioClip <cached>5__5;

			private float <dt>5__6;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <FadeSwitch>d__67(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<cached>5__5 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<waitLimit>5__1 = <>4__this.fadeDuration + 15f;
					<waited>5__2 = 0f;
					<startVol>5__3 = audioSource.volume;
					<t>5__4 = 0f;
					goto IL_0156;
				case 1:
					<>1__state = -1;
					goto IL_0156;
				case 2:
					<>1__state = -1;
					goto IL_0297;
				case 3:
					{
						<>1__state = -1;
						break;
					}
					IL_0156:
					if (<t>5__4 < <>4__this.fadeDuration || (<>4__this.preloadingUrls.Contains(url) && <waited>5__2 < <waitLimit>5__1))
					{
						<dt>5__6 = Time.deltaTime;
						<t>5__4 += <dt>5__6;
						<waited>5__2 += <dt>5__6;
						if (<t>5__4 <= <>4__this.fadeDuration)
						{
							audioSource.volume = Mathf.Lerp(<startVol>5__3, 0f, <t>5__4 / <>4__this.fadeDuration);
						}
						else
						{
							audioSource.volume = 0f;
						}
						if (<>4__this.preloadingUrls.Contains(url) || !(<t>5__4 >= <>4__this.fadeDuration))
						{
							<>2__current = null;
							<>1__state = 1;
							return true;
						}
					}
					audioSource.Stop();
					<>4__this.ReleaseCurrentClip();
					if (<>4__this.clipCache.TryGetValue(url, out <cached>5__5) && (Object)(object)<cached>5__5 != (Object)null)
					{
						<>4__this.currentClipUrl = url;
						audioSource.clip = <cached>5__5;
						audioSource.volume = 0f;
						audioSource.Play();
						<t>5__4 = 0f;
						goto IL_0297;
					}
					<>2__current = ((MonoBehaviour)<>4__this).StartCoroutine(<>4__this.LoadAndFadeIn(url, cfgVolume));
					<>1__state = 3;
					return true;
					IL_0297:
					if (<t>5__4 < <>4__this.fadeDuration)
					{
						<t>5__4 += Time.deltaTime;
						audioSource.volume = Mathf.Lerp(0f, <>4__this.FinalVolume(cfgVolume), <t>5__4 / <>4__this.fadeDuration);
						<>2__current = null;
						<>1__state = 2;
						return true;
					}
					audioSource.volume = <>4__this.FinalVolume(cfgVolume);
					((BaseUnityPlugin)<>4__this).Logger.LogInfo((object)$"[Glitnir] Tocando do cache (vol={audioSource.volume:F2}).");
					break;
				}
				return false;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		[CompilerGenerated]
		private sealed class <FadeSwitchCached>d__66 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			public AudioClip nextClip;

			public string url;

			public float cfgVolume;

			public Plugin <>4__this;

			private float <startVol>5__1;

			private float <t>5__2;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <FadeSwitchCached>d__66(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<startVol>5__1 = audioSource.volume;
					<t>5__2 = 0f;
					goto IL_00a3;
				case 1:
					<>1__state = -1;
					goto IL_00a3;
				case 2:
					{
						<>1__state = -1;
						break;
					}
					IL_00a3:
					if (<t>5__2 < <>4__this.fadeDuration)
					{
						<t>5__2 += Time.deltaTime;
						audioSource.volume = Mathf.Lerp(<startVol>5__1, 0f, <t>5__2 / <>4__this.fadeDuration);
						<>2__current = null;
						<>1__state = 1;
						return true;
					}
					audioSource.Stop();
					<>4__this.currentClipUrl = url;
					audioSource.clip = nextClip;
					audioSource.volume = 0f;
					audioSource.Play();
					<t>5__2 = 0f;
					break;
				}
				if (<t>5__2 < <>4__this.fadeDuration)
				{
					<t>5__2 += Time.deltaTime;
					audioSource.volume = Mathf.Lerp(0f, <>4__this.FinalVolume(cfgVolume), <t>5__2 / <>4__this.fadeDuration);
					<>2__current = null;
					<>1__state = 2;
					return true;
				}
				audioSource.volume = <>4__this.FinalVolume(cfgVolume);
				((BaseUnityPlugin)<>4__this).Logger.LogInfo((object)$"[Glitnir] Tocando do cache (vol={audioSource.volume:F2}).");
				return false;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		[CompilerGenerated]
		private sealed class <LoadAndFadeIn>d__69 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			public string url;

			public float cfgVolume;

			public Plugin <>4__this;

			private AudioClip <preloaded>5__1;

			private float <t2>5__2;

			private UnityWebRequest <req>5__3;

			private AudioClip <clip>5__4;

			private float <t>5__5;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <LoadAndFadeIn>d__69(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				int num = <>1__state;
				if (num == -3 || (uint)(num - 2) <= 1u)
				{
					try
					{
					}
					finally
					{
						<>m__Finally1();
					}
				}
				<preloaded>5__1 = null;
				<req>5__3 = null;
				<clip>5__4 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_0213: Unknown result type (might be due to invalid IL or missing references)
				//IL_0219: Invalid comparison between Unknown and I4
				//IL_01cc: Unknown result type (might be due to invalid IL or missing references)
				bool result;
				try
				{
					switch (<>1__state)
					{
					default:
						result = false;
						goto end_IL_0000;
					case 0:
						<>1__state = -1;
						if (string.IsNullOrWhiteSpace(url))
						{
							result = false;
						}
						else
						{
							if (<>4__this.clipCache.TryGetValue(url, out <preloaded>5__1) && (Object)(object)<preloaded>5__1 != (Object)null)
							{
								<>4__this.currentClipUrl = url;
								audioSource.clip = <preloaded>5__1;
								audioSource.volume = 0f;
								audioSource.Play();
								<t2>5__2 = 0f;
								goto IL_013c;
							}
							<req>5__3 = UnityWebRequestMultimedia.GetAudioClip(url, (AudioType)13);
							<>1__state = -3;
							((DownloadHandlerAudioClip)<req>5__3.downloadHandler).compressed = false;
							<req>5__3.timeout = 15;
							<>2__current = <req>5__3.SendWebRequest();
							<>1__state = 2;
							result = true;
						}
						goto end_IL_0000;
					case 1:
						<>1__state = -1;
						goto IL_013c;
					case 2:
						<>1__state = -3;
						if ((int)<req>5__3.result != 1)
						{
							((BaseUnityPlugin)<>4__this).Logger.LogError((object)("[Glitnir] Erro ao carregar: " + <req>5__3.error + " — URL: " + url));
							<>4__this.clipCache[url] = null;
							result = false;
							break;
						}
						<clip>5__4 = DownloadHandlerAudioClip.GetContent(<req>5__3);
						if ((Object)(object)<clip>5__4 == (Object)null || <>4__this.currentUrl != url)
						{
							if ((Object)(object)<clip>5__4 != (Object)null)
							{
								Object.Destroy((Object)(object)<clip>5__4);
							}
							result = false;
							break;
						}
						<>4__this.clipCache[url] = <clip>5__4;
						<>4__this.preloadingUrls.Remove(url);
						<>4__this.ReleaseCurrentClip();
						audioSource.clip = <clip>5__4;
						audioSource.volume = 0f;
						audioSource.Play();
						<>4__this.currentClipUrl = url;
						<t>5__5 = 0f;
						goto IL_03cc;
					case 3:
						{
							<>1__state = -3;
							goto IL_03cc;
						}
						IL_013c:
						if (<t2>5__2 < <>4__this.fadeDuration)
						{
							<t2>5__2 += Time.deltaTime;
							audioSource.volume = Mathf.Lerp(0f, <>4__this.FinalVolume(cfgVolume), <t2>5__2 / <>4__this.fadeDuration);
							<>2__current = null;
							<>1__state = 1;
							result = true;
						}
						else
						{
							audioSource.volume = <>4__this.FinalVolume(cfgVolume);
							((BaseUnityPlugin)<>4__this).Logger.LogInfo((object)$"[Glitnir] Tocando (vol={audioSource.volume:F2}).");
							result = false;
						}
						goto end_IL_0000;
						IL_03cc:
						if (<t>5__5 < <>4__this.fadeDuration)
						{
							<t>5__5 += Time.deltaTime;
							audioSource.volume = Mathf.Lerp(0f, <>4__this.FinalVolume(cfgVolume), <t>5__5 / <>4__this.fadeDuration);
							<>2__current = null;
							<>1__state = 3;
							result = true;
						}
						else
						{
							audioSource.volume = <>4__this.FinalVolume(cfgVolume);
							((BaseUnityPlugin)<>4__this).Logger.LogInfo((object)$"[Glitnir] Tocando (vol={audioSource.volume:F2}).");
							<clip>5__4 = null;
							<>m__Finally1();
							<req>5__3 = null;
							result = false;
						}
						goto end_IL_0000;
					}
					<>m__Finally1();
					end_IL_0000:;
				}
				catch
				{
					//try-fault
					((IDisposable)this).Dispose();
					throw;
				}
				return result;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			private void <>m__Finally1()
			{
				<>1__state = -1;
				if (<req>5__3 != null)
				{
					((IDisposable)<req>5__3).Dispose();
				}
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		[CompilerGenerated]
		private sealed class <PreloadClip>d__64 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			public string url;

			public Plugin <>4__this;

			private UnityWebRequest <req>5__1;

			private AudioClip <clip>5__2;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <PreloadClip>d__64(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				int num = <>1__state;
				if (num == -3 || num == 1)
				{
					try
					{
					}
					finally
					{
						<>m__Finally1();
					}
				}
				<req>5__1 = null;
				<clip>5__2 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_0087: Unknown result type (might be due to invalid IL or missing references)
				//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
				//IL_00d4: Invalid comparison between Unknown and I4
				bool result;
				try
				{
					switch (<>1__state)
					{
					default:
						result = false;
						break;
					case 0:
						<>1__state = -1;
						<>4__this.preloadingUrls.Add(url);
						((BaseUnityPlugin)<>4__this).Logger.LogInfo((object)("[Glitnir] Pré-carregando: " + url));
						<req>5__1 = UnityWebRequestMultimedia.GetAudioClip(url, (AudioType)13);
						<>1__state = -3;
						((DownloadHandlerAudioClip)<req>5__1.downloadHandler).compressed = false;
						<req>5__1.timeout = 20;
						<>2__current = <req>5__1.SendWebRequest();
						<>1__state = 1;
						result = true;
						break;
					case 1:
						<>1__state = -3;
						if ((int)<req>5__1.result != 1)
						{
							((BaseUnityPlugin)<>4__this).Logger.LogWarning((object)("[Glitnir] Falha no pré-carregamento: " + <req>5__1.error + " — URL: " + url));
							<>4__this.clipCache[url] = null;
							<>4__this.preloadingUrls.Remove(url);
							result = false;
							<>m__Finally1();
							break;
						}
						<clip>5__2 = DownloadHandlerAudioClip.GetContent(<req>5__1);
						if ((Object)(object)<clip>5__2 != (Object)null)
						{
							<>4__this.clipCache[url] = <clip>5__2;
							((BaseUnityPlugin)<>4__this).Logger.LogInfo((object)$"[Glitnir] Cache: {((Object)<clip>5__2).name} ({<>4__this.clipCache.Count} clips em RAM)");
						}
						<>4__this.preloadingUrls.Remove(url);
						<clip>5__2 = null;
						<>m__Finally1();
						<req>5__1 = null;
						result = false;
						break;
					}
				}
				catch
				{
					//try-fault
					((IDisposable)this).Dispose();
					throw;
				}
				return result;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			private void <>m__Finally1()
			{
				<>1__state = -1;
				if (<req>5__1 != null)
				{
					((IDisposable)<req>5__1).Dispose();
				}
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		[CompilerGenerated]
		private sealed class <PreloadMenuMusic>d__71 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			public Plugin <>4__this;

			private AudioClip <cached>5__1;

			private UnityWebRequest <req>5__2;

			private AudioClip <clip>5__3;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <PreloadMenuMusic>d__71(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				int num = <>1__state;
				if (num == -3 || num == 1)
				{
					try
					{
					}
					finally
					{
						<>m__Finally1();
					}
				}
				<cached>5__1 = null;
				<req>5__2 = null;
				<clip>5__3 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_016a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0170: Invalid comparison between Unknown and I4
				//IL_0123: Unknown result type (might be due to invalid IL or missing references)
				bool result;
				try
				{
					switch (<>1__state)
					{
					default:
						result = false;
						break;
					case 0:
						<>1__state = -1;
						if (<>4__this.menuEntry == null || !<>4__this.menuEnabled || !<>4__this.menuEntry.IsActive)
						{
							result = false;
						}
						else if (<>4__this.clipCache.TryGetValue(<>4__this.menuEntry.url, out <cached>5__1))
						{
							if ((Object)(object)<cached>5__1 != (Object)null)
							{
								<>4__this.menuClip = <cached>5__1;
								<>4__this.menuClipReady = true;
								((BaseUnityPlugin)<>4__this).Logger.LogInfo((object)"[Glitnir] Menu: usando clip do cache.");
							}
							result = false;
						}
						else
						{
							((BaseUnityPlugin)<>4__this).Logger.LogInfo((object)"[Glitnir] Pré-carregando música do menu...");
							<req>5__2 = UnityWebRequestMultimedia.GetAudioClip(<>4__this.menuEntry.url, (AudioType)13);
							<>1__state = -3;
							((DownloadHandlerAudioClip)<req>5__2.downloadHandler).compressed = false;
							<req>5__2.timeout = 15;
							<>2__current = <req>5__2.SendWebRequest();
							<>1__state = 1;
							result = true;
						}
						break;
					case 1:
						<>1__state = -3;
						if ((int)<req>5__2.result != 1)
						{
							((BaseUnityPlugin)<>4__this).Logger.LogError((object)("[Glitnir] Falha no menu: " + <req>5__2.error));
							<>4__this.clipCache[<>4__this.menuEntry.url] = null;
							result = false;
							<>m__Finally1();
							break;
						}
						<clip>5__3 = DownloadHandlerAudioClip.GetContent(<req>5__2);
						if ((Object)(object)<clip>5__3 != (Object)null)
						{
							<>4__this.clipCache[<>4__this.menuEntry.url] = <clip>5__3;
							<>4__this.menuClip = <clip>5__3;
							<>4__this.menuClipReady = true;
						}
						((BaseUnityPlugin)<>4__this).Logger.LogInfo((object)("[Glitnir] Menu " + (<>4__this.menuClipReady ? "pronto." : "clip nulo!")));
						<clip>5__3 = null;
						<>m__Finally1();
						<req>5__2 = null;
						result = false;
						break;
					}
				}
				catch
				{
					//try-fault
					((IDisposable)this).Dispose();
					throw;
				}
				return result;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			private void <>m__Finally1()
			{
				<>1__state = -1;
				if (<req>5__2 != null)
				{
					((IDisposable)<req>5__2).Dispose();
				}
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		private static GameObject musicObject;

		private static AudioSource audioSource;

		private string currentClipUrl = "";

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

		private readonly HashSet<string> preloadingUrls = new HashSet<string>();

		private Coroutine fadeCoroutine = null;

		private float fadeDuration = 1f;

		private FileSystemWatcher configWatcher;

		private bool reloadPending = false;

		private float _reloadCooldown = 0f;

		private Harmony harmony;

		private MusicEntry menuEntry;

		private float menuVolume = 0.3f;

		private bool menuEnabled = true;

		private bool biomesEnabled = true;

		private float biomeVolume = 0.6f;

		private Dictionary<Biome, MusicEntry> biomeMap = new Dictionary<Biome, MusicEntry>();

		private bool terrEnabled = true;

		private float terrVolume = 0.65f;

		private float terrRadius = 90f;

		private float terrDungeonYMin = 4500f;

		private float terrDungeonYMax = 5500f;

		private List<TerritoryEntry> terrList = new List<TerritoryEntry>();

		private bool zonesEnabled = true;

		private List<ZoneEntry> zoneList = new List<ZoneEntry>();

		private bool bossEnabled = true;

		private float bossVolume = 0.7f;

		private float bossRadius = 120f;

		private Dictionary<string, MusicEntry> bossMap = new Dictionary<string, MusicEntry>();

		private bool creatEnabled = true;

		private float creatVolume = 0.55f;

		private float creatRadius = 30f;

		private Dictionary<string, MusicEntry> creatMap = new Dictionary<string, MusicEntry>();

		private MusicState currentState = MusicState.None;

		private string currentUrl = "";

		private AudioClip menuClip = null;

		private bool menuClipReady = false;

		private bool worldLoaded = false;

		private float checkInterval = 2f;

		private float checkTimer = 0f;

		private Vector3 _lastCheckPos = Vector3.zero;

		private readonly Dictionary<string, Vector3> _locPosCache = new Dictionary<string, Vector3>();

		private float _locCacheTimer = 0f;

		private const float PreloadAheadMultiplier = 1.5f;

		private readonly List<Character> _charBuffer = new List<Character>();

		public static bool VanillaMuted { get; private set; }

		private string ConfigPath => Path.Combine(Paths.ConfigPath, "glitnir.musiczones", "music_config.yaml");

		private float FinalVolume(float cfgVolume)
		{
			return cfgVolume * MusicManPatches.RealMusicVolume;
		}

		private float CurrentCfgVolume()
		{
			return currentState switch
			{
				MusicState.Boss => bossVolume, 
				MusicState.Creature => creatVolume, 
				MusicState.Territory => terrVolume, 
				MusicState.Biome => biomeVolume, 
				_ => menuVolume, 
			};
		}

		private void MuteVanilla()
		{
			if (!VanillaMuted)
			{
				VanillaMuted = true;
				MusicManPatches.InvalidateSourceCache();
				((BaseUnityPlugin)this).Logger.LogInfo((object)"[Glitnir] Vanilla silenciada.");
			}
		}

		private void UnmuteVanilla()
		{
			if (VanillaMuted)
			{
				VanillaMuted = false;
				((BaseUnityPlugin)this).Logger.LogInfo((object)"[Glitnir] Vanilla restaurada.");
			}
		}

		private void Awake()
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Expected O, but got Unknown
			((BaseUnityPlugin)this).Logger.LogInfo((object)"[Glitnir Music Zones] v1.0.0 iniciando...");
			harmony = new Harmony("glitnir.musiczones");
			try
			{
				MusicManPatches.ApplyAll(harmony);
				((BaseUnityPlugin)this).Logger.LogInfo((object)"[Glitnir] Patches Harmony aplicados com sucesso.");
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)("[Glitnir] Falha ao aplicar patches: " + ex.Message));
			}
			EnsureDefaultConfig();
			LoadConfig();
			CreateMusicPlayer();
			StartConfigWatcher();
			((MonoBehaviour)this).StartCoroutine(PreloadMenuMusic());
		}

		private void OnDestroy()
		{
			Harmony obj = harmony;
			if (obj != null)
			{
				obj.UnpatchSelf();
			}
			configWatcher?.Dispose();
			UnmuteVanilla();
			ClearCache();
		}

		private void Update()
		{
			if (_reloadCooldown > 0f)
			{
				_reloadCooldown -= Time.deltaTime;
			}
			if (reloadPending && _reloadCooldown <= 0f)
			{
				reloadPending = false;
				_reloadCooldown = 1f;
				((BaseUnityPlugin)this).Logger.LogInfo((object)"[Glitnir] Config alterada — recarregando...");
				LoadConfig();
				currentUrl = "";
				currentState = MusicState.None;
			}
			bool flag = (Object)(object)ZNet.instance != (Object)null;
			if (flag && !worldLoaded && (Object)(object)Player.m_localPlayer != (Object)null)
			{
				worldLoaded = true;
				((BaseUnityPlugin)this).Logger.LogInfo((object)"[Glitnir] Mundo carregado — parando música do menu.");
				StopOurMusic();
				menuClip = null;
				menuClipReady = false;
			}
			if (!flag && worldLoaded)
			{
				worldLoaded = false;
				UnmuteVanilla();
				ClearCache();
				_locPosCache.Clear();
				((BaseUnityPlugin)this).Logger.LogInfo((object)"[Glitnir] Voltou ao menu.");
				((MonoBehaviour)this).StartCoroutine(PreloadMenuMusic());
			}
			if (!flag)
			{
				if (!menuEnabled || menuEntry == null || !menuEntry.IsActive)
				{
					if (VanillaMuted)
					{
						UnmuteVanilla();
					}
					return;
				}
				if (menuClipReady && currentState != MusicState.Menu)
				{
					PlayCachedClip(menuClip, FinalVolume(menuVolume), MusicState.Menu, menuEntry.url);
				}
				if (currentState == MusicState.Menu && audioSource.isPlaying)
				{
					audioSource.volume = FinalVolume(menuVolume);
				}
			}
			else if (worldLoaded)
			{
				if (audioSource.isPlaying)
				{
					audioSource.volume = FinalVolume(CurrentCfgVolume());
				}
				checkTimer -= Time.deltaTime;
				if (!(checkTimer > 0f))
				{
					checkTimer = checkInterval;
					UpdateInGameMusic();
				}
			}
		}

		private void UpdateInGameMusic()
		{
			//IL_001d: 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_0023: 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_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0346: Unknown result type (might be due to invalid IL or missing references)
			//IL_034c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0358: Unknown result type (might be due to invalid IL or missing references)
			//IL_035d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0365: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: 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)
			//IL_017a: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				return;
			}
			Vector3 position = ((Component)localPlayer).transform.position;
			float num = Vector3.Distance(position, _lastCheckPos);
			checkInterval = ((num < 3f) ? 4f : 2f);
			_lastCheckPos = position;
			_locCacheTimer += checkInterval;
			if (_locCacheTimer > 30f)
			{
				_locPosCache.Clear();
				_locCacheTimer = 0f;
			}
			TryPreloadNearby(position);
			if (bossEnabled || creatEnabled)
			{
				string text = null;
				string text2 = null;
				float num2 = Math.Max(bossRadius, creatRadius);
				_charBuffer.Clear();
				foreach (Character allCharacter in Character.GetAllCharacters())
				{
					if (!((Object)(object)allCharacter == (Object)null) && !allCharacter.IsDead() && Vector3.Distance(position, ((Component)allCharacter).transform.position) <= num2)
					{
						_charBuffer.Add(allCharacter);
					}
				}
				foreach (Character item in _charBuffer)
				{
					float num3 = Vector3.Distance(position, ((Component)item).transform.position);
					string key = ((Object)item).name.Replace("(Clone)", "").Trim();
					if (bossEnabled && text == null && num3 <= bossRadius && bossMap.TryGetValue(key, out var value) && value.IsActive)
					{
						text = value.url;
					}
					if (creatEnabled && text2 == null && num3 <= creatRadius && creatMap.TryGetValue(key, out var value2) && value2.IsActive)
					{
						text2 = value2.url;
					}
					if (text != null && text2 != null)
					{
						break;
					}
				}
				if (text != null)
				{
					TryPreload(text);
					SwitchMusic(text, bossVolume, MusicState.Boss);
					return;
				}
				if (text2 != null)
				{
					TryPreload(text2);
					SwitchMusic(text2, creatVolume, MusicState.Creature);
					return;
				}
			}
			if (terrEnabled)
			{
				string territoryMusic = GetTerritoryMusic(position);
				if (!string.IsNullOrEmpty(territoryMusic))
				{
					TryPreload(territoryMusic);
					SwitchMusic(territoryMusic, terrVolume, MusicState.Territory);
					return;
				}
			}
			if (zonesEnabled && GetZoneMatch(position, out var url, out var volume))
			{
				TryPreload(url);
				SwitchMusic(url, volume, MusicState.Territory);
				return;
			}
			if (biomesEnabled)
			{
				Biome key2 = (Biome)((WorldGenerator.instance != null) ? ((int)WorldGenerator.instance.GetBiome(position.x, position.z, 0.02f, false)) : 0);
				if (biomeMap.TryGetValue(key2, out var value3) && value3.IsActive)
				{
					TryPreload(value3.url);
					SwitchMusic(value3.url, biomeVolume, MusicState.Biome);
					return;
				}
			}
			if (currentState != 0)
			{
				if (fadeCoroutine != null)
				{
					((MonoBehaviour)this).StopCoroutine(fadeCoroutine);
				}
				fadeCoroutine = ((MonoBehaviour)this).StartCoroutine(FadeOutAndStop(andUnmute: true));
				currentState = MusicState.None;
				currentUrl = "";
				((BaseUnityPlugin)this).Logger.LogInfo((object)"[Glitnir] Sem zona ativa — vanilla tocando.");
			}
		}

		private void TryPreloadNearby(Vector3 pos)
		{
			//IL_0028: 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_0039: 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_00c6: 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_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_0137: Unknown result type (might be due to invalid IL or missing references)
			//IL_013d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0146: Unknown result type (might be due to invalid IL or missing references)
			//IL_014b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0160: Unknown result type (might be due to invalid IL or missing references)
			//IL_0165: Unknown result type (might be due to invalid IL or missing references)
			//IL_016d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0174: Unknown result type (might be due to invalid IL or missing references)
			//IL_0181: 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_018e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0247: Unknown result type (might be due to invalid IL or missing references)
			//IL_0252: Unknown result type (might be due to invalid IL or missing references)
			//IL_0258: Unknown result type (might be due to invalid IL or missing references)
			//IL_025d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0269: Unknown result type (might be due to invalid IL or missing references)
			//IL_0270: Unknown result type (might be due to invalid IL or missing references)
			foreach (ZoneEntry zone in zoneList)
			{
				if (zone.IsActive)
				{
					float num = Vector3.Distance(new Vector3(pos.x, 0f, pos.z), new Vector3(zone.x, 0f, zone.z));
					if (num <= zone.radius * 1.5f)
					{
						TryPreload(zone.url);
					}
				}
			}
			if (biomesEnabled && WorldGenerator.instance != null)
			{
				float num2 = 64f;
				Vector3[] array = (Vector3[])(object)new Vector3[5]
				{
					pos,
					new Vector3(pos.x + num2, pos.y, pos.z),
					new Vector3(pos.x - num2, pos.y, pos.z),
					new Vector3(pos.x, pos.y, pos.z + num2),
					new Vector3(pos.x, pos.y, pos.z - num2)
				};
				Vector3[] array2 = array;
				foreach (Vector3 val in array2)
				{
					Biome biome = WorldGenerator.instance.GetBiome(val.x, val.z, 0.02f, false);
					if (biomeMap.TryGetValue(biome, out var value) && value.IsActive)
					{
						TryPreload(value.url);
					}
				}
			}
			if (terrEnabled)
			{
				foreach (TerritoryEntry terr in terrList)
				{
					if (terr.IsActive && _locPosCache.TryGetValue(terr.location, out var value2))
					{
						float num3 = ((terr.radius > 0f) ? terr.radius : terrRadius);
						float num4 = Vector3.Distance(new Vector3(pos.x, 0f, pos.z), new Vector3(value2.x, 0f, value2.z));
						if (num4 <= num3 * 1.5f)
						{
							TryPreload(terr.url);
						}
					}
				}
			}
			if ((!bossEnabled && !creatEnabled) || _charBuffer.Count <= 0)
			{
				return;
			}
			foreach (Character item in _charBuffer)
			{
				if (!((Object)(object)item == (Object)null))
				{
					string key = ((Object)item).name.Replace("(Clone)", "").Trim();
					if (bossEnabled && bossMap.TryGetValue(key, out var value3) && value3.IsActive)
					{
						TryPreload(value3.url);
					}
					if (creatEnabled && creatMap.TryGetValue(key, out var value4) && value4.IsActive)
					{
						TryPreload(value4.url);
					}
				}
			}
		}

		private string GetTerritoryMusic(Vector3 origin)
		{
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: 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_014f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0166: Unknown result type (might be due to invalid IL or missing references)
			//IL_016c: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)ZoneSystem.instance == (Object)null)
			{
				return null;
			}
			LocationInstance val = default(LocationInstance);
			foreach (TerritoryEntry terr in terrList)
			{
				if (!terr.IsActive)
				{
					continue;
				}
				float num = ((terr.dungeonYMin >= 0f) ? terr.dungeonYMin : terrDungeonYMin);
				float num2 = ((terr.dungeonYMax >= 0f) ? terr.dungeonYMax : terrDungeonYMax);
				bool flag = origin.y >= num && origin.y <= num2;
				if (terr.dungeonOnly)
				{
					if (!flag)
					{
						continue;
					}
					return terr.url;
				}
				if (!_locPosCache.TryGetValue(terr.location, out var value))
				{
					if (!ZoneSystem.instance.FindClosestLocation(terr.location, origin, ref val))
					{
						continue;
					}
					value = val.m_position;
					_locPosCache[terr.location] = value;
				}
				float num3 = ((terr.radius > 0f) ? terr.radius : terrRadius);
				float num4 = (flag ? ((float)Math.Sqrt(Math.Pow(origin.x - value.x, 2.0) + Math.Pow(origin.z - value.z, 2.0))) : Vector3.Distance(origin, value));
				if (!(num4 <= num3))
				{
					continue;
				}
				return terr.url;
			}
			return null;
		}

		private bool GetZoneMatch(Vector3 origin, out string url, out float volume)
		{
			//IL_0028: 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_0039: 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)
			foreach (ZoneEntry zone in zoneList)
			{
				if (zone.IsActive)
				{
					float num = Vector3.Distance(new Vector3(origin.x, 0f, origin.z), new Vector3(zone.x, 0f, zone.z));
					if (num <= zone.radius)
					{
						url = zone.url;
						volume = zone.volume;
						return true;
					}
				}
			}
			url = null;
			volume = 0f;
			return false;
		}

		private void TryPreload(string url)
		{
			if (!string.IsNullOrWhiteSpace(url) && !clipCache.ContainsKey(url) && !preloadingUrls.Contains(url))
			{
				((MonoBehaviour)this).StartCoroutine(PreloadClip(url));
			}
		}

		[IteratorStateMachine(typeof(<PreloadClip>d__64))]
		private IEnumerator PreloadClip(string url)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <PreloadClip>d__64(0)
			{
				<>4__this = this,
				url = url
			};
		}

		private void SwitchMusic(string url, float cfgVolume, MusicState state)
		{
			if (!(currentUrl == url))
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)$"[Glitnir] [{state}] → {url}");
				currentState = state;
				currentUrl = url;
				MuteVanilla();
				if (fadeCoroutine != null)
				{
					((MonoBehaviour)this).StopCoroutine(fadeCoroutine);
				}
				if (clipCache.TryGetValue(url, out var value) && (Object)(object)value != (Object)null)
				{
					fadeCoroutine = ((MonoBehaviour)this).StartCoroutine(FadeSwitchCached(value, url, cfgVolume));
				}
				else
				{
					fadeCoroutine = ((MonoBehaviour)this).StartCoroutine(FadeSwitch(url, cfgVolume));
				}
			}
		}

		[IteratorStateMachine(typeof(<FadeSwitchCached>d__66))]
		private IEnumerator FadeSwitchCached(AudioClip nextClip, string url, float cfgVolume)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <FadeSwitchCached>d__66(0)
			{
				<>4__this = this,
				nextClip = nextClip,
				url = url,
				cfgVolume = cfgVolume
			};
		}

		[IteratorStateMachine(typeof(<FadeSwitch>d__67))]
		private IEnumerator FadeSwitch(string url, float cfgVolume)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <FadeSwitch>d__67(0)
			{
				<>4__this = this,
				url = url,
				cfgVolume = cfgVolume
			};
		}

		[IteratorStateMachine(typeof(<FadeOutAndStop>d__68))]
		private IEnumerator FadeOutAndStop(bool andUnmute = false)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <FadeOutAndStop>d__68(0)
			{
				<>4__this = this,
				andUnmute = andUnmute
			};
		}

		[IteratorStateMachine(typeof(<LoadAndFadeIn>d__69))]
		private IEnumerator LoadAndFadeIn(string url, float cfgVolume)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <LoadAndFadeIn>d__69(0)
			{
				<>4__this = this,
				url = url,
				cfgVolume = cfgVolume
			};
		}

		private void PlayCachedClip(AudioClip clip, float finalVolume, MusicState state, string url)
		{
			if (!(currentUrl == url))
			{
				currentState = state;
				currentUrl = url;
				currentClipUrl = url;
				MuteVanilla();
				audioSource.Stop();
				audioSource.clip = clip;
				audioSource.volume = finalVolume;
				audioSource.Play();
			}
		}

		[IteratorStateMachine(typeof(<PreloadMenuMusic>d__71))]
		private IEnumerator PreloadMenuMusic()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <PreloadMenuMusic>d__71(0)
			{
				<>4__this = this
			};
		}

		private void StopOurMusic()
		{
			if (fadeCoroutine != null)
			{
				((MonoBehaviour)this).StopCoroutine(fadeCoroutine);
			}
			audioSource.Stop();
			ReleaseCurrentClip();
			currentState = MusicState.None;
			currentUrl = "";
		}

		private void ReleaseCurrentClip()
		{
			if (!string.IsNullOrEmpty(currentClipUrl))
			{
				if (!clipCache.ContainsKey(currentClipUrl) && (Object)(object)audioSource.clip != (Object)null)
				{
					Object.Destroy((Object)(object)audioSource.clip);
				}
				audioSource.clip = null;
				currentClipUrl = "";
			}
		}

		private void ClearCache()
		{
			foreach (AudioClip value in clipCache.Values)
			{
				if ((Object)(object)value != (Object)null)
				{
					Object.Destroy((Object)(object)value);
				}
			}
			clipCache.Clear();
			preloadingUrls.Clear();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"[Glitnir] Cache de clips liberado.");
		}

		private void CreateMusicPlayer()
		{
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Expected O, but got Unknown
			if (!((Object)(object)musicObject != (Object)null) || !((Object)(object)audioSource != (Object)null))
			{
				if ((Object)(object)musicObject == (Object)null)
				{
					musicObject = new GameObject("Glitnir Music Player");
					Object.DontDestroyOnLoad((Object)(object)musicObject);
				}
				audioSource = musicObject.GetComponent<AudioSource>() ?? musicObject.AddComponent<AudioSource>();
				audioSource.loop = true;
				audioSource.spatialBlend = 0f;
				audioSource.volume = 1f;
			}
		}

		private void StartConfigWatcher()
		{
			try
			{
				string directoryName = Path.GetDirectoryName(ConfigPath);
				string fileName = Path.GetFileName(ConfigPath);
				if (Directory.Exists(directoryName))
				{
					configWatcher = new FileSystemWatcher(directoryName, fileName)
					{
						NotifyFilter = NotifyFilters.LastWrite,
						EnableRaisingEvents = true
					};
					configWatcher.Changed += delegate
					{
						reloadPending = true;
					};
					((BaseUnityPlugin)this).Logger.LogInfo((object)"[Glitnir] Watcher de config ativo.");
				}
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("[Glitnir] Watcher não iniciado: " + ex.Message));
			}
		}

		private void LoadConfig()
		{
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Expected O, but got Unknown
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			if (!File.Exists(ConfigPath))
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("[Glitnir] Config não encontrada: " + ConfigPath));
				return;
			}
			try
			{
				string text = File.ReadAllText(ConfigPath);
				IDeserializer val = ((BuilderSkeleton<DeserializerBuilder>)new DeserializerBuilder()).WithNamingConvention(UnderscoredNamingConvention.Instance).IgnoreUnmatchedProperties().Build();
				YamlConfig yamlConfig = val.Deserialize<YamlConfig>(text);
				if (yamlConfig == null)
				{
					throw new Exception("YAML resultou em objeto nulo.");
				}
				bool enabled = yamlConfig.menu.enabled;
				float volume = yamlConfig.menu.volume;
				MusicEntry musicEntry = new MusicEntry(enabled: true, yamlConfig.menu.url);
				bool enabled2 = yamlConfig.biomes.enabled;
				float volume2 = yamlConfig.biomes.volume;
				Dictionary<Biome, MusicEntry> dictionary = new Dictionary<Biome, MusicEntry>();
				foreach (KeyValuePair<string, YamlTrack> track in yamlConfig.biomes.tracks)
				{
					if (Enum.TryParse<Biome>(track.Key, out Biome result))
					{
						dictionary[result] = new MusicEntry(track.Value.enabled, track.Value.url);
					}
				}
				bool enabled3 = yamlConfig.territories.enabled;
				float volume3 = yamlConfig.territories.volume;
				float radius = yamlConfig.territories.radius;
				float dungeon_y_min = yamlConfig.territories.dungeon_y_min;
				float dungeon_y_max = yamlConfig.territories.dungeon_y_max;
				List<TerritoryEntry> list = new List<TerritoryEntry>();
				foreach (YamlTerritoryTrack track2 in yamlConfig.territories.tracks)
				{
					list.Add(new TerritoryEntry
					{
						location = track2.location,
						radius = track2.radius,
						dungeonYMin = track2.dungeon_y_min,
						dungeonYMax = track2.dungeon_y_max,
						dungeonOnly = track2.dungeon_only,
						enabled = track2.enabled,
						url = track2.url
					});
				}
				bool enabled4 = yamlConfig.zones.enabled;
				List<ZoneEntry> list2 = new List<ZoneEntry>();
				foreach (YamlZoneTrack track3 in yamlConfig.zones.tracks)
				{
					list2.Add(new ZoneEntry
					{
						name = track3.name,
						x = track3.x,
						z = track3.z,
						radius = track3.radius,
						volume = track3.volume,
						enabled = track3.enabled,
						url = track3.url
					});
				}
				bool enabled5 = yamlConfig.bosses.enabled;
				float volume4 = yamlConfig.bosses.volume;
				float radius2 = yamlConfig.bosses.radius;
				Dictionary<string, MusicEntry> dictionary2 = new Dictionary<string, MusicEntry>();
				foreach (KeyValuePair<string, YamlTrack> track4 in yamlConfig.bosses.tracks)
				{
					dictionary2[track4.Key] = new MusicEntry(track4.Value.enabled, track4.Value.url);
				}
				bool enabled6 = yamlConfig.creatures.enabled;
				float volume5 = yamlConfig.creatures.volume;
				float radius3 = yamlConfig.creatures.radius;
				Dictionary<string, MusicEntry> dictionary3 = new Dictionary<string, MusicEntry>();
				foreach (KeyValuePair<string, YamlTrack> track5 in yamlConfig.creatures.tracks)
				{
					dictionary3[track5.Key] = new MusicEntry(track5.Value.enabled, track5.Value.url);
				}
				ClearCache();
				_locPosCache.Clear();
				menuEnabled = enabled;
				menuVolume = volume;
				menuEntry = musicEntry;
				biomesEnabled = enabled2;
				biomeVolume = volume2;
				biomeMap = dictionary;
				terrEnabled = enabled3;
				terrVolume = volume3;
				terrRadius = radius;
				terrDungeonYMin = dungeon_y_min;
				terrDungeonYMax = dungeon_y_max;
				terrList = list;
				zonesEnabled = enabled4;
				zoneList = list2;
				bossEnabled = enabled5;
				bossVolume = volume4;
				bossRadius = radius2;
				bossMap = dictionary2;
				creatEnabled = enabled6;
				creatVolume = volume5;
				creatRadius = radius3;
				creatMap = dictionary3;
				((BaseUnityPlugin)this).Logger.LogInfo((object)("[Glitnir] Config carregada: " + $"{biomeMap.Count} biomas, {terrList.Count} territórios, " + $"{zoneList.Count} zonas, {bossMap.Count} bosses, {creatMap.Count} criaturas."));
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)("[Glitnir] Erro ao ler config: " + ex.Message));
				((BaseUnityPlugin)this).Logger.LogError((object)("[Glitnir] Verifique o arquivo: " + ConfigPath));
			}
		}

		private void EnsureDefaultConfig()
		{
			if (!File.Exists(ConfigPath))
			{
				Directory.CreateDirectory(Path.GetDirectoryName(ConfigPath));
				File.WriteAllText(ConfigPath, "# ╔══════════════════════════════════════════════════════════════════╗\r\n# ║           GLITNIR MUSIC ZONES — music_config.yaml               ║\r\n# ╚══════════════════════════════════════════════════════════════════╝\r\n# Use URLs diretas de MP3 (sem expiração). Recomendado: GitHub Releases\r\n# ou cdn.pixabay.com. Evite links do Discord (expiram em horas).\r\n#\r\n# Após salvar o arquivo, a config recarrega automaticamente no jogo.\r\n\r\n# ─── MENU PRINCIPAL ────────────────────────────────────────────────\r\nmenu:\r\n  enabled: true\r\n  volume: 0.3\r\n  url: \"https://cdn.pixabay.com/download/audio/2025/07/24/audio_9d4a9c72f8.mp3?filename=wesleysert-glitnir-valhhala-1-379314.mp3\"\r\n\r\n# ─── BIOMAS ────────────────────────────────────────────────────────\r\n# Biomas disponíveis: Meadows, BlackForest, Swamp, Mountain, Plains,\r\n#                     Mistlands, AshLands, DeepNorth, Ocean\r\nbiomes:\r\n  enabled: true\r\n  volume: 0.6\r\n  tracks:\r\n    Meadows:\r\n      enabled: true\r\n      url: \"\"\r\n    BlackForest:\r\n      enabled: true\r\n      url: \"\"\r\n    Swamp:\r\n      enabled: true\r\n      url: \"\"\r\n    Mountain:\r\n      enabled: true\r\n      url: \"\"\r\n    Plains:\r\n      enabled: true\r\n      url: \"\"\r\n    Mistlands:\r\n      enabled: true\r\n      url: \"\"\r\n    AshLands:\r\n      enabled: true\r\n      url: \"\"\r\n    DeepNorth:\r\n      enabled: true\r\n      url: \"\"\r\n    Ocean:\r\n      enabled: true\r\n      url: \"\"\r\n\r\n# ─── TERRITÓRIOS (Locations do ZoneSystem) ─────────────────────────\r\n# location:      nome exato da Location (ex: StartTemple, Crypt2)\r\n# radius:        raio em unidades (0 = usa o radius global abaixo)\r\n# dungeon_only:  true = só toca dentro da dungeon (faixa Y)\r\n# dungeon_y_min/max: faixa Y da dungeon (-1 = usa o global)\r\nterritories:\r\n  enabled: true\r\n  volume: 0.65\r\n  radius: 90.0\r\n  dungeon_y_min: 4500.0\r\n  dungeon_y_max: 5500.0\r\n  tracks:\r\n    - enabled: true\r\n      location: StartTemple\r\n      radius: 60.0\r\n      dungeon_only: false\r\n      dungeon_y_min: -1\r\n      dungeon_y_max: -1\r\n      url: \"\"\r\n\r\n    - enabled: false\r\n      location: Vendor_BlackForest\r\n      radius: 0.0\r\n      dungeon_only: false\r\n      dungeon_y_min: -1\r\n      dungeon_y_max: -1\r\n      url: \"\"\r\n\r\n    - enabled: true\r\n      location: Crypt2\r\n      radius: 90.0\r\n      dungeon_only: true\r\n      dungeon_y_min: 4500\r\n      dungeon_y_max: 5500\r\n      url: \"\"\r\n\r\n    - enabled: true\r\n      location: Crypt3\r\n      radius: 90.0\r\n      dungeon_only: true\r\n      dungeon_y_min: 4500\r\n      dungeon_y_max: 5500\r\n      url: \"\"\r\n\r\n    - enabled: true\r\n      location: Crypt4\r\n      radius: 90.0\r\n      dungeon_only: true\r\n      dungeon_y_min: 4500\r\n      dungeon_y_max: 5500\r\n      url: \"\"\r\n\r\n# ─── ZONAS POR COORDENADA ──────────────────────────────────────────\r\n# Use para vilas ou regiões sem Location no ZoneSystem.\r\n# x/z: coordenadas do centro no mapa do Valheim\r\nzones:\r\n  enabled: true\r\n  tracks:\r\n    - enabled: false\r\n      name: Exemplo Vila\r\n      x: 0.0\r\n      z: 0.0\r\n      radius: 80.0\r\n      volume: 0.65\r\n      url: \"\"\r\n\r\n# ─── BOSSES ────────────────────────────────────────────────────────\r\n# Prefab name do boss sem '(Clone)'. Toca enquanto o boss estiver vivo no raio.\r\n# Bosses vanilla: Eikthyr, gd_king, Bonemass, Dragon, GoblinKing, SeekerQueen, Fader\r\nbosses:\r\n  enabled: true\r\n  volume: 0.7\r\n  radius: 120.0\r\n  tracks:\r\n    Eikthyr:\r\n      enabled: true\r\n      url: \"\"\r\n    gd_king:\r\n      enabled: true\r\n      url: \"\"\r\n    Bonemass:\r\n      enabled: true\r\n      url: \"\"\r\n    Dragon:\r\n      enabled: true\r\n      url: \"\"\r\n    GoblinKing:\r\n      enabled: true\r\n      url: \"\"\r\n    SeekerQueen:\r\n      enabled: true\r\n      url: \"\"\r\n    Fader:\r\n      enabled: true\r\n      url: \"\"\r\n\r\n# ─── CRIATURAS ─────────────────────────────────────────────────────\r\n# Toca enquanto houver ao menos uma criatura viva no raio.\r\ncreatures:\r\n  enabled: true\r\n  volume: 0.55\r\n  radius: 30.0\r\n  tracks:\r\n    Troll:\r\n      enabled: false\r\n      url: \"\"\r\n    GoblinBrute:\r\n      enabled: false\r\n      url: \"\"\r\n    BlobTar:\r\n      enabled: false\r\n      url: \"\"\r\n    Seeker:\r\n      enabled: false\r\n      url: \"\"\r\n    Leech:\r\n      enabled: false\r\n      url: \"\"\r\n");
				((BaseUnityPlugin)this).Logger.LogInfo((object)("[Glitnir] Config padrão criada em: " + ConfigPath));
			}
		}
	}
}