diff --git a/osu.Android.props b/osu.Android.props
index 939d179b1d..24afbb86fb 100644
--- a/osu.Android.props
+++ b/osu.Android.props
@@ -54,6 +54,6 @@
-
+
diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneBananaShower.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneBananaShower.cs
index 56e378d19e..20911b8d06 100644
--- a/osu.Game.Rulesets.Catch.Tests/TestSceneBananaShower.cs
+++ b/osu.Game.Rulesets.Catch.Tests/TestSceneBananaShower.cs
@@ -29,6 +29,12 @@ namespace osu.Game.Rulesets.Catch.Tests
{
}
+ [Test]
+ public void TestBananaShower()
+ {
+ AddUntilStep("player is done", () => !Player.ValidForResume);
+ }
+
protected override IBeatmap CreateBeatmap(RulesetInfo ruleset)
{
var beatmap = new Beatmap
@@ -40,7 +46,7 @@ namespace osu.Game.Rulesets.Catch.Tests
}
};
- beatmap.HitObjects.Add(new BananaShower { StartTime = 200, Duration = 5000, NewCombo = true });
+ beatmap.HitObjects.Add(new BananaShower { StartTime = 200, Duration = 3000, NewCombo = true });
return beatmap;
}
diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneJuiceStream.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneJuiceStream.cs
new file mode 100644
index 0000000000..cbc87459e1
--- /dev/null
+++ b/osu.Game.Rulesets.Catch.Tests/TestSceneJuiceStream.cs
@@ -0,0 +1,56 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System.Collections.Generic;
+using NUnit.Framework;
+using osu.Game.Beatmaps;
+using osu.Game.Rulesets.Catch.Objects;
+using osu.Game.Rulesets.Objects;
+using osu.Game.Rulesets.Objects.Types;
+using osu.Game.Tests.Visual;
+using osuTK;
+
+namespace osu.Game.Rulesets.Catch.Tests
+{
+ public class TestSceneJuiceStream : PlayerTestScene
+ {
+ public TestSceneJuiceStream()
+ : base(new CatchRuleset())
+ {
+ }
+
+ [Test]
+ public void TestJuiceStreamEndingCombo()
+ {
+ AddUntilStep("player is done", () => !Player.ValidForResume);
+ }
+
+ protected override IBeatmap CreateBeatmap(RulesetInfo ruleset) => new Beatmap
+ {
+ BeatmapInfo = new BeatmapInfo
+ {
+ BaseDifficulty = new BeatmapDifficulty { CircleSize = 5, SliderMultiplier = 2 },
+ Ruleset = ruleset
+ },
+ HitObjects = new List
+ {
+ new JuiceStream
+ {
+ X = 0.5f,
+ Path = new SliderPath(PathType.Linear, new[]
+ {
+ Vector2.Zero,
+ new Vector2(0, 100)
+ }),
+ StartTime = 200
+ },
+ new Banana
+ {
+ X = 0.5f,
+ StartTime = 1000,
+ NewCombo = true
+ }
+ }
+ };
+ }
+}
diff --git a/osu.Game.Rulesets.Catch/Objects/BananaShower.cs b/osu.Game.Rulesets.Catch/Objects/BananaShower.cs
index 0c754412e5..c3488aec11 100644
--- a/osu.Game.Rulesets.Catch/Objects/BananaShower.cs
+++ b/osu.Game.Rulesets.Catch/Objects/BananaShower.cs
@@ -1,6 +1,7 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
+using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Objects.Types;
namespace osu.Game.Rulesets.Catch.Objects
@@ -11,6 +12,8 @@ namespace osu.Game.Rulesets.Catch.Objects
public override bool LastInCombo => true;
+ public override Judgement CreateJudgement() => new IgnoreJudgement();
+
protected override void CreateNestedHitObjects()
{
base.CreateNestedHitObjects();
diff --git a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs
index 11e2466275..642ff0246e 100644
--- a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs
+++ b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs
@@ -7,6 +7,7 @@ using osu.Game.Audio;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Rulesets.Catch.UI;
+using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Types;
@@ -19,6 +20,8 @@ namespace osu.Game.Rulesets.Catch.Objects
///
private const float base_scoring_distance = 100;
+ public override Judgement CreateJudgement() => new IgnoreJudgement();
+
public int RepeatCount { get; set; }
public double Velocity;
diff --git a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs
index ff2471f8bf..0b3809150a 100644
--- a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs
+++ b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs
@@ -89,7 +89,7 @@ namespace osu.Game.Rulesets.Catch.UI
if (fruit.HitObject.LastInCombo)
{
- if (((CatchJudgement)result.Judgement).ShouldExplodeFor(result))
+ if (result.Judgement is CatchJudgement catchJudgement && catchJudgement.ShouldExplodeFor(result))
runAfterLoaded(() => MovableCatcher.Explode());
else
MovableCatcher.Drop();
diff --git a/osu.Game.Rulesets.Mania/Judgements/HoldNoteJudgement.cs b/osu.Game.Rulesets.Mania/Judgements/HoldNoteJudgement.cs
deleted file mode 100644
index e8b48768a1..0000000000
--- a/osu.Game.Rulesets.Mania/Judgements/HoldNoteJudgement.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
-// See the LICENCE file in the repository root for full licence text.
-
-using osu.Game.Rulesets.Scoring;
-
-namespace osu.Game.Rulesets.Mania.Judgements
-{
- public class HoldNoteJudgement : ManiaJudgement
- {
- public override bool AffectsCombo => false;
-
- protected override int NumericResultFor(HitResult result) => 0;
- }
-}
diff --git a/osu.Game.Rulesets.Mania/Objects/BarLine.cs b/osu.Game.Rulesets.Mania/Objects/BarLine.cs
index 0981b028b2..09a746042b 100644
--- a/osu.Game.Rulesets.Mania/Objects/BarLine.cs
+++ b/osu.Game.Rulesets.Mania/Objects/BarLine.cs
@@ -1,6 +1,7 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
+using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Objects;
namespace osu.Game.Rulesets.Mania.Objects
@@ -8,5 +9,7 @@ namespace osu.Game.Rulesets.Mania.Objects
public class BarLine : ManiaHitObject, IBarLine
{
public bool Major { get; set; }
+
+ public override Judgement CreateJudgement() => new IgnoreJudgement();
}
}
diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableBarLine.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableBarLine.cs
index 56bc797c7f..08b5b75f9c 100644
--- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableBarLine.cs
+++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableBarLine.cs
@@ -71,8 +71,6 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
{
}
- protected override void UpdateStateTransforms(ArmedState state)
- {
- }
+ protected override void UpdateStateTransforms(ArmedState state) => this.FadeOut(150);
}
}
diff --git a/osu.Game.Rulesets.Mania/Objects/HoldNote.cs b/osu.Game.Rulesets.Mania/Objects/HoldNote.cs
index 86d3d2b2b0..049bf55f90 100644
--- a/osu.Game.Rulesets.Mania/Objects/HoldNote.cs
+++ b/osu.Game.Rulesets.Mania/Objects/HoldNote.cs
@@ -4,7 +4,6 @@
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Rulesets.Judgements;
-using osu.Game.Rulesets.Mania.Judgements;
using osu.Game.Rulesets.Objects.Types;
using osu.Game.Rulesets.Scoring;
@@ -103,7 +102,7 @@ namespace osu.Game.Rulesets.Mania.Objects
}
}
- public override Judgement CreateJudgement() => new HoldNoteJudgement();
+ public override Judgement CreateJudgement() => new IgnoreJudgement();
protected override HitWindows CreateHitWindows() => HitWindows.Empty;
}
diff --git a/osu.Game.Rulesets.Osu/Judgements/OsuSliderTailJudgement.cs b/osu.Game.Rulesets.Osu/Judgements/OsuSliderTailJudgement.cs
deleted file mode 100644
index 5104d9494b..0000000000
--- a/osu.Game.Rulesets.Osu/Judgements/OsuSliderTailJudgement.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
-// See the LICENCE file in the repository root for full licence text.
-
-using osu.Game.Rulesets.Scoring;
-
-namespace osu.Game.Rulesets.Osu.Judgements
-{
- public class OsuSliderTailJudgement : OsuJudgement
- {
- public override bool AffectsCombo => false;
-
- protected override int NumericResultFor(HitResult result) => 0;
- }
-}
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPointConnection.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPointConnection.cs
index a5e89210f6..921b23cb13 100644
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPointConnection.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPointConnection.cs
@@ -20,6 +20,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
private const int spacing = 32;
private const double preempt = 800;
+ public override bool RemoveWhenNotAlive => false;
+
///
/// The start time of .
///
@@ -79,27 +81,31 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
drawableObject.HitObject.DefaultsApplied += scheduleRefresh;
}
- private void scheduleRefresh() => Scheduler.AddOnce(refresh);
+ private void scheduleRefresh()
+ {
+ Scheduler.AddOnce(refresh);
+ }
private void refresh()
{
ClearInternal();
- if (End == null)
- return;
-
OsuHitObject osuStart = Start.HitObject;
- OsuHitObject osuEnd = End.HitObject;
+ double startTime = osuStart.GetEndTime();
- if (osuEnd.NewCombo)
- return;
+ LifetimeStart = startTime;
- if (osuStart is Spinner || osuEnd is Spinner)
+ OsuHitObject osuEnd = End?.HitObject;
+
+ if (osuEnd == null || osuEnd.NewCombo || osuStart is Spinner || osuEnd is Spinner)
+ {
+ // ensure we always set a lifetime for full LifetimeManagementContainer benefits
+ LifetimeEnd = LifetimeStart;
return;
+ }
Vector2 startPosition = osuStart.EndPosition;
Vector2 endPosition = osuEnd.Position;
- double startTime = osuStart.GetEndTime();
double endTime = osuEnd.StartTime;
Vector2 distanceVector = endPosition - startPosition;
@@ -107,6 +113,9 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
float rotation = (float)(Math.Atan2(distanceVector.Y, distanceVector.X) * (180 / Math.PI));
double duration = endTime - startTime;
+ double? firstTransformStartTime = null;
+ double finalTransformEndTime = startTime;
+
for (int d = (int)(spacing * 1.5); d < distance - spacing; d += spacing)
{
float fraction = (float)d / distance;
@@ -125,16 +134,23 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
Scale = new Vector2(1.5f * osuEnd.Scale),
});
+ if (firstTransformStartTime == null)
+ firstTransformStartTime = fadeInTime;
+
using (fp.BeginAbsoluteSequence(fadeInTime))
{
fp.FadeIn(osuEnd.TimeFadeIn);
fp.ScaleTo(osuEnd.Scale, osuEnd.TimeFadeIn, Easing.Out);
fp.MoveTo(pointEndPosition, osuEnd.TimeFadeIn, Easing.Out);
fp.Delay(fadeOutTime - fadeInTime).FadeOut(osuEnd.TimeFadeIn);
- }
- fp.Expire(true);
+ finalTransformEndTime = fadeOutTime + osuEnd.TimeFadeIn;
+ }
}
+
+ // todo: use Expire() on FollowPoints and take lifetime from them when https://github.com/ppy/osu-framework/issues/3300 is fixed.
+ LifetimeStart = firstTransformStartTime ?? startTime;
+ LifetimeEnd = finalTransformEndTime;
}
}
}
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPointRenderer.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPointRenderer.cs
index be192080f9..4d73e711bb 100644
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPointRenderer.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPointRenderer.cs
@@ -12,7 +12,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
///
/// Visualises connections between s.
///
- public class FollowPointRenderer : CompositeDrawable
+ public class FollowPointRenderer : LifetimeManagementContainer
{
///
/// All the s contained by this .
@@ -45,8 +45,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
/// The index of in .
private void addConnection(FollowPointConnection connection)
{
- AddInternal(connection);
-
// Groups are sorted by their start time when added such that the index can be used to post-process other surrounding connections
int index = connections.AddInPlace(connection, Comparer.Create((g1, g2) => g1.StartTime.Value.CompareTo(g2.StartTime.Value)));
@@ -74,6 +72,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
FollowPointConnection previousConnection = connections[index - 1];
previousConnection.End = connection.Start;
}
+
+ AddInternal(connection);
}
///
diff --git a/osu.Game.Rulesets.Osu/Objects/SliderTailCircle.cs b/osu.Game.Rulesets.Osu/Objects/SliderTailCircle.cs
index c17d2275b8..127c36fcc0 100644
--- a/osu.Game.Rulesets.Osu/Objects/SliderTailCircle.cs
+++ b/osu.Game.Rulesets.Osu/Objects/SliderTailCircle.cs
@@ -4,7 +4,6 @@
using osu.Framework.Bindables;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Objects;
-using osu.Game.Rulesets.Osu.Judgements;
using osu.Game.Rulesets.Scoring;
namespace osu.Game.Rulesets.Osu.Objects
@@ -23,7 +22,7 @@ namespace osu.Game.Rulesets.Osu.Objects
pathVersion.BindValueChanged(_ => Position = slider.EndPosition);
}
- public override Judgement CreateJudgement() => new OsuSliderTailJudgement();
+ public override Judgement CreateJudgement() => new IgnoreJudgement();
protected override HitWindows CreateHitWindows() => HitWindows.Empty;
}
diff --git a/osu.Game.Rulesets.Taiko.Tests/TestSceneSwellJudgements.cs b/osu.Game.Rulesets.Taiko.Tests/TestSceneSwellJudgements.cs
index f27e329e8e..ccacc50de1 100644
--- a/osu.Game.Rulesets.Taiko.Tests/TestSceneSwellJudgements.cs
+++ b/osu.Game.Rulesets.Taiko.Tests/TestSceneSwellJudgements.cs
@@ -8,7 +8,6 @@ using osu.Framework.Allocation;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Scoring;
-using osu.Game.Rulesets.Taiko.Judgements;
using osu.Game.Rulesets.Taiko.Objects;
using osu.Game.Screens.Play;
using osu.Game.Tests.Visual;
@@ -28,7 +27,7 @@ namespace osu.Game.Rulesets.Taiko.Tests
public void TestZeroTickTimeOffsets()
{
AddUntilStep("gameplay finished", () => Player.ScoreProcessor.HasCompleted);
- AddAssert("all tick offsets are 0", () => Player.Results.Where(r => r.Judgement is TaikoSwellTickJudgement).All(r => r.TimeOffset == 0));
+ AddAssert("all tick offsets are 0", () => Player.Results.Where(r => r.HitObject is SwellTick).All(r => r.TimeOffset == 0));
}
protected override bool Autoplay => true;
diff --git a/osu.Game.Rulesets.Taiko/Objects/BarLine.cs b/osu.Game.Rulesets.Taiko/Objects/BarLine.cs
index 2afbbc737c..6306195704 100644
--- a/osu.Game.Rulesets.Taiko/Objects/BarLine.cs
+++ b/osu.Game.Rulesets.Taiko/Objects/BarLine.cs
@@ -1,6 +1,7 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
+using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Objects;
namespace osu.Game.Rulesets.Taiko.Objects
@@ -8,5 +9,7 @@ namespace osu.Game.Rulesets.Taiko.Objects
public class BarLine : TaikoHitObject, IBarLine
{
public bool Major { get; set; }
+
+ public override Judgement CreateJudgement() => new IgnoreJudgement();
}
}
diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableBarLine.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableBarLine.cs
index 1a5a797f28..e9caabbcc8 100644
--- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableBarLine.cs
+++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableBarLine.cs
@@ -54,5 +54,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
Alpha = 0.75f
});
}
+
+ protected override void UpdateStateTransforms(ArmedState state) => this.FadeOut(150);
}
}
diff --git a/osu.Game.Rulesets.Taiko/Objects/SwellTick.cs b/osu.Game.Rulesets.Taiko/Objects/SwellTick.cs
index 91f4d3dbe7..bdc0478195 100644
--- a/osu.Game.Rulesets.Taiko/Objects/SwellTick.cs
+++ b/osu.Game.Rulesets.Taiko/Objects/SwellTick.cs
@@ -3,13 +3,12 @@
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Scoring;
-using osu.Game.Rulesets.Taiko.Judgements;
namespace osu.Game.Rulesets.Taiko.Objects
{
public class SwellTick : TaikoHitObject
{
- public override Judgement CreateJudgement() => new TaikoSwellTickJudgement();
+ public override Judgement CreateJudgement() => new IgnoreJudgement();
protected override HitWindows CreateHitWindows() => HitWindows.Empty;
}
diff --git a/osu.Game.Tests/Gameplay/TestSceneDrainingHealthProcessor.cs b/osu.Game.Tests/Gameplay/TestSceneDrainingHealthProcessor.cs
index 244e37f017..885abb61b5 100644
--- a/osu.Game.Tests/Gameplay/TestSceneDrainingHealthProcessor.cs
+++ b/osu.Game.Tests/Gameplay/TestSceneDrainingHealthProcessor.cs
@@ -154,6 +154,7 @@ namespace osu.Game.Tests.Gameplay
private class JudgeableHitObject : HitObject
{
public override Judgement CreateJudgement() => new Judgement();
+ protected override HitWindows CreateHitWindows() => new HitWindows();
}
}
}
diff --git a/osu.Game.Tests/Gameplay/TestSceneHitObjectAccentColour.cs b/osu.Game.Tests/Gameplay/TestSceneHitObjectAccentColour.cs
index 17dc27543d..7a89642e11 100644
--- a/osu.Game.Tests/Gameplay/TestSceneHitObjectAccentColour.cs
+++ b/osu.Game.Tests/Gameplay/TestSceneHitObjectAccentColour.cs
@@ -11,8 +11,8 @@ using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Textures;
using osu.Framework.Testing;
using osu.Game.Audio;
-using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Drawables;
+using osu.Game.Rulesets.Objects.Legacy;
using osu.Game.Rulesets.Objects.Types;
using osu.Game.Skinning;
using osu.Game.Tests.Visual;
@@ -78,7 +78,7 @@ namespace osu.Game.Tests.Gameplay
}
}
- private class TestHitObjectWithCombo : HitObject, IHasComboInformation
+ private class TestHitObjectWithCombo : ConvertHitObject, IHasComboInformation
{
public bool NewCombo { get; } = false;
public int ComboOffset { get; } = 0;
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableScrollingRuleset.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableScrollingRuleset.cs
index 46f62b9541..b25b81c9af 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableScrollingRuleset.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableScrollingRuleset.cs
@@ -20,6 +20,7 @@ using osu.Game.Rulesets.Difficulty;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Drawables;
+using osu.Game.Rulesets.Objects.Legacy;
using osu.Game.Rulesets.Objects.Types;
using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.UI;
@@ -289,7 +290,7 @@ namespace osu.Game.Tests.Visual.Gameplay
#region HitObject
- private class TestHitObject : HitObject, IHasEndTime
+ private class TestHitObject : ConvertHitObject, IHasEndTime
{
public double EndTime { get; set; }
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorMeter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorMeter.cs
index 8904b54b0d..1527cba6fc 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorMeter.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorMeter.cs
@@ -2,16 +2,17 @@
// See the LICENCE file in the repository root for full licence text.
using NUnit.Framework;
-using osu.Game.Rulesets.Objects;
using System;
using System.Collections.Generic;
using osu.Game.Rulesets.Judgements;
using osu.Framework.Utils;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
+using osu.Framework.Threading;
using osu.Game.Graphics.Sprites;
using osu.Game.Rulesets.Catch.Scoring;
using osu.Game.Rulesets.Mania.Scoring;
+using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Osu.Scoring;
using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.Taiko.Scoring;
@@ -43,6 +44,22 @@ namespace osu.Game.Tests.Visual.Gameplay
AddRepeatStep("New max negative", () => newJudgement(-hitWindows.WindowFor(HitResult.Meh)), 20);
AddRepeatStep("New max positive", () => newJudgement(hitWindows.WindowFor(HitResult.Meh)), 20);
AddStep("New fixed judgement (50ms)", () => newJudgement(50));
+
+ AddStep("Judgement barrage", () =>
+ {
+ int runCount = 0;
+
+ ScheduledDelegate del = null;
+
+ del = Scheduler.AddDelayed(() =>
+ {
+ newJudgement(runCount++ / 10f);
+
+ if (runCount == 500)
+ // ReSharper disable once AccessToModifiedClosure
+ del?.Cancel();
+ }, 10, true);
+ });
}
[Test]
diff --git a/osu.Game.Tests/Visual/Online/TestSceneCommentsPage.cs b/osu.Game.Tests/Visual/Online/TestSceneCommentsPage.cs
index 0ed8864860..a28a0107a1 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneCommentsPage.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneCommentsPage.cs
@@ -13,6 +13,8 @@ using osu.Framework.Bindables;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics;
using osuTK;
+using JetBrains.Annotations;
+using NUnit.Framework;
namespace osu.Game.Tests.Visual.Online
{
@@ -30,6 +32,8 @@ namespace osu.Game.Tests.Visual.Online
private readonly BindableBool showDeleted = new BindableBool();
private readonly Container content;
+ private TestCommentsPage commentsPage;
+
public TestSceneCommentsPage()
{
Add(new FillFlowContainer
@@ -57,15 +61,29 @@ namespace osu.Game.Tests.Visual.Online
}
}
});
+ }
- AddStep("load comments", () => createPage(getCommentBundle()));
- AddStep("load empty comments", () => createPage(getEmptyCommentBundle()));
+ [Test]
+ public void TestAppendDuplicatedComment()
+ {
+ AddStep("Create page", () => createPage(getCommentBundle()));
+ AddAssert("Dictionary length is 10", () => commentsPage?.DictionaryLength == 10);
+ AddStep("Append existing comment", () => commentsPage?.AppendComments(getCommentSubBundle()));
+ AddAssert("Dictionary length is 10", () => commentsPage?.DictionaryLength == 10);
+ }
+
+ [Test]
+ public void TestEmptyBundle()
+ {
+ AddStep("Create page", () => createPage(getEmptyCommentBundle()));
+ AddAssert("Dictionary length is 0", () => commentsPage?.DictionaryLength == 0);
}
private void createPage(CommentBundle commentBundle)
{
+ commentsPage = null;
content.Clear();
- content.Add(new CommentsPage(commentBundle)
+ content.Add(commentsPage = new TestCommentsPage(commentBundle)
{
ShowDeleted = { BindTarget = showDeleted }
});
@@ -182,5 +200,33 @@ namespace osu.Game.Tests.Visual.Online
}
},
};
+
+ private CommentBundle getCommentSubBundle() => new CommentBundle
+ {
+ Comments = new List
+ {
+ new Comment
+ {
+ Id = 1,
+ Message = "Simple test comment",
+ LegacyName = "TestUser1",
+ CreatedAt = DateTimeOffset.Now,
+ VotesCount = 5
+ },
+ },
+ IncludedComments = new List(),
+ };
+
+ private class TestCommentsPage : CommentsPage
+ {
+ public TestCommentsPage(CommentBundle commentBundle)
+ : base(commentBundle)
+ {
+ }
+
+ public new void AppendComments([NotNull] CommentBundle bundle) => base.AppendComments(bundle);
+
+ public int DictionaryLength => CommentDictionary.Count;
+ }
}
}
diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapInfoWedge.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapInfoWedge.cs
index f49d7a14a6..e02ebf3be1 100644
--- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapInfoWedge.cs
+++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapInfoWedge.cs
@@ -13,6 +13,7 @@ using osu.Game.Rulesets;
using osu.Game.Rulesets.Catch;
using osu.Game.Rulesets.Mania;
using osu.Game.Rulesets.Objects;
+using osu.Game.Rulesets.Objects.Legacy;
using osu.Game.Rulesets.Objects.Types;
using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.Taiko;
@@ -194,7 +195,7 @@ namespace osu.Game.Tests.Visual.SongSelect
public new BufferedWedgeInfo Info => base.Info;
}
- private class TestHitObject : HitObject, IHasPosition
+ private class TestHitObject : ConvertHitObject, IHasPosition
{
public float X { get; } = 0;
public float Y { get; } = 0;
diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneUserListToolbar.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneUserListToolbar.cs
new file mode 100644
index 0000000000..02b8839922
--- /dev/null
+++ b/osu.Game.Tests/Visual/UserInterface/TestSceneUserListToolbar.cs
@@ -0,0 +1,57 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System;
+using System.Collections.Generic;
+using osu.Framework.Allocation;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Game.Graphics.Sprites;
+using osu.Game.Overlays;
+using osu.Game.Overlays.Home.Friends;
+using osuTK;
+
+namespace osu.Game.Tests.Visual.UserInterface
+{
+ public class TestSceneUserListToolbar : OsuTestScene
+ {
+ public override IReadOnlyList RequiredTypes => new[]
+ {
+ typeof(UserSortTabControl),
+ typeof(OverlaySortTabControl<>),
+ typeof(OverlayPanelDisplayStyleControl),
+ typeof(UserListToolbar),
+ };
+
+ [Cached]
+ private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Purple);
+
+ public TestSceneUserListToolbar()
+ {
+ UserListToolbar toolbar;
+ OsuSpriteText sort;
+ OsuSpriteText displayStyle;
+
+ Add(toolbar = new UserListToolbar
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ });
+
+ Add(new FillFlowContainer
+ {
+ AutoSizeAxes = Axes.Both,
+ Direction = FillDirection.Vertical,
+ Spacing = new Vector2(0, 5),
+ Children = new Drawable[]
+ {
+ sort = new OsuSpriteText(),
+ displayStyle = new OsuSpriteText()
+ }
+ });
+
+ toolbar.SortCriteria.BindValueChanged(criteria => sort.Text = $"Criteria: {criteria.NewValue}", true);
+ toolbar.DisplayStyle.BindValueChanged(style => displayStyle.Text = $"Style: {style.NewValue}", true);
+ }
+ }
+}
diff --git a/osu.Game/Graphics/UserInterface/LoadingLayer.cs b/osu.Game/Graphics/UserInterface/LoadingLayer.cs
index 25a62acaba..35b33c3d03 100644
--- a/osu.Game/Graphics/UserInterface/LoadingLayer.cs
+++ b/osu.Game/Graphics/UserInterface/LoadingLayer.cs
@@ -64,7 +64,7 @@ namespace osu.Game.Graphics.UserInterface
protected override void Update()
{
base.Update();
- MainContents.Size = new Vector2(Math.Min(100, Math.Min(DrawWidth, DrawHeight) * 0.25f));
+ MainContents.Size = new Vector2(Math.Clamp(Math.Min(DrawWidth, DrawHeight) * 0.25f, 30, 100));
}
protected override void Dispose(bool isDisposing)
diff --git a/osu.Game/Graphics/UserInterface/LoadingSpinner.cs b/osu.Game/Graphics/UserInterface/LoadingSpinner.cs
index b5a235f9d8..36d429b8c1 100644
--- a/osu.Game/Graphics/UserInterface/LoadingSpinner.cs
+++ b/osu.Game/Graphics/UserInterface/LoadingSpinner.cs
@@ -93,7 +93,7 @@ namespace osu.Game.Graphics.UserInterface
private void rotate()
{
- spinner.Spin(spin_duration * 4, RotationDirection.Clockwise);
+ spinner.Spin(spin_duration * 3.5f, RotationDirection.Clockwise);
MainContents.RotateTo(0).Then()
.RotateTo(90, spin_duration, Easing.InOutQuart).Then()
diff --git a/osu.Game/Overlays/BeatmapSet/BeatmapSetLayoutSection.cs b/osu.Game/Overlays/BeatmapSet/BeatmapSetLayoutSection.cs
new file mode 100644
index 0000000000..e6d433f7bc
--- /dev/null
+++ b/osu.Game/Overlays/BeatmapSet/BeatmapSetLayoutSection.cs
@@ -0,0 +1,29 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Framework.Extensions.Color4Extensions;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Effects;
+using osuTK;
+using osuTK.Graphics;
+
+namespace osu.Game.Overlays.BeatmapSet
+{
+ public class BeatmapSetLayoutSection : Container
+ {
+ public BeatmapSetLayoutSection()
+ {
+ RelativeSizeAxes = Axes.X;
+ AutoSizeAxes = Axes.Y;
+ Masking = true;
+ EdgeEffect = new EdgeEffectParameters
+ {
+ Colour = Color4.Black.Opacity(0.25f),
+ Type = EdgeEffectType.Shadow,
+ Radius = 3,
+ Offset = new Vector2(0f, 1f),
+ };
+ }
+ }
+}
diff --git a/osu.Game/Overlays/BeatmapSet/Info.cs b/osu.Game/Overlays/BeatmapSet/Info.cs
index 0f2d6a9e35..bac658b76e 100644
--- a/osu.Game/Overlays/BeatmapSet/Info.cs
+++ b/osu.Game/Overlays/BeatmapSet/Info.cs
@@ -3,17 +3,14 @@
using osu.Framework.Allocation;
using osu.Framework.Bindables;
-using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
-using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Shapes;
using osu.Game.Beatmaps;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Sprites;
using osuTK;
-using osuTK.Graphics;
namespace osu.Game.Overlays.BeatmapSet
{
@@ -43,14 +40,6 @@ namespace osu.Game.Overlays.BeatmapSet
RelativeSizeAxes = Axes.X;
Height = base_height;
- Masking = true;
- EdgeEffect = new EdgeEffectParameters
- {
- Colour = Color4.Black.Opacity(0.25f),
- Type = EdgeEffectType.Shadow,
- Radius = 3,
- Offset = new Vector2(0f, 1f),
- };
Children = new Drawable[]
{
diff --git a/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs b/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs
index e831c8ce42..7607eac1f8 100644
--- a/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs
+++ b/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs
@@ -19,7 +19,7 @@ using osu.Game.Users;
namespace osu.Game.Overlays.BeatmapSet.Scores
{
- public class ScoresContainer : CompositeDrawable
+ public class ScoresContainer : BeatmapSetLayoutSection
{
private const int spacing = 15;
@@ -34,7 +34,6 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
private readonly LoadingLayer loading;
private readonly LeaderboardModSelector modSelector;
private readonly NoScoresPlaceholder noScoresPlaceholder;
- private readonly FillFlowContainer content;
private readonly NotSupporterPlaceholder notSupporterPlaceholder;
[Resolved]
@@ -76,15 +75,13 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
public ScoresContainer()
{
- RelativeSizeAxes = Axes.X;
- AutoSizeAxes = Axes.Y;
- InternalChildren = new Drawable[]
+ AddRange(new Drawable[]
{
background = new Box
{
RelativeSizeAxes = Axes.Both,
},
- content = new FillFlowContainer
+ new FillFlowContainer
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
@@ -164,8 +161,8 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
}
}
}
- },
- };
+ }
+ });
}
[BackgroundDependencyLoader]
@@ -223,7 +220,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
if (Beatmap.Value?.OnlineBeatmapID.HasValue != true || Beatmap.Value.Status <= BeatmapSetOnlineStatus.Pending)
{
Scores = null;
- content.Hide();
+ Hide();
return;
}
@@ -237,7 +234,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
notSupporterPlaceholder.Hide();
- content.Show();
+ Show();
loading.Show();
getScoresRequest = new GetScoresRequest(Beatmap.Value, Beatmap.Value.Ruleset, scope.Value, modSelector.SelectedMods);
diff --git a/osu.Game/Overlays/BeatmapSetOverlay.cs b/osu.Game/Overlays/BeatmapSetOverlay.cs
index d29997f7e5..0d16c4842d 100644
--- a/osu.Game/Overlays/BeatmapSetOverlay.cs
+++ b/osu.Game/Overlays/BeatmapSetOverlay.cs
@@ -13,6 +13,7 @@ using osu.Game.Graphics.Containers;
using osu.Game.Online.API.Requests;
using osu.Game.Overlays.BeatmapSet;
using osu.Game.Overlays.BeatmapSet.Scores;
+using osu.Game.Overlays.Comments;
using osu.Game.Rulesets;
using osuTK;
@@ -40,6 +41,7 @@ namespace osu.Game.Overlays
{
OsuScrollContainer scroll;
Info info;
+ CommentsSection comments;
Children = new Drawable[]
{
@@ -51,29 +53,33 @@ namespace osu.Game.Overlays
{
RelativeSizeAxes = Axes.Both,
ScrollbarVisible = false,
- Child = new ReverseChildIDFillFlowContainer
+ Child = new ReverseChildIDFillFlowContainer
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Direction = FillDirection.Vertical,
Spacing = new Vector2(0, 20),
- Children = new Drawable[]
+ Children = new[]
{
- new ReverseChildIDFillFlowContainer
+ new BeatmapSetLayoutSection
{
- AutoSizeAxes = Axes.Y,
- RelativeSizeAxes = Axes.X,
- Direction = FillDirection.Vertical,
- Children = new Drawable[]
+ Child = new ReverseChildIDFillFlowContainer
{
- Header = new Header(),
- info = new Info()
- }
+ AutoSizeAxes = Axes.Y,
+ RelativeSizeAxes = Axes.X,
+ Direction = FillDirection.Vertical,
+ Children = new Drawable[]
+ {
+ Header = new Header(),
+ info = new Info()
+ }
+ },
},
new ScoresContainer
{
Beatmap = { BindTarget = Header.Picker.Beatmap }
- }
+ },
+ comments = new CommentsSection()
},
},
},
@@ -81,6 +87,7 @@ namespace osu.Game.Overlays
Header.BeatmapSet.BindTo(beatmapSet);
info.BeatmapSet.BindTo(beatmapSet);
+ comments.BeatmapSet.BindTo(beatmapSet);
Header.Picker.Beatmap.ValueChanged += b =>
{
@@ -143,5 +150,30 @@ namespace osu.Game.Overlays
beatmapSet.Value = set;
Show();
}
+
+ private class CommentsSection : BeatmapSetLayoutSection
+ {
+ public readonly Bindable BeatmapSet = new Bindable();
+
+ public CommentsSection()
+ {
+ CommentsContainer comments;
+
+ Add(comments = new CommentsContainer());
+
+ BeatmapSet.BindValueChanged(beatmapSet =>
+ {
+ if (beatmapSet.NewValue?.OnlineBeatmapSetID is int onlineBeatmapSetID)
+ {
+ Show();
+ comments.ShowComments(CommentableType.Beatmapset, onlineBeatmapSetID);
+ }
+ else
+ {
+ Hide();
+ }
+ }, true);
+ }
+ }
}
}
diff --git a/osu.Game/Overlays/Comments/CommentsHeader.cs b/osu.Game/Overlays/Comments/CommentsHeader.cs
index 1aa40201f1..83f44ccd80 100644
--- a/osu.Game/Overlays/Comments/CommentsHeader.cs
+++ b/osu.Game/Overlays/Comments/CommentsHeader.cs
@@ -109,6 +109,7 @@ namespace osu.Game.Overlays.Comments
public enum CommentsSortCriteria
{
+ [System.ComponentModel.Description(@"Recent")]
New,
Old,
Top
diff --git a/osu.Game/Overlays/Comments/CommentsPage.cs b/osu.Game/Overlays/Comments/CommentsPage.cs
index 4f82ee5a19..9b146b0a7d 100644
--- a/osu.Game/Overlays/Comments/CommentsPage.cs
+++ b/osu.Game/Overlays/Comments/CommentsPage.cs
@@ -61,15 +61,15 @@ namespace osu.Game.Overlays.Comments
return;
}
- appendComments(commentBundle);
+ AppendComments(commentBundle);
}
private DrawableComment getDrawableComment(Comment comment)
{
- if (commentDictionary.TryGetValue(comment.Id, out var existing))
+ if (CommentDictionary.TryGetValue(comment.Id, out var existing))
return existing;
- return commentDictionary[comment.Id] = new DrawableComment(comment)
+ return CommentDictionary[comment.Id] = new DrawableComment(comment)
{
ShowDeleted = { BindTarget = ShowDeleted },
Sort = { BindTarget = Sort },
@@ -81,31 +81,28 @@ namespace osu.Game.Overlays.Comments
{
var request = new GetCommentsRequest(CommentableId.Value, Type.Value, Sort.Value, page, drawableComment.Comment.Id);
- request.Success += response => Schedule(() => appendComments(response));
+ request.Success += response => Schedule(() => AppendComments(response));
api.PerformAsync(request);
}
- private readonly Dictionary commentDictionary = new Dictionary();
+ protected readonly Dictionary CommentDictionary = new Dictionary();
///
/// Appends retrieved comments to the subtree rooted of comments in this page.
///
/// The bundle of comments to add.
- private void appendComments([NotNull] CommentBundle bundle)
+ protected void AppendComments([NotNull] CommentBundle bundle)
{
var orphaned = new List();
- foreach (var topLevel in bundle.Comments)
- addNewComment(topLevel);
-
- foreach (var child in bundle.IncludedComments)
+ foreach (var comment in bundle.Comments.Concat(bundle.IncludedComments))
{
- // Included comments can contain the parent comment, which already exists in the hierarchy.
- if (commentDictionary.ContainsKey(child.Id))
+ // Exclude possible duplicated comments.
+ if (CommentDictionary.ContainsKey(comment.Id))
continue;
- addNewComment(child);
+ addNewComment(comment);
}
// Comments whose parents were seen later than themselves can now be added.
@@ -121,7 +118,7 @@ namespace osu.Game.Overlays.Comments
// Comments that have no parent are added as top-level comments to the flow.
flow.Add(drawableComment);
}
- else if (commentDictionary.TryGetValue(comment.ParentId.Value, out var parentDrawable))
+ else if (CommentDictionary.TryGetValue(comment.ParentId.Value, out var parentDrawable))
{
// The comment's parent has already been seen, so the parent<-> child links can be added.
comment.ParentComment = parentDrawable.Comment;
diff --git a/osu.Game/Overlays/Home/Friends/UserListToolbar.cs b/osu.Game/Overlays/Home/Friends/UserListToolbar.cs
new file mode 100644
index 0000000000..f7c5e9f4fd
--- /dev/null
+++ b/osu.Game/Overlays/Home/Friends/UserListToolbar.cs
@@ -0,0 +1,45 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osuTK;
+using osu.Framework.Bindables;
+
+namespace osu.Game.Overlays.Home.Friends
+{
+ public class UserListToolbar : CompositeDrawable
+ {
+ public Bindable SortCriteria => sortControl.Current;
+
+ public Bindable DisplayStyle => styleControl.Current;
+
+ private readonly UserSortTabControl sortControl;
+ private readonly OverlayPanelDisplayStyleControl styleControl;
+
+ public UserListToolbar()
+ {
+ AutoSizeAxes = Axes.Both;
+
+ AddInternal(new FillFlowContainer
+ {
+ AutoSizeAxes = Axes.Both,
+ Direction = FillDirection.Horizontal,
+ Spacing = new Vector2(10, 0),
+ Children = new Drawable[]
+ {
+ sortControl = new UserSortTabControl
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ },
+ styleControl = new OverlayPanelDisplayStyleControl
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ }
+ }
+ });
+ }
+ }
+}
diff --git a/osu.Game/Overlays/Home/Friends/UserSortTabControl.cs b/osu.Game/Overlays/Home/Friends/UserSortTabControl.cs
new file mode 100644
index 0000000000..2479fa4638
--- /dev/null
+++ b/osu.Game/Overlays/Home/Friends/UserSortTabControl.cs
@@ -0,0 +1,19 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System.ComponentModel;
+
+namespace osu.Game.Overlays.Home.Friends
+{
+ public class UserSortTabControl : OverlaySortTabControl
+ {
+ }
+
+ public enum UserSortCriteria
+ {
+ [Description(@"Recently Active")]
+ LastVisit,
+ Rank,
+ Username
+ }
+}
diff --git a/osu.Game/Overlays/OverlayPanelDisplayStyleControl.cs b/osu.Game/Overlays/OverlayPanelDisplayStyleControl.cs
new file mode 100644
index 0000000000..7269007b41
--- /dev/null
+++ b/osu.Game/Overlays/OverlayPanelDisplayStyleControl.cs
@@ -0,0 +1,101 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Framework.Graphics.Sprites;
+using osu.Framework.Graphics.UserInterface;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osuTK;
+using osu.Framework.Input.Events;
+using osu.Game.Graphics.UserInterface;
+using osu.Framework.Allocation;
+using osuTK.Graphics;
+using osu.Framework.Graphics.Cursor;
+
+namespace osu.Game.Overlays
+{
+ public class OverlayPanelDisplayStyleControl : OsuTabControl
+ {
+ protected override Dropdown CreateDropdown() => null;
+
+ protected override TabItem CreateTabItem(OverlayPanelDisplayStyle value) => new PanelDisplayTabItem(value);
+
+ protected override bool AddEnumEntriesAutomatically => false;
+
+ public OverlayPanelDisplayStyleControl()
+ {
+ AutoSizeAxes = Axes.Both;
+
+ AddTabItem(new PanelDisplayTabItem(OverlayPanelDisplayStyle.Card)
+ {
+ Icon = FontAwesome.Solid.Square
+ });
+ AddTabItem(new PanelDisplayTabItem(OverlayPanelDisplayStyle.List)
+ {
+ Icon = FontAwesome.Solid.Bars
+ });
+ }
+
+ protected override TabFillFlowContainer CreateTabFlow() => new TabFillFlowContainer
+ {
+ AutoSizeAxes = Axes.Both,
+ Direction = FillDirection.Horizontal
+ };
+
+ private class PanelDisplayTabItem : TabItem, IHasTooltip
+ {
+ public IconUsage Icon
+ {
+ set => icon.Icon = value;
+ }
+
+ [Resolved]
+ private OverlayColourProvider colourProvider { get; set; }
+
+ public string TooltipText => $@"{Value} view";
+
+ private readonly SpriteIcon icon;
+
+ public PanelDisplayTabItem(OverlayPanelDisplayStyle value)
+ : base(value)
+ {
+ Size = new Vector2(11);
+ AddRange(new Drawable[]
+ {
+ icon = new SpriteIcon
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ RelativeSizeAxes = Axes.Both,
+ FillMode = FillMode.Fit
+ },
+ new HoverClickSounds()
+ });
+ }
+
+ protected override void OnActivated() => updateState();
+
+ protected override void OnDeactivated() => updateState();
+
+ protected override bool OnHover(HoverEvent e)
+ {
+ updateState();
+ return base.OnHover(e);
+ }
+
+ protected override void OnHoverLost(HoverLostEvent e)
+ {
+ updateState();
+ base.OnHoverLost(e);
+ }
+
+ private void updateState() => icon.Colour = Active.Value || IsHovered ? colourProvider.Light1 : Color4.White;
+ }
+ }
+
+ public enum OverlayPanelDisplayStyle
+ {
+ Card,
+ List
+ }
+}
diff --git a/osu.Game/Overlays/OverlaySortTabControl.cs b/osu.Game/Overlays/OverlaySortTabControl.cs
index 5a713ab08e..395f3aec4c 100644
--- a/osu.Game/Overlays/OverlaySortTabControl.cs
+++ b/osu.Game/Overlays/OverlaySortTabControl.cs
@@ -15,6 +15,8 @@ using osu.Game.Graphics.Sprites;
using osuTK.Graphics;
using osu.Game.Overlays.Comments;
using JetBrains.Annotations;
+using System;
+using osu.Framework.Extensions;
namespace osu.Game.Overlays
{
@@ -132,7 +134,7 @@ namespace osu.Game.Overlays
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Font = OsuFont.GetFont(size: 12),
- Text = value.ToString()
+ Text = (value as Enum)?.GetDescription() ?? value.ToString()
}
}
});
diff --git a/osu.Game/Overlays/RankingsOverlay.cs b/osu.Game/Overlays/RankingsOverlay.cs
index 3304c6ebec..afb23883ac 100644
--- a/osu.Game/Overlays/RankingsOverlay.cs
+++ b/osu.Game/Overlays/RankingsOverlay.cs
@@ -138,6 +138,12 @@ namespace osu.Game.Overlays
Country.Value = requested;
}
+ public void ShowSpotlights()
+ {
+ Scope.Value = RankingsScope.Spotlights;
+ Show();
+ }
+
private void loadNewContent()
{
loading.Show();
diff --git a/osu.Game.Rulesets.Taiko/Judgements/TaikoSwellTickJudgement.cs b/osu.Game/Rulesets/Judgements/IgnoreJudgement.cs
similarity index 63%
rename from osu.Game.Rulesets.Taiko/Judgements/TaikoSwellTickJudgement.cs
rename to osu.Game/Rulesets/Judgements/IgnoreJudgement.cs
index b28b6a0d17..1871249c94 100644
--- a/osu.Game.Rulesets.Taiko/Judgements/TaikoSwellTickJudgement.cs
+++ b/osu.Game/Rulesets/Judgements/IgnoreJudgement.cs
@@ -1,11 +1,11 @@
-// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Game.Rulesets.Scoring;
-namespace osu.Game.Rulesets.Taiko.Judgements
+namespace osu.Game.Rulesets.Judgements
{
- public class TaikoSwellTickJudgement : TaikoJudgement
+ public class IgnoreJudgement : Judgement
{
public override bool AffectsCombo => false;
diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs
index 67fe18e8dd..9a5e25c8ac 100644
--- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs
+++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs
@@ -99,12 +99,9 @@ namespace osu.Game.Rulesets.Objects.Drawables
{
var judgement = HitObject.CreateJudgement();
- if (judgement != null)
- {
- Result = CreateResult(judgement);
- if (Result == null)
- throw new InvalidOperationException($"{GetType().ReadableName()} must provide a {nameof(JudgementResult)} through {nameof(CreateResult)}.");
- }
+ Result = CreateResult(judgement);
+ if (Result == null)
+ throw new InvalidOperationException($"{GetType().ReadableName()} must provide a {nameof(JudgementResult)} through {nameof(CreateResult)}.");
loadSamples();
}
@@ -265,7 +262,7 @@ namespace osu.Game.Rulesets.Objects.Drawables
}
}
- if (state.Value != ArmedState.Idle && LifetimeEnd == double.MaxValue)
+ if (state.Value != ArmedState.Idle && LifetimeEnd == double.MaxValue || HitObject.HitWindows == null)
Expire();
}
else
diff --git a/osu.Game/Rulesets/Objects/HitObject.cs b/osu.Game/Rulesets/Objects/HitObject.cs
index c09844e0c6..9a8efdde84 100644
--- a/osu.Game/Rulesets/Objects/HitObject.cs
+++ b/osu.Game/Rulesets/Objects/HitObject.cs
@@ -144,9 +144,9 @@ namespace osu.Game.Rulesets.Objects
///
/// Creates the that represents the scoring information for this .
- /// May be null.
///
- public virtual Judgement CreateJudgement() => null;
+ [NotNull]
+ public virtual Judgement CreateJudgement() => new Judgement();
///
/// Creates the for this .
diff --git a/osu.Game/Rulesets/Objects/Legacy/Catch/ConvertHit.cs b/osu.Game/Rulesets/Objects/Legacy/Catch/ConvertHit.cs
index febfd3696c..19722fb796 100644
--- a/osu.Game/Rulesets/Objects/Legacy/Catch/ConvertHit.cs
+++ b/osu.Game/Rulesets/Objects/Legacy/Catch/ConvertHit.cs
@@ -8,7 +8,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Catch
///
/// Legacy osu!catch Hit-type, used for parsing Beatmaps.
///
- internal sealed class ConvertHit : HitObject, IHasCombo, IHasXPosition
+ internal sealed class ConvertHit : ConvertHitObject, IHasCombo, IHasXPosition
{
public float X { get; set; }
diff --git a/osu.Game/Rulesets/Objects/Legacy/Catch/ConvertSpinner.cs b/osu.Game/Rulesets/Objects/Legacy/Catch/ConvertSpinner.cs
index 0089d1eb88..9de311c9d7 100644
--- a/osu.Game/Rulesets/Objects/Legacy/Catch/ConvertSpinner.cs
+++ b/osu.Game/Rulesets/Objects/Legacy/Catch/ConvertSpinner.cs
@@ -8,7 +8,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Catch
///
/// Legacy osu!catch Spinner-type, used for parsing Beatmaps.
///
- internal sealed class ConvertSpinner : HitObject, IHasEndTime, IHasXPosition, IHasCombo
+ internal sealed class ConvertSpinner : ConvertHitObject, IHasEndTime, IHasXPosition, IHasCombo
{
public double EndTime { get; set; }
diff --git a/osu.Game/Rulesets/Objects/Legacy/ConvertHitObject.cs b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObject.cs
new file mode 100644
index 0000000000..e3b0d8a498
--- /dev/null
+++ b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObject.cs
@@ -0,0 +1,18 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Game.Rulesets.Judgements;
+using osu.Game.Rulesets.Scoring;
+
+namespace osu.Game.Rulesets.Objects.Legacy
+{
+ ///
+ /// A hit object only used for conversion, not actual gameplay.
+ ///
+ internal abstract class ConvertHitObject : HitObject
+ {
+ public override Judgement CreateJudgement() => new IgnoreJudgement();
+
+ protected override HitWindows CreateHitWindows() => HitWindows.Empty;
+ }
+}
diff --git a/osu.Game/Rulesets/Objects/Legacy/ConvertSlider.cs b/osu.Game/Rulesets/Objects/Legacy/ConvertSlider.cs
index 53cdf457c4..924182b265 100644
--- a/osu.Game/Rulesets/Objects/Legacy/ConvertSlider.cs
+++ b/osu.Game/Rulesets/Objects/Legacy/ConvertSlider.cs
@@ -9,7 +9,7 @@ using osu.Game.Beatmaps.ControlPoints;
namespace osu.Game.Rulesets.Objects.Legacy
{
- internal abstract class ConvertSlider : HitObject, IHasCurve, IHasLegacyLastTickOffset
+ internal abstract class ConvertSlider : ConvertHitObject, IHasCurve, IHasLegacyLastTickOffset
{
///
/// Scoring distance with a speed-adjusted beat length of 1 second.
diff --git a/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHit.cs b/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHit.cs
index 883ef55df0..0b69817c13 100644
--- a/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHit.cs
+++ b/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHit.cs
@@ -2,17 +2,14 @@
// See the LICENCE file in the repository root for full licence text.
using osu.Game.Rulesets.Objects.Types;
-using osu.Game.Rulesets.Scoring;
namespace osu.Game.Rulesets.Objects.Legacy.Mania
{
///
/// Legacy osu!mania Hit-type, used for parsing Beatmaps.
///
- internal sealed class ConvertHit : HitObject, IHasXPosition
+ internal sealed class ConvertHit : ConvertHitObject, IHasXPosition
{
public float X { get; set; }
-
- protected override HitWindows CreateHitWindows() => HitWindows.Empty;
}
}
diff --git a/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHold.cs b/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHold.cs
index 69e6f8379d..1d92d638dd 100644
--- a/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHold.cs
+++ b/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHold.cs
@@ -2,18 +2,15 @@
// See the LICENCE file in the repository root for full licence text.
using osu.Game.Rulesets.Objects.Types;
-using osu.Game.Rulesets.Scoring;
namespace osu.Game.Rulesets.Objects.Legacy.Mania
{
- internal sealed class ConvertHold : HitObject, IHasXPosition, IHasEndTime
+ internal sealed class ConvertHold : ConvertHitObject, IHasXPosition, IHasEndTime
{
public float X { get; set; }
public double EndTime { get; set; }
public double Duration => EndTime - StartTime;
-
- protected override HitWindows CreateHitWindows() => HitWindows.Empty;
}
}
diff --git a/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertSlider.cs b/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertSlider.cs
index 4486c5d906..84cde5fa95 100644
--- a/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertSlider.cs
+++ b/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertSlider.cs
@@ -2,7 +2,6 @@
// See the LICENCE file in the repository root for full licence text.
using osu.Game.Rulesets.Objects.Types;
-using osu.Game.Rulesets.Scoring;
namespace osu.Game.Rulesets.Objects.Legacy.Mania
{
@@ -12,7 +11,5 @@ namespace osu.Game.Rulesets.Objects.Legacy.Mania
internal sealed class ConvertSlider : Legacy.ConvertSlider, IHasXPosition
{
public float X { get; set; }
-
- protected override HitWindows CreateHitWindows() => HitWindows.Empty;
}
}
diff --git a/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertSpinner.cs b/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertSpinner.cs
index c6d1f1922c..7dc13e27cd 100644
--- a/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertSpinner.cs
+++ b/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertSpinner.cs
@@ -2,21 +2,18 @@
// See the LICENCE file in the repository root for full licence text.
using osu.Game.Rulesets.Objects.Types;
-using osu.Game.Rulesets.Scoring;
namespace osu.Game.Rulesets.Objects.Legacy.Mania
{
///
/// Legacy osu!mania Spinner-type, used for parsing Beatmaps.
///
- internal sealed class ConvertSpinner : HitObject, IHasEndTime, IHasXPosition
+ internal sealed class ConvertSpinner : ConvertHitObject, IHasEndTime, IHasXPosition
{
public double EndTime { get; set; }
public double Duration => EndTime - StartTime;
public float X { get; set; }
-
- protected override HitWindows CreateHitWindows() => HitWindows.Empty;
}
}
diff --git a/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertHit.cs b/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertHit.cs
index e40b5b4505..069366bad3 100644
--- a/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertHit.cs
+++ b/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertHit.cs
@@ -2,7 +2,6 @@
// See the LICENCE file in the repository root for full licence text.
using osu.Game.Rulesets.Objects.Types;
-using osu.Game.Rulesets.Scoring;
using osuTK;
namespace osu.Game.Rulesets.Objects.Legacy.Osu
@@ -10,7 +9,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Osu
///
/// Legacy osu! Hit-type, used for parsing Beatmaps.
///
- internal sealed class ConvertHit : HitObject, IHasPosition, IHasCombo
+ internal sealed class ConvertHit : ConvertHitObject, IHasPosition, IHasCombo
{
public Vector2 Position { get; set; }
@@ -21,7 +20,5 @@ namespace osu.Game.Rulesets.Objects.Legacy.Osu
public bool NewCombo { get; set; }
public int ComboOffset { get; set; }
-
- protected override HitWindows CreateHitWindows() => HitWindows.Empty;
}
}
diff --git a/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertSlider.cs b/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertSlider.cs
index a163329d47..e947690668 100644
--- a/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertSlider.cs
+++ b/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertSlider.cs
@@ -2,7 +2,6 @@
// See the LICENCE file in the repository root for full licence text.
using osu.Game.Rulesets.Objects.Types;
-using osu.Game.Rulesets.Scoring;
using osuTK;
namespace osu.Game.Rulesets.Objects.Legacy.Osu
@@ -21,7 +20,5 @@ namespace osu.Game.Rulesets.Objects.Legacy.Osu
public bool NewCombo { get; set; }
public int ComboOffset { get; set; }
-
- protected override HitWindows CreateHitWindows() => HitWindows.Empty;
}
}
diff --git a/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertSpinner.cs b/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertSpinner.cs
index 5d96a61633..8b21aab411 100644
--- a/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertSpinner.cs
+++ b/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertSpinner.cs
@@ -2,7 +2,6 @@
// See the LICENCE file in the repository root for full licence text.
using osu.Game.Rulesets.Objects.Types;
-using osu.Game.Rulesets.Scoring;
using osuTK;
namespace osu.Game.Rulesets.Objects.Legacy.Osu
@@ -10,7 +9,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Osu
///
/// Legacy osu! Spinner-type, used for parsing Beatmaps.
///
- internal sealed class ConvertSpinner : HitObject, IHasEndTime, IHasPosition, IHasCombo
+ internal sealed class ConvertSpinner : ConvertHitObject, IHasEndTime, IHasPosition, IHasCombo
{
public double EndTime { get; set; }
@@ -22,8 +21,6 @@ namespace osu.Game.Rulesets.Objects.Legacy.Osu
public float Y => Position.Y;
- protected override HitWindows CreateHitWindows() => HitWindows.Empty;
-
public bool NewCombo { get; set; }
public int ComboOffset { get; set; }
diff --git a/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertHit.cs b/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertHit.cs
index efb9810927..cb5178ce48 100644
--- a/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertHit.cs
+++ b/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertHit.cs
@@ -1,15 +1,12 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-using osu.Game.Rulesets.Scoring;
-
namespace osu.Game.Rulesets.Objects.Legacy.Taiko
{
///
/// Legacy osu!taiko Hit-type, used for parsing Beatmaps.
///
- internal sealed class ConvertHit : HitObject
+ internal sealed class ConvertHit : ConvertHitObject
{
- protected override HitWindows CreateHitWindows() => HitWindows.Empty;
}
}
diff --git a/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertSlider.cs b/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertSlider.cs
index b365fd34ae..821554f7ee 100644
--- a/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertSlider.cs
+++ b/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertSlider.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-using osu.Game.Rulesets.Scoring;
-
namespace osu.Game.Rulesets.Objects.Legacy.Taiko
{
///
@@ -10,6 +8,5 @@ namespace osu.Game.Rulesets.Objects.Legacy.Taiko
///
internal sealed class ConvertSlider : Legacy.ConvertSlider
{
- protected override HitWindows CreateHitWindows() => HitWindows.Empty;
}
}
diff --git a/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertSpinner.cs b/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertSpinner.cs
index 840ba51ac2..8e28487f2f 100644
--- a/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertSpinner.cs
+++ b/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertSpinner.cs
@@ -2,19 +2,16 @@
// See the LICENCE file in the repository root for full licence text.
using osu.Game.Rulesets.Objects.Types;
-using osu.Game.Rulesets.Scoring;
namespace osu.Game.Rulesets.Objects.Legacy.Taiko
{
///
/// Legacy osu!taiko Spinner-type, used for parsing Beatmaps.
///
- internal sealed class ConvertSpinner : HitObject, IHasEndTime
+ internal sealed class ConvertSpinner : ConvertHitObject, IHasEndTime
{
public double EndTime { get; set; }
public double Duration => EndTime - StartTime;
-
- protected override HitWindows CreateHitWindows() => HitWindows.Empty;
}
}
diff --git a/osu.Game/Rulesets/Scoring/JudgementProcessor.cs b/osu.Game/Rulesets/Scoring/JudgementProcessor.cs
index 3016007f98..334b95f808 100644
--- a/osu.Game/Rulesets/Scoring/JudgementProcessor.cs
+++ b/osu.Game/Rulesets/Scoring/JudgementProcessor.cs
@@ -125,8 +125,6 @@ namespace osu.Game.Rulesets.Scoring
simulate(nested);
var judgement = obj.CreateJudgement();
- if (judgement == null)
- return;
var result = CreateResult(obj, judgement);
if (result == null)
diff --git a/osu.Game/Screens/Charts/ChartInfo.cs b/osu.Game/Screens/Charts/ChartInfo.cs
deleted file mode 100644
index d9a9ad5eeb..0000000000
--- a/osu.Game/Screens/Charts/ChartInfo.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
-// See the LICENCE file in the repository root for full licence text.
-
-namespace osu.Game.Screens.Charts
-{
- public class ChartInfo : ScreenWhiteBox
- {
- }
-}
diff --git a/osu.Game/Screens/Charts/ChartListing.cs b/osu.Game/Screens/Charts/ChartListing.cs
deleted file mode 100644
index 18bba6433f..0000000000
--- a/osu.Game/Screens/Charts/ChartListing.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
-// See the LICENCE file in the repository root for full licence text.
-
-using System;
-using System.Collections.Generic;
-
-namespace osu.Game.Screens.Charts
-{
- public class ChartListing : ScreenWhiteBox
- {
- protected override IEnumerable PossibleChildren => new[]
- {
- typeof(ChartInfo)
- };
- }
-}
diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs
index 3bec4b8f6f..3a6f02f811 100644
--- a/osu.Game/Screens/Edit/Editor.cs
+++ b/osu.Game/Screens/Edit/Editor.cs
@@ -93,15 +93,15 @@ namespace osu.Game.Screens.Edit
EditorMenuBar menuBar;
- var fileMenuItems = new List