using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; 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.Networking; [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("MusicCenterMusicReplacer")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.1.0.0")] [assembly: AssemblyInformationalVersion("0.1.0")] [assembly: AssemblyProduct("MusicCenterMusicReplacer")] [assembly: AssemblyTitle("MusicCenterMusicReplacer")] [assembly: AssemblyVersion("0.1.0.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 MusicCenterMusicReplacer { internal static class AudioFileLoader { internal static IEnumerator LoadFromPluginFolder(string fileName, Action onLoaded) { string directoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); if (string.IsNullOrWhiteSpace(directoryName)) { Plugin.Log.LogError((object)"Could not determine the plugin directory."); onLoaded(null); yield break; } string fullPath = Path.Combine(directoryName, fileName); if (!File.Exists(fullPath)) { Plugin.Log.LogWarning((object)("Music file not found: " + fullPath)); Plugin.Log.LogWarning((object)"Place boombox.ogg, boombox.wav or boombox.mp3 next to the DLL."); onLoaded(null); yield break; } AudioType audioType = GetAudioType(Path.GetExtension(fullPath)); if ((int)audioType == 0) { Plugin.Log.LogError((object)("Unsupported audio extension: " + Path.GetExtension(fullPath))); onLoaded(null); yield break; } string absoluteUri = new Uri(fullPath).AbsoluteUri; UnityWebRequest request = UnityWebRequestMultimedia.GetAudioClip(absoluteUri, audioType); try { yield return request.SendWebRequest(); if ((int)request.result != 1) { Plugin.Log.LogError((object)("Could not load music: " + request.error)); onLoaded(null); yield break; } AudioClip content = DownloadHandlerAudioClip.GetContent(request); if ((Object)(object)content == (Object)null) { Plugin.Log.LogError((object)"Unity returned an empty AudioClip."); onLoaded(null); } else { ((Object)content).name = "MusicCenter_" + Path.GetFileNameWithoutExtension(fullPath); Plugin.Log.LogInfo((object)$"Music loaded: {Path.GetFileName(fullPath)} ({content.length:0.00}s)."); onLoaded(content); } } finally { ((IDisposable)request)?.Dispose(); } } private static AudioType GetAudioType(string extension) { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) return (AudioType)(extension.ToLowerInvariant() switch { ".ogg" => 14, ".wav" => 20, ".mp3" => 13, _ => 0, }); } } [BepInPlugin("com.artem.musiccentermusicreplacer", "Music Center Music Replacer", "0.1.0")] [BepInProcess("REPO.exe")] public sealed class Plugin : BaseUnityPlugin { public const string PluginGuid = "com.artem.musiccentermusicreplacer"; public const string PluginName = "Music Center Music Replacer"; public const string PluginVersion = "0.1.0"; private static readonly HashSet BoomboxSounds = new HashSet(); private ConfigEntry _enabled; private ConfigEntry _audioFileName; private ConfigEntry _forceLoop; private AudioClip? _replacementClip; private Harmony? _harmony; internal static Plugin? Instance { get; private set; } internal static ManualLogSource Log { get; private set; } = null; private void Awake() { //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Expected O, but got Unknown Instance = this; Log = ((BaseUnityPlugin)this).Logger; _enabled = ((BaseUnityPlugin)this).Config.Bind("General", "Enabled", true, "Enables replacement of the Museum Boombox / music center track."); _audioFileName = ((BaseUnityPlugin)this).Config.Bind("Audio", "AudioFileName", "boombox.ogg", "Audio file placed next to the DLL. Supported: .ogg, .wav and .mp3."); _forceLoop = ((BaseUnityPlugin)this).Config.Bind("Playback", "ForceLoop", true, "Loops the custom track while the boombox is being held."); _harmony = new Harmony("com.artem.musiccentermusicreplacer"); _harmony.PatchAll(); ((MonoBehaviour)this).StartCoroutine(AudioFileLoader.LoadFromPluginFolder(_audioFileName.Value, OnReplacementLoaded)); Log.LogInfo((object)"Music Center Music Replacer v0.1.0 loaded."); } private void OnDestroy() { Harmony? harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } BoomboxSounds.Clear(); Instance = null; } private void OnReplacementLoaded(AudioClip? clip) { _replacementClip = clip; if (!((Object)(object)clip == (Object)null)) { ValuableBoombox[] array = Resources.FindObjectsOfTypeAll(); for (int i = 0; i < array.Length; i++) { RegisterBoombox(array[i]); } } } internal static void RegisterBoombox(ValuableBoombox? boombox) { Plugin instance = Instance; if (!((Object)(object)instance == (Object)null) && !((Object)(object)boombox == (Object)null) && boombox.soundBoomboxMusic != null) { Sound soundBoomboxMusic = boombox.soundBoomboxMusic; BoomboxSounds.Add(soundBoomboxMusic); instance.ApplyReplacement(soundBoomboxMusic, restartIfPlaying: true); } } private void ApplyReplacement(Sound sound, bool restartIfPlaying) { AudioClip replacementClip = _replacementClip; if (!_enabled.Value || (Object)(object)replacementClip == (Object)null) { return; } AudioSource source = sound.Source; bool flag = (Object)(object)source != (Object)null && source.isPlaying; sound.Sounds = (AudioClip[])(object)new AudioClip[1] { replacementClip }; if ((Object)(object)source != (Object)null) { source.loop = _forceLoop.Value; if (restartIfPlaying && flag) { source.Stop(); source.clip = replacementClip; source.time = 0f; source.Play(); Log.LogInfo((object)"[MUSIC START] Music center restarted from 0:00."); } } } internal static void BeforeSoundPlay(Sound? sound) { Plugin instance = Instance; if ((Object)(object)instance == (Object)null || sound == null || !BoomboxSounds.Contains(sound)) { return; } AudioClip replacementClip = instance._replacementClip; if (instance._enabled.Value && !((Object)(object)replacementClip == (Object)null)) { sound.Sounds = (AudioClip[])(object)new AudioClip[1] { replacementClip }; AudioSource source = sound.Source; if ((Object)(object)source != (Object)null) { source.Stop(); source.clip = replacementClip; source.time = 0f; source.loop = instance._forceLoop.Value; } } } internal static void AfterSoundPlay(Sound? sound) { Plugin instance = Instance; if ((Object)(object)instance == (Object)null || sound == null || !BoomboxSounds.Contains(sound)) { return; } AudioClip replacementClip = instance._replacementClip; if (!instance._enabled.Value || (Object)(object)replacementClip == (Object)null) { return; } AudioSource source = sound.Source; if (!((Object)(object)source == (Object)null)) { source.clip = replacementClip; source.loop = instance._forceLoop.Value; source.time = 0f; if (!source.isPlaying) { source.Play(); } Log.LogInfo((object)"[MUSIC START] Music center started from 0:00."); } } } [HarmonyPatch(typeof(ValuableBoombox), "Start")] internal static class ValuableBoomboxStartPatch { private static void Postfix(ValuableBoombox __instance) { Plugin.RegisterBoombox(__instance); } } [HarmonyPatch] internal static class BoomboxSoundPlayPatch { private static IEnumerable TargetMethods() { return from method in AccessTools.GetDeclaredMethods(typeof(Sound)) where method.Name == "Play" select method; } private static void Prefix(Sound __instance) { Plugin.BeforeSoundPlay(__instance); } private static void Postfix(Sound __instance) { Plugin.AfterSoundPlay(__instance); } } }