mirror of
https://github.com/ppy/osu-tools.git
synced 2025-06-07 23:07:01 +09:00
Merge branch 'master' into freestyle-mods
This commit is contained in:
commit
8aa6173b90
8 changed files with 190 additions and 48 deletions
|
@ -4,6 +4,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using Alba.CsConsoleFormat;
|
||||
using JetBrains.Annotations;
|
||||
using McMaster.Extensions.CommandLineUtils;
|
||||
|
@ -27,6 +28,9 @@ namespace PerformanceCalculator.Profile
|
|||
[AllowedValues("0", "1", "2", "3")]
|
||||
public int? Ruleset { get; }
|
||||
|
||||
private const int max_api_scores = 200;
|
||||
private const int max_api_scores_in_one_query = 100;
|
||||
|
||||
public override void Execute()
|
||||
{
|
||||
var displayPlays = new List<UserPlayInfo>();
|
||||
|
@ -39,22 +43,28 @@ namespace PerformanceCalculator.Profile
|
|||
|
||||
Console.WriteLine("Getting user top scores...");
|
||||
|
||||
foreach (var play in GetJsonFromApi<List<SoloScoreInfo>>($"users/{userData.Id}/scores/best?mode={rulesetApiName}&limit=100"))
|
||||
var apiScores = new List<SoloScoreInfo>();
|
||||
|
||||
for (int i = 0; i < max_api_scores; i += max_api_scores_in_one_query)
|
||||
{
|
||||
apiScores.AddRange(GetJsonFromApi<List<SoloScoreInfo>>($"users/{userData.Id}/scores/best?mode={rulesetApiName}&limit={max_api_scores_in_one_query}&offset={i}"));
|
||||
Thread.Sleep(200);
|
||||
}
|
||||
|
||||
foreach (var play in apiScores)
|
||||
{
|
||||
var working = ProcessorWorkingBeatmap.FromFileOrId(play.BeatmapID.ToString());
|
||||
|
||||
Mod[] mods = play.Mods.Select(x => x.ToMod(ruleset)).ToArray();
|
||||
|
||||
var scoreInfo = play.ToScoreInfo(mods);
|
||||
var scoreInfo = play.ToScoreInfo(mods, working.BeatmapInfo);
|
||||
scoreInfo.Ruleset = ruleset.RulesetInfo;
|
||||
|
||||
var score = new ProcessorScoreDecoder(working).Parse(scoreInfo);
|
||||
|
||||
var difficultyCalculator = ruleset.CreateDifficultyCalculator(working);
|
||||
var difficultyAttributes = difficultyCalculator.Calculate(scoreInfo.Mods);
|
||||
var performanceCalculator = ruleset.CreatePerformanceCalculator();
|
||||
|
||||
var ppAttributes = performanceCalculator?.Calculate(score.ScoreInfo, difficultyAttributes);
|
||||
var ppAttributes = performanceCalculator?.Calculate(scoreInfo, difficultyAttributes);
|
||||
var thisPlay = new UserPlayInfo
|
||||
{
|
||||
Beatmap = working.BeatmapInfo,
|
||||
|
|
|
@ -40,6 +40,10 @@ namespace PerformanceCalculator.Simulate
|
|||
[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
|
||||
|
@ -73,6 +77,7 @@ namespace PerformanceCalculator.Simulate
|
|||
Accuracy = GetAccuracy(beatmap, statistics),
|
||||
MaxCombo = Combo ?? (int)Math.Round(PercentCombo / 100 * beatmapMaxCombo),
|
||||
Statistics = statistics,
|
||||
LegacyTotalScore = LegacyTotalScore,
|
||||
Mods = mods
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
// 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 osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
|
||||
namespace PerformanceCalculatorGUI.Components.TextBoxes
|
||||
{
|
||||
public partial class ReadonlyOsuTextBox : OsuTextBox
|
||||
{
|
||||
private readonly string text;
|
||||
private readonly bool hasBackground;
|
||||
|
||||
public ReadonlyOsuTextBox(string text, bool hasBackground = true)
|
||||
{
|
||||
this.text = text;
|
||||
this.hasBackground = hasBackground;
|
||||
|
||||
Text = text;
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
if (!hasBackground)
|
||||
BackgroundUnfocused = BackgroundUnfocused.Opacity(0);
|
||||
|
||||
base.LoadComplete();
|
||||
}
|
||||
|
||||
protected override void OnUserTextAdded(string added)
|
||||
{
|
||||
NotifyInputError();
|
||||
Text = text;
|
||||
}
|
||||
|
||||
protected override void OnUserTextRemoved(string removed)
|
||||
{
|
||||
NotifyInputError();
|
||||
Text = text;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -24,7 +24,7 @@ namespace PerformanceCalculatorGUI
|
|||
public Score Parse(ScoreInfo scoreInfo)
|
||||
{
|
||||
var score = new Score { ScoreInfo = scoreInfo };
|
||||
score.ScoreInfo.LegacyTotalScore = score.ScoreInfo.TotalScore;
|
||||
score.ScoreInfo.LegacyTotalScore ??= score.ScoreInfo.TotalScore;
|
||||
PopulateMaximumStatistics(score.ScoreInfo, beatmap);
|
||||
StandardisedScoreMigrationTools.UpdateFromLegacy(score.ScoreInfo, beatmap);
|
||||
return score;
|
||||
|
|
|
@ -26,6 +26,7 @@ using osu.Game.Screens.Edit;
|
|||
using osu.Game.Screens.Edit.Components;
|
||||
using osu.Game.Screens.Edit.Components.Timelines.Summary;
|
||||
using osu.Game.Screens.Edit.Compose.Components.Timeline;
|
||||
using osu.Game.Skinning;
|
||||
using osuTK.Input;
|
||||
|
||||
namespace PerformanceCalculatorGUI.Screens.ObjectInspection
|
||||
|
@ -133,7 +134,7 @@ namespace PerformanceCalculatorGUI.Screens.ObjectInspection
|
|||
timeline = new Timeline(new TimelineBlueprintContainer())
|
||||
}
|
||||
},
|
||||
rulesetContainer = new Container
|
||||
rulesetContainer = new RulesetSkinProvidingContainer(rulesetInstance, playableBeatmap, null)
|
||||
{
|
||||
Origin = Anchor.TopRight,
|
||||
Anchor = Anchor.TopRight,
|
||||
|
|
|
@ -74,6 +74,8 @@ namespace PerformanceCalculatorGUI.Screens
|
|||
public override bool ShouldShowConfirmationDialogOnSwitch => false;
|
||||
|
||||
private const float username_container_height = 40;
|
||||
private const int max_api_scores = 200;
|
||||
private const int max_api_scores_in_one_query = 100;
|
||||
|
||||
public ProfileScreen()
|
||||
{
|
||||
|
@ -289,11 +291,17 @@ namespace PerformanceCalculatorGUI.Screens
|
|||
|
||||
Schedule(() => loadingLayer.Text.Value = $"Calculating {player.Username} top scores...");
|
||||
|
||||
var apiScores = await apiManager.GetJsonFromApi<List<SoloScoreInfo>>($"users/{player.OnlineID}/scores/best?mode={ruleset.Value.ShortName}&limit=100").ConfigureAwait(false);
|
||||
var apiScores = new List<SoloScoreInfo>();
|
||||
|
||||
for (int i = 0; i < max_api_scores; i += max_api_scores_in_one_query)
|
||||
{
|
||||
apiScores.AddRange(await apiManager.GetJsonFromApi<List<SoloScoreInfo>>($"users/{player.OnlineID}/scores/best?mode={ruleset.Value.ShortName}&limit={max_api_scores_in_one_query}&offset={i}").ConfigureAwait(false));
|
||||
await Task.Delay(200, token).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
if (includePinnedCheckbox.Current.Value)
|
||||
{
|
||||
var pinnedScores = await apiManager.GetJsonFromApi<List<SoloScoreInfo>>($"users/{player.OnlineID}/scores/pinned?mode={ruleset.Value.ShortName}&limit=100")
|
||||
var pinnedScores = await apiManager.GetJsonFromApi<List<SoloScoreInfo>>($"users/{player.OnlineID}/scores/pinned?mode={ruleset.Value.ShortName}&limit={max_api_scores_in_one_query}")
|
||||
.ConfigureAwait(false);
|
||||
apiScores = apiScores.Concat(pinnedScores.Where(p => !apiScores.Any(b => b.ID == p.ID)).ToArray()).ToList();
|
||||
}
|
||||
|
|
96
PerformanceCalculatorGUI/Screens/Simulate/AttributesTable.cs
Normal file
96
PerformanceCalculatorGUI/Screens/Simulate/AttributesTable.cs
Normal file
|
@ -0,0 +1,96 @@
|
|||
// 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.Linq;
|
||||
using Humanizer;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Overlays;
|
||||
using PerformanceCalculatorGUI.Components.TextBoxes;
|
||||
|
||||
namespace PerformanceCalculatorGUI.Screens.Simulate
|
||||
{
|
||||
public partial class AttributesTable : Container
|
||||
{
|
||||
public readonly Bindable<Dictionary<string, object>> Attributes = new Bindable<Dictionary<string, object>>();
|
||||
private const float row_height = 35;
|
||||
|
||||
private FillFlowContainer backgroundFlow;
|
||||
private GridContainer grid;
|
||||
|
||||
[Resolved]
|
||||
private OverlayColourProvider colourProvider { get; set; }
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
RelativeSizeAxes = Axes.X;
|
||||
AutoSizeAxes = Axes.Y;
|
||||
|
||||
CornerRadius = ExtendedLabelledTextBox.CORNER_RADIUS;
|
||||
Masking = true;
|
||||
|
||||
AddRangeInternal(new Drawable[]
|
||||
{
|
||||
backgroundFlow = new FillFlowContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Direction = FillDirection.Vertical
|
||||
},
|
||||
grid = new GridContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
ColumnDimensions = new[] { new Dimension(GridSizeMode.AutoSize), new Dimension() }
|
||||
}
|
||||
});
|
||||
|
||||
Attributes.BindValueChanged(onAttributesChanged);
|
||||
}
|
||||
|
||||
private void onAttributesChanged(ValueChangedEvent<Dictionary<string, object>> changedEvent)
|
||||
{
|
||||
grid.RowDimensions = Enumerable.Repeat(new Dimension(GridSizeMode.Absolute, row_height), changedEvent.NewValue.Count).ToArray();
|
||||
grid.Content = changedEvent.NewValue.Select(s => createRowContent(s.Key, s.Value)).ToArray();
|
||||
|
||||
backgroundFlow.Children = changedEvent.NewValue.Select((_, i) => new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Height = row_height,
|
||||
Colour = colourProvider.Background4.Opacity(i % 2 == 0 ? 0.7f : 0.9f),
|
||||
}).ToArray();
|
||||
}
|
||||
|
||||
private Drawable[] createRowContent(string label, object value) => new Drawable[]
|
||||
{
|
||||
new OsuSpriteText
|
||||
{
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
Font = OsuFont.GetFont(size: 16, weight: FontWeight.Bold),
|
||||
Text = label.Humanize().ToLowerInvariant(),
|
||||
Margin = new MarginPadding { Left = 15, Right = 10 },
|
||||
UseFullGlyphHeight = true
|
||||
},
|
||||
new ReadonlyOsuTextBox(FormattableString.Invariant($"{value:N2}"), false)
|
||||
{
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
Height = 1,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
SelectAllOnFocus = true,
|
||||
FontSize = 18,
|
||||
CornerRadius = ExtendedLabelledTextBox.CORNER_RADIUS
|
||||
},
|
||||
}.ToArray();
|
||||
}
|
||||
}
|
|
@ -5,7 +5,6 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Humanizer;
|
||||
using osu.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio;
|
||||
|
@ -40,6 +39,7 @@ using PerformanceCalculatorGUI.Components;
|
|||
using PerformanceCalculatorGUI.Components.TextBoxes;
|
||||
using PerformanceCalculatorGUI.Configuration;
|
||||
using PerformanceCalculatorGUI.Screens.ObjectInspection;
|
||||
using PerformanceCalculatorGUI.Screens.Simulate;
|
||||
|
||||
namespace PerformanceCalculatorGUI.Screens
|
||||
{
|
||||
|
@ -71,10 +71,10 @@ namespace PerformanceCalculatorGUI.Screens
|
|||
private SwitchButton fullScoreDataSwitch;
|
||||
|
||||
private DifficultyAttributes difficultyAttributes;
|
||||
private FillFlowContainer difficultyAttributesContainer;
|
||||
private FillFlowContainer performanceAttributesContainer;
|
||||
private AttributesTable difficultyAttributesContainer;
|
||||
|
||||
private PerformanceCalculator performanceCalculator;
|
||||
private AttributesTable performanceAttributesContainer;
|
||||
|
||||
[Cached]
|
||||
private Bindable<DifficultyCalculator> difficultyCalculator = new Bindable<DifficultyCalculator>();
|
||||
|
@ -418,37 +418,23 @@ namespace PerformanceCalculatorGUI.Screens
|
|||
{
|
||||
new OsuSpriteText
|
||||
{
|
||||
Margin = new MarginPadding { Left = 10f, Top = 5f, Bottom = 10.0f },
|
||||
Margin = new MarginPadding { Left = 10f, Vertical = 5f },
|
||||
Origin = Anchor.TopLeft,
|
||||
Height = 20,
|
||||
Text = "Difficulty Attributes"
|
||||
},
|
||||
difficultyAttributesContainer = new FillFlowContainer
|
||||
{
|
||||
Direction = FillDirection.Vertical,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Anchor = Anchor.TopLeft,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Spacing = new Vector2(0, 2f)
|
||||
},
|
||||
difficultyAttributesContainer = new AttributesTable(),
|
||||
new OsuSpriteText
|
||||
{
|
||||
Margin = new MarginPadding(10.0f),
|
||||
Margin = new MarginPadding { Left = 10f, Vertical = 5f },
|
||||
Origin = Anchor.TopLeft,
|
||||
Height = 20,
|
||||
Text = "Performance Attributes"
|
||||
},
|
||||
performanceAttributesContainer = new FillFlowContainer
|
||||
{
|
||||
Direction = FillDirection.Vertical,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Anchor = Anchor.TopLeft,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Spacing = new Vector2(0, 2f)
|
||||
},
|
||||
performanceAttributesContainer = new AttributesTable(),
|
||||
new OsuSpriteText
|
||||
{
|
||||
Margin = new MarginPadding(10.0f),
|
||||
Margin = new MarginPadding { Left = 10f, Vertical = 5f },
|
||||
Origin = Anchor.TopLeft,
|
||||
Height = 20,
|
||||
Text = "Strain graph (alt+scroll to zoom)"
|
||||
|
@ -674,14 +660,7 @@ namespace PerformanceCalculatorGUI.Screens
|
|||
try
|
||||
{
|
||||
difficultyAttributes = difficultyCalculator.Value.Calculate(appliedMods.Value);
|
||||
difficultyAttributesContainer.Children = AttributeConversion.ToDictionary(difficultyAttributes).Select(x =>
|
||||
new ExtendedLabelledTextBox
|
||||
{
|
||||
ReadOnly = true,
|
||||
Label = x.Key.Humanize().ToLowerInvariant(),
|
||||
Text = FormattableString.Invariant($"{x.Value:N2}")
|
||||
}
|
||||
).ToArray();
|
||||
difficultyAttributesContainer.Attributes.Value = AttributeConversion.ToDictionary(difficultyAttributes);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
@ -754,17 +733,11 @@ namespace PerformanceCalculatorGUI.Screens
|
|||
Statistics = statistics,
|
||||
Mods = appliedMods.Value.ToArray(),
|
||||
TotalScore = score,
|
||||
Ruleset = ruleset.Value
|
||||
Ruleset = ruleset.Value,
|
||||
LegacyTotalScore = legacyTotalScore,
|
||||
}, difficultyAttributes);
|
||||
|
||||
performanceAttributesContainer.Children = AttributeConversion.ToDictionary(ppAttributes).Select(x =>
|
||||
new ExtendedLabelledTextBox
|
||||
{
|
||||
ReadOnly = true,
|
||||
Label = x.Key.Humanize().ToLowerInvariant(),
|
||||
Text = FormattableString.Invariant($"{x.Value:N2}")
|
||||
}
|
||||
).ToArray();
|
||||
performanceAttributesContainer.Attributes.Value = AttributeConversion.ToDictionary(ppAttributes);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
@ -922,7 +895,10 @@ namespace PerformanceCalculatorGUI.Screens
|
|||
private void resetCalculations()
|
||||
{
|
||||
createCalculators();
|
||||
|
||||
resetMods();
|
||||
legacyTotalScore = null;
|
||||
|
||||
calculateDifficulty();
|
||||
calculatePerformance();
|
||||
populateScoreParams();
|
||||
|
@ -1013,6 +989,8 @@ namespace PerformanceCalculatorGUI.Screens
|
|||
notificationDisplay.Display(new Notification(message));
|
||||
}
|
||||
|
||||
private long? legacyTotalScore;
|
||||
|
||||
private void populateSettingsFromScore(long scoreId)
|
||||
{
|
||||
if (scoreIdPopulateButton.State.Value == ButtonState.Loading)
|
||||
|
@ -1037,6 +1015,8 @@ namespace PerformanceCalculatorGUI.Screens
|
|||
ruleset.Value = rulesets.GetRuleset(scoreInfo.RulesetID);
|
||||
appliedMods.Value = scoreInfo.Mods.Select(x => x.ToMod(ruleset.Value.CreateInstance())).ToList();
|
||||
|
||||
legacyTotalScore = scoreInfo.LegacyTotalScore;
|
||||
|
||||
fullScoreDataSwitch.Current.Value = true;
|
||||
|
||||
// TODO: this shouldn't be done in 2 lines
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue