Decompiled source of BingBong BoomBox v1.2.0

BingBongBoomBox.dll

Decompiled a week ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
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.Web;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Photon.Pun;
using UnityEngine;
using UnityEngine.Networking;
using Zorro.Core;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("BingBongBoomBox")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+6492a568987d6ea8c0bdfd4a1ed7f8f6158487b0")]
[assembly: AssemblyProduct("BingBong BoomBox")]
[assembly: AssemblyTitle("BingBongBoomBox")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace BepInEx
{
	[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
	[Conditional("CodeGeneration")]
	internal sealed class BepInAutoPluginAttribute : Attribute
	{
		public BepInAutoPluginAttribute(string? id = null, string? name = null, string? version = null)
		{
		}
	}
}
namespace BepInEx.Preloader.Core.Patching
{
	[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
	[Conditional("CodeGeneration")]
	internal sealed class PatcherAutoPluginAttribute : Attribute
	{
		public PatcherAutoPluginAttribute(string? id = null, string? name = null, string? version = null)
		{
		}
	}
}
namespace BingBongPlayer
{
	[BepInPlugin("com.damianmqr.bingbongplayer", "BingBongBoomBox", "1.2.0")]
	public class BingBongPlayerPlugin : BaseUnityPlugin
	{
		private enum SongLoadingState
		{
			Loaded,
			Loading,
			Error
		}

		[Serializable]
		private class SongMetadata
		{
			public string? title;
		}

		[Serializable]
		private class SongRequest
		{
			public string url = "";

			public string hash = "";

			public string requestedBy = "";

			public int requestedByActor = -1;

			public string title = "";
		}

		[Serializable]
		private class SongQueueWrapper
		{
			public List<SongRequest> items = new List<SongRequest>();
		}

		[Serializable]
		private class HostConfigPayload
		{
			public bool publicEnqueue;

			public bool globalAudio;

			public bool bypassEnv;

			public bool allowDuplicates;

			public bool autoAdvance;

			public float maxHearingDistance;

			public int maxQueueSize;

			public int perUserQueueLimit;

			public string v;
		}

		[HarmonyPatch(typeof(Item))]
		private static class ItemPatches
		{
			private static bool IsBingBong(Item it)
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_0008: Unknown result type (might be due to invalid IL or missing references)
				int result;
				if ((it.itemTags & 0x10) == 0)
				{
					ItemUIData uIData = it.UIData;
					if (uIData == null || !(uIData.itemName?.IndexOf("BingBong", StringComparison.OrdinalIgnoreCase) >= 0))
					{
						string name = ((Object)it).name;
						result = ((name != null && name.IndexOf("BingBong", StringComparison.OrdinalIgnoreCase) >= 0) ? 1 : 0);
						goto IL_0077;
					}
				}
				result = 1;
				goto IL_0077;
				IL_0077:
				return (byte)result != 0;
			}

			[HarmonyPostfix]
			[HarmonyPatch("Awake")]
			private static void Awake_Post(Item __instance)
			{
				//IL_0062: Unknown result type (might be due to invalid IL or missing references)
				//IL_0068: Invalid comparison between Unknown and I4
				if (!IsBingBong(__instance))
				{
					return;
				}
				bingBong = ((Component)__instance).transform;
				Transform transform = ((Component)__instance).transform;
				bingBongMouth = null;
				Animator[] componentsInChildren = ((Component)transform).GetComponentsInChildren<Animator>(true);
				Animator[] array = componentsInChildren;
				foreach (Animator val in array)
				{
					try
					{
						AnimatorControllerParameter[] parameters = val.parameters;
						AnimatorControllerParameter val2 = null;
						AnimatorControllerParameter[] array2 = parameters;
						foreach (AnimatorControllerParameter val3 in array2)
						{
							if ((int)val3.type == 1 && val3.name.IndexOf("mouth", StringComparison.OrdinalIgnoreCase) >= 0)
							{
								val2 = val3;
								break;
							}
						}
						if (val2 != null)
						{
							mouthOpenParam = val2.name;
							mouthOpenHash = val2.nameHash;
							bingBongMouth = val;
							break;
						}
					}
					catch
					{
					}
				}
			}

			[HarmonyPrefix]
			[HarmonyPatch("OnDestroy")]
			private static void OnDestroy_Pre(Item __instance)
			{
				if ((Object)(object)bingBong == (Object)(object)((Component)__instance).transform)
				{
					mouthOpenParam = null;
					mouthOpenHash = 0;
					bingBongMouth = null;
					bingBong = null;
				}
			}
		}

		[CompilerGenerated]
		private sealed class <>c__DisplayClass136_0
		{
			public int requestorActor;

			public List<string> lines;

			public Func<SongRequest, bool> <>9__3;

			internal bool <EnqueueYouTubePlaylist>b__0(SongRequest it)
			{
				return it.requestedByActor == requestorActor;
			}

			internal void <EnqueueYouTubePlaylist>b__1(object s, DataReceivedEventArgs e)
			{
				if (!string.IsNullOrEmpty(e.Data))
				{
					lines.Add(e.Data);
				}
			}

			internal bool <EnqueueYouTubePlaylist>b__3(SongRequest it)
			{
				return it.requestedByActor == requestorActor;
			}
		}

		[CompilerGenerated]
		private sealed class <>c__DisplayClass136_1
		{
			public string url;

			internal bool <EnqueueYouTubePlaylist>b__4(SongRequest it)
			{
				return it.url.Equals(url, StringComparison.OrdinalIgnoreCase);
			}
		}

		[CompilerGenerated]
		private sealed class <>c__DisplayClass144_0
		{
			public string titleFromPrint;

			internal void <DownloadAudio>b__0(object s, DataReceivedEventArgs e)
			{
				if (!string.IsNullOrEmpty(e.Data) && e.Data.StartsWith("title-current:"))
				{
					titleFromPrint = e.Data.Substring("title-current:".Length).Trim();
				}
			}
		}

		[CompilerGenerated]
		private sealed class <>c__DisplayClass155_0
		{
			public string fetched;

			internal void <FetchTitleCoroutine>b__0(object s, DataReceivedEventArgs e)
			{
				if (!string.IsNullOrEmpty(e.Data) && e.Data.StartsWith("title-current:"))
				{
					fetched = e.Data.Substring("title-current:".Length).Trim();
				}
			}
		}

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

			private object <>2__current;

			public float delay;

			public string url;

			public string userId;

			public BingBongPlayerPlugin <>4__this;

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

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

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

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

			private bool MoveNext()
			{
				//IL_0027: Unknown result type (might be due to invalid IL or missing references)
				//IL_0031: Expected O, but got Unknown
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<>2__current = (object)new WaitForSecondsRealtime(delay);
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					<>4__this.PlayAudio(url, userId);
					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 <DebounceRequestCoroutine>d__127 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public float delay;

			public string url;

			public BingBongPlayerPlugin <>4__this;

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

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

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

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

			private bool MoveNext()
			{
				//IL_0027: Unknown result type (might be due to invalid IL or missing references)
				//IL_0031: Expected O, but got Unknown
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<>2__current = (object)new WaitForSecondsRealtime(delay);
					<>1__state = 1;
					return true;
				case 1:
				{
					<>1__state = -1;
					PhotonView? photonView = BingBongPlayerPlugin.photonView;
					if (photonView != null)
					{
						photonView.RPC("RPC_RequestEnqueue", (RpcTarget)0, new object[2] { url, <>4__this.userId });
					}
					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 <DownloadAudio>d__144 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public string url;

			public string outputPath;

			public string metadataPath;

			public BingBongPlayerPlugin <>4__this;

			private <>c__DisplayClass144_0 <>8__1;

			private ProcessStartInfo <psi>5__2;

			private Process <proc>5__3;

			private float <startTime>5__4;

			private SongMetadata <metadata>5__5;

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

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

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

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>8__1 = null;
				<psi>5__2 = null;
				<proc>5__3 = null;
				<metadata>5__5 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<>8__1 = new <>c__DisplayClass144_0();
					<>4__this.CleanupOldTempFiles();
					<>4__this.songLoadingState = SongLoadingState.Loading;
					<>8__1.titleFromPrint = "";
					if (string.IsNullOrEmpty(<>4__this.ytDlpPath) || !File.Exists(<>4__this.ytDlpPath) || string.IsNullOrEmpty(<>4__this.ffmpegPath) || !File.Exists(<>4__this.ffmpegPath))
					{
						<>4__this.songLoadingState = SongLoadingState.Error;
						return false;
					}
					<psi>5__2 = new ProcessStartInfo
					{
						FileName = <>4__this.ytDlpPath,
						RedirectStandardOutput = true,
						RedirectStandardError = true,
						UseShellExecute = false,
						CreateNoWindow = true
					};
					<psi>5__2.ArgumentList.Add("--no-playlist");
					<psi>5__2.ArgumentList.Add("--max-filesize");
					<psi>5__2.ArgumentList.Add($"{<>4__this.MaxAudioSizeMb}M");
					<psi>5__2.ArgumentList.Add("--extractor-args");
					<psi>5__2.ArgumentList.Add("youtube:player_client=tv_simply,default,-tv");
					<psi>5__2.ArgumentList.Add("-x");
					<psi>5__2.ArgumentList.Add("-f");
					<psi>5__2.ArgumentList.Add("bestaudio[abr<=128]/bestaudio[abr<=160]/bestaudio");
					<psi>5__2.ArgumentList.Add("--ffmpeg-location");
					<psi>5__2.ArgumentList.Add(<>4__this.ffmpegPath);
					<psi>5__2.ArgumentList.Add("--audio-format");
					<psi>5__2.ArgumentList.Add("wav");
					<psi>5__2.ArgumentList.Add("--print");
					<psi>5__2.ArgumentList.Add("title-current:%(title)s");
					<psi>5__2.ArgumentList.Add("--no-simulate");
					<psi>5__2.ArgumentList.Add("-o");
					<psi>5__2.ArgumentList.Add(outputPath);
					<psi>5__2.ArgumentList.Add(url);
					<proc>5__3 = new Process
					{
						StartInfo = <psi>5__2
					};
					<proc>5__3.OutputDataReceived += delegate(object s, DataReceivedEventArgs e)
					{
						if (!string.IsNullOrEmpty(e.Data) && e.Data.StartsWith("title-current:"))
						{
							<>8__1.titleFromPrint = e.Data.Substring("title-current:".Length).Trim();
						}
					};
					<proc>5__3.ErrorDataReceived += delegate
					{
					};
					try
					{
						<proc>5__3.Start();
					}
					catch (Exception)
					{
						<>4__this.songLoadingState = SongLoadingState.Error;
						<>4__this.downloadCoroutine = null;
						return false;
					}
					<proc>5__3.BeginOutputReadLine();
					<proc>5__3.BeginErrorReadLine();
					<startTime>5__4 = Time.realtimeSinceStartup;
					break;
				case 1:
					<>1__state = -1;
					break;
				}
				if (!<proc>5__3.HasExited)
				{
					if (!(Time.realtimeSinceStartup - <startTime>5__4 > (float)(<>4__this.TitleProbeTimeoutSec + 60)))
					{
						<>2__current = null;
						<>1__state = 1;
						return true;
					}
					try
					{
						<proc>5__3.Kill();
					}
					catch
					{
					}
				}
				if (File.Exists(outputPath))
				{
					if (!string.IsNullOrWhiteSpace(<>8__1.titleFromPrint))
					{
						<>4__this.currentSongTitle = <>8__1.titleFromPrint;
					}
					try
					{
						<metadata>5__5 = new SongMetadata
						{
							title = <>4__this.currentSongTitle
						};
						File.WriteAllText(metadataPath, JsonUtility.ToJson((object)<metadata>5__5));
						<metadata>5__5 = null;
					}
					catch
					{
					}
					<>4__this.currentPlaybackCoroutine = ((MonoBehaviour)<>4__this).StartCoroutine(<>4__this.LoadAndPlay(outputPath));
				}
				else
				{
					<>4__this.songLoadingState = SongLoadingState.Error;
					if (<>4__this.ActAsHost())
					{
						<>4__this.PlayNextImpl();
					}
				}
				<>4__this.downloadCoroutine = null;
				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 <EnqueueYouTubePlaylist>d__136 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public string playlistUrl;

			public string requestorId;

			public int requestorActor;

			public BingBongPlayerPlugin <>4__this;

			private <>c__DisplayClass136_0 <>8__1;

			private int <remainingQueueSlots>5__2;

			private int <userCount>5__3;

			private int <remainingUserSlots>5__4;

			private int <maxToAdd>5__5;

			private ProcessStartInfo <psi>5__6;

			private Process <proc>5__7;

			private bool <started>5__8;

			private float <startTime>5__9;

			private int <added>5__10;

			private List<string>.Enumerator <>s__11;

			private string <raw>5__12;

			private <>c__DisplayClass136_1 <>8__13;

			private int <tab>5__14;

			private string <title>5__15;

			private int <uCount>5__16;

			private bool <ok>5__17;

			private SongRequest <addedItem>5__18;

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

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

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

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>8__1 = null;
				<psi>5__6 = null;
				<proc>5__7 = null;
				<>s__11 = default(List<string>.Enumerator);
				<raw>5__12 = null;
				<>8__13 = null;
				<title>5__15 = null;
				<addedItem>5__18 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<>8__1 = new <>c__DisplayClass136_0();
					<>8__1.requestorActor = requestorActor;
					if (string.IsNullOrEmpty(<>4__this.ytDlpPath) || !File.Exists(<>4__this.ytDlpPath))
					{
						return false;
					}
					<remainingQueueSlots>5__2 = Math.Max(0, <>4__this.MaxQueueSize - <>4__this.queue.Count);
					<userCount>5__3 = <>4__this.queue.Count((SongRequest it) => it.requestedByActor == <>8__1.requestorActor);
					<remainingUserSlots>5__4 = Math.Max(0, <>4__this.PerUserQueueLimit - <userCount>5__3);
					<maxToAdd>5__5 = Math.Min(<remainingQueueSlots>5__2, <remainingUserSlots>5__4);
					if (<maxToAdd>5__5 <= 0)
					{
						return false;
					}
					<psi>5__6 = new ProcessStartInfo
					{
						FileName = <>4__this.ytDlpPath,
						RedirectStandardOutput = true,
						RedirectStandardError = true,
						UseShellExecute = false,
						CreateNoWindow = true
					};
					<psi>5__6.ArgumentList.Add("--yes-playlist");
					<psi>5__6.ArgumentList.Add("--flat-playlist");
					<psi>5__6.ArgumentList.Add("--ignore-errors");
					<psi>5__6.ArgumentList.Add("--playlist-items");
					<psi>5__6.ArgumentList.Add($"1-{<maxToAdd>5__5}");
					<psi>5__6.ArgumentList.Add("--print");
					<psi>5__6.ArgumentList.Add("%(title)s\t%(webpage_url)s");
					<psi>5__6.ArgumentList.Add(playlistUrl);
					<proc>5__7 = new Process
					{
						StartInfo = <psi>5__6
					};
					<>8__1.lines = new List<string>();
					<proc>5__7.OutputDataReceived += delegate(object s, DataReceivedEventArgs e)
					{
						if (!string.IsNullOrEmpty(e.Data))
						{
							<>8__1.lines.Add(e.Data);
						}
					};
					<proc>5__7.ErrorDataReceived += delegate
					{
					};
					<started>5__8 = false;
					try
					{
						<started>5__8 = <proc>5__7.Start();
					}
					catch (Exception)
					{
					}
					if (!<started>5__8)
					{
						return false;
					}
					<proc>5__7.BeginOutputReadLine();
					<proc>5__7.BeginErrorReadLine();
					<startTime>5__9 = Time.realtimeSinceStartup;
					break;
				case 1:
					<>1__state = -1;
					break;
				}
				if (!<proc>5__7.HasExited)
				{
					if (!(Time.realtimeSinceStartup - <startTime>5__9 > (float)<>4__this.PlaylistProbeTimeoutSec))
					{
						<>2__current = null;
						<>1__state = 1;
						return true;
					}
					try
					{
						<proc>5__7.Kill();
					}
					catch
					{
					}
				}
				<added>5__10 = 0;
				<>s__11 = <>8__1.lines.GetEnumerator();
				try
				{
					while (<>s__11.MoveNext())
					{
						<raw>5__12 = <>s__11.Current;
						<>8__13 = new <>c__DisplayClass136_1();
						if (string.IsNullOrWhiteSpace(<raw>5__12))
						{
							continue;
						}
						<tab>5__14 = <raw>5__12.IndexOf('\t');
						if (<tab>5__14 <= 0 || <tab>5__14 >= <raw>5__12.Length - 1)
						{
							continue;
						}
						<title>5__15 = <raw>5__12.Substring(0, <tab>5__14).Trim();
						<>8__13.url = <raw>5__12.Substring(<tab>5__14 + 1).Trim();
						if (<>4__this.queue.Count >= <>4__this.MaxQueueSize)
						{
							break;
						}
						<uCount>5__16 = <>4__this.queue.Count((SongRequest it) => it.requestedByActor == <>8__1.requestorActor);
						if (<uCount>5__16 >= <>4__this.PerUserQueueLimit)
						{
							break;
						}
						if (<>4__this.AllowDuplicates || !<>4__this.queue.Any((SongRequest it) => it.url.Equals(<>8__13.url, StringComparison.OrdinalIgnoreCase)))
						{
							<ok>5__17 = <>4__this.TryEnqueueInternal(<>8__13.url, requestorId, <>8__1.requestorActor, out <addedItem>5__18, <title>5__15);
							if (<ok>5__17 && <addedItem>5__18 != null)
							{
								<added>5__10++;
							}
							<>8__13 = null;
							<title>5__15 = null;
							<addedItem>5__18 = null;
							<raw>5__12 = null;
						}
					}
				}
				finally
				{
					((IDisposable)<>s__11).Dispose();
				}
				<>s__11 = default(List<string>.Enumerator);
				if (<added>5__10 > 0)
				{
					<>4__this.BroadcastQueue();
				}
				if (<added>5__10 > 0 && !audioSource.isPlaying && <>4__this.songLoadingState != SongLoadingState.Loading)
				{
					<>4__this.PlayNextImpl();
				}
				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 <FetchTitleCoroutine>d__155 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public string hash;

			public string url;

			public BingBongPlayerPlugin <>4__this;

			private <>c__DisplayClass155_0 <>8__1;

			private ProcessStartInfo <psi>5__2;

			private Process <proc>5__3;

			private bool <started>5__4;

			private float <startTime>5__5;

			private string <metadataPath>5__6;

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

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

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

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>8__1 = null;
				<psi>5__2 = null;
				<proc>5__3 = null;
				<metadataPath>5__6 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<>8__1 = new <>c__DisplayClass155_0();
					<>4__this.titleFetchInProgress.Add(hash);
					if (string.IsNullOrEmpty(<>4__this.ytDlpPath) || !File.Exists(<>4__this.ytDlpPath))
					{
						<>4__this.titleFetchInProgress.Remove(hash);
						return false;
					}
					<>8__1.fetched = "";
					<psi>5__2 = new ProcessStartInfo
					{
						FileName = <>4__this.ytDlpPath,
						RedirectStandardOutput = true,
						RedirectStandardError = true,
						UseShellExecute = false,
						CreateNoWindow = true
					};
					<psi>5__2.ArgumentList.Add("--no-playlist");
					<psi>5__2.ArgumentList.Add("--skip-download");
					<psi>5__2.ArgumentList.Add("--print");
					<psi>5__2.ArgumentList.Add("title-current:%(title)s");
					<psi>5__2.ArgumentList.Add(url);
					<proc>5__3 = new Process
					{
						StartInfo = <psi>5__2
					};
					<proc>5__3.OutputDataReceived += delegate(object s, DataReceivedEventArgs e)
					{
						if (!string.IsNullOrEmpty(e.Data) && e.Data.StartsWith("title-current:"))
						{
							<>8__1.fetched = e.Data.Substring("title-current:".Length).Trim();
						}
					};
					<proc>5__3.ErrorDataReceived += delegate
					{
					};
					<started>5__4 = false;
					try
					{
						<started>5__4 = <proc>5__3.Start();
					}
					catch (Exception)
					{
					}
					if (!<started>5__4)
					{
						<>4__this.titleFetchInProgress.Remove(hash);
						return false;
					}
					<proc>5__3.BeginOutputReadLine();
					<proc>5__3.BeginErrorReadLine();
					<startTime>5__5 = Time.realtimeSinceStartup;
					break;
				case 1:
					<>1__state = -1;
					break;
				}
				if (!<proc>5__3.HasExited)
				{
					if (!(Time.realtimeSinceStartup - <startTime>5__5 > (float)<>4__this.TitleProbeTimeoutSec))
					{
						<>2__current = null;
						<>1__state = 1;
						return true;
					}
					try
					{
						<proc>5__3.Kill();
					}
					catch
					{
					}
				}
				if (!string.IsNullOrWhiteSpace(<>8__1.fetched))
				{
					<>4__this.UpdateQueueTitle(hash, <>8__1.fetched);
					try
					{
						<metadataPath>5__6 = Path.Combine(<>4__this.tempAudioDir, "bingbong_" + hash + ".json");
						File.WriteAllText(<metadataPath>5__6, JsonUtility.ToJson((object)new SongMetadata
						{
							title = <>8__1.fetched
						}));
						<metadataPath>5__6 = null;
					}
					catch
					{
					}
				}
				<>4__this.titleFetchInProgress.Remove(hash);
				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 <LoadAndPlay>d__146 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public string path;

			public BingBongPlayerPlugin <>4__this;

			private UnityWebRequest <www>5__1;

			private AudioClip <clip>5__2;

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

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

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

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				int num = <>1__state;
				if (num == -3 || num == 1)
				{
					try
					{
					}
					finally
					{
						<>m__Finally1();
					}
				}
				<www>5__1 = null;
				<clip>5__2 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
				//IL_00af: Invalid comparison between Unknown and I4
				bool result;
				try
				{
					switch (<>1__state)
					{
					default:
						result = false;
						break;
					case 0:
						<>1__state = -1;
						if ((Object)(object)audioSource == (Object)null)
						{
							<>4__this.songLoadingState = SongLoadingState.Error;
							result = false;
							break;
						}
						<>4__this.songLoadingState = SongLoadingState.Loaded;
						<www>5__1 = UnityWebRequestMultimedia.GetAudioClip("file://" + path, (AudioType)20);
						<>1__state = -3;
						<>2__current = <www>5__1.SendWebRequest();
						<>1__state = 1;
						result = true;
						break;
					case 1:
						<>1__state = -3;
						if ((int)<www>5__1.result != 1)
						{
							<>4__this.songLoadingState = SongLoadingState.Error;
							result = false;
						}
						else
						{
							<clip>5__2 = DownloadHandlerAudioClip.GetContent(<www>5__1);
							audioSource.clip = <clip>5__2;
							if (<>4__this.ActAsHost())
							{
								audioSource.Play();
							}
							result = false;
						}
						<>m__Finally1();
						break;
					}
				}
				catch
				{
					//try-fault
					((IDisposable)this).Dispose();
					throw;
				}
				return result;
			}

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

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

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

		private static ManualLogSource? logger;

		private static AudioSource? audioSource;

		private static PhotonView? photonView;

		private string? ytDlpPath;

		private string? ffmpegPath;

		private string urlInput = "";

		private Coroutine? currentPlaybackCoroutine;

		private Coroutine? debouncePlayCoroutine = null;

		private Coroutine? downloadCoroutine = null;

		private const ushort BingBongItemID = 13;

		private static string? mouthOpenParam = null;

		private static int mouthOpenHash = 0;

		public static Transform? bingBong = null;

		public static Animator? bingBongMouth = null;

		private ConfigEntry<float>? volumeSetting;

		private ConfigEntry<int>? maxAudioSizeMbCfg;

		private ConfigEntry<int>? maxTempFilesCfg;

		private ConfigEntry<int>? maxQueueSizeCfg;

		private ConfigEntry<int>? perUserQueueLimitCfg;

		private ConfigEntry<bool>? allowDuplicatesCfg;

		private ConfigEntry<bool>? autoAdvanceCfg;

		private ConfigEntry<int>? titleProbeTimeoutSecCfg;

		private ConfigEntry<int>? playlistProbeTimeoutSecCfg;

		private ConfigEntry<bool>? globalAudioCfg;

		private ConfigEntry<bool>? bypassEnvCfg;

		private ConfigEntry<bool>? publicEnqueueCfg;

		private ConfigEntry<float>? maxHearingDistanceCfg;

		private ConfigEntry<float>? uiScaleCfg;

		private ConfigEntry<bool>? showAdvancedCfg;

		private bool hostPublicEnqueue = false;

		private bool hostGlobalAudio = false;

		private bool hostBypassEnv = false;

		private bool hostAllowDuplicates = false;

		private bool hostAutoAdvance = true;

		private float hostMaxHearingDistance = 35f;

		private int hostMaxQueueSize = 20;

		private int hostPerUserQueueLimit = 5;

		private float syncInterval = 5f;

		private float lastSyncTime = 0f;

		private float lastConfigBroadcast = -999f;

		private bool sentInitialConfig = false;

		public float vocalLow = 300f;

		public float vocalHigh = 3400f;

		public int sampleSize = 256;

		public float currentVolume = 0.45f;

		public FFTWindow fftWindow = (FFTWindow)5;

		private bool lastConnectedState = false;

		private float[]? spectrumData;

		private string? tempAudioDir;

		private string currentSongTitle = "";

		private string currentSongHash = "";

		private string lastUsedPlayer = "";

		private string userId = Guid.NewGuid().ToString();

		private bool manualStop = false;

		private SongLoadingState songLoadingState = SongLoadingState.Loaded;

		public static readonly string[] LoadingProgress = new string[4] { "Loading.", "Loading..", "Loading...", "Loading" };

		private bool hostHasMod = PhotonNetwork.IsMasterClient;

		private readonly List<SongRequest> queue = new List<SongRequest>();

		private Vector2 queueScroll = Vector2.zero;

		private Vector2 panelScroll = Vector2.zero;

		private readonly HashSet<string> titleFetchInProgress = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

		private float spectrumTimer = 0f;

		private float spectrumInterval = 0.012f;

		private GUIStyle? boxStyle;

		private GUIStyle? labelStyle;

		private GUIStyle? buttonStyle;

		private GUIStyle? sliderStyle;

		private GUIStyle? sliderThumbStyle;

		private GUIStyle? headerStyle;

		private GUIStyle? smallLabelStyle;

		private GUIStyle? toggleStyle;

		private GUIStyle? foldoutStyle;

		private Texture2D? boxBgTex;

		private Texture2D? sliderBgTex;

		private Texture2D? sliderThumbTex;

		private Texture2D? buttonNormalBgTex;

		private Texture2D? buttonHoverBgTex;

		private bool initializedStyles;

		private float appliedUiScale = -1f;

		private static readonly string[] AllowedHosts = new string[20]
		{
			"youtube.com", "www.youtube.com", "m.youtube.com", "music.youtube.com", "www.music.youtube.com", "youtu.be", "www.youtu.be", "soundcloud.com", "www.soundcloud.com", "vimeo.com",
			"www.vimeo.com", "bandcamp.com", "www.bandcamp.com", "twitch.tv", "www.twitch.tv", "clips.twitch.tv", "tiktok.com", "www.tiktok.com", "mixcloud.com", "www.mixcloud.com"
		};

		private int MaxAudioSizeMb => Mathf.Max(1, maxAudioSizeMbCfg?.Value ?? 100);

		private int MaxTempFiles => Mathf.Max(1, maxTempFilesCfg?.Value ?? 5);

		private int MaxQueueSize => Mathf.Max(1, (!ActAsHost()) ? ((hostMaxQueueSize > 0) ? hostMaxQueueSize : 20) : (maxQueueSizeCfg?.Value ?? 20));

		private int PerUserQueueLimit => Mathf.Max(1, (!ActAsHost()) ? ((hostPerUserQueueLimit > 0) ? hostPerUserQueueLimit : 5) : (perUserQueueLimitCfg?.Value ?? 5));

		private bool AllowDuplicates => (!ActAsHost()) ? hostAllowDuplicates : (allowDuplicatesCfg?.Value ?? false);

		private bool AutoAdvance => (!ActAsHost()) ? hostAutoAdvance : (autoAdvanceCfg?.Value ?? true);

		private int TitleProbeTimeoutSec => Mathf.Max(5, titleProbeTimeoutSecCfg?.Value ?? 20);

		private int PlaylistProbeTimeoutSec => Mathf.Max(5, playlistProbeTimeoutSecCfg?.Value ?? 30);

		private bool GlobalAudio => (!ActAsHost()) ? hostGlobalAudio : (globalAudioCfg?.Value ?? false);

		private bool BypassEnv => (!ActAsHost()) ? hostBypassEnv : (bypassEnvCfg?.Value ?? false);

		private bool PublicEnqueue => (!ActAsHost()) ? hostPublicEnqueue : (publicEnqueueCfg?.Value ?? false);

		private float MaxHearingDistance => Mathf.Clamp((!ActAsHost()) ? ((hostMaxHearingDistance <= 0f) ? 35f : hostMaxHearingDistance) : (maxHearingDistanceCfg?.Value ?? 35f), 5f, 10000f);

		private float UiScale => Mathf.Clamp(uiScaleCfg?.Value ?? 1f, 0.75f, 2f);

		private bool ShowAdvanced => showAdvancedCfg?.Value ?? false;

		private bool ActAsHost()
		{
			return PhotonNetwork.IsMasterClient || (!hostHasMod && lastUsedPlayer == userId);
		}

		private int LocalActor()
		{
			return (PhotonNetwork.LocalPlayer != null) ? PhotonNetwork.LocalPlayer.ActorNumber : (-1);
		}

		private int GetCurrentHolderActorNumber()
		{
			try
			{
				foreach (Player allPlayer in PlayerHandler.GetAllPlayers())
				{
					if ((Object)(object)allPlayer == (Object)null || (Object)(object)allPlayer.character == (Object)null || !allPlayer.HasInAnySlot((ushort)13))
					{
						continue;
					}
					int num = -1;
					try
					{
						Character character = allPlayer.character;
						int? obj;
						if (character == null)
						{
							obj = null;
						}
						else
						{
							PhotonView obj2 = ((MonoBehaviourPun)character).photonView;
							obj = ((obj2 != null) ? new int?(obj2.OwnerActorNr) : null);
						}
						int? num2 = obj;
						num = num2.GetValueOrDefault(-1);
					}
					catch
					{
					}
					if (num <= 0)
					{
						try
						{
							PhotonView obj4 = ((MonoBehaviourPun)allPlayer).photonView;
							num = ((obj4 != null) ? obj4.OwnerActorNr : (-1));
						}
						catch
						{
						}
					}
					if (num <= 0)
					{
						continue;
					}
					return num;
				}
			}
			catch (Exception ex)
			{
				ManualLogSource? obj6 = logger;
				if (obj6 != null)
				{
					obj6.LogWarning((object)("GetCurrentHolderActorNumber failed: " + ex.Message));
				}
			}
			return -1;
		}

		private bool IsRequestorHolder(int requestorActorNumber)
		{
			int currentHolderActorNumber = GetCurrentHolderActorNumber();
			return currentHolderActorNumber > 0 && requestorActorNumber == currentHolderActorNumber;
		}

		private void Awake()
		{
			//IL_03a8: Unknown result type (might be due to invalid IL or missing references)
			logger = ((BaseUnityPlugin)this).Logger;
			photonView = ((Component)this).gameObject.AddComponent<PhotonView>();
			photonView.ViewID = 215151321;
			spectrumData = new float[sampleSize];
			string path = Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location) ?? Paths.PluginPath;
			ytDlpPath = Path.Combine(path, "yt-dlp.exe");
			ffmpegPath = Path.Combine(path, "ffmpeg.exe");
			tempAudioDir = Path.Combine(Path.GetTempPath(), "BingBongAudio");
			Directory.CreateDirectory(tempAudioDir);
			CleanupOldTempFiles();
			if (!File.Exists(ytDlpPath))
			{
				ManualLogSource? obj = logger;
				if (obj != null)
				{
					obj.LogError((object)"yt-dlp.exe not found!");
				}
			}
			if (!File.Exists(ffmpegPath))
			{
				ManualLogSource? obj2 = logger;
				if (obj2 != null)
				{
					obj2.LogError((object)"ffmpeg.exe not found!");
				}
			}
			volumeSetting = ((BaseUnityPlugin)this).Config.Bind<float>("Audio", "Volume", 0.45f, "Default playback volume (0.0 to 1.0)");
			currentVolume = Mathf.Clamp01(volumeSetting.Value);
			maxAudioSizeMbCfg = ((BaseUnityPlugin)this).Config.Bind<int>("Limits", "MaxAudioSizeMB", 100, "Max file size yt-dlp may download.");
			maxTempFilesCfg = ((BaseUnityPlugin)this).Config.Bind<int>("Limits", "MaxTempFiles", 5, "How many cached WAVs to keep.");
			maxQueueSizeCfg = ((BaseUnityPlugin)this).Config.Bind<int>("Limits", "MaxQueueSize", 20, "Max items allowed in queue. (Host only)");
			perUserQueueLimitCfg = ((BaseUnityPlugin)this).Config.Bind<int>("Limits", "PerUserQueueLimit", 5, "Max items one user can have pending in the queue. (Host only)");
			allowDuplicatesCfg = ((BaseUnityPlugin)this).Config.Bind<bool>("Queue", "AllowDuplicates", false, "Allow the same URL to be enqueued multiple times. (Host only)");
			autoAdvanceCfg = ((BaseUnityPlugin)this).Config.Bind<bool>("Queue", "AutoAdvance", true, "Automatically advance to next track when one finishes. (Host only)");
			titleProbeTimeoutSecCfg = ((BaseUnityPlugin)this).Config.Bind<int>("Advanced", "TitleProbeTimeoutSec", 20, "Timeout for title probes (seconds).");
			playlistProbeTimeoutSecCfg = ((BaseUnityPlugin)this).Config.Bind<int>("Advanced", "PlaylistProbeTimeoutSec", 30, "Timeout for playlist expansion (seconds).");
			globalAudioCfg = ((BaseUnityPlugin)this).Config.Bind<bool>("Audio", "GlobalAudio", false, "2D audio heard anywhere. (Host only)");
			bypassEnvCfg = ((BaseUnityPlugin)this).Config.Bind<bool>("Audio", "BypassEnvironmentEffects", false, "Bypass reverb/occlusion. (Host only)");
			maxHearingDistanceCfg = ((BaseUnityPlugin)this).Config.Bind<float>("Audio", "MaxHearingDistance", 35f, "3D audio max distance. (Host only)");
			publicEnqueueCfg = ((BaseUnityPlugin)this).Config.Bind<bool>("Queue", "PublicEnqueue", false, "Non-holders may add and control playback. (Host only)");
			uiScaleCfg = ((BaseUnityPlugin)this).Config.Bind<float>("UI", "UiScale", 1f, "Scale UI text/vertical only (client)");
			showAdvancedCfg = ((BaseUnityPlugin)this).Config.Bind<bool>("UI", "ShowAdvanced", false, "Show Advanced section (client)");
			audioSource = ((Component)this).gameObject.AddComponent<AudioSource>();
			audioSource.spatialBlend = 1f;
			audioSource.volume = currentVolume;
			audioSource.loop = false;
			audioSource.rolloffMode = (AudioRolloffMode)1;
			audioSource.minDistance = 1f;
			audioSource.maxDistance = MaxHearingDistance;
			audioSource.bypassEffects = BypassEnv;
			audioSource.bypassListenerEffects = BypassEnv;
			audioSource.bypassReverbZones = BypassEnv;
			new Harmony("com.damianmqr.bingbongplayer").PatchAll();
		}

		private void OnDestroy()
		{
			if (currentPlaybackCoroutine != null)
			{
				((MonoBehaviour)this).StopCoroutine(currentPlaybackCoroutine);
			}
			if (debouncePlayCoroutine != null)
			{
				((MonoBehaviour)this).StopCoroutine(debouncePlayCoroutine);
			}
			if (downloadCoroutine != null)
			{
				((MonoBehaviour)this).StopCoroutine(downloadCoroutine);
			}
		}

		private void LateUpdate()
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Invalid comparison between Unknown and I4
			//IL_01af: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0288: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d5: Unknown result type (might be due to invalid IL or missing references)
			bool flag = (int)PhotonNetwork.Server == 1;
			if (lastConnectedState && !flag)
			{
				StopAndResetSong();
				queue.Clear();
				sentInitialConfig = false;
			}
			lastConnectedState = flag;
			if ((Object)(object)audioSource == (Object)null || !PhotonNetwork.IsConnectedAndReady || (Object)(object)photonView == (Object)null)
			{
				return;
			}
			if (ActAsHost())
			{
				if (!sentInitialConfig)
				{
					BroadcastHostConfig();
					sentInitialConfig = true;
				}
				if (Time.time - lastConfigBroadcast > 15f)
				{
					BroadcastHostConfig();
				}
			}
			if (ActAsHost() && Time.time - lastSyncTime > syncInterval)
			{
				photonView.RPC("RPC_SyncPlaying", (RpcTarget)1, new object[4]
				{
					currentSongHash,
					audioSource.isPlaying,
					PhotonNetwork.IsMasterClient,
					currentSongTitle
				});
				if (audioSource.isPlaying)
				{
					photonView.RPC("RPC_SyncTime", (RpcTarget)1, new object[2] { currentSongHash, audioSource.time });
				}
				lastSyncTime = Time.time;
			}
			bool flag2 = Singleton<PeakHandler>.Instance?.isPlayingCinematic ?? false;
			Vector3? val = null;
			if ((Object)(object)bingBong != (Object)null)
			{
				val = bingBong.position;
			}
			else
			{
				Player? obj = FindPlayerWithBingBong();
				Vector3? obj2;
				if (obj == null)
				{
					obj2 = null;
				}
				else
				{
					Character character = obj.character;
					obj2 = ((character != null) ? new Vector3?(character.Center) : null);
				}
				val = obj2;
			}
			if (GlobalAudio)
			{
				audioSource.spatialBlend = 0f;
				audioSource.volume = currentVolume;
			}
			else
			{
				audioSource.spatialBlend = (flag2 ? 0f : 1f);
				audioSource.maxDistance = MaxHearingDistance;
				audioSource.volume = (val.HasValue ? currentVolume : 0f);
				if (val.HasValue)
				{
					((Component)audioSource).transform.position = val.Value;
				}
			}
			audioSource.bypassEffects = BypassEnv;
			audioSource.bypassListenerEffects = BypassEnv;
			audioSource.bypassReverbZones = BypassEnv;
			if (ActAsHost() && AutoAdvance && !manualStop && (Object)(object)audioSource.clip != (Object)null && !audioSource.isPlaying && !string.IsNullOrEmpty(currentSongHash) && songLoadingState == SongLoadingState.Loaded)
			{
				PlayNextImpl();
			}
			if (!((Object)(object)audioSource != (Object)null) || !((Object)(object)bingBongMouth != (Object)null) || mouthOpenParam == null)
			{
				return;
			}
			spectrumTimer += Time.deltaTime;
			if (!(spectrumTimer >= spectrumInterval))
			{
				return;
			}
			spectrumTimer = 0f;
			float num = 0f;
			if (audioSource.isPlaying && spectrumData != null && (Object)(object)audioSource.clip != (Object)null)
			{
				audioSource.GetSpectrumData(spectrumData, 0, fftWindow);
				float num2 = (float)AudioSettings.outputSampleRate / 2f / (float)sampleSize;
				int num3 = Mathf.FloorToInt(vocalLow / num2);
				int num4 = Mathf.CeilToInt(vocalHigh / num2);
				num3 = Mathf.Clamp(num3, 0, sampleSize - 1);
				num4 = Mathf.Clamp(num4, 0, sampleSize - 1);
				float num5 = 0f;
				int num6 = 0;
				for (int i = num3; i <= num4; i++)
				{
					num5 += spectrumData[i];
					num6++;
				}
				float num7 = ((num6 > 0) ? (num5 / (float)num6) : 0f);
				num = Mathf.Clamp01(num7 * 50f);
			}
			try
			{
				bingBongMouth.SetFloat(mouthOpenHash, num);
			}
			catch
			{
			}
		}

		private void BroadcastHostConfig()
		{
			lastConfigBroadcast = Time.time;
			HostConfigPayload hostConfigPayload = new HostConfigPayload
			{
				publicEnqueue = PublicEnqueue,
				globalAudio = GlobalAudio,
				bypassEnv = BypassEnv,
				allowDuplicates = AllowDuplicates,
				autoAdvance = AutoAdvance,
				maxHearingDistance = MaxHearingDistance,
				maxQueueSize = MaxQueueSize,
				perUserQueueLimit = PerUserQueueLimit,
				v = "1.2.0"
			};
			PhotonView? obj = photonView;
			if (obj != null)
			{
				obj.RPC("RPC_ConfigSync", (RpcTarget)1, new object[1] { JsonUtility.ToJson((object)hostConfigPayload) });
			}
		}

		[PunRPC]
		private void RPC_ConfigSync(string json)
		{
			try
			{
				HostConfigPayload hostConfigPayload = JsonUtility.FromJson<HostConfigPayload>(json);
				if (hostConfigPayload != null)
				{
					hostPublicEnqueue = hostConfigPayload.publicEnqueue;
					hostGlobalAudio = hostConfigPayload.globalAudio;
					hostBypassEnv = hostConfigPayload.bypassEnv;
					hostAllowDuplicates = hostConfigPayload.allowDuplicates;
					hostAutoAdvance = hostConfigPayload.autoAdvance;
					hostMaxHearingDistance = hostConfigPayload.maxHearingDistance;
					hostMaxQueueSize = hostConfigPayload.maxQueueSize;
					hostPerUserQueueLimit = hostConfigPayload.perUserQueueLimit;
				}
			}
			catch
			{
			}
		}

		private Player? FindPlayerWithBingBong()
		{
			foreach (Player allPlayer in PlayerHandler.GetAllPlayers())
			{
				if ((Object)(object)allPlayer.character != (Object)null && allPlayer.HasInAnySlot((ushort)13))
				{
					return allPlayer;
				}
			}
			return null;
		}

		private Texture2D MakeSolidColorTex(Color col)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Expected O, but got Unknown
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			Texture2D val = new Texture2D(1, 1);
			val.SetPixel(0, 0, col);
			val.Apply();
			return val;
		}

		private void InitStyles()
		{
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Expected O, but got Unknown
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Expected O, but got Unknown
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Expected O, but got Unknown
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0145: Unknown result type (might be due to invalid IL or missing references)
			//IL_014b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0156: Unknown result type (might be due to invalid IL or missing references)
			//IL_0163: Expected O, but got Unknown
			//IL_016e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0173: Unknown result type (might be due to invalid IL or missing references)
			//IL_018b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0191: Unknown result type (might be due to invalid IL or missing references)
			//IL_019c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a9: Expected O, but got Unknown
			//IL_01b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ef: Expected O, but got Unknown
			//IL_01fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_021c: Expected O, but got Unknown
			//IL_0227: Unknown result type (might be due to invalid IL or missing references)
			//IL_022c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0244: Unknown result type (might be due to invalid IL or missing references)
			//IL_024c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0271: Unknown result type (might be due to invalid IL or missing references)
			//IL_027b: Expected O, but got Unknown
			//IL_0281: Expected O, but got Unknown
			//IL_0297: 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)
			//IL_02d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02db: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0302: Expected O, but got Unknown
			//IL_0303: Unknown result type (might be due to invalid IL or missing references)
			//IL_0328: Unknown result type (might be due to invalid IL or missing references)
			//IL_0332: Expected O, but got Unknown
			//IL_0333: Unknown result type (might be due to invalid IL or missing references)
			//IL_0345: Unknown result type (might be due to invalid IL or missing references)
			//IL_035c: Expected O, but got Unknown
			//IL_0372: Unknown result type (might be due to invalid IL or missing references)
			//IL_0397: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_03e6: Expected O, but got Unknown
			//IL_03f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0408: Unknown result type (might be due to invalid IL or missing references)
			//IL_0421: Unknown result type (might be due to invalid IL or missing references)
			//IL_043f: Expected O, but got Unknown
			if (initializedStyles && Mathf.Abs(appliedUiScale - UiScale) < 0.001f)
			{
				return;
			}
			appliedUiScale = UiScale;
			Font val = null;
			Font[] array = Resources.FindObjectsOfTypeAll<Font>();
			foreach (Font val2 in array)
			{
				if (((Object)val2).name == "DarumaDropOne-Regular")
				{
					val = val2;
					break;
				}
			}
			if (!((Object)(object)val == (Object)null) || PhotonNetwork.IsConnectedAndReady)
			{
				boxBgTex = MakeSolidColorTex(new Color(0f, 0f, 0f, 0.8f));
				int num = Mathf.RoundToInt(12f * UiScale);
				GUIStyle val3 = new GUIStyle(GUI.skin.box)
				{
					padding = new RectOffset(12, 12, num, num),
					margin = new RectOffset(10, 10, 10, 10)
				};
				val3.normal.background = boxBgTex;
				boxStyle = val3;
				GUIStyle val4 = new GUIStyle(GUI.skin.label)
				{
					fontSize = Mathf.RoundToInt(14f * UiScale)
				};
				val4.normal.textColor = Color.white;
				val4.richText = true;
				labelStyle = val4;
				GUIStyle val5 = new GUIStyle(GUI.skin.label)
				{
					fontSize = Mathf.RoundToInt(12f * UiScale)
				};
				val5.normal.textColor = Color.white;
				val5.richText = true;
				smallLabelStyle = val5;
				GUIStyle val6 = new GUIStyle(GUI.skin.label)
				{
					fontSize = Mathf.RoundToInt(22f * UiScale)
				};
				val6.normal.textColor = Color.white;
				val6.richText = true;
				headerStyle = val6;
				toggleStyle = new GUIStyle(GUI.skin.toggle)
				{
					fontSize = Mathf.RoundToInt(13f * UiScale)
				};
				foldoutStyle = new GUIStyle(GUI.skin.button)
				{
					fontSize = Mathf.RoundToInt(13f * UiScale),
					alignment = (TextAnchor)3,
					padding = new RectOffset(8, 8, Mathf.RoundToInt(6f * UiScale), Mathf.RoundToInt(6f * UiScale))
				};
				buttonNormalBgTex = MakeSolidColorTex(new Color(0.2f, 0.2f, 0.2f, 0.95f));
				buttonHoverBgTex = MakeSolidColorTex(new Color(0.3f, 0.3f, 0.3f, 0.95f));
				GUIStyle val7 = new GUIStyle(GUI.skin.button)
				{
					fontSize = Mathf.RoundToInt(13f * UiScale),
					margin = new RectOffset(5, 5, 5, 5),
					padding = new RectOffset(8, 8, Mathf.RoundToInt(6f * UiScale), Mathf.RoundToInt(6f * UiScale))
				};
				val7.normal.background = buttonNormalBgTex;
				val7.hover.background = buttonHoverBgTex;
				buttonStyle = val7;
				sliderBgTex = MakeSolidColorTex(new Color(0.15f, 0.15f, 0.15f, 1f));
				sliderThumbTex = MakeSolidColorTex(new Color(1f, 0.6f, 0f, 1f));
				GUIStyle val8 = new GUIStyle(GUI.skin.horizontalSlider);
				val8.normal.background = sliderBgTex;
				val8.fixedHeight = Mathf.RoundToInt(12f * UiScale);
				sliderStyle = val8;
				GUIStyle val9 = new GUIStyle(GUI.skin.horizontalSliderThumb);
				val9.normal.background = sliderThumbTex;
				val9.fixedWidth = Mathf.RoundToInt(16f * UiScale);
				val9.fixedHeight = Mathf.RoundToInt(16f * UiScale);
				sliderThumbStyle = val9;
				if ((Object)(object)val != (Object)null)
				{
					labelStyle.font = val;
					smallLabelStyle.font = val;
					headerStyle.font = val;
					buttonStyle.font = val;
					toggleStyle.font = val;
					foldoutStyle.font = val;
				}
				initializedStyles = true;
			}
		}

		private void OnGUI()
		{
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: Unknown result type (might be due to invalid IL or missing references)
			//IL_0157: 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_0e0e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0e32: Unknown result type (might be due to invalid IL or missing references)
			//IL_0e37: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)Player.localPlayer == (Object)null || (Object)(object)photonView == (Object)null)
			{
				return;
			}
			InitStyles();
			if (!initializedStyles)
			{
				return;
			}
			GUIManager instance = GUIManager.instance;
			if (instance != null)
			{
				GameObject pauseMenu = instance.pauseMenu;
				if (((pauseMenu != null) ? new bool?(pauseMenu.activeSelf) : null).GetValueOrDefault())
				{
					float num = 10f;
					float num2 = Mathf.Min(720f, (float)Screen.width - 2f * num);
					float num3 = (float)Screen.height - 2f * num;
					Rect val = default(Rect);
					((Rect)(ref val))..ctor(num, num, num2, num3);
					GUILayout.BeginArea(val, boxStyle);
					panelScroll = GUILayout.BeginScrollView(panelScroll, (GUILayoutOption[])(object)new GUILayoutOption[2]
					{
						GUILayout.Width(num2 - 8f),
						GUILayout.Height(num3 - 8f)
					});
					GUILayout.Label("【BingBong Player】", headerStyle, Array.Empty<GUILayoutOption>());
					GUILayout.Label(ActAsHost() ? "※ You are the acting host." : "※ Waiting for host…", smallLabelStyle, Array.Empty<GUILayoutOption>());
					bool flag = Player.localPlayer.HasInAnySlot((ushort)13);
					if (flag || PublicEnqueue)
					{
						GUILayout.Space(4f * UiScale);
						GUILayout.Label("URL:", labelStyle, Array.Empty<GUILayoutOption>());
						GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
						urlInput = GUILayout.TextField(urlInput, (GUILayoutOption[])(object)new GUILayoutOption[2]
						{
							GUILayout.Width(num2 - 180f),
							GUILayout.Height(26f * UiScale)
						});
						if (GUILayout.Button("Clear", buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[2]
						{
							GUILayout.Width(70f),
							GUILayout.Height(26f * UiScale)
						}))
						{
							urlInput = "";
						}
						if (GUILayout.Button("Add »", buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[2]
						{
							GUILayout.Width(70f),
							GUILayout.Height(26f * UiScale)
						}))
						{
							RequestEnqueue(urlInput);
						}
						GUILayout.EndHorizontal();
						GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
						bool enabled = flag || PublicEnqueue;
						GUI.enabled = enabled;
						if (GUILayout.Button("Stop", buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(26f * UiScale) }))
						{
							photonView.RPC("RPC_RequestStop", (RpcTarget)0, Array.Empty<object>());
						}
						if (GUILayout.Button("〈〈 10s", buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(26f * UiScale) }))
						{
							photonView.RPC("RPC_RequestSeek", (RpcTarget)0, new object[1] { -10f });
						}
						if (GUILayout.Button("10s 〉〉", buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(26f * UiScale) }))
						{
							photonView.RPC("RPC_RequestSeek", (RpcTarget)0, new object[1] { 10f });
						}
						if (GUILayout.Button("Next »", buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(26f * UiScale) }))
						{
							photonView.RPC("RPC_RequestNext", (RpcTarget)0, Array.Empty<object>());
						}
						GUI.enabled = true;
						if (!flag && PublicEnqueue)
						{
							GUILayout.Label("※ Public enqueue is enabled.", smallLabelStyle, Array.Empty<GUILayoutOption>());
						}
						GUILayout.EndHorizontal();
					}
					GUILayout.Space(8f * UiScale);
					GUILayout.Box("", (GUILayoutOption[])(object)new GUILayoutOption[2]
					{
						GUILayout.ExpandWidth(true),
						GUILayout.Height(1f)
					});
					GUILayout.Space(8f * UiScale);
					GUILayout.Label($"Local Volume: {Mathf.RoundToInt(currentVolume * 100f)}%", labelStyle, Array.Empty<GUILayoutOption>());
					float num4 = GUILayout.HorizontalSlider(currentVolume, 0f, 1f, sliderStyle, sliderThumbStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(num2 - 40f) });
					if (Mathf.Abs(num4 - currentVolume) > 0.001f)
					{
						currentVolume = num4;
						if (volumeSetting != null)
						{
							volumeSetting.Value = num4;
						}
						if ((Object)(object)audioSource != (Object)null)
						{
							audioSource.volume = currentVolume;
						}
					}
					GUILayout.Space(8f * UiScale);
					GUILayout.Box("", (GUILayoutOption[])(object)new GUILayoutOption[2]
					{
						GUILayout.ExpandWidth(true),
						GUILayout.Height(1f)
					});
					GUILayout.Space(8f * UiScale);
					bool flag2 = ShowAdvanced;
					string text = (flag2 ? "▼ Advanced" : "► Advanced");
					if (GUILayout.Button(text, foldoutStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(26f * UiScale) }))
					{
						flag2 = !flag2;
						if (showAdvancedCfg != null)
						{
							showAdvancedCfg.Value = flag2;
						}
					}
					if (flag2)
					{
						bool enabled2 = ActAsHost();
						GUI.enabled = enabled2;
						bool flag3 = GUILayout.Toggle(GlobalAudio, " Global Audio (2D / Hear Anywhere)", toggleStyle, Array.Empty<GUILayoutOption>());
						bool flag4 = GUILayout.Toggle(BypassEnv, " Bypass Environment Effects", toggleStyle, Array.Empty<GUILayoutOption>());
						bool flag5 = GUILayout.Toggle(PublicEnqueue, " Allow Public Enqueue (add/controls)", toggleStyle, Array.Empty<GUILayoutOption>());
						if (flag3 != GlobalAudio)
						{
							globalAudioCfg.Value = flag3;
							BroadcastHostConfig();
						}
						if (flag4 != BypassEnv)
						{
							bypassEnvCfg.Value = flag4;
							BroadcastHostConfig();
						}
						if (flag5 != PublicEnqueue)
						{
							publicEnqueueCfg.Value = flag5;
							BroadcastHostConfig();
						}
						if (!GlobalAudio)
						{
							GUILayout.Label($"Max Hearing Distance: {Mathf.RoundToInt(MaxHearingDistance)}m", labelStyle, Array.Empty<GUILayoutOption>());
							float num5 = GUILayout.HorizontalSlider(MaxHearingDistance, 5f, 300f, sliderStyle, sliderThumbStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(num2 - 40f) });
							if (Mathf.Abs(num5 - MaxHearingDistance) > 0.001f)
							{
								maxHearingDistanceCfg.Value = num5;
								BroadcastHostConfig();
							}
						}
						GUILayout.Label($"Max Queue Size: {MaxQueueSize}", smallLabelStyle, Array.Empty<GUILayoutOption>());
						int num6 = Mathf.RoundToInt(GUILayout.HorizontalSlider((float)MaxQueueSize, 5f, 50f, sliderStyle, sliderThumbStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(num2 - 40f) }));
						if (num6 != MaxQueueSize)
						{
							maxQueueSizeCfg.Value = num6;
							BroadcastHostConfig();
						}
						GUILayout.Label($"Per-User Queue Limit: {PerUserQueueLimit}", smallLabelStyle, Array.Empty<GUILayoutOption>());
						int num7 = Mathf.RoundToInt(GUILayout.HorizontalSlider((float)PerUserQueueLimit, 1f, 15f, sliderStyle, sliderThumbStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(num2 - 40f) }));
						if (num7 != PerUserQueueLimit)
						{
							perUserQueueLimitCfg.Value = num7;
							BroadcastHostConfig();
						}
						bool flag6 = GUILayout.Toggle(AllowDuplicates, " Allow Duplicate URLs", toggleStyle, Array.Empty<GUILayoutOption>());
						if (flag6 != AllowDuplicates)
						{
							allowDuplicatesCfg.Value = flag6;
							BroadcastHostConfig();
						}
						bool flag7 = GUILayout.Toggle(AutoAdvance, " Auto-Advance", toggleStyle, Array.Empty<GUILayoutOption>());
						if (flag7 != AutoAdvance)
						{
							autoAdvanceCfg.Value = flag7;
							BroadcastHostConfig();
						}
						GUI.enabled = true;
						GUILayout.Label($"UI Scale: {UiScale:0.00}x", smallLabelStyle, Array.Empty<GUILayoutOption>());
						float num8 = GUILayout.HorizontalSlider(UiScale, 0.75f, 2f, sliderStyle, sliderThumbStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(num2 - 40f) });
						if (Mathf.Abs(num8 - UiScale) > 0.001f)
						{
							uiScaleCfg.Value = num8;
						}
					}
					if (songLoadingState == SongLoadingState.Loading)
					{
						GUILayout.Space(8f * UiScale);
						GUILayout.Box("", (GUILayoutOption[])(object)new GUILayoutOption[2]
						{
							GUILayout.ExpandWidth(true),
							GUILayout.Height(1f)
						});
						GUILayout.Space(8f * UiScale);
						int num9 = Mathf.FloorToInt(Time.time) % LoadingProgress.Length;
						GUILayout.Label(LoadingProgress[num9], labelStyle, Array.Empty<GUILayoutOption>());
					}
					else if (songLoadingState == SongLoadingState.Error)
					{
						GUILayout.Space(8f * UiScale);
						GUILayout.Box("", (GUILayoutOption[])(object)new GUILayoutOption[2]
						{
							GUILayout.ExpandWidth(true),
							GUILayout.Height(1f)
						});
						GUILayout.Space(8f * UiScale);
						GUILayout.Label("ERROR! Couldn't load audio.", labelStyle, Array.Empty<GUILayoutOption>());
					}
					else if (!string.IsNullOrEmpty(currentSongTitle))
					{
						AudioSource? obj = audioSource;
						if ((Object)(object)((obj != null) ? obj.clip : null) != (Object)null && (audioSource.isPlaying || audioSource.time > 0f))
						{
							GUILayout.Space(8f * UiScale);
							GUILayout.Box("", (GUILayoutOption[])(object)new GUILayoutOption[2]
							{
								GUILayout.ExpandWidth(true),
								GUILayout.Height(1f)
							});
							GUILayout.Space(8f * UiScale);
							GUILayout.Label("Now Playing: 「" + currentSongTitle + "」", labelStyle, Array.Empty<GUILayoutOption>());
							int num10 = Mathf.FloorToInt(audioSource.time / 60f);
							int num11 = Mathf.FloorToInt(audioSource.time % 60f);
							int num12 = Mathf.FloorToInt(audioSource.clip.length / 60f);
							int num13 = Mathf.FloorToInt(audioSource.clip.length % 60f);
							GUILayout.Label($"{num10:D2}:{num11:D2} / {num12:D2}:{num13:D2}", labelStyle, Array.Empty<GUILayoutOption>());
						}
					}
					GUILayout.Space(8f * UiScale);
					GUILayout.Box("", (GUILayoutOption[])(object)new GUILayoutOption[2]
					{
						GUILayout.ExpandWidth(true),
						GUILayout.Height(1f)
					});
					GUILayout.Space(8f * UiScale);
					GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
					GUILayout.Label($"【Queue】 ({queue.Count}/{MaxQueueSize})", labelStyle, Array.Empty<GUILayoutOption>());
					GUILayout.FlexibleSpace();
					if (flag || PublicEnqueue)
					{
						if (GUILayout.Button("〜 Shuffle", buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(24f * UiScale) }))
						{
							photonView.RPC("RPC_RequestShuffle", (RpcTarget)0, Array.Empty<object>());
						}
						if (GUILayout.Button("[ ] Clear", buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(24f * UiScale) }))
						{
							photonView.RPC("RPC_RequestClearQueue", (RpcTarget)0, Array.Empty<object>());
						}
					}
					GUILayout.EndHorizontal();
					float num14 = 140f * UiScale;
					float num15 = Mathf.Clamp((float)Screen.height * 0.65f, 160f, (float)Screen.height - 260f);
					float num16 = 22f * UiScale;
					float num17 = Mathf.Clamp((float)queue.Count * num16 + 8f, num14, num15);
					queueScroll = GUILayout.BeginScrollView(queueScroll, (GUILayoutOption[])(object)new GUILayoutOption[2]
					{
						GUILayout.Height(num17),
						GUILayout.Width(num2 - 20f)
					});
					for (int i = 0; i < queue.Count; i++)
					{
						SongRequest songRequest = queue[i];
						string arg = (string.IsNullOrEmpty(songRequest.title) ? "Fetching title…" : songRequest.title);
						GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
						GUILayout.Label($"{i + 1}. • {arg} ({ShortId(songRequest.requestedBy)})", smallLabelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(num2 - 180f) });
						bool enabled3 = flag || PublicEnqueue || songRequest.requestedByActor == LocalActor();
						GUI.enabled = enabled3;
						if (GUILayout.Button("Remove", buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(90f) }))
						{
							photonView.RPC("RPC_RequestRemoveAt", (RpcTarget)0, new object[1] { i });
						}
						GUI.enabled = true;
						GUILayout.EndHorizontal();
					}
					GUILayout.EndScrollView();
					GUILayout.EndScrollView();
					GUILayout.EndArea();
					return;
				}
			}
			if (Player.localPlayer.HasInAnySlot((ushort)13))
			{
				GUILayout.BeginArea(new Rect(10f, 10f, 480f, (float)Mathf.RoundToInt(100f * UiScale)));
				GUILayout.Label("<b>Press [ESC] to access Music Player</b>", labelStyle, Array.Empty<GUILayoutOption>());
				GUILayout.EndArea();
			}
		}

		private string ShortId(string id)
		{
			return string.IsNullOrEmpty(id) ? "??" : ((id.Length <= 6) ? id : id.Substring(0, 6));
		}

		private void RequestEnqueue(string url)
		{
			if (!string.IsNullOrWhiteSpace(url) && IsSupportedMediaUrl(url))
			{
				if (debouncePlayCoroutine != null)
				{
					((MonoBehaviour)this).StopCoroutine(debouncePlayCoroutine);
					debouncePlayCoroutine = null;
				}
				debouncePlayCoroutine = ((MonoBehaviour)this).StartCoroutine(DebounceRequestCoroutine(0.4f, url));
			}
		}

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

		[PunRPC]
		private void RPC_RequestEnqueue(string url, string requestorId, PhotonMessageInfo info)
		{
			//IL_0028: 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)
			if (!IsSupportedMediaUrl(url) || !ActAsHost())
			{
				return;
			}
			int requestorActor = ((info.Sender != null) ? info.Sender.ActorNumber : (-1));
			if (IsYouTubePlaylistUrl(url))
			{
				((MonoBehaviour)this).StartCoroutine(EnqueueYouTubePlaylist(url, requestorId, requestorActor));
				return;
			}
			SongRequest addedItem;
			bool flag = TryEnqueueInternal(url, requestorId, requestorActor, out addedItem, null);
			BroadcastQueue();
			if (flag && addedItem != null && string.IsNullOrEmpty(addedItem.title))
			{
				StartTitleFetchIfNeeded(addedItem.hash, addedItem.url);
			}
			if (!audioSource.isPlaying && songLoadingState != SongLoadingState.Loading)
			{
				PlayNextImpl();
			}
		}

		[PunRPC]
		private void RPC_RequestRemoveAt(int index, PhotonMessageInfo info)
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			if (ActAsHost() && index >= 0 && index < queue.Count)
			{
				int num = ((info.Sender != null) ? info.Sender.ActorNumber : (-1));
				SongRequest songRequest = queue[index];
				if (songRequest.requestedByActor == num || IsRequestorHolder(num) || PublicEnqueue)
				{
					queue.RemoveAt(index);
					BroadcastQueue();
				}
			}
		}

		[PunRPC]
		private void RPC_RequestClearQueue(PhotonMessageInfo info)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			if (ActAsHost())
			{
				int requestorActorNumber = ((info.Sender != null) ? info.Sender.ActorNumber : (-1));
				if (PublicEnqueue || IsRequestorHolder(requestorActorNumber))
				{
					queue.Clear();
					BroadcastQueue();
				}
			}
		}

		[PunRPC]
		private void RPC_RequestNext(PhotonMessageInfo info)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			if (ActAsHost())
			{
				int requestorActorNumber = ((info.Sender != null) ? info.Sender.ActorNumber : (-1));
				if (PublicEnqueue || IsRequestorHolder(requestorActorNumber))
				{
					PlayNextImpl();
				}
			}
		}

		[PunRPC]
		private void RPC_RequestShuffle(PhotonMessageInfo info)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			if (!ActAsHost())
			{
				return;
			}
			int requestorActorNumber = ((info.Sender != null) ? info.Sender.ActorNumber : (-1));
			if (PublicEnqueue || IsRequestorHolder(requestorActorNumber))
			{
				Random random = new Random();
				for (int num = queue.Count - 1; num > 0; num--)
				{
					int num2 = random.Next(num + 1);
					List<SongRequest> list = queue;
					int index = num;
					List<SongRequest> list2 = queue;
					int index2 = num2;
					SongRequest value = queue[num2];
					SongRequest value2 = queue[num];
					list[index] = value;
					list2[index2] = value2;
				}
				BroadcastQueue();
			}
		}

		[PunRPC]
		private void RPC_RequestStop(PhotonMessageInfo info)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			if (ActAsHost())
			{
				int requestorActorNumber = ((info.Sender != null) ? info.Sender.ActorNumber : (-1));
				if (PublicEnqueue || IsRequestorHolder(requestorActorNumber))
				{
					photonView.RPC("RPC_StopAudio", (RpcTarget)0, Array.Empty<object>());
				}
			}
		}

		[PunRPC]
		private void RPC_RequestSeek(float seconds, PhotonMessageInfo info)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			if (ActAsHost())
			{
				int requestorActorNumber = ((info.Sender != null) ? info.Sender.ActorNumber : (-1));
				if ((PublicEnqueue || IsRequestorHolder(requestorActorNumber)) && !((Object)(object)audioSource == (Object)null) && !((Object)(object)audioSource.clip == (Object)null))
				{
					float num = Mathf.Clamp(audioSource.time + seconds, 0f, audioSource.clip.length);
					audioSource.time = num;
					photonView.RPC("RPC_SyncTime", (RpcTarget)1, new object[2] { currentSongHash, num });
				}
			}
		}

		private bool IsYouTubePlaylistUrl(string url)
		{
			if (!Uri.TryCreate(url, UriKind.Absolute, out Uri result))
			{
				return false;
			}
			string text = result.Host.ToLowerInvariant();
			if (!text.Contains("youtube.com") && !text.Contains("youtu.be") && !text.Contains("music.youtube.com"))
			{
				return false;
			}
			NameValueCollection nameValueCollection = HttpUtility.ParseQueryString(result.Query);
			bool flag = !string.IsNullOrEmpty(nameValueCollection["list"]);
			bool flag2 = false;
			if (text.Contains("youtu.be"))
			{
				string value = result.AbsolutePath.Trim('/');
				flag2 = !string.IsNullOrEmpty(value);
			}
			else
			{
				string value2 = nameValueCollection["v"];
				if (!string.IsNullOrEmpty(value2))
				{
					flag2 = true;
				}
				string text2 = result.AbsolutePath.ToLowerInvariant();
				if (text2.StartsWith("/shorts/"))
				{
					flag2 = true;
				}
			}
			return flag && !flag2;
		}

		[IteratorStateMachine(typeof(<EnqueueYouTubePlaylist>d__136))]
		private IEnumerator EnqueueYouTubePlaylist(string playlistUrl, string requestorId, int requestorActor)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <EnqueueYouTubePlaylist>d__136(0)
			{
				<>4__this = this,
				playlistUrl = playlistUrl,
				requestorId = requestorId,
				requestorActor = requestorActor
			};
		}

		private bool TryEnqueueInternal(string url, string requestorId, int requestorActor, out SongRequest? addedItem, string? knownTitle)
		{
			string url2 = url;
			addedItem = null;
			if (queue.Count >= MaxQueueSize)
			{
				return false;
			}
			int num = queue.Count((SongRequest it) => it.requestedByActor == requestorActor);
			if (num >= PerUserQueueLimit)
			{
				return false;
			}
			if (!AllowDuplicates && queue.Any((SongRequest it) => it.url.Equals(url2, StringComparison.OrdinalIgnoreCase)))
			{
				return false;
			}
			string safeSongId = GetSafeSongId(url2);
			string path = Path.Combine(tempAudioDir, "bingbong_" + safeSongId + ".json");
			string text = knownTitle ?? "";
			if (string.IsNullOrEmpty(text) && File.Exists(path))
			{
				try
				{
					text = JsonUtility.FromJson<SongMetadata>(File.ReadAllText(path))?.title ?? "";
				}
				catch
				{
					text = "";
				}
			}
			SongRequest songRequest = new SongRequest
			{
				url = url2,
				hash = safeSongId,
				requestedBy = requestorId,
				requestedByActor = requestorActor,
				title = text
			};
			queue.Add(songRequest);
			addedItem = songRequest;
			if (!string.IsNullOrEmpty(text))
			{
				try
				{
					File.WriteAllText(path, JsonUtility.ToJson((object)new SongMetadata
					{
						title = text
					}));
				}
				catch
				{
				}
			}
			if (string.IsNullOrEmpty(text))
			{
				StartTitleFetchIfNeeded(safeSongId, url2);
			}
			return true;
		}

		private void PlayNextImpl()
		{
			manualStop = false;
			if (queue.Count == 0)
			{
				StopAndResetSong();
				BroadcastQueue();
				return;
			}
			SongRequest songRequest = queue[0];
			queue.RemoveAt(0);
			BroadcastQueue();
			lastUsedPlayer = songRequest.requestedBy;
			PhotonView? obj = photonView;
			if (obj != null)
			{
				obj.RPC("RPC_StopAudio", (RpcTarget)0, Array.Empty<object>());
			}
			PlayAudio(songRequest.url, lastUsedPlayer);
			if (string.IsNullOrEmpty(songRequest.title))
			{
				StartTitleFetchIfNeeded(songRequest.hash, songRequest.url);
			}
		}

		private void BroadcastQueue()
		{
			SongQueueWrapper songQueueWrapper = new SongQueueWrapper
			{
				items = queue
			};
			string text = JsonUtility.ToJson((object)songQueueWrapper);
			photonView.RPC("RPC_SyncQueue", (RpcTarget)1, new object[1] { text });
		}

		[PunRPC]
		private void RPC_SyncQueue(string json)
		{
			try
			{
				SongQueueWrapper songQueueWrapper = JsonUtility.FromJson<SongQueueWrapper>(json);
				if (songQueueWrapper != null && songQueueWrapper.items != null)
				{
					queue.Clear();
					queue.AddRange(songQueueWrapper.items.Take(MaxQueueSize));
				}
			}
			catch
			{
			}
		}

		[IteratorStateMachine(typeof(<DebouncePlayCoroutine>d__141))]
		private IEnumerator DebouncePlayCoroutine(float delay, string url, string userId)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <DebouncePlayCoroutine>d__141(0)
			{
				<>4__this = this,
				delay = delay,
				url = url,
				userId = userId
			};
		}

		[PunRPC]
		private void RPC_PlayAudio(string url, string userId, PhotonMessageInfo info)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			if ((info.Sender == null || info.Sender.IsMasterClient || !hostHasMod) && !string.IsNullOrWhiteSpace(url) && IsSupportedMediaUrl(url))
			{
				if (debouncePlayCoroutine != null)
				{
					((MonoBehaviour)this).StopCoroutine(debouncePlayCoroutine);
					debouncePlayCoroutine = null;
				}
				debouncePlayCoroutine = ((MonoBehaviour)this).StartCoroutine(DebouncePlayCoroutine(1f, url, userId));
			}
		}

		private void PlayAudio(string url, string userId)
		{
			debouncePlayCoroutine = null;
			if (string.IsNullOrWhiteSpace(url) || !IsSupportedMediaUrl(url))
			{
				return;
			}
			lastUsedPlayer = userId;
			manualStop = false;
			if (ActAsHost())
			{
				AudioSource? obj = audioSource;
				if (obj != null)
				{
					obj.Stop();
				}
				PhotonView? obj2 = photonView;
				if (obj2 != null)
				{
					obj2.RPC("RPC_StopAudio", (RpcTarget)1, Array.Empty<object>());
				}
				PhotonView? obj3 = photonView;
				if (obj3 != null)
				{
					obj3.RPC("RPC_PlayAudio", (RpcTarget)1, new object[2] { url, userId });
				}
			}
			currentSongTitle = "Unknown";
			currentSongHash = GetSafeSongId(url);
			string text = Path.Combine(tempAudioDir, "bingbong_" + currentSongHash + ".wav");
			string text2 = Path.Combine(tempAudioDir, "bingbong_" + currentSongHash + ".json");
			if (File.Exists(text2))
			{
				try
				{
					string text3 = File.ReadAllText(text2);
					SongMetadata songMetadata = JsonUtility.FromJson<SongMetadata>(text3);
					if (!string.IsNullOrEmpty(songMetadata?.title))
					{
						currentSongTitle = songMetadata.title;
					}
				}
				catch
				{
					currentSongTitle = "Unknown";
				}
			}
			if (currentPlaybackCoroutine != null)
			{
				((MonoBehaviour)this).StopCoroutine(currentPlaybackCoroutine);
			}
			if (File.Exists(text))
			{
				currentPlaybackCoroutine = ((MonoBehaviour)this).StartCoroutine(LoadAndPlay(text));
				return;
			}
			if (downloadCoroutine != null)
			{
				((MonoBehaviour)this).StopCoroutine(downloadCoroutine);
				downloadCoroutine = null;
			}
			downloadCoroutine = ((MonoBehaviour)this).StartCoroutine(DownloadAudio(url, text, text2));
		}

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

		private string GetSafeSongId(string url)
		{
			try
			{
				Uri uri = new Uri(url);
				string text = uri.Host.ToLowerInvariant();
				if (text.Contains("youtu.be"))
				{
					string text2 = uri.AbsolutePath.Trim('/');
					if (!string.IsNullOrEmpty(text2))
					{
						return text2;
					}
				}
				if (text.Contains("youtube.com") || text.Contains("music.youtube.com"))
				{
					NameValueCollection nameValueCollection = HttpUtility.ParseQueryString(uri.Query);
					string text3 = nameValueCollection["v"];
					if (!string.IsNullOrEmpty(text3))
					{
						return text3;
					}
					string text4 = uri.AbsolutePath.Trim('/');
					if (text4.StartsWith("shorts/", StringComparison.OrdinalIgnoreCase))
					{
						string[] array = text4.Split('/');
						if (array.Length >= 2 && array[1].Length > 0)
						{
							return array[1];
						}
					}
				}
			}
			catch
			{
			}
			using SHA1 sHA = SHA1.Create();
			byte[] array2 = sHA.ComputeHash(Encoding.UTF8.GetBytes(url));
			return BitConverter.ToString(array2, 0, 6).Replace("-", "");
		}

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

		[PunRPC]
		private void RPC_StopAudio()
		{
			manualStop = true;
			if ((Object)(object)audioSource != (Object)null)
			{
				audioSource.Stop();
				audioSource.clip = null;
			}
		}

		[PunRPC]
		private void RPC_SyncTime(string songHash, float hostTime)
		{
			if (!ActAsHost() && (Object)(object)audioSource != (Object)null && (Object)(object)audioSource.clip != (Object)null && songHash == currentSongHash && Mathf.Abs(audioSource.time - hostTime) > 0.5f && hostTime >= 0f && hostTime <= audioSource.clip.length)
			{
				audioSource.time = hostTime;
			}
		}

		[PunRPC]
		private void RPC_SyncPlaying(string songHash, bool hostIsPlaying, bool isOwner, string hostTitle)
		{
			if (isOwner)
			{
				hostHasMod = true;
			}
			if (!string.IsNullOrEmpty(hostTitle))
			{
				currentSongTitle = hostTitle;
			}
			if (!ActAsHost() && (Object)(object)audioSource != (Object)null)
			{
				if (!audioSource.isPlaying && hostIsPlaying && (Object)(object)audioSource.clip != (Object)null && songHash == currentSongHash)
				{
					audioSource.Play();
				}
				if (audioSource.isPlaying && (!hostIsPlaying || songHash != currentSongHash))
				{
					audioSource.Stop();
				}
			}
		}

		private void StopAndResetSong()
		{
			if (currentPlaybackCoroutine != null)
			{
				((MonoBehaviour)this).StopCoroutine(currentPlaybackCoroutine);
			}
			AudioSource? obj = audioSource;
			if (obj != null)
			{
				obj.Stop();
			}
			if ((Object)(object)audioSource != (Object)null)
			{
				audioSource.clip = null;
			}
			songLoadingState = SongLoadingState.Loaded;
			currentSongTitle = "";
			currentSongHash = "";
			lastUsedPlayer = "";
			manualStop = false;
			hostHasMod = PhotonNetwork.IsMasterClient;
		}

		private void CleanupOldTempFiles()
		{
			if (string.IsNullOrEmpty(tempAudioDir) || !Directory.Exists(tempAudioDir))
			{
				return;
			}
			List<FileInfo> list = (from f in new DirectoryInfo(tempAudioDir).GetFiles("bingbong_*.wav")
				orderby f.LastAccessTimeUtc descending
				select f).ToList();
			for (int i = MaxTempFiles; i < list.Count; i++)
			{
				FileInfo fileInfo = list[i];
				try
				{
					fileInfo.Delete();
				}
				catch
				{
				}
				string path = Path.ChangeExtension(fileInfo.FullName, ".json");
				if (File.Exists(path))
				{
					try
					{
						File.Delete(path);
					}
					catch
					{
					}
				}
			}
		}

		private bool IsSupportedMediaUrl(string url)
		{
			if (!Uri.TryCreate(url, UriKind.Absolute, out Uri result))
			{
				return false;
			}
			string value = result.Host.ToLowerInvariant();
			if (AllowedHosts.Contains(value))
			{
				return true;
			}
			return result.Scheme == Uri.UriSchemeHttp || result.Scheme == Uri.UriSchemeHttps;
		}

		private void StartTitleFetchIfNeeded(string hash, string url)
		{
			if (!ActAsHost() || titleFetchInProgress.Contains(hash))
			{
				return;
			}
			string path = Path.Combine(tempAudioDir, "bingbong_" + hash + ".json");
			if (File.Exists(path))
			{
				try
				{
					SongMetadata songMetadata = JsonUtility.FromJson<SongMetadata>(File.ReadAllText(path));
					if (!string.IsNullOrEmpty(songMetadata?.title))
					{
						UpdateQueueTitle(hash, songMetadata.title);
						return;
					}
				}
				catch
				{
				}
			}
			((MonoBehaviour)this).StartCoroutine(FetchTitleCoroutine(hash, url));
		}

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

		private void UpdateQueueTitle(string hash, string title)
		{
			bool flag = false;
			for (int i = 0; i < queue.Count; i++)
			{
				if (queue[i].hash == hash && string.IsNullOrEmpty(queue[i].title))
				{
					queue[i].title = title;
					flag = true;
				}
			}
			if (flag)
			{
				BroadcastQueue();
			}
			if (currentSongHash == hash && (string.IsNullOrEmpty(currentSongTitle) || currentSongTitle == "Unknown"))
			{
				currentSongTitle = title;
			}
		}
	}
}