Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of BoomboxCartUpgrade v1.3.4
BoomBoxCartUpgradeMod.dll
Decompiled 2 weeks ago
The result has been truncated due to the large size, download it to view full contents!
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.Runtime.Versioning; using System.Security; using System.Security.Permissions; 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.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("BoomboxCartUpgrade")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("BoomboxCartUpgrade")] [assembly: AssemblyCopyright("Copyright © 2025")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("37e852e0-b511-4315-8182-68c0a54e1ba9")] [assembly: AssemblyFileVersion("1.3.4.0")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.3.4.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace BoomBoxCartMod { 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; public AudioSource audioSource; 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() { return ((Object)(object)audioSource == (Object)null) ? null : audioSource.clip; } public void SetVolume(float volume) { audioSource.volume = volume; UpdateAudioRangeBasedOnVolume(); } public void UpdateAudioRangeBasedOnVolume() { UpdateAudioRangeBasedOnVolume(audioSource.volume); } public void UpdateAudioRangeBasedOnVolume(float volume) { //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0085: 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(AudioClip clip) { audioSource.Stop(); audioSource.clip = clip; audioSource.time = 0f; SetQuality(qualityLevel); UpdateAudioRangeBasedOnVolume(); } 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) { audioSource.time = time; } public bool IsPlaying() { return audioSource.isPlaying; } public void Play() { audioSource.Play(); } public void Pause() { audioSource.Pause(); } public void Stop() { audioSource.Stop(); audioSource.clip = null; } private void OnDestroy() { Object.Destroy((Object)(object)lowPassFilter); 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 = null; public List<AudioEntry> playbackQueue = new List<AudioEntry>(); public bool isPlaying = false; public float absVolume = 0.6f; public float personalVolumePercentage = 0.35f; public bool loopQueue = false; public bool underglowEnabled = false; public bool visualizerEnabled = true; public bool pendingPlaybackStart = false; public int stateVersion = 0; public int playbackTime = 0; public int playbackStartTimestamp = 0; } public class AudioEntry { public string Title; public string Url; public double Duration = -1.0; public int StartTime = 0; 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; } else if (Instance.UseTimeStampOnce.Value) { StartTime = 0; } return result; } public AudioClip GetAudioClip() { return DownloadHelper.downloadedClips.ContainsKey(Url) ? DownloadHelper.downloadedClips[Url] : null; } } private static BoomBoxCartMod Instance = BoomBoxCartMod.instance; public PhotonView photonView; public AudioPlayer audioPlayer; public Visualizer visualizer; public VisualEffects visualEffects; public DownloadHelper downloadHelper = null; private bool syncFinished = false; public bool startPlayBackOnDownload = true; public BoomboxData data = new BoomboxData(); private static bool mutePressed = false; private bool isApplyingSharedState = false; private string pendingCurrentSongDownloadUrl = null; private int lastAppliedSharedStateVersion = -1; private Hashtable lastSharedState = null; private float monsterAttractTimer = 0f; private float monsterAttractInterval = 1f; private static bool applyQualityToDownloads = false; private static bool monstersCanHearMusic = false; 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>(); } PersistentData.SetBoomboxViewInitialized(photonView.ViewID); Logger.LogInfo((object)$"Boombox initialized on this cart. AudioPlayer: {audioPlayer}, PhotonView: {photonView}"); } private void Start() { ApplyVisualStateFromData(); LoadSharedStateFromRoom(); } private void Update() { //IL_0062: Unknown result type (might be due to invalid IL or missing references) if (PhotonNetwork.IsMasterClient && data.isPlaying && MonstersCanHearMusic && (Object)(object)EnemyDirector.instance != (Object)null) { monsterAttractTimer += Time.deltaTime; if (monsterAttractTimer >= monsterAttractInterval) { EnemyDirector.instance.SetInvestigate(((Component)this).transform.position, 5f, false); monsterAttractTimer = 0f; } } else { monsterAttractTimer = 0f; } AudioSource audioSource = audioPlayer.audioSource; bool flag = (Object)(object)audioSource.clip != (Object)null && audioSource.time >= Math.Max(0f, audioSource.clip.length - 0.05f); if (!(syncFinished && data.isPlaying && !audioSource.isPlaying && flag) || !PhotonNetwork.IsMasterClient) { return; } int currentSongIndex = GetCurrentSongIndex(); if (currentSongIndex == -1) { DismissQueueLocal(); Logger.LogDebug((object)"Dismiss queue, invalid current song."); } else if (currentSongIndex + 1 >= data.playbackQueue.Count) { Logger.LogDebug((object)"Finish playing song"); if (LoopQueue && data.playbackQueue.Count > 0) { SelectSongIndex(0); return; } data.currentSong = null; data.playbackTime = 0; data.isPlaying = false; SetPlaybackReferenceFromSeconds(0f); PublishSharedState(updateTime: true); } else { SelectSongIndex(currentSongIndex + 1); } } public void TogglePlaying(bool value) { data.isPlaying = value; } public static long GetCurrentServerTimeMilliseconds() { return PhotonNetwork.ServerTimestamp; } 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 Hashtable CreateSharedState(bool includeTime, bool updateQueue) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Expected O, but got Unknown //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Expected O, but got Unknown //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Expected O, but got Unknown //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Expected O, but got Unknown //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Expected O, but got Unknown //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Expected O, but got Unknown //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Expected O, but got Unknown //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Expected O, but got Unknown //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Expected O, but got Unknown //IL_0109: Expected O, but got Unknown Hashtable val = new Hashtable(); ((Dictionary<object, object>)val).Add((object)"propVersion", (object)data.stateVersion); ((Dictionary<object, object>)val).Add((object)"IDKey", (object)data.key); ((Dictionary<object, object>)val).Add((object)"isPlaying", (object)(data.currentSong != null && data.isPlaying)); ((Dictionary<object, object>)val).Add((object)"pendingPlaybackStart", (object)data.pendingPlaybackStart); ((Dictionary<object, object>)val).Add((object)"absVolume", (object)data.absVolume); ((Dictionary<object, object>)val).Add((object)"loopQueue", (object)data.loopQueue); ((Dictionary<object, object>)val).Add((object)"underglow", (object)data.underglowEnabled); ((Dictionary<object, object>)val).Add((object)"visualizer", (object)data.visualizerEnabled); ((Dictionary<object, object>)val).Add((object)"currentSongIndex", (object)GetCurrentSongIndex()); Hashtable val2 = val; if (includeTime) { ((Dictionary<object, object>)(object)val2).Add((object)"playbackStartTimestamp", (object)data.playbackStartTimestamp); } if (updateQueue) { ((Dictionary<object, object>)(object)val2).Add((object)"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)string.Format("Created table with queue size: {0}", JsonConvert.DeserializeObject<SharedAudioEntry[]>((string)val2[(object)"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) { ApplyChangedValues(propertiesThatChanged); } } private void ApplyChangedValues(Hashtable propertiesThatChanged) { isApplyingSharedState = true; if (!((Dictionary<object, object>)(object)propertiesThatChanged).ContainsKey((object)"propVersion")) { isApplyingSharedState = false; return; } int num = (int)propertiesThatChanged[(object)"propVersion"]; if (num < data.stateVersion) { isApplyingSharedState = false; return; } int currentSongIndex = GetCurrentSongIndex(); bool flag = ((Dictionary<object, object>)(object)propertiesThatChanged).ContainsKey((object)"queue"); try { if (flag) { string text = (string)propertiesThatChanged[(object)"queue"]; SharedAudioEntry[] array = JsonConvert.DeserializeObject<SharedAudioEntry[]>(text); 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)$"Updated queue to size {data.playbackQueue.Count}."); } else { data.playbackQueue = new List<AudioEntry>(); } } if (((Dictionary<object, object>)(object)propertiesThatChanged).ContainsKey((object)"currentSongIndex")) { int num2 = (int)propertiesThatChanged[(object)"currentSongIndex"]; 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)$"Invalid currentsong index: {num2}."); } } else if (flag) { data.currentSong = data.playbackQueue[currentSongIndex]; } if (((Dictionary<object, object>)(object)propertiesThatChanged).ContainsKey((object)"pendingPlaybackStart")) { bool pendingPlaybackStart = (bool)propertiesThatChanged[(object)"pendingPlaybackStart"]; data.pendingPlaybackStart = pendingPlaybackStart; } if (((Dictionary<object, object>)(object)propertiesThatChanged).ContainsKey((object)"isPlaying")) { bool flag2 = (bool)propertiesThatChanged[(object)"isPlaying"]; data.isPlaying = data.currentSong != null && flag2; } if (((Dictionary<object, object>)(object)propertiesThatChanged).ContainsKey((object)"absVolume")) { float value = (float)propertiesThatChanged[(object)"absVolume"]; float num3 = Mathf.Clamp01(Convert.ToSingle(value)); if (data.absVolume != num3) { data.absVolume = num3; float volume = num3 * data.personalVolumePercentage; audioPlayer.SetVolume(volume); } } if (((Dictionary<object, object>)(object)propertiesThatChanged).ContainsKey((object)"loopQueue")) { bool loopQueue = (bool)propertiesThatChanged[(object)"loopQueue"]; data.loopQueue = loopQueue; } if (((Dictionary<object, object>)(object)propertiesThatChanged).ContainsKey((object)"underglow") && Instance.SyncVisuals.Value) { bool underglowEnabled = (bool)propertiesThatChanged[(object)"underglow"]; data.underglowEnabled = underglowEnabled; ApplyVisualStateFromData(); ((Component)this).GetComponent<BoomboxUI>()?.UpdateDataFromBoomBox(); } if (((Dictionary<object, object>)(object)propertiesThatChanged).ContainsKey((object)"visualizer") && Instance.SyncVisuals.Value) { bool visualizerEnabled = (bool)propertiesThatChanged[(object)"visualizer"]; data.visualizerEnabled = visualizerEnabled; ApplyVisualStateFromData(); ((Component)this).GetComponent<BoomboxUI>()?.UpdateDataFromBoomBox(); } if (((Dictionary<object, object>)(object)propertiesThatChanged).ContainsKey((object)"playbackStartTimestamp")) { int num4 = (int)propertiesThatChanged[(object)"playbackStartTimestamp"]; data.playbackStartTimestamp = num4; SetPlaybackTime(num4); } if (((Dictionary<object, object>)(object)propertiesThatChanged).ContainsKey((object)"IDKey")) { string text2 = (string)propertiesThatChanged[(object)"IDKey"]; if (!string.IsNullOrWhiteSpace(text2)) { data.key = text2; } } } catch (Exception ex) { Logger.LogWarning((object)("Error occured while reading properties: " + ex.Message)); } ApplySharedPlaybackState(); ((Component)this).GetComponent<BoomboxUI>()?.UpdateDataFromBoomBox(); syncFinished = true; isApplyingSharedState = false; } private void ApplySharedPlaybackState() { if (data.currentSong?.Url == null) { Logger.LogDebug((object)("ApplySharedPlaybackState: No current song" + ((data.currentSong == null) ? "" : "URL") + "!")); data.pendingPlaybackStart = false; audioPlayer.Stop(); UpdateUIStatus("Ready to play music! Enter a Video URL"); return; } AudioClip val = data.currentSong?.GetAudioClip(); if ((Object)(object)val == (Object)null) { audioPlayer.Stop(); startPlayBackOnDownload = data.pendingPlaybackStart; if (data.pendingPlaybackStart) { UpdateUIStatus("Loading: " + data.currentSong.Title); } if (!data.pendingPlaybackStart) { EnsureCurrentSongDownloaded(); } return; } if ((Object)(object)audioPlayer.GetClip() != (Object)(object)val) { audioPlayer.Stop(); audioPlayer.audioSource.clip = val; 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()) { Logger.LogDebug((object)$"ApplySharedPlaybackState: Starting playback - timestamp={data.playbackStartTimestamp}"); audioPlayer.Play(); SetPlaybackTime(data.playbackStartTimestamp); Logger.LogDebug((object)$"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>(); 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() { return !isApplyingSharedState && PhotonNetwork.IsConnected && PhotonNetwork.CurrentRoom != null && (Object)(object)photonView != (Object)null; } 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)$"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)$"GetTrackedPlaybackSeconds: Returning cached playbackTime={data.playbackTime} (not playing, time <= 0)"); return data.playbackTime; } float time = audioPlayer.GetTime(); Logger.LogDebug((object)$"GetTrackedPlaybackSeconds: Returning audioPlayer.GetTime()={time}, isPlaying={audioPlayer.IsPlaying()}"); return time; } if (data.playbackTime > 0) { Logger.LogDebug((object)$"GetTrackedPlaybackSeconds: Returning cached playbackTime={data.playbackTime} (no clip)"); return data.playbackTime; } float num = Math.Max(0f, (float)(GetCurrentServerTimeMilliseconds() - data.playbackStartTimestamp) / 1000f); Logger.LogDebug((object)$"GetTrackedPlaybackSeconds: Calculating from timestamp: {num}s"); return num; } private void CleanupCurrentPlayback() { StopLocalPlayback(updateSharedFlag: true); } private bool ShouldRequestMasterMutation() { return PhotonNetwork.IsConnected && PhotonNetwork.CurrentRoom != null && !PhotonNetwork.IsMasterClient; } public void SetPlaybackTime(long relativeStartTimeMillis) { float num = Math.Max(0f, (float)(GetCurrentServerTimeMilliseconds() - relativeStartTimeMillis) / 1000f); Logger.LogDebug((object)$"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)$"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 { SetPlaybackReferenceFromSeconds(audioPlayer.GetTime()); PublishSharedState(updateTime: true); } } } public void SetPlaybackStateLocal(bool startPlaying) { if (data.currentSong != null) { if (ShouldRequestMasterMutation()) { BaseListener.RPC(photonView, "RequestSetPlaybackState", (RpcTarget)2, startPlaying, PhotonNetwork.LocalPlayer.ActorNumber); } else if ((Object)(object)data.currentSong.GetAudioClip() == (Object)null) { startPlayBackOnDownload = startPlaying; data.isPlaying = false; data.pendingPlaybackStart = startPlaying; PublishSharedState(updateTime: true); } else { float trackedPlaybackSeconds = GetTrackedPlaybackSeconds(); Logger.LogDebug((object)$"SetPlaybackStateLocal: trackedPlaybackSeconds={trackedPlaybackSeconds}, isPlaying={startPlaying}"); SetPlaybackReferenceFromSeconds(trackedPlaybackSeconds); Logger.LogDebug((object)$"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 ((Object)(object)data.currentSong.GetAudioClip() == (Object)null) { 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)"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); } else { 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; 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; } 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; } AudioEntry audioEntry = data.playbackQueue[index]; bool flag = audioEntry == 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) { SetPlaybackReferenceFromSeconds(playbackSeconds); PublishSharedState(updateTime: true); } } [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() { if (!((Object)(object)data.currentSong?.GetAudioClip() == (Object)null)) { ApplySharedPlaybackState(); } } public double EstimateDownloadTimeSeconds(double durationSeconds, int downloadSpeedMbps) { int bitrateKbps = DownloadHelper.GetBitrateKbps(ApplyQualityToDownloads ? 4 : AudioPlayer.GetQuality()); double num = (double)bitrateKbps * 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] { "1.3.4", PhotonNetwork.LocalPlayer.ActorNumber }); } } } private void OnDisable() { PersistentData.RemoveBoomboxViewInitialized(photonView.ViewID); data.playbackTime = (int)Math.Round(audioPlayer.GetTime()); } private void OnDestroy() { 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 BoomBoxCartMod Instance = BoomBoxCartMod.instance; private PhysGrabCart cart; private BoomboxUI boomboxUI; private Boombox boombox; private int currentControllerId = -1; private static ManualLogSource Logger => Instance.logger; private void Awake() { cart = ((Component)this).GetComponent<PhysGrabCart>(); boombox = ((Component)this).GetComponent<Boombox>(); if ((Object)(object)cart == (Object)null) { Logger.LogError((object)"BoomboxController: PhysGrabCart component not found!"); } else if ((Object)(object)boombox == (Object)null) { Logger.LogError((object)"BoomboxController: Boombox component not found!"); } } private bool IsLocalPlayerGrabbingCart() { return PlayerGrabbingTracker.IsLocalPlayerGrabbingCart(((Component)this).gameObject); } public void RequestBoomboxControl() { if (IsLocalPlayerGrabbingCart()) { int actorNumber = PhotonNetwork.LocalPlayer.ActorNumber; BaseListener.RPC(((MonoBehaviourPun)this).photonView, "RequestControl", (RpcTarget)2, actorNumber); } } [PunRPC] private void RequestControl(int requesterId) { if (PhotonNetwork.IsMasterClient) { bool flag = true; if (requesterId == PhotonNetwork.LocalPlayer.ActorNumber) { flag = PlayerGrabbingTracker.IsLocalPlayerGrabbingCart(((Component)this).gameObject); } if ((currentControllerId == -1 || !Instance.baseListener.GetAllModUsers().Contains(requesterId)) && flag) { BaseListener.RPC(((MonoBehaviourPun)this).photonView, "SetController", (RpcTarget)0, requesterId); } } } [PunRPC] private void SetController(int controllerId) { try { currentControllerId = controllerId; if (controllerId == PhotonNetwork.LocalPlayer.ActorNumber) { EnsureBoomboxUIExists(); if ((Object)(object)boomboxUI != (Object)null) { boomboxUI.ShowUI(); } else { Logger.LogError((object)"Failed to create BoomboxUI component"); } } else if ((Object)(object)boomboxUI != (Object)null && boomboxUI.IsUIVisible()) { boomboxUI.HideUI(); } } catch (Exception ex) { Logger.LogError((object)("Error in SetController: " + ex.Message + "\n" + ex.StackTrace)); } } private void EnsureBoomboxUIExists() { if ((Object)(object)boomboxUI == (Object)null) { boomboxUI = ((Component)this).gameObject.GetComponent<BoomboxUI>(); if ((Object)(object)boomboxUI == (Object)null) { boomboxUI = ((Component)this).gameObject.AddComponent<BoomboxUI>(); } } } public void ReleaseControl() { if (currentControllerId == PhotonNetwork.LocalPlayer.ActorNumber) { BaseListener.RPC(((MonoBehaviourPun)this).photonView, "RequestRelease", (RpcTarget)2, PhotonNetwork.LocalPlayer.ActorNumber); } } [PunRPC] private void RequestRelease(int releaserId) { if (PhotonNetwork.IsMasterClient && currentControllerId == releaserId) { BaseListener.RPC(((MonoBehaviourPun)this).photonView, "SetController", (RpcTarget)0, -1); } } private void OnPlayerReleasedCart(int playerActorNumber) { if (playerActorNumber == currentControllerId && PhotonNetwork.IsMasterClient) { BaseListener.RPC(((MonoBehaviourPun)this).photonView, "SetController", (RpcTarget)0, -1); } } public void LocalPlayerReleasedCart() { int actorNumber = PhotonNetwork.LocalPlayer.ActorNumber; if (currentControllerId == actorNumber) { ReleaseControl(); } } } public class BoomboxUI : MonoBehaviourPun { private static BoomBoxCartMod Instance = BoomBoxCartMod.instance; public PhotonView photonView; public static bool anyUISHown = false; public bool showUI = false; private string urlInput = ""; private bool isTimeSliderBeingDragged = false; private int songIndexForTime = -2; private float songTimePerc = 0f; private float lastSentSongTimePerc = -1f; private float lastSentVolume = 0.3f; private bool isVolumeSliderBeingDragged = false; private bool isIndividualVolumeBeingDragged = false; private int qualityLevel = 3; private string[] qualityLabels = new string[5] { "REALLY Low (You Freak)", "Low", "Medium-Low", "Medium-High", "High" }; private bool isQualitySliderBeingDragged = false; 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 = 0f; public string statusMessage = ""; private CursorLockMode previousLockMode; private bool previousCursorVisible; private bool stylesInitialized = false; private Vector2 scrollPosition = Vector2.zero; private Vector2 queueScrollPosition = Vector2.zero; private const float refreshHoldTime = 5f; private const int maxRefreshSymbols = 5; private float? refreshObjectStart = null; private bool refreshObjectSent = false; private string lastUrl = null; private static ManualLogSource Logger => Instance.logger; private void Awake() { //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: 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 - 400), (float)(Screen.height / 2 - 175), 800f, 550f); } 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; } 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_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0056: 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 && (Object)(object)boombox.data.currentSong.GetAudioClip() == (Object)null) { 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_001a: Unknown result type (might be due to invalid IL or missing references) if (showUI) { 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_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Expected O, but got Unknown //IL_000c: Unknown result type (might be due to invalid IL or missing references) Texture2D val = new Texture2D(1, 1); val.SetPixel(0, 0, color); val.Apply(); return val; } private void InitializeStyles() { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Expected O, but got Unknown //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Expected O, but got Unknown //IL_0133: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Expected O, but got Unknown //IL_0149: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Expected O, but got Unknown //IL_0179: Unknown result type (might be due to invalid IL or missing references) //IL_019d: Unknown result type (might be due to invalid IL or missing references) //IL_01a7: Expected O, but got Unknown //IL_01b3: Unknown result type (might be due to invalid IL or missing references) //IL_01bd: Expected O, but got Unknown //IL_01f4: Unknown result type (might be due to invalid IL or missing references) //IL_0224: Unknown result type (might be due to invalid IL or missing references) //IL_023f: Unknown result type (might be due to invalid IL or missing references) //IL_0255: Unknown result type (might be due to invalid IL or missing references) //IL_026b: Unknown result type (might be due to invalid IL or missing references) //IL_0290: Unknown result type (might be due to invalid IL or missing references) //IL_029a: Expected O, but got Unknown //IL_02a5: Unknown result type (might be due to invalid IL or missing references) //IL_02af: Expected O, but got Unknown //IL_02c4: Unknown result type (might be due to invalid IL or missing references) //IL_02ce: Expected O, but got Unknown //IL_02d8: Unknown result type (might be due to invalid IL or missing references) //IL_02e2: Expected O, but got Unknown //IL_02fc: Unknown result type (might be due to invalid IL or missing references) //IL_0306: Expected O, but got Unknown //IL_0337: Unknown result type (might be due to invalid IL or missing references) //IL_035c: Unknown result type (might be due to invalid IL or missing references) //IL_0366: Expected O, but got Unknown //IL_0372: Unknown result type (might be due to invalid IL or missing references) //IL_037c: Expected O, but got Unknown //IL_039d: Unknown result type (might be due to invalid IL or missing references) //IL_03a7: Expected O, but got Unknown //IL_03b2: Unknown result type (might be due to invalid IL or missing references) //IL_03bc: Expected O, but got Unknown //IL_03c8: Unknown result type (might be due to invalid IL or missing references) //IL_03d2: Expected O, but got Unknown //IL_03dd: Unknown result type (might be due to invalid IL or missing references) //IL_0401: Unknown result type (might be due to invalid IL or missing references) //IL_040b: Expected O, but got Unknown //IL_0417: Unknown result type (might be due to invalid IL or missing references) //IL_0421: Expected O, but got Unknown //IL_042c: Unknown result type (might be due to invalid IL or missing references) //IL_046a: Unknown result type (might be due to invalid IL or missing references) //IL_0474: Expected O, but got Unknown //IL_0492: Unknown result type (might be due to invalid IL or missing references) //IL_049c: Expected O, but got Unknown //IL_04c2: Unknown result type (might be due to invalid IL or missing references) //IL_04cc: Expected O, but got Unknown //IL_04d4: Unknown result type (might be due to invalid IL or missing references) //IL_04de: Expected O, but got Unknown //IL_04fe: Unknown result type (might be due to invalid IL or missing references) //IL_052e: Unknown result type (might be due to invalid IL or missing references) //IL_0552: Unknown result type (might be due to invalid IL or missing references) //IL_055c: Expected O, but got Unknown //IL_057c: Unknown result type (might be due to invalid IL or missing references) //IL_0597: 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_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Expected O, but got Unknown //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) if (showUI) { if (!stylesInitialized) { InitializeStyles(); } windowRect = GUILayout.Window(0, windowRect, new WindowFunction(DrawUI), "Boombox Controller", windowStyle, Array.Empty<GUILayoutOption>()); } } private void DrawUI(int windowID) { //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) if (boombox?.data == null) { return; } object obj; if (!Instance.baseListener.audioMuted) { obj = ""; } else { Key value = Instance.GlobalMuteKey.Value; obj = " - MUTED(" + ((object)(Key)(ref value)).ToString() + ")"; } GUILayout.Label("Control The Boombox In The Cart" + (string?)obj, headerStyle, Array.Empty<GUILayoutOption>()); GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); GUILayout.BeginVertical((GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(400f) }); DrawMainPanel(boombox); GUILayout.EndVertical(); GUILayout.BeginVertical((GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.Width(420f), GUILayout.ExpandHeight(true) }); DrawQueue(boombox); GUILayout.EndVertical(); GUILayout.EndHorizontal(); GUILayout.FlexibleSpace(); GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); GUILayout.FlexibleSpace(); if (GUILayout.Button("Close", buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.Width(300f), GUILayout.Height(36f) })) { if ((Object)(object)controller != (Object)null) { controller.ReleaseControl(); } else { HideUI(); } } GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); GUI.DragWindow(); } private void DrawMainPanel(Boombox boombox) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_01e2: Unknown result type (might be due to invalid IL or missing references) //IL_01e9: Unknown result type (might be due to invalid IL or missing references) //IL_01ee: Unknown result type (might be due to invalid IL or missing references) //IL_01f7: Unknown result type (might be due to invalid IL or missing references) //IL_06d5: Unknown result type (might be due to invalid IL or missing references) //IL_0647: Unknown result type (might be due to invalid IL or missing references) //IL_0669: Unknown result type (might be due to invalid IL or missing references) //IL_06dc: Unknown result type (might be due to invalid IL or missing references) //IL_06e1: Unknown result type (might be due to invalid IL or missing references) //IL_06ea: Unknown result type (might be due to invalid IL or missing references) //IL_0814: Unknown result type (might be due to invalid IL or missing references) //IL_081b: Unknown result type (might be due to invalid IL or missing references) //IL_0820: Unknown result type (might be due to invalid IL or missing references) //IL_0829: Unknown result type (might be due to invalid IL or missing references) //IL_0930: Unknown result type (might be due to invalid IL or missing references) //IL_0937: Unknown result type (might be due to invalid IL or missing references) //IL_093c: Unknown result type (might be due to invalid IL or missing references) //IL_0945: 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); } string text2 = ((boombox?.data != null && boombox.data.playbackQueue.Count > 0) ? "+ ENQUEUE" : "▶ PLAY"); if (GUILayout.Button(text2, buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(40f) })) { var (text3, seconds) = IsValidVideoUrl(urlInput); if (string.IsNullOrEmpty(text3)) { ShowErrorMessage("Invalid Video URL!"); } else if (lastUrl != text3) { lastUrl = text3; boombox.EnqueueSongLocal(text3, seconds); GUI.FocusControl((string)null); } } string text4 = ((boombox.data.currentSong == null) ? "..." : (boombox.data.isPlaying ? "▌▌ PAUSE" : "▶ RESUME")); if (GUILayout.Button(text4, 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() && (Object)(object)boombox.data.currentSong?.GetAudioClip() == (Object)null && 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], 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)) { isQualitySliderBeingDragged = true; } } float num8 = GUILayout.HorizontalSlider((float)qualityLevel, 0f, 4f, sliderStyle, GUI.skin.horizontalSliderThumb, Array.Empty<GUILayoutOption>()); int num9 = Mathf.RoundToInt(num8); if (num9 != qualityLevel && !isQualitySliderBeingDragged) { isQualitySliderBeingDragged = true; } qualityLevel = num9; if ((Object)(object)boombox?.audioPlayer != (Object)null) { boombox.audioPlayer.SetQuality(qualityLevel); } GUILayout.EndHorizontal(); GUILayout.Space(10f); bool applyQualityToDownloads = Boombox.ApplyQualityToDownloads; bool flag2 = GUILayout.Toggle(applyQualityToDownloads, "Apply Quality Setting to Downloads", Array.Empty<GUILayoutOption>()); if (flag2 != applyQualityToDownloads) { Boombox.ApplyQualityToDownloads = flag2; } GUILayout.Space(10f); bool monstersCanHearMusic = Boombox.MonstersCanHearMusic; bool flag3 = GUILayout.Toggle(monstersCanHearMusic, "Monsters can hear audio", Array.Empty<GUILayoutOption>()); if (flag3 != monstersCanHearMusic) { Boombox.MonstersCanHearMusic = flag3; } GUILayout.Space(10f); bool loopQueue = boombox.LoopQueue; bool flag4 = GUILayout.Toggle(loopQueue, "Loop queue", Array.Empty<GUILayoutOption>()); if (flag4 != loopQueue && PhotonNetwork.IsMasterClient) { boombox.SetLoopQueueLocal(flag4); } GUILayout.Space(10f); bool underglowEnabled = boombox.data.underglowEnabled; bool flag5 = GUILayout.Toggle(underglowEnabled, "RGB Underglow enabled", Array.Empty<GUILayoutOption>()); if (flag5 != underglowEnabled) { boombox.SetUnderglowEnabledLocal(flag5); UpdateDataFromBoomBox(); } GUILayout.Space(10f); bool visualizerEnabled = boombox.data.visualizerEnabled; bool flag6 = GUILayout.Toggle(visualizerEnabled, "Audio Visualizer enabled", Array.Empty<GUILayoutOption>()); if (flag6 != visualizerEnabled) { boombox.SetVisualizerEnabledLocal(flag6); UpdateDataFromBoomBox(); } GUILayout.EndScrollView(); } private void DrawQueue(Boombox boombox) { //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_015d: Unknown result type (might be due to invalid IL or missing references) //IL_0162: Unknown result type (might be due to invalid IL or missing references) GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); GUILayout.Label(" Playback Queue", queueHeaderStyle, Array.Empty<GUILayoutOption>()); if (PhotonNetwork.IsMasterClient) { float num = Time.time - (refreshObjectStart ?? Time.time); int num2 = 1 + (int)Mathf.Floor(num / 1f); string text = ((num > 0f && num <= 5f) ? (new string('!', num2) + new string('.', Math.Max(0, 5 - num2))) : "RESET"); if (GUILayout.RepeatButton(text, smallButtonStyle, Array.Empty<GUILayoutOption>())) { if (!refreshObjectStart.HasValue) { refreshObjectStart = Time.time; } else if (!refreshObjectSent && num >= 5f) { boombox.ResetData(); lastUrl = null; refreshObjectSent = true; } } } if (GUILayout.Button("Dismiss Queue", smallButtonStyle, Array.Empty<GUILayoutOption>())) { boombox.DismissQueueLocal(); lastUrl = null; } GUILayout.EndHorizontal(); queueScrollPosition = GUILayout.BeginScrollView(queueScrollPosition, false, true, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandHeight(true) }); List<Boombox.AudioEntry> playbackQueue = boombox.data.playbackQueue; int currentSongIndex = boombox.GetCurrentSongIndex(); if (playbackQueue.Count == 0) { GUILayout.Label(" Queue is empty and no song is playing.", labelStyle, Array.Empty<GUILayoutOption>()); } for (int i = 0; i < playbackQueue.Count; i++) { Boombox.AudioEntry audioEntry = playbackQueue[i]; bool flag = i == currentSongIndex; GUIStyle val = (flag ? currentSongStyle : queueEntryStyle); string text2 = (flag ? "▶ " : $"{i - ((currentSongIndex != -1) ? currentSongIndex : 0)}. "); string text3 = ClipText(text2 + audioEntry.Title, 280f, val); GUILayout.BeginHorizontal(val, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(32f) }); if (GUILayout.Button(text3, val, (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.ExpandWidth(true), GUILayout.Height(32f) }) && !flag) { boombox.SelectSongIndex(i); } if (!flag) { if (i > 0) { if (GUILayout.Button("▲", smallButtonStyle, (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.Width(25f), GUILayout.Height(28f) })) { boombox.MoveQueueItemLocal(i, i - 1); } } else { GUILayout.Space(30f); } if (i + 1 < playbackQueue.Count) { if (GUILayout.Button("▼", smallButtonStyle, (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.Width(25f), GUILayout.Height(28f) })) { boombox.MoveQueueItemLocal(i, i + 1); } } else { GUILayout.Space(30f); } if (GUILayout.Button("X", smallButtonStyle, (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.Width(25f), GUILayout.Height(28f) })) { boombox.RemoveQueueItemLocal(i); } } GUILayout.EndHorizontal(); } GUILayout.EndScrollView(); } private string ClipText(string text, float maxWidth, GUIStyle style) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Expected O, but got Unknown //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0036: 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) Vector2 val = style.CalcSize(new GUIContent(text)); string text2 = text; int length = text.Length; while (val.x > maxWidth) { text2 = text2.Substring(0, text2.Length - 4) + "..."; val = style.CalcSize(new GUIContent(text2)); } return text2; } private string PrintTime(float time) { return $"{(int)Math.Floor(time / 60f)}:{(int)(time % 60f)}"; } private (string cleanedUrl, int seconds) IsValidVideoUrl(string url) { return DownloadHelper.IsValidVideoUrl(url); } private void ShowErrorMessage(string message) { errorMessage = message; errorMessageTime = Time.time + 3f; } private void OnDestroy() { //IL_001a: Unknown result type (might be due to invalid IL or missing references) if (showUI) { anyUISHown = false; showUI = false; Cursor.lockState = previousLockMode; Cursor.visible = previousCursorVisible; } if ((Object)(object)backgroundTexture != (Object)null) { Object.Destroy((Object)(object)backgroundTexture); } if ((Object)(object)buttonTexture != (Object)null) { Object.Destroy((Object)(object)buttonTexture); } if ((Object)(object)sliderBackgroundTexture != (Object)null) { Object.Destroy((Object)(object)sliderBackgroundTexture); } if ((Object)(object)sliderThumbTexture != (Object)null) { Object.Destroy((Object)(object)sliderThumbTexture); } if ((Object)(object)textFieldBackgroundTexture != (Object)null) { Object.Destroy((Object)(object)textFieldBackgroundTexture); } } } public class DownloadHelper : MonoBehaviourPunCallbacks { private static BoomBoxCartMod Instance = BoomBoxCartMod.instance; private Boombox boomboxParent = null; public static Dictionary<string, AudioClip> downloadedClips = new Dictionary<string, AudioClip>(); public static Dictionary<string, SongInfo> songInfo = new Dictionary<string, SongInfo>(); public static Dictionary<string, HashSet<int>> downloadsReady = new Dictionary<string, HashSet<int>>(); public static Dictionary<string, HashSet<int>> downloadErrors = new Dictionary<string, HashSet<int>>(); public const int INITIAL_DOWNLOAD_TIMEOUT = 11; private const int TIMEOUT_THRESHOLD = 10; private Dictionary<string, Coroutine> timeoutCoroutines = new Dictionary<string, Coroutine>(); private Queue<string> downloadJobQueue = new Queue<string>(); private bool isProcessingQueue = false; private string currentRequestId = null; private string currentDownloadUrl = null; private bool isTimeoutRecovery = false; private Coroutine processingCoroutine; private static readonly Regex[] supportedVideoUrlRegexes = new Regex[5] { new Regex("^(?<CleanedUrl>((?:https?:)?\\/\\/)?(((?:www|m)\\.)?((?:youtube(?:-nocookie)?\\.com|youtu\\.be))|music\\.youtube\\.com)(\\/(?:[\\w\\-]+\\?v=|embed\\/|live\\/|v\\/)?)([\\w\\-]+))(?<TrailingParams>(&(\\S+&)*?(t=(?<TimeStamp>(?<Seconds>\\d+)))\\S*)?\\S*?)$", RegexOptions.IgnoreCase | RegexOptions.Compiled), new Regex("^(?<CleanedUrl>((?:https?:)?\\/\\/)?((?:www)?\\.?)(rutube\\.ru)(\\/video\\/)([\\w\\-]+))(?<TrailingParams>(\\?(?:\\S+&)*?(t=(?<TimeStamp>(?<Seconds>\\d+)))\\S*)?\\S*?)$", RegexOptions.IgnoreCase | RegexOptions.Compiled), new Regex("^(?<CleanedUrl>((?:https?:)?\\/\\/)?((?:www)?\\.?)(music\\.yandex\\.ru)(\\/album\\/\\d+\\/track\\/)([\\w\\-]+))(?<TrailingParams>(?:\\?(\\S+&)*?(t=(?<TimeStamp>(?<Seconds>\\d+)))\\S*)?\\S*?)$", RegexOptions.IgnoreCase | RegexOptions.Compiled), new Regex("^(?<CleanedUrl>((?:https?:)?\\/\\/)?((?:www|m)\\.)?(bilibili\\.com)(\\/video\\/)([\\w\\-]+))(?<TrailingParams>(\\?(?:\\S+&)*?(t=(?<TimeStamp>(?<Seconds>\\d+)))\\S*)?\\S*?)$", RegexOptions.IgnoreCase | RegexOptions.Compiled), new Regex("^(?<CleanedUrl>((?:https?:)?\\/\\/)?((?:www|m)\\.)?(soundcloud\\.com|snd\\.sc)\\/([\\w\\-]+\\/[\\w\\-]+))(?<TrailingParams>(?:\\?(?:\\S+&*?#)*?t=(?<TimeStamp>(?<Minutes>\\d+)(?:\\/|(?:%3A))(?<Seconds>\\d{1,2})))?\\S*)?$", RegexOptions.IgnoreCase | RegexOptions.Compiled) }; private static ManualLogSource Logger => Instance.logger; private void Awake() { boomboxParent = ((Component)this).gameObject.GetComponent<Boombox>(); } private void OnDestroy() { downloadJobQueue.Clear(); foreach (Coroutine value in timeoutCoroutines.Values) { if (value != null) { ((MonoBehaviour)this).StopCoroutine(value); } } timeoutCoroutines.Clear(); } public bool IsProcessingQueue() { return isProcessingQueue; } public string GetCurrentDownloadUrl() { return currentDownloadUrl; } public static (string cleanedUrl, int seconds) IsValidVideoUrl(string url) { if (!string.IsNullOrWhiteSpace(url)) { Regex[] array = supportedVideoUrlRegexes; foreach (Regex regex in array) { Match match = regex.Match(url); if (!match.Success) { continue; } Group group = match.Groups["CleanedUrl"]; if (!group.Success) { continue; } Group group2 = match.Groups["TimeStamp"]; int num = 0; if (group2.Success) { Group group3 = match.Groups["Seconds"]; Group group4 = match.Groups["Minutes"]; if (group3.Success && int.TryParse(group3.Value, out var result)) { num = result; } if (group4.Success && int.TryParse(group4.Value, out var result2)) { num += result2 * 60; } } return (group.Value, num); } } return (null, 0); } public static int CheckDownloadCount(string url, bool includeErrors = false) { if (string.IsNullOrEmpty(url)) { return 0; } int num = 0; if (downloadsReady.ContainsKey(url)) { num += downloadsReady[url].Count; } if (downloadErrors.ContainsKey(url)) { num += downloadErrors[url].Count; } return num; } public void EnqueueDownload(string Url) { downloadJobQueue.Enqueue(Url); } public void DismissDownloadQueue() { downloadJobQueue.Clear(); } public void StartDownloadJob() { if (!isProcessingQueue) { processingCoroutine = ((MonoBehaviour)this).StartCoroutine(ProcessDownloadQueue()); } } public static int GetBitrateKbps(string quality) { if (1 == 0) { } int result = quality switch { "32K" => 32, "64K" => 64, "96K" => 96, "128K" => 128, _ => 192, }; if (1 == 0) { } return result; } public static int GetBitrateKbps(int qualityLevel) { if (1 == 0) { } int result = qualityLevel switch { 0 => 32, 1 => 64, 2 => 96, 3 => 128, _ => 192, }; if (1 == 0) { } return result; } public static double EstimateSizeBytes(int bitrateKbps, double durationSeconds) { return (double)bitrateKbps * 1000.0 / 8.0 * durationSeconds; } public void DownloadQueue(int startIndex) { if (startIndex < 0 || startIndex >= boomboxParent.data.playbackQueue.Count) { startIndex = 0; } for (int i = startIndex; i < boomboxParent.data.playbackQueue.Count; i++) { downloadJobQueue.Enqueue(boomboxParent.data.playbackQueue.ElementAt(i).Url); } for (int j = 0; j < startIndex; j++) { downloadJobQueue.Enqueue(boomboxParent.data.playbackQueue.ElementAt(j).Url); } StartDownloadJob(); } [PunRPC] public void NotifyPlayersOfErrors(string message) { Logger.LogWarning((object)message); boomboxParent.UpdateUIStatus(message); } [PunRPC] public void ReportDownloadError(int actorNumber, string url, string errorMessage) { if (actorNumber == PhotonNetwork.LocalPlayer.ActorNumber) { boomboxParent.UpdateUIStatus("Error: " + errorMessage); } if (PhotonNetwork.IsMasterClient) { if (!downloadErrors.ContainsKey(url)) { downloadErrors[url] = new HashSet<int>(); } if (!downloadErrors[url].Contains(actorNumber)) { downloadErrors[url].Add(actorNumber); Logger.LogError((object)$"Player {actorNumber} reported download error for {url}: {errorMessage}"); } } } [PunRPC] public void SetSongInfo(string url, string title, double duration, int actorNumber) { if (!PhotonNetwork.IsMasterClient || string.IsNullOrWhiteSpace(url) || string.IsNullOrWhiteSpace(title)) { return; } if (PhotonNetwork.IsMasterClient && DownloadHelper.songInfo.ContainsKey(url) && actorNumber != PhotonNetwork.LocalPlayer.ActorNumber) { SongInfo songInfo = DownloadHelper.songInfo[url]; if (!songInfo.IsInvalid()) { return; } } DownloadHelper.songInfo[url] = new SongInfo(title, duration); bool flag = false; if (boomboxParent?.data?.playbackQueue != null) { foreach (Boombox.AudioEntry item in boomboxParent.data.playbackQueue.FindAll((Boombox.AudioEntry entry) => entry.Url == url)) { if (item.Title != title) { item.Title = title; flag = true; } if (item.Duration != duration) { item.Duration = duration; } flag = true; } } if (boomboxParent?.data?.currentSong != null && boomboxParent.data.currentSong.Url == url) { boomboxParent.data.currentSong.Title = title; if (boomboxParent.data.pendingPlaybackStart) { boomboxParent.UpdateUIStatus("Loading: " + title); } else if ((Object)(object)boomboxParent.data.currentSong.GetAudioClip() != (Object)null && boomboxParent.data.isPlaying) { boomboxParent.UpdateUIStatus("Now playing: " + title); } else if ((Object)(object)boomboxParent.data.currentSong.GetAudioClip() != (Object)null) { boomboxParent.UpdateUIStatus("Ready to play: " + title); } else { boomboxParent.UpdateUIStatus("Loading: " + title); } } if (flag) { Boombox boombox = boomboxParent; if (boombox != null) { ((Component)boombox).GetComponent<BoomboxUI>()?.UpdateDataFromBoomBox(); } if (PhotonNetwork.IsMasterClient) { boomboxParent.PublishSharedState(updateTime: false, updateQueue: true); } } } private IEnumerator ProcessDownloadQueue() { isProcessingQueue = true; Logger.LogDebug((object)"Master Client Download Queue Processor started."); while (downloadJobQueue.Count > 0 && isProcessingQueue) { string url = downloadJobQueue.Dequeue(); yield return MasterClientInitiateSync(url); if ((Object)(object)this == (Object)null) { yield break; } } if (!((Object)(object)this == (Object)null)) { isProcessingQueue = false; currentDownloadUrl = null; Logger.LogDebug((object)"Master Client Download Queue Processor finished."); } } private IEnumerator MasterClientInitiateSync(string url) { if (!boomboxParent.data.playbackQueue.Any((Boombox.AudioEntry entry) => entry.Url == url)) { yield break; } string requestId = Guid.NewGuid().ToString(); currentDownloadUrl = url; currentRequestId = requestId; if (downloadsReady.ContainsKey(url)) { if (downloadsReady[url].Count >= Instance.baseListener.GetAllModUsers().Count) { if (boomboxParent.data.pendingPlaybackStart && url == boomboxParent.data.currentSong?.Url) { boomboxParent.FinalizePendingPlaybackStart(boomboxParent.startPlayBackOnDownload); } yield break; } downloadsReady[url].Clear(); } else { downloadsReady[url] = new HashSet<int>(); } if (downloadErrors.ContainsKey(url)) { downloadErrors[url].Clear(); } else { downloadErrors[url] = new HashSet<int>(); } BaseListener.RPC(((MonoBehaviourPun)this).photonView, "StartDownloadAndSync", (RpcTarget)0, url, PhotonNetwork.LocalPlayer.ActorNumber); timeoutCoroutines[requestId] = ((MonoBehaviour)this).StartCoroutine(DownloadTimeoutCoroutine(requestId, url)); yield return WaitForPlayersReadyOrFailed(url); Coroutine coroutine = default(Coroutine); if ((timeoutCoroutines?.TryGetValue(requestId, out coroutine) ?? false) && coroutine != null) { ((MonoBehaviour)this).StopCoroutine(coroutine); timeoutCoroutines.Remove(requestId); } if (!(currentDownloadUrl != url)) { currentDownloadUrl = null; currentRequestId = null; Logger.LogDebug((object)("Consensus finished for " + url + ", Starting Playback.")); Boombox boombox = boomboxParent; if (boombox != null && (boombox.data?.pendingPlaybackStart).GetValueOrDefault() && url == boomboxParent.data.currentSong?.Url) { boomboxParent.FinalizePendingPlaybackStart(boomboxParent.startPlayBackOnDownload); } } } private int SongTimeout(string url) { double num = songInfo[url].duration; if (num < 0.0) { num = 180.0; } double a = boomboxParent.EstimateDownloadTimeSeconds(num, Instance.DownloadSpeed.Value); return (int)Math.Round(a); } private IEnumerator DownloadTimeoutCoroutine(string requestId, string url) { int num; if (songInfo.ContainsKey(url)) { _ = songInfo[url].duration; num = 0; } else { num = 1; } if (num != 0) { yield return (object)new WaitForSeconds(11f); } while (YoutubeDL.isInitializing) { yield return (object)new WaitForSeconds(1f); } int num2; if (songInfo.ContainsKey(url)) { _ = songInfo[url].duration; num2 = 1; } else { num2 = 0; } if (num2 != 0) { int timeout = SongTimeout(url); Logger.LogDebug((object)$"Using download timeout: {timeout}"); yield return (object)new WaitForSeconds((float)timeout); } if (currentRequestId == requestId && isProcessingQueue) { Logger.LogWarning((object)("Download timeout for url: " + url)); Logger.LogInfo((object)"Master client initiating timeout recovery"); isTimeoutRecovery = true; foreach (int player in Instance.baseListener.GetAllModUsers()) { if (!downloadsReady[url].Contains(player)) { if (!downloadErrors.ContainsKey(url)) { downloadErrors[url] = new HashSet<int>(); } downloadErrors[url].Add(player); Logger.LogWarning((object)$"Player {player} timed out during download"); } } if (downloadsReady.ContainsKey(url) && downloadsReady[url].Count > 0) { string timeoutMessage = $"Some players timed out. Continuing playback for {downloadsReady[url].Count} players."; BaseListener.RPC(((MonoBehaviourPun)this).photonView, "NotifyPlayersOfErrors", (RpcTarget)0, timeoutMessage); if (boomboxParent.data.pendingPlaybackStart && boomboxParent.data.currentSong?.Url == url) { boomboxParent.FinalizePendingPlaybackStart(boomboxParent.startPlayBackOnDownload); } } else { BaseListener.RPC(((MonoBehaviourPun)this).photonView, "NotifyPlayersOfErrors", (RpcTarget)0, "Download timed out for all players."); } currentDownloadUrl = null; currentRequestId = null; isTimeoutRecovery = false; } timeoutCoroutines.Remove(requestId); } [PunRPC] public async void StartDownloadAndSync(string url, int requesterId) { if (url == null || requesterId != PhotonNetwork.MasterClient.ActorNumber) { return; } if (currentDownloadUrl != url) { currentDownloadUrl = url; if (!downloadsReady.ContainsKey(url)) { downloadsReady[url] = new HashSet<int>(); } if (!downloadErrors.ContainsKey(url)) { downloadErrors[url] = new HashSet<int>(); } } if (downloadedClips.ContainsKey(url)) { boomboxParent?.HandleDownloadedCurrentSong(); BaseListener.RPC(((MonoBehaviourPun)this).photonView, "ReportDownloadComplete", (RpcTarget)2, url, PhotonNetwork.LocalPlayer.ActorNumber); } else if (await StartAudioDownload(url) && (Object)(object)this != (Object)null) { boomboxParent?.HandleDownloadedCurrentSong(); BaseListener.RPC(((MonoBehaviourPun)this).photonView, "ReportDownloadComplete", (RpcTarget)2, url, PhotonNetwork.LocalPlayer.ActorNumber); } } [PunRPC] public void ReportDownloadComplete(string url, int actorNumber) { if (PhotonNetwork.IsMasterClient && url != null) { if (!downloadsReady.ContainsKey(url)) { downloadsReady[url] = new HashSet<int>(); } if (downloadErrors.ContainsKey(url) && downloadErrors[url].Contains(actorNumber)) { downloadErrors[url].Remove(actorNumber); } if (!downloadsReady[url].Contains(actorNumber)) { downloadsReady[url].Add(actorNumber); } } } private IEnumerator WaitForPlayersReadyOrFailed(string url) { int totalPlayers = Instance.baseListener.GetAllModUsers().Count; int readyCount = 0; int errorCount = 0; float waitTime = 0.1f; float? partialConsensusStartTime = null; while ((Object)(object)this != (Object)null) { readyCount = (downloadsReady.ContainsKey(url) ? downloadsReady[url].Count : 0); errorCount = (downloadErrors.ContainsKey(url) ? downloadErrors[url].Count : 0); bool allAccountedFor = readyCount + errorCount >= totalPlayers; bool partialConsensus = readyCount > 0 && errorCount > 0; bool timeOutReached = false; if (!partialConsensus) { partialConsensusStartTime = null; } else if (!partialConsensusStartTime.HasValue) { partialConsensusStartTime = Time.time; } else { timeOutReached = Time.time - partialConsensusStartTime.Value >= 10f; } if (allAccountedFor || timeOutReached) { break; } yield return (object)new WaitForSeconds(waitTime); } if ((Object)(object)this != (Object)null) { Logger.LogInfo((object)$"Ready to proceed with playback. Ready: {readyCount}, Errors: {errorCount}, Total: {totalPlayers} for url: {url}"); } } public static async Task<AudioClip> GetAudioClipAsync(string filePath, SongInfo info) { await Task.Yield(); if (!File.Exists(filePath)) { throw new Exception("Audio file not found at path: " + filePath); } Uri fileUri = new Uri(filePath); string uri = fileUri.AbsoluteUri; UnityWebRequest www = UnityWebRequestMultimedia.GetAudioClip(uri, (AudioType)13); try { www.timeout = 11; ((DownloadHandlerAudioClip)www.downloadHandler).streamAudio = true; TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>(); UnityWebRequestAsyncOperation operation = www.SendWebRequest(); ((AsyncOperation)operation).completed += delegate { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Invalid comparison between Unknown and I4 if ((int)www.result != 1) { Logger.LogError((object)("Web request failed: " + www.error + ", URI: " + uri)); tcs.SetException(new Exception("Failed to load audio file: " + www.error)); } else { tcs.SetResult(result: true); } }; await tcs.Task; AudioClip clip = DownloadHandlerAudioClip.GetContent(www); if ((Object)(object)clip == (Object)null) { throw new Exception("Failed to get AudioClip content."); } return clip; } finally { if (www != null) { ((IDisposable)www).Dispose(); } } } public async Task<bool> StartAudioDownload(string url) { if (downloadedClips.ContainsKey(url)) { return true; } try { SongInfo info = (songInfo.ContainsKey(url) ? songInfo[url] : null); if (info?.IsInvalid() ?? true) { SongInfo tempInfo = await YoutubeDL.DownloadAudioInfoAsync(url); if (!songInfo.ContainsKey(url) || songInfo[url].IsInvalid()) { songInfo[url] = tempInfo; info = tempInfo; if (!tempInfo.IsInvalid()) { BaseListener.RPC(((MonoBehaviourPun)this).photonView, "SetSongInfo", (RpcTarget)0, url, info.title, info.duration, PhotonNetwork.LocalPlayer.ActorNumber); } } } string filePath = await YoutubeDL.DownloadAudioAsync(url, info); if (boomboxParent?.data?.currentSong?.Url == url) { boomboxParent?.UpdateUIStatus("Processing audio: " + info.title); } AudioClip clip = await GetAudioClipAsync(filePath, info); downloadedClips[url] = clip; Logger.LogDebug((object)("Downloaded and cached clip for video: " + info.title)); if ((Object)(object)clip != (Object)null && info.IsInvalid()) { SongInfo newInfo = await YoutubeDL.DownloadAudioInfoAsync(url); if (!newInfo.IsInvalid() && !songInfo.ContainsKey(url)) { songInfo[url] = newInfo; BaseListener.RPC(((MonoBehaviourPun)this).photonView, "SetSongInfo", (RpcTarget)0, url, newInfo.title, newInfo.duration, PhotonNetwork.LocalPlayer.ActorNumber); } } } catch (Exception ex) {