Decompiled source of Death Guanyu Song v2.1.0

DeathMusicMod.dll

Decompiled 11 hours ago
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<bool> ModEnabled;

	public static ConfigEntry<float> MusicVolume;

	public static ConfigEntry<float> 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<bool>("General", "Enable Mod", true, "是否启用关羽之歌。关闭后死亡不再播放");
		MusicVolume = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Music Volume", 1f, new ConfigDescription("关羽之歌的音量大小(1.0 = 与游戏BGM同等音量)", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1.5f), new object[0]));
		MusicDuration = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Music Duration", 8f, new ConfigDescription("关羽之歌的播放时长(秒)", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 16f), new object[0]));
		MusicPlayerObject = new GameObject("DeathMusicPlayer");
		Object.DontDestroyOnLoad((Object)(object)MusicPlayerObject);
		MusicPlayer = MusicPlayerObject.AddComponent<DeathMusicPlayer>();
		((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<DeathMusicPlayer>();
			}
			if ((Object)(object)MusicPlayer == (Object)null)
			{
				ModLogger.LogWarning((object)"MusicPlayer 已被销毁,正在重建...");
				MusicPlayerObject = new GameObject("DeathMusicPlayer");
				Object.DontDestroyOnLoad((Object)(object)MusicPlayerObject);
				MusicPlayer = MusicPlayerObject.AddComponent<DeathMusicPlayer>();
				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>();
		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();
	}
}