mirror of
https://github.com/ppy/osu-tools.git
synced 2025-06-08 07:17:01 +09:00
79 lines
3.9 KiB
C#
79 lines
3.9 KiB
C#
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
|
// See the LICENCE file in the repository root for full licence text.
|
|
|
|
using JetBrains.Annotations;
|
|
using McMaster.Extensions.CommandLineUtils;
|
|
using osu.Game.Beatmaps;
|
|
using osu.Game.Rulesets;
|
|
using osu.Game.Rulesets.Catch;
|
|
using osu.Game.Rulesets.Catch.Objects;
|
|
using osu.Game.Rulesets.Mods;
|
|
using osu.Game.Rulesets.Scoring;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
|
|
namespace PerformanceCalculator.Simulate
|
|
{
|
|
[Command(Name = "catch", Description = "Computes the performance (pp) of a simulated osu!catch play.")]
|
|
public class CatchSimulateCommand : SimulateCommand
|
|
{
|
|
[UsedImplicitly]
|
|
[Option(Template = "-c|--combo <combo>", Description = "Maximum combo during play. Defaults to beatmap maximum.")]
|
|
public override int? Combo { get; }
|
|
|
|
[UsedImplicitly]
|
|
[Option(Template = "-C|--percent-combo <combo>", Description = "Percentage of beatmap maximum combo achieved. Alternative to combo option. Enter as decimal 0-100.")]
|
|
public override double PercentCombo { get; } = 100;
|
|
|
|
[UsedImplicitly]
|
|
[Option(Template = "-T|--tiny-droplets <tinys>", Description = "Number of tiny droplets hit. Will override accuracy if used. Otherwise is automatically calculated.")]
|
|
public override int? Mehs { get; }
|
|
|
|
[UsedImplicitly]
|
|
[Option(Template = "-D|--droplets <droplets>", Description = "Number of droplets hit. Will override accuracy if used. Otherwise is automatically calculated.")]
|
|
public override int? Goods { get; }
|
|
|
|
public override Ruleset Ruleset => new CatchRuleset();
|
|
|
|
protected override Dictionary<HitResult, int> GenerateHitResults(IBeatmap beatmap, Mod[] mods) => generateHitResults(beatmap, Accuracy / 100, Misses, Mehs, Goods);
|
|
|
|
private static Dictionary<HitResult, int> generateHitResults(IBeatmap beatmap, double accuracy, int countMiss, int? countMeh, int? countGood)
|
|
{
|
|
int maxCombo = beatmap.GetMaxCombo();
|
|
int maxTinyDroplets = beatmap.HitObjects.OfType<JuiceStream>().Sum(s => s.NestedHitObjects.OfType<TinyDroplet>().Count());
|
|
int maxDroplets = beatmap.HitObjects.OfType<JuiceStream>().Sum(s => s.NestedHitObjects.OfType<Droplet>().Count()) - maxTinyDroplets;
|
|
int maxFruits = beatmap.HitObjects.Sum(h => h is Fruit ? 1 : (h as JuiceStream)?.NestedHitObjects.Count(n => n is Fruit) ?? 0);
|
|
|
|
// Either given or max value minus misses
|
|
int countDroplets = countGood ?? Math.Max(0, maxDroplets - countMiss);
|
|
|
|
// Max value minus whatever misses are left. Negative if impossible missCount
|
|
int countFruits = maxFruits - (countMiss - (maxDroplets - countDroplets));
|
|
|
|
// Either given or the max amount of hit objects with respect to accuracy minus the already calculated fruits and drops.
|
|
// Negative if accuracy not feasable with missCount.
|
|
int countTinyDroplets = countMeh ?? (int)Math.Round(accuracy * (maxCombo + maxTinyDroplets)) - countFruits - countDroplets;
|
|
|
|
// Whatever droplets are left
|
|
int countTinyMisses = maxTinyDroplets - countTinyDroplets;
|
|
|
|
return new Dictionary<HitResult, int>
|
|
{
|
|
{ HitResult.Great, countFruits },
|
|
{ HitResult.LargeTickHit, countDroplets },
|
|
{ HitResult.SmallTickHit, countTinyDroplets },
|
|
{ HitResult.SmallTickMiss, countTinyMisses },
|
|
{ HitResult.Miss, countMiss }
|
|
};
|
|
}
|
|
|
|
protected override double GetAccuracy(IBeatmap beatmap, Dictionary<HitResult, int> statistics)
|
|
{
|
|
double hits = statistics[HitResult.Great] + statistics[HitResult.LargeTickHit] + statistics[HitResult.SmallTickHit];
|
|
double total = hits + statistics[HitResult.Miss] + statistics[HitResult.SmallTickMiss];
|
|
|
|
return hits / total;
|
|
}
|
|
}
|
|
}
|