Decompiled source of sPEAKer v1.1.5

plugins/onlystar.sPEAKer.dll

Decompiled 6 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Cryptography;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using Microsoft.CodeAnalysis;
using PEAKLib.Core;
using Photon.Pun;
using Photon.Realtime;
using TMPro;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
using sPEAKer.Scripts;

[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("onlystar")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyDescription("Some guy had it aboard. Does it still work?")]
[assembly: AssemblyFileVersion("1.1.5.0")]
[assembly: AssemblyInformationalVersion("1.1.5+459268a459bae0219dfda5650d27b80ea72c1fc9")]
[assembly: AssemblyProduct("onlystar.sPEAKer")]
[assembly: AssemblyTitle("sPEAKer")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.1.5.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 sPEAKer
{
	[BepInPlugin("onlystar.sPEAKer", "sPEAKer", "1.1.5")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		[CompilerGenerated]
		private sealed class <DelayedSpawn>d__53 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			private Player <masterClient>5__1;

			private List<Character>.Enumerator <>s__2;

			private Character <character>5__3;

			private Vector3 <spawnPos>5__4;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <DelayedSpawn>d__53(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<masterClient>5__1 = null;
				<>s__2 = default(List<Character>.Enumerator);
				<character>5__3 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_0026: Unknown result type (might be due to invalid IL or missing references)
				//IL_0030: Expected O, but got Unknown
				//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
				//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
				//IL_00af: Unknown result type (might be due to invalid IL or missing references)
				//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
				//IL_00be: Unknown result type (might be due to invalid IL or missing references)
				//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
				//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
				//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
				//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<>2__current = (object)new WaitForSeconds(2f);
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					<masterClient>5__1 = PhotonNetwork.MasterClient;
					<>s__2 = Character.AllCharacters.GetEnumerator();
					try
					{
						while (<>s__2.MoveNext())
						{
							<character>5__3 = <>s__2.Current;
							Character obj = <character>5__3;
							if (!object.Equals((obj != null) ? ((MonoBehaviourPun)obj).photonView.Owner : null, <masterClient>5__1))
							{
								continue;
							}
							<spawnPos>5__4 = <character>5__3.Center + Vector3.up + Random.insideUnitSphere * 1.5f;
							PhotonNetwork.InstantiateItemRoom(((Object)_prefab).name, <spawnPos>5__4, Quaternion.identity);
							break;
						}
					}
					finally
					{
						((IDisposable)<>s__2).Dispose();
					}
					<>s__2 = default(List<Character>.Enumerator);
					return false;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		private static GameObject _prefab = null;

		public static PeakBundle Bundle = null;

		private ConfigEntry<bool> debugModeConfig = null;

		private ConfigEntry<bool> loadDemoSongConfig = null;

		private ConfigEntry<string> externalAudioFolderPathConfig = null;

		private ConfigEntry<bool> spawnAtGameStartConfig = null;

		private ConfigEntry<bool> spawnWithF4Config = null;

		private ConfigEntry<bool> recallEnabledConfig = null;

		private ConfigEntry<bool> extendedFormatSupportConfig = null;

		private static Plugin Instance { get; set; } = null;


		internal static ManualLogSource Log { get; private set; } = null;


		public static bool DebugMode { get; private set; }

		public static bool LoadDemoSong { get; private set; }

		public static string ExternalAudioFolderPath { get; private set; } = "";


		private static bool SpawnAtGameStart { get; set; }

		private static bool SpawnWithF4 { get; set; }

		private static bool RecallEnabled { get; set; }

		public static bool ExtendedFormatSupport { get; private set; }

		private void Awake()
		{
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			SetUserConfigs();
			LocalizationFix();
			if (DebugMode)
			{
				Log.LogInfo((object)"[sPEAKer] Plugin awakening...");
			}
			ModDefinition.GetOrCreate(((BaseUnityPlugin)this).Info.Metadata);
			AudioMaster.EnsureInitialized();
			Netcode.EnsureInitialized();
			BundleLoader.LoadBundleWithName((BaseUnityPlugin)(object)this, "ps.peakbundle", (Action<PeakBundle>)InitSpeaker);
		}

		private void InitSpeaker(PeakBundle bundle)
		{
			if (DebugMode)
			{
				Log.LogInfo((object)"[sPEAKer] Initializing sPEAKer with bundle...");
			}
			Bundle = bundle;
			GameObject val = Bundle.LoadAsset<GameObject>("assets/sPEAKer.prefab");
			if ((Object)(object)val == (Object)null)
			{
				Log.LogError((object)"[sPEAKer] Failed to load sPEAKer prefab!");
				return;
			}
			_prefab = val;
			if (DebugMode)
			{
				Log.LogInfo((object)"[sPEAKer] Successfully loaded sPEAKer prefab.");
			}
			SceneManager.sceneLoaded += OnSceneLoaded;
			val.AddComponent<Controller>();
			Bundle.Mod.RegisterContent();
			Log.LogInfo((object)"[sPEAKer] Plugin sPEAKer is loaded!");
		}

		private void SetUserConfigs()
		{
			externalAudioFolderPathConfig = ((BaseUnityPlugin)this).Config.Bind<string>("Audio Loading", "ExternalAudioFolderPath", Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) ?? throw new InvalidOperationException(), "..\\onlystar-sPEAKer Music"), "Folder path where the mod will load mixtapes and external audio from. It's recommended to leave unchanged.");
			ExternalAudioFolderPath = externalAudioFolderPathConfig.Value;
			loadDemoSongConfig = ((BaseUnityPlugin)this).Config.Bind<bool>("Audio Loading", "LoadDemoSong", true, "Include a demo song in your track list.");
			LoadDemoSong = loadDemoSongConfig.Value;
			extendedFormatSupportConfig = ((BaseUnityPlugin)this).Config.Bind<bool>("Audio Loading", "ExtendedFormatSupport", true, "Enables loading of .mp3 and .wav files. May impact performance.");
			ExtendedFormatSupport = extendedFormatSupportConfig.Value;
			spawnAtGameStartConfig = ((BaseUnityPlugin)this).Config.Bind<bool>("Spawning", "SpawnAtGameStart", true, "Automatically spawn a sPEAKer around the crash site when a game starts.");
			SpawnAtGameStart = spawnAtGameStartConfig.Value;
			spawnWithF4Config = ((BaseUnityPlugin)this).Config.Bind<bool>("Spawning", "SpawnWithF4", true, "Allows the host to spawn a sPEAKer in their hands when pressing F4.\nNotes:\n  - Only one sPEAKer may exist at a time (for now).\n  - Only the host can spawn a sPEAKer (for now).");
			SpawnWithF4 = spawnWithF4Config.Value;
			recallEnabledConfig = ((BaseUnityPlugin)this).Config.Bind<bool>("Spawning", "RecallEnabled", true, "Enables recalling existing sPEAKer when pressing F4.\nNotes:\n  - Only works if SpawnWithF4 is enabled.\n  - sPEAKer will only be recalled if it's in the ground.");
			RecallEnabled = recallEnabledConfig.Value;
			debugModeConfig = ((BaseUnityPlugin)this).Config.Bind<bool>("zZzZz", "Debug", false, "Enable debug mode AKA verbose logging. If you want to report a bug, this is the way.");
			DebugMode = debugModeConfig.Value;
		}

		private void Update()
		{
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Invalid comparison between Unknown and I4
			if (Input.GetKeyDown((KeyCode)285) && SpawnWithF4 && PhotonNetwork.IsMasterClient)
			{
				bool flag = DoesSpeakerExist();
				if (RecallEnabled)
				{
					if (flag)
					{
						Controller controller = Object.FindAnyObjectByType<Controller>();
						if ((int)controller.item.itemState == 0)
						{
							controller.KillYourself();
							Instance.SpawnAtHand();
						}
					}
					else
					{
						Instance.SpawnAtHand();
					}
				}
				else if (!flag)
				{
					Instance.SpawnAtHand();
				}
				else if (DebugMode)
				{
					Log.LogInfo((object)"[sPEAKer:AudioMaster] Speaker already exists - not spawning another one");
				}
			}
			if (Input.GetKeyDown((KeyCode)289) && DebugMode)
			{
				Object.FindAnyObjectByType<Controller>().LogAllComponents();
			}
		}

		private void OnDestroy()
		{
			if (DebugMode)
			{
				Log.LogInfo((object)"[sPEAKer] Plugin destroying...");
			}
			SceneManager.sceneLoaded -= OnSceneLoaded;
			Instance = null;
			Log = null;
		}

		private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
		{
			if (SpawnAtGameStart && ((Scene)(ref scene)).name.StartsWith("Level_") && PhotonNetwork.IsConnected && PhotonNetwork.IsMasterClient)
			{
				((MonoBehaviour)this).StartCoroutine(DelayedSpawn());
			}
		}

		private void LocalizationFix()
		{
			LocalizedText.mainTable["NAME_SPEAKER"] = new List<string>(13)
			{
				"sPEAKer", "sPEAKer", "sPEAKer", "sPEAKer", "sPEAKer", "sPEAKer", "sPEAKer", "sPEAKer", "sPEAKer", "sPEAKer",
				"sPEAKer", "sPEAKer", "sPEAKer"
			};
			LocalizedText.mainTable["VOLUME"] = new List<string>(14)
			{
				"Volume", "Volume", "Volume", "Volume", "Lautstärke", "Volumen", "Volumen", "Volume", "Громкость", "Гучність",
				"音量", "音量", "音量", "볼륨"
			};
			LocalizedText.mainTable["TURN ON"] = new List<string>(13)
			{
				"Turn On", "Allumer", "Accendere", "Einschalten", "Encender", "Encender", "Ligar", "Включить", "Увімкнути", "打开",
				"打開", "電源を入れる", "켜다"
			};
			LocalizedText.mainTable["PAUSE"] = new List<string>(14)
			{
				"Pause", "Pause", "Pausa", "Pause", "Pausa", "Pausa", "Pausa", "Pausa", "Пауза", "Пауза",
				"暂停", "暫停", "一時停止", "일시정지"
			};
			LocalizedText.mainTable["..."] = new List<string>(1) { "..." };
		}

		private bool DoesSpeakerExist()
		{
			if ((Object)(object)Object.FindAnyObjectByType<Controller>() != (Object)null)
			{
				return true;
			}
			if (AudioMaster.Instance.IsSpeakerActive())
			{
				return true;
			}
			return false;
		}

		[IteratorStateMachine(typeof(<DelayedSpawn>d__53))]
		private static IEnumerator DelayedSpawn()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <DelayedSpawn>d__53(0);
		}

		public void SpawnAtHand()
		{
			//IL_001a: 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_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			PhotonNetwork.Instantiate("0_Items/" + ((Object)_prefab).name, Character.localCharacter.Center + Vector3.up * 3f, Quaternion.identity, (byte)0, (object[])null).GetComponent<Item>().Interact(Character.localCharacter);
		}
	}
}
namespace sPEAKer.Scripts
{
	public class AudioMaster : MonoBehaviourPun
	{
		[CompilerGenerated]
		private sealed class <>c__DisplayClass64_0
		{
			public string folderPath;

			internal IEnumerable<string> <ProcessAudioFolder>b__0(string pattern)
			{
				return Directory.GetFiles(folderPath, pattern, SearchOption.TopDirectoryOnly);
			}
		}

		[CompilerGenerated]
		private sealed class <>c__DisplayClass66_0
		{
			public string mixtapePath;

			internal IEnumerable<string> <LoadMixtape>b__0(string pattern)
			{
				return Directory.GetFiles(mixtapePath, pattern, SearchOption.TopDirectoryOnly);
			}
		}

		[CompilerGenerated]
		private sealed class <InitializeAsync>d__61 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public AudioMaster <>4__this;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <InitializeAsync>d__61(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					IsLoading = true;
					if (Plugin.DebugMode)
					{
						Plugin.Log.LogInfo((object)"[sPEAKer:AudioMaster] Starting initialization...");
					}
					<>2__current = ((MonoBehaviour)<>4__this).StartCoroutine(<>4__this.LoadFolderAudio());
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					<>2__current = ((MonoBehaviour)<>4__this).StartCoroutine(<>4__this.LoadBundleAudio());
					<>1__state = 2;
					return true;
				case 2:
					<>1__state = -1;
					IsInitialized = true;
					IsLoading = false;
					if (Plugin.DebugMode)
					{
						Plugin.Log.LogInfo((object)("[sPEAKer:AudioMaster] Initialization complete. Total clips loaded: " + LoadedAudioClips.Count + ", Mixtapes loaded: " + AvailableMixtapes.Count));
					}
					return false;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		[CompilerGenerated]
		private sealed class <LoadAudioClipsFromMixtapes>d__65 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public string basePath;

			public AudioMaster <>4__this;

			private int <mixtapeSuccessCount>5__1;

			private int <mixtapeFailCount>5__2;

			private string[] <subDirectories>5__3;

			private string[] <>s__4;

			private int <>s__5;

			private string <mixtapeDir>5__6;

			private MixtapeInfo <lastMixtape>5__7;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <LoadAudioClipsFromMixtapes>d__65(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<subDirectories>5__3 = null;
				<>s__4 = null;
				<mixtapeDir>5__6 = null;
				<lastMixtape>5__7 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<mixtapeSuccessCount>5__1 = 0;
					<mixtapeFailCount>5__2 = 0;
					<subDirectories>5__3 = Directory.GetDirectories(basePath);
					if (Plugin.DebugMode && <subDirectories>5__3.Length != 0)
					{
						Plugin.Log.LogInfo((object)("[sPEAKer:AudioMaster] Found " + <subDirectories>5__3.Length + " potential mixtape folders in " + basePath));
					}
					<>s__4 = <subDirectories>5__3;
					<>s__5 = 0;
					break;
				case 1:
					<>1__state = -1;
					<lastMixtape>5__7 = AvailableMixtapes.LastOrDefault();
					if (<lastMixtape>5__7 != null && <lastMixtape>5__7.Path == <mixtapeDir>5__6 && <lastMixtape>5__7.SongCount > 0)
					{
						<mixtapeSuccessCount>5__1++;
					}
					else if (<lastMixtape>5__7 == null || <lastMixtape>5__7.Path != <mixtapeDir>5__6)
					{
						<mixtapeFailCount>5__2++;
					}
					<lastMixtape>5__7 = null;
					<mixtapeDir>5__6 = null;
					<>s__5++;
					break;
				}
				if (<>s__5 < <>s__4.Length)
				{
					<mixtapeDir>5__6 = <>s__4[<>s__5];
					<>2__current = ((MonoBehaviour)<>4__this).StartCoroutine(<>4__this.LoadMixtape(<mixtapeDir>5__6));
					<>1__state = 1;
					return true;
				}
				<>s__4 = null;
				if (Plugin.DebugMode)
				{
					Plugin.Log.LogInfo((object)("[sPEAKer:AudioMaster] All mixtape folder loading complete for " + basePath + ". Success: " + <mixtapeSuccessCount>5__1 + ", Failed: " + <mixtapeFailCount>5__2));
				}
				return false;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		[CompilerGenerated]
		private sealed class <LoadBundleAudio>d__62 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public AudioMaster <>4__this;

			private int <waitCount>5__1;

			private string[] <allAssets>5__2;

			private string[] <jblFX>5__3;

			private string <whiteNoise>5__4;

			private string[] <>s__5;

			private int <>s__6;

			private string <fx>5__7;

			private AudioClip <clip>5__8;

			private string <filename>5__9;

			private AudioClip <whiteNoiseClip>5__10;

			private AudioClip <demoClip>5__11;

			private string <songHash>5__12;

			private int <index>5__13;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <LoadBundleAudio>d__62(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<allAssets>5__2 = null;
				<jblFX>5__3 = null;
				<whiteNoise>5__4 = null;
				<>s__5 = null;
				<fx>5__7 = null;
				<clip>5__8 = null;
				<filename>5__9 = null;
				<whiteNoiseClip>5__10 = null;
				<demoClip>5__11 = null;
				<songHash>5__12 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_0057: Unknown result type (might be due to invalid IL or missing references)
				//IL_0061: Expected O, but got Unknown
				//IL_02ae: Unknown result type (might be due to invalid IL or missing references)
				//IL_02b4: Invalid comparison between Unknown and I4
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					if (Plugin.DebugMode)
					{
						Plugin.Log.LogInfo((object)"[sPEAKer:AudioMaster] Starting bundle audio loading...");
					}
					<waitCount>5__1 = 0;
					goto IL_0082;
				case 1:
					<>1__state = -1;
					<waitCount>5__1++;
					goto IL_0082;
				case 2:
					{
						<>1__state = -1;
						return false;
					}
					IL_0082:
					if (Plugin.Bundle == null && <waitCount>5__1 < 100)
					{
						<>2__current = (object)new WaitForSeconds(0.1f);
						<>1__state = 1;
						return true;
					}
					if (Plugin.Bundle == null)
					{
						Plugin.Log.LogError((object)"[sPEAKer:AudioMaster] Bundle not available after 10 seconds - skipping bundle audio loading");
						return false;
					}
					if (Plugin.DebugMode)
					{
						Plugin.Log.LogInfo((object)"[sPEAKer:AudioMaster] Bundle is now available, proceeding with loading...");
					}
					<allAssets>5__2 = Plugin.Bundle.GetAllAssetNames();
					if (Plugin.DebugMode)
					{
						Plugin.Log.LogInfo((object)("[sPEAKer:AudioMaster] Total assets in bundle: " + <allAssets>5__2.Length));
					}
					<jblFX>5__3 = <allAssets>5__2.Where((string asset) => asset.Contains("jbl_fx") && asset.EndsWith(".ogg")).ToArray();
					<>s__5 = <jblFX>5__3;
					for (<>s__6 = 0; <>s__6 < <>s__5.Length; <>s__6++)
					{
						<fx>5__7 = <>s__5[<>s__6];
						<clip>5__8 = Plugin.Bundle.LoadAsset<AudioClip>(<fx>5__7);
						<filename>5__9 = Path.GetFileNameWithoutExtension(<fx>5__7);
						SoundEffects.SetClip(<filename>5__9, <clip>5__8);
						<clip>5__8 = null;
						<filename>5__9 = null;
						<fx>5__7 = null;
					}
					<>s__5 = null;
					<whiteNoise>5__4 = <allAssets>5__2.FirstOrDefault((string asset) => asset.Contains("whitenoise"));
					if (!string.IsNullOrEmpty(<whiteNoise>5__4))
					{
						<whiteNoiseClip>5__10 = Plugin.Bundle.LoadAsset<AudioClip>(<whiteNoise>5__4);
						SoundEffects.SetClip("whitenoise", <whiteNoiseClip>5__10);
						<whiteNoiseClip>5__10 = null;
					}
					if (Plugin.LoadDemoSong)
					{
						<demoClip>5__11 = Plugin.Bundle.LoadAsset<AudioClip>("assets/speaker audio/portal.ogg");
						if ((Object)(object)<demoClip>5__11 != (Object)null)
						{
							<demoClip>5__11.LoadAudioData();
							if ((int)<demoClip>5__11.loadState == 2)
							{
								LoadedAudioClips.Add(<demoClip>5__11);
								<songHash>5__12 = <>4__this.GenerateAudioHash(<demoClip>5__11);
								<index>5__13 = LoadedAudioClips.Count - 1;
								SongHashToIndex[<songHash>5__12] = <index>5__13;
								IndexToSongHash[<index>5__13] = <songHash>5__12;
								if (Plugin.DebugMode)
								{
									Plugin.Log.LogInfo((object)("[sPEAKer:AudioMaster] Successfully loaded demo song: " + ((Object)<demoClip>5__11).name));
								}
								<songHash>5__12 = null;
							}
							else
							{
								Plugin.Log.LogError((object)"[sPEAKer:AudioMaster] Failed to load demo song audio data");
							}
						}
						else
						{
							Plugin.Log.LogError((object)"[sPEAKer:AudioMaster] Failed to load demo song from bundle");
						}
						<demoClip>5__11 = null;
					}
					if (Plugin.DebugMode)
					{
						Plugin.Log.LogInfo((object)"[sPEAKer:AudioMaster] Bundle loading complete.");
					}
					<>2__current = null;
					<>1__state = 2;
					return true;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		[CompilerGenerated]
		private sealed class <LoadFolderAudio>d__63 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public AudioMaster <>4__this;

			private List<string> <foldersToProcess>5__1;

			private string <originalFolderPath>5__2;

			private string <pluginsPath>5__3;

			private Exception <e>5__4;

			private string[] <subDirectories>5__5;

			private string[] <>s__6;

			private int <>s__7;

			private string <subDir>5__8;

			private string <markerFile>5__9;

			private List<string>.Enumerator <>s__10;

			private string <folderPath>5__11;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <LoadFolderAudio>d__63(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				int num = <>1__state;
				if (num == -3 || (uint)(num - 1) <= 1u)
				{
					try
					{
					}
					finally
					{
						<>m__Finally1();
					}
				}
				<foldersToProcess>5__1 = null;
				<originalFolderPath>5__2 = null;
				<pluginsPath>5__3 = null;
				<e>5__4 = null;
				<subDirectories>5__5 = null;
				<>s__6 = null;
				<subDir>5__8 = null;
				<markerFile>5__9 = null;
				<>s__10 = default(List<string>.Enumerator);
				<folderPath>5__11 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				try
				{
					switch (<>1__state)
					{
					default:
						return false;
					case 0:
						<>1__state = -1;
						<foldersToProcess>5__1 = new List<string>();
						<originalFolderPath>5__2 = Plugin.ExternalAudioFolderPath;
						if (Directory.Exists(<originalFolderPath>5__2))
						{
							<foldersToProcess>5__1.Add(<originalFolderPath>5__2);
							if (Plugin.DebugMode)
							{
								Plugin.Log.LogInfo((object)("[sPEAKer:AudioMaster] Added original folder: " + <originalFolderPath>5__2));
							}
						}
						else
						{
							if (Plugin.DebugMode)
							{
								Plugin.Log.LogWarning((object)("[sPEAKer:AudioMaster] Original external folder not found: " + <originalFolderPath>5__2 + " - Creating it now."));
							}
							try
							{
								Directory.CreateDirectory(<originalFolderPath>5__2);
								<foldersToProcess>5__1.Add(<originalFolderPath>5__2);
								if (Plugin.DebugMode)
								{
									Plugin.Log.LogInfo((object)"[sPEAKer:AudioMaster] Created original Sounds folder successfully.");
								}
							}
							catch (Exception ex)
							{
								<e>5__4 = ex;
								Plugin.Log.LogError((object)("[sPEAKer:AudioMaster] Failed to create original external folder: " + <e>5__4.Message));
							}
						}
						<pluginsPath>5__3 = Path.GetDirectoryName(<originalFolderPath>5__2) ?? string.Empty;
						if (Directory.Exists(<pluginsPath>5__3))
						{
							<foldersToProcess>5__1.Add(<pluginsPath>5__3.Substring(0, <pluginsPath>5__3.Length - 3));
							if (Plugin.DebugMode)
							{
								Plugin.Log.LogInfo((object)("[sPEAKer:AudioMaster] Scanning plugins folder for mixtape mods: " + <pluginsPath>5__3));
							}
							<subDirectories>5__5 = Directory.GetDirectories(<pluginsPath>5__3);
							<>s__6 = <subDirectories>5__5;
							for (<>s__7 = 0; <>s__7 < <>s__6.Length; <>s__7++)
							{
								<subDir>5__8 = <>s__6[<>s__7];
								<markerFile>5__9 = Path.Combine(<subDir>5__8, "sPEAKer.json");
								if (File.Exists(<markerFile>5__9) && !<foldersToProcess>5__1.Contains(<subDir>5__8))
								{
									<foldersToProcess>5__1.Add(<subDir>5__8);
									if (Plugin.DebugMode)
									{
										Plugin.Log.LogInfo((object)("[sPEAKer:AudioMaster] Found mixtape mod folder: " + <subDir>5__8));
									}
								}
								<markerFile>5__9 = null;
								<subDir>5__8 = null;
							}
							<>s__6 = null;
							<subDirectories>5__5 = null;
						}
						else if (Plugin.DebugMode)
						{
							Plugin.Log.LogWarning((object)("[sPEAKer:AudioMaster] Plugins folder not found: " + <pluginsPath>5__3));
						}
						if (Plugin.DebugMode)
						{
							Plugin.Log.LogInfo((object)("[sPEAKer:AudioMaster] Total folders to process: " + <foldersToProcess>5__1.Count));
						}
						<>s__10 = <foldersToProcess>5__1.GetEnumerator();
						<>1__state = -3;
						break;
					case 1:
						<>1__state = -3;
						<>2__current = ((MonoBehaviour)<>4__this).StartCoroutine(<>4__this.LoadAudioClipsFromMixtapes(<folderPath>5__11));
						<>1__state = 2;
						return true;
					case 2:
						<>1__state = -3;
						<folderPath>5__11 = null;
						break;
					}
					if (<>s__10.MoveNext())
					{
						<folderPath>5__11 = <>s__10.Current;
						<>2__current = ((MonoBehaviour)<>4__this).StartCoroutine(<>4__this.ProcessAudioFolder(<folderPath>5__11));
						<>1__state = 1;
						return true;
					}
					<>m__Finally1();
					<>s__10 = default(List<string>.Enumerator);
					return false;
				}
				catch
				{
					//try-fault
					((IDisposable)this).Dispose();
					throw;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			private void <>m__Finally1()
			{
				<>1__state = -1;
				((IDisposable)<>s__10).Dispose();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		[CompilerGenerated]
		private sealed class <LoadMixtape>d__66 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public string mixtapePath;

			public AudioMaster <>4__this;

			private <>c__DisplayClass66_0 <>8__1;

			private string <mixtapeName>5__2;

			private MixtapeInfo <mixtapeInfo>5__3;

			private string <metadataPath>5__4;

			private List<string> <searchPatterns>5__5;

			private List<string> <audioFiles>5__6;

			private int <songSuccessCount>5__7;

			private int <songFailCount>5__8;

			private float <totalDuration>5__9;

			private string <jsonContent>5__10;

			private MixtapeMetadata <metadata>5__11;

			private Exception <e>5__12;

			private List<string>.Enumerator <>s__13;

			private string <audioFile>5__14;

			private string <fileName>5__15;

			private string <url>5__16;

			private AudioType <audioType>5__17;

			private UnityWebRequest <www>5__18;

			private AudioClip <clip>5__19;

			private string <songHash>5__20;

			private int <index>5__21;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <LoadMixtape>d__66(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				int num = <>1__state;
				if ((uint)(num - -4) <= 1u || (uint)(num - 1) <= 1u)
				{
					try
					{
						if (num == -4 || (uint)(num - 1) <= 1u)
						{
							try
							{
							}
							finally
							{
								<>m__Finally2();
							}
						}
					}
					finally
					{
						<>m__Finally1();
					}
				}
				<>8__1 = null;
				<mixtapeName>5__2 = null;
				<mixtapeInfo>5__3 = null;
				<metadataPath>5__4 = null;
				<searchPatterns>5__5 = null;
				<audioFiles>5__6 = null;
				<jsonContent>5__10 = null;
				<metadata>5__11 = null;
				<e>5__12 = null;
				<>s__13 = default(List<string>.Enumerator);
				<audioFile>5__14 = null;
				<fileName>5__15 = null;
				<url>5__16 = null;
				<www>5__18 = null;
				<clip>5__19 = null;
				<songHash>5__20 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_0423: Unknown result type (might be due to invalid IL or missing references)
				//IL_0429: Invalid comparison between Unknown and I4
				//IL_0431: Unknown result type (might be due to invalid IL or missing references)
				//IL_0437: Invalid comparison between Unknown and I4
				//IL_04f8: Unknown result type (might be due to invalid IL or missing references)
				//IL_04fe: Invalid comparison between Unknown and I4
				//IL_050c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0512: Invalid comparison between Unknown and I4
				//IL_037a: Unknown result type (might be due to invalid IL or missing references)
				//IL_037f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0385: Unknown result type (might be due to invalid IL or missing references)
				//IL_038b: Invalid comparison between Unknown and I4
				//IL_03c7: Unknown result type (might be due to invalid IL or missing references)
				//IL_03ea: Unknown result type (might be due to invalid IL or missing references)
				try
				{
					switch (<>1__state)
					{
					default:
						return false;
					case 0:
						<>1__state = -1;
						<>8__1 = new <>c__DisplayClass66_0();
						<>8__1.mixtapePath = mixtapePath;
						<mixtapeName>5__2 = new DirectoryInfo(<>8__1.mixtapePath).Name;
						if (Plugin.DebugMode)
						{
							Plugin.Log.LogInfo((object)("[sPEAKer:AudioMaster] Loading mixtape from folder: " + <mixtapeName>5__2));
						}
						<mixtapeInfo>5__3 = new MixtapeInfo
						{
							Name = <mixtapeName>5__2,
							Author = "Unknown",
							FirstSongIndex = LoadedAudioClips.Count,
							Path = <>8__1.mixtapePath
						};
						<metadataPath>5__4 = Path.Combine(<>8__1.mixtapePath, "mixtape.json");
						if (File.Exists(<metadataPath>5__4))
						{
							try
							{
								<jsonContent>5__10 = File.ReadAllText(<metadataPath>5__4);
								<metadata>5__11 = JsonUtility.FromJson<MixtapeMetadata>(<jsonContent>5__10);
								if (!string.IsNullOrEmpty(<metadata>5__11.name))
								{
									<mixtapeInfo>5__3.Name = <metadata>5__11.name;
								}
								if (!string.IsNullOrEmpty(<metadata>5__11.author))
								{
									<mixtapeInfo>5__3.Author = <metadata>5__11.author;
								}
								if (Plugin.DebugMode)
								{
									Plugin.Log.LogInfo((object)("[sPEAKer:AudioMaster] Loaded mixtape metadata - Name: " + <mixtapeInfo>5__3.Name + ", Author: " + <mixtapeInfo>5__3.Author));
								}
								<jsonContent>5__10 = null;
								<metadata>5__11 = null;
							}
							catch (Exception ex)
							{
								<e>5__12 = ex;
								Plugin.Log.LogWarning((object)("[sPEAKer:AudioMaster] Failed to parse mixtape metadata for " + <mixtapeName>5__2 + ": " + <e>5__12.Message));
							}
						}
						<searchPatterns>5__5 = new List<string> { "*.ogg" };
						if (Plugin.ExtendedFormatSupport)
						{
							<searchPatterns>5__5.Add("*.mp3");
							<searchPatterns>5__5.Add("*.wav");
						}
						<audioFiles>5__6 = <searchPatterns>5__5.SelectMany((string pattern) => Directory.GetFiles(<>8__1.mixtapePath, pattern, SearchOption.TopDirectoryOnly)).ToList();
						if (Plugin.DebugMode)
						{
							Plugin.Log.LogInfo((object)("[sPEAKer:AudioMaster] Found " + <audioFiles>5__6.Count + " audio files in mixtape."));
						}
						<songSuccessCount>5__7 = 0;
						<songFailCount>5__8 = 0;
						<totalDuration>5__9 = 0f;
						<>s__13 = <audioFiles>5__6.GetEnumerator();
						<>1__state = -3;
						break;
					case 1:
						<>1__state = -4;
						if ((int)<www>5__18.result == 2 || (int)<www>5__18.result == 3)
						{
							Plugin.Log.LogError((object)("[sPEAKer:AudioMaster] Failed to load mixtape audio: " + <fileName>5__15 + " - Error: " + <www>5__18.error));
							<songFailCount>5__8++;
							goto IL_0681;
						}
						<clip>5__19 = DownloadHandlerAudioClip.GetContent(<www>5__18);
						if ((Object)(object)<clip>5__19 != (Object)null)
						{
							((Object)<clip>5__19).name = Path.GetFileNameWithoutExtension(<audioFile>5__14);
							<clip>5__19.LoadAudioData();
							goto IL_04f2;
						}
						Plugin.Log.LogError((object)("[sPEAKer:AudioMaster] Failed to get AudioClip content for mixtape song: " + <fileName>5__15));
						<songFailCount>5__8++;
						goto IL_0679;
					case 2:
						{
							<>1__state = -4;
							goto IL_04f2;
						}
						IL_0681:
						<>m__Finally2();
						<www>5__18 = null;
						<fileName>5__15 = null;
						<url>5__16 = null;
						<audioFile>5__14 = null;
						break;
						IL_04f2:
						if ((int)<clip>5__19.loadState == 1)
						{
							<>2__current = null;
							<>1__state = 2;
							return true;
						}
						if ((int)<clip>5__19.loadState == 2)
						{
							LoadedAudioClips.Add(<clip>5__19);
							<songHash>5__20 = <>4__this.GenerateAudioHash(<clip>5__19);
							<index>5__21 = LoadedAudioClips.Count - 1;
							SongHashToIndex[<songHash>5__20] = <index>5__21;
							IndexToSongHash[<index>5__21] = <songHash>5__20;
							<totalDuration>5__9 += <clip>5__19.length;
							if (Plugin.DebugMode)
							{
								Plugin.Log.LogInfo((object)("[sPEAKer:AudioMaster] Successfully loaded mixtape song: " + ((Object)<clip>5__19).name + " (Length: " + <clip>5__19.length + "s)"));
							}
							<songSuccessCount>5__7++;
							<songHash>5__20 = null;
						}
						else
						{
							Plugin.Log.LogError((object)("[sPEAKer:AudioMaster] Failed to preload audio data for mixtape song: " + <fileName>5__15));
							<songFailCount>5__8++;
						}
						goto IL_0679;
						IL_0679:
						<clip>5__19 = null;
						goto IL_0681;
					}
					while (<>s__13.MoveNext())
					{
						<audioFile>5__14 = <>s__13.Current;
						<fileName>5__15 = Path.GetFileName(<audioFile>5__14);
						if (Plugin.DebugMode)
						{
							Plugin.Log.LogInfo((object)("[sPEAKer:AudioMaster] Loading mixtape song: " + <fileName>5__15));
						}
						<url>5__16 = "file://" + <audioFile>5__14.Replace('\\', '/').Replace("+", "%2B").Replace("#", "%23");
						<audioType>5__17 = <>4__this.GetAudioTypeFromExtension(<audioFile>5__14);
						if ((int)<audioType>5__17 == 0)
						{
							if (Plugin.DebugMode)
							{
								Plugin.Log.LogWarning((object)("[sPEAKer:AudioMaster] Skipping unsupported file type in mixtape: " + <fileName>5__15));
							}
							continue;
						}
						<www>5__18 = UnityWebRequestMultimedia.GetAudioClip(<url>5__16, <audioType>5__17);
						<>1__state = -4;
						((DownloadHandlerAudioClip)<www>5__18.downloadHandler).streamAudio = false;
						<>2__current = <www>5__18.SendWebRequest();
						<>1__state = 1;
						return true;
					}
					<>m__Finally1();
					<>s__13 = default(List<string>.Enumerator);
					<mixtapeInfo>5__3.SongCount = <songSuccessCount>5__7;
					<mixtapeInfo>5__3.LastSongIndex = <mixtapeInfo>5__3.FirstSongIndex + <songSuccessCount>5__7 - 1;
					<mixtapeInfo>5__3.TotalLength = <>4__this.FormatDuration(<totalDuration>5__9);
					if (<songSuccessCount>5__7 > 0)
					{
						AvailableMixtapes.Add(<mixtapeInfo>5__3);
						if (Plugin.DebugMode)
						{
							Plugin.Log.LogInfo((object)("[sPEAKer:AudioMaster] Successfully loaded mixtape '" + <mixtapeInfo>5__3.Name + "' by " + <mixtapeInfo>5__3.Author + " - " + <songSuccessCount>5__7 + " songs, " + <mixtapeInfo>5__3.TotalLength + " total"));
						}
					}
					else
					{
						Plugin.Log.LogWarning((object)("[sPEAKer:AudioMaster] Mixtape folder '" + <mixtapeInfo>5__3.Name + "' contains no valid audio files."));
					}
					return false;
				}
				catch
				{
					//try-fault
					((IDisposable)this).Dispose();
					throw;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			private void <>m__Finally1()
			{
				<>1__state = -1;
				((IDisposable)<>s__13).Dispose();
			}

			private void <>m__Finally2()
			{
				<>1__state = -3;
				if (<www>5__18 != null)
				{
					((IDisposable)<www>5__18).Dispose();
				}
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		[CompilerGenerated]
		private sealed class <ProcessAudioFolder>d__64 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public string folderPath;

			public AudioMaster <>4__this;

			private <>c__DisplayClass64_0 <>8__1;

			private List<string> <searchPatterns>5__2;

			private List<string> <audioFiles>5__3;

			private int <successCount>5__4;

			private int <failCount>5__5;

			private List<string>.Enumerator <>s__6;

			private string <file>5__7;

			private string <fileName>5__8;

			private string <url>5__9;

			private AudioType <audioType>5__10;

			private UnityWebRequest <www>5__11;

			private AudioClip <clip>5__12;

			private string <songHash>5__13;

			private int <index>5__14;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <ProcessAudioFolder>d__64(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				int num = <>1__state;
				if ((uint)(num - -4) <= 1u || (uint)(num - 1) <= 1u)
				{
					try
					{
						if (num == -4 || (uint)(num - 1) <= 1u)
						{
							try
							{
							}
							finally
							{
								<>m__Finally2();
							}
						}
					}
					finally
					{
						<>m__Finally1();
					}
				}
				<>8__1 = null;
				<searchPatterns>5__2 = null;
				<audioFiles>5__3 = null;
				<>s__6 = default(List<string>.Enumerator);
				<file>5__7 = null;
				<fileName>5__8 = null;
				<url>5__9 = null;
				<www>5__11 = null;
				<clip>5__12 = null;
				<songHash>5__13 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_02f5: Unknown result type (might be due to invalid IL or missing references)
				//IL_02fb: Invalid comparison between Unknown and I4
				//IL_0303: Unknown result type (might be due to invalid IL or missing references)
				//IL_0309: Invalid comparison between Unknown and I4
				//IL_03ca: Unknown result type (might be due to invalid IL or missing references)
				//IL_03d0: Invalid comparison between Unknown and I4
				//IL_03de: Unknown result type (might be due to invalid IL or missing references)
				//IL_03e4: Invalid comparison between Unknown and I4
				//IL_024c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0251: Unknown result type (might be due to invalid IL or missing references)
				//IL_0257: Unknown result type (might be due to invalid IL or missing references)
				//IL_025d: Invalid comparison between Unknown and I4
				//IL_0299: Unknown result type (might be due to invalid IL or missing references)
				//IL_02bc: Unknown result type (might be due to invalid IL or missing references)
				try
				{
					switch (<>1__state)
					{
					default:
						return false;
					case 0:
						<>1__state = -1;
						<>8__1 = new <>c__DisplayClass64_0();
						<>8__1.folderPath = folderPath;
						if (Plugin.DebugMode)
						{
							Plugin.Log.LogInfo((object)("[sPEAKer:AudioMaster] Processing loose audio files in: " + <>8__1.folderPath));
						}
						<searchPatterns>5__2 = new List<string> { "*.ogg" };
						if (Plugin.ExtendedFormatSupport)
						{
							if (Plugin.DebugMode)
							{
								Plugin.Log.LogInfo((object)"[sPEAKer:AudioMaster] Extended format support is ON. Searching for .mp3 and .wav files.");
							}
							<searchPatterns>5__2.Add("*.mp3");
							<searchPatterns>5__2.Add("*.wav");
						}
						<audioFiles>5__3 = <searchPatterns>5__2.SelectMany((string pattern) => Directory.GetFiles(<>8__1.folderPath, pattern, SearchOption.TopDirectoryOnly)).ToList();
						if (Plugin.DebugMode)
						{
							Plugin.Log.LogInfo((object)("[sPEAKer:AudioMaster] Found " + <audioFiles>5__3.Count + " loose audio files in " + <>8__1.folderPath));
						}
						if (<audioFiles>5__3.Count == 0)
						{
							if (Plugin.DebugMode)
							{
								Plugin.Log.LogInfo((object)("[sPEAKer:AudioMaster] No loose audio files found, skipping: " + <>8__1.folderPath));
							}
							return false;
						}
						<successCount>5__4 = 0;
						<failCount>5__5 = 0;
						<>s__6 = <audioFiles>5__3.GetEnumerator();
						<>1__state = -3;
						break;
					case 1:
						<>1__state = -4;
						if ((int)<www>5__11.result == 2 || (int)<www>5__11.result == 3)
						{
							Plugin.Log.LogError((object)("[sPEAKer:AudioMaster] Failed to load audio: " + <fileName>5__8 + " - Error: " + <www>5__11.error));
							<failCount>5__5++;
							goto IL_053b;
						}
						<clip>5__12 = DownloadHandlerAudioClip.GetContent(<www>5__11);
						if ((Object)(object)<clip>5__12 != (Object)null)
						{
							((Object)<clip>5__12).name = Path.GetFileNameWithoutExtension(<file>5__7);
							<clip>5__12.LoadAudioData();
							goto IL_03c4;
						}
						Plugin.Log.LogError((object)("[sPEAKer:AudioMaster] Failed to get AudioClip content for: " + <fileName>5__8));
						<failCount>5__5++;
						goto IL_0533;
					case 2:
						{
							<>1__state = -4;
							goto IL_03c4;
						}
						IL_053b:
						<>m__Finally2();
						<www>5__11 = null;
						<fileName>5__8 = null;
						<url>5__9 = null;
						<file>5__7 = null;
						break;
						IL_03c4:
						if ((int)<clip>5__12.loadState == 1)
						{
							<>2__current = null;
							<>1__state = 2;
							return true;
						}
						if ((int)<clip>5__12.loadState == 2)
						{
							LoadedAudioClips.Add(<clip>5__12);
							<songHash>5__13 = <>4__this.GenerateAudioHash(<clip>5__12);
							<index>5__14 = LoadedAudioClips.Count - 1;
							SongHashToIndex[<songHash>5__13] = <index>5__14;
							IndexToSongHash[<index>5__14] = <songHash>5__13;
							if (Plugin.DebugMode)
							{
								Plugin.Log.LogInfo((object)("[sPEAKer:AudioMaster] Successfully loaded and preloaded audio: " + ((Object)<clip>5__12).name + " (Length: " + <clip>5__12.length + "s)"));
							}
							<successCount>5__4++;
							<songHash>5__13 = null;
						}
						else
						{
							Plugin.Log.LogError((object)("[sPEAKer:AudioMaster] Failed to preload audio data for: " + <fileName>5__8));
							<failCount>5__5++;
						}
						goto IL_0533;
						IL_0533:
						<clip>5__12 = null;
						goto IL_053b;
					}
					while (<>s__6.MoveNext())
					{
						<file>5__7 = <>s__6.Current;
						<fileName>5__8 = Path.GetFileName(<file>5__7);
						if (Plugin.DebugMode)
						{
							Plugin.Log.LogInfo((object)("[sPEAKer:AudioMaster] Loading file: " + <fileName>5__8));
						}
						<url>5__9 = "file://" + <file>5__7.Replace('\\', '/').Replace("+", "%2B").Replace("#", "%23");
						<audioType>5__10 = <>4__this.GetAudioTypeFromExtension(<file>5__7);
						if ((int)<audioType>5__10 == 0)
						{
							if (Plugin.DebugMode)
							{
								Plugin.Log.LogWarning((object)("[sPEAKer:AudioMaster] Skipping unsupported file type: " + <fileName>5__8));
							}
							continue;
						}
						<www>5__11 = UnityWebRequestMultimedia.GetAudioClip(<url>5__9, <audioType>5__10);
						<>1__state = -4;
						((DownloadHandlerAudioClip)<www>5__11.downloadHandler).streamAudio = false;
						<>2__current = <www>5__11.SendWebRequest();
						<>1__state = 1;
						return true;
					}
					<>m__Finally1();
					<>s__6 = default(List<string>.Enumerator);
					if (Plugin.DebugMode)
					{
						Plugin.Log.LogInfo((object)("[sPEAKer:AudioMaster] Loose file processing complete for " + <>8__1.folderPath + ". Success: " + <successCount>5__4 + ", Failed: " + <failCount>5__5));
					}
					return false;
				}
				catch
				{
					//try-fault
					((IDisposable)this).Dispose();
					throw;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			private void <>m__Finally1()
			{
				<>1__state = -1;
				((IDisposable)<>s__6).Dispose();
			}

			private void <>m__Finally2()
			{
				<>1__state = -3;
				if (<www>5__11 != null)
				{
					((IDisposable)<www>5__11).Dispose();
				}
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		private static AudioMaster _instance;

		private Transform? _targetTransform = null;

		private Character? _targetCharacter = null;

		private bool _isFollowing;

		public static List<AudioClip> LoadedAudioClips { get; private set; } = new List<AudioClip>();


		private static List<MixtapeInfo> AvailableMixtapes { get; set; } = new List<MixtapeInfo>();


		public static AudioSource PersistentAudioSource { get; private set; } = null;


		private static AudioSource EffectsAudioSource { get; set; } = null;


		public static AudioSource YoutubeAudioSource { get; private set; } = null;


		public static bool IsInitialized { get; private set; }

		private static bool IsLoading { get; set; }

		public static bool IsYoutubeMode { get; private set; }

		public static Dictionary<string, int> SongHashToIndex { get; private set; } = new Dictionary<string, int>();


		public static Dictionary<int, string> IndexToSongHash { get; private set; } = new Dictionary<int, string>();


		public static PlaybackState CurrentPlaybackState { get; private set; } = PlaybackState.Stopped;


		public static int CurrentSongIndex { get; private set; }

		public static float CurrentPausedTime { get; private set; }

		public static AudioMaster Instance
		{
			get
			{
				//IL_0030: Unknown result type (might be due to invalid IL or missing references)
				//IL_0036: Expected O, but got Unknown
				if ((Object)(object)_instance == (Object)null)
				{
					_instance = Object.FindAnyObjectByType<AudioMaster>();
					if ((Object)(object)_instance == (Object)null)
					{
						GameObject val = new GameObject("PersistentSpeakerAudioLoader");
						_instance = val.AddComponent<AudioMaster>();
						Object.DontDestroyOnLoad((Object)(object)val);
						if (Plugin.DebugMode)
						{
							Plugin.Log.LogInfo((object)"[sPEAKer:AudioMaster] Created new instance and marked as DontDestroyOnLoad.");
						}
					}
				}
				return _instance;
			}
		}

		public static void EnsureInitialized()
		{
			if (Plugin.DebugMode)
			{
				Plugin.Log.LogInfo((object)"[sPEAKer:AudioMaster] EnsureInitialized called.");
			}
			AudioMaster instance = Instance;
			if (!IsInitialized && !IsLoading)
			{
				if (Plugin.DebugMode)
				{
					Plugin.Log.LogInfo((object)"[sPEAKer:AudioMaster] Not initialized, starting initialization...");
				}
				((MonoBehaviour)instance).StartCoroutine(instance.InitializeAsync());
			}
		}

		private void Awake()
		{
			if (Plugin.DebugMode)
			{
				Plugin.Log.LogInfo((object)"[sPEAKer:AudioMaster] Awake called.");
			}
			if ((Object)(object)_instance != (Object)null && (Object)(object)_instance != (Object)(object)this)
			{
				if (Plugin.DebugMode)
				{
					Plugin.Log.LogInfo((object)"[sPEAKer:AudioMaster] Duplicate instance detected, destroying.");
				}
				Object.Destroy((Object)(object)((Component)this).gameObject);
				return;
			}
			_instance = this;
			Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject);
			if (Plugin.DebugMode)
			{
				Plugin.Log.LogInfo((object)"[sPEAKer:AudioMaster] Instance set and marked as DontDestroyOnLoad.");
			}
			InitializeAudioSources();
			SceneManager.sceneLoaded += OnSceneLoaded;
			if (!IsInitialized && !IsLoading)
			{
				((MonoBehaviour)this).StartCoroutine(InitializeAsync());
			}
		}

		private void InitializeAudioSources()
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Expected O, but got Unknown
			AnimationCurve val = new AnimationCurve();
			val.AddKey(0f, 1f);
			val.AddKey(0.1f, 0.9f);
			val.AddKey(0.3f, 0.6f);
			val.AddKey(0.6f, 0.3f);
			val.AddKey(1f, 0.05f);
			if ((Object)(object)PersistentAudioSource == (Object)null)
			{
				PersistentAudioSource = ((Component)this).gameObject.AddComponent<AudioSource>();
				PersistentAudioSource.loop = false;
				PersistentAudioSource.playOnAwake = false;
				PersistentAudioSource.volume = 0.35f;
				PersistentAudioSource.minDistance = 2f;
				PersistentAudioSource.maxDistance = 25f;
				PersistentAudioSource.spatialBlend = 1f;
				PersistentAudioSource.dopplerLevel = 0.1f;
				PersistentAudioSource.spatialize = true;
				PersistentAudioSource.rolloffMode = (AudioRolloffMode)2;
				PersistentAudioSource.SetCustomCurve((AudioSourceCurveType)0, val);
				if (Plugin.DebugMode)
				{
					Plugin.Log.LogInfo((object)"[sPEAKer:AudioMaster] Created persistent audio source.");
				}
			}
			if ((Object)(object)EffectsAudioSource == (Object)null)
			{
				EffectsAudioSource = ((Component)this).gameObject.AddComponent<AudioSource>();
				EffectsAudioSource.playOnAwake = false;
				EffectsAudioSource.loop = false;
				EffectsAudioSource.spatialBlend = 1f;
				EffectsAudioSource.volume = 1f;
				EffectsAudioSource.minDistance = 2f;
				EffectsAudioSource.maxDistance = 25f;
				EffectsAudioSource.rolloffMode = (AudioRolloffMode)0;
				if (Plugin.DebugMode)
				{
					Plugin.Log.LogInfo((object)"[sPEAKer:AudioMaster] Created effects audio source.");
				}
			}
			if ((Object)(object)YoutubeAudioSource == (Object)null)
			{
				YoutubeAudioSource = ((Component)this).gameObject.AddComponent<AudioSource>();
				YoutubeAudioSource.playOnAwake = false;
				YoutubeAudioSource.loop = false;
				YoutubeAudioSource.spatialBlend = 1f;
				YoutubeAudioSource.volume = 0.35f;
				YoutubeAudioSource.minDistance = 2f;
				YoutubeAudioSource.maxDistance = 25f;
				YoutubeAudioSource.dopplerLevel = 0.1f;
				YoutubeAudioSource.spatialize = true;
				YoutubeAudioSource.rolloffMode = (AudioRolloffMode)2;
				YoutubeAudioSource.SetCustomCurve((AudioSourceCurveType)0, val);
				if (Plugin.DebugMode)
				{
					Plugin.Log.LogInfo((object)"[sPEAKer:AudioMaster] Created YouTube audio source.");
				}
			}
		}

		[IteratorStateMachine(typeof(<InitializeAsync>d__61))]
		private IEnumerator InitializeAsync()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <InitializeAsync>d__61(0)
			{
				<>4__this = this
			};
		}

		[IteratorStateMachine(typeof(<LoadBundleAudio>d__62))]
		private IEnumerator LoadBundleAudio()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <LoadBundleAudio>d__62(0)
			{
				<>4__this = this
			};
		}

		[IteratorStateMachine(typeof(<LoadFolderAudio>d__63))]
		private IEnumerator LoadFolderAudio()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <LoadFolderAudio>d__63(0)
			{
				<>4__this = this
			};
		}

		[IteratorStateMachine(typeof(<ProcessAudioFolder>d__64))]
		private IEnumerator ProcessAudioFolder(string folderPath)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <ProcessAudioFolder>d__64(0)
			{
				<>4__this = this,
				folderPath = folderPath
			};
		}

		[IteratorStateMachine(typeof(<LoadAudioClipsFromMixtapes>d__65))]
		private IEnumerator LoadAudioClipsFromMixtapes(string basePath)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <LoadAudioClipsFromMixtapes>d__65(0)
			{
				<>4__this = this,
				basePath = basePath
			};
		}

		[IteratorStateMachine(typeof(<LoadMixtape>d__66))]
		private IEnumerator LoadMixtape(string mixtapePath)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <LoadMixtape>d__66(0)
			{
				<>4__this = this,
				mixtapePath = mixtapePath
			};
		}

		public void LoadAudioClipsFromBundle()
		{
			//IL_02f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f8: Invalid comparison between Unknown and I4
			//IL_0318: Unknown result type (might be due to invalid IL or missing references)
			//IL_031e: Invalid comparison between Unknown and I4
			if (Plugin.DebugMode)
			{
				Plugin.Log.LogInfo((object)"[sPEAKer:AudioMaster] Starting bundle audio loading...");
			}
			string[] allAssetNames = Plugin.Bundle.GetAllAssetNames();
			if (Plugin.DebugMode)
			{
				Plugin.Log.LogInfo((object)("[sPEAKer:AudioMaster] Total assets in bundle: " + allAssetNames.Length));
				Plugin.Log.LogInfo((object)"--- All Assets in Bundle ---");
				string[] array = allAssetNames;
				foreach (string text in array)
				{
					Plugin.Log.LogInfo((object)("  -> " + text));
				}
				Plugin.Log.LogInfo((object)"----------------------------");
			}
			string[] array2 = allAssetNames.Where((string asset) => asset.Contains("jbl_fx") && asset.EndsWith(".ogg")).ToArray();
			if (Plugin.DebugMode)
			{
				Plugin.Log.LogInfo((object)$"[sPEAKer:AudioMaster] Found {array2.Length} JBL_FX assets:");
				string[] array3 = array2;
				foreach (string text2 in array3)
				{
					Plugin.Log.LogInfo((object)("  -> " + text2));
				}
			}
			string[] array4 = array2;
			foreach (string text3 in array4)
			{
				AudioClip clip2 = Plugin.Bundle.LoadAsset<AudioClip>(text3);
				string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(text3);
				SoundEffects.SetClip(fileNameWithoutExtension, clip2);
			}
			string text4 = allAssetNames.FirstOrDefault((string asset) => asset.Contains("whitenoise"));
			if (Plugin.DebugMode)
			{
				Plugin.Log.LogInfo((object)("[sPEAKer:AudioMaster] Found whitenoise asset: " + (text4 ?? "NULL")));
			}
			AudioClip clip3 = Plugin.Bundle.LoadAsset<AudioClip>(text4);
			SoundEffects.SetClip("whitenoise", clip3);
			string[] array5 = allAssetNames.Where((string asset) => asset.Contains("speaker audio") && asset.EndsWith(".ogg")).ToArray();
			if (Plugin.DebugMode)
			{
				Plugin.Log.LogInfo((object)("[sPEAKer:AudioMaster] Found " + array5.Length + " demo songs in bundle."));
				string[] array6 = array5;
				foreach (string text5 in array6)
				{
					Plugin.Log.LogInfo((object)("  -> " + text5));
				}
			}
			int num = 0;
			int num2 = 0;
			string[] array7 = array5;
			foreach (string text6 in array7)
			{
				if (Plugin.DebugMode)
				{
					Plugin.Log.LogInfo((object)("[sPEAKer:AudioMaster] Loading bundle audio: " + text6));
				}
				try
				{
					AudioClip clip = Plugin.Bundle.LoadAsset<AudioClip>(text6);
					if ((Object)(object)clip != (Object)null)
					{
						if ((int)clip.loadState == 2)
						{
							goto IL_0354;
						}
						clip.LoadAudioData();
						if ((int)clip.loadState != 3)
						{
							goto IL_0354;
						}
						Plugin.Log.LogError((object)("[sPEAKer:AudioMaster] Failed to preload audio data for bundle clip: " + ((Object)clip).name));
						num2++;
					}
					else
					{
						Plugin.Log.LogError((object)("[sPEAKer:AudioMaster] Failed to load audio clip from bundle: " + text6));
						num2++;
					}
					goto end_IL_02b9;
					IL_0354:
					if (!LoadedAudioClips.Any((AudioClip c) => ((Object)c).name == ((Object)clip).name))
					{
						LoadedAudioClips.Add(clip);
						string text7 = GenerateAudioHash(clip);
						int num3 = LoadedAudioClips.Count - 1;
						SongHashToIndex[text7] = num3;
						IndexToSongHash[num3] = text7;
						if (Plugin.DebugMode)
						{
							Plugin.Log.LogInfo((object)("[sPEAKer:AudioMaster] Successfully loaded bundle audio: " + ((Object)clip).name + " (Length: " + clip.length + "s)"));
						}
						num++;
					}
					else if (Plugin.DebugMode)
					{
						Plugin.Log.LogWarning((object)("[sPEAKer:AudioMaster] Audio clip already loaded: " + ((Object)clip).name));
					}
					end_IL_02b9:;
				}
				catch (Exception ex)
				{
					Plugin.Log.LogError((object)("[sPEAKer:AudioMaster] Exception loading " + text6 + ": " + ex.Message));
					num2++;
				}
			}
			if (Plugin.DebugMode)
			{
				Plugin.Log.LogInfo((object)("[sPEAKer:AudioMaster] Bundle loading complete. Success: " + num + ", Failed: " + num2 + ", Total clips now: " + LoadedAudioClips.Count));
			}
			if (LoadedAudioClips.Count > 0 && Plugin.DebugMode)
			{
				Plugin.Log.LogInfo((object)"[sPEAKer:AudioMaster] All loaded clips:");
				for (int n = 0; n < LoadedAudioClips.Count; n++)
				{
					Plugin.Log.LogInfo((object)("  [" + (n + 1) + "] " + ((Object)LoadedAudioClips[n]).name));
				}
			}
		}

		public static void UpdatePlaybackState(PlaybackState newState, int songIndex = -1, float pausedTime = 0f)
		{
			CurrentPlaybackState = newState;
			if (songIndex >= 0)
			{
				CurrentSongIndex = songIndex;
			}
			CurrentPausedTime = pausedTime;
			if (Plugin.DebugMode)
			{
				Plugin.Log.LogInfo((object)$"[sPEAKer:AudioMaster] Playback state updated - State: {newState}, Song: {CurrentSongIndex}, PausedTime: {pausedTime}");
			}
		}

		public static void ResetPlaybackState()
		{
			CurrentPlaybackState = PlaybackState.Stopped;
			CurrentSongIndex = 0;
			CurrentPausedTime = 0f;
			if (Plugin.DebugMode)
			{
				Plugin.Log.LogInfo((object)"[sPEAKer:AudioMaster] Playback state reset to defaults");
			}
		}

		private string FormatDuration(float totalSeconds)
		{
			int num = Mathf.FloorToInt(totalSeconds / 60f);
			int num2 = Mathf.FloorToInt(totalSeconds % 60f);
			return $"{num}:{num2:00}";
		}

		private string GenerateAudioHash(AudioClip clip)
		{
			string s = ((Object)clip).name + "|" + clip.length + "|" + clip.frequency;
			using MD5 mD = MD5.Create();
			byte[] inArray = mD.ComputeHash(Encoding.UTF8.GetBytes(s));
			return Convert.ToBase64String(inArray).Substring(0, 12);
		}

		public static MixtapeInfo GetMixtapeForSongIndex(int songIndex)
		{
			return AvailableMixtapes.FirstOrDefault((MixtapeInfo m) => m.ContainsSongIndex(songIndex)) ?? throw new InvalidOperationException();
		}

		private AudioType GetAudioTypeFromExtension(string filePath)
		{
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			return (AudioType)(Path.GetExtension(filePath).ToLowerInvariant() switch
			{
				".mp3" => 13, 
				".wav" => 20, 
				".ogg" => 14, 
				_ => 0, 
			});
		}

		public static void PlayFX(AudioClip clip)
		{
			if (!((Object)(object)EffectsAudioSource == (Object)null) && !((Object)(object)clip == (Object)null))
			{
				EffectsAudioSource.clip = clip;
				EffectsAudioSource.Play();
				if (Plugin.DebugMode)
				{
					Plugin.Log.LogInfo((object)("[sPEAKer:AudioMaster] Playing sound effect: " + ((Object)clip).name));
				}
			}
		}

		public void SetVolume(float newVolume)
		{
			if ((Object)(object)PersistentAudioSource != (Object)null)
			{
				PersistentAudioSource.volume = Mathf.Clamp(newVolume, 0f, 1f);
				if (Plugin.DebugMode)
				{
					Plugin.Log.LogInfo((object)("[sPEAKer:AudioMaster] Volume set to " + PersistentAudioSource.volume));
				}
			}
		}

		public void SetFollow(Transform? target)
		{
			_targetTransform = target;
			_targetCharacter = null;
			_isFollowing = (Object)(object)target != (Object)null;
			if (Plugin.DebugMode)
			{
				if (_isFollowing)
				{
					Plugin.Log.LogInfo((object)("[sPEAKer:AudioMaster] Set to follow transform: " + ((Object)target).name));
				}
				else
				{
					Plugin.Log.LogInfo((object)"[sPEAKer:AudioMaster] Stopped following.");
				}
			}
		}

		public void SetFollow(Character? target)
		{
			_targetCharacter = target;
			_targetTransform = null;
			_isFollowing = (Object)(object)target != (Object)null;
			if (Plugin.DebugMode)
			{
				if (_isFollowing)
				{
					Plugin.Log.LogInfo((object)("[sPEAKer:AudioMaster] Set to follow character: " + ((target != null) ? ((Object)target).name : null)));
				}
				else
				{
					Plugin.Log.LogInfo((object)"[sPEAKer:AudioMaster] Stopped following.");
				}
			}
		}

		public static void SetYoutubeMode(bool enabled)
		{
			IsYoutubeMode = enabled;
			if (Plugin.DebugMode)
			{
				Plugin.Log.LogInfo((object)$"[sPEAKer:AudioMaster] YouTube mode set to {enabled}");
			}
		}

		public static void PauseLocalAudio()
		{
			if ((Object)(object)PersistentAudioSource != (Object)null && PersistentAudioSource.isPlaying)
			{
				PersistentAudioSource.Pause();
				if (Plugin.DebugMode)
				{
					Plugin.Log.LogInfo((object)"[sPEAKer:AudioMaster] Local audio paused for YouTube mode");
				}
			}
		}

		public static void ResumeLocalAudio()
		{
			if ((Object)(object)PersistentAudioSource != (Object)null && (Object)(object)PersistentAudioSource.clip != (Object)null)
			{
				PersistentAudioSource.UnPause();
				if (Plugin.DebugMode)
				{
					Plugin.Log.LogInfo((object)"[sPEAKer:AudioMaster] Local audio resumed from YouTube mode");
				}
			}
		}

		public bool IsSpeakerActive()
		{
			if (_isFollowing && (Object)(object)_targetCharacter != (Object)null)
			{
				return true;
			}
			return false;
		}

		private void LateUpdate()
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: 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_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			if (_isFollowing)
			{
				Vector3 val = Vector3.zero;
				if ((Object)(object)_targetTransform != (Object)null)
				{
					val = _targetTransform.position;
				}
				else if ((Object)(object)_targetCharacter != (Object)null)
				{
					val = _targetCharacter.Center;
				}
				if ((Object)(object)PersistentAudioSource != (Object)null && ((Component)PersistentAudioSource).transform.position != val)
				{
					((Component)PersistentAudioSource).transform.position = val;
				}
				if ((Object)(object)EffectsAudioSource != (Object)null && ((Component)EffectsAudioSource).transform.position != val)
				{
					((Component)EffectsAudioSource).transform.position = val;
				}
				if ((Object)(object)YoutubeAudioSource != (Object)null && ((Component)YoutubeAudioSource).transform.position != val)
				{
					((Component)YoutubeAudioSource).transform.position = val;
				}
			}
		}

		private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
		{
			if (((Scene)(ref scene)).name == "Airport")
			{
				if ((Object)(object)PersistentAudioSource != (Object)null && PersistentAudioSource.isPlaying)
				{
					PersistentAudioSource.Stop();
				}
				if (Plugin.DebugMode)
				{
					Plugin.Log.LogInfo((object)"[sPEAKer:AudioMaster] Airport scene detected - stopped audio playback");
				}
			}
		}

		private void OnDestroy()
		{
			if (Plugin.DebugMode)
			{
				Plugin.Log.LogInfo((object)"[sPEAKer:AudioMaster] OnDestroy called.");
			}
			SceneManager.sceneLoaded -= OnSceneLoaded;
			if ((Object)(object)_instance == (Object)(object)this)
			{
				IsInitialized = false;
				IsLoading = false;
			}
		}
	}
	[Serializable]
	public class MixtapeMetadata
	{
		public string name;

		public string author;
	}
	public class MixtapeInfo
	{
		public string Name;

		public string Author;

		public string TotalLength;

		public int FirstSongIndex;

		public int LastSongIndex;

		public int SongCount;

		public string Path;

		public bool ContainsSongIndex(int index)
		{
			return index >= FirstSongIndex && index <= LastSongIndex;
		}
	}
	public enum PlaybackState
	{
		Stopped,
		Playing,
		Paused
	}
	public static class SoundEffects
	{
		public static AudioClip Connected { get; private set; }

		public static AudioClip Connecting { get; private set; }

		public static AudioClip Party { get; private set; }

		public static AudioClip TurnOn { get; private set; }

		public static AudioClip VolMax { get; private set; }

		public static AudioClip WhiteNoise { get; private set; }

		public static void SetClip(string filename, AudioClip clip)
		{
			switch (filename.ToLower().Replace(" ", ""))
			{
			case "connected":
				Connected = clip;
				break;
			case "connecting":
				Connecting = clip;
				break;
			case "party":
				Party = clip;
				break;
			case "turnon":
				TurnOn = clip;
				break;
			case "volmax":
				VolMax = clip;
				break;
			case "whitenoise":
				WhiteNoise = clip;
				break;
			}
		}
	}
	public class Controller : MonoBehaviourPun
	{
		[CompilerGenerated]
		private sealed class <DelayedUIUpdate>d__46 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public Controller <>4__this;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <DelayedUIUpdate>d__46(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<>2__current = null;
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					<>4__this._playbackState = AudioMaster.CurrentPlaybackState;
					<>4__this._currentSongIndex = AudioMaster.CurrentSongIndex;
					<>4__this._pausedTime = AudioMaster.CurrentPausedTime;
					<>4__this._isTurnedOn = <>4__this._playbackState != PlaybackState.Stopped;
					if (<>4__this._playbackState == PlaybackState.Playing)
					{
						<>4__this.item.UIData.mainInteractPrompt = "PAUSE";
					}
					else if (<>4__this._playbackState == PlaybackState.Paused)
					{
						<>4__this.item.UIData.mainInteractPrompt = "PLAY";
					}
					else
					{
						<>4__this.item.UIData.mainInteractPrompt = "TURN ON";
					}
					if (Plugin.DebugMode)
					{
						Plugin.Log.LogInfo((object)$"[sPEAKer:Controller] Delayed UI update - Final state: {<>4__this._playbackState}, Prompt: {<>4__this.item.UIData.mainInteractPrompt}");
					}
					return false;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		[CompilerGenerated]
		private sealed class <InitializeWhenReady>d__17 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public Controller <>4__this;

			private int <waitCount>5__1;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <InitializeWhenReady>d__17(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_0049: Unknown result type (might be due to invalid IL or missing references)
				//IL_0053: Expected O, but got Unknown
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					if (Plugin.DebugMode)
					{
						Plugin.Log.LogInfo((object)"[sPEAKer:Controller] Waiting for AudioMaster to initialize...");
					}
					<waitCount>5__1 = 0;
					break;
				case 1:
					<>1__state = -1;
					<waitCount>5__1++;
					break;
				}
				if (!AudioMaster.IsInitialized && <waitCount>5__1 < 50)
				{
					<>2__current = (object)new WaitForSeconds(0.1f);
					<>1__state = 1;
					return true;
				}
				if (!AudioMaster.IsInitialized)
				{
					Plugin.Log.LogError((object)"[sPEAKer:Controller] AudioMaster failed to initialize after 5 seconds!");
					return false;
				}
				Item item = <>4__this.item;
				item.OnScrolled = (Action<float>)Delegate.Combine(item.OnScrolled, new Action<float>(<>4__this.HandleScroll));
				<>4__this._currentAudioClips = AudioMaster.LoadedAudioClips.ToArray();
				if (Plugin.DebugMode)
				{
					Plugin.Log.LogInfo((object)("[sPEAKer:Controller] Loaded " + <>4__this._currentAudioClips.Length + " audio clips"));
				}
				AudioMaster.Instance.SetFollow(((Component)<>4__this).transform);
				<>4__this.SyncWithPersistentAudio();
				<>4__this._isInitialized = true;
				return false;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		[CompilerGenerated]
		private sealed class <MonitorPlayback>d__27 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public Controller <>4__this;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <MonitorPlayback>d__27(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_0067: Unknown result type (might be due to invalid IL or missing references)
				//IL_0071: Expected O, but got Unknown
				//IL_00af: Unknown result type (might be due to invalid IL or missing references)
				//IL_00b9: Expected O, but got Unknown
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					if (Plugin.DebugMode)
					{
						Plugin.Log.LogInfo((object)"[sPEAKer:Controller] OWNER: Playback monitor started.");
					}
					<>2__current = (object)new WaitUntil((Func<bool>)(() => (Object)(object)AudioMaster.PersistentAudioSource != (Object)null && AudioMaster.PersistentAudioSource.isPlaying));
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					break;
				case 2:
					<>1__state = -1;
					break;
				}
				if (<>4__this._playbackState == PlaybackState.Playing && AudioMaster.PersistentAudioSource.isPlaying)
				{
					if (AudioMaster.IsYoutubeMode)
					{
						if (Plugin.DebugMode)
						{
							Plugin.Log.LogInfo((object)"[sPEAKer:Controller] OWNER: Playback monitor ended - YouTube mode active.");
						}
						return false;
					}
					<>2__current = (object)new WaitForSeconds(0.5f);
					<>1__state = 2;
					return true;
				}
				if (<>4__this._playbackState == PlaybackState.Playing && !AudioMaster.IsYoutubeMode)
				{
					if (Plugin.DebugMode)
					{
						Plugin.Log.LogInfo((object)"[sPEAKer:Controller] OWNER: Song finished. Automatically playing next track.");
					}
					<>4__this.NextSong();
				}
				if (Plugin.DebugMode)
				{
					Plugin.Log.LogInfo((object)"[sPEAKer:Controller] OWNER: Playback monitor ended.");
				}
				return false;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		[CompilerGenerated]
		private sealed class <TurnOnSequence>d__22 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public Controller <>4__this;

			private float <waitTime>5__1;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <TurnOnSequence>d__22(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_0090: Unknown result type (might be due to invalid IL or missing references)
				//IL_009a: Expected O, but got Unknown
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<>4__this._isTurningOn = true;
					<>4__this.item.UIData.mainInteractPrompt = "...";
					((MonoBehaviourPun)<>4__this).photonView.RPC("RPC_PlayTurnOn", (RpcTarget)0, Array.Empty<object>());
					<waitTime>5__1 = (((Object)(object)SoundEffects.TurnOn != (Object)null) ? SoundEffects.TurnOn.length : 0.5f);
					<>2__current = (object)new WaitForSeconds(<waitTime>5__1);
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					<>4__this._isTurnedOn = true;
					<>4__this._isTurningOn = false;
					<>4__this._playbackState = PlaybackState.Paused;
					<>4__this.item.UIData.mainInteractPrompt = "PLAY";
					return false;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		public Item item;

		private bool _isInitialized;

		private bool _isTurningOn;

		private bool _isTurnedOn;

		private bool _wasUsingPrimary;

		private bool _wasUsingSecondary;

		private int _currentSongIndex;

		private float _pausedTime;

		private PlaybackState _playbackState = PlaybackState.Stopped;

		private AudioClip[] _currentAudioClips;

		private Coroutine _monitorCoroutine;

		private const float VolumeStep = 0.05f;

		private bool _wasPocketed;

		private bool _isFollowingCharacter;

		private Character? _pocketedByCharacter;

		private int _followTargetPhotonViewID = -1;

		private void Start()
		{
			if (Plugin.DebugMode)
			{
				Plugin.Log.LogInfo((object)("[sPEAKer:Controller] Start called for " + ((Object)((Component)this).gameObject).name));
			}
			item = ((Component)this).GetComponent<Item>();
			if ((Object)(object)item == (Object)null)
			{
				Plugin.Log.LogError((object)("[sPEAKer:Controller] No Item component found on " + ((Object)((Component)this).gameObject).name));
				return;
			}
			AudioMaster.EnsureInitialized();
			((MonoBehaviour)this).StartCoroutine(InitializeWhenReady());
		}

		[IteratorStateMachine(typeof(<InitializeWhenReady>d__17))]
		private IEnumerator InitializeWhenReady()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <InitializeWhenReady>d__17(0)
			{
				<>4__this = this
			};
		}

		private void Update()
		{
			if (_isInitialized)
			{
				bool isUsingPrimary = item.isUsingPrimary;
				if (isUsingPrimary && !_wasUsingPrimary)
				{
					PrimaryUse();
				}
				_wasUsingPrimary = isUsingPrimary;
				bool isUsingSecondary = item.isUsingSecondary;
				if (isUsingSecondary && !_wasUsingSecondary)
				{
					SecondaryUse();
				}
				_wasUsingSecondary = isUsingSecondary;
			}
		}

		private void PrimaryUse()
		{
			if (_isTurningOn)
			{
				return;
			}
			if (AudioMaster.IsYoutubeMode)
			{
			}
			if (Plugin.DebugMode)
			{
				Plugin.Log.LogInfo((object)$"[sPEAKer:Controller] Primary pressed. Current state: {_playbackState}");
			}
			switch (_playbackState)
			{
			case PlaybackState.Stopped:
				if (!_isTurnedOn)
				{
					((MonoBehaviour)this).StartCoroutine(TurnOnSequence());
					break;
				}
				item.UIData.mainInteractPrompt = "PAUSE";
				StartPlayback();
				break;
			case PlaybackState.Playing:
				item.UIData.mainInteractPrompt = "PLAY";
				PausePlayback();
				break;
			case PlaybackState.Paused:
				item.UIData.mainInteractPrompt = "PAUSE";
				ResumePlayback();
				break;
			}
		}

		private void SecondaryUse()
		{
			if (!_isTurningOn)
			{
				NextSong();
			}
		}

		private void HandleScroll(float scrollAmount)
		{
			if (!((Object)(object)AudioMaster.PersistentAudioSource == (Object)null) && ((MonoBehaviourPun)this).photonView.IsMine)
			{
				float volume = AudioMaster.PersistentAudioSource.volume;
				float num = volume;
				if (scrollAmount > 0f)
				{
					num += 0.05f;
				}
				else if (scrollAmount < 0f)
				{
					num -= 0.05f;
				}
				num = Mathf.Clamp(num, 0f, 1f);
				Netcode.Instance.SendVolumeChange(((MonoBehaviourPun)this).photonView, num);
			}
		}

		[IteratorStateMachine(typeof(<TurnOnSequence>d__22))]
		private IEnumerator TurnOnSequence()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <TurnOnSequence>d__22(0)
			{
				<>4__this = this
			};
		}

		private void StartPlayback()
		{
			if (_currentAudioClips == null || _currentAudioClips.Length == 0 || (Object)(object)AudioMaster.PersistentAudioSource == (Object)null)
			{
				Plugin.Log.LogWarning((object)"[sPEAKer:Controller] Cannot start playback: no audio clips available");
				return;
			}
			if (Plugin.DebugMode)
			{
				Plugin.Log.LogInfo((object)"[sPEAKer:Controller] Starting playback...");
			}
			Netcode.Instance.SendStartPlayback(((MonoBehaviourPun)this).photonView, _currentSongIndex);
		}

		private void PausePlayback()
		{
			if (_playbackState == PlaybackState.Playing)
			{
				float num = (((Object)(object)AudioMaster.PersistentAudioSource != (Object)null) ? AudioMaster.PersistentAudioSource.time : 0f);
				if (Plugin.DebugMode)
				{
					Plugin.Log.LogInfo((object)$"[sPEAKer:Controller] Pausing at {num}s");
				}
				Netcode.Instance.SendPausePlayback(((MonoBehaviourPun)this).photonView, num);
			}
		}

		private void ResumePlayback()
		{
			if (_playbackState == PlaybackState.Paused)
			{
				if (Plugin.DebugMode)
				{
					Plugin.Log.LogInfo((object)$"[sPEAKer:Controller] Resuming from {_pausedTime}s");
				}
				Netcode.Instance.SendResumePlayback(((MonoBehaviourPun)this).photonView, _pausedTime);
			}
		}

		private void NextSong()
		{
			if (PhotonNetwork.IsMasterClient)
			{
				AudioClip[] currentAudioClips = _currentAudioClips;
				if (currentAudioClips == null || currentAudioClips.Length <= 1)
				{
					if (Plugin.DebugMode)
					{
						Plugin.Log.LogInfo((object)"[sPEAKer:Controller] Not enough songs to switch");
					}
					return;
				}
				_currentSongIndex = (_currentSongIndex + 1) % _currentAudioClips.Length;
				if (Plugin.DebugMode)
				{
					Plugin.Log.LogInfo((object)("[sPEAKer:Controller] Switching to song " + (_currentSongIndex + 1)));
				}
				string text = AudioMaster.IndexToSongHash[_currentSongIndex];
				string name = ((Object)_currentAudioClips[_currentSongIndex]).name;
				((MonoBehaviourPun)this).photonView.RPC("RPC_NextSong", (RpcTarget)0, new object[2] { text, name });
			}
			else
			{
				((MonoBehaviourPun)this).photonView.RPC("RPC_RequestNextSong", PhotonNetwork.MasterClient, Array.Empty<object>());
			}
		}

		[IteratorStateMachine(typeof(<MonitorPlayback>d__27))]
		private IEnumerator MonitorPlayback()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <MonitorPlayback>d__27(0)
			{
				<>4__this = this
			};
		}

		private void PlayCurrentSound()
		{
			if (_currentSongIndex < 0 || _currentSongIndex >= _currentAudioClips.Length)
			{
				Plugin.Log.LogError((object)("[sPEAKer:Controller] Invalid sound index: " + _currentSongIndex));
				return;
			}
			if ((Object)(object)AudioMaster.PersistentAudioSource == (Object)null)
			{
				Plugin.Log.LogError((object)"[sPEAKer:Controller] Persistent audio source is null!");
				return;
			}
			AudioClip val = _currentAudioClips[_currentSongIndex];
			if ((Object)(object)val == (Object)null)
			{
				Plugin.Log.LogError((object)("[sPEAKer:Controller] Clip at index " + _currentSongIndex + " is null!"));
				return;
			}
			AudioMaster.PersistentAudioSource.clip = val;
			AudioMaster.PersistentAudioSource.Play();
			if (Plugin.DebugMode)
			{
				Plugin.Log.LogInfo((object)("[sPEAKer:Controller] Playing sound " + (_currentSongIndex + 1) + ": " + ((Object)val).name));
			}
			MixtapeInfo mixtapeForSongIndex = AudioMaster.GetMixtapeForSongIndex(_currentSongIndex);
			if (mixtapeForSongIndex != null)
			{
				sPEAKerUI.Instance.ShowTrackName(mixtapeForSongIndex.Name + " - " + ((Object)val).name);
			}
			else
			{
				sPEAKerUI.Instance.ShowTrackName(((Object)val).name);
			}
		}

		private void HandleNetworkStartPlayback(string songHash, string songName)
		{
			if (Plugin.DebugMode)
			{
				Plugin.Log.LogInfo((object)("[sPEAKer:Controller] CLIENT RECEIVED: HandleNetworkStartPlayback - songHash=" + songHash));
			}
			_playbackState = PlaybackState.Playing;
			_pausedTime = 0f;
			if (AudioMaster.SongHashToIndex.TryGetValue(songHash, out var value))
			{
				_currentSongIndex = value;
				PlayCurrentSound();
			}
			else
			{
				if (Plugin.DebugMode)
				{
					Plugin.Log.LogWarning((object)"[sPEAKer:Controller] Song not available locally, playing white noise");
				}
				AudioMaster.PersistentAudioSource.clip = SoundEffects.WhiteNoise;
				AudioMaster.PersistentAudioSource.Play();
				sPEAKerUI.Instance.ShowTrackName(songName);
			}
			AudioMaster.UpdatePlaybackState(PlaybackState.Playing, _currentSongIndex);
			if (((MonoBehaviourPun)this).photonView.IsMine && !AudioMaster.IsYoutubeMode)
			{
				if (_monitorCoroutine != null)
				{
					((MonoBehaviour)this).StopCoroutine(_monitorCoroutine);
				}
				_monitorCoroutine = ((MonoBehaviour)this).StartCoroutine(MonitorPlayback());
			}
		}

		private void HandleNetworkPausePlayback(float pauseTime)
		{
			if (Plugin.DebugMode)
			{
				Plugin.Log.LogInfo((object)$"[sPEAKer:Controller] HandleNetworkPausePlayback at {pauseTime}s");
			}
			_playbackState = PlaybackState.Paused;
			_pausedTime = pauseTime;
			AudioMaster.UpdatePlaybackState(PlaybackState.Paused, _currentSongIndex, pauseTime);
			if ((Object)(object)AudioMaster.PersistentAudioSource != (Object)null && AudioMaster.PersistentAudioSource.isPlaying)
			{
				AudioMaster.PersistentAudioSource.Pause();
			}
			if (((MonoBehaviourPun)this).photonView.IsMine && _monitorCoroutine != null)
			{
				((MonoBehaviour)this).StopCoroutine(_monitorCoroutine);
				_monitorCoroutine = null;
			}
		}

		private void HandleNetworkResumePlayback(float resumeTime)
		{
			if (Plugin.DebugMode)
			{
				Plugin.Log.LogInfo((object)$"[sPEAKer:Controller] HandleNetworkResumePlayback from {resumeTime}s");
			}
			_playbackState = PlaybackState.Playing;
			_pausedTime = resumeTime;
			AudioMaster.UpdatePlaybackState(PlaybackState.Playing, _currentSongIndex, resumeTime);
			if ((Object)(object)AudioMaster.PersistentAudioSource != (Object)null)
			{
				if ((Object)(object)AudioMaster.PersistentAudioSource.clip == (Object)null)
				{
					PlayCurrentSound();
				}
				AudioMaster.PersistentAudioSource.time = resumeTime;
				AudioMaster.PersistentAudioSource.UnPause();
			}
			if (((MonoBehaviourPun)this).photonView.IsMine && !AudioMaster.IsYoutubeMode)
			{
				if (_monitorCoroutine != null)
				{
					((MonoBehaviour)this).StopCoroutine(_monitorCoroutine);
				}
				_monitorCoroutine = ((MonoBehaviour)this).StartCoroutine(MonitorPlayback());
			}
		}

		private void HandleNetworkStopPlayback()
		{
			if (Plugin.DebugMode)
			{
				Plugin.Log.LogInfo((object)"[sPEAKer:Controller] HandleNetworkStopPlayback called");
			}
			_playbackState = PlaybackState.Stopped;
			_pausedTime = 0f;
			AudioMaster.UpdatePlaybackState(PlaybackState.Stopped, 0);
			if ((Object)(object)AudioMaster.PersistentAudioSource != (Object)null && AudioMaster.PersistentAudioSource.isPlaying)
			{
				AudioMaster.PersistentAudioSource.Stop();
				AudioMaster.PersistentAudioSource.clip = null;
			}
			if (((MonoBehaviourPun)this).photonView.IsMine && _monitorCoroutine != null)
			{
				((MonoBehaviour)this).StopCoroutine(_monitorCoroutine);
				_monitorCoroutine = null;
			}
		}

		private void HandleNetworkNextSong(string songHash, string songName)
		{
			if (Plugin.DebugMode)
			{
				Plugin.Log.LogInfo((object)("[sPEAKer:Controller] HandleNetworkNextSong called - songHash=" + songHash));
			}
			if (_playbackState != PlaybackState.Playing)
			{
				return;
			}
			if (AudioMaster.SongHashToIndex.TryGetValue(songHash, out var value))
			{
				_currentSongIndex = value;
				PlayCurrentSound();
			}
			else
			{
				if (Plugin.DebugMode)
				{
					Plugin.Log.LogWarning((object)"[sPEAKer:Controller] Song not available for next song, playing white noise");
				}
				AudioMaster.PersistentAudioSource.clip = SoundEffects.WhiteNoise;
				AudioMaster.PersistentAudioSource.Play();
				sPEAKerUI.Instance.ShowTrackName(songName);
			}
			AudioMaster.UpdatePlaybackState(PlaybackState.Playing, _currentSongIndex);
			if (((MonoBehaviourPun)this).photonView.IsMine)
			{
				if (_monitorCoroutine != null)
				{
					((MonoBehaviour)this).StopCoroutine(_monitorCoroutine);
				}
				_monitorCoroutine = ((MonoBehaviour)this).StartCoroutine(MonitorPlayback());
			}
		}

		private void HandleNetworkVolumeChange(float newVolume)
		{
			if (Plugin.DebugMode)
			{
				Plugin.Log.LogInfo((object)("[sPEAKer:Controller] HandleNetworkVolumeChange called with value " + newVolume));
			}
			AudioMaster.Instance.SetVolume(newVolume);
		}

		[PunRPC]
		private void RPC_StartPlayback(string songHash, string songName)
		{
			if (Plugin.DebugMode)
			{
				Plugin.Log.LogInfo((object)("[sPEAKer:Controller] RPC_StartPlayback called - hash=" + songHash + ", name=" + songName));
			}
			HandleNetworkStartPlayback(songHash, songName);
			Netcode.Instance.CachedPlaybackState = 1;
			Netcode.Instance.CachedSongHash = songHash;
			Netcode.Instance.CachedSongName = songName;
		}

		[PunRPC]
		private void RPC_PausePlayback(float pauseTime)
		{
			if (Plugin.DebugMode)
			{
				Plugin.Log.LogInfo((object)$"[sPEAKer:Controller] RPC_PausePlayback at {pauseTime}s");
			}
			HandleNetworkPausePlayback(pauseTime);
			Netcode.Instance.CachedPlaybackState = 2;
		}

		[PunRPC]
		private void RPC_ResumePlayback(float resumeTime)
		{
			if (Plugin.DebugMode)
			{
				Plugin.Log.LogInfo((object)$"[sPEAKer:Controller] RPC_ResumePlayback from {resumeTime}s");
			}
			HandleNetworkResumePlayback(resumeTime);
			Netcode.Instance.CachedPlaybackState = 1;
		}

		[PunRPC]
		private void RPC_StopPlayback()
		{
			if (Plugin.DebugMode)
			{
				Plugin.Log.LogInfo((object)"[sPEAKer:Controller] RPC_StopPlayback called");
			}
			HandleNetworkStopPlayback();
			Netcode.Instance.CachedPlaybackState = 0;
		}

		[PunRPC]
		private void RPC_NextSong(string songHash, string songName)
		{
			if (Plugin.DebugMode)
			{
				Plugin.Log.LogInfo((object)("[sPEAKer:Controller] RPC_NextSong called - hash=" + songHash + ", name=" + songName));
			}
			HandleNetworkNextSong(songHash, songName);
			Netcode.Instance.CachedSongHash = songHash;
			Netcode.Instance.CachedSongName = songName;
		}

		[PunRPC]
		private void RPC_RequestNextSong()
		{
			if (Plugin.DebugMode)
			{
				Plugin.Log.LogInfo((object)"[sPEAKer:Controller] RPC_RequestNextSong called");
			}
			if (PhotonNetwork.IsMasterClient)
			{
				SecondaryUse();
			}
		}

		[PunRPC]
		private void RPC_SetVolume(float newVolume)
		{
			if (Plugin.DebugMode)
			{
				Plugin.Log.LogInfo((object)$"[sPEAKer:Controller] RPC_SetVolume called with value {newVolume}");
			}
			HandleNetworkVolumeChange(newVolume);
		}

		[PunRPC]
		private void RPC_PlayTurnOn()
		{
			if (Plugin.DebugMode)
			{
				Plugin.Log.LogInfo((object)"[sPEAKer:Controller] RPC_PlayTurnOn called");
			}
			AudioMaster.PlayFX(SoundEffects.TurnOn);
		}

		private void OnDestroy()
		{
			if (Plugin.DebugMode)
			{
				Plugin.Log.LogInfo((object)"[sPEAKer:Controller] OnDestroy called");
			}
			if ((Object)(object)item != (Object)null)
			{
				Item obj = item;
				obj.OnScrolled = (Action<float>)Delegate.Remove(obj.OnScrolled, new Action<float>(HandleScroll));
			}
		}

		private void OnDisable()
		{
			if (Plugin.DebugMode)
			{
				Plugin.Log.LogInfo((object)"[sPEAKer:Controller] OnDisable called - Speaker being pocketed");
			}
			if (!((Object)(object)item == (Object)null) && !((Object)(object)item.lastHolderCharacter == (Object)null))
			{
				_wasPocketed = true;
				_pocketedByCharacter = item.lastHolderCharacter;
				AudioMaster.Instance.SetFollow(_pocketedByCharacter);
				_followTargetPhotonViewID = ((MonoBehaviourPun)_pocketedByCharacter).photonView.ViewID;
				_isFollowingCharacter = true;
				Netcode.Instance.CachedFollowViewID = _followTargetPhotonViewID;
				Netcode.Instance.CachedIsFollowingCharacter = _isFollowingCharacter;
			}
		}

		private void OnEnable()
		{
			if (Plugin.DebugMode)
			{
				Plugin.Log.LogInfo((object)$"[sPEAKer:Controller] OnEnable called - Speaker being unpocketed. {_wasPocketed} {(Object)(object)AudioMaster.Instance == (Object)null}");
			}
			Netcode.Instance.CachedFollowViewID = _followTargetPhotonViewID;
			Netcode.Instance.CachedIsFollowingCharacter = _isFollowingCharacter;
			((MonoBehaviour)this).StartCoroutine(DelayedUIUpdate());
		}

		[IteratorStateMachine(typeof(<DelayedUIUpdate>d__46))]
		private IEnumerator DelayedUIUpdate()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <DelayedUIUpdate>d__46(0)
			{
				<>4__this = this
			};
		}

		private void SyncWithPersistentAudio()
		{
			if ((Object)(object)AudioMaster.PersistentAudioSource == (Object)null || !AudioMaster.PersistentAudioSource.isPlaying)
			{
				if (Plugin.DebugMode)
				{
					Plugin.Log.LogInfo((object)"[sPEAKer:Controller] No active playback to sync with.");
				}
				return;
			}
			_playbackState = PlaybackState.Playing;
			_isTurnedOn = true;
			_currentSongIndex = AudioMaster.CurrentSongIndex;
			if (_currentSongIndex >= 0 && _currentSongIndex < _currentAudioClips.Length)
			{
				AudioClip clip = AudioMaster.PersistentAudioSource.clip;
				AudioClip val = _currentAudioClips[_currentSongIndex];
				if ((Object)(object)clip != (Object)null && (Object)(object)val != (Object)null && ((Object)clip).name == ((Object)val).name)
				{
					if (Plugin.DebugMode)
					{
						Plugin.Log.LogInfo((object)("[sPEAKer:Controller] Synced with existing playback - song " + (_currentSongIndex + 1) + ": " + ((Object)val).name));
					}
				}
				else if (Plugin.DebugMode)
				{
					Plugin.Log.LogInfo((object)"[sPEAKer:Controller] Song mismatch detected during sync - client might be playing white noise");
				}
			}
			else
			{
				if (Plugin.DebugMode)
				{
					Plugin.Log.LogWarning((object)("[sPEAKer:Controller] Invalid song index during sync: " + _currentSongIndex));
				}
				_currentSongIndex = 0;
			}
			if (((MonoBehaviourPun)this).photonView.IsMine)
			{
				if (_monitorCoroutine != null)
				{
					((MonoBehaviour)this).StopCoroutine(_monitorCoroutine);
				}
				_monitorCoroutine = ((MonoBehaviour)this).StartCoroutine(MonitorPlayback());
			}
		}

		public void LogAllComponents()
		{
			Plugin.Log.LogInfo((object)("[sPEAKer:Controller] Starting component discovery for " + ((Object)((Component)this).gameObject).name));
			LogComponentsRecursive(((Component)this).gameObject, 0);
		}

		private void LogComponentsRecursive(GameObject obj, int depth)
		{
			string text = new string(' ', depth * 2);
			Plugin.Log.LogInfo((object)("[sPEAKer:Controller] " + text + "GameObject: " + ((Object)obj).name));
			Component[] components = obj.GetComponents<Component>();
			Component[] array = components;
			foreach (Component val in array)
			{
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				string name = ((object)val).GetType().Name;
				if (name == "Controller" || name == "Netcode")
				{
					continue;
				}
				Plugin.Log.LogInfo((object)("[sPEAKer:Controller] " + text + "  Component: " + name));
				PhotonView val2 = (PhotonView)(object)((val is PhotonView) ? val : null);
				if (val2 != null)
				{
					ManualLogSource log = Plugin.Log;
					object[] obj2 = new object[4] { text, val2.ViewID, val2.IsMine, null };
					Player owner = val2.Owner;
					obj2[3] = ((owner != null) ? owner.NickName : null) ?? "null";
					log.LogInfo((object)string.Format("[sPEAKer:Controller] {0}    ViewID: {1}, IsMine: {2}, Owner: {3}", obj2));
				}
				Renderer val3 = (Renderer)(object)((val is Renderer) ? val : null);
				if (val3 != null)
				{
					Plugin.Log.LogInfo((object)$"[sPEAKer:Controller] {text}    Enabled: {val3.enabled}, Visible: {val3.isVisible}");
				}
				if (!(((object)val).GetType().Name == "Item"))
				{
					continue;
				}
				Type type = ((object)val).GetType();
				FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				PropertyInfo[] properties = type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				Plugin.Log.LogInfo((object)("[sPEAKer:Controller] " + text + "    Item Fields:"));
				FieldInfo[] array2 = fields;
				foreach (FieldInfo fieldInfo in array2)
				{
					try
					{
						object value = fieldInfo.GetValue(val);
						Plugin.Log.LogInfo((object)$"[sPEAKer:Controller] {text}      {fieldInfo.Name}: {value}");
					}
					catch
					{
						Plugin.Log.LogInfo((object)("[sPEAKer:Controller] " + text + "      " + fieldInfo.Name + ": <access error>"));
					}
				}
				Plugin.Log.LogInfo((object)("[sPEAKer:Controller] " + text + "    Item Properties:"));
				PropertyInfo[] array3 = properties;
				foreach (PropertyInfo propertyInfo in array3)
				{
					if (propertyInfo.CanRead)
					{
						try
						{
							object value2 = propertyInfo.GetValue(val);
							Plugin.Log.LogInfo((object)$"[sPEAKer:Controller] {text}      {propertyInfo.Name}: {value2}");
						}
						catch
						{
							Plugin.Log.LogInfo((object)("[sPEAKer:Controller] " + text + "      " + propertyInfo.Name + ": <access error>"));
						}
					}
				}
			}
			for (int l = 0; l < obj.transform.childCount; l++)
			{
				LogComponentsRecursive(((Component)obj.transform.GetChild(l)).gameObject, depth + 1);
			}
		}

		public void KillYourself()
		{
			PhotonNetwork.Destroy(((Component)this).gameObject);
		}
	}
	public class Netcode : MonoBehaviourPunCallbacks
	{
		[CompilerGenerated]
		private sealed class <DelayedSyncSend>d__35 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public int targetActorNumber;

			public Netcode <>4__this;

			private float <currentTime>5__1;

			private float <currentVolume>5__2;

			private NetworkSyncData <syncData>5__3;

			private Player <targetPlayer>5__4;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <DelayedSyncSend>d__35(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<syncData>5__3 = null;
				<targetPlayer>5__4 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_0026: Unknown result type (might be due to invalid IL or missing references)
				//IL_0030: Expected O, but got Unknown
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<>2__current = (object)new WaitForSeconds(2f);
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					<currentTime>5__1 = 0f;
					<currentVolume>5__2 = 0.35f;
					if ((Object)(object)AudioMaster.PersistentAudioSource != (Object)null)
					{
						<currentTime>5__1 = AudioMaster.PersistentAudioSource.time;
						<currentVolume>5__2 = AudioMaster.PersistentAudioSource.volume;
					}
					<syncData>5__3 = new NetworkSyncData
					{
						PlaybackStateInt = (int)AudioMaster.CurrentPlaybackState,
						SongHash = ((AudioMaster.CurrentPlaybackState != 0) ? AudioMaster.IndexToSongHash.GetValueOrDefault(AudioMaster.CurrentSongIndex, "") : ""),
						SongName = ((AudioMaster.CurrentPlaybackState != 0 && AudioMaster.CurrentSongIndex < AudioMaster.LoadedAudioClips.Count) ? ((Object)AudioMaster.LoadedAudioClips[AudioMaste