예제 #1
0
        protected override DifficultyAttributes Calculate(IBeatmap beatmap, Mod[] mods, double clockRate)
        {
            var hitObjects = beatmap.HitObjects as List <OsuHitObject>;

            double mapLength = 0;

            if (beatmap.HitObjects.Count > 0)
            {
                mapLength = (beatmap.HitObjects.Last().StartTime - beatmap.HitObjects.First().StartTime) / 1000 / clockRate;
            }

            double preemptNoClockRate = BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.ApproachRate, 1800, 1200, 450);
            var    noteDensities      = NoteDensity.CalculateNoteDensities(hitObjects, preemptNoClockRate);

            // Tap
            var tapAttributes = Tap.CalculateTapAttributes(hitObjects, clockRate);

            // Finger Control
            double fingerControlDiff = FingerControl.CalculateFingerControlDiff(hitObjects, clockRate);

            // Aim
            var aimAttributes = Aim.CalculateAimAttributes(hitObjects, clockRate, tapAttributes.StrainHistory, noteDensities);

            double tapSr           = tap_multiplier * Math.Pow(tapAttributes.TapDifficulty, sr_exponent);
            double aimSr           = aim_multiplier * Math.Pow(aimAttributes.FcProbabilityThroughput, sr_exponent);
            double fingerControlSr = finger_control_multiplier * Math.Pow(fingerControlDiff, sr_exponent);
            double sr = Mean.PowerMean(new[] { tapSr, aimSr, fingerControlSr }, 7) * 1.131;

            HitWindows hitWindows = new OsuHitWindows();

            hitWindows.SetDifficulty(beatmap.BeatmapInfo.BaseDifficulty.OverallDifficulty);

            // Todo: These int casts are temporary to achieve 1:1 results with osu!stable, and should be removed in the future
            double hitWindowGreat = (int)(hitWindows.WindowFor(HitResult.Great)) / clockRate;
            double preempt        = (int)BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.ApproachRate, 1800, 1200, 450) / clockRate;

            int maxCombo = beatmap.HitObjects.Count;

            // Add the ticks + tail of the slider. 1 is subtracted because the head circle would be counted twice (once for the slider itself in the line above)
            maxCombo += beatmap.HitObjects.OfType <Slider>().Sum(s => s.NestedHitObjects.Count - 1);

            return(new OsuDifficultyAttributes
            {
                StarRating = sr,
                Mods = mods,
                Length = mapLength,

                TapSr = tapSr,
                TapDiff = tapAttributes.TapDifficulty,
                StreamNoteCount = tapAttributes.StreamNoteCount,
                MashTapDiff = tapAttributes.MashedTapDifficulty,

                FingerControlSr = fingerControlSr,
                FingerControlDiff = fingerControlDiff,

                AimSr = aimSr,
                AimDiff = aimAttributes.FcProbabilityThroughput,
                AimHiddenFactor = aimAttributes.HiddenFactor,
                ComboTps = aimAttributes.ComboThroughputs,
                MissTps = aimAttributes.MissThroughputs,
                MissCounts = aimAttributes.MissCounts,
                CheeseNoteCount = aimAttributes.CheeseNoteCount,
                CheeseLevels = aimAttributes.CheeseLevels,
                CheeseFactors = aimAttributes.CheeseFactors,

                ApproachRate = preempt > 1200 ? (1800 - preempt) / 120 : (1200 - preempt) / 150 + 5,
                OverallDifficulty = (80 - hitWindowGreat) / 6,
                MaxCombo = maxCombo
            });
        }
예제 #2
0
        protected override DifficultyAttributes Calculate(IBeatmap beatmap, Mod[] mods, double clockRate)
        {
            var hitObjects = beatmap.HitObjects as List <OsuHitObject>;

            if (beatmap.HitObjects.Count == 0)
            {
                return new OsuDifficultyAttributes {
                           Mods = mods
                }
            }
            ;

            double mapLength = (beatmap.HitObjects.Last().StartTime - beatmap.HitObjects.First().StartTime) / 1000 / clockRate;

            // Tap
            (var tapDiff, var streamNoteCount, var mashLevels, var tapSkills, var strainHistory) =
                Tap.CalculateTapAttributes(hitObjects, clockRate);

            // Finger Control
            double fingerControlDiff = FingerControl.CalculateFingerControlDiff(hitObjects, clockRate);

            // Aim
            (var aimDiff, var fcTimeTP, var comboTPs, var missTPs, var missCounts,
             var cheeseNoteCount, var cheeseLevels, var cheeseFactors, var graphText) =
                Aim.CalculateAimAttributes(hitObjects, clockRate, strainHistory);

            // graph for aim
            string graphFilePath = Path.Combine("cache", $"graph_{beatmap.BeatmapInfo.OnlineBeatmapID}.txt");

            File.WriteAllText(graphFilePath, graphText);

            double tapSR           = tapMultiplier * Math.Pow(tapDiff, srExponent);
            double aimSR           = aimMultiplier * Math.Pow(aimDiff, srExponent);
            double fingerControlSR = fingerControlMultiplier * Math.Pow(fingerControlDiff, srExponent);
            double sr = Mean.PowerMean(new double[] { tapSR, aimSR, fingerControlSR }, 7) * 1.131;

            HitWindows hitWindows = new OsuHitWindows();

            hitWindows.SetDifficulty(beatmap.BeatmapInfo.BaseDifficulty.OverallDifficulty);

            // Todo: These int casts are temporary to achieve 1:1 results with osu!stable, and should be removed in the future
            double hitWindowGreat = (int)(hitWindows.Great / 2) / clockRate;
            double preempt        = (int)BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.ApproachRate, 1800, 1200, 450) / clockRate;

            int maxCombo = beatmap.HitObjects.Count;

            // Add the ticks + tail of the slider. 1 is subtracted because the head circle would be counted twice (once for the slider itself in the line above)
            maxCombo += beatmap.HitObjects.OfType <Slider>().Sum(s => s.NestedHitObjects.Count - 1);

            return(new OsuDifficultyAttributes
            {
                StarRating = sr,
                Mods = mods,
                Length = mapLength,

                TapSR = tapSR,
                TapDiff = tapDiff,
                StreamNoteCount = streamNoteCount,
                MashLevels = mashLevels,
                TapSkills = tapSkills,

                FingerControlSR = fingerControlSR,
                FingerControlDiff = fingerControlDiff,

                AimSR = aimSR,
                AimDiff = aimDiff,
                ComboTPs = comboTPs,
                MissTPs = missTPs,
                MissCounts = missCounts,
                CheeseNoteCount = cheeseNoteCount,
                CheeseLevels = cheeseLevels,
                CheeseFactors = cheeseFactors,

                ApproachRate = preempt > 1200 ? (1800 - preempt) / 120 : (1200 - preempt) / 150 + 5,
                OverallDifficulty = (80 - hitWindowGreat) / 6,
                MaxCombo = maxCombo
            });
        }