Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of GlitnirSounds v0.1.2
GlitnirMusicZones.dll
Decompiled 2 hours agousing 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)); } } } }