mirror of
https://github.com/osukey/osukey.git
synced 2025-08-05 07:33:55 +09:00
Merge remote-tracking branch 'refs/remotes/origin/master' into multiplier-text
This commit is contained in:
@ -587,13 +587,16 @@ namespace osu.Game.Screens.Select
|
||||
switch (d)
|
||||
{
|
||||
case DrawableCarouselBeatmapSet set:
|
||||
{
|
||||
lastSet = set;
|
||||
|
||||
set.MoveToX(set.Item.State.Value == CarouselItemState.Selected ? -100 : 0, 500, Easing.OutExpo);
|
||||
set.MoveToY(currentY, 750, Easing.OutExpo);
|
||||
break;
|
||||
}
|
||||
|
||||
case DrawableCarouselBeatmap beatmap:
|
||||
{
|
||||
if (beatmap.Item.State.Value == CarouselItemState.Selected)
|
||||
scrollTarget = currentY + beatmap.DrawHeight / 2 - DrawHeight / 2;
|
||||
|
||||
@ -619,6 +622,7 @@ namespace osu.Game.Screens.Select
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Screens.Select.Filter;
|
||||
@ -29,28 +30,29 @@ namespace osu.Game.Screens.Select.Carousel
|
||||
Beatmap.RulesetID == criteria.Ruleset.ID ||
|
||||
(Beatmap.RulesetID == 0 && criteria.Ruleset.ID > 0 && criteria.AllowConvertedBeatmaps);
|
||||
|
||||
match &= criteria.StarDifficulty.IsInRange(Beatmap.StarDifficulty);
|
||||
match &= criteria.ApproachRate.IsInRange(Beatmap.BaseDifficulty.ApproachRate);
|
||||
match &= criteria.DrainRate.IsInRange(Beatmap.BaseDifficulty.DrainRate);
|
||||
match &= criteria.CircleSize.IsInRange(Beatmap.BaseDifficulty.CircleSize);
|
||||
match &= criteria.Length.IsInRange(Beatmap.Length);
|
||||
match &= criteria.BPM.IsInRange(Beatmap.BPM);
|
||||
match &= !criteria.StarDifficulty.HasFilter || criteria.StarDifficulty.IsInRange(Beatmap.StarDifficulty);
|
||||
match &= !criteria.ApproachRate.HasFilter || criteria.ApproachRate.IsInRange(Beatmap.BaseDifficulty.ApproachRate);
|
||||
match &= !criteria.DrainRate.HasFilter || criteria.DrainRate.IsInRange(Beatmap.BaseDifficulty.DrainRate);
|
||||
match &= !criteria.CircleSize.HasFilter || criteria.CircleSize.IsInRange(Beatmap.BaseDifficulty.CircleSize);
|
||||
match &= !criteria.Length.HasFilter || criteria.Length.IsInRange(Beatmap.Length);
|
||||
match &= !criteria.BPM.HasFilter || criteria.BPM.IsInRange(Beatmap.BPM);
|
||||
|
||||
match &= criteria.BeatDivisor.IsInRange(Beatmap.BeatDivisor);
|
||||
match &= criteria.OnlineStatus.IsInRange(Beatmap.Status);
|
||||
match &= !criteria.BeatDivisor.HasFilter || criteria.BeatDivisor.IsInRange(Beatmap.BeatDivisor);
|
||||
match &= !criteria.OnlineStatus.HasFilter || criteria.OnlineStatus.IsInRange(Beatmap.Status);
|
||||
|
||||
match &= criteria.Creator.Matches(Beatmap.Metadata.AuthorString);
|
||||
match &= criteria.Artist.Matches(Beatmap.Metadata.Artist) ||
|
||||
match &= !criteria.Creator.HasFilter || criteria.Creator.Matches(Beatmap.Metadata.AuthorString);
|
||||
match &= !criteria.Artist.HasFilter || criteria.Artist.Matches(Beatmap.Metadata.Artist) ||
|
||||
criteria.Artist.Matches(Beatmap.Metadata.ArtistUnicode);
|
||||
|
||||
if (match)
|
||||
{
|
||||
var terms = new List<string>();
|
||||
|
||||
terms.AddRange(Beatmap.Metadata.SearchableTerms);
|
||||
terms.Add(Beatmap.Version);
|
||||
|
||||
foreach (var criteriaTerm in criteria.SearchTerms)
|
||||
{
|
||||
match &=
|
||||
Beatmap.Metadata.SearchableTerms.Any(term => term.IndexOf(criteriaTerm, StringComparison.InvariantCultureIgnoreCase) >= 0) ||
|
||||
Beatmap.Version.IndexOf(criteriaTerm, StringComparison.InvariantCultureIgnoreCase) >= 0;
|
||||
}
|
||||
match &= terms.Any(term => term.IndexOf(criteriaTerm, StringComparison.InvariantCultureIgnoreCase) >= 0);
|
||||
}
|
||||
|
||||
Filtered.Value = !match;
|
||||
|
@ -37,13 +37,13 @@ namespace osu.Game.Screens.Select.Carousel
|
||||
{
|
||||
default:
|
||||
case SortMode.Artist:
|
||||
return string.Compare(BeatmapSet.Metadata.Artist, otherSet.BeatmapSet.Metadata.Artist, StringComparison.InvariantCultureIgnoreCase);
|
||||
return string.Compare(BeatmapSet.Metadata.Artist, otherSet.BeatmapSet.Metadata.Artist, StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
case SortMode.Title:
|
||||
return string.Compare(BeatmapSet.Metadata.Title, otherSet.BeatmapSet.Metadata.Title, StringComparison.InvariantCultureIgnoreCase);
|
||||
return string.Compare(BeatmapSet.Metadata.Title, otherSet.BeatmapSet.Metadata.Title, StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
case SortMode.Author:
|
||||
return string.Compare(BeatmapSet.Metadata.Author.Username, otherSet.BeatmapSet.Metadata.Author.Username, StringComparison.InvariantCultureIgnoreCase);
|
||||
return string.Compare(BeatmapSet.Metadata.Author.Username, otherSet.BeatmapSet.Metadata.Author.Username, StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
case SortMode.DateAdded:
|
||||
return otherSet.BeatmapSet.DateAdded.CompareTo(BeatmapSet.DateAdded);
|
||||
|
@ -12,11 +12,18 @@ using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using System;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Framework.Bindables;
|
||||
using System.Collections.Generic;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using System.Linq;
|
||||
|
||||
namespace osu.Game.Screens.Select.Details
|
||||
{
|
||||
public class AdvancedStats : Container
|
||||
{
|
||||
[Resolved]
|
||||
private IBindable<IReadOnlyList<Mod>> mods { get; set; }
|
||||
|
||||
private readonly StatisticRow firstValue, hpDrain, accuracy, approachRate, starDifficulty;
|
||||
|
||||
private BeatmapInfo beatmap;
|
||||
@ -30,22 +37,7 @@ namespace osu.Game.Screens.Select.Details
|
||||
|
||||
beatmap = value;
|
||||
|
||||
//mania specific
|
||||
if ((Beatmap?.Ruleset?.ID ?? 0) == 3)
|
||||
{
|
||||
firstValue.Title = "Key Amount";
|
||||
firstValue.Value = (int)MathF.Round(Beatmap?.BaseDifficulty?.CircleSize ?? 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
firstValue.Title = "Circle Size";
|
||||
firstValue.Value = Beatmap?.BaseDifficulty?.CircleSize ?? 0;
|
||||
}
|
||||
|
||||
hpDrain.Value = Beatmap?.BaseDifficulty?.DrainRate ?? 0;
|
||||
accuracy.Value = Beatmap?.BaseDifficulty?.OverallDifficulty ?? 0;
|
||||
approachRate.Value = Beatmap?.BaseDifficulty?.ApproachRate ?? 0;
|
||||
starDifficulty.Value = (float)(Beatmap?.StarDifficulty ?? 0);
|
||||
updateStatistics();
|
||||
}
|
||||
}
|
||||
|
||||
@ -73,6 +65,45 @@ namespace osu.Game.Screens.Select.Details
|
||||
starDifficulty.AccentColour = colours.Yellow;
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
mods.BindValueChanged(_ => updateStatistics(), true);
|
||||
}
|
||||
|
||||
private void updateStatistics()
|
||||
{
|
||||
BeatmapDifficulty baseDifficulty = Beatmap?.BaseDifficulty;
|
||||
BeatmapDifficulty adjustedDifficulty = null;
|
||||
|
||||
if (baseDifficulty != null && mods.Value.Any(m => m is IApplicableToDifficulty))
|
||||
{
|
||||
adjustedDifficulty = baseDifficulty.Clone();
|
||||
|
||||
foreach (var mod in mods.Value.OfType<IApplicableToDifficulty>())
|
||||
mod.ApplyToDifficulty(adjustedDifficulty);
|
||||
}
|
||||
|
||||
//mania specific
|
||||
if ((Beatmap?.Ruleset?.ID ?? 0) == 3)
|
||||
{
|
||||
firstValue.Title = "Key Amount";
|
||||
firstValue.Value = ((int)MathF.Round(baseDifficulty?.CircleSize ?? 0), (int)MathF.Round(adjustedDifficulty?.CircleSize ?? 0));
|
||||
}
|
||||
else
|
||||
{
|
||||
firstValue.Title = "Circle Size";
|
||||
firstValue.Value = (baseDifficulty?.CircleSize ?? 0, adjustedDifficulty?.CircleSize);
|
||||
}
|
||||
|
||||
starDifficulty.Value = ((float)(Beatmap?.StarDifficulty ?? 0), null);
|
||||
|
||||
hpDrain.Value = (baseDifficulty?.DrainRate ?? 0, adjustedDifficulty?.DrainRate);
|
||||
accuracy.Value = (baseDifficulty?.OverallDifficulty ?? 0, adjustedDifficulty?.OverallDifficulty);
|
||||
approachRate.Value = (baseDifficulty?.ApproachRate ?? 0, adjustedDifficulty?.ApproachRate);
|
||||
}
|
||||
|
||||
private class StatisticRow : Container, IHasAccentColour
|
||||
{
|
||||
private const float value_width = 25;
|
||||
@ -80,8 +111,11 @@ namespace osu.Game.Screens.Select.Details
|
||||
|
||||
private readonly float maxValue;
|
||||
private readonly bool forceDecimalPlaces;
|
||||
private readonly OsuSpriteText name, value;
|
||||
private readonly Bar bar;
|
||||
private readonly OsuSpriteText name, valueText;
|
||||
private readonly Bar bar, modBar;
|
||||
|
||||
[Resolved]
|
||||
private OsuColour colours { get; set; }
|
||||
|
||||
public string Title
|
||||
{
|
||||
@ -89,16 +123,29 @@ namespace osu.Game.Screens.Select.Details
|
||||
set => name.Text = value;
|
||||
}
|
||||
|
||||
private float difficultyValue;
|
||||
private (float baseValue, float? adjustedValue) value;
|
||||
|
||||
public float Value
|
||||
public (float baseValue, float? adjustedValue) Value
|
||||
{
|
||||
get => difficultyValue;
|
||||
get => value;
|
||||
set
|
||||
{
|
||||
difficultyValue = value;
|
||||
bar.Length = value / maxValue;
|
||||
this.value.Text = value.ToString(forceDecimalPlaces ? "0.00" : "0.##");
|
||||
if (value == this.value)
|
||||
return;
|
||||
|
||||
this.value = value;
|
||||
|
||||
bar.Length = value.baseValue / maxValue;
|
||||
|
||||
valueText.Text = (value.adjustedValue ?? value.baseValue).ToString(forceDecimalPlaces ? "0.00" : "0.##");
|
||||
modBar.Length = (value.adjustedValue ?? 0) / maxValue;
|
||||
|
||||
if (value.adjustedValue > value.baseValue)
|
||||
modBar.AccentColour = valueText.Colour = colours.Red;
|
||||
else if (value.adjustedValue < value.baseValue)
|
||||
modBar.AccentColour = valueText.Colour = colours.BlueDark;
|
||||
else
|
||||
modBar.AccentColour = valueText.Colour = Color4.White;
|
||||
}
|
||||
}
|
||||
|
||||
@ -135,13 +182,22 @@ namespace osu.Game.Screens.Select.Details
|
||||
BackgroundColour = Color4.White.Opacity(0.5f),
|
||||
Padding = new MarginPadding { Left = name_width + 10, Right = value_width + 10 },
|
||||
},
|
||||
modBar = new Bar
|
||||
{
|
||||
Origin = Anchor.CentreLeft,
|
||||
Anchor = Anchor.CentreLeft,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Alpha = 0.5f,
|
||||
Height = 5,
|
||||
Padding = new MarginPadding { Left = name_width + 10, Right = value_width + 10 },
|
||||
},
|
||||
new Container
|
||||
{
|
||||
Anchor = Anchor.TopRight,
|
||||
Origin = Anchor.TopRight,
|
||||
Width = value_width,
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
Child = value = new OsuSpriteText
|
||||
Child = valueText = new OsuSpriteText
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
|
@ -27,8 +27,8 @@ namespace osu.Game.Screens.Select.Details
|
||||
|
||||
metrics = value;
|
||||
|
||||
var retries = Metrics?.Retries ?? new int[0];
|
||||
var fails = Metrics?.Fails ?? new int[0];
|
||||
var retries = Metrics?.Retries ?? Array.Empty<int>();
|
||||
var fails = Metrics?.Fails ?? Array.Empty<int>();
|
||||
|
||||
float maxValue = fails.Any() ? fails.Zip(retries, (fail, retry) => fail + retry).Max() : 0;
|
||||
failGraph.MaxValue = maxValue;
|
||||
|
@ -44,8 +44,10 @@ namespace osu.Game.Screens.Select
|
||||
}
|
||||
|
||||
public struct OptionalRange<T> : IEquatable<OptionalRange<T>>
|
||||
where T : struct, IComparable
|
||||
where T : struct
|
||||
{
|
||||
public bool HasFilter => Max != null || Min != null;
|
||||
|
||||
public bool IsInRange(T value)
|
||||
{
|
||||
if (Min != null)
|
||||
@ -79,17 +81,19 @@ namespace osu.Game.Screens.Select
|
||||
public bool IsUpperInclusive;
|
||||
|
||||
public bool Equals(OptionalRange<T> other)
|
||||
=> Min.Equals(other.Min)
|
||||
&& Max.Equals(other.Max)
|
||||
=> EqualityComparer<T?>.Default.Equals(Min, other.Min)
|
||||
&& EqualityComparer<T?>.Default.Equals(Max, other.Max)
|
||||
&& IsLowerInclusive.Equals(other.IsLowerInclusive)
|
||||
&& IsUpperInclusive.Equals(other.IsUpperInclusive);
|
||||
}
|
||||
|
||||
public struct OptionalTextFilter : IEquatable<OptionalTextFilter>
|
||||
{
|
||||
public bool HasFilter => !string.IsNullOrEmpty(SearchTerm);
|
||||
|
||||
public bool Matches(string value)
|
||||
{
|
||||
if (string.IsNullOrEmpty(SearchTerm))
|
||||
if (!HasFilter)
|
||||
return true;
|
||||
|
||||
// search term is guaranteed to be non-empty, so if the string we're comparing is empty, it's not matching
|
||||
@ -101,7 +105,7 @@ namespace osu.Game.Screens.Select
|
||||
|
||||
public string SearchTerm;
|
||||
|
||||
public bool Equals(OptionalTextFilter other) => SearchTerm?.Equals(other.SearchTerm) ?? true;
|
||||
public bool Equals(OptionalTextFilter other) => SearchTerm == other.SearchTerm;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -170,7 +170,7 @@ namespace osu.Game.Screens.Select
|
||||
}
|
||||
|
||||
private static void updateCriteriaRange<T>(ref FilterCriteria.OptionalRange<T> range, string op, T value)
|
||||
where T : struct, IComparable
|
||||
where T : struct
|
||||
{
|
||||
switch (op)
|
||||
{
|
||||
|
@ -21,6 +21,9 @@ namespace osu.Game.Screens.Select.Leaderboards
|
||||
{
|
||||
public Action<ScoreInfo> ScoreSelected;
|
||||
|
||||
[Resolved]
|
||||
private RulesetStore rulesets { get; set; }
|
||||
|
||||
private BeatmapInfo beatmap;
|
||||
|
||||
public BeatmapInfo Beatmap
|
||||
@ -172,7 +175,7 @@ namespace osu.Game.Screens.Select.Leaderboards
|
||||
|
||||
req.Success += r =>
|
||||
{
|
||||
scoresCallback?.Invoke(r.Scores);
|
||||
scoresCallback?.Invoke(r.Scores.Select(s => s.CreateScoreInfo(rulesets)));
|
||||
TopScore = r.UserScore;
|
||||
};
|
||||
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
using System;
|
||||
using System.Threading;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
@ -10,6 +11,7 @@ using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osu.Game.Online.Leaderboards;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Scoring;
|
||||
using osuTK;
|
||||
|
||||
@ -27,6 +29,9 @@ namespace osu.Game.Screens.Select.Leaderboards
|
||||
|
||||
protected override bool StartHidden => true;
|
||||
|
||||
[Resolved]
|
||||
private RulesetStore rulesets { get; set; }
|
||||
|
||||
public UserTopScoreContainer()
|
||||
{
|
||||
RelativeSizeAxes = Axes.X;
|
||||
@ -77,9 +82,11 @@ namespace osu.Game.Screens.Select.Leaderboards
|
||||
if (newScore == null)
|
||||
return;
|
||||
|
||||
LoadComponentAsync(new LeaderboardScore(newScore.Score, newScore.Position, false)
|
||||
var scoreInfo = newScore.Score.CreateScoreInfo(rulesets);
|
||||
|
||||
LoadComponentAsync(new LeaderboardScore(scoreInfo, newScore.Position, false)
|
||||
{
|
||||
Action = () => ScoreSelected?.Invoke(newScore.Score)
|
||||
Action = () => ScoreSelected?.Invoke(scoreInfo)
|
||||
}, drawableScore =>
|
||||
{
|
||||
scoreContainer.Child = drawableScore;
|
||||
|
@ -262,8 +262,10 @@ namespace osu.Game.Screens.Select
|
||||
|
||||
protected virtual void ApplyFilterToCarousel(FilterCriteria criteria)
|
||||
{
|
||||
if (this.IsCurrentScreen())
|
||||
Carousel.Filter(criteria);
|
||||
// if not the current screen, we want to get carousel in a good presentation state before displaying (resume or enter).
|
||||
bool shouldDebounce = this.IsCurrentScreen();
|
||||
|
||||
Schedule(() => Carousel.Filter(criteria, shouldDebounce));
|
||||
}
|
||||
|
||||
private DependencyContainer dependencies;
|
||||
@ -437,8 +439,6 @@ namespace osu.Game.Screens.Select
|
||||
{
|
||||
base.OnEntering(last);
|
||||
|
||||
Carousel.Filter(FilterControl.CreateCriteria(), false);
|
||||
|
||||
this.FadeInFromZero(250);
|
||||
FilterControl.Activate();
|
||||
}
|
||||
|
Reference in New Issue
Block a user