using System; using System.Collections; using System.Collections.Generic; using System.Collections.Specialized; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Cryptography; using System.Security.Permissions; using System.Text; using System.Threading.Tasks; using System.Web; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using Photon.Pun; using Photon.Realtime; using UnityEngine; using UnityEngine.Networking; using YoutubeDLSharp; using Zorro.Core; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("BingBongBoomBox")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+3a4bb035269eb489b8be6a93caad20fd1910a332")] [assembly: AssemblyProduct("BingBong BoomBox")] [assembly: AssemblyTitle("BingBongBoomBox")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace BepInEx { [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] [Conditional("CodeGeneration")] internal sealed class BepInAutoPluginAttribute : Attribute { public BepInAutoPluginAttribute(string? id = null, string? name = null, string? version = null) { } } } namespace BepInEx.Preloader.Core.Patching { [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] [Conditional("CodeGeneration")] internal sealed class PatcherAutoPluginAttribute : Attribute { public PatcherAutoPluginAttribute(string? id = null, string? name = null, string? version = null) { } } } namespace BingBongBoomBox { [BepInPlugin("xyz.restorerootfs.bingbongboomboxplus", "BingBongBoomBox", "1.2.0")] public class BingBongPlayerPlugin : BaseUnityPlugin { private enum SongLoadingState { Loaded, Loading, Error } [Serializable] private class SongMetadata { public string? title; } [Serializable] private class SongRequest { public string url = ""; public string hash = ""; public string requestedBy = ""; public int requestedByActor = -1; public string title = ""; } [Serializable] private class SongQueueWrapper { public List items = new List(); } [Serializable] private class HostConfigPayload { public bool publicEnqueue; public bool globalAudio; public bool bypassEnv; public bool allowDuplicates; public bool autoAdvance; public float maxHearingDistance; public int maxQueueSize; public int perUserQueueLimit; public string v; } [HarmonyPatch(typeof(Item))] private static class ItemPatches { private static bool IsBingBong(Item it) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) if ((it.itemTags & 0x10) == 0) { ItemUIData uIData = it.UIData; if (uIData == null || !(uIData.itemName?.IndexOf("BingBong", StringComparison.OrdinalIgnoreCase) >= 0)) { string name = ((Object)it).name; if (name == null) { return false; } return name.IndexOf("BingBong", StringComparison.OrdinalIgnoreCase) >= 0; } } return true; } [HarmonyPostfix] [HarmonyPatch("Awake")] private static void Awake_Post(Item __instance) { //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Invalid comparison between Unknown and I4 if (!IsBingBong(__instance)) { return; } bingBong = ((Component)__instance).transform; Transform transform = ((Component)__instance).transform; bingBongMouth = null; Animator[] componentsInChildren = ((Component)transform).GetComponentsInChildren(true); foreach (Animator val in componentsInChildren) { try { AnimatorControllerParameter[] parameters = val.parameters; AnimatorControllerParameter val2 = null; AnimatorControllerParameter[] array = parameters; foreach (AnimatorControllerParameter val3 in array) { if ((int)val3.type == 1 && val3.name.IndexOf("mouth", StringComparison.OrdinalIgnoreCase) >= 0) { val2 = val3; break; } } if (val2 != null) { mouthOpenParam = val2.name; mouthOpenHash = val2.nameHash; bingBongMouth = val; break; } } catch { } } } [HarmonyPrefix] [HarmonyPatch("OnDestroy")] private static void OnDestroy_Pre(Item __instance) { if ((Object)(object)bingBong == (Object)(object)((Component)__instance).transform) { mouthOpenParam = null; mouthOpenHash = 0; bingBongMouth = null; bingBong = null; } } } private static ManualLogSource? logger; private static AudioSource? audioSource; private static PhotonView? photonView; private string? ytDlpPath; private string? ffmpegPath; private string? denoPath; private string urlInput = ""; private Coroutine? currentPlaybackCoroutine; private Coroutine? debouncePlayCoroutine; private Coroutine? downloadCoroutine; private const ushort BingBongItemID = 13; private static string? mouthOpenParam; private static int mouthOpenHash = 0; public static Transform? bingBong = null; public static Animator? bingBongMouth = null; private ConfigEntry? volumeSetting; private ConfigEntry? maxAudioSizeMbCfg; private ConfigEntry? maxTempFilesCfg; private ConfigEntry? maxQueueSizeCfg; private ConfigEntry? perUserQueueLimitCfg; private ConfigEntry? allowDuplicatesCfg; private ConfigEntry? autoAdvanceCfg; private ConfigEntry? titleProbeTimeoutSecCfg; private ConfigEntry? playlistProbeTimeoutSecCfg; private ConfigEntry? globalAudioCfg; private ConfigEntry? bypassEnvCfg; private ConfigEntry? publicEnqueueCfg; private ConfigEntry? maxHearingDistanceCfg; private ConfigEntry? uiScaleCfg; private ConfigEntry? showAdvancedCfg; private bool hostPublicEnqueue; private bool hostGlobalAudio; private bool hostBypassEnv; private bool hostAllowDuplicates; private bool hostAutoAdvance = true; private float hostMaxHearingDistance = 35f; private int hostMaxQueueSize = 20; private int hostPerUserQueueLimit = 5; private float syncInterval = 5f; private float lastSyncTime; private float lastConfigBroadcast = -999f; private bool sentInitialConfig; public float vocalLow = 300f; public float vocalHigh = 3400f; public int sampleSize = 256; public float currentVolume = 0.45f; public FFTWindow fftWindow = (FFTWindow)5; private bool lastConnectedState; private float[]? spectrumData; private string? tempAudioDir; private string currentSongTitle = ""; private string currentSongHash = ""; private string lastUsedPlayer = ""; private string userId = Guid.NewGuid().ToString(); private bool manualStop; private SongLoadingState songLoadingState; public static readonly string[] LoadingProgress = new string[4] { "Loading.", "Loading..", "Loading...", "Loading" }; private bool hostHasMod = PhotonNetwork.IsMasterClient; private readonly List queue = new List(); private Vector2 queueScroll = Vector2.zero; private Vector2 panelScroll = Vector2.zero; private readonly HashSet titleFetchInProgress = new HashSet(StringComparer.OrdinalIgnoreCase); private float spectrumTimer; private float spectrumInterval = 0.012f; private GUIStyle? boxStyle; private GUIStyle? labelStyle; private GUIStyle? buttonStyle; private GUIStyle? sliderStyle; private GUIStyle? sliderThumbStyle; private GUIStyle? headerStyle; private GUIStyle? smallLabelStyle; private GUIStyle? toggleStyle; private GUIStyle? foldoutStyle; private Texture2D? boxBgTex; private Texture2D? sliderBgTex; private Texture2D? sliderThumbTex; private Texture2D? buttonNormalBgTex; private Texture2D? buttonHoverBgTex; private bool initializedStyles; private float appliedUiScale = -1f; private static readonly string[] AllowedHosts = new string[20] { "youtube.com", "www.youtube.com", "m.youtube.com", "music.youtube.com", "www.music.youtube.com", "youtu.be", "www.youtu.be", "soundcloud.com", "www.soundcloud.com", "vimeo.com", "www.vimeo.com", "bandcamp.com", "www.bandcamp.com", "twitch.tv", "www.twitch.tv", "clips.twitch.tv", "tiktok.com", "www.tiktok.com", "mixcloud.com", "www.mixcloud.com" }; private int MaxAudioSizeMb => Mathf.Max(1, maxAudioSizeMbCfg?.Value ?? 100); private int MaxTempFiles => Mathf.Max(1, maxTempFilesCfg?.Value ?? 5); private int MaxQueueSize => Mathf.Max(1, (!ActAsHost()) ? ((hostMaxQueueSize > 0) ? hostMaxQueueSize : 20) : (maxQueueSizeCfg?.Value ?? 20)); private int PerUserQueueLimit => Mathf.Max(1, (!ActAsHost()) ? ((hostPerUserQueueLimit > 0) ? hostPerUserQueueLimit : 5) : (perUserQueueLimitCfg?.Value ?? 5)); private bool AllowDuplicates { get { if (!ActAsHost()) { return hostAllowDuplicates; } return allowDuplicatesCfg?.Value ?? false; } } private bool AutoAdvance { get { if (!ActAsHost()) { return hostAutoAdvance; } return autoAdvanceCfg?.Value ?? true; } } private int TitleProbeTimeoutSec => Mathf.Max(5, titleProbeTimeoutSecCfg?.Value ?? 20); private int PlaylistProbeTimeoutSec => Mathf.Max(5, playlistProbeTimeoutSecCfg?.Value ?? 30); private bool GlobalAudio { get { if (!ActAsHost()) { return hostGlobalAudio; } return globalAudioCfg?.Value ?? false; } } private bool BypassEnv { get { if (!ActAsHost()) { return hostBypassEnv; } return bypassEnvCfg?.Value ?? false; } } private bool PublicEnqueue { get { if (!ActAsHost()) { return hostPublicEnqueue; } return publicEnqueueCfg?.Value ?? false; } } private float MaxHearingDistance => Mathf.Clamp((!ActAsHost()) ? ((hostMaxHearingDistance <= 0f) ? 35f : hostMaxHearingDistance) : (maxHearingDistanceCfg?.Value ?? 35f), 5f, 10000f); private float UiScale => Mathf.Clamp(uiScaleCfg?.Value ?? 1f, 0.75f, 2f); private bool ShowAdvanced => showAdvancedCfg?.Value ?? false; private bool ActAsHost() { if (!PhotonNetwork.IsMasterClient) { if (!hostHasMod) { return lastUsedPlayer == userId; } return false; } return true; } private int LocalActor() { if (PhotonNetwork.LocalPlayer == null) { return -1; } return PhotonNetwork.LocalPlayer.ActorNumber; } private int GetCurrentHolderActorNumber() { try { foreach (Player allPlayer in PlayerHandler.GetAllPlayers()) { if ((Object)(object)allPlayer == (Object)null || (Object)(object)allPlayer.character == (Object)null || !allPlayer.HasInAnySlot((ushort)13)) { continue; } int num = -1; try { Character character = allPlayer.character; int? obj; if (character == null) { obj = null; } else { PhotonView obj2 = ((MonoBehaviourPun)character).photonView; obj = ((obj2 != null) ? new int?(obj2.OwnerActorNr) : ((int?)null)); } num = obj ?? (-1); } catch { } if (num <= 0) { try { PhotonView obj4 = ((MonoBehaviourPun)allPlayer).photonView; num = ((obj4 != null) ? obj4.OwnerActorNr : (-1)); } catch { } } if (num > 0) { return num; } } } catch (Exception ex) { ManualLogSource? obj6 = logger; if (obj6 != null) { obj6.LogWarning((object)("GetCurrentHolderActorNumber failed: " + ex.Message)); } } return -1; } private bool IsRequestorHolder(int requestorActorNumber) { int currentHolderActorNumber = GetCurrentHolderActorNumber(); if (currentHolderActorNumber > 0) { return requestorActorNumber == currentHolderActorNumber; } return false; } private void Awake() { //IL_0437: Unknown result type (might be due to invalid IL or missing references) logger = ((BaseUnityPlugin)this).Logger; photonView = ((Component)this).gameObject.AddComponent(); photonView.ViewID = 215151321; spectrumData = new float[sampleSize]; string pluginDir = Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location) ?? Paths.PluginPath; ytDlpPath = Path.Combine(pluginDir, "yt-dlp.exe"); ffmpegPath = Path.Combine(pluginDir, "ffmpeg.exe"); denoPath = Path.Combine(pluginDir, "deno.exe"); tempAudioDir = Path.Combine(Path.GetTempPath(), "BingBongAudio"); Directory.CreateDirectory(tempAudioDir); CleanupOldTempFiles(); if (!File.Exists(ytDlpPath)) { ManualLogSource? obj = logger; if (obj != null) { obj.LogWarning((object)"yt-dlp was not found! Fetching..."); } Task.Run(async delegate { await Utils.DownloadYtDlp(pluginDir); }).GetAwaiter().GetResult(); } if (!File.Exists(ffmpegPath)) { ManualLogSource? obj2 = logger; if (obj2 != null) { obj2.LogWarning((object)"ffmpeg was not found! Fetching..."); } Task.Run(async delegate { await Utils.DownloadFFmpeg(pluginDir); }).GetAwaiter().GetResult(); } if (!File.Exists(denoPath)) { ManualLogSource? obj3 = logger; if (obj3 != null) { obj3.LogWarning((object)"Deno was not found! Fetching..."); } Task.Run(async delegate { await Utils.DownloadDeno(pluginDir); }).GetAwaiter().GetResult(); } volumeSetting = ((BaseUnityPlugin)this).Config.Bind("Audio", "Volume", 0.45f, "Default playback volume (0.0 to 1.0)"); currentVolume = Mathf.Clamp01(volumeSetting.Value); maxAudioSizeMbCfg = ((BaseUnityPlugin)this).Config.Bind("Limits", "MaxAudioSizeMB", 100, "Max file size yt-dlp may download."); maxTempFilesCfg = ((BaseUnityPlugin)this).Config.Bind("Limits", "MaxTempFiles", 5, "How many cached WAVs to keep."); maxQueueSizeCfg = ((BaseUnityPlugin)this).Config.Bind("Limits", "MaxQueueSize", 20, "Max items allowed in queue. (Host only)"); perUserQueueLimitCfg = ((BaseUnityPlugin)this).Config.Bind("Limits", "PerUserQueueLimit", 5, "Max items one user can have pending in the queue. (Host only)"); allowDuplicatesCfg = ((BaseUnityPlugin)this).Config.Bind("Queue", "AllowDuplicates", false, "Allow the same URL to be enqueued multiple times. (Host only)"); autoAdvanceCfg = ((BaseUnityPlugin)this).Config.Bind("Queue", "AutoAdvance", true, "Automatically advance to next track when one finishes. (Host only)"); titleProbeTimeoutSecCfg = ((BaseUnityPlugin)this).Config.Bind("Advanced", "TitleProbeTimeoutSec", 20, "Timeout for title probes (seconds)."); playlistProbeTimeoutSecCfg = ((BaseUnityPlugin)this).Config.Bind("Advanced", "PlaylistProbeTimeoutSec", 30, "Timeout for playlist expansion (seconds)."); globalAudioCfg = ((BaseUnityPlugin)this).Config.Bind("Audio", "GlobalAudio", false, "2D audio heard anywhere. (Host only)"); bypassEnvCfg = ((BaseUnityPlugin)this).Config.Bind("Audio", "BypassEnvironmentEffects", false, "Bypass reverb/occlusion. (Host only)"); maxHearingDistanceCfg = ((BaseUnityPlugin)this).Config.Bind("Audio", "MaxHearingDistance", 35f, "3D audio max distance. (Host only)"); publicEnqueueCfg = ((BaseUnityPlugin)this).Config.Bind("Queue", "PublicEnqueue", false, "Non-holders may add and control playback. (Host only)"); uiScaleCfg = ((BaseUnityPlugin)this).Config.Bind("UI", "UiScale", 1f, "Scale UI text/vertical only (client)"); showAdvancedCfg = ((BaseUnityPlugin)this).Config.Bind("UI", "ShowAdvanced", false, "Show Advanced section (client)"); audioSource = ((Component)this).gameObject.AddComponent(); audioSource.spatialBlend = 1f; audioSource.volume = currentVolume; audioSource.loop = false; audioSource.rolloffMode = (AudioRolloffMode)1; audioSource.minDistance = 1f; audioSource.maxDistance = MaxHearingDistance; audioSource.bypassEffects = BypassEnv; audioSource.bypassListenerEffects = BypassEnv; audioSource.bypassReverbZones = BypassEnv; new Harmony("xyz.restorerootfs.bingbongboomboxplus").PatchAll(); } private void OnDestroy() { if (currentPlaybackCoroutine != null) { ((MonoBehaviour)this).StopCoroutine(currentPlaybackCoroutine); } if (debouncePlayCoroutine != null) { ((MonoBehaviour)this).StopCoroutine(debouncePlayCoroutine); } if (downloadCoroutine != null) { ((MonoBehaviour)this).StopCoroutine(downloadCoroutine); } } private void LateUpdate() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Invalid comparison between Unknown and I4 //IL_016a: Unknown result type (might be due to invalid IL or missing references) //IL_019f: Unknown result type (might be due to invalid IL or missing references) //IL_0231: Unknown result type (might be due to invalid IL or missing references) //IL_0354: Unknown result type (might be due to invalid IL or missing references) bool flag = (int)PhotonNetwork.Server == 1; if (lastConnectedState && !flag) { StopAndResetSong(); queue.Clear(); sentInitialConfig = false; } lastConnectedState = flag; if ((Object)(object)audioSource == (Object)null || !PhotonNetwork.IsConnectedAndReady || (Object)(object)photonView == (Object)null) { return; } if (ActAsHost()) { if (!sentInitialConfig) { BroadcastHostConfig(); sentInitialConfig = true; } if (Time.time - lastConfigBroadcast > 15f) { BroadcastHostConfig(); } } if (ActAsHost() && Time.time - lastSyncTime > syncInterval) { photonView.RPC("RPC_SyncPlaying", (RpcTarget)1, new object[4] { currentSongHash, audioSource.isPlaying, PhotonNetwork.IsMasterClient, currentSongTitle }); if (audioSource.isPlaying) { photonView.RPC("RPC_SyncTime", (RpcTarget)1, new object[2] { currentSongHash, audioSource.time }); } lastSyncTime = Time.time; } bool flag2 = Singleton.Instance?.isPlayingCinematic ?? false; Vector3? val = null; if ((Object)(object)bingBong != (Object)null) { val = bingBong.position; } else { Player? obj = FindPlayerWithBingBong(); Vector3? obj2; if (obj == null) { obj2 = null; } else { Character character = obj.character; obj2 = ((character != null) ? new Vector3?(character.Center) : ((Vector3?)null)); } val = obj2; } if (GlobalAudio) { audioSource.spatialBlend = 0f; audioSource.volume = currentVolume; } else { audioSource.spatialBlend = (flag2 ? 0f : 1f); audioSource.maxDistance = MaxHearingDistance; audioSource.volume = (val.HasValue ? currentVolume : 0f); if (val.HasValue) { ((Component)audioSource).transform.position = val.Value; } } audioSource.bypassEffects = BypassEnv; audioSource.bypassListenerEffects = BypassEnv; audioSource.bypassReverbZones = BypassEnv; if (ActAsHost() && AutoAdvance && !manualStop && (Object)(object)audioSource.clip != (Object)null && !audioSource.isPlaying && !string.IsNullOrEmpty(currentSongHash) && songLoadingState == SongLoadingState.Loaded) { PlayNextImpl(); } if (!((Object)(object)audioSource != (Object)null) || !((Object)(object)bingBongMouth != (Object)null) || mouthOpenParam == null) { return; } spectrumTimer += Time.deltaTime; if (!(spectrumTimer >= spectrumInterval)) { return; } spectrumTimer = 0f; float num = 0f; if (audioSource.isPlaying && spectrumData != null && (Object)(object)audioSource.clip != (Object)null) { audioSource.GetSpectrumData(spectrumData, 0, fftWindow); float num2 = (float)AudioSettings.outputSampleRate / 2f / (float)sampleSize; int num3 = Mathf.FloorToInt(vocalLow / num2); int num4 = Mathf.CeilToInt(vocalHigh / num2); int num5 = Mathf.Clamp(num3, 0, sampleSize - 1); num4 = Mathf.Clamp(num4, 0, sampleSize - 1); float num6 = 0f; int num7 = 0; for (int i = num5; i <= num4; i++) { num6 += spectrumData[i]; num7++; } num = Mathf.Clamp01(((num7 > 0) ? (num6 / (float)num7) : 0f) * 50f); } try { bingBongMouth.SetFloat(mouthOpenHash, num); } catch { } } private void BroadcastHostConfig() { lastConfigBroadcast = Time.time; HostConfigPayload hostConfigPayload = new HostConfigPayload { publicEnqueue = PublicEnqueue, globalAudio = GlobalAudio, bypassEnv = BypassEnv, allowDuplicates = AllowDuplicates, autoAdvance = AutoAdvance, maxHearingDistance = MaxHearingDistance, maxQueueSize = MaxQueueSize, perUserQueueLimit = PerUserQueueLimit, v = "1.2.0" }; PhotonView? obj = photonView; if (obj != null) { obj.RPC("RPC_ConfigSync", (RpcTarget)1, new object[1] { JsonUtility.ToJson((object)hostConfigPayload) }); } } [PunRPC] private void RPC_ConfigSync(string json) { try { HostConfigPayload hostConfigPayload = JsonUtility.FromJson(json); if (hostConfigPayload != null) { hostPublicEnqueue = hostConfigPayload.publicEnqueue; hostGlobalAudio = hostConfigPayload.globalAudio; hostBypassEnv = hostConfigPayload.bypassEnv; hostAllowDuplicates = hostConfigPayload.allowDuplicates; hostAutoAdvance = hostConfigPayload.autoAdvance; hostMaxHearingDistance = hostConfigPayload.maxHearingDistance; hostMaxQueueSize = hostConfigPayload.maxQueueSize; hostPerUserQueueLimit = hostConfigPayload.perUserQueueLimit; } } catch { } } private Player? FindPlayerWithBingBong() { foreach (Player allPlayer in PlayerHandler.GetAllPlayers()) { if ((Object)(object)allPlayer.character != (Object)null && allPlayer.HasInAnySlot((ushort)13)) { return allPlayer; } } return null; } private Texture2D MakeSolidColorTex(Color col) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Expected O, but got Unknown Texture2D val = new Texture2D(1, 1); val.SetPixel(0, 0, col); val.Apply(); return val; } private void InitStyles() { //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Expected O, but got Unknown //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Expected O, but got Unknown //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Expected O, but got Unknown //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Expected O, but got Unknown //IL_0141: Unknown result type (might be due to invalid IL or missing references) //IL_0146: 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_0163: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Unknown result type (might be due to invalid IL or missing references) //IL_0179: Expected O, but got Unknown //IL_0184: Unknown result type (might be due to invalid IL or missing references) //IL_0189: Unknown result type (might be due to invalid IL or missing references) //IL_01a0: Unknown result type (might be due to invalid IL or missing references) //IL_01a6: Unknown result type (might be due to invalid IL or missing references) //IL_01b0: Unknown result type (might be due to invalid IL or missing references) //IL_01bc: Expected O, but got Unknown //IL_01c7: Unknown result type (might be due to invalid IL or missing references) //IL_01cc: Unknown result type (might be due to invalid IL or missing references) //IL_01e8: Expected O, but got Unknown //IL_01f3: Unknown result type (might be due to invalid IL or missing references) //IL_01f8: Unknown result type (might be due to invalid IL or missing references) //IL_020f: Unknown result type (might be due to invalid IL or missing references) //IL_0216: Unknown result type (might be due to invalid IL or missing references) //IL_023b: Unknown result type (might be due to invalid IL or missing references) //IL_0245: Expected O, but got Unknown //IL_024a: Expected O, but got Unknown //IL_0260: Unknown result type (might be due to invalid IL or missing references) //IL_0285: Unknown result type (might be due to invalid IL or missing references) //IL_029f: Unknown result type (might be due to invalid IL or missing references) //IL_02a4: Unknown result type (might be due to invalid IL or missing references) //IL_02bb: Unknown result type (might be due to invalid IL or missing references) //IL_02c0: Unknown result type (might be due to invalid IL or missing references) //IL_02ca: Expected O, but got Unknown //IL_02ca: Unknown result type (might be due to invalid IL or missing references) //IL_02ef: Unknown result type (might be due to invalid IL or missing references) //IL_02f9: Expected O, but got Unknown //IL_02f9: Unknown result type (might be due to invalid IL or missing references) //IL_030a: Unknown result type (might be due to invalid IL or missing references) //IL_0320: Expected O, but got Unknown //IL_0336: Unknown result type (might be due to invalid IL or missing references) //IL_035b: Unknown result type (might be due to invalid IL or missing references) //IL_0375: Unknown result type (might be due to invalid IL or missing references) //IL_037a: Unknown result type (might be due to invalid IL or missing references) //IL_038b: Unknown result type (might be due to invalid IL or missing references) //IL_03a8: Expected O, but got Unknown //IL_03b3: Unknown result type (might be due to invalid IL or missing references) //IL_03b8: Unknown result type (might be due to invalid IL or missing references) //IL_03c9: Unknown result type (might be due to invalid IL or missing references) //IL_03e1: Unknown result type (might be due to invalid IL or missing references) //IL_03fe: Expected O, but got Unknown if (initializedStyles && Mathf.Abs(appliedUiScale - UiScale) < 0.001f) { return; } appliedUiScale = UiScale; Font val = null; Font[] array = Resources.FindObjectsOfTypeAll(); foreach (Font val2 in array) { if (((Object)val2).name == "DarumaDropOne-Regular") { val = val2; break; } } if (!((Object)(object)val == (Object)null) || PhotonNetwork.IsConnectedAndReady) { boxBgTex = MakeSolidColorTex(new Color(0f, 0f, 0f, 0.8f)); int num = Mathf.RoundToInt(12f * UiScale); GUIStyle val3 = new GUIStyle(GUI.skin.box) { padding = new RectOffset(12, 12, num, num), margin = new RectOffset(10, 10, 10, 10) }; val3.normal.background = boxBgTex; boxStyle = val3; GUIStyle val4 = new GUIStyle(GUI.skin.label) { fontSize = Mathf.RoundToInt(14f * UiScale) }; val4.normal.textColor = Color.white; val4.richText = true; labelStyle = val4; GUIStyle val5 = new GUIStyle(GUI.skin.label) { fontSize = Mathf.RoundToInt(12f * UiScale) }; val5.normal.textColor = Color.white; val5.richText = true; smallLabelStyle = val5; GUIStyle val6 = new GUIStyle(GUI.skin.label) { fontSize = Mathf.RoundToInt(22f * UiScale) }; val6.normal.textColor = Color.white; val6.richText = true; headerStyle = val6; toggleStyle = new GUIStyle(GUI.skin.toggle) { fontSize = Mathf.RoundToInt(13f * UiScale) }; foldoutStyle = new GUIStyle(GUI.skin.button) { fontSize = Mathf.RoundToInt(13f * UiScale), alignment = (TextAnchor)3, padding = new RectOffset(8, 8, Mathf.RoundToInt(6f * UiScale), Mathf.RoundToInt(6f * UiScale)) }; buttonNormalBgTex = MakeSolidColorTex(new Color(0.2f, 0.2f, 0.2f, 0.95f)); buttonHoverBgTex = MakeSolidColorTex(new Color(0.3f, 0.3f, 0.3f, 0.95f)); GUIStyle val7 = new GUIStyle(GUI.skin.button) { fontSize = Mathf.RoundToInt(13f * UiScale), margin = new RectOffset(5, 5, 5, 5), padding = new RectOffset(8, 8, Mathf.RoundToInt(6f * UiScale), Mathf.RoundToInt(6f * UiScale)) }; val7.normal.background = buttonNormalBgTex; val7.hover.background = buttonHoverBgTex; buttonStyle = val7; sliderBgTex = MakeSolidColorTex(new Color(0.15f, 0.15f, 0.15f, 1f)); sliderThumbTex = MakeSolidColorTex(new Color(1f, 0.6f, 0f, 1f)); GUIStyle val8 = new GUIStyle(GUI.skin.horizontalSlider); val8.normal.background = sliderBgTex; val8.fixedHeight = Mathf.RoundToInt(12f * UiScale); sliderStyle = val8; GUIStyle val9 = new GUIStyle(GUI.skin.horizontalSliderThumb); val9.normal.background = sliderThumbTex; val9.fixedWidth = Mathf.RoundToInt(16f * UiScale); val9.fixedHeight = Mathf.RoundToInt(16f * UiScale); sliderThumbStyle = val9; if ((Object)(object)val != (Object)null) { labelStyle.font = val; smallLabelStyle.font = val; headerStyle.font = val; buttonStyle.font = val; toggleStyle.font = val; foldoutStyle.font = val; } initializedStyles = true; } } private void OnGUI() { //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0c78: Unknown result type (might be due to invalid IL or missing references) //IL_0c9c: Unknown result type (might be due to invalid IL or missing references) //IL_0ca1: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)Player.localPlayer == (Object)null || (Object)(object)photonView == (Object)null) { return; } InitStyles(); if (!initializedStyles) { return; } if (!GUIManager.InPauseMenu) { if (Player.localPlayer.HasInAnySlot((ushort)13)) { GUILayout.BeginArea(new Rect(10f, 10f, 480f, (float)Mathf.RoundToInt(100f * UiScale))); GUILayout.Label("Press [ESC] to access Music Player", labelStyle, Array.Empty()); GUILayout.EndArea(); } return; } float num = 10f; float num2 = Mathf.Min(720f, (float)Screen.width - 2f * num); float num3 = (float)Screen.height - 2f * num; GUILayout.BeginArea(new Rect(num, num, num2, num3), boxStyle); panelScroll = GUILayout.BeginScrollView(panelScroll, (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.Width(num2 - 8f), GUILayout.Height(num3 - 8f) }); GUILayout.Label("【BingBong Player】", headerStyle, Array.Empty()); GUILayout.Label(ActAsHost() ? "※ You are the acting host." : "※ Waiting for host…", smallLabelStyle, Array.Empty()); bool flag = Player.localPlayer.HasInAnySlot((ushort)13); if (flag || PublicEnqueue) { GUILayout.Space(4f * UiScale); GUILayout.Label("URL:", labelStyle, Array.Empty()); GUILayout.BeginHorizontal(Array.Empty()); urlInput = GUILayout.TextField(urlInput, (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.Width(num2 - 180f), GUILayout.Height(26f * UiScale) }); if (GUILayout.Button("Clear", buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.Width(70f), GUILayout.Height(26f * UiScale) })) { urlInput = ""; } if (GUILayout.Button("Add »", buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.Width(70f), GUILayout.Height(26f * UiScale) })) { RequestEnqueue(urlInput); } GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(Array.Empty()); GUI.enabled = flag || PublicEnqueue; if (GUILayout.Button("Stop", buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(26f * UiScale) })) { photonView.RPC("RPC_RequestStop", (RpcTarget)0, Array.Empty()); } if (GUILayout.Button("〈〈 10s", buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(26f * UiScale) })) { photonView.RPC("RPC_RequestSeek", (RpcTarget)0, new object[1] { -10f }); } if (GUILayout.Button("10s 〉〉", buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(26f * UiScale) })) { photonView.RPC("RPC_RequestSeek", (RpcTarget)0, new object[1] { 10f }); } if (GUILayout.Button("Next »", buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(26f * UiScale) })) { photonView.RPC("RPC_RequestNext", (RpcTarget)0, Array.Empty()); } GUI.enabled = true; if (!flag && PublicEnqueue) { GUILayout.Label("※ Public enqueue is enabled.", smallLabelStyle, Array.Empty()); } GUILayout.EndHorizontal(); } GUILayout.Space(8f * UiScale); GUILayout.Box("", (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.ExpandWidth(true), GUILayout.Height(1f) }); GUILayout.Space(8f * UiScale); GUILayout.Label($"Local Volume: {Mathf.RoundToInt(currentVolume * 100f)}%", labelStyle, Array.Empty()); float num4 = GUILayout.HorizontalSlider(currentVolume, 0f, 1f, sliderStyle, sliderThumbStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(num2 - 40f) }); if (Mathf.Abs(num4 - currentVolume) > 0.001f) { currentVolume = num4; if (volumeSetting != null) { volumeSetting.Value = num4; } if ((Object)(object)audioSource != (Object)null) { audioSource.volume = currentVolume; } } GUILayout.Space(8f * UiScale); GUILayout.Box("", (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.ExpandWidth(true), GUILayout.Height(1f) }); GUILayout.Space(8f * UiScale); bool flag2 = ShowAdvanced; if (GUILayout.Button(flag2 ? "▼ Advanced" : "► Advanced", foldoutStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(26f * UiScale) })) { flag2 = !flag2; if (showAdvancedCfg != null) { showAdvancedCfg.Value = flag2; } } if (flag2) { GUI.enabled = ActAsHost(); bool flag3 = GUILayout.Toggle(GlobalAudio, " Global Audio (2D / Hear Anywhere)", toggleStyle, Array.Empty()); bool flag4 = GUILayout.Toggle(BypassEnv, " Bypass Environment Effects", toggleStyle, Array.Empty()); bool flag5 = GUILayout.Toggle(PublicEnqueue, " Allow Public Enqueue (add/controls)", toggleStyle, Array.Empty()); if (flag3 != GlobalAudio) { globalAudioCfg.Value = flag3; BroadcastHostConfig(); } if (flag4 != BypassEnv) { bypassEnvCfg.Value = flag4; BroadcastHostConfig(); } if (flag5 != PublicEnqueue) { publicEnqueueCfg.Value = flag5; BroadcastHostConfig(); } if (!GlobalAudio) { GUILayout.Label($"Max Hearing Distance: {Mathf.RoundToInt(MaxHearingDistance)}m", labelStyle, Array.Empty()); float num5 = GUILayout.HorizontalSlider(MaxHearingDistance, 5f, 300f, sliderStyle, sliderThumbStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(num2 - 40f) }); if (Mathf.Abs(num5 - MaxHearingDistance) > 0.001f) { maxHearingDistanceCfg.Value = num5; BroadcastHostConfig(); } } GUILayout.Label($"Max Queue Size: {MaxQueueSize}", smallLabelStyle, Array.Empty()); int num6 = Mathf.RoundToInt(GUILayout.HorizontalSlider((float)MaxQueueSize, 5f, 50f, sliderStyle, sliderThumbStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(num2 - 40f) })); if (num6 != MaxQueueSize) { maxQueueSizeCfg.Value = num6; BroadcastHostConfig(); } GUILayout.Label($"Per-User Queue Limit: {PerUserQueueLimit}", smallLabelStyle, Array.Empty()); int num7 = Mathf.RoundToInt(GUILayout.HorizontalSlider((float)PerUserQueueLimit, 1f, 15f, sliderStyle, sliderThumbStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(num2 - 40f) })); if (num7 != PerUserQueueLimit) { perUserQueueLimitCfg.Value = num7; BroadcastHostConfig(); } bool flag6 = GUILayout.Toggle(AllowDuplicates, " Allow Duplicate URLs", toggleStyle, Array.Empty()); if (flag6 != AllowDuplicates) { allowDuplicatesCfg.Value = flag6; BroadcastHostConfig(); } bool flag7 = GUILayout.Toggle(AutoAdvance, " Auto-Advance", toggleStyle, Array.Empty()); if (flag7 != AutoAdvance) { autoAdvanceCfg.Value = flag7; BroadcastHostConfig(); } GUI.enabled = true; GUILayout.Label($"UI Scale: {UiScale:0.00}x", smallLabelStyle, Array.Empty()); float num8 = GUILayout.HorizontalSlider(UiScale, 0.75f, 2f, sliderStyle, sliderThumbStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(num2 - 40f) }); if (Mathf.Abs(num8 - UiScale) > 0.001f) { uiScaleCfg.Value = num8; } } if (songLoadingState == SongLoadingState.Loading) { GUILayout.Space(8f * UiScale); GUILayout.Box("", (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.ExpandWidth(true), GUILayout.Height(1f) }); GUILayout.Space(8f * UiScale); int num9 = Mathf.FloorToInt(Time.time) % LoadingProgress.Length; GUILayout.Label(LoadingProgress[num9], labelStyle, Array.Empty()); } else if (songLoadingState == SongLoadingState.Error) { GUILayout.Space(8f * UiScale); GUILayout.Box("", (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.ExpandWidth(true), GUILayout.Height(1f) }); GUILayout.Space(8f * UiScale); GUILayout.Label("ERROR! Couldn't load audio.", labelStyle, Array.Empty()); } else if (!string.IsNullOrEmpty(currentSongTitle)) { AudioSource? obj = audioSource; if ((Object)(object)((obj != null) ? obj.clip : null) != (Object)null && (audioSource.isPlaying || audioSource.time > 0f)) { GUILayout.Space(8f * UiScale); GUILayout.Box("", (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.ExpandWidth(true), GUILayout.Height(1f) }); GUILayout.Space(8f * UiScale); GUILayout.Label("Now Playing: 「" + currentSongTitle + "」", labelStyle, Array.Empty()); int num10 = Mathf.FloorToInt(audioSource.time / 60f); int num11 = Mathf.FloorToInt(audioSource.time % 60f); int num12 = Mathf.FloorToInt(audioSource.clip.length / 60f); int num13 = Mathf.FloorToInt(audioSource.clip.length % 60f); GUILayout.Label($"{num10:D2}:{num11:D2} / {num12:D2}:{num13:D2}", labelStyle, Array.Empty()); } } GUILayout.Space(8f * UiScale); GUILayout.Box("", (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.ExpandWidth(true), GUILayout.Height(1f) }); GUILayout.Space(8f * UiScale); GUILayout.BeginHorizontal(Array.Empty()); GUILayout.Label($"【Queue】 ({queue.Count}/{MaxQueueSize})", labelStyle, Array.Empty()); GUILayout.FlexibleSpace(); if (flag || PublicEnqueue) { if (GUILayout.Button("〜 Shuffle", buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(24f * UiScale) })) { photonView.RPC("RPC_RequestShuffle", (RpcTarget)0, Array.Empty()); } if (GUILayout.Button("[ ] Clear", buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(24f * UiScale) })) { photonView.RPC("RPC_RequestClearQueue", (RpcTarget)0, Array.Empty()); } } GUILayout.EndHorizontal(); float num14 = 140f * UiScale; float num15 = Mathf.Clamp((float)Screen.height * 0.65f, 160f, (float)Screen.height - 260f); float num16 = 22f * UiScale; float num17 = Mathf.Clamp((float)queue.Count * num16 + 8f, num14, num15); queueScroll = GUILayout.BeginScrollView(queueScroll, (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.Height(num17), GUILayout.Width(num2 - 20f) }); for (int i = 0; i < queue.Count; i++) { SongRequest songRequest = queue[i]; string arg = (string.IsNullOrEmpty(songRequest.title) ? "Fetching title…" : songRequest.title); GUILayout.BeginHorizontal(Array.Empty()); GUILayout.Label($"{i + 1}. • {arg} ({ShortId(songRequest.requestedBy)})", smallLabelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(num2 - 180f) }); GUI.enabled = flag || PublicEnqueue || songRequest.requestedByActor == LocalActor(); if (GUILayout.Button("Remove", buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(90f) })) { photonView.RPC("RPC_RequestRemoveAt", (RpcTarget)0, new object[1] { i }); } GUI.enabled = true; GUILayout.EndHorizontal(); } GUILayout.EndScrollView(); GUILayout.EndScrollView(); GUILayout.EndArea(); } private string ShortId(string id) { if (!string.IsNullOrEmpty(id)) { if (id.Length > 6) { return id.Substring(0, 6); } return id; } return "??"; } private void RequestEnqueue(string url) { if (!string.IsNullOrWhiteSpace(url) && IsSupportedMediaUrl(url)) { if (debouncePlayCoroutine != null) { ((MonoBehaviour)this).StopCoroutine(debouncePlayCoroutine); debouncePlayCoroutine = null; } debouncePlayCoroutine = ((MonoBehaviour)this).StartCoroutine(DebounceRequestCoroutine(0.4f, url)); } } private IEnumerator DebounceRequestCoroutine(float delay, string url) { yield return (object)new WaitForSecondsRealtime(delay); PhotonView? obj = photonView; if (obj != null) { obj.RPC("RPC_RequestEnqueue", (RpcTarget)0, new object[2] { url, userId }); } } [PunRPC] private void RPC_RequestEnqueue(string url, string requestorId, PhotonMessageInfo info) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) if (!IsSupportedMediaUrl(url) || !ActAsHost()) { return; } int requestorActor = ((info.Sender != null) ? info.Sender.ActorNumber : (-1)); if (IsYouTubePlaylistUrl(url)) { ((MonoBehaviour)this).StartCoroutine(EnqueueYouTubePlaylist(url, requestorId, requestorActor)); return; } SongRequest addedItem; bool num = TryEnqueueInternal(url, requestorId, requestorActor, out addedItem, null); BroadcastQueue(); if (num && addedItem != null && string.IsNullOrEmpty(addedItem.title)) { StartTitleFetchIfNeeded(addedItem.hash, addedItem.url); } if (!audioSource.isPlaying && songLoadingState != SongLoadingState.Loading) { PlayNextImpl(); } } [PunRPC] private void RPC_RequestRemoveAt(int index, PhotonMessageInfo info) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) if (ActAsHost() && index >= 0 && index < queue.Count) { int num = ((info.Sender != null) ? info.Sender.ActorNumber : (-1)); if (queue[index].requestedByActor == num || IsRequestorHolder(num) || PublicEnqueue) { queue.RemoveAt(index); BroadcastQueue(); } } } [PunRPC] private void RPC_RequestClearQueue(PhotonMessageInfo info) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) if (ActAsHost()) { int requestorActorNumber = ((info.Sender != null) ? info.Sender.ActorNumber : (-1)); if (PublicEnqueue || IsRequestorHolder(requestorActorNumber)) { queue.Clear(); BroadcastQueue(); } } } [PunRPC] private void RPC_RequestNext(PhotonMessageInfo info) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) if (ActAsHost()) { int requestorActorNumber = ((info.Sender != null) ? info.Sender.ActorNumber : (-1)); if (PublicEnqueue || IsRequestorHolder(requestorActorNumber)) { PlayNextImpl(); } } } [PunRPC] private void RPC_RequestShuffle(PhotonMessageInfo info) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) if (!ActAsHost()) { return; } int requestorActorNumber = ((info.Sender != null) ? info.Sender.ActorNumber : (-1)); if (PublicEnqueue || IsRequestorHolder(requestorActorNumber)) { Random random = new Random(); for (int num = queue.Count - 1; num > 0; num--) { int num2 = random.Next(num + 1); List list = queue; int index = num; List list2 = queue; int index2 = num2; SongRequest value = queue[num2]; SongRequest value2 = queue[num]; list[index] = value; list2[index2] = value2; } BroadcastQueue(); } } [PunRPC] private void RPC_RequestStop(PhotonMessageInfo info) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) if (!ActAsHost()) { return; } int requestorActorNumber = ((info.Sender != null) ? info.Sender.ActorNumber : (-1)); if (PublicEnqueue || IsRequestorHolder(requestorActorNumber)) { PhotonView? obj = photonView; if (obj != null) { obj.RPC("RPC_StopAudio", (RpcTarget)0, Array.Empty()); } } } [PunRPC] private void RPC_RequestSeek(float seconds, PhotonMessageInfo info) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) if (ActAsHost()) { int requestorActorNumber = ((info.Sender != null) ? info.Sender.ActorNumber : (-1)); if ((PublicEnqueue || IsRequestorHolder(requestorActorNumber)) && !((Object)(object)audioSource == (Object)null) && !((Object)(object)audioSource.clip == (Object)null)) { float num = Mathf.Clamp(audioSource.time + seconds, 0f, audioSource.clip.length); audioSource.time = num; photonView.RPC("RPC_SyncTime", (RpcTarget)1, new object[2] { currentSongHash, num }); } } } private bool IsYouTubePlaylistUrl(string url) { if (!Uri.TryCreate(url, UriKind.Absolute, out Uri result)) { return false; } string text = result.Host.ToLowerInvariant(); if (!text.Contains("youtube.com") && !text.Contains("youtu.be") && !text.Contains("music.youtube.com")) { return false; } NameValueCollection nameValueCollection = HttpUtility.ParseQueryString(result.Query); bool num = !string.IsNullOrEmpty(nameValueCollection["list"]); bool flag = false; if (text.Contains("youtu.be")) { flag = !string.IsNullOrEmpty(result.AbsolutePath.Trim('/')); } else { if (!string.IsNullOrEmpty(nameValueCollection["v"])) { flag = true; } if (result.AbsolutePath.ToLowerInvariant().StartsWith("/shorts/")) { flag = true; } } if (num) { return !flag; } return false; } private IEnumerator EnqueueYouTubePlaylist(string playlistUrl, string requestorId, int requestorActor) { if (string.IsNullOrEmpty(ytDlpPath) || !File.Exists(ytDlpPath)) { yield break; } int val = Math.Max(0, MaxQueueSize - queue.Count); int num = queue.Count((SongRequest it) => it.requestedByActor == requestorActor); int val2 = Math.Max(0, PerUserQueueLimit - num); int num2 = Math.Min(val, val2); if (num2 <= 0) { yield break; } ProcessStartInfo processStartInfo = new ProcessStartInfo { FileName = ytDlpPath, RedirectStandardOutput = true, RedirectStandardError = true, UseShellExecute = false, CreateNoWindow = true }; processStartInfo.ArgumentList.Add("--yes-playlist"); processStartInfo.ArgumentList.Add("--flat-playlist"); processStartInfo.ArgumentList.Add("--ignore-errors"); processStartInfo.ArgumentList.Add("--playlist-items"); processStartInfo.ArgumentList.Add($"1-{num2}"); processStartInfo.ArgumentList.Add("--print"); processStartInfo.ArgumentList.Add("%(title)s\t%(webpage_url)s"); processStartInfo.ArgumentList.Add("--js-runtimes"); processStartInfo.ArgumentList.Add(denoPath); processStartInfo.ArgumentList.Add(playlistUrl); Process proc = new Process { StartInfo = processStartInfo }; List lines = new List(); proc.OutputDataReceived += delegate(object s, DataReceivedEventArgs e) { if (!string.IsNullOrEmpty(e.Data)) { lines.Add(e.Data); } }; proc.ErrorDataReceived += delegate { }; bool flag = false; try { flag = proc.Start(); } catch (Exception) { } if (!flag) { yield break; } proc.BeginOutputReadLine(); proc.BeginErrorReadLine(); float startTime = Time.realtimeSinceStartup; while (!proc.HasExited) { if (Time.realtimeSinceStartup - startTime > (float)PlaylistProbeTimeoutSec) { try { proc.Kill(); } catch { } break; } yield return null; } int num3 = 0; foreach (string item in lines) { if (string.IsNullOrWhiteSpace(item)) { continue; } int num4 = item.IndexOf('\t'); if (num4 > 0 && num4 < item.Length - 1) { string knownTitle = item.Substring(0, num4).Trim(); string url = item.Substring(num4 + 1).Trim(); if (queue.Count >= MaxQueueSize || queue.Count((SongRequest it) => it.requestedByActor == requestorActor) >= PerUserQueueLimit) { break; } if ((AllowDuplicates || !queue.Any((SongRequest it) => it.url.Equals(url, StringComparison.OrdinalIgnoreCase))) && TryEnqueueInternal(url, requestorId, requestorActor, out SongRequest addedItem, knownTitle) && addedItem != null) { num3++; } } } if (num3 > 0) { BroadcastQueue(); } if (num3 > 0 && !audioSource.isPlaying && songLoadingState != SongLoadingState.Loading) { PlayNextImpl(); } } private bool TryEnqueueInternal(string url, string requestorId, int requestorActor, out SongRequest? addedItem, string? knownTitle) { addedItem = null; if (queue.Count >= MaxQueueSize) { return false; } if (queue.Count((SongRequest it) => it.requestedByActor == requestorActor) >= PerUserQueueLimit) { return false; } if (!AllowDuplicates && queue.Any((SongRequest it) => it.url.Equals(url, StringComparison.OrdinalIgnoreCase))) { return false; } string safeSongId = GetSafeSongId(url); string path = Path.Combine(tempAudioDir, "bingbong_" + safeSongId + ".json"); string text = knownTitle ?? ""; if (string.IsNullOrEmpty(text) && File.Exists(path)) { try { text = JsonUtility.FromJson(File.ReadAllText(path))?.title ?? ""; } catch { text = ""; } } SongRequest songRequest = new SongRequest { url = url, hash = safeSongId, requestedBy = requestorId, requestedByActor = requestorActor, title = text }; queue.Add(songRequest); addedItem = songRequest; if (!string.IsNullOrEmpty(text)) { try { File.WriteAllText(path, JsonUtility.ToJson((object)new SongMetadata { title = text })); } catch { } } if (string.IsNullOrEmpty(text)) { StartTitleFetchIfNeeded(safeSongId, url); } return true; } private void PlayNextImpl() { manualStop = false; if (queue.Count == 0) { StopAndResetSong(); BroadcastQueue(); return; } SongRequest songRequest = queue[0]; queue.RemoveAt(0); BroadcastQueue(); lastUsedPlayer = songRequest.requestedBy; PhotonView? obj = photonView; if (obj != null) { obj.RPC("RPC_StopAudio", (RpcTarget)0, Array.Empty()); } PlayAudio(songRequest.url, lastUsedPlayer); if (string.IsNullOrEmpty(songRequest.title)) { StartTitleFetchIfNeeded(songRequest.hash, songRequest.url); } } private void BroadcastQueue() { string text = JsonUtility.ToJson((object)new SongQueueWrapper { items = queue }); photonView.RPC("RPC_SyncQueue", (RpcTarget)1, new object[1] { text }); } [PunRPC] private void RPC_SyncQueue(string json) { try { SongQueueWrapper songQueueWrapper = JsonUtility.FromJson(json); if (songQueueWrapper != null && songQueueWrapper.items != null) { queue.Clear(); queue.AddRange(songQueueWrapper.items.Take(MaxQueueSize)); } } catch { } } private IEnumerator DebouncePlayCoroutine(float delay, string url, string userId) { yield return (object)new WaitForSecondsRealtime(delay); PlayAudio(url, userId); } [PunRPC] private void RPC_PlayAudio(string url, string userId, PhotonMessageInfo info) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) Player sender = info.Sender; if ((sender == null || sender.IsMasterClient || !hostHasMod) && !string.IsNullOrWhiteSpace(url) && IsSupportedMediaUrl(url)) { if (debouncePlayCoroutine != null) { ((MonoBehaviour)this).StopCoroutine(debouncePlayCoroutine); debouncePlayCoroutine = null; } debouncePlayCoroutine = ((MonoBehaviour)this).StartCoroutine(DebouncePlayCoroutine(1f, url, userId)); } } private void PlayAudio(string url, string userId) { debouncePlayCoroutine = null; if (string.IsNullOrWhiteSpace(url) || !IsSupportedMediaUrl(url)) { return; } lastUsedPlayer = userId; manualStop = false; if (ActAsHost()) { AudioSource? obj = audioSource; if (obj != null) { obj.Stop(); } PhotonView? obj2 = photonView; if (obj2 != null) { obj2.RPC("RPC_StopAudio", (RpcTarget)1, Array.Empty()); } PhotonView? obj3 = photonView; if (obj3 != null) { obj3.RPC("RPC_PlayAudio", (RpcTarget)1, new object[2] { url, userId }); } } currentSongTitle = "Unknown"; currentSongHash = GetSafeSongId(url); string text = Path.Combine(tempAudioDir, "bingbong_" + currentSongHash + ".wav"); string text2 = Path.Combine(tempAudioDir, "bingbong_" + currentSongHash + ".json"); if (File.Exists(text2)) { try { SongMetadata songMetadata = JsonUtility.FromJson(File.ReadAllText(text2)); if (!string.IsNullOrEmpty(songMetadata?.title)) { currentSongTitle = songMetadata.title; } } catch { currentSongTitle = "Unknown"; } } if (currentPlaybackCoroutine != null) { ((MonoBehaviour)this).StopCoroutine(currentPlaybackCoroutine); } if (File.Exists(text)) { currentPlaybackCoroutine = ((MonoBehaviour)this).StartCoroutine(LoadAndPlay(text)); return; } if (downloadCoroutine != null) { ((MonoBehaviour)this).StopCoroutine(downloadCoroutine); downloadCoroutine = null; } downloadCoroutine = ((MonoBehaviour)this).StartCoroutine(DownloadAudio(url, text, text2)); } private IEnumerator DownloadAudio(string url, string outputPath, string metadataPath) { CleanupOldTempFiles(); songLoadingState = SongLoadingState.Loading; string titleFromPrint = ""; if (string.IsNullOrEmpty(ytDlpPath) || !File.Exists(ytDlpPath) || string.IsNullOrEmpty(ffmpegPath) || !File.Exists(ffmpegPath)) { songLoadingState = SongLoadingState.Error; yield break; } ProcessStartInfo processStartInfo = new ProcessStartInfo { FileName = ytDlpPath, RedirectStandardOutput = true, RedirectStandardError = true, UseShellExecute = false, CreateNoWindow = true }; processStartInfo.ArgumentList.Add("--no-playlist"); processStartInfo.ArgumentList.Add("--max-filesize"); processStartInfo.ArgumentList.Add($"{MaxAudioSizeMb}M"); processStartInfo.ArgumentList.Add("--extractor-args"); processStartInfo.ArgumentList.Add("youtube:player_client=tv_simply,default,-tv"); processStartInfo.ArgumentList.Add("-x"); processStartInfo.ArgumentList.Add("-f"); processStartInfo.ArgumentList.Add("bestaudio[abr<=128]/bestaudio[abr<=160]/bestaudio"); processStartInfo.ArgumentList.Add("--ffmpeg-location"); processStartInfo.ArgumentList.Add(ffmpegPath); processStartInfo.ArgumentList.Add("--js-runtimes"); processStartInfo.ArgumentList.Add(denoPath); processStartInfo.ArgumentList.Add("--audio-format"); processStartInfo.ArgumentList.Add("wav"); processStartInfo.ArgumentList.Add("--print"); processStartInfo.ArgumentList.Add("title-current:%(title)s"); processStartInfo.ArgumentList.Add("--no-simulate"); processStartInfo.ArgumentList.Add("-o"); processStartInfo.ArgumentList.Add(outputPath); processStartInfo.ArgumentList.Add(url); Process proc = new Process { StartInfo = processStartInfo }; proc.OutputDataReceived += delegate(object s, DataReceivedEventArgs e) { if (!string.IsNullOrEmpty(e.Data) && e.Data.StartsWith("title-current:")) { titleFromPrint = e.Data.Substring("title-current:".Length).Trim(); } }; proc.ErrorDataReceived += delegate { }; try { proc.Start(); } catch (Exception) { songLoadingState = SongLoadingState.Error; downloadCoroutine = null; yield break; } proc.BeginOutputReadLine(); proc.BeginErrorReadLine(); float startTime = Time.realtimeSinceStartup; while (!proc.HasExited) { if (Time.realtimeSinceStartup - startTime > (float)(TitleProbeTimeoutSec + 60)) { try { proc.Kill(); } catch { } break; } yield return null; } if (File.Exists(outputPath)) { if (!string.IsNullOrWhiteSpace(titleFromPrint)) { currentSongTitle = titleFromPrint; } try { SongMetadata songMetadata = new SongMetadata { title = currentSongTitle }; File.WriteAllText(metadataPath, JsonUtility.ToJson((object)songMetadata)); } catch { } currentPlaybackCoroutine = ((MonoBehaviour)this).StartCoroutine(LoadAndPlay(outputPath)); } else { songLoadingState = SongLoadingState.Error; if (ActAsHost()) { PlayNextImpl(); } } downloadCoroutine = null; } private string GetSafeSongId(string url) { try { Uri uri = new Uri(url); string text = uri.Host.ToLowerInvariant(); if (text.Contains("youtu.be")) { string text2 = uri.AbsolutePath.Trim('/'); if (!string.IsNullOrEmpty(text2)) { return text2; } } if (text.Contains("youtube.com") || text.Contains("music.youtube.com")) { string text3 = HttpUtility.ParseQueryString(uri.Query)["v"]; if (!string.IsNullOrEmpty(text3)) { return text3; } string text4 = uri.AbsolutePath.Trim('/'); if (text4.StartsWith("shorts/", StringComparison.OrdinalIgnoreCase)) { string[] array = text4.Split('/'); if (array.Length >= 2 && array[1].Length > 0) { return array[1]; } } } } catch { } using SHA1 sHA = SHA1.Create(); return BitConverter.ToString(sHA.ComputeHash(Encoding.UTF8.GetBytes(url)), 0, 6).Replace("-", ""); } private IEnumerator LoadAndPlay(string path) { if ((Object)(object)audioSource == (Object)null) { songLoadingState = SongLoadingState.Error; yield break; } songLoadingState = SongLoadingState.Loaded; UnityWebRequest www = UnityWebRequestMultimedia.GetAudioClip("file://" + path, (AudioType)20); try { yield return www.SendWebRequest(); if ((int)www.result != 1) { songLoadingState = SongLoadingState.Error; yield break; } AudioClip content = DownloadHandlerAudioClip.GetContent(www); audioSource.clip = content; if (ActAsHost()) { audioSource.Play(); } } finally { ((IDisposable)www)?.Dispose(); } } [PunRPC] private void RPC_StopAudio() { manualStop = true; if ((Object)(object)audioSource != (Object)null) { audioSource.Stop(); audioSource.clip = null; } } [PunRPC] private void RPC_SyncTime(string songHash, float hostTime) { if (!ActAsHost() && (Object)(object)audioSource != (Object)null && (Object)(object)audioSource.clip != (Object)null && songHash == currentSongHash && Mathf.Abs(audioSource.time - hostTime) > 0.5f && hostTime >= 0f && hostTime <= audioSource.clip.length) { audioSource.time = hostTime; } } [PunRPC] private void RPC_SyncPlaying(string songHash, bool hostIsPlaying, bool isOwner, string hostTitle) { if (isOwner) { hostHasMod = true; } if (!string.IsNullOrEmpty(hostTitle)) { currentSongTitle = hostTitle; } if (!ActAsHost() && (Object)(object)audioSource != (Object)null) { if (!audioSource.isPlaying && hostIsPlaying && (Object)(object)audioSource.clip != (Object)null && songHash == currentSongHash) { audioSource.Play(); } if (audioSource.isPlaying && (!hostIsPlaying || songHash != currentSongHash)) { audioSource.Stop(); } } } private void StopAndResetSong() { if (currentPlaybackCoroutine != null) { ((MonoBehaviour)this).StopCoroutine(currentPlaybackCoroutine); } AudioSource? obj = audioSource; if (obj != null) { obj.Stop(); } if ((Object)(object)audioSource != (Object)null) { audioSource.clip = null; } songLoadingState = SongLoadingState.Loaded; currentSongTitle = ""; currentSongHash = ""; lastUsedPlayer = ""; manualStop = false; hostHasMod = PhotonNetwork.IsMasterClient; } private void CleanupOldTempFiles() { if (string.IsNullOrEmpty(tempAudioDir) || !Directory.Exists(tempAudioDir)) { return; } List list = (from f in new DirectoryInfo(tempAudioDir).GetFiles("bingbong_*.wav") orderby f.LastAccessTimeUtc descending select f).ToList(); for (int num = MaxTempFiles; num < list.Count; num++) { FileInfo fileInfo = list[num]; try { fileInfo.Delete(); } catch { } string path = Path.ChangeExtension(fileInfo.FullName, ".json"); if (File.Exists(path)) { try { File.Delete(path); } catch { } } } } private bool IsSupportedMediaUrl(string url) { if (!Uri.TryCreate(url, UriKind.Absolute, out Uri result)) { return false; } string value = result.Host.ToLowerInvariant(); if (AllowedHosts.Contains(value)) { return true; } if (!(result.Scheme == Uri.UriSchemeHttp)) { return result.Scheme == Uri.UriSchemeHttps; } return true; } private void StartTitleFetchIfNeeded(string hash, string url) { if (!ActAsHost() || titleFetchInProgress.Contains(hash)) { return; } string path = Path.Combine(tempAudioDir, "bingbong_" + hash + ".json"); if (File.Exists(path)) { try { SongMetadata songMetadata = JsonUtility.FromJson(File.ReadAllText(path)); if (!string.IsNullOrEmpty(songMetadata?.title)) { UpdateQueueTitle(hash, songMetadata.title); return; } } catch { } } ((MonoBehaviour)this).StartCoroutine(FetchTitleCoroutine(hash, url)); } private IEnumerator FetchTitleCoroutine(string hash, string url) { titleFetchInProgress.Add(hash); if (string.IsNullOrEmpty(ytDlpPath) || !File.Exists(ytDlpPath)) { titleFetchInProgress.Remove(hash); yield break; } string fetched = ""; ProcessStartInfo processStartInfo = new ProcessStartInfo { FileName = ytDlpPath, RedirectStandardOutput = true, RedirectStandardError = true, UseShellExecute = false, CreateNoWindow = true }; processStartInfo.ArgumentList.Add("--no-playlist"); processStartInfo.ArgumentList.Add("--skip-download"); processStartInfo.ArgumentList.Add("--print"); processStartInfo.ArgumentList.Add("title-current:%(title)s"); processStartInfo.ArgumentList.Add("--js-runtimes"); processStartInfo.ArgumentList.Add(denoPath); processStartInfo.ArgumentList.Add(url); Process proc = new Process { StartInfo = processStartInfo }; proc.OutputDataReceived += delegate(object s, DataReceivedEventArgs e) { if (!string.IsNullOrEmpty(e.Data) && e.Data.StartsWith("title-current:")) { fetched = e.Data.Substring("title-current:".Length).Trim(); } }; proc.ErrorDataReceived += delegate { }; bool flag = false; try { flag = proc.Start(); } catch (Exception) { } if (!flag) { titleFetchInProgress.Remove(hash); yield break; } proc.BeginOutputReadLine(); proc.BeginErrorReadLine(); float startTime = Time.realtimeSinceStartup; while (!proc.HasExited) { if (Time.realtimeSinceStartup - startTime > (float)TitleProbeTimeoutSec) { try { proc.Kill(); } catch { } break; } yield return null; } if (!string.IsNullOrWhiteSpace(fetched)) { UpdateQueueTitle(hash, fetched); try { File.WriteAllText(Path.Combine(tempAudioDir, "bingbong_" + hash + ".json"), JsonUtility.ToJson((object)new SongMetadata { title = fetched })); } catch { } } titleFetchInProgress.Remove(hash); } private void UpdateQueueTitle(string hash, string title) { bool flag = false; for (int i = 0; i < queue.Count; i++) { if (queue[i].hash == hash && string.IsNullOrEmpty(queue[i].title)) { queue[i].title = title; flag = true; } } if (flag) { BroadcastQueue(); } if (currentSongHash == hash && (string.IsNullOrEmpty(currentSongTitle) || currentSongTitle == "Unknown")) { currentSongTitle = title; } } } }