1
0
mirror of https://github.com/ppy/osu.git synced 2025-01-21 19:43:22 +08:00

Merge branch 'master' into osu-markdown

This commit is contained in:
Dan Balasescu 2021-05-10 20:02:04 +09:00 committed by GitHub
commit e7355da201
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
62 changed files with 466 additions and 591 deletions

View File

@ -1,28 +1,22 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // 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. // See the LICENCE file in the repository root for full licence text.
using System.Collections.Generic;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Replays;
using osu.Game.Rulesets.EmptyFreeform.Objects; using osu.Game.Rulesets.EmptyFreeform.Objects;
using osu.Game.Rulesets.Replays; using osu.Game.Rulesets.Replays;
namespace osu.Game.Rulesets.EmptyFreeform.Replays namespace osu.Game.Rulesets.EmptyFreeform.Replays
{ {
public class EmptyFreeformAutoGenerator : AutoGenerator public class EmptyFreeformAutoGenerator : AutoGenerator<EmptyFreeformReplayFrame>
{ {
protected Replay Replay;
protected List<ReplayFrame> Frames => Replay.Frames;
public new Beatmap<EmptyFreeformHitObject> Beatmap => (Beatmap<EmptyFreeformHitObject>)base.Beatmap; public new Beatmap<EmptyFreeformHitObject> Beatmap => (Beatmap<EmptyFreeformHitObject>)base.Beatmap;
public EmptyFreeformAutoGenerator(IBeatmap beatmap) public EmptyFreeformAutoGenerator(IBeatmap beatmap)
: base(beatmap) : base(beatmap)
{ {
Replay = new Replay();
} }
public override Replay Generate() protected override void GenerateFrames()
{ {
Frames.Add(new EmptyFreeformReplayFrame()); Frames.Add(new EmptyFreeformReplayFrame());
@ -35,8 +29,6 @@ namespace osu.Game.Rulesets.EmptyFreeform.Replays
// todo: add required inputs and extra frames. // todo: add required inputs and extra frames.
}); });
} }
return Replay;
} }
} }
} }

View File

@ -1,28 +1,22 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // 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. // See the LICENCE file in the repository root for full licence text.
using System.Collections.Generic;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Replays;
using osu.Game.Rulesets.Pippidon.Objects; using osu.Game.Rulesets.Pippidon.Objects;
using osu.Game.Rulesets.Replays; using osu.Game.Rulesets.Replays;
namespace osu.Game.Rulesets.Pippidon.Replays namespace osu.Game.Rulesets.Pippidon.Replays
{ {
public class PippidonAutoGenerator : AutoGenerator public class PippidonAutoGenerator : AutoGenerator<PippidonReplayFrame>
{ {
protected Replay Replay;
protected List<ReplayFrame> Frames => Replay.Frames;
public new Beatmap<PippidonHitObject> Beatmap => (Beatmap<PippidonHitObject>)base.Beatmap; public new Beatmap<PippidonHitObject> Beatmap => (Beatmap<PippidonHitObject>)base.Beatmap;
public PippidonAutoGenerator(IBeatmap beatmap) public PippidonAutoGenerator(IBeatmap beatmap)
: base(beatmap) : base(beatmap)
{ {
Replay = new Replay();
} }
public override Replay Generate() protected override void GenerateFrames()
{ {
Frames.Add(new PippidonReplayFrame()); Frames.Add(new PippidonReplayFrame());
@ -34,8 +28,6 @@ namespace osu.Game.Rulesets.Pippidon.Replays
Position = hitObject.Position, Position = hitObject.Position,
}); });
} }
return Replay;
} }
} }
} }

View File

@ -1,28 +1,22 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // 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. // See the LICENCE file in the repository root for full licence text.
using System.Collections.Generic;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Replays;
using osu.Game.Rulesets.EmptyScrolling.Objects; using osu.Game.Rulesets.EmptyScrolling.Objects;
using osu.Game.Rulesets.Replays; using osu.Game.Rulesets.Replays;
namespace osu.Game.Rulesets.EmptyScrolling.Replays namespace osu.Game.Rulesets.EmptyScrolling.Replays
{ {
public class EmptyScrollingAutoGenerator : AutoGenerator public class EmptyScrollingAutoGenerator : AutoGenerator<EmptyScrollingReplayFrame>
{ {
protected Replay Replay;
protected List<ReplayFrame> Frames => Replay.Frames;
public new Beatmap<EmptyScrollingHitObject> Beatmap => (Beatmap<EmptyScrollingHitObject>)base.Beatmap; public new Beatmap<EmptyScrollingHitObject> Beatmap => (Beatmap<EmptyScrollingHitObject>)base.Beatmap;
public EmptyScrollingAutoGenerator(IBeatmap beatmap) public EmptyScrollingAutoGenerator(IBeatmap beatmap)
: base(beatmap) : base(beatmap)
{ {
Replay = new Replay();
} }
public override Replay Generate() protected override void GenerateFrames()
{ {
Frames.Add(new EmptyScrollingReplayFrame()); Frames.Add(new EmptyScrollingReplayFrame());
@ -34,8 +28,6 @@ namespace osu.Game.Rulesets.EmptyScrolling.Replays
// todo: add required inputs and extra frames. // todo: add required inputs and extra frames.
}); });
} }
return Replay;
} }
} }
} }

View File

@ -2,29 +2,23 @@
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
using System; using System;
using System.Collections.Generic;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Replays;
using osu.Game.Rulesets.Pippidon.Objects; using osu.Game.Rulesets.Pippidon.Objects;
using osu.Game.Rulesets.Pippidon.UI; using osu.Game.Rulesets.Pippidon.UI;
using osu.Game.Rulesets.Replays; using osu.Game.Rulesets.Replays;
namespace osu.Game.Rulesets.Pippidon.Replays namespace osu.Game.Rulesets.Pippidon.Replays
{ {
public class PippidonAutoGenerator : AutoGenerator public class PippidonAutoGenerator : AutoGenerator<PippidonReplayFrame>
{ {
protected Replay Replay;
protected List<ReplayFrame> Frames => Replay.Frames;
public new Beatmap<PippidonHitObject> Beatmap => (Beatmap<PippidonHitObject>)base.Beatmap; public new Beatmap<PippidonHitObject> Beatmap => (Beatmap<PippidonHitObject>)base.Beatmap;
public PippidonAutoGenerator(IBeatmap beatmap) public PippidonAutoGenerator(IBeatmap beatmap)
: base(beatmap) : base(beatmap)
{ {
Replay = new Replay();
} }
public override Replay Generate() protected override void GenerateFrames()
{ {
int currentLane = 0; int currentLane = 0;
@ -55,8 +49,6 @@ namespace osu.Game.Rulesets.Pippidon.Replays
currentLane = hitObject.Lane; currentLane = hitObject.Lane;
} }
return Replay;
} }
private void addFrame(double time, PippidonAction direction) private void addFrame(double time, PippidonAction direction)

View File

@ -52,6 +52,6 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.422.0" /> <PackageReference Include="ppy.osu.Game.Resources" Version="2021.422.0" />
<PackageReference Include="ppy.osu.Framework.Android" Version="2021.506.0" /> <PackageReference Include="ppy.osu.Framework.Android" Version="2021.507.0" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -5,7 +5,6 @@ using System;
using System.Linq; using System.Linq;
using osu.Framework.Utils; using osu.Framework.Utils;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Replays;
using osu.Game.Rulesets.Catch.Beatmaps; using osu.Game.Rulesets.Catch.Beatmaps;
using osu.Game.Rulesets.Catch.Objects; using osu.Game.Rulesets.Catch.Objects;
using osu.Game.Rulesets.Catch.UI; using osu.Game.Rulesets.Catch.UI;
@ -13,26 +12,19 @@ using osu.Game.Rulesets.Replays;
namespace osu.Game.Rulesets.Catch.Replays namespace osu.Game.Rulesets.Catch.Replays
{ {
internal class CatchAutoGenerator : AutoGenerator internal class CatchAutoGenerator : AutoGenerator<CatchReplayFrame>
{ {
public const double RELEASE_DELAY = 20;
public new CatchBeatmap Beatmap => (CatchBeatmap)base.Beatmap; public new CatchBeatmap Beatmap => (CatchBeatmap)base.Beatmap;
public CatchAutoGenerator(IBeatmap beatmap) public CatchAutoGenerator(IBeatmap beatmap)
: base(beatmap) : base(beatmap)
{ {
Replay = new Replay();
} }
protected Replay Replay; protected override void GenerateFrames()
private CatchReplayFrame currentFrame;
public override Replay Generate()
{ {
if (Beatmap.HitObjects.Count == 0) if (Beatmap.HitObjects.Count == 0)
return Replay; return;
// todo: add support for HT DT // todo: add support for HT DT
const double dash_speed = Catcher.BASE_SPEED; const double dash_speed = Catcher.BASE_SPEED;
@ -119,15 +111,11 @@ namespace osu.Game.Rulesets.Catch.Replays
} }
} }
} }
return Replay;
} }
private void addFrame(double time, float? position = null, bool dashing = false) private void addFrame(double time, float? position = null, bool dashing = false)
{ {
var last = currentFrame; Frames.Add(new CatchReplayFrame(time, position, dashing, LastFrame));
currentFrame = new CatchReplayFrame(time, position, dashing, last);
Replay.Frames.Add(currentFrame);
} }
} }
} }

View File

@ -3,7 +3,6 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using osu.Game.Replays;
using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Rulesets.Mania.Beatmaps;
using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects;
@ -11,7 +10,7 @@ using osu.Game.Rulesets.Replays;
namespace osu.Game.Rulesets.Mania.Replays namespace osu.Game.Rulesets.Mania.Replays
{ {
internal class ManiaAutoGenerator : AutoGenerator internal class ManiaAutoGenerator : AutoGenerator<ManiaReplayFrame>
{ {
public const double RELEASE_DELAY = 20; public const double RELEASE_DELAY = 20;
@ -22,8 +21,6 @@ namespace osu.Game.Rulesets.Mania.Replays
public ManiaAutoGenerator(ManiaBeatmap beatmap) public ManiaAutoGenerator(ManiaBeatmap beatmap)
: base(beatmap) : base(beatmap)
{ {
Replay = new Replay();
columnActions = new ManiaAction[Beatmap.TotalColumns]; columnActions = new ManiaAction[Beatmap.TotalColumns];
var normalAction = ManiaAction.Key1; var normalAction = ManiaAction.Key1;
@ -43,12 +40,10 @@ namespace osu.Game.Rulesets.Mania.Replays
} }
} }
protected Replay Replay; protected override void GenerateFrames()
public override Replay Generate()
{ {
if (Beatmap.HitObjects.Count == 0) if (Beatmap.HitObjects.Count == 0)
return Replay; return;
var pointGroups = generateActionPoints().GroupBy(a => a.Time).OrderBy(g => g.First().Time); var pointGroups = generateActionPoints().GroupBy(a => a.Time).OrderBy(g => g.First().Time);
@ -70,10 +65,8 @@ namespace osu.Game.Rulesets.Mania.Replays
} }
} }
Replay.Frames.Add(new ManiaReplayFrame(group.First().Time, actions.ToArray())); Frames.Add(new ManiaReplayFrame(group.First().Time, actions.ToArray()));
} }
return Replay;
} }
private IEnumerable<IActionPoint> generateActionPoints() private IEnumerable<IActionPoint> generateActionPoints()

View File

@ -26,6 +26,10 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
{ {
AccentColour = Color4.Transparent AccentColour = Color4.Transparent
}; };
// SliderSelectionBlueprint relies on calling ReceivePositionalInputAt on this drawable to determine whether selection should occur.
// Without AlwaysPresent, a movement in a parent container (ie. the editor composer area resizing) could cause incorrect input handling.
AlwaysPresent = true;
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]

View File

