private void Setup() { Plugin.Log.Debug($"Setup start."); if (this.pauseController != null) { this.pauseController.didResumeEvent += OnGameResume; } if (ScoreDataBase.Instance.Init) { this.relativeScoreAndImmediateRankCounter.relativeScoreOrImmediateRankDidChangeEvent += this.RelativeScoreAndImmediateRankCounter_relativeScoreOrImmediateRankDidChangeEvent; } var beatmapLevel = CurrentData.difficultyBeatmap.level; this._currentBeatmapDifficulty = CurrentData.difficultyBeatmap.difficulty; var levelID = beatmapLevel.levelID; this._currentCustomBeatmapLevel = Loader.GetLevelByHash(levelID.Split('_').Last()); this.songRawPP = ScoreDataBase.Instance.Init ? PPCounterUtil.GetPP(_currentCustomBeatmapLevel, _currentBeatmapDifficulty) : 0; if (_currentCustomBeatmapLevel != null) { HMMainThreadDispatcher.instance.Enqueue(this.SetCustomLabel(_currentCustomBeatmapLevel, _currentBeatmapDifficulty)); } this._currentStarSong = SongDataCoreUtil.GetBeatStarSong(_currentCustomBeatmapLevel); this._currentStarSongDiff = SongDataCoreUtil.GetBeatStarSongDiffculityStats(_currentCustomBeatmapLevel, _currentBeatmapDifficulty); if (this.statusManager.StatusJSON["beatmap"] == null) { this.statusManager.StatusJSON["beatmap"] = new JSONObject(); } var beatmapJson = this.statusManager.StatusJSON["beatmap"].AsObject; if (this._currentStarSong != null && this._currentStarSongDiff != null) { var multiplier = this.statusManager.GameStatus.songSpeedMultiplier; if (ScoreDataBase.Instance.Init) { if (multiplier == 1 || !PPCounterUtil.AllowedPositiveModifiers(levelID)) { beatmapJson["pp"] = new JSONNumber(this.songRawPP * 1.12); } else { beatmapJson["pp"] = new JSONNumber(PPCounterUtil.CalculatePP(this.songRawPP, multiplier)); } } beatmapJson["star"] = new JSONNumber(this._currentStarSongDiff.star); beatmapJson["downloadCount"] = new JSONNumber(this._currentStarSong.downloadCount); beatmapJson["upVotes"] = new JSONNumber(this._currentStarSong.upVotes); beatmapJson["downVotes"] = new JSONNumber(this._currentStarSong.downVotes); beatmapJson["rating"] = new JSONNumber(this._currentStarSong.rating); } HMMainThreadDispatcher.instance.Enqueue(this.SongStartWait(this._currentStarSong != null && this._currentStarSongDiff != null)); }
private static SongDataCoreDataStatus _GetBeatmapDetails(CustomPreviewBeatmapLevel level, out BeatmapDetails beatmapDetails) { if (!IsDataAvailable || !SongDataCorePlugin.Songs.Data.Songs.TryGetValue(GetCustomLevelHash(level), out var song)) { beatmapDetails = null; return(SongDataCoreDataStatus.NoData); } try { float bpm = song.bpm; if (bpm < 0.001f) { beatmapDetails = null; return(SongDataCoreDataStatus.InvalidBPM); } // NOTE: since BeatSaver calculates the duration of a song using the last note (or event?) of a beatmap, instead of the using the length of the audio file, // it is extremely likely that this duration is going to be a bit shorter than the actual length of the audio (typically < 10 seconds shorter) // (or even vastly shorter if there is a long period of no notes at the end of a beatmap) // despite that, i'll keep this limitation since the difference should usually be minimal // and the speedup compared to loading beatmap details for the first time is fairly massive Func <KeyValuePair <BeatStarCharacteristics, Dictionary <string, BeatStarSongDifficultyStats> >, float> getDuration = delegate(KeyValuePair <BeatStarCharacteristics, Dictionary <string, BeatStarSongDifficultyStats> > characteristics) { var characteristicDurations = characteristics.Value.Select(delegate(KeyValuePair <string, BeatStarSongDifficultyStats> data) { if (data.Value == null) { return(0f); } else { return(Convert.ToSingle(data.Value.len)); } }); return(characteristicDurations.Any() ? characteristicDurations.Max() : 0f); }; var durations = song.characteristics.Select(getDuration); float duration; if (durations.Any(x => x > 0f)) { // assuming the maximum is the actual duration duration = durations.Max(); } else { beatmapDetails = null; return(SongDataCoreDataStatus.InvalidDuration); } SimplifiedDifficultyBeatmapSet[] difficultyBeatmapSets; try { difficultyBeatmapSets = song.characteristics.Select(delegate(KeyValuePair <BeatStarCharacteristics, Dictionary <string, BeatStarSongDifficultyStats> > characteristicPair) { BeatStarCharacteristics loadedCharacteristicName = characteristicPair.Key; string actualCharacteristicName = loadedCharacteristicName != BeatStarCharacteristics.Unkown ? loadedCharacteristicName.ToString() : null; if (string.IsNullOrEmpty(actualCharacteristicName)) { Logger.log.Debug($"Unable to create SimplifiedDifficultyBeatmapSet from BeatSaver data: could not parse '{loadedCharacteristicName.ToString()}' as a valid characteristic."); return(null); } SimplifiedDifficultyBeatmap[] difficultyBeatmaps = characteristicPair.Value.Where(x => x.Value != null).Select(delegate(KeyValuePair <string, BeatStarSongDifficultyStats> difficultyPair) { // this will throw an exception (that will be caught) if the difficulty name cannot be parsed var diffString = difficultyPair.Key == "Expert+" ? "ExpertPlus" : difficultyPair.Key; var diff = (BeatmapDifficulty)Enum.Parse(typeof(BeatmapDifficulty), diffString); BeatStarSongDifficultyStats data = difficultyPair.Value; // NOTE: from my testing, the parsed NJS could be 0, so that should be fixed by loading the details stored locally return(new SimplifiedDifficultyBeatmap(diff, Convert.ToSingle(data.njs), data.nts, data.bmb, data.obs, 0)); }).ToArray(); return(new SimplifiedDifficultyBeatmapSet(actualCharacteristicName, difficultyBeatmaps)); }).ToArray(); } catch (ArgumentException) { // NOTE: this exception should only be able to be thrown when parsing BeatmapDifficulty, // but that may change if the above function is changed in the future beatmapDetails = null; return(SongDataCoreDataStatus.InvalidDifficultyString); } // if there were any errors during the creation of the SimplifiedDifficultyBeatmapSet objects, do not create a BeatmapDetails object from it // currently, the only error we need to check for here is if the characteristic name is invalid if (difficultyBeatmapSets.Any(x => x == null || string.IsNullOrEmpty(x.CharacteristicName) || x.DifficultyBeatmaps == null)) { beatmapDetails = null; return(SongDataCoreDataStatus.InvalidCharacteristicString); } beatmapDetails = new BeatmapDetails(level.levelID, level.songName, bpm, duration, difficultyBeatmapSets); return(SongDataCoreDataStatus.Success); } catch (Exception e) { Logger.log.Debug($"Exception thrown when trying to create BeatmapDetails object for level ID '{level.levelID}' from information provided by SongDataCore"); Logger.log.Debug(e); beatmapDetails = null; return(SongDataCoreDataStatus.ExceptionThrown); } }