Decompiled source of EmPeak v1.2.5

BepInEx/plugins/BetterBugle/BetterBugle.dll

Decompiled a week 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.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Photon.Pun;
using UnityEngine;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("BetterBugle")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("0.1.0.0")]
[assembly: AssemblyInformationalVersion("0.1.0")]
[assembly: AssemblyProduct("BetterBugle")]
[assembly: AssemblyTitle("BetterBugle")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.1.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.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]
	[Microsoft.CodeAnalysis.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]
	[Microsoft.CodeAnalysis.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 BepInEx
{
	[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
	[Conditional("CodeGeneration")]
	internal sealed class BepInAutoPluginAttribute : Attribute
	{
		public BepInAutoPluginAttribute(string? id = null, string? name = null, string? version = null)
		{
		}
	}
}
namespace BepInEx.Preloader.Core.Patching
{
	[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
	[Conditional("CodeGeneration")]
	internal sealed class PatcherAutoPluginAttribute : Attribute
	{
		public PatcherAutoPluginAttribute(string? id = null, string? name = null, string? version = null)
		{
		}
	}
}
namespace BetterBugle
{
	[BepInPlugin("BetterBugle", "BetterBugle", "0.1.0")]
	public class Plugin : BaseUnityPlugin
	{
		[HarmonyPatch(typeof(BugleSFX), "Start")]
		public static class BuglePatch_Start
		{
			[HarmonyPostfix]
			public static void ReplaceBugleClips(ref AudioClip[] ___bugle)
			{
				if (CustomBugleClips.Count > 0)
				{
					___bugle = CustomBugleClips.ToArray();
					Log.LogInfo((object)$">>> [BetterBugle] Bugle sound list replaced ({___bugle.Length} clips).");
				}
			}
		}

		[HarmonyPatch(typeof(BugleSFX), "Update")]
		public static class BuglePatch_ForceSound
		{
			[HarmonyPostfix]
			public static void OverridePlayedSound(BugleSFX __instance)
			{
				if (CustomBugleClips.Count == 0)
				{
					return;
				}
				AudioSource buglePlayer = __instance.buglePlayer;
				if (!((Object)(object)buglePlayer == (Object)null))
				{
					int ownerActorNr = ((MonoBehaviourPun)__instance).photonView.OwnerActorNr;
					int soundIndexForPlayer = BugleSync.GetSoundIndexForPlayer(ownerActorNr);
					AudioClip val = CustomBugleClips[Mathf.Clamp(soundIndexForPlayer, 0, CustomBugleClips.Count - 1)];
					if (__instance.hold && (Object)(object)buglePlayer.clip != (Object)(object)val)
					{
						buglePlayer.clip = val;
						buglePlayer.Play();
						Log.LogInfo((object)$"[BetterBugle] Play: Actor {ownerActorNr} | Clip: {((Object)val).name}");
					}
					if (__instance.hold && buglePlayer.isPlaying)
					{
						ManualLogSource log = Log;
						object arg = ownerActorNr;
						AudioClip clip = buglePlayer.clip;
						log.LogDebug((object)string.Format("[BetterBugle] Playing (actor {0}): {1}", arg, ((clip != null) ? ((Object)clip).name : null) ?? "null"));
					}
					else if (!__instance.hold && buglePlayer.isPlaying)
					{
						ManualLogSource log2 = Log;
						object arg2 = ownerActorNr;
						AudioClip clip2 = buglePlayer.clip;
						log2.LogDebug((object)string.Format("[BetterBugle] Stopping (actor {0}): {1}", arg2, ((clip2 != null) ? ((Object)clip2).name : null) ?? "null"));
						buglePlayer.Stop();
					}
				}
			}
		}

		internal static Plugin Instance;

		internal static List<AudioClip> CustomBugleClips = new List<AudioClip>();

		internal static int SelectedIndex = 0;

		internal static ConfigEntry<KeyCode> ControllerNextKey;

		internal static ConfigEntry<KeyCode> ControllerPreviousKey;

		internal static ConfigEntry<KeyCode> KeyboardNextKey;

		internal static ConfigEntry<KeyCode> KeyboardPreviousKey;

		public static ManualLogSource Log = null;

		private static bool isInitialized = false;

		private static bool isInGameScene = false;

		public static bool HasBugleInHand = false;

		private bool hasGivenBugle = false;

		private bool hasDuplicatedSpawner = false;

		private bool hasLoggedUpdateOnce = false;

		public const string Id = "BetterBugle";

		public static string Name => "BetterBugle";

		public static string Version => "0.1.0";

		private void Awake()
		{
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			SceneManager.sceneLoaded += OnSceneLoaded;
			Log.LogInfo((object)"[BetterBugle] Awake called.");
			Debug.Log((object)">>> [BetterBugle] Plugin is initializing...");
			new Harmony(((BaseUnityPlugin)this).Info.Metadata.GUID).PatchAll();
			Log.LogInfo((object)"[BetterBugle] Harmony patches applied.");
			ControllerNextKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Controls", "ControllerNextKey", (KeyCode)335, "Controller button to go to the next sound (default: RB)");
			ControllerPreviousKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Controls", "ControllerPreviousKey", (KeyCode)334, "Controller button to go to the previous sound (default: LB)");
			KeyboardNextKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Controls", "KeyboardNextKey", (KeyCode)280, "Keyboard key to go to the next sound");
			KeyboardPreviousKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Controls", "KeyboardPreviousKey", (KeyCode)281, "Keyboard key to go to the previous sound");
			((MonoBehaviour)this).StartCoroutine(LoadAllAudioClips());
			((MonoBehaviour)this).StartCoroutine(WaitForSceneLoadAndInit());
		}

		private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
		{
			if (((Scene)(ref scene)).name != "Airport")
			{
				Debug.Log((object)("[BetterBugle] Scene loaded: " + ((Scene)(ref scene)).name + ", starting spawner duplication check."));
				hasDuplicatedSpawner = false;
				((MonoBehaviour)this).StartCoroutine(WaitAndDuplicateSpawner());
			}
		}

		private IEnumerator WaitAndDuplicateSpawner()
		{
			while ((Object)(object)GameObject.Find("Bugle_Spawner") == (Object)null)
			{
				yield return null;
			}
			GameObject originalSpawner = GameObject.Find("Bugle_Spawner");
			if (!((Object)(object)originalSpawner != (Object)null) || hasDuplicatedSpawner)
			{
				yield break;
			}
			Vector3 basePosition = new Vector3(19.2f, 5.1f, -364.8f);
			for (int i = 0; i < 3; i++)
			{
				Vector3 offset = new Vector3((float)i * 0.5f, 0f, 0f);
				GameObject clone = Object.Instantiate<GameObject>(originalSpawner, basePosition + offset, originalSpawner.transform.rotation);
				((Object)clone).name = $"Bugle_Spawner_Clone_{i + 1}";
				SingleItemSpawner spawner = clone.GetComponent<SingleItemSpawner>();
				if ((Object)(object)spawner != (Object)null)
				{
					spawner.TrySpawnItems();
				}
			}
			hasDuplicatedSpawner = true;
			Debug.Log((object)"[BetterBugle] Bugle_Spawner duplicated 3 times near custom position and forced spawn called.");
		}

		private void OnDestroy()
		{
			SceneManager.sceneLoaded -= OnSceneLoaded;
		}

		private IEnumerator LoadAllAudioClips()
		{
			string folderPath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "Sounds");
			Log.LogInfo((object)(">>> [BetterBugle] Loading sounds from folder: " + folderPath));
			if (!Directory.Exists(folderPath))
			{
				Log.LogWarning((object)(">>> [BetterBugle] Folder not found: " + folderPath));
				yield break;
			}
			string[] audioFiles = Directory.GetFiles(folderPath, "*.ogg");
			if (audioFiles.Length == 0)
			{
				Log.LogWarning((object)">>> [BetterBugle] No .ogg files found in the Sounds folder.");
				yield break;
			}
			string[] array = audioFiles;
			foreach (string file in array)
			{
				string url = "file://" + file;
				WWW www = new WWW(url);
				try
				{
					yield return www;
					AudioClip clip = www.GetAudioClip(false, false, (AudioType)14);
					if ((Object)(object)clip != (Object)null)
					{
						((Object)clip).name = Path.GetFileName(file);
						CustomBugleClips.Add(clip);
						Log.LogInfo((object)(">>> [BetterBugle] Loaded audio: " + ((Object)clip).name));
					}
					else
					{
						Log.LogError((object)(">>> [BetterBugle] Failed to load audio: " + Path.GetFileName(file)));
					}
				}
				finally
				{
					((IDisposable)www)?.Dispose();
				}
			}
			Log.LogInfo((object)$">>> [BetterBugle] Final count of loaded clips: {CustomBugleClips.Count}");
			isInitialized = true;
		}

		private IEnumerator WaitForSceneLoadAndInit()
		{
			Log.LogInfo((object)"[BetterBugle] Waiting for scene to load...");
			while ((Object)(object)Character.localCharacter == (Object)null)
			{
				yield return null;
			}
			isInGameScene = true;
			Log.LogInfo((object)"[BetterBugle] Scene loaded, initializing BetterBugleUI and components.");
			GameObject uiObject = new GameObject("BetterBugleUI");
			Object.DontDestroyOnLoad((Object)(object)uiObject);
			BetterBugleUI.Instance = uiObject.AddComponent<BetterBugleUI>();
			Debug.Log((object)">>> [BetterBugle] BetterBugleUI created after scene load.");
		}

		private void Update()
		{
			//IL_0190: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_020e: Unknown result type (might be due to invalid IL or missing references)
			if (!isInitialized || !isInGameScene || CustomBugleClips.Count == 0)
			{
				return;
			}
			if (!hasLoggedUpdateOnce)
			{
				Debug.Log((object)$"[BetterBugle] Update called - isInitialized={isInitialized}, isInGameScene={isInGameScene}, CustomBugleClips.Count={CustomBugleClips.Count}");
				hasLoggedUpdateOnce = true;
			}
			Character localCharacter = Character.localCharacter;
			if ((Object)(object)localCharacter == (Object)null)
			{
				return;
			}
			Character[] array = Object.FindObjectsByType<Character>((FindObjectsSortMode)0);
			foreach (Character val in array)
			{
				if ((Object)(object)val != (Object)null && (Object)(object)((Component)val).GetComponent<BugleSync>() == (Object)null)
				{
					((Component)val).gameObject.AddComponent<BugleSync>();
					Debug.Log((object)("[BetterBugle] BugleSync added to character " + ((Object)val).name + "."));
				}
			}
			CharacterData component = ((Component)localCharacter).GetComponent<CharacterData>();
			if (!((Object)(object)component == (Object)null) && !((Object)(object)component.currentItem == (Object)null) && HasBugleInHand)
			{
				float axis = Input.GetAxis("Mouse ScrollWheel");
				if (axis > 0f)
				{
					Debug.Log((object)"[BetterBugle] Mouse scroll up detected");
					ChangeSound(1);
				}
				else if (axis < 0f)
				{
					Debug.Log((object)"[BetterBugle] Mouse scroll down detected");
					ChangeSound(-1);
				}
				if (Input.GetKeyDown(ControllerNextKey.Value))
				{
					Debug.Log((object)"[BetterBugle] Controller next key pressed");
					ChangeSound(1);
				}
				if (Input.GetKeyDown(ControllerPreviousKey.Value))
				{
					Debug.Log((object)"[BetterBugle] Controller previous key pressed");
					ChangeSound(-1);
				}
				if (Input.GetKeyDown(KeyboardNextKey.Value))
				{
					Debug.Log((object)"[BetterBugle] Keyboard next key pressed");
					ChangeSound(1);
				}
				if (Input.GetKeyDown(KeyboardPreviousKey.Value))
				{
					Debug.Log((object)"[BetterBugle] Keyboard previous key pressed");
					ChangeSound(-1);
				}
			}
		}

		public static void SyncSound(int index)
		{
			if (!((Object)(object)Character.localCharacter == (Object)null))
			{
				SelectedIndex = Mathf.Clamp(index, 0, CustomBugleClips.Count - 1);
				BugleSync component = ((Component)Character.localCharacter).GetComponent<BugleSync>();
				if (component != null)
				{
					((MonoBehaviourPun)component).photonView.RPC("RPC_SyncBugleSound", (RpcTarget)0, new object[1] { SelectedIndex });
				}
				string name = ((Object)CustomBugleClips[SelectedIndex]).name;
				Debug.Log((object)(">>> [BetterBugle] Synced sound: " + name));
				BetterBugleUI.Instance?.ShowSound(SelectedIndex + 1, name);
			}
		}

		private void ChangeSound(int direction)
		{
			int index = (SelectedIndex + direction + CustomBugleClips.Count) % CustomBugleClips.Count;
			SyncSound(index);
		}
	}
	[HarmonyPatch(typeof(CharacterItems), "Equip")]
	public class Patch_CharacterItems_Equip
	{
		private static void Postfix(CharacterItems __instance)
		{
			if (!((Object)(object)__instance.character != (Object)null) || !((Object)(object)__instance.character.data != (Object)null))
			{
				return;
			}
			Item currentItem = __instance.character.data.currentItem;
			if ((Object)(object)currentItem != (Object)null)
			{
				BugleSFX component = ((Component)currentItem).GetComponent<BugleSFX>();
				Plugin.HasBugleInHand = (Object)(object)component != (Object)null;
				if (Plugin.HasBugleInHand)
				{
					Debug.Log((object)"[BetterBugle] Bugle equipped.");
				}
				else
				{
					Debug.Log((object)"[BetterBugle] Bugle not equipped.");
				}
			}
			else
			{
				Plugin.HasBugleInHand = false;
			}
		}
	}
	public class BugleSync : MonoBehaviourPun
	{
		public static Dictionary<int, int> syncedIndexes = new Dictionary<int, int>();

		[PunRPC]
		public void RPC_SyncBugleSound(int index)
		{
			syncedIndexes[((MonoBehaviourPun)this).photonView.OwnerActorNr] = index;
			Plugin.Log.LogInfo((object)$">>> [BetterBugle] RPC received for player {((MonoBehaviourPun)this).photonView.OwnerActorNr} with index {index}");
		}

		public static int GetSoundIndexForPlayer(int actorNumber)
		{
			if (syncedIndexes.TryGetValue(actorNumber, out var value))
			{
				return value;
			}
			return 0;
		}
	}
	public class BetterBugleUI : MonoBehaviour
	{
		public static BetterBugleUI Instance;

		public bool IsVisible = false;

		private float lastChangeTime = -10f;

		private string soundDisplay = "";

		private GUIStyle customStyle;

		private bool fontLoaded = false;

		private int offsetX;

		private int offsetY;

		private int fontSize;

		private ConfigEntry<int> offsetXConfig;

		private ConfigEntry<int> offsetYConfig;

		private ConfigEntry<int> fontSizeConfig;

		private void Start()
		{
			offsetXConfig = ((BaseUnityPlugin)Plugin.Instance).Config.Bind<int>("UI", "OffsetX", 0, "Horizontal offset of the UI display");
			offsetYConfig = ((BaseUnityPlugin)Plugin.Instance).Config.Bind<int>("UI", "OffsetY", 130, "Vertical offset of the UI display");
			fontSizeConfig = ((BaseUnityPlugin)Plugin.Instance).Config.Bind<int>("UI", "FontSize", 42, "Font size of the UI display");
			offsetX = offsetXConfig.Value;
			offsetY = offsetYConfig.Value;
			fontSize = fontSizeConfig.Value;
		}

		private void Update()
		{
			if (customStyle != null)
			{
				customStyle.fontSize = fontSize;
			}
		}

		public void ShowSound(int index, string name)
		{
			soundDisplay = $"SOUND {index} : {name}";
			IsVisible = true;
			lastChangeTime = Time.time;
		}

		private void OnGUI()
		{
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Expected O, but got Unknown
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			if (!IsVisible)
			{
				return;
			}
			if (Time.time - lastChangeTime > 3f)
			{
				IsVisible = false;
				return;
			}
			if (!fontLoaded)
			{
				Font[] array = Resources.FindObjectsOfTypeAll<Font>();
				foreach (Font val in array)
				{
					if (((Object)val).name == "DarumaDropOne-Regular")
					{
						customStyle = new GUIStyle(GUI.skin.label);
						customStyle.font = val;
						customStyle.fontSize = fontSize;
						customStyle.alignment = (TextAnchor)7;
						customStyle.normal.textColor = Color.white;
						fontLoaded = true;
						break;
					}
				}
			}
			GUI.Label(new Rect((float)offsetX, (float)(Screen.height - offsetY), (float)Screen.width, 50f), soundDisplay, customStyle);
		}
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
}