mirror of
https://github.com/ppy/osu-tools.git
synced 2025-06-07 23:07:01 +09:00
96 lines
4 KiB
C#
96 lines
4 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 System;
|
|
using System.Collections.Generic;
|
|
using System.ComponentModel.DataAnnotations;
|
|
using JetBrains.Annotations;
|
|
using McMaster.Extensions.CommandLineUtils;
|
|
using osu.Game.Beatmaps;
|
|
using osu.Game.Rulesets;
|
|
using osu.Game.Rulesets.Mods;
|
|
using osu.Game.Rulesets.Scoring;
|
|
using osu.Game.Scoring;
|
|
|
|
namespace PerformanceCalculator.Simulate
|
|
{
|
|
public abstract class SimulateCommand : ProcessorCommand
|
|
{
|
|
public abstract Ruleset Ruleset { get; }
|
|
|
|
[UsedImplicitly]
|
|
[Required]
|
|
[Argument(0, Name = "beatmap", Description = "Required. Can be either a path to beatmap file (.osu) or beatmap ID.")]
|
|
public string Beatmap { get; }
|
|
|
|
[UsedImplicitly]
|
|
[Option(Template = "-a|--accuracy <accuracy>", Description = "Accuracy. Enter as decimal 0-100. Defaults to 100. Scales hit results as well and is rounded to the nearest possible value for the beatmap.")]
|
|
public double Accuracy { get; } = 100;
|
|
|
|
[UsedImplicitly]
|
|
[Option(CommandOptionType.MultipleValue, Template = "-m|--mod <mod>", Description = "One for each mod. The mods to compute the performance with. Values: hr, dt, hd, fl, etc...")]
|
|
public string[] Mods { get; }
|
|
|
|
[UsedImplicitly]
|
|
[Option(CommandOptionType.MultipleValue, Template = "-o|--mod-option <option>",
|
|
Description = "The options of mods, with one for each setting. Specified as acryonym_settingkey=value. Example: DT_speed_change=1.35")]
|
|
public string[] ModOptions { get; set; } = [];
|
|
|
|
[UsedImplicitly]
|
|
[Option(Template = "-X|--misses <misses>", Description = "Number of misses. Defaults to 0.")]
|
|
public int Misses { get; }
|
|
|
|
[UsedImplicitly]
|
|
[Option(Template = "-l|--legacy-total-score <score>", Description = "Amount of legacy total score.")]
|
|
public long? LegacyTotalScore { get; }
|
|
|
|
//
|
|
// Options implemented in the ruleset-specific commands
|
|
// -> Catch renames Mehs/Goods to (tiny-)droplets
|
|
// -> Mania does not have Combo
|
|
// -> Taiko does not have Mehs
|
|
//
|
|
[UsedImplicitly]
|
|
public virtual int? Mehs { get; }
|
|
|
|
[UsedImplicitly]
|
|
public virtual int? Goods { get; }
|
|
|
|
[UsedImplicitly]
|
|
public virtual int? Combo { get; }
|
|
|
|
[UsedImplicitly]
|
|
public virtual double PercentCombo { get; }
|
|
|
|
public override void Execute()
|
|
{
|
|
var ruleset = Ruleset;
|
|
|
|
var workingBeatmap = ProcessorWorkingBeatmap.FromFileOrId(Beatmap);
|
|
var mods = ParseMods(ruleset, Mods, ModOptions);
|
|
var beatmap = workingBeatmap.GetPlayableBeatmap(ruleset.RulesetInfo, mods);
|
|
|
|
int beatmapMaxCombo = beatmap.GetMaxCombo();
|
|
var statistics = GenerateHitResults(beatmap, mods);
|
|
var scoreInfo = new ScoreInfo(beatmap.BeatmapInfo, ruleset.RulesetInfo)
|
|
{
|
|
Accuracy = GetAccuracy(beatmap, statistics, mods),
|
|
MaxCombo = Combo ?? (int)Math.Round(PercentCombo / 100 * beatmapMaxCombo),
|
|
Statistics = statistics,
|
|
LegacyTotalScore = LegacyTotalScore,
|
|
Mods = mods
|
|
};
|
|
|
|
var difficultyCalculator = ruleset.CreateDifficultyCalculator(workingBeatmap);
|
|
var difficultyAttributes = difficultyCalculator.Calculate(mods);
|
|
var performanceCalculator = ruleset.CreatePerformanceCalculator();
|
|
var performanceAttributes = performanceCalculator?.Calculate(scoreInfo, difficultyAttributes);
|
|
|
|
OutputPerformance(scoreInfo, performanceAttributes, difficultyAttributes);
|
|
}
|
|
|
|
protected abstract Dictionary<HitResult, int> GenerateHitResults(IBeatmap beatmap, Mod[] mods);
|
|
|
|
protected virtual double GetAccuracy(IBeatmap beatmap, Dictionary<HitResult, int> statistics, Mod[] mods) => 0;
|
|
}
|
|
}
|