1
0
mirror of https://github.com/ppy/osu.git synced 2024-11-11 16:27:26 +08:00

Merge branch 'master' into fix-follow-circle

This commit is contained in:
Dean Herbert 2020-02-03 09:58:12 +09:00 committed by GitHub
commit cf4788d7ef
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 215 additions and 65 deletions

View File

@ -23,7 +23,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
/// <summary> /// <summary>
/// The start time of <see cref="Start"/>. /// The start time of <see cref="Start"/>.
/// </summary> /// </summary>
public readonly Bindable<double> StartTime = new Bindable<double>(); public readonly Bindable<double> StartTime = new BindableDouble();
/// <summary> /// <summary>
/// The <see cref="DrawableOsuHitObject"/> which <see cref="FollowPoint"/>s will exit from. /// The <see cref="DrawableOsuHitObject"/> which <see cref="FollowPoint"/>s will exit from.

View File

@ -22,7 +22,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
private readonly IBindable<Vector2> positionBindable = new Bindable<Vector2>(); private readonly IBindable<Vector2> positionBindable = new Bindable<Vector2>();
private readonly IBindable<int> stackHeightBindable = new Bindable<int>(); private readonly IBindable<int> stackHeightBindable = new Bindable<int>();
private readonly IBindable<float> scaleBindable = new Bindable<float>(); private readonly IBindable<float> scaleBindable = new BindableFloat();
public OsuAction? HitAction => HitArea.HitAction; public OsuAction? HitAction => HitArea.HitAction;

View File

@ -37,7 +37,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
InternalChild = scaleContainer = new ReverseArrowPiece(); InternalChild = scaleContainer = new ReverseArrowPiece();
} }
private readonly IBindable<float> scaleBindable = new Bindable<float>(); private readonly IBindable<float> scaleBindable = new BindableFloat();
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load() private void load()

View File

@ -37,7 +37,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
private readonly IBindable<Vector2> positionBindable = new Bindable<Vector2>(); private readonly IBindable<Vector2> positionBindable = new Bindable<Vector2>();
private readonly IBindable<int> stackHeightBindable = new Bindable<int>(); private readonly IBindable<int> stackHeightBindable = new Bindable<int>();
private readonly IBindable<float> scaleBindable = new Bindable<float>(); private readonly IBindable<float> scaleBindable = new BindableFloat();
public DrawableSlider(Slider s) public DrawableSlider(Slider s)
: base(s) : base(s)

View File

@ -52,7 +52,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
}; };
} }
private readonly IBindable<float> scaleBindable = new Bindable<float>(); private readonly IBindable<float> scaleBindable = new BindableFloat();
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load() private void load()

View File

