private void GeneratePlaylistWithMinTime(float minTime, BeatmapDifficulty?difficulty = null, Action <List <IBeatmapLevel> > playlistLoaded = null) { var totalDuration = 0f; var pickFrom = new List <IPreviewBeatmapLevel>(); foreach (var pack in beatmapLevelPackCollection.beatmapLevelPacks) { pickFrom = pickFrom.Union(pack.beatmapLevelCollection.beatmapLevels).ToList(); } var ret = new List <IBeatmapLevel>(); Action addAnotherSong = null; addAnotherSong = async() => { var currentIndex = rand.Next(0, pickFrom.Count); var currentLevel = pickFrom.ElementAt(currentIndex); pickFrom.RemoveAt(currentIndex); Action <IBeatmapLevel> SongLoaded = (loadedLevel) => { //If a difficulty was specified, we'll only pick songs that have that difficulty //NOTE: We can't filter out maps during the union because this beatmap data might not //be populated until the level is loaded if (difficulty == null || loadedLevel.beatmapLevelData.difficultyBeatmapSets.Any(x => x.difficultyBeatmaps.Any(y => y.difficulty == difficulty))) { Logger.Debug($"ADDED: {loadedLevel.songName} ({loadedLevel.songDuration})"); totalDuration += loadedLevel.songDuration; ret.Add(loadedLevel); centerViewController.SetProgress(totalDuration / minTime); } if (totalDuration < minTime && pickFrom.Count > 0) { addAnotherSong(); } else { playlistLoaded(ret); } }; if (!(currentLevel is IBeatmapLevel)) { if (await SongHelpers.HasDLCLevel(currentLevel.levelID)) { Misc.Logger.Debug("Loading DLC level..."); var result = await SongHelpers.GetDLCLevel(currentLevel); if (result != null && !(result?.isError == true)) { SongLoaded(result?.beatmapLevel); } } else { Logger.Debug($"Skipping unowned DLC ({currentLevel.songName})"); if (pickFrom.Count > 0) { addAnotherSong(); } else { playlistLoaded(ret); } } } else if (currentLevel is CustomLevel) { Logger.Debug("Loading custom song data..."); SongLoader.Instance.LoadAudioClipForLevel((CustomLevel)currentLevel, SongLoaded); } else { Logger.Debug("Reading OST data without songloader..."); SongLoaded(currentLevel as IBeatmapLevel); } }; addAnotherSong(); }
protected override void DidActivate(bool firstActivation, ActivationType activationType) { if (activationType == ActivationType.AddedToHierarchy) { title = Plugin.Name; navigationController = BeatSaberUI.CreateViewController <GenericNavigationController>(); navigationController.didFinishEvent += (_) => mainFlowCoordinator.InvokeMethod("DismissFlowCoordinator", this, null, false); if (soloFreePlayFlowCoordinator == null) { soloFreePlayFlowCoordinator = Resources.FindObjectsOfTypeAll <SoloFreePlayFlowCoordinator>().First(); } if (_additionalContentModel == null) { _additionalContentModel = Resources.FindObjectsOfTypeAll <AdditionalContentModelSO>().First(); } if (_primaryLevelCollection == null) { _primaryLevelCollection = _additionalContentModel.alwaysOwnedPacks.First(x => x.packID == "OstVol1").beatmapLevelCollection as BeatmapLevelCollectionSO; } if (_secondaryLevelCollection == null) { _secondaryLevelCollection = _additionalContentModel.alwaysOwnedPacks.First(x => x.packID == "OstVol2").beatmapLevelCollection as BeatmapLevelCollectionSO; } if (_extrasLevelCollection == null) { _extrasLevelCollection = _additionalContentModel.alwaysOwnedPacks.First(x => x.packID == "Extras").beatmapLevelCollection as BeatmapLevelCollectionSO; } if (beatmapLevelPackCollection == null) { beatmapLevelPackCollection = soloFreePlayFlowCoordinator.GetField <IBeatmapLevelPackCollection>("_levelPackCollection"); } if (centerViewController == null) { centerViewController = BeatSaberUI.CreateViewController <CenterViewController>(); centerViewController.GenerateButtonPressed += () => { centerViewController.SetUIType(CenterViewController.UIType.ProgressBar); GeneratePlaylistWithMinTime(centerViewController.GetTimeValue(), centerViewController.UseOnlyPreferredDifficulty ? centerViewController.PreferredDifficulty : (BeatmapDifficulty?)null, (playlist) => { var duration = 0f; foreach (var song in playlist) { duration += song.songDuration; Logger.Debug($"PLAYLIST ITEM: {song.songName} ({song.songDuration})"); } Logger.Debug($"TOTAL DURATION: {duration}"); centerViewController.SetUIType(CenterViewController.UIType.GenerationButton); //Launch first level Config.Enabled = true; Plugin.instance.loadedLevels = new Queue <IBeatmapLevel>(playlist); var firstMap = SongHelpers.GetClosestDifficultyPreferLower(Plugin.instance.loadedLevels.First(), centerViewController.PreferredDifficulty); SongStitcher.songSwitched -= SongSwitched; SongStitcher.songSwitched += SongSwitched; var playerDataModel = Resources.FindObjectsOfTypeAll <PlayerDataModelSO>().First(); MenuTransitionsHelperSO menuTransitionHelper = Resources.FindObjectsOfTypeAll <MenuTransitionsHelperSO>().FirstOrDefault(); menuTransitionHelper.StartStandardLevel(firstMap, playerDataModel.currentLocalPlayer.gameplayModifiers, playerDataModel.currentLocalPlayer.playerSpecificSettings, null, "Menu", false, null, SongFinished); }); }; } ProvideInitialViewControllers(navigationController); SetViewControllersToNavigationConctroller(navigationController, new VRUIViewController[] { centerViewController }); } }
public void Update() { if (gamePauseManager.pause) { return; //Don't do anything if we're paused } //if (audioTimeSyncController.songTime > 10f && playlist.Count > 0 && !_loadingSong) if (audioTimeSyncController.songTime >= audioTimeSyncController.songLength - 0.3f && playlist.Count > 0 && !_loadingSong) { Logger.Debug("Switching song..."); audioTimeSyncController.StopSong(); //If we don't, there's a chance the song would progress to `songLength - 0.2f` and the base game would finish the game scene Logger.Debug($"Current song: {gameplayCoreSceneSetupData.difficultyBeatmap.level.songName}"); //Clear out old data from objects that would have ideally been recreated ClearOldData(); //Set up new song var gameplayModifiers = gameplayCoreSceneSetupData.gameplayModifiers; var playerSpecificSettings = gameplayCoreSceneSetupData.playerSpecificSettings; float songSpeedMul = gameplayModifiers.songSpeedMul; var level = playlist.Dequeue(); //Load song if it's a custom level if (level is CustomPreviewBeatmapLevel) { var task = Task.Run(async() => await SongHelpers.GetLevelFromPreview(level)); task.Wait(); var result = task.Result; if (result != null && !(result?.isError == true)) { level = result?.beatmapLevel; } } Logger.Debug($"New song: {level.songName}"); var oldMap = gameplayCoreSceneSetupData.difficultyBeatmap; Logger.Debug($"Getting closest difficulty to {gameplayCoreSceneSetupData.difficultyBeatmap.difficulty} with characteristic {gameplayCoreSceneSetupData.difficultyBeatmap.parentDifficultyBeatmapSet.beatmapCharacteristic}..."); IDifficultyBeatmap map = SongHelpers.GetClosestDifficultyPreferLower(level as IBeatmapLevel, (BeatmapDifficulty)preferredDifficulty, gameplayCoreSceneSetupData.difficultyBeatmap.parentDifficultyBeatmapSet.beatmapCharacteristic); Logger.Debug($"Got: {map.difficulty} ({map.parentDifficultyBeatmapSet.beatmapCharacteristic})"); gameplayCoreSceneSetupData.SetField("_difficultyBeatmap", map); BeatmapData beatmapData = BeatDataTransformHelper.CreateTransformedBeatmapData(map.beatmapData, gameplayModifiers, gameplayCoreSceneSetupData.practiceSettings, gameplayCoreSceneSetupData.playerSpecificSettings); beatmapDataModel.beatmapData = beatmapData; //If this is the last song, set up the viewcontrollers in a way that the proper data is displayed after the song var currentPack = levelDetailViewController.GetField <IBeatmapLevelPack>("_pack"); var currentPlayer = levelDetailViewController.GetField <PlayerData>("_playerData"); var currentShowPlayerStats = levelDetailViewController.GetField <bool>("_showPlayerStats"); levelDetailViewController.SetData(currentPack, map.level, currentPlayer, currentShowPlayerStats); audioTimeSyncController.Init(map.level.beatmapLevelData.audioClip, 0f, map.level.songTimeOffset, songSpeedMul); beatmapObjectSpawnController.Init(level.beatsPerMinute, beatmapData.beatmapLinesData.Length, gameplayModifiers.fastNotes ? 20f : (map.noteJumpMovementSpeed == 0 ? map.difficulty.NoteJumpMovementSpeed() : map.noteJumpMovementSpeed), map.noteJumpStartBeatOffset, gameplayModifiers.disappearingArrows, gameplayModifiers.ghostNotes); pauseMenuManager.Init(map.level.songName, map.level.songSubName, map.difficulty.Name()); //Deal with characteristic issues Saber.SaberType saberType; if (gameplayCoreSceneSetup.UseOneSaberOnly(map.parentDifficultyBeatmapSet.beatmapCharacteristic, playerSpecificSettings, out saberType)) { gameplayCoreSceneSetup.GetField <PlayerController>("_playerController").AllowOnlyOneSaber(saberType); } else { gameplayCoreSceneSetup .GetField <PlayerController>("_playerController") .GetField <SaberManager>("_saberManager") .SetField("_allowOnlyOneSaber", false); } Logger.Debug("Starting new song..."); audioTimeSyncController.StartSong(); Logger.Debug("Song started!"); songSwitched?.Invoke(oldMap, map); _loadingSong = false; } //else if (audioTimeSyncController.songTime > 10f && (playlist == null || playlist.Count <= 0) && !_loadingSong) else if (audioTimeSyncController.songTime >= audioTimeSyncController.songLength - 0.3f && (playlist == null || playlist.Count <= 0)) { _loadingSong = true; //Only show the following log message once Logger.Debug($"Would have switched songs, but playlist was null ({playlist == null}) or empty ({playlist?.Count <= 0})"); } }