using 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 Gloomwood.Saving; using Gloomwood.Sound; using Gloomwood.UI; using Gloomwood.World; using HarmonyLib; using UnityEngine; using UnityEngine.Events; using UnityEngine.Networking; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.6.2", FrameworkDisplayName = ".NET Framework 4.6.2")] [assembly: AssemblyCompany("PhonographSoundMod")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("PhonographSoundMod")] [assembly: AssemblyTitle("PhonographSoundMod")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] namespace PhonographSoundMod; public static class AudioLoader { [CompilerGenerated] private sealed class d__2 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public string filePath; public ManualLogSource log; public Action onLoaded; private UnityWebRequest 5__2; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__2(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(); } } 5__2 = null; <>1__state = -2; } private bool MoveNext() { //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) bool result; try { switch (<>1__state) { default: result = false; break; case 0: { <>1__state = -1; if (!File.Exists(filePath)) { log.LogError((object)("[AudioLoader] File not found: " + filePath)); onLoaded(null); result = false; break; } AudioType audioType = GetAudioType(filePath); if ((int)audioType == 0) { log.LogError((object)("[AudioLoader] Unsupported file type: " + Path.GetExtension(filePath))); onLoaded(null); result = false; break; } string text = "file:///" + filePath.Replace('\\', '/'); log.LogInfo((object)("[AudioLoader] Loading: " + text)); 5__2 = UnityWebRequestMultimedia.GetAudioClip(text, audioType); <>1__state = -3; <>2__current = 5__2.SendWebRequest(); <>1__state = 1; result = true; break; } case 1: <>1__state = -3; if (5__2.isNetworkError || 5__2.isHttpError) { log.LogError((object)("[AudioLoader] Failed to load audio: " + 5__2.error)); onLoaded(null); result = false; } else { AudioClip content = DownloadHandlerAudioClip.GetContent(5__2); if (!((Object)(object)content == (Object)null)) { ((Object)content).name = Path.GetFileNameWithoutExtension(filePath); log.LogInfo((object)$"[AudioLoader] Loaded clip '{((Object)content).name}' ({content.length:F2}s, {content.channels}ch, {content.frequency}Hz)"); onLoaded(content); <>m__Finally1(); 5__2 = null; result = false; break; } log.LogError((object)"[AudioLoader] DownloadHandlerAudioClip returned null."); onLoaded(null); 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 (5__2 != null) { ((IDisposable)5__2).Dispose(); } } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private static readonly string[] SupportedExtensions = new string[3] { ".wav", ".ogg", ".mp3" }; public static string FindAudioFile(string folder) { string[] supportedExtensions = SupportedExtensions; foreach (string text in supportedExtensions) { string[] files = Directory.GetFiles(folder, "*" + text); int num = 0; if (num < files.Length) { return files[num]; } } return null; } [IteratorStateMachine(typeof(d__2))] public static IEnumerator LoadClipCoroutine(string filePath, Action onLoaded, ManualLogSource log) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__2(0) { filePath = filePath, onLoaded = onLoaded, log = log }; } private static AudioType GetAudioType(string path) { return (AudioType)(Path.GetExtension(path).ToLowerInvariant() switch { ".wav" => 20, ".ogg" => 14, ".mp3" => 13, _ => 0, }); } } [BepInPlugin("com.wanderan51.gloomwood.phonographsound", "PhonographSoundMod", "1.0.0")] public class Plugin : BaseUnityPlugin { internal static float SaveVolume = 1f; internal static float AmbientVolume = 1f; private static readonly Harmony _harmony = new Harmony("com.wanderan51.gloomwood.phonographsound"); internal static AudioClip SaveClip { get; private set; } internal static AudioClip AmbientClip { get; private set; } internal static ManualLogSource Log { get; private set; } private void Awake() { //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Expected O, but got Unknown //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Expected O, but got Unknown //IL_024f: Unknown result type (might be due to invalid IL or missing references) //IL_025d: Expected O, but got Unknown //IL_032c: Unknown result type (might be due to invalid IL or missing references) //IL_033a: Expected O, but got Unknown //IL_03f0: Unknown result type (might be due to invalid IL or missing references) //IL_03fd: Expected O, but got Unknown //IL_0493: Unknown result type (might be due to invalid IL or missing references) //IL_04a0: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; ConfigEntry saveVol = ((BaseUnityPlugin)this).Config.Bind("Audio", "SaveVolumeMultiplier", 1f, new ConfigDescription("Volume for the save sound (0.0-2.0).", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 2f), Array.Empty())); SaveVolume = saveVol.Value; saveVol.SettingChanged += delegate { SaveVolume = saveVol.Value; }; ConfigEntry ambVol = ((BaseUnityPlugin)this).Config.Bind("Audio", "AmbientVolumeMultiplier", 1f, new ConfigDescription("Volume for the ambient loop (0.0-2.0).", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 2f), Array.Empty())); AmbientVolume = ambVol.Value; ambVol.SettingChanged += delegate { AmbientVolume = ambVol.Value; }; string path = Path.Combine(Paths.PluginPath, "PhonographSoundMod", "Sounds"); string text = Path.Combine(path, "Save"); string text2 = Path.Combine(path, "Ambient"); Directory.CreateDirectory(text); Directory.CreateDirectory(text2); string text3 = AudioLoader.FindAudioFile(text); if (text3 != null) { ((MonoBehaviour)this).StartCoroutine(AudioLoader.LoadClipCoroutine(text3, delegate(AudioClip c) { SaveClip = c; if ((Object)(object)c != (Object)null) { Log.LogInfo((object)("[PhonographSoundMod] Save clip ready: " + ((Object)c).name)); } }, Log)); } else { Log.LogWarning((object)("[PhonographSoundMod] No save sound found in: " + text)); } string text4 = AudioLoader.FindAudioFile(text2); if (text4 != null) { ((MonoBehaviour)this).StartCoroutine(AudioLoader.LoadClipCoroutine(text4, delegate(AudioClip c) { AmbientClip = c; if ((Object)(object)c != (Object)null) { Log.LogInfo((object)("[PhonographSoundMod] Ambient clip ready: " + ((Object)c).name)); } }, Log)); } else { Log.LogWarning((object)("[PhonographSoundMod] No ambient sound found in: " + text2)); } MethodInfo methodInfo = null; MethodInfo[] methods = typeof(Phonograph).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (MethodInfo methodInfo2 in methods) { if (!(methodInfo2.Name != "SaveGame")) { ParameterInfo[] parameters = methodInfo2.GetParameters(); if (parameters.Length == 1 && parameters[0].ParameterType == typeof(int)) { methodInfo = methodInfo2; break; } } } if (methodInfo != null) { _harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(SaveGamePatch), "Prefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Log.LogInfo((object)"[PhonographSoundMod] Patched Phonograph.SaveGame(int)."); } else { Log.LogError((object)"[PhonographSoundMod] Could not find Phonograph.SaveGame(int)!"); } MethodInfo methodInfo3 = null; methods = typeof(SaveGameMenu).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (MethodInfo methodInfo4 in methods) { if (!(methodInfo4.Name != "TrySaveGame")) { ParameterInfo[] parameters2 = methodInfo4.GetParameters(); if (parameters2.Length == 2 && parameters2[0].ParameterType == typeof(int) && parameters2[1].ParameterType == typeof(bool)) { methodInfo3 = methodInfo4; break; } } } if (methodInfo3 != null) { _harmony.Patch((MethodBase)methodInfo3, new HarmonyMethod(typeof(TrySaveGamePatch), "Prefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Log.LogInfo((object)"[PhonographSoundMod] Patched SaveGameMenu.TrySaveGame(int, bool)."); } else { Log.LogError((object)"[PhonographSoundMod] Could not find SaveGameMenu.TrySaveGame(int, bool)!"); } MethodInfo methodInfo5 = null; methods = typeof(SaveLoadManager).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (MethodInfo methodInfo6 in methods) { if (!(methodInfo6.Name != "TryQuickSave")) { ParameterInfo[] parameters3 = methodInfo6.GetParameters(); if (parameters3.Length == 1 && parameters3[0].ParameterType == typeof(bool)) { methodInfo5 = methodInfo6; break; } } } if (methodInfo5 != null) { _harmony.Patch((MethodBase)methodInfo5, (HarmonyMethod)null, new HarmonyMethod(typeof(QuickSavePatch), "Postfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Log.LogInfo((object)"[PhonographSoundMod] Patched SaveLoadManager.TryQuickSave."); } else { Log.LogError((object)"[PhonographSoundMod] Could not find SaveLoadManager.TryQuickSave!"); } MethodInfo methodInfo7 = null; methods = typeof(Phonograph).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (MethodInfo methodInfo8 in methods) { if (methodInfo8.Name == "Start" && methodInfo8.GetParameters().Length == 0) { methodInfo7 = methodInfo8; break; } } if (methodInfo7 != null) { _harmony.Patch((MethodBase)methodInfo7, (HarmonyMethod)null, new HarmonyMethod(typeof(PhonographStartPatch), "Postfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Log.LogInfo((object)"[PhonographSoundMod] Patched Phonograph.Start()."); } else { Log.LogError((object)"[PhonographSoundMod] Could not find Phonograph.Start()!"); } } } internal static class SaveGamePatch { private static readonly FieldInfo UseSourceField = typeof(Phonograph).GetField("useSource", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); private static readonly FieldInfo AudioSourceField = typeof(SoundSource).GetField("audioSource", BindingFlags.Instance | BindingFlags.NonPublic); private static readonly FieldInfo OnActivateField = typeof(Phonograph).GetField("OnActivate", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); public static void Prefix(Phonograph __instance, int saveSlot) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Expected O, but got Unknown //IL_00ec: Unknown result type (might be due to invalid IL or missing references) Plugin.Log.LogInfo((object)"[PhonographSoundMod] Phonograph.SaveGame fired!"); OnActivateField?.SetValue(__instance, (object?)new UnityEvent()); object? obj = UseSourceField?.GetValue(__instance); SoundSource val = (SoundSource)((obj is SoundSource) ? obj : null); AudioSource val2 = (AudioSource)(((Object)(object)val != (Object)null) ? /*isinst with value type is only supported in some contexts*/: null); UseSourceField?.SetValue(__instance, null); if ((Object)(object)Plugin.SaveClip == (Object)null) { Plugin.Log.LogWarning((object)"[PhonographSoundMod] Save clip not ready."); } else if ((Object)(object)val2 != (Object)null) { val2.Stop(); val2.clip = Plugin.SaveClip; val2.volume = Plugin.SaveVolume; val2.loop = false; val2.Play(); Plugin.Log.LogInfo((object)("[PhonographSoundMod] Playing save: " + ((Object)Plugin.SaveClip).name)); } else { AudioSource.PlayClipAtPoint(Plugin.SaveClip, ((Component)__instance).transform.position, Plugin.SaveVolume); Plugin.Log.LogInfo((object)"[PhonographSoundMod] PlayClipAtPoint fallback."); } } } internal static class TrySaveGamePatch { private static readonly FieldInfo SaveSlotSoundField = typeof(SaveGameMenu).GetField("saveSlotSound", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); public static void Prefix(SaveGameMenu __instance, int saveSlot, bool overwriteSave) { Plugin.Log.LogInfo((object)"[PhonographSoundMod] TrySaveGame fired – silencing saveSlotSound."); SaveSlotSoundField?.SetValue(__instance, null); } } internal static class QuickSavePatch { public static void Postfix(bool __result) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) if (__result && !((Object)(object)Plugin.SaveClip == (Object)null)) { Vector3 val = (((Object)(object)Camera.main != (Object)null) ? ((Component)Camera.main).transform.position : Vector3.zero); AudioSource.PlayClipAtPoint(Plugin.SaveClip, val, Plugin.SaveVolume); Plugin.Log.LogInfo((object)("[PhonographSoundMod] QuickSave – playing: " + ((Object)Plugin.SaveClip).name)); } } } internal static class PhonographStartPatch { private static readonly FieldInfo AudioSourceField = typeof(SoundSource).GetField("audioSource", BindingFlags.Instance | BindingFlags.NonPublic); private static readonly FieldInfo LoopSoundSourceField = typeof(Phonograph).GetField("loopSoundSource", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); private static readonly PropertyInfo MinRangeProp = typeof(SoundSource).GetProperty("MinRange", BindingFlags.Instance | BindingFlags.Public); private static readonly PropertyInfo MaxRangeProp = typeof(SoundSource).GetProperty("MaxRange", BindingFlags.Instance | BindingFlags.Public); private static readonly PropertyInfo SpatialBlendProp = typeof(SoundSource).GetProperty("SpatialBlend", BindingFlags.Instance | BindingFlags.Public); public static void Postfix(Phonograph __instance) { Plugin.Log.LogInfo((object)("[PhonographSoundMod] Phonograph.Start() on: " + ((Object)((Component)__instance).gameObject).name)); if ((Object)(object)Plugin.AmbientClip == (Object)null) { Plugin.Log.LogWarning((object)"[PhonographSoundMod] Ambient clip not ready."); return; } SoundSource loopSoundSource = __instance.loopSoundSource; if ((Object)(object)loopSoundSource == (Object)null) { Plugin.Log.LogWarning((object)"[PhonographSoundMod] loopSoundSource is null."); return; } float num = ((SpatialBlendProp != null) ? ((float)SpatialBlendProp.GetValue(loopSoundSource)) : 1f); float num2 = ((MinRangeProp != null) ? ((float)MinRangeProp.GetValue(loopSoundSource)) : 1f); float num3 = ((MaxRangeProp != null) ? ((float)MaxRangeProp.GetValue(loopSoundSource)) : 20f); object? obj = AudioSourceField?.GetValue(loopSoundSource); AudioSource val = (AudioSource)((obj is AudioSource) ? obj : null); if ((Object)(object)val != (Object)null) { val.Stop(); ((Behaviour)val).enabled = false; } LoopSoundSourceField?.SetValue(__instance, null); ((Behaviour)loopSoundSource).enabled = false; AudioSource obj2 = ((Component)__instance).gameObject.AddComponent(); obj2.clip = Plugin.AmbientClip; obj2.volume = Plugin.AmbientVolume; obj2.loop = true; obj2.spatialBlend = num; obj2.minDistance = num2; obj2.maxDistance = num3; obj2.rolloffMode = (AudioRolloffMode)0; obj2.playOnAwake = false; obj2.Play(); ((Component)__instance).gameObject.AddComponent(); Plugin.Log.LogInfo((object)$"[PhonographSoundMod] Ambient playing – blend:{num:F2} min:{num2:F1} max:{num3:F1} clip:{((Object)Plugin.AmbientClip).name}"); } } internal class PauseAwareAudio : MonoBehaviour { private AudioSource _source; private bool _wasPaused; private void Awake() { _source = ((Component)this).GetComponent(); } private void Update() { bool flag = Time.timeScale == 0f || AudioListener.pause; if (flag && !_wasPaused) { if ((Object)(object)_source != (Object)null && _source.isPlaying) { _source.Pause(); } _wasPaused = true; } else if (!flag && _wasPaused) { if ((Object)(object)_source != (Object)null) { _source.UnPause(); } _wasPaused = false; } } } internal static class MyPluginInfo { internal const string PLUGIN_GUID = "com.wanderan51.gloomwood.phonographsound"; internal const string PLUGIN_NAME = "PhonographSoundMod"; internal const string PLUGIN_VERSION = "1.0.0"; }