@ -2,10 +2,8 @@
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
using System; using System;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Replays;
using osu.Game.Rulesets.Taiko.Objects; using osu.Game.Rulesets.Taiko.Objects;
using osu.Game.Rulesets.Replays; using osu.Game.Rulesets.Replays;
using osu.Game.Rulesets.Taiko.Beatmaps; using osu.Game.Rulesets.Taiko.Beatmaps;
@ -13,7 +11,7 @@ using osu.Game.Rulesets.Objects;
namespace osu.Game.Rulesets.Taiko.Replays namespace osu.Game.Rulesets.Taiko.Replays
{ {
public class TaikoAutoGenerator : AutoGenerator public class TaikoAutoGenerator : AutoGenerator<TaikoReplayFrame>
{ {
public new TaikoBeatmap Beatmap => (TaikoBeatmap)base.Beatmap; public new TaikoBeatmap Beatmap => (TaikoBeatmap)base.Beatmap;
@ -22,16 +20,12 @@ namespace osu.Game.Rulesets.Taiko.Replays
public TaikoAutoGenerator(IBeatmap beatmap) public TaikoAutoGenerator(IBeatmap beatmap)
: base(beatmap) : base(beatmap)
{ {
Replay = new Replay();
} }
protected Replay Replay; protected override void GenerateFrames()
protected List<ReplayFrame> Frames => Replay.Frames;
public override Replay Generate()
{ {
if (Beatmap.HitObjects.Count == 0) if (Beatmap.HitObjects.Count == 0)
return Replay; return;
bool hitButton = true; bool hitButton = true;
@ -128,8 +122,6 @@ namespace osu.Game.Rulesets.Taiko.Replays
hitButton = !hitButton; hitButton = !hitButton;
} }
return Replay;
} }
} }
} }

View File

@ -4,9 +4,11 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using NUnit.Framework; using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Testing; using osu.Framework.Testing;
using osu.Game.Rulesets; using osu.Game.Rulesets;
using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.Scoring;
using osu.Game.Screens.Play.HUD; using osu.Game.Screens.Play.HUD;
namespace osu.Game.Tests.Visual.Gameplay namespace osu.Game.Tests.Visual.Gameplay
@ -17,31 +19,21 @@ namespace osu.Game.Tests.Visual.Gameplay
protected override Ruleset CreateRulesetForSkinProvider() => new OsuRuleset(); protected override Ruleset CreateRulesetForSkinProvider() => new OsuRuleset();
[Cached]
private ScoreProcessor scoreProcessor = new ScoreProcessor();
[SetUpSteps] [SetUpSteps]
public void SetUpSteps() public void SetUpSteps()
{ {
AddStep("Create combo counters", () => SetContents(() => AddStep("Create combo counters", () => SetContents(() => new SkinnableComboCounter()));
{
var comboCounter = new SkinnableComboCounter();
comboCounter.Current.Value = 1;
return comboCounter;
}));
} }
[Test] [Test]
public void TestComboCounterIncrementing() public void TestComboCounterIncrementing()
{ {
AddRepeatStep("increase combo", () => AddRepeatStep("increase combo", () => scoreProcessor.Combo.Value++, 10);
{
foreach (var counter in comboCounters)
counter.Current.Value++;
}, 10);
AddStep("reset combo", () => AddStep("reset combo", () => scoreProcessor.Combo.Value = 0);
{
foreach (var counter in comboCounters)
counter.Current.Value = 0;
});
} }
} }
} }

View File

