Decompiled source of CybergrindMusicExplorer v2.1.0
plugins/Jukebox/Jukebox.dll
Decompiled 3 weeks ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.CodeDom.Compiler; using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Resources; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Threading; using BepInEx; using Discord; using HarmonyLib; using Jukebox.Components; using Jukebox.Input; using Jukebox.UI; using Jukebox.UI.Elements; using Jukebox.UI.Windows; using Jukebox.Utils; using JukeboxCore.Assets; using JukeboxCore.Collections; using JukeboxCore.Components; using JukeboxCore.Models.Preferences; using JukeboxCore.Models.Song; using JukeboxCore.Utils; using Newtonsoft.Json; using SettingsMenu.Components; using SettingsMenu.Components.Pages; using Steamworks; using TMPro; using UnityEngine; using UnityEngine.AddressableAssets; using UnityEngine.EventSystems; using UnityEngine.Events; using UnityEngine.InputSystem; using UnityEngine.Networking; using UnityEngine.ResourceManagement.AsyncOperations; using UnityEngine.SceneManagement; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("Jukebox")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("Jukebox")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("B01B8657-61B6-4BC3-BFAF-F43D4C264B4B")] [assembly: AssemblyFileVersion("2.1.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyVersion("2.1.0.0")] namespace Jukebox { [BepInProcess("ULTRAKILL.exe")] [BepInPlugin("dev.flazhik.jukebox", "Jukebox", "2.1.0")] public class JukeboxPlugin : BaseUnityPlugin { [ExternalAsset("Assets/Jukebox/Bootstrap.prefab", typeof(GameObject))] private static GameObject _bootstrap; private static readonly string CatalogDir; private static Harmony _harmony; private static bool _motDShown; private static bool _init; static JukeboxPlugin() { CatalogDir = Path.Combine(PathsUtils.AssemblyPath, "Assets"); } private void Awake() { //IL_000f: 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) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Expected O, but got Unknown Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture; Addressables.InitializeAsync().WaitForCompletion(); Addressables.LoadContentCatalogAsync(Path.Combine(CatalogDir, "catalog.json"), true, (string)null).WaitForCompletion(); _harmony = new Harmony("dev.flazhik.jukebox"); Startup(); } private void Startup() { _harmony.PatchAll(); FileInfo fileInfo = new FileInfo(Path.Combine(PathsUtils.AssemblyPath, "cookies.txt")); if (fileInfo.Exists) { fileInfo.Delete(); } SceneManager.sceneLoaded += OnSceneLoaded; } private void OnSceneLoaded(Scene scene, LoadSceneMode loadSceneMode) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) if (scene != SceneManager.GetActiveScene()) { return; } switch (SceneHelper.CurrentScene) { case "Bootstrap": SetDefaultPrefsValues(); break; case "Main Menu": if (!_init) { MonoSingleton<AssetsManager>.Instance.LoadAssets(Resources.Jukebox); MonoSingleton<AssetsManager>.Instance.RegisterPrefabs(Assembly.GetExecutingAssembly()); _init = true; } break; case "Endless": Object.Instantiate<GameObject>(_bootstrap); if (!_motDShown) { ((MonoBehaviour)MonoSingleton<JukeboxManager>.Instance).StartCoroutine(MotD()); } break; } } private static void SetDefaultPrefsValues() { foreach (KeyValuePair<string, object> item in new Dictionary<string, object> { { "jukebox.volumeBoost", 0f }, { "jukebox.individualBoostPerTrack", false }, { "jukebox.showTrackPanelIndefinitely", false }, { "jukebox.alwaysPlayIntro", true }, { "jukebox.discordAndSteamIntegration", true }, { "jukebox.enableTracksPreview", true }, { "jukebox.preventDuplicateTracks", false }, { "jukebox.nowPlayingHud", true }, { "jukebox.enableCalmThemes", true }, { "jukebox.songPanelStyle", 0 }, { "jukebox.currentPlaylist", "slot1" }, { "jukebox.calmThemeEnemiesThreshold", 2 }, { "jukebox.effects.parry", null }, { "jukebox.effects.wavecomplete", null }, { "jukebox.effects.gameover", null }, { "jukebox.effects.aww", null }, { "jukebox.effects.terminal-music", null }, { "jukebox.downloader.separateFolderPerPlaylist", true } }) { MonoSingleton<PrefsManager>.Instance.defaultValues.Add(item.Key, item.Value); } } private static IEnumerator MotD() { yield return (object)new WaitForSeconds(1.5f); InputAction menu = MonoSingleton<JukeboxInputs>.Instance.Menu; string text = GeneralExtensions.Join<InputBinding>((IEnumerable<InputBinding>)(object)menu.bindings, (Func<InputBinding, string>)((InputBinding binding) => InputExtensions.GetBindingDisplayStringWithoutOverride(menu, binding, (DisplayStringOptions)0)), ", "); MonoSingleton<HudMessageReceiver>.Instance.SendHudMessage("Jukebox menu is available by pressing <color=orange>" + text + "</color>", "", "", 0, false, false, true); _motDShown = true; } } internal static class PluginInfo { public const string GUID = "dev.flazhik.jukebox"; public const string NAME = "Jukebox"; public const string VERSION = "2.1.0"; } [GeneratedCode("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] [DebuggerNonUserCode] [CompilerGenerated] internal class Resources { private static ResourceManager resourceMan; private static CultureInfo resourceCulture; [EditorBrowsable(EditorBrowsableState.Advanced)] internal static ResourceManager ResourceManager { get { if (resourceMan == null) { resourceMan = new ResourceManager("Jukebox.Resources", typeof(Resources).Assembly); } return resourceMan; } } [EditorBrowsable(EditorBrowsableState.Advanced)] internal static CultureInfo Culture { get { return resourceCulture; } set { resourceCulture = value; } } internal static byte[] Jukebox => (byte[])ResourceManager.GetObject("Jukebox", resourceCulture); internal Resources() { } } } namespace Jukebox.Utils { public static class FloatExtensions { public static string SecondsToHumanReadable(this float value) { int num = (int)value; int num2 = num / 60; int num3 = num - num2 * 60; return $"{num2:00}:{num3:00}"; } } public static class IntExtensions { public static int Mod(this int num, int mod) { return (num % mod + mod) % mod; } } public abstract class ReflectionUtils { private const BindingFlags PrivateFields = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; public static T GetPrivate<T>(object instance, Type classType, string field) { FieldInfo field2 = classType.GetField(field, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); return (T)((field2 != null) ? field2.GetValue(instance) : null); } public static void SetPrivate<T, TV>(T instance, Type classType, string field, TV value) { FieldInfo field2 = classType.GetField(field, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.SetField); if (field2 != null) { field2.SetValue(instance, value); } } } public static class ScrollingTextUnscaled { public static IEnumerator ShowText(TMP_Text text, string message, float secondsBetweenLetters = 0.005f, AudioSource clickAudio = null) { int currentLetter = 0; text.text = ""; while (currentLetter < message.Length) { int num; if (message[currentLetter] == '<') { while (message[currentLetter] != '>' && currentLetter <= message.Length) { num = currentLetter + 1; currentLetter = num; } } else if (currentLetter < message.Length - 1) { while (currentLetter < message.Length - 1 && message[currentLetter + 1] == ' ') { num = currentLetter + 1; currentLetter = num; } } num = currentLetter + 1; currentLetter = num; text.text = message.Substring(0, currentLetter); if ((Object)(object)clickAudio != (Object)null && message[currentLetter - 1] != '\n' && message[currentLetter - 1] != ' ') { clickAudio.Play(); } yield return (object)new WaitForSecondsRealtime(secondsBetweenLetters); } } public static IEnumerator HideText(TMP_Text text, float secondsBetweenLetters = 0.005f) { int currentLetter = text.text.Length - 1; string message = text.text; while (currentLetter >= 0) { int num; if (text.text[currentLetter] == '>') { while (text.text[currentLetter] != '<' && currentLetter >= 0) { num = currentLetter - 1; currentLetter = num; } } num = currentLetter - 1; currentLetter = num; text.text = message.Substring(0, currentLetter + 1); yield return (object)new WaitForSecondsRealtime(secondsBetweenLetters); } } } } namespace Jukebox.UI { public class JukeboxCredits : MonoBehaviour { [SerializeField] private TMP_Text[] terminalText; [SerializeField] private AudioSource click; [SerializeField] private GameObject firstWindow; [SerializeField] private GameObject secondWindow; [SerializeField] private List<GameObject> lastWindows; private string[] originalText; private void Awake() { originalText = terminalText.Select((TMP_Text t) => t.text).ToArray(); } private void OnEnable() { firstWindow.SetActive(false); secondWindow.SetActive(false); foreach (GameObject lastWindow in lastWindows) { lastWindow.SetActive(false); } TMP_Text[] array = terminalText; for (int i = 0; i < array.Length; i++) { array[i].text = string.Empty; } ((MonoBehaviour)this).StartCoroutine(WindowsRoutine()); } private IEnumerator WindowsRoutine() { yield return TerminalTextRoutine(0); firstWindow.SetActive(true); yield return TerminalTextRoutine(1); yield return TerminalTextRoutine(2); secondWindow.SetActive(true); yield return TerminalTextRoutine(3); yield return TerminalTextRoutine(4); foreach (GameObject lastWindow in lastWindows) { lastWindow.SetActive(true); } } private IEnumerator TerminalTextRoutine(int index) { return ScrollingTextUnscaled.ShowText(terminalText[index], originalText[index], 0.01f, click); } } public class JukeboxCustomContentButton : CustomContentButton { [SerializeField] public GameObject introAndLoopIcon; [SerializeField] public GameObject calmThemeIcon; } public class JukeboxUI : MonoBehaviour { [SerializeField] public GameObject jukeboxMenuTemplate; [SerializeField] public GameObject playbackMenuTemplate; [SerializeField] public GameObject nowPlayingHudTemplate; [SerializeField] public GameObject nowPlayingHudClassicTemplate; private GameObject jukeboxMenu; private GameObject playbackMenu; private ReadOnlyCollection<JukeboxWindow> windows; public void OpenDownloader() { JukeboxMenuWindow component = jukeboxMenu.GetComponent<JukeboxMenuWindow>(); component.Open(); component.OpenDownloader(); } protected void Awake() { InstantiateUI(); windows = new ReadOnlyCollection<JukeboxWindow>(new List<JukeboxWindow> { jukeboxMenu.GetComponent<JukeboxWindow>(), playbackMenu.GetComponent<JukeboxPlaybackWindow>() }); foreach (JukeboxWindow window in windows) { ((Component)window).gameObject.SetActive(false); } } protected void Update() { ManageWindows(); } private void ManageWindows() { if (GameIsPaused()) { return; } if (MonoSingleton<InputManager>.Instance.InputSource.Pause.WasPerformedThisFrame) { foreach (JukeboxWindow window in windows) { if (window.IsOpened()) { window.Close(); } } return; } JukeboxWindow jukeboxWindow = windows.FirstOrDefault((JukeboxWindow w) => w.hotkey.ToInputAction().WasPerformedThisFrame()); if ((Object)(object)jukeboxWindow != (Object)null) { foreach (JukeboxWindow window2 in windows) { if (InputExtensions.IsActionEqual(window2.hotkey.ToInputAction(), jukeboxWindow.hotkey.ToInputAction(), (string)null)) { window2.Toggle(); } else { window2.Close(); } } } if (!windows.Any((JukeboxWindow w) => GameStateManager.Instance.IsStateActive(w.StateKey())) && MonoSingleton<OptionsManager>.Instance.paused) { MonoSingleton<JukeboxPauseManager>.Instance.UnPause(); } } private void InstantiateUI() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject { name = "JukeboxCanvas" }; val.AddComponent<Canvas>(); GameObject val2 = GameObject.Find("/Canvas"); Canvas component = val.GetComponent<Canvas>(); component.renderMode = (RenderMode)1; component.sortingOrder = val2.GetComponent<Canvas>().sortingOrder + 1; val.AddComponent<CanvasScaler>(); val.AddComponent<GraphicRaycaster>(); jukeboxMenu = Object.Instantiate<GameObject>(jukeboxMenuTemplate, val2.transform); playbackMenu = Object.Instantiate<GameObject>(playbackMenuTemplate, val2.transform); Object.Instantiate<GameObject>(nowPlayingHudTemplate, GameObject.Find("/Player/Main Camera/HUD Camera/HUD/GunCanvas").transform, false); Object.Instantiate<GameObject>(nowPlayingHudClassicTemplate, val2.transform.Find("Crosshair Filler"), false); } private static bool GameIsPaused() { return GameStateManager.Instance.IsStateActive("pause"); } } public class ScrollUIImageUnscaled : MonoBehaviour { private RawImage img; public float xSpeed; public float ySpeed; private void Start() { img = ((Component)this).GetComponent<RawImage>(); } private void Update() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: 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_0108: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) Rect uvRect = img.uvRect; Vector2 val = ((Rect)(ref uvRect)).position + new Vector2(xSpeed, ySpeed) * Time.unscaledDeltaTime; while ((double)val.x > 1.0) { val.x -= 1f; } while ((double)val.x < -1.0) { val.x += 1f; } while ((double)val.y > 1.0) { val.y -= 1f; } while ((double)val.y < -1.0) { val.y += 1f; } RawImage obj = img; uvRect = img.uvRect; Vector2 val2 = ((Rect)(ref uvRect)).position + new Vector2(xSpeed, ySpeed) * Time.unscaledDeltaTime; uvRect = img.uvRect; obj.uvRect = new Rect(val2, ((Rect)(ref uvRect)).size); } } } namespace Jukebox.UI.Windows { public class JukeboxMenuWindow : JukeboxWindow { [SerializeField] protected Button[] buttons; [SerializeField] protected GameObject activeBgObject; [SerializeField] protected GameObject generalSettings; [SerializeField] protected Button downloaderButton; [SerializeField] protected GameObject downloaderPage; public override string StateKey() { return "jukeboxMenu"; } protected override void Awake() { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Expected O, but got Unknown base.Awake(); Button[] array = buttons; foreach (Button button in array) { ((UnityEvent)button.onClick).AddListener((UnityAction)delegate { SetActiveButton(button); }); } JukeboxMusicPlayer.OnNextSong += OnNextSong; } public void OnNextSong(JukeboxSong song) { if (song.IsCustom) { ReflectionUtils.GetPrivate<Slider>(generalSettings.GetComponentInChildren<SettingsSlider>(true), typeof(SettingsSlider), "slider").value = MonoSingleton<JukeboxManager>.Instance.player.VolumeBoost; } } public void OpenDownloader() { SettingsMenu component = ((Component)this).gameObject.GetComponent<SettingsMenu>(); if (!ReflectionUtils.GetPrivate<bool>(component, typeof(SettingsMenu), "initialized")) { component.Initialize(); } component.SetActivePage(downloaderPage); SetActiveButton(downloaderButton); } protected void OnDestroy() { JukeboxMusicPlayer.OnNextSong -= OnNextSong; } private void SetActiveButton(Button button) { //IL_0032: Unknown result type (might be due to invalid IL or missing references) activeBgObject.transform.SetParent(((Component)button).transform); activeBgObject.transform.SetSiblingIndex(0); activeBgObject.transform.localPosition = Vector3.zero; } } public class JukeboxPlaybackWindow : JukeboxWindow { public override string StateKey() { return "jukeboxPlayback"; } } public abstract class JukeboxWindow : MonoBehaviour { [SerializeField] public InputActionReference hotkey; public abstract string StateKey(); public void Open() { ((Component)this).gameObject.SetActive(true); MonoSingleton<JukeboxPauseManager>.Instance.Pause(StateKey(), ((Component)this).gameObject); } public void Close() { GameStateManager.Instance.PopState(StateKey()); ((Component)this).gameObject.SetActive(false); } public void Toggle() { if (IsOpened()) { Close(); } else { Open(); } } protected virtual void Awake() { if ((Object)(object)hotkey != (Object)null) { hotkey = InputActionReference.Create(MonoSingleton<InputManager>.Instance.InputSource.Actions.asset.FindAction(hotkey.ToInputAction().id)); } } public bool IsOpened() { return ((Component)this).gameObject.activeSelf; } } } namespace Jukebox.UI.Themes { public class ThemeEnemySettings : MonoBehaviour { [SerializeField] public TMP_Text title; [SerializeField] public Image icon; [SerializeField] public GameObject radianceBg; [SerializeField] public Toggle toggle; [SerializeField] public Counter counter; } public class ThemeSettingsMenu : MonoBehaviour { [SerializeField] private Counter threshold; [SerializeField] private GameObject enemyTemplate; [SerializeField] private GameObject regularEnemies; [SerializeField] private GameObject radiantEnemies; [SerializeField] private Button[] tabButtons; [SerializeField] private GameObject activeTab; [SerializeField] private List<AssetReferenceT<SpawnableObject>> enemies; private void Awake() { //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Expected O, but got Unknown //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_01f1: Unknown result type (might be due to invalid IL or missing references) JukeboxThemesManager themesManager = MonoSingleton<JukeboxThemesManager>.Instance; threshold.SetDefaultValue(MonoSingleton<PrefsManager>.Instance.GetIntLocal("jukebox.calmThemeEnemiesThreshold", 0)); threshold.OnChanged += OnThresholdChanged; Button[] array = tabButtons; foreach (Button button in array) { ((UnityEvent)button.onClick).AddListener((UnityAction)delegate { //IL_0055: Unknown result type (might be due to invalid IL or missing references) activeTab.transform.SetParent(((Component)button).transform); activeTab.transform.SetSiblingIndex(0); activeTab.transform.localPosition = Vector3.zero; }); } foreach (AssetReferenceT<SpawnableObject> enemy2 in enemies) { AsyncOperationHandle<SpawnableObject> val = enemy2.LoadAssetAsync(); SpawnableObject enemy = val.WaitForCompletion(); Addressables.Release<SpawnableObject>(val); Dictionary<bool, ThemeEnemySettings> respectiveSettings = new Dictionary<bool, ThemeEnemySettings>(); GameObject[] array2 = (GameObject[])(object)new GameObject[2] { regularEnemies, radiantEnemies }; foreach (GameObject val2 in array2) { GameObject val3 = Object.Instantiate<GameObject>(enemyTemplate, val2.transform); bool radiant = (Object)(object)val2 == (Object)(object)radiantEnemies; Sprite gridIcon = enemy.gridIcon; ThemeEnemySettings enemySettings = val3.GetComponent<ThemeEnemySettings>(); enemySettings.icon.sprite = gridIcon; enemySettings.title.text = (radiant ? ("Radiant " + enemy.objectName) : enemy.objectName); enemySettings.radianceBg.SetActive(radiant); int? thresholdFor = themesManager.GetThresholdFor(enemy.enemyType, radiant); if (!thresholdFor.HasValue) { enemySettings.counter.SetDefaultValue(0); } else { enemySettings.counter.SetDefaultValue(thresholdFor.Value); } enemySettings.toggle.isOn = thresholdFor.HasValue; enemySettings.counter.OnChanged += delegate(int value) { //IL_002c: Unknown result type (might be due to invalid IL or missing references) enemySettings.toggle.isOn = true; themesManager.SetThresholdFor(enemy.enemyType, value, radiant); }; ((UnityEvent<bool>)(object)enemySettings.toggle.onValueChanged).AddListener((UnityAction<bool>)delegate(bool on) { //IL_005a: 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 (on) { themesManager.SetThresholdFor(enemy.enemyType, enemySettings.counter.Value, radiant); } else { themesManager.DisableThresholdFor(enemy.enemyType, radiant); } }); respectiveSettings[radiant] = enemySettings; val3.SetActive(true); } respectiveSettings[false].counter.OnChanged += delegate(int value) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) int? thresholdFor2 = themesManager.GetThresholdFor(enemy.enemyType, radiant: true); if (!thresholdFor2.HasValue || thresholdFor2.Value > value) { themesManager.SetThresholdFor(enemy.enemyType, value, radiant: true); respectiveSettings[true].toggle.isOn = true; respectiveSettings[true].counter.Value = value; } }; ((UnityEvent<bool>)(object)respectiveSettings[false].toggle.onValueChanged).AddListener((UnityAction<bool>)delegate(bool on) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) if (on && !themesManager.GetThresholdFor(enemy.enemyType, radiant: true).HasValue) { respectiveSettings[true].toggle.isOn = true; respectiveSettings[true].counter.Value = respectiveSettings[false].counter.Value; } }); } } private void OnDestroy() { threshold.OnChanged -= OnThresholdChanged; } private static void OnThresholdChanged(int value) { MonoSingleton<PrefsManager>.Instance.SetIntLocal("jukebox.calmThemeEnemiesThreshold", value); } } } namespace Jukebox.UI.SongPanel { public class ClassicSongPanel : SongPanel { protected override SongPanelStyle Style => SongPanelStyle.Classic; protected override IEnumerator FadeIn(JukeboxSongMetadata metadata) { float time = 0f; while ((double)time < (double)panelApproachTime) { time += Time.unscaledDeltaTime; panelGroup.alpha = (active ? (time / panelApproachTime) : 0f); yield return null; } panelGroup.alpha = (active ? 1 : 0); } protected override IEnumerator Await() { float time = panelStayTime; while ((double)time > 0.0 || showIndefinitely) { panelGroup.alpha = (active ? 1 : 0); if ((double)time > 0.0) { time -= Time.unscaledDeltaTime; } yield return null; } } protected override IEnumerator FadeOut() { float time = panelApproachTime; while ((double)time > 0.0) { time -= Time.unscaledDeltaTime; panelGroup.alpha = (active ? (time / panelApproachTime) : 0f); yield return null; } panelGroup.alpha = 0f; } } public class JukeboxSongPanel : SongPanel { [SerializeField] public Vector2 startDimensions; [SerializeField] public Vector2 targetDimensions; private Coroutine rollingTextRoutine; protected override SongPanelStyle Style => SongPanelStyle.Jukebox; protected override IEnumerator FadeIn(JukeboxSongMetadata metadata) { ((Graphic)base.text).color = new Color(1f, 1f, 1f, 1f); RectTransform rect = ((Component)panelGroup).GetComponent<RectTransform>(); rect.sizeDelta = startDimensions; string text = ((!string.IsNullOrEmpty(metadata.Artist)) ? ("<color=#999>" + metadata.Artist + "</color>") : string.Empty); if (rollingTextRoutine != null) { ((MonoBehaviour)this).StopCoroutine(rollingTextRoutine); } base.text.text = string.Empty; rollingTextRoutine = ((MonoBehaviour)this).StartCoroutine(ScrollingTextUnscaled.ShowText(base.text, metadata.Title.ToUpper() + " " + text, 0.022f)); float time = 0f; while (time < panelApproachTime) { panelGroup.alpha = (active ? 1 : 0); time += Time.unscaledDeltaTime; if (time > panelApproachTime) { time = panelApproachTime; } rect.sizeDelta = startDimensions + (targetDimensions - startDimensions) * time / panelApproachTime; yield return null; } } protected override IEnumerator Await() { float time = panelStayTime; while ((double)time > 0.0 || showIndefinitely) { panelGroup.alpha = (active ? 1 : 0); if ((double)time > 0.0) { time -= Time.unscaledDeltaTime; } yield return null; } } protected override IEnumerator FadeOut() { rollingTextRoutine = ((MonoBehaviour)this).StartCoroutine(ScrollingTextUnscaled.HideText(text, 0.022f)); RectTransform rect = ((Component)panelGroup).GetComponent<RectTransform>(); float time = panelApproachTime; yield return (object)new WaitUntil((Func<bool>)(() => text.text.Length <= 20)); while ((double)time > 0.0) { panelGroup.alpha = (active ? 1 : 0); time -= Time.unscaledDeltaTime; if (time < 0f) { time = 0f; } rect.sizeDelta = startDimensions + (targetDimensions - startDimensions) * time / panelApproachTime; yield return null; } panelGroup.alpha = 0f; } } public class PlaylistSelectable : DirectoryTreeBrowser<JukeboxSong> { [SerializeField] public GameObject selectPlaylistPanel; [SerializeField] public string playlistName; [SerializeField] public Button button; [SerializeField] public GameObject empty; protected override int maxPageLength => 6; protected override IDirectoryTree<JukeboxSong> baseDirectory { get { JukeboxPlaylist val; using (StreamReader streamReader = new StreamReader(File.Open(JukeboxPlaylist.PathForPlaylist(playlistName), FileMode.OpenOrCreate))) { val = JsonConvert.DeserializeObject<JukeboxPlaylist>(streamReader.ReadToEnd()); } List<SongIdentifier> source = ((val != null) ? ((Playlist)val).ids : new List<SongIdentifier>()); return (IDirectoryTree<JukeboxSong>)(object)new FakeDirectoryTree<JukeboxSong>("Songs", from id in source where (int)id.type != 1 || File.Exists(id.path) select MonoSingleton<JukeboxSongsLoader>.Instance.Load(id), (IEnumerable<IDirectoryTree<JukeboxSong>>)null, (IDirectoryTree<JukeboxSong>)null); } } private void Awake() { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Expected O, but got Unknown ((UnityEvent)button.onClick).AddListener((UnityAction)delegate { MonoSingleton<PrefsManager>.Instance.SetStringLocal("jukebox.currentPlaylist", playlistName); MonoSingleton<JukeboxManager>.Instance.playlistEditor.ReloadPlaylist(); selectPlaylistPanel.SetActive(false); }); } private void OnEnable() { base.currentDirectory = ((DirectoryTreeBrowser<JukeboxSong>)this).baseDirectory; ((DirectoryTreeBrowser<JukeboxSong>)this).Rebuild(true); } protected override Action BuildLeaf(JukeboxSong item, int indexInPage) { GameObject go = Object.Instantiate<GameObject>(base.itemButtonTemplate, base.itemButtonTemplate.transform.parent); go.SetActive(true); go.GetComponent<Image>().sprite = item.Metadata.Icon; return delegate { Object.Destroy((Object)(object)go); }; } public override void Rebuild(bool setToPageZero = true) { base.Rebuild(setToPageZero); Transform itemParent = base.itemParent; LayoutRebuilder.ForceRebuildLayoutImmediate((RectTransform)(object)((itemParent is RectTransform) ? itemParent : null)); empty.SetActive(!base.currentDirectory.files.Any()); } } public abstract class SongPanel : MonoBehaviour { [SerializeField] public CanvasGroup panelGroup; [SerializeField] public Sprite defaultIcon; [SerializeField] public float panelApproachTime; [SerializeField] public float panelStayTime; public TMP_Text text; public Image icon; protected bool showIndefinitely; protected bool active; private Coroutine displayRoutine; protected abstract SongPanelStyle Style { get; } protected abstract IEnumerator FadeIn(JukeboxSongMetadata metadata); protected abstract IEnumerator Await(); protected abstract IEnumerator FadeOut(); public void Awake() { PrefsManager.onPrefChanged = (Action<string, object>)Delegate.Combine(PrefsManager.onPrefChanged, new Action<string, object>(OnPrefChanged)); JukeboxMusicPlayer.OnNextSong += OnNextSong; JukeboxMusicPlayer.OnStop += OnStop; showIndefinitely = MonoSingleton<PrefsManager>.Instance.GetBoolLocal("jukebox.showTrackPanelIndefinitely", false); active = MonoSingleton<PrefsManager>.Instance.GetIntLocal("jukebox.songPanelStyle", 0) == (int)Style; } public void OnDestroy() { PrefsManager.onPrefChanged = (Action<string, object>)Delegate.Remove(PrefsManager.onPrefChanged, new Action<string, object>(OnPrefChanged)); JukeboxMusicPlayer.OnNextSong -= OnNextSong; JukeboxMusicPlayer.OnStop -= OnStop; } private IEnumerator ShowPanelRoutine(JukeboxSongMetadata metadata) { string text = ((!string.IsNullOrEmpty(metadata.Artist)) ? ("<color=#999>" + metadata.Artist + "</color>") : string.Empty); this.text.text = metadata.Title.ToUpper() + " " + text; icon.sprite = (((Object)(object)metadata.Icon != (Object)null) ? metadata.Icon : defaultIcon); yield return FadeIn(metadata); yield return Await(); yield return FadeOut(); } private void OnNextSong(JukeboxSong song) { active = MonoSingleton<PrefsManager>.Instance.GetIntLocal("jukebox.songPanelStyle", 0) == (int)Style; if (displayRoutine != null) { ((MonoBehaviour)this).StopCoroutine(displayRoutine); } displayRoutine = ((MonoBehaviour)this).StartCoroutine(ShowPanelRoutine(song.Metadata)); } private void OnStop() { active = false; } private void OnPrefChanged(string key, object value) { if (key.Equals("jukebox.showTrackPanelIndefinitely")) { showIndefinitely = (bool)value; } if (key.Equals("jukebox.songPanelStyle")) { active = (int)value == (int)Style; } } } public class SongPanelOption : MonoBehaviour { private static readonly Color Active = new Color(0.68f, 0.68f, 0.68f, 0.25f); private static readonly Color Inactive = new Color(0f, 0f, 0f, 0.59f); public SongPanelStyle style; private void Start() { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) ((Graphic)((Component)this).gameObject.GetComponent<Image>()).color = ((MonoSingleton<PrefsManager>.Instance.GetIntLocal("jukebox.songPanelStyle", 0) == (int)style) ? Active : Inactive); } public void Select() { //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) Button[] componentsInChildren = ((Component)((Component)this).transform.parent).GetComponentsInChildren<Button>(); foreach (Button val in componentsInChildren) { ((Graphic)((Component)val).gameObject.GetComponent<Image>()).color = (((Object)(object)val == (Object)(object)((Component)this).gameObject.GetComponent<Button>()) ? Active : Inactive); } MonoSingleton<PrefsManager>.Instance.SetIntLocal("jukebox.songPanelStyle", (int)style); } } public enum SongPanelStyle { Jukebox, Classic } } namespace Jukebox.UI.Elements { public class Counter : MonoBehaviour { [SerializeField] private TextMeshProUGUI textValue; [SerializeField] private CounterButton increase; [SerializeField] private CounterButton decrease; [SerializeField] private int minValue; [SerializeField] private int maxValue; private int tmpValue; private IEnumerator changeValueRoutine; private int value; public int Value { get { return value; } set { this.value = value; ((TMP_Text)textValue).text = Value.ToString(); this.OnChanged?.Invoke(value); } } public event Action<int> OnChanged; public void Awake() { AddEvents(increase, delegate { tmpValue = ChangeValue((int i) => i + 1); }); AddEvents(decrease, delegate { tmpValue = ChangeValue((int i) => i - 1); }); } public void SetDefaultValue(int defaultValue) { Value = defaultValue; tmpValue = defaultValue; ((TMP_Text)textValue).text = defaultValue.ToString(); } private void AddEvents(CounterButton button, Action<int> callback) { button.OnDown += delegate { changeValueRoutine = ChangeValueRoutine(callback); ((MonoBehaviour)this).StartCoroutine(changeValueRoutine); }; button.OnUp += SaveValue; button.OnExit += SaveValue; } private void SaveValue() { if (changeValueRoutine != null) { ((MonoBehaviour)this).StopCoroutine(changeValueRoutine); } Value = tmpValue; this.OnChanged?.Invoke(Value); } private IEnumerator ChangeValueRoutine(Action<int> callback) { callback(tmpValue); yield return (object)new WaitForSecondsRealtime(0.3f); while (true) { callback(tmpValue); yield return (object)new WaitForSecondsRealtime(0.1f); } } private int ChangeValue(Func<int, int> operation) { int result = ValidateOperation(operation); ((TMP_Text)textValue).text = result.ToString(); return result; } private int ValidateOperation(Func<int, int> operation) { int num = operation(tmpValue); if (num >= minValue && num <= maxValue) { return num; } return tmpValue; } } public class CounterButton : Button { public bool pressed; public event Action OnDown; public event Action OnUp; public event Action OnExit; public override void OnPointerDown(PointerEventData eventData) { pressed = true; ((Selectable)this).OnPointerDown(eventData); this.OnDown?.Invoke(); } public override void OnPointerUp(PointerEventData eventData) { pressed = false; ((Selectable)this).OnPointerUp(eventData); this.OnUp?.Invoke(); } public override void OnPointerExit(PointerEventData eventData) { ((Selectable)this).OnPointerExit(eventData); if (pressed) { this.OnExit?.Invoke(); } pressed = false; } } } namespace Jukebox.UI.Effects { public class SoundEffectButton : MonoBehaviour { [SerializeField] private string prefsKey; [SerializeField] private TMP_Text title; [SerializeField] private TMP_Text fileNameText; [SerializeField] private TMP_Text browserWindowTitle; protected void Awake() { //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Expected O, but got Unknown ChangeFileName(MonoSingleton<PrefsManager>.Instance.GetStringLocal(prefsKey, (string)null)); PrefsManager.onPrefChanged = (Action<string, object>)Delegate.Combine(PrefsManager.onPrefChanged, new Action<string, object>(OnPrefChanged)); ((UnityEvent)((Component)this).GetComponent<Button>().onClick).AddListener((UnityAction)delegate { browserWindowTitle.text = "Select file for " + title.text; }); } protected void OnDestroy() { PrefsManager.onPrefChanged = (Action<string, object>)Delegate.Remove(PrefsManager.onPrefChanged, new Action<string, object>(OnPrefChanged)); } private void OnPrefChanged(string key, object value) { if (key.Equals(prefsKey)) { ChangeFileName((string)value); } } private void ChangeFileName(string fileName) { fileNameText.text = ((fileName != null) ? new FileInfo(fileName).Name : "Default"); } } } namespace Jukebox.UI.Decorators { public class ControlBindDecorator : MonoBehaviour { [SerializeField] public InputActionReference action; protected void Awake() { //IL_0040: Unknown result type (might be due to invalid IL or missing references) InputAction val = MonoSingleton<InputManager>.Instance.InputSource.Actions.asset.FindAction(action.ToInputAction().id); ((Component)this).GetComponentInChildren<ControlsOptionsKey>().RebuildBindings(val, MonoSingleton<InputManager>.Instance.InputSource.Actions.KeyboardMouseScheme); } } public abstract class UIDecorator<T> : MonoBehaviour where T : MonoBehaviour { [SerializeField] public GameObject hint; protected GameObject control; protected abstract GameObject Template(); protected abstract void Init(); public void Start() { //IL_0028: Unknown result type (might be due to invalid IL or missing references) control = Object.Instantiate<GameObject>(Template(), ((Component)this).transform); control.transform.position = ((Component)this).transform.position; Object.Destroy((Object)(object)hint); Init(); Object.Destroy((Object)(object)((Component)this).GetComponent<T>()); } } public class SliderDecorator : UIDecorator<SliderDecorator> { [AddressableAsset("Assets/Prefabs/UI/Settings/Elements/Slider Button.prefab", typeof(GameObject))] private static GameObject sliderTemplate; [SerializeField] public float minValue; [SerializeField] public float maxValue; [SerializeField] public SliderValueToTextConfig sliderConfig; protected override GameObject Template() { return sliderTemplate; } protected override void Init() { Slider componentInChildren = ((Component)this).GetComponentInChildren<Slider>(); componentInChildren.minValue = minValue; componentInChildren.maxValue = maxValue; ReflectionUtils.GetPrivate<SliderValueToText>(((Component)this).GetComponentInChildren<SettingsSlider>(), typeof(SettingsSlider), "sliderValueToText").ConfigureFrom(sliderConfig); } } } namespace Jukebox.Patches { [HarmonyPatch(typeof(AudioMixerController))] public static class AudioMixerControllerPatch { [HarmonyPostfix] [HarmonyPatch(typeof(AudioMixerController), "Update")] public static void AudioMixerController_Update_Postfix(AudioMixerController __instance) { if (!((Object)(object)MonoSingleton<JukeboxManager>.Instance == (Object)null)) { __instance.musicSound.SetFloat("allVolume", __instance.CalculateVolume(__instance.musicVolume) + MonoSingleton<JukeboxManager>.Instance.player.VolumeBoost); } } } [HarmonyPatch(typeof(DiscordController))] public static class DiscordControllerPatch { [Serializable] [CompilerGenerated] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static UpdateActivityHandler <>9__0_0; internal void <DiscordController_UpdateWave_Prefix>b__0_0(Result _) { } } [HarmonyPrefix] [HarmonyPatch(typeof(DiscordController), "UpdateWave")] public static bool DiscordController_UpdateWave_Prefix(int wave) { //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Expected O, but got Unknown if (JukeboxMusicPlayer.CurrentSong == null || !MonoSingleton<PrefsManager>.Instance.GetBoolLocal("jukebox.discordAndSteamIntegration", false)) { return true; } if ((Object)(object)DiscordController.Instance == (Object)null) { return false; } bool @private = ReflectionUtils.GetPrivate<bool>(DiscordController.Instance, typeof(DiscordController), "disabled"); Activity private2 = ReflectionUtils.GetPrivate<Activity>(DiscordController.Instance, typeof(DiscordController), "cachedActivity"); ActivityManager private3 = ReflectionUtils.GetPrivate<ActivityManager>(DiscordController.Instance, typeof(DiscordController), "activityManager"); Discord private4 = ReflectionUtils.GetPrivate<Discord>(DiscordController.Instance, typeof(DiscordController), "discord"); if (@private) { return false; } private2.Details = $"WAVE: {wave} | \ud83c\udfb5 {JukeboxMusicPlayer.CurrentSong.ArtistAndTrack}"; ReflectionUtils.SetPrivate<DiscordController, Activity>(DiscordController.Instance, typeof(DiscordController), "cachedActivity", private2); if (private4 == null || private3 == null) { return false; } Activity val = private2; object obj = <>c.<>9__0_0; if (obj == null) { UpdateActivityHandler val2 = delegate { }; <>c.<>9__0_0 = val2; obj = (object)val2; } private3.UpdateActivity(val, (UpdateActivityHandler)obj); return false; } } [HarmonyPatch(typeof(FinalCyberRank))] public static class FinalCyberRankPatch { [HarmonyPrefix] [HarmonyPatch(typeof(FinalCyberRank), "GameOver")] public static bool FinalCyberRank_GameOver_Prefix() { if ((Object)(object)MonoSingleton<JukeboxManager>.Instance.player != (Object)null) { MonoSingleton<JukeboxManager>.Instance.player.Stop(); } return true; } } [HarmonyPatch(typeof(InputActions))] public static class InputActionsPatch { [HarmonyPostfix] [HarmonyPatch(/*Could not decode attribute arguments.*/)] public static void InputActions_Constructor_Postfix(InputActions __instance) { if (__instance.asset.FindActionMap("Jukebox", false) == null) { MergeInputActionAssets(__instance); } } private static void MergeInputActionAssets(InputActions ukInputActions) { if (Resources.FindObjectsOfTypeAll(typeof(InputActionAsset)).Length == 0) { Debug.LogError((object)"Couldn't load InputActionAsset"); return; } string text = "{\r\n \"maps\": [\r\n {\r\n \"name\": \"Jukebox\",\r\n \"id\": \"9dda5277-7734-4ec3-ad76-c8c0e5763d02\",\r\n \"actions\": [\r\n {\r\n \"name\": \"Next Track\",\r\n \"type\": \"Button\",\r\n \"id\": \"09c701ba-74bc-4818-80a7-d1049e88ed97\",\r\n \"expectedControlType\": \"Button\",\r\n \"processors\": \"\",\r\n \"interactions\": \"\",\r\n \"initialStateCheck\": false\r\n },\r\n {\r\n \"name\": \"Jukebox Menu\",\r\n \"type\": \"Button\",\r\n \"id\": \"2031a43b-3913-4384-a334-02669e72c30d\",\r\n \"expectedControlType\": \"Button\",\r\n \"processors\": \"\",\r\n \"interactions\": \"\",\r\n \"initialStateCheck\": false\r\n },\r\n {\r\n \"name\": \"Disable Player\",\r\n \"type\": \"Button\",\r\n \"id\": \"3675ceba-90d0-46f5-b634-d6c13d208ff6\",\r\n \"expectedControlType\": \"Button\",\r\n \"processors\": \"\",\r\n \"interactions\": \"\",\r\n \"initialStateCheck\": false\r\n },\r\n {\r\n \"name\": \"Playback Menu\",\r\n \"type\": \"Button\",\r\n \"id\": \"fa8430f8-91e7-454b-91f7-8b0147642ef9\",\r\n \"expectedControlType\": \"Button\",\r\n \"processors\": \"\",\r\n \"interactions\": \"\",\r\n \"initialStateCheck\": false\r\n }\r\n ],\r\n \"bindings\": [\r\n {\r\n \"name\": \"\",\r\n \"id\": \"8ec3310e-3f25-46a8-9a97-347d624fb616\",\r\n \"path\": \"<Keyboard>/f3\",\r\n \"interactions\": \"\",\r\n \"processors\": \"\",\r\n \"groups\": \"Keyboard & Mouse\",\r\n \"action\": \"Next Track\",\r\n \"isComposite\": false,\r\n \"isPartOfComposite\": false\r\n },\r\n {\r\n \"name\": \"\",\r\n \"id\": \"b6df442f-c08f-4187-940a-9b684fa729c5\",\r\n \"path\": \"<Keyboard>/f4\",\r\n \"interactions\": \"\",\r\n \"processors\": \"\",\r\n \"groups\": \"Keyboard & Mouse\",\r\n \"action\": \"Jukebox Menu\",\r\n \"isComposite\": false,\r\n \"isPartOfComposite\": false\r\n },\r\n {\r\n \"name\": \"\",\r\n \"id\": \"48676d48-feb2-406e-bc66-91f1aa7b11f1\",\r\n \"path\": \"<Keyboard>/backquote\",\r\n \"interactions\": \"\",\r\n \"processors\": \"\",\r\n \"groups\": \"Keyboard & Mouse\",\r\n \"action\": \"Playback Menu\",\r\n \"isComposite\": false,\r\n \"isPartOfComposite\": false\r\n },\r\n {\r\n \"name\": \"\",\r\n \"id\": \"b86c9dc7-c6a1-4490-8aaa-bcb7dc1aa3cd\",\r\n \"path\": \"<Keyboard>/f10\",\r\n \"interactions\": \"\",\r\n \"processors\": \"\",\r\n \"groups\": \"Keyboard & Mouse\",\r\n \"action\": \"Disable Player\",\r\n \"isComposite\": false,\r\n \"isPartOfComposite\": false\r\n }\r\n ]\r\n }\r\n ]\r\n }"; InputActionSetupExtensions.AddActionMap(ukInputActions.asset, InputActionMap.FromJson(text)[0]); } } [HarmonyPatch(typeof(InputManager))] public static class InputManagerPatch { [HarmonyPrefix] [HarmonyPatch(typeof(InputManager), "Rebind")] public static bool InputManager_Rebind_Prefix(InputManager __instance, InputAction action, int? existingIndex, Action onComplete, Action onCancel, InputControlScheme scheme) { //IL_001c: 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_0074: Unknown result type (might be due to invalid IL or missing references) if (action.actionMap.name != "Jukebox") { return true; } __instance.WaitForButton((Action<string>)delegate(string path) { //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: 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) if (path == "<Mouse>/leftButton") { onComplete?.Invoke(); } else if (((IEnumerable<InputBinding>)(object)action.bindings).Any((InputBinding binding) => InputSystem.FindControl(((InputBinding)(ref binding)).path) == InputSystem.FindControl(path))) { onComplete?.Invoke(); } else { BindingSyntax val = ((!existingIndex.HasValue) ? InputActionSetupExtensions.AddBinding(action, default(InputBinding)) : InputActionSetupExtensions.ChangeBinding(action, existingIndex.GetValueOrDefault())); val = ((BindingSyntax)(ref val)).WithPath(path); ((BindingSyntax)(ref val)).WithGroup(((InputControlScheme)(ref scheme)).bindingGroup); __instance.actionModified?.Invoke(action); if (onComplete != null) { onComplete(); } } }, (Action)delegate { onCancel?.Invoke(); }, ((IEnumerable<DeviceRequirement>)(object)((InputControlScheme)(ref scheme)).deviceRequirements).Select((DeviceRequirement requirement) => ((DeviceRequirement)(ref requirement)).controlPath).ToList()); return false; } } [HarmonyPatch(typeof(ScreenZone))] public static class ScreenZonePatch { private static PreviewHelper _helper; private static ScreenZone _cgTerminal; [HarmonyPostfix] [HarmonyPatch(typeof(ScreenZone), "Awake")] public static void ScreenZone_Awake_Postfix(ScreenZone __instance) { if (!(((Object)__instance).name != "Cybergrind Shop")) { PreviewHelper previewHelper = default(PreviewHelper); if (!((Component)__instance).TryGetComponent<PreviewHelper>(ref previewHelper)) { ((Component)__instance).gameObject.AddComponent<PreviewHelper>(); } _cgTerminal = __instance; } } [HarmonyPrefix] [HarmonyPatch(typeof(ScreenZone), "Update")] public static bool ScreenZone_Update_Prefix(bool ___inZone, ScreenZone __instance) { if ((Object)(object)_cgTerminal != (Object)(object)__instance) { return true; } if ((Object)(object)_helper == (Object)null) { PreviewHelper helper = default(PreviewHelper); if (!((Component)__instance).TryGetComponent<PreviewHelper>(ref helper)) { return true; } _helper = helper; } _helper.inZone = ___inZone; return true; } } [HarmonyPatch(typeof(SteamController))] public static class SteamControllerPatch { [HarmonyPrefix] [HarmonyPatch(typeof(SteamController), "UpdateWave")] public static bool SteamController_UpdateWave_Prefix(int wave) { if (JukeboxMusicPlayer.CurrentSong == null || !MonoSingleton<PrefsManager>.Instance.GetBoolLocal("jukebox.discordAndSteamIntegration", false)) { return true; } if (!SteamClient.IsValid) { return false; } SteamFriends.SetRichPresence("wave", $"WAVE: {wave} | \ud83c\udfb5 {JukeboxMusicPlayer.CurrentSong.ArtistAndTrack}"); return false; } } } namespace Jukebox.Input { [ConfigureSingleton(/*Could not decode attribute arguments.*/)] public class JukeboxInputs : MonoSingleton<JukeboxInputs> { private InputActionMap jukeboxActionMap; public InputAction Menu { get; private set; } public InputAction Playback { get; private set; } public InputAction NextTrack { get; private set; } public InputAction DisablePlayer { get; private set; } protected void Awake() { base.Awake(); jukeboxActionMap = MonoSingleton<InputManager>.Instance.InputSource.Actions.asset.FindActionMap("Jukebox", false); Menu = jukeboxActionMap.FindAction("Jukebox Menu", false); Playback = jukeboxActionMap.FindAction("Playback Menu", false); NextTrack = jukeboxActionMap.FindAction("Next Track", false); DisablePlayer = jukeboxActionMap.FindAction("Disable Player", false); } } } namespace Jukebox.Components { public class CybergrindEffectsChanger : MonoBehaviour { private const string TerminalPath = "/FirstRoom/Room/Cybergrind Shop/Music"; private CrowdReactions crowdReactions; private PrefsManager prefsManager; private AudioClip awwDefault; private AudioClip cheerDefault; private AudioClip cheerLongDefault; private AudioClip terminalMusicDefault; private AudioClip gameOverDefault; private static AudioSource EndMusicAudioSource { get { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) Scene activeScene = SceneManager.GetActiveScene(); return ((Scene)(ref activeScene)).GetRootGameObjects().First((GameObject o) => ((Object)o).name == "EndMusic").GetComponent<AudioSource>(); } } private static AudioSource MenuMusicAudioSource => GameObject.Find("/FirstRoom/Room/Cybergrind Shop/Music").GetComponent<AudioSource>(); private void Awake() { crowdReactions = MonoSingleton<CrowdReactions>.Instance; prefsManager = MonoSingleton<PrefsManager>.Instance; awwDefault = Object.Instantiate<AudioClip>(crowdReactions.aww, ((Component)this).gameObject.transform); cheerDefault = Object.Instantiate<AudioClip>(crowdReactions.cheer, ((Component)this).gameObject.transform); cheerLongDefault = Object.Instantiate<AudioClip>(crowdReactions.cheerLong, ((Component)this).gameObject.transform); terminalMusicDefault = Object.Instantiate<AudioClip>(MenuMusicAudioSource.clip, ((Component)this).gameObject.transform); gameOverDefault = Object.Instantiate<AudioClip>(EndMusicAudioSource.clip, ((Component)this).gameObject.transform); ((MonoBehaviour)this).StartCoroutine(Setup()); PrefsManager.onPrefChanged = (Action<string, object>)Delegate.Combine(PrefsManager.onPrefChanged, new Action<string, object>(OnPrefChanged)); } private void OnDestroy() { PrefsManager.onPrefChanged = (Action<string, object>)Delegate.Remove(PrefsManager.onPrefChanged, new Action<string, object>(OnPrefChanged)); } private IEnumerator Setup() { yield return PrepareParrySfx(); yield return PrepareWaveCompleteSfx(); yield return PrepareAwwSfx(); yield return PrepareGameOverSfx(); yield return PrepareTerminalMusic(); } private IEnumerator PrepareParrySfx() { yield return PrepareClip(prefsManager.GetStringLocal("jukebox.effects.parry", (string)null), delegate(AudioClip clip) { crowdReactions.cheer = clip; }, cheerDefault); } private IEnumerator PrepareWaveCompleteSfx() { yield return PrepareClip(prefsManager.GetStringLocal("jukebox.effects.wavecomplete", (string)null), delegate(AudioClip clip) { crowdReactions.cheerLong = clip; }, cheerLongDefault); } private IEnumerator PrepareAwwSfx() { yield return PrepareClip(prefsManager.GetStringLocal("jukebox.effects.aww", (string)null), delegate(AudioClip clip) { crowdReactions.aww = clip; }, awwDefault); } private IEnumerator PrepareGameOverSfx() { yield return PrepareClip(prefsManager.GetStringLocal("jukebox.effects.gameover", (string)null), delegate(AudioClip clip) { EndMusicAudioSource.clip = clip; }, gameOverDefault); } private IEnumerator PrepareTerminalMusic() { AudioSource terminalMusic = MenuMusicAudioSource; yield return PrepareClip(prefsManager.GetStringLocal("jukebox.effects.terminal-music", (string)null), delegate(AudioClip clip) { terminalMusic.Stop(); terminalMusic.volume = 1f; terminalMusic.clip = clip; terminalMusic.Play(); }, terminalMusicDefault); } private IEnumerator PrepareClip(string path, Action<AudioClip> callback, AudioClip fallback) { if (path != null) { yield return Download(new FileInfo(path), callback); } else { callback(fallback); } } private IEnumerator Download(FileSystemInfo path, Action<AudioClip> callback) { DownloadHandlerAudioClip handler = new DownloadHandlerAudioClip(new Uri(path.FullName).AbsoluteUri, CustomMusicFileBrowser.extensionTypeDict[path.Extension.ToLower()]); UnityWebRequest wr = new UnityWebRequest(new Uri(path.FullName).AbsoluteUri, "GET", (DownloadHandler)(object)handler, (UploadHandler)null); try { yield return wr.SendWebRequest(); if (wr.responseCode == 200) { callback(handler.audioClip); } } finally { ((IDisposable)wr)?.Dispose(); } } private void OnPrefChanged(string key, object value) { switch (key) { case "jukebox.effects.wavecomplete": ((MonoBehaviour)this).StartCoroutine(PrepareWaveCompleteSfx()); break; case "jukebox.effects.aww": ((MonoBehaviour)this).StartCoroutine(PrepareAwwSfx()); break; case "jukebox.effects.gameover": ((MonoBehaviour)this).StartCoroutine(PrepareGameOverSfx()); break; case "jukebox.effects.terminal-music": ((MonoBehaviour)this).StartCoroutine(PrepareTerminalMusic()); break; case "jukebox.effects.parry": ReflectionUtils.GetPrivate<AudioSource>(crowdReactions, typeof(CrowdReactions), "aud").Stop(); ((MonoBehaviour)this).StartCoroutine(PrepareParrySfx()); break; } } } public class JukeboxEffectsBrowser : DirectoryTreeBrowser<FileInfo> { private static readonly DirectoryInfo EffectsDirectory = new DirectoryInfo(Path.Combine(PathsUtils.ApplicationPath, "Cybergrind", "Effects")); [SerializeField] private JukeboxTerminalPanel navigator; [SerializeField] private GameObject effectsMenu; private string currentPrefKey; protected override int maxPageLength => 3; protected override IDirectoryTree<FileInfo> baseDirectory => (IDirectoryTree<FileInfo>)new FileDirectoryTree(EffectsDirectory, (IDirectoryTree<FileInfo>)null); public void NextPage() { base.SetPage((base.currentPage != base.maxPages - 1) ? (base.currentPage + 1) : 0); } public void PreviousPage() { base.SetPage((base.currentPage == 0) ? (base.maxPages - 1) : (base.currentPage - 1)); } public void SetCurrentPrefKey(string key) { currentPrefKey = key; } public void ResetToDefault() { MonoSingleton<PrefsManager>.Instance.SetStringLocal(currentPrefKey, (string)null); } protected override Action BuildLeaf(FileInfo item, int indexInPage) { //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Expected O, but got Unknown GameObject go = Object.Instantiate<GameObject>(base.itemButtonTemplate, base.itemParent); CustomContentButton component = go.GetComponent<CustomContentButton>(); component.text.text = item.Name; go.SetActive(true); ((UnityEvent)component.button.onClick).AddListener((UnityAction)delegate { MonoSingleton<PrefsManager>.Instance.SetStringLocal(currentPrefKey, item.FullName); navigator.GoToNoMenu(effectsMenu); }); return delegate { Object.Destroy((Object)(object)go); }; } public void OpenEffectsFolder() { Application.OpenURL(new Uri(EffectsDirectory.FullName).AbsoluteUri); } public override void Rebuild(bool setToPageZero = true) { Transform itemParent = base.itemParent; LayoutRebuilder.ForceRebuildLayoutImmediate((RectTransform)(object)((itemParent is RectTransform) ? itemParent : null)); base.Rebuild(setToPageZero); } } public class JukeboxMusicChanger : MonoBehaviour { private enum ThemeVariation { Battle, Calm } private const int FadeSpeed = 1; public AudioSource clean; public AudioSource battle; private JukeboxThemesManager themesManager; private Coroutine updateRoutine; private ThemeVariation currentTheme; private static bool CalmThemesAllowed => MonoSingleton<PrefsManager>.Instance.GetBoolLocal("jukebox.enableCalmThemes", false); public void Awake() { themesManager = MonoSingleton<JukeboxThemesManager>.Instance; } private void Update() { if (!((Object)(object)clean.clip == (Object)null)) { if (currentTheme == ThemeVariation.Calm) { clean.volume = Mathf.MoveTowards(clean.volume, 1f, 1f * Time.deltaTime); battle.volume = Mathf.MoveTowards(battle.volume, 0f, 1f * Time.deltaTime); } else { clean.volume = Mathf.MoveTowards(clean.volume, 0f, 1f * Time.deltaTime); battle.volume = Mathf.MoveTowards(battle.volume, 1f, 1f * Time.deltaTime); } } } public void ChangeTo(AudioClip battleTheme, AudioClip calmTheme) { if (updateRoutine != null) { ((MonoBehaviour)this).StopCoroutine(updateRoutine); } battle.time = 0f; clean.time = 0f; clean.clip = calmTheme; battle.clip = battleTheme; battle.Play(); battle.volume = 1f; if ((Object)(object)clean.clip != (Object)null) { clean.Play(); if (CalmThemesAllowed && themesManager.FewEnemies) { clean.volume = 1f; battle.volume = 0f; } } updateRoutine = ((MonoBehaviour)this).StartCoroutine(SlowUpdate()); } private IEnumerator SlowUpdate() { while (true) { if (CalmThemesAllowed && themesManager.FewEnemies) { PlayCalmTheme(); } else { PlayBattleTheme(); } yield return (object)new WaitForSecondsRealtime(0.1f); } } private void PlayBattleTheme() { if (currentTheme != 0) { currentTheme = ThemeVariation.Battle; if ((Object)(object)clean.clip != (Object)null) { battle.timeSamples = clean.timeSamples; } } } private void PlayCalmTheme() { if (currentTheme != ThemeVariation.Calm) { currentTheme = ThemeVariation.Calm; if ((Object)(object)clean.clip != (Object)null) { clean.timeSamples = battle.timeSamples; } } } } public class JukeboxThemesManager : MonoSingleton<JukeboxThemesManager> { private static readonly string PreferencesPath = Path.Combine(Directory.GetParent(Application.dataPath).FullName, "Preferences", "JukeboxThemes.json"); private PrefsManager prefsManager; private EnemyTracker enemyTracker; private JukeboxThemesConfig preferences = new JukeboxThemesConfig(); private bool isDirty; public bool FewEnemies { get { if (EnemiesAlive <= CalmThemeThreshold) { return SpecialEnemiesThresholdReached(); } return false; } } private int CalmThemeThreshold => prefsManager.GetIntLocal("jukebox.calmThemeEnemiesThreshold", 0); private int EnemiesAlive => enemyTracker.enemies.Count((EnemyIdentifier enemy) => !enemy.dead); protected override void Awake() { base.Awake(); prefsManager = MonoSingleton<PrefsManager>.Instance; enemyTracker = MonoSingleton<EnemyTracker>.Instance; LoadPreferences(); ((MonoBehaviour)this).InvokeRepeating("SlowUpdate", 0f, 3f); } private void SlowUpdate() { if (isDirty) { SavePreferences(); isDirty = false; } } protected override void OnDestroy() { SavePreferences(); isDirty = false; base.OnDestroy(); } public int? GetThresholdFor(EnemyType type, bool radiant = false) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) Dictionary<EnemyType, int> dictionary = (radiant ? preferences.calmTheme.specialRadiantEnemies : preferences.calmTheme.specialEnemies); if (!dictionary.ContainsKey(type)) { return null; } return dictionary[type]; } public void SetThresholdFor(EnemyType type, int value, bool radiant = false) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) (radiant ? preferences.calmTheme.specialRadiantEnemies : preferences.calmTheme.specialEnemies)[type] = value; isDirty = true; } public void DisableThresholdFor(EnemyType type, bool radiant) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) Dictionary<EnemyType, int> dictionary = (radiant ? preferences.calmTheme.specialRadiantEnemies : preferences.calmTheme.specialEnemies); if (dictionary.ContainsKey(type)) { dictionary.Remove(type); } isDirty = true; } private bool SpecialEnemiesThresholdReached() { return (from enemy in enemyTracker.enemies where !enemy.dead group enemy by new { enemy.enemyType, enemy.hasRadianceEffected }).All(group => { //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0023: 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_0045: Unknown result type (might be due to invalid IL or missing references) if (group.Key.hasRadianceEffected) { if (preferences.calmTheme.specialRadiantEnemies.ContainsKey(group.Key.enemyType)) { return preferences.calmTheme.specialRadiantEnemies[group.Key.enemyType] >= group.Count(); } return true; } return !preferences.calmTheme.specialEnemies.ContainsKey(group.Key.enemyType) || preferences.calmTheme.specialEnemies[group.Key.enemyType] >= group.Count(); }); } private void LoadPreferences() { JukeboxThemesConfig val; using (StreamReader streamReader = new StreamReader(File.Open(PreferencesPath, FileMode.OpenOrCreate))) { val = JsonConvert.DeserializeObject<JukeboxThemesConfig>(streamReader.ReadToEnd()); } if (val?.calmTheme == null) { SavePreferences(); } else { preferences = val.Equalize(); } isDirty = true; } private void SavePreferences() { File.WriteAllText(PreferencesPath, JsonConvert.SerializeObject((object)preferences)); } } public class DeckShuffled<T> : IEnumerable<T>, IEnumerable { private List<T> current; public DeckShuffled(IEnumerable<T> target) { current = Randomize(target).ToList(); } public void Reshuffle() { if (current.Count > 1) { IEnumerable<T> source = current.Take(Mathf.FloorToInt((float)(current.Count / 2))); IEnumerable<T> source2 = current.Skip(Mathf.FloorToInt((float)(current.Count / 2))); current = Randomize(source).Concat(Randomize(source2)).ToList(); } } private static IEnumerable<T> Randomize(IEnumerable<T> source) { T[] arr = source.ToArray(); int i = arr.Length - 1; while (i > 0) { int swapIndex = Random.Range(0, i + 1); yield return arr[swapIndex]; arr[swapIndex] = arr[i]; int num = i - 1; i = num; } yield return arr[0]; } public IEnumerator<T> GetEnumerator() { return current.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return current.GetEnumerator(); } } public class JukeboxFileBrowser : DirectoryTreeBrowser<JukeboxSong> { [SerializeField] private JukeboxTerminalPanel navigator; [SerializeField] private JukeboxPlaylistEditor playlistEditorLogic; [SerializeField] private GameObject playlistEditor; [Header("Load all warning")] [SerializeField] private TMP_Text loadAllWarningText; [SerializeField] private GameObject yesAndNoButtons; [SerializeField] private GameObject imADumbassButton; [SerializeField] private Sprite youtubeIcon; protected override int maxPageLength => 4; protected override IDirectoryTree<JukeboxSong> baseDirectory => (IDirectoryTree<JukeboxSong>)new JukeboxFileTree(PathsUtils.MusicPath, (IDirectoryTree<JukeboxSong>)null); public void NextPage() { base.SetPage((base.currentPage != base.maxPages - 1) ? (base.currentPage + 1) : 0); } public void PreviousPage() { base.SetPage((base.currentPage == 0) ? (base.maxPages - 1) : (base.currentPage - 1)); } public void LoadAllFromCurrentFolder() { foreach (JukeboxSong file in base.currentDirectory.files) { playlistEditorLogic.playlist.Add(file.Id); } ((DirectoryTreeBrowser<JukeboxSong>)playlistEditorLogic).Rebuild(true); } public void SetWarningText() { if (!base.currentDirectory.files.Any()) { yesAndNoButtons.SetActive(false); imADumbassButton.SetActive(true); loadAllWarningText.text = ((!base.currentDirectory.children.Any()) ? "Oh, I get it. \"Yes, I would like to add a whopping total of 0 songs\". Very funny." : "This folder contains no songs."); } else if (base.currentDirectory.files.Count() == 1) { loadAllWarningText.text = "It's a single song in there, but ok. Would you like me to add it?"; } else { loadAllWarningText.text = $"Do you want to add <color=green>{base.currentDirectory.files.Count()}</color> tracks " + "from the folder <color=yellow>" + base.currentDirectory.name + "</color> to your playlist?"; } } public void Refresh() { ((DirectoryTreeBrowser<JukeboxSong>)this).baseDirectory.Refresh(); ((DirectoryTreeBrowser<JukeboxSong>)this).Rebuild(true); } protected override Action BuildLeaf(JukeboxSong song, int indexInPage) { //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Expected O, but got Unknown GameObject go = Object.Instantiate<GameObject>(base.itemButtonTemplate, base.itemParent, false); JukeboxCustomContentButton component = go.GetComponent<JukeboxCustomContentButton>(); JukeboxSongMetadata metadata = song.Metadata; ((UnityEvent)((CustomContentButton)component).button.onClick).AddListener((UnityAction)delegate { int count = ((Playlist)playlistEditorLogic.playlist).Count; int page = ((DirectoryTreeBrowser<JukeboxSong>)playlistEditorLogic).PageOf(count); playlistEditorLogic.playlist.Add(song.Id); ((DirectoryTreeBrowser<JukeboxSong>)playlistEditorLogic).SetPage(page); playlistEditorLogic.Select(count); navigator.GoToNoMenu(playlistEditor); }); string text = ((!string.IsNullOrEmpty(metadata.Artist)) ? ("<color=#gray>" + metadata.Artist + "</color>") : string.Empty); ((CustomContentButton)component).text.text = metadata.Title + " " + text; ((CustomContentButton)component).icon.sprite = metadata.Icon; component.introAndLoopIcon.SetActive(metadata.Composite.GotIntroAndLoop); component.calmThemeIcon.SetActive(metadata.Composite.GotCalmTheme || metadata.Composite.GotCalmLoop || metadata.Composite.GotCalmIntro); go.SetActive(true); return delegate { Object.Destroy((Object)(object)go); }; } protected override Action BuildDirectory(IDirectoryTree<JukeboxSong> folder, int indexInPage) { //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Expected O, but got Unknown GameObject btn = Object.Instantiate<GameObject>(base.folderButtonTemplate, base.itemParent, false); ((UnityEventBase)btn.GetComponent<Button>().onClick).RemoveAllListeners(); ((UnityEvent)btn.GetComponent<Button>().onClick).AddListener((UnityAction)delegate { base.StepDown(folder); }); btn.GetComponentInChildren<TMP_Text>().text = folder.name; btn.SetActive(true); if (folder.name == "YouTube" && folder.parent?.parent == null) { ((Component)btn.transform.Find("Icon")).GetComponent<Image>().sprite = youtubeIcon; } return delegate { Object.Destroy((Object)(object)btn); }; } } [ConfigureSingleton(/*Could not decode attribute arguments.*/)] public class JukeboxManager : MonoSingleton<JukeboxManager> { private const string CanvasPath = "/Canvas"; private const string CybergrindShopPath = "/FirstRoom/Room/Cybergrind Shop"; private const string PanelPath = "/FirstRoom/Room/Cybergrind Shop/Canvas/Background/Main Panel"; [SerializeField] public GameObject songPanel; [SerializeField] public JukeboxPlaylistEditor playlistEditor; [SerializeField] public JukeboxMusicPlayer player; [SerializeField] private GameObject terminalPanel; [SerializeField] private GameObject musicLogic; [SerializeField] private GameObject musicChanger; protected void Awake() { base.Awake(); ReplaceOriginalLogic(); SetupTerminal(); SetupSongPanel(); } private void SetupTerminal() { GameObject val = GameObject.Find("/FirstRoom/Room/Cybergrind Shop/Canvas/Background/Main Panel"); terminalPanel.transform.SetParent(val.transform, false); } private void ReplaceOriginalLogic() { Transform val = GameObject.Find("/FirstRoom/Room/Cybergrind Shop").transform.Find("Logic"); Object.Destroy((Object)(object)((Component)val.Find("Music")).gameObject); musicLogic.transform.parent = val; CustomMusicPlayer obj = Resources.FindObjectsOfTypeAll<CustomMusicPlayer>()[0]; Transform parent = ((Component)obj).transform.parent; Object.Destroy((Object)(object)((Component)obj).gameObject); musicChanger.transform.parent = ((Component)parent).transform; } private void SetupSongPanel() { GameObject val = GameObject.Find("/Canvas"); Object.Destroy((Object)(object)((Component)val.transform.Find("SongPanel")).gameObject); songPanel.transform.SetParent(val.transform, false); } } public class JukeboxMusicPlayer : MonoBehaviour { [SerializeField] private JukeboxPlaylistEditor playlistEditor; [SerializeField] private JukeboxSongsLoader loader; [SerializeField] private JukeboxMusicChanger changer; private Coroutine playlistRoutine; private bool forcedChange; private bool stopped; private bool allowVolumeBoost; private static float VolumeBoostValue => MonoSingleton<PrefsManager>.Instance.GetFloatLocal("jukebox.volumeBoost", 0f); private static bool AlwaysPlayIntro => MonoSingleton<PrefsManager>.Instance.GetBoolLocal("jukebox.alwaysPlayIntro", false); private static bool IndividualBoostPerTrack => MonoSingleton<PrefsManager>.Instance.GetBoolLocal("jukebox.individualBoostPerTrack", false); public AudioSource Source => changer.battle; public static JukeboxSong CurrentSong { get; private set; } public static int CurrentSongIndex { get; private set; } public float VolumeBoost { get; private set; } public static event Action<JukeboxSong> OnNextSong; public static event Action<IEnumerable<SongIdentifier>> OnOrderChange; public static event Action OnStop; public void Awake() { changer = ((Component)this).gameObject.GetComponent<JukeboxMusicChanger>(); PrefsManager.onPrefChanged = (Action<string, object>)Delegate.Combine(PrefsManager.onPrefChanged, new Action<string, object>(OnPrefChanged)); MonoSingleton<JukeboxInputs>.Instance.DisablePlayer.performed += OnPlayerDisabled; } public void OnDestroy() { CurrentSong = null; PrefsManager.onPrefChanged = (Action<string, object>)Delegate.Remove(PrefsManager.onPrefChanged, new Action<string, object>(OnPrefChanged)); MonoSingleton<JukeboxInputs>.Instance.DisablePlayer.performed -= OnPlayerDisabled; } public void OnEnable() { StartPlaylist(); } public void StartPlaylist() { stopped = false; if (((Playlist)playlistEditor.playlist).Count < 1) { Debug.LogError((object)"No songs in playlist, somehow. Not starting playlist routine..."); } else { playlistRoutine = ((MonoBehaviour)this).StartCoroutine(PlaylistRoutine()); } } public void Stop() { stopped = true; } public void StopPlaylist() { Source.Stop(); ((MonoBehaviour)this).StopCoroutine(playlistRoutine); CurrentSong = null; stopped = true; } public void ChangeTrack(int index) { CurrentSongIndex = index; forcedChange = true; } private IEnumerator PlaylistRoutine() { WaitUntil songFinished = new WaitUntil((Func<bool>)(() => ((!Source.isPlaying && Application.isFocused) || MonoSingleton<JukeboxInputs>.Instance.NextTrack.WasPerformedThisFrame() || forcedChange) && !stopped)); bool firstSong2 = true; JukeboxPlaylist playlist = playlistEditor.playlist; IEnumerable<SongIdentifier> shuffled = (((Playlist)playlist).shuffled ? new DeckShuffled<SongIdentifier>(((Playlist)playlist).ids).AsEnumerable() : ((Playlist)playlist).ids.AsEnumerable()); while (!stopped) { if (shuffled is DeckShuffled<SongIdentifier> deckShuffled) { deckShuffled.Reshuffle(); } List<SongIdentifier> currentOrder = shuffled.ToList(); JukeboxMusicPlayer.OnOrderChange?.Invoke(currentOrder); CurrentSongIndex = (((int)((Playlist)playlist).loopMode == 1) ? currentOrder.FindIndex((SongIdentifier id) => object.Equals(id, ((Playlist)playlist).ids[((Playlist)playlist).selected])) : 0); while (CurrentSongIndex < currentOrder.Count) { forcedChange = false; SongIdentifier val = currentOrder[CurrentSongIndex]; JukeboxSong song = loader.Load(val); NextSong(song); PresenceController.UpdateCyberGrindWave(MonoSingleton<EndlessGrid>.Instance.currentWave); yield return song.Acquire(Play(firstSong2)); firstSong2 = false; CurrentSongIndex++; IEnumerator Play(bool firstSong) { if ((firstSong || AlwaysPlayIntro) && (Object)(object)song.IntroClip != (Object)null) { changer.ChangeTo(song.IntroClip, song.CalmIntroClip); yield return songFinished; } int clipsPlayed = 0; for (int i = 0; i < song.Clips.Count; i++) { if (stopped) { break; } do { JukeboxMusicChanger jukeboxMusicChanger = changer; AudioClip battleTheme = song.Clips[i]; List<AudioClip> calmClips = song.CalmClips; jukeboxMusicChanger.ChangeTo(battleTheme, (calmClips != null && calmClips.Count > i) ? song.CalmClips[i] : null); yield return songFinished; int num = clipsPlayed + 1; clipsPlayed = num; } while ((int)((Playlist)playlist).loopMode == 1 && !stopped && !forcedChange && !MonoSingleton<JukeboxInputs>.Instance.NextTrack.WasPerformedThisFrame()); if ((int)((Playlist)playlist).loopMode != 1 && song.MaxClipsIfNotRepeating > 0 && clipsPlayed >= song.MaxClipsIfNotRepeating) { break; } } } } } } private void OnPlayerDisabled(CallbackContext _) { if (!stopped) { StopPlaylist(); JukeboxMusicPlayer.OnStop?.Invoke(); } else { StartPlaylist(); } } private void OnPrefChanged(string key, object value) { if (!(key == "jukebox.volumeBoost")) { if (key == "jukebox.individualBoostPerTrack") { VolumeBoost = CalculateBoostFor(CurrentSong); } return; } if (IndividualBoostPerTrack) { JukeboxSong currentSong = CurrentSong; if (currentSong != null && currentSong.IsCustom) { MonoSingleton<JukeboxVolumeManager>.Instance.SetVolumeBoostFor(CurrentSong.Id.path, (float)value); } } VolumeBoost = (float)value; } private void NextSong(JukeboxSong song) { CurrentSong = song; allowVolumeBoost = song.IsCustom; VolumeBoost = CalculateBoostFor(song); JukeboxMusicPlayer.OnNextSong?.Invoke(song); } private float CalculateBoostFor(JukeboxSong song) { if (!allowVolumeBoost) { return 0f; } if (!IndividualBoostPerTrack) { return VolumeBoostValue; } if (song != null) { float? volumeBoostFor = MonoSingleton<JukeboxVolumeManager>.Instance.GetVolumeBoostFor(song.Id.path); if (volumeBoostFor.HasValue) { return volumeBoostFor.GetValueOrDefault(); } } return VolumeBoostValue; } } [ConfigureSingleton(/*Could not decode attribute arguments.*/)] public class JukeboxPauseManager : MonoSingleton<JukeboxPauseManager> { public void Pause(string stateKey, GameObject window) { //IL_0031: 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_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Expected O, but got Unknown ((Behaviour)MonoSingleton<NewMovement>.Instance).enabled = false; MonoSingleton<CameraController>.Instance.activated = false; MonoSingleton<GunControl>.Instance.activated = false; GameStateManager.Instance.RegisterState(new GameState(stateKey, (GameObject[])(object)new GameObject[1] { window }) { cursorLock = (LockMode)2, cameraInputLock = (LockMode)1, playerInputLock = (LockMode)1 }); MonoSingleton<OptionsManager>.Instance.paused = true; } public void UnPause() { Time.timeScale = MonoSingleton<TimeController>.Instance.timeScale * MonoSingleton<TimeController>.Instance.timeScaleModifier; MonoSingleton<OptionsManager>.Instance.paused = false; MonoSingleton<CameraController>.Instance.activated = true; ((Behaviour)MonoSingleton<NewMovement>.Instance).enabled = true; MonoSingleton<GunControl>.Instance.activated = true; } } public class JukeboxPlayback : DirectoryTreeBrowser<SongIdentifier> { [SerializeField] private Sprite defaultIcon; [SerializeField] private GameObject disclaimer; [SerializeField] private GameObject buttonsSection; private readonly List<Transform> buttons = new List<Transform>(); private IEnumerable<SongIdentifier> order = new List<SongIdentifier>(); protected override int maxPageLength => 6; protected override IDirectoryTree<SongIdentifier> baseDirectory => (IDirectoryTree<SongIdentifier>)(object)new FakeDirectoryTree<SongIdentifier>("Playlist", order, (IEnumerable<IDirectoryTree<SongIdentifier>>)null, (IDirectoryTree<SongIdentifier>)null); private CustomContentButton CurrentButton { get { Transform? obj = buttons.ElementAtOrDefault(JukeboxMusicPlayer.CurrentSongIndex % ((DirectoryTreeBrowser<SongIdentifier>)this).maxPageLength); if (obj == null) { return null; } return ((Component)obj).GetComponent<CustomContentButton>(); } } protected void Awake() { JukeboxMusicPlayer.OnOrderChange += OnOrderChange; JukeboxMusicPlayer.OnNextSong += OnNextSong; } protected void OnDestroy() { JukeboxMusicPlayer.OnOrderChange -= OnOrderChange; JukeboxMusicPlayer.OnNextSong -= OnNextSong; } protected void OnEnable() { base.GoToBase(); } public void NextPage() { base.SetPage((base.currentPage != base.maxPages - 1) ? (base.currentPage + 1) : 0); } public void PreviousPage() { base.SetPage((base.currentPage == 0) ? (base.maxPages - 1) : (base.currentPage - 1)); } protected override Action BuildLeaf(SongIdentifier id, int indexInPage) { //IL_014a: Unknown result type (might be due to invalid IL or missing references) //IL_0154: Expected O, but got Unknown //IL_011c: Unknown result type (might be due to invalid IL or missing references) JukeboxSongMetadata metadata = MonoSingleton<JukeboxSongsLoader>.Instance.Load(id).Metadata; GameObject go = Object.Instantiate<GameObject>(base.itemButtonTemplate, base.itemButtonTemplate.transform.parent); CustomContentButton component = go.GetComponent<CustomContentButton>(); string text = ((!string.IsNullOrEmpty(metadata.Artist)) ? ("<color=#gray>" + metadata.Artist + "</color>") : string.Empty); component.text.text = metadata.Title + " " + text; component.icon.sprite = (((Object)(object)metadata.Icon != (Object)null) ? metadata.Icon : defaultIcon); go.SetActive(true); buttons.Add(go.transform); if (base.PageOf(JukeboxMusicPlayer.CurrentSongIndex) == base.currentPage && (Object)(object)component == (Object)(object)CurrentButton) { ((Graphic)component.border).color = new Color(0.5f, 0.5f, 0.5f, 0.5f); Object.Destroy((Object)(object)go.GetComponent<Button>()); } else { ((UnityEvent)component.button.onClick).AddListener((UnityAction)delegate { MonoSingleton<JukeboxManager>.Instance.player.ChangeTrack(base.currentPage * ((DirectoryTreeBrowser<SongIdentifier>)this).maxPageLength + indexInPage - 1); }); } return delegate { Object.Destroy((Object)(object)go); }; } private void OnOrderChange(IEnumerable<SongIdentifier> songs) { order = songs; ((DirectoryTreeBrowser<SongIdentifier>)this).Rebuild(true); } private void OnNextSong(JukeboxSong _) { buttonsSection.SetActive(true); disclaimer.SetActive(false); ((DirectoryTreeBrowser<SongIdentifier>)this).Rebuild(false); } public override void Rebuild(bool setToPageZero = true) { buttons.Clear(); Transform itemParent = base.itemParent; LayoutRebuilder.ForceRebuildLayoutImmediate((RectTransform)(object)((itemParent is RectTransform) ? itemParent : null)); base.Rebuild(setToPageZero); } } public class JukeboxPlaylistEditor : DirectoryTreeBrowser<JukeboxSong> { private readonly Dictionary<Transform, Coroutine> changeAnchorRoutines = new Dictionary<Transform, Coroutine>(); private readonly List<Transform> buttons = new List<Transform>(); [SerializeField] private JukeboxSongsLoader loader; [SerializeField] private JukeboxSoundtrackBrowser browser; [SerializeField] private Sprite defaultIcon; [SerializeField] private Sprite loopSprite; [SerializeField] private Sprite loopOnceSprite; [Header("UI Elements")] [SerializeField] private Image loopModeImage; [SerializeField] private Image shuffleImage; [SerializeField] private RectTransform selectedControls; [SerializeField] private List<Transform> anchors; public JukeboxPlaylist playlist = new JukeboxPlaylist(); protected override int maxPageLength => anchors.Count; protected override IDirectoryTree<JukeboxSong> baseDirectory => (IDirectoryTree<JukeboxSong>)(object)new FakeDirectoryTree<JukeboxSong>("Songs", ((Playlist)playlist).ids.Select((SongIdentifier id) => loader.Load(id)), (IEnumerable<IDirectoryTree<JukeboxSong>>)null, (IDirectoryTree<JukeboxSong>)null); private JukeboxCustomContentButton CurrentButton { get { Transform? obj = buttons.ElementAtOrDefault(((Playlist)playlist).selected % ((DirectoryTreeBrowser<JukeboxSong>)this).maxPageLength); if (obj == null) { return null; } return ((Component)obj).GetComponent<JukeboxCustomContentButton>(); } } private void Start() { ReloadPlaylist(); PrefsManager.onPrefChanged = (Action<string, object>)Delegate.Combine(PrefsManager.onPrefChanged, new Action<string, object>(OnPrefChange)); } public void ReloadPlaylist() { //IL_0009: Expected O, but got Unknown //IL_004e: Unknown result type (might be due to invalid IL or missing references) try { LoadPlaylist(); } catch (JsonReaderException val) { JsonReaderException val2 = val; Debug.LogError((object)("Error loading Playlist.json: '" + ((Exception)(object)val2).Message + "'. Recreating file.")); File.Delete(JukeboxPlaylist.currentPath); LoadPlaylist(); } Select(((Playlist)playlist).selected); SetLoopMode(((Playlist)playlist).loopMode); SetShuffle(((Playlist)playlist).shuffled); ((Playlist)playlist).OnChanged += SavePlaylist; } private void OnDestroy() { ((Playlist)playlist).OnChanged -= SavePlaylist; PrefsManager.onPrefChanged = (Action<string, object>)Delegate.Remove(PrefsManager.onPrefChanged, new Action<string, object>(OnPrefChange)); } public void SavePlaylist() { File.WriteAllText(JukeboxPlaylist.currentPath, JsonConvert.SerializeObject((object)playlist)); } public void LoadPlaylist() { Debug.Log((object)("Loading Playlist " + JukeboxPlaylist.currentPath)); JukeboxPlaylist val; using (StreamReader streamReader = new StreamReader(File.Open(JukeboxPlaylist.currentPath, FileMode.OpenOrCreate))) { val = JsonConvert.DeserializeObject<JukeboxPlaylist>(streamReader.ReadToEnd()); } if (val == null) { CreateEmpty(); } else { val.RemoveNonExisting(); if (((Playlist)val).ids.Count == 0) { CreateEmpty(); } else { playlist = val; } base.currentDirectory = ((DirectoryTreeBrowser<JukeboxSong>)this).baseDirectory; ((DirectoryTreeBrowser<JukeboxSong>)this).Rebuild(true); } if (MonoSingleton<PrefsManager>.Instance.GetBoolLocal("jukebox.preventDuplicateTracks", false)) { playlist.RemoveDuplicates(); } ((DirectoryTreeBrowser<JukeboxSong>)this).Rebuild(true); void CreateEmpty() { Debug.Log((object)("No saved playlist found at " + JukeboxPlaylist.currentPath + ". Creating default...")); CreateDefaultPlaylist(); } } public void Remove() { ((Playlist)playlist).Remove(((Playlist)playlist).selected); if (((Playlist)playlist).selected >= ((Playlist)playlist).ids.Count) { Select(((Playlist)playlist).Count - 1); } ((DirectoryTreeBrowser<JukeboxSong>)this).Rebuild(false); } public void ClearPlaylist() { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Expected O, but got Unknown ((Playlist)playlist).ids.Clear(); AssetReferenceSoundtrackSong val = browser.rootFolder[0]; playlist.Add(new SongIdentifier(((AssetReference)val).AssetGUID, (IdentifierType)0)); ((DirectoryTreeBrowser<JukeboxSong>)this).Rebuild(true); } public void NextPage() { base.SetPage((base.currentPage != base.maxPages - 1) ? (base.currentPage + 1) : 0); } public void PreviousPage() { base.SetPage((base.currentPage == 0) ? (base.maxPages - 1) : (base.currentPage - 1)); } public void MoveUp() { Move(-1); } public void MoveDown() { Move(1); } public void Move(int amount) { int num = ((Playlist)playlist).selected % ((DirectoryTreeBrowser<JukeboxSong>)this).maxPageLength; int index = num + amount; int count = ((Playlist)playlist).ids.Count; bool num2 = base.PageOf(((Playlist)playlist).selected) == base.PageOf((((Playlist)playlist).selected + amount).Mod(count)); ((Playlist)playlist).Swap(((Playlist)playlist).selected, (((Playlist)playlist).selected + amount).Mod(count)); if (num2) { ChangeAnchorOf(buttons[num], anchors[index]); ChangeAnchorOf((Transform)(object)selectedControls, anchors[index]); ChangeAnchorOf(buttons[index], anchors[num]); JukeboxCustomContentButton currentButton = CurrentButton; buttons.RemoveAt(num); buttons.Insert(index, ((Component)currentButton).transform); Select(((Playlist)playlist).selected + amount, rebuild: false); } else { ((Component)selectedControls).gameObject.SetActive(false); Select((((Playlist)playlist).selected + amount).Mod(count)); } } public void ChangeAnchorOf(Transform obj, Transform anchor, float time = 0.15f) { if (changeAnchorRoutines.ContainsKey(obj)) { if (changeAnchorRoutines[obj] != null) { ((MonoBehaviour)this).StopCoroutine(changeAnchorRoutines[obj]); } changeAnchorRoutines.Remove(obj); } changeAnchorRoutines.Add(obj, ((MonoBehaviour)this).StartCoroutine(ChangeAnchorOverTime())); IEnumerator ChangeAnchorOverTime() { float t = 0f; while ((double)t < (double)time && (double)time > 0.0) { obj.position = Vector3.MoveTowards(obj.position, anchor.position, Time.deltaTime * 2f); if (!((double)Vector3.Distance(obj.position, anchor.position) > (double)Mathf.Epsilon)) { break; } yield return null; } obj.position = anchor.position; } } public void ToggleLoopMode() { //IL_0007: Unknown result type (might be due to invalid IL or missing references) SetLoopMode((LoopMode)(((int)((Playlist)playlist).loopMode == 0) ? 1 : 0)); } private void SetLoopMode(LoopMode mode) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) ((Playlist)playlist).loopMode = mode; loopModeImage.sprite = (((int)((Playlist)playlist).loopMode == 0) ? loopSprite : loopOnceSprite); } public void ToggleShuffle() { SetShuffle(!((Playlist)playlist).shuffled); } private void SetShuffle(bool shuffle) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) ((Playlist)playlist).shuffled = shuffle; ((Graphic)shuffleImage).color = (shuffle ? Color.white : Color.gray); } public void Select(int newIndex, bool rebuild = true) { //IL_0048: 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_0104: Unknown result type (might be due to invalid IL or missing references) //IL_0198: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) if (newIndex < 0 || newIndex >= ((Playlist)playlist).Count) { Debug.LogWarning((object)"Attempted to set current index outside bounds of playlist"); return; } int num = ((base.PageOf(newIndex) == base.currentPage) ? 1 : 0); if (Object.op_Implicit((Object)(object)CurrentButton)) { ((Graphic)((CustomContentButton)CurrentButton).border).color = Color.white; if ((Object)(object)((CustomContentButton)CurrentButton).iconInset != (Object)null) { ((Graphic)((CustomContentButton)CurrentButton).iconInset).color = Color.white; } } int selected = ((Playlist)playlist).selected; ((Playlist)playlist).selected = newIndex; if (base.PageOf(selected) < base.PageOf(newIndex)) { ChangeAnchorOf((Transform)(object)selectedControls, anchors.First(), 0f); } else if (base.PageOf(selected) > base.PageOf(newIndex)) { ChangeAnchorOf((Transform)(object)selectedControls, anchors.Last(), 0f); } if (Object.op_Implicit((Object)(object)CurrentButton)) { ((Graphic)((CustomContentButton)CurrentButton).border).color = Color.red; if ((Object)(object)((CustomContentButton)CurrentButton).iconInset != (Object)null) { ((Graphic)((CustomContentButton)CurrentButton).iconInset).color = Color.red; } } Transform val = anchors[((Playlist)playlist).selected % ((DirectoryTreeBrowser<JukeboxSong>)this).maxPageLength]; if (num != 0) { ((Component)selectedControls).gameObject.SetActive(true); ChangeAnchorOf((Transform)(object)selectedControls, val); } else { ((Component)selectedControls).gameObject.SetActive(false); ((Component)selectedControls).transform.position = val.position; } if (rebuild) { ((DirectoryTreeBrowser<JukeboxSong>)this).Rebuild(false); if (MonoSingleton<PrefsManager>.Instance.GetBoolLocal("jukebox.enableTracksPreview", false) && MonoSingleton<FistControl>.Instance.shopping) { JukeboxSong song = loader.Load(((Playlist)playlist).ids[newIndex]); Object.FindObjectOfType<PreviewHelper>().PlayPreview(song); } } } public override void Rebuild(bool setToPageZero = true) { foreach (KeyValuePair<Transform, Coroutine> changeAnchorRoutine in changeAnchorRoutines) { if (changeAnchorRoutine.Value != null) { ((MonoBehaviour)this).StopCoroutine(changeAnchorRoutine.Value); } } changeAnchorRoutines.Clear(); buttons.Clear(); base.Rebuild(setToPageZero); if (buttons.Count < ((DirectoryTreeBrowser<JukeboxSong>)this).maxPageLength) { ChangeAnchorOf(base.plusButton.transform, anchors[buttons.Count], 0f); } Transform itemParent = base.itemParent; LayoutRebuilder.ForceRebuildLayoutImmediate((RectTransform)(object)((itemParent is RectTransform) ? itemParent : null)); } protected override Action BuildLeaf(JukeboxSong song, int currentIndex) { //IL_0212: Unknown result type (might be due to invalid IL or missing references) //IL_021c: Expected O, but got Unknown //IL_018e: Unknown result type (might be due to invalid IL or missing references) //IL_01b6: Unknown result type (might be due to invalid IL or missing references) JukeboxSongMetadata metadata = song.Metadata; GameObject go = Object.Instantiate<GameObject>(base.itemButtonTemplate, base.itemButtonTemplate.transform.parent); JukeboxCustomContentButton contentButton = go.GetComponent<JukeboxCustomContentButton>(); string text = ((!string.IsNullOrEmpty(metadata.Artist)) ? ("<color=#gray>" + metadata.Artist + "</color>") : string.Empty); ((CustomContentButton)contentButton).text.text = metadata.Title + " " + text; ((CustomContentButton)contentButton).icon.sprite = (((Object)(object)metadata.Icon != (Object)null) ? metadata.Icon : defaultIcon); contentButton.introAndLoopIcon.SetActive(metadata.Composite.GotIntroAndLoop); contentButton.calmThemeIcon.SetActive(metadata.Composite.GotCalmTheme || metadata.Composite.GotCalmLoop || metadata.Composite.GotCalmIntro); go.SetActive(true); ChangeAnchorOf(go.transform, anchors[currentIndex], 0f); buttons.Add(go.transform); if (base.PageOf(((Playlist)playlist).selected) == base.currentPage && (Object)(object)contentButton == (Object)(object)CurrentButton) { ((Graphic)((CustomContentButton)contentButton).border).color = Color.red; if ((Object)(object)((CustomContentButton)CurrentButton).iconInset != (Object)null) { ((Graphic)((CustomContentButton)CurrentButton).iconInset).color = Color.red; } ((Component)selectedControls).gameObject.SetActive(true); ChangeAnchorOf((Transform)(object)selectedControls, anchors[currentIndex]); return delegate { ((Component)selectedControls).gameObject.SetActive(false); Object.Destroy((Object)(object)go); }; } ((UnityEvent)((CustomContentButton)contentButton).button.onClick).AddListener((UnityAction)delegate { Select(buttons.IndexOf(((Component)contentButton).transform) + base.currentPage * ((DirectoryTreeBrowser<JukeboxSong>)this).maxPageLength); }); return delegate { Object.Destroy((Object)(object)go); }; } private void CreateDefaultPlaylist() { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Expected O, but got Unknown foreach (AssetReferenceSoundtrackSong item in browser.rootFolder)
plugins/Jukebox/JukeboxCore.dll
Decompiled 3 weeks agousing System; using System.CodeDom.Compiler; using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Net.Http; using System.Net.Http.Headers; using System.Reflection; using System.Resources; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Text.RegularExpressions; using System.Threading.Tasks; using BepInEx; using BepInEx.Configuration; using JetBrains.Annotations; using JukeboxCore.Assets; using JukeboxCore.Components; using JukeboxCore.Exceptions; using JukeboxCore.Models.Song; using JukeboxCore.Themes; using JukeboxCore.Utils; using Newtonsoft.Json; using TagLib; using UnityEngine; using UnityEngine.AddressableAssets; using UnityEngine.Networking; using UnityEngine.ResourceManagement.AsyncOperations; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("JukeboxCore")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("JukeboxCore")] [assembly: AssemblyCopyright("Copyright © 2025")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("AB57436D-F3D9-454E-8F64-33F23AFD6690")] [assembly: AssemblyFileVersion("2.1.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyVersion("2.1.0.0")] namespace JukeboxCore { [ConfigureSingleton(/*Could not decode attribute arguments.*/)] public class MainThreadDispatcher : MonoSingleton<MainThreadDispatcher> { private static readonly Queue<Action> ExecutionQueue = new Queue<Action>(); public void Enqueue(Action action) { lock (ExecutionQueue) { ExecutionQueue.Enqueue(action); } } private void Update() { lock (ExecutionQueue) { while (ExecutionQueue.Count > 0) { ExecutionQueue.Dequeue()?.Invoke(); } } } } [GeneratedCode("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] [DebuggerNonUserCode] [CompilerGenerated] internal class Resources { private static ResourceManager resourceMan; private static CultureInfo resourceCulture; [EditorBrowsable(EditorBrowsableState.Advanced)] internal static ResourceManager ResourceManager { get { if (resourceMan == null) { resourceMan = new ResourceManager("JukeboxCore.Resources", typeof(Resources).Assembly); } return resourceMan; } } [EditorBrowsable(EditorBrowsableState.Advanced)] internal static CultureInfo Culture { get { return resourceCulture; } set { resourceCulture = value; } } internal static byte[] JukeboxCore => (byte[])ResourceManager.GetObject("JukeboxCore", resourceCulture); internal Resources() { } } public struct UnscaledTimeSince { private float time; public static implicit operator float(UnscaledTimeSince ts) { return Time.unscaledTime - ts.time; } public static implicit operator UnscaledTimeSince(float ts) { UnscaledTimeSince result = default(UnscaledTimeSince); result.time = Time.unscaledTime - ts; return result; } } } namespace JukeboxCore.Utils { public static class CompositeSongsUtils { private static readonly List<string> SpecialPostfixes = new List<string> { "intro", "loop", "calm", "calmloop", "calmintro" }; public static JukeboxSongMetadata.CompositeProperties GetSongComponents(string guid, SoundtrackSong song) { return new JukeboxSongMetadata.CompositeProperties.Builder().GotIntroAndLoop((Object)(object)song.introClip != (Object)null).GotCalmIntro(val: false).GotCalmLoop(MonoSingleton<JukeboxStaticData>.Instance.calmThemes.FindCalmClipsFor(guid) != null) .Build; } public static JukeboxSongMetadata.CompositeProperties GetSongComponents(FileInfo fileInfo) { JukeboxSongMetadata.CompositeProperties.Builder builder = new JukeboxSongMetadata.CompositeProperties.Builder(); List<FileInfo> source = (from file in fileInfo.Directory?.GetFiles() where WithoutPostfix(file).Name.Equals(fileInfo.Name) select file).Select(delegate(FileInfo file) { if (HasSpecialPostfix(file, "calmintro")) { builder.GotCalmIntro(val: true); } if (HasSpecialPostfix(file, "calmloop")) { builder.GotCalmLoop(val: true); } if (HasSpecialPostfix(file, "calm")) { builder.GotCalmTheme(val: true); } return file; }).ToList() ?? new List<FileInfo>(); if (source.Any((FileInfo file) => HasSpecialPostfix(file, "intro")) && source.Any((FileInfo file) => HasSpecialPostfix(file, "loop"))) { builder.GotIntroAndLoop(val: true); } return builder.Build; } public static FileInfo WithPostfix(FileInfo path, string postfix) { return new FileInfo(Path.GetDirectoryName(path.FullName) + "\\" + Path.GetFileNameWithoutExtension(path.FullName) + "_" + postfix + path.Extension); } public static FileInfo WithoutPostfix(FileInfo path) { if (HasAnySpecialPostfix(path)) { return new FileInfo(Regex.Replace(path.FullName, "_[a-zA-Z]+\\.[a-zA-Z0-9]+$", path.Extension)); } return path; } public static bool HasValidExtenstion(FileInfo path) { return CustomMusicFileBrowser.extensionTypeDict.Keys.Any((string extension) => path.Extension.ToLower().Equals(extension)); } private static bool HasAnySpecialPostfix(FileInfo path) { return SpecialPostfixes.Any((string postfix) => HasSpecialPostfix(path, postfix)); } private static bool HasSpecialPostfix(FileInfo path, string postfix) { return Path.GetFileNameWithoutExtension(path.Name).EndsWith("_" + postfix); } } public static class ConfigUtils { public static readonly ConfigFile BepInExConfig = new ConfigFile(PathsUtils.BepInExConfigPath, true); } public static class GenericUtils { public static string FirstNonEmpty(params string[] options) { return options.FirstOrDefault((string option) => !string.IsNullOrEmpty(option)); } } public static class NetworkUtils { private const int RetryAttempts = 3; private static readonly HttpClient Client; static NetworkUtils() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Expected O, but got Unknown //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Expected O, but got Unknown Client = new HttpClient(); Client.Timeout = TimeSpan.FromSeconds(5.0); Client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); Client.DefaultRequestHeaders.UserAgent.TryParseAdd("com.google.android.youtube/17.36.4 (Linux; U; Android 12; GB) gzip"); } public static async Task<string> GetRaw(string url) { for (int i = 0; i < 3; i++) { try { string text = await (await Client.GetAsync(url)).Content.ReadAsStringAsync(); if (text == null) { continue; } return text; } catch (Exception) { if (i == 2) { throw; } } } throw new HttpRequestException(); } public static async Task<Texture2D> DownloadImage(string url) { UnityWebRequest request = UnityWebRequestTexture.GetTexture(url); try { await request.SendWebRequest(); if (request.error != null) { throw new ImageDownloadFailedException(url, request.error); } return DownloadHandlerTexture.GetContent(request); } finally { ((IDisposable)request)?.Dispose(); } } } public static class ObjectExtensions { public static bool IsOneOf(this object v, params object[] options) { return options.Any((object o) => o.Equals(v)); } } public static class PathsUtils { private static readonly List<string> ReservedWords = new List<string> { "CON", "PRN", "AUX", "CLOCK$", "NUL", "COM0", "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9", "LPT0", "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9" }; public static readonly string ApplicationPath = Path.Combine(Directory.GetParent(Application.dataPath)?.FullName); public static readonly string AssemblyPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); public static readonly string MusicPath = Path.Combine(ApplicationPath, "CyberGrind", "Music"); public static readonly string BepInExConfigPath = Path.Combine(Paths.ConfigPath, "Jukebox", "config.cfg"); public static string CoerceValidFileName(string filename) { string text = Regex.Escape(new string(Path.GetInvalidFileNameChars())); string pattern = "[" + text + "]+"; string seed = Regex.Replace(filename, pattern, "_"); return ReservedWords.Select((string reservedWord) => "^" + reservedWord + "\\.").Aggregate(seed, (string current, string reservedWordPattern) => Regex.Replace(current, reservedWordPattern, "_reservedWord_.", RegexOptions.IgnoreCase)); } } public class UnityWebRequestAwaiter : INotifyCompletion { private readonly UnityWebRequestAsyncOperation asyncOp; private Action continuation; public bool IsCompleted => ((AsyncOperation)asyncOp).isDone; public UnityWebRequestAwaiter(UnityWebRequestAsyncOperation asyncOp) { this.asyncOp = asyncOp; ((AsyncOperation)asyncOp).completed += OnRequestCompleted; } public void GetResult() { } public void OnCompleted(Action action) { continuation = action; } private void OnRequestCompleted(AsyncOperation obj) { continuation(); } } public static class UnityWebRequestAwaiterExtensions { public static UnityWebRequestAwaiter GetAwaiter(this UnityWebRequestAsyncOperation asyncOp) { return new UnityWebRequestAwaiter(asyncOp); } } } namespace JukeboxCore.Themes { [CreateAssetMenu(menuName = "Jukebox/Calm theme")] public class CalmThemeEntry : ScriptableObject { [SerializeField] public AssetReferenceSoundtrackSong reference; [SerializeField] public List<AssetReferenceT<AudioClip>> calmVariationClips; } [CreateAssetMenu(menuName = "Jukebox/Calm Themes Data")] public class SoundtrackCalmThemes : ScriptableObject { [SerializeField] public CalmThemeEntry[] calmClips; public List<AssetReferenceT<AudioClip>> FindCalmClipsFor(string guid) { CalmThemeEntry calmThemeEntry = calmClips.FirstOrDefault((CalmThemeEntry variation) => ((AssetReference)variation.reference).AssetGUID == guid); if (!((Object)(object)calmThemeEntry != (Object)null)) { return null; } return calmThemeEntry.calmVariationClips; } } } namespace JukeboxCore.Models.Song { public sealed class JukeboxCustomSong : JukeboxSong { [ExternalAsset("Assets/Jukebox/Textures/music_note.png", typeof(Sprite))] private static Sprite defaultIcon; private readonly List<UnityWebRequest> requests = new List<UnityWebRequest>(); private List<DownloadHandlerAudioClip> handles; protected override Lazy<JukeboxSongMetadata> GetMetadata => new Lazy<JukeboxSongMetadata>(delegate { JukeboxSongMetadata jukeboxSongMetadata = JukeboxSongMetadata.From(new FileInfo(base.Id.path)); if ((Object)(object)jukeboxSongMetadata.Icon == (Object)null) { jukeboxSongMetadata.Icon = defaultIcon; } return jukeboxSongMetadata; }); private JukeboxCustomSong(string path) : base(new SongIdentifier(path, (IdentifierType)1)) { }//IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Expected O, but got Unknown ~JukeboxCustomSong() { requests.ForEach(delegate(UnityWebRequest request) { request.Dispose(); }); } public static JukeboxCustomSong Create(string path) { return new JukeboxCustomSong(path); } protected override IEnumerator AcquireInternal(IEnumerator callback) { handles = new List<DownloadHandlerAudioClip>(); if (base.Metadata.Composite.GotIntroAndLoop) { yield return Download(CompositeSongsUtils.WithPostfix(new FileInfo(base.Id.path), "intro"), delegate(AudioClip c) { base.IntroClip = c; }); } yield return Download(base.Metadata.Composite.GotIntroAndLoop ? CompositeSongsUtils.WithPostfix(new FileInfo(base.Id.path), "loop") : new FileInfo(base.Id.path), delegate(AudioClip c) { base.Clips = new List<AudioClip> { c }; }); if (base.Metadata.Composite.GotCalmIntro) { yield return Download(CompositeSongsUtils.WithPostfix(new FileInfo(base.Id.path), "calmintro"), delegate(AudioClip c) { base.CalmIntroClip = c; }); } if (base.Metadata.Composite.GotCalmTheme) { yield return Download(CompositeSongsUtils.WithPostfix(new FileInfo(base.Id.path), "calm"), delegate(AudioClip c) { base.CalmClips = new List<AudioClip> { c }; }); } if (base.Metadata.Composite.GotCalmLoop) { yield return Download(CompositeSongsUtils.WithPostfix(new FileInfo(base.Id.path), "calmloop"), delegate(AudioClip c) { base.CalmClips = new List<AudioClip> { c }; }); } yield return callback; IEnumerator Download(FileSystemInfo path, Action<AudioClip> downloadCallback) { UnityWebRequest audioClip = UnityWebRequestMultimedia.GetAudioClip(new Uri(path.FullName).AbsoluteUri, CustomMusicFileBrowser.extensionTypeDict[path.Extension.ToLower()]); requests.Add(audioClip); DownloadHandler downloadHandler = audioClip.downloadHandler; DownloadHandlerAudioClip handle = (DownloadHandlerAudioClip)(object)((downloadHandler is DownloadHandlerAudioClip) ? downloadHandler : null); handles.Add(handle); if (handle != null) { handle.streamAudio = true; audioClip.SendWebRequest(); yield return audioClip; downloadCallback(handle.audioClip); } } } protected override void DisposeInternal() { DisposeOfRequests(); DisposeOfHandlers(); handles = null; DestroyClipIfPresent(base.IntroClip); foreach (AudioClip clip in base.Clips) { DestroyClipIfPresent(clip); } } private void DisposeOfRequests() { requests.ForEach(delegate(UnityWebRequest request) { request.Dispose(); }); } private void DisposeOfHandlers() { handles.ForEach(delegate(DownloadHandlerAudioClip request) { ((DownloadHandler)request).Dispose(); }); } private static void DestroyClipIfPresent(AudioClip clip) { if ((Object)(object)clip != (Object)null) { Object.Destroy((Object)(object)clip); } } } public class JukeboxPlaylist : Playlist { public static string currentPath => Path.Combine(Playlist.directory.FullName, MonoSingleton<PrefsManager>.Instance.GetStringLocal("jukebox.currentPlaylist", (string)null) + ".json"); public JukeboxPlaylist() { } public JukeboxPlaylist(IEnumerable<SongIdentifier> passedIds) : base(MonoSingleton<PrefsManager>.Instance.GetBoolLocal("jukebox.preventDuplicateTracks", false) ? passedIds.Distinct() : passedIds) { } public static string PathForPlaylist(string name) { return Path.Combine(Playlist.directory.FullName, name + ".json"); } public void Add(SongIdentifier id) { if (!MonoSingleton<PrefsManager>.Instance.GetBoolLocal("jukebox.preventDuplicateTracks", false) || !((Playlist)this).ids.Contains(id)) { ((Playlist)this).Add(id); } } public void RemoveDuplicates() { List<SongIdentifier> list = ((Playlist)this).ids.Distinct().ToList(); ((Playlist)this).ids.Clear(); foreach (SongIdentifier item in list) { Add(item); } } public void RemoveNonExisting() { List<SongIdentifier> list = ((Playlist)this).ids.Where((SongIdentifier id) => (int)id.type == 0 || new FileInfo(id.path).Exists).ToList(); ((Playlist)this).ids.Clear(); foreach (SongIdentifier item in list) { Add(item); } } } public abstract class JukeboxSong { private readonly Lazy<JukeboxSongMetadata> lazyMetadata; public SongIdentifier Id { get; } public JukeboxSongMetadata Metadata => lazyMetadata.Value; public AudioClip IntroClip { get; protected set; } public AudioClip CalmIntroClip { get; protected set; } public List<AudioClip> Clips { get; protected set; } public List<AudioClip> CalmClips { get; protected set; } public int MaxClipsIfNotRepeating { get; protected set; } public bool IsCustom => (int)Id.type == 1; public string ArtistAndTrack { get { if (Metadata.Artist == null) { return Metadata.Title; } return Metadata.Artist + " — " + Metadata.Title; } } protected abstract Lazy<JukeboxSongMetadata> GetMetadata { get; } protected JukeboxSong(SongIdentifier id) { Id = id; lazyMetadata = GetMetadata; } public IEnumerator Acquire(IEnumerator callback) { yield return AcquireInternal(callback); Dispose(); } private void Dispose() { DisposeInternal(); IntroClip = null; CalmIntroClip = null; Clips = null; CalmClips = null; MaxClipsIfNotRepeating = -1; } protected abstract IEnumerator AcquireInternal(IEnumerator callback); protected abstract void DisposeInternal(); } public static class JukeboxSongFactory { public static JukeboxSong Create(SongIdentifier id) { //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_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_000c: Invalid comparison between Unknown and I4 IdentifierType type = id.type; if ((int)type != 0) { if ((int)type == 1) { return JukeboxCustomSong.Create(id.path); } throw new ArgumentOutOfRangeException(); } return JukeboxSoundtrackSong.Create(id.path); } } public class JukeboxSongMetadata { public class CompositeProperties { public class Builder { public CompositeProperties Build { get; } public Builder() { Build = new CompositeProperties(); } public Builder GotIntroAndLoop(bool val) { Build.GotIntroAndLoop = val; return this; } public Builder GotCalmIntro(bool val) { Build.GotCalmIntro = val; return this; } public Builder GotCalmTheme(bool val) { Build.GotCalmTheme = val; return this; } public Builder GotCalmLoop(bool val) { Build.GotCalmLoop = val; return this; } } public bool GotIntroAndLoop { get; private set; } public bool GotCalmIntro { get; private set; } public bool GotCalmTheme { get; private set; } public bool GotCalmLoop { get; private set; } private CompositeProperties() { } } public Sprite Icon { get; set; } public string Title { get; } public string Artist { get; } public CompositeProperties Composite { get; } private JukeboxSongMetadata(Sprite icon, string title, CompositeProperties composite, string artist = null) { Icon = icon; Title = title; Composite = composite; Artist = artist; } public static JukeboxSongMetadata From(FileInfo srcFile) { CompositeProperties songComponents = CompositeSongsUtils.GetSongComponents(srcFile); FileInfo fileInfo = (songComponents.GotIntroAndLoop ? CompositeSongsUtils.WithPostfix(srcFile, "intro") : srcFile); try { Tag tag = File.Create(fileInfo.FullName).Tag; return new JukeboxSongMetadata(LoadCover(tag), (!string.IsNullOrEmpty(tag.Title)) ? tag.Title : Path.GetFileNameWithoutExtension(srcFile.Name), songComponents, GenericUtils.FirstNonEmpty(tag.FirstPerformer, tag.FirstComposer, tag.FirstAlbumArtist)); } catch (Exception) { return new JukeboxSongMetadata(null, fileInfo.Name, songComponents); } } public static JukeboxSongMetadata From(AssetReferenceSoundtrackSong reference) { //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) AsyncOperationHandle<SoundtrackSong> val = ((AssetReferenceT<SoundtrackSong>)(object)reference).LoadAssetAsync(); val.WaitForCompletion(); SoundtrackSong result = val.Result; return new JukeboxSongMetadata(result.icon, result.songName, CompositeSongsUtils.GetSongComponents(((AssetReference)reference).AssetGUID, result), result.extraLevelBit); } private static Sprite LoadCover(Tag tag) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Expected O, but got Unknown //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) if (tag.Pictures.Length == 0) { return null; } using MemoryStream memoryStream = new MemoryStream(tag.Pictures[0].Data.Data); try { memoryStream.Seek(0L, SeekOrigin.Begin); Texture2D val = new Texture2D(2, 2); ImageConversion.LoadImage(val, memoryStream.ToArray()); return Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), 100f); } catch (Exception) { return null; } } } public sealed class JukeboxSoundtrackSong : JukeboxSong { private AsyncOperationHandle<SoundtrackSong> handle; private readonly List<AsyncOperationHandle<AudioClip>> calmClipsHandles = new List<AsyncOperationHandle<AudioClip>>(); protected override Lazy<JukeboxSongMetadata> GetMetadata => new Lazy<JukeboxSongMetadata>(() => JukeboxSongMetadata.From(new AssetReferenceSoundtrackSong(base.Id.path))); private JukeboxSoundtrackSong(string path) : base(new SongIdentifier(path, (IdentifierType)0)) { }//IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Expected O, but got Unknown public static JukeboxSoundtrackSong Create(string path) { return new JukeboxSoundtrackSong(path); } protected override IEnumerator AcquireInternal(IEnumerator callback) { handle = Addressables.LoadAssetAsync<SoundtrackSong>((object)base.Id.path); yield return handle; SoundtrackSong addressable = handle.Result; base.IntroClip = addressable.introClip; base.Clips = addressable.clips; List<AssetReferenceT<AudioClip>> list = MonoSingleton<JukeboxStaticData>.Instance.calmThemes.FindCalmClipsFor(base.Id.path); if (list != null) { base.CalmClips = new List<AudioClip>(); foreach (AsyncOperationHandle<AudioClip> calmClipHandle in list.Select((AssetReferenceT<AudioClip> clip) => Addressables.LoadAssetAsync<AudioClip>((object)((AssetReference)clip).AssetGUID))) { calmClipsHandles.Add(calmClipHandle); yield return calmClipHandle; base.CalmClips.Add(calmClipHandle.Result); } } base.MaxClipsIfNotRepeating = addressable.maxClipsIfNotRepeating; yield return callback; } protected override void DisposeInternal() { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) Addressables.Release<SoundtrackSong>(handle); foreach (AsyncOperationHandle<AudioClip> calmClipsHandle in calmClipsHandles) { Addressables.Release<AudioClip>(calmClipsHandle); } calmClipsHandles.Clear(); handle = default(AsyncOperationHandle<SoundtrackSong>); } } } namespace JukeboxCore.Models.Preferences { [JsonObject(/*Could not decode attribute arguments.*/)] public class JukeboxThemesConfig { public class CalmThemeConfig { [JsonProperty(/*Could not decode attribute arguments.*/)] public Dictionary<EnemyType, int> specialEnemies = new Dictionary<EnemyType, int> { { (EnemyType)19, 1 }, { (EnemyType)5, 1 }, { (EnemyType)26, 1 }, { (EnemyType)2, 1 }, { (EnemyType)7, 2 } }; [JsonProperty(/*Could not decode attribute arguments.*/)] public Dictionary<EnemyType, int> specialRadiantEnemies = new Dictionary<EnemyType, int> { { (EnemyType)19, 0 }, { (EnemyType)5, 0 }, { (EnemyType)26, 0 }, { (EnemyType)2, 0 }, { (EnemyType)7, 1 } }; } [JsonProperty("calmThemeConfig")] public CalmThemeConfig calmTheme = new CalmThemeConfig(); public JukeboxThemesConfig Equalize() { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) foreach (KeyValuePair<EnemyType, int> specialEnemy in calmTheme.specialEnemies) { if (!calmTheme.specialRadiantEnemies.ContainsKey(specialEnemy.Key)) { calmTheme.specialRadiantEnemies.Add(specialEnemy.Key, 0); } if (calmTheme.specialRadiantEnemies[specialEnemy.Key] > specialEnemy.Value) { calmTheme.specialRadiantEnemies[specialEnemy.Key] = specialEnemy.Value; } } return this; } } [JsonObject(/*Could not decode attribute arguments.*/)] public class JukeboxVolumeConfig { [JsonProperty(/*Could not decode attribute arguments.*/)] public Dictionary<string, float> boostSettings = new Dictionary<string, float>(); } } namespace JukeboxCore.Models.Downloader { public enum TrackDownloadingState { None, Enqueued, PreProcessing, Downloading, PostProcessing, Success, Failed } public class DownloadableSongMetadata { public string Id { get; private set; } public string Url { get; private set; } public string ThumbnailUrl { get; private set; } public string Title { get; private set; } public string Artist { get; private set; } [CanBeNull] public string Playlist { get; private set; } public DownloadableSongMetadata(string id, string url, string thumbnailUrl, string title, string artist, string playlist) { Id = id; Url = url; ThumbnailUrl = thumbnailUrl; Title = title; Artist = artist; Playlist = playlist; } } public class DownloadableEntityState { [CanBeNull] public Sprite thumbnail; public TrackDownloadingState? state; public float? progress; [CanBeNull] public string eta; } } namespace JukeboxCore.Exceptions { public class CookiesRequiredException : JukeboxException { public override string Message => "Cookies required"; } public class ImageDownloadFailedException : JukeboxException { private readonly string url; private readonly string reason; public override string Message => "An error has occured while downloading image " + url + ": " + reason; public ImageDownloadFailedException(string url, string reason) { this.url = url; this.reason = reason; } } public class InvalidCookiesFileException : JukeboxException { public override string Message => "Invalid cookies.txt file"; } public class InvalidVideoUrlException : JukeboxException { public override string Message => "Invalid URL or track is not available"; } public abstract class JukeboxException : ArgumentException { } public class PlaylistIsUnviewableException : JukeboxException { public override string Message => "This type of playlist cannot be downloaded"; } } namespace JukeboxCore.Events { public abstract class JukeboxEvent<T> : EventArgs { public T newState; public abstract void Mutate(T state); } public class EventStore<T> { private readonly Dictionary<string, Action<JukeboxEvent<T>>> listeners = new Dictionary<string, Action<JukeboxEvent<T>>>(); public void Subscribe(string id, Action<JukeboxEvent<T>> listener) { if (!listeners.ContainsKey(id)) { listeners[id] = delegate { }; } Dictionary<string, Action<JukeboxEvent<T>>> dictionary = listeners; dictionary[id] = (Action<JukeboxEvent<T>>)Delegate.Combine(dictionary[id], listener); } public void Unsubscribe(string id, Action<JukeboxEvent<T>> listener) { if (listeners.ContainsKey(id)) { Dictionary<string, Action<JukeboxEvent<T>>> dictionary = listeners; dictionary[id] = (Action<JukeboxEvent<T>>)Delegate.Remove(dictionary[id], listener); } } public void Invoke(string id, JukeboxEvent<T> arg) { if (listeners.TryGetValue(id, out var value)) { value?.Invoke(arg); } } public void Clear() { listeners.Clear(); } } public abstract class EventManager<T> { private readonly EventStore<T> events = new EventStore<T>(); private readonly Dictionary<string, T> states = new Dictionary<string, T>(); public void Register(string id) { if (!states.ContainsKey(id)) { states.Add(id, DefaultState(id)); } } public T StateOf(string id) { if (!states.TryGetValue(id, out var value)) { return default(T); } return value; } public void Subscribe(string id, Action<JukeboxEvent<T>> action) { events.Subscribe(id, action); } public void Unsubscribe(string id, Action<JukeboxEvent<T>> action) { events.Unsubscribe(id, action); } public void Invoke(string id, JukeboxEvent<T> e) { if (states.TryGetValue(id, out var value)) { e.Mutate(value); } events.Invoke(id, e); } public void Map(Action<KeyValuePair<string, T>> action) { foreach (KeyValuePair<string, T> state in states) { action(state); } } public void Clear() { states.Clear(); events.Clear(); } protected abstract T DefaultState(string id); } } namespace JukeboxCore.Components { [ConfigureSingleton(/*Could not decode attribute arguments.*/)] public class JukeboxStaticData : MonoSingleton<JukeboxStaticData> { [SerializeField] public SoundtrackCalmThemes calmThemes; protected void Awake() { base.Awake(); MonoSingleton<AssetsManager>.Instance.LoadAssets(Resources.JukeboxCore); MonoSingleton<AssetsManager>.Instance.RegisterPrefabs(Assembly.GetExecutingAssembly()); } } [ConfigureSingleton(/*Could not decode attribute arguments.*/)] public class JukeboxSongsLoader : MonoSingleton<JukeboxSongsLoader> { private readonly Dictionary<SongIdentifier, JukeboxSong> cache = new Dictionary<SongIdentifier, JukeboxSong>(); public JukeboxSong Load(SongIdentifier id) { if (cache.TryGetValue(id, out var value)) { return value; } cache.Add(id, JukeboxSongFactory.Create(id)); return cache[id]; } } public class RingPlaceholder : MonoBehaviour { private UnscaledTimeSince sinceEnabled; private void Awake() { Random.Range(0, 1); } private void OnEnable() { sinceEnabled = 0f; } private void Update() { //IL_0021: Unknown result type (might be due to invalid IL or missing references) ((Component)this).transform.localRotation = Quaternion.Euler(0f, 0f, (float)sinceEnabled * -360f); } } } namespace JukeboxCore.Collections { public class JukeboxFileTree : IDirectoryTree<JukeboxSong>, IDirectoryTree { public string name { get; private set; } public IDirectoryTree<JukeboxSong> parent { get; set; } public IEnumerable<IDirectoryTree<JukeboxSong>> children { get; private set; } public IEnumerable<JukeboxSong> files { get; private set; } private DirectoryInfo RealDirectory { get; } public JukeboxFileTree(string path, IDirectoryTree<JukeboxSong> parent = null) { RealDirectory = new DirectoryInfo(path); this.parent = parent; Refresh(); } private JukeboxFileTree(DirectoryInfo realDirectory, IDirectoryTree<JukeboxSong> parent = null) { RealDirectory = realDirectory; this.parent = parent; Refresh(); } public void Refresh() { RealDirectory.Create(); name = RealDirectory.Name; DirectoryInfo[] youTubeFolderOnTop = GetYouTubeFolderOnTop(RealDirectory.GetDirectories()); children = youTubeFolderOnTop.Select((DirectoryInfo dir) => new JukeboxFileTree(dir, this)); files = (from file in RealDirectory.GetFiles().Where(CompositeSongsUtils.HasValidExtenstion) group file by CompositeSongsUtils.WithoutPostfix(file).FullName into @group select MonoSingleton<JukeboxSongsLoader>.Instance.Load(new SongIdentifier(@group.Key, (IdentifierType)1))).ToList(); } public override bool Equals(object obj) { if (obj != null && !(GetType() != obj.GetType())) { return string.Equals(RealDirectory.FullName, (obj as DirectoryInfo)?.FullName, StringComparison.InvariantCultureIgnoreCase); } return false; } public override int GetHashCode() { return RealDirectory.GetHashCode(); } public IEnumerable<JukeboxSong> GetFilesRecursive() { return children.SelectMany((IDirectoryTree<JukeboxSong> child) => child.GetFilesRecursive()).Concat(files); } private DirectoryInfo[] GetYouTubeFolderOnTop(DirectoryInfo[] directories) { if (parent == null && directories.Length > 1) { DirectoryInfo ytFolder = directories.FirstOrDefault((DirectoryInfo folder) => folder.Name.Equals("YouTube")); if (ytFolder != null) { return directories.Where((DirectoryInfo e) => !e.Equals(ytFolder)).Prepend(ytFolder).ToArray(); } } return directories; } } } namespace JukeboxCore.Assets { [AttributeUsage(AttributeTargets.Field)] public class AddressableAsset : Attribute { public string Path { get; } public Type AssetType { get; } public AddressableAsset(string path, Type type) { Path = path; AssetType = type; } } [ConfigureSingleton(/*Could not decode attribute arguments.*/)] public class AssetsManager : MonoSingleton<AssetsManager> { private const BindingFlags Flags = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; private readonly List<AssetBundle> bundles = new List<AssetBundle>(); public void LoadAssets(byte[] raw) { bundles.Add(AssetBundle.LoadFromMemory(raw)); } public void RegisterPrefabs(Assembly assembly) { Type[] types = assembly.GetTypes(); foreach (Type type in types) { CheckType(type); } } private void CheckType(IReflect type) { type.GetFields(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).ToList().ForEach(ProcessField); } private void ProcessField(FieldInfo field) { //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) if (field.FieldType.IsArray || !typeof(Object).IsAssignableFrom(field.FieldType) || !field.IsStatic) { return; } ExternalAsset customAttribute = field.GetCustomAttribute<ExternalAsset>(); AddressableAsset addressableAsset = field.GetCustomAttribute<AddressableAsset>(); if (customAttribute != null) { field.SetValue(null, LoadAsset(customAttribute.Path, customAttribute.Type)); } if (addressableAsset != null) { AsyncOperationHandle<GameObject> val = Addressables.LoadAssetAsync<GameObject>((object)addressableAsset.Path); val.Completed += delegate(AsyncOperationHandle<GameObject> value) { field.SetValue(null, Convert.ChangeType(value.Result, addressableAsset.AssetType)); }; } } private Object LoadAsset(string path, Type type) { return bundles.Select((AssetBundle bundle) => bundle.LoadAsset(path, type)).FirstOrDefault(); } } [AttributeUsage(AttributeTargets.Field)] public class ExternalAsset : Attribute { public string Path { get; } public Type Type { get; } public ExternalAsset(string path, Type type) { Path = path; Type = type; } } }
plugins/Jukebox/TagLibSharp.dll
Decompiled 3 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.Collections.ObjectModel; using System.Diagnostics; using System.Globalization; using System.IO; using System.IO.Compression; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Runtime.Versioning; using System.Text; using System.Xml; using Microsoft.CodeAnalysis; using TagLib.Aac; using TagLib.Aiff; using TagLib.Ape; using TagLib.Asf; using TagLib.Audible; using TagLib.Dsf; using TagLib.Flac; using TagLib.Gif; using TagLib.IFD; using TagLib.IFD.Entries; using TagLib.IFD.Makernotes; using TagLib.IFD.Tags; using TagLib.IIM; using TagLib.Id3v1; using TagLib.Id3v2; using TagLib.Image; using TagLib.Image.NoMetadata; using TagLib.Jpeg; using TagLib.Matroska; using TagLib.Mpeg; using TagLib.Mpeg4; using TagLib.MusePack; using TagLib.NonContainer; using TagLib.Ogg; using TagLib.Ogg.Codecs; using TagLib.Png; using TagLib.Riff; using TagLib.Tiff; using TagLib.Tiff.Arw; using TagLib.Tiff.Cr2; using TagLib.Tiff.Dng; using TagLib.Tiff.Nef; using TagLib.Tiff.Pef; using TagLib.Tiff.Rw2; using TagLib.WavPack; using TagLib.Xmp; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.6.2", FrameworkDisplayName = ".NET Framework 4.6.2")] [assembly: AssemblyCompany("Brian Nickel, Gabriel Burt, Stephen Shaw, etc")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyCopyright("Copyright (c) 2006-2007 Brian Nickel. Copyright (c) 2009-2020 Other contributors")] [assembly: AssemblyDescription("A library for for reading and writing metadata in media files, including video, audio, and photo formats.")] [assembly: AssemblyFileVersion("2.3.0.0")] [assembly: AssemblyInformationalVersion("2.3.0.0")] [assembly: AssemblyProduct("TagLib#")] [assembly: AssemblyTitle("TagLibSharp")] [assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/mono/taglib-sharp")] [assembly: AssemblyVersion("2.3.0.0")] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class IsReadOnlyAttribute : Attribute { } } namespace TagLib { public enum StringType { Latin1, UTF16, UTF16BE, UTF8, UTF16LE } public class ByteVector : IList<byte>, ICollection<byte>, IEnumerable<byte>, IEnumerable, IComparable<ByteVector> { private static readonly uint[] crc_table = new uint[256] { 0u, 79764919u, 159529838u, 222504665u, 319059676u, 398814059u, 445009330u, 507990021u, 638119352u, 583659535u, 797628118u, 726387553u, 890018660u, 835552979u, 1015980042u, 944750013u, 1276238704u, 1221641927u, 1167319070u, 1095957929u, 1595256236u, 1540665371u, 1452775106u, 1381403509u, 1780037320u, 1859660671u, 1671105958u, 1733955601u, 2031960084u, 2111593891u, 1889500026u, 1952343757u, 2552477408u, 2632100695u, 2443283854u, 2506133561u, 2334638140u, 2414271883u, 2191915858u, 2254759653u, 3190512472u, 3135915759u, 3081330742u, 3009969537u, 2905550212u, 2850959411u, 2762807018u, 2691435357u, 3560074640u, 3505614887u, 3719321342u, 3648080713u, 3342211916u, 3287746299u, 3467911202u, 3396681109u, 4063920168u, 4143685023u, 4223187782u, 4286162673u, 3779000052u, 3858754371u, 3904687514u, 3967668269u, 881225847u, 809987520u, 1023691545u, 969234094u, 662832811u, 591600412u, 771767749u, 717299826u, 311336399u, 374308984u, 453813921u, 533576470u, 25881363u, 88864420u, 134795389u, 214552010u, 2023205639u, 2086057648u, 1897238633u, 1976864222u, 1804852699u, 1867694188u, 1645340341u, 1724971778u, 1587496639u, 1516133128u, 1461550545u, 1406951526u, 1302016099u, 1230646740u, 1142491917u, 1087903418u, 2896545431u, 2825181984u, 2770861561u, 2716262478u, 3215044683u, 3143675388u, 3055782693u, 3001194130u, 2326604591u, 2389456536u, 2200899649u, 2280525302u, 2578013683u, 2640855108u, 2418763421u, 2498394922u, 3769900519u, 3832873040u, 3912640137u, 3992402750u, 4088425275u, 4151408268u, 4197601365u, 4277358050u, 3334271071u, 3263032808u, 3476998961u, 3422541446u, 3585640067u, 3514407732u, 3694837229u, 3640369242u, 1762451694u, 1842216281u, 1619975040u, 1682949687u, 2047383090u, 2127137669u, 1938468188u, 2001449195u, 1325665622u, 1271206113u, 1183200824u, 1111960463u, 1543535498u, 1489069629u, 1434599652u, 1363369299u, 622672798u, 568075817u, 748617968u, 677256519u, 907627842u, 853037301u, 1067152940u, 995781531u, 51762726u, 131386257u, 177728840u, 240578815u, 269590778u, 349224269u, 429104020u, 491947555u, 4046411278u, 4126034873u, 4172115296u, 4234965207u, 3794477266u, 3874110821u, 3953728444u, 4016571915u, 3609705398u, 3555108353u, 3735388376u, 3664026991u, 3290680682u, 3236090077u, 3449943556u, 3378572211u, 3174993278u, 3120533705u, 3032266256u, 2961025959u, 2923101090u, 2868635157u, 2813903052u, 2742672763u, 2604032198u, 2683796849u, 2461293480u, 2524268063u, 2284983834u, 2364738477u, 2175806836u, 2238787779u, 1569362073u, 1498123566u, 1409854455u, 1355396672u, 1317987909u, 1246755826u, 1192025387u, 1137557660u, 2072149281u, 2135122070u, 1912620623u, 1992383480u, 1753615357u, 1816598090u, 1627664531u, 1707420964u, 295390185u, 358241886u, 404320391u, 483945776u, 43990325u, 106832002u, 186451547u, 266083308u, 932423249u, 861060070u, 1041341759u, 986742920u, 613929101u, 542559546u, 756411363u, 701822548u, 3316196985u, 3244833742u, 3425377559u, 3370778784u, 3601682597u, 3530312978u, 3744426955u, 3689838204u, 3819031489u, 3881883254u, 3928223919u, 4007849240u, 4037393693u, 4100235434u, 4180117107u, 4259748804u, 2310601993u, 2373574846u, 2151335527u, 2231098320u, 2596047829u, 2659030626u, 2470359227u, 2550115596u, 2947551409u, 2876312838u, 2788305887u, 2733848168u, 3165939309u, 3094707162u, 3040238851u, 2985771188u }; private static bool use_broken_latin1; private static readonly ReadOnlyByteVector td1 = new ReadOnlyByteVector(1); private static readonly ReadOnlyByteVector td2 = new ReadOnlyByteVector(2); private static Encoding last_utf16_encoding = Encoding.Unicode; private readonly List<byte> data = new List<byte>(); public byte[] Data => data.ToArray(); public bool IsEmpty => data.Count == 0; public uint Checksum { get { uint num = 0u; foreach (byte datum in data) { num = (num << 8) ^ crc_table[((num >> 24) & 0xFF) ^ datum]; } return num; } } public static bool UseBrokenLatin1Behavior { get { return use_broken_latin1; } set { use_broken_latin1 = value; } } public int Count => data.Count; public bool IsSynchronized => false; public object SyncRoot => this; public virtual bool IsReadOnly => false; public virtual bool IsFixedSize => false; public byte this[int index] { get { return data[index]; } set { if (IsReadOnly) { throw new NotSupportedException("Cannot edit readonly objects."); } data[index] = value; } } public ByteVector() { } public ByteVector(ByteVector vector) { if (vector != null) { data.AddRange(vector); } } public ByteVector(params byte[] data) { if (data != null) { this.data.AddRange(data); } } public ByteVector(byte[] data, int length) { if (length > data.Length) { throw new ArgumentOutOfRangeException("length", "Length exceeds size of data."); } if (length < 0) { throw new ArgumentOutOfRangeException("length", "Length is less than zero."); } if (length == data.Length) { this.data.AddRange(data); return; } byte[] array = new byte[length]; Array.Copy(data, 0, array, 0, length); this.data.AddRange(array); } public ByteVector(int size) : this(size, 0) { } public ByteVector(int size, byte value) { if (size < 0) { throw new ArgumentOutOfRangeException("size", "Size is less than zero."); } if (size != 0) { byte[] array = new byte[size]; for (int i = 0; i < size; i++) { array[i] = value; } data.AddRange(array); } } public ByteVector Mid(int startIndex, int length) { if (startIndex < 0 || startIndex > Count) { throw new ArgumentOutOfRangeException("startIndex"); } if (length < 0 || startIndex + length > Count) { throw new ArgumentOutOfRangeException("length"); } if (length == 0) { return new ByteVector(); } if (startIndex + length > data.Count) { length = data.Count - startIndex; } byte[] array = new byte[length]; data.CopyTo(startIndex, array, 0, length); return array; } public ByteVector Mid(int index) { return Mid(index, Count - index); } public int Find(ByteVector pattern, int offset, int byteAlign) { if (pattern == null) { throw new ArgumentNullException("pattern"); } if (offset < 0) { throw new ArgumentOutOfRangeException("offset", "offset must be at least 0."); } if (byteAlign < 1) { throw new ArgumentOutOfRangeException("byteAlign", "byteAlign must be at least 1."); } if (pattern.Count > Count - offset) { return -1; } if (pattern.Count == 1) { byte b = pattern[0]; for (int i = offset; i < data.Count; i += byteAlign) { if (data[i] == b) { return i; } } return -1; } int[] array = new int[256]; for (int j = 0; j < 256; j++) { array[j] = pattern.Count; } for (int k = 0; k < pattern.Count - 1; k++) { array[pattern[k]] = pattern.Count - k - 1; } for (int l = pattern.Count - 1 + offset; l < data.Count; l += array[data[l]]) { int num = l; int num2 = pattern.Count - 1; while (num2 >= 0 && data[num] == pattern[num2]) { num--; num2--; } if (-1 == num2 && (num + 1 - offset) % byteAlign == 0) { return num + 1; } } return -1; } public int Find(ByteVector pattern, int offset) { return Find(pattern, offset, 1); } public int Find(ByteVector pattern) { return Find(pattern, 0, 1); } public int RFind(ByteVector pattern, int offset, int byteAlign) { if (pattern == null) { throw new ArgumentNullException("pattern"); } if (offset < 0) { throw new ArgumentOutOfRangeException("offset"); } if (pattern.Count == 0 || pattern.Count > Count - offset) { return -1; } if (pattern.Count == 1) { byte b = pattern[0]; for (int num = Count - offset - 1; num >= 0; num -= byteAlign) { if (data[num] == b) { return num; } } return -1; } int[] array = new int[256]; for (int i = 0; i < 256; i++) { array[i] = pattern.Count; } for (int num2 = pattern.Count - 1; num2 > 0; num2--) { array[pattern[num2]] = num2; } for (int num3 = Count - offset - pattern.Count; num3 >= 0; num3 -= array[data[num3]]) { if ((offset - num3) % byteAlign == 0 && ContainsAt(pattern, num3)) { return num3; } } return -1; } public int RFind(ByteVector pattern, int offset) { return RFind(pattern, offset, 1); } public int RFind(ByteVector pattern) { return RFind(pattern, 0, 1); } public bool ContainsAt(ByteVector pattern, int offset, int patternOffset, int patternLength) { if (pattern == null) { throw new ArgumentNullException("pattern"); } if (pattern.Count < patternLength) { patternLength = pattern.Count; } if (patternLength > data.Count || offset >= data.Count || patternOffset >= pattern.Count || patternLength <= 0 || offset < 0) { return false; } for (int i = 0; i < patternLength - patternOffset; i++) { if (data[i + offset] != pattern[i + patternOffset]) { return false; } } return true; } public bool ContainsAt(ByteVector pattern, int offset, int patternOffset) { return ContainsAt(pattern, offset, patternOffset, int.MaxValue); } public bool ContainsAt(ByteVector pattern, int offset) { return ContainsAt(pattern, offset, 0); } public bool StartsWith(ByteVector pattern) { return ContainsAt(pattern, 0); } public bool EndsWith(ByteVector pattern) { if (pattern == null) { throw new ArgumentNullException("pattern"); } return ContainsAt(pattern, data.Count - pattern.Count); } public int EndsWithPartialMatch(ByteVector pattern) { if (pattern == null) { throw new ArgumentNullException("pattern"); } if (pattern.Count > data.Count) { return -1; } int num = data.Count - pattern.Count; for (int i = 1; i < pattern.Count; i++) { if (ContainsAt(pattern, num + i, 0, pattern.Count - i)) { return num + i; } } return -1; } public void Add(ByteVector data) { if (IsReadOnly) { throw new NotSupportedException("Cannot edit readonly objects."); } if (data != null) { this.data.AddRange(data); } } public void Add(byte[] data) { if (IsReadOnly) { throw new NotSupportedException("Cannot edit readonly objects."); } if (data != null) { this.data.AddRange(data); } } public void Insert(int index, ByteVector data) { if (IsReadOnly) { throw new NotSupportedException("Cannot edit readonly objects."); } if (data != null) { this.data.InsertRange(index, data); } } public void Insert(int index, byte[] data) { if (IsReadOnly) { throw new NotSupportedException("Cannot edit readonly objects."); } if (data != null) { this.data.InsertRange(index, data); } } public ByteVector Resize(int size, byte padding) { if (IsReadOnly) { throw new NotSupportedException("Cannot edit readonly objects."); } if (data.Count > size) { data.RemoveRange(size, data.Count - size); } while (data.Count < size) { data.Add(padding); } return this; } public ByteVector Resize(int size) { return Resize(size, 0); } public void RemoveRange(int index, int count) { if (IsReadOnly) { throw new NotSupportedException("Cannot edit readonly objects."); } data.RemoveRange(index, count); } public int ToInt(bool mostSignificantByteFirst) { int num = 0; int num2 = ((Count > 4) ? 3 : (Count - 1)); for (int i = 0; i <= num2; i++) { int num3 = (mostSignificantByteFirst ? (num2 - i) : i); num |= this[i] << num3 * 8; } return num; } public int ToInt() { return ToInt(mostSignificantByteFirst: true); } public uint ToUInt(bool mostSignificantByteFirst) { uint num = 0u; int num2 = ((Count > 4) ? 3 : (Count - 1)); for (int i = 0; i <= num2; i++) { int num3 = (mostSignificantByteFirst ? (num2 - i) : i); num |= (uint)(this[i] << num3 * 8); } return num; } public uint ToUInt() { return ToUInt(mostSignificantByteFirst: true); } public short ToShort(bool mostSignificantByteFirst) { short num = 0; int num2 = ((Count > 2) ? 1 : (Count - 1)); for (int i = 0; i <= num2; i++) { int num3 = (mostSignificantByteFirst ? (num2 - i) : i); num |= (short)(this[i] << num3 * 8); } return num; } public short ToShort() { return ToShort(mostSignificantByteFirst: true); } public ushort ToUShort(bool mostSignificantByteFirst) { ushort num = 0; int num2 = ((Count > 2) ? 1 : (Count - 1)); for (int i = 0; i <= num2; i++) { int num3 = (mostSignificantByteFirst ? (num2 - i) : i); num |= (ushort)(this[i] << num3 * 8); } return num; } public ushort ToUShort() { return ToUShort(mostSignificantByteFirst: true); } public long ToLong(bool mostSignificantByteFirst) { long num = 0L; int num2 = ((Count > 8) ? 7 : (Count - 1)); for (int i = 0; i <= num2; i++) { int num3 = (mostSignificantByteFirst ? (num2 - i) : i); num |= (long)((ulong)this[i] << num3 * 8); } return num; } public long ToLong() { return ToLong(mostSignificantByteFirst: true); } public ulong ToULong(bool mostSignificantByteFirst) { ulong num = 0uL; int num2 = ((Count > 8) ? 7 : (Count - 1)); for (int i = 0; i <= num2; i++) { int num3 = (mostSignificantByteFirst ? (num2 - i) : i); num |= (ulong)this[i] << num3 * 8; } return num; } public ulong ToULong() { return ToULong(mostSignificantByteFirst: true); } public float ToFloat(bool mostSignificantByteFirst) { byte[] array = (byte[])Data.Clone(); if (mostSignificantByteFirst) { Array.Reverse((Array)array); } return BitConverter.ToSingle(array, 0); } public float ToFloat() { return ToFloat(mostSignificantByteFirst: true); } public double ToDouble(bool mostSignificantByteFirst) { byte[] array = (byte[])Data.Clone(); if (mostSignificantByteFirst) { Array.Reverse((Array)array); } return BitConverter.ToDouble(array, 0); } public double ToDouble() { return ToDouble(mostSignificantByteFirst: true); } public double ToExtendedPrecision() { int num = ((this[0] & 0x7F) << 8) | this[1]; ulong num2 = ((ulong)this[2] << 24) | ((ulong)this[3] << 16) | ((ulong)this[4] << 8) | this[5]; ulong num3 = ((ulong)this[6] << 24) | ((ulong)this[7] << 16) | ((ulong)this[8] << 8) | this[9]; double num4; if (num == 0 && num2 == 0L && num3 == 0L) { num4 = 0.0; } else if (num == 32767) { num4 = double.PositiveInfinity; } else { num -= 16383; num4 = (double)num2 * Math.Pow(2.0, num -= 31); num4 += (double)num3 * Math.Pow(2.0, num -= 32); } if ((this[0] & 0x80) == 0) { return num4; } return 0.0 - num4; } public string ToString(StringType type, int offset, int count) { if (offset < 0 || offset > Count) { throw new ArgumentOutOfRangeException("offset"); } if (count < 0 || count + offset > Count) { throw new ArgumentOutOfRangeException("count"); } ByteVector bom = ((type == StringType.UTF16 && data.Count - offset > 1) ? Mid(offset, 2) : null); string @string = StringTypeToEncoding(type, bom).GetString(Data, offset, count); if (@string.Length != 0 && (@string[0] == '\ufffe' || @string[0] == '\ufeff')) { return @string.Substring(1); } return @string; } [Obsolete("Use ToString(StringType,int,int)")] public string ToString(StringType type, int offset) { return ToString(type, offset, Count - offset); } public string ToString(StringType type) { return ToString(type, 0, Count); } public override string ToString() { return ToString(StringType.UTF8, 0, Count); } public string[] ToStrings(StringType type, int offset) { return ToStrings(type, offset, int.MaxValue); } public string[] ToStrings(StringType type, int offset, int count) { int num = 0; int num2 = offset; List<string> list = new List<string>(); ByteVector byteVector = TextDelimiter(type); int count2 = byteVector.Count; while (num < count && num2 < Count) { int num3 = num2; if (num + 1 == count) { num2 = offset + count; } else { num2 = Find(byteVector, num3, count2); if (num2 < 0) { num2 = Count; } } int num4 = num2 - num3; if (num4 == 0) { list.Add(string.Empty); } else { string text = ToString(type, num3, num4); if (text.Length != 0 && (text[0] == '\ufffe' || text[0] == '\ufeff')) { text = text.Substring(1); } list.Add(text); } num2 += count2; } return list.ToArray(); } public static bool operator ==(ByteVector first, ByteVector second) { bool flag = (object)first == null; bool flag2 = (object)second == null; if (flag && flag2) { return true; } if (flag || flag2) { return false; } return first.Equals(second); } public static bool operator !=(ByteVector first, ByteVector second) { return !(first == second); } public static bool operator <(ByteVector first, ByteVector second) { if (first == null) { throw new ArgumentNullException("first"); } if (second == null) { throw new ArgumentNullException("second"); } return first.CompareTo(second) < 0; } public static bool operator <=(ByteVector first, ByteVector second) { if (first == null) { throw new ArgumentNullException("first"); } if (second == null) { throw new ArgumentNullException("second"); } return first.CompareTo(second) <= 0; } public static bool operator >(ByteVector first, ByteVector second) { if (first == null) { throw new ArgumentNullException("first"); } if (second == null) { throw new ArgumentNullException("second"); } return first.CompareTo(second) > 0; } public static bool operator >=(ByteVector first, ByteVector second) { if (first == null) { throw new ArgumentNullException("first"); } if (second == null) { throw new ArgumentNullException("second"); } return first.CompareTo(second) >= 0; } public static ByteVector operator +(ByteVector first, ByteVector second) { return new ByteVector(first) { second }; } public static implicit operator ByteVector(byte value) { return new ByteVector(value); } public static implicit operator ByteVector(byte[] value) { return new ByteVector(value); } public static implicit operator ByteVector(string value) { return FromString(value, StringType.UTF8); } public static ByteVector FromInt(int value, bool mostSignificantByteFirst) { ByteVector byteVector = new ByteVector(); for (int i = 0; i < 4; i++) { int num = (mostSignificantByteFirst ? (3 - i) : i); byteVector.Add((byte)((uint)(value >> num * 8) & 0xFFu)); } return byteVector; } public static ByteVector FromInt(int value) { return FromInt(value, mostSignificantByteFirst: true); } public static ByteVector FromUInt(uint value, bool mostSignificantByteFirst) { ByteVector byteVector = new ByteVector(); for (int i = 0; i < 4; i++) { int num = (mostSignificantByteFirst ? (3 - i) : i); byteVector.Add((byte)((value >> num * 8) & 0xFFu)); } return byteVector; } public static ByteVector FromUInt(uint value) { return FromUInt(value, mostSignificantByteFirst: true); } public static ByteVector FromShort(short value, bool mostSignificantByteFirst) { ByteVector byteVector = new ByteVector(); for (int i = 0; i < 2; i++) { int num = (mostSignificantByteFirst ? (1 - i) : i); byteVector.Add((byte)((uint)(value >> num * 8) & 0xFFu)); } return byteVector; } public static ByteVector FromShort(short value) { return FromShort(value, mostSignificantByteFirst: true); } public static ByteVector FromUShort(ushort value, bool mostSignificantByteFirst) { ByteVector byteVector = new ByteVector(); for (int i = 0; i < 2; i++) { int num = (mostSignificantByteFirst ? (1 - i) : i); byteVector.Add((byte)((uint)(value >> num * 8) & 0xFFu)); } return byteVector; } public static ByteVector FromUShort(ushort value) { return FromUShort(value, mostSignificantByteFirst: true); } public static ByteVector FromLong(long value, bool mostSignificantByteFirst) { ByteVector byteVector = new ByteVector(); for (int i = 0; i < 8; i++) { int num = (mostSignificantByteFirst ? (7 - i) : i); byteVector.Add((byte)((value >> num * 8) & 0xFF)); } return byteVector; } public static ByteVector FromLong(long value) { return FromLong(value, mostSignificantByteFirst: true); } public static ByteVector FromULong(ulong value, bool mostSignificantByteFirst) { ByteVector byteVector = new ByteVector(); for (int i = 0; i < 8; i++) { int num = (mostSignificantByteFirst ? (7 - i) : i); byteVector.Add((byte)((value >> num * 8) & 0xFF)); } return byteVector; } public static ByteVector FromULong(ulong value) { return FromULong(value, mostSignificantByteFirst: true); } public static ByteVector FromString(string text, StringType type, int length) { ByteVector byteVector = new ByteVector(); if (type == StringType.UTF16) { byteVector.Add(new byte[2] { 255, 254 }); } if (text == null || text.Length == 0) { return byteVector; } if (text.Length > length) { text = text.Substring(0, length); } byteVector.Add(StringTypeToEncoding(type, byteVector).GetBytes(text)); return byteVector; } public static ByteVector FromString(string text, StringType type) { return FromString(text, type, int.MaxValue); } public static ByteVector FromString(string text, int length) { return FromString(text, StringType.UTF8, length); } [Obsolete("Use FromString(string,StringType)")] public static ByteVector FromString(string text) { return FromString(text, StringType.UTF8); } public static ByteVector FromPath(string path) { byte[] firstChunk; return FromPath(path, out firstChunk, copyFirstChunk: false); } internal static ByteVector FromPath(string path, out byte[] firstChunk, bool copyFirstChunk) { if (path == null) { throw new ArgumentNullException("path"); } return FromFile(new File.LocalFileAbstraction(path), out firstChunk, copyFirstChunk); } public static ByteVector FromFile(File.IFileAbstraction abstraction) { byte[] firstChunk; return FromFile(abstraction, out firstChunk, copyFirstChunk: false); } internal static ByteVector FromFile(File.IFileAbstraction abstraction, out byte[] firstChunk, bool copyFirstChunk) { if (abstraction == null) { throw new ArgumentNullException("abstraction"); } Stream readStream = abstraction.ReadStream; ByteVector result = FromStream(readStream, out firstChunk, copyFirstChunk); abstraction.CloseStream(readStream); return result; } public static ByteVector FromStream(Stream stream) { byte[] firstChunk; return FromStream(stream, out firstChunk, copyFirstChunk: false); } internal static ByteVector FromStream(Stream stream, out byte[] firstChunk, bool copyFirstChunk) { ByteVector byteVector = new ByteVector(); byte[] array = new byte[4096]; int num = array.Length; int num2 = 0; bool flag = false; firstChunk = null; int num3; do { Array.Clear(array, 0, array.Length); num3 = stream.Read(array, 0, num); byteVector.Add(array); num2 += num3; if (flag) { continue; } if (copyFirstChunk) { if (firstChunk == null || firstChunk.Length != num) { firstChunk = new byte[num]; } Array.Copy(array, 0, firstChunk, 0, num3); } flag = true; } while ((num2 != stream.Length || stream.Length <= 0) && (num3 >= num || stream.Length > 0)); if (stream.Length > 0 && byteVector.Count != stream.Length) { byteVector.Resize((int)stream.Length); } return byteVector; } public static ByteVector TextDelimiter(StringType type) { if (type != StringType.UTF16 && type != StringType.UTF16BE && type != StringType.UTF16LE) { return td1; } return td2; } private static Encoding StringTypeToEncoding(StringType type, ByteVector bom) { switch (type) { case StringType.UTF16: if (bom == null) { return last_utf16_encoding; } if (bom[0] == byte.MaxValue && bom[1] == 254) { return last_utf16_encoding = Encoding.Unicode; } if (bom[1] == byte.MaxValue && bom[0] == 254) { return last_utf16_encoding = Encoding.BigEndianUnicode; } return last_utf16_encoding; case StringType.UTF16BE: return Encoding.BigEndianUnicode; case StringType.UTF8: return Encoding.UTF8; case StringType.UTF16LE: return Encoding.Unicode; default: if (use_broken_latin1) { return Encoding.Default; } try { return Encoding.GetEncoding("latin1"); } catch (ArgumentException) { return Encoding.UTF8; } } } public override bool Equals(object other) { if (!(other is ByteVector)) { return false; } return Equals((ByteVector)other); } public bool Equals(ByteVector other) { return CompareTo(other) == 0; } public override int GetHashCode() { return (int)Checksum; } public int CompareTo(ByteVector other) { if ((object)other == null) { throw new ArgumentNullException("other"); } int num = Count - other.Count; int num2 = 0; while (num == 0 && num2 < Count) { num = this[num2] - other[num2]; num2++; } return num; } public IEnumerator<byte> GetEnumerator() { return data.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return data.GetEnumerator(); } public void Clear() { if (IsReadOnly) { throw new NotSupportedException("Cannot edit readonly objects."); } data.Clear(); } public void Add(byte item) { if (IsReadOnly) { throw new NotSupportedException("Cannot edit readonly objects."); } data.Add(item); } public bool Remove(byte item) { if (IsReadOnly) { throw new NotSupportedException("Cannot edit readonly objects."); } return data.Remove(item); } public void CopyTo(byte[] array, int arrayIndex) { data.CopyTo(array, arrayIndex); } public bool Contains(byte item) { return data.Contains(item); } public void RemoveAt(int index) { if (IsReadOnly) { throw new NotSupportedException("Cannot edit readonly objects."); } data.RemoveAt(index); } public void Insert(int index, byte item) { if (IsReadOnly) { throw new NotSupportedException("Cannot edit readonly objects."); } data.Insert(index, item); } public int IndexOf(byte item) { return data.IndexOf(item); } } [ComVisible(false)] public class ByteVectorCollection : ListBase<ByteVector> { public ByteVectorCollection() { } public ByteVectorCollection(IEnumerable<ByteVector> list) { if (list != null) { Add(list); } } public ByteVectorCollection(params ByteVector[] list) { if (list != null) { Add(list); } } public override void SortedInsert(ByteVector item, bool unique) { if (item == null) { throw new ArgumentNullException("item"); } int i; for (i = 0; i < base.Count; i++) { if (item == base[i] && unique) { return; } if (item >= base[i]) { break; } } Insert(i + 1, item); } public ByteVector ToByteVector(ByteVector separator) { if (separator == null) { throw new ArgumentNullException("separator"); } ByteVector byteVector = new ByteVector(); for (int i = 0; i < base.Count; i++) { if (i != 0 && separator.Count > 0) { byteVector.Add(separator); } byteVector.Add(base[i]); } return byteVector; } public static ByteVectorCollection Split(ByteVector vector, ByteVector pattern, int byteAlign, int max) { if (vector == null) { throw new ArgumentNullException("vector"); } if (pattern == null) { throw new ArgumentNullException("pattern"); } if (byteAlign < 1) { throw new ArgumentOutOfRangeException("byteAlign", "byteAlign must be at least 1."); } ByteVectorCollection byteVectorCollection = new ByteVectorCollection(); int num = 0; int num2 = vector.Find(pattern, 0, byteAlign); while (num2 != -1 && (max < 1 || max > byteVectorCollection.Count + 1)) { byteVectorCollection.Add(vector.Mid(num, num2 - num)); num = num2 + pattern.Count; num2 = vector.Find(pattern, num2 + pattern.Count, byteAlign); } if (num < vector.Count) { byteVectorCollection.Add(vector.Mid(num, vector.Count - num)); } return byteVectorCollection; } public static ByteVectorCollection Split(ByteVector vector, ByteVector pattern, int byteAlign) { return Split(vector, pattern, byteAlign, 0); } public static ByteVectorCollection Split(ByteVector vector, ByteVector pattern) { return Split(vector, pattern, 1); } } public class CombinedTag : Tag { private readonly List<Tag> tags; public virtual Tag[] Tags => tags.ToArray(); public override TagTypes TagTypes { get { TagTypes tagTypes = TagTypes.None; foreach (Tag tag in tags) { if (tag != null) { tagTypes |= tag.TagTypes; } } return tagTypes; } } public override string Title { get { foreach (Tag tag in tags) { if (tag != null) { string title = tag.Title; if (title != null) { return title; } } } return null; } set { foreach (Tag tag in tags) { if (tag != null) { tag.Title = value; } } } } public override string Subtitle { get { foreach (Tag tag in tags) { if (tag != null) { string subtitle = tag.Subtitle; if (subtitle != null) { return subtitle; } } } return null; } set { foreach (Tag tag in tags) { if (tag != null) { tag.Subtitle = value; } } } } public override string Description { get { foreach (Tag tag in tags) { if (tag != null) { string description = tag.Description; if (description != null) { return description; } } } return null; } set { foreach (Tag tag in tags) { if (tag != null) { tag.Description = value; } } } } public override string[] Performers { get { foreach (Tag tag in tags) { if (tag != null) { string[] performers = tag.Performers; if (performers != null && performers.Length != 0) { return performers; } } } return new string[0]; } set { foreach (Tag tag in tags) { if (tag != null) { tag.Performers = value; } } } } public override string[] PerformersSort { get { foreach (Tag tag in tags) { if (tag != null) { string[] performersSort = tag.PerformersSort; if (performersSort != null && performersSort.Length != 0) { return performersSort; } } } return new string[0]; } set { foreach (Tag tag in tags) { if (tag != null) { tag.PerformersSort = value; } } } } public override string[] PerformersRole { get { foreach (Tag tag in tags) { if (tag != null) { string[] performersRole = tag.PerformersRole; if (performersRole != null && performersRole.Length != 0) { return performersRole; } } } return new string[0]; } set { foreach (Tag tag in tags) { if (tag != null) { tag.PerformersRole = value; } } } } public override string[] AlbumArtistsSort { get { foreach (Tag tag in tags) { if (tag != null) { string[] albumArtistsSort = tag.AlbumArtistsSort; if (albumArtistsSort != null && albumArtistsSort.Length != 0) { return albumArtistsSort; } } } return new string[0]; } set { foreach (Tag tag in tags) { if (tag != null) { tag.AlbumArtistsSort = value; } } } } public override string[] AlbumArtists { get { foreach (Tag tag in tags) { if (tag != null) { string[] albumArtists = tag.AlbumArtists; if (albumArtists != null && albumArtists.Length != 0) { return albumArtists; } } } return new string[0]; } set { foreach (Tag tag in tags) { if (tag != null) { tag.AlbumArtists = value; } } } } public override string[] Composers { get { foreach (Tag tag in tags) { if (tag != null) { string[] composers = tag.Composers; if (composers != null && composers.Length != 0) { return composers; } } } return new string[0]; } set { foreach (Tag tag in tags) { if (tag != null) { tag.Composers = value; } } } } public override string[] ComposersSort { get { foreach (Tag tag in tags) { if (tag != null) { string[] composersSort = tag.ComposersSort; if (composersSort != null && composersSort.Length != 0) { return composersSort; } } } return new string[0]; } set { foreach (Tag tag in tags) { if (tag != null) { tag.ComposersSort = value; } } } } public override string TitleSort { get { foreach (Tag tag in tags) { if (tag != null) { string titleSort = tag.TitleSort; if (titleSort != null && titleSort.Length > 0) { return titleSort; } } } return null; } set { foreach (Tag tag in tags) { if (tag != null) { tag.TitleSort = value; } } } } public override string AlbumSort { get { foreach (Tag tag in tags) { if (tag != null) { string albumSort = tag.AlbumSort; if (albumSort != null && albumSort.Length > 0) { return albumSort; } } } return null; } set { foreach (Tag tag in tags) { if (tag != null) { tag.AlbumSort = value; } } } } public override string Album { get { foreach (Tag tag in tags) { if (tag != null) { string album = tag.Album; if (album != null) { return album; } } } return null; } set { foreach (Tag tag in tags) { if (tag != null) { tag.Album = value; } } } } public override string Comment { get { foreach (Tag tag in tags) { if (tag != null) { string comment = tag.Comment; if (comment != null) { return comment; } } } return null; } set { foreach (Tag tag in tags) { if (tag != null) { tag.Comment = value; } } } } public override string[] Genres { get { foreach (Tag tag in tags) { if (tag != null) { string[] genres = tag.Genres; if (genres != null && genres.Length != 0) { return genres; } } } return new string[0]; } set { foreach (Tag tag in tags) { if (tag != null) { tag.Genres = value; } } } } public override uint Year { get { foreach (Tag tag in tags) { if (tag != null) { uint year = tag.Year; if (year != 0) { return year; } } } return 0u; } set { foreach (Tag tag in tags) { if (tag != null) { tag.Year = value; } } } } public override uint Track { get { foreach (Tag tag in tags) { if (tag != null) { uint track = tag.Track; if (track != 0) { return track; } } } return 0u; } set { foreach (Tag tag in tags) { if (tag != null) { tag.Track = value; } } } } public override uint TrackCount { get { foreach (Tag tag in tags) { if (tag != null) { uint trackCount = tag.TrackCount; if (trackCount != 0) { return trackCount; } } } return 0u; } set { foreach (Tag tag in tags) { if (tag != null) { tag.TrackCount = value; } } } } public override uint Disc { get { foreach (Tag tag in tags) { if (tag != null) { uint disc = tag.Disc; if (disc != 0) { return disc; } } } return 0u; } set { foreach (Tag tag in tags) { if (tag != null) { tag.Disc = value; } } } } public override uint DiscCount { get { foreach (Tag tag in tags) { if (tag != null) { uint discCount = tag.DiscCount; if (discCount != 0) { return discCount; } } } return 0u; } set { foreach (Tag tag in tags) { if (tag != null) { tag.DiscCount = value; } } } } public override string Lyrics { get { foreach (Tag tag in tags) { if (tag != null) { string lyrics = tag.Lyrics; if (lyrics != null) { return lyrics; } } } return null; } set { foreach (Tag tag in tags) { if (tag != null) { tag.Lyrics = value; } } } } public override string Grouping { get { foreach (Tag tag in tags) { if (tag != null) { string grouping = tag.Grouping; if (grouping != null) { return grouping; } } } return null; } set { foreach (Tag tag in tags) { if (tag != null) { tag.Grouping = value; } } } } public override uint BeatsPerMinute { get { foreach (Tag tag in tags) { if (tag != null) { uint beatsPerMinute = tag.BeatsPerMinute; if (beatsPerMinute != 0) { return beatsPerMinute; } } } return 0u; } set { foreach (Tag tag in tags) { if (tag != null) { tag.BeatsPerMinute = value; } } } } public override string Conductor { get { foreach (Tag tag in tags) { if (tag != null) { string conductor = tag.Conductor; if (conductor != null) { return conductor; } } } return null; } set { foreach (Tag tag in tags) { if (tag != null) { tag.Conductor = value; } } } } public override string Copyright { get { foreach (Tag tag in tags) { if (tag != null) { string copyright = tag.Copyright; if (copyright != null) { return copyright; } } } return null; } set { foreach (Tag tag in tags) { if (tag != null) { tag.Copyright = value; } } } } public override DateTime? DateTagged { get { foreach (Tag tag in tags) { if (tag != null) { DateTime? dateTagged = tag.DateTagged; if (dateTagged.HasValue) { return dateTagged; } } } return null; } set { foreach (Tag tag in tags) { if (tag != null) { tag.DateTagged = value; } } } } public override string MusicBrainzArtistId { get { foreach (Tag tag in tags) { if (tag != null) { string musicBrainzArtistId = tag.MusicBrainzArtistId; if (musicBrainzArtistId != null) { return musicBrainzArtistId; } } } return null; } set { foreach (Tag tag in tags) { if (tag != null) { tag.MusicBrainzArtistId = value; } } } } public override string MusicBrainzReleaseGroupId { get { foreach (Tag tag in tags) { if (tag != null) { string musicBrainzReleaseGroupId = tag.MusicBrainzReleaseGroupId; if (musicBrainzReleaseGroupId != null) { return musicBrainzReleaseGroupId; } } } return null; } set { foreach (Tag tag in tags) { if (tag != null) { tag.MusicBrainzReleaseGroupId = value; } } } } public override string MusicBrainzReleaseId { get { foreach (Tag tag in tags) { if (tag != null) { string musicBrainzReleaseId = tag.MusicBrainzReleaseId; if (musicBrainzReleaseId != null) { return musicBrainzReleaseId; } } } return null; } set { foreach (Tag tag in tags) { if (tag != null) { tag.MusicBrainzReleaseId = value; } } } } public override string MusicBrainzReleaseArtistId { get { foreach (Tag tag in tags) { if (tag != null) { string musicBrainzReleaseArtistId = tag.MusicBrainzReleaseArtistId; if (musicBrainzReleaseArtistId != null) { return musicBrainzReleaseArtistId; } } } return null; } set { foreach (Tag tag in tags) { if (tag != null) { tag.MusicBrainzReleaseArtistId = value; } } } } public override string MusicBrainzTrackId { get { foreach (Tag tag in tags) { if (tag != null) { string musicBrainzTrackId = tag.MusicBrainzTrackId; if (musicBrainzTrackId != null) { return musicBrainzTrackId; } } } return null; } set { foreach (Tag tag in tags) { if (tag != null) { tag.MusicBrainzTrackId = value; } } } } public override string MusicBrainzDiscId { get { foreach (Tag tag in tags) { if (tag != null) { string musicBrainzDiscId = tag.MusicBrainzDiscId; if (musicBrainzDiscId != null) { return musicBrainzDiscId; } } } return null; } set { foreach (Tag tag in tags) { if (tag != null) { tag.MusicBrainzDiscId = value; } } } } public override string MusicIpId { get { foreach (Tag tag in tags) { if (tag != null) { string musicIpId = tag.MusicIpId; if (musicIpId != null) { return musicIpId; } } } return null; } set { foreach (Tag tag in tags) { if (tag != null) { tag.MusicIpId = value; } } } } public override string AmazonId { get { foreach (Tag tag in tags) { if (tag != null) { string amazonId = tag.AmazonId; if (amazonId != null) { return amazonId; } } } return null; } set { foreach (Tag tag in tags) { if (tag != null) { tag.AmazonId = value; } } } } public override string MusicBrainzReleaseStatus { get { foreach (Tag tag in tags) { if (tag != null) { string musicBrainzReleaseStatus = tag.MusicBrainzReleaseStatus; if (musicBrainzReleaseStatus != null) { return musicBrainzReleaseStatus; } } } return null; } set { foreach (Tag tag in tags) { if (tag != null) { tag.MusicBrainzReleaseStatus = value; } } } } public override string MusicBrainzReleaseType { get { foreach (Tag tag in tags) { if (tag != null) { string musicBrainzReleaseType = tag.MusicBrainzReleaseType; if (musicBrainzReleaseType != null) { return musicBrainzReleaseType; } } } return null; } set { foreach (Tag tag in tags) { if (tag != null) { tag.MusicBrainzReleaseType = value; } } } } public override string MusicBrainzReleaseCountry { get { foreach (Tag tag in tags) { if (tag != null) { string musicBrainzReleaseCountry = tag.MusicBrainzReleaseCountry; if (musicBrainzReleaseCountry != null) { return musicBrainzReleaseCountry; } } } return null; } set { foreach (Tag tag in tags) { if (tag != null) { tag.MusicBrainzReleaseCountry = value; } } } } public override IPicture[] Pictures { get { foreach (Tag tag in tags) { if (tag != null) { IPicture[] pictures = tag.Pictures; if (pictures != null && pictures.Length != 0) { return pictures; } } } return base.Pictures; } set { foreach (Tag tag in tags) { if (tag != null) { tag.Pictures = value; } } } } public override double ReplayGainTrackGain { get { foreach (Tag tag in tags) { if (tag != null) { double replayGainTrackGain = tag.ReplayGainTrackGain; if (!double.IsNaN(replayGainTrackGain)) { return replayGainTrackGain; } } } return double.NaN; } set { foreach (Tag tag in tags) { if (tag != null) { tag.ReplayGainTrackGain = value; } } } } public override double ReplayGainTrackPeak { get { foreach (Tag tag in tags) { if (tag != null) { double replayGainTrackPeak = tag.ReplayGainTrackPeak; if (!double.IsNaN(replayGainTrackPeak)) { return replayGainTrackPeak; } } } return double.NaN; } set { foreach (Tag tag in tags) { if (tag != null) { tag.ReplayGainTrackPeak = value; } } } } public override double ReplayGainAlbumGain { get { foreach (Tag tag in tags) { if (tag != null) { double replayGainAlbumGain = tag.ReplayGainAlbumGain; if (!double.IsNaN(replayGainAlbumGain)) { return replayGainAlbumGain; } } } return double.NaN; } set { foreach (Tag tag in tags) { if (tag != null) { tag.ReplayGainAlbumGain = value; } } } } public override double ReplayGainAlbumPeak { get { foreach (Tag tag in tags) { if (tag != null) { double replayGainAlbumPeak = tag.ReplayGainAlbumPeak; if (!double.IsNaN(replayGainAlbumPeak)) { return replayGainAlbumPeak; } } } return double.NaN; } set { foreach (Tag tag in tags) { if (tag != null) { tag.ReplayGainAlbumPeak = value; } } } } public override string InitialKey { get { foreach (Tag tag in tags) { if (tag != null) { string initialKey = tag.InitialKey; if (initialKey != null) { return initialKey; } } } return null; } set { foreach (Tag tag in tags) { if (tag != null) { tag.InitialKey = value; } } } } public override string RemixedBy { get { foreach (Tag tag in tags) { if (tag != null) { string remixedBy = tag.RemixedBy; if (remixedBy != null) { return remixedBy; } } } return null; } set { foreach (Tag tag in tags) { if (tag != null) { tag.RemixedBy = value; } } } } public override string Publisher { get { foreach (Tag tag in tags) { if (tag != null) { string publisher = tag.Publisher; if (publisher != null) { return publisher; } } } return null; } set { foreach (Tag tag in tags) { if (tag != null) { tag.Publisher = value; } } } } public override string ISRC { get { foreach (Tag tag in tags) { if (tag != null) { string iSRC = tag.ISRC; if (iSRC != null) { return iSRC; } } } return null; } set { foreach (Tag tag in tags) { if (tag != null) { tag.ISRC = value; } } } } public override string Length { get { foreach (Tag tag in tags) { if (tag != null) { string length = tag.Length; if (length != null) { return length; } } } return null; } set { foreach (Tag tag in tags) { if (tag != null) { tag.Length = value; } } } } public override bool IsEmpty { get { foreach (Tag tag in tags) { if (tag.IsEmpty) { return true; } } return false; } } public CombinedTag() { tags = new List<Tag>(); } public CombinedTag(params Tag[] tags) { this.tags = new List<Tag>(tags); } public void SetTags(params Tag[] tags) { this.tags.Clear(); this.tags.AddRange(tags); } protected void InsertTag(int index, Tag tag) { tags.Insert(index, tag); } protected void AddTag(Tag tag) { tags.Add(tag); } protected void RemoveTag(Tag tag) { tags.Remove(tag); } protected void ClearTags() { tags.Clear(); } public override void Clear() { foreach (Tag tag in tags) { tag.Clear(); } } } [Serializable] public class CorruptFileException : Exception { public CorruptFileException(string message) : base(message) { } public CorruptFileException() { } public CorruptFileException(string message, Exception innerException) : base(message, innerException) { } protected CorruptFileException(SerializationInfo info, StreamingContext context) : base(info, context) { } } internal static class Debugger { public delegate void DebugMessageSentHandler(string message); private struct DebugTimeData { public TimeSpan time; public long occurances; public DebugTimeData(TimeSpan time, int occurances) { this.time = time; this.occurances = occurances; } } private static readonly string allowed = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ`~!@#$%^&*()_+-={}[];:'\",.<>?/\\|"; private static readonly Dictionary<object, Dictionary<object, DebugTimeData>> debug_times = new Dictionary<object, Dictionary<object, DebugTimeData>>(); public static event DebugMessageSentHandler DebugMessageSent; public static void Debug(string message) { Debugger.DebugMessageSent?.Invoke(message); } public static void DumpHex(ByteVector data) { DumpHex(data.Data); } public static void DumpHex(byte[] data) { int num = 16; int num2 = data.Length / num + ((data.Length % num != 0) ? 1 : 0); for (int i = 0; i < num2; i++) { for (int j = 0; j < num; j++) { if (i == num2 - 1 && data.Length % num != 0 && j >= data.Length % num) { Console.Write(" "); } else { Console.Write(" {0:x2}", data[i * num + j]); } } Console.Write(" | "); for (int k = 0; k < num; k++) { if (i == num2 - 1 && data.Length % num != 0 && k >= data.Length % num) { Console.Write(" "); } else { WriteByte2(data[i * num + k]); } } Console.WriteLine(); } Console.WriteLine(); } private static void WriteByte2(byte data) { string text = allowed; foreach (char c in text) { if (c == data) { Console.Write(c); return; } } Console.Write("."); } public static void AddDebugTime(object o1, object o2, DateTime start) { DebugTimeData value = new DebugTimeData(DateTime.Now - start, 1); if (debug_times.ContainsKey(o1) && debug_times[o1].ContainsKey(o2)) { value.time += debug_times[o1][o2].time; value.occurances += debug_times[o1][o2].occurances; } if (!debug_times.ContainsKey(o1)) { debug_times.Add(o1, new Dictionary<object, DebugTimeData>()); } if (!debug_times[o1].ContainsKey(o2)) { debug_times[o1].Add(o2, value); } else { debug_times[o1][o2] = value; } } public static void DumpDebugTime(object o1) { Console.WriteLine(o1.ToString()); if (!debug_times.ContainsKey(o1)) { return; } foreach (KeyValuePair<object, DebugTimeData> item in debug_times[o1]) { Console.WriteLine(" {0}", item.Key); Console.WriteLine(" Objects: {0}", item.Value.time); Console.WriteLine(" Total: {0}", item.Value.occurances); Console.WriteLine(" Average: {0}", new TimeSpan(item.Value.time.Ticks / item.Value.occurances)); Console.WriteLine(); } debug_times.Remove(o1); } } [Flags] public enum ReadStyle { None = 0, Average = 2, PictureLazy = 4 } public abstract class File : IDisposable { public enum AccessMode { Read, Write, Closed } public delegate File FileTypeResolver(IFileAbstraction abstraction, string mimetype, ReadStyle style); public class LocalFileAbstraction : IFileAbstraction { private readonly string name; public string Name => name; public Stream ReadStream => System.IO.File.Open(Name, FileMode.Open, FileAccess.Read, FileShare.Read); public Stream WriteStream => System.IO.File.Open(Name, FileMode.Open, FileAccess.ReadWrite); public LocalFileAbstraction(string path) { if (path == null) { throw new ArgumentNullException("path"); } name = path; } public void CloseStream(Stream stream) { if (stream == null) { throw new ArgumentNullException("stream"); } stream.Close(); } } public interface IFileAbstraction { string Name { get; } Stream ReadStream { get; } Stream WriteStream { get; } void CloseStream(Stream stream); } private Stream file_stream; protected IFileAbstraction file_abstraction; private static readonly int buffer_size = 1024; private static readonly List<FileTypeResolver> file_type_resolvers = new List<FileTypeResolver>(); private List<string> corruption_reasons; public static uint BufferSize => (uint)buffer_size; public abstract Tag Tag { get; } public abstract Properties Properties { get; } public TagTypes TagTypesOnDisk { get; protected set; } public TagTypes TagTypes => Tag?.TagTypes ?? TagTypes.None; public string Name => file_abstraction.Name; public string MimeType { get; internal set; } public long Tell { get { if (Mode != AccessMode.Closed) { return file_stream.Position; } return 0L; } } public long Length { get { if (Mode != AccessMode.Closed) { return file_stream.Length; } return 0L; } } public long InvariantStartPosition { get; protected set; } = -1L; public long InvariantEndPosition { get; protected set; } = -1L; public AccessMode Mode { get { if (file_stream == null) { return AccessMode.Closed; } if (file_stream.CanWrite) { return AccessMode.Write; } return AccessMode.Read; } set { if (Mode != value && (Mode != AccessMode.Write || value != 0)) { if (file_stream != null) { file_abstraction.CloseStream(file_stream); } file_stream = null; switch (value) { case AccessMode.Read: file_stream = file_abstraction.ReadStream; break; case AccessMode.Write: file_stream = file_abstraction.WriteStream; break; } Mode = value; } } } public IFileAbstraction FileAbstraction => file_abstraction; public virtual bool Writeable => !PossiblyCorrupt; public bool PossiblyCorrupt => corruption_reasons != null; public IEnumerable<string> CorruptionReasons => corruption_reasons; protected File(string path) { if (path == null) { throw new ArgumentNullException("path"); } file_abstraction = new LocalFileAbstraction(path); } protected File(IFileAbstraction abstraction) { if (abstraction == null) { throw new ArgumentNullException("abstraction"); } file_abstraction = abstraction; } internal void MarkAsCorrupt(string reason) { if (corruption_reasons == null) { corruption_reasons = new List<string>(); } corruption_reasons.Add(reason); } public void Dispose() { Mode = AccessMode.Closed; } public abstract void Save(); public abstract void RemoveTags(TagTypes types); public abstract Tag GetTag(TagTypes type, bool create); public Tag GetTag(TagTypes type) { return GetTag(type, create: false); } public ByteVector ReadBlock(int length) { if (length < 0) { throw new ArgumentException("Length must be non-negative", "length"); } if (length == 0) { return new ByteVector(); } Mode = AccessMode.Read; byte[] array = new byte[length]; int num = 0; int num2 = 0; int num3 = length; do { num = file_stream.Read(array, num2, num3); num2 += num; num3 -= num; } while (num3 > 0 && num != 0); return new ByteVector(array, num2); } public void WriteBlock(ByteVector data) { if (data == null) { throw new ArgumentNullException("data"); } Mode = AccessMode.Write; file_stream.Write(data.Data, 0, data.Count); } public long Find(ByteVector pattern, long startPosition, ByteVector before) { if (pattern == null) { throw new ArgumentNullException("pattern"); } Mode = AccessMode.Read; if (pattern.Count > buffer_size) { return -1L; } long num = startPosition; long position = file_stream.Position; try { file_stream.Position = startPosition; ByteVector byteVector = ReadBlock(buffer_size); while (byteVector.Count > 0) { int num2 = byteVector.Find(pattern); if (before != null && byteVector.Find(before) < num2) { return -1L; } if (num2 >= 0) { return num + num2; } num += buffer_size - pattern.Count; if (before != null && before.Count > pattern.Count) { num -= before.Count - pattern.Count; } file_stream.Position = num; byteVector = ReadBlock(buffer_size); } return -1L; } finally { file_stream.Position = position; } } public long Find(ByteVector pattern, long startPosition) { return Find(pattern, startPosition, null); } public long Find(ByteVector pattern) { return Find(pattern, 0L); } private long RFind(ByteVector pattern, long startPosition, ByteVector after) { if (pattern == null) { throw new ArgumentNullException("pattern"); } Mode = AccessMode.Read; if (pattern.Count > buffer_size) { return -1L; } long position = file_stream.Position; long num = Length - startPosition; int num2 = buffer_size; num2 = (int)Math.Min(num, buffer_size); num -= num2; file_stream.Position = num; ByteVector byteVector = ReadBlock(num2); while (byteVector.Count > 0) { long num3 = byteVector.RFind(pattern); if (num3 >= 0) { file_stream.Position = position; return num + num3; } if (after != null && byteVector.RFind(after) >= 0) { file_stream.Position = position; return -1L; } num2 = (int)Math.Min(num, buffer_size); num -= num2; if (num2 + pattern.Count > buffer_size) { num += pattern.Count; } file_stream.Position = num; byteVector = ReadBlock(num2); } file_stream.Position = position; return -1L; } public long RFind(ByteVector pattern, long startPosition) { return RFind(pattern, startPosition, null); } public long RFind(ByteVector pattern) { return RFind(pattern, 0L); } public void Insert(ByteVector data, long start, long replace) { if (data == null) { throw new ArgumentNullException("data"); } Insert(data, data.Count, start, replace); } public void Insert(ByteVector data, long start) { Insert(data, start, 0L); } public void Insert(long size, long start) { Insert(null, size, start, 0L); } public void RemoveBlock(long start, long length) { if (length > 0) { Mode = AccessMode.Write; int length2 = buffer_size; long num = start + length; long num2 = start; ByteVector byteVector = (byte)1; while (byteVector.Count != 0) { file_stream.Position = num; byteVector = ReadBlock(length2); num += byteVector.Count; file_stream.Position = num2; WriteBlock(byteVector); num2 += byteVector.Count; } Truncate(num2); } } public void Seek(long offset, SeekOrigin origin) { if (Mode != AccessMode.Closed) { file_stream.Seek(offset, origin); } } public void Seek(long offset) { Seek(offset, SeekOrigin.Begin); } public static File Create(string path) { return Create(path, null, ReadStyle.Average); } public static File Create(IFileAbstraction abstraction) { return Create(abstraction, null, ReadStyle.Average); } public static File Create(string path, ReadStyle propertiesStyle) { return Create(path, null, propertiesStyle); } public static File Create(IFileAbstraction abstraction, ReadStyle propertiesStyle) { return Create(abstraction, null, propertiesStyle); } public static File Create(string path, string mimetype, ReadStyle propertiesStyle) { return Create(new LocalFileAbstraction(path), mimetype, propertiesStyle); } public static File Create(IFileAbstraction abstraction, string mimetype, ReadStyle propertiesStyle) { if (mimetype == null) { string text = string.Empty; int num = abstraction.Name.LastIndexOf(".") + 1; if (num >= 1 && num < abstraction.Name.Length) { text = abstraction.Name.Substring(num, abstraction.Name.Length - num); } mimetype = "taglib/" + text.ToLower(CultureInfo.InvariantCulture); } foreach (FileTypeResolver file_type_resolver in file_type_resolvers) { File file = file_type_resolver(abstraction, mimetype, propertiesStyle); if (file != null) { return file; } } if (!FileTypes.AvailableTypes.ContainsKey(mimetype)) { throw new UnsupportedFormatException(string.Format(CultureInfo.InvariantCulture, "{0} ({1})", abstraction.Name, mimetype)); } Type type = FileTypes.AvailableTypes[mimetype]; try { File obj = (File)Activator.CreateInstance(type, abstraction, propertiesStyle); obj.MimeType = mimetype; return obj; } catch (TargetInvocationException ex) { PrepareExceptionForRethrow(ex.InnerException); throw ex.InnerException; } } public static void AddFileTypeResolver(FileTypeResolver resolver) { if (resolver != null) { file_type_resolvers.Insert(0, resolver); } } protected void PreSave() { if (!Writeable) { throw new InvalidOperationException("File not writeable."); } if (PossiblyCorrupt) { throw new CorruptFileException("Corrupted file cannot be saved."); } if (Tag?.Pictures == null) { return; } IPicture[] pictures = Tag.Pictures; for (int i = 0; i < pictures.Length; i++) { if (pictures[i] is ILazy lazy) { lazy.Load(); } } } private void Insert(ByteVector data, long size, long start, long replace) { Mode = AccessMode.Write; if (size == replace) { if (data != null) { file_stream.Position = start; WriteBlock(data); } return; } if (size < replace) { if (data != null) { file_stream.Position = start; WriteBlock(data); } RemoveBlock(start + size, replace - size); return; } int num = (int)(size - replace); int num2 = num % buffer_size; if (num2 != 0) { num += buffer_size - num2; } long num3 = start + replace; long num4 = start; file_stream.Position = num3; byte[] data2 = ReadBlock(num).Data; num3 += num; if (data != null) { file_stream.Position = num4; WriteBlock(data); } else if (start + size > Length) { file_stream.SetLength(start + size); } num4 += size; byte[] array = new byte[data2.Length]; Array.Copy(data2, 0, array, 0, data2.Length); while (num != 0) { file_stream.Position = num3; int num5 = file_stream.Read(data2, 0, (num < data2.Length) ? num : data2.Length); num3 += num; file_stream.Position = num4; file_stream.Write(array, 0, (num < array.Length) ? num : array.Length); num4 += num; Array.Copy(data2, 0, array, 0, num5); num = num5; } } protected void Truncate(long length) { AccessMode mode = Mode; Mode = AccessMode.Write; file_stream.SetLength(length); Mode = mode; } private static void PrepareExceptionForRethrow(Exception ex) { StreamingContext context = new StreamingContext(StreamingContextStates.CrossAppDomain); ObjectManager objectManager = new ObjectManager(null, context); SerializationInfo info = new SerializationInfo(ex.GetType(), new FormatterConverter()); ex.GetObjectData(info, context); objectManager.RegisterObject(ex, 1L, info); objectManager.DoFixups(); } } public static class FileTypes { private static Dictionary<string, Type> file_types; private static readonly Type[] static_file_types; public static IDictionary<string, Type> AvailableTypes => file_types; static FileTypes() { static_file_types = new Type[26] { typeof(TagLib.Aac.File), typeof(TagLib.Aiff.File), typeof(TagLib.Ape.File), typeof(TagLib.Asf.File), typeof(TagLib.Audible.File), typeof(TagLib.Dsf.File), typeof(TagLib.Flac.File), typeof(TagLib.Matroska.File), typeof(TagLib.Gif.File), typeof(TagLib.Image.NoMetadata.File), typeof(TagLib.Jpeg.File), typeof(TagLib.Mpeg4.File), typeof(AudioFile), typeof(TagLib.Mpeg.File), typeof(TagLib.MusePack.File), typeof(TagLib.Ogg.File), typeof(TagLib.Png.File), typeof(TagLib.Riff.File), typeof(TagLib.Tiff.Arw.File), typeof(TagLib.Tiff.Cr2.File), typeof(TagLib.Tiff.Dng.File), typeof(TagLib.Tiff.File), typeof(TagLib.Tiff.Nef.File), typeof(TagLib.Tiff.Pef.File), typeof(TagLib.Tiff.Rw2.File), typeof(TagLib.WavPack.File) }; Init(); } internal static void Init() { if (file_types == null) { file_types = new Dictionary<string, Type>(); Type[] array = static_file_types; for (int i = 0; i < array.Length; i++) { Register(array[i]); } } } public static void Register(Type type) { Attribute[] customAttributes = Attribute.GetCustomAttributes(type, typeof(SupportedMimeType), inherit: false); if (customAttributes.Length != 0) { Attribute[] array = customAttributes; for (int i = 0; i < array.Length; i++) { SupportedMimeType supportedMimeType = (SupportedMimeType)array[i]; file_types.Add(supportedMimeType.MimeType, type); } } } } public static class Genres { private static readonly string[] audio = new string[148] { "Blues", "Classic Rock", "Country", "Dance", "Disco", "Funk", "Grunge", "Hip-Hop", "Jazz", "Metal", "New Age", "Oldies", "Other", "Pop", "R&B", "Rap", "Reggae", "Rock", "Techno", "Industrial", "Alternative", "Ska", "Death Metal", "Pranks", "Soundtrack", "Euro-Techno", "Ambient", "Trip-Hop", "Vocal", "Jazz+Funk", "Fusion", "Trance", "Classical", "Instrumental", "Acid", "House", "Game", "Sound Clip", "Gospel", "Noise", "Alternative Rock", "Bass", "Soul", "Punk", "Space", "Meditative", "Instrumental Pop", "Instrumental Rock", "Ethnic", "Gothic", "Darkwave", "Techno-Industrial", "Electronic", "Pop-Folk", "Eurodance", "Dream", "Southern Rock", "Comedy", "Cult", "Gangsta", "Top 40", "Christian Rap", "Pop/Funk", "Jungle", "Native American", "Cabaret", "New Wave", "Psychedelic", "Rave", "Showtunes", "Trailer", "Lo-Fi", "Tribal", "Acid Punk", "Acid Jazz", "Polka", "Retro", "Musical", "Rock & Roll", "Hard Rock", "Folk", "Folk/Rock", "National Folk", "Swing", "Fusion", "Bebob", "Latin", "Revival", "Celtic", "Bluegrass", "Avantgarde", "Gothic Rock", "Progressive Rock", "Psychedelic Rock", "Symphonic Rock", "Slow Rock", "Big Band", "Chorus", "Easy Listening", "Acoustic", "Humour", "Speech", "Chanson", "Opera", "Chamber Music", "Sonata", "Symphony", "Booty Bass", "Primus", "Porn Groove", "Satire", "Slow Jam", "Club", "Tango", "Samba", "Folklore", "Ballad", "Power Ballad", "Rhythmic Soul", "Freestyle", "Duet", "Punk Rock", "Drum Solo", "A Cappella", "Euro-House", "Dance Hall", "Goa", "Drum & Bass", "Club-House", "Hardcore", "Terror", "Indie", "BritPop", "Negerpunk", "Polsk Punk", "Beat", "Christian Gangsta Rap", "Heavy Metal", "Black Metal", "Crossover", "Contemporary Christian", "Christian Rock", "Merengue", "Salsa", "Thrash Metal", "Anime", "Jpop", "Synthpop" }; private static readonly string[] video = new string[40] { "Action", "Action/Adventure", "Adult", "Adventure", "Catastrophe", "Child's", "Claymation", "Comedy", "Concert", "Documentary", "Drama", "Eastern", "Entertaining", "Erotic", "Extremal Sport", "Fantasy", "Fashion", "Historical", "Horror", "Horror/Mystic", "Humor", "Indian", "Informercial", "Melodrama", "Military & War", "Music Video", "Musical", "Mystery", "Nature", "Political Satire", "Popular Science", "Psychological Thriller", "Religion", "Science Fiction", "Scifi Action", "Slapstick", "Splatter", "Sports", "Thriller", "Western" }; public static string[] Audio => (string[])audio.Clone(); public static string[] Video => (string[])video.Clone(); public static byte AudioToIndex(string name) { for (byte b = 0; b < audio.Length; b++) { if (name == audio[b]) { return b; } } return byte.MaxValue; } public static byte VideoToIndex(string name) { for (byte b = 0; b < video.Length; b++) { if (name == video[b]) { return b; } } return byte.MaxValue; } public static string IndexToAudio(byte index) { if (index >= audio.Length) { return null; } return audio[index]; } public static string IndexToVideo(byte index) { if (index >= video.Length) { return null; } return video[index]; } public static string IndexToAudio(string text) { return IndexToAudio(StringToByte(text)); } public static string IndexToVideo(string text) { return IndexToVideo(StringToByte(text)); } private static byte StringToByte(string text) { int num; if (text != null && text.Length > 2 && text[0] == '(' && (num = text.IndexOf(')')) != -1 && byte.TryParse(text.Substring(1, num - 1), out var result)) { return result; } if (text != null && byte.TryParse(text, out result)) { return result; } return byte.MaxValue; } } [Flags] public enum MediaTypes { None = 0, Audio = 1, Video = 2, Photo = 4, Text = 8 } public interface ICodec { TimeSpan Duration { get; } MediaTypes MediaTypes { get; } string Description { get; } } public interface IAudioCodec : ICodec { int AudioBitrate { get; } int AudioSampleRate { get; } int AudioChannels { get; } } public interface ILosslessAudioCodec { int BitsPerSample { get; } } public interface IVideoCodec : ICodec { int VideoWidth { get; } int VideoHeight { get; } } public interface IPhotoCodec : ICodec { int PhotoWidth { get; } int PhotoHeight { get; } int PhotoQuality { get; } } public interface ILazy { bool IsLoaded { get; } void Load(); } public class ListBase<T> : IList<T>, ICollection<T>, IEnumerable<T>, IEnumerable where T : IComparable<T> { private readonly List<T> data = new List<T>(); public bool IsEmpty => Count == 0; public bool IsReadOnly => false; public bool IsFixedSize => false; public T this[int index] { get { return data[index]; } set { data[index] = value; } } public int Count => data.Count; public bool IsSynchronized => false; public object SyncRoot => this; public ListBase() { } public ListBase(ListBase<T> list) { if (list != null) { Add(list); } } public ListBase(params T[] list) { if (list != null) { Add(list); } } public void Add(ListBase<T> list) { if (list != null) { data.AddRange(list); } } public void Add(IEnumerable<T> list) { if (list != null) { data.AddRange(list); } } public void Add(T[] list) { if (list != null) { data.AddRange(list); } } public virtual void SortedInsert(T item, bool unique) { if (item == null) { throw new ArgumentNullException("item"); } int i; for (i = 0; i < data.Count; i++) { if (item.CompareTo(data[i]) == 0 && unique) { return; } if (item.CompareTo(data[i]) <= 0) { break; } } Insert(i, item); } public void SortedInsert(T item) { if (item == null) { throw new ArgumentNullException("item"); } SortedInsert(item, unique: false); } public T[] ToArray() { return data.ToArray(); } public void Add(T item) { data.Add(item); } public void Clear() { data.Clear(); } public bool Contains(T item) { return data.Contains(item); } public int IndexOf(T item) { return data.IndexOf(item); } public void Insert(int index, T item) { data.Insert(index, item); } public bool Remove(T item) { return data.Remove(item); } public void RemoveAt(int index) { data.RemoveAt(index); } public string ToString(string separator) { StringBuilder stringBuilder = new StringBuilder(); for (int i = 0; i < Count; i++) { if (i != 0) { stringBuilder.Append(separator); } stringBuilder.Append(this[i]); } return stringBuilder.ToString(); } public override string ToString() { return ToString(", "); } public void CopyTo(T[] array, int arrayIndex) { data.CopyTo(array, arrayIndex); } public IEnumerator<T> GetEnumerator() { return data.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return data.GetEnumerator(); } } public class TextBox : Box { private ByteVector data; public override ByteVector Data { get { return data; } set { data = value; } } public TextBox(BoxHeader header, File file, IsoHandlerBox handler) : base(header, handler) { if (file == null) { throw new ArgumentNullException("file"); } data = LoadData(file); } } public class UrlBox : Box { private ByteVector data; public override ByteVector Data { get { return data; } set { data = value; } } public UrlBox(BoxHeader header, File file, IsoHandlerBox handler) : base(header, handler) { if (file == null) { throw new ArgumentNullException("file"); } data = LoadData(file); } } public enum PictureType { Other = 0, FileIcon = 1, OtherFileIcon = 2, FrontCover = 3, BackCover = 4, LeafletPage = 5, Media = 6, LeadArtist = 7, Artist = 8, Conductor = 9, Band = 10, Composer = 11, Lyricist = 12, RecordingLocation = 13, DuringRecording = 14, DuringPerformance = 15, MovieScreenCapture = 16, ColoredFish = 17, Illustration = 18, BandLogo = 19, PublisherLogo = 20, NotAPicture = 255 } public interface IPicture { string MimeType { get; set; } PictureType Type { get; set; } string Filename { get; set; } string Description { get; set; } ByteVector Data { get; set; } } public class Picture : IPicture { private static readonly string[] lutExtensionMime = new string[150] { "aac", "audio/aac", "abw", "application/x-abiword", "arc", "application/octet-stream", "avi", "video/x-msvideo", "azw", "application/vnd.amazon.ebook", "bin", "application/octet-stream", "bmp", "image/bmp", "bmp", "image/x-windows-bmp", "bm", "image/bmp", "bz", "application/x-bzip", "bz2", "application/x-bzip2", "csh", "application/x-csh", "css", "text/css", "csv", "text/csv", "doc", "application/msword", "eot", "application/vnd.ms-fontobject", "epub", "application/epub+zip", "gif", "image/gif", "htm", "text/html", "html", "text/html", "ico", "image/x-icon", "ics", "text/calendar", "jar", "application/java-archive", "jpg", "image/jpeg", "jpeg", "image/jpeg", "js", "application/javascript", "json", "application/json", "mid", "audio/midi", "midi", "audio/midi", "mp3", "audio/mpeg", "mp1", "audio/mpeg", "mp2", "audio/mpeg", "mpg", "video/mpeg", "mpeg", "video/mpeg", "m4a", "audio/mp4", "mp4", "video/mp4", "m4v", "video/mp4", "mpkg", "application/vnd.apple.installer+xml", "odp", "application/vnd.oasis.opendocument.presentation", "ods", "application/vnd.oasis.opendocument.spreadsheet", "odt", "application/vnd.oasis.opendocument.text", "oga", "audio/ogg", "ogg", "audio/ogg", "ogx", "application/ogg", "ogv", "video/ogg", "otf", "font/otf", "png", "image/png", "pdf", "application/pdf", "ppt", "application/vnd.ms-powerpoint", "rar", "application/x-rar-compressed", "rtf", "application/rtf", "sh", "application/x-sh", "svg", "image/svg+xml", "swf", "application/x-shockwave-flash", "tar", "application/x-tar", "tif", "image/tiff", "tiff", "image/tiff", "ts", "video/vnd.dlna.mpeg-tts", "ttf", "font/ttf", "vsd", "application/vnd.visio", "wav", "audio/x-wav", "weba", "audio/webm", "webm", "video/webm", "webp", "image/webp", "woff", "font/woff", "woff2", "font/woff2", "xhtml", "application/xhtml+xml", "xls", "application/vnd.ms", "xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "xml", "application/xml", "xul", "application/vnd.mozilla.xul+xml", "zip", "application/zip", "3gp", "video/3gpp", "3g2", "video/3gpp2", "7z", "application/x-7z-compressed" }; public string MimeType { get; set; } public PictureType Type { get; set; } public string Filename { get; set; } public string Description { get; set; } public ByteVector Data { get; set; } public Picture() { } public Picture(string path) { if (path == null) { throw new ArgumentNullException("path"); } Data = ByteVector.FromPath(path); Filename = Path.GetFileName(path); Description = Filename; MimeType = GetMimeFromExtension(Filename); Type = (MimeType.StartsWith("image/") ? PictureType.FrontCover : PictureType.NotAPicture); } public Picture(File.IFileAbstraction abstraction) { if (abstraction == null) { throw new ArgumentNullException("abstraction"); } Data = ByteVector.FromFile(abstraction); Filename = abstraction.Name; Description = abstraction.Name; if (!string.IsNullOrEmpty(Filename) && Filename.Contains(".")) { MimeType = GetMimeFromExtension(Filename); Type = (MimeType.StartsWith("image/") ? PictureType.FrontCover : PictureType.NotAPicture); return; } string extensionFromData = GetExtensionFromData(Data); MimeType = GetMimeFromExtension(extensionFromData); if (extensionFromData != null) { Type = PictureType.FrontCover; Filename = (Description = "cover" + extensionFromData); } else { Type = PictureType.NotAPicture; Filename = "UnknownType"; } } public Picture(ByteVector data) { if (data == null) { throw new ArgumentNullException("data"); } Data = new ByteVector(data); string extensionFromData = GetExtensionFromData(data); MimeType = GetMimeFromExtension(extensionFromData); if (extensionFromData != null) { Type = PictureType.FrontCover; Filename = (Description = "cover" + extensionFromData); } else { Type = PictureType.NotAPicture; Filename = "UnknownType"; } } public Picture(IPicture picture) { MimeType = picture.MimeType; Type = picture.Type; Filename = picture.Filename; Description = picture.Description; Data = picture.Data; } [Obsolete("Use Picture(string filename) constructor instead.")] public static Picture CreateFromPath(string filename) { return new Picture(filename); } [Obsolete("Use Picture(File.IFileAbstraction abstraction) constructor instead.")] public static Picture CreateFromFile(File.IFileAbstraction abstraction) { return new Picture(abstraction); } public static string GetExtensionFromData(ByteVector data) { string result = null; if (data.Count >= 4) { if (data[1] == 80 && data[2] == 78 && data[3] == 71) { result = ".png"; } else if (data[0] == 71 && data[1] == 73 && data[2] == 70) { result = ".gif"; } else if (data[0] == 66 && data[1] == 77) { result = ".bmp"; } else if (data[0] == byte.MaxValue && data[1] == 216 && data[data.Count - 2] == byte.MaxValue && data[data.Count - 1] == 217) { result = ".jpg"; } } return result; } public static string GetExtensionFromMime(string mime) { string result = null; for (int i = 1; i < lutExtensionMime.Length; i += 2) { if (lutExtensionMime[i] == mime) { result = lutExtensionMime[i - 1]; break; } } return result; } public static string GetMimeFromExtension(string name) { string result = "application/octet-stream"; if (string.IsNullOrEmpty(name)) { return result; } string extension = Path.GetExtension(name); extension = ((!string.IsNullOrEmpty(extension)) ? extension.Substring(1) : name); extension = extension.ToLower(); for (int i = 0; i < lutExtensionMime.Length; i += 2) { if (lutExtensionMime[i] == extension) { result = lutExtensionMime[i + 1]; break; } } return result; } } public class PictureLazy : IPicture, ILazy { private string mime_type; private PictureType type; private string filename; private ByteVector data; private File.IFileAbstraction file; private readonly long stream_offset; private readonly long stream_size = -1L; public string MimeType { get { if (mime_type == null) { Load(); } return mime_type; } set { mime_type = value; } } public PictureType Type { get { if (type == PictureType.Other && mime_type == null) { Load(); } return type; } set { type = value; } } public string Filename { get { if (filename == null) { Load(); } return filename; } set { filename = value; } } public string Description { get; set; } public ByteVector Data { get { if (data == null) { Load(); } return data; } set { data = value; } } public bool IsLoaded => data != null; public PictureLazy() { } public PictureLazy(string path) { if (path == null) { throw new ArgumentNullException("path"); } file = new File.LocalFileAbstraction(path); filename = Path.GetFileName(path); Description = filename; mime_type = Picture.GetMimeFromExtension(filename); type = (mime_type.StartsWith("image/") ? PictureType.FrontCover : PictureType.NotAPicture); } public PictureLazy(File.IFileAbstraction abstraction, long offset = 0L, long size = -1L) { if (abstraction == null) { throw new ArgumentNullException("abstraction"); } file = abstraction; stream_offset = offset; stream_size = size; filename = abstraction.Name; Description = abstraction.Name; if (!string.IsNullOrEmpty(filename) && filename.Contains(".")) { mime_type = Picture.GetMimeFromExtension(filename); type = (mime_type.StartsWith("image/") ? PictureType.FrontCover : PictureType.NotAPicture); } } public PictureLazy(ByteVector data) { if (data == null) { throw new ArgumentNullException("data"); } Data = new ByteVector(data); string extensionFromData = Picture.GetExtensionFromData(data); MimeType = Picture.GetMimeFromExtension(extensionFromData); if (extensionFromData != null) { type = PictureType.FrontCover; filename = (Description = "cover" + extensionFromData); } else { type = PictureType.NotAPicture; filename = "UnknownType"; } } public PictureLazy(IPicture picture) { mime_type = picture.MimeType; type = picture.Type; filename = picture.Filename; Description = picture.Description; data = picture.Data; } public void Load() { if (data != null) { return; } Stream stream = null; try { if (stream_size == 0L) { data = new ByteVector(); } else if (stream_size > 0) { stream = file.ReadStream; stream.Seek(stream_offset, SeekOrigin.Begin); int num = 0; int num2 = 0; int num3 = (int)stream_size; byte[] buffer = new byte[num3]; do { num = stream.Read(buffer, num2, num3); num2 += num; num3 -= num; } while (num3 > 0 && num != 0); data = new ByteVector(buffer, num2); } else { stream = file.ReadStream; stream.Seek(stream_offset, SeekOrigin.Begin); data = ByteVector.FromStream(stream); } } finally { if (stream != null && file != null) { file.CloseStream(stream); } file = null; } if (mime_type != null) { return; } string extensionFromData = Picture.GetExtensionFromData(data); MimeType = Picture.GetMimeFromExtension(extensionFromData); if (extensionFromData != null) { type = PictureType.FrontCover; if (filename == null) { string text2 = (Description = "cover" + extensionFromData); filename = text2; } } else { type = PictureType.NotAPicture; if (filename == null) { filename = "UnknownType"; } } } } public class Properties : IAudioCodec, ICodec, IVideoCodec, IPhotoCodec { private readonly ICodec[] codecs = new ICodec[0]; private TimeSpan duration = TimeSpan.Zero; public IEnumerable<ICodec> Codecs => codecs; public TimeSpan Duration { get { TimeSpan timeSpan = duration; if (timeSpan != TimeSpan.Zero) { return timeSpan; } ICodec[] array = codecs; foreach (ICodec codec in array) { if (codec != null && codec.Duration > timeSpan) { timeSpan = codec.Duration; } } return timeSpan; } } public MediaTypes MediaTypes { get { MediaTypes mediaTypes = MediaTypes.None; ICodec[] array = codecs; foreach (ICodec codec in array) { if (codec != null) { mediaTypes |= codec.MediaTypes; } } return mediaTypes; } } public string Description { get { StringBuilder stringBuilder = new StringBuilder(); ICodec[] array = codecs; foreach (ICodec codec in array) { if (codec != null) { if (stringBuilder.Length != 0) { stringBuilder.Append("; "); } stringBuilder.Append(codec.Description); } } return stringBuilder.ToString(); } } public int AudioBitrate { get { ICodec[] array = codecs; foreach (ICodec codec in array) { if (codec != null && (codec.MediaTypes & MediaTypes.Audio) != 0 && codec is IAudioCodec audioCodec && audioCodec.AudioBitrate != 0) { return audioCodec.AudioBitrate; } } return 0; } } public int AudioSampleRate { get { ICodec[] array = codecs; foreach (ICodec codec in array) { if (codec != null && (codec.MediaTypes & MediaTypes.Audio) != 0 && codec is IAudioCodec audioCodec && audioCodec.AudioSampleRate != 0) { return audioCodec.AudioSampleRate; } } return 0; } } public int BitsPerSample { get { ICodec[] array = codecs; foreach (ICodec codec in array) { if (codec != null && (codec.MediaTypes & MediaTypes.Audio) != 0 && codec is ILosslessAudioCodec losslessAudioCodec && losslessAudioCodec.BitsPerSample != 0) { return losslessAudioCodec.BitsPerSample; } } return 0; } } public int AudioChannels { get { ICodec[] array = codecs; foreach (ICodec codec in array) { if (codec != null && (codec.MediaTypes & MediaTypes.Audio) != 0 && codec is IAudioCodec audioCodec && audioCodec.AudioChannels != 0) { return audioCodec.AudioChannels; } } return 0; } } public int VideoWidth { get { ICodec[] array = codecs; foreach (ICodec codec in array) { if (codec != null && (codec.MediaTypes & MediaTypes.Video) != 0 && codec is IVideoCodec videoCodec && videoCodec.VideoWidth != 0) { return videoCodec.VideoWidth; } } return 0; } } public int VideoHeight { get { ICodec[] array = codecs; foreach (ICodec codec in array) { if (codec != null && (codec.MediaTypes & MediaTypes.Video) != 0 && codec is IVideoCodec videoCodec && videoCodec.VideoHeight != 0) { return videoCodec.VideoHeight; } } return 0; } } public int PhotoWidth { get { ICodec[] array = codecs; foreach (ICodec codec in array) { if (codec != null && (codec.MediaTypes & MediaTypes.Photo) != 0 && codec is IPhotoCodec photoCodec && photoCodec.PhotoWidth != 0) { return photoCodec.PhotoWidth; } } return 0; } } public int PhotoHeight { get { ICodec[] array = codecs; foreach (ICodec codec in array) { if (codec != null && (codec.MediaTypes & MediaTypes.Photo) != 0 && codec is IPhotoCodec photoCodec && photoCodec.PhotoHeight != 0) { return photoCodec.PhotoHeight; } } return 0; } } public int PhotoQuality { get { ICodec[] array = codecs; foreach (ICodec codec in array) { if (codec != null && (codec.MediaTypes & MediaTypes.Photo) != 0 && codec is IPhotoCodec photoCodec && photoCodec.PhotoQuality != 0) { return photoCodec.PhotoQuality; } } return 0; } } public Properties() { } public Properties(TimeSpan duration, params ICodec[] codecs) { this.duration = duration; if (codecs != null) { this.codecs = codecs; } } public Properties(TimeSpan duration, IEnumerable<ICodec> codecs) { this.duration = duration; if (codecs != null) { this.codecs = new List<ICodec>(codecs).ToArray(); } } } public sealed class ReadOnlyByteVector : ByteVector { public override bool IsReadOnly => true; public override bool IsFixedSize => true; public ReadOnlyByteVector() { } public ReadOnlyByteVector(int size, byte value) : base(size, value) { } public ReadOnlyByteVector(int size) : this(size, 0) { } public ReadOnlyByteVector(ByteVector vector) : base(vector) { } public ReadOnlyByteVector(byte[] data, int length) : base(data, length) { } public ReadOnlyByteVector(params byte[] data) : base(data) { } public static implicit operator ReadOnlyByteVector(byte value) { return new ReadOnlyByteVector(value); } public static implicit operator ReadOnlyByteVector(byte[] value) { return new ReadOnlyByteVector(value); } public static implicit operator ReadOnlyByteVector(string value) { return new ReadOnlyByteVector(ByteVector.FromString(value, StringType.UTF8)); } } [ComVisible(false)] public class StringCollection : ListBase<string> { public StringCollection() { } public StringCollection(StringCollection values) { Add(values); } public StringCollection(params string[] values) { Add(values); } public StringCollection(ByteVectorCollection vectorList, StringType type) { foreach (ByteVector vector in vectorList) { Add(vector.ToString(type)); } } public StringCollection(ByteVectorCollection vectorList) : this(vectorList, StringType.UTF8) { } public static StringCollection Split(string value, string pattern) { if (value == null) { throw new ArgumentNullException("value"); } if (pattern == null) { throw new ArgumentNullException("pattern"); } StringCollection stringCollection = new StringCollection(); int num = 0; int num2 = value.IndexOf(pattern, 0); int length = pattern.Length; while (num2 != -1) { stringCollection.Add(value.Substring(num, num2 - num)); num = num2 + length; num2 = value.IndexOf(pattern, num); } stringCollection.Add(value.Substring(num)); return stringCollection; } } [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] public sealed class SupportedMimeType : Attribute { private static readonly List<SupportedMimeType> mimetypes; public string MimeType { get; private set; } public string Extension { get; private set; } public static IEnumerable<string> AllMimeTypes { get { foreach (SupportedMimeType mimetype in mimetypes) { yield return mimetype.MimeType; } } } public static IEnumerable<string> AllExtensions { get { foreach (SupportedMimeType mimetype in mimetypes) { if (mimetype.Extension != null) { yield return mimetype.Extension; } } } } static SupportedMimeType() { mimetypes = new List<SupportedMimeType>(); FileTypes.Init(); } public SupportedMimeType(string mimetype) { MimeType = mimetype; mimetypes.Add(this); } public SupportedMimeType(string mimetype, string extension) : this(mimetype) { Extension = extension; } } [Flags] public enum TagTypes : uint { None = 0u, Xiph = 1u, Id3v1 = 2u, Id3v2 = 4u, Ape = 8u, Apple = 0x10u, Asf = 0x20u, RiffInfo = 0x40u, MovieId = 0x80u, DivX = 0x100u, FlacMetadata = 0x200u, TiffIFD = 0x400u, XMP = 0x800u, JpegComment = 0x1000u, GifComment = 0x2000u, Png = 0x4000u, IPTCIIM = 0x8000u, AudibleMetadata = 0x10000u, Matroska = 0x20000u, AllTags = uint.MaxValue } public abstract class Tag { public abstract TagTypes TagTypes { get; } public virtual string Title { get { return null; } set { } } public virtual string TitleSort { get { return null; } set { } } public virtual string Subtitle { get { return null; } set { } } public virtual string Description { get { return null; } set { } } public virtual string[] Performers { get { return new string[0]; } set { } } public virtual string[] PerformersSort { get { return new string[0]; } set { } } public virtual string[] PerformersRole { get { return new string[0]; } set { } } public virtual string[] AlbumArtists { get { return new string[0]; } set { } } public virtual string[] AlbumArtistsSort { get { return new string[0]; } set { } } public virtual string[] Composers { get { return new string[0]; } set { } } public virtual string[] ComposersSort { get { return new string[0]; } set { } } public virtual string Album { get { return null; } set { } } public virtual string AlbumSort { get { return null; } set { } } public virtual string Comment { get { return null; } set { } } public virtual string[] Genres { get { return new string[0]; } set { } } public virtual uint Year { get { return 0u; } set { } } public virtual uint Track { get { return 0u; } set { } } public virtual uint TrackCount { get { return 0u; } set { } } public virtual uint Disc { get { return 0u; } set { } } public virtual uint DiscCount { get { return 0u; } set { } } public virtual string Lyrics { get { return null; } set { } } public virtual string Grouping { get { return null; } set { } } public virtual uint BeatsPerMinute { get { return 0u; } set { } } public virtual string Conductor { get { return null; } set { } } public virtual string Copyright { get { return null; } set { } } public virtual DateTime? DateTagged { get { return null; } set { } } public virtual string MusicBrainzArtistId { get { return null; } set { } } public virtual string MusicBrainzReleaseGroupId { get { return null; } set { } } public virtual string MusicBrainzReleaseId { get { return null; } set { } } public virtual string MusicBrainzReleaseArtistId { get { return null; } set { } } public virtual string MusicBrainzTrackId { get { return null; } set { } } public virtual string MusicBrainzDiscId { get { return null; } set { } } public virtual string MusicIpId { get { return null; } set { } } public virtual string AmazonId { get { return null; } set { } } public virtual string MusicBrainzReleaseStatus { get { return null; } set { } } public virtual string MusicBrainzReleaseType { get { return null; } set { } } public virtual string MusicBrainzReleaseCountry { get { return null; } set { } } public virtual double ReplayGainTrackGain { get { return double.NaN; } set { } } public virtual double ReplayGainTrackPeak { get { return double.NaN; } set { } } public virtual double ReplayGainAlbumGain { get { return double.NaN; } set { } } public virtual double ReplayGainAlbumPeak { get { return double.NaN; } set { } } public virtual string InitialKey { get { return null; } set { } } public virtual string RemixedBy { get { return null; } set { } } public virtual string Publisher { get