Decompiled source of Valheim Music Plus v1.13.0

bin/BiomeMusic.dll

Decompiled 3 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using UnityEngine;
using UnityEngine.Networking;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("BiomeMusic")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("BiomeMusic")]
[assembly: AssemblyTitle("BiomeMusic")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace BiomeMusic;

[BepInPlugin("kadabra.biomemusic", "BiomeMusic", "1.13.0")]
public class BiomeMusicPlugin : BaseUnityPlugin
{
	private static ManualLogSource Log;

	private ConfigEntry<float> cfgVolume;

	private ConfigEntry<float> cfgMinGap;

	private ConfigEntry<float> cfgMaxGap;

	private ConfigEntry<float> cfgFadeTime;

	private ConfigEntry<float> cfgBossRadius;

	private ConfigEntry<float> cfgBuildingRadius;

	private ConfigEntry<float> cfgHomeGrace;

	private ConfigEntry<float> cfgFireplaceRadius;

	private AudioSource source;

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

	private readonly List<AudioClip> globalClips = new List<AudioClip>();

	private readonly Dictionary<string, (AudioClip clip, float pos)> _saved = new Dictionary<string, (AudioClip, float)>();

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

	private string _currentZone = "";

	private bool _isFading;

	private bool _skipNextGap;

	private float _lastShelterTime = -999f;

	private void Awake()
	{
		Log = ((BaseUnityPlugin)this).Logger;
		cfgVolume = ((BaseUnityPlugin)this).Config.Bind<float>("Audio", "Volume", 0.8f, "Volume of your tracks (0.0-1.0)");
		cfgMinGap = ((BaseUnityPlugin)this).Config.Bind<float>("Audio", "MinGap", 1f, "Min seconds gap between tracks (natural endings)");
		cfgMaxGap = ((BaseUnityPlugin)this).Config.Bind<float>("Audio", "MaxGap", 3f, "Max seconds gap between tracks (natural endings)");
		cfgFadeTime = ((BaseUnityPlugin)this).Config.Bind<float>("Audio", "FadeTime", 2f, "Seconds to fade in/out on zone change");
		cfgBossRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Detection", "BossRadius", 150f, "Meters to detect a nearby boss");
		cfgBuildingRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Detection", "BuildingRadius", 1f, "Meters to detect nearby structural pieces");
		cfgHomeGrace = ((BaseUnityPlugin)this).Config.Bind<float>("Detection", "HomeGrace", 3f, "Seconds home music lingers after leaving shelter");
		cfgFireplaceRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Detection", "FireplaceRadius", 12f, "Meters to detect a burning fireplace outdoors");
		((MonoBehaviour)this).StartCoroutine(LoadAllClips(Path.Combine(Paths.PluginPath, "BiomeMusic", "music")));
	}

	private void SilenceMusicMan()
	{
		MusicMan instance = MusicMan.instance;
		if ((Object)(object)instance == (Object)null)
		{
			return;
		}
		AudioSource[] componentsInChildren = ((Component)instance).GetComponentsInChildren<AudioSource>();
		foreach (AudioSource val in componentsInChildren)
		{
			if ((Object)(object)val != (Object)null && val.isPlaying)
			{
				val.Stop();
			}
		}
	}

	private IEnumerator VanillaSilencer()
	{
		while (true)
		{
			if ((Object)(object)Player.m_localPlayer != (Object)null)
			{
				SilenceMusicMan();
			}
			yield return (object)new WaitForSeconds(0.5f);
		}
	}

	private AudioClip NextClip(string zone)
	{
		if (!clips.ContainsKey(zone) || clips[zone].Count == 0)
		{
			return null;
		}
		if (!_queues.ContainsKey(zone) || _queues[zone].Count == 0)
		{
			List<AudioClip> list = new List<AudioClip>(clips[zone]);
			for (int num = list.Count - 1; num > 0; num--)
			{
				int index = Random.Range(0, num + 1);
				AudioClip value = list[num];
				list[num] = list[index];
				list[index] = value;
			}
			_queues[zone] = new Queue<AudioClip>(list);
			Log.LogInfo((object)$"[BiomeMusic] [{zone}] reshuffled ({list.Count} tracks)");
		}
		return _queues[zone].Dequeue();
	}

	private IEnumerator FadeOutAndStop()
	{
		_isFading = true;
		float startVol = source.volume;
		float elapsed = 0f;
		float duration = cfgFadeTime.Value;
		while (elapsed < duration && source.isPlaying)
		{
			source.volume = Mathf.Lerp(startVol, 0f, elapsed / duration);
			elapsed += Time.deltaTime;
			yield return null;
		}
		source.Stop();
		source.volume = cfgVolume.Value;
		_isFading = false;
	}

	private IEnumerator FadeIn()
	{
		float elapsed = 0f;
		float duration = cfgFadeTime.Value;
		while (elapsed < duration)
		{
			source.volume = Mathf.Lerp(0f, cfgVolume.Value, elapsed / duration);
			elapsed += Time.deltaTime;
			yield return null;
		}
		source.volume = cfgVolume.Value;
	}

	private bool IsBossNearby(Player player)
	{
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			Collider[] array = Physics.OverlapSphere(((Component)player).transform.position, cfgBossRadius.Value);
			for (int i = 0; i < array.Length; i++)
			{
				Character componentInParent = ((Component)array[i]).GetComponentInParent<Character>();
				if ((Object)(object)componentInParent != (Object)null && (Object)(object)componentInParent != (Object)(object)player && componentInParent.IsBoss() && !componentInParent.IsDead())
				{
					return true;
				}
			}
		}
		catch
		{
		}
		return false;
	}

	private bool IsNearFireplace(Player player)
	{
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			Collider[] array = Physics.OverlapSphere(((Component)player).transform.position, cfgFireplaceRadius.Value);
			for (int i = 0; i < array.Length; i++)
			{
				Fireplace componentInParent = ((Component)array[i]).GetComponentInParent<Fireplace>();
				if ((Object)(object)componentInParent != (Object)null && componentInParent.IsBurning())
				{
					return true;
				}
			}
		}
		catch
		{
		}
		return false;
	}

	private bool IsNearBuilding(Player player)
	{
		//IL_0008: Unknown result type (might be due to invalid IL or missing references)
		//IL_003d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0042: Unknown result type (might be due to invalid IL or missing references)
		//IL_0046: Unknown result type (might be due to invalid IL or missing references)
		//IL_0054: Unknown result type (might be due to invalid IL or missing references)
		//IL_0059: Unknown result type (might be due to invalid IL or missing references)
		//IL_005d: Unknown result type (might be due to invalid IL or missing references)
		//IL_006b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0070: Unknown result type (might be due to invalid IL or missing references)
		//IL_0074: Unknown result type (might be due to invalid IL or missing references)
		int num = 0;
		Collider[] array = Physics.OverlapSphere(((Component)player).transform.position, cfgBuildingRadius.Value);
		foreach (Collider val in array)
		{
			if ((Object)(object)((Component)val).GetComponentInParent<WearNTear>() != (Object)null)
			{
				float[] array2 = new float[3];
				Bounds bounds = val.bounds;
				array2[0] = ((Bounds)(ref bounds)).size.x;
				bounds = val.bounds;
				array2[1] = ((Bounds)(ref bounds)).size.y;
				bounds = val.bounds;
				array2[2] = ((Bounds)(ref bounds)).size.z;
				if (Mathf.Max(array2) > 0.8f && ++num >= 5)
				{
					return true;
				}
			}
		}
		return false;
	}

	private string GetBiomeKey(Player player)
	{
		//IL_0061: Unknown result type (might be due to invalid IL or missing references)
		//IL_0066: Unknown result type (might be due to invalid IL or missing references)
		//IL_0067: Unknown result type (might be due to invalid IL or missing references)
		//IL_006a: Invalid comparison between Unknown and I4
		//IL_008f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0092: Invalid comparison between Unknown and I4
		//IL_006c: Unknown result type (might be due to invalid IL or missing references)
		//IL_006e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0084: Expected I4, but got Unknown
		//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a6: Invalid comparison between Unknown and I4
		//IL_0094: Unknown result type (might be due to invalid IL or missing references)
		//IL_0097: Invalid comparison between Unknown and I4
		//IL_0084: Unknown result type (might be due to invalid IL or missing references)
		//IL_0086: Invalid comparison between Unknown and I4
		//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ae: Invalid comparison between Unknown and I4
		//IL_0099: Unknown result type (might be due to invalid IL or missing references)
		//IL_009c: Invalid comparison between Unknown and I4
		//IL_0088: Unknown result type (might be due to invalid IL or missing references)
		//IL_008b: Invalid comparison between Unknown and I4
		if (IsBossNearby(player))
		{
			return "boss";
		}
		bool num = player.InShelter();
		bool flag = IsNearFireplace(player);
		if (num && flag)
		{
			_lastShelterTime = Time.time;
			return "home";
		}
		if (Time.time - _lastShelterTime < cfgHomeGrace.Value)
		{
			return "home";
		}
		if (IsNearBuilding(player))
		{
			return "approaching";
		}
		Biome currentBiome = player.GetCurrentBiome();
		if ((int)currentBiome <= 16)
		{
			switch (currentBiome - 1)
			{
			default:
				if ((int)currentBiome != 8)
				{
					if ((int)currentBiome != 16)
					{
						break;
					}
					return "plains";
				}
				return "blackforest";
			case 0:
				return "meadows";
			case 1:
				return "swamp";
			case 3:
				return "mountain";
			case 2:
				break;
			}
		}
		else if ((int)currentBiome <= 64)
		{
			if ((int)currentBiome == 32)
			{
				return "ashlands";
			}
			if ((int)currentBiome == 64)
			{
				return "deepnorth";
			}
		}
		else
		{
			if ((int)currentBiome == 256)
			{
				return "ocean";
			}
			if ((int)currentBiome == 512)
			{
				return "mistlands";
			}
		}
		return "meadows";
	}

	private IEnumerator LoadAllClips(string root)
	{
		string[] array = new string[12]
		{
			"meadows", "blackforest", "swamp", "mountain", "plains", "ocean", "mistlands", "ashlands", "deepnorth", "home",
			"boss", "approaching"
		};
		string[] array2 = array;
		foreach (string biome in array2)
		{
			string dir = Path.Combine(root, biome);
			if (Directory.Exists(dir))
			{
				clips[biome] = new List<AudioClip>();
				string[] files = Directory.GetFiles(dir, "*.ogg");
				foreach (string path in files)
				{
					yield return ((MonoBehaviour)this).StartCoroutine(LoadClip(path, clips[biome], (AudioType)14));
				}
				files = Directory.GetFiles(dir, "*.wav");
				foreach (string path2 in files)
				{
					yield return ((MonoBehaviour)this).StartCoroutine(LoadClip(path2, clips[biome], (AudioType)20));
				}
				Log.LogInfo((object)$"[BiomeMusic] {biome}: {clips[biome].Count} track(s)");
			}
		}
		string globalDir = Path.Combine(root, "global");
		if (Directory.Exists(globalDir))
		{
			array2 = Directory.GetFiles(globalDir, "*.ogg");
			foreach (string path3 in array2)
			{
				yield return ((MonoBehaviour)this).StartCoroutine(LoadClip(path3, globalClips, (AudioType)14));
			}
			array2 = Directory.GetFiles(globalDir, "*.wav");
			foreach (string path4 in array2)
			{
				yield return ((MonoBehaviour)this).StartCoroutine(LoadClip(path4, globalClips, (AudioType)20));
			}
			Log.LogInfo((object)$"[BiomeMusic] global: {globalClips.Count} track(s)");
			string[] array3 = new string[11]
			{
				"meadows", "blackforest", "swamp", "mountain", "plains", "ocean", "mistlands", "ashlands", "deepnorth", "home",
				"approaching"
			};
			foreach (string key in array3)
			{
				if (!clips.ContainsKey(key))
				{
					clips[key] = new List<AudioClip>();
				}
				clips[key].AddRange(globalClips);
			}
		}
		GameObject val = new GameObject("BiomeMusicPlayer");
		Object.DontDestroyOnLoad((Object)(object)val);
		source = val.AddComponent<AudioSource>();
		source.spatialBlend = 0f;
		source.loop = false;
		source.volume = cfgVolume.Value;
		int num = 0;
		foreach (List<AudioClip> value in clips.Values)
		{
			num += value.Count;
		}
		Log.LogInfo((object)$"[BiomeMusic] Ready — {num} total slots.");
		((MonoBehaviour)this).StartCoroutine(VanillaSilencer());
		((MonoBehaviour)this).StartCoroutine(MusicLoop());
	}

	private IEnumerator LoadClip(string path, List<AudioClip> target, AudioType type)
	{
		//IL_0015: Unknown result type (might be due to invalid IL or missing references)
		//IL_0016: Unknown result type (might be due to invalid IL or missing references)
		UnityWebRequest req = UnityWebRequestMultimedia.GetAudioClip("file://" + path, type);
		try
		{
			((DownloadHandlerAudioClip)req.downloadHandler).streamAudio = false;
			yield return req.SendWebRequest();
			if ((int)req.result == 1)
			{
				AudioClip content = DownloadHandlerAudioClip.GetContent(req);
				((Object)content).name = Path.GetFileNameWithoutExtension(path);
				target.Add(content);
			}
			else
			{
				Log.LogWarning((object)("[BiomeMusic] Load failed: " + path + " — " + req.error));
			}
		}
		finally
		{
			((IDisposable)req)?.Dispose();
		}
	}

	private IEnumerator MusicLoop()
	{
		yield return (object)new WaitForSeconds(20f);
		while (true)
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				yield return (object)new WaitForSeconds(2f);
				continue;
			}
			string biomeKey = GetBiomeKey(localPlayer);
			if (_isFading)
			{
				yield return (object)new WaitForSeconds(0.1f);
				continue;
			}
			if (source.isPlaying)
			{
				if (biomeKey != _currentZone)
				{
					_saved[_currentZone] = (source.clip, source.time);
					_skipNextGap = true;
					Log.LogInfo((object)$"[BiomeMusic] [{_currentZone}→{biomeKey}] saved {source.time:F0}s — fading");
					((MonoBehaviour)this).StartCoroutine(FadeOutAndStop());
				}
				yield return (object)new WaitForSeconds(1f);
				continue;
			}
			if (!_skipNextGap)
			{
				float num = Random.Range(cfgMinGap.Value, cfgMaxGap.Value);
				yield return (object)new WaitForSeconds(num);
			}
			_skipNextGap = false;
			localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				continue;
			}
			biomeKey = GetBiomeKey(localPlayer);
			if (!clips.ContainsKey(biomeKey) || clips[biomeKey].Count == 0)
			{
				yield return (object)new WaitForSeconds(2f);
				continue;
			}
			float num2 = 0f;
			AudioClip val;
			if (_saved.TryGetValue(biomeKey, out (AudioClip, float) value) && (Object)(object)value.Item1 != (Object)null && value.Item1.length - value.Item2 > 10f)
			{
				(val, num2) = value;
				_saved.Remove(biomeKey);
				Log.LogInfo((object)$"[BiomeMusic] ↩ Resume [{biomeKey}] {((Object)val).name} from {num2:F0}s");
			}
			else
			{
				val = NextClip(biomeKey);
				if (_saved.ContainsKey(biomeKey))
				{
					_saved.Remove(biomeKey);
				}
				Log.LogInfo((object)$"[BiomeMusic] ▶ [{biomeKey}] {((Object)val).name} ({val.length:F0}s)");
			}
			_currentZone = biomeKey;
			source.clip = val;
			source.time = num2;
			source.volume = 0f;
			source.Play();
			yield return ((MonoBehaviour)this).StartCoroutine(FadeIn());
		}
	}
}

obj/Release/BiomeMusic.dll

Decompiled 3 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using UnityEngine;
using UnityEngine.Networking;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("BiomeMusic")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("BiomeMusic")]
[assembly: AssemblyTitle("BiomeMusic")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace BiomeMusic;

[BepInPlugin("kadabra.biomemusic", "BiomeMusic", "1.13.0")]
public class BiomeMusicPlugin : BaseUnityPlugin
{
	private static ManualLogSource Log;

	private ConfigEntry<float> cfgVolume;

	private ConfigEntry<float> cfgMinGap;

	private ConfigEntry<float> cfgMaxGap;

	private ConfigEntry<float> cfgFadeTime;

	private ConfigEntry<float> cfgBossRadius;

	private ConfigEntry<float> cfgBuildingRadius;

	private ConfigEntry<float> cfgHomeGrace;

	private ConfigEntry<float> cfgFireplaceRadius;

	private AudioSource source;

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

	private readonly List<AudioClip> globalClips = new List<AudioClip>();

	private readonly Dictionary<string, (AudioClip clip, float pos)> _saved = new Dictionary<string, (AudioClip, float)>();

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

	private string _currentZone = "";

	private bool _isFading;

	private bool _skipNextGap;

	private float _lastShelterTime = -999f;

	private void Awake()
	{
		Log = ((BaseUnityPlugin)this).Logger;
		cfgVolume = ((BaseUnityPlugin)this).Config.Bind<float>("Audio", "Volume", 0.8f, "Volume of your tracks (0.0-1.0)");
		cfgMinGap = ((BaseUnityPlugin)this).Config.Bind<float>("Audio", "MinGap", 1f, "Min seconds gap between tracks (natural endings)");
		cfgMaxGap = ((BaseUnityPlugin)this).Config.Bind<float>("Audio", "MaxGap", 3f, "Max seconds gap between tracks (natural endings)");
		cfgFadeTime = ((BaseUnityPlugin)this).Config.Bind<float>("Audio", "FadeTime", 2f, "Seconds to fade in/out on zone change");
		cfgBossRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Detection", "BossRadius", 150f, "Meters to detect a nearby boss");
		cfgBuildingRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Detection", "BuildingRadius", 1f, "Meters to detect nearby structural pieces");
		cfgHomeGrace = ((BaseUnityPlugin)this).Config.Bind<float>("Detection", "HomeGrace", 3f, "Seconds home music lingers after leaving shelter");
		cfgFireplaceRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Detection", "FireplaceRadius", 12f, "Meters to detect a burning fireplace outdoors");
		((MonoBehaviour)this).StartCoroutine(LoadAllClips(Path.Combine(Paths.PluginPath, "BiomeMusic", "music")));
	}

	private void SilenceMusicMan()
	{
		MusicMan instance = MusicMan.instance;
		if ((Object)(object)instance == (Object)null)
		{
			return;
		}
		AudioSource[] componentsInChildren = ((Component)instance).GetComponentsInChildren<AudioSource>();
		foreach (AudioSource val in componentsInChildren)
		{
			if ((Object)(object)val != (Object)null && val.isPlaying)
			{
				val.Stop();
			}
		}
	}

	private IEnumerator VanillaSilencer()
	{
		while (true)
		{
			if ((Object)(object)Player.m_localPlayer != (Object)null)
			{
				SilenceMusicMan();
			}
			yield return (object)new WaitForSeconds(0.5f);
		}
	}

	private AudioClip NextClip(string zone)
	{
		if (!clips.ContainsKey(zone) || clips[zone].Count == 0)
		{
			return null;
		}
		if (!_queues.ContainsKey(zone) || _queues[zone].Count == 0)
		{
			List<AudioClip> list = new List<AudioClip>(clips[zone]);
			for (int num = list.Count - 1; num > 0; num--)
			{
				int index = Random.Range(0, num + 1);
				AudioClip value = list[num];
				list[num] = list[index];
				list[index] = value;
			}
			_queues[zone] = new Queue<AudioClip>(list);
			Log.LogInfo((object)$"[BiomeMusic] [{zone}] reshuffled ({list.Count} tracks)");
		}
		return _queues[zone].Dequeue();
	}

	private IEnumerator FadeOutAndStop()
	{
		_isFading = true;
		float startVol = source.volume;
		float elapsed = 0f;
		float duration = cfgFadeTime.Value;
		while (elapsed < duration && source.isPlaying)
		{
			source.volume = Mathf.Lerp(startVol, 0f, elapsed / duration);
			elapsed += Time.deltaTime;
			yield return null;
		}
		source.Stop();
		source.volume = cfgVolume.Value;
		_isFading = false;
	}

	private IEnumerator FadeIn()
	{
		float elapsed = 0f;
		float duration = cfgFadeTime.Value;
		while (elapsed < duration)
		{
			source.volume = Mathf.Lerp(0f, cfgVolume.Value, elapsed / duration);
			elapsed += Time.deltaTime;
			yield return null;
		}
		source.volume = cfgVolume.Value;
	}

	private bool IsBossNearby(Player player)
	{
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			Collider[] array = Physics.OverlapSphere(((Component)player).transform.position, cfgBossRadius.Value);
			for (int i = 0; i < array.Length; i++)
			{
				Character componentInParent = ((Component)array[i]).GetComponentInParent<Character>();
				if ((Object)(object)componentInParent != (Object)null && (Object)(object)componentInParent != (Object)(object)player && componentInParent.IsBoss() && !componentInParent.IsDead())
				{
					return true;
				}
			}
		}
		catch
		{
		}
		return false;
	}

	private bool IsNearFireplace(Player player)
	{
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			Collider[] array = Physics.OverlapSphere(((Component)player).transform.position, cfgFireplaceRadius.Value);
			for (int i = 0; i < array.Length; i++)
			{
				Fireplace componentInParent = ((Component)array[i]).GetComponentInParent<Fireplace>();
				if ((Object)(object)componentInParent != (Object)null && componentInParent.IsBurning())
				{
					return true;
				}
			}
		}
		catch
		{
		}
		return false;
	}

	private bool IsNearBuilding(Player player)
	{
		//IL_0008: Unknown result type (might be due to invalid IL or missing references)
		//IL_003d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0042: Unknown result type (might be due to invalid IL or missing references)
		//IL_0046: Unknown result type (might be due to invalid IL or missing references)
		//IL_0054: Unknown result type (might be due to invalid IL or missing references)
		//IL_0059: Unknown result type (might be due to invalid IL or missing references)
		//IL_005d: Unknown result type (might be due to invalid IL or missing references)
		//IL_006b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0070: Unknown result type (might be due to invalid IL or missing references)
		//IL_0074: Unknown result type (might be due to invalid IL or missing references)
		int num = 0;
		Collider[] array = Physics.OverlapSphere(((Component)player).transform.position, cfgBuildingRadius.Value);
		foreach (Collider val in array)
		{
			if ((Object)(object)((Component)val).GetComponentInParent<WearNTear>() != (Object)null)
			{
				float[] array2 = new float[3];
				Bounds bounds = val.bounds;
				array2[0] = ((Bounds)(ref bounds)).size.x;
				bounds = val.bounds;
				array2[1] = ((Bounds)(ref bounds)).size.y;
				bounds = val.bounds;
				array2[2] = ((Bounds)(ref bounds)).size.z;
				if (Mathf.Max(array2) > 0.8f && ++num >= 5)
				{
					return true;
				}
			}
		}
		return false;
	}

	private string GetBiomeKey(Player player)
	{
		//IL_0061: Unknown result type (might be due to invalid IL or missing references)
		//IL_0066: Unknown result type (might be due to invalid IL or missing references)
		//IL_0067: Unknown result type (might be due to invalid IL or missing references)
		//IL_006a: Invalid comparison between Unknown and I4
		//IL_008f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0092: Invalid comparison between Unknown and I4
		//IL_006c: Unknown result type (might be due to invalid IL or missing references)
		//IL_006e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0084: Expected I4, but got Unknown
		//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a6: Invalid comparison between Unknown and I4
		//IL_0094: Unknown result type (might be due to invalid IL or missing references)
		//IL_0097: Invalid comparison between Unknown and I4
		//IL_0084: Unknown result type (might be due to invalid IL or missing references)
		//IL_0086: Invalid comparison between Unknown and I4
		//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ae: Invalid comparison between Unknown and I4
		//IL_0099: Unknown result type (might be due to invalid IL or missing references)
		//IL_009c: Invalid comparison between Unknown and I4
		//IL_0088: Unknown result type (might be due to invalid IL or missing references)
		//IL_008b: Invalid comparison between Unknown and I4
		if (IsBossNearby(player))
		{
			return "boss";
		}
		bool num = player.InShelter();
		bool flag = IsNearFireplace(player);
		if (num && flag)
		{
			_lastShelterTime = Time.time;
			return "home";
		}
		if (Time.time - _lastShelterTime < cfgHomeGrace.Value)
		{
			return "home";
		}
		if (IsNearBuilding(player))
		{
			return "approaching";
		}
		Biome currentBiome = player.GetCurrentBiome();
		if ((int)currentBiome <= 16)
		{
			switch (currentBiome - 1)
			{
			default:
				if ((int)currentBiome != 8)
				{
					if ((int)currentBiome != 16)
					{
						break;
					}
					return "plains";
				}
				return "blackforest";
			case 0:
				return "meadows";
			case 1:
				return "swamp";
			case 3:
				return "mountain";
			case 2:
				break;
			}
		}
		else if ((int)currentBiome <= 64)
		{
			if ((int)currentBiome == 32)
			{
				return "ashlands";
			}
			if ((int)currentBiome == 64)
			{
				return "deepnorth";
			}
		}
		else
		{
			if ((int)currentBiome == 256)
			{
				return "ocean";
			}
			if ((int)currentBiome == 512)
			{
				return "mistlands";
			}
		}
		return "meadows";
	}

	private IEnumerator LoadAllClips(string root)
	{
		string[] array = new string[12]
		{
			"meadows", "blackforest", "swamp", "mountain", "plains", "ocean", "mistlands", "ashlands", "deepnorth", "home",
			"boss", "approaching"
		};
		string[] array2 = array;
		foreach (string biome in array2)
		{
			string dir = Path.Combine(root, biome);
			if (Directory.Exists(dir))
			{
				clips[biome] = new List<AudioClip>();
				string[] files = Directory.GetFiles(dir, "*.ogg");
				foreach (string path in files)
				{
					yield return ((MonoBehaviour)this).StartCoroutine(LoadClip(path, clips[biome], (AudioType)14));
				}
				files = Directory.GetFiles(dir, "*.wav");
				foreach (string path2 in files)
				{
					yield return ((MonoBehaviour)this).StartCoroutine(LoadClip(path2, clips[biome], (AudioType)20));
				}
				Log.LogInfo((object)$"[BiomeMusic] {biome}: {clips[biome].Count} track(s)");
			}
		}
		string globalDir = Path.Combine(root, "global");
		if (Directory.Exists(globalDir))
		{
			array2 = Directory.GetFiles(globalDir, "*.ogg");
			foreach (string path3 in array2)
			{
				yield return ((MonoBehaviour)this).StartCoroutine(LoadClip(path3, globalClips, (AudioType)14));
			}
			array2 = Directory.GetFiles(globalDir, "*.wav");
			foreach (string path4 in array2)
			{
				yield return ((MonoBehaviour)this).StartCoroutine(LoadClip(path4, globalClips, (AudioType)20));
			}
			Log.LogInfo((object)$"[BiomeMusic] global: {globalClips.Count} track(s)");
			string[] array3 = new string[11]
			{
				"meadows", "blackforest", "swamp", "mountain", "plains", "ocean", "mistlands", "ashlands", "deepnorth", "home",
				"approaching"
			};
			foreach (string key in array3)
			{
				if (!clips.ContainsKey(key))
				{
					clips[key] = new List<AudioClip>();
				}
				clips[key].AddRange(globalClips);
			}
		}
		GameObject val = new GameObject("BiomeMusicPlayer");
		Object.DontDestroyOnLoad((Object)(object)val);
		source = val.AddComponent<AudioSource>();
		source.spatialBlend = 0f;
		source.loop = false;
		source.volume = cfgVolume.Value;
		int num = 0;
		foreach (List<AudioClip> value in clips.Values)
		{
			num += value.Count;
		}
		Log.LogInfo((object)$"[BiomeMusic] Ready — {num} total slots.");
		((MonoBehaviour)this).StartCoroutine(VanillaSilencer());
		((MonoBehaviour)this).StartCoroutine(MusicLoop());
	}

	private IEnumerator LoadClip(string path, List<AudioClip> target, AudioType type)
	{
		//IL_0015: Unknown result type (might be due to invalid IL or missing references)
		//IL_0016: Unknown result type (might be due to invalid IL or missing references)
		UnityWebRequest req = UnityWebRequestMultimedia.GetAudioClip("file://" + path, type);
		try
		{
			((DownloadHandlerAudioClip)req.downloadHandler).streamAudio = false;
			yield return req.SendWebRequest();
			if ((int)req.result == 1)
			{
				AudioClip content = DownloadHandlerAudioClip.GetContent(req);
				((Object)content).name = Path.GetFileNameWithoutExtension(path);
				target.Add(content);
			}
			else
			{
				Log.LogWarning((object)("[BiomeMusic] Load failed: " + path + " — " + req.error));
			}
		}
		finally
		{
			((IDisposable)req)?.Dispose();
		}
	}

	private IEnumerator MusicLoop()
	{
		yield return (object)new WaitForSeconds(20f);
		while (true)
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				yield return (object)new WaitForSeconds(2f);
				continue;
			}
			string biomeKey = GetBiomeKey(localPlayer);
			if (_isFading)
			{
				yield return (object)new WaitForSeconds(0.1f);
				continue;
			}
			if (source.isPlaying)
			{
				if (biomeKey != _currentZone)
				{
					_saved[_currentZone] = (source.clip, source.time);
					_skipNextGap = true;
					Log.LogInfo((object)$"[BiomeMusic] [{_currentZone}→{biomeKey}] saved {source.time:F0}s — fading");
					((MonoBehaviour)this).StartCoroutine(FadeOutAndStop());
				}
				yield return (object)new WaitForSeconds(1f);
				continue;
			}
			if (!_skipNextGap)
			{
				float num = Random.Range(cfgMinGap.Value, cfgMaxGap.Value);
				yield return (object)new WaitForSeconds(num);
			}
			_skipNextGap = false;
			localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				continue;
			}
			biomeKey = GetBiomeKey(localPlayer);
			if (!clips.ContainsKey(biomeKey) || clips[biomeKey].Count == 0)
			{
				yield return (object)new WaitForSeconds(2f);
				continue;
			}
			float num2 = 0f;
			AudioClip val;
			if (_saved.TryGetValue(biomeKey, out (AudioClip, float) value) && (Object)(object)value.Item1 != (Object)null && value.Item1.length - value.Item2 > 10f)
			{
				(val, num2) = value;
				_saved.Remove(biomeKey);
				Log.LogInfo((object)$"[BiomeMusic] ↩ Resume [{biomeKey}] {((Object)val).name} from {num2:F0}s");
			}
			else
			{
				val = NextClip(biomeKey);
				if (_saved.ContainsKey(biomeKey))
				{
					_saved.Remove(biomeKey);
				}
				Log.LogInfo((object)$"[BiomeMusic] ▶ [{biomeKey}] {((Object)val).name} ({val.length:F0}s)");
			}
			_currentZone = biomeKey;
			source.clip = val;
			source.time = num2;
			source.volume = 0f;
			source.Play();
			yield return ((MonoBehaviour)this).StartCoroutine(FadeIn());
		}
	}
}