@ -4,7 +4,8 @@
using NUnit.Framework; using NUnit.Framework;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Framework.Testing; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Configuration; using osu.Game.Configuration;
using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Scoring;
using osu.Game.Screens.Play.HUD; using osu.Game.Screens.Play.HUD;
@ -20,24 +21,28 @@ namespace osu.Game.Tests.Visual.Gameplay
[Resolved] [Resolved]
private OsuConfigManager config { get; set; } private OsuConfigManager config { get; set; }
[SetUpSteps] private void create(HealthProcessor healthProcessor)
public void SetUpSteps()
{ {
AddStep("create layer", () => AddStep("create layer", () =>
{ {
Child = layer = new FailingLayer(); Child = new HealthProcessorContainer(healthProcessor)
layer.BindHealthProcessor(new DrainingHealthProcessor(1)); {
RelativeSizeAxes = Axes.Both,
Child = layer = new FailingLayer()
};
layer.ShowHealth.BindTo(showHealth); layer.ShowHealth.BindTo(showHealth);
}); });
AddStep("show health", () => showHealth.Value = true); AddStep("show health", () => showHealth.Value = true);
AddStep("enable layer", () => config.SetValue(OsuSetting.FadePlayfieldWhenHealthLow, true)); AddStep("enable layer", () => config.SetValue(OsuSetting.FadePlayfieldWhenHealthLow, true));
AddUntilStep("layer is visible", () => layer.IsPresent);
} }
[Test] [Test]
public void TestLayerFading() public void TestLayerFading()
{ {
create(new DrainingHealthProcessor(0));
AddSliderStep("current health", 0.0, 1.0, 1.0, val => AddSliderStep("current health", 0.0, 1.0, 1.0, val =>
{ {
if (layer != null) if (layer != null)
@ -53,6 +58,8 @@ namespace osu.Game.Tests.Visual.Gameplay
[Test] [Test]
public void TestLayerDisabledViaConfig() public void TestLayerDisabledViaConfig()
{ {
create(new DrainingHealthProcessor(0));
AddUntilStep("layer is visible", () => layer.IsPresent);
AddStep("disable layer", () => config.SetValue(OsuSetting.FadePlayfieldWhenHealthLow, false)); AddStep("disable layer", () => config.SetValue(OsuSetting.FadePlayfieldWhenHealthLow, false));
AddStep("set health to 0.10", () => layer.Current.Value = 0.1); AddStep("set health to 0.10", () => layer.Current.Value = 0.1);
AddUntilStep("layer is not visible", () => !layer.IsPresent); AddUntilStep("layer is not visible", () => !layer.IsPresent);
@ -61,7 +68,8 @@ namespace osu.Game.Tests.Visual.Gameplay
[Test] [Test]
public void TestLayerVisibilityWithAccumulatingProcessor() public void TestLayerVisibilityWithAccumulatingProcessor()
{ {
AddStep("bind accumulating processor", () => layer.BindHealthProcessor(new AccumulatingHealthProcessor(1))); create(new AccumulatingHealthProcessor(1));
AddUntilStep("layer is not visible", () => !layer.IsPresent);
AddStep("set health to 0.10", () => layer.Current.Value = 0.1); AddStep("set health to 0.10", () => layer.Current.Value = 0.1);
AddUntilStep("layer is not visible", () => !layer.IsPresent); AddUntilStep("layer is not visible", () => !layer.IsPresent);
} }
@ -69,7 +77,7 @@ namespace osu.Game.Tests.Visual.Gameplay
[Test] [Test]
public void TestLayerVisibilityWithDrainingProcessor() public void TestLayerVisibilityWithDrainingProcessor()
{ {
AddStep("bind accumulating processor", () => layer.BindHealthProcessor(new DrainingHealthProcessor(1))); create(new DrainingHealthProcessor(0));
AddStep("set health to 0.10", () => layer.Current.Value = 0.1); AddStep("set health to 0.10", () => layer.Current.Value = 0.1);
AddWaitStep("wait for potential fade", 10); AddWaitStep("wait for potential fade", 10);
AddAssert("layer is still visible", () => layer.IsPresent); AddAssert("layer is still visible", () => layer.IsPresent);
@ -78,6 +86,8 @@ namespace osu.Game.Tests.Visual.Gameplay
[Test] [Test]
public void TestLayerVisibilityWithDifferentOptions() public void TestLayerVisibilityWithDifferentOptions()
{ {
create(new DrainingHealthProcessor(0));
AddStep("set health to 0.10", () => layer.Current.Value = 0.1); AddStep("set health to 0.10", () => layer.Current.Value = 0.1);
AddStep("don't show health", () => showHealth.Value = false); AddStep("don't show health", () => showHealth.Value = false);
@ -96,5 +106,16 @@ namespace osu.Game.Tests.Visual.Gameplay
AddStep("enable FadePlayfieldWhenHealthLow", () => config.SetValue(OsuSetting.FadePlayfieldWhenHealthLow, true)); AddStep("enable FadePlayfieldWhenHealthLow", () => config.SetValue(OsuSetting.FadePlayfieldWhenHealthLow, true));
AddUntilStep("layer fade is visible", () => layer.IsPresent); AddUntilStep("layer fade is visible", () => layer.IsPresent);
} }
private class HealthProcessorContainer : Container
{
[Cached(typeof(HealthProcessor))]
private readonly HealthProcessor healthProcessor;
public HealthProcessorContainer(HealthProcessor healthProcessor)
{
this.healthProcessor = healthProcessor;
}
}
} }
} }

View File

@ -10,6 +10,7 @@ using osu.Framework.Graphics.Containers;
using osu.Framework.Testing; using osu.Framework.Testing;
using osu.Game.Configuration; using osu.Game.Configuration;
using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Scoring;
using osu.Game.Screens.Play; using osu.Game.Screens.Play;
using osuTK.Input; using osuTK.Input;
@ -19,6 +20,12 @@ namespace osu.Game.Tests.Visual.Gameplay
{ {
private HUDOverlay hudOverlay; private HUDOverlay hudOverlay;
[Cached]
private ScoreProcessor scoreProcessor = new ScoreProcessor();
[Cached(typeof(HealthProcessor))]
private HealthProcessor healthProcessor = new DrainingHealthProcessor(0);
// best way to check without exposing. // best way to check without exposing.
private Drawable hideTarget => hudOverlay.KeyCounter; private Drawable hideTarget => hudOverlay.KeyCounter;
private FillFlowContainer<KeyCounter> keyCounterFlow => hudOverlay.KeyCounter.ChildrenOfType<FillFlowContainer<KeyCounter>>().First(); private FillFlowContainer<KeyCounter> keyCounterFlow => hudOverlay.KeyCounter.ChildrenOfType<FillFlowContainer<KeyCounter>>().First();
@ -31,9 +38,9 @@ namespace osu.Game.Tests.Visual.Gameplay
{ {
createNew(); createNew();
AddRepeatStep("increase combo", () => { hudOverlay.ComboCounter.Current.Value++; }, 10); AddRepeatStep("increase combo", () => { scoreProcessor.Combo.Value++; }, 10);
AddStep("reset combo", () => { hudOverlay.ComboCounter.Current.Value = 0; }); AddStep("reset combo", () => { scoreProcessor.Combo.Value = 0; });
} }
[Test] [Test]
@ -139,12 +146,12 @@ namespace osu.Game.Tests.Visual.Gameplay
{ {
AddStep("create overlay", () => AddStep("create overlay", () =>
{ {
hudOverlay = new HUDOverlay(null, null, null, Array.Empty<Mod>()); hudOverlay = new HUDOverlay(null, Array.Empty<Mod>());
// Add any key just to display the key counter visually. // Add any key just to display the key counter visually.
hudOverlay.KeyCounter.Add(new KeyCounterKeyboard(Key.Space)); hudOverlay.KeyCounter.Add(new KeyCounterKeyboard(Key.Space));
hudOverlay.ComboCounter.Current.Value = 1; scoreProcessor.Combo.Value = 1;
action?.Invoke(hudOverlay); action?.Invoke(hudOverlay);

View File

@ -2,15 +2,16 @@
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
using NUnit.Framework; using NUnit.Framework;
using osu.Game.Rulesets.Judgements; using osu.Framework.Allocation;
using osu.Framework.Utils;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Threading; using osu.Framework.Threading;
using osu.Framework.Utils;
using osu.Game.Graphics.Sprites; using osu.Game.Graphics.Sprites;
using osu.Game.Rulesets.Catch.Scoring; using osu.Game.Rulesets.Catch.Scoring;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Mania.Scoring; using osu.Game.Rulesets.Mania.Scoring;
using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Osu.Scoring; using osu.Game.Rulesets.Osu.Scoring;
using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.Taiko.Scoring; using osu.Game.Rulesets.Taiko.Scoring;
@ -20,14 +21,11 @@ namespace osu.Game.Tests.Visual.Gameplay
{ {
public class TestSceneHitErrorMeter : OsuTestScene public class TestSceneHitErrorMeter : OsuTestScene
{ {
private BarHitErrorMeter barMeter;
private BarHitErrorMeter barMeter2;
private BarHitErrorMeter barMeter3;
private ColourHitErrorMeter colourMeter;
private ColourHitErrorMeter colourMeter2;
private ColourHitErrorMeter colourMeter3;
private HitWindows hitWindows; private HitWindows hitWindows;
[Cached]
private ScoreProcessor scoreProcessor = new ScoreProcessor();
public TestSceneHitErrorMeter() public TestSceneHitErrorMeter()
{ {
recreateDisplay(new OsuHitWindows(), 5); recreateDisplay(new OsuHitWindows(), 5);
@ -105,40 +103,40 @@ namespace osu.Game.Tests.Visual.Gameplay
} }
}); });
Add(barMeter = new BarHitErrorMeter(hitWindows, true) Add(new BarHitErrorMeter(hitWindows, true)
{ {
Anchor = Anchor.CentreRight, Anchor = Anchor.CentreRight,
Origin = Anchor.CentreRight, Origin = Anchor.CentreRight,
}); });
Add(barMeter2 = new BarHitErrorMeter(hitWindows, false) Add(new BarHitErrorMeter(hitWindows, false)
{ {
Anchor = Anchor.CentreLeft, Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft, Origin = Anchor.CentreLeft,
}); });
Add(barMeter3 = new BarHitErrorMeter(hitWindows, true) Add(new BarHitErrorMeter(hitWindows, true)
{ {
Anchor = Anchor.BottomCentre, Anchor = Anchor.BottomCentre,
Origin = Anchor.CentreLeft, Origin = Anchor.CentreLeft,
Rotation = 270, Rotation = 270,
}); });
Add(colourMeter = new ColourHitErrorMeter(hitWindows) Add(new ColourHitErrorMeter(hitWindows)
{ {
Anchor = Anchor.CentreRight, Anchor = Anchor.CentreRight,
Origin = Anchor.CentreRight, Origin = Anchor.CentreRight,
Margin = new MarginPadding { Right = 50 } Margin = new MarginPadding { Right = 50 }
}); });
Add(colourMeter2 = new ColourHitErrorMeter(hitWindows) Add(new ColourHitErrorMeter(hitWindows)
{ {
Anchor = Anchor.CentreLeft, Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft, Origin = Anchor.CentreLeft,
Margin = new MarginPadding { Left = 50 } Margin = new MarginPadding { Left = 50 }
}); });
Add(colourMeter3 = new ColourHitErrorMeter(hitWindows) Add(new ColourHitErrorMeter(hitWindows)
{ {
Anchor = Anchor.BottomCentre, Anchor = Anchor.BottomCentre,
Origin = Anchor.CentreLeft, Origin = Anchor.CentreLeft,
@ -149,18 +147,11 @@ namespace osu.Game.Tests.Visual.Gameplay
private void newJudgement(double offset = 0) private void newJudgement(double offset = 0)
{ {
var judgement = new JudgementResult(new HitObject(), new Judgement()) scoreProcessor.ApplyResult(new JudgementResult(new HitCircle { HitWindows = hitWindows }, new Judgement())
{ {
TimeOffset = offset == 0 ? RNG.Next(-150, 150) : offset, TimeOffset = offset == 0 ? RNG.Next(-150, 150) : offset,
Type = HitResult.Perfect, Type = HitResult.Perfect,
}; });
barMeter.OnNewJudgement(judgement);
barMeter2.OnNewJudgement(judgement);
barMeter3.OnNewJudgement(judgement);
colourMeter.OnNewJudgement(judgement);
colourMeter2.OnNewJudgement(judgement);
colourMeter3.OnNewJudgement(judgement);
} }
} }
} }

View File

@ -2,6 +2,7 @@
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
using System; using System;
using osu.Framework.Allocation;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Testing; using osu.Framework.Testing;
@ -17,6 +18,12 @@ namespace osu.Game.Tests.Visual.Gameplay
{ {
public class TestSceneSkinEditorMultipleSkins : SkinnableTestScene public class TestSceneSkinEditorMultipleSkins : SkinnableTestScene
{ {
[Cached]
private readonly ScoreProcessor scoreProcessor = new ScoreProcessor();
[Cached(typeof(HealthProcessor))]
private HealthProcessor healthProcessor = new DrainingHealthProcessor(0);
[SetUpSteps] [SetUpSteps]
public void SetUpSteps() public void SetUpSteps()
{ {
@ -28,11 +35,9 @@ namespace osu.Game.Tests.Visual.Gameplay
var working = CreateWorkingBeatmap(ruleset.RulesetInfo); var working = CreateWorkingBeatmap(ruleset.RulesetInfo);
var beatmap = working.GetPlayableBeatmap(ruleset.RulesetInfo); var beatmap = working.GetPlayableBeatmap(ruleset.RulesetInfo);
ScoreProcessor scoreProcessor = new ScoreProcessor();
var drawableRuleset = ruleset.CreateDrawableRulesetWith(beatmap); var drawableRuleset = ruleset.CreateDrawableRulesetWith(beatmap);
var hudOverlay = new HUDOverlay(scoreProcessor, null, drawableRuleset, Array.Empty<Mod>()) var hudOverlay = new HUDOverlay(drawableRuleset, Array.Empty<Mod>())
{ {
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,
@ -40,7 +45,7 @@ namespace osu.Game.Tests.Visual.Gameplay
// Add any key just to display the key counter visually. // Add any key just to display the key counter visually.
hudOverlay.KeyCounter.Add(new KeyCounterKeyboard(Key.Space)); hudOverlay.KeyCounter.Add(new KeyCounterKeyboard(Key.Space));
hudOverlay.ComboCounter.Current.Value = 1; scoreProcessor.Combo.Value = 1;
return new Container return new Container
{ {

View File

@ -1,49 +1,36 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // 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. // See the LICENCE file in the repository root for full licence text.
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework; using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Testing; using osu.Framework.Testing;
using osu.Game.Rulesets; using osu.Game.Rulesets;
using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.Scoring;
using osu.Game.Screens.Play.HUD; using osu.Game.Screens.Play.HUD;
namespace osu.Game.Tests.Visual.Gameplay namespace osu.Game.Tests.Visual.Gameplay
{ {
public class TestSceneSkinnableAccuracyCounter : SkinnableTestScene public class TestSceneSkinnableAccuracyCounter : SkinnableTestScene
{ {
private IEnumerable<SkinnableAccuracyCounter> accuracyCounters => CreatedDrawables.OfType<SkinnableAccuracyCounter>();
protected override Ruleset CreateRulesetForSkinProvider() => new OsuRuleset(); protected override Ruleset CreateRulesetForSkinProvider() => new OsuRuleset();
[Cached]
private ScoreProcessor scoreProcessor = new ScoreProcessor();
[SetUpSteps] [SetUpSteps]
public void SetUpSteps() public void SetUpSteps()
{ {
AddStep("Create combo counters", () => SetContents(() => AddStep("Set initial accuracy", () => scoreProcessor.Accuracy.Value = 1);
{ AddStep("Create accuracy counters", () => SetContents(() => new SkinnableAccuracyCounter()));
var accuracyCounter = new SkinnableAccuracyCounter();
accuracyCounter.Current.Value = 1;
return accuracyCounter;
}));
} }
[Test] [Test]
public void TestChangingAccuracy() public void TestChangingAccuracy()
{ {
AddStep(@"Reset all", delegate AddStep(@"Reset all", () => scoreProcessor.Accuracy.Value = 1);
{
foreach (var s in accuracyCounters)
s.Current.Value = 1;
});
AddStep(@"Hit! :D", delegate AddStep(@"Miss :(", () => scoreProcessor.Accuracy.Value -= 0.023);
{
foreach (var s in accuracyCounters)
s.Current.Value -= 0.023f;
});
} }
} }
} }

View File

@ -14,6 +14,7 @@ using osu.Game.Configuration;
using osu.Game.Rulesets; using osu.Game.Rulesets;
using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.Scoring;
using osu.Game.Screens.Play; using osu.Game.Screens.Play;
using osuTK.Input; using osuTK.Input;
@ -23,6 +24,12 @@ namespace osu.Game.Tests.Visual.Gameplay
{ {
private HUDOverlay hudOverlay; private HUDOverlay hudOverlay;
[Cached]
private ScoreProcessor scoreProcessor = new ScoreProcessor();
[Cached(typeof(HealthProcessor))]
private HealthProcessor healthProcessor = new DrainingHealthProcessor(0);
private IEnumerable<HUDOverlay> hudOverlays => CreatedDrawables.OfType<HUDOverlay>(); private IEnumerable<HUDOverlay> hudOverlays => CreatedDrawables.OfType<HUDOverlay>();
// best way to check without exposing. // best way to check without exposing.
@ -37,17 +44,9 @@ namespace osu.Game.Tests.Visual.Gameplay
{ {
createNew(); createNew();
AddRepeatStep("increase combo", () => AddRepeatStep("increase combo", () => scoreProcessor.Combo.Value++, 10);
{
foreach (var hud in hudOverlays)
hud.ComboCounter.Current.Value++;
}, 10);
AddStep("reset combo", () => AddStep("reset combo", () => scoreProcessor.Combo.Value = 0);
{
foreach (var hud in hudOverlays)
hud.ComboCounter.Current.Value = 0;
});
} }
[Test] [Test]
@ -80,13 +79,11 @@ namespace osu.Game.Tests.Visual.Gameplay
{ {
SetContents(() => SetContents(() =>
{ {
hudOverlay = new HUDOverlay(null, null, null, Array.Empty<Mod>()); hudOverlay = new HUDOverlay(null, Array.Empty<Mod>());
// Add any key just to display the key counter visually. // Add any key just to display the key counter visually.
hudOverlay.KeyCounter.Add(new KeyCounterKeyboard(Key.Space)); hudOverlay.KeyCounter.Add(new KeyCounterKeyboard(Key.Space));
hudOverlay.ComboCounter.Current.Value = 1;
action?.Invoke(hudOverlay); action?.Invoke(hudOverlay);
return hudOverlay; return hudOverlay;

View File

@ -4,11 +4,14 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using NUnit.Framework; using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Testing; using osu.Framework.Testing;
using osu.Game.Rulesets; using osu.Game.Rulesets;
using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.Osu.Judgements; using osu.Game.Rulesets.Osu.Judgements;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Scoring;
using osu.Game.Screens.Play.HUD; using osu.Game.Screens.Play.HUD;
namespace osu.Game.Tests.Visual.Gameplay namespace osu.Game.Tests.Visual.Gameplay
@ -19,6 +22,9 @@ namespace osu.Game.Tests.Visual.Gameplay
protected override Ruleset CreateRulesetForSkinProvider() => new OsuRuleset(); protected override Ruleset CreateRulesetForSkinProvider() => new OsuRuleset();
[Cached(typeof(HealthProcessor))]
private HealthProcessor healthProcessor = new DrainingHealthProcessor(0);
[SetUpSteps] [SetUpSteps]
public void SetUpSteps() public void SetUpSteps()
{ {
@ -28,8 +34,7 @@ namespace osu.Game.Tests.Visual.Gameplay
}); });
AddStep(@"Reset all", delegate AddStep(@"Reset all", delegate
{ {
foreach (var s in healthDisplays) healthProcessor.Health.Value = 1;
s.Current.Value = 1;
}); });
} }
@ -38,23 +43,21 @@ namespace osu.Game.Tests.Visual.Gameplay
{ {
AddRepeatStep(@"decrease hp", delegate AddRepeatStep(@"decrease hp", delegate
{ {
foreach (var healthDisplay in healthDisplays) healthProcessor.Health.Value -= 0.08f;
healthDisplay.Current.Value -= 0.08f;
}, 10); }, 10);
AddRepeatStep(@"increase hp without flash", delegate AddRepeatStep(@"increase hp without flash", delegate
{ {
foreach (var healthDisplay in healthDisplays) healthProcessor.Health.Value += 0.1f;
healthDisplay.Current.Value += 0.1f;
}, 3); }, 3);
AddRepeatStep(@"increase hp with flash", delegate AddRepeatStep(@"increase hp with flash", delegate
{ {
foreach (var healthDisplay in healthDisplays) healthProcessor.Health.Value += 0.1f;
healthProcessor.ApplyResult(new JudgementResult(new HitCircle(), new OsuJudgement())
{ {
healthDisplay.Current.Value += 0.1f; Type = HitResult.Perfect
healthDisplay.Flash(new JudgementResult(null, new OsuJudgement())); });
}
}, 3); }, 3);
} }
} }

View File

@ -4,10 +4,12 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using NUnit.Framework; using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Testing; using osu.Framework.Testing;
using osu.Game.Rulesets; using osu.Game.Rulesets;
using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.Scoring;
using osu.Game.Screens.Play.HUD; using osu.Game.Screens.Play.HUD;
namespace osu.Game.Tests.Visual.Gameplay namespace osu.Game.Tests.Visual.Gameplay
@ -18,37 +20,27 @@ namespace osu.Game.Tests.Visual.Gameplay
protected override Ruleset CreateRulesetForSkinProvider() => new OsuRuleset(); protected override Ruleset CreateRulesetForSkinProvider() => new OsuRuleset();
[Cached]
private ScoreProcessor scoreProcessor = new ScoreProcessor();
[SetUpSteps] [SetUpSteps]
public void SetUpSteps() public void SetUpSteps()
{ {
AddStep("Create combo counters", () => SetContents(() => AddStep("Create score counters", () => SetContents(() => new SkinnableScoreCounter()));
{
var comboCounter = new SkinnableScoreCounter();
comboCounter.Current.Value = 1;
return comboCounter;
}));
} }
[Test] [Test]
public void TestScoreCounterIncrementing() public void TestScoreCounterIncrementing()
{ {
AddStep(@"Reset all", delegate AddStep(@"Reset all", () => scoreProcessor.TotalScore.Value = 0);
{
foreach (var s in scoreCounters)
s.Current.Value = 0;
});
AddStep(@"Hit! :D", delegate AddStep(@"Hit! :D", () => scoreProcessor.TotalScore.Value += 300);
{
foreach (var s in scoreCounters)
s.Current.Value += 300;
});
} }
[Test] [Test]
public void TestVeryLargeScore() public void TestVeryLargeScore()
{ {
AddStep("set large score", () => scoreCounters.ForEach(counter => counter.Current.Value = 1_000_000_000)); AddStep("set large score", () => scoreCounters.ForEach(counter => scoreProcessor.TotalScore.Value = 1_000_000_000));
} }
} }
} }

View File

@ -133,6 +133,16 @@ namespace osu.Game.Tests.Visual.Gameplay
AddUntilStep("storyboard ends", () => Player.GameplayClockContainer.GameplayClock.CurrentTime >= currentStoryboardDuration); AddUntilStep("storyboard ends", () => Player.GameplayClockContainer.GameplayClock.CurrentTime >= currentStoryboardDuration);
} }
[Test]
public void TestPerformExitNoOutro()
{
CreateTest(null);
AddStep("disable storyboard", () => LocalConfig.SetValue(OsuSetting.ShowStoryboard, false));
AddUntilStep("completion set by processor", () => Player.ScoreProcessor.HasCompleted.Value);
AddStep("exit via pause", () => Player.ExitViaPause());
AddAssert("player exited", () => Stack.CurrentScreen == null);
}
protected override bool AllowFail => true; protected override bool AllowFail => true;
protected override Ruleset CreatePlayerRuleset() => new OsuRuleset(); protected override Ruleset CreatePlayerRuleset() => new OsuRuleset();

View File

@ -2,7 +2,10 @@
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
using System; using System;
using System.Linq;
using NUnit.Framework; using NUnit.Framework;
using osu.Framework.Testing;
using osu.Game.Graphics.UserInterface;
using osu.Game.Online.API; using osu.Game.Online.API;
using osu.Game.Online.API.Requests; using osu.Game.Online.API.Requests;
using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.API.Requests.Responses;
@ -14,21 +17,34 @@ namespace osu.Game.Tests.Visual.Online
{ {
private DummyAPIAccess dummyAPI => (DummyAPIAccess)API; private DummyAPIAccess dummyAPI => (DummyAPIAccess)API;
private NewsOverlay news; private NewsOverlay overlay;
[SetUp] [SetUp]
public void SetUp() => Schedule(() => Child = news = new NewsOverlay()); public void SetUp() => Schedule(() => Child = overlay = new NewsOverlay());
[Test] [Test]
public void TestRequest() public void TestRequest()
{ {
setUpNewsResponse(responseExample); setUpNewsResponse(responseExample);
AddStep("Show", () => news.Show()); AddStep("Show", () => overlay.Show());
AddStep("Show article", () => news.ShowArticle("article")); AddStep("Show article", () => overlay.ShowArticle("article"));
} }
private void setUpNewsResponse(GetNewsResponse r) [Test]
=> AddStep("set up response", () => public void TestCursorRequest()
{
setUpNewsResponse(responseWithCursor, "Set up cursor response");
AddStep("Show", () => overlay.Show());
AddUntilStep("Show More button is visible", () => showMoreButton?.Alpha == 1);
setUpNewsResponse(responseWithNoCursor, "Set up no cursor response");
AddStep("Click Show More", () => showMoreButton?.Click());
AddUntilStep("Show More button is hidden", () => showMoreButton?.Alpha == 0);
}
private ShowMoreButton showMoreButton => overlay.ChildrenOfType<ShowMoreButton>().FirstOrDefault();
private void setUpNewsResponse(GetNewsResponse r, string testName = "Set up response")
=> AddStep(testName, () =>
{ {
dummyAPI.HandleRequest = request => dummyAPI.HandleRequest = request =>
{ {
@ -40,7 +56,7 @@ namespace osu.Game.Tests.Visual.Online
}; };
}); });
private GetNewsResponse responseExample => new GetNewsResponse private static GetNewsResponse responseExample => new GetNewsResponse
{ {
NewsPosts = new[] NewsPosts = new[]
{ {
@ -62,5 +78,37 @@ namespace osu.Game.Tests.Visual.Online
} }
} }
}; };
private static GetNewsResponse responseWithCursor => new GetNewsResponse
{
NewsPosts = new[]
{
new APINewsPost
{
Title = "This post has an image which starts with \"/\" and has many authors!",
Preview = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
Author = "someone, someone1, someone2, someone3, someone4",
FirstImage = "/help/wiki/shared/news/banners/monthly-beatmapping-contest.png",
PublishedAt = DateTimeOffset.Now
}
},
Cursor = new Cursor()
};
private static GetNewsResponse responseWithNoCursor => new GetNewsResponse
{
NewsPosts = new[]
{
new APINewsPost
{
Title = "This post has a full-url image! (HTML entity: &amp;)",
Preview = "boom (HTML entity: &amp;)",
Author = "user (HTML entity: &amp;)",
FirstImage = "https://assets.ppy.sh/artists/88/header.jpg",
PublishedAt = DateTimeOffset.Now
}
},
Cursor = null
};
} }
} }

View File

@ -108,7 +108,7 @@ namespace osu.Game.Tests.Visual.SongSelect
AddAssert("check version", () => infoWedge.Info.VersionLabel.Current.Value == $"{ruleset.ShortName}Version"); AddAssert("check version", () => infoWedge.Info.VersionLabel.Current.Value == $"{ruleset.ShortName}Version");
AddAssert("check title", () => infoWedge.Info.TitleLabel.Current.Value == $"{ruleset.ShortName}Source — {ruleset.ShortName}Title"); AddAssert("check title", () => infoWedge.Info.TitleLabel.Current.Value == $"{ruleset.ShortName}Source — {ruleset.ShortName}Title");
AddAssert("check artist", () => infoWedge.Info.ArtistLabel.Current.Value == $"{ruleset.ShortName}Artist"); AddAssert("check artist", () => infoWedge.Info.ArtistLabel.Current.Value == $"{ruleset.ShortName}Artist");
AddAssert("check author", () => infoWedge.Info.MapperContainer.Children.OfType<OsuSpriteText>().Any(s => s.Current.Value == $"{ruleset.ShortName}Author")); AddAssert("check author", () => infoWedge.Info.MapperContainer.ChildrenOfType<OsuSpriteText>().Any(s => s.Current.Value == $"{ruleset.ShortName}Author"));
} }
private void testInfoLabels(int expectedCount) private void testInfoLabels(int expectedCount)
@ -124,7 +124,7 @@ namespace osu.Game.Tests.Visual.SongSelect
AddAssert("check empty version", () => string.IsNullOrEmpty(infoWedge.Info.VersionLabel.Current.Value)); AddAssert("check empty version", () => string.IsNullOrEmpty(infoWedge.Info.VersionLabel.Current.Value));
AddAssert("check default title", () => infoWedge.Info.TitleLabel.Current.Value == Beatmap.Default.BeatmapInfo.Metadata.Title); AddAssert("check default title", () => infoWedge.Info.TitleLabel.Current.Value == Beatmap.Default.BeatmapInfo.Metadata.Title);
AddAssert("check default artist", () => infoWedge.Info.ArtistLabel.Current.Value == Beatmap.Default.BeatmapInfo.Metadata.Artist); AddAssert("check default artist", () => infoWedge.Info.ArtistLabel.Current.Value == Beatmap.Default.BeatmapInfo.Metadata.Artist);
AddAssert("check empty author", () => !infoWedge.Info.MapperContainer.Children.Any()); AddAssert("check empty author", () => !infoWedge.Info.MapperContainer.ChildrenOfType<OsuSpriteText>().Any());
AddAssert("check no info labels", () => !infoWedge.Info.ChildrenOfType<BeatmapInfoWedge.WedgeInfoText.InfoLabel>().Any()); AddAssert("check no info labels", () => !infoWedge.Info.ChildrenOfType<BeatmapInfoWedge.WedgeInfoText.InfoLabel>().Any());
} }

View File

@ -304,6 +304,7 @@ namespace osu.Game.Tests.Visual.SongSelect
AddStep(@"Sort by BPM", () => config.SetValue(OsuSetting.SongSelectSortingMode, SortMode.BPM)); AddStep(@"Sort by BPM", () => config.SetValue(OsuSetting.SongSelectSortingMode, SortMode.BPM));
AddStep(@"Sort by Length", () => config.SetValue(OsuSetting.SongSelectSortingMode, SortMode.Length)); AddStep(@"Sort by Length", () => config.SetValue(OsuSetting.SongSelectSortingMode, SortMode.Length));
AddStep(@"Sort by Difficulty", () => config.SetValue(OsuSetting.SongSelectSortingMode, SortMode.Difficulty)); AddStep(@"Sort by Difficulty", () => config.SetValue(OsuSetting.SongSelectSortingMode, SortMode.Difficulty));
AddStep(@"Sort by Source", () => config.SetValue(OsuSetting.SongSelectSortingMode, SortMode.Source));
} }
[Test] [Test]

View File

@ -4,11 +4,10 @@
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Game.Graphics.Sprites; using osu.Game.Graphics.Sprites;
using osu.Game.Screens.Play.HUD;
namespace osu.Game.Graphics.UserInterface namespace osu.Game.Graphics.UserInterface
{ {
public abstract class ScoreCounter : RollingCounter<double>, IScoreCounter public abstract class ScoreCounter : RollingCounter<double>
{ {
protected override double RollingDuration => 1000; protected override double RollingDuration => 1000;
protected override Easing RollingEasing => Easing.Out; protected override Easing RollingEasing => Easing.Out;

View File

@ -23,6 +23,8 @@ namespace osu.Game.Online.API.Requests
return req; return req;
} }
protected override string FileExtension => ".osz";
protected override string Target => $@"beatmapsets/{Model.OnlineBeatmapSetID}/download{(noVideo ? "?noVideo=1" : "")}"; protected override string Target => $@"beatmapsets/{Model.OnlineBeatmapSetID}/download{(noVideo ? "?noVideo=1" : "")}";
} }
} }

View File

@ -13,6 +13,8 @@ using osuTK.Graphics;
using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Users;
using osu.Game.Graphics.Containers;
namespace osu.Game.Overlays.BeatmapSet namespace osu.Game.Overlays.BeatmapSet
{ {
@ -50,7 +52,7 @@ namespace osu.Game.Overlays.BeatmapSet
fields.Children = new Drawable[] fields.Children = new Drawable[]
{ {
new Field("mapped by", BeatmapSet.Metadata.Author.Username, OsuFont.GetFont(weight: FontWeight.Regular, italics: true)), new Field("mapped by", BeatmapSet.Metadata.Author, OsuFont.GetFont(weight: FontWeight.Regular, italics: true)),
new Field("submitted", online.Submitted, OsuFont.GetFont(weight: FontWeight.Bold)) new Field("submitted", online.Submitted, OsuFont.GetFont(weight: FontWeight.Bold))
{ {
Margin = new MarginPadding { Top = 5 }, Margin = new MarginPadding { Top = 5 },
@ -146,6 +148,25 @@ namespace osu.Game.Overlays.BeatmapSet
} }
}; };
} }
public Field(string first, User second, FontUsage secondFont)
{
AutoSizeAxes = Axes.Both;
Direction = FillDirection.Horizontal;
Children = new[]
{
new LinkFlowContainer(s =>
{
s.Font = OsuFont.GetFont(size: 11);
}).With(d =>
{
d.AutoSizeAxes = Axes.Both;
d.AddText($"{first} ");
d.AddUserLink(second, s => s.Font = secondFont.With(size: 11));
}),
};
}
} }
} }
} }

View File

@ -100,7 +100,7 @@ namespace osu.Game.Overlays.News.Displays
{ {
content.Add(loaded); content.Add(loaded);
showMore.IsLoading = false; showMore.IsLoading = false;
showMore.Show(); showMore.Alpha = lastCursor == null ? 0 : 1;
}, (cancellationToken = new CancellationTokenSource()).Token); }, (cancellationToken = new CancellationTokenSource()).Token);
} }

View File

@ -204,7 +204,7 @@ namespace osu.Game.Overlays.Volume
{ {
displayVolume = value; displayVolume = value;
if (displayVolume > 0.99f) if (displayVolume >= 0.995f)
{ {
text.Text = "MAX"; text.Text = "MAX";
maxGlow.EffectColour = meterColour.Opacity(2f); maxGlow.EffectColour = meterColour.Opacity(2f);

View File

@ -1,40 +1,36 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // 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. // See the LICENCE file in the repository root for full licence text.
using System.Collections.Generic;
using System.Linq;
using JetBrains.Annotations;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Replays; using osu.Game.Replays;
using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects;
namespace osu.Game.Rulesets.Replays namespace osu.Game.Rulesets.Replays
{ {
public abstract class AutoGenerator : IAutoGenerator public abstract class AutoGenerator
{ {
/// <summary> /// <summary>
/// Creates the auto replay and returns it. /// The default duration of a key press in milliseconds.
/// Every subclass of OsuAutoGeneratorBase should implement this!
/// </summary> /// </summary>
public abstract Replay Generate(); public const double KEY_UP_DELAY = 50;
#region Parameters
/// <summary> /// <summary>
/// The beatmap we're making. /// The beatmap the autoplay is generated for.
/// </summary> /// </summary>
protected IBeatmap Beatmap; protected IBeatmap Beatmap { get; }
#endregion
protected AutoGenerator(IBeatmap beatmap) protected AutoGenerator(IBeatmap beatmap)
{ {
Beatmap = beatmap; Beatmap = beatmap;
} }
#region Constants /// <summary>
/// Generate the replay of the autoplay.
// Shared amongst all modes /// </summary>
public const double KEY_UP_DELAY = 50; public abstract Replay Generate();
#endregion
protected virtual HitObject GetNextObject(int currentIndex) protected virtual HitObject GetNextObject(int currentIndex)
{ {
@ -44,4 +40,37 @@ namespace osu.Game.Rulesets.Replays
return Beatmap.HitObjects[currentIndex + 1]; return Beatmap.HitObjects[currentIndex + 1];
} }
} }
public abstract class AutoGenerator<TFrame> : AutoGenerator
where TFrame : ReplayFrame
{
/// <summary>
/// The replay frames of the autoplay.
/// </summary>
protected readonly List<TFrame> Frames = new List<TFrame>();
[CanBeNull]
protected TFrame LastFrame => Frames.Count == 0 ? null : Frames[^1];
protected AutoGenerator(IBeatmap beatmap)
: base(beatmap)
{
}
public sealed override Replay Generate()
{
Frames.Clear();
GenerateFrames();
return new Replay
{
Frames = Frames.OrderBy(frame => frame.Time).Cast<ReplayFrame>().ToList()
};
}
/// <summary>
/// Generate the replay frames of the autoplay and populate <see cref="Frames"/>.
/// </summary>
protected abstract void GenerateFrames();
}
} }

View File

@ -1,12 +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.Game.Replays;
namespace osu.Game.Rulesets.Replays
{
public interface IAutoGenerator
{
Replay Generate();
}
}

View File

@ -17,7 +17,6 @@ using osu.Framework.Input.Bindings;
using osu.Framework.Input.Events; using osu.Framework.Input.Events;
using osu.Framework.Logging; using osu.Framework.Logging;
using osu.Framework.Screens; using osu.Framework.Screens;
using osu.Framework.Timing;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Configuration; using osu.Game.Configuration;
using osu.Game.Graphics; using osu.Game.Graphics;
@ -144,8 +143,7 @@ namespace osu.Game.Screens.Edit
// Todo: should probably be done at a DrawableRuleset level to share logic with Player. // Todo: should probably be done at a DrawableRuleset level to share logic with Player.
clock = new EditorClock(playableBeatmap, beatDivisor) { IsCoupled = false }; clock = new EditorClock(playableBeatmap, beatDivisor) { IsCoupled = false };
clock.ChangeSource(loadableBeatmap.Track);
UpdateClockSource();
dependencies.CacheAs(clock); dependencies.CacheAs(clock);
AddInternal(clock); AddInternal(clock);
@ -308,11 +306,7 @@ namespace osu.Game.Screens.Edit
/// <summary> /// <summary>
/// If the beatmap's track has changed, this method must be called to keep the editor in a valid state. /// If the beatmap's track has changed, this method must be called to keep the editor in a valid state.
/// </summary> /// </summary>
public void UpdateClockSource() public void UpdateClockSource() => clock.ChangeSource(Beatmap.Value.Track);
{
var sourceClock = (IAdjustableClock)Beatmap.Value.Track ?? new StopwatchClock();
clock.ChangeSource(sourceClock);
}
protected void Save() protected void Save()
{ {
@ -583,7 +577,7 @@ namespace osu.Game.Screens.Edit
private void resetTrack(bool seekToStart = false) private void resetTrack(bool seekToStart = false)
{ {
Beatmap.Value.Track?.Stop(); Beatmap.Value.Track.Stop();
if (seekToStart) if (seekToStart)
{ {

View File

@ -4,12 +4,11 @@
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Graphics.UserInterface;
using osuTK; using osuTK;
namespace osu.Game.Screens.Play.HUD namespace osu.Game.Screens.Play.HUD
{ {
public class DefaultAccuracyCounter : PercentageCounter, IAccuracyCounter, ISkinnableComponent public class DefaultAccuracyCounter : GameplayAccuracyCounter, ISkinnableComponent
{ {
private readonly Vector2 offset = new Vector2(-20, 5); private readonly Vector2 offset = new Vector2(-20, 5);

View File

@ -7,11 +7,12 @@ using osu.Framework.Graphics;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Graphics.Sprites; using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterface;
using osu.Game.Rulesets.Scoring;
using osuTK; using osuTK;
namespace osu.Game.Screens.Play.HUD namespace osu.Game.Screens.Play.HUD
{ {
public class DefaultComboCounter : RollingCounter<int>, IComboCounter, ISkinnableComponent public class DefaultComboCounter : RollingCounter<int>, ISkinnableComponent
{ {
private readonly Vector2 offset = new Vector2(20, 5); private readonly Vector2 offset = new Vector2(20, 5);
@ -24,7 +25,11 @@ namespace osu.Game.Screens.Play.HUD
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(OsuColour colours) => Colour = colours.BlueLighter; private void load(OsuColour colours, ScoreProcessor scoreProcessor)
{
Colour = colours.BlueLighter;
Current.BindTo(scoreProcessor.Combo);
}
protected override void Update() protected override void Update()
{ {

View File

@ -107,7 +107,7 @@ namespace osu.Game.Screens.Play.HUD
GlowColour = colours.BlueDarker; GlowColour = colours.BlueDarker;
} }
public override void Flash(JudgementResult result) => Scheduler.AddOnce(flash); protected override void Flash(JudgementResult result) => Scheduler.AddOnce(flash);
private void flash() private void flash()
{ {

View File

@ -4,11 +4,10 @@
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Graphics.UserInterface;
namespace osu.Game.Screens.Play.HUD namespace osu.Game.Screens.Play.HUD
{ {
public class DefaultScoreCounter : ScoreCounter, ISkinnableComponent public class DefaultScoreCounter : GameplayScoreCounter, ISkinnableComponent
{ {
public DefaultScoreCounter() public DefaultScoreCounter()
: base(6) : base(6)

View File

@ -39,7 +39,6 @@ namespace osu.Game.Screens.Play.HUD
private readonly Container boxes; private readonly Container boxes;
private Bindable<bool> fadePlayfieldWhenHealthLow; private Bindable<bool> fadePlayfieldWhenHealthLow;
private HealthProcessor healthProcessor;
public FailingLayer() public FailingLayer()
{ {
@ -88,18 +87,10 @@ namespace osu.Game.Screens.Play.HUD
updateState(); updateState();
} }
public override void BindHealthProcessor(HealthProcessor processor)
{
base.BindHealthProcessor(processor);
healthProcessor = processor;
updateState();
}
private void updateState() private void updateState()
{ {
// Don't display ever if the ruleset is not using a draining health display. // Don't display ever if the ruleset is not using a draining health display.
var showLayer = healthProcessor is DrainingHealthProcessor && fadePlayfieldWhenHealthLow.Value && ShowHealth.Value; var showLayer = HealthProcessor is DrainingHealthProcessor && fadePlayfieldWhenHealthLow.Value && ShowHealth.Value;
this.FadeTo(showLayer ? 1 : 0, fade_time, Easing.OutQuint); this.FadeTo(showLayer ? 1 : 0, fade_time, Easing.OutQuint);
} }

View File

@ -0,0 +1,18 @@
// 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.Game.Graphics.UserInterface;
using osu.Game.Rulesets.Scoring;
namespace osu.Game.Screens.Play.HUD
{
public abstract class GameplayAccuracyCounter : PercentageCounter
{
[BackgroundDependencyLoader]
private void load(ScoreProcessor scoreProcessor)
{
Current.BindTo(scoreProcessor.Accuracy);
}
}
}

View File

@ -0,0 +1,46 @@
// 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 osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Game.Configuration;
using osu.Game.Graphics.UserInterface;
using osu.Game.Rulesets.Scoring;
namespace osu.Game.Screens.Play.HUD
{
public abstract class GameplayScoreCounter : ScoreCounter
{
private Bindable<ScoringMode> scoreDisplayMode;
protected GameplayScoreCounter(int leading = 0, bool useCommaSeparator = false)
: base(leading, useCommaSeparator)
{
}
[BackgroundDependencyLoader]
private void load(OsuConfigManager config, ScoreProcessor scoreProcessor)
{
scoreDisplayMode = config.GetBindable<ScoringMode>(OsuSetting.ScoreDisplayMode);
scoreDisplayMode.BindValueChanged(scoreMode =>
{
switch (scoreMode.NewValue)
{
case ScoringMode.Standardised:
RequiredDisplayDigits.Value = 6;
break;
case ScoringMode.Classic:
RequiredDisplayDigits.Value = 8;
break;
default:
throw new ArgumentOutOfRangeException(nameof(scoreMode));
}
}, true);
Current.BindTo(scoreProcessor.TotalScore);
}
}
}

View File

@ -1,6 +1,7 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // 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. // See the LICENCE file in the repository root for full licence text.
using osu.Framework.Allocation;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Judgements;
@ -11,26 +12,43 @@ namespace osu.Game.Screens.Play.HUD
{ {
/// <summary> /// <summary>
/// A container for components displaying the current player health. /// A container for components displaying the current player health.
/// Gets bound automatically to the <see cref="HealthProcessor"/> when inserted to <see cref="DrawableRuleset.Overlays"/> hierarchy. /// Gets bound automatically to the <see cref="Rulesets.Scoring.HealthProcessor"/> when inserted to <see cref="DrawableRuleset.Overlays"/> hierarchy.
/// </summary> /// </summary>
public abstract class HealthDisplay : Container, IHealthDisplay public abstract class HealthDisplay : Container
{ {
[Resolved]
protected HealthProcessor HealthProcessor { get; private set; }
public Bindable<double> Current { get; } = new BindableDouble(1) public Bindable<double> Current { get; } = new BindableDouble(1)
{ {
MinValue = 0, MinValue = 0,
MaxValue = 1 MaxValue = 1
}; };
public virtual void Flash(JudgementResult result) protected virtual void Flash(JudgementResult result)
{ {
} }
/// <summary> [BackgroundDependencyLoader]
/// Bind the tracked fields of <see cref="HealthProcessor"/> to this health display. private void load()
/// </summary>
public virtual void BindHealthProcessor(HealthProcessor processor)
{ {
Current.BindTo(processor.Health); Current.BindTo(HealthProcessor.Health);
HealthProcessor.NewJudgement += onNewJudgement;
}
private void onNewJudgement(JudgementResult judgement)
{
if (judgement.IsHit && judgement.Type != HitResult.IgnoreHit)
Flash(judgement);
}
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
if (HealthProcessor != null)
HealthProcessor.NewJudgement -= onNewJudgement;
} }
} }
} }

View File

@ -7,7 +7,6 @@ using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Game.Configuration; using osu.Game.Configuration;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Scoring;
using osu.Game.Screens.Play.HUD.HitErrorMeters; using osu.Game.Screens.Play.HUD.HitErrorMeters;
@ -22,17 +21,11 @@ namespace osu.Game.Screens.Play.HUD
private readonly HitWindows hitWindows; private readonly HitWindows hitWindows;
private readonly ScoreProcessor processor; public HitErrorDisplay(HitWindows hitWindows)
public HitErrorDisplay(ScoreProcessor processor, HitWindows hitWindows)
{ {
this.processor = processor;
this.hitWindows = hitWindows; this.hitWindows = hitWindows;
RelativeSizeAxes = Axes.Both; RelativeSizeAxes = Axes.Both;
if (processor != null)
processor.NewJudgement += onNewJudgement;
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
@ -47,15 +40,6 @@ namespace osu.Game.Screens.Play.HUD
type.BindValueChanged(typeChanged, true); type.BindValueChanged(typeChanged, true);
} }
private void onNewJudgement(JudgementResult result)
{
if (result.HitObject.HitWindows.WindowFor(HitResult.Miss) == 0)
return;
foreach (var c in Children)
c.OnNewJudgement(result);
}
private void typeChanged(ValueChangedEvent<ScoreMeterType> type) private void typeChanged(ValueChangedEvent<ScoreMeterType> type)
{ {
Children.ForEach(c => c.FadeOut(fade_duration, Easing.OutQuint)); Children.ForEach(c => c.FadeOut(fade_duration, Easing.OutQuint));
@ -139,13 +123,5 @@ namespace osu.Game.Screens.Play.HUD
Add(display); Add(display);
display.FadeInFromZero(fade_duration, Easing.OutQuint); display.FadeInFromZero(fade_duration, Easing.OutQuint);
} }
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
if (processor != null)
processor.NewJudgement -= onNewJudgement;
}
} }
} }

View File

@ -214,7 +214,7 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters
private const int max_concurrent_judgements = 50; private const int max_concurrent_judgements = 50;
public override void OnNewJudgement(JudgementResult judgement) protected override void OnNewJudgement(JudgementResult judgement)
{ {
if (!judgement.IsHit) if (!judgement.IsHit)
return; return;

View File

@ -26,7 +26,7 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters
InternalChild = judgementsFlow = new JudgementFlow(); InternalChild = judgementsFlow = new JudgementFlow();
} }
public override void OnNewJudgement(JudgementResult judgement) => judgementsFlow.Push(GetColourForHitResult(HitWindows.ResultFor(judgement.TimeOffset))); protected override void OnNewJudgement(JudgementResult judgement) => judgementsFlow.Push(GetColourForHitResult(HitWindows.ResultFor(judgement.TimeOffset)));
private class JudgementFlow : FillFlowContainer<HitErrorCircle> private class JudgementFlow : FillFlowContainer<HitErrorCircle>
{ {

View File

@ -14,6 +14,9 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters
{ {
protected readonly HitWindows HitWindows; protected readonly HitWindows HitWindows;
[Resolved]
private ScoreProcessor processor { get; set; }
[Resolved] [Resolved]
private OsuColour colours { get; set; } private OsuColour colours { get; set; }
@ -22,7 +25,22 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters
HitWindows = hitWindows; HitWindows = hitWindows;
} }
public abstract void OnNewJudgement(JudgementResult judgement); protected override void LoadComplete()
{
base.LoadComplete();
processor.NewJudgement += onNewJudgement;
}
private void onNewJudgement(JudgementResult result)
{
if (result.HitObject.HitWindows?.WindowFor(HitResult.Miss) == 0)
return;
OnNewJudgement(result);
}
protected abstract void OnNewJudgement(JudgementResult judgement);
protected Color4 GetColourForHitResult(HitResult result) protected Color4 GetColourForHitResult(HitResult result)
{ {
@ -47,5 +65,13 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters
return colours.BlueLight; return colours.BlueLight;
} }
} }
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
if (processor != null)
processor.NewJudgement -= onNewJudgement;
}
} }
} }

View File

@ -1,19 +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.Bindables;
using osu.Framework.Graphics;
namespace osu.Game.Screens.Play.HUD
{
/// <summary>
/// An interface providing a set of methods to update a accuracy counter.
/// </summary>
public interface IAccuracyCounter : IDrawable
{
/// <summary>
/// The current accuracy to be displayed.
/// </summary>
Bindable<double> Current { get; }
}
}

View File

@ -1,19 +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.Bindables;
using osu.Framework.Graphics;
namespace osu.Game.Screens.Play.HUD
{
/// <summary>
/// An interface providing a set of methods to update a combo counter.
/// </summary>
public interface IComboCounter : IDrawable
{
/// <summary>
/// The current combo to be displayed.
/// </summary>
Bindable<int> Current { get; }
}
}

View File

@ -1,26 +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.Bindables;
using osu.Framework.Graphics;
using osu.Game.Rulesets.Judgements;
namespace osu.Game.Screens.Play.HUD
{
/// <summary>
/// An interface providing a set of methods to update a health display.
/// </summary>
public interface IHealthDisplay : IDrawable
{
/// <summary>
/// The current health to be displayed.
/// </summary>
Bindable<double> Current { get; }
/// <summary>
/// Flash the display for a specified result type.
/// </summary>
/// <param name="result">The result type.</param>
void Flash(JudgementResult result);
}
}

View File

@ -1,25 +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.Bindables;
using osu.Framework.Graphics;
namespace osu.Game.Screens.Play.HUD
{
/// <summary>
/// An interface providing a set of methods to update a score counter.
/// </summary>
public interface IScoreCounter : IDrawable
{
/// <summary>
/// The current score to be displayed.
/// </summary>
Bindable<double> Current { get; }
/// <summary>
/// The number of digits required to display most sane scores.
/// This may be exceeded in very rare cases, but is useful to pad or space the display to avoid it jumping around.
/// </summary>
Bindable<int> RequiredDisplayDigits { get; }
}
}

View File

@ -6,6 +6,7 @@ using osu.Framework.Bindables;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Game.Rulesets.Scoring;
using osu.Game.Skinning; using osu.Game.Skinning;
using osuTK; using osuTK;
@ -14,7 +15,7 @@ namespace osu.Game.Screens.Play.HUD
/// <summary> /// <summary>
/// Uses the 'x' symbol and has a pop-out effect while rolling over. /// Uses the 'x' symbol and has a pop-out effect while rolling over.
/// </summary> /// </summary>
public class LegacyComboCounter : CompositeDrawable, IComboCounter, ISkinnableComponent public class LegacyComboCounter : CompositeDrawable, ISkinnableComponent
{ {
public Bindable<int> Current { get; } = new BindableInt { MinValue = 0, }; public Bindable<int> Current { get; } = new BindableInt { MinValue = 0, };
@ -79,7 +80,7 @@ namespace osu.Game.Screens.Play.HUD
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load() private void load(ScoreProcessor scoreProcessor)
{ {
InternalChildren = new[] InternalChildren = new[]
{ {
@ -95,7 +96,7 @@ namespace osu.Game.Screens.Play.HUD
}, },
}; };
Current.ValueChanged += combo => updateCount(combo.NewValue == 0); Current.BindTo(scoreProcessor.Combo);
} }
protected override void LoadComplete() protected override void LoadComplete()
@ -109,7 +110,7 @@ namespace osu.Game.Screens.Play.HUD
popOutCount.Origin = Origin; popOutCount.Origin = Origin;
popOutCount.Anchor = Anchor; popOutCount.Anchor = Anchor;
updateCount(false); Current.BindValueChanged(combo => updateCount(combo.NewValue == 0), true);
} }
private void updateCount(bool rolling) private void updateCount(bool rolling)

View File

@ -1,29 +1,16 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // 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. // See the LICENCE file in the repository root for full licence text.
using osu.Framework.Bindables;
using osu.Game.Skinning; using osu.Game.Skinning;
namespace osu.Game.Screens.Play.HUD namespace osu.Game.Screens.Play.HUD
{ {
public class SkinnableAccuracyCounter : SkinnableDrawable, IAccuracyCounter public class SkinnableAccuracyCounter : SkinnableDrawable
{ {
public Bindable<double> Current { get; } = new Bindable<double>();
public SkinnableAccuracyCounter() public SkinnableAccuracyCounter()
: base(new HUDSkinComponent(HUDSkinComponents.AccuracyCounter), _ => new DefaultAccuracyCounter()) : base(new HUDSkinComponent(HUDSkinComponents.AccuracyCounter), _ => new DefaultAccuracyCounter())
{ {
CentreComponent = false; CentreComponent = false;
} }
private IAccuracyCounter skinnedCounter;
protected override void SkinChanged(ISkinSource skin, bool allowFallback)
{
base.SkinChanged(skin, allowFallback);
skinnedCounter = Drawable as IAccuracyCounter;
skinnedCounter?.Current.BindTo(Current);
}
} }
} }

View File

@ -1,29 +1,16 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // 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. // See the LICENCE file in the repository root for full licence text.
using osu.Framework.Bindables;
using osu.Game.Skinning; using osu.Game.Skinning;
namespace osu.Game.Screens.Play.HUD namespace osu.Game.Screens.Play.HUD
{ {
public class SkinnableComboCounter : SkinnableDrawable, IComboCounter public class SkinnableComboCounter : SkinnableDrawable
{ {
public Bindable<int> Current { get; } = new Bindable<int>();
public SkinnableComboCounter() public SkinnableComboCounter()
: base(new HUDSkinComponent(HUDSkinComponents.ComboCounter), skinComponent => new DefaultComboCounter()) : base(new HUDSkinComponent(HUDSkinComponents.ComboCounter), skinComponent => new DefaultComboCounter())
{ {
CentreComponent = false; CentreComponent = false;
} }
private IComboCounter skinnedCounter;
protected override void SkinChanged(ISkinSource skin, bool allowFallback)
{
base.SkinChanged(skin, allowFallback);
skinnedCounter = Drawable as IComboCounter;
skinnedCounter?.Current.BindTo(Current);
}
} }
} }

View File

@ -1,50 +1,16 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // 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. // See the LICENCE file in the repository root for full licence text.
using System;
using osu.Framework.Bindables;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Scoring;
using osu.Game.Skinning; using osu.Game.Skinning;
namespace osu.Game.Screens.Play.HUD namespace osu.Game.Screens.Play.HUD
{ {
public class SkinnableHealthDisplay : SkinnableDrawable, IHealthDisplay public class SkinnableHealthDisplay : SkinnableDrawable
{ {
public Bindable<double> Current { get; } = new BindableDouble(1)
{
MinValue = 0,
MaxValue = 1
};
public void Flash(JudgementResult result) => skinnedCounter?.Flash(result);
private HealthProcessor processor;
public void BindHealthProcessor(HealthProcessor processor)
{
if (this.processor != null)
throw new InvalidOperationException("Can't bind to a processor more than once");
this.processor = processor;
Current.BindTo(processor.Health);
}
public SkinnableHealthDisplay() public SkinnableHealthDisplay()
: base(new HUDSkinComponent(HUDSkinComponents.HealthDisplay), _ => new DefaultHealthDisplay()) : base(new HUDSkinComponent(HUDSkinComponents.HealthDisplay), _ => new DefaultHealthDisplay())
{ {
CentreComponent = false; CentreComponent = false;
} }
private IHealthDisplay skinnedCounter;
protected override void SkinChanged(ISkinSource skin, bool allowFallback)
{
base.SkinChanged(skin, allowFallback);
skinnedCounter = Drawable as IHealthDisplay;
skinnedCounter?.Current.BindTo(Current);
}
} }
} }

View File

@ -1,61 +1,16 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // 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. // See the LICENCE file in the repository root for full licence text.
using System;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Game.Configuration;
using osu.Game.Rulesets.Scoring;
using osu.Game.Skinning; using osu.Game.Skinning;
namespace osu.Game.Screens.Play.HUD namespace osu.Game.Screens.Play.HUD
{ {
public class SkinnableScoreCounter : SkinnableDrawable, IScoreCounter public class SkinnableScoreCounter : SkinnableDrawable
{ {
public Bindable<double> Current { get; } = new Bindable<double>();
private Bindable<ScoringMode> scoreDisplayMode;
public Bindable<int> RequiredDisplayDigits { get; } = new Bindable<int>();
public SkinnableScoreCounter() public SkinnableScoreCounter()
: base(new HUDSkinComponent(HUDSkinComponents.ScoreCounter), _ => new DefaultScoreCounter()) : base(new HUDSkinComponent(HUDSkinComponents.ScoreCounter), _ => new DefaultScoreCounter())
{ {
CentreComponent = false; CentreComponent = false;
} }
[BackgroundDependencyLoader]
private void load(OsuConfigManager config)
{
scoreDisplayMode = config.GetBindable<ScoringMode>(OsuSetting.ScoreDisplayMode);
scoreDisplayMode.BindValueChanged(scoreMode =>
{
switch (scoreMode.NewValue)
{
case ScoringMode.Standardised:
RequiredDisplayDigits.Value = 6;
break;
case ScoringMode.Classic:
RequiredDisplayDigits.Value = 8;
break;
default:
throw new ArgumentOutOfRangeException(nameof(scoreMode));
}
}, true);
}
private IScoreCounter skinnedCounter;
protected override void SkinChanged(ISkinSource skin, bool allowFallback)
{
base.SkinChanged(skin, allowFallback);
skinnedCounter = Drawable as IScoreCounter;
skinnedCounter?.Current.BindTo(Current);
skinnedCounter?.RequiredDisplayDigits.BindTo(RequiredDisplayDigits);
}
} }
} }

View File

@ -14,7 +14,6 @@ using osu.Game.Input.Bindings;
using osu.Game.Overlays; using osu.Game.Overlays;
using osu.Game.Overlays.Notifications; using osu.Game.Overlays.Notifications;
using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.UI; using osu.Game.Rulesets.UI;
using osu.Game.Screens.Play.HUD; using osu.Game.Screens.Play.HUD;
using osuTK; using osuTK;
@ -34,21 +33,16 @@ namespace osu.Game.Screens.Play
public float TopScoringElementsHeight { get; private set; } public float TopScoringElementsHeight { get; private set; }
public readonly KeyCounterDisplay KeyCounter; public readonly KeyCounterDisplay KeyCounter;
public readonly SkinnableComboCounter ComboCounter;
public readonly SkinnableScoreCounter ScoreCounter; public readonly SkinnableScoreCounter ScoreCounter;
public readonly SkinnableAccuracyCounter AccuracyCounter; public readonly SkinnableAccuracyCounter AccuracyCounter;
public readonly SkinnableHealthDisplay HealthDisplay; public readonly SkinnableHealthDisplay HealthDisplay;
public readonly SongProgress Progress; public readonly SongProgress Progress;
public readonly ModDisplay ModDisplay; public readonly ModDisplay ModDisplay;
public readonly HitErrorDisplay HitErrorDisplay;
public readonly HoldForMenuButton HoldToQuit; public readonly HoldForMenuButton HoldToQuit;
public readonly PlayerSettingsOverlay PlayerSettingsOverlay; public readonly PlayerSettingsOverlay PlayerSettingsOverlay;
public readonly FailingLayer FailingLayer;
public Bindable<bool> ShowHealthbar = new Bindable<bool>(true); public Bindable<bool> ShowHealthbar = new Bindable<bool>(true);
private readonly ScoreProcessor scoreProcessor;
private readonly HealthProcessor healthProcessor;
private readonly DrawableRuleset drawableRuleset; private readonly DrawableRuleset drawableRuleset;
private readonly IReadOnlyList<Mod> mods; private readonly IReadOnlyList<Mod> mods;
@ -76,10 +70,8 @@ namespace osu.Game.Screens.Play
private IEnumerable<Drawable> hideTargets => new Drawable[] { visibilityContainer, KeyCounter, topRightElements }; private IEnumerable<Drawable> hideTargets => new Drawable[] { visibilityContainer, KeyCounter, topRightElements };
public HUDOverlay(ScoreProcessor scoreProcessor, HealthProcessor healthProcessor, DrawableRuleset drawableRuleset, IReadOnlyList<Mod> mods) public HUDOverlay(DrawableRuleset drawableRuleset, IReadOnlyList<Mod> mods)
{ {
this.scoreProcessor = scoreProcessor;
this.healthProcessor = healthProcessor;
this.drawableRuleset = drawableRuleset; this.drawableRuleset = drawableRuleset;
this.mods = mods; this.mods = mods;
@ -87,7 +79,7 @@ namespace osu.Game.Screens.Play
Children = new Drawable[] Children = new Drawable[]
{ {
FailingLayer = CreateFailingLayer(), CreateFailingLayer(),
visibilityContainer = new Container visibilityContainer = new Container
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
@ -106,8 +98,8 @@ namespace osu.Game.Screens.Play
HealthDisplay = CreateHealthDisplay(), HealthDisplay = CreateHealthDisplay(),
AccuracyCounter = CreateAccuracyCounter(), AccuracyCounter = CreateAccuracyCounter(),
ScoreCounter = CreateScoreCounter(), ScoreCounter = CreateScoreCounter(),
ComboCounter = CreateComboCounter(), CreateComboCounter(),
HitErrorDisplay = CreateHitErrorDisplayOverlay(), CreateHitErrorDisplayOverlay(),
} }
}, },
}, },
@ -159,12 +151,6 @@ namespace osu.Game.Screens.Play
[BackgroundDependencyLoader(true)] [BackgroundDependencyLoader(true)]
private void load(OsuConfigManager config, NotificationOverlay notificationOverlay) private void load(OsuConfigManager config, NotificationOverlay notificationOverlay)
{ {
if (scoreProcessor != null)
BindScoreProcessor(scoreProcessor);
if (healthProcessor != null)
BindHealthProcessor(healthProcessor);
if (drawableRuleset != null) if (drawableRuleset != null)
{ {
BindDrawableRuleset(drawableRuleset); BindDrawableRuleset(drawableRuleset);
@ -276,13 +262,13 @@ namespace osu.Game.Screens.Play
Progress.BindDrawableRuleset(drawableRuleset); Progress.BindDrawableRuleset(drawableRuleset);
} }
protected virtual SkinnableAccuracyCounter CreateAccuracyCounter() => new SkinnableAccuracyCounter(); protected SkinnableAccuracyCounter CreateAccuracyCounter() => new SkinnableAccuracyCounter();
protected virtual SkinnableScoreCounter CreateScoreCounter() => new SkinnableScoreCounter(); protected SkinnableScoreCounter CreateScoreCounter() => new SkinnableScoreCounter();
protected virtual SkinnableComboCounter CreateComboCounter() => new SkinnableComboCounter(); protected SkinnableComboCounter CreateComboCounter() => new SkinnableComboCounter();
protected virtual SkinnableHealthDisplay CreateHealthDisplay() => new SkinnableHealthDisplay(); protected SkinnableHealthDisplay CreateHealthDisplay() => new SkinnableHealthDisplay();
protected virtual FailingLayer CreateFailingLayer() => new FailingLayer protected virtual FailingLayer CreateFailingLayer() => new FailingLayer
{ {
@ -315,32 +301,10 @@ namespace osu.Game.Screens.Play
AutoSizeAxes = Axes.Both, AutoSizeAxes = Axes.Both,
}; };
protected virtual HitErrorDisplay CreateHitErrorDisplayOverlay() => new HitErrorDisplay(scoreProcessor, drawableRuleset?.FirstAvailableHitWindows); protected virtual HitErrorDisplay CreateHitErrorDisplayOverlay() => new HitErrorDisplay(drawableRuleset?.FirstAvailableHitWindows);
protected virtual PlayerSettingsOverlay CreatePlayerSettingsOverlay() => new PlayerSettingsOverlay(); protected virtual PlayerSettingsOverlay CreatePlayerSettingsOverlay() => new PlayerSettingsOverlay();
protected virtual void BindScoreProcessor(ScoreProcessor processor)
{
ScoreCounter?.Current.BindTo(processor.TotalScore);
AccuracyCounter?.Current.BindTo(processor.Accuracy);
ComboCounter?.Current.BindTo(processor.Combo);
if (HealthDisplay is IHealthDisplay shd)
{
processor.NewJudgement += judgement =>
{
if (judgement.IsHit && judgement.Type != HitResult.IgnoreHit)
shd.Flash(judgement);
};
}
}
protected virtual void BindHealthProcessor(HealthProcessor processor)
{
HealthDisplay?.BindHealthProcessor(processor);
FailingLayer?.BindHealthProcessor(processor);
}
public bool OnPressed(GlobalAction action) public bool OnPressed(GlobalAction action)
{ {
switch (action) switch (action)

View File

@ -203,9 +203,13 @@ namespace osu.Game.Screens.Play
ScoreProcessor.ApplyBeatmap(playableBeatmap); ScoreProcessor.ApplyBeatmap(playableBeatmap);
ScoreProcessor.Mods.BindTo(Mods); ScoreProcessor.Mods.BindTo(Mods);
dependencies.CacheAs(ScoreProcessor);
HealthProcessor = ruleset.CreateHealthProcessor(playableBeatmap.HitObjects[0].StartTime); HealthProcessor = ruleset.CreateHealthProcessor(playableBeatmap.HitObjects[0].StartTime);
HealthProcessor.ApplyBeatmap(playableBeatmap); HealthProcessor.ApplyBeatmap(playableBeatmap);
dependencies.CacheAs(HealthProcessor);
if (!ScoreProcessor.Mode.Disabled) if (!ScoreProcessor.Mode.Disabled)
config.BindWith(OsuSetting.ScoreDisplayMode, ScoreProcessor.Mode); config.BindWith(OsuSetting.ScoreDisplayMode, ScoreProcessor.Mode);
@ -341,7 +345,7 @@ namespace osu.Game.Screens.Play
// display the cursor above some HUD elements. // display the cursor above some HUD elements.
DrawableRuleset.Cursor?.CreateProxy() ?? new Container(), DrawableRuleset.Cursor?.CreateProxy() ?? new Container(),
DrawableRuleset.ResumeOverlay?.CreateProxy() ?? new Container(), DrawableRuleset.ResumeOverlay?.CreateProxy() ?? new Container(),
HUDOverlay = new HUDOverlay(ScoreProcessor, HealthProcessor, DrawableRuleset, Mods.Value) HUDOverlay = new HUDOverlay(DrawableRuleset, Mods.Value)
{ {
HoldToQuit = HoldToQuit =
{ {
@ -541,9 +545,11 @@ namespace osu.Game.Screens.Play
} }
// if the score is ready for display but results screen has not been pushed yet (e.g. storyboard is still playing beyond gameplay), then transition to results screen instead of exiting. // if the score is ready for display but results screen has not been pushed yet (e.g. storyboard is still playing beyond gameplay), then transition to results screen instead of exiting.
if (prepareScoreForDisplayTask != null) if (prepareScoreForDisplayTask != null && completionProgressDelegate == null)
{
updateCompletionState(true); updateCompletionState(true);
} }
}
this.Exit(); this.Exit();
} }

View File

@ -28,6 +28,7 @@ using osu.Game.Rulesets;
using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.UI; using osu.Game.Rulesets.UI;
using osu.Game.Screens.Ranking.Expanded; using osu.Game.Screens.Ranking.Expanded;
using osu.Game.Graphics.Containers;
namespace osu.Game.Screens.Select namespace osu.Game.Screens.Select
{ {
@ -286,7 +287,7 @@ namespace osu.Game.Screens.Select
Margin = new MarginPadding { Top = 10 }, Margin = new MarginPadding { Top = 10 },
Direction = FillDirection.Horizontal, Direction = FillDirection.Horizontal,
AutoSizeAxes = Axes.Both, AutoSizeAxes = Axes.Both,
Children = getMapper(metadata) Child = getMapper(metadata),
}, },
infoLabelContainer = new FillFlowContainer infoLabelContainer = new FillFlowContainer
{ {
@ -406,24 +407,20 @@ namespace osu.Game.Screens.Select
}); });
} }
private OsuSpriteText[] getMapper(BeatmapMetadata metadata) private Drawable getMapper(BeatmapMetadata metadata)
{ {
if (string.IsNullOrEmpty(metadata.Author?.Username)) if (metadata.Author == null)
return Array.Empty<OsuSpriteText>(); return Empty();
return new[] return new LinkFlowContainer(s =>
{ {
new OsuSpriteText s.Font = OsuFont.GetFont(weight: FontWeight.Bold, size: 15);
}).With(d =>
{ {
Text = "mapped by ", d.AutoSizeAxes = Axes.Both;
Font = OsuFont.GetFont(size: 15), d.AddText("mapped by ");
}, d.AddUserLink(metadata.Author);
new OsuSpriteText });
{
Text = metadata.Author.Username,
Font = OsuFont.GetFont(weight: FontWeight.Bold, size: 15),
}
};
} }
protected override void Dispose(bool isDisposing) protected override void Dispose(bool isDisposing)

View File

@ -71,6 +71,9 @@ namespace osu.Game.Screens.Select.Carousel
case SortMode.Author: case SortMode.Author:
return string.Compare(BeatmapSet.Metadata.Author.Username, otherSet.BeatmapSet.Metadata.Author.Username, StringComparison.OrdinalIgnoreCase); return string.Compare(BeatmapSet.Metadata.Author.Username, otherSet.BeatmapSet.Metadata.Author.Username, StringComparison.OrdinalIgnoreCase);
case SortMode.Source:
return string.Compare(BeatmapSet.Metadata.Source, otherSet.BeatmapSet.Metadata.Source, StringComparison.OrdinalIgnoreCase);
case SortMode.DateAdded: case SortMode.DateAdded:
return otherSet.BeatmapSet.DateAdded.CompareTo(BeatmapSet.DateAdded); return otherSet.BeatmapSet.DateAdded.CompareTo(BeatmapSet.DateAdded);

View File

@ -28,7 +28,10 @@ namespace osu.Game.Screens.Select.Filter
[Description("Rank Achieved")] [Description("Rank Achieved")]
RankAchieved, RankAchieved,
[Description("Source")]
Source,
[Description("Title")] [Description("Title")]
Title Title,
} }
} }

View File

@ -4,14 +4,13 @@
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Game.Graphics.Sprites; using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterface;
using osu.Game.Screens.Play; using osu.Game.Screens.Play;
using osu.Game.Screens.Play.HUD; using osu.Game.Screens.Play.HUD;
using osuTK; using osuTK;
namespace osu.Game.Skinning namespace osu.Game.Skinning
{ {
public class LegacyAccuracyCounter : PercentageCounter, IAccuracyCounter, ISkinnableComponent public class LegacyAccuracyCounter : GameplayAccuracyCounter, ISkinnableComponent
{ {
private readonly ISkin skin; private readonly ISkin skin;

View File

@ -16,7 +16,7 @@ using osuTK.Graphics;
namespace osu.Game.Skinning namespace osu.Game.Skinning
{ {
public class LegacyHealthDisplay : CompositeDrawable, IHealthDisplay, ISkinnableComponent public class LegacyHealthDisplay : HealthDisplay
{ {
private const double epic_cutoff = 0.5; private const double epic_cutoff = 0.5;
@ -28,12 +28,6 @@ namespace osu.Game.Skinning
private bool isNewStyle; private bool isNewStyle;
public Bindable<double> Current { get; } = new BindableDouble(1)
{
MinValue = 0,
MaxValue = 1
};
public LegacyHealthDisplay(Skin skin) public LegacyHealthDisplay(Skin skin)
{ {
this.skin = skin; this.skin = skin;
@ -83,7 +77,7 @@ namespace osu.Game.Skinning
marker.Position = fill.Position + new Vector2(fill.DrawWidth, isNewStyle ? fill.DrawHeight / 2 : 0); marker.Position = fill.Position + new Vector2(fill.DrawWidth, isNewStyle ? fill.DrawHeight / 2 : 0);
} }
public void Flash(JudgementResult result) => marker.Flash(result); protected override void Flash(JudgementResult result) => marker.Flash(result);
private static Texture getTexture(Skin skin, string name) => skin.GetTexture($"scorebar-{name}"); private static Texture getTexture(Skin skin, string name) => skin.GetTexture($"scorebar-{name}");
@ -254,7 +248,7 @@ namespace osu.Game.Skinning
Main.ScaleTo(1.4f).Then().ScaleTo(1, 200, Easing.Out); Main.ScaleTo(1.4f).Then().ScaleTo(1, 200, Easing.Out);
} }
public class LegacyHealthPiece : CompositeDrawable, IHealthDisplay public class LegacyHealthPiece : CompositeDrawable
{ {
public Bindable<double> Current { get; } = new Bindable<double>(); public Bindable<double> Current { get; } = new Bindable<double>();

View File

@ -1,24 +1,20 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // 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. // See the LICENCE file in the repository root for full licence text.
using osu.Framework.Bindables;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Game.Graphics.Sprites; using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterface;
using osu.Game.Screens.Play.HUD; using osu.Game.Screens.Play.HUD;
using osuTK; using osuTK;
namespace osu.Game.Skinning namespace osu.Game.Skinning
{ {
public class LegacyScoreCounter : ScoreCounter, ISkinnableComponent public class LegacyScoreCounter : GameplayScoreCounter, ISkinnableComponent
{ {
private readonly ISkin skin; private readonly ISkin skin;
protected override double RollingDuration => 1000; protected override double RollingDuration => 1000;
protected override Easing RollingEasing => Easing.Out; protected override Easing RollingEasing => Easing.Out;
public new Bindable<double> Current { get; } = new Bindable<double>();
public LegacyScoreCounter(ISkin skin) public LegacyScoreCounter(ISkin skin)
: base(6) : base(6)
{ {
@ -27,9 +23,6 @@ namespace osu.Game.Skinning
this.skin = skin; this.skin = skin;
// base class uses int for display, but externally we bind to ScoreProcessor as a double for now.
Current.BindValueChanged(v => base.Current.Value = (int)v.NewValue);
Scale = new Vector2(0.96f); Scale = new Vector2(0.96f);
Margin = new MarginPadding(10); Margin = new MarginPadding(10);
} }

View File

@ -4,7 +4,6 @@
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Framework.Input.Events; using osu.Framework.Input.Events;
using osu.Framework.Timing;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints; using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Screens.Edit; using osu.Game.Screens.Edit;
@ -46,7 +45,7 @@ namespace osu.Game.Tests.Visual
private void beatmapChanged(ValueChangedEvent<WorkingBeatmap> e) private void beatmapChanged(ValueChangedEvent<WorkingBeatmap> e)
{ {
Clock.ControlPointInfo = e.NewValue.Beatmap.ControlPointInfo; Clock.ControlPointInfo = e.NewValue.Beatmap.ControlPointInfo;
Clock.ChangeSource((IAdjustableClock)e.NewValue.Track ?? new StopwatchClock()); Clock.ChangeSource(e.NewValue.Track);
Clock.ProcessFrame(); Clock.ProcessFrame();
} }

View File

@ -29,7 +29,7 @@
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="5.0.0" /> <PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="5.0.0" />
<PackageReference Include="Microsoft.NETCore.Targets" Version="3.1.0" /> <PackageReference Include="Microsoft.NETCore.Targets" Version="3.1.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="ppy.osu.Framework" Version="2021.506.0" /> <PackageReference Include="ppy.osu.Framework" Version="2021.507.0" />
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.422.0" /> <PackageReference Include="ppy.osu.Game.Resources" Version="2021.422.0" />
<PackageReference Include="Sentry" Version="3.3.4" /> <PackageReference Include="Sentry" Version="3.3.4" />
<PackageReference Include="SharpCompress" Version="0.28.2" /> <PackageReference Include="SharpCompress" Version="0.28.2" />

View File

@ -70,7 +70,7 @@
<Reference Include="System.Net.Http" /> <Reference Include="System.Net.Http" />
</ItemGroup> </ItemGroup>
<ItemGroup Label="Package References"> <ItemGroup Label="Package References">
<PackageReference Include="ppy.osu.Framework.iOS" Version="2021.506.0" /> <PackageReference Include="ppy.osu.Framework.iOS" Version="2021.507.0" />
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.422.0" /> <PackageReference Include="ppy.osu.Game.Resources" Version="2021.422.0" />
</ItemGroup> </ItemGroup>
<!-- See https://github.com/dotnet/runtime/issues/35988 (can be removed after Xamarin uses net5.0 / net6.0) --> <!-- See https://github.com/dotnet/runtime/issues/35988 (can be removed after Xamarin uses net5.0 / net6.0) -->
@ -93,7 +93,7 @@
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.6" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.6" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.6" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.6" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" /> <PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="ppy.osu.Framework" Version="2021.506.0" /> <PackageReference Include="ppy.osu.Framework" Version="2021.507.0" />
<PackageReference Include="SharpCompress" Version="0.28.2" /> <PackageReference Include="SharpCompress" Version="0.28.2" />
<PackageReference Include="NUnit" Version="3.13.2" /> <PackageReference Include="NUnit" Version="3.13.2" />
<PackageReference Include="SharpRaven" Version="2.4.0" /> <PackageReference Include="SharpRaven" Version="2.4.0" />