public static void OnLoad() { try { var _levelListViewController = Resources.FindObjectsOfTypeAll <SelectLevelCategoryViewController>().Last(); _levelListViewController.didActivateEvent += _levelListViewController_didActivateEvent; if (_levelListViewController) { // move the icon control var iconSegmentedControl = _levelListViewController.GetField <IconSegmentedControl, SelectLevelCategoryViewController>("_levelFilterCategoryIconSegmentedControl"); ((RectTransform)iconSegmentedControl.transform).anchoredPosition = new Vector2(0, 4.5f); _requestButton = _levelListViewController.CreateUIButton("SRMButton", "PracticeButton", new Vector2(14, -4.5f), new Vector2(15f, 105f), () => { _requestButton.interactable = false; SRMButtonPressed(); _requestButton.interactable = true; }, "SRM"); _requestButton.ToggleWordWrapping(false); _requestButton.SetButtonTextSize(5f); UIHelper.AddHintText(_requestButton.transform as RectTransform, "Manage the current request queue"); UpdateRequestUI(); Plugin.Log("Created request button!"); } } catch { Plugin.Log("Unable to create request button"); } // check if flow coordinator has been setup yet if (_flowCoordinator == null) { _flowCoordinator = BeatSaberMarkupLanguage.BeatSaberUI.CreateFlowCoordinator <RequestFlowCoordinator>(); } SongListUtils.Initialize(); ChatHandler.instance.Init(); WriteQueueSummaryToFile(); WriteQueueStatusToFile(QueueMessage(RequestBotConfig.Instance.RequestQueueOpen)); if (Instance) { return; } new GameObject("SongRequestManager").AddComponent <RequestBot>(); }
public static void OnLoad() { try { var _levelListViewController = Resources.FindObjectsOfTypeAll <LevelCollectionViewController>().First(); if (_levelListViewController) { _requestButton = UIHelper.CreateUIButton(_levelListViewController.rectTransform, "OkButton", new Vector2(66, -3.5f), new Vector2(9f, 5.5f), () => { _requestButton.interactable = false; SRMButtonPressed(); _requestButton.interactable = true; }, "SRM"); (_requestButton.transform as RectTransform).anchorMin = new Vector2(1, 1); (_requestButton.transform as RectTransform).anchorMax = new Vector2(1, 1); _requestButton.ToggleWordWrapping(false); _requestButton.SetButtonTextSize(3.5f); UIHelper.AddHintText(_requestButton.transform as RectTransform, "Manage the current request queue"); UpdateRequestUI(); Plugin.Log("Created request button!"); } } catch { Plugin.Log("Unable to create request button"); } // check if flow coordinator has been setup yet if (_flowCoordinator == null) { _flowCoordinator = BeatSaberMarkupLanguage.BeatSaberUI.CreateFlowCoordinator <RequestFlowCoordinator>(); } SongListUtils.Initialize(); ChatHandler.instance.Init(); WriteQueueSummaryToFile(); WriteQueueStatusToFile(QueueMessage(RequestBotConfig.Instance.RequestQueueOpen)); if (Instance) { return; } new GameObject("SongRequestManager").AddComponent <RequestBot>(); }
private static async void ProcessSongRequest(int index, bool fromHistory = false) { if ((RequestQueue.Songs.Count > 0 && !fromHistory) || (RequestHistory.Songs.Count > 0 && fromHistory)) { SongRequest request = null; if (!fromHistory) { SetRequestStatus(index, RequestStatus.Played); request = DequeueRequest(index); } else { request = RequestHistory.Songs.ElementAt(index); } if (request == null) { Plugin.Log("Can't process a null request! Aborting!"); return; } else { Plugin.Log($"Processing song request {request.song["songName"].Value}"); } string songName = request.song["songName"].Value; string songIndex = $"{request.song["id"].Value} ({request.song["songName"].Value} - {request.song["levelAuthor"].Value})"; songIndex = normalize.RemoveDirectorySymbols(ref songIndex); // Remove invalid characters. string currentSongDirectory = Path.Combine(Environment.CurrentDirectory, "Beat Saber_Data\\CustomLevels", songIndex); string songHash = request.song["hash"].Value.ToUpper(); // Check to see if level exists, download if not. // Replace with level check. //CustomLevel[] levels = SongLoader.CustomLevels.Where(l => l.levelID.StartsWith(songHash)).ToArray(); //if (levels.Length == 0) var rat = SongCore.Collections.levelIDsForHash(songHash); bool mapexists = (rat.Count > 0) && (rat[0] != ""); if (!SongCore.Loader.CustomLevels.ContainsKey(currentSongDirectory) && !mapexists) { EmptyDirectory(".requestcache", false); //SongMap map; //if (MapDatabase.MapLibrary.TryGetValue(songIndex, out map)) //{ // if (map.path != "") // { // songIndex = map.song["version"].Value; // songName = map.song["songName"].Value; // currentSongDirectory = Path.Combine(Environment.CurrentDirectory, "CustomSongs", songIndex); // songHash = map.song["hashMd5"].Value.ToUpper(); // Directory.CreateDirectory(currentSongDirectory); // // HACK to allow playing alternate songs not in custom song directory // CopyFilesRecursively(new DirectoryInfo(map.path),new DirectoryInfo( currentSongDirectory)); // goto here; // } //} //Plugin.Log("Downloading"); if (Directory.Exists(currentSongDirectory)) { EmptyDirectory(currentSongDirectory, true); Plugin.Log($"Deleting {currentSongDirectory}"); } string localPath = Path.Combine(Environment.CurrentDirectory, ".requestcache", $"{request.song["id"].Value}.zip"); //string dl = $"https://beatsaver.com {request.song["downloadURL"].Value}"; //Instance.QueueChatMessage($"Download url: {dl}, {request.song}"); // Insert code to replace local path with ZIP path here //SongMap map; //if (MapDatabase.MapLibrary.TryGetValue(songIndex, out map)) //{ // if (map.path != "") // { // songIndex = map.song["version"].Value; // songName = map.song["songName"].Value; // currentSongDirectory = Path.Combine(Environment.CurrentDirectory, "CustomSongs", songIndex); // songHash = map.song["hashMd5"].Value.ToUpper(); // Directory.CreateDirectory(currentSongDirectory); // // HACK to allow playing alternate songs not in custom song directory // CopyFilesRecursively(new DirectoryInfo(map.path),new DirectoryInfo( currentSongDirectory)); // goto here; // } //} #if UNRELEASED // Direct download hack var ext = Path.GetExtension(request.song["coverURL"].Value); var k = request.song["coverURL"].Value.Replace(ext, ".zip"); var songZip = await Plugin.WebClient.DownloadSong($"https://beatsaver.com{k}", System.Threading.CancellationToken.None); #else var songZip = await Plugin.WebClient.DownloadSong($"https://beatsaver.com{request.song["downloadURL"].Value}", System.Threading.CancellationToken.None); #endif Stream zipStream = new MemoryStream(songZip); try { // open zip archive from memory stream ZipArchive archive = new ZipArchive(zipStream, ZipArchiveMode.Read); archive.ExtractToDirectory(currentSongDirectory); archive.Dispose(); } catch (Exception e) { Plugin.Log($"Unable to extract ZIP! Exception: {e}"); return; } zipStream.Close(); here: await Task.Run(async() => { while (!SongCore.Loader.AreSongsLoaded && SongCore.Loader.AreSongsLoading) { await Task.Delay(25); } }); Loader.Instance.RefreshSongs(); await Task.Run(async() => { while (!SongCore.Loader.AreSongsLoaded && SongCore.Loader.AreSongsLoading) { await Task.Delay(25); } }); EmptyDirectory(".requestcache", true); //levels = SongLoader.CustomLevels.Where(l => l.levelID.StartsWith(songHash)).ToArray(); } else { //Instance.QueueChatMessage($"Directory exists: {currentSongDirectory}"); Plugin.Log($"Song {songName} already exists!"); } // Dismiss the song request viewcontroller now //_songRequestMenu.Dismiss(); _flowCoordinator.Dismiss(); if (true) { //Plugin.Log($"Scrolling to level {levels[0].levelID}"); bool success = false; Dispatcher.RunCoroutine(SongListUtils.ScrollToLevel(request.song["hash"].Value.ToUpper(), (s) => success = s, false)); // Redownload the song if we failed to scroll to it } else { Plugin.Log("Failed to find new level!"); } if (!request.song.IsNull && RequestBotConfig.Instance.SendNextSongBeingPlayedtoChat) { new DynamicText().AddUser(ref request.requestor).AddSong(request.song).QueueMessage(NextSonglink.ToString()); // Display next song message } #if UNRELEASED if (!request.song.IsNull) // Experimental! { ChatHandler.Send("marker " + new DynamicText().AddUser(ref request.requestor).AddSong(request.song).Parse(NextSonglink.ToString()), true); } #endif } }
public static IEnumerator ScrollToLevel(string levelID, Action <bool> callback, bool animated, bool isRetry = false) { if (_levelCollectionViewController) { Plugin.Log($"Scrolling to {levelID}! Retry={isRetry}"); // handle if song browser is present if (Plugin.SongBrowserPluginPresent) { Plugin.SongBrowserCancelFilter(); } // Make sure our custom songpack is selected var packIndex = SelectCustomSongPack(); yield return(null); int songIndex = 0; // get the table view var levelsTableView = _levelCollectionViewController.GetField <LevelCollectionTableView, LevelCollectionViewController>("_levelCollectionTableView"); //RequestBot.Instance.QueueChatMessage($"selecting song: {levelID} pack: {packIndex}"); yield return(null); // get the table view var tableView = levelsTableView.GetField <TableView, LevelCollectionTableView>("_tableView"); // get list of beatmaps, this is pre-sorted, etc var beatmaps = levelsTableView.GetField <IPreviewBeatmapLevel[], LevelCollectionTableView>("_previewBeatmapLevels").ToList(); // get the row number for the song we want songIndex = beatmaps.FindIndex(x => (x.levelID.Split('_')[2] == levelID)); // bail if song is not found, shouldn't happen if (songIndex >= 0) { // if header is being shown, increment row if (levelsTableView.GetField <bool, LevelCollectionTableView>("_showLevelPackHeader")) { songIndex++; } Plugin.Log($"Selecting row {songIndex}"); // scroll to song tableView.ScrollToCellWithIdx(songIndex, TableViewScroller.ScrollPositionType.Beginning, animated); // select song, and fire the event tableView.SelectCellWithIdx(songIndex, true); Plugin.Log("Selected song with index " + songIndex); callback?.Invoke(true); if (RequestBotConfig.Instance.ClearNoFail) { try { // disable no fail gamepaly modifier var gameplayModifiersPanelController = Resources.FindObjectsOfTypeAll <GameplayModifiersPanelController>().First(); gameplayModifiersPanelController.gameplayModifiers.noFail = false; //gameplayModifiersPanelController.gameplayModifiers.ResetToDefault(); gameplayModifiersPanelController.Refresh(); } catch { } } yield break; } } if (!isRetry) { yield return(SongListUtils.RefreshSongs(false, false)); yield return(ScrollToLevel(levelID, callback, animated, true)); yield break; } //var tempLevels = SongLoaderPlugin.SongLoader.CustomLevels.Where(l => l.levelID == levelID).ToArray(); //foreach (var l in tempLevels) // SongLoaderPlugin.SongLoader.CustomLevels.Remove(l); Plugin.Log($"Failed to scroll to {levelID}!"); callback?.Invoke(false); }
public static void OnLoad() { try { var _levelListViewController = Resources.FindObjectsOfTypeAll <LevelPackLevelsViewController>().First(); if (_levelListViewController) { _requestButton = BeatSaberUI.CreateUIButton(_levelListViewController.rectTransform, "OkButton", new Vector2(66, -3.5f), new Vector2(9f, 5.5f), () => { _requestButton.interactable = false; _songRequestMenu.Present(); _requestButton.interactable = true; }, "SRM"); (_requestButton.transform as RectTransform).anchorMin = new Vector2(1, 1); (_requestButton.transform as RectTransform).anchorMax = new Vector2(1, 1); _requestButton.ToggleWordWrapping(false); _requestButton.SetButtonTextSize(3.5f); BeatSaberUI.AddHintText(_requestButton.transform as RectTransform, "Manage the current request queue"); UpdateRequestUI(); Plugin.Log("Created request button!"); } } catch { Plugin.Log("Unable to create request button"); } if (_songRequestListViewController == null) { _songRequestListViewController = BeatSaberUI.CreateViewController <RequestBotListViewController>(); } if (_KeyboardViewController == null) { _KeyboardViewController = BeatSaberUI.CreateViewController <CustomViewController>(); RectTransform KeyboardContainer = new GameObject("KeyboardContainer", typeof(RectTransform)).transform as RectTransform; KeyboardContainer.SetParent(_KeyboardViewController.rectTransform, false); KeyboardContainer.sizeDelta = new Vector2(60f, 40f); var mykeyboard = new KEYBOARD(KeyboardContainer, ""); #if UNRELEASED //mykeyboard.AddKeys(BOTKEYS, 0.4f); AddKeyboard(mykeyboard, "emotes.kbd", 0.4f); #endif mykeyboard.AddKeys(KEYBOARD.QWERTY); // You can replace this with DVORAK if you like mykeyboard.DefaultActions(); #if UNRELEASED const string SEARCH = @" [CLEAR SEARCH]/0 /2 [NEWEST]/0 /2 [UNFILTERED]/30 /2 [PP]/0'!addsongs/top/pp pp%CR%' /2 [SEARCH]/0"; #else const string SEARCH = @" [CLEAR SEARCH]/0 /2 [NEWEST]/0 /2 [UNFILTERED]/30 /2 [SEARCH]/0"; #endif mykeyboard.SetButtonType("OkButton"); // Adding this alters button positions??! Why? mykeyboard.AddKeys(SEARCH, 0.75f); mykeyboard.SetAction("CLEAR SEARCH", ClearSearch); mykeyboard.SetAction("UNFILTERED", UnfilteredSearch); mykeyboard.SetAction("SEARCH", MSD); mykeyboard.SetAction("NEWEST", Newest); #if UNRELEASED AddKeyboard(mykeyboard, "decks.kbd", 0.4f); #endif // The UI for this might need a bit of work. AddKeyboard(mykeyboard, "RightPanel.kbd"); } if (_songRequestMenu == null) { _songRequestMenu = BeatSaberUI.CreateCustomMenu <CustomMenu>("Song Request Queue"); _songRequestMenu.SetMainViewController(_songRequestListViewController, true); _songRequestMenu.SetRightViewController(_KeyboardViewController, false); } SongListUtils.Initialize(); WriteQueueSummaryToFile(); WriteQueueStatusToFile(QueueMessage(RequestBotConfig.Instance.RequestQueueOpen)); // Yes, this is disabled on purpose. StreamCore will init this class for you now, so don't uncomment this! -Brian //if (Instance) return; //new GameObject("SongRequestManager").AddComponent<RequestBot>(); }
private static IEnumerator ProcessSongRequest(int index, bool fromHistory = false) { if ((RequestQueue.Songs.Count > 0 && !fromHistory) || (RequestHistory.Songs.Count > 0 && fromHistory)) { SongRequest request = null; if (!fromHistory) { SetRequestStatus(index, RequestStatus.Played); request = DequeueRequest(index); } else { request = RequestHistory.Songs.ElementAt(index); } if (request == null) { Plugin.Log("Can't process a null request! Aborting!"); yield break; } else { Plugin.Log($"Processing song request {request.song["songName"].Value}"); } string songName = request.song["songName"].Value; string songIndex = $"{request.song["id"].Value} ({request.song["songName"].Value} - {request.song["levelAuthor"].Value})"; songIndex = normalize.RemoveDirectorySymbols(ref songIndex); // Remove invalid characters. string currentSongDirectory = Path.Combine(Environment.CurrentDirectory, "Beat Saber_Data\\CustomLevels", songIndex); string songHash = request.song["hash"].Value.ToUpper(); // Check to see if level exists, download if not. // Replace with level check. //CustomLevel[] levels = SongLoader.CustomLevels.Where(l => l.levelID.StartsWith(songHash)).ToArray(); //if (levels.Length == 0) var rat = SongCore.Collections.levelIDsForHash(songHash); bool mapexists = (rat.Count > 0) && (rat[0] != ""); if (!SongCore.Loader.CustomLevels.ContainsKey(currentSongDirectory) && !mapexists) { Utilities.EmptyDirectory(".requestcache", false); //SongMap map; //if (MapDatabase.MapLibrary.TryGetValue(songIndex, out map)) //{ // if (map.path != "") // { // songIndex = map.song["version"].Value; // songName = map.song["songName"].Value; // currentSongDirectory = Path.Combine(Environment.CurrentDirectory, "CustomSongs", songIndex); // songHash = map.song["hashMd5"].Value.ToUpper(); // Directory.CreateDirectory(currentSongDirectory); // // HACK to allow playing alternate songs not in custom song directory // CopyFilesRecursively(new DirectoryInfo(map.path),new DirectoryInfo( currentSongDirectory)); // goto here; // } //} //Plugin.Log("Downloading"); if (Directory.Exists(currentSongDirectory)) { Utilities.EmptyDirectory(currentSongDirectory, true); Plugin.Log($"Deleting {currentSongDirectory}"); } string localPath = Path.Combine(Environment.CurrentDirectory, ".requestcache", $"{request.song["id"].Value}.zip"); //string dl = $"https://beatsaver.com {request.song["downloadURL"].Value}"; //Instance.QueueChatMessage($"Download url: {dl}, {request.song}"); yield return(Utilities.DownloadFile($"https://beatsaver.com{request.song["downloadURL"].Value}", localPath)); yield return(Utilities.ExtractZip(localPath, currentSongDirectory)); here: yield return(new WaitUntil(() => SongCore.Loader.AreSongsLoaded && !SongCore.Loader.AreSongsLoading)); Loader.Instance.RefreshSongs(); yield return(new WaitUntil(() => SongCore.Loader.AreSongsLoaded && !SongCore.Loader.AreSongsLoading)); Utilities.EmptyDirectory(".requestcache", true); //levels = SongLoader.CustomLevels.Where(l => l.levelID.StartsWith(songHash)).ToArray(); } else { //Instance.QueueChatMessage($"Directory exists: {currentSongDirectory}"); Plugin.Log($"Song {songName} already exists!"); } // Dismiss the song request viewcontroller now _songRequestMenu.Dismiss(); if (true) { //Plugin.Log($"Scrolling to level {levels[0].levelID}"); bool success = false; yield return(SongListUtils.ScrollToLevel(request.song["hash"].Value.ToUpper(), (s) => success = s, false)); yield return(null); // Redownload the song if we failed to scroll to it } else { Plugin.Log("Failed to find new level!"); } if (!request.song.IsNull) { new DynamicText().AddUser(ref request.requestor).AddSong(request.song).QueueMessage(NextSonglink.ToString()); // Display next song message } #if UNRELEASED if (!request.song.IsNull) // Experimental! { TwitchWebSocketClient.SendCommand("/marker " + new DynamicText().AddUser(ref request.requestor).AddSong(request.song).Parse(NextSonglink.ToString())); } #endif } }