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 MineshaftElevatorMusic v1.0.6
BepInEx\plugins\MineshaftElevatorMusic\MineshaftElevatorMusic.dll
Decompiled 5 months agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using Unity.Collections; using Unity.Netcode; using UnityEngine; using UnityEngine.Networking; using UnityEngine.SceneManagement; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("MineshaftElevatorMusic")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.6.0")] [assembly: AssemblyInformationalVersion("1.0.6")] [assembly: AssemblyProduct("MineshaftElevatorMusic")] [assembly: AssemblyTitle("MineshaftElevatorMusic")] [assembly: AssemblyVersion("1.0.6.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace MineshaftElevatorMusic { [BepInPlugin("pl.mineshaft.elevator.music", "Mineshaft Elevator Music", "1.0.6")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { [CompilerGenerated] private sealed class <LoadClipIfNeeded>d__50 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public Plugin <>4__this; public string fileName; private UnityWebRequest <req>5__2; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <LoadClipIfNeeded>d__50(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if (num == -3 || num == 1) { try { } finally { <>m__Finally1(); } } <req>5__2 = null; <>1__state = -2; } private bool MoveNext() { //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Invalid comparison between Unknown and I4 //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) bool result; try { int num = <>1__state; Plugin plugin = <>4__this; switch (num) { default: result = false; break; case 0: { <>1__state = -1; if (plugin._clipCache.ContainsKey(fileName)) { result = false; break; } string text = Path.Combine(plugin._musicFolder, fileName); if (!File.Exists(text)) { plugin._log.LogWarning((object)("File not found: " + text)); result = false; break; } string text2 = Path.GetExtension(text).ToLowerInvariant(); AudioType val = plugin.GuessAudioType(text2); if ((int)val == 0) { plugin._log.LogWarning((object)("Unsupported audio extension: " + text2)); result = false; break; } <req>5__2 = UnityWebRequestMultimedia.GetAudioClip(new Uri(text).AbsoluteUri, val); <>1__state = -3; <>2__current = <req>5__2.SendWebRequest(); <>1__state = 1; result = true; break; } case 1: <>1__state = -3; if ((int)<req>5__2.result != 1) { plugin._log.LogWarning((object)("Failed to load " + fileName + ": " + <req>5__2.error)); result = false; } else { AudioClip content = DownloadHandlerAudioClip.GetContent(<req>5__2); if (!((Object)(object)content == (Object)null)) { plugin._clipCache[fileName] = content; plugin._log.LogInfo((object)("Loaded clip: " + fileName)); <>m__Finally1(); <req>5__2 = null; result = false; break; } plugin._log.LogWarning((object)("Loaded clip is null: " + fileName)); result = false; } <>m__Finally1(); break; } } catch { //try-fault ((IDisposable)this).Dispose(); throw; } return result; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; if (<req>5__2 != null) { ((IDisposable)<req>5__2).Dispose(); } } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <PlayFromSync>d__49 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public Plugin <>4__this; public string fileName; public double startServerTime; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <PlayFromSync>d__49(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_00d7: 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) int num = <>1__state; Plugin plugin = <>4__this; switch (num) { default: return false; case 0: <>1__state = -1; if ((Object)(object)plugin._elevatorSource == (Object)null) { plugin._elevatorSource = plugin.FindElevatorAudioSource(); } if ((Object)(object)plugin._elevatorSource == (Object)null) { plugin._log.LogWarning((object)"Could not find elevator audio source to play custom music."); return false; } <>2__current = plugin.LoadClipIfNeeded(fileName); <>1__state = 1; return true; case 1: { <>1__state = -1; if (!plugin._clipCache.TryGetValue(fileName, out var value) || (Object)(object)value == (Object)null) { plugin._log.LogWarning((object)("Missing clip " + fileName + ".")); return false; } double num2; if (!((Object)(object)NetworkManager.Singleton != (Object)null)) { num2 = 0.0; } else { NetworkTime serverTime = NetworkManager.Singleton.ServerTime; num2 = ((NetworkTime)(ref serverTime)).Time; } double num3 = num2; double num4 = Math.Max(0.0, startServerTime - num3); double num5 = AudioSettings.dspTime + num4; plugin._elevatorSource.Stop(); plugin._elevatorSource.clip = value; plugin._elevatorSource.PlayScheduled(num5); plugin._isPlayingCustom = true; plugin._currentTrackName = fileName; return false; } } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <PreloadAllClips>d__45 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public Plugin <>4__this; private List<string>.Enumerator <>7__wrap1; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <PreloadAllClips>d__45(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if (num == -3 || num == 1) { try { } finally { <>m__Finally1(); } } <>7__wrap1 = default(List<string>.Enumerator); <>1__state = -2; } private bool MoveNext() { try { int num = <>1__state; Plugin plugin = <>4__this; switch (num) { default: return false; case 0: <>1__state = -1; <>7__wrap1 = plugin._files.GetEnumerator(); <>1__state = -3; break; case 1: <>1__state = -3; break; } if (<>7__wrap1.MoveNext()) { string current = <>7__wrap1.Current; <>2__current = plugin.LoadClipIfNeeded(Path.GetFileName(current)); <>1__state = 1; return true; } <>m__Finally1(); <>7__wrap1 = default(List<string>.Enumerator); return false; } catch { //try-fault ((IDisposable)this).Dispose(); throw; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; ((IDisposable)<>7__wrap1).Dispose(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <WaitForLethalConfig>d__58 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public Plugin <>4__this; private int <i>5__2; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <WaitForLethalConfig>d__58(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Expected O, but got Unknown int num = <>1__state; Plugin plugin = <>4__this; switch (num) { default: return false; case 0: <>1__state = -1; <i>5__2 = 0; break; case 1: <>1__state = -1; <i>5__2++; break; } if (<i>5__2 < 50) { if (plugin.TryRegisterLethalConfig()) { return false; } <>2__current = (object)new WaitForSeconds(0.2f); <>1__state = 1; return true; } return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <WaitForNetworkManager>d__35 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public Plugin <>4__this; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <WaitForNetworkManager>d__35(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Expected O, but got Unknown int num = <>1__state; Plugin plugin = <>4__this; switch (num) { default: return false; case 0: <>1__state = -1; break; case 1: <>1__state = -1; break; } if ((Object)(object)NetworkManager.Singleton == (Object)null || NetworkManager.Singleton.CustomMessagingManager == null) { <>2__current = null; <>1__state = 1; return true; } NetworkManager.Singleton.CustomMessagingManager.RegisterNamedMessageHandler("MineshaftElevatorMusic.Sync", new HandleNamedMessageDelegate(plugin.OnSyncMessage)); return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private const string ModGuid = "pl.mineshaft.elevator.music"; private const string ModName = "Mineshaft Elevator Music"; private const string ModVersion = "1.0.6"; private const string MessageName = "MineshaftElevatorMusic.Sync"; private string[] _vanillaNameKeywords = new string[3] { "elevator", "mineshaft", "mine" }; private string[] _clipNameWhitelist = Array.Empty<string>(); private string[] _objectNameWhitelist = Array.Empty<string>(); private static readonly string[] SupportedExtensions = new string[3] { ".ogg", ".wav", ".mp3" }; private readonly Dictionary<string, AudioClip> _clipCache = new Dictionary<string, AudioClip>(StringComparer.OrdinalIgnoreCase); private readonly List<string> _files = new List<string>(); private readonly Queue<string> _shuffleQueue = new Queue<string>(); private ManualLogSource _log; private string _musicFolder; private AudioSource _elevatorSource; private bool _isPlayingCustom; private string _currentTrackName; private int _lastVanillaClipId = -1; private double _lastVanillaStartDspTime; private float _vanillaStartWindow = 0.15f; private bool _requireElevatorActive = true; private bool _replaceAnyPlayingInMineshaft; private bool _enableDebugLogs; private string _lastCandidateName; private float _nextDebugLogTime; private bool _loggedNoSource; private ConfigEntry<string> _vanillaKeywordsEntry; private ConfigEntry<string> _clipWhitelistEntry; private ConfigEntry<string> _objectWhitelistEntry; private ConfigEntry<float> _startWindowEntry; private ConfigEntry<bool> _requirePlayingEntry; private ConfigEntry<bool> _replaceAnyEntry; private ConfigEntry<bool> _debugEntry; private void Awake() { //IL_0283: Unknown result type (might be due to invalid IL or missing references) _log = ((BaseUnityPlugin)this).Logger; _musicFolder = Path.Combine(Paths.ConfigPath, "MineshaftElevatorMusic"); Directory.CreateDirectory(_musicFolder); _log.LogInfo((object)"Mineshaft Elevator Music 1.0.6 loaded."); _vanillaKeywordsEntry = ((BaseUnityPlugin)this).Config.Bind<string>("General", "VanillaNameKeywords", "elevator,mineshaft,mine", "Comma-separated keywords used to detect the vanilla mineshaft elevator audio source."); _vanillaNameKeywords = SplitKeywords(_vanillaKeywordsEntry.Value); _clipWhitelistEntry = ((BaseUnityPlugin)this).Config.Bind<string>("General", "ClipNameWhitelist", "", "Optional comma-separated list of exact clip name fragments to match (higher priority than keywords)."); _clipNameWhitelist = SplitKeywords(_clipWhitelistEntry.Value); _objectWhitelistEntry = ((BaseUnityPlugin)this).Config.Bind<string>("General", "ObjectNameWhitelist", "", "Optional comma-separated list of object name fragments to match (higher priority than keywords)."); _objectNameWhitelist = SplitKeywords(_objectWhitelistEntry.Value); _startWindowEntry = ((BaseUnityPlugin)this).Config.Bind<float>("General", "VanillaStartWindowSeconds", 0.15f, "Only triggers replacement when the vanilla clip time is within this start window."); _vanillaStartWindow = Mathf.Clamp(_startWindowEntry.Value, 0.01f, 1f); _requirePlayingEntry = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "RequireElevatorAudioPlaying", true, "If true, only attempts to replace when the vanilla elevator audio is actively playing."); _requireElevatorActive = _requirePlayingEntry.Value; _replaceAnyEntry = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ReplaceAnyPlayingInMineshaft", false, "If true, replaces the first playing audio source in the mineshaft regardless of name match."); _replaceAnyPlayingInMineshaft = _replaceAnyEntry.Value; _debugEntry = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "EnableDebugLogs", false, "If true, logs candidate audio sources and matches to help troubleshooting."); _enableDebugLogs = _debugEntry.Value; _vanillaKeywordsEntry.SettingChanged += delegate { _vanillaNameKeywords = SplitKeywords(_vanillaKeywordsEntry.Value); }; _clipWhitelistEntry.SettingChanged += delegate { _clipNameWhitelist = SplitKeywords(_clipWhitelistEntry.Value); }; _objectWhitelistEntry.SettingChanged += delegate { _objectNameWhitelist = SplitKeywords(_objectWhitelistEntry.Value); }; _startWindowEntry.SettingChanged += delegate { _vanillaStartWindow = Mathf.Clamp(_startWindowEntry.Value, 0.01f, 1f); }; _requirePlayingEntry.SettingChanged += delegate { _requireElevatorActive = _requirePlayingEntry.Value; }; _replaceAnyEntry.SettingChanged += delegate { _replaceAnyPlayingInMineshaft = _replaceAnyEntry.Value; }; _debugEntry.SettingChanged += delegate { _enableDebugLogs = _debugEntry.Value; }; SceneManager.sceneLoaded += OnSceneLoaded; new Harmony("pl.mineshaft.elevator.music").PatchAll(); RegisterNetcodeHandler(); RefreshFileList(); ((MonoBehaviour)this).StartCoroutine(PreloadAllClips()); ((MonoBehaviour)this).StartCoroutine(WaitForLethalConfig()); } private void OnDestroy() { SceneManager.sceneLoaded -= OnSceneLoaded; } private void RegisterNetcodeHandler() { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Expected O, but got Unknown if ((Object)(object)NetworkManager.Singleton == (Object)null || NetworkManager.Singleton.CustomMessagingManager == null) { ((MonoBehaviour)this).StartCoroutine(WaitForNetworkManager()); } else { NetworkManager.Singleton.CustomMessagingManager.RegisterNamedMessageHandler("MineshaftElevatorMusic.Sync", new HandleNamedMessageDelegate(OnSyncMessage)); } } [IteratorStateMachine(typeof(<WaitForNetworkManager>d__35))] private IEnumerator WaitForNetworkManager() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <WaitForNetworkManager>d__35(0) { <>4__this = this }; } private void OnSceneLoaded(Scene scene, LoadSceneMode mode) { if (IsMineshaftLoaded()) { _elevatorSource = null; _isPlayingCustom = false; _currentTrackName = null; _lastVanillaClipId = -1; _lastVanillaStartDspTime = 0.0; _loggedNoSource = false; _nextDebugLogTime = 0f; } } private void Update() { if (!IsMineshaftLoaded()) { _elevatorSource = null; _isPlayingCustom = false; _currentTrackName = null; return; } if ((Object)(object)_elevatorSource == (Object)null) { _elevatorSource = FindElevatorAudioSource(); if ((Object)(object)_elevatorSource != (Object)null) { _loggedNoSource = false; } } if (!((Object)(object)_elevatorSource == (Object)null)) { if (_requireElevatorActive && !_elevatorSource.isPlaying) { _isPlayingCustom = false; _currentTrackName = null; } else if (!_isPlayingCustom && (Object)(object)_elevatorSource.clip != (Object)null && IsCandidateSource(_elevatorSource) && IsHost() && ShouldTriggerReplacement(_elevatorSource)) { TryStartAndSync(); } } } private bool IsHost() { if ((Object)(object)NetworkManager.Singleton != (Object)null) { return NetworkManager.Singleton.IsHost; } return false; } private bool IsMineshaftLoaded() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) for (int i = 0; i < SceneManager.sceneCount; i++) { Scene sceneAt = SceneManager.GetSceneAt(i); if (((Scene)(ref sceneAt)).isLoaded && ((Scene)(ref sceneAt)).name.IndexOf("mineshaft", StringComparison.OrdinalIgnoreCase) >= 0) { return true; } } return false; } private AudioSource FindElevatorAudioSource() { AudioSource[] array = Object.FindObjectsOfType<AudioSource>(true); foreach (AudioSource val in array) { if ((Object)(object)val == (Object)null || (Object)(object)val.clip == (Object)null) { continue; } string text = ((Object)val.clip).name ?? string.Empty; string text2 = (((Object)(object)((Component)val).gameObject != (Object)null) ? ((Object)((Component)val).gameObject).name : string.Empty); if (!IsCandidateNames(text, text2) && !_replaceAnyPlayingInMineshaft) { continue; } string text3 = text2 + " / " + text; if (_lastCandidateName != text3) { _lastCandidateName = text3; if (_enableDebugLogs) { _log.LogInfo((object)("Found candidate elevator audio source: " + text3)); } } return val; } if (_enableDebugLogs && Time.time >= _nextDebugLogTime && !_loggedNoSource) { _nextDebugLogTime = Time.time + 2f; LogPlayingSources(); } return null; } private bool IsVanillaClip(string name) { if (string.IsNullOrWhiteSpace(name)) { return false; } string text = name.ToLowerInvariant(); string[] vanillaNameKeywords = _vanillaNameKeywords; foreach (string value in vanillaNameKeywords) { if (text.Contains(value)) { return true; } } return false; } private bool IsCandidateSource(AudioSource source) { if (_replaceAnyPlayingInMineshaft) { return true; } if ((Object)(object)source == (Object)null) { return false; } string clipName = (((Object)(object)source.clip != (Object)null) ? ((Object)source.clip).name : string.Empty); string objName = (((Object)(object)((Component)source).gameObject != (Object)null) ? ((Object)((Component)source).gameObject).name : string.Empty); return IsCandidateNames(clipName, objName); } private bool IsCandidateNames(string clipName, string objName) { if (MatchesAny(clipName, _clipNameWhitelist)) { return true; } if (MatchesAny(objName, _objectNameWhitelist)) { return true; } if (!IsVanillaClip(clipName)) { return IsVanillaClip(objName); } return true; } private void RefreshFileList() { _files.Clear(); string[] supportedExtensions = SupportedExtensions; foreach (string text in supportedExtensions) { string[] files = Directory.GetFiles(_musicFolder, "*" + text, SearchOption.TopDirectoryOnly); _files.AddRange(files); } _log.LogInfo((object)$"Found {_files.Count} music files in {_musicFolder}"); RefillShuffleQueue(); } [IteratorStateMachine(typeof(<PreloadAllClips>d__45))] private IEnumerator PreloadAllClips() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <PreloadAllClips>d__45(0) { <>4__this = this }; } private void TryStartAndSync() { //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) if (_files.Count == 0) { RefreshFileList(); } if (_files.Count == 0) { _log.LogWarning((object)"No music files found. Put .ogg/.wav/.mp3 in the folder."); return; } string nextTrackName = GetNextTrackName(); if (string.IsNullOrWhiteSpace(nextTrackName)) { _log.LogWarning((object)"Could not pick a track. Check the music folder."); return; } NetworkTime serverTime = NetworkManager.Singleton.ServerTime; double startServerTime = ((NetworkTime)(ref serverTime)).Time + 0.10000000149011612; SendSync(nextTrackName, startServerTime); ((MonoBehaviour)this).StartCoroutine(PlayFromSync(nextTrackName, startServerTime)); } private void SendSync(string fileName, double startServerTime) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)NetworkManager.Singleton == (Object)null) { return; } FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(1024, (Allocator)2, -1); try { ((FastBufferWriter)(ref val)).WriteValueSafe(fileName, false); ((FastBufferWriter)(ref val)).WriteValueSafe<double>(ref startServerTime, default(ForPrimitives)); foreach (ulong connectedClientsId in NetworkManager.Singleton.ConnectedClientsIds) { if (connectedClientsId != NetworkManager.Singleton.LocalClientId) { NetworkManager.Singleton.CustomMessagingManager.SendNamedMessage("MineshaftElevatorMusic.Sync", connectedClientsId, val, (NetworkDelivery)3); } } } finally { ((IDisposable)(FastBufferWriter)(ref val)).Dispose(); } } private void OnSyncMessage(ulong clientId, FastBufferReader reader) { //IL_0010: 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) string fileName = default(string); ((FastBufferReader)(ref reader)).ReadValueSafe(ref fileName, false); double startServerTime = default(double); ((FastBufferReader)(ref reader)).ReadValueSafe<double>(ref startServerTime, default(ForPrimitives)); ((MonoBehaviour)this).StartCoroutine(PlayFromSync(fileName, startServerTime)); } [IteratorStateMachine(typeof(<PlayFromSync>d__49))] private IEnumerator PlayFromSync(string fileName, double startServerTime) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <PlayFromSync>d__49(0) { <>4__this = this, fileName = fileName, startServerTime = startServerTime }; } [IteratorStateMachine(typeof(<LoadClipIfNeeded>d__50))] private IEnumerator LoadClipIfNeeded(string fileName) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <LoadClipIfNeeded>d__50(0) { <>4__this = this, fileName = fileName }; } private AudioType GuessAudioType(string ext) { return (AudioType)(ext switch { ".ogg" => 14, ".wav" => 20, ".mp3" => 13, _ => 0, }); } private bool ShouldTriggerReplacement(AudioSource source) { if ((Object)(object)source.clip == (Object)null) { return false; } int instanceID = ((Object)source.clip).GetInstanceID(); double dspTime = AudioSettings.dspTime; if ((instanceID != _lastVanillaClipId || source.time <= _vanillaStartWindow) && source.time <= _vanillaStartWindow) { _lastVanillaClipId = instanceID; _lastVanillaStartDspTime = dspTime; if (_enableDebugLogs) { _log.LogInfo((object)$"Trigger replacement for clip {((Object)source.clip).name} at time {source.time:0.000}s."); } return true; } return false; } private string GetNextTrackName() { if (_shuffleQueue.Count == 0) { RefillShuffleQueue(); } if (_shuffleQueue.Count == 0) { return null; } return _shuffleQueue.Dequeue(); } private void RefillShuffleQueue() { _shuffleQueue.Clear(); if (_files.Count == 0) { return; } List<string> list = new List<string>(_files); for (int num = list.Count - 1; num > 0; num--) { int index = Random.Range(0, num + 1); string value = list[num]; list[num] = list[index]; list[index] = value; } foreach (string item in list) { _shuffleQueue.Enqueue(Path.GetFileName(item)); } } private string[] SplitKeywords(string value) { if (string.IsNullOrWhiteSpace(value)) { return new string[3] { "elevator", "mineshaft", "mine" }; } string[] array = value.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries); for (int i = 0; i < array.Length; i++) { array[i] = array[i].Trim().ToLowerInvariant(); } if (array.Length != 0) { return array; } return new string[3] { "elevator", "mineshaft", "mine" }; } private bool MatchesAny(string value, string[] tokens) { if (string.IsNullOrWhiteSpace(value) || tokens == null || tokens.Length == 0) { return false; } string text = value.ToLowerInvariant(); foreach (string value2 in tokens) { if (!string.IsNullOrWhiteSpace(value2) && text.Contains(value2)) { return true; } } return false; } private void LogPlayingSources() { try { AudioSource[] array = Object.FindObjectsOfType<AudioSource>(true); int num = 0; _log.LogInfo((object)"No elevator source found yet. Listing up to 10 playing AudioSources:"); AudioSource[] array2 = array; foreach (AudioSource val in array2) { if (!((Object)(object)val == (Object)null) && val.isPlaying) { string arg = (((Object)(object)((Component)val).gameObject != (Object)null) ? ((Object)((Component)val).gameObject).name : "<null>"); string arg2 = (((Object)(object)val.clip != (Object)null) ? ((Object)val.clip).name : "<null>"); _log.LogInfo((object)$" Playing: {arg} / {arg2} (time={val.time:0.00})"); num++; if (num >= 10) { break; } } } if (num == 0) { _log.LogInfo((object)" (No playing AudioSources found)"); } _loggedNoSource = true; } catch (Exception ex) { _log.LogDebug((object)("Failed to log playing sources: " + ex.Message)); } } [IteratorStateMachine(typeof(<WaitForLethalConfig>d__58))] private IEnumerator WaitForLethalConfig() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <WaitForLethalConfig>d__58(0) { <>4__this = this }; } private bool TryRegisterLethalConfig() { try { Type lethalConfigManagerType = GetLethalConfigManagerType(); if (lethalConfigManagerType == null) { return false; } if (lethalConfigManagerType.GetMethod("AddConfigItem", new Type[1] { typeof(object) }) == null) { return false; } lethalConfigManagerType.GetMethod("QueueCustomConfigFileForAutoGeneration", new Type[1] { typeof(ConfigFile) })?.Invoke(null, new object[1] { ((BaseUnityPlugin)this).Config }); lethalConfigManagerType.GetMethod("SetModDescription", new Type[1] { typeof(string) })?.Invoke(null, new object[1] { "Replaces the mineshaft elevator ride music with synced random tracks from a local folder." }); AddTextItem("VanillaNameKeywords", "Comma-separated keywords used to detect the vanilla mineshaft elevator audio source.", _vanillaKeywordsEntry); AddTextItem("ClipNameWhitelist", "Optional comma-separated clip name fragments to match.", _clipWhitelistEntry); AddTextItem("ObjectNameWhitelist", "Optional comma-separated object name fragments to match.", _objectWhitelistEntry); AddFloatSlider("VanillaStartWindowSeconds", "Only triggers replacement when the vanilla clip time is within this start window.", _startWindowEntry, 0.01f, 1f); AddBoolItem("RequireElevatorAudioPlaying", "Only attempts to replace when the vanilla elevator audio is actively playing.", _requirePlayingEntry); AddBoolItem("ReplaceAnyPlayingInMineshaft", "Replace the first playing audio source in the mineshaft (troubleshooting).", _replaceAnyEntry); AddBoolItem("EnableDebugLogs", "Log candidate audio sources and triggers (troubleshooting).", _debugEntry); _log.LogInfo((object)"LethalConfig integration registered."); return true; } catch (Exception ex) { _log.LogDebug((object)("LethalConfig integration skipped: " + ex.Message)); return false; } } private void AddTextItem(string name, string description, ConfigEntry<string> entry) { TryAddConfigItem("LethalConfig.ConfigItems.TextInputFieldConfigItem", "LethalConfig.ConfigItems.TextInputFieldOptions", entry, name, description); } private void AddBoolItem(string name, string description, ConfigEntry<bool> entry) { TryAddConfigItem("LethalConfig.ConfigItems.BoolCheckBoxConfigItem", "LethalConfig.ConfigItems.BoolCheckBoxOptions", entry, name, description); } private void AddFloatSlider(string name, string description, ConfigEntry<float> entry, float min, float max) { TryAddConfigItem("LethalConfig.ConfigItems.FloatSliderConfigItem", "LethalConfig.ConfigItems.FloatSliderOptions", entry, name, description, min, max); } private void TryAddConfigItem(string itemTypeName, string optionsTypeName, object entry, string name, string description, float? min = null, float? max = null) { Type type = Type.GetType(itemTypeName + ", LethalConfig"); Type type2 = Type.GetType(optionsTypeName + ", LethalConfig"); MethodInfo methodInfo = GetLethalConfigManagerType()?.GetMethod("AddConfigItem", new Type[1] { typeof(object) }); if (!(type == null) && !(type2 == null) && !(methodInfo == null)) { object obj = Activator.CreateInstance(type2); SetProp(type2, obj, "Section", "General"); SetProp(type2, obj, "Name", name); SetProp(type2, obj, "Description", description); SetProp(type2, obj, "RequiresRestart", false); if (min.HasValue) { SetProp(type2, obj, "Min", min.Value); } if (max.HasValue) { SetProp(type2, obj, "Max", max.Value); } object obj2 = Activator.CreateInstance(type, entry, obj); methodInfo.Invoke(null, new object[1] { obj2 }); } } private Type GetLethalConfigManagerType() { Type type = Type.GetType("LethalConfig.LethalConfigManager, LethalConfig"); if (type != null) { return type; } Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { if (string.Equals(assembly.GetName().Name, "LethalConfig", StringComparison.OrdinalIgnoreCase)) { type = assembly.GetType("LethalConfig.LethalConfigManager", throwOnError: false); if (type != null) { return type; } } } return null; } private void SetProp(Type type, object instance, string prop, object value) { PropertyInfo property = type.GetProperty(prop); if (property != null && property.CanWrite) { property.SetValue(instance, value, null); } } } }