mirror of
https://github.com/ppy/osu-tools.git
synced 2025-06-07 23:07:01 +09:00
Massive simplification
This commit is contained in:
parent
25344481aa
commit
5f3a13052c
5 changed files with 375 additions and 615 deletions
|
@ -1,53 +0,0 @@
|
|||
// 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.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osu.Game.Rulesets;
|
||||
using osuTK;
|
||||
using osu.Game.Users.Drawables;
|
||||
|
||||
namespace PerformanceCalculatorGUI.Components
|
||||
{
|
||||
public partial class ExtendedCombinedProfileScore : ExtendedProfileScore
|
||||
{
|
||||
private APIUser User;
|
||||
|
||||
public ExtendedCombinedProfileScore(ExtendedScore score, APIUser user)
|
||||
: base(score)
|
||||
{
|
||||
User = user;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(RulesetStore rulesets)
|
||||
{
|
||||
AddInternal(new UpdateableAvatar(User, false)
|
||||
{
|
||||
Size = new Vector2(height)
|
||||
});
|
||||
}
|
||||
|
||||
protected override ExtendedProfileItemContainer ProfileScoreItems(RulesetStore rulesets)
|
||||
{
|
||||
var items = new ExtendedProfileItemContainer {
|
||||
// This doesn't show the rounded corners on the right hand side but it's the best I could figure out, please feel free to improve it
|
||||
Position = new Vector2(height, 0),
|
||||
Padding = new MarginPadding { Right = height },
|
||||
|
||||
OnHoverAction = () =>
|
||||
{
|
||||
positionChangeText.Text = $"#{Score.Position.Value}";
|
||||
},
|
||||
OnUnhoverAction = () =>
|
||||
{
|
||||
positionChangeText.Text = $"{Score.PositionChange.Value:+0;-0;-}";
|
||||
},
|
||||
Children = ProfileScoreDrawables(rulesets)
|
||||
};
|
||||
|
||||
return items;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -25,6 +25,7 @@ using osu.Game.Rulesets.Difficulty;
|
|||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Rulesets.UI;
|
||||
using osu.Game.Utils;
|
||||
using osu.Game.Users.Drawables;
|
||||
using osuTK;
|
||||
using PerformanceCalculatorGUI.Components.TextBoxes;
|
||||
|
||||
|
@ -73,7 +74,7 @@ namespace PerformanceCalculatorGUI.Components
|
|||
|
||||
public partial class ExtendedProfileScore : CompositeDrawable
|
||||
{
|
||||
protected const int height = 35;
|
||||
private const int height = 35;
|
||||
private const int performance_width = 100;
|
||||
private const int rank_difference_width = 35;
|
||||
private const int small_text_font_size = 11;
|
||||
|
@ -81,6 +82,8 @@ namespace PerformanceCalculatorGUI.Components
|
|||
private const float performance_background_shear = 0.45f;
|
||||
|
||||
public readonly ExtendedScore Score;
|
||||
|
||||
public readonly bool ShowAvatar;
|
||||
|
||||
[Resolved]
|
||||
private OsuColour colours { get; set; }
|
||||
|
@ -88,11 +91,12 @@ namespace PerformanceCalculatorGUI.Components
|
|||
[Resolved]
|
||||
private OverlayColourProvider colourProvider { get; set; }
|
||||
|
||||
protected OsuSpriteText positionChangeText;
|
||||
private OsuSpriteText positionChangeText;
|
||||
|
||||
public ExtendedProfileScore(ExtendedScore score)
|
||||
public ExtendedProfileScore(ExtendedScore score, bool showAvatar = false)
|
||||
{
|
||||
Score = score;
|
||||
ShowAvatar = showAvatar;
|
||||
|
||||
RelativeSizeAxes = Axes.X;
|
||||
Height = height;
|
||||
|
@ -101,14 +105,20 @@ namespace PerformanceCalculatorGUI.Components
|
|||
[BackgroundDependencyLoader]
|
||||
private void load(RulesetStore rulesets)
|
||||
{
|
||||
AddInternal(ProfileScoreItems(rulesets));
|
||||
|
||||
Score.PositionChange.BindValueChanged(v => { positionChangeText.Text = $"{v.NewValue:+0;-0;-}"; });
|
||||
}
|
||||
|
||||
protected virtual ExtendedProfileItemContainer ProfileScoreItems(RulesetStore rulesets)
|
||||
{
|
||||
var items = new ExtendedProfileItemContainer {
|
||||
if (ShowAvatar)
|
||||
{
|
||||
AddInternal(new UpdateableAvatar(Score.SoloScore.User, false)
|
||||
{
|
||||
Size = new Vector2(height)
|
||||
});
|
||||
}
|
||||
|
||||
AddInternal(new ExtendedProfileItemContainer
|
||||
{
|
||||
// Resize to make room for avatar if necessary
|
||||
X = ShowAvatar ? height : 0,
|
||||
Padding = ShowAvatar ? new MarginPadding { Right = height } : new MarginPadding {},
|
||||
|
||||
OnHoverAction = () =>
|
||||
{
|
||||
positionChangeText.Text = $"#{Score.Position.Value}";
|
||||
|
@ -117,263 +127,257 @@ namespace PerformanceCalculatorGUI.Components
|
|||
{
|
||||
positionChangeText.Text = $"{Score.PositionChange.Value:+0;-0;-}";
|
||||
},
|
||||
Children = ProfileScoreDrawables(rulesets)
|
||||
};
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
protected Drawable[] ProfileScoreDrawables(RulesetStore rulesets)
|
||||
{
|
||||
Drawable[] drawables = {
|
||||
new Container
|
||||
Children = new Drawable[]
|
||||
{
|
||||
Name = "Rank difference",
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
Width = rank_difference_width,
|
||||
Child = positionChangeText = new OsuSpriteText
|
||||
new Container
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Colour = colourProvider.Light1,
|
||||
Text = Score.PositionChange.Value.ToString()
|
||||
}
|
||||
},
|
||||
new Container
|
||||
{
|
||||
Name = "Score info",
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Padding = new MarginPadding { Left = rank_difference_width, Right = performance_width },
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new FillFlowContainer
|
||||
Name = "Rank difference",
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
Width = rank_difference_width,
|
||||
Child = positionChangeText = new OsuSpriteText
|
||||
{
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Horizontal,
|
||||
Spacing = new Vector2(10, 0),
|
||||
Children = new Drawable[]
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Colour = colourProvider.Light1,
|
||||
Text = Score.PositionChange.Value.ToString()
|
||||
}
|
||||
},
|
||||
new Container
|
||||
{
|
||||
Name = "Score info",
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Padding = new MarginPadding { Left = rank_difference_width, Right = performance_width },
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new FillFlowContainer
|
||||
{
|
||||
new UpdateableRank(Score.SoloScore.Rank)
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Horizontal,
|
||||
Spacing = new Vector2(10, 0),
|
||||
Children = new Drawable[]
|
||||
{
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
Size = new Vector2(50, 20),
|
||||
},
|
||||
new FillFlowContainer
|
||||
{
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Vertical,
|
||||
Spacing = new Vector2(0, 0.5f),
|
||||
Children = new Drawable[]
|
||||
new UpdateableRank(Score.SoloScore.Rank)
|
||||
{
|
||||
new ScoreBeatmapMetadataContainer(Score.SoloScore.Beatmap),
|
||||
new FillFlowContainer
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
Size = new Vector2(50, 20),
|
||||
},
|
||||
new FillFlowContainer
|
||||
{
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Vertical,
|
||||
Spacing = new Vector2(0, 0.5f),
|
||||
Children = new Drawable[]
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Horizontal,
|
||||
Spacing = new Vector2(15, 0),
|
||||
Children = new Drawable[]
|
||||
new ScoreBeatmapMetadataContainer(Score.SoloScore.Beatmap),
|
||||
new FillFlowContainer
|
||||
{
|
||||
new OsuSpriteText
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Horizontal,
|
||||
Spacing = new Vector2(15, 0),
|
||||
Children = new Drawable[]
|
||||
{
|
||||
Text = $"{Score.SoloScore.Beatmap?.DifficultyName}",
|
||||
Font = OsuFont.GetFont(size: 12, weight: FontWeight.Regular),
|
||||
Colour = colours.Yellow
|
||||
},
|
||||
new DrawableDate(Score.SoloScore.EndedAt, 12)
|
||||
{
|
||||
Colour = colourProvider.Foreground1
|
||||
new OsuSpriteText
|
||||
{
|
||||
Text = $"{Score.SoloScore.Beatmap?.DifficultyName}",
|
||||
Font = OsuFont.GetFont(size: 12, weight: FontWeight.Regular),
|
||||
Colour = colours.Yellow
|
||||
},
|
||||
new DrawableDate(Score.SoloScore.EndedAt, 12)
|
||||
{
|
||||
Colour = colourProvider.Foreground1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
new FillFlowContainer
|
||||
{
|
||||
Anchor = Anchor.CentreRight,
|
||||
Origin = Anchor.CentreRight,
|
||||
AutoSizeAxes = Axes.X,
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
Direction = FillDirection.Horizontal,
|
||||
Children = new Drawable[]
|
||||
},
|
||||
new FillFlowContainer
|
||||
{
|
||||
new Container
|
||||
Anchor = Anchor.CentreRight,
|
||||
Origin = Anchor.CentreRight,
|
||||
AutoSizeAxes = Axes.X,
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
Direction = FillDirection.Horizontal,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
AutoSizeAxes = Axes.X,
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
Padding = new MarginPadding { Horizontal = 10, Vertical = 5 },
|
||||
Anchor = Anchor.CentreRight,
|
||||
Origin = Anchor.CentreRight,
|
||||
Child = new FillFlowContainer
|
||||
new Container
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Vertical,
|
||||
Origin = Anchor.CentreLeft,
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Children = new Drawable[]
|
||||
AutoSizeAxes = Axes.X,
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
Padding = new MarginPadding { Horizontal = 10, Vertical = 5 },
|
||||
Anchor = Anchor.CentreRight,
|
||||
Origin = Anchor.CentreRight,
|
||||
Child = new FillFlowContainer
|
||||
{
|
||||
new FillFlowContainer
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Vertical,
|
||||
Origin = Anchor.CentreLeft,
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Horizontal,
|
||||
Spacing = new Vector2(10, 0),
|
||||
Children = new Drawable[]
|
||||
new FillFlowContainer
|
||||
{
|
||||
new FillFlowContainer
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Horizontal,
|
||||
Spacing = new Vector2(10, 0),
|
||||
Children = new Drawable[]
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Width = 110,
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
Direction = FillDirection.Vertical,
|
||||
Children = new Drawable[]
|
||||
new FillFlowContainer
|
||||
{
|
||||
new OsuSpriteText
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Width = 110,
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
Direction = FillDirection.Vertical,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
Text = Score.SoloScore.Accuracy.FormatAccuracy(),
|
||||
Font = OsuFont.GetFont(weight: FontWeight.Bold, italics: true),
|
||||
Colour = colours.Yellow,
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre
|
||||
},
|
||||
new OsuSpriteText
|
||||
{
|
||||
Text = $"{Score.SoloScore.MaxCombo}x {{ {formatStatistics(Score.SoloScore.Statistics)} }}",
|
||||
Font = OsuFont.GetFont(size: small_text_font_size, weight: FontWeight.Regular),
|
||||
Colour = colourProvider.Light2,
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre
|
||||
},
|
||||
}
|
||||
},
|
||||
new FillFlowContainer
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Width = 60,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Direction = FillDirection.Vertical,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Container
|
||||
{
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Child = new OsuSpriteText
|
||||
new OsuSpriteText
|
||||
{
|
||||
Font = OsuFont.GetFont(weight: FontWeight.Bold),
|
||||
Text = Score.LivePP != null ? $"{Score.LivePP:0}pp" : "- pp"
|
||||
Text = Score.SoloScore.Accuracy.FormatAccuracy(),
|
||||
Font = OsuFont.GetFont(weight: FontWeight.Bold, italics: true),
|
||||
Colour = colours.Yellow,
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre
|
||||
},
|
||||
},
|
||||
new OsuSpriteText
|
||||
new OsuSpriteText
|
||||
{
|
||||
Text = $"{Score.SoloScore.MaxCombo}x {{ {formatStatistics(Score.SoloScore.Statistics)} }}",
|
||||
Font = OsuFont.GetFont(size: small_text_font_size, weight: FontWeight.Regular),
|
||||
Colour = colourProvider.Light2,
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre
|
||||
},
|
||||
}
|
||||
},
|
||||
new FillFlowContainer
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Width = 60,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Direction = FillDirection.Vertical,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
Font = OsuFont.GetFont(size: small_text_font_size),
|
||||
Text = "live"
|
||||
new Container
|
||||
{
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Child = new OsuSpriteText
|
||||
{
|
||||
Font = OsuFont.GetFont(weight: FontWeight.Bold),
|
||||
Text = Score.LivePP != null ? $"{Score.LivePP:0}pp" : "- pp"
|
||||
},
|
||||
},
|
||||
new OsuSpriteText
|
||||
{
|
||||
Font = OsuFont.GetFont(size: small_text_font_size),
|
||||
Text = "live"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
new FillFlowContainer
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Anchor = Anchor.CentreRight,
|
||||
Origin = Anchor.CentreRight,
|
||||
Direction = FillDirection.Horizontal,
|
||||
Spacing = new Vector2(2),
|
||||
Children = Score.SoloScore.Mods.Select(mod =>
|
||||
},
|
||||
new FillFlowContainer
|
||||
{
|
||||
var ruleset = rulesets.GetRuleset(Score.SoloScore.RulesetID) ?? throw new InvalidOperationException();
|
||||
|
||||
return new ModIcon(mod.ToMod(ruleset.CreateInstance()))
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Anchor = Anchor.CentreRight,
|
||||
Origin = Anchor.CentreRight,
|
||||
Direction = FillDirection.Horizontal,
|
||||
Spacing = new Vector2(2),
|
||||
Children = Score.SoloScore.Mods.Select(mod =>
|
||||
{
|
||||
Scale = new Vector2(0.35f)
|
||||
};
|
||||
}).ToList(),
|
||||
var ruleset = rulesets.GetRuleset(Score.SoloScore.RulesetID) ?? throw new InvalidOperationException();
|
||||
|
||||
return new ModIcon(mod.ToMod(ruleset.CreateInstance()))
|
||||
{
|
||||
Scale = new Vector2(0.35f)
|
||||
};
|
||||
}).ToList(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
new Container
|
||||
{
|
||||
Name = "Performance",
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
Width = performance_width,
|
||||
Anchor = Anchor.CentreRight,
|
||||
Origin = Anchor.CentreRight,
|
||||
Children = new Drawable[]
|
||||
},
|
||||
new Container
|
||||
{
|
||||
new Box
|
||||
Name = "Performance",
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
Width = performance_width,
|
||||
Anchor = Anchor.CentreRight,
|
||||
Origin = Anchor.CentreRight,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
Anchor = Anchor.TopRight,
|
||||
Origin = Anchor.TopRight,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Height = 0.5f,
|
||||
Colour = colourProvider.Background4,
|
||||
Shear = new Vector2(-performance_background_shear, 0),
|
||||
EdgeSmoothness = new Vector2(2, 0),
|
||||
},
|
||||
new Box
|
||||
{
|
||||
Anchor = Anchor.TopRight,
|
||||
Origin = Anchor.TopRight,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
RelativePositionAxes = Axes.Y,
|
||||
Height = -0.5f,
|
||||
Position = new Vector2(0, 1),
|
||||
Colour = colourProvider.Background4,
|
||||
Shear = new Vector2(performance_background_shear, 0),
|
||||
EdgeSmoothness = new Vector2(2, 0),
|
||||
},
|
||||
new FillFlowContainer
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Padding = new MarginPadding
|
||||
new Box
|
||||
{
|
||||
Vertical = 5,
|
||||
Left = 30,
|
||||
Right = 20
|
||||
Anchor = Anchor.TopRight,
|
||||
Origin = Anchor.TopRight,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Height = 0.5f,
|
||||
Colour = colourProvider.Background4,
|
||||
Shear = new Vector2(-performance_background_shear, 0),
|
||||
EdgeSmoothness = new Vector2(2, 0),
|
||||
},
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Direction = FillDirection.Vertical,
|
||||
Children = new Drawable[]
|
||||
new Box
|
||||
{
|
||||
new ExtendedOsuSpriteText
|
||||
Anchor = Anchor.TopRight,
|
||||
Origin = Anchor.TopRight,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
RelativePositionAxes = Axes.Y,
|
||||
Height = -0.5f,
|
||||
Position = new Vector2(0, 1),
|
||||
Colour = colourProvider.Background4,
|
||||
Shear = new Vector2(performance_background_shear, 0),
|
||||
EdgeSmoothness = new Vector2(2, 0),
|
||||
},
|
||||
new FillFlowContainer
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Padding = new MarginPadding
|
||||
{
|
||||
Font = OsuFont.GetFont(weight: FontWeight.Bold),
|
||||
Text = $"{Score.SoloScore.PP:0}pp",
|
||||
Colour = colourProvider.Highlight1,
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
TooltipContent = $"{AttributeConversion.ToReadableString(Score.PerformanceAttributes)}"
|
||||
Vertical = 5,
|
||||
Left = 30,
|
||||
Right = 20
|
||||
},
|
||||
new OsuSpriteText
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Direction = FillDirection.Vertical,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
Font = OsuFont.GetFont(size: small_text_font_size),
|
||||
Text = $"{Score.SoloScore.PP - Score.LivePP:+0.0;-0.0;-}",
|
||||
Colour = colourProvider.Light1,
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre
|
||||
new ExtendedOsuSpriteText
|
||||
{
|
||||
Font = OsuFont.GetFont(weight: FontWeight.Bold),
|
||||
Text = $"{Score.SoloScore.PP:0}pp",
|
||||
Colour = colourProvider.Highlight1,
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
TooltipContent = $"{AttributeConversion.ToReadableString(Score.PerformanceAttributes)}"
|
||||
},
|
||||
new OsuSpriteText
|
||||
{
|
||||
Font = OsuFont.GetFont(size: small_text_font_size),
|
||||
Text = $"{Score.SoloScore.PP - Score.LivePP:+0.0;-0.0;-}",
|
||||
Colour = colourProvider.Light1,
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
return drawables;
|
||||
Score.PositionChange.BindValueChanged(v => { positionChangeText.Text = $"{v.NewValue:+0;-0;-}"; });
|
||||
}
|
||||
|
||||
private static string formatStatistics(Dictionary<HitResult, int> statistics)
|
||||
|
|
|
@ -102,10 +102,6 @@ namespace PerformanceCalculatorGUI
|
|||
{
|
||||
Action = () => setScreen(new ProfileScreen())
|
||||
},
|
||||
new ScreenSelectionButton("Combined Profile", FontAwesome.Solid.Users)
|
||||
{
|
||||
Action = () => setScreen(new CombinedProfileScreen())
|
||||
},
|
||||
new ScreenSelectionButton("Player Leaderboard", FontAwesome.Solid.List)
|
||||
{
|
||||
Action = () => setScreen(new LeaderboardScreen())
|
||||
|
|
|
@ -1,236 +0,0 @@
|
|||
// 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.Linq;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Logging;
|
||||
using osu.Game.Graphics;
|
||||
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.Graphics;
|
||||
using PerformanceCalculatorGUI.Components;
|
||||
using PerformanceCalculatorGUI.Components.TextBoxes;
|
||||
using PerformanceCalculatorGUI.Configuration;
|
||||
|
||||
namespace PerformanceCalculatorGUI.Screens
|
||||
{
|
||||
public partial class CombinedProfileScreen : ProfileScreen
|
||||
{
|
||||
[Cached]
|
||||
private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Plum);
|
||||
|
||||
[Resolved]
|
||||
private NotificationDisplay notificationDisplay { get; set; }
|
||||
|
||||
[Resolved]
|
||||
private APIManager apiManager { get; set; }
|
||||
|
||||
[Resolved]
|
||||
private Bindable<RulesetInfo> ruleset { get; set; }
|
||||
|
||||
[Resolved]
|
||||
private SettingsManager configManager { get; set; }
|
||||
|
||||
[Resolved]
|
||||
private RulesetStore rulesets { get; set; }
|
||||
|
||||
private SwitchButton onlyShowBest;
|
||||
|
||||
public CombinedProfileScreen()
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
usernameTextBox.Label = "Usernames";
|
||||
usernameTextBox.PlaceholderText = "user1, user2, user3";
|
||||
|
||||
checkboxContainer.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"
|
||||
},
|
||||
onlyShowBest = 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 = "Only display best score on each beatmap"
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
protected readonly struct ScoreWithUser
|
||||
{
|
||||
public readonly ExtendedScore Score;
|
||||
public readonly APIUser User;
|
||||
|
||||
public ScoreWithUser(ExtendedScore score, APIUser user)
|
||||
{
|
||||
Score = score;
|
||||
User = user;
|
||||
}
|
||||
}
|
||||
|
||||
protected async Task<List<ScoreWithUser>> GetPlaysWithUser(APIUser player, CancellationToken token)
|
||||
{
|
||||
var plays = await base.GetPlays(player, token);
|
||||
var playsWithUser = new List<ScoreWithUser>();
|
||||
|
||||
foreach (ExtendedScore play in plays)
|
||||
{
|
||||
playsWithUser.Add(new ScoreWithUser(play, player));
|
||||
}
|
||||
|
||||
return playsWithUser;
|
||||
}
|
||||
|
||||
protected override void calculateProfile(string usernames)
|
||||
{
|
||||
currentUser = "";
|
||||
|
||||
string[] Usernames = usernames.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
|
||||
|
||||
if (Usernames.Count() < 1)
|
||||
{
|
||||
usernameTextBox.FlashColour(Color4.Red, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
calculationCancellatonToken?.Cancel();
|
||||
calculationCancellatonToken?.Dispose();
|
||||
|
||||
loadingLayer.Show();
|
||||
calculationButton.State.Value = ButtonState.Loading;
|
||||
|
||||
scores.Clear();
|
||||
|
||||
calculationCancellatonToken = new CancellationTokenSource();
|
||||
var token = calculationCancellatonToken.Token;
|
||||
|
||||
Task.Run(async () =>
|
||||
{
|
||||
Schedule(() =>
|
||||
{
|
||||
sortingTabControl.Alpha = 1.0f;
|
||||
sortingTabControl.Current.Value = ProfileSortCriteria.Local;
|
||||
|
||||
layout.RowDimensions = new[]
|
||||
{
|
||||
new Dimension(GridSizeMode.Absolute, username_container_height),
|
||||
new Dimension(GridSizeMode.AutoSize),
|
||||
new Dimension(GridSizeMode.AutoSize),
|
||||
new Dimension()
|
||||
};
|
||||
});
|
||||
|
||||
if (token.IsCancellationRequested)
|
||||
return;
|
||||
|
||||
var allPlays = new List<ScoreWithUser>();
|
||||
|
||||
Schedule(() => loadingLayer.Text.Value = "Getting user data...");
|
||||
|
||||
foreach (string username in Usernames)
|
||||
{
|
||||
var player = await apiManager.GetJsonFromApi<APIUser>($"users/{username}/{ruleset.Value.ShortName}");
|
||||
|
||||
// Append player username to current user string
|
||||
currentUser += (currentUser == "") ? player.Username : (", " + player.Username);
|
||||
System.Console.WriteLine(currentUser);
|
||||
|
||||
var plays = await GetPlaysWithUser(player, token);
|
||||
allPlays = allPlays.Concat(plays).ToList();
|
||||
}
|
||||
|
||||
if (token.IsCancellationRequested)
|
||||
return;
|
||||
|
||||
if (onlyShowBest.Current.Value)
|
||||
{
|
||||
Schedule(() => loadingLayer.Text.Value = "Filtering scores");
|
||||
|
||||
var filteredPlays = new List<ScoreWithUser>();
|
||||
|
||||
// List of every beatmap ID in combined plays without duplicates
|
||||
List<int> beatmapIDs = allPlays.Select(x => x.Score.SoloScore.BeatmapID).Distinct().ToList();
|
||||
|
||||
foreach (int ID in beatmapIDs)
|
||||
{
|
||||
List<ScoreWithUser> playsOnBeatmap = allPlays.Where(x => x.Score.SoloScore.BeatmapID == ID).OrderByDescending(x => x.Score.SoloScore.PP).ToList();
|
||||
ScoreWithUser bestPlayOnBeatmap = playsOnBeatmap.First();
|
||||
|
||||
filteredPlays.Add(bestPlayOnBeatmap);
|
||||
}
|
||||
|
||||
allPlays = filteredPlays;
|
||||
}
|
||||
|
||||
if (token.IsCancellationRequested)
|
||||
return;
|
||||
|
||||
var localOrdered = allPlays.OrderByDescending(x => x.Score.SoloScore.PP).ToList();
|
||||
var liveOrdered = allPlays.OrderByDescending(x => x.Score.LivePP ?? 0).ToList();
|
||||
|
||||
Schedule(() =>
|
||||
{
|
||||
foreach (var play in allPlays)
|
||||
{
|
||||
scores.Add(new ExtendedCombinedProfileScore(play.Score, play.User));
|
||||
|
||||
var score = play.Score;
|
||||
|
||||
if (score.LivePP != null)
|
||||
{
|
||||
score.Position.Value = localOrdered.IndexOf(play) + 1;
|
||||
score.PositionChange.Value = liveOrdered.IndexOf(play) - localOrdered.IndexOf(play);
|
||||
}
|
||||
}
|
||||
});
|
||||
}, token).ContinueWith(t =>
|
||||
{
|
||||
Logger.Log(t.Exception?.ToString(), level: LogLevel.Error);
|
||||
notificationDisplay.Display(new Notification(t.Exception?.Flatten().Message));
|
||||
}, TaskContinuationOptions.OnlyOnFaulted).ContinueWith(t =>
|
||||
{
|
||||
Schedule(() =>
|
||||
{
|
||||
loadingLayer.Hide();
|
||||
calculationButton.State.Value = ButtonState.Done;
|
||||
updateSorting(ProfileSortCriteria.Local);
|
||||
});
|
||||
}, TaskContinuationOptions.None);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -36,25 +36,24 @@ namespace PerformanceCalculatorGUI.Screens
|
|||
[Cached]
|
||||
private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Plum);
|
||||
|
||||
protected StatefulButton calculationButton;
|
||||
protected VerboseLoadingLayer loadingLayer;
|
||||
private StatefulButton calculationButton;
|
||||
private SwitchButton includePinnedCheckbox;
|
||||
private SwitchButton onlyDisplayBestCheckbox;
|
||||
private VerboseLoadingLayer loadingLayer;
|
||||
|
||||
protected FillFlowContainer checkboxContainer;
|
||||
protected SwitchButton includePinnedCheckbox;
|
||||
private GridContainer layout;
|
||||
|
||||
protected GridContainer layout;
|
||||
private FillFlowContainer<ExtendedProfileScore> scores;
|
||||
|
||||
protected FillFlowContainer<ExtendedProfileScore> scores;
|
||||
|
||||
protected LabelledTextBox usernameTextBox;
|
||||
private LabelledTextBox usernameTextBox;
|
||||
private Container userPanelContainer;
|
||||
private UserCard userPanel;
|
||||
|
||||
protected string currentUser;
|
||||
private string currentUsers;
|
||||
|
||||
protected CancellationTokenSource calculationCancellatonToken;
|
||||
private CancellationTokenSource calculationCancellatonToken;
|
||||
|
||||
protected OverlaySortTabControl<ProfileSortCriteria> sortingTabControl;
|
||||
private OverlaySortTabControl<ProfileSortCriteria> sortingTabControl;
|
||||
private readonly Bindable<ProfileSortCriteria> sorting = new Bindable<ProfileSortCriteria>(ProfileSortCriteria.Local);
|
||||
|
||||
[Resolved]
|
||||
|
@ -74,7 +73,7 @@ namespace PerformanceCalculatorGUI.Screens
|
|||
|
||||
public override bool ShouldShowConfirmationDialogOnSwitch => false;
|
||||
|
||||
protected const float username_container_height = 40;
|
||||
private const float username_container_height = 40;
|
||||
|
||||
public ProfileScreen()
|
||||
{
|
||||
|
@ -123,8 +122,8 @@ namespace PerformanceCalculatorGUI.Screens
|
|||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Anchor = Anchor.TopLeft,
|
||||
Label = "Username",
|
||||
PlaceholderText = "peppy",
|
||||
Label = "Username(s)",
|
||||
PlaceholderText = "peppy, rloseise, peppy2",
|
||||
CommitOnFocusLoss = false
|
||||
},
|
||||
calculationButton = new StatefulButton("Start calculation")
|
||||
|
@ -153,7 +152,7 @@ namespace PerformanceCalculatorGUI.Screens
|
|||
AutoSizeAxes = Axes.Y,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
checkboxContainer = new FillFlowContainer
|
||||
new FillFlowContainer
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Horizontal,
|
||||
|
@ -174,6 +173,20 @@ namespace PerformanceCalculatorGUI.Screens
|
|||
Font = OsuFont.Torus.With(weight: FontWeight.SemiBold, size: 14),
|
||||
UseFullGlyphHeight = false,
|
||||
Text = "Include pinned scores"
|
||||
},
|
||||
onlyDisplayBestCheckbox = 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 = "Only display best score on each beatmap"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -211,64 +224,25 @@ namespace PerformanceCalculatorGUI.Screens
|
|||
|
||||
usernameTextBox.OnCommit += (_, _) => { calculateProfile(usernameTextBox.Current.Value); };
|
||||
sorting.ValueChanged += e => { updateSorting(e.NewValue); };
|
||||
includePinnedCheckbox.Current.ValueChanged += e => { calculateProfile(currentUser); };
|
||||
includePinnedCheckbox.Current.ValueChanged += e => { calculateProfile(currentUsers); };
|
||||
onlyDisplayBestCheckbox.Current.ValueChanged += e => { calculateProfile(currentUsers); };
|
||||
|
||||
if (RuntimeInfo.IsDesktop)
|
||||
HotReloadCallbackReceiver.CompilationFinished += _ => Schedule(() => { calculateProfile(currentUser); });
|
||||
HotReloadCallbackReceiver.CompilationFinished += _ => Schedule(() => { calculateProfile(currentUsers); });
|
||||
}
|
||||
|
||||
protected async Task<List<ExtendedScore>> GetPlays(APIUser player, CancellationToken token)
|
||||
private void calculateProfile(string usernames)
|
||||
{
|
||||
var plays = new List<ExtendedScore>();
|
||||
var rulesetInstance = ruleset.Value.CreateInstance();
|
||||
|
||||
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");
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
foreach (var score in apiScores)
|
||||
{
|
||||
if (token.IsCancellationRequested)
|
||||
return new List<ExtendedScore>();
|
||||
|
||||
var working = ProcessorWorkingBeatmap.FromFileOrId(score.BeatmapID.ToString(), cachePath: configManager.GetBindable<string>(Settings.CachePath).Value);
|
||||
|
||||
Schedule(() => loadingLayer.Text.Value = $"Calculating {working.Metadata}");
|
||||
|
||||
Mod[] mods = score.Mods.Select(x => x.ToMod(rulesetInstance)).ToArray();
|
||||
|
||||
var scoreInfo = score.ToScoreInfo(rulesets, working.BeatmapInfo);
|
||||
|
||||
var parsedScore = new ProcessorScoreDecoder(working).Parse(scoreInfo);
|
||||
|
||||
var difficultyCalculator = rulesetInstance.CreateDifficultyCalculator(working);
|
||||
var difficultyAttributes = difficultyCalculator.Calculate(mods);
|
||||
var performanceCalculator = rulesetInstance.CreatePerformanceCalculator();
|
||||
|
||||
double? livePp = score.PP;
|
||||
var perfAttributes = await performanceCalculator?.CalculateAsync(parsedScore.ScoreInfo, difficultyAttributes, token)!;
|
||||
score.PP = perfAttributes?.Total ?? 0.0;
|
||||
|
||||
var extendedScore = new ExtendedScore(score, livePp, perfAttributes);
|
||||
plays.Add(extendedScore);
|
||||
}
|
||||
|
||||
return plays;
|
||||
}
|
||||
|
||||
protected virtual void calculateProfile(string username)
|
||||
{
|
||||
if (string.IsNullOrEmpty(username))
|
||||
if (string.IsNullOrEmpty(usernames))
|
||||
{
|
||||
usernameTextBox.FlashColour(Color4.Red, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
currentUsers = "";
|
||||
|
||||
string[] Usernames = usernames.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
|
||||
bool calculatingSingleProfile = Usernames.Count() <= 1;
|
||||
|
||||
calculationCancellatonToken?.Cancel();
|
||||
calculationCancellatonToken?.Dispose();
|
||||
|
@ -283,22 +257,11 @@ namespace PerformanceCalculatorGUI.Screens
|
|||
|
||||
Task.Run(async () =>
|
||||
{
|
||||
Schedule(() => loadingLayer.Text.Value = "Getting user data...");
|
||||
|
||||
var player = await apiManager.GetJsonFromApi<APIUser>($"users/{username}/{ruleset.Value.ShortName}");
|
||||
|
||||
currentUser = player.Username;
|
||||
|
||||
Schedule(() =>
|
||||
Schedule(() =>
|
||||
{
|
||||
if (userPanel != null)
|
||||
userPanelContainer.Remove(userPanel, true);
|
||||
|
||||
userPanelContainer.Add(userPanel = new UserCard(player)
|
||||
{
|
||||
RelativeSizeAxes = Axes.X
|
||||
});
|
||||
|
||||
if (userPanel != null)
|
||||
userPanelContainer.Remove(userPanel, true);
|
||||
|
||||
sortingTabControl.Alpha = 1.0f;
|
||||
sortingTabControl.Current.Value = ProfileSortCriteria.Local;
|
||||
|
||||
|
@ -310,14 +273,95 @@ namespace PerformanceCalculatorGUI.Screens
|
|||
new Dimension()
|
||||
};
|
||||
});
|
||||
|
||||
if (token.IsCancellationRequested)
|
||||
return;
|
||||
|
||||
var plays = new List<ExtendedScore>();
|
||||
var players = new List<APIUser>();
|
||||
var rulesetInstance = ruleset.Value.CreateInstance();
|
||||
|
||||
foreach (string username in Usernames)
|
||||
{
|
||||
Schedule(() => loadingLayer.Text.Value = "Getting user data...");
|
||||
|
||||
var player = await apiManager.GetJsonFromApi<APIUser>($"users/{username}/{ruleset.Value.ShortName}");
|
||||
players.Add(player);
|
||||
|
||||
// Append player username to current user(s) string
|
||||
currentUsers += (currentUsers == "") ? player.Username : (", " + player.Username);
|
||||
|
||||
// Add user card if only calculating single profile
|
||||
if (calculatingSingleProfile)
|
||||
{
|
||||
Schedule(() =>
|
||||
{
|
||||
userPanelContainer.Add(userPanel = new UserCard(player)
|
||||
{
|
||||
RelativeSizeAxes = Axes.X
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
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");
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
foreach (var score in apiScores)
|
||||
{
|
||||
if (token.IsCancellationRequested)
|
||||
return;
|
||||
|
||||
var working = ProcessorWorkingBeatmap.FromFileOrId(score.BeatmapID.ToString(), cachePath: configManager.GetBindable<string>(Settings.CachePath).Value);
|
||||
|
||||
Schedule(() => loadingLayer.Text.Value = $"Calculating {working.Metadata}");
|
||||
|
||||
Mod[] mods = score.Mods.Select(x => x.ToMod(rulesetInstance)).ToArray();
|
||||
|
||||
var scoreInfo = score.ToScoreInfo(rulesets, working.BeatmapInfo);
|
||||
|
||||
var parsedScore = new ProcessorScoreDecoder(working).Parse(scoreInfo);
|
||||
|
||||
var difficultyCalculator = rulesetInstance.CreateDifficultyCalculator(working);
|
||||
var difficultyAttributes = difficultyCalculator.Calculate(mods);
|
||||
var performanceCalculator = rulesetInstance.CreatePerformanceCalculator();
|
||||
|
||||
double? livePp = score.PP;
|
||||
var perfAttributes = await performanceCalculator?.CalculateAsync(parsedScore.ScoreInfo, difficultyAttributes, token)!;
|
||||
score.PP = perfAttributes?.Total ?? 0.0;
|
||||
|
||||
var extendedScore = new ExtendedScore(score, livePp, perfAttributes);
|
||||
plays.Add(extendedScore);
|
||||
}
|
||||
}
|
||||
|
||||
if (token.IsCancellationRequested)
|
||||
return;
|
||||
|
||||
// Filter plays if only displaying best score on each beatmap
|
||||
if (onlyDisplayBestCheckbox.Current.Value)
|
||||
{
|
||||
Schedule(() => loadingLayer.Text.Value = $"Filtering plays");
|
||||
|
||||
var filteredPlays = new List<ExtendedScore>();
|
||||
|
||||
// List of all beatmap IDs in plays without duplicates
|
||||
var beatmapIDs = plays.Select(x => x.SoloScore.BeatmapID).Distinct().ToList();
|
||||
|
||||
var plays = await GetPlays(player, token);
|
||||
|
||||
if (token.IsCancellationRequested)
|
||||
return;
|
||||
foreach (int ID in beatmapIDs)
|
||||
{
|
||||
var bestPlayOnBeatmap = plays.Where(x => x.SoloScore.BeatmapID == ID).OrderByDescending(x => x.SoloScore.PP).First();
|
||||
filteredPlays.Add(bestPlayOnBeatmap);
|
||||
}
|
||||
|
||||
plays = filteredPlays;
|
||||
}
|
||||
|
||||
var localOrdered = plays.OrderByDescending(x => x.SoloScore.PP).ToList();
|
||||
var liveOrdered = plays.OrderByDescending(x => x.LivePP ?? 0).ToList();
|
||||
|
@ -326,8 +370,8 @@ namespace PerformanceCalculatorGUI.Screens
|
|||
{
|
||||
foreach (var play in plays)
|
||||
{
|
||||
scores.Add(new ExtendedProfileScore(play));
|
||||
|
||||
scores.Add(new ExtendedProfileScore(play, !calculatingSingleProfile));
|
||||
|
||||
if (play.LivePP != null)
|
||||
{
|
||||
play.Position.Value = localOrdered.IndexOf(play) + 1;
|
||||
|
@ -336,29 +380,34 @@ namespace PerformanceCalculatorGUI.Screens
|
|||
}
|
||||
});
|
||||
|
||||
decimal totalLocalPP = 0;
|
||||
for (var i = 0; i < localOrdered.Count; i++)
|
||||
totalLocalPP += (decimal)(Math.Pow(0.95, i) * (localOrdered[i].SoloScore.PP ?? 0));
|
||||
if (calculatingSingleProfile)
|
||||
{
|
||||
var player = players.First();
|
||||
|
||||
decimal totalLocalPP = 0;
|
||||
for (var i = 0; i < localOrdered.Count; i++)
|
||||
totalLocalPP += (decimal)(Math.Pow(0.95, i) * (localOrdered[i].SoloScore.PP ?? 0));
|
||||
|
||||
decimal totalLivePP = player.Statistics.PP ?? (decimal)0.0;
|
||||
decimal totalLivePP = player.Statistics.PP ?? (decimal)0.0;
|
||||
|
||||
decimal nonBonusLivePP = 0;
|
||||
for (var i = 0; i < liveOrdered.Count; i++)
|
||||
nonBonusLivePP += (decimal)(Math.Pow(0.95, i) * liveOrdered[i].LivePP ?? 0);
|
||||
decimal nonBonusLivePP = 0;
|
||||
for (var i = 0; i < liveOrdered.Count; i++)
|
||||
nonBonusLivePP += (decimal)(Math.Pow(0.95, i) * liveOrdered[i].LivePP ?? 0);
|
||||
|
||||
//todo: implement properly. this is pretty damn wrong.
|
||||
var playcountBonusPP = (totalLivePP - nonBonusLivePP);
|
||||
totalLocalPP += playcountBonusPP;
|
||||
//todo: implement properly. this is pretty damn wrong.
|
||||
var playcountBonusPP = (totalLivePP - nonBonusLivePP);
|
||||
totalLocalPP += playcountBonusPP;
|
||||
|
||||
Schedule(() =>
|
||||
{
|
||||
userPanel.Data.Value = new UserCardData
|
||||
{
|
||||
LivePP = totalLivePP,
|
||||
LocalPP = totalLocalPP,
|
||||
PlaycountPP = playcountBonusPP
|
||||
};
|
||||
});
|
||||
Schedule(() =>
|
||||
{
|
||||
userPanel.Data.Value = new UserCardData
|
||||
{
|
||||
LivePP = totalLivePP,
|
||||
LocalPP = totalLocalPP,
|
||||
PlaycountPP = playcountBonusPP
|
||||
};
|
||||
});
|
||||
}
|
||||
}, token).ContinueWith(t =>
|
||||
{
|
||||
Logger.Log(t.Exception?.ToString(), level: LogLevel.Error);
|
||||
|
@ -393,7 +442,7 @@ namespace PerformanceCalculatorGUI.Screens
|
|||
return base.OnKeyDown(e);
|
||||
}
|
||||
|
||||
protected void updateSorting(ProfileSortCriteria sortCriteria)
|
||||
private void updateSorting(ProfileSortCriteria sortCriteria)
|
||||
{
|
||||
if (!scores.Children.Any())
|
||||
return;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue