1
0
Fork 0
mirror of https://github.com/ppy/osu-tools.git synced 2025-06-09 17:44:46 +09:00

Merge branch 'ppy:master' into better_accuracy_estimator

This commit is contained in:
Givikap120 2024-06-28 23:16:09 +03:00 committed by GitHub
commit 925b8f5461
Signed by: github
GPG key ID: B5690EEEBB952194
14 changed files with 51 additions and 65 deletions

4
.vscode/launch.json vendored
View file

@ -7,7 +7,7 @@
"request": "launch",
"program": "dotnet",
"args": [
"${workspaceRoot}/PerformanceCalculator/bin/Debug/net5.0/PerformanceCalculator.dll",
"${workspaceRoot}/PerformanceCalculator/bin/Debug/net8.0/PerformanceCalculator.dll",
"place-your-arguments-here (launch.json)"
],
"cwd": "${workspaceRoot}",
@ -21,7 +21,7 @@
"request": "launch",
"program": "dotnet",
"args": [
"${workspaceRoot}/PerformanceCalculator/bin/Release/net5.0/PerformanceCalculator.dll",
"${workspaceRoot}/PerformanceCalculator/bin/Release/net8.0/PerformanceCalculator.dll",
"place-your-arguments-here (launch.json)"
],
"cwd": "${workspaceRoot}",

View file

@ -1,13 +1,11 @@
// 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.Linq;
using McMaster.Extensions.CommandLineUtils;
using osu.Game.Beatmaps;
using osu.Game.Database;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Scoring.Legacy;
using osu.Game.Scoring;
using osu.Game.Scoring.Legacy;
@ -26,9 +24,6 @@ namespace PerformanceCalculator.Performance
{
var score = base.CreateScore(apiScore, ruleset, apiBeatmap, workingBeatmap);
score.Mods = score.Mods.Append(ruleset.CreateMod<ModClassic>()).ToArray();
score.IsLegacyScore = true;
score.LegacyTotalScore = (int)score.TotalScore;
LegacyScoreDecoder.PopulateMaximumStatistics(score, workingBeatmap);
StandardisedScoreMigrationTools.UpdateFromLegacy(
score,

View file

@ -84,23 +84,41 @@ namespace PerformanceCalculator.Performance
{ "mods", ((int)mods).ToString(CultureInfo.InvariantCulture) }
};
var beatmap = GetJsonFromApi<APIBeatmap>($"beatmaps/{beatmapId}");
switch (rulesetId)
{
case 0:
return GetJsonFromApi<AttributesResponse<OsuDifficultyAttributes>>($"beatmaps/{beatmapId}/attributes", HttpMethod.Post, parameters).Attributes;
return getMergedAttributes<OsuDifficultyAttributes>(beatmap);
case 1:
return GetJsonFromApi<AttributesResponse<TaikoDifficultyAttributes>>($"beatmaps/{beatmapId}/attributes", HttpMethod.Post, parameters).Attributes;
return getMergedAttributes<TaikoDifficultyAttributes>(beatmap);
case 2:
return GetJsonFromApi<AttributesResponse<CatchDifficultyAttributes>>($"beatmaps/{beatmapId}/attributes", HttpMethod.Post, parameters).Attributes;
return getMergedAttributes<CatchDifficultyAttributes>(beatmap);
case 3:
return GetJsonFromApi<AttributesResponse<ManiaDifficultyAttributes>>($"beatmaps/{beatmapId}/attributes", HttpMethod.Post, parameters).Attributes;
return getMergedAttributes<ManiaDifficultyAttributes>(beatmap);
default:
throw new ArgumentOutOfRangeException(nameof(rulesetId));
}
DifficultyAttributes getMergedAttributes<TAttributes>(APIBeatmap apiBeatmap)
where TAttributes : DifficultyAttributes, new()
{
// the osu-web endpoint queries osu-beatmap-difficulty-cache, which in turn does not return the full set of attributes -
// it skips ones that are already present on `APIBeatmap`
// (https://github.com/ppy/osu-beatmap-difficulty-lookup-cache/blob/db2203368221109803f2031788da31deb94e0f11/BeatmapDifficultyLookupCache/DifficultyCache.cs#L125-L128).
// to circumvent this, do some manual grafting on our side to produce a fully populated set of attributes.
var databasedAttributes = GetJsonFromApi<AttributesResponse<TAttributes>>($"beatmaps/{beatmapId}/attributes", HttpMethod.Post, parameters).Attributes;
var fullAttributes = new TAttributes();
fullAttributes.FromDatabaseAttributes(databasedAttributes.ToDatabaseAttributes().ToDictionary(
pair => pair.attributeId,
pair => Convert.ToDouble(pair.value, CultureInfo.InvariantCulture)
), apiBeatmap);
return fullAttributes;
}
}
[JsonObject(MemberSerialization.OptIn)]

View file

@ -58,7 +58,7 @@ namespace PerformanceCalculator.Simulate
var maxCombo = GetMaxCombo(beatmap);
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.OfType<Fruit>().Count() + 2 * beatmap.HitObjects.OfType<JuiceStream>().Count() + beatmap.HitObjects.OfType<JuiceStream>().Sum(s => s.RepeatCount);
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);

View file

@ -80,11 +80,12 @@ namespace PerformanceCalculator.Simulate
int delta = targetTotal - remainingHits;
// Each great and perfect increases total by 5 (great-meh=5)
// There is no difference in accuracy between them, so just halve arbitrarily.
greats = Math.Min(delta / 5, remainingHits) / 2;
int perfects = greats.Value;
// There is no difference in accuracy between them, so just halve arbitrarily (favouring perfects for an odd number).
int greatsAndPerfects = Math.Min(delta / 5, remainingHits);
greats = greatsAndPerfects / 2;
int perfects = greatsAndPerfects - greats.Value;
delta -= (greats.Value + perfects) * 5;
remainingHits -= (greats.Value + perfects);
remainingHits -= greats.Value + perfects;
// Each good increases total by 3 (good-meh=3).
countGood = Math.Min(delta / 3, remainingHits);
@ -93,6 +94,7 @@ namespace PerformanceCalculator.Simulate
// Each ok increases total by 1 (ok-meh=1).
oks = delta;
remainingHits -= oks.Value;
// Everything else is a meh, as initially assumed.
countMeh = remainingHits;

View file

@ -97,7 +97,7 @@ namespace PerformanceCalculatorGUI.Components
{
graphsContainer.Clear();
var skills = val.NewValue.Where(x => x is StrainSkill).ToArray();
var skills = val.NewValue.Where(x => x is StrainSkill or StrainDecaySkill).ToArray();
// dont bother if there are no strain skills to draw
if (skills.Length == 0)

View file

@ -101,7 +101,7 @@ namespace PerformanceCalculatorGUI.Components.TextBoxes
OnFocused?.Invoke();
base.OnFocus(e);
GetContainingInputManager().TriggerFocusContention(this);
GetContainingFocusManager()?.TriggerFocusContention(this);
}
}

View file

@ -3,7 +3,6 @@
using System.Globalization;
using osu.Framework.Bindables;
using osu.Framework.Extensions;
using osu.Game.Graphics.UserInterface;
namespace PerformanceCalculatorGUI.Components.TextBoxes
@ -14,7 +13,7 @@ namespace PerformanceCalculatorGUI.Components.TextBoxes
{
protected override bool AllowIme => false;
protected override bool CanAddCharacter(char character) => character.IsAsciiDigit() || character == CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator[0];
protected override bool CanAddCharacter(char character) => char.IsAsciiDigit(character) || character == CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator[0];
protected override void OnUserTextAdded(string added)
{

View file

@ -6,10 +6,10 @@
<LangVersion>latest</LangVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="ppy.osu.Game" Version="2024.130.2" />
<PackageReference Include="ppy.osu.Game.Rulesets.Osu" Version="2024.130.2" />
<PackageReference Include="ppy.osu.Game.Rulesets.Taiko" Version="2024.130.2" />
<PackageReference Include="ppy.osu.Game.Rulesets.Catch" Version="2024.130.2" />
<PackageReference Include="ppy.osu.Game.Rulesets.Mania" Version="2024.130.2" />
<PackageReference Include="ppy.osu.Game" Version="2024.625.2" />
<PackageReference Include="ppy.osu.Game.Rulesets.Osu" Version="2024.625.2" />
<PackageReference Include="ppy.osu.Game.Rulesets.Taiko" Version="2024.625.2" />
<PackageReference Include="ppy.osu.Game.Rulesets.Catch" Version="2024.625.2" />
<PackageReference Include="ppy.osu.Game.Rulesets.Mania" Version="2024.625.2" />
</ItemGroup>
</Project>

View file

@ -4,21 +4,15 @@
using System.Collections.Generic;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Game.Beatmaps;
using osu.Game.Graphics;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Catch.Difficulty.Preprocessing;
using osu.Game.Rulesets.Catch.Edit;
using osu.Game.Rulesets.Catch.UI;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.UI;
namespace PerformanceCalculatorGUI.Screens.ObjectInspection
{
public partial class CatchObjectInspectorRuleset : DrawableCatchRuleset
public partial class CatchObjectInspectorRuleset : DrawableCatchEditorRuleset
{
private readonly CatchDifficultyHitObject[] difficultyHitObjects;
@ -36,36 +30,12 @@ namespace PerformanceCalculatorGUI.Screens.ObjectInspection
public override bool PropagateNonPositionalInputSubTree => false;
protected override Playfield CreatePlayfield() => new CatchObjectInspectorPlayfield(Beatmap.Difficulty);
public override bool AllowBackwardsSeeks => true;
protected override void Update()
{
base.Update();
objectDifficultyValuesContainer.CurrentDifficultyHitObject.Value = difficultyHitObjects.LastOrDefault(x => x.StartTime < Clock.CurrentTime);
}
private partial class CatchObjectInspectorPlayfield : CatchEditorPlayfield
{
protected override GameplayCursorContainer CreateCursor() => null!;
public CatchObjectInspectorPlayfield(IBeatmapDifficultyInfo difficulty)
: base(difficulty)
{
DisplayJudgements.Value = false;
AddInternal(new Container
{
RelativeSizeAxes = Axes.X,
Y = 440,
Height = 6.0f,
CornerRadius = 4.0f,
Masking = true,
Child = new Box
{
Colour = OsuColour.Gray(0.5f),
RelativeSizeAxes = Axes.Both
}
});
}
}
}
}

View file

@ -9,7 +9,6 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Utils;
using osu.Game.Graphics.Containers;
using osu.Game.Overlays;
using osu.Game.Rulesets.Catch.Difficulty.Preprocessing;
@ -132,7 +131,7 @@ namespace PerformanceCalculatorGUI.Screens.ObjectInspection
});
if (hitObject.Angle is not null)
flowContainer.Add(new ObjectInspectorDifficultyValue("Angle", MathUtils.RadiansToDegrees(hitObject.Angle.Value)));
flowContainer.Add(new ObjectInspectorDifficultyValue("Angle", double.RadiansToDegrees(hitObject.Angle.Value)));
if (hitObject.BaseObject is Slider)
{

View file

@ -178,7 +178,6 @@ namespace PerformanceCalculatorGUI.Screens.ObjectInspection
},
"taiko" => new TaikoPlayfieldAdjustmentContainer
{
RelativeSizeAxes = Axes.Both,
Child = new TaikoObjectInspectorRuleset(rulesetInstance, playableBeatmap, modifiedMods, difficultyCalculator.Value as ExtendedTaikoDifficultyCalculator,
processorBeatmap.Track.Rate)
{

View file

@ -10,13 +10,14 @@ using osu.Game.Rulesets;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Osu.Difficulty.Preprocessing;
using osu.Game.Rulesets.Osu.Edit;
using osu.Game.Rulesets.Osu.Objects.Drawables;
using osu.Game.Rulesets.Osu.UI;
using osu.Game.Rulesets.UI;
namespace PerformanceCalculatorGUI.Screens.ObjectInspection
{
public partial class OsuObjectInspectorRuleset : DrawableOsuRuleset
public partial class OsuObjectInspectorRuleset : DrawableOsuEditorRuleset
{
private readonly OsuDifficultyHitObject[] difficultyHitObjects;
@ -39,6 +40,8 @@ namespace PerformanceCalculatorGUI.Screens.ObjectInspection
public override bool PropagateNonPositionalInputSubTree => false;
public override bool AllowBackwardsSeeks => true;
protected override Playfield CreatePlayfield() => new OsuObjectInspectorPlayfield(difficultyHitObjects);
private partial class OsuObjectInspectorPlayfield : OsuPlayfield
@ -55,14 +58,12 @@ namespace PerformanceCalculatorGUI.Screens.ObjectInspection
protected override void OnNewDrawableHitObject(DrawableHitObject d)
{
base.OnNewDrawableHitObject(d);
d.ApplyCustomUpdateState += updateState;
}
private void updateState(DrawableHitObject hitObject, ArmedState state)
{
if (state == ArmedState.Idle)
return;
if (hitObject is DrawableSliderRepeat repeat)
{
repeat.Arrow.ApplyTransformsAt(hitObject.StateUpdateTime, true);

View file

@ -8,12 +8,13 @@ using osu.Game.Beatmaps;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Taiko.Difficulty.Preprocessing;
using osu.Game.Rulesets.Taiko.Edit;
using osu.Game.Rulesets.Taiko.UI;
using osu.Game.Rulesets.UI;
namespace PerformanceCalculatorGUI.Screens.ObjectInspection
{
public partial class TaikoObjectInspectorRuleset : DrawableTaikoRuleset
public partial class TaikoObjectInspectorRuleset : DrawableTaikoEditorRuleset
{
private readonly TaikoDifficultyHitObject[] difficultyHitObjects;
@ -31,6 +32,8 @@ namespace PerformanceCalculatorGUI.Screens.ObjectInspection
public override bool PropagateNonPositionalInputSubTree => false;
public override bool AllowBackwardsSeeks => true;
protected override Playfield CreatePlayfield() => new TaikoObjectInspectorPlayfield();
protected override void Update()