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 MuteMusic v1.0.3
BepInEx/plugins/MuteMusic/MuteMusic.dll
Decompiled 5 days agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; 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 UnityEngine; 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("MuteMusic")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.3.0")] [assembly: AssemblyInformationalVersion("1.0.3")] [assembly: AssemblyProduct("Mute Music")] [assembly: AssemblyTitle("MuteMusic")] [assembly: AssemblyVersion("1.0.3.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [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] [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] [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 MuteMusic { public static class AudioNames { private static readonly string[] Protected = new string[12] { "speaker", "shipintro", "introspeech", "shiplanding", "shiparrive", "shipdepart", "shipmotor", "ship3d", "shipdoor", "turbulence", "thruster", "shipalarm" }; private static readonly string[] GameplayKeep = new string[5] { "boombox", "radio", "walkie", "heartbeat", "jester" }; private static readonly string[] Soundtrack = new string[8] { "music", "theme", "daytime", "evening", "soundtrack", "icecream", "timeofday", "menuaudio" }; public static bool IsProtected(string? name) { return ContainsAny(name, Protected); } public static bool IsGameplayKeep(string? name) { return ContainsAny(name, GameplayKeep); } public static bool IsSoundtrack(string? name) { if (string.IsNullOrEmpty(name) || IsProtected(name) || IsGameplayKeep(name)) { return false; } return ContainsAny(name, Soundtrack); } public static bool IsDropshipMelody(string? objectName, string? sourceName, string? clipName) { if (IsProtected(objectName) || IsProtected(sourceName) || IsProtected(clipName) || IsGameplayKeep(objectName) || IsGameplayKeep(sourceName) || IsGameplayKeep(clipName)) { return false; } if (ContainsAny(clipName, "icecream") || ContainsAny(objectName, "icecream")) { return true; } if (!IsBareMusicName(objectName)) { return IsBareMusicName(sourceName); } return true; } public static bool IsBareMusicName(string? name) { if (string.IsNullOrEmpty(name)) { return false; } string text = name.Trim(); if (text.Equals("music", StringComparison.OrdinalIgnoreCase)) { return true; } if (text.StartsWith("music (", StringComparison.OrdinalIgnoreCase)) { return text.EndsWith(")", StringComparison.Ordinal); } return false; } public static bool ContainsAny(string? text, params string[] needles) { if (string.IsNullOrEmpty(text) || needles == null || needles.Length == 0) { return false; } foreach (string value in needles) { if (!string.IsNullOrEmpty(value) && text.IndexOf(value, StringComparison.OrdinalIgnoreCase) >= 0) { return true; } } return false; } } public static class VolumeMath { public const float Silent = 0.001f; public static float Clamp01(float value) { if (float.IsNaN(value) || float.IsInfinity(value)) { return 0f; } if (value < 0f) { return 0f; } if (value > 1f) { return 1f; } return value; } public static bool IsSilent(float value) { return Clamp01(value) <= 0.001f; } } internal static class HarmonyPatches { internal static void Apply(Harmony harmony) { string[] array = new string[5] { "MenuManager", "SoundManager", "StartOfRound", "TimeOfDay", "ItemDropship" }; foreach (string text in array) { Type type = AccessTools.TypeByName(text); if (type == null || type.Assembly.GetName().Name != "Assembly-CSharp") { continue; } foreach (MethodInfo declaredMethod in AccessTools.GetDeclaredMethods(type)) { try { PatchMethod(harmony, text, declaredMethod); } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("Skip patch " + text + "." + declaredMethod.Name + ": " + ex.Message)); } } } } } private static void PatchMethod(Harmony harmony, string typeName, MethodInfo method) { //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Expected O, but got Unknown //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Expected O, but got Unknown //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Expected O, but got Unknown //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Expected O, but got Unknown //IL_014f: Unknown result type (might be due to invalid IL or missing references) //IL_015c: Expected O, but got Unknown //IL_01d7: Unknown result type (might be due to invalid IL or missing references) //IL_01e4: Expected O, but got Unknown bool flag; switch (method.Name) { case "Awake": case "Start": case "OnEnable": flag = true; break; default: flag = false; break; } if (flag) { harmony.Patch((MethodBase)method, (HarmonyMethod)null, new HarmonyMethod(typeof(HarmonyPatches), "AfterReady", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } else { switch (method.Name) { case "PlayRandomOutsideMusic": case "PlayTimeMusicDelayed": case "StartMusic": flag = true; break; default: flag = false; break; } if (flag) { harmony.Patch((MethodBase)method, new HarmonyMethod(typeof(HarmonyPatches), "SkipIfMusicMuted", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } else if (method.Name == "firstDayAnimation") { harmony.Patch((MethodBase)method, (HarmonyMethod)null, new HarmonyMethod(typeof(HarmonyPatches), "WrapShipIntro", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } else if (method.Name == "PlayFirstDayShipAnimation") { harmony.Patch((MethodBase)method, (HarmonyMethod)null, new HarmonyMethod(typeof(HarmonyPatches), "AfterIntroStart", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } else if (method.Name == "openingDoorsSequence") { harmony.Patch((MethodBase)method, (HarmonyMethod)null, new HarmonyMethod(typeof(HarmonyPatches), "WrapRoundMusic", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } else { flag = typeName == "ItemDropship"; if (flag) { bool flag2; switch (method.Name) { case "Update": case "LandShipClientRpc": case "DeliverVehicleClientRpc": case "ShipLandedAnimationEvent": case "ShipLandedInAnimation": flag2 = true; break; default: flag2 = false; break; } flag = flag2; } if (!flag) { return; } harmony.Patch((MethodBase)method, (HarmonyMethod)null, new HarmonyMethod(typeof(HarmonyPatches), "AfterDropship", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } } ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)("Patched " + typeName + "." + method.Name)); } } private static void AfterReady(object __instance) { try { MusicController.Register(__instance); Plugin.EnsureTicker(); MusicController.Scan(); MusicController.ApplyTracked(); if (__instance.GetType().Name == "ItemDropship") { MusicController.SilenceDropship(__instance); } } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("AfterReady " + __instance?.GetType().Name + ": " + ex.Message)); } } } private static bool SkipIfMusicMuted() { return !VolumeMath.IsSilent(ModConfig.EffectiveVolume); } private static void AfterDropship(object __instance) { try { MusicController.SilenceDropship(__instance); } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("AfterDropship: " + ex.Message)); } } } private static void AfterIntroStart(object __instance) { try { MusicController.Register(__instance); MusicController.SilenceIntro(includeSpeaker: true); } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("AfterIntroStart: " + ex.Message)); } } } private static void WrapShipIntro(object __instance, ref IEnumerator __result) { try { MusicController.Register(__instance); if (__result != null) { __result = MusicController.SilenceWhile(__result, includeSpeaker: true); } } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("WrapShipIntro: " + ex.Message)); } } } private static void WrapRoundMusic(object __instance, ref IEnumerator __result) { try { MusicController.Register(__instance); if (__result != null) { __result = MusicController.SilenceWhile(__result, includeSpeaker: false); } } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("WrapRoundMusic: " + ex.Message)); } } } } internal static class ModConfig { internal static ConfigEntry<float> MusicVolume; internal static float EffectiveVolume { get { try { return (MusicVolume == null) ? 0f : VolumeMath.Clamp01(MusicVolume.Value); } catch { return 0f; } } } internal static void Bind(ConfigFile config) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Expected O, but got Unknown MusicVolume = config.Bind<float>("General", "MusicVolume", 0f, new ConfigDescription("Soundtrack muted when 0, vanilla when 1. Independent from master volume.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>())); } } internal static class MusicController { private static readonly Dictionary<int, float> OriginalVolumes = new Dictionary<int, float>(); private static readonly HashSet<int> TrackedIds = new HashSet<int>(); private static readonly List<AudioSource> Tracked = new List<AudioSource>(); private static readonly Dictionary<string, Type?> TypeCache = new Dictionary<string, Type>(); private static readonly string[] MusicFields = new string[11] { "MenuAudio", "musicSource", "TimeOfDayMusic", "musicAudio", "elevatorJingleMusic", "companyVisitMusic", "endStatsMusic", "rewardsMusic", "advertMusic", "firstTimeAudio", "coldOpen2Audio" }; private static readonly BindingFlags AnyMember = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; private static Component? MenuManager; private static Component? _soundManager; private static Component? _startOfRound; private static Component? _timeOfDay; private static float _nextScan; private static string _lastScene = ""; private static readonly Dictionary<int, List<AudioSource>> DropshipSources = new Dictionary<int, List<AudioSource>>(); internal static void Register(object instance) { Component val = (Component)((instance is Component) ? instance : null); if (val != null && Object.op_Implicit((Object)(object)val)) { switch (((object)val).GetType().Name) { case "MenuManager": MenuManager = val; break; case "SoundManager": _soundManager = val; break; case "StartOfRound": _startOfRound = val; break; case "TimeOfDay": _timeOfDay = val; break; } } } internal static void OnSceneChanged() { MenuManager = null; _soundManager = null; _startOfRound = null; _timeOfDay = null; Tracked.Clear(); TrackedIds.Clear(); OriginalVolumes.Clear(); DropshipSources.Clear(); _lastScene = ""; _nextScan = 0f; } internal static void Tick() { try { ApplyTracked(); if (Time.unscaledTime >= _nextScan) { _nextScan = Time.unscaledTime + 8f; Scan(); } } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("MusicController.Tick: " + ex.Message)); } } } internal static void Scan() { //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) if (_soundManager == null) { _soundManager = FindSingleton("SoundManager"); } if (_startOfRound == null) { _startOfRound = FindSingleton("StartOfRound"); } if (_timeOfDay == null) { _timeOfDay = FindSingleton("TimeOfDay"); } CollectFields(MenuManager); CollectFields(_soundManager); CollectFields(_startOfRound); CollectFields(_timeOfDay); Scene activeScene = SceneManager.GetActiveScene(); string name = ((Scene)(ref activeScene)).name; if (name != _lastScene) { _lastScene = name; Dump(); } } internal static void ApplyTracked() { float effectiveVolume = ModConfig.EffectiveVolume; for (int num = Tracked.Count - 1; num >= 0; num--) { AudioSource val = Tracked[num]; if ((Object)(object)val == (Object)null || AudioNames.IsProtected(Names(val))) { if ((Object)(object)val == (Object)null) { Tracked.RemoveAt(num); } else { TrackedIds.Remove(((Object)val).GetInstanceID()); Tracked.RemoveAt(num); } } else { ApplyToSource(val, effectiveVolume); } } } internal static void ApplyToSource(AudioSource source, float volume) { if (!((Object)(object)source == (Object)null)) { int instanceID = ((Object)source).GetInstanceID(); if (!OriginalVolumes.ContainsKey(instanceID)) { OriginalVolumes[instanceID] = ((source.volume > 0.01f && !source.mute) ? source.volume : 1f); } source.mute = VolumeMath.IsSilent(volume); source.volume = OriginalVolumes[instanceID] * volume; if (VolumeMath.IsSilent(volume) && source.isPlaying) { source.Stop(); source.playOnAwake = false; } } } internal static IEnumerator SilenceWhile(IEnumerator original, bool includeSpeaker) { if (original != null) { TrySilence(includeSpeaker); while (original.MoveNext()) { TrySilence(includeSpeaker); yield return original.Current; } TrySilence(includeSpeaker); } } internal static void SilenceDropship(object instance) { Component val = (Component)((instance is Component) ? instance : null); if (val == null || !Object.op_Implicit((Object)(object)val)) { return; } int instanceID = ((Object)val).GetInstanceID(); if (!DropshipSources.TryGetValue(instanceID, out List<AudioSource> value)) { value = new List<AudioSource>(); AudioSource[] componentsInChildren = val.GetComponentsInChildren<AudioSource>(true); foreach (AudioSource val2 in componentsInChildren) { if (Object.op_Implicit((Object)(object)val2)) { string clipName = (((Object)(object)val2.clip != (Object)null) ? ((Object)val2.clip).name : ""); if (AudioNames.IsDropshipMelody(((Object)((Component)val2).gameObject).name, ((Object)val2).name, clipName)) { value.Add(val2); } } } if (value.Count == 0) { return; } DropshipSources[instanceID] = value; } float effectiveVolume = ModConfig.EffectiveVolume; for (int j = 0; j < value.Count; j++) { AudioSource val3 = value[j]; if (Object.op_Implicit((Object)(object)val3)) { Track(val3); ApplyToSource(val3, effectiveVolume); } } } internal static void SilenceIntro(bool includeSpeaker) { if (VolumeMath.IsSilent(ModConfig.EffectiveVolume)) { StopNamed(_timeOfDay, "TimeOfDayMusic", hardMute: true); StopNamed(_soundManager, "musicSource", hardMute: true); StopNamed(_startOfRound, "firstTimeAudio", hardMute: true); StopNamed(_startOfRound, "coldOpen2Audio", hardMute: true); if (includeSpeaker) { StopNamed(_startOfRound, "speakerAudioSource", hardMute: false); StopNamed(_startOfRound, "speakerAudio", hardMute: false); } } } private static void TrySilence(bool includeSpeaker) { try { SilenceIntro(includeSpeaker); } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("SilenceIntro: " + ex.Message)); } } } private static void StopNamed(object? instance, string field, bool hardMute) { if (instance == null) { return; } AudioSource member = GetMember<AudioSource>(instance, field); if (member != null && Object.op_Implicit((Object)(object)member)) { member.Stop(); if (hardMute) { member.mute = true; member.volume = 0f; member.playOnAwake = false; } } } private static void CollectFields(Component? component) { if (!Object.op_Implicit((Object)(object)component)) { return; } string[] musicFields = MusicFields; foreach (string name in musicFields) { AudioSource member = GetMember<AudioSource>(component, name); if (member != null && Object.op_Implicit((Object)(object)member)) { Track(member); } } } private static Component? FindSingleton(string typeName) { Type type = ResolveType(typeName); if (type == null) { return null; } try { object? obj = type.GetProperty("Instance", AnyMember)?.GetValue(null, null); Component val = (Component)((obj is Component) ? obj : null); if (val != null && Object.op_Implicit((Object)(object)val)) { return val; } object? obj2 = type.GetField("Instance", AnyMember)?.GetValue(null); return (Component?)((obj2 is Component) ? obj2 : null); } catch { return null; } } private static Type? ResolveType(string typeName) { if (TypeCache.TryGetValue(typeName, out Type value)) { return value; } Type type = AccessTools.TypeByName(typeName); if (type != null && type.Assembly.GetName().Name != "Assembly-CSharp") { type = null; } TypeCache[typeName] = type; return type; } private static T? GetMember<T>(object? obj, string name) where T : class { if (obj == null) { return null; } try { Type type = obj.GetType(); if (type.GetField(name, AnyMember)?.GetValue(obj) is T result) { return result; } return type.GetProperty(name, AnyMember)?.GetValue(obj, null) as T; } catch { return null; } } private static void Track(AudioSource source) { if (!((Object)(object)source == (Object)null) && !AudioNames.IsProtected(Names(source))) { int instanceID = ((Object)source).GetInstanceID(); if (TrackedIds.Add(instanceID)) { Tracked.Add(source); } } } private static string Names(AudioSource source) { string text = (((Object)(object)source.clip != (Object)null) ? ((Object)source.clip).name : ""); return ((Object)((Component)source).gameObject).name + " " + ((Object)source).name + " " + text; } private static void Dump() { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) ManualLogSource log = Plugin.Log; if (log != null) { Scene activeScene = SceneManager.GetActiveScene(); log.LogInfo((object)$"Scene={((Scene)(ref activeScene)).name} tracked={Tracked.Count}"); } } } [BepInPlugin("lc.mutemusic", "Mute Music", "1.0.3")] public sealed class Plugin : BaseUnityPlugin { public const string PluginGuid = "lc.mutemusic"; public const string PluginName = "Mute Music"; public const string PluginVersion = "1.0.3"; private Harmony? _harmony; private static GameObject? _ticker; internal static ManualLogSource Log { get; private set; } private void Awake() { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Expected O, but got Unknown try { Log = ((BaseUnityPlugin)this).Logger; ModConfig.Bind(((BaseUnityPlugin)this).Config); _harmony = new Harmony("lc.mutemusic"); HarmonyPatches.Apply(_harmony); EnsureTicker(); SceneManager.sceneLoaded += OnSceneLoaded; Log.LogInfo((object)string.Format("{0} {1} loaded. Music volume {2:0.00}.", "Mute Music", "1.0.3", ModConfig.EffectiveVolume)); } catch (Exception arg) { ((BaseUnityPlugin)this).Logger.LogError((object)$"Mute Music failed to load: {arg}"); } } internal static void EnsureTicker() { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Expected O, but got Unknown if (!Object.op_Implicit((Object)(object)_ticker)) { _ticker = new GameObject("MuteMusicTicker"); Object.DontDestroyOnLoad((Object)(object)_ticker); _ticker.AddComponent<MuteMusicTicker>(); } } internal static void TickAll() { try { MusicController.Tick(); } catch (Exception ex) { ManualLogSource log = Log; if (log != null) { log.LogWarning((object)("tick: " + ex.Message)); } } } private void OnSceneLoaded(Scene scene, LoadSceneMode mode) { ManualLogSource log = Log; if (log != null) { log.LogInfo((object)("Scene loaded: " + ((Scene)(ref scene)).name)); } MusicController.OnSceneChanged(); EnsureTicker(); TickAll(); } } internal sealed class MuteMusicTicker : MonoBehaviour { private void Start() { ((MonoBehaviour)this).InvokeRepeating("SlowTick", 0.5f, 2f); } private void SlowTick() { Plugin.TickAll(); } } }