@ -57,7 +57,7 @@ namespace osu.Game.Rulesets.Osu.Objects
public double Radius => OBJECT_RADIUS * Scale; public double Radius => OBJECT_RADIUS * Scale;
public readonly Bindable<float> ScaleBindable = new Bindable<float>(1); public readonly Bindable<float> ScaleBindable = new BindableFloat(1);
public float Scale public float Scale
{ {

View File

@ -57,7 +57,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
autoCursorScale = config.GetBindable<bool>(OsuSetting.AutoCursorSize); autoCursorScale = config.GetBindable<bool>(OsuSetting.AutoCursorSize);
autoCursorScale.ValueChanged += _ => calculateScale(); autoCursorScale.ValueChanged += _ => calculateScale();
CursorScale = new Bindable<float>(); CursorScale = new BindableFloat();
CursorScale.ValueChanged += e => ActiveCursor.Scale = cursorTrail.Scale = new Vector2(e.NewValue); CursorScale.ValueChanged += e => ActiveCursor.Scale = cursorTrail.Scale = new Vector2(e.NewValue);
calculateScale(); calculateScale();

View File

@ -50,7 +50,7 @@ namespace osu.Game.Rulesets.Osu.UI
{ {
Add(localCursorContainer = new OsuCursorContainer()); Add(localCursorContainer = new OsuCursorContainer());
localCursorScale = new Bindable<float>(); localCursorScale = new BindableFloat();
localCursorScale.BindTo(localCursorContainer.CursorScale); localCursorScale.BindTo(localCursorContainer.CursorScale);
localCursorScale.BindValueChanged(scale => cursorScaleContainer.Scale = new Vector2(scale.NewValue), true); localCursorScale.BindValueChanged(scale => cursorScaleContainer.Scale = new Vector2(scale.NewValue), true);
} }

View File

@ -302,8 +302,8 @@ namespace osu.Game.Tests.Visual.Background
} }
public readonly Bindable<bool> DimEnabled = new Bindable<bool>(); public readonly Bindable<bool> DimEnabled = new Bindable<bool>();
public readonly Bindable<double> DimLevel = new Bindable<double>(); public readonly Bindable<double> DimLevel = new BindableDouble();
public readonly Bindable<double> BlurLevel = new Bindable<double>(); public readonly Bindable<double> BlurLevel = new BindableDouble();
public new BeatmapCarousel Carousel => base.Carousel; public new BeatmapCarousel Carousel => base.Carousel;

View File

