/// <summary> /// Select a level pack. /// </summary> /// <param name="levelPackId"></param> public void SelectLevelPack(String levelPackId) { Logger.Trace("SelectLevelPack({0})", levelPackId); try { //var levelPacks = GetLevelPackCollection(); IBeatmapLevelPack pack = GetLevelPackByPackId(levelPackId); if (pack == null) { Logger.Debug("Could not locate requested level pack..."); return; } Logger.Info("Selecting level pack: {0}", pack.packID); LevelFilteringNavigationController.SelectBeatmapLevelPackOrPlayList(pack, null); LevelFilteringNavigationController.TabBarDidSwitch(); Logger.Debug("Done selecting level pack!"); } catch (Exception e) { Logger.Exception(e); } }
/// <summary> /// Sorting returns list sorted by alphabetical order of the directories they are contained in. /// </summary> /// <param name="levels"></param> /// <returns></returns> private List <IPreviewBeatmapLevel> SortVanilla(List <IPreviewBeatmapLevel> levels) { Logger.Info("Sorting song list by vanilla ordering."); return(levels .OrderBy(level => _cachedFileSystemOrder.TryGetValue(level.levelID, out int index) ? index : int.MaxValue) .ToList()); }
/// <summary> /// Select a level collection. /// </summary> /// <param name="levelCollectionName"></param> public void SelectLevelCollection(String levelCollectionName) { Logger.Trace("SelectLevelCollection({0})", levelCollectionName); try { IAnnotatedBeatmapLevelCollection collection = GetLevelCollectionByName(levelCollectionName); if (collection == null) { Logger.Debug("Could not locate requested level collection..."); return; } Logger.Info("Selecting level collection: {0}", collection.collectionName); LevelFilteringNavigationController.SelectBeatmapLevelPackOrPlayList(collection as IBeatmapLevelPack, collection as IPlaylist); LevelFilteringNavigationController.TabBarDidSwitch(); Logger.Debug("Done selecting level collection!"); } catch (Exception e) { Logger.Exception(e); } }
/// <summary> /// Sorting by newest (file time, creation+modified). /// </summary> /// <param name="levels"></param> /// <returns></returns> private List <IPreviewBeatmapLevel> SortNewest(List <IPreviewBeatmapLevel> levels) { Logger.Info("Sorting song list as newest."); return(levels .OrderByDescending(x => _cachedLastWriteTimes.ContainsKey(x.levelID) ? _cachedLastWriteTimes[x.levelID] : int.MinValue) .ToList()); }
/// <summary> /// Migrate old favorites into new system. /// </summary> public static void MigrateFavorites() { String migratedPlaylistPath = Path.Combine(Environment.CurrentDirectory, "Playlists", MigratedFavoritesPlaylistName); String oldFavoritesPath = Path.Combine(Environment.CurrentDirectory, "Playlists", DefaultConvertedFavoritesPlaylistName); // Skip if already migrated or if the song browser favorites do not exist if (!File.Exists(oldFavoritesPath) || File.Exists(migratedPlaylistPath)) { return; } Logger.Info("Migrating [{0}] into the In-Game favorites.", oldFavoritesPath); Playlist oldFavorites = Playlist.LoadPlaylist(oldFavoritesPath); PlayerDataModel playerData = Resources.FindObjectsOfTypeAll <PlayerDataModel>().FirstOrDefault(); foreach (PlaylistSong song in oldFavorites.songs) { string levelID = CustomLevelLoader.kCustomLevelPrefixId + song.hash; Logger.Info("Migrating song into ingame favorites: {0}", levelID); playerData.playerData.favoritesLevelIds.Add(levelID); } Logger.Info("Moving [{0}->{1}] into the In-Game favorites.", oldFavoritesPath, migratedPlaylistPath); File.Move(oldFavoritesPath, migratedPlaylistPath); playerData.Save(); }
#pragma warning disable IDE0051 // Remove unused private members static void Prefix(FlowCoordinator flowCoordinator, Action finishedCallback = null, ViewController.AnimationDirection animationDirection = ViewController.AnimationDirection.Horizontal, bool immediately = false, bool replaceTopViewController = false) #pragma warning restore IDE0051 // Remove unused private members { var flowType = flowCoordinator.GetType(); if (flowType == typeof(SoloFreePlayFlowCoordinator)) { Logger.Info("Initializing SongBrowser for Single Player Mode"); SongBrowser.SongBrowserApplication.Instance.HandleSoloModeSelection(); } else if (flowType == typeof(MultiplayerLevelSelectionFlowCoordinator)) { Logger.Info("Initializing SongBrowser for Multiplayer Mode"); SongBrowser.SongBrowserApplication.Instance.HandleMultiplayerModeSelection(); } else if (flowType == typeof(PartyFreePlayFlowCoordinator)) { Logger.Info("Initializing SongBrowser for Party Mode"); SongBrowser.SongBrowserApplication.Instance.HandlePartyModeSelection(); } else if (flowType == typeof(CampaignFlowCoordinator)) { Logger.Info("Initializing SongBrowser for Multiplayer Mode"); SongBrowser.SongBrowserApplication.Instance.HandleCampaignModeSelection(); } return; }
/// <summary> /// Save helper. /// </summary> private void _Save(String path) { if (this.DisableSavingSettings) { Logger.Info("Saving settings has been disabled..."); return; } if (searchTerms.Count > 10) { searchTerms.RemoveRange(10, searchTerms.Count - 10); } var settings = new XmlWriterSettings { OmitXmlDeclaration = false, Indent = true, NewLineOnAttributes = true, NewLineHandling = System.Xml.NewLineHandling.Entitize }; using (var stream = new StreamWriter(path, false, Utf8Encoding)) { using (var writer = XmlWriter.Create(stream, settings)) { SettingsSerializer.Serialize(writer, this); } } }
/// <summary> /// Select a level pack. /// </summary> /// <param name="levelPackId"></param> public void SelectLevelPack(String levelPackId) { Logger.Trace("SelectLevelPack({0})", levelPackId); try { var levelPacks = GetLevelPackCollection(); var index = GetLevelPackIndexByPackId(levelPackId); var pack = GetLevelPackByPackId(levelPackId); if (index < 0) { Logger.Debug("Cannot select level packs yet..."); return; } Logger.Info("Selecting level pack index: {0}", pack.packName); var tableView = LevelPacksTableView.GetPrivateField <TableView>("_tableView"); LevelPacksTableView.SelectCellWithIdx(index); tableView.SelectCellWithIdx(index, true); tableView.ScrollToCellWithIdx(0, TableViewScroller.ScrollPositionType.Beginning, false); for (int i = 0; i < index; i++) { tableView.GetPrivateField <TableViewScroller>("_scroller").PageScrollDown(); } Logger.Debug("Done selecting level pack!"); } catch (Exception e) { Logger.Exception(e); } }
/// <summary> /// Sorting by star rating. /// </summary> /// <param name="levels"></param> /// <returns></returns> private List <IPreviewBeatmapLevel> SortStars(List <IPreviewBeatmapLevel> levels) { Logger.Info("Sorting song list by star points..."); if (!SongDataCore.Plugin.Songs.IsDataAvailable()) { SortWasMissingData = true; return(levels); } return(levels .OrderByDescending(x => { var hash = SongBrowserModel.GetSongHash(x.levelID); var stars = 0.0; if (SongDataCore.Plugin.Songs.Data.Songs.ContainsKey(hash)) { var diffs = SongDataCore.Plugin.Songs.Data.Songs[hash].diffs; stars = diffs.Max(y => (PluginConfig.Instance.InvertSortResults) ? -y.star : y.star); } //Logger.Debug("Stars={0}", stars); if (stars != 0) { return stars; } return double.MinValue; }) .ToList()); }
private List <BeatmapLevelSO> FilterSearch(List <BeatmapLevelSO> levels) { // Make sure we can actually search. if (this._settings.searchTerms.Count <= 0) { Logger.Error("Tried to search for a song with no valid search terms..."); SortSongName(levels); return(levels); } string searchTerm = this._settings.searchTerms[0]; if (String.IsNullOrEmpty(searchTerm)) { Logger.Error("Empty search term entered."); SortSongName(levels); return(levels); } Logger.Info("Filtering song list by search term: {0}", searchTerm); var terms = searchTerm.Split(' '); foreach (var term in terms) { levels = levels.Intersect( levels .Where(x => $"{x.songName} {x.songSubName} {x.songAuthorName}".ToLower().Contains(term.ToLower())) .ToList( ) ).ToList(); } return(levels); }
private void SortDifficulty(List <BeatmapLevelSO> levels) { Logger.Info("Sorting song list by difficulty..."); IEnumerable <BeatmapDifficulty> difficultyIterator = Enum.GetValues(typeof(BeatmapDifficulty)).Cast <BeatmapDifficulty>(); Dictionary <string, int> levelIdToDifficultyValue = new Dictionary <string, int>(); foreach (var level in levels) { if (!levelIdToDifficultyValue.ContainsKey(level.levelID)) { int difficultyValue = 0; // Get the beatmap difficulties var difficulties = level.difficultyBeatmapSets .Where(x => x.beatmapCharacteristic == this.CurrentBeatmapCharacteristicSO) .SelectMany(x => x.difficultyBeatmaps); foreach (IDifficultyBeatmap difficultyBeatmap in difficulties) { difficultyValue += _difficultyWeights[difficultyBeatmap.difficulty]; } levelIdToDifficultyValue.Add(level.levelID, difficultyValue); } } _sortedSongs = levels .OrderBy(x => levelIdToDifficultyValue[x.levelID]) .ThenBy(x => x.songName) .ToList(); _sortedSongs = levels; }
/// <summary> /// Sorting by BeatSaver heat stat. /// </summary> /// <param name="levelIds"></param> /// <returns></returns> private List <IPreviewBeatmapLevel> SortBeatSaverHeat(List <IPreviewBeatmapLevel> levelIds) { Logger.Info("Sorting song list by BeatSaver Heat!"); // Do not always have data when trying to sort by heat if (!SongDataCore.Plugin.Songs.IsDataAvailable()) { SortWasMissingData = true; return(levelIds); } return(levelIds .OrderByDescending(x => { var hash = SongBrowserModel.GetSongHash(x.levelID); if (SongDataCore.Plugin.Songs.Data.Songs.ContainsKey(hash)) { return SongDataCore.Plugin.Songs.Data.Songs[hash].heat; } else { return int.MinValue; } }) .ToList()); }
/// <summary> /// Sorting by BeatSaver playcount stat. /// </summary> /// <param name="levelIds"></param> /// <returns></returns> private List <IPreviewBeatmapLevel> SortBeatSaverPlayCount(List <IPreviewBeatmapLevel> levelIds) { Logger.Info("Sorting song list by BeatSaver PlayCount"); return(levelIds); // Do not always have data when trying to sort by UpVotes /*if (!SongDataCore.Plugin.Songs.IsDataAvailable()) * { * SortWasMissingData = true; * return levelIds; * } * * return levelIds * .OrderByDescending(x => { * var hash = SongBrowserModel.GetSongHash(x.levelID); * if (SongDataCore.Plugin.Songs.Data.Songs.ContainsKey(hash)) * { * return SongDataCore.Plugin.Songs.Data.Songs[hash].plays; * } * else * { * return int.MinValue; * } * }) * .ToList();*/ }
/// <summary> /// Sorting by PP. /// </summary> /// <param name="levels"></param> /// <returns></returns> private List <IPreviewBeatmapLevel> SortPerformancePoints(List <IPreviewBeatmapLevel> levels) { Logger.Info("Sorting song list by performance points..."); if (!SongDataCore.Plugin.Songs.IsDataAvailable()) { SortWasMissingData = true; return(levels); } return(levels .OrderByDescending(x => { var hash = SongBrowserModel.GetSongHash(x.levelID); if (SongDataCore.Plugin.Songs.Data.Songs.ContainsKey(hash)) { return SongDataCore.Plugin.Songs.Data.Songs[hash].diffs.Max(y => y.pp); } else { return 0; } }) .ToList()); }
/// <summary> /// Sorting by the song name. /// </summary> /// <param name="levels"></param> /// <returns></returns> private List <IPreviewBeatmapLevel> SortSongLength(List <IPreviewBeatmapLevel> levels) { Logger.Info("Sorting song list by songDuration/songName"); return(levels .OrderBy(x => x.songDuration) .ThenBy(x => x.songName) .ToList()); }
/// <summary> /// Sorting by the song name. /// </summary> /// <param name="levels"></param> /// <returns></returns> private List <IPreviewBeatmapLevel> SortSongName(List <IPreviewBeatmapLevel> levels) { Logger.Info("Sorting song list as default (songName)"); return(levels .OrderBy(x => x.songName) .ThenBy(x => x.songAuthorName) .ToList()); }
/// <summary> /// Sorting by song users play count. /// </summary> /// <param name="levels"></param> /// <returns></returns> private List <IPreviewBeatmapLevel> SortPlayCount(List <IPreviewBeatmapLevel> levels) { Logger.Info("Sorting song list by playcount"); return(levels .OrderByDescending(x => _levelIdToPlayCount.ContainsKey(x.levelID) ? _levelIdToPlayCount[x.levelID] : 0) .ThenBy(x => x.songName) .ToList()); }
/// <summary> /// Sorting by the song author. /// </summary> /// <param name="levelIds"></param> /// <returns></returns> private List <IPreviewBeatmapLevel> SortAuthor(List <IPreviewBeatmapLevel> levelIds) { Logger.Info("Sorting song list by author"); return(levelIds .OrderBy(x => x.songAuthorName) .ThenBy(x => x.songName) .ToList()); }
/// <summary> /// Filter songs based on playerdata favorites. /// </summary> private List <IPreviewBeatmapLevel> FilterFavorites(List <IPreviewBeatmapLevel> levels) { Logger.Info("Filtering song list as favorites playlist..."); PlayerDataModel playerData = Resources.FindObjectsOfTypeAll <PlayerDataModel>().FirstOrDefault(); return(levels.Where(x => playerData.playerData.favoritesLevelIds.Contains(x.levelID)).ToList()); }
/// <summary> /// Sorting by the song name. /// </summary> /// <param name="levels"></param> /// <returns></returns> private List <IPreviewBeatmapLevel> SortSongBpm(List <IPreviewBeatmapLevel> levels) { Logger.Info("Sorting song list by beatsPerMinute/songName"); return(levels .OrderBy(x => x.beatsPerMinute) .ThenBy(x => x.songName) .ToList()); }
private void SortSongName(List <BeatmapLevelSO> levels) { Logger.Info("Sorting song list as default (songName)"); _sortedSongs = levels .OrderBy(x => x.songName) .ThenBy(x => x.songAuthorName) .ToList(); }
private void SortPerformancePoints(List <BeatmapLevelSO> levels) { Logger.Info("Sorting song list by performance points..."); _sortedSongs = levels .OrderByDescending(x => _levelIdToScoreSaberData.ContainsKey(x.levelID) ? _levelIdToScoreSaberData[x.levelID].maxPp : 0) .ToList(); }
private void SortPlayCount(List <BeatmapLevelSO> levels) { Logger.Info("Sorting song list by playcount"); _sortedSongs = levels .OrderByDescending(x => _levelIdToPlayCount[x.levelID]) .ThenBy(x => x.songName) .ToList(); }
private void SortNewest(List <BeatmapLevelSO> levels) { Logger.Info("Sorting song list as newest."); _sortedSongs = levels .OrderBy(x => _weights.ContainsKey(x.levelID) ? _weights[x.levelID] : 0) .ThenByDescending(x => !_levelIdToCustomLevel.ContainsKey(x.levelID) ? (_weights.ContainsKey(x.levelID) ? _weights[x.levelID] : 0) : _cachedLastWriteTimes[x.levelID]) .ToList(); }
/// <summary> /// For now the editing playlist will be considered the favorites playlist. /// Users can edit the settings file themselves. /// </summary> private List <BeatmapLevelSO> FilterFavorites() { Logger.Info("Filtering song list as favorites playlist..."); if (this.CurrentEditingPlaylist != null) { this.CurrentPlaylist = this.CurrentEditingPlaylist; } return(this.FilterPlaylist()); }
/// <summary> /// Get the song cache from the game. /// </summary> public void UpdateLevelRecords() { Stopwatch timer = new Stopwatch(); timer.Start(); // Calculate some information about the custom song dir String customSongsPath = Path.Combine(Environment.CurrentDirectory, CUSTOM_SONGS_DIR); String revSlashCustomSongPath = customSongsPath.Replace('\\', '/'); double currentCustomSongDirLastWriteTIme = (File.GetLastWriteTimeUtc(customSongsPath) - EPOCH).TotalMilliseconds; bool customSongDirChanged = false; if (_customSongDirLastWriteTime != currentCustomSongDirLastWriteTIme) { customSongDirChanged = true; _customSongDirLastWriteTime = currentCustomSongDirLastWriteTIme; } if (!Directory.Exists(customSongsPath)) { Logger.Error("CustomSong directory is missing..."); return; } // Map some data for custom songs Regex r = new Regex(@"(\d+-\d+)", RegexOptions.IgnoreCase); Stopwatch lastWriteTimer = new Stopwatch(); lastWriteTimer.Start(); foreach (KeyValuePair <string, CustomPreviewBeatmapLevel> level in SongCore.Loader.CustomLevels) { // If we already know this levelID, don't both updating it. // SongLoader should filter duplicates but in case of failure we don't want to crash if (!_cachedLastWriteTimes.ContainsKey(level.Value.levelID) || customSongDirChanged) { double lastWriteTime = GetSongUserDate(level.Value); _cachedLastWriteTimes[level.Value.levelID] = lastWriteTime; } } lastWriteTimer.Stop(); Logger.Info("Determining song download time and determining mappings took {0}ms", lastWriteTimer.ElapsedMilliseconds); // Update song Infos, directory tree, and sort this.UpdatePlayCounts(); // Signal complete if (SongCore.Loader.CustomLevels.Count > 0) { didFinishProcessingSongs?.Invoke(SongCore.Loader.CustomLevels); } timer.Stop(); Logger.Info("Updating songs infos took {0}ms", timer.ElapsedMilliseconds); }
private void SortRandom(List <BeatmapLevelSO> levels) { Logger.Info("Sorting song list by random (seed={0})...", this.Settings.randomSongSeed); System.Random rnd = new System.Random(this.Settings.randomSongSeed); _sortedSongs = levels .OrderBy(x => rnd.Next()) .ToList(); }
/// <summary> /// Randomize the sorting. /// </summary> /// <param name="levelIds"></param> /// <returns></returns> private List <IPreviewBeatmapLevel> SortRandom(List <IPreviewBeatmapLevel> levelIds) { Logger.Info("Sorting song list by random (seed={0})...", Settings.randomSongSeed); System.Random rnd = new System.Random(Settings.randomSongSeed); return(levelIds .OrderBy(x => x.songName) .OrderBy(x => rnd.Next()) .ToList()); }
public bool SelectLevelCategory(String levelCategoryName) { Logger.Trace("SelectLevelCategory({0})", levelCategoryName); try { if (String.IsNullOrEmpty(levelCategoryName)) { // hack for now, just assume custom levels if a user has an old settings file, corrects itself first time they change level packs. levelCategoryName = SelectLevelCategoryViewController.LevelCategory.CustomSongs.ToString(); } SelectLevelCategoryViewController.LevelCategory category; try { category = (SelectLevelCategoryViewController.LevelCategory)Enum.Parse(typeof(SelectLevelCategoryViewController.LevelCategory), levelCategoryName, true); } catch (Exception) { // invalid input return(false); } if (category == LevelFilteringNavigationController.selectedLevelCategory) { Logger.Debug($"Level category [{category}] is already selected"); return(false); } Logger.Info("Selecting level category: {0}", levelCategoryName); var selectLeveCategoryViewController = LevelFilteringNavigationController.GetComponentInChildren <SelectLevelCategoryViewController>(); var iconSegementController = selectLeveCategoryViewController.GetComponentInChildren <IconSegmentedControl>(); int selectCellNumber = (from x in selectLeveCategoryViewController.GetField <SelectLevelCategoryViewController.LevelCategoryInfo[], SelectLevelCategoryViewController>("_levelCategoryInfos") select x.levelCategory).ToList().IndexOf(category); iconSegementController.SelectCellWithNumber(selectCellNumber); selectLeveCategoryViewController.LevelFilterCategoryIconSegmentedControlDidSelectCell(iconSegementController, selectCellNumber); LevelFilteringNavigationController.UpdateSecondChildControllerContent(category); //AnnotatedBeatmapLevelCollectionsViewController.RefreshAvailability(); Logger.Debug("Done selecting level category."); return(true); } catch (Exception e) { Logger.Exception(e); } return(false); }
/// <summary> /// Scroll TableView to proper row, fire events. /// </summary> /// <param name="table"></param> /// <param name="levelID"></param> public void SelectAndScrollToLevel(string levelID) { Logger.Debug("Scrolling to LevelID: {0}", levelID); // Check once per load if (!_checkedForTwitchPlugin) { Logger.Info("Checking for BeatSaber Twitch Integration Plugin..."); _detectedTwitchPluginQueue = Resources.FindObjectsOfTypeAll <HMUI.ViewController>().Any(x => x.name == "RequestInfo"); Logger.Info("BeatSaber Twitch Integration plugin detected: " + _detectedTwitchPluginQueue); _checkedForTwitchPlugin = true; } // Skip scrolling to level if twitch plugin has queue active. if (_detectedTwitchPluginQueue) { Logger.Debug("Skipping SelectAndScrollToLevel() because we detected Twitch Integration Plugin has a Queue active..."); return; } // try to find the index and scroll to it int selectedIndex = 0; List <IPreviewBeatmapLevel> levels = GetCurrentLevelCollectionLevels().ToList(); if (levels.Count <= 0) { return; } // acquire the index or try the last row selectedIndex = levels.FindIndex(x => x.levelID == levelID); if (selectedIndex < 0) { // this might look like an off by one error but the _level list we keep is missing the header entry BeatSaber. // so the last row is +1 the max index, the count. int maxCount = levels.Count; int selectedRow = LevelCollectionTableView.GetPrivateField <int>("_selectedRow"); Logger.Debug("Song is not in the level pack, cannot scroll to it... Using last known row {0}/{1}", selectedRow, maxCount); selectedIndex = Math.Min(maxCount, selectedRow); } else { // the header counts as an index, so if the index came from the level array we have to add 1. selectedIndex += 1; } ScrollToLevelByRow(selectedIndex); }