Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add an option to include pinned scores when calculating a profile #246

Merged
merged 4 commits into from
Jan 29, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions PerformanceCalculatorGUI/Components/ExtendedProfileScore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,14 @@
public class ExtendedScore
{
public SoloScoreInfo SoloScore { get; }
public double LivePP { get; }
public double? LivePP { get; }

public Bindable<int> Position { get; } = new Bindable<int>();
public Bindable<int> PositionChange { get; } = new Bindable<int>();

public PerformanceAttributes PerformanceAttributes { get; }

public ExtendedScore(SoloScoreInfo score, double livePP, PerformanceAttributes attributes)
public ExtendedScore(SoloScoreInfo score, double? livePP, PerformanceAttributes attributes)

Check notice on line 43 in PerformanceCalculatorGUI/Components/ExtendedProfileScore.cs

View workflow job for this annotation

GitHub Actions / Code Quality

Convert into primary constructor in PerformanceCalculatorGUI\Components\ExtendedProfileScore.cs on line 43
{
SoloScore = score;
PerformanceAttributes = attributes;
Expand Down Expand Up @@ -256,7 +256,7 @@
Child = new OsuSpriteText
{
Font = OsuFont.GetFont(weight: FontWeight.Bold),
Text = $"{Score.LivePP:0}pp"
Text = Score.LivePP != null ? $"{Score.LivePP:0}pp" : "- pp"
},
},
new OsuSpriteText
Expand All @@ -282,7 +282,7 @@
{
var ruleset = rulesets.GetRuleset(Score.SoloScore.RulesetID) ?? throw new InvalidOperationException();

return new ModIcon(ruleset.CreateInstance().CreateModFromAcronym(mod.Acronym)!)
return new ModIcon(mod.ToMod(ruleset.CreateInstance()))
{
Scale = new Vector2(0.35f)
};
Expand Down
39 changes: 0 additions & 39 deletions PerformanceCalculatorGUI/RulesetHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,50 +20,11 @@
using osu.Game.Rulesets.Taiko;
using osu.Game.Rulesets.Taiko.Objects;
using osu.Game.Skinning;
using osu.Game.Utils;

namespace PerformanceCalculatorGUI
{
public static class RulesetHelper
{
/// <summary>
/// Transforms a given <see cref="Mod"/> combination into one which is applicable to legacy scores.
/// This is used to match osu!stable/osu!web calculations for the time being, until such a point that these mods do get considered.
/// </summary>
public static Mod[] ConvertToLegacyDifficultyAdjustmentMods(Ruleset ruleset, Mod[] mods)
{
var beatmap = new EmptyWorkingBeatmap
{
BeatmapInfo =
{
Ruleset = ruleset.RulesetInfo,
Difficulty = new BeatmapDifficulty()
}
};

var allMods = ruleset.CreateAllMods().ToArray();

var allowedMods = ModUtils.FlattenMods(
ruleset.CreateDifficultyCalculator(beatmap).CreateDifficultyAdjustmentModCombinations())
.Select(m => m.GetType())
.Distinct()
.ToHashSet();

// Special case to allow either DT or NC.
if (allowedMods.Any(type => type.IsSubclassOf(typeof(ModDoubleTime))) && mods.Any(m => m is ModNightcore))
allowedMods.Add(allMods.Single(m => m is ModNightcore).GetType());

var result = new List<Mod>();

var classicMod = allMods.SingleOrDefault(m => m is ModClassic);
if (classicMod != null)
result.Add(classicMod);

result.AddRange(mods.Where(m => allowedMods.Contains(m.GetType())));

return result.ToArray();
}

public static DifficultyCalculator GetExtendedDifficultyCalculator(RulesetInfo ruleset, IWorkingBeatmap working)
{
return ruleset.OnlineID switch
Expand Down Expand Up @@ -373,7 +334,7 @@
(6 * total);
}

private class EmptyWorkingBeatmap : WorkingBeatmap

Check failure on line 337 in PerformanceCalculatorGUI/RulesetHelper.cs

View workflow job for this annotation

GitHub Actions / Code Quality

Class 'EmptyWorkingBeatmap' is never used in PerformanceCalculatorGUI\RulesetHelper.cs on line 337
{
public EmptyWorkingBeatmap()
: base(new BeatmapInfo(), null)
Expand Down
2 changes: 1 addition & 1 deletion PerformanceCalculatorGUI/Screens/LeaderboardScreen.cs
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,7 @@
var parsedScore = new ProcessorScoreDecoder(working).Parse(scoreInfo);

var difficultyCalculator = rulesetInstance.CreateDifficultyCalculator(working);
var difficultyAttributes = difficultyCalculator.Calculate(RulesetHelper.ConvertToLegacyDifficultyAdjustmentMods(rulesetInstance, mods));
var difficultyAttributes = difficultyCalculator.Calculate(mods);
var performanceCalculator = rulesetInstance.CreatePerformanceCalculator();

var livePp = score.PP ?? 0.0;
Expand Down Expand Up @@ -353,7 +353,7 @@
decimal totalLivePP = player.PP ?? (decimal)0.0;

index = 0;
decimal nonBonusLivePP = (decimal)liveOrdered.Select(x => x.LivePP).Sum(play => Math.Pow(0.95, index++) * play);

Check failure on line 356 in PerformanceCalculatorGUI/Screens/LeaderboardScreen.cs

View workflow job for this annotation

GitHub Actions / Code Quality

Possible 'System.InvalidOperationException' in PerformanceCalculatorGUI\Screens\LeaderboardScreen.cs on line 356

//todo: implement properly. this is pretty damn wrong.
var playcountBonusPP = (totalLivePP - nonBonusLivePP);
Expand Down
52 changes: 45 additions & 7 deletions PerformanceCalculatorGUI/Screens/ProfileScreen.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,15 @@
using osu.Framework.Graphics.Containers;
using osu.Framework.Input.Events;
using osu.Framework.Logging;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterfaceV2;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Overlays;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Mods;
using osuTK;
using osuTK.Graphics;
using osuTK.Input;
using PerformanceCalculatorGUI.Components;
Expand All @@ -34,6 +37,7 @@
private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Plum);

private StatefulButton calculationButton;
private SwitchButton includePinnedCheckbox;
private VerboseLoadingLayer loadingLayer;

private GridContainer layout;
Expand Down Expand Up @@ -147,6 +151,30 @@
AutoSizeAxes = Axes.Y,
Children = new Drawable[]
{
new FillFlowContainer
{
AutoSizeAxes = Axes.Both,
Direction = FillDirection.Horizontal,
Margin = new MarginPadding { Vertical = 2, Left = 10 },
Spacing = new Vector2(5),
Children = new Drawable[]
{
includePinnedCheckbox = new SwitchButton
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
Current = { Value = true },
},
new OsuSpriteText
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
Font = OsuFont.Torus.With(weight: FontWeight.SemiBold, size: 14),
UseFullGlyphHeight = false,
Text = "Include pinned scores"
}
}
},
sortingTabControl = new OverlaySortTabControl<ProfileSortCriteria>
{
Anchor = Anchor.CentreRight,
Expand Down Expand Up @@ -181,6 +209,7 @@

usernameTextBox.OnCommit += (_, _) => { calculateProfile(usernameTextBox.Current.Value); };
sorting.ValueChanged += e => { updateSorting(e.NewValue); };
includePinnedCheckbox.Current.ValueChanged += e => { calculateProfile(currentUser); };

if (RuntimeInfo.IsDesktop)
HotReloadCallbackReceiver.CompilationFinished += _ => Schedule(() => { calculateProfile(currentUser); });
Expand Down Expand Up @@ -246,6 +275,12 @@

var apiScores = await apiManager.GetJsonFromApi<List<SoloScoreInfo>>($"users/{player.OnlineID}/scores/best?mode={ruleset.Value.ShortName}&limit=100");

if (includePinnedCheckbox.Current.Value)
{
var pinnedScores = await apiManager.GetJsonFromApi<List<SoloScoreInfo>>($"users/{player.OnlineID}/scores/pinned?mode={ruleset.Value.ShortName}&limit=100");
apiScores = apiScores.Concat(pinnedScores.Where(p => !apiScores.Any(b => b.ID == p.ID))).ToList();

Check failure on line 281 in PerformanceCalculatorGUI/Screens/ProfileScreen.cs

View workflow job for this annotation

GitHub Actions / Code Quality

Captured variable is modified in the outer scope in PerformanceCalculatorGUI\Screens\ProfileScreen.cs on line 281
}

foreach (var score in apiScores)
{
if (token.IsCancellationRequested)
Expand All @@ -262,10 +297,10 @@
var parsedScore = new ProcessorScoreDecoder(working).Parse(scoreInfo);

var difficultyCalculator = rulesetInstance.CreateDifficultyCalculator(working);
var difficultyAttributes = difficultyCalculator.Calculate(RulesetHelper.ConvertToLegacyDifficultyAdjustmentMods(rulesetInstance, mods));
var difficultyAttributes = difficultyCalculator.Calculate(mods);
var performanceCalculator = rulesetInstance.CreatePerformanceCalculator();

var livePp = score.PP ?? 0.0;
double? livePp = score.PP;
var perfAttributes = await performanceCalculator?.CalculateAsync(parsedScore.ScoreInfo, difficultyAttributes, token)!;
score.PP = perfAttributes?.Total ?? 0.0;

Expand All @@ -279,15 +314,17 @@
return;

var localOrdered = plays.OrderByDescending(x => x.SoloScore.PP).ToList();
var liveOrdered = plays.OrderByDescending(x => x.LivePP).ToList();
var liveOrdered = plays.OrderByDescending(x => x.LivePP ?? 0).ToList();

Schedule(() =>
{
foreach (var play in plays)
{
play.Position.Value = localOrdered.IndexOf(play) + 1;
play.PositionChange.Value = liveOrdered.IndexOf(play) - localOrdered.IndexOf(play);
scores.SetLayoutPosition(scores[liveOrdered.IndexOf(play)], localOrdered.IndexOf(play));
if (play.LivePP != null)
{
play.Position.Value = localOrdered.IndexOf(play) + 1;
play.PositionChange.Value = liveOrdered.IndexOf(play) - localOrdered.IndexOf(play);
}
}
});

Expand All @@ -299,7 +336,7 @@

decimal nonBonusLivePP = 0;
for (var i = 0; i < liveOrdered.Count; i++)
nonBonusLivePP += (decimal)(Math.Pow(0.95, i) * liveOrdered[i].LivePP);
nonBonusLivePP += (decimal)(Math.Pow(0.95, i) * liveOrdered[i].LivePP ?? 0);

//todo: implement properly. this is pretty damn wrong.
var playcountBonusPP = (totalLivePP - nonBonusLivePP);
Expand All @@ -324,6 +361,7 @@
{
loadingLayer.Hide();
calculationButton.State.Value = ButtonState.Done;
updateSorting(ProfileSortCriteria.Local);
});
}, TaskContinuationOptions.None);
}
Expand Down
Loading