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));
        }
Esempio n. 2
0
        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);
            }
        }