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 CustomElevatorAudio v1.0.0
Custom Elevator Audio.dll
Decompiled 14 hours agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using Unity.Collections; using Unity.Netcode; 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: AssemblyTitle("Custom Elevator Audio")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("Custom Elevator Audio")] [assembly: AssemblyCopyright("Copyright © 2026")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("bb9da844-988b-4075-bc3b-20396c69ea66")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyVersion("1.0.0.0")] namespace CustomElevatorAudio; public enum PlaybackMode { Random, PreventSongRepeat, Shuffle, Reshuffle } [BepInPlugin("com.donobus.CustomElevatorAudio", "Custom Elevator Audio", "1.0.0")] public class Plugin : BaseUnityPlugin { private Harmony harmony; public static ConfigEntry<string> MusicFolderPath; public static List<AudioClip> CustomMusicClips = new List<AudioClip>(); public static Dictionary<string, AudioClip> CustomMusicClipsByFileName = new Dictionary<string, AudioClip>(StringComparer.Ordinal); public static ConfigEntry<float> MusicVolume; public static ConfigEntry<bool> EnableDoppler; public static ConfigEntry<PlaybackMode> AudioPlaybackMode; public static ConfigEntry<bool> EnableHostSync; public static ConfigEntry<KeyboardShortcut> ReloadKeybind; private bool isReloading = false; private void Awake() { //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Expected O, but got Unknown ((BaseUnityPlugin)this).Logger.LogInfo((object)"=== CustomElevatorAudio Loaded ==="); MusicFolderPath = ((BaseUnityPlugin)this).Config.Bind<string>("General", "MusicFolderPath", "C:\\Program Files (x86)\\Steam\\steamapps\\common\\Lethal Company\\Custom Elevator Audio", "The absolute path to the folder containing your custom .mp3 files."); ReloadKeybind = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("General", "ReloadKeybind", new KeyboardShortcut((KeyCode)287, Array.Empty<KeyCode>()), "Press this key in-game to instantly reload the music folder without restarting the game."); MusicVolume = ((BaseUnityPlugin)this).Config.Bind<float>("Audio Settings", "MusicVolume", 1f, "The volume of the custom elevator music (0.0 to 1.0)."); EnableDoppler = ((BaseUnityPlugin)this).Config.Bind<bool>("Audio Settings", "EnableDoppler", true, "Set to false to disable the pitch-bending doppler effect as you move relative to the Elevator."); AudioPlaybackMode = ((BaseUnityPlugin)this).Config.Bind<PlaybackMode>("Audio Settings", "PlaybackMode", PlaybackMode.PreventSongRepeat, "Choose how songs are selected: Random (pure randomness), PreventSongRepeat (no back-to-back repeats), Shuffle (loops one fixed randomized list), or Reshuffle (creates a completely new random order every loop, ensuring no back-to-back repeats across boundaries)."); EnableHostSync = ((BaseUnityPlugin)this).Config.Bind<bool>("Audio Settings", "EnableHostSync", false, "If true AND you are the host, your chosen song is broadcast to all clients. If true on a client, that client will try to find a local file with the same name as the host's chosen song and play it; if no matching file exists locally, it falls back to that client's own PlaybackMode setting. Has no effect unless the HOST also has this enabled."); ((MonoBehaviour)this).StartCoroutine(LoadAllCustomMusic()); harmony = new Harmony("com.donobus.CustomElevatorAudio"); harmony.PatchAll(); } private void Update() { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) MineshaftElevatorPatch.EnsureMessageHandlerRegistered(); KeyboardShortcut value = ReloadKeybind.Value; if (((KeyboardShortcut)(ref value)).IsDown() && !isReloading) { Debug.Log((object)"[CustomElevatorAudio] Reload keybind pressed! Reloading audio files..."); ((MonoBehaviour)this).StartCoroutine(ReloadMusicRoutine()); } } private IEnumerator ReloadMusicRoutine() { isReloading = true; CustomMusicClips.Clear(); CustomMusicClipsByFileName.Clear(); MineshaftElevatorPatch.ResetStateForReload(); yield return ((MonoBehaviour)this).StartCoroutine(LoadAllCustomMusic()); isReloading = false; Debug.Log((object)"[CustomElevatorAudio] Reload complete!"); } private IEnumerator LoadAllCustomMusic() { string folderPath = MusicFolderPath.Value; if (!Directory.Exists(folderPath)) { Debug.LogWarning((object)"[CustomElevatorAudio] Folder path is invalid or does not exist."); yield break; } string[] mp3Files = GetValidMp3Files(folderPath); if (mp3Files.Length == 0) { Debug.LogWarning((object)"[CustomElevatorAudio] No .mp3 files found in folder."); yield break; } string[] array = mp3Files; foreach (string file in array) { string uri = "file://" + file.Replace("\\", "/"); string fileNameNoExt = Path.GetFileNameWithoutExtension(file); UnityWebRequest uwr = UnityWebRequestMultimedia.GetAudioClip(uri, (AudioType)13); try { yield return uwr.SendWebRequest(); if ((int)uwr.result == 1) { AudioClip clip = DownloadHandlerAudioClip.GetContent(uwr); ((Object)clip).name = "CustomElevatorSong_" + fileNameNoExt; CustomMusicClips.Add(clip); if (!CustomMusicClipsByFileName.ContainsKey(fileNameNoExt)) { CustomMusicClipsByFileName.Add(fileNameNoExt, clip); } else { Debug.LogWarning((object)("[CustomElevatorAudio] Duplicate file name '" + fileNameNoExt + "' (case-sensitive match). Host Sync matching will only ever use the first one loaded.")); } Debug.Log((object)("[CustomElevatorAudio] Pre-loaded successfully: " + Path.GetFileName(file))); } else { Debug.LogError((object)("[CustomElevatorAudio] Failed to load " + Path.GetFileName(file) + ": " + uwr.error)); } } finally { ((IDisposable)uwr)?.Dispose(); } } Debug.Log((object)$"[CustomElevatorAudio] Total custom songs loaded into rotation: {CustomMusicClips.Count}"); if (CustomMusicClips.Count > 0) { MineshaftElevatorPatch.GenerateShuffleDeck(checkBoundaryRepeat: false); } } private string[] GetValidMp3Files(string path) { try { return Directory.GetFiles(path, "*.mp3"); } catch { return new string[0]; } } } [HarmonyPatch(typeof(MineshaftElevatorController))] public class MineshaftElevatorPatch { private static AudioClip activeSong; private static AudioClip lastPlayedSong; private static bool wasPlayingMusic; private static Random rng; private static string hostSyncedSongName; private static bool receivedHostSync; private static bool hostAlreadySelected; private static bool hostHasBroadcastedSync; private static bool hasSelectedSongThisTrip; private static List<int> shuffleDeck; private static int shufflePointer; public const string ClipNamePrefix = "CustomElevatorSong_"; private static FieldRef<MineshaftElevatorController, AudioSource> JingleField; private static FieldRef<MineshaftElevatorController, bool> PlayMusicField; private static bool fieldAccessReady; private const string SyncMessageName = "CustomElevatorAudio_ElevatorSongSync"; private static NetworkManager registeredOnManager; static MineshaftElevatorPatch() { activeSong = null; lastPlayedSong = null; wasPlayingMusic = false; rng = new Random(); hostSyncedSongName = null; receivedHostSync = false; hostAlreadySelected = false; hostHasBroadcastedSync = false; hasSelectedSongThisTrip = false; shuffleDeck = new List<int>(); shufflePointer = 0; fieldAccessReady = false; registeredOnManager = null; try { JingleField = AccessTools.FieldRefAccess<MineshaftElevatorController, AudioSource>("elevatorJingleMusic"); PlayMusicField = AccessTools.FieldRefAccess<MineshaftElevatorController, bool>("playMusic"); fieldAccessReady = true; } catch (Exception arg) { Debug.LogError((object)$"[CustomElevatorAudio] Failed to bind to MineshaftElevatorController's private fields - elevator music support disabled. {arg}"); fieldAccessReady = false; } } public static void ResetStateForReload() { activeSong = null; lastPlayedSong = null; hostAlreadySelected = false; receivedHostSync = false; hostSyncedSongName = null; hostHasBroadcastedSync = false; wasPlayingMusic = false; hasSelectedSongThisTrip = false; shuffleDeck.Clear(); shufflePointer = 0; if (fieldAccessReady) { MineshaftElevatorController[] array = Object.FindObjectsOfType<MineshaftElevatorController>(); foreach (MineshaftElevatorController val in array) { AudioSource val2 = JingleField.Invoke(val); if ((Object)(object)val2 != (Object)null) { val2.Stop(); val2.clip = null; } } } Debug.Log((object)"[CustomElevatorAudio] Elevator patch variables reset for incoming reload."); } [HarmonyPatch("Update")] [HarmonyPostfix] private static void UpdatePostfix(MineshaftElevatorController __instance) { if (!fieldAccessReady || Plugin.CustomMusicClips.Count == 0) { return; } bool flag = PlayMusicField.Invoke(__instance); if ((Object)(object)StartOfRound.Instance != (Object)null && StartOfRound.Instance.inShipPhase) { return; } if ((Object)(object)NetworkManager.Singleton != (Object)null && NetworkManager.Singleton.IsHost && !hostHasBroadcastedSync && NetworkManager.Singleton.CustomMessagingManager != null) { if (Plugin.EnableHostSync.Value && (Object)(object)activeSong != (Object)null) { SendSongSyncToClients(GetFileNameForClip(activeSong)); } else if (!Plugin.EnableHostSync.Value) { SendSongSyncToClients("<HOST_SYNC_DISABLED>"); } hostHasBroadcastedSync = true; } if (flag && !wasPlayingMusic) { activeSong = null; receivedHostSync = false; hostSyncedSongName = null; hostAlreadySelected = false; hostHasBroadcastedSync = false; hasSelectedSongThisTrip = false; if ((Object)(object)NetworkManager.Singleton != (Object)null && NetworkManager.Singleton.IsHost) { ChooseSongLocally(); } } else if (!flag && wasPlayingMusic) { activeSong = null; hasSelectedSongThisTrip = false; hostHasBroadcastedSync = false; } wasPlayingMusic = flag; if (flag) { EnforceElevatorMusic(); return; } AudioSource val = JingleField.Invoke(__instance); if ((Object)(object)val != (Object)null && (Object)(object)val.clip != (Object)null && ((Object)val.clip).name.ToLower().StartsWith("CustomElevatorSong_".ToLower())) { val.volume = 0f; if (val.isPlaying) { val.Stop(); } } } private static void EnforceElevatorMusic() { if (Plugin.CustomMusicClips.Count == 0) { return; } if (!Plugin.EnableHostSync.Value && receivedHostSync) { Debug.Log((object)"[CustomElevatorAudio] EnableHostSync was disabled. Clearing sync state to resume local playback."); receivedHostSync = false; hostSyncedSongName = null; activeSong = null; } if ((Object)(object)activeSong == (Object)null) { if (Plugin.EnableHostSync.Value && (Object)(object)NetworkManager.Singleton != (Object)null && NetworkManager.Singleton.IsClient && !NetworkManager.Singleton.IsHost) { if (receivedHostSync) { Debug.Log((object)"[CustomElevatorAudio] Client has host sync data but no active clip. Reapplying."); ApplyHostSyncedSong(hostSyncedSongName); } else if (!NetworkManager.Singleton.IsConnectedClient) { Debug.Log((object)"[CustomElevatorAudio] Client not fully connected, falling back to local song selection."); ChooseSongLocally(); } else { Debug.Log((object)"[CustomElevatorAudio] Waiting for host song selection..."); } return; } ChooseSongLocally(); } ApplyClipToSources(); } public static void GenerateShuffleDeck(bool checkBoundaryRepeat) { if (Plugin.CustomMusicClips.Count == 0) { return; } shuffleDeck.Clear(); for (int i = 0; i < Plugin.CustomMusicClips.Count; i++) { shuffleDeck.Add(i); } int num = 0; bool flag = false; while (!flag && num < 50) { num++; int num2 = shuffleDeck.Count; while (num2 > 1) { num2--; int index = rng.Next(num2 + 1); int value = shuffleDeck[index]; shuffleDeck[index] = shuffleDeck[num2]; shuffleDeck[num2] = value; } flag = true; if (checkBoundaryRepeat && shuffleDeck.Count >= 2 && (Object)(object)lastPlayedSong != (Object)null) { AudioClip val = Plugin.CustomMusicClips[shuffleDeck[0]]; if ((Object)(object)val == (Object)(object)lastPlayedSong) { flag = false; } } } shufflePointer = 0; string text = $"\n[CustomElevatorAudio] --- NEW ELEVATOR SHUFFLE DECK GENERATED (Valid: {flag}, Attempts: {num}) ---"; for (int j = 0; j < shuffleDeck.Count; j++) { text += $"\n {j + 1}. {((Object)Plugin.CustomMusicClips[shuffleDeck[j]]).name}"; } text += "\n---------------------------------------------------------"; Debug.Log((object)text); } private static void ChooseSongLocally() { if (Plugin.CustomMusicClips.Count == 0 || hasSelectedSongThisTrip || (hostAlreadySelected && (Object)(object)NetworkManager.Singleton != (Object)null && NetworkManager.Singleton.IsHost)) { return; } int num = 0; PlaybackMode value = Plugin.AudioPlaybackMode.Value; if (value == PlaybackMode.Shuffle || value == PlaybackMode.Reshuffle) { if (shuffleDeck.Count != Plugin.CustomMusicClips.Count) { GenerateShuffleDeck(checkBoundaryRepeat: false); } if (shufflePointer >= shuffleDeck.Count) { if (value == PlaybackMode.Reshuffle) { Debug.Log((object)"[CustomElevatorAudio] Elevator deck exhausted. Reshuffling playlist with repeat boundary guards!"); GenerateShuffleDeck(checkBoundaryRepeat: true); } else { Debug.Log((object)"[CustomElevatorAudio] Elevator deck exhausted. Standard Shuffle looping back to start of fixed deck."); shufflePointer = 0; } } if (shuffleDeck.Count > 0) { num = shuffleDeck[shufflePointer]; AudioClip val = Plugin.CustomMusicClips[num]; if (Plugin.CustomMusicClips.Count >= 2 && (Object)(object)lastPlayedSong != (Object)null && (Object)(object)val == (Object)(object)lastPlayedSong) { Debug.Log((object)$"[CustomElevatorAudio] Elevator {value} Mode: Track index {num} ({((Object)val).name}) matches last played song. Skipping to next deck position."); shufflePointer++; if (shufflePointer >= shuffleDeck.Count) { if (value == PlaybackMode.Reshuffle) { GenerateShuffleDeck(checkBoundaryRepeat: true); } else { shufflePointer = 0; } } num = shuffleDeck[shufflePointer]; val = Plugin.CustomMusicClips[num]; } activeSong = val; shufflePointer++; Debug.Log((object)$"[CustomElevatorAudio] Elevator {value} Mode: Playing track index {num} ({shufflePointer}/{shuffleDeck.Count})"); } else { num = rng.Next(Plugin.CustomMusicClips.Count); activeSong = Plugin.CustomMusicClips[num]; } } else if (value == PlaybackMode.PreventSongRepeat && Plugin.CustomMusicClips.Count >= 2 && (Object)(object)lastPlayedSong != (Object)null) { Debug.Log((object)("[CustomElevatorAudio] Elevator anti-repeat active. Making sure we don't play: " + ((Object)lastPlayedSong).name)); do { num = rng.Next(Plugin.CustomMusicClips.Count); activeSong = Plugin.CustomMusicClips[num]; } while ((Object)(object)activeSong == (Object)(object)lastPlayedSong); } else { num = rng.Next(Plugin.CustomMusicClips.Count); activeSong = Plugin.CustomMusicClips[num]; } lastPlayedSong = activeSong; hostAlreadySelected = true; hasSelectedSongThisTrip = true; Debug.Log((object)$"[CustomElevatorAudio] {GetRoleTag()} ELEVATOR CHOSEN SONG ({num + 1} of {Plugin.CustomMusicClips.Count}): {((Object)activeSong).name}"); } [HarmonyPatch("Update")] [HarmonyPostfix] private static void ApplyClipToJingleSource(MineshaftElevatorController __instance) { if (!fieldAccessReady || (Object)(object)activeSong == (Object)null) { return; } AudioSource val = JingleField.Invoke(__instance); if (!((Object)(object)val == (Object)null) && ((Component)val).gameObject.activeInHierarchy && ((Behaviour)val).enabled) { if ((Object)(object)val.clip != (Object)(object)activeSong) { val.clip = activeSong; val.time = 0f; } val.loop = true; val.volume = Plugin.MusicVolume.Value; val.dopplerLevel = (Plugin.EnableDoppler.Value ? 1f : 0f); if (!val.isPlaying) { val.Play(); } } } private static void ApplyClipToSources(object _dummy = null) { } private static string GetRoleTag() { if ((Object)(object)NetworkManager.Singleton == (Object)null) { return "[NO-NET]"; } if (NetworkManager.Singleton.IsHost) { return "[HOST]"; } if (NetworkManager.Singleton.IsClient) { return "[CLIENT]"; } return "[NO-NET]"; } private static string GetFileNameForClip(AudioClip clip) { if ((Object)(object)clip == (Object)null) { return null; } if (((Object)clip).name.StartsWith("CustomElevatorSong_", StringComparison.Ordinal)) { return ((Object)clip).name.Substring("CustomElevatorSong_".Length); } return ((Object)clip).name; } internal static void EnsureMessageHandlerRegistered() { //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Expected O, but got Unknown if (!((Object)(object)NetworkManager.Singleton == (Object)null) && NetworkManager.Singleton.CustomMessagingManager != null && !((Object)(object)registeredOnManager == (Object)(object)NetworkManager.Singleton)) { NetworkManager.Singleton.CustomMessagingManager.RegisterNamedMessageHandler("CustomElevatorAudio_ElevatorSongSync", new HandleNamedMessageDelegate(OnSongSyncMessageReceived)); registeredOnManager = NetworkManager.Singleton; Debug.Log((object)("[CustomElevatorAudio] " + GetRoleTag() + " Elevator Host Sync message handler registered.")); } } private unsafe static void SendSongSyncToClients(string songFileName) { //IL_0073: Unknown result type (might be due to invalid IL or missing references) if (!string.IsNullOrEmpty(songFileName) && !((Object)(object)NetworkManager.Singleton == (Object)null) && NetworkManager.Singleton.IsHost && NetworkManager.Singleton.CustomMessagingManager != null) { FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(FastBufferWriter.GetWriteSize(songFileName, false), (Allocator)2, -1); try { ((FastBufferWriter)(ref val)).WriteValueSafe(songFileName, false); NetworkManager.Singleton.CustomMessagingManager.SendNamedMessageToAll("CustomElevatorAudio_ElevatorSongSync", val, (NetworkDelivery)2); } finally { ((IDisposable)(*(FastBufferWriter*)(&val))/*cast due to .constrained prefix*/).Dispose(); } Debug.Log((object)("[CustomElevatorAudio] " + GetRoleTag() + " Elevator Host Sync: broadcast song selection '" + songFileName + "' to all clients.")); } } private static void OnSongSyncMessageReceived(ulong senderClientId, FastBufferReader reader) { string text = default(string); ((FastBufferReader)(ref reader)).ReadValueSafe(ref text, false); Debug.Log((object)("[CustomElevatorAudio] " + GetRoleTag() + " Elevator Host Sync: received broadcast for '" + text + "'.")); if ((Object)(object)NetworkManager.Singleton == (Object)null || NetworkManager.Singleton.IsHost) { return; } if (!Plugin.EnableHostSync.Value) { Debug.Log((object)("[CustomElevatorAudio] " + GetRoleTag() + " Elevator Host Sync: EnableHostSync is off locally, ignoring broadcast.")); } else if (text == "<HOST_SYNC_DISABLED>") { Debug.Log((object)("[CustomElevatorAudio] " + GetRoleTag() + " Elevator: host explicitly broadcast that their sync is disabled. Proceeding locally.")); receivedHostSync = false; hostSyncedSongName = null; if ((Object)(object)activeSong == (Object)null) { ChooseSongLocally(); } } else { ApplyHostSyncedSong(text); } } private static void ApplyHostSyncedSong(string hostFileName) { hostSyncedSongName = hostFileName; receivedHostSync = true; if (!string.IsNullOrEmpty(hostFileName) && Plugin.CustomMusicClipsByFileName.TryGetValue(hostFileName, out var value)) { activeSong = value; lastPlayedSong = value; Debug.Log((object)("[CustomElevatorAudio] " + GetRoleTag() + " Elevator: using host synced song '" + hostFileName + "'.")); } else { Debug.Log((object)("[CustomElevatorAudio] " + GetRoleTag() + " Elevator: missing '" + hostFileName + "', using local selection.")); receivedHostSync = false; activeSong = null; ChooseSongLocally(); } } }