Decompiled source of CarretaFuracao v0.7.9

BepInEx\plugins\CarretaFuracao\CarretaFuracao.dll

Decompiled 2 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using BoomBoxCartMod.Patches;
using BoomBoxCartMod.Util;
using ExitGames.Client.Photon;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using Photon.Pun;
using Photon.Realtime;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.Networking;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("CarretaFuracao")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("CarretaFuracao")]
[assembly: AssemblyCopyright("Copyright © 2025")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("37e852e0-b511-4315-8182-68c0a54e1ba9")]
[assembly: AssemblyFileVersion("0.7.9.0")]
[assembly: AssemblyVersion("0.7.9.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[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 BoomBoxCartMod
{
	[BepInPlugin("LucasGPT.CarretaFuracao", "CarretaFuracao", "0.7.9")]
	public class BoomBoxCartMod : BaseUnityPlugin
	{
		public enum VisualizerPaused
		{
			Show,
			PausePosition,
			Hide
		}

		public enum CookieUsage
		{
			OFF,
			FILE,
			BROWSER
		}

		public enum BrowserType
		{
			chrome,
			firefox,
			edge,
			brave,
			safari
		}

		public const string modGUID = "LucasGPT.CarretaFuracao";

		public const string modName = "CarretaFuracao";

		public const string modVersion = "0.7.9";

		private readonly Harmony harmony = new Harmony("LucasGPT.CarretaFuracao");

		public BaseListener baseListener;

		internal static BoomBoxCartMod instance;

		internal ManualLogSource logger;

		public PersistentData data;

		private bool _modDisabled;

		private bool resourcesReinstalling;

		public bool initialized { get; private set; }

		public bool modDisabled
		{
			get
			{
				return _modDisabled;
			}
			set
			{
				if (_modDisabled != value)
				{
					logger.LogInfo((object)("Mod " + (value ? "Disabled" : "Enabled")));
				}
				_modDisabled = value;
				if (!value || data == null)
				{
					return;
				}
				foreach (Boombox allBoombox in data.GetAllBoomboxes())
				{
					PhotonView photonView = allBoombox.photonView;
					Object.Destroy((Object)(object)allBoombox);
					if (photonView != null)
					{
						photonView.RefreshRpcMonoBehaviourCache();
					}
				}
				data.GetAllBoomboxes().Clear();
				data.GetBoomboxData().Clear();
			}
		}

		public ConfigEntry<CookieUsage> CookiePassthrough { get; private set; }

		public ConfigEntry<string> CookiePath { get; private set; }

		public ConfigEntry<BrowserType> Browser { get; private set; }

		public ConfigEntry<int> DownloadSpeed { get; private set; }

		public ConfigEntry<Key> OpenUIKey { get; private set; }

		public ConfigEntry<Key> MenuKey { get; private set; }

		public ConfigEntry<Key> GlobalMuteKey { get; private set; }

		public ConfigEntry<bool> MasterClientDismissQueue { get; private set; }

		public ConfigEntry<bool> UseTimeStampOnce { get; private set; }

		public ConfigEntry<bool> RestoreBoomboxes { get; private set; }

		public ConfigEntry<bool> AutoResume { get; private set; }

		public ConfigEntry<float> UnderglowBeatSpeed { get; private set; }

		public ConfigEntry<float> UnderglowBassBias { get; private set; }

		public ConfigEntry<VisualizerPaused> VisualizerBehaviourPaused { get; private set; }

		public ConfigEntry<bool> SyncVisuals { get; private set; }

		public ConfigEntry<bool> ReinstallResources { get; private set; }

		private void Update()
		{
			Boombox.TickRuntime();
		}

		private void Awake()
		{
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Expected O, but got Unknown
			//IL_021d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0227: Expected O, but got Unknown
			//IL_025b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0265: Expected O, but got Unknown
			if ((Object)(object)instance == (Object)null)
			{
				instance = this;
			}
			data = new PersistentData();
			logger = Logger.CreateLogSource("LucasGPT.CarretaFuracao");
			logger.LogInfo((object)"BoomBoxCartMod loaded!");
			logger.LogInfo((object)"CarretaFuracao 0.7.9");
			AudioSettings.Initialize(((BaseUnityPlugin)this).Config);
			LocalMusic.Initialize();
			harmony.PatchAll();
			CookiePassthrough = ((BaseUnityPlugin)this).Config.Bind<CookieUsage>("Downloader", "CookiePassthrough", CookieUsage.OFF, "Pass cookies from either your browser or an exported file. (OFF, FILE, BROWSER)");
			CookiePath = ((BaseUnityPlugin)this).Config.Bind<string>("Downloader", "CustomCookiePath", "", "Path to where the browser cookies are located, if the browser selection does not work.");
			Browser = ((BaseUnityPlugin)this).Config.Bind<BrowserType>("Downloader", "BrowserCookies", BrowserType.firefox, "Select the browser you are using for cookies (chrome, firefox, edge, brave, safari). This is unlikely to work.");
			DownloadSpeed = ((BaseUnityPlugin)this).Config.Bind<int>("Downloader", "DownloadSpeed", 10, new ConfigDescription("Estimated download speed in Mbps (not MBps). Used for download timeout estimation.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 100), Array.Empty<object>()));
			OpenUIKey = ((BaseUnityPlugin)this).Config.Bind<Key>("Binds", "OpenUIKey", (Key)19, "Press E to turn CarretaFuracao on/off while grabbing the cart.");
			MenuKey = ((BaseUnityPlugin)this).Config.Bind<Key>("Binds", "MenuKey", (Key)39, "Press Y to open/close the compact CarretaFuracao controls while grabbing the cart.");
			GlobalMuteKey = ((BaseUnityPlugin)this).Config.Bind<Key>("Binds", "GlobalMuteKey", (Key)27, "Key to mute all playback.");
			MasterClientDismissQueue = ((BaseUnityPlugin)this).Config.Bind<bool>("Queue", "MasterClientDismissQueue", true, "Allow only the master client to dismiss the queue.");
			UseTimeStampOnce = ((BaseUnityPlugin)this).Config.Bind<bool>("Queue", "UseTimeStampOnce", false, "Only use the timestamp provided with a Url the first time the song is played.");
			RestoreBoomboxes = ((BaseUnityPlugin)this).Config.Bind<bool>("Queue", "RestoreBoomboxes", true, "Restore BoomBoxes and their Queues when you load back into a level.");
			AutoResume = ((BaseUnityPlugin)this).Config.Bind<bool>("Queue", "AutoResume", false, "Automatically resume playback when entering a new lobby.");
			UnderglowBeatSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("Visual", "UnderglowBeatSpeed", 1.2f, new ConfigDescription("Scales how much detected beat energy speeds up the RGB underglow cycle. 0 = disabled, 6 = more aggressive.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 6f), Array.Empty<object>()));
			UnderglowBassBias = ((BaseUnityPlugin)this).Config.Bind<float>("Visual", "UnderglowBassBias", 0.8f, new ConfigDescription("Blends between broad beat response and isolated low-band response. 0 = broad response, 1 = strongest bass isolation.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
			VisualizerBehaviourPaused = ((BaseUnityPlugin)this).Config.Bind<VisualizerPaused>("Visual", "VisualizerOnPaused", VisualizerPaused.Hide, "Visualizer behaviour when music is paused.");
			SyncVisuals = ((BaseUnityPlugin)this).Config.Bind<bool>("Visual", "SyncVisuals", true, "Sync if underglow/visualizer are enabled with the lobby, or only apply it to yourself.");
			ReinstallResources = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "ReinstallResources", false, "Reinstall resources on startup.");
			ReinstallResources.SettingChanged += delegate(object s, EventArgs _)
			{
				if (initialized)
				{
					ConfigEntry<bool> val = (ConfigEntry<bool>)s;
					if (resourcesReinstalling)
					{
						if (!val.Value)
						{
							val.Value = true;
						}
					}
					else if (YoutubeDL.IsUpdatingResources)
					{
						logger.LogInfo((object)"Already updating resources...");
						val.Value = false;
					}
					else
					{
						if (val.Value)
						{
							logger.LogInfo((object)"Reinstalling resources...");
							resourcesReinstalling = true;
						}
						Task.Run(async delegate
						{
							await YoutubeDL.Reinstall();
							logger.LogInfo((object)"Finished reinstalling resources.");
							ReinstallResources.Value = false;
							resourcesReinstalling = false;
						});
					}
				}
			};
			logger.LogInfo((object)"BoomBoxCartMod initialization finished!");
			initialized = true;
		}

		private void Start()
		{
			if (ReinstallResources.Value)
			{
				ReinstallResources.Value = true;
			}
			else
			{
				logger.LogInfo((object)"CarretaFuracao: modo local pronto. Downloader online nao sera inicializado no startup.");
			}
		}

		private void OnDestroy()
		{
			YoutubeDL.CleanUp();
		}
	}
	public class AudioPlayer : MonoBehaviourPunCallbacks
	{
		private static BoomBoxCartMod Instance = BoomBoxCartMod.instance;

		public float minDistance = 3f;

		public float maxDistanceBase = 15f;

		public float maxDistanceAddition = 30f;

		private static int qualityLevel = 4;

		private AudioLowPassFilter lowPassFilter;

		private AudioEchoFilter cartDelay;

		public AudioSource audioSource;

		public string currentUrl;

		private static ManualLogSource Logger => Instance.logger;

		private void Awake()
		{
			audioSource = ((Component)this).gameObject.AddComponent<AudioSource>();
			audioSource.volume = 0.15f;
			audioSource.spatialBlend = 1f;
			audioSource.playOnAwake = false;
			audioSource.rolloffMode = (AudioRolloffMode)2;
			audioSource.spread = 90f;
			audioSource.dopplerLevel = 0f;
			audioSource.reverbZoneMix = 1f;
			audioSource.spatialize = true;
			audioSource.loop = false;
			audioSource.mute = Instance.baseListener.audioMuted;
			lowPassFilter = ((Component)this).gameObject.AddComponent<AudioLowPassFilter>();
			((Behaviour)lowPassFilter).enabled = false;
			UpdateAudioRangeBasedOnVolume();
		}

		private void Update()
		{
			if (Instance.baseListener.audioMuted != audioSource.mute)
			{
				audioSource.mute = Instance.baseListener.audioMuted;
			}
		}

		public AudioClip GetClip()
		{
			if (!((Object)(object)audioSource == (Object)null))
			{
				return audioSource.clip;
			}
			return null;
		}

		public void SetDelayedOutput(bool delayed)
		{
			if ((Object)(object)cartDelay == (Object)null && delayed)
			{
				cartDelay = ((Component)this).gameObject.AddComponent<AudioEchoFilter>();
				cartDelay.delay = 25f;
				cartDelay.decayRatio = 0f;
				cartDelay.dryMix = 0f;
				cartDelay.wetMix = 1f;
			}
			if ((Object)(object)cartDelay != (Object)null)
			{
				((Behaviour)cartDelay).enabled = delayed;
			}
		}

		public void SetVolume(float volume)
		{
			audioSource.volume = volume;
			UpdateAudioRangeBasedOnVolume();
		}

		public void UpdateAudioRangeBasedOnVolume()
		{
			UpdateAudioRangeBasedOnVolume(audioSource.volume);
		}

		public void UpdateAudioRangeBasedOnVolume(float volume)
		{
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Expected O, but got Unknown
			float num = Mathf.Lerp(maxDistanceBase, maxDistanceBase + maxDistanceAddition, volume);
			audioSource.minDistance = minDistance;
			audioSource.maxDistance = num;
			AnimationCurve val = new AnimationCurve((Keyframe[])(object)new Keyframe[3]
			{
				new Keyframe(0f, 1f),
				new Keyframe(minDistance, 0.9f),
				new Keyframe(num, 0f)
			});
			audioSource.SetCustomCurve((AudioSourceCurveType)0, val);
		}

		public void SetClip(string url)
		{
			if (url != null && (!(url == currentUrl) || !((Object)(object)audioSource.clip != (Object)null)) && DownloadHelper.downloadedClips.TryGetValue(url, out var value) && (Object)(object)value != (Object)null)
			{
				audioSource.clip = value;
				currentUrl = url;
			}
		}

		public void SetQuality(int level)
		{
			qualityLevel = Mathf.Clamp(level, 0, 4);
			switch (qualityLevel)
			{
			case 0:
				((Behaviour)lowPassFilter).enabled = true;
				lowPassFilter.cutoffFrequency = 1500f;
				break;
			case 1:
				((Behaviour)lowPassFilter).enabled = true;
				lowPassFilter.cutoffFrequency = 3000f;
				break;
			case 2:
				((Behaviour)lowPassFilter).enabled = true;
				lowPassFilter.cutoffFrequency = 4500f;
				break;
			case 3:
				((Behaviour)lowPassFilter).enabled = true;
				lowPassFilter.cutoffFrequency = 6000f;
				break;
			case 4:
				((Behaviour)lowPassFilter).enabled = false;
				break;
			}
		}

		public static int GetQuality()
		{
			return qualityLevel;
		}

		public float GetTime()
		{
			return audioSource.time;
		}

		public void SetTime(float time)
		{
			if ((Object)(object)audioSource.clip != (Object)null && time > audioSource.clip.length)
			{
				time = Mathf.Max(0f, audioSource.clip.length - 0.05f);
				Logger.LogDebug((object)$"SetTime: Clamped time from {audioSource.time} to {time} (clip length: {audioSource.clip.length})");
			}
			audioSource.time = time;
		}

		public bool IsPlaying()
		{
			return audioSource.isPlaying;
		}

		public bool SongReachedEnd()
		{
			if ((Object)(object)audioSource.clip != (Object)null)
			{
				return audioSource.time >= Math.Max(0f, audioSource.clip.length - 0.05f);
			}
			return false;
		}

		public void Play()
		{
			audioSource.Play();
		}

		public void Pause()
		{
			audioSource.Pause();
		}

		public void Stop()
		{
			if (!((Object)(object)audioSource == (Object)null))
			{
				audioSource.Stop();
				audioSource.clip = null;
				currentUrl = null;
			}
		}

		private void OnDestroy()
		{
			Stop();
			Object.Destroy((Object)(object)lowPassFilter);
			if ((Object)(object)cartDelay != (Object)null)
			{
				Object.Destroy((Object)(object)cartDelay);
			}
			Object.Destroy((Object)(object)audioSource);
		}
	}
	public class Boombox : MonoBehaviourPunCallbacks
	{
		private class SharedAudioEntry
		{
			public string title;

			public string url;

			public double duration;

			public int startTime;
		}

		public class BoomboxData
		{
			public string key = Guid.NewGuid().ToString();

			public AudioEntry currentSong;

			public List<AudioEntry> playbackQueue = new List<AudioEntry>();

			public bool isPlaying;

			public float absVolume = AudioSettings.MasterValue;

			public float personalVolumePercentage = AudioSettings.PersonalValue;

			public bool loopQueue;

			public bool delayedOutput;

			public bool underglowEnabled;

			public bool visualizerEnabled = true;

			public bool pendingPlaybackStart;

			public int stateVersion;

			public int playbackTime;

			public int playbackStartTimestamp;
		}

		public class AudioEntry
		{
			public string Title;

			public string Url;

			public double Duration = -1.0;

			public int StartTime;

			public AudioEntry(string url, SongInfo info)
			{
				Url = url;
				Title = info.title;
				Duration = info.duration;
			}

			private int PeekStartTime(Boombox boombox)
			{
				if (boombox.data != null && boombox.data.playbackTime != 0)
				{
					return boombox.data.playbackTime;
				}
				return StartTime;
			}

			public int UseStartTime(Boombox boombox)
			{
				int result = PeekStartTime(boombox);
				if (boombox.data != null && boombox.data.playbackTime != 0)
				{
					boombox.data.playbackTime = 0;
					return result;
				}
				if (Instance.UseTimeStampOnce.Value)
				{
					StartTime = 0;
				}
				return result;
			}

			public bool ClipLoaded()
			{
				if (DownloadHelper.downloadedClips.ContainsKey(Url))
				{
					return (Object)(object)DownloadHelper.downloadedClips[Url] != (Object)null;
				}
				return false;
			}
		}

		public PhotonView photonView;

		public AudioPlayer audioPlayer;

		public Visualizer visualizer;

		public VisualEffects visualEffects;

		public DownloadHelper downloadHelper;

		private bool syncFinished;

		public bool startPlayBackOnDownload = true;

		public BoomboxData data = new BoomboxData();

		private static bool mutePressed = false;

		private bool isApplyingSharedState;

		private string pendingCurrentSongDownloadUrl;

		private int lastAppliedSharedStateVersion = -1;

		private Hashtable lastSharedState;

		private static readonly List<string> levelPlaylistOrderKeys = new List<string>();

		private static int levelPlaylistIndex = 0;

		private static bool levelHasStartedPlayback = false;

		private static readonly HashSet<Boombox> liveCarretas = new HashSet<Boombox>();

		private static int lastRuntimeFrame = -1;

		private static int lastGlobalAdvanceServerTimestamp = int.MinValue;

		private float nextFollowerSyncTime;

		private bool runtimeStartLogged;

		private string nextPreparedUrl;

		private float monsterAttractTimer;

		private const float monsterAttractInterval = 1f;

		private static bool applyQualityToDownloads = false;

		private static bool monstersCanHearMusic = false;

		private static BoomBoxCartMod Instance => BoomBoxCartMod.instance;

		private static ManualLogSource Logger => Instance.logger;

		public static bool ApplyQualityToDownloads
		{
			get
			{
				return applyQualityToDownloads;
			}
			set
			{
				applyQualityToDownloads = value;
			}
		}

		public static bool MonstersCanHearMusic
		{
			get
			{
				return monstersCanHearMusic;
			}
			set
			{
				monstersCanHearMusic = value;
			}
		}

		public bool LoopQueue
		{
			get
			{
				return data.loopQueue;
			}
			set
			{
				data.loopQueue = value;
			}
		}

		private void Awake()
		{
			audioPlayer = ((Component)this).gameObject.AddComponent<AudioPlayer>();
			downloadHelper = ((Component)this).gameObject.AddComponent<DownloadHelper>();
			photonView = ((Component)this).GetComponent<PhotonView>();
			if ((Object)(object)photonView == (Object)null)
			{
				Logger.LogError((object)"PhotonView not found on Boombox object.");
				return;
			}
			if ((Object)(object)((Component)this).GetComponent<BoomboxController>() == (Object)null)
			{
				((Component)this).gameObject.AddComponent<BoomboxController>();
			}
			if ((Object)(object)((Component)this).GetComponent<Visualizer>() == (Object)null)
			{
				visualizer = ((Component)this).gameObject.AddComponent<Visualizer>();
				visualizer.audioSource = audioPlayer.audioSource;
			}
			if ((Object)(object)((Component)this).GetComponent<VisualEffects>() == (Object)null)
			{
				visualEffects = ((Component)this).gameObject.AddComponent<VisualEffects>();
			}
			RegisterRuntimeCart(this);
			PersistentData.SetBoomboxViewInitialized(photonView.ViewID);
			Logger.LogInfo((object)$"Boombox initialized on this cart. AudioPlayer: {audioPlayer}, PhotonView: {photonView}");
		}

		private void Start()
		{
			audioPlayer.SetVolume(data.absVolume * data.personalVolumePercentage);
			audioPlayer.SetDelayedOutput(data.delayedOutput);
			ApplyVisualStateFromData();
			LoadSharedStateFromRoom();
		}

		public static void ResetLevelPlaylistSession()
		{
			levelPlaylistOrderKeys.Clear();
			levelPlaylistIndex = 0;
			levelHasStartedPlayback = false;
			lastGlobalAdvanceServerTimestamp = int.MinValue;
			if (!PhotonNetwork.IsMasterClient)
			{
				return;
			}
			List<LocalMusic.LocalTrack> list = new List<LocalMusic.LocalTrack>(LocalMusic.Tracks);
			Random random = new Random(Guid.NewGuid().GetHashCode());
			for (int num = list.Count - 1; num > 0; num--)
			{
				int index = random.Next(num + 1);
				LocalMusic.LocalTrack value = list[num];
				list[num] = list[index];
				list[index] = value;
			}
			foreach (LocalMusic.LocalTrack item in list)
			{
				if (item != null && !string.IsNullOrWhiteSpace(item.Key))
				{
					levelPlaylistOrderKeys.Add(item.Key);
				}
			}
			BoomBoxCartMod instance = BoomBoxCartMod.instance;
			if (instance != null)
			{
				ManualLogSource logger = instance.logger;
				if (logger != null)
				{
					logger.LogInfo((object)("CarretaFuracao: nova ordem do level criada com " + levelPlaylistOrderKeys.Count + " faixa(s)."));
				}
			}
			int i;
			for (i = 0; i < levelPlaylistOrderKeys.Count; i++)
			{
				LocalMusic.LocalTrack localTrack = LocalMusic.Tracks.FirstOrDefault((LocalMusic.LocalTrack item) => item != null && item.Key == levelPlaylistOrderKeys[i]);
				BoomBoxCartMod instance2 = BoomBoxCartMod.instance;
				if (instance2 != null)
				{
					ManualLogSource logger2 = instance2.logger;
					if (logger2 != null)
					{
						logger2.LogInfo((object)("  ORDEM " + (i + 1) + ": " + ((localTrack != null) ? localTrack.Title : levelPlaylistOrderKeys[i])));
					}
				}
			}
		}

		private void EnsureLevelPlaylistSession()
		{
			if (PhotonNetwork.IsMasterClient && (levelPlaylistOrderKeys.Count != LocalMusic.Tracks.Count || levelPlaylistOrderKeys.Any((string key) => FindLocalTrackByKey(key) == null)))
			{
				ResetLevelPlaylistSession();
			}
		}

		private int GetLevelPlaylistIndexForKey(string key)
		{
			if (string.IsNullOrWhiteSpace(key))
			{
				return -1;
			}
			return levelPlaylistOrderKeys.IndexOf(key);
		}

		public static void RegisterRuntimeCart(Boombox cart)
		{
			if (!((Object)(object)cart == (Object)null) && liveCarretas.Add(cart))
			{
				Logger.LogInfo((object)("CarretaFuracao REGISTER cart=" + cart.photonView.ViewID));
			}
		}

		public static void TickRuntime()
		{
			if (Instance == null || Instance.modDisabled || lastRuntimeFrame == Time.frameCount)
			{
				return;
			}
			lastRuntimeFrame = Time.frameCount;
			foreach (Boombox activeCarreta in GetActiveCarretas())
			{
				try
				{
					activeCarreta.TickPlayback();
				}
				catch (Exception ex)
				{
					Logger.LogError((object)("CarretaFuracao runtime cart=" + activeCarreta.photonView.ViewID + ": " + ex));
				}
			}
		}

		public static List<Boombox> GetRuntimeCarretas()
		{
			return liveCarretas.Where((Boombox cart) => (Object)(object)cart != (Object)null && cart.data != null).ToList();
		}

		private async void PrepareNextTrack()
		{
			if (AudioSettings.Preload == null || !AudioSettings.Preload.Value || data.currentSong == null || !data.currentSong.ClipLoaded() || data.playbackQueue.Count < 2)
			{
				return;
			}
			int currentSongIndex = GetCurrentSongIndex();
			if (currentSongIndex < 0)
			{
				return;
			}
			string url = data.playbackQueue[(currentSongIndex + 1) % data.playbackQueue.Count].Url;
			if (url == nextPreparedUrl || !LocalMusic.IsLocalUrl(url))
			{
				return;
			}
			nextPreparedUrl = url;
			try
			{
				await LocalClipCache.Load(url);
			}
			catch (Exception ex)
			{
				Logger.LogWarning((object)("CarretaFuracao preload: " + ex.Message));
			}
		}

		private static List<Boombox> GetActiveCarretas()
		{
			return (from cart in liveCarretas
				where (Object)(object)cart != (Object)null && cart.data != null && cart.data.currentSong != null && cart.data.playbackQueue != null && cart.data.playbackQueue.Count > 0 && (cart.data.isPlaying || cart.data.pendingPlaybackStart)
				orderby (!((Object)(object)cart.photonView != (Object)null)) ? int.MaxValue : cart.photonView.ViewID
				select cart).ToList();
		}

		private static Boombox GetActiveLeader()
		{
			return GetActiveCarretas().FirstOrDefault();
		}

		private Boombox GetOtherActiveCarreta()
		{
			return GetActiveCarretas().FirstOrDefault((Boombox cart) => (Object)(object)cart != (Object)null && (Object)(object)cart != (Object)(object)this);
		}

		private bool EnsureQueueUsesLevelOrder()
		{
			EnsureLevelPlaylistSession();
			bool flag = data.playbackQueue != null && data.playbackQueue.Count == levelPlaylistOrderKeys.Count;
			if (flag)
			{
				for (int i = 0; i < levelPlaylistOrderKeys.Count; i++)
				{
					AudioEntry audioEntry = data.playbackQueue[i];
					if (audioEntry == null || audioEntry.Url != levelPlaylistOrderKeys[i])
					{
						flag = false;
						break;
					}
				}
			}
			if (flag)
			{
				return false;
			}
			data.playbackQueue.Clear();
			foreach (string levelPlaylistOrderKey in levelPlaylistOrderKeys)
			{
				SongInfo info = (DownloadHelper.songInfo.ContainsKey(levelPlaylistOrderKey) ? DownloadHelper.songInfo[levelPlaylistOrderKey] : new SongInfo());
				data.playbackQueue.Add(new AudioEntry(levelPlaylistOrderKey, info));
			}
			data.currentSong = null;
			return true;
		}

		private void ApplySyncedLevelTrackInternal(int index, int sharedPlaybackStartTimestamp, bool startPlaying)
		{
			if (PhotonNetwork.IsMasterClient)
			{
				bool updateQueue = EnsureQueueUsesLevelOrder();
				if (data.playbackQueue != null && data.playbackQueue.Count != 0)
				{
					index = (index % data.playbackQueue.Count + data.playbackQueue.Count) % data.playbackQueue.Count;
					RegisterRuntimeCart(this);
					runtimeStartLogged = false;
					levelHasStartedPlayback = true;
					levelPlaylistIndex = index;
					data.currentSong = data.playbackQueue[index];
					StopLocalPlayback(updateSharedFlag: true);
					data.playbackTime = 0;
					data.pendingPlaybackStart = false;
					data.isPlaying = startPlaying;
					data.loopQueue = true;
					data.playbackStartTimestamp = sharedPlaybackStartTimestamp;
					startPlayBackOnDownload = true;
					ApplyNativeCarretaLoopState();
					PublishSharedState(updateTime: true, updateQueue, force: true);
					ApplySharedPlaybackState();
				}
			}
		}

		private static void SyncActiveCarretasToIndex(int index, int sharedPlaybackStartTimestamp, Boombox includeIfNone = null)
		{
			if (!PhotonNetwork.IsMasterClient)
			{
				return;
			}
			List<Boombox> activeCarretas = GetActiveCarretas();
			if (activeCarretas.Count == 0 && (Object)(object)includeIfNone != (Object)null)
			{
				activeCarretas.Add(includeIfNone);
			}
			foreach (Boombox item in activeCarretas)
			{
				if (!((Object)(object)item == (Object)null))
				{
					item.ApplySyncedLevelTrackInternal(index, sharedPlaybackStartTimestamp, startPlaying: true);
				}
			}
		}

		private void StartOrJoinSynchronizedPlaybackInternal()
		{
			if (!PhotonNetwork.IsMasterClient)
			{
				return;
			}
			RegisterRuntimeCart(this);
			EnsureLevelPlaylistSession();
			if (levelPlaylistOrderKeys.Count == 0)
			{
				Logger.LogWarning((object)(photonView.ViewID + " CarretaFuracao: nenhum arquivo local encontrado."));
				return;
			}
			Boombox otherActiveCarreta = GetOtherActiveCarreta();
			data.delayedOutput = (Object)(object)otherActiveCarreta != (Object)null;
			int num = (((Object)(object)otherActiveCarreta != (Object)null) ? otherActiveCarreta.GetCurrentSongIndex() : levelPlaylistIndex);
			if (num < 0)
			{
				num = levelPlaylistIndex;
			}
			int index = (levelHasStartedPlayback ? ((num + 1) % levelPlaylistOrderKeys.Count) : 0);
			int sharedPlaybackStartTimestamp = (int)GetCurrentServerTimeMilliseconds();
			foreach (Boombox activeCarreta in GetActiveCarretas())
			{
				if ((Object)(object)activeCarreta != (Object)(object)this)
				{
					activeCarreta.ApplySyncedLevelTrackInternal(index, sharedPlaybackStartTimestamp, startPlaying: true);
				}
			}
			ApplySyncedLevelTrackInternal(index, sharedPlaybackStartTimestamp, startPlaying: true);
			Logger.LogInfo((object)(photonView.ViewID + " CarretaFuracao POWER NEXT: index " + index));
		}

		private static void MoveSynchronizedPlaylist(Boombox requester, int direction)
		{
			if (PhotonNetwork.IsMasterClient && !((Object)(object)requester == (Object)null) && levelPlaylistOrderKeys.Count != 0)
			{
				Boombox activeLeader = GetActiveLeader();
				int num = (((Object)(object)activeLeader != (Object)null) ? activeLeader.GetCurrentSongIndex() : levelPlaylistIndex);
				if (num < 0)
				{
					num = levelPlaylistIndex;
				}
				int index = ((num + direction) % levelPlaylistOrderKeys.Count + levelPlaylistOrderKeys.Count) % levelPlaylistOrderKeys.Count;
				int sharedPlaybackStartTimestamp = (int)GetCurrentServerTimeMilliseconds();
				levelPlaylistIndex = index;
				SyncActiveCarretasToIndex(index, sharedPlaybackStartTimestamp, requester);
			}
		}

		private static void AdvanceSynchronizedPlaylistAtEnd(Boombox requester)
		{
			if (!PhotonNetwork.IsMasterClient || (Object)(object)requester == (Object)null || levelPlaylistOrderKeys.Count == 0 || (Object)(object)GetActiveLeader() != (Object)(object)requester)
			{
				return;
			}
			int num = (int)GetCurrentServerTimeMilliseconds();
			if (lastGlobalAdvanceServerTimestamp == int.MinValue || (uint)(num - lastGlobalAdvanceServerTimestamp) >= 500u)
			{
				lastGlobalAdvanceServerTimestamp = num;
				int currentSongIndex = requester.GetCurrentSongIndex();
				if (currentSongIndex < 0)
				{
					currentSongIndex = levelPlaylistIndex;
				}
				int num2 = (levelPlaylistIndex = (currentSongIndex + 1) % levelPlaylistOrderKeys.Count);
				SyncActiveCarretasToIndex(num2, num);
				Logger.LogInfo((object)(requester.photonView.ViewID + " CarretaFuracao PLAYLIST NEXT: " + (num2 + 1) + "/" + levelPlaylistOrderKeys.Count));
			}
		}

		private static void SyncActiveCarretasSeek(float playbackSeconds, Boombox requester)
		{
			if (!PhotonNetwork.IsMasterClient || (Object)(object)requester == (Object)null)
			{
				return;
			}
			float num = Math.Max(0f, playbackSeconds);
			int playbackStartTimestamp = (int)((double)GetCurrentServerTimeMilliseconds() - Math.Round(num * 1000f));
			List<Boombox> activeCarretas = GetActiveCarretas();
			if (activeCarretas.Count == 0)
			{
				activeCarretas.Add(requester);
			}
			foreach (Boombox item in activeCarretas)
			{
				if (!((Object)(object)item == (Object)null) && item.data != null && item.data.currentSong != null)
				{
					item.data.playbackStartTimestamp = playbackStartTimestamp;
					item.data.playbackTime = 0;
					item.data.pendingPlaybackStart = false;
					item.data.isPlaying = true;
					if ((Object)(object)item.audioPlayer != (Object)null && (Object)(object)item.audioPlayer.GetClip() != (Object)null)
					{
						item.audioPlayer.SetTime(num);
					}
					item.PublishSharedState(updateTime: true, updateQueue: false, force: true);
				}
			}
		}

		private void ApplyFollowerCartLocalSync()
		{
			if (Time.unscaledTime < nextFollowerSyncTime || !data.isPlaying || data.currentSong == null || (Object)(object)audioPlayer == (Object)null || (Object)(object)audioPlayer.GetClip() == (Object)null)
			{
				return;
			}
			nextFollowerSyncTime = Time.unscaledTime + 0.25f;
			float num = PlaybackElapsedSeconds(data.playbackStartTimestamp);
			if (!(num >= audioPlayer.GetClip().length))
			{
				if (!audioPlayer.IsPlaying())
				{
					audioPlayer.Play();
				}
				if (Math.Abs(audioPlayer.GetTime() - num) > 0.08f)
				{
					audioPlayer.SetTime(num);
				}
			}
		}

		private void TickPlayback()
		{
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			if (!runtimeStartLogged)
			{
				runtimeStartLogged = true;
				Logger.LogInfo((object)("CarretaFuracao CLOCK cart=" + photonView.ViewID + " componentEnabled=" + ((Behaviour)this).enabled + " objectActive=" + ((Component)this).gameObject.activeInHierarchy + " host=" + PhotonNetwork.IsMasterClient + " position=" + PlaybackElapsedSeconds(data.playbackStartTimestamp).ToString("0.000") + "s"));
			}
			if (PhotonNetwork.IsMasterClient && data.isPlaying && MonstersCanHearMusic && (Object)(object)EnemyDirector.instance != (Object)null)
			{
				monsterAttractTimer += Time.deltaTime;
				if (monsterAttractTimer >= 1f)
				{
					EnemyDirector.instance.SetInvestigate(((Component)this).transform.position, 5f, false);
					monsterAttractTimer = 0f;
				}
			}
			else
			{
				monsterAttractTimer = 0f;
			}
			ApplyFollowerCartLocalSync();
			PrepareNextTrack();
			if (PhotonNetwork.IsMasterClient && data.isPlaying && data.currentSong != null && (Object)(object)audioPlayer != (Object)null && (Object)(object)audioPlayer.GetClip() != (Object)null)
			{
				float length = audioPlayer.GetClip().length;
				float val = Math.Max(0f, audioPlayer.GetTime());
				float val2 = Math.Max(0f, PlaybackElapsedSeconds(data.playbackStartTimestamp));
				float num = Math.Max(val, val2);
				if (length > 0.05f && num >= length - 0.05f)
				{
					AdvanceSynchronizedPlaylistAtEnd(this);
				}
			}
		}

		public void ToggleRandomJukeboxLocal()
		{
			if (ShouldRequestMasterMutation())
			{
				BaseListener.RPC(photonView, "RequestToggleRandomJukebox", (RpcTarget)2, PhotonNetwork.LocalPlayer.ActorNumber);
			}
			else if (data != null && (data.isPlaying || data.pendingPlaybackStart))
			{
				StopRandomJukeboxInternal();
			}
			else
			{
				StartRandomJukeboxInternal();
			}
		}

		private void StopRandomJukeboxInternal()
		{
			if (PhotonNetwork.IsMasterClient)
			{
				string text = data?.currentSong?.Title ?? "(nenhuma)";
				Logger.LogInfo((object)(photonView.ViewID + " CarretaFuracao E JUKEBOX: STOP | " + text));
				int currentSongIndex = GetCurrentSongIndex();
				if (currentSongIndex >= 0)
				{
					levelPlaylistIndex = currentSongIndex;
				}
				DismissQueueLocal();
			}
		}

		private LocalMusic.LocalTrack FindLocalTrackByKey(string key)
		{
			if (string.IsNullOrWhiteSpace(key))
			{
				return null;
			}
			return LocalMusic.Tracks.FirstOrDefault((LocalMusic.LocalTrack track) => track != null && track.Key == key);
		}

		private void StartRandomJukeboxInternal()
		{
			StartOrJoinSynchronizedPlaybackInternal();
		}

		public void PlayPreviousRandomJukeboxLocal()
		{
			if (ShouldRequestMasterMutation())
			{
				BaseListener.RPC(photonView, "RequestPreviousRandomJukebox", (RpcTarget)2, PhotonNetwork.LocalPlayer.ActorNumber);
			}
			else
			{
				PlayPreviousRandomJukeboxInternal();
			}
		}

		private void PlayPreviousRandomJukeboxInternal()
		{
			if (PhotonNetwork.IsMasterClient)
			{
				EnsureLevelPlaylistSession();
				MoveSynchronizedPlaylist(this, -1);
			}
		}

		public void PlayNextRandomJukeboxLocal()
		{
			if (ShouldRequestMasterMutation())
			{
				BaseListener.RPC(photonView, "RequestNextRandomJukebox", (RpcTarget)2, PhotonNetwork.LocalPlayer.ActorNumber);
			}
			else
			{
				PlayNextRandomJukeboxInternal();
			}
		}

		private void PlayNextRandomJukeboxInternal()
		{
			if (PhotonNetwork.IsMasterClient)
			{
				EnsureLevelPlaylistSession();
				MoveSynchronizedPlaylist(this, 1);
			}
		}

		[PunRPC]
		public void RequestPreviousRandomJukebox(int requesterId)
		{
			if (PhotonNetwork.IsMasterClient)
			{
				PlayPreviousRandomJukeboxInternal();
			}
		}

		[PunRPC]
		public void RequestNextRandomJukebox(int requesterId)
		{
			if (PhotonNetwork.IsMasterClient)
			{
				PlayNextRandomJukeboxInternal();
			}
		}

		[PunRPC]
		public void RequestToggleRandomJukebox(int requesterId)
		{
			if (PhotonNetwork.IsMasterClient)
			{
				ToggleRandomJukeboxLocal();
			}
		}

		public void TogglePlaying(bool value)
		{
			data.isPlaying = value;
		}

		public static long GetCurrentServerTimeMilliseconds()
		{
			return PhotonNetwork.ServerTimestamp;
		}

		public static float PlaybackElapsedSeconds(int startedAt)
		{
			return Math.Max(0f, (float)(PhotonNetwork.ServerTimestamp - startedAt) / 1000f);
		}

		public long GetRelativePlaybackMilliseconds()
		{
			return GetCurrentServerTimeMilliseconds() - (long)Math.Round(GetTrackedPlaybackSeconds() * 1000f);
		}

		public int GetCurrentSongIndex()
		{
			if (data.currentSong == null)
			{
				return -1;
			}
			return data.playbackQueue.IndexOf(data.currentSong);
		}

		private string GetPropertyKey(string propertyName)
		{
			if ((Object)(object)photonView == (Object)null)
			{
				return propertyName;
			}
			return $"boombox_{photonView.ViewID}_{propertyName}";
		}

		private Hashtable CreateSharedState(bool includeTime, bool updateQueue)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Expected O, but got Unknown
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Expected O, but got Unknown
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Expected O, but got Unknown
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Expected O, but got Unknown
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Expected O, but got Unknown
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Expected O, but got Unknown
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Expected O, but got Unknown
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Expected O, but got Unknown
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_0139: Expected O, but got Unknown
			//IL_0139: Unknown result type (might be due to invalid IL or missing references)
			//IL_0155: Expected O, but got Unknown
			//IL_0156: Expected O, but got Unknown
			Hashtable val = new Hashtable();
			((Dictionary<object, object>)val).Add((object)GetPropertyKey("propVersion"), (object)data.stateVersion);
			((Dictionary<object, object>)val).Add((object)GetPropertyKey("IDKey"), (object)data.key);
			((Dictionary<object, object>)val).Add((object)GetPropertyKey("isPlaying"), (object)(data.currentSong != null && data.isPlaying));
			((Dictionary<object, object>)val).Add((object)GetPropertyKey("pendingPlaybackStart"), (object)data.pendingPlaybackStart);
			((Dictionary<object, object>)val).Add((object)GetPropertyKey("absVolume"), (object)data.absVolume);
			((Dictionary<object, object>)val).Add((object)GetPropertyKey("loopQueue"), (object)data.loopQueue);
			((Dictionary<object, object>)val).Add((object)GetPropertyKey("delayedOutput"), (object)data.delayedOutput);
			((Dictionary<object, object>)val).Add((object)GetPropertyKey("underglow"), (object)data.underglowEnabled);
			((Dictionary<object, object>)val).Add((object)GetPropertyKey("visualizer"), (object)data.visualizerEnabled);
			((Dictionary<object, object>)val).Add((object)GetPropertyKey("currentSongIndex"), (object)GetCurrentSongIndex());
			Hashtable val2 = val;
			if (includeTime)
			{
				((Dictionary<object, object>)(object)val2).Add((object)GetPropertyKey("playbackStartTimestamp"), (object)data.playbackStartTimestamp);
			}
			if (updateQueue)
			{
				((Dictionary<object, object>)(object)val2).Add((object)GetPropertyKey("queue"), (object)JsonConvert.SerializeObject((object)data.playbackQueue.Select((AudioEntry entry) => new SharedAudioEntry
				{
					title = entry.Title,
					url = entry.Url,
					duration = entry.Duration,
					startTime = entry.StartTime
				}).ToArray()));
				Logger.LogDebug((object)(photonView.ViewID + string.Format("Created table with queue size: {0}", JsonConvert.DeserializeObject<SharedAudioEntry[]>((string)val2[(object)GetPropertyKey("queue")]).Count())));
			}
			return val2;
		}

		private void LoadSharedStateFromRoom()
		{
			if (PhotonNetwork.IsConnected && PhotonNetwork.CurrentRoom != null && !((Object)(object)photonView == (Object)null))
			{
				Hashtable customProperties = ((RoomInfo)PhotonNetwork.CurrentRoom).CustomProperties;
				ApplyChangedValues(customProperties);
				if (PhotonNetwork.IsMasterClient && ((Dictionary<object, object>)(object)customProperties).Count > 0)
				{
					PublishSharedState(updateTime: true, updateQueue: true, force: true);
				}
			}
		}

		public override void OnRoomPropertiesUpdate(Hashtable propertiesThatChanged)
		{
			((MonoBehaviourPunCallbacks)this).OnRoomPropertiesUpdate(propertiesThatChanged);
			if (!((Object)(object)photonView == (Object)null) && propertiesThatChanged != null && !PhotonNetwork.IsMasterClient)
			{
				ApplyChangedValues(propertiesThatChanged);
			}
		}

		private void ApplyChangedValues(Hashtable propertiesThatChanged)
		{
			isApplyingSharedState = true;
			string propertyKey = GetPropertyKey("propVersion");
			if (!((Dictionary<object, object>)(object)propertiesThatChanged).ContainsKey((object)propertyKey))
			{
				isApplyingSharedState = false;
				return;
			}
			int num = (int)propertiesThatChanged[(object)propertyKey];
			if (num < data.stateVersion || num <= lastAppliedSharedStateVersion)
			{
				isApplyingSharedState = false;
				return;
			}
			int currentSongIndex = GetCurrentSongIndex();
			string propertyKey2 = GetPropertyKey("queue");
			bool flag = ((Dictionary<object, object>)(object)propertiesThatChanged).ContainsKey((object)propertyKey2);
			try
			{
				if (flag)
				{
					SharedAudioEntry[] array = JsonConvert.DeserializeObject<SharedAudioEntry[]>((string)propertiesThatChanged[(object)propertyKey2]);
					if (array != null)
					{
						data.playbackQueue = array.Select(delegate(SharedAudioEntry entry)
						{
							string title = (string.IsNullOrWhiteSpace(entry.title) ? "Unknown Title" : entry.title);
							_ = entry.duration;
							double duration = entry.duration;
							string url = entry.url;
							SongInfo info = new SongInfo(title, duration);
							return new AudioEntry(url, info)
							{
								StartTime = entry.startTime
							};
						}).ToList();
						Logger.LogDebug((object)(photonView.ViewID + $"Updated queue to size {data.playbackQueue.Count}."));
					}
					else
					{
						data.playbackQueue = new List<AudioEntry>();
					}
				}
				string propertyKey3 = GetPropertyKey("currentSongIndex");
				if (((Dictionary<object, object>)(object)propertiesThatChanged).ContainsKey((object)propertyKey3))
				{
					int num2 = (int)propertiesThatChanged[(object)propertyKey3];
					if (num2 >= 0 && num2 < data.playbackQueue.Count)
					{
						data.currentSong = data.playbackQueue[num2];
					}
					else
					{
						data.currentSong = null;
						data.pendingPlaybackStart = false;
						audioPlayer.Stop();
						UpdateUIStatus("Ready to play music! Enter a Video URL");
						Logger.LogDebug((object)(photonView.ViewID + $"Invalid currentsong index: {num2}."));
					}
				}
				else if (flag)
				{
					data.currentSong = data.playbackQueue[currentSongIndex];
				}
				string propertyKey4 = GetPropertyKey("pendingPlaybackStart");
				if (((Dictionary<object, object>)(object)propertiesThatChanged).ContainsKey((object)propertyKey4))
				{
					bool pendingPlaybackStart = (bool)propertiesThatChanged[(object)propertyKey4];
					data.pendingPlaybackStart = pendingPlaybackStart;
				}
				string propertyKey5 = GetPropertyKey("isPlaying");
				if (((Dictionary<object, object>)(object)propertiesThatChanged).ContainsKey((object)propertyKey5))
				{
					bool flag2 = (bool)propertiesThatChanged[(object)propertyKey5];
					data.isPlaying = data.currentSong != null && flag2;
				}
				string propertyKey6 = GetPropertyKey("absVolume");
				if (((Dictionary<object, object>)(object)propertiesThatChanged).ContainsKey((object)propertyKey6))
				{
					float num3 = Mathf.Clamp01(Convert.ToSingle((float)propertiesThatChanged[(object)propertyKey6]));
					AudioSettings.RememberMaster(num3);
					if (data.absVolume != num3)
					{
						data.absVolume = num3;
						float volume = num3 * data.personalVolumePercentage;
						audioPlayer.SetVolume(volume);
					}
				}
				string propertyKey7 = GetPropertyKey("delayedOutput");
				if (((Dictionary<object, object>)(object)propertiesThatChanged).ContainsKey((object)propertyKey7))
				{
					data.delayedOutput = (bool)propertiesThatChanged[(object)propertyKey7];
				}
				string propertyKey8 = GetPropertyKey("loopQueue");
				if (((Dictionary<object, object>)(object)propertiesThatChanged).ContainsKey((object)propertyKey8))
				{
					bool loopQueue = (bool)propertiesThatChanged[(object)propertyKey8];
					data.loopQueue = loopQueue;
				}
				string propertyKey9 = GetPropertyKey("underglow");
				if (((Dictionary<object, object>)(object)propertiesThatChanged).ContainsKey((object)propertyKey9) && Instance.SyncVisuals.Value)
				{
					bool underglowEnabled = (bool)propertiesThatChanged[(object)propertyKey9];
					data.underglowEnabled = underglowEnabled;
					ApplyVisualStateFromData();
					((Component)this).GetComponent<BoomboxUI>()?.UpdateDataFromBoomBox();
				}
				string propertyKey10 = GetPropertyKey("visualizer");
				if (((Dictionary<object, object>)(object)propertiesThatChanged).ContainsKey((object)propertyKey10) && Instance.SyncVisuals.Value)
				{
					bool visualizerEnabled = (bool)propertiesThatChanged[(object)propertyKey10];
					data.visualizerEnabled = visualizerEnabled;
					ApplyVisualStateFromData();
					((Component)this).GetComponent<BoomboxUI>()?.UpdateDataFromBoomBox();
				}
				string propertyKey11 = GetPropertyKey("playbackStartTimestamp");
				if (((Dictionary<object, object>)(object)propertiesThatChanged).ContainsKey((object)propertyKey11))
				{
					int num4 = (int)propertiesThatChanged[(object)propertyKey11];
					data.playbackStartTimestamp = num4;
					SetPlaybackTime(num4);
				}
				string propertyKey12 = GetPropertyKey("IDKey");
				if (((Dictionary<object, object>)(object)propertiesThatChanged).ContainsKey((object)propertyKey12))
				{
					string text = (string)propertiesThatChanged[(object)propertyKey12];
					if (!string.IsNullOrWhiteSpace(text))
					{
						data.key = text;
					}
				}
			}
			catch (Exception ex)
			{
				Logger.LogWarning((object)("Error occured while reading properties: " + ex.Message));
			}
			ApplySharedPlaybackState();
			((Component)this).GetComponent<BoomboxUI>()?.UpdateDataFromBoomBox();
			data.stateVersion = num;
			lastAppliedSharedStateVersion = num;
			syncFinished = true;
			isApplyingSharedState = false;
		}

		private bool ShouldUseNativeCarretaLoop()
		{
			return false;
		}

		private void ApplyNativeCarretaLoopState()
		{
			if (!((Object)(object)audioPlayer == (Object)null) && !((Object)(object)audioPlayer.audioSource == (Object)null))
			{
				bool flag = ShouldUseNativeCarretaLoop();
				if (audioPlayer.audioSource.loop != flag)
				{
					audioPlayer.audioSource.loop = flag;
					Logger.LogInfo((object)(photonView.ViewID + " CarretaFuracao NATIVE LOOP: " + (flag ? "ON" : "OFF")));
				}
			}
		}

		private void ApplySharedPlaybackState()
		{
			ApplyNativeCarretaLoopState();
			audioPlayer.SetVolume(data.absVolume * data.personalVolumePercentage);
			audioPlayer.SetDelayedOutput(data.delayedOutput);
			if (data.currentSong?.Url == null)
			{
				Logger.LogDebug((object)(photonView.ViewID + "ApplySharedPlaybackState: No current song" + ((data.currentSong == null) ? "" : "URL") + "!"));
				data.pendingPlaybackStart = false;
				audioPlayer.Stop();
				UpdateUIStatus("Ready to play music! Enter a Video URL");
				return;
			}
			AudioEntry currentSong = data.currentSong;
			if (currentSong == null || !currentSong.ClipLoaded())
			{
				audioPlayer.Stop();
				startPlayBackOnDownload = data.pendingPlaybackStart;
				if (data.pendingPlaybackStart)
				{
					UpdateUIStatus("Loading: " + data.currentSong.Title);
				}
				if (!data.pendingPlaybackStart)
				{
					EnsureCurrentSongDownloaded();
				}
				return;
			}
			if (data.currentSong.Url != audioPlayer.currentUrl)
			{
				audioPlayer.Stop();
				audioPlayer.SetClip(data.currentSong.Url);
				audioPlayer.SetQuality(AudioPlayer.GetQuality());
				audioPlayer.UpdateAudioRangeBasedOnVolume();
			}
			ApplyVisualStateFromData();
			if (data.pendingPlaybackStart)
			{
				if (audioPlayer.IsPlaying())
				{
					audioPlayer.Pause();
				}
				UpdateUIStatus("Loading: " + data.currentSong.Title);
			}
			else if (data.isPlaying)
			{
				if (!audioPlayer.IsPlaying() && PlaybackElapsedSeconds(data.playbackStartTimestamp) < audioPlayer.GetClip().length)
				{
					Logger.LogDebug((object)(photonView.ViewID + $"ApplySharedPlaybackState: Starting playback - timestamp={data.playbackStartTimestamp}"));
					audioPlayer.Play();
					SetPlaybackTime(data.playbackStartTimestamp);
					Logger.LogDebug((object)(photonView.ViewID + $"ApplySharedPlaybackState: After Play(), audioPlayer.GetTime()={audioPlayer.GetTime()}"));
				}
				UpdateUIStatus("Now playing: " + data.currentSong.Title);
			}
			else
			{
				if (audioPlayer.IsPlaying())
				{
					audioPlayer.Pause();
				}
				UpdateUIStatus("Ready to play: " + data.currentSong.Title);
			}
		}

		public void ApplyVisualStateFromData()
		{
			if ((Object)(object)visualEffects == (Object)null)
			{
				visualEffects = ((Component)this).gameObject.AddComponent<VisualEffects>();
				if ((Object)(object)visualizer != (Object)null)
				{
					visualizer.audioSource = audioPlayer.audioSource;
				}
			}
			visualEffects.SetLights(data.underglowEnabled);
			if (data.visualizerEnabled)
			{
				if ((Object)(object)visualizer == (Object)null)
				{
					visualizer = ((Component)this).gameObject.AddComponent<Visualizer>();
				}
				visualizer.audioSource = audioPlayer.audioSource;
			}
			else if ((Object)(object)visualizer != (Object)null)
			{
				Object.Destroy((Object)(object)visualizer);
				visualizer = null;
			}
		}

		private async void EnsureCurrentSongDownloaded()
		{
			string url = data.currentSong?.Url;
			if (string.IsNullOrWhiteSpace(url) || (Object)(object)downloadHelper == (Object)null || DownloadHelper.downloadedClips.ContainsKey(url) || pendingCurrentSongDownloadUrl == url)
			{
				return;
			}
			pendingCurrentSongDownloadUrl = url;
			try
			{
				if (await downloadHelper.StartAudioDownload(url))
				{
					BaseListener.RPC(photonView, "ReportDownloadComplete", (RpcTarget)2, url, PhotonNetwork.LocalPlayer.ActorNumber);
				}
			}
			finally
			{
				if (pendingCurrentSongDownloadUrl == url)
				{
					pendingCurrentSongDownloadUrl = null;
				}
			}
			if (!((Object)(object)this == (Object)null) && !(data.currentSong?.Url != url))
			{
				ApplySharedPlaybackState();
			}
		}

		private void UpdateStatusFromState()
		{
			if (data.currentSong == null)
			{
				UpdateUIStatus("Ready to play music! Enter a Video URL");
			}
			else if (data.pendingPlaybackStart)
			{
				UpdateUIStatus("Loading: " + data.currentSong.Title);
			}
			else if (data.isPlaying)
			{
				UpdateUIStatus("Now playing: " + data.currentSong.Title);
			}
			else
			{
				UpdateUIStatus("Ready to play: " + data.currentSong.Title);
			}
		}

		public bool CanPublish()
		{
			if (PhotonNetwork.IsMasterClient && !isApplyingSharedState && PhotonNetwork.IsConnected && PhotonNetwork.CurrentRoom != null)
			{
				return (Object)(object)photonView != (Object)null;
			}
			return false;
		}

		public void PublishSharedState(bool updateTime, bool updateQueue = false, bool force = false)
		{
			if (CanPublish())
			{
				if (PhotonNetwork.IsMasterClient)
				{
					data.stateVersion++;
				}
				Hashtable val = CreateSharedState(updateTime, updateQueue);
				PhotonNetwork.CurrentRoom.SetCustomProperties(val, (Hashtable)null, (WebFlags)null);
				lastSharedState = val;
				syncFinished = true;
			}
		}

		private void StopLocalPlayback(bool updateSharedFlag)
		{
			audioPlayer.Stop();
			if (updateSharedFlag)
			{
				TogglePlaying(value: false);
			}
		}

		private void SetPlaybackReferenceFromSeconds(float totalSeconds)
		{
			float num = Math.Max(0f, totalSeconds);
			data.playbackStartTimestamp = (int)((double)GetCurrentServerTimeMilliseconds() - Math.Round(num * 1000f));
			Logger.LogDebug((object)(photonView.ViewID + $"SetPlaybackReferenceFromSeconds: Set to {num}s, timestamp={data.playbackStartTimestamp}"));
		}

		private float GetTrackedPlaybackSeconds()
		{
			if ((Object)(object)audioPlayer?.GetClip() != (Object)null)
			{
				if (!audioPlayer.IsPlaying() && data.playbackTime > 0 && audioPlayer.GetTime() <= 0f)
				{
					Logger.LogDebug((object)(photonView.ViewID + $"GetTrackedPlaybackSeconds: Returning cached playbackTime={data.playbackTime} (not playing, time <= 0)"));
					return data.playbackTime;
				}
				float time = audioPlayer.GetTime();
				Logger.LogDebug((object)(photonView.ViewID + $"GetTrackedPlaybackSeconds: Returning audioPlayer.GetTime()={time}, isPlaying={audioPlayer.IsPlaying()}"));
				return time;
			}
			if (data.playbackTime > 0)
			{
				Logger.LogDebug((object)(photonView.ViewID + $"GetTrackedPlaybackSeconds: Returning cached playbackTime={data.playbackTime} (no clip)"));
				return data.playbackTime;
			}
			float num = Math.Max(0f, PlaybackElapsedSeconds(data.playbackStartTimestamp));
			Logger.LogDebug((object)(photonView.ViewID + $"GetTrackedPlaybackSeconds: Calculating from timestamp: {num}s"));
			return num;
		}

		private void CleanupCurrentPlayback()
		{
			StopLocalPlayback(updateSharedFlag: true);
		}

		private bool ShouldRequestMasterMutation()
		{
			if (PhotonNetwork.IsConnected && PhotonNetwork.CurrentRoom != null)
			{
				return !PhotonNetwork.IsMasterClient;
			}
			return false;
		}

		public void SetPlaybackTime(long relativeStartTimeMillis)
		{
			float num = Math.Max(0f, PlaybackElapsedSeconds((int)relativeStartTimeMillis));
			Logger.LogDebug((object)(photonView.ViewID + $"SetPlaybackTime: Setting audioPlayer time to {num}s (from timestamp {relativeStartTimeMillis})"));
			audioPlayer.SetTime(num);
		}

		public void EnqueueSongLocal(string url, int seconds)
		{
			if (string.IsNullOrWhiteSpace(url))
			{
				return;
			}
			if (ShouldRequestMasterMutation())
			{
				BaseListener.RPC(photonView, "RequestEnqueueSong", (RpcTarget)2, url, seconds, PhotonNetwork.LocalPlayer.ActorNumber);
				return;
			}
			SongInfo info = (DownloadHelper.songInfo.ContainsKey(url) ? DownloadHelper.songInfo[url] : new SongInfo());
			AudioEntry audioEntry = new AudioEntry(url, info)
			{
				StartTime = seconds
			};
			data.playbackQueue.Add(audioEntry);
			bool flag = data.currentSong == null;
			if (flag)
			{
				data.currentSong = audioEntry;
				data.playbackTime = 0;
				Logger.LogDebug((object)(photonView.ViewID + $"Set currentsong local {data.currentSong}"));
				StopLocalPlayback(updateSharedFlag: true);
				data.pendingPlaybackStart = true;
				startPlayBackOnDownload = true;
				SetPlaybackReferenceFromSeconds(audioEntry.UseStartTime(this));
			}
			PublishSharedState(flag, updateQueue: true);
			if (PhotonNetwork.IsMasterClient)
			{
				downloadHelper.EnqueueDownload(url);
				downloadHelper.StartDownloadJob();
			}
		}

		public void CommitPlaybackSeek()
		{
			if (data.currentSong != null)
			{
				if (ShouldRequestMasterMutation())
				{
					BaseListener.RPC(photonView, "RequestCommitPlaybackSeek", (RpcTarget)2, audioPlayer.GetTime(), PhotonNetwork.LocalPlayer.ActorNumber);
				}
				else
				{
					SyncActiveCarretasSeek(audioPlayer.GetTime(), this);
				}
			}
		}

		public void SetPlaybackStateLocal(bool startPlaying)
		{
			if (data.currentSong != null)
			{
				if (ShouldRequestMasterMutation())
				{
					BaseListener.RPC(photonView, "RequestSetPlaybackState", (RpcTarget)2, startPlaying, PhotonNetwork.LocalPlayer.ActorNumber);
				}
				else if (!data.currentSong.ClipLoaded())
				{
					startPlayBackOnDownload = startPlaying;
					data.isPlaying = false;
					data.pendingPlaybackStart = startPlaying;
					PublishSharedState(updateTime: true);
				}
				else
				{
					float trackedPlaybackSeconds = GetTrackedPlaybackSeconds();
					Logger.LogDebug((object)(photonView.ViewID + $"SetPlaybackStateLocal: trackedPlaybackSeconds={trackedPlaybackSeconds}, isPlaying={startPlaying}"));
					SetPlaybackReferenceFromSeconds(trackedPlaybackSeconds);
					Logger.LogDebug((object)(photonView.ViewID + $"SetPlaybackStateLocal: Final state - isPlaying={startPlaying}, timestamp={data.playbackStartTimestamp}"));
					data.isPlaying = startPlaying;
					data.pendingPlaybackStart = false;
					PublishSharedState(updateTime: true, updateQueue: false, force: true);
				}
			}
		}

		public void JumpPlaybackBySeconds(float seconds)
		{
			if (!data.currentSong.ClipLoaded())
			{
				return;
			}
			if (ShouldRequestMasterMutation())
			{
				BaseListener.RPC(photonView, "RequestJumpPlaybackBySeconds", (RpcTarget)2, seconds, PhotonNetwork.LocalPlayer.ActorNumber);
				return;
			}
			float num = Math.Max(0f, GetTrackedPlaybackSeconds() + seconds);
			if ((Object)(object)audioPlayer?.GetClip() != (Object)null)
			{
				num = Math.Min(num, Math.Max(0f, audioPlayer.GetClip().length - 0.5f));
			}
			SetPlaybackReferenceFromSeconds(num);
			data.pendingPlaybackStart = false;
			PublishSharedState(updateTime: true);
		}

		public void SelectSongIndex(int index)
		{
			if (index < 0 || index >= data.playbackQueue.Count)
			{
				return;
			}
			if (ShouldRequestMasterMutation())
			{
				BaseListener.RPC(photonView, "RequestSelectSongIndex", (RpcTarget)2, index, PhotonNetwork.LocalPlayer.ActorNumber);
				return;
			}
			data.currentSong = data.playbackQueue[index];
			StopLocalPlayback(updateSharedFlag: true);
			data.playbackTime = 0;
			data.pendingPlaybackStart = true;
			startPlayBackOnDownload = true;
			PublishSharedState(updateTime: true);
			if (PhotonNetwork.IsMasterClient)
			{
				string text = data.currentSong?.Url;
				if (text != null && DownloadHelper.downloadsReady.ContainsKey(text) && DownloadHelper.downloadsReady[text].Count >= Instance.baseListener.GetAllModUsers().Count && data.pendingPlaybackStart)
				{
					Logger.LogDebug((object)(photonView.ViewID + "Skipping download queue, as all users are ready to play."));
					FinalizePendingPlaybackStart(startPlayBackOnDownload);
				}
				else
				{
					downloadHelper.DismissDownloadQueue();
					downloadHelper.DownloadQueue(index);
				}
			}
		}

		public void SetVolumeLocal(float volume)
		{
			if (ShouldRequestMasterMutation())
			{
				BaseListener.RPC(photonView, "RequestSetVolume", (RpcTarget)2, volume, PhotonNetwork.LocalPlayer.ActorNumber);
				return;
			}
			AudioSettings.RememberMaster(volume);
			foreach (Boombox runtimeCarreta in GetRuntimeCarretas())
			{
				if (!((Object)(object)runtimeCarreta == (Object)(object)this))
				{
					runtimeCarreta.data.absVolume = Mathf.Clamp01(volume);
					if ((Object)(object)runtimeCarreta.audioPlayer != (Object)null)
					{
						runtimeCarreta.audioPlayer.SetVolume(runtimeCarreta.data.absVolume * runtimeCarreta.data.personalVolumePercentage);
					}
					runtimeCarreta.PublishSharedState(updateTime: false);
				}
			}
			data.absVolume = Mathf.Clamp01(volume);
			float volume2 = data.absVolume * data.personalVolumePercentage;
			audioPlayer.SetVolume(volume2);
			PublishSharedState(updateTime: false);
		}

		public void SetLoopQueueLocal(bool loop)
		{
			if (ShouldRequestMasterMutation())
			{
				BaseListener.RPC(photonView, "RequestSetLoopQueue", (RpcTarget)2, loop, PhotonNetwork.LocalPlayer.ActorNumber);
			}
			else
			{
				data.loopQueue = loop;
				ApplyNativeCarretaLoopState();
				PublishSharedState(updateTime: false);
			}
		}

		public void SetUnderglowEnabledLocal(bool enabled)
		{
			if (Instance.SyncVisuals.Value)
			{
				if (ShouldRequestMasterMutation())
				{
					BaseListener.RPC(photonView, "RequestSetUnderglowEnabled", (RpcTarget)2, enabled, PhotonNetwork.LocalPlayer.ActorNumber);
				}
				else
				{
					data.underglowEnabled = enabled;
					ApplyVisualStateFromData();
					((Component)this).GetComponent<BoomboxUI>()?.UpdateDataFromBoomBox();
					PublishSharedState(updateTime: false);
				}
			}
			else
			{
				data.underglowEnabled = enabled;
				ApplyVisualStateFromData();
				((Component)this).GetComponent<BoomboxUI>()?.UpdateDataFromBoomBox();
			}
		}

		public void SetVisualizerEnabledLocal(bool enabled)
		{
			if (Instance.SyncVisuals.Value)
			{
				if (ShouldRequestMasterMutation())
				{
					BaseListener.RPC(photonView, "RequestSetVisualizerEnabled", (RpcTarget)2, enabled, PhotonNetwork.LocalPlayer.ActorNumber);
				}
				else
				{
					data.visualizerEnabled = enabled;
					ApplyVisualStateFromData();
					((Component)this).GetComponent<BoomboxUI>()?.UpdateDataFromBoomBox();
					PublishSharedState(updateTime: false);
				}
			}
			else
			{
				data.visualizerEnabled = enabled;
				ApplyVisualStateFromData();
				((Component)this).GetComponent<BoomboxUI>()?.UpdateDataFromBoomBox();
			}
		}

		public void DismissQueueLocal()
		{
			if (ShouldRequestMasterMutation())
			{
				BaseListener.RPC(photonView, "RequestDismissQueue", (RpcTarget)2, PhotonNetwork.LocalPlayer.ActorNumber);
				return;
			}
			if ((Object)(object)audioPlayer != (Object)null && (Object)(object)audioPlayer.audioSource != (Object)null)
			{
				audioPlayer.audioSource.loop = false;
			}
			StopLocalPlayback(updateSharedFlag: true);
			data.playbackQueue.Clear();
			data.currentSong = null;
			data.pendingPlaybackStart = false;
			data.playbackTime = 0;
			SetPlaybackReferenceFromSeconds(0f);
			PublishSharedState(updateTime: true, updateQueue: true);
			if (PhotonNetwork.IsMasterClient)
			{
				downloadHelper.DismissDownloadQueue();
				downloadHelper.ForceCancelDownload();
			}
			UpdateUIStatus("Ready to play music! Enter a Video URL");
		}

		public void MoveQueueItemLocal(int index, int newIndex)
		{
			if (index >= 0 && index < data.playbackQueue.Count && newIndex >= 0 && newIndex < data.playbackQueue.Count && index != newIndex)
			{
				if (ShouldRequestMasterMutation())
				{
					BaseListener.RPC(photonView, "RequestMoveQueueItem", (RpcTarget)2, index, newIndex, PhotonNetwork.LocalPlayer.ActorNumber);
				}
				else
				{
					AudioEntry item = data.playbackQueue[index];
					data.playbackQueue.RemoveAt(index);
					data.playbackQueue.Insert(newIndex, item);
					PublishSharedState(updateTime: false, updateQueue: true);
				}
			}
		}

		public void RemoveQueueItemLocal(int index)
		{
			if (index < 0 || index >= data.playbackQueue.Count)
			{
				return;
			}
			if (ShouldRequestMasterMutation())
			{
				BaseListener.RPC(photonView, "RequestRemoveQueueItem", (RpcTarget)2, index, PhotonNetwork.LocalPlayer.ActorNumber);
				return;
			}
			bool flag = data.playbackQueue[index] == data.currentSong;
			data.playbackQueue.RemoveAt(index);
			if (flag)
			{
				if (data.playbackQueue.Count == 0)
				{
					data.currentSong = null;
					data.isPlaying = false;
					data.playbackTime = 0;
					data.pendingPlaybackStart = false;
					SetPlaybackReferenceFromSeconds(0f);
				}
				else
				{
					int index2 = Math.Min(index, data.playbackQueue.Count - 1);
					if (index >= data.playbackQueue.Count && LoopQueue)
					{
						index2 = 0;
					}
					data.currentSong = data.playbackQueue[index2];
					data.isPlaying = false;
					data.playbackTime = 0;
					data.pendingPlaybackStart = true;
					startPlayBackOnDownload = true;
					SetPlaybackReferenceFromSeconds(data.currentSong.UseStartTime(this));
				}
			}
			if (PhotonNetwork.IsMasterClient && data.currentSong?.Url != null)
			{
				downloadHelper.DismissDownloadQueue();
				downloadHelper.DownloadQueue(GetCurrentSongIndex());
			}
			PublishSharedState(flag, updateQueue: true);
		}

		public void FinalizePendingPlaybackStart(bool startPlaying)
		{
			if (data.currentSong != null)
			{
				data.pendingPlaybackStart = false;
				data.isPlaying = startPlaying;
				SetPlaybackReferenceFromSeconds(data.currentSong.UseStartTime(this));
				startPlayBackOnDownload = true;
				PublishSharedState(updateTime: true, updateQueue: false, force: true);
			}
		}

		[PunRPC]
		public void RequestEnqueueSong(string url, int seconds, int requesterId)
		{
			if (PhotonNetwork.IsMasterClient)
			{
				EnqueueSongLocal(url, seconds);
			}
		}

		[PunRPC]
		public void RequestCommitPlaybackSeek(float playbackSeconds, int requesterId)
		{
			if (PhotonNetwork.IsMasterClient && data.currentSong != null)
			{
				SyncActiveCarretasSeek(playbackSeconds, this);
			}
		}

		[PunRPC]
		public void RequestSetPlaybackState(bool startPlaying, int requesterId)
		{
			if (PhotonNetwork.IsMasterClient)
			{
				SetPlaybackStateLocal(startPlaying);
			}
		}

		[PunRPC]
		public void RequestJumpPlaybackBySeconds(float seconds, int requesterId)
		{
			if (PhotonNetwork.IsMasterClient)
			{
				JumpPlaybackBySeconds(seconds);
			}
		}

		[PunRPC]
		public void RequestSelectSongIndex(int index, int requesterId)
		{
			if (PhotonNetwork.IsMasterClient)
			{
				SelectSongIndex(index);
			}
		}

		[PunRPC]
		public void RequestSetVolume(float volume, int requesterId)
		{
			if (PhotonNetwork.IsMasterClient)
			{
				SetVolumeLocal(volume);
			}
		}

		[PunRPC]
		public void RequestSetLoopQueue(bool loop, int requesterId)
		{
			if (PhotonNetwork.IsMasterClient)
			{
				SetLoopQueueLocal(loop);
			}
		}

		[PunRPC]
		public void RequestSetUnderglowEnabled(bool enabled, int requesterId)
		{
			if (PhotonNetwork.IsMasterClient && Instance.SyncVisuals.Value)
			{
				SetUnderglowEnabledLocal(enabled);
			}
		}

		[PunRPC]
		public void RequestSetVisualizerEnabled(bool enabled, int requesterId)
		{
			if (PhotonNetwork.IsMasterClient && Instance.SyncVisuals.Value)
			{
				SetVisualizerEnabledLocal(enabled);
			}
		}

		[PunRPC]
		public void RequestDismissQueue(int requesterId)
		{
			if (PhotonNetwork.IsMasterClient && (!Instance.MasterClientDismissQueue.Value || PhotonNetwork.MasterClient.ActorNumber == requesterId))
			{
				DismissQueueLocal();
			}
		}

		[PunRPC]
		public void RequestMoveQueueItem(int index, int newIndex, int requesterId)
		{
			if (PhotonNetwork.IsMasterClient)
			{
				MoveQueueItemLocal(index, newIndex);
			}
		}

		[PunRPC]
		public void RequestRemoveQueueItem(int index, int requesterId)
		{
			if (PhotonNetwork.IsMasterClient)
			{
				RemoveQueueItemLocal(index);
			}
		}

		public void HandleDownloadedCurrentSong()
		{
			AudioEntry currentSong = data.currentSong;
			if (currentSong != null && currentSong.ClipLoaded())
			{
				ApplySharedPlaybackState();
			}
		}

		public double EstimateDownloadTimeSeconds(double durationSeconds, int downloadSpeedMbps)
		{
			double num = (double)DownloadHelper.GetBitrateKbps(ApplyQualityToDownloads ? 4 : AudioPlayer.GetQuality()) * 1000.0 / 8.0 * durationSeconds;
			double num2 = (double)Math.Max(1, downloadSpeedMbps) / 8.0 * 1024.0 * 1024.0;
			double num3 = num / num2 * 2.5;
			double num4 = durationSeconds * 0.005;
			return (5.0 + num3 + num4) * 1.3;
		}

		public void UpdateUIStatus(string message)
		{
			if (!((Object)(object)this == (Object)null))
			{
				BoomboxUI component = ((Component)this).GetComponent<BoomboxUI>();
				if ((Object)(object)component != (Object)null && component.IsUIVisible())
				{
					component.UpdateStatus(message);
				}
			}
		}

		public override void OnPlayerEnteredRoom(Player newPlayer)
		{
			((MonoBehaviourPunCallbacks)this).OnPlayerEnteredRoom(newPlayer);
			if (PhotonNetwork.IsMasterClient && !Instance.modDisabled)
			{
				PhotonView obj = ((MonoBehaviourPun)Instance.baseListener).photonView;
				if (obj != null)
				{
					obj.RPC("BaseListener", newPlayer, new object[2]
					{
						"0.7.9",
						PhotonNetwork.LocalPlayer.ActorNumber
					});
				}
			}
		}

		public override void OnDisable()
		{
			((MonoBehaviourPunCallbacks)this).OnDisable();
			PersistentData.RemoveBoomboxViewInitialized(photonView.ViewID);
			data.playbackTime = (int)Math.Round(audioPlayer.GetTime());
		}

		private void OnDestroy()
		{
			liveCarretas.Remove(this);
			Instance.data.GetAllBoomboxes().Remove(this);
			Object.Destroy((Object)(object)((Component)this).GetComponent<BoomboxUI>());
			if ((Object)(object)visualizer != (Object)null)
			{
				Object.Destroy((Object)(object)visualizer);
			}
			Object.Destroy((Object)(object)((Component)this).gameObject.GetComponent<VisualEffects>());
			Object.Destroy((Object)(object)audioPlayer);
			Object.Destroy((Object)(object)downloadHelper);
			Object.Destroy((Object)(object)((Component)this).gameObject.GetComponent<BoomboxController>());
			photonView.RefreshRpcMonoBehaviourCache();
		}

		public void ResetData()
		{
			if (PhotonNetwork.IsMasterClient)
			{
				Logger.LogInfo((object)$"Resetting Boombox {photonView.ViewID}");
				startPlayBackOnDownload = true;
				data.pendingPlaybackStart = false;
				UpdateUIStatus("Ready to play music! Enter a Video URL");
				CleanupCurrentPlayback();
				downloadHelper.DismissDownloadQueue();
				List<BoomboxData> boomboxData = Instance.data.GetBoomboxData();
				int index = boomboxData.Count;
				if (boomboxData.Contains(data))
				{
					index = boomboxData.IndexOf(data);
					boomboxData.Remove(data);
				}
				int stateVersion = data.stateVersion;
				data = new BoomboxData();
				data.stateVersion = stateVersion + 1;
				ApplyVisualStateFromData();
				if (Instance.RestoreBoomboxes.Value)
				{
					boomboxData.Insert(index, data);
				}
				PublishSharedState(updateTime: true, updateQueue: true, force: true);
			}
		}
	}
	public class BoomboxController : MonoBehaviourPun
	{
		private static BoomboxController openPanel;

		private BoomboxUI panel;

		public void RequestBoomboxControl()
		{
			if ((Object)(object)panel != (Object)null && panel.IsUIVisible())
			{
				ReleaseControl();
			}
			else if (PlayerGrabbingTracker.IsLocalPlayerGrabbingCart(((Component)this).gameObject))
			{
				if ((Object)(object)openPanel != (Object)null && (Object)(object)openPanel != (Object)(object)this)
				{
					openPanel.ReleaseControl();
				}
				if ((Object)(object)panel == (Object)null)
				{
					panel = ((Component)this).GetComponent<BoomboxUI>() ?? ((Component)this).gameObject.AddComponent<BoomboxUI>();
				}
				panel.ShowUI();
				openPanel = this;
			}
		}

		public void ReleaseControl()
		{
			if ((Object)(object)panel != (Object)null)
			{
				panel.HideUI();
			}
			if ((Object)(object)openPanel == (Object)(object)this)
			{
				openPanel = null;
			}
		}

		public void LocalPlayerReleasedCart()
		{
			ReleaseControl();
		}

		private void OnDisable()
		{
			ReleaseControl();
		}

		private void OnDestroy()
		{
			ReleaseControl();
		}
	}
	public class BoomboxUI : MonoBehaviourPun
	{
		private static BoomBoxCartMod Instance = BoomBoxCartMod.instance;

		public PhotonView photonView;

		public static bool anyUISHown = false;

		public bool showUI;

		private string urlInput = "";

		private bool isTimeSliderBeingDragged;

		private int songIndexForTime = -2;

		private float songTimePerc;

		private float lastSentSongTimePerc = -1f;

		private float lastSentVolume = 0.2f;

		private bool isVolumeSliderBeingDragged;

		private bool isIndividualVolumeBeingDragged;

		private int qualityLevel = 3;

		private string[] qualityLabels = new string[5] { "REALLY Low (You Freak)", "Low", "Medium-Low", "Medium-High", "High" };

		private bool isQualitySliderBeingDragged;

		private int lastSentQualityLevel = 3;

		private Rect windowRect;

		private Boombox boombox;

		private BoomboxController controller;

		private VisualEffects visualEffects;

		private Visualizer visualizer;

		private GUIStyle windowStyle;

		private GUIStyle headerStyle;

		private GUIStyle buttonStyle;

		private GUIStyle smallButtonStyle;

		private GUIStyle textFieldStyle;

		private GUIStyle labelStyle;

		private GUIStyle sliderStyle;

		private GUIStyle statusStyle;

		private GUIStyle scrollViewStyle;

		private GUIStyle queueHeaderStyle;

		private GUIStyle queueEntryStyle;

		private GUIStyle currentSongStyle;

		private Texture2D backgroundTexture;

		private Texture2D buttonTexture;

		private Texture2D sliderBackgroundTexture;

		private Texture2D sliderThumbTexture;

		private Texture2D textFieldBackgroundTexture;

		private Vector2 urlScrollPosition = Vector2.zero;

		private float textFieldVisibleWidth = 350f;

		private string errorMessage = "";

		private float errorMessageTime;

		public string statusMessage = "";

		private CursorLockMode previousLockMode;

		private bool previousCursorVisible;

		private bool stylesInitialized;

		private Vector2 scrollPosition = Vector2.zero;

		private Vector2 queueScrollPosition = Vector2.zero;

		private const float refreshHoldTime = 5f;

		private const int maxRefreshSymbols = 5;

		private float? refreshObjectStart;

		private bool refreshObjectSent;

		private string lastUrl;

		private static ManualLogSource Logger => Instance.logger;

		private void Awake()
		{
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				boombox = ((Component)this).GetComponent<Boombox>();
				if ((Object)(object)boombox != (Object)null)
				{
					photonView = boombox.photonView;
				}
				else
				{
					Logger.LogError((object)"BoomboxUI: Failed to find Boombox component");
					photonView = ((Component)this).GetComponent<PhotonView>();
				}
				controller = ((Component)this).GetComponent<BoomboxController>();
				visualEffects = ((Component)this).GetComponent<VisualEffects>();
				if ((Object)(object)visualEffects == (Object)null)
				{
					visualEffects = ((Component)this).gameObject.AddComponent<VisualEffects>();
				}
				visualizer = ((Component)this).GetComponent<Visualizer>();
				boombox?.ApplyVisualStateFromData();
				RefreshVisualComponentRefs();
				if ((Object)(object)photonView == (Object)null)
				{
					Logger.LogError((object)"BoomboxUI: Failed to find PhotonView component");
				}
				windowRect = new Rect((float)(Screen.width / 2 - 230), (float)(Screen.height / 2 - 170), 460f, 340f);
			}
			catch (Exception ex)
			{
				Logger.LogError((object)("Error in BoomboxUI.Awake: " + ex.Message + "\n" + ex.StackTrace));
			}
		}

		private void Update()
		{
			if (Time.time > errorMessageTime && !string.IsNullOrEmpty(errorMessage))
			{
				errorMessage = "";
			}
			if (showUI && Keyboard.current != null && ((ButtonControl)Keyboard.current.escapeKey).wasPressedThisFrame)
			{
				if ((Object)(object)controller != (Object)null)
				{
					controller.ReleaseControl();
				}
				else
				{
					HideUI();
				}
			}
			if (isTimeSliderBeingDragged && ((Mouse.current != null && Mouse.current.leftButton.wasReleasedThisFrame) || songIndexForTime != boombox.GetCurrentSongIndex()))
			{
				isTimeSliderBeingDragged = false;
				SendTimeUpdate();
				songIndexForTime = -2;
				songTimePerc = 0f;
				lastSentSongTimePerc = -1f;
			}
			if (isVolumeSliderBeingDragged && Mouse.current != null && Mouse.current.leftButton.wasReleasedThisFrame)
			{
				isVolumeSliderBeingDragged = false;
				SendVolumeUpdate();
			}
			if (isIndividualVolumeBeingDragged && Mouse.current != null && Mouse.current.leftButton.wasReleasedThisFrame)
			{
				isIndividualVolumeBeingDragged = false;
				AudioSettings.SetPersonal(boombox.data.personalVolumePercentage);
			}
			if (isQualitySliderBeingDragged && Mouse.current != null && Mouse.current.leftButton.wasReleasedThisFrame)
			{
				isQualitySliderBeingDragged = false;
				SendQualityUpdate();
			}
			if (refreshObjectStart.HasValue && Mouse.current != null && Mouse.current.leftButton.wasReleasedThisFrame)
			{
				refreshObjectStart = null;
				refreshObjectSent = false;
			}
		}

		public void ShowUI()
		{
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			if (!showUI)
			{
				if ((Object)(object)boombox == (Object)null || (Object)(object)photonView == (Object)null)
				{
					Logger.LogError((object)"Cannot show UI - boombox or photonView is null");
					return;
				}
				anyUISHown = true;
				showUI = true;
				previousLockMode = Cursor.lockState;
				previousCursorVisible = Cursor.visible;
				Cursor.visible = true;
				Cursor.lockState = (CursorLockMode)0;
				UpdateDataFromBoomBox();
				UpdateStatusFromBoombox();
			}
		}

		public void UpdateDataFromBoomBox()
		{
			if ((Object)(object)boombox != (Object)null)
			{
				lastSentVolume = boombox.data.absVolume;
				qualityLevel = AudioPlayer.GetQuality();
				lastSentQualityLevel = qualityLevel;
				RefreshVisualComponentRefs();
			}
		}

		private void RefreshVisualComponentRefs()
		{
			visualEffects = ((Component)this).GetComponent<VisualEffects>();
			visualizer = ((Component)this).GetComponent<Visualizer>();
		}

		public void UpdateStatusFromBoombox()
		{
			if ((Object)(object)boombox != (Object)null)
			{
				if (YoutubeDL.IsUpdatingResources)
				{
					statusMessage = YoutubeDL.ResourceUpdateStatus;
				}
				else if (boombox.downloadHelper.IsProcessingQueue() && boombox.data.currentSong != null && !boombox.data.currentSong.ClipLoaded())
				{
					statusMessage = "Downloading audio from " + boombox.downloadHelper.GetCurrentDownloadUrl() + "...";
				}
				else if (boombox.data.currentSong != null && boombox.data.pendingPlaybackStart)
				{
					statusMessage = "Loading: " + boombox.data.currentSong.Title;
				}
				else if (boombox.data.currentSong != null && boombox.data.isPlaying)
				{
					statusMessage = "Now playing: " + boombox.data.currentSong.Title;
				}
				else if (!string.IsNullOrEmpty(boombox.data.currentSong?.Url))
				{
					statusMessage = "Ready to play: " + boombox.data.currentSong.Title;
				}
				else
				{
					statusMessage = "Ready to play music! Enter a Video URL";
				}
			}
		}

		private void SendTimeUpdate()
		{
			if (songTimePerc != lastSentSongTimePerc)
			{
				lastSentSongTimePerc = songTimePerc;
				if (boombox?.GetCurrentSongIndex() == songIndexForTime && songIndexForTime != -1 && (Object)(object)boombox?.audioPlayer?.GetClip() != (Object)null && boombox.audioPlayer.GetClip().length > 0f)
				{
					float time = Math.Max(0f, Math.Min(songTimePerc * boombox.audioPlayer.GetClip().length, boombox.audioPlayer.GetClip().length - 0.05f));
					boombox.audioPlayer.SetTime(time);
					boombox.CommitPlaybackSeek();
				}
				else if (songIndexForTime != boombox.GetCurrentSongIndex())
				{
					UpdateDataFromBoomBox();
				}
			}
		}

		private void SendVolumeUpdate()
		{
			if (boombox.data.absVolume != lastSentVolume)
			{
				lastSentVolume = boombox.data.absVolume;
				boombox.SetVolumeLocal(boombox.data.absVolume);
			}
		}

		private void SendQualityUpdate()
		{
			if (qualityLevel != lastSentQualityLevel)
			{
				lastSentQualityLevel = qualityLevel;
				if ((Object)(object)boombox != (Object)null)
				{
					boombox.audioPlayer?.SetQuality(qualityLevel);
				}
			}
		}

		public void HideUI()
		{
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			if (showUI)
			{
				if ((Object)(object)boombox != (Object)null && isVolumeSliderBeingDragged)
				{
					isVolumeSliderBeingDragged = false;
					SendVolumeUpdate();
				}
				if ((Object)(object)boombox != (Object)null && isIndividualVolumeBeingDragged)
				{
					isIndividualVolumeBeingDragged = false;
					AudioSettings.SetPersonal(boombox.data.personalVolumePercentage);
				}
				anyUISHown = false;
				showUI = false;
				Cursor.lockState = previousLockMode;
				Cursor.visible = previousCursorVisible;
			}
		}

		public bool IsUIVisible()
		{
			return showUI;
		}

		public void UpdateStatus(string message)
		{
			statusMessage = message;
		}

		private Texture2D CreateColorTexture(Color color)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Expected O, but got Unknown
			Texture2D val = new Texture2D(1, 1);
			val.SetPixel(0, 0, color);
			val.Apply();
			return val;
		}

		private void InitializeStyles()
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Expected O, but got Unknown
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_011b: Expected O, but got Unknown
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: Expected O, but got Unknown
			//IL_013e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0148: Expected O, but got Unknown
			//IL_016c: Unknown result type (might be due to invalid IL or missing references)
			//IL_018e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0198: Expected O, but got Unknown
			//IL_01a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ad: Expected O, but got Unknown
			//IL_01e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0212: 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_0241: Unknown result type (might be due to invalid IL or missing references)
			//IL_0256: Unknown result type (might be due to invalid IL or missing references)
			//IL_0279: Unknown result type (might be due to invalid IL or missing references)
			//IL_0283: Expected O, but got Unknown
			//IL_028d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0297: Expected O, but got Unknown
			//IL_02aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b4: Expected O, but got Unknown
			//IL_02be: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c8: Expected O, but got Unknown
			//IL_02e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ea: Expected O, but got Unknown
			//IL_031a: Unknown result type (might be due to invalid IL or missing references)
			//IL_033d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0347: Expected O, but got Unknown
			//IL_0352: Unknown result type (might be due to invalid IL or missing references)
			//IL_035c: Expected O, but got Unknown
			//IL_037c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0386: Expected O, but got Unknown
			//IL_0390: Unknown result type (might be due to invalid IL or missing references)
			//IL_039a: Expected O, but got Unknown
			//IL_03a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_03af: Expected O, but got Unknown
			//IL_03ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_03dc: 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_03fb: Expected O, but got Unknown
			//IL_0406: Unknown result type (might be due to invalid IL or missing references)
			//IL_0440: Unknown result type (might be due to invalid IL or missing references)
			//IL_044a: Expected O, but got Unknown
			//IL_0467: Unknown result type (might be due to invalid IL or missing references)
			//IL_0471: Expected O, but got Unknown
			//IL_0495: Unknown result type (might be due to invalid IL or missing references)
			//IL_049f: Expected O, but got Unknown
			//IL_04a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_04b0: Expected O, but got Unknown
			//IL_04d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_04ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0521: Unknown result type (might be due to invalid IL or missing references)
			//IL_052b: Expected O, but got Unknown
			//IL_054b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0565: Unknown result type (might be due to invalid IL or missing references)
			if (!stylesInitialized)
			{
				backgroundTexture = CreateColorTexture(new Color(0.1f, 0.1f, 0.1f, 0.9f));
				buttonTexture = CreateColorTexture(new Color(0.2f, 0.2f, 0.3f, 1f));
				sliderBackgroundTexture = CreateColorTexture(new Color(0.15f, 0.15f, 0.2f, 1f));
				sliderThumbTexture = CreateColorTexture(new Color(0.7f, 0.7f, 0.8f, 1f));
				textFieldBackgroundTexture = CreateColorTexture(new Color(0.15f, 0.17f, 0.2f, 1f));
				windowStyle = new GUIStyle(GUI.skin.window);
				windowStyle.normal.background = backgroundTexture;
				windowStyle.onNormal.background = backgroundTexture;
				windowStyle.border = new RectOffset(10, 10, 10, 10);
				windowStyle.padding = new RectOffset(15, 15, 20, 15);
				headerStyle = new GUIStyle(GUI.skin.label);
				headerStyle.fontSize = 18;
				headerStyle.fontStyle = (FontStyle)1;
				headerStyle.normal.textColor = Color.white;
				headerStyle.alignment = (TextAnchor)4;
				headerStyle.margin = new RectOffset(0, 0, 10, 20);
				buttonStyle = new GUIStyle(GUI.skin.button);
				buttonStyle.normal.background = buttonTexture;
				buttonStyle.hover.background = CreateColorTexture(new Color(0.3f, 0.3f, 0.4f, 1f));
				buttonStyle.active.background = CreateColorTexture(new Color(0.4f, 0.4f, 0.5f, 1f));
				buttonStyle.normal.textColor = Color.white;
				buttonStyle.hover.textColor = Color.white;
				buttonStyle.active.textColor = Color.white;
				buttonStyle.fontSize = 14;
				buttonStyle.padding = new RectOffset(15, 15, 8, 8);
				buttonStyle.margin = new RectOffset(5, 5, 5, 5);
				buttonStyle.alignment = (TextAnchor)4;
				smallButtonStyle = new GUIStyle(buttonStyle);
				smallButtonStyle.padding = new RectOffset(8, 8, 4, 4);
				smallButtonStyle.fontSize = 12;
				textFieldStyle = new GUIStyle(GUI.skin.textField);
				textFieldStyle.normal.background = textFieldBackgroundTexture;
				textFieldStyle.normal.textColor = new Color(1f, 1f, 1f);
				textFieldStyle.fontSize = 14;
				textFieldStyle.padding = new RectOffset(10, 10, 8, 8);
				scrollViewStyle = new GUIStyle(GUI.skin.scrollView);
				scrollViewStyle.normal.background = textFieldBackgroundTexture;
				scrollViewStyle.border = new RectOffset(2, 2, 2, 2);
				scrollViewStyle.padding = new RectOffset(0, 0, 0, 0);
				labelStyle = new GUIStyle(GUI.skin.label);
				labelStyle.normal.textColor = Color.white;
				labelStyle.fontSize = 14;
				labelStyle.margin = new RectOffset(0, 0, 10, 5);
				statusStyle = new GUIStyle(GUI.skin.label);
				statusStyle.normal.textColor = Color.cyan;
				statusStyle.fontSize = 14;
				statusStyle.wordWrap = true;
				statusStyle.alignment = (TextAnchor)4;
				sliderStyle = new GUIStyle(GUI.skin.horizontalSlider);
				sliderStyle.normal.background = sliderBackgroundTexture;
				queueHeaderStyle = new GUIStyle(headerStyle);
				queueHeaderStyle.fontSize = 16;
				queueHeaderStyle.alignment = (TextAnchor)3;
				queueHeaderStyle.margin = new RectOffset(5, 0, 10, 5);
				queueEntryStyle = new GUIStyle(textFieldStyle);
				queueEntryStyle.normal.background = CreateColorTexture(new Color(0.1f, 0.1f, 0.1f, 0.7f));
				queueEntryStyle.hover.background = CreateColorTexture(new Color(0.2f, 0.2f, 0.2f, 0.8f));
				queueEntryStyle.alignment = (TextAnchor)3;
				currentSongStyle = new GUIStyle(queueEntryStyle);
				currentSongStyle.normal.background = CreateColorTexture(new Color(0.1f, 0.3f, 0.1f, 0.9f));
				currentSongStyle.normal.textColor = Color.yellow;
				currentSongStyle.hover.background = currentSongStyle.normal.background;
				stylesInitialized = true;
			}
		}

		private void OnGUI()
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Expected O, but got Unknown
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			if (showUI)
			{
				if (!stylesInitialized)
				{
					InitializeStyles();
				}
				windowRect = GUILayout.Window(0, windowRect, new WindowFunction(DrawUI), "CarretaFuracao", windowStyle, Array.Empty<GUILayoutOption>());
			}
		}

		private void DrawUI(int windowID)
		{
			if (boombox?.data != null)
			{
				DrawCompactPanel(boombox);
				GUI.DragWindow();
			}
		}

		private void DrawCompactPanel(Boombox boombox)
		{
			GUILayout.Space(6f);
			float num = 0f;
			float num2 = 0f;
			float num3 = 0f;
			string text = "??";
			bool flag = (Object)(object)boombox.audioPlayer?.GetClip() != (Object)null;
			if (flag)
			{
				num = boombox.audioPlayer.audioSource.time;
				num2 = boombox.audioPlayer.GetClip().length;
				if (num2 > 0f)
				{
					num3 = num / num2;
					text = PrintTime(num2);
				}
				else
				{
					flag = false;
				}
			}
			GUILayout.Label(PrintTime(num) + " / " + text, labelStyle, Array.Empty<GUILayoutOption>());
			float num4 = GUILayout.HorizontalSlider(num3, 0f, 1f, sliderStyle, GUI.skin.horizontalSliderThumb, Array.Empty<GUILayoutOption>());
			int currentSongIndex = boombox.GetCurrentSongIndex();
			if (flag && currentSongIndex != -1 && num4 != num3)
			{
				isTimeSliderBeingDragged = true;
				if (songIndexForTime == -2)
				{
					songIndexForTime = currentSongIndex;
				}
				if (songIndexForTime == currentSongIndex)
				{
					float time = Math.Max(0f, Math.Min(num4 * num2, boombox.audioPlayer.GetClip().length - 0.05f));
					boombox.audioPlayer.audioSource.time = time;
					songTimePerc = num4;
				}
			}
			GUILayout.Space(10f);
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			if (GUILayout.Button("◀ Anterior", buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(38f) }))
			{
				boombox.PlayPreviousRandomJukeboxLocal();
			}
			if (GUILayout.Button("Pular ▶", buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(38f) }))
			{
				boombox.PlayNextRandomJukeboxLocal();
			}
			GUILayout.EndHorizontal();
			GUILayout.Space(14f);
			GUILayout.Label($"Volume Master: {Mathf.Round(boombox.data.absVolume * 100f)}%", labelStyle, Array.Empty<GUILayoutOption>());
			float num5 = GUILayout.HorizontalSlider(boombox.data.absVolume, 0f, 1f, sliderStyle, GUI.skin.horizontalSliderThumb, Array.Empty<GUILayoutOption>());
			if (num5 != boombox.data.absVolume)
			{
				isVolumeSliderBeingDragged = true;
				boombox.data.absVolume = num5;
				if ((Object)(object)boombox.audioPlayer?.audioSource != (Object)null)
				{
					boombox.audioPlayer.SetVolume(boombox.data.absVolume * boombox.data.personalVolumePercentage);
				}
			}
			GUILayout.Space(12f);
			GUILayout.Label($"Volume Pessoal: {Mathf.Round(boombox.data.personalVolumePercentage * 100f)}%", labelStyle, Array.Empty<GUILayoutOption>());
			float num6 = GUILayout.HorizontalSlider(boombox.data.personalVolumePercentage, 0f, 1f, sliderStyle, GUI.skin.horizontalSliderThumb, Array.Empty<GUILayoutOption>());
			if (num6 != boombox.data.personalVolumePercentage)
			{
				isIndividualVolumeBeingDragged = true;
				boombox.data.personalVolumePercentage = num6;
				if ((Object)(object)boombox.audioPlayer?.audioSource != (Object)null)
				{
					boombox.audioPlayer.SetVolume(boombox.data.absVolume * boombox.data.personalVolumePercentage);
				}
			}
			GUILayout.Space(10f);
			GUILayout.Label("E: ligar/desligar", statusStyle, Array.Empty<GUILayoutOption>());
			GUILayout.Space(8f);
			if (GUILayout.Button("Fechar", buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(36f) }))
			{
				if ((Object)(object)controller != (Object)null)
				{
					controller.ReleaseControl();
				}
				else
				{
					HideUI();
				}
			}
		}

		private void DrawMainPanel(Boombox boombox)
		{
			//IL_0002: 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_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_05ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_0564: Unknown result type (might be due to invalid IL or missing references)
			//IL_0584: Unknown result type (might be due to invalid IL or missing references)
			//IL_05f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_05f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_05ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0701: Unknown result type (might be due to invalid IL or missing references)
			//IL_0708: Unknown result type (might be due to invalid IL or missing references)
			//IL_070d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0716: Unknown result type (might be due to invalid IL or missing references)
			//IL_07fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0805: Unknown result type (might be due to invalid IL or missing references)
			//IL_080a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0813: Unknown result type (might be due to invalid IL or missing references)
			scrollPosition = GUILayout.BeginScrollView(scrollPosition, false, false, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandHeight(true) });
			GUILayout.Space(10f);
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.Label("Enter Video URL:", labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) });
			if (GUILayout.Button("Clear", smallButtonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(60f) }))
			{
				urlInput = "";
				GUI.FocusControl((string)null);
			}
			GUILayout.EndHorizontal();
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			urlScrollPosition = GUILayout.BeginScrollView(urlScrollPosition, false, false, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(60f) });
			urlInput = GUILayout.TextField(urlInput, textFieldStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(34f) });
			urlInput = Regex.Replace(urlInput, "\\s+", "");
			GUILayout.EndScrollView();
			GUILayout.EndHorizontal();
			float num = 0f;
			float num2 = 0f;
			float num3 = 0f;
			string text = "??";
			bool flag = (Object)(object)boombox != (Object)null && (Object)(object)boombox.audioPlayer?.GetClip() != (Object)null;
			if (flag)
			{
				num = boombox.audioPlayer.audioSource.time;
				num2 = boombox.audioPlayer.GetClip().length;
				if (num2 > 0f)
				{
					num3 = num / num2;
					text = PrintTime(num2);
				}
				else
				{
					flag = false;
				}
			}
			GUILayout.Label(PrintTime(num) + " / " + text, labelStyle, Array.Empty<GUILayoutOption>());
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			Rect lastRect;
			if (flag && (int)Event.current.type == 0)
			{
				lastRect = GUILayoutUtility.GetLastRect();
				if (((Rect)(ref lastRect)).Contains(Event.current.mousePosition))
				{
					isTimeSliderBeingDragged = true;
				}
			}
			float num4 = GUILayout.HorizontalSlider(num3, 0f, 1f, sliderStyle, GUI.skin.horizontalSliderThumb, Array.Empty<GUILayoutOption>());
			int currentSongIndex = boombox.GetCurrentSongIndex();
			if (flag && currentSongIndex != -1 && num4 != num3)
			{
				if (!isTimeSliderBeingDragged)
				{
					isTimeSliderBeingDragged = true;
				}
				if (songIndexForTime == -2)
				{
					songIndexForTime = currentSongIndex;
				}
				if (songIndexForTime == currentSongIndex)
				{
					float time = Math.Max(0f, Math.Min(num4 * num2, boombox.audioPlayer.GetClip().length - 0.05f));
					boombox.audioPlayer.audioSource.time = time;
					songTimePerc = num4;
				}
			}
			GUILayout.EndHorizontal();
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			if (GUILayout.Button("<<", smallButtonStyle, (GUILayoutOption[])(object)new GUILayoutOption[2]
			{
				GUILayout.Width(40f),
				GUILayout.Height(40f)
			}) && (Object)(object)boombox != (Object)null && boombox.data.currentSong != null)
			{
				boombox.JumpPlaybackBySeconds(-10f);
			}
			if (GUILayout.Button((boombox?.data != null && boombox.data.playbackQueue.Count > 0) ? "+ ENQUEUE" : "▶ PLAY", buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(40f) }))
			{
				var (text2, seconds) = IsValidVideoUrl(urlInput);
				if (string.IsNullOrEmpty(text2))
				{
					ShowErrorMessage("Invalid Video URL!");
				}
				else if (lastUrl != text2)
				{
					lastUrl = text2;
					boombox.EnqueueSongLocal(text2, seconds);
					GUI.FocusControl((string)null);
				}
			}
			if (GUILayout.Button((boombox.data.currentSong == null) ? "..." : (boombox.data.isPlaying ? "▌▌ PAUSE" : "▶ RESUME"), buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(40f) }) && boombox.data.currentSong != null)
			{
				boombox.SetPlaybackStateLocal(!boombox.data.isPlaying);
			}
			if (GUILayout.Button(">>", smallButtonStyle, (GUILayoutOption[])(object)new GUILayoutOption[2]
			{
				GUILayout.Width(40f),
				GUILayout.Height(40f)
			}) && (Object)(object)boombox != (Object)null && boombox.data.currentSong != null)
			{
				boombox.JumpPlaybackBySeconds(10f);
			}
			GUILayout.EndHorizontal();
			if ((Object)(object)boombox != (Object)null && boombox.downloadHelper.IsProcessingQueue())
			{
				Boombox.AudioEntry currentSong = boombox.data.currentSong;
				if ((currentSong == null || !currentSong.ClipLoaded()) && boombox.downloadHelper.GetCurrentDownloadUrl() != null)
				{
					GUILayout.Space(10f);
					GUILayout.Label("Download in progress...", statusStyle, Array.Empty<GUILayoutOption>());
					GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
					GUILayout.FlexibleSpace();
					if (GUILayout.Button("Force Cancel Download", buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[2]
					{
						GUILayout.Width(200f),
						GUILayout.Height(30f)
					}))
					{
						boombox.downloadHelper.ForceCancelDownload();
					}
					GUILayout.FlexibleSpace();
					GUILayout.EndHorizontal();
				}
			}
			GUILayout.Space(15f);
			if (!string.IsNullOrEmpty(statusMessage))
			{
				GUILayout.Label(statusMessage, statusStyle, Array.Empty<GUILayoutOption>());
				GUILayout.Space(5f);
			}
			if (!string.IsNullOrEmpty(errorMessage))
			{
				GUI.color = Color.red;
				GUILayout.Label(errorMessage, labelStyle, Array.Empty<GUILayoutOption>());
				GUI.color = Color.white;
				GUILayout.Space(5f);
			}
			GUILayout.Space(15f);
			float num5 = boombox.data.absVolume * 100f;
			GUILayout.Label($"Volume: {Mathf.Round(num5)}%", labelStyle, Array.Empty<GUILayoutOption>());
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			if ((int)Event.current.type == 0)
			{
				lastRect = GUILayoutUtility.GetLastRect();
				if (((Rect)(ref lastRect)).Contains(Event.current.mousePosition))
				{
					isVolumeSliderBeingDragged = true;
				}
			}
			float num6 = GUILayout.HorizontalSlider(boombox.data.absVolume, 0f, 1f, sliderStyle, GUI.skin.horizontalSliderThumb, Array.Empty<GUILayoutOption>());
			if (num6 != boombox.data.absVolume)
			{
				if (!isVolumeSliderBeingDragged)
				{
					isVolumeSliderBeingDragged = true;
				}
				if ((Object)(object)boombox.audioPlayer?.audioSource != (Object)null)
				{
					float volume = boombox.data.absVolume * boombox.data.personalVolumePercentage;
					boombox.audioPlayer.SetVolume(volume);
				}
				boombox.data.absVolume = num6;
			}
			GUILayout.EndHorizontal();
			GUILayout.Space(15f);
			GUILayout.Label($"Personal Volume Multiplier: {Mathf.Round(boombox.data.personalVolumePercentage * 100.001f)}%", labelStyle, Array.Empty<GUILayoutOption>());
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			if ((int)Event.current.type == 0)
			{
				lastRect = GUILayoutUtility.GetLastRect();
				if (((Rect)(ref lastRect)).Contains(Event.current.mousePosition))
				{
					isIndividualVolumeBeingDragged = true;
				}
			}
			float num7 = GUILayout.HorizontalSlider(boombox.data.personalVolumePercentage, 0f, 1f, sliderStyle, GUI.skin.horizontalSliderThumb, Array.Empty<GUILayoutOption>());
			if (num7 != boombox.data.personalVolumePercentage)
			{
				isIndividualVolumeBeingDragged = true;
				boombox.data.personalVolumePercentage = num7;
				if ((Object)(object)boombox.audioPlayer?.audioSource != (Object)null)
				{
					boombox.audioPlayer.SetVolume(boombox.data.absVolume * boombox.data.personalVolumePercentage);
				}
			}
			GUILayout.EndHorizontal();
			GUILayout.Space(15f);
			GUILayout.Label("Audio Quality: " + qualityLabels[qualityLevel]