The BepInEx console will not appear when launching like it does for other games on Thunderstore. This is normal (and helps prevent crashes during startup). You can turn it back on in your BepInEx.cfg file.
Decompiled source of MinecraftBackgroundMusic v0.3.1
BepInEx/plugins/BackgroundMusic.dll
Decompiled a day agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; using UnityEngine.Networking; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: IgnoresAccessChecksTo("Assembly-CSharp")] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("com.mthwj.minecraftmusic")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("0.1.0.0")] [assembly: AssemblyInformationalVersion("0.1.0")] [assembly: AssemblyProduct("com.mthwj.minecraftmusic")] [assembly: AssemblyTitle("MinecraftMusicPlugin")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.1.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace BepInEx { [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] [Conditional("CodeGeneration")] internal sealed class BepInAutoPluginAttribute : Attribute { public BepInAutoPluginAttribute(string? id = null, string? name = null, string? version = null) { } } } namespace BepInEx.Preloader.Core.Patching { [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] [Conditional("CodeGeneration")] internal sealed class PatcherAutoPluginAttribute : Attribute { public PatcherAutoPluginAttribute(string? id = null, string? name = null, string? version = null) { } } } namespace MinecraftMusicPlugin { [BepInPlugin("com.mthwj.minecraftmusic", "MinecraftMusicPlugin", "0.1.0")] public class Plugin : BaseUnityPlugin { [HarmonyPatch(typeof(AmbienceAudio), "FixedUpdate")] private static class AmbienceAudio_FixedUpdate_Patch { [CompilerGenerated] private sealed class <LoadAndFadeAudio>d__5 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public MonoBehaviour context; public string path; public string region; private AudioSource <source>5__1; private float <targetVolume>5__2; private bool <needsFadeOut>5__3; private float <timer>5__4; private float <startVolume>5__5; private UnityWebRequest <uwr>5__6; private AudioClip <clip>5__7; private float <fadeInTimer>5__8; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <LoadAndFadeAudio>d__5(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if (num == -3 || (uint)(num - 2) <= 1u) { try { } finally { <>m__Finally1(); } } <source>5__1 = null; <uwr>5__6 = null; <clip>5__7 = null; <>1__state = -2; } private bool MoveNext() { //IL_01f4: Unknown result type (might be due to invalid IL or missing references) //IL_01fa: Invalid comparison between Unknown and I4 bool result; try { ManualLogSource? logger7; switch (<>1__state) { default: result = false; goto end_IL_0000; case 0: { <>1__state = -1; <source>5__1 = ((Component)context).GetComponent<AmbienceAudio>().mainMusic; <targetVolume>5__2 = Mathf.Max(<source>5__1.volume, 0.5f); <needsFadeOut>5__3 = isMusicPlaying && HasRegionSpecificMusic(region, out string _); if (<needsFadeOut>5__3) { ManualLogSource? logger8 = Logger; if (logger8 != null) { logger8.LogDebug((object)("Fading out current track for " + region)); } <timer>5__4 = 0f; <startVolume>5__5 = <source>5__1.volume; goto IL_0132; } goto IL_0180; } case 1: <>1__state = -1; goto IL_0132; case 2: { <>1__state = -3; if ((int)<uwr>5__6.result != 1) { ManualLogSource? logger = Logger; if (logger != null) { logger.LogError((object)("Failed to load MP3: " + <uwr>5__6.error)); } result = false; break; } <clip>5__7 = DownloadHandlerAudioClip.GetContent(<uwr>5__6); if ((Object)(object)<clip>5__7 == (Object)null) { ManualLogSource? logger2 = Logger; if (logger2 != null) { logger2.LogError((object)("Failed to create AudioClip from " + path + ": Null clip")); } result = false; break; } ManualLogSource? logger3 = Logger; if (logger3 != null) { logger3.LogInfo((object)$"MP3 loaded, length: {<clip>5__7.length} seconds"); } <source>5__1.clip = <clip>5__7; <source>5__1.volume = 0f; <source>5__1.Play(); ManualLogSource? logger4 = Logger; if (logger4 != null) { logger4.LogDebug((object)("Fading in new track: " + Path.GetFileName(path))); } <fadeInTimer>5__8 = 0f; goto IL_036a; } case 3: { <>1__state = -3; goto IL_036a; } IL_036a: if (<fadeInTimer>5__8 < 1f) { <fadeInTimer>5__8 += Time.deltaTime; <source>5__1.volume = Mathf.Lerp(0f, <targetVolume>5__2, <fadeInTimer>5__8 / 1f); <>2__current = null; <>1__state = 3; result = true; } else { <source>5__1.volume = <targetVolume>5__2; isMusicPlaying = true; ManualLogSource? logger5 = Logger; if (logger5 != null) { logger5.LogInfo((object)("Playing MP3 via mainMusic: " + Path.GetFileName(path))); } <clip>5__7 = null; <>m__Finally1(); <uwr>5__6 = null; result = false; } goto end_IL_0000; IL_0132: if (!(<timer>5__4 < 1f)) { <source>5__1.Stop(); <source>5__1.clip = null; ManualLogSource? logger6 = Logger; if (logger6 != null) { logger6.LogDebug((object)("Stopped previous track for " + region)); } goto IL_0180; } <timer>5__4 += Time.deltaTime; <source>5__1.volume = Mathf.Lerp(<startVolume>5__5, 0f, <timer>5__4 / 1f); <>2__current = null; <>1__state = 1; result = true; goto end_IL_0000; IL_0180: logger7 = Logger; if (logger7 != null) { logger7.LogInfo((object)("Starting to load MP3 from: " + path)); } <uwr>5__6 = UnityWebRequestMultimedia.GetAudioClip("file:///" + path, (AudioType)13); <>1__state = -3; <>2__current = <uwr>5__6.SendWebRequest(); <>1__state = 2; result = true; goto end_IL_0000; } <>m__Finally1(); end_IL_0000:; } catch { //try-fault ((IDisposable)this).Dispose(); throw; } return result; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; if (<uwr>5__6 != null) { ((IDisposable)<uwr>5__6).Dispose(); } } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private static bool Prefix(AmbienceAudio __instance) { //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) Transform transform = ((Component)__instance).transform; object obj; if (transform == null) { obj = null; } else { Transform root = transform.root; obj = ((root != null) ? ((Component)root).GetComponent<CharacterData>() : null); } CharacterData val = (CharacterData)obj; if ((Object)(object)val == (Object)null) { ManualLogSource? logger = Logger; if (logger != null) { logger.LogWarning((object)"CharacterData component not found on root transform"); } return true; } if (val.sinceDead > 0.5f && !val.passedOut && !val.dead && !val.fullyPassedOut) { float z = ((Component)__instance).transform.position.z; float y = ((Component)__instance).transform.position.y; isMusicPlaying = __instance.mainMusic.isPlaying && (Object)(object)__instance.mainMusic.clip != (Object)null; ManualLogSource? logger2 = Logger; if (logger2 != null) { logger2.LogDebug((object)$"Position: z={z}, y={y}, isMusicPlaying={isMusicPlaying}, mainMusicVolume={__instance.mainMusic.volume}"); } if (z > __instance.beachStingerZ && !__instance.playedBeach) { ManualLogSource? logger3 = Logger; if (logger3 != null) { logger3.LogInfo((object)"Entered beach region, overriding with Minecraft music"); } TryPlayMusicForRegion((MonoBehaviour)(object)__instance, "Beach"); __instance.playedBeach = true; return false; } if (z > __instance.tropicsStingerZ && !__instance.playedTropics) { ManualLogSource? logger4 = Logger; if (logger4 != null) { logger4.LogInfo((object)"Entered tropics region, overriding with Minecraft music"); } TryPlayMusicForRegion((MonoBehaviour)(object)__instance, "Tropics"); __instance.playedTropics = true; return false; } if (z > __instance.alpineStingerZ && !__instance.playedAlpine) { ManualLogSource? logger5 = Logger; if (logger5 != null) { logger5.LogInfo((object)"Entered alpine region, overriding with Minecraft music"); } TryPlayMusicForRegion((MonoBehaviour)(object)__instance, "Alpine"); __instance.playedAlpine = true; return false; } if (z > __instance.calderaStingerZ && !__instance.playedCaldera) { ManualLogSource? logger6 = Logger; if (logger6 != null) { logger6.LogInfo((object)"Entered caldera region, overriding with Minecraft music"); } TryPlayMusicForRegion((MonoBehaviour)(object)__instance, "Caldera"); __instance.playedCaldera = true; return false; } if (y > __instance.kilnStingerY && !__instance.playedKiln) { ManualLogSource? logger7 = Logger; if (logger7 != null) { logger7.LogInfo((object)"Entered kiln region, overriding with Minecraft music"); } TryPlayMusicForRegion((MonoBehaviour)(object)__instance, "Kiln"); __instance.playedKiln = true; return false; } if (z > __instance.peaksTingerZ && !__instance.playedPeak) { ManualLogSource? logger8 = Logger; if (logger8 != null) { logger8.LogInfo((object)"Entered peak region, overriding with Minecraft music"); } TryPlayMusicForRegion((MonoBehaviour)(object)__instance, "Peak"); __instance.playedPeak = true; return false; } if (!isMusicPlaying && (Object)(object)__instance.mainMusic.clip != (Object)null) { string currentRegion = GetCurrentRegion(__instance); ManualLogSource? logger9 = Logger; if (logger9 != null) { logger9.LogInfo((object)("Current track ended, playing new random MP3 for " + currentRegion)); } TryPlayMusicForRegion((MonoBehaviour)(object)__instance, currentRegion); return false; } } else { ManualLogSource? logger10 = Logger; if (logger10 != null) { logger10.LogInfo((object)"Character conditions not met, fading out music"); } __instance.mainMusic.volume = Mathf.Lerp(__instance.mainMusic.volume, 0f, Time.deltaTime / 1f); } return true; } private static string GetCurrentRegion(AmbienceAudio __instance) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) float z = ((Component)__instance).transform.position.z; float y = ((Component)__instance).transform.position.y; if (y > __instance.kilnStingerY) { return "Kiln"; } if (z > __instance.peaksTingerZ) { return "Peak"; } if (z > __instance.calderaStingerZ) { return "Caldera"; } if (z > __instance.alpineStingerZ) { return "Alpine"; } if (z > __instance.tropicsStingerZ) { return "Tropics"; } if (z > __instance.beachStingerZ) { return "Beach"; } return "Default"; } private static bool HasRegionSpecificMusic(string region, out string folderPath) { if (1 == 0) { } string text = region switch { "Beach" => beachFolderConfig.Value.Trim(), "Tropics" => tropicsFolderConfig.Value.Trim(), "Alpine" => alpineFolderConfig.Value.Trim(), "Caldera" => calderaFolderConfig.Value.Trim(), "Kiln" => kilnFolderConfig.Value.Trim(), "Peak" => peakFolderConfig.Value.Trim(), _ => defaultFolderConfig.Value.Trim(), }; if (1 == 0) { } string text2 = text; folderPath = (Path.IsPathRooted(text2) ? text2 : Path.Combine(musicFolder, text2)); if (region == "Default" || !Directory.Exists(folderPath) || Directory.GetFiles(folderPath, "*.mp3").Length == 0) { folderPath = Path.Combine(musicFolder, defaultFolderConfig.Value.Trim()); return false; } return true; } private static void TryPlayMusicForRegion(MonoBehaviour context, string region) { if (!HasRegionSpecificMusic(region, out string folderPath) && currentRegion == "Default" && isMusicPlaying) { ManualLogSource? logger = Logger; if (logger != null) { logger.LogDebug((object)("Skipping playback for " + region + " as already playing from Default")); } } else { PlayRandomMp3(context, region, folderPath); currentRegion = (HasRegionSpecificMusic(region, out string _) ? region : "Default"); } } private static void PlayRandomMp3(MonoBehaviour context, string region, string folderPath) { if (!Directory.Exists(folderPath)) { ManualLogSource? logger = Logger; if (logger != null) { logger.LogError((object)("No MP3s available for " + region + " or Default at " + folderPath + "!")); } return; } string[] files = Directory.GetFiles(folderPath, "*.mp3"); if (files.Length == 0) { ManualLogSource? logger2 = Logger; if (logger2 != null) { logger2.LogError((object)("No MP3 files found in " + folderPath + " for " + region + "!")); } } else { Random random = new Random(); string path = files[random.Next(files.Length)]; ManualLogSource? logger3 = Logger; if (logger3 != null) { logger3.LogInfo((object)("Loading MP3 for " + region + ": " + Path.GetFileName(path))); } context.StartCoroutine(LoadAndFadeAudio(context, path, region)); } } [IteratorStateMachine(typeof(<LoadAndFadeAudio>d__5))] private static IEnumerator LoadAndFadeAudio(MonoBehaviour context, string path, string region) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <LoadAndFadeAudio>d__5(0) { context = context, path = path, region = region }; } } internal static ManualLogSource? Logger; private static string musicFolder = string.Empty; private static bool isMusicPlaying = false; private static ConfigEntry<string> beachFolderConfig = null; private static ConfigEntry<string> tropicsFolderConfig = null; private static ConfigEntry<string> alpineFolderConfig = null; private static ConfigEntry<string> calderaFolderConfig = null; private static ConfigEntry<string> kilnFolderConfig = null; private static ConfigEntry<string> peakFolderConfig = null; private static ConfigEntry<string> defaultFolderConfig = null; private static string currentRegion = "Default"; private const float FADE_DURATION = 1f; public const string Id = "com.mthwj.minecraftmusic"; public static string Name => "MinecraftMusicPlugin"; public static string Version => "0.1.0"; private void Awake() { //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Expected O, but got Unknown Logger = ((BaseUnityPlugin)this).Logger; musicFolder = Path.Combine(Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location) ?? throw new InvalidOperationException("Plugin location not found"), "CustomBackgroundMusic"); ManualLogSource? logger = Logger; if (logger != null) { logger.LogInfo((object)("Plugin com.mthwj.minecraftmusic is loaded! Music folder: " + musicFolder)); } beachFolderConfig = ((BaseUnityPlugin)this).Config.Bind<string>("MusicFolders", "BeachFolder", "Beach", "Folder for Beach region music (relative to CustomBackgroundMusic or absolute path)."); tropicsFolderConfig = ((BaseUnityPlugin)this).Config.Bind<string>("MusicFolders", "TropicsFolder", "Tropics", "Folder for Tropics region music (relative to CustomBackgroundMusic or absolute path)."); alpineFolderConfig = ((BaseUnityPlugin)this).Config.Bind<string>("MusicFolders", "AlpineFolder", "Alpine", "Folder for Alpine region music (relative to CustomBackgroundMusic or absolute path)."); calderaFolderConfig = ((BaseUnityPlugin)this).Config.Bind<string>("MusicFolders", "CalderaFolder", "Caldera", "Folder for Caldera region music (relative to CustomBackgroundMusic or absolute path)."); kilnFolderConfig = ((BaseUnityPlugin)this).Config.Bind<string>("MusicFolders", "KilnFolder", "Kiln", "Folder for Kiln region music (relative to CustomBackgroundMusic or absolute path)."); peakFolderConfig = ((BaseUnityPlugin)this).Config.Bind<string>("MusicFolders", "PeakFolder", "Peak", "Folder for Peak region music (relative to CustomBackgroundMusic or absolute path)."); defaultFolderConfig = ((BaseUnityPlugin)this).Config.Bind<string>("MusicFolders", "DefaultFolder", "Default", "Fallback folder if region-specific folder is missing or empty (relative to CustomBackgroundMusic or absolute path)."); Harmony val = new Harmony("com.mthwj.minecraftmusic.patch"); val.PatchAll(); ManualLogSource? logger2 = Logger; if (logger2 != null) { logger2.LogInfo((object)"Harmony patches applied successfully"); } } } } namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] internal sealed class IgnoresAccessChecksToAttribute : Attribute { public IgnoresAccessChecksToAttribute(string assemblyName) { } } }