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.4
GlitnirMusicZones.dll
Decompiled 3 days agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; using UnityEngine.Audio; 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] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace 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: false\r\n volume: 0.0500\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\n# mode: custom = toca a url configurada (silencia vanilla)\r\n# vanilla = deixa a música do jogo tocar normalmente\r\n# mute = silêncio total (nem mod nem vanilla)\r\nbiomes:\r\n enabled: true\r\n volume: 0.0500\r\n tracks:\r\n Meadows:\r\n enabled: true\r\n mode: custom\r\n url: \"https://cdn.pixabay.com/download/audio/2026/05/25/audio_d304cbd8a2.mp3?filename=morgnar-neve-540465.mp3\"\r\n BlackForest:\r\n enabled: true\r\n mode: custom\r\n url: \"https://cdn.pixabay.com/download/audio/2026/05/22/audio_62456d9582.mp3?filename=morgnar-mire-of-ancients-538620.mp3\"\r\n Swamp:\r\n enabled: true\r\n mode: custom\r\n url: \"https://cdn.pixabay.com/download/audio/2026/05/25/audio_47a47ff6c2.mp3?filename=morgnar-pantano-540510.mp3\"\r\n Mountain:\r\n enabled: true\r\n mode: custom\r\n url: \"https://cdn.pixabay.com/download/audio/2026/05/25/audio_e6186facfc.mp3?filename=morgnar-mist-over-runestones-540508.mp3\"\r\n Plains:\r\n enabled: true\r\n mode: custom\r\n url: \"https://cdn.pixabay.com/download/audio/2026/05/25/audio_0f67273299.mp3?filename=morgnar-planicie-540517.mp3\"\r\n Mistlands:\r\n enabled: true\r\n mode: custom\r\n url: \"https://cdn.pixabay.com/download/audio/2026/05/25/audio_e6186facfc.mp3?filename=morgnar-mist-over-runestones-540508.mp3\"\r\n AshLands:\r\n enabled: true\r\n mode: custom\r\n url: \"https://cdn.pixabay.com/download/audio/2026/05/25/audio_d97092169a.mp3?filename=morgnar-ashlands-540519.mp3\"\r\n DeepNorth:\r\n enabled: true\r\n mode: custom\r\n url: \"https://cdn.pixabay.com/download/audio/2026/05/25/audio_2fe0daf552.mp3?filename=morgnar-deepnorth-540531.mp3\"\r\n Ocean:\r\n enabled: true\r\n mode: custom\r\n url: \"https://cdn.pixabay.com/download/audio/2026/05/25/audio_2fe0daf552.mp3?filename=morgnar-deepnorth-540531.mp3\"\r\n\r\n# ─── LOCATIONS (Pontos de interesse 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\nlocations:\r\n enabled: false\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: false\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: 4500.0\r\n dungeon_y_max: -1\r\n url: \"\"\r\n\r\n - enabled: false\r\n location: Crypt2\r\n radius: 90.0\r\n dungeon_only: false\r\n dungeon_y_min: 4500.0\r\n dungeon_y_max: 5500.0\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: false\r\n location: MountainCave01\r\n radius: 90.0\r\n dungeon_only: false\r\n dungeon_y_min: 4500\r\n dungeon_y_max: 5500\r\n url: \"\"\r\n\r\n# ─── TERRITORIES (Zonas por coordenada XZ) ─────────────────────────\r\n# Use para vilas ou regiões sem Location no ZoneSystem.\r\n# x/z: coordenadas do centro no mapa do Valheim\r\n# mode: custom = toca a url configurada (silencia vanilla)\r\n# vanilla = deixa a música do jogo tocar normalmente\r\n# mute = silêncio total (nem mod nem vanilla)\r\nterritories:\r\n enabled: true\r\n tracks:\r\n - enabled: true\r\n name: BosquePrmadico\r\n x: 25186.0\r\n z: 4411.0\r\n radius: 700.0\r\n volume: 0.0500\r\n mode: custom\r\n url: \"https://cdn.pixabay.com/download/audio/2026/05/25/audio_d304cbd8a2.mp3?filename=morgnar-neve-540465.mp3\"\r\n\r\n - enabled: true\r\n name: Vila Prado\r\n x: -245.0\r\n z: 336.0\r\n radius: 200.0\r\n volume: 0.0500\r\n mode: custom\r\n url: \"https://cdn.pixabay.com/download/audio/2026/05/22/audio_e0d6b4179f.mp3?filename=morgnar-harbor-hearth-village-1-538622.mp3\"\r\n\r\n - enabled: true\r\n name: Skjalfhame\r\n x: -37714.0\r\n z: 9799.0\r\n radius: 100.0\r\n volume: 0.0500\r\n mode: custom\r\n url: \"https://cdn.pixabay.com/download/audio/2026/05/25/audio_6ab79d7f51.mp3?filename=morgnar-vila-540514.mp3\"\r\n\r\n - enabled: true\r\n name: Hrotghar\r\n x: 3337.0\r\n z: -6096.0\r\n radius: 400.0\r\n volume: 0.0500\r\n mode: custom\r\n url: \"https://cdn.pixabay.com/download/audio/2026/05/25/audio_6ab79d7f51.mp3?filename=morgnar-vila-540514.mp3\"\r\n\r\n - enabled: true\r\n name: Winterhold\r\n x: 17938.0\r\n z: 14584.0\r\n radius: 70.0\r\n volume: 0.0500\r\n mode: custom\r\n url: \"https://cdn.pixabay.com/download/audio/2026/05/25/audio_6ab79d7f51.mp3?filename=morgnar-vila-540514.mp3\"\r\n\r\n - enabled: true\r\n name: Vila da Floresta Negra\r\n x: -1997.0\r\n z: -5333.0\r\n radius: 50.0\r\n volume: 0.0500\r\n mode: custom\r\n url: \"https://cdn.pixabay.com/download/audio/2026/05/25/audio_6ab79d7f51.mp3?filename=morgnar-vila-540514.mp3\"\r\n\r\n - enabled: true\r\n name: Vila do Pantano\r\n x: 4917.0\r\n z: -2571.0\r\n radius: 200.0\r\n volume: 0.0500\r\n mode: custom\r\n url: \"https://cdn.pixabay.com/download/audio/2026/05/22/audio_e0d6b4179f.mp3?filename=morgnar-harbor-hearth-village-1-538622.mp3\"\r\n\r\n - enabled: true\r\n name: Vila da Montanha\r\n x: 6508.0\r\n z: 3735.0\r\n radius: 400.0\r\n volume: 0.0500\r\n mode: custom\r\n url: \"https://cdn.pixabay.com/download/audio/2026/05/22/audio_e0d6b4179f.mp3?filename=morgnar-harbor-hearth-village-1-538622.mp3\"\r\n\r\n - enabled: true\r\n name: Varghard - Reino dos Humanos\r\n x: 13695.0\r\n z: 19496.0\r\n radius: 400.0\r\n volume: 0.0500\r\n mode: mute\r\n url: \"\"\r\n\r\n - enabled: true\r\n name: Eryndel - Reino dos Elfos\r\n x: 21474.0\r\n z: 12080.0\r\n radius: 400.0\r\n volume: 0.0500\r\n mode: mute\r\n url: \"\"\r\n\r\n - enabled: true\r\n name: Drakthar - Reino dos Orcs\r\n x: -7346.0\r\n z: 20523.0\r\n radius: 400.0\r\n volume: 0.0500\r\n mode: mute\r\n url: \"\"\r\n\r\n - enabled: true\r\n name: Coliseu\r\n x: 1745.0\r\n z: 21713.0\r\n radius: 500.0\r\n volume: 0.0500\r\n mode: mute\r\n url: \"\"\r\n\r\n - enabled: true\r\n name: Brumello - Reino dos Halflings\r\n x: -15671.0\r\n z: 15840.0\r\n radius: 500.0\r\n volume: 0.0500\r\n mode: mute\r\n url: \"\"\r\n\r\n - enabled: true\r\n name: Cabaré do Sjar\r\n x: 14691.0\r\n z: 17973.0\r\n radius: 50.0\r\n volume: 0.0500\r\n mode: mute\r\n url: \"\"\r\n\r\n - enabled: true\r\n name: Forte Falkreath\r\n x: -22106.0\r\n z: 9622.0\r\n radius: 100.0\r\n volume: 0.0500\r\n mode: custom\r\n url: \"https://cdn.pixabay.com/download/audio/2026/05/25/audio_c2d6bad590.mp3?filename=morgnar-falkreath-citadel-541114.mp3\"\r\n\r\n - enabled: false\r\n name: Parkour\r\n x: 6508.0\r\n z: 3735.0\r\n radius: 400.0\r\n volume: 0.0500\r\n mode: custom\r\n url: \"https://cdn.pixabay.com/download/audio/2026/05/25/audio_4d4bef9969.mp3?filename=morgnar-mead-hall-waltz-541115.mp3\"\r\n\r\n - enabled: true\r\n name: Jorrvaskr\r\n x: 11411.0\r\n z: 19191.0\r\n radius: 70.0\r\n volume: 0.0500\r\n mode: custom\r\n url: \"https://cdn.pixabay.com/download/audio/2026/05/22/audio_a9a5df53e2.mp3?filename=morgnar-harbor-hearth-village-538619.mp3\"\r\n\r\n - enabled: true\r\n name: Calindel\r\n x: 8590.0\r\n z: 20394.0\r\n radius: 70.0\r\n volume: 0.0500\r\n mode: custom\r\n url: \"https://cdn.pixabay.com/download/audio/2026/05/22/audio_a9a5df53e2.mp3?filename=morgnar-harbor-hearth-village-538619.mp3\"\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.0500\r\n radius: 120.0\r\n tracks:\r\n Eikthyr:\r\n enabled: true\r\n url: \"https://cdn.pixabay.com/download/audio/2026/05/22/audio_1a619af2ce.mp3?filename=morgnar-stag-of-thunder-538616.mp3\"\r\n gd_king:\r\n enabled: true\r\n url: \"https://cdn.pixabay.com/download/audio/2026/05/22/audio_1a619af2ce.mp3?filename=morgnar-stag-of-thunder-538616.mp3\"\r\n Bonemass:\r\n enabled: true\r\n url: \"https://cdn.pixabay.com/download/audio/2026/05/22/audio_1a619af2ce.mp3?filename=morgnar-stag-of-thunder-538616.mp3\"\r\n Dragon:\r\n enabled: true\r\n url: \"https://cdn.pixabay.com/download/audio/2026/05/22/audio_1a619af2ce.mp3?filename=morgnar-stag-of-thunder-538616.mp3\"\r\n GoblinKing:\r\n enabled: true\r\n url: \"https://cdn.pixabay.com/download/audio/2026/05/22/audio_1a619af2ce.mp3?filename=morgnar-stag-of-thunder-538616.mp3\"\r\n SeekerQueen:\r\n enabled: true\r\n url: \"https://cdn.pixabay.com/download/audio/2026/05/22/audio_1a619af2ce.mp3?filename=morgnar-stag-of-thunder-538616.mp3\"\r\n Fader:\r\n enabled: true\r\n url: \"https://cdn.pixabay.com/download/audio/2026/05/22/audio_1a619af2ce.mp3?filename=morgnar-stag-of-thunder-538616.mp3\"\r\n brutoGLIT:\r\n enabled: true\r\n url: \"https://cdn.pixabay.com/download/audio/2026/05/22/audio_1a619af2ce.mp3?filename=morgnar-stag-of-thunder-538616.mp3\"\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.0500\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 readonly FieldRef<MusicMan, AudioSource> _musicSourceRef = AccessTools.FieldRefAccess<MusicMan, AudioSource>("m_musicSource"); private static float _lastKnownVolume = 1f; private static AudioSource MusicManSource { get { if ((Object)(object)MusicMan.instance == (Object)null) { return null; } try { return _musicSourceRef.Invoke(MusicMan.instance); } catch { return null; } } } public static float RealMusicVolume => _lastKnownVolume; public static AudioMixerGroup GetMusicGroup() { AudioSource musicManSource = MusicManSource; return (musicManSource != null) ? musicManSource.outputAudioMixerGroup : null; } internal static void SetInitialVolume(float v) { if (v > 0f) { _lastKnownVolume = v; } } private static void PrefixUpdate() { float masterMusicVolume = MusicMan.m_masterMusicVolume; if (masterMusicVolume > 0f) { _lastKnownVolume = masterMusicVolume; } } private static void PostfixUpdate() { if (Plugin.VanillaMuted) { MusicMan.m_masterMusicVolume = 0f; AudioSource musicManSource = MusicManSource; if ((Object)(object)musicManSource != (Object)null && musicManSource.isPlaying) { musicManSource.Stop(); } } } 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; } 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_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0059: 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("PrefixUpdate", BindingFlags.Static | BindingFlags.NonPublic)); HarmonyMethod val4 = new HarmonyMethod(typeFromHandle.GetMethod("PostfixUpdate", BindingFlags.Static | BindingFlags.NonPublic)); MethodInfo methodInfo = null; MethodInfo[] methods = typeof(MusicMan).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (MethodInfo methodInfo2 in methods) { if (methodInfo2.Name == "StartMusic") { harmony.Patch((MethodBase)methodInfo2, val, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } else if (methodInfo2.Name == "Queue") { harmony.Patch((MethodBase)methodInfo2, val2, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } else if (methodInfo2.Name == "Update") { methodInfo = methodInfo2; } } if (methodInfo != null) { harmony.Patch((MethodBase)methodInfo, val3, val4, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } } } public class YamlConfig { public YamlMenu menu { get; set; } = new YamlMenu(); public YamlBiomes biomes { get; set; } = new YamlBiomes(); public YamlLocations locations { get; set; } = new YamlLocations(); public YamlTerritories territories { get; set; } = new YamlTerritories(); 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 YamlLocations { 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<YamlLocationTrack> tracks { get; set; } = new List<YamlLocationTrack>(); } public class YamlTerritories { public bool enabled { get; set; } = true; public List<YamlTerritoryTrack> tracks { get; set; } = new List<YamlTerritoryTrack>(); } 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 mode { get; set; } = "custom"; public string url { get; set; } = ""; } public class YamlLocationTrack { 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 YamlTerritoryTrack { 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 mode { get; set; } = "custom"; public string url { get; set; } = ""; } public enum TerritoryMode { Custom, Vanilla, Mute } [BepInPlugin("glitnir.musiczones", "Glitnir Music Zones", "1.0.0")] public class Plugin : BaseUnityPlugin { private enum MusicState { None, Menu, Biome, Location, Territory, Boss, Creature } internal class LocationEntry { 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 TerritoryEntry { public string name; public float x; public float z; public float radius; public float volume; public bool enabled; public TerritoryMode mode; public string url; public bool IsActive => enabled && (mode != TerritoryMode.Custom || !string.IsNullOrWhiteSpace(url)); } internal class MusicEntry { public bool enabled; public string url; public TerritoryMode mode; public bool IsActive => enabled && (mode != TerritoryMode.Custom || !string.IsNullOrWhiteSpace(url)); public MusicEntry(bool enabled, string url, TerritoryMode mode = TerritoryMode.Custom) { this.enabled = enabled; this.url = url ?? ""; this.mode = mode; } } 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 const int MaxCachedClips = 12; private readonly Queue<string> _cacheInsertionOrder = new Queue<string>(); private Coroutine fadeCoroutine = null; private bool isFading = false; private float fadeDuration = 1f; private FileSystemWatcher configWatcher; private bool reloadPending = false; private float _reloadCooldown = 0f; private DateTime _watcherEventTime = DateTime.MinValue; private const float WatcherSettleDelay = 0.3f; 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 locEnabled = true; private float locVolume = 0.65f; private float locRadius = 90f; private float locDungeonYMin = 4500f; private float locDungeonYMax = 5500f; private List<LocationEntry> locList = new List<LocationEntry>(); private bool terrEnabled = true; private List<TerritoryEntry> terrList = new List<TerritoryEntry>(); 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 float currentCfgVolume = 1f; 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 void MuteVanilla() { if (!VanillaMuted) { VanillaMuted = true; ((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(); if ((Object)(object)MusicMan.instance != (Object)null && MusicMan.m_masterMusicVolume > 0f) { MusicManPatches.SetInitialVolume(MusicMan.m_masterMusicVolume); } ((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 && (DateTime.UtcNow - _watcherEventTime).TotalSeconds >= 0.30000001192092896) { reloadPending = false; _reloadCooldown = 1f; ((BaseUnityPlugin)this).Logger.LogInfo((object)"[Glitnir] Config alterada — recarregando..."); LoadConfig(); currentUrl = ""; currentState = MusicState.None; } if ((Object)(object)audioSource != (Object)null && audioSource.isPlaying && !isFading) { audioSource.volume = FinalVolume(currentCfgVolume); } 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(); } } else if (menuClipReady && currentState != MusicState.Menu) { PlayCachedClip(menuClip, FinalVolume(menuVolume), MusicState.Menu, menuEntry.url, menuVolume); } } else if (worldLoaded) { 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_02d2: Unknown result type (might be due to invalid IL or missing references) //IL_031b: Unknown result type (might be due to invalid IL or missing references) //IL_04a7: Unknown result type (might be due to invalid IL or missing references) //IL_04ad: Unknown result type (might be due to invalid IL or missing references) //IL_04b9: Unknown result type (might be due to invalid IL or missing references) //IL_04be: Unknown result type (might be due to invalid IL or missing references) //IL_04c6: 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_018c: Unknown result type (might be due to invalid IL or missing references) //IL_0194: 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()) { if (Vector3.Distance(position, ((Component)allCharacter).transform.position) <= num2) { _charBuffer.Add(allCharacter); } if (_charBuffer.Count >= 64) { break; } } } 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 (locEnabled) { string locationMusic = GetLocationMusic(position); if (!string.IsNullOrEmpty(locationMusic)) { TryPreload(locationMusic); SwitchMusic(locationMusic, locVolume, MusicState.Location); return; } } if (terrEnabled && GetTerritoryMatch(position, out var url, out var volume, out var mode)) { switch (mode) { case TerritoryMode.Custom: TryPreload(url); SwitchMusic(url, volume, MusicState.Territory); return; case TerritoryMode.Mute: if (currentState != MusicState.Territory || currentUrl != "__mute__") { ((BaseUnityPlugin)this).Logger.LogInfo((object)"[Glitnir] [Territory/Mute] Silenciando tudo."); MuteVanilla(); if (fadeCoroutine != null) { ((MonoBehaviour)this).StopCoroutine(fadeCoroutine); } isFading = false; if (audioSource.isPlaying) { fadeCoroutine = ((MonoBehaviour)this).StartCoroutine(FadeOutAndStop()); } currentState = MusicState.Territory; currentUrl = "__mute__"; } return; case TerritoryMode.Vanilla: if (currentState != MusicState.Territory || currentUrl != "__vanilla__") { ((BaseUnityPlugin)this).Logger.LogInfo((object)"[Glitnir] [Territory/Vanilla] Restaurando música vanilla."); if (fadeCoroutine != null) { ((MonoBehaviour)this).StopCoroutine(fadeCoroutine); } isFading = false; fadeCoroutine = ((MonoBehaviour)this).StartCoroutine(FadeOutAndStop(andUnmute: true)); currentState = MusicState.Territory; currentUrl = "__vanilla__"; } 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) { switch (value3.mode) { case TerritoryMode.Custom: TryPreload(value3.url); SwitchMusic(value3.url, biomeVolume, MusicState.Biome); return; case TerritoryMode.Mute: if (currentState != MusicState.Biome || currentUrl != "__mute__biome__") { ((BaseUnityPlugin)this).Logger.LogInfo((object)"[Glitnir] [Biome/Mute] Silenciando tudo."); MuteVanilla(); if (fadeCoroutine != null) { ((MonoBehaviour)this).StopCoroutine(fadeCoroutine); } isFading = false; if (audioSource.isPlaying) { fadeCoroutine = ((MonoBehaviour)this).StartCoroutine(FadeOutAndStop()); } currentState = MusicState.Biome; currentUrl = "__mute__biome__"; } return; case TerritoryMode.Vanilla: if (currentState != MusicState.Biome || currentUrl != "__vanilla__biome__") { ((BaseUnityPlugin)this).Logger.LogInfo((object)"[Glitnir] [Biome/Vanilla] Restaurando música vanilla."); if (fadeCoroutine != null) { ((MonoBehaviour)this).StopCoroutine(fadeCoroutine); } isFading = false; fadeCoroutine = ((MonoBehaviour)this).StartCoroutine(FadeOutAndStop(andUnmute: true)); currentState = MusicState.Biome; currentUrl = "__vanilla__biome__"; } return; } } } if (currentState != MusicState.None) { 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_0033: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_0124: 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_0133: Unknown result type (might be due to invalid IL or missing references) //IL_0138: 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_0145: 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_0154: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Unknown result type (might be due to invalid IL or missing references) //IL_016e: Unknown result type (might be due to invalid IL or missing references) //IL_0173: Unknown result type (might be due to invalid IL or missing references) //IL_017b: Unknown result type (might be due to invalid IL or missing references) //IL_0182: Unknown result type (might be due to invalid IL or missing references) //IL_018f: Unknown result type (might be due to invalid IL or missing references) //IL_0194: Unknown result type (might be due to invalid IL or missing references) //IL_019c: Unknown result type (might be due to invalid IL or missing references) //IL_0255: Unknown result type (might be due to invalid IL or missing references) //IL_0260: Unknown result type (might be due to invalid IL or missing references) //IL_0266: Unknown result type (might be due to invalid IL or missing references) //IL_026b: Unknown result type (might be due to invalid IL or missing references) //IL_0277: Unknown result type (might be due to invalid IL or missing references) //IL_027e: Unknown result type (might be due to invalid IL or missing references) foreach (TerritoryEntry terr in terrList) { if (terr.IsActive && terr.mode == TerritoryMode.Custom) { float num = Vector3.Distance(new Vector3(pos.x, 0f, pos.z), new Vector3(terr.x, 0f, terr.z)); if (num <= terr.radius * 1.5f) { TryPreload(terr.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 (locEnabled) { foreach (LocationEntry loc in locList) { if (loc.IsActive && _locPosCache.TryGetValue(loc.location, out var value2)) { float num3 = ((loc.radius > 0f) ? loc.radius : locRadius); float num4 = Vector3.Distance(new Vector3(pos.x, 0f, pos.z), new Vector3(value2.x, 0f, value2.z)); if (num4 <= num3 * 1.5f) { TryPreload(loc.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 GetLocationMusic(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_013b: Unknown result type (might be due to invalid IL or missing references) //IL_0141: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_015e: 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 (LocationEntry loc in locList) { if (!loc.IsActive) { continue; } float num = ((loc.dungeonYMin >= 0f) ? loc.dungeonYMin : locDungeonYMin); float num2 = ((loc.dungeonYMax >= 0f) ? loc.dungeonYMax : locDungeonYMax); bool flag = origin.y >= num && origin.y <= num2; if (loc.dungeonOnly) { if (!flag) { continue; } return loc.url; } if (!_locPosCache.TryGetValue(loc.location, out var value)) { if (!ZoneSystem.instance.FindClosestLocation(loc.location, origin, ref val)) { continue; } value = val.m_position; _locPosCache[loc.location] = value; } float num3 = ((loc.radius > 0f) ? loc.radius : locRadius); float num4 = (float)Math.Sqrt(Math.Pow(origin.x - value.x, 2.0) + Math.Pow(origin.z - value.z, 2.0)); if (!(num4 <= num3)) { continue; } return loc.url; } return null; } private bool GetTerritoryMatch(Vector3 origin, out string url, out float volume, out TerritoryMode mode) { //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 (TerritoryEntry terr in terrList) { if (terr.IsActive) { float num = Vector3.Distance(new Vector3(origin.x, 0f, origin.z), new Vector3(terr.x, 0f, terr.z)); if (num <= terr.radius) { url = terr.url; volume = terr.volume; mode = terr.mode; return true; } } } url = null; volume = 0f; mode = TerritoryMode.Custom; return false; } private void TryPreload(string url) { if (!string.IsNullOrWhiteSpace(url) && !clipCache.ContainsKey(url) && !preloadingUrls.Contains(url)) { ((MonoBehaviour)this).StartCoroutine(PreloadClip(url)); } } private void AddToCache(string url, AudioClip clip) { if ((Object)(object)clip == (Object)null) { clipCache[url] = null; return; } bool flag = !clipCache.ContainsKey(url); clipCache[url] = clip; if (flag) { _cacheInsertionOrder.Enqueue(url); } int num = 0; int count = _cacheInsertionOrder.Count; while (_cacheInsertionOrder.Count > 12 && num < count) { num++; string text = _cacheInsertionOrder.Peek(); if (text == currentClipUrl) { break; } _cacheInsertionOrder.Dequeue(); if (clipCache.TryGetValue(text, out var value) && (Object)(object)value != (Object)null) { Object.Destroy((Object)(object)value); ((BaseUnityPlugin)this).Logger.LogInfo((object)$"[Glitnir] Cache LRU: liberando '{text.Split(new char[1] { '/' }).Last()}' ({clipCache.Count - 1} clips)"); } clipCache.Remove(text); } } private IEnumerator PreloadClip(string url) { preloadingUrls.Add(url); ((BaseUnityPlugin)this).Logger.LogInfo((object)("[Glitnir] Pré-carregando: " + url)); UnityWebRequest req = UnityWebRequestMultimedia.GetAudioClip(url, (AudioType)13); try { ((DownloadHandlerAudioClip)req.downloadHandler).compressed = false; req.timeout = 20; yield return req.SendWebRequest(); if ((int)req.result != 1) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("[Glitnir] Falha no pré-carregamento (URL inválida/expirada?): " + req.error + " — " + url)); clipCache[url] = null; preloadingUrls.Remove(url); yield break; } AudioClip clip = DownloadHandlerAudioClip.GetContent(req); preloadingUrls.Remove(url); if ((Object)(object)clip != (Object)null) { AddToCache(url, clip); ((BaseUnityPlugin)this).Logger.LogInfo((object)$"[Glitnir] Cache: {((Object)clip).name} ({clipCache.Count} clips em RAM)"); } } finally { ((IDisposable)req)?.Dispose(); } } private void SwitchMusic(string url, float cfgVolume, MusicState state) { if (!(currentUrl == url)) { ((BaseUnityPlugin)this).Logger.LogInfo((object)$"[Glitnir] [{state}] → {url}"); currentState = state; currentUrl = url; currentCfgVolume = cfgVolume; MuteVanilla(); if (fadeCoroutine != null) { ((MonoBehaviour)this).StopCoroutine(fadeCoroutine); } isFading = false; 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)); } } } private IEnumerator FadeSwitchCached(AudioClip nextClip, string url, float cfgVolume) { isFading = true; try { float startVol = audioSource.volume; float t = 0f; while (t < fadeDuration) { t += Time.deltaTime; audioSource.volume = Mathf.Lerp(startVol, 0f, t / fadeDuration); yield return null; } audioSource.Stop(); currentClipUrl = url; audioSource.clip = nextClip; audioSource.volume = 0f; audioSource.Play(); t = 0f; while (t < fadeDuration) { t += Time.deltaTime; audioSource.volume = Mathf.Lerp(0f, FinalVolume(cfgVolume), t / fadeDuration); yield return null; } audioSource.volume = FinalVolume(cfgVolume); ((BaseUnityPlugin)this).Logger.LogInfo((object)$"[Glitnir] Tocando do cache (vol={audioSource.volume:F2})."); } finally { isFading = false; } } private IEnumerator FadeSwitch(string url, float cfgVolume) { isFading = true; try { float waitLimit = fadeDuration + 15f; float waited = 0f; float startVol = audioSource.volume; float t = 0f; while (t < fadeDuration || (preloadingUrls.Contains(url) && waited < waitLimit)) { float dt = Time.deltaTime; t += dt; waited += dt; if (t <= fadeDuration) { audioSource.volume = Mathf.Lerp(startVol, 0f, t / fadeDuration); } else { audioSource.volume = 0f; } if (!preloadingUrls.Contains(url) && t >= fadeDuration) { break; } yield return null; } audioSource.Stop(); ReleaseCurrentClip(); if (clipCache.TryGetValue(url, out var cached) && (Object)(object)cached != (Object)null) { currentClipUrl = url; audioSource.clip = cached; audioSource.volume = 0f; audioSource.Play(); t = 0f; while (t < fadeDuration) { t += Time.deltaTime; audioSource.volume = Mathf.Lerp(0f, FinalVolume(cfgVolume), t / fadeDuration); yield return null; } audioSource.volume = FinalVolume(cfgVolume); ((BaseUnityPlugin)this).Logger.LogInfo((object)$"[Glitnir] Tocando do cache (vol={audioSource.volume:F2})."); } else { yield return ((MonoBehaviour)this).StartCoroutine(LoadAndFadeIn(url, cfgVolume)); } } finally { isFading = false; } } private IEnumerator FadeOutAndStop(bool andUnmute = false) { isFading = true; try { float startVol = audioSource.volume; float t = 0f; while (t < fadeDuration) { t += Time.deltaTime; audioSource.volume = Mathf.Lerp(startVol, 0f, t / fadeDuration); yield return null; } audioSource.Stop(); ReleaseCurrentClip(); if (andUnmute) { UnmuteVanilla(); } } finally { isFading = false; } } private IEnumerator LoadAndFadeIn(string url, float cfgVolume) { if (string.IsNullOrWhiteSpace(url)) { yield break; } if (clipCache.TryGetValue(url, out var preloaded) && (Object)(object)preloaded != (Object)null) { currentClipUrl = url; audioSource.clip = preloaded; audioSource.volume = 0f; audioSource.Play(); float t2 = 0f; while (t2 < fadeDuration) { t2 += Time.deltaTime; audioSource.volume = Mathf.Lerp(0f, FinalVolume(cfgVolume), t2 / fadeDuration); yield return null; } audioSource.volume = FinalVolume(cfgVolume); ((BaseUnityPlugin)this).Logger.LogInfo((object)$"[Glitnir] Tocando (vol={audioSource.volume:F2})."); yield break; } UnityWebRequest req = UnityWebRequestMultimedia.GetAudioClip(url, (AudioType)13); try { ((DownloadHandlerAudioClip)req.downloadHandler).compressed = false; req.timeout = 15; yield return req.SendWebRequest(); if ((int)req.result != 1) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("[Glitnir] Falha ao carregar (URL inválida/expirada?): " + req.error + " — " + url)); clipCache[url] = null; yield break; } AudioClip clip = DownloadHandlerAudioClip.GetContent(req); if ((Object)(object)clip == (Object)null || currentUrl != url) { if ((Object)(object)clip != (Object)null) { Object.Destroy((Object)(object)clip); } yield break; } AddToCache(url, clip); preloadingUrls.Remove(url); ReleaseCurrentClip(); audioSource.clip = clip; audioSource.volume = 0f; audioSource.Play(); currentClipUrl = url; float t3 = 0f; while (t3 < fadeDuration) { t3 += Time.deltaTime; audioSource.volume = Mathf.Lerp(0f, FinalVolume(cfgVolume), t3 / fadeDuration); yield return null; } audioSource.volume = FinalVolume(cfgVolume); ((BaseUnityPlugin)this).Logger.LogInfo((object)$"[Glitnir] Tocando (vol={audioSource.volume:F2})."); } finally { ((IDisposable)req)?.Dispose(); } } private void PlayCachedClip(AudioClip clip, float finalVolume, MusicState state, string url, float cfgVolume) { if (!(currentUrl == url)) { currentState = state; currentUrl = url; currentClipUrl = url; currentCfgVolume = cfgVolume; MuteVanilla(); audioSource.Stop(); audioSource.clip = clip; audioSource.volume = finalVolume; audioSource.Play(); } } private IEnumerator PreloadMenuMusic() { if (menuEntry == null || !menuEnabled || !menuEntry.IsActive) { yield break; } if (clipCache.TryGetValue(menuEntry.url, out var cached)) { if ((Object)(object)cached != (Object)null) { menuClip = cached; menuClipReady = true; ((BaseUnityPlugin)this).Logger.LogInfo((object)"[Glitnir] Menu: usando clip do cache."); } yield break; } ((BaseUnityPlugin)this).Logger.LogInfo((object)"[Glitnir] Pré-carregando música do menu..."); UnityWebRequest req = UnityWebRequestMultimedia.GetAudioClip(menuEntry.url, (AudioType)13); try { ((DownloadHandlerAudioClip)req.downloadHandler).compressed = false; req.timeout = 15; yield return req.SendWebRequest(); if ((int)req.result != 1) { ((BaseUnityPlugin)this).Logger.LogError((object)("[Glitnir] Falha no menu: " + req.error)); clipCache[menuEntry.url] = null; yield break; } AudioClip clip = DownloadHandlerAudioClip.GetContent(req); if ((Object)(object)clip != (Object)null) { AddToCache(menuEntry.url, clip); menuClip = clip; menuClipReady = true; } ((BaseUnityPlugin)this).Logger.LogInfo((object)("[Glitnir] Menu " + (menuClipReady ? "pronto." : "clip nulo!"))); } finally { ((IDisposable)req)?.Dispose(); } } private void StopOurMusic() { if (fadeCoroutine != null) { ((MonoBehaviour)this).StopCoroutine(fadeCoroutine); } isFading = false; 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() { menuClip = null; menuClipReady = false; foreach (AudioClip value in clipCache.Values) { if ((Object)(object)value != (Object)null) { Object.Destroy((Object)(object)value); } } clipCache.Clear(); preloadingUrls.Clear(); _cacheInsertionOrder.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; TryConnectToMusicMixer(); } } private void TryConnectToMusicMixer() { AudioMixerGroup musicGroup = MusicManPatches.GetMusicGroup(); if ((Object)(object)musicGroup != (Object)null) { audioSource.outputAudioMixerGroup = musicGroup; ((BaseUnityPlugin)this).Logger.LogInfo((object)"[Glitnir] AudioSource conectado ao mixer de música do jogo."); } else { ((MonoBehaviour)this).StartCoroutine(RetryConnectMixer()); } } private IEnumerator RetryConnectMixer() { float elapsed = 0f; while (elapsed < 10f) { yield return (object)new WaitForSeconds(0.5f); elapsed += 0.5f; AudioMixerGroup group = MusicManPatches.GetMusicGroup(); if ((Object)(object)group != (Object)null) { audioSource.outputAudioMixerGroup = group; ((BaseUnityPlugin)this).Logger.LogInfo((object)"[Glitnir] AudioSource conectado ao mixer de música do jogo (retry)."); yield break; } } ((BaseUnityPlugin)this).Logger.LogError((object)"[Glitnir] Não foi possível conectar ao AudioMixerGroup do MusicMan — o slider 'Volume da música' pode não afetar o volume do mod!"); } 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 { _watcherEventTime = DateTime.UtcNow; 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_016f: 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)) { TerritoryMode mode = TerritoryMode.Custom; if (!string.IsNullOrWhiteSpace(track.Value.mode)) { string text2 = track.Value.mode.Trim().ToLowerInvariant(); string text3 = text2; mode = ((text3 == "vanilla") ? TerritoryMode.Vanilla : ((text3 == "mute") ? TerritoryMode.Mute : TerritoryMode.Custom)); } dictionary[result] = new MusicEntry(track.Value.enabled, track.Value.url, mode); } } bool enabled3 = yamlConfig.locations.enabled; float volume3 = yamlConfig.locations.volume; float radius = yamlConfig.locations.radius; float dungeon_y_min = yamlConfig.locations.dungeon_y_min; float dungeon_y_max = yamlConfig.locations.dungeon_y_max; List<LocationEntry> list = new List<LocationEntry>(); foreach (YamlLocationTrack track2 in yamlConfig.locations.tracks) { list.Add(new LocationEntry { 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.territories.enabled; List<TerritoryEntry> list2 = new List<TerritoryEntry>(); foreach (YamlTerritoryTrack track3 in yamlConfig.territories.tracks) { TerritoryMode mode2 = TerritoryMode.Custom; if (!string.IsNullOrWhiteSpace(track3.mode)) { string text4 = track3.mode.Trim().ToLowerInvariant(); string text5 = text4; mode2 = ((text5 == "vanilla") ? TerritoryMode.Vanilla : ((text5 == "mute") ? TerritoryMode.Mute : TerritoryMode.Custom)); } list2.Add(new TerritoryEntry { name = track3.name, x = track3.x, z = track3.z, radius = track3.radius, volume = track3.volume, enabled = track3.enabled, mode = mode2, 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; locEnabled = enabled3; locVolume = volume3; locRadius = radius; locDungeonYMin = dungeon_y_min; locDungeonYMax = dungeon_y_max; locList = list; terrEnabled = enabled4; terrList = 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, {locList.Count} locations, " + $"{terrList.Count} territories, {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: false\r\n volume: 0.0500\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\n# mode: custom = toca a url configurada (silencia vanilla)\r\n# vanilla = deixa a música do jogo tocar normalmente\r\n# mute = silêncio total (nem mod nem vanilla)\r\nbiomes:\r\n enabled: true\r\n volume: 0.0500\r\n tracks:\r\n Meadows:\r\n enabled: true\r\n mode: custom\r\n url: \"https://cdn.pixabay.com/download/audio/2026/05/25/audio_d304cbd8a2.mp3?filename=morgnar-neve-540465.mp3\"\r\n BlackForest:\r\n enabled: true\r\n mode: custom\r\n url: \"https://cdn.pixabay.com/download/audio/2026/05/22/audio_62456d9582.mp3?filename=morgnar-mire-of-ancients-538620.mp3\"\r\n Swamp:\r\n enabled: true\r\n mode: custom\r\n url: \"https://cdn.pixabay.com/download/audio/2026/05/25/audio_47a47ff6c2.mp3?filename=morgnar-pantano-540510.mp3\"\r\n Mountain:\r\n enabled: true\r\n mode: custom\r\n url: \"https://cdn.pixabay.com/download/audio/2026/05/25/audio_e6186facfc.mp3?filename=morgnar-mist-over-runestones-540508.mp3\"\r\n Plains:\r\n enabled: true\r\n mode: custom\r\n url: \"https://cdn.pixabay.com/download/audio/2026/05/25/audio_0f67273299.mp3?filename=morgnar-planicie-540517.mp3\"\r\n Mistlands:\r\n enabled: true\r\n mode: custom\r\n url: \"https://cdn.pixabay.com/download/audio/2026/05/25/audio_e6186facfc.mp3?filename=morgnar-mist-over-runestones-540508.mp3\"\r\n AshLands:\r\n enabled: true\r\n mode: custom\r\n url: \"https://cdn.pixabay.com/download/audio/2026/05/25/audio_d97092169a.mp3?filename=morgnar-ashlands-540519.mp3\"\r\n DeepNorth:\r\n enabled: true\r\n mode: custom\r\n url: \"https://cdn.pixabay.com/download/audio/2026/05/25/audio_2fe0daf552.mp3?filename=morgnar-deepnorth-540531.mp3\"\r\n Ocean:\r\n enabled: true\r\n mode: custom\r\n url: \"https://cdn.pixabay.com/download/audio/2026/05/25/audio_2fe0daf552.mp3?filename=morgnar-deepnorth-540531.mp3\"\r\n\r\n# ─── LOCATIONS (Pontos de interesse 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\nlocations:\r\n enabled: false\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: false\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: 4500.0\r\n dungeon_y_max: -1\r\n url: \"\"\r\n\r\n - enabled: false\r\n location: Crypt2\r\n radius: 90.0\r\n dungeon_only: false\r\n dungeon_y_min: 4500.0\r\n dungeon_y_max: 5500.0\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: false\r\n location: MountainCave01\r\n radius: 90.0\r\n dungeon_only: false\r\n dungeon_y_min: 4500\r\n dungeon_y_max: 5500\r\n url: \"\"\r\n\r\n# ─── TERRITORIES (Zonas por coordenada XZ) ─────────────────────────\r\n# Use para vilas ou regiões sem Location no ZoneSystem.\r\n# x/z: coordenadas do centro no mapa do Valheim\r\n# mode: custom = toca a url configurada (silencia vanilla)\r\n# vanilla = deixa a música do jogo tocar normalmente\r\n# mute = silêncio total (nem mod nem vanilla)\r\nterritories:\r\n enabled: true\r\n tracks:\r\n - enabled: true\r\n name: BosquePrmadico\r\n x: 25186.0\r\n z: 4411.0\r\n radius: 700.0\r\n volume: 0.0500\r\n mode: custom\r\n url: \"https://cdn.pixabay.com/download/audio/2026/05/25/audio_d304cbd8a2.mp3?filename=morgnar-neve-540465.mp3\"\r\n\r\n - enabled: true\r\n name: Vila Prado\r\n x: -245.0\r\n z: 336.0\r\n radius: 200.0\r\n volume: 0.0500\r\n mode: custom\r\n url: \"https://cdn.pixabay.com/download/audio/2026/05/22/audio_e0d6b4179f.mp3?filename=morgnar-harbor-hearth-village-1-538622.mp3\"\r\n\r\n - enabled: true\r\n name: Skjalfhame\r\n x: -37714.0\r\n z: 9799.0\r\n radius: 100.0\r\n volume: 0.0500\r\n mode: custom\r\n url: \"https://cdn.pixabay.com/download/audio/2026/05/25/audio_6ab79d7f51.mp3?filename=morgnar-vila-540514.mp3\"\r\n\r\n - enabled: true\r\n name: Hrotghar\r\n x: 3337.0\r\n z: -6096.0\r\n radius: 400.0\r\n volume: 0.0500\r\n mode: custom\r\n url: \"https://cdn.pixabay.com/download/audio/2026/05/25/audio_6ab79d7f51.mp3?filename=morgnar-vila-540514.mp3\"\r\n\r\n - enabled: true\r\n name: Winterhold\r\n x: 17938.0\r\n z: 14584.0\r\n radius: 70.0\r\n volume: 0.0500\r\n mode: custom\r\n url: \"https://cdn.pixabay.com/download/audio/2026/05/25/audio_6ab79d7f51.mp3?filename=morgnar-vila-540514.mp3\"\r\n\r\n - enabled: true\r\n name: Vila da Floresta Negra\r\n x: -1997.0\r\n z: -5333.0\r\n radius: 50.0\r\n volume: 0.0500\r\n mode: custom\r\n url: \"https://cdn.pixabay.com/download/audio/2026/05/25/audio_6ab79d7f51.mp3?filename=morgnar-vila-540514.mp3\"\r\n\r\n - enabled: true\r\n name: Vila do Pantano\r\n x: 4917.0\r\n z: -2571.0\r\n radius: 200.0\r\n volume: 0.0500\r\n mode: custom\r\n url: \"https://cdn.pixabay.com/download/audio/2026/05/22/audio_e0d6b4179f.mp3?filename=morgnar-harbor-hearth-village-1-538622.mp3\"\r\n\r\n - enabled: true\r\n name: Vila da Montanha\r\n x: 6508.0\r\n z: 3735.0\r\n radius: 400.0\r\n volume: 0.0500\r\n mode: custom\r\n url: \"https://cdn.pixabay.com/download/audio/2026/05/22/audio_e0d6b4179f.mp3?filename=morgnar-harbor-hearth-village-1-538622.mp3\"\r\n\r\n - enabled: true\r\n name: Varghard - Reino dos Humanos\r\n x: 13695.0\r\n z: 19496.0\r\n radius: 400.0\r\n volume: 0.0500\r\n mode: mute\r\n url: \"\"\r\n\r\n - enabled: true\r\n name: Eryndel - Reino dos Elfos\r\n x: 21474.0\r\n z: 12080.0\r\n radius: 400.0\r\n volume: 0.0500\r\n mode: mute\r\n url: \"\"\r\n\r\n - enabled: true\r\n name: Drakthar - Reino dos Orcs\r\n x: -7346.0\r\n z: 20523.0\r\n radius: 400.0\r\n volume: 0.0500\r\n mode: mute\r\n url: \"\"\r\n\r\n - enabled: true\r\n name: Coliseu\r\n x: 1745.0\r\n z: 21713.0\r\n radius: 500.0\r\n volume: 0.0500\r\n mode: mute\r\n url: \"\"\r\n\r\n - enabled: true\r\n name: Brumello - Reino dos Halflings\r\n x: -15671.0\r\n z: 15840.0\r\n radius: 500.0\r\n volume: 0.0500\r\n mode: mute\r\n url: \"\"\r\n\r\n - enabled: true\r\n name: Cabaré do Sjar\r\n x: 14691.0\r\n z: 17973.0\r\n radius: 50.0\r\n volume: 0.0500\r\n mode: mute\r\n url: \"\"\r\n\r\n - enabled: true\r\n name: Forte Falkreath\r\n x: -22106.0\r\n z: 9622.0\r\n radius: 100.0\r\n volume: 0.0500\r\n mode: custom\r\n url: \"https://cdn.pixabay.com/download/audio/2026/05/25/audio_c2d6bad590.mp3?filename=morgnar-falkreath-citadel-541114.mp3\"\r\n\r\n - enabled: false\r\n name: Parkour\r\n x: 6508.0\r\n z: 3735.0\r\n radius: 400.0\r\n volume: 0.0500\r\n mode: custom\r\n url: \"https://cdn.pixabay.com/download/audio/2026/05/25/audio_4d4bef9969.mp3?filename=morgnar-mead-hall-waltz-541115.mp3\"\r\n\r\n - enabled: true\r\n name: Jorrvaskr\r\n x: 11411.0\r\n z: 19191.0\r\n radius: 70.0\r\n volume: 0.0500\r\n mode: custom\r\n url: \"https://cdn.pixabay.com/download/audio/2026/05/22/audio_a9a5df53e2.mp3?filename=morgnar-harbor-hearth-village-538619.mp3\"\r\n\r\n - enabled: true\r\n name: Calindel\r\n x: 8590.0\r\n z: 20394.0\r\n radius: 70.0\r\n volume: 0.0500\r\n mode: custom\r\n url: \"https://cdn.pixabay.com/download/audio/2026/05/22/audio_a9a5df53e2.mp3?filename=morgnar-harbor-hearth-village-538619.mp3\"\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.0500\r\n radius: 120.0\r\n tracks:\r\n Eikthyr:\r\n enabled: true\r\n url: \"https://cdn.pixabay.com/download/audio/2026/05/22/audio_1a619af2ce.mp3?filename=morgnar-stag-of-thunder-538616.mp3\"\r\n gd_king:\r\n enabled: true\r\n url: \"https://cdn.pixabay.com/download/audio/2026/05/22/audio_1a619af2ce.mp3?filename=morgnar-stag-of-thunder-538616.mp3\"\r\n Bonemass:\r\n enabled: true\r\n url: \"https://cdn.pixabay.com/download/audio/2026/05/22/audio_1a619af2ce.mp3?filename=morgnar-stag-of-thunder-538616.mp3\"\r\n Dragon:\r\n enabled: true\r\n url: \"https://cdn.pixabay.com/download/audio/2026/05/22/audio_1a619af2ce.mp3?filename=morgnar-stag-of-thunder-538616.mp3\"\r\n GoblinKing:\r\n enabled: true\r\n url: \"https://cdn.pixabay.com/download/audio/2026/05/22/audio_1a619af2ce.mp3?filename=morgnar-stag-of-thunder-538616.mp3\"\r\n SeekerQueen:\r\n enabled: true\r\n url: \"https://cdn.pixabay.com/download/audio/2026/05/22/audio_1a619af2ce.mp3?filename=morgnar-stag-of-thunder-538616.mp3\"\r\n Fader:\r\n enabled: true\r\n url: \"https://cdn.pixabay.com/download/audio/2026/05/22/audio_1a619af2ce.mp3?filename=morgnar-stag-of-thunder-538616.mp3\"\r\n brutoGLIT:\r\n enabled: true\r\n url: \"https://cdn.pixabay.com/download/audio/2026/05/22/audio_1a619af2ce.mp3?filename=morgnar-stag-of-thunder-538616.mp3\"\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.0500\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)); } } } }