@ -0,0 +1,175 @@
// 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 NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Testing;
using osu.Game.Beatmaps;
using osu.Game.Graphics;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Mods;
using osu.Game.Screens.Select.Details;
using osuTK.Graphics;
namespace osu.Game.Tests.Visual.SongSelect
{
[System.ComponentModel.Description("Advanced beatmap statistics display")]
public class TestSceneAdvancedStats : OsuTestScene
{
private TestAdvancedStats advancedStats;
[Resolved]
private RulesetStore rulesets { get; set; }
[Resolved]
private OsuColour colours { get; set; }
[SetUp]
public void Setup() => Schedule(() => Child = advancedStats = new TestAdvancedStats
{
Width = 500
});
private BeatmapInfo exampleBeatmapInfo => new BeatmapInfo
{
RulesetID = 0,
Ruleset = rulesets.AvailableRulesets.First(),
BaseDifficulty = new BeatmapDifficulty
{
CircleSize = 7.2f,
DrainRate = 3,
OverallDifficulty = 5.7f,
ApproachRate = 3.5f
},
StarDifficulty = 4.5f
};
[Test]
public void TestNoMod()
{
AddStep("set beatmap", () => advancedStats.Beatmap = exampleBeatmapInfo);
AddStep("no mods selected", () => SelectedMods.Value = Array.Empty<Mod>());
AddAssert("first bar text is Circle Size", () => advancedStats.ChildrenOfType<SpriteText>().First().Text == "Circle Size");
AddAssert("circle size bar is white", () => barIsWhite(advancedStats.FirstValue));
AddAssert("HP drain bar is white", () => barIsWhite(advancedStats.HpDrain));
AddAssert("accuracy bar is white", () => barIsWhite(advancedStats.Accuracy));
AddAssert("approach rate bar is white", () => barIsWhite(advancedStats.ApproachRate));
}
[Test]
public void TestManiaFirstBarText()
{
AddStep("set beatmap", () => advancedStats.Beatmap = new BeatmapInfo
{
Ruleset = rulesets.GetRuleset(3),
BaseDifficulty = new BeatmapDifficulty
{
CircleSize = 5,
DrainRate = 4.3f,
OverallDifficulty = 4.5f,
ApproachRate = 3.1f
},
StarDifficulty = 8
});
AddAssert("first bar text is Key Count", () => advancedStats.ChildrenOfType<SpriteText>().First().Text == "Key Count");
}
[Test]
public void TestEasyMod()
{
AddStep("set beatmap", () => advancedStats.Beatmap = exampleBeatmapInfo);
AddStep("select EZ mod", () =>
{
var ruleset = advancedStats.Beatmap.Ruleset.CreateInstance();
SelectedMods.Value = new[] { ruleset.GetAllMods().OfType<ModEasy>().Single() };
});
AddAssert("circle size bar is blue", () => barIsBlue(advancedStats.FirstValue));
AddAssert("HP drain bar is blue", () => barIsBlue(advancedStats.HpDrain));
AddAssert("accuracy bar is blue", () => barIsBlue(advancedStats.Accuracy));
AddAssert("approach rate bar is blue", () => barIsBlue(advancedStats.ApproachRate));
}
[Test]
public void TestHardRockMod()
{
AddStep("set beatmap", () => advancedStats.Beatmap = exampleBeatmapInfo);
AddStep("select HR mod", () =>
{
var ruleset = advancedStats.Beatmap.Ruleset.CreateInstance();
SelectedMods.Value = new[] { ruleset.GetAllMods().OfType<ModHardRock>().Single() };
});
AddAssert("circle size bar is red", () => barIsRed(advancedStats.FirstValue));
AddAssert("HP drain bar is red", () => barIsRed(advancedStats.HpDrain));
AddAssert("accuracy bar is red", () => barIsRed(advancedStats.Accuracy));
AddAssert("approach rate bar is red", () => barIsRed(advancedStats.ApproachRate));
}
[Test]
public void TestUnchangedDifficultyAdjustMod()
{
AddStep("set beatmap", () => advancedStats.Beatmap = exampleBeatmapInfo);
AddStep("select unchanged Difficulty Adjust mod", () =>
{
var ruleset = advancedStats.Beatmap.Ruleset.CreateInstance();
var difficultyAdjustMod = ruleset.GetAllMods().OfType<ModDifficultyAdjust>().Single();
difficultyAdjustMod.ReadFromDifficulty(advancedStats.Beatmap.BaseDifficulty);
SelectedMods.Value = new[] { difficultyAdjustMod };
});
AddAssert("circle size bar is white", () => barIsWhite(advancedStats.FirstValue));
AddAssert("HP drain bar is white", () => barIsWhite(advancedStats.HpDrain));
AddAssert("accuracy bar is white", () => barIsWhite(advancedStats.Accuracy));
AddAssert("approach rate bar is white", () => barIsWhite(advancedStats.ApproachRate));
}
[Test]
public void TestChangedDifficultyAdjustMod()
{
AddStep("set beatmap", () => advancedStats.Beatmap = exampleBeatmapInfo);
AddStep("select changed Difficulty Adjust mod", () =>
{
var ruleset = advancedStats.Beatmap.Ruleset.CreateInstance();
var difficultyAdjustMod = ruleset.GetAllMods().OfType<ModDifficultyAdjust>().Single();
var originalDifficulty = advancedStats.Beatmap.BaseDifficulty;
var adjustedDifficulty = new BeatmapDifficulty
{
CircleSize = originalDifficulty.CircleSize,
DrainRate = originalDifficulty.DrainRate - 0.5f,
OverallDifficulty = originalDifficulty.OverallDifficulty,
ApproachRate = originalDifficulty.ApproachRate + 2.2f,
};
difficultyAdjustMod.ReadFromDifficulty(adjustedDifficulty);
SelectedMods.Value = new[] { difficultyAdjustMod };
});
AddAssert("circle size bar is white", () => barIsWhite(advancedStats.FirstValue));
AddAssert("drain rate bar is blue", () => barIsBlue(advancedStats.HpDrain));
AddAssert("accuracy bar is white", () => barIsWhite(advancedStats.Accuracy));
AddAssert("approach rate bar is red", () => barIsRed(advancedStats.ApproachRate));
}
private bool barIsWhite(AdvancedStats.StatisticRow row) => row.ModBar.AccentColour == Color4.White;
private bool barIsBlue(AdvancedStats.StatisticRow row) => row.ModBar.AccentColour == colours.BlueDark;
private bool barIsRed(AdvancedStats.StatisticRow row) => row.ModBar.AccentColour == colours.Red;
private class TestAdvancedStats : AdvancedStats
{
public new StatisticRow FirstValue => base.FirstValue;
public new StatisticRow HpDrain => base.HpDrain;
public new StatisticRow Accuracy => base.Accuracy;
public new StatisticRow ApproachRate => base.ApproachRate;
}
}
}

View File

@ -3,14 +3,8 @@
using System.Linq; using System.Linq;
using NUnit.Framework; using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Testing;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Graphics;
using osu.Game.Graphics.UserInterface;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Mods;
using osu.Game.Screens.Select; using osu.Game.Screens.Select;
namespace osu.Game.Tests.Visual.SongSelect namespace osu.Game.Tests.Visual.SongSelect
@ -180,27 +174,5 @@ namespace osu.Game.Tests.Visual.SongSelect
OnlineBeatmapID = 162, OnlineBeatmapID = 162,
}); });
} }
[Resolved]
private RulesetStore rulesets { get; set; }
[Resolved]
private OsuColour colours { get; set; }
[Test]
public void TestModAdjustments()
{
TestAllMetrics();
Ruleset ruleset = rulesets.AvailableRulesets.First().CreateInstance();
AddStep("with EZ mod", () => SelectedMods.Value = new[] { ruleset.GetAllMods().First(m => m is ModEasy) });
AddAssert("first bar coloured blue", () => details.ChildrenOfType<Bar>().Skip(1).First().AccentColour == colours.BlueDark);
AddStep("with HR mod", () => SelectedMods.Value = new[] { ruleset.GetAllMods().First(m => m is ModHardRock) });
AddAssert("first bar coloured red", () => details.ChildrenOfType<Bar>().Skip(1).First().AccentColour == colours.Red);
}
} }
} }

View File

@ -34,7 +34,7 @@ namespace osu.Game.Rulesets.Objects
/// </summary> /// </summary>
public event Action DefaultsApplied; public event Action DefaultsApplied;
public readonly Bindable<double> StartTimeBindable = new Bindable<double>(); public readonly Bindable<double> StartTimeBindable = new BindableDouble();
/// <summary> /// <summary>
/// The time at which the HitObject starts. /// The time at which the HitObject starts.

View File

@ -36,7 +36,7 @@ namespace osu.Game.Screens.Backgrounds
/// <summary> /// <summary>
/// The amount of blur to be applied in addition to user-specified blur. /// The amount of blur to be applied in addition to user-specified blur.
/// </summary> /// </summary>
public readonly Bindable<float> BlurAmount = new Bindable<float>(); public readonly Bindable<float> BlurAmount = new BindableFloat();
internal readonly IBindable<bool> IsBreakTime = new Bindable<bool>(); internal readonly IBindable<bool> IsBreakTime = new Bindable<bool>();
@ -119,7 +119,7 @@ namespace osu.Game.Screens.Backgrounds
/// <remarks> /// <remarks>
/// Used in contexts where there can potentially be both user and screen-specified blurring occuring at the same time, such as in <see cref="PlayerLoader"/> /// Used in contexts where there can potentially be both user and screen-specified blurring occuring at the same time, such as in <see cref="PlayerLoader"/>
/// </remarks> /// </remarks>
public readonly Bindable<float> BlurAmount = new Bindable<float>(); public readonly Bindable<float> BlurAmount = new BindableFloat();
public Background Background public Background Background
{ {

View File

@ -16,6 +16,7 @@ using System.Collections.Generic;
using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Mods;
using System.Linq; using System.Linq;
using osu.Framework.Threading; using osu.Framework.Threading;
using osu.Framework.Utils;
using osu.Game.Configuration; using osu.Game.Configuration;
using osu.Game.Overlays.Settings; using osu.Game.Overlays.Settings;
@ -26,7 +27,8 @@ namespace osu.Game.Screens.Select.Details
[Resolved] [Resolved]
private IBindable<IReadOnlyList<Mod>> mods { get; set; } private IBindable<IReadOnlyList<Mod>> mods { get; set; }
private readonly StatisticRow firstValue, hpDrain, accuracy, approachRate, starDifficulty; protected readonly StatisticRow FirstValue, HpDrain, Accuracy, ApproachRate;
private readonly StatisticRow starDifficulty;
private BeatmapInfo beatmap; private BeatmapInfo beatmap;
@ -52,10 +54,10 @@ namespace osu.Game.Screens.Select.Details
Spacing = new Vector2(4f), Spacing = new Vector2(4f),
Children = new[] Children = new[]
{ {
firstValue = new StatisticRow(), //circle size/key amount FirstValue = new StatisticRow(), //circle size/key amount
hpDrain = new StatisticRow { Title = "HP Drain" }, HpDrain = new StatisticRow { Title = "HP Drain" },
accuracy = new StatisticRow { Title = "Accuracy" }, Accuracy = new StatisticRow { Title = "Accuracy" },
approachRate = new StatisticRow { Title = "Approach Rate" }, ApproachRate = new StatisticRow { Title = "Approach Rate" },
starDifficulty = new StatisticRow(10, true) { Title = "Star Difficulty" }, starDifficulty = new StatisticRow(10, true) { Title = "Star Difficulty" },
}, },
}; };
@ -122,24 +124,24 @@ namespace osu.Game.Screens.Select.Details
case 3: case 3:
// Account for mania differences locally for now // Account for mania differences locally for now
// Eventually this should be handled in a more modular way, allowing rulesets to return arbitrary difficulty attributes // Eventually this should be handled in a more modular way, allowing rulesets to return arbitrary difficulty attributes
firstValue.Title = "Key Count"; FirstValue.Title = "Key Count";
firstValue.Value = (baseDifficulty?.CircleSize ?? 0, null); FirstValue.Value = (baseDifficulty?.CircleSize ?? 0, null);
break; break;
default: default:
firstValue.Title = "Circle Size"; FirstValue.Title = "Circle Size";
firstValue.Value = (baseDifficulty?.CircleSize ?? 0, adjustedDifficulty?.CircleSize); FirstValue.Value = (baseDifficulty?.CircleSize ?? 0, adjustedDifficulty?.CircleSize);
break; break;
} }
starDifficulty.Value = ((float)(Beatmap?.StarDifficulty ?? 0), null); starDifficulty.Value = ((float)(Beatmap?.StarDifficulty ?? 0), null);
hpDrain.Value = (baseDifficulty?.DrainRate ?? 0, adjustedDifficulty?.DrainRate); HpDrain.Value = (baseDifficulty?.DrainRate ?? 0, adjustedDifficulty?.DrainRate);
accuracy.Value = (baseDifficulty?.OverallDifficulty ?? 0, adjustedDifficulty?.OverallDifficulty); Accuracy.Value = (baseDifficulty?.OverallDifficulty ?? 0, adjustedDifficulty?.OverallDifficulty);
approachRate.Value = (baseDifficulty?.ApproachRate ?? 0, adjustedDifficulty?.ApproachRate); ApproachRate.Value = (baseDifficulty?.ApproachRate ?? 0, adjustedDifficulty?.ApproachRate);
} }
private class StatisticRow : Container, IHasAccentColour public class StatisticRow : Container, IHasAccentColour
{ {
private const float value_width = 25; private const float value_width = 25;
private const float name_width = 70; private const float name_width = 70;
@ -147,7 +149,8 @@ namespace osu.Game.Screens.Select.Details
private readonly float maxValue; private readonly float maxValue;
private readonly bool forceDecimalPlaces; private readonly bool forceDecimalPlaces;
private readonly OsuSpriteText name, valueText; private readonly OsuSpriteText name, valueText;
private readonly Bar bar, modBar; private readonly Bar bar;
public readonly Bar ModBar;
[Resolved] [Resolved]
private OsuColour colours { get; set; } private OsuColour colours { get; set; }
@ -173,14 +176,14 @@ namespace osu.Game.Screens.Select.Details
bar.Length = value.baseValue / maxValue; bar.Length = value.baseValue / maxValue;
valueText.Text = (value.adjustedValue ?? value.baseValue).ToString(forceDecimalPlaces ? "0.00" : "0.##"); valueText.Text = (value.adjustedValue ?? value.baseValue).ToString(forceDecimalPlaces ? "0.00" : "0.##");
modBar.Length = (value.adjustedValue ?? 0) / maxValue; ModBar.Length = (value.adjustedValue ?? 0) / maxValue;
if (value.adjustedValue > value.baseValue) if (Precision.AlmostEquals(value.baseValue, value.adjustedValue ?? value.baseValue, 0.05f))
modBar.AccentColour = valueText.Colour = colours.Red; ModBar.AccentColour = valueText.Colour = Color4.White;
else if (value.adjustedValue > value.baseValue)
ModBar.AccentColour = valueText.Colour = colours.Red;
else if (value.adjustedValue < value.baseValue) else if (value.adjustedValue < value.baseValue)
modBar.AccentColour = valueText.Colour = colours.BlueDark; ModBar.AccentColour = valueText.Colour = colours.BlueDark;
else
modBar.AccentColour = valueText.Colour = Color4.White;
} }
} }
@ -217,7 +220,7 @@ namespace osu.Game.Screens.Select.Details
BackgroundColour = Color4.White.Opacity(0.5f), BackgroundColour = Color4.White.Opacity(0.5f),
Padding = new MarginPadding { Left = name_width + 10, Right = value_width + 10 }, Padding = new MarginPadding { Left = name_width + 10, Right = value_width + 10 },
}, },
modBar = new Bar ModBar = new Bar
{ {
Origin = Anchor.CentreLeft, Origin = Anchor.CentreLeft,
Anchor = Anchor.CentreLeft, Anchor = Anchor.CentreLeft,

View File

@ -149,8 +149,8 @@ namespace osu.Game.Screens.Select
private readonly IBindable<RulesetInfo> ruleset = new Bindable<RulesetInfo>(); private readonly IBindable<RulesetInfo> ruleset = new Bindable<RulesetInfo>();
private readonly Bindable<bool> showConverted = new Bindable<bool>(); private readonly Bindable<bool> showConverted = new Bindable<bool>();
private readonly Bindable<double> minimumStars = new Bindable<double>(); private readonly Bindable<double> minimumStars = new BindableDouble();
private readonly Bindable<double> maximumStars = new Bindable<double>(); private readonly Bindable<double> maximumStars = new BindableDouble();
public readonly Box Background; public readonly Box Background;

View File

@ -47,7 +47,7 @@ namespace osu.Game.Tests.Visual
public readonly Bindable<ScrollingDirection> Direction = new Bindable<ScrollingDirection>(); public readonly Bindable<ScrollingDirection> Direction = new Bindable<ScrollingDirection>();
IBindable<ScrollingDirection> IScrollingInfo.Direction => Direction; IBindable<ScrollingDirection> IScrollingInfo.Direction => Direction;
public readonly Bindable<double> TimeRange = new Bindable<double>(1000) { Value = 1000 }; public readonly Bindable<double> TimeRange = new BindableDouble(1000) { Value = 1000 };
IBindable<double> IScrollingInfo.TimeRange => TimeRange; IBindable<double> IScrollingInfo.TimeRange => TimeRange;
public readonly TestScrollAlgorithm Algorithm = new TestScrollAlgorithm(); public readonly TestScrollAlgorithm Algorithm = new TestScrollAlgorithm();