Decompiled source of CustomMusic v1.0.0

CustomMusic.dll

Decompiled 2 days ago
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.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using HarmonyLib;
using UnityEngine;
using UnityEngine.Networking;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("CustomMusic")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("CustomMusic")]
[assembly: AssemblyCopyright("Copyright ©  2026")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("257ad1fd-38e8-48d3-93e0-190ceb523928")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("1.0.0.0")]
[BepInPlugin("com.custommusic.mod", "Custom Music", "3.1.0")]
public class CustomMusicPlugin : BaseUnityPlugin
{
	private AudioSource audioSource;

	private AudioClip currentClip;

	private Coroutine loadCoroutine;

	private Harmony harmony;

	private readonly List<string> songs = new List<string>();

	private bool showUI = false;

	private bool isPaused = false;

	private bool gamePausedMusic = false;

	private int selectedSong = -1;

	private Vector2 uiScroll;

	private string status = "Ready";

	private Rect windowRect = new Rect(20f, 20f, 430f, 470f);

	private const int WindowId = 563821;

	private const float PauseThreshold = 0.001f;

	private const float SlowMotionThreshold = 0.95f;

	private const float SlowMotionPitch = 0.35f;

	public static CustomMusicPlugin Instance { get; private set; }

	private string MusicFolder => Path.Combine(Paths.PluginPath, "CustomMusic");

	private void Awake()
	{
		//IL_005c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0066: Expected O, but got Unknown
		Instance = this;
		audioSource = ((Component)this).gameObject.AddComponent<AudioSource>();
		audioSource.playOnAwake = false;
		audioSource.loop = true;
		audioSource.volume = 1f;
		audioSource.pitch = 1f;
		try
		{
			harmony = new Harmony("com.custommusic.mod.inputguard");
			harmony.PatchAll(typeof(CustomMusicPlugin).Assembly);
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Mouse input guard enabled.");
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)("Could not install mouse input guard: " + ex));
			((BaseUnityPlugin)this).Logger.LogWarning((object)"The music UI will work, but clicks may still reach the game.");
		}
		RefreshSongs();
		((BaseUnityPlugin)this).Logger.LogInfo((object)("Custom Music 3.1 loaded. Music folder: " + MusicFolder));
	}

	private void Update()
	{
		if (Input.GetKeyDown((KeyCode)291))
		{
			showUI = !showUI;
		}
		SyncWithGameTime();
	}

	public static bool ShouldBlockGameMouseInput(int button)
	{
		if (button != 0 || (Object)(object)Instance == (Object)null || !Instance.showUI)
		{
			return false;
		}
		return Instance.IsPointerOverWindow();
	}

	private bool IsPointerOverWindow()
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_0009: Unknown result type (might be due to invalid IL or missing references)
		//IL_0015: Unknown result type (might be due to invalid IL or missing references)
		//IL_0027: Unknown result type (might be due to invalid IL or missing references)
		Vector3 mousePosition = Input.mousePosition;
		Vector2 val = default(Vector2);
		((Vector2)(ref val))..ctor(mousePosition.x, (float)Screen.height - mousePosition.y);
		return ((Rect)(ref windowRect)).Contains(val);
	}

	private void SyncWithGameTime()
	{
		if ((Object)(object)audioSource == (Object)null || (Object)(object)audioSource.clip == (Object)null)
		{
			return;
		}
		float timeScale = Time.timeScale;
		if (timeScale <= 0.001f)
		{
			if (audioSource.isPlaying)
			{
				audioSource.Pause();
				gamePausedMusic = true;
			}
			return;
		}
		if (gamePausedMusic)
		{
			gamePausedMusic = false;
			if (!isPaused)
			{
				audioSource.UnPause();
			}
		}
		audioSource.pitch = ((timeScale < 0.95f) ? 0.35f : 1f);
	}

	private void RefreshSongs()
	{
		try
		{
			if (!Directory.Exists(MusicFolder))
			{
				Directory.CreateDirectory(MusicFolder);
			}
			songs.Clear();
			string[] files = Directory.GetFiles(MusicFolder);
			foreach (string text in files)
			{
				if (Path.GetExtension(text).Equals(".ogg", StringComparison.OrdinalIgnoreCase))
				{
					songs.Add(text);
				}
			}
			songs.Sort(StringComparer.OrdinalIgnoreCase);
			if (songs.Count > 0)
			{
				selectedSong = Mathf.Clamp(selectedSong, 0, songs.Count - 1);
			}
			else
			{
				selectedSong = -1;
			}
			status = "Found " + songs.Count + " song(s).";
			((BaseUnityPlugin)this).Logger.LogInfo((object)status);
		}
		catch (Exception ex)
		{
			status = "Error scanning music folder.";
			((BaseUnityPlugin)this).Logger.LogError((object)ex);
		}
	}

	private void PlaySelectedSong()
	{
		if (selectedSong < 0 || selectedSong >= songs.Count)
		{
			status = "Please select a song first.";
			return;
		}
		if (loadCoroutine != null)
		{
			((MonoBehaviour)this).StopCoroutine(loadCoroutine);
			loadCoroutine = null;
		}
		isPaused = false;
		gamePausedMusic = false;
		loadCoroutine = ((MonoBehaviour)this).StartCoroutine(LoadAndPlayCoroutine(songs[selectedSong]));
	}

	private IEnumerator LoadAndPlayCoroutine(string filePath)
	{
		if (!File.Exists(filePath))
		{
			status = "File not found.";
			loadCoroutine = null;
			yield break;
		}
		string fileUri;
		try
		{
			fileUri = new Uri(filePath).AbsoluteUri;
		}
		catch (Exception ex)
		{
			Exception ex2 = ex;
			status = "Invalid music file path.";
			((BaseUnityPlugin)this).Logger.LogError((object)ex2);
			loadCoroutine = null;
			yield break;
		}
		UnityWebRequest request = UnityWebRequestMultimedia.GetAudioClip(fileUri, (AudioType)14);
		try
		{
			yield return request.SendWebRequest();
			if (request.isNetworkError || request.isHttpError)
			{
				status = "Load failed: " + request.error;
				((BaseUnityPlugin)this).Logger.LogError((object)status);
				loadCoroutine = null;
				yield break;
			}
			AudioClip loadedClip = DownloadHandlerAudioClip.GetContent(request);
			if ((Object)(object)loadedClip == (Object)null)
			{
				status = "Could not create AudioClip.";
				((BaseUnityPlugin)this).Logger.LogError((object)status);
				loadCoroutine = null;
				yield break;
			}
			if ((Object)(object)audioSource != (Object)null)
			{
				audioSource.Stop();
				audioSource.clip = null;
			}
			if ((Object)(object)currentClip != (Object)null)
			{
				Object.Destroy((Object)(object)currentClip);
				currentClip = null;
			}
			currentClip = loadedClip;
			audioSource.clip = currentClip;
			audioSource.loop = true;
			audioSource.volume = 1f;
			audioSource.pitch = 1f;
			if (Time.timeScale <= 0.001f)
			{
				gamePausedMusic = true;
				status = "Loaded; waiting for game to resume.";
			}
			else
			{
				audioSource.Play();
				SyncWithGameTime();
				status = "Playing: " + Path.GetFileName(filePath);
			}
			((BaseUnityPlugin)this).Logger.LogInfo((object)status);
		}
		finally
		{
			((IDisposable)request)?.Dispose();
		}
		loadCoroutine = null;
	}

	private void PauseMusic()
	{
		if ((Object)(object)audioSource == (Object)null || (Object)(object)audioSource.clip == (Object)null)
		{
			status = "No music loaded.";
			return;
		}
		audioSource.Pause();
		isPaused = true;
		gamePausedMusic = false;
		status = "Music paused.";
	}

	private void ResumeMusic()
	{
		if ((Object)(object)audioSource == (Object)null || (Object)(object)audioSource.clip == (Object)null)
		{
			status = "No music loaded.";
			return;
		}
		isPaused = false;
		if (Time.timeScale <= 0.001f)
		{
			gamePausedMusic = true;
			status = "Waiting for game to resume.";
			return;
		}
		gamePausedMusic = false;
		audioSource.UnPause();
		SyncWithGameTime();
		status = "Music resumed.";
	}

	private void StopMusic()
	{
		if ((Object)(object)audioSource != (Object)null)
		{
			audioSource.Stop();
			audioSource.pitch = 1f;
		}
		isPaused = false;
		gamePausedMusic = false;
		status = "Music stopped.";
	}

	private void KeepWindowOnScreen()
	{
		float num = Mathf.Max(280f, (float)Screen.width - 16f);
		float num2 = Mathf.Max(220f, (float)Screen.height - 16f);
		((Rect)(ref windowRect)).width = Mathf.Clamp(((Rect)(ref windowRect)).width, Mathf.Min(280f, num), num);
		((Rect)(ref windowRect)).height = Mathf.Clamp(((Rect)(ref windowRect)).height, Mathf.Min(220f, num2), num2);
		((Rect)(ref windowRect)).x = Mathf.Clamp(((Rect)(ref windowRect)).x, 0f, Mathf.Max(0f, (float)Screen.width - ((Rect)(ref windowRect)).width));
		((Rect)(ref windowRect)).y = Mathf.Clamp(((Rect)(ref windowRect)).y, 0f, Mathf.Max(0f, (float)Screen.height - ((Rect)(ref windowRect)).height));
	}

	private void OnGUI()
	{
		//IL_001e: Unknown result type (might be due to invalid IL or missing references)
		//IL_002a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0039: Expected O, but got Unknown
		//IL_0034: Unknown result type (might be due to invalid IL or missing references)
		//IL_0039: Unknown result type (might be due to invalid IL or missing references)
		if (showUI)
		{
			KeepWindowOnScreen();
			windowRect = GUI.Window(563821, windowRect, new WindowFunction(DrawWindow), "Custom Music 3.1");
		}
	}

	private void DrawWindow(int windowID)
	{
		//IL_0077: Unknown result type (might be due to invalid IL or missing references)
		//IL_0079: Unknown result type (might be due to invalid IL or missing references)
		//IL_007e: Unknown result type (might be due to invalid IL or missing references)
		//IL_007f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0084: Unknown result type (might be due to invalid IL or missing references)
		//IL_0089: Unknown result type (might be due to invalid IL or missing references)
		//IL_0387: Unknown result type (might be due to invalid IL or missing references)
		Rect val = default(Rect);
		((Rect)(ref val))..ctor(8f, 22f, ((Rect)(ref windowRect)).width - 16f, ((Rect)(ref windowRect)).height - 52f);
		float num = 350f + (float)songs.Count * 28f;
		Rect val2 = default(Rect);
		((Rect)(ref val2))..ctor(0f, 0f, Mathf.Max(100f, ((Rect)(ref val)).width - 20f), num);
		uiScroll = GUI.BeginScrollView(val, uiScroll, val2);
		GUILayout.BeginArea(val2);
		GUILayout.BeginVertical(Array.Empty<GUILayoutOption>());
		GUILayout.Label("Press F10 to hide/show this window.", Array.Empty<GUILayoutOption>());
		GUILayout.Label("Music folder: BepInEx/plugins/CustomMusic", Array.Empty<GUILayoutOption>());
		GUILayout.Label("Status: " + status, Array.Empty<GUILayoutOption>());
		GUILayout.Label("Game time scale: " + Time.timeScale.ToString("0.00"), Array.Empty<GUILayoutOption>());
		string text = ((Time.timeScale <= 0.001f) ? "Paused" : ((Time.timeScale < 0.95f) ? "Slow Motion" : "Normal"));
		GUILayout.Label("Game mode: " + text, Array.Empty<GUILayoutOption>());
		GUILayout.Space(6f);
		GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
		if (GUILayout.Button("Refresh Songs", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(28f) }))
		{
			RefreshSongs();
		}
		if (GUILayout.Button("Hide", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(28f) }))
		{
			showUI = false;
		}
		GUILayout.EndHorizontal();
		GUILayout.Space(6f);
		GUILayout.Label("Available OGG Songs:", Array.Empty<GUILayoutOption>());
		if (songs.Count == 0)
		{
			GUILayout.Label("No .ogg files found. Add music to the CustomMusic folder.", Array.Empty<GUILayoutOption>());
		}
		else
		{
			for (int i = 0; i < songs.Count; i++)
			{
				bool flag = selectedSong == i;
				string fileName = Path.GetFileName(songs[i]);
				if (GUILayout.Toggle(flag, fileName, GUI.skin.button, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(26f) }))
				{
					selectedSong = i;
				}
			}
		}
		GUILayout.Space(6f);
		GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
		if (GUILayout.Button("Play Selected", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(30f) }))
		{
			PlaySelectedSong();
		}
		if (GUILayout.Button("Pause", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(30f) }))
		{
			PauseMusic();
		}
		GUILayout.EndHorizontal();
		GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
		if (GUILayout.Button("Resume", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(30f) }))
		{
			ResumeMusic();
		}
		if (GUILayout.Button("Stop", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(30f) }))
		{
			StopMusic();
		}
		GUILayout.EndHorizontal();
		GUILayout.Space(5f);
		GUILayout.Label("Slow-motion pitch: 0.35 | Normal pitch: 1.00", Array.Empty<GUILayoutOption>());
		GUILayout.EndVertical();
		GUILayout.EndArea();
		GUI.EndScrollView();
		GUI.DragWindow(new Rect(0f, 0f, ((Rect)(ref windowRect)).width, 18f));
	}

	private void OnDestroy()
	{
		if (loadCoroutine != null)
		{
			((MonoBehaviour)this).StopCoroutine(loadCoroutine);
			loadCoroutine = null;
		}
		if ((Object)(object)audioSource != (Object)null)
		{
			audioSource.Stop();
			audioSource.clip = null;
		}
		if ((Object)(object)currentClip != (Object)null)
		{
			Object.Destroy((Object)(object)currentClip);
			currentClip = null;
		}
		if (harmony != null)
		{
			try
			{
				harmony.UnpatchSelf();
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Harmony cleanup warning: " + ex.Message));
			}
		}
		if ((Object)(object)Instance == (Object)(object)this)
		{
			Instance = null;
		}
	}
}
[HarmonyPatch(typeof(Input), "GetMouseButtonDown", new Type[] { typeof(int) })]
internal static class CustomMusicBlockMouseDownPatch
{
	private static bool Prefix(int button, ref bool __result)
	{
		if (!CustomMusicPlugin.ShouldBlockGameMouseInput(button))
		{
			return true;
		}
		__result = false;
		return false;
	}
}
[HarmonyPatch(typeof(Input), "GetMouseButton", new Type[] { typeof(int) })]
internal static class CustomMusicBlockMouseHeldPatch
{
	private static bool Prefix(int button, ref bool __result)
	{
		if (!CustomMusicPlugin.ShouldBlockGameMouseInput(button))
		{
			return true;
		}
		__result = false;
		return false;
	}
}
[HarmonyPatch(typeof(Input), "GetMouseButtonUp", new Type[] { typeof(int) })]
internal static class CustomMusicBlockMouseUpPatch
{
	private static bool Prefix(int button, ref bool __result)
	{
		if (!CustomMusicPlugin.ShouldBlockGameMouseInput(button))
		{
			return true;
		}
		__result = false;
		return false;
	}
}