using System; using System.Collections; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using UnityEngine; using UnityEngine.Networking; [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: AssemblyCopyright("Copyright © 2026")] [assembly: CompilationRelaxations(8)] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("RepoFirstMod")] [assembly: AssemblyTitle("RepoFirstMod")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("0f4ffe05-9a3f-4605-9876-fe6a1584ccad")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyVersion("1.0.0.0")] namespace DeathMusicMod; [BepInPlugin("com.lhd.deathmusic", "死亡播放关羽之歌", "2.0.0")] public class Plugin : BaseUnityPlugin { public static ConfigEntry ModEnabled; public static ConfigEntry MusicVolume; public static ConfigEntry MusicDuration; public static ManualLogSource ModLogger; public static AudioClip DeathClip; public static GameObject MusicPlayerObject; public static DeathMusicPlayer MusicPlayer; public static float LastDeathTime = -999f; private void Awake() { //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Expected O, but got Unknown //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Expected O, but got Unknown //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Expected O, but got Unknown //IL_0163: Unknown result type (might be due to invalid IL or missing references) //IL_0169: Expected O, but got Unknown //IL_01e0: Unknown result type (might be due to invalid IL or missing references) //IL_01ed: Expected O, but got Unknown //IL_0252: Unknown result type (might be due to invalid IL or missing references) //IL_025f: Expected O, but got Unknown ModLogger = ((BaseUnityPlugin)this).Logger; ModEnabled = ((BaseUnityPlugin)this).Config.Bind("General", "Enable Mod", true, "是否启用关羽之歌。关闭后死亡不再播放"); MusicVolume = ((BaseUnityPlugin)this).Config.Bind("General", "Music Volume", 1f, new ConfigDescription("关羽之歌的音量大小(1.0 = 与游戏BGM同等音量)", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1.5f), new object[0])); MusicDuration = ((BaseUnityPlugin)this).Config.Bind("General", "Music Duration", 8f, new ConfigDescription("关羽之歌的播放时长(秒)", (AcceptableValueBase)(object)new AcceptableValueRange(1f, 16f), new object[0])); MusicPlayerObject = new GameObject("DeathMusicPlayer"); Object.DontDestroyOnLoad((Object)(object)MusicPlayerObject); MusicPlayer = MusicPlayerObject.AddComponent(); ((MonoBehaviour)this).StartCoroutine(LoadAudioClip()); ((BaseUnityPlugin)this).Logger.LogInfo((object)"=== 死亡播放关羽之歌 Mod v2.0 已加载 ==="); ((BaseUnityPlugin)this).Logger.LogInfo((object)("音量: " + MusicVolume.Value + " | 时长: " + MusicDuration.Value + "秒 | 启用: " + ModEnabled.Value)); Harmony val = new Harmony("com.lhd.deathmusic"); MethodInfo method = typeof(PlayerAvatar).GetMethod("PlayerDeath"); MethodInfo method2 = typeof(PlayerAvatar).GetMethod("PlayerDeathRPC"); MethodInfo method3 = typeof(PlayerDeathLocalPatch).GetMethod("Postfix"); MethodInfo method4 = typeof(PlayerDeathRPCPatch).GetMethod("Postfix"); if (method != null && method3 != null) { val.Patch((MethodBase)method, (HarmonyMethod)null, new HarmonyMethod(method3), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); ((BaseUnityPlugin)this).Logger.LogInfo((object)("PlayerDeath Patch 已注入: " + method.DeclaringType.Name + "." + method.Name)); } else { ((BaseUnityPlugin)this).Logger.LogError((object)"PlayerDeath Patch 注入失败!原始方法或 Postfix 为 null"); } if (method2 != null && method4 != null) { val.Patch((MethodBase)method2, (HarmonyMethod)null, new HarmonyMethod(method4), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); ((BaseUnityPlugin)this).Logger.LogInfo((object)("PlayerDeathRPC Patch 已注入: " + method2.DeclaringType.Name + "." + method2.Name)); } else { ((BaseUnityPlugin)this).Logger.LogError((object)"PlayerDeathRPC Patch 注入失败!原始方法或 Postfix 为 null"); } ((BaseUnityPlugin)this).Logger.LogInfo((object)"Harmony Patch 注入完成。监控 PlayerDeath + PlayerDeathRPC 中..."); } public static void TriggerDeathMusicSafe() { //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Expected O, but got Unknown if ((Object)(object)MusicPlayer == (Object)null) { GameObject val = GameObject.Find("DeathMusicPlayer"); if ((Object)(object)val != (Object)null) { MusicPlayer = val.GetComponent(); } if ((Object)(object)MusicPlayer == (Object)null) { ModLogger.LogWarning((object)"MusicPlayer 已被销毁,正在重建..."); MusicPlayerObject = new GameObject("DeathMusicPlayer"); Object.DontDestroyOnLoad((Object)(object)MusicPlayerObject); MusicPlayer = MusicPlayerObject.AddComponent(); ModLogger.LogInfo((object)"MusicPlayer 重建完成"); } } if ((Object)(object)MusicPlayer != (Object)null) { MusicPlayer.TriggerDeathMusic(); } else { Debug.LogError((object)"[关羽之歌] MusicPlayer 重建失败!"); } } private IEnumerator LoadAudioClip() { string dllPath = Assembly.GetExecutingAssembly().Location; string modDir = Path.GetDirectoryName(dllPath); string audioPath = Path.Combine(modDir, "关羽之歌.WAV"); if (!File.Exists(audioPath)) { audioPath = "D:\\REPO_mods\\DeathMusicMod\\关羽之歌.WAV"; } if (!File.Exists(audioPath)) { ModLogger.LogError((object)("找不到关羽之歌文件!请把 关羽之歌.WAV 放在 " + modDir)); yield break; } string url = "file:///" + audioPath.Replace('\\', '/'); ModLogger.LogInfo((object)("正在加载关羽之歌: " + audioPath)); UnityWebRequest www = UnityWebRequestMultimedia.GetAudioClip(url, (AudioType)20); try { yield return www.SendWebRequest(); if ((int)www.result == 1) { DeathClip = DownloadHandlerAudioClip.GetContent(www); ModLogger.LogInfo((object)("关羽之歌加载成功!时长: " + DeathClip.length + "秒, 采样率: " + DeathClip.frequency + "Hz")); } else { ModLogger.LogError((object)("关羽之歌加载失败: " + www.error)); } } finally { ((IDisposable)www)?.Dispose(); } } } public class DeathMusicPlayer : MonoBehaviour { private AudioSource audioSource; private bool isPlaying; private Coroutine stopCoroutine; private static FieldInfo constantMusicSourceField; private static FieldInfo constantMusicVolumeField; private static FieldInfo levelMusicSourceField; private float bgmSavedVolume = -1f; private void Awake() { audioSource = ((Component)this).gameObject.AddComponent(); audioSource.playOnAwake = false; audioSource.loop = false; audioSource.spatialBlend = 0f; CacheReflectionFields(); } private static void CacheReflectionFields() { BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; try { Type typeFromHandle = typeof(ConstantMusic); constantMusicSourceField = typeFromHandle.GetField("audioSource", bindingAttr); constantMusicVolumeField = typeFromHandle.GetField("volume", bindingAttr); } catch { } try { Type typeFromHandle2 = typeof(LevelMusic); levelMusicSourceField = typeFromHandle2.GetField("audioSource", bindingAttr); } catch { } } public void TriggerDeathMusic() { if (!Plugin.ModEnabled.Value) { return; } if ((Object)(object)Plugin.DeathClip == (Object)null) { Plugin.ModLogger.LogWarning((object)"关羽之歌文件尚未加载完成,跳过"); return; } float time = Time.time; if (time - Plugin.LastDeathTime < 5f) { Plugin.ModLogger.LogInfo((object)("距上次死亡 " + (time - Plugin.LastDeathTime).ToString("F1") + " 秒 < 5 秒,继续当前播放")); Plugin.LastDeathTime = time; return; } Plugin.LastDeathTime = time; if (stopCoroutine != null) { ((MonoBehaviour)this).StopCoroutine(stopCoroutine); } ((MonoBehaviour)this).StartCoroutine(PlayAfterDelay(1f)); } private IEnumerator PlayAfterDelay(float delay) { yield return (object)new WaitForSeconds(delay); if (!((Object)(object)Plugin.DeathClip == (Object)null)) { audioSource.clip = Plugin.DeathClip; audioSource.volume = Plugin.MusicVolume.Value; audioSource.Play(); isPlaying = true; DuckBGM(0.5f); float duration = Mathf.Min(Plugin.MusicDuration.Value, Plugin.DeathClip.length); if (duration <= 0f) { duration = Plugin.DeathClip.length; } stopCoroutine = ((MonoBehaviour)this).StartCoroutine(StopAfterDuration(duration)); Plugin.ModLogger.LogInfo((object)("关羽之歌播放中... 音量:" + Plugin.MusicVolume.Value + " 时长:" + duration + "秒 | BGM已压低至0.5倍")); } } private IEnumerator StopAfterDuration(float duration) { yield return (object)new WaitForSeconds(duration); StopMusic(); } private void StopMusic() { if (audioSource.isPlaying) { audioSource.Stop(); } isPlaying = false; RestoreBGM(); Plugin.ModLogger.LogInfo((object)"关羽之歌播放结束,BGM 已恢复"); } private void DuckBGM(float multiplier) { try { if ((Object)(object)ConstantMusic.instance != (Object)null && constantMusicSourceField != null) { object? value = constantMusicSourceField.GetValue(ConstantMusic.instance); AudioSource val = (AudioSource)((value is AudioSource) ? value : null); if ((Object)(object)val != (Object)null) { bgmSavedVolume = val.volume; val.volume = bgmSavedVolume * multiplier; Plugin.ModLogger.LogInfo((object)("ConstantMusic 音量: " + bgmSavedVolume + " -> " + val.volume)); } } if ((Object)(object)LevelMusic.instance != (Object)null && levelMusicSourceField != null) { object? value2 = levelMusicSourceField.GetValue(LevelMusic.instance); AudioSource val = (AudioSource)((value2 is AudioSource) ? value2 : null); if ((Object)(object)val != (Object)null) { AudioSource obj = val; obj.volume *= multiplier; Plugin.ModLogger.LogInfo((object)"LevelMusic 音量已压低"); } } } catch (Exception ex) { Plugin.ModLogger.LogWarning((object)("压低 BGM 失败: " + ex.Message)); } } private void RestoreBGM() { try { if ((Object)(object)ConstantMusic.instance != (Object)null && constantMusicSourceField != null && bgmSavedVolume > 0f) { object? value = constantMusicSourceField.GetValue(ConstantMusic.instance); AudioSource val = (AudioSource)((value is AudioSource) ? value : null); if ((Object)(object)val != (Object)null) { val.volume = bgmSavedVolume; Plugin.ModLogger.LogInfo((object)("ConstantMusic 音量已恢复: " + bgmSavedVolume)); } } } catch { } bgmSavedVolume = -1f; } private void Update() { if (isPlaying && !audioSource.isPlaying && audioSource.time > 0f) { isPlaying = false; RestoreBGM(); } } private void OnDestroy() { RestoreBGM(); } } [HarmonyPatch(typeof(PlayerAvatar), "PlayerDeathRPC")] public static class PlayerDeathRPCPatch { [HarmonyPostfix] public static void Postfix() { Debug.Log((object)"[关羽之歌] !!! PlayerDeathRPC 被调用了!(联机死亡)"); Plugin.TriggerDeathMusicSafe(); } } [HarmonyPatch(typeof(PlayerAvatar), "PlayerDeath")] public static class PlayerDeathLocalPatch { [HarmonyPostfix] public static void Postfix() { Debug.Log((object)"[关羽之歌] !!! PlayerDeath 被调用了!(本地死亡)"); Plugin.TriggerDeathMusicSafe(); } }