Skip to content

Commit

Permalink
Merge pull request #246 from stanriders/add-pinned-scores
Browse files Browse the repository at this point in the history
Add an option to include pinned scores when calculating a profile
  • Loading branch information
peppy authored Jan 29, 2025
2 parents c8a907d + ab871ac commit 841c1a9
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 51 deletions.
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 @@ namespace PerformanceCalculatorGUI.Components
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 @@ private void load(RulesetStore rulesets)
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 @@ private void load(RulesetStore rulesets)
{
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
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 @@ private async Task<UserLeaderboardData> calculatePlayer(UserStatistics player, C
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
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 @@ public partial class ProfileScreen : PerformanceCalculatorScreen
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 @@ private void load()
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 @@ private void load()

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 @@ private void calculateProfile(string username)

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 @@ private void calculateProfile(string username)
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 @@ private void calculateProfile(string username)
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 @@ private void calculateProfile(string username)

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 @@ private void calculateProfile(string username)
{
loadingLayer.Hide();
calculationButton.State.Value = ButtonState.Done;
updateSorting(ProfileSortCriteria.Local);
});
}, TaskContinuationOptions.None);
}
Expand Down

0 comments on commit 841c1a9

Please sign in to comment.