diff --git a/osu.Android.props b/osu.Android.props
index 215a9a8090..0f6e32d664 100644
--- a/osu.Android.props
+++ b/osu.Android.props
@@ -61,6 +61,6 @@
-
+
diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs
index 33f93cdb4a..406c0af28d 100644
--- a/osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs
+++ b/osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs
@@ -15,6 +15,7 @@ using osu.Framework.Graphics.Sprites;
using osuTK.Graphics;
using osu.Framework.Audio.Sample;
using osu.Framework.Graphics.Textures;
+using osu.Game.Audio;
namespace osu.Game.Rulesets.Catch.Tests
{
@@ -92,7 +93,7 @@ namespace osu.Game.Rulesets.Catch.Tests
return null;
}
- public SampleChannel GetSample(string sampleName) =>
+ public SampleChannel GetSample(ISampleInfo sampleInfo) =>
throw new NotImplementedException();
public Texture GetTexture(string componentName) =>
diff --git a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableCatchHitObject.cs b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableCatchHitObject.cs
index a1279e8443..f4218061d4 100644
--- a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableCatchHitObject.cs
+++ b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableCatchHitObject.cs
@@ -58,14 +58,12 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
ApplyResult(r => r.Type = CheckPosition.Invoke(HitObject) ? HitResult.Perfect : HitResult.Miss);
}
- protected override bool UseTransformStateManagement => false;
+ protected sealed override double InitialLifetimeOffset => HitObject.TimePreempt;
- protected override void UpdateState(ArmedState state)
+ protected override void UpdateInitialTransforms() => this.FadeIn(200);
+
+ protected override void UpdateStateTransforms(ArmedState state)
{
- // TODO: update to use new state management.
- using (BeginAbsoluteSequence(HitObject.StartTime - HitObject.TimePreempt))
- this.FadeIn(200);
-
var endTime = (HitObject as IHasEndTime)?.EndTime ?? HitObject.StartTime;
using (BeginAbsoluteSequence(endTime, true))
diff --git a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs
index 62abe53559..ceda643335 100644
--- a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs
+++ b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs
@@ -53,7 +53,7 @@ namespace osu.Game.Rulesets.Catch.UI
if (lastPlateableFruit == null)
return;
- // this is required to make this run after the last caught fruit runs UpdateState at least once.
+ // this is required to make this run after the last caught fruit runs updateState() at least once.
// TODO: find a better alternative
if (lastPlateableFruit.IsLoaded)
action();
diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableBarLine.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableBarLine.cs
index 9c3197504f..e9c352c97e 100644
--- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableBarLine.cs
+++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableBarLine.cs
@@ -69,7 +69,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
Alpha = 0.2f;
}
- protected override void UpdateState(ArmedState state)
+ protected override void UpdateStateTransforms(ArmedState state)
{
}
}
diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs
index 952c6e128e..fc3b6885d7 100644
--- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs
+++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs
@@ -8,6 +8,7 @@ using osu.Framework.Graphics;
using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
using osu.Framework.Graphics.Containers;
using osu.Framework.Input.Bindings;
+using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.UI.Scrolling;
@@ -104,6 +105,12 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
bodyPiece.Height = DrawHeight - Head.Height / 2 + Tail.Height / 2;
}
+ protected override void UpdateStateTransforms(ArmedState state)
+ {
+ using (BeginDelayedSequence(HitObject.Duration, true))
+ base.UpdateStateTransforms(state);
+ }
+
protected void BeginHold()
{
holdStartTime = Time.Current;
diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableManiaHitObject.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableManiaHitObject.cs
index db6b53e76d..ce1484d460 100644
--- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableManiaHitObject.cs
+++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableManiaHitObject.cs
@@ -45,24 +45,11 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
{
Anchor = Origin = e.NewValue == ScrollingDirection.Up ? Anchor.TopCentre : Anchor.BottomCentre;
}
- }
- public abstract class DrawableManiaHitObject : DrawableManiaHitObject
- where TObject : ManiaHitObject
- {
- public new readonly TObject HitObject;
+ protected override void UpdateInitialTransforms() => this.FadeIn();
- protected DrawableManiaHitObject(TObject hitObject)
- : base(hitObject)
+ protected override void UpdateStateTransforms(ArmedState state)
{
- HitObject = hitObject;
- }
-
- protected override bool UseTransformStateManagement => false;
-
- protected override void UpdateState(ArmedState state)
- {
- // TODO: update to use new state management.
switch (state)
{
case ArmedState.Miss:
@@ -75,4 +62,16 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
}
}
}
+
+ public abstract class DrawableManiaHitObject : DrawableManiaHitObject
+ where TObject : ManiaHitObject
+ {
+ public new readonly TObject HitObject;
+
+ protected DrawableManiaHitObject(TObject hitObject)
+ : base(hitObject)
+ {
+ HitObject = hitObject;
+ }
+ }
}
diff --git a/osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoPlayfield.cs b/osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoPlayfield.cs
index 6f9856df83..3c84d900a6 100644
--- a/osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoPlayfield.cs
+++ b/osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoPlayfield.cs
@@ -247,10 +247,6 @@ namespace osu.Game.Rulesets.Taiko.Tests
: base(hitObject)
{
}
-
- protected override void UpdateState(ArmedState state)
- {
- }
}
}
}
diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableBarLine.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableBarLine.cs
index f8909fb98c..bf89f7e15b 100644
--- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableBarLine.cs
+++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableBarLine.cs
@@ -53,9 +53,5 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
Alpha = 0.75f
});
}
-
- protected override void UpdateState(ArmedState state)
- {
- }
}
}
diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs
index 9b4df74a61..f4407a7b54 100644
--- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs
+++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs
@@ -88,13 +88,13 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
ApplyResult(r => r.Type = HitResult.Miss);
}
- protected override void UpdateState(ArmedState state)
+ protected override void UpdateStateTransforms(ArmedState state)
{
switch (state)
{
case ArmedState.Hit:
case ArmedState.Miss:
- this.FadeOut(100).Expire();
+ this.Delay(HitObject.Duration).FadeOut(100).Expire();
break;
}
}
diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRollTick.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRollTick.cs
index 9259c693d9..cef9a53deb 100644
--- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRollTick.cs
+++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRollTick.cs
@@ -39,7 +39,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
ApplyResult(r => r.Type = HitResult.Great);
}
- protected override void UpdateState(ArmedState state)
+ protected override void UpdateStateTransforms(ArmedState state)
{
switch (state)
{
diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs
index 34ae7db984..fa45067210 100644
--- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs
+++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs
@@ -92,56 +92,42 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
Size = BaseSize * Parent.RelativeChildSize;
}
- protected override void UpdateState(ArmedState state)
+ protected override void UpdateStateTransforms(ArmedState state)
{
- // TODO: update to use new state management.
- var circlePiece = MainPiece as CirclePiece;
- circlePiece?.FlashBox.FinishTransforms();
-
- var offset = !AllJudged ? 0 : Time.Current - HitObject.StartTime;
-
- using (BeginDelayedSequence(HitObject.StartTime - Time.Current + offset, true))
+ switch (state)
{
- switch (State.Value)
- {
- case ArmedState.Idle:
- validActionPressed = false;
+ case ArmedState.Idle:
+ validActionPressed = false;
- UnproxyContent();
- this.Delay(HitObject.HitWindows.HalfWindowFor(HitResult.Miss)).Expire();
- break;
+ UnproxyContent();
+ this.Delay(HitObject.HitWindows.HalfWindowFor(HitResult.Miss)).Expire();
+ break;
- case ArmedState.Miss:
- this.FadeOut(100)
- .Expire();
- break;
+ case ArmedState.Miss:
+ this.FadeOut(100)
+ .Expire();
+ break;
- case ArmedState.Hit:
- // If we're far enough away from the left stage, we should bring outselves in front of it
- ProxyContent();
+ case ArmedState.Hit:
+ // If we're far enough away from the left stage, we should bring outselves in front of it
+ ProxyContent();
- var flash = circlePiece?.FlashBox;
+ var flash = (MainPiece as CirclePiece)?.FlashBox;
+ flash?.FadeTo(0.9f).FadeOut(300);
- if (flash != null)
- {
- flash.FadeTo(0.9f);
- flash.FadeOut(300);
- }
+ const float gravity_time = 300;
+ const float gravity_travel_height = 200;
- const float gravity_time = 300;
- const float gravity_travel_height = 200;
+ this.ScaleTo(0.8f, gravity_time * 2, Easing.OutQuad);
- this.ScaleTo(0.8f, gravity_time * 2, Easing.OutQuad);
+ this.MoveToY(-gravity_travel_height, gravity_time, Easing.Out)
+ .Then()
+ .MoveToY(gravity_travel_height * 2, gravity_time * 2, Easing.In);
- this.MoveToY(-gravity_travel_height, gravity_time, Easing.Out)
- .Then()
- .MoveToY(gravity_travel_height * 2, gravity_time * 2, Easing.In);
+ this.FadeOut(800)
+ .Expire();
- this.FadeOut(800)
- .Expire();
-
- break;
- }
+ break;
}
}
diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableStrongNestedHit.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableStrongNestedHit.cs
index 98a2e8a721..108e42eea5 100644
--- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableStrongNestedHit.cs
+++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableStrongNestedHit.cs
@@ -18,9 +18,5 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
{
MainObject = mainObject;
}
-
- protected override void UpdateState(ArmedState state)
- {
- }
}
}
diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs
index 82448ec7d5..094ad1230f 100644
--- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs
+++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs
@@ -25,6 +25,11 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
private const float target_ring_scale = 5f;
private const float inner_ring_alpha = 0.65f;
+ ///
+ /// Offset away from the start time of the swell at which the ring starts appearing.
+ ///
+ private const double ring_appear_offset = 100;
+
private readonly List ticks = new List();
private readonly Container bodyContainer;
@@ -179,26 +184,34 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
}
}
- protected override void UpdateState(ArmedState state)
+ protected override void UpdateInitialTransforms()
{
- const float preempt = 100;
- const float out_transition_time = 300;
+ base.UpdateInitialTransforms();
+
+ using (BeginAbsoluteSequence(HitObject.StartTime - ring_appear_offset, true))
+ targetRing.ScaleTo(target_ring_scale, 400, Easing.OutQuint);
+ }
+
+ protected override void UpdateStateTransforms(ArmedState state)
+ {
+ const double transition_duration = 300;
switch (state)
{
case ArmedState.Idle:
- UnproxyContent();
expandingRing.FadeTo(0);
- using (BeginAbsoluteSequence(HitObject.StartTime - preempt, true))
- targetRing.ScaleTo(target_ring_scale, preempt * 4, Easing.OutQuint);
break;
case ArmedState.Miss:
case ArmedState.Hit:
- this.FadeOut(out_transition_time, Easing.Out);
- bodyContainer.ScaleTo(1.4f, out_transition_time);
+ using (BeginAbsoluteSequence(Time.Current, true))
+ {
+ this.FadeOut(transition_duration, Easing.Out);
+ bodyContainer.ScaleTo(1.4f, transition_duration);
+
+ Expire();
+ }
- Expire();
break;
}
}
@@ -212,9 +225,10 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
// Make the swell stop at the hit target
X = Math.Max(0, X);
- double t = Math.Min(HitObject.StartTime, Time.Current);
- if (t == HitObject.StartTime)
+ if (Time.Current >= HitObject.StartTime - ring_appear_offset)
ProxyContent();
+ else
+ UnproxyContent();
}
private bool? lastWasCentre;
diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwellTick.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwellTick.cs
index 41a8fd9a75..8b27d78101 100644
--- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwellTick.cs
+++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwellTick.cs
@@ -1,7 +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.Objects.Drawables;
using osu.Game.Rulesets.Scoring;
namespace osu.Game.Rulesets.Taiko.Objects.Drawables
@@ -21,10 +20,6 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
{
}
- protected override void UpdateState(ArmedState state)
- {
- }
-
public override bool OnPressed(TaikoAction action) => false;
}
}
diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs
index b46738c69a..5f3bab5b28 100644
--- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs
+++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs
@@ -78,10 +78,31 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
public abstract bool OnPressed(TaikoAction action);
public virtual bool OnReleased(TaikoAction action) => false;
+ protected override void UpdateInitialTransforms() => this.FadeIn();
+
+ public override double LifetimeStart
+ {
+ get => base.LifetimeStart;
+ set
+ {
+ base.LifetimeStart = value;
+ proxiedContent.LifetimeStart = value;
+ }
+ }
+
+ public override double LifetimeEnd
+ {
+ get => base.LifetimeEnd;
+ set
+ {
+ base.LifetimeEnd = value;
+ proxiedContent.LifetimeEnd = value;
+ }
+ }
+
private class ProxiedContentContainer : Container
{
- public override double LifetimeStart => Parent?.LifetimeStart ?? base.LifetimeStart;
- public override double LifetimeEnd => Parent?.LifetimeEnd ?? base.LifetimeEnd;
+ public override bool RemoveWhenNotAlive => false;
}
}
@@ -121,8 +142,6 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
}
}
- protected override bool UseTransformStateManagement => false;
-
// Normal and clap samples are handled by the drum
protected override IEnumerable GetSamples() => HitObject.Samples.Where(s => s.Name != HitSampleInfo.HIT_NORMAL && s.Name != HitSampleInfo.HIT_CLAP);
diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs
index e62dc45cab..a10f70a344 100644
--- a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs
+++ b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs
@@ -44,9 +44,8 @@ namespace osu.Game.Rulesets.Taiko.UI
private readonly JudgementContainer judgementContainer;
internal readonly HitTarget HitTarget;
- private readonly Container topLevelHitContainer;
-
- private readonly Container barlineContainer;
+ private readonly ProxyContainer topLevelHitContainer;
+ private readonly ProxyContainer barlineContainer;
private readonly Container overlayBackgroundContainer;
private readonly Container backgroundContainer;
@@ -108,7 +107,7 @@ namespace osu.Game.Rulesets.Taiko.UI
}
}
},
- barlineContainer = new Container
+ barlineContainer = new ProxyContainer
{
RelativeSizeAxes = Axes.Both,
Padding = new MarginPadding { Left = HIT_TARGET_OFFSET }
@@ -183,7 +182,7 @@ namespace osu.Game.Rulesets.Taiko.UI
}
}
},
- topLevelHitContainer = new Container
+ topLevelHitContainer = new ProxyContainer
{
Name = "Top level hit objects",
RelativeSizeAxes = Axes.Both,
@@ -256,5 +255,15 @@ namespace osu.Game.Rulesets.Taiko.UI
break;
}
}
+
+ private class ProxyContainer : LifetimeManagementContainer
+ {
+ public new MarginPadding Padding
+ {
+ set => base.Padding = value;
+ }
+
+ public void Add(Drawable proxy) => AddInternal(proxy);
+ }
}
}
diff --git a/osu.Game.Tests/Beatmaps/Formats/LegacyStoryboardDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/LegacyStoryboardDecoderTest.cs
index 971518909d..953763c95d 100644
--- a/osu.Game.Tests/Beatmaps/Formats/LegacyStoryboardDecoderTest.cs
+++ b/osu.Game.Tests/Beatmaps/Formats/LegacyStoryboardDecoderTest.cs
@@ -58,7 +58,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
int spriteCount = background.Elements.Count(x => x.GetType() == typeof(StoryboardSprite));
int animationCount = background.Elements.Count(x => x.GetType() == typeof(StoryboardAnimation));
- int sampleCount = background.Elements.Count(x => x.GetType() == typeof(StoryboardSample));
+ int sampleCount = background.Elements.Count(x => x.GetType() == typeof(StoryboardSampleInfo));
Assert.AreEqual(15, spriteCount);
Assert.AreEqual(1, animationCount);
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneScrollingHitObjects.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneScrollingHitObjects.cs
index 0a9cdc6a8e..aa80819694 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneScrollingHitObjects.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneScrollingHitObjects.cs
@@ -200,10 +200,6 @@ namespace osu.Game.Tests.Visual.Gameplay
break;
}
}
-
- protected override void UpdateState(ArmedState state)
- {
- }
}
private class TestDrawableHitObject : DrawableHitObject
@@ -216,10 +212,6 @@ namespace osu.Game.Tests.Visual.Gameplay
AddInternal(new Box { Size = new Vector2(75) });
}
-
- protected override void UpdateState(ArmedState state)
- {
- }
}
}
}
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableDrawable.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableDrawable.cs
index 0b5978e3eb..6c003e62ec 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableDrawable.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableDrawable.cs
@@ -10,6 +10,7 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Textures;
+using osu.Game.Audio;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Game.Skinning;
@@ -253,7 +254,7 @@ namespace osu.Game.Tests.Visual.Gameplay
public Texture GetTexture(string componentName) => throw new NotImplementedException();
- public SampleChannel GetSample(string sampleName) => throw new NotImplementedException();
+ public SampleChannel GetSample(ISampleInfo sampleInfo) => throw new NotImplementedException();
public TValue GetValue(Func query) where TConfiguration : SkinConfiguration => throw new NotImplementedException();
}
@@ -264,7 +265,7 @@ namespace osu.Game.Tests.Visual.Gameplay
public Texture GetTexture(string componentName) => throw new NotImplementedException();
- public SampleChannel GetSample(string sampleName) => throw new NotImplementedException();
+ public SampleChannel GetSample(ISampleInfo sampleInfo) => throw new NotImplementedException();
public TValue GetValue(Func query) where TConfiguration : SkinConfiguration => throw new NotImplementedException();
}
@@ -275,7 +276,7 @@ namespace osu.Game.Tests.Visual.Gameplay
public Texture GetTexture(string componentName) => throw new NotImplementedException();
- public SampleChannel GetSample(string sampleName) => throw new NotImplementedException();
+ public SampleChannel GetSample(ISampleInfo sampleInfo) => throw new NotImplementedException();
public TValue GetValue(Func query) where TConfiguration : SkinConfiguration => throw new NotImplementedException();
}
diff --git a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs
index 680250a226..263eada07c 100644
--- a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs
+++ b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs
@@ -15,6 +15,7 @@ using osu.Framework.MathUtils;
using osu.Framework.Platform;
using osu.Framework.Screens;
using osu.Game.Beatmaps;
+using osu.Game.Configuration;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Osu;
@@ -79,8 +80,12 @@ namespace osu.Game.Tests.Visual.SongSelect
Dependencies.Cache(manager = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, host, defaultBeatmap = Beatmap.Default));
Beatmap.SetDefault();
+
+ Dependencies.Cache(config = new OsuConfigManager(LocalStorage));
}
+ private OsuConfigManager config;
+
[SetUp]
public virtual void SetUp() => Schedule(() =>
{
@@ -111,13 +116,15 @@ namespace osu.Game.Tests.Visual.SongSelect
AddAssert("random map selected", () => songSelect.CurrentBeatmap != defaultBeatmap);
- AddStep(@"Sort by Artist", delegate { songSelect.FilterControl.Sort = SortMode.Artist; });
- AddStep(@"Sort by Title", delegate { songSelect.FilterControl.Sort = SortMode.Title; });
- AddStep(@"Sort by Author", delegate { songSelect.FilterControl.Sort = SortMode.Author; });
- AddStep(@"Sort by DateAdded", delegate { songSelect.FilterControl.Sort = SortMode.DateAdded; });
- AddStep(@"Sort by BPM", delegate { songSelect.FilterControl.Sort = SortMode.BPM; });
- AddStep(@"Sort by Length", delegate { songSelect.FilterControl.Sort = SortMode.Length; });
- AddStep(@"Sort by Difficulty", delegate { songSelect.FilterControl.Sort = SortMode.Difficulty; });
+ var sortMode = config.GetBindable(OsuSetting.SongSelectSortingMode);
+
+ AddStep(@"Sort by Artist", delegate { sortMode.Value = SortMode.Artist; });
+ AddStep(@"Sort by Title", delegate { sortMode.Value = SortMode.Title; });
+ AddStep(@"Sort by Author", delegate { sortMode.Value = SortMode.Author; });
+ AddStep(@"Sort by DateAdded", delegate { sortMode.Value = SortMode.DateAdded; });
+ AddStep(@"Sort by BPM", delegate { sortMode.Value = SortMode.BPM; });
+ AddStep(@"Sort by Length", delegate { sortMode.Value = SortMode.Length; });
+ AddStep(@"Sort by Difficulty", delegate { sortMode.Value = SortMode.Difficulty; });
}
[Test]
diff --git a/osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs
index 17df9ccc7e..14c6ea5c8e 100644
--- a/osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs
+++ b/osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs
@@ -121,7 +121,7 @@ namespace osu.Game.Beatmaps.Formats
var layer = parseLayer(split[2]);
var path = cleanFilename(split[3]);
var volume = split.Length > 4 ? float.Parse(split[4], CultureInfo.InvariantCulture) : 100;
- storyboard.GetLayer(layer).Add(new StoryboardSample(path, time, volume));
+ storyboard.GetLayer(layer).Add(new StoryboardSampleInfo(path, time, (int)volume));
break;
}
}
diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs
index 19f46c1d6a..b13e115387 100644
--- a/osu.Game/Configuration/OsuConfigManager.cs
+++ b/osu.Game/Configuration/OsuConfigManager.cs
@@ -8,6 +8,7 @@ using osu.Framework.Platform;
using osu.Game.Overlays;
using osu.Game.Rulesets.Scoring;
using osu.Game.Screens.Select;
+using osu.Game.Screens.Select.Filter;
namespace osu.Game.Configuration
{
@@ -25,6 +26,9 @@ namespace osu.Game.Configuration
Set(OsuSetting.DisplayStarsMinimum, 0.0, 0, 10, 0.1);
Set(OsuSetting.DisplayStarsMaximum, 10.0, 0, 10, 0.1);
+ Set(OsuSetting.SongSelectGroupingMode, GroupMode.All);
+ Set(OsuSetting.SongSelectSortingMode, SortMode.Title);
+
Set(OsuSetting.RandomSelectAlgorithm, RandomSelectAlgorithm.RandomPermutation);
Set(OsuSetting.ChatDisplayHeight, ChatOverlay.DEFAULT_HEIGHT, 0.2, 1);
@@ -150,6 +154,8 @@ namespace osu.Game.Configuration
SaveUsername,
DisplayStarsMinimum,
DisplayStarsMaximum,
+ SongSelectGroupingMode,
+ SongSelectSortingMode,
RandomSelectAlgorithm,
ShowFpsDisplay,
ChatDisplayHeight,
diff --git a/osu.Game/Graphics/ScreenshotManager.cs b/osu.Game/Graphics/ScreenshotManager.cs
index 524a4742c0..f532302de2 100644
--- a/osu.Game/Graphics/ScreenshotManager.cs
+++ b/osu.Game/Graphics/ScreenshotManager.cs
@@ -22,7 +22,7 @@ using SixLabors.ImageSharp;
namespace osu.Game.Graphics
{
- public class ScreenshotManager : Container, IKeyBindingHandler, IHandleGlobalInput
+ public class ScreenshotManager : Container, IKeyBindingHandler, IHandleGlobalKeyboardInput
{
private readonly BindableBool cursorVisibility = new BindableBool(true);
diff --git a/osu.Game/Input/Bindings/GlobalActionContainer.cs b/osu.Game/Input/Bindings/GlobalActionContainer.cs
index b70072a222..bf758e21d9 100644
--- a/osu.Game/Input/Bindings/GlobalActionContainer.cs
+++ b/osu.Game/Input/Bindings/GlobalActionContainer.cs
@@ -10,7 +10,7 @@ using osu.Framework.Input.Bindings;
namespace osu.Game.Input.Bindings
{
- public class GlobalActionContainer : DatabasedKeyBindingContainer, IHandleGlobalInput
+ public class GlobalActionContainer : DatabasedKeyBindingContainer, IHandleGlobalKeyboardInput
{
private readonly Drawable handler;
diff --git a/osu.Game/Input/IdleTracker.cs b/osu.Game/Input/IdleTracker.cs
index cbc446a126..39ccf9fe1c 100644
--- a/osu.Game/Input/IdleTracker.cs
+++ b/osu.Game/Input/IdleTracker.cs
@@ -12,7 +12,7 @@ namespace osu.Game.Input
///
/// Track whether the end-user is in an idle state, based on their last interaction with the game.
///
- public class IdleTracker : Component, IKeyBindingHandler, IHandleGlobalInput
+ public class IdleTracker : Component, IKeyBindingHandler, IHandleGlobalKeyboardInput
{
private readonly double timeToIdle;
diff --git a/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs b/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs
index 8a6b52b7ee..919f8a2fa0 100644
--- a/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs
+++ b/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs
@@ -1,21 +1,22 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-using System.Linq;
+using System.Collections.Generic;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
+using osu.Game.Online.API;
using osu.Game.Online.API.Requests;
+using osu.Game.Online.API.Requests.Responses;
using osu.Game.Overlays.Direct;
using osu.Game.Users;
using osuTK;
namespace osu.Game.Overlays.Profile.Sections.Beatmaps
{
- public class PaginatedBeatmapContainer : PaginatedContainer
+ public class PaginatedBeatmapContainer : PaginatedContainer
{
private const float panel_padding = 10f;
private readonly BeatmapSetType type;
- private GetUserBeatmapsRequest request;
public PaginatedBeatmapContainer(BeatmapSetType type, Bindable user, string header, string missing = "None... yet.")
: base(user, header, missing)
@@ -27,40 +28,15 @@ namespace osu.Game.Overlays.Profile.Sections.Beatmaps
ItemsContainer.Spacing = new Vector2(panel_padding);
}
- protected override void ShowMore()
- {
- request = new GetUserBeatmapsRequest(User.Value.Id, type, VisiblePages++, ItemsPerPage);
- request.Success += sets => Schedule(() =>
+ protected override APIRequest> CreateRequest() =>
+ new GetUserBeatmapsRequest(User.Value.Id, type, VisiblePages++, ItemsPerPage);
+
+ protected override Drawable CreateDrawableItem(APIBeatmapSet model) => !model.OnlineBeatmapSetID.HasValue
+ ? null
+ : new DirectGridPanel(model.ToBeatmapSet(Rulesets))
{
- MoreButton.FadeTo(sets.Count == ItemsPerPage ? 1 : 0);
- MoreButton.IsLoading = false;
-
- if (!sets.Any() && VisiblePages == 1)
- {
- MissingText.Show();
- return;
- }
-
- foreach (var s in sets)
- {
- if (!s.OnlineBeatmapSetID.HasValue)
- continue;
-
- ItemsContainer.Add(new DirectGridPanel(s.ToBeatmapSet(Rulesets))
- {
- Anchor = Anchor.TopCentre,
- Origin = Anchor.TopCentre,
- });
- }
- });
-
- Api.Queue(request);
- }
-
- protected override void Dispose(bool isDisposing)
- {
- base.Dispose(isDisposing);
- request?.Cancel();
- }
+ Anchor = Anchor.TopCentre,
+ Origin = Anchor.TopCentre,
+ };
}
}
diff --git a/osu.Game/Overlays/Profile/Sections/Historical/PaginatedMostPlayedBeatmapContainer.cs b/osu.Game/Overlays/Profile/Sections/Historical/PaginatedMostPlayedBeatmapContainer.cs
index 23072f8d90..6e6d6272c7 100644
--- a/osu.Game/Overlays/Profile/Sections/Historical/PaginatedMostPlayedBeatmapContainer.cs
+++ b/osu.Game/Overlays/Profile/Sections/Historical/PaginatedMostPlayedBeatmapContainer.cs
@@ -1,19 +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.Linq;
+using System.Collections.Generic;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
+using osu.Game.Online.API;
using osu.Game.Online.API.Requests;
+using osu.Game.Online.API.Requests.Responses;
using osu.Game.Users;
namespace osu.Game.Overlays.Profile.Sections.Historical
{
- public class PaginatedMostPlayedBeatmapContainer : PaginatedContainer
+ public class PaginatedMostPlayedBeatmapContainer : PaginatedContainer
{
- private GetUserMostPlayedBeatmapsRequest request;
-
public PaginatedMostPlayedBeatmapContainer(Bindable user)
: base(user, "Most Played Beatmaps", "No records. :(")
{
@@ -22,35 +22,10 @@ namespace osu.Game.Overlays.Profile.Sections.Historical
ItemsContainer.Direction = FillDirection.Vertical;
}
- protected override void ShowMore()
- {
- request = new GetUserMostPlayedBeatmapsRequest(User.Value.Id, VisiblePages++, ItemsPerPage);
- request.Success += beatmaps => Schedule(() =>
- {
- MoreButton.FadeTo(beatmaps.Count == ItemsPerPage ? 1 : 0);
- MoreButton.IsLoading = false;
+ protected override APIRequest> CreateRequest() =>
+ new GetUserMostPlayedBeatmapsRequest(User.Value.Id, VisiblePages++, ItemsPerPage);
- if (!beatmaps.Any() && VisiblePages == 1)
- {
- MissingText.Show();
- return;
- }
-
- MissingText.Hide();
-
- foreach (var beatmap in beatmaps)
- {
- ItemsContainer.Add(new DrawableMostPlayedBeatmap(beatmap.GetBeatmapInfo(Rulesets), beatmap.PlayCount));
- }
- });
-
- Api.Queue(request);
- }
-
- protected override void Dispose(bool isDisposing)
- {
- base.Dispose(isDisposing);
- request?.Cancel();
- }
+ protected override Drawable CreateDrawableItem(APIUserMostPlayedBeatmap model) =>
+ new DrawableMostPlayedBeatmap(model.GetBeatmapInfo(Rulesets), model.PlayCount);
}
}
diff --git a/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs b/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs
index b459afcb49..bb221bd43a 100644
--- a/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs
+++ b/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs
@@ -11,22 +11,27 @@ using osu.Game.Graphics.Sprites;
using osu.Game.Online.API;
using osu.Game.Rulesets;
using osu.Game.Users;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
namespace osu.Game.Overlays.Profile.Sections
{
- public abstract class PaginatedContainer : FillFlowContainer
+ public abstract class PaginatedContainer : FillFlowContainer
{
- protected readonly FillFlowContainer ItemsContainer;
- protected readonly ShowMoreButton MoreButton;
- protected readonly OsuSpriteText MissingText;
+ private readonly ShowMoreButton moreButton;
+ private readonly OsuSpriteText missingText;
+ private APIRequest> retrievalRequest;
+ private CancellationTokenSource loadCancellation;
+
+ [Resolved]
+ private IAPIProvider api { get; set; }
protected int VisiblePages;
protected int ItemsPerPage;
protected readonly Bindable User = new Bindable();
-
- protected IAPIProvider Api;
- protected APIRequest RetrievalRequest;
+ protected readonly FillFlowContainer ItemsContainer;
protected RulesetStore Rulesets;
protected PaginatedContainer(Bindable user, string header, string missing)
@@ -51,15 +56,15 @@ namespace osu.Game.Overlays.Profile.Sections
RelativeSizeAxes = Axes.X,
Spacing = new Vector2(0, 2),
},
- MoreButton = new ShowMoreButton
+ moreButton = new ShowMoreButton
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
Alpha = 0,
Margin = new MarginPadding { Top = 10 },
- Action = ShowMore,
+ Action = showMore,
},
- MissingText = new OsuSpriteText
+ missingText = new OsuSpriteText
{
Font = OsuFont.GetFont(size: 15),
Text = missing,
@@ -69,9 +74,8 @@ namespace osu.Game.Overlays.Profile.Sections
}
[BackgroundDependencyLoader]
- private void load(IAPIProvider api, RulesetStore rulesets)
+ private void load(RulesetStore rulesets)
{
- Api = api;
Rulesets = rulesets;
User.ValueChanged += onUserChanged;
@@ -80,13 +84,54 @@ namespace osu.Game.Overlays.Profile.Sections
private void onUserChanged(ValueChangedEvent e)
{
+ loadCancellation?.Cancel();
+ retrievalRequest?.Cancel();
+
VisiblePages = 0;
ItemsContainer.Clear();
if (e.NewValue != null)
- ShowMore();
+ showMore();
}
- protected abstract void ShowMore();
+ private void showMore()
+ {
+ loadCancellation = new CancellationTokenSource();
+
+ retrievalRequest = CreateRequest();
+ retrievalRequest.Success += UpdateItems;
+
+ api.Queue(retrievalRequest);
+ }
+
+ protected virtual void UpdateItems(List items) => Schedule(() =>
+ {
+ if (!items.Any() && VisiblePages == 1)
+ {
+ moreButton.Hide();
+ moreButton.IsLoading = false;
+ missingText.Show();
+ return;
+ }
+
+ LoadComponentsAsync(items.Select(CreateDrawableItem).Where(d => d != null), drawables =>
+ {
+ missingText.Hide();
+ moreButton.FadeTo(items.Count == ItemsPerPage ? 1 : 0);
+ moreButton.IsLoading = false;
+
+ ItemsContainer.AddRange(drawables);
+ }, loadCancellation.Token);
+ });
+
+ protected abstract APIRequest> CreateRequest();
+
+ protected abstract Drawable CreateDrawableItem(TModel model);
+
+ protected override void Dispose(bool isDisposing)
+ {
+ base.Dispose(isDisposing);
+ retrievalRequest?.Cancel();
+ }
}
}
diff --git a/osu.Game/Overlays/Profile/Sections/Ranks/PaginatedScoreContainer.cs b/osu.Game/Overlays/Profile/Sections/Ranks/PaginatedScoreContainer.cs
index 4a9ac6e5c7..853b9db0a7 100644
--- a/osu.Game/Overlays/Profile/Sections/Ranks/PaginatedScoreContainer.cs
+++ b/osu.Game/Overlays/Profile/Sections/Ranks/PaginatedScoreContainer.cs
@@ -5,18 +5,18 @@ using osu.Framework.Graphics.Containers;
using osu.Game.Online.API.Requests;
using osu.Game.Users;
using System;
-using System.Collections.Generic;
-using System.Linq;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
+using osu.Game.Online.API.Requests.Responses;
+using System.Collections.Generic;
+using osu.Game.Online.API;
namespace osu.Game.Overlays.Profile.Sections.Ranks
{
- public class PaginatedScoreContainer : PaginatedContainer
+ public class PaginatedScoreContainer : PaginatedContainer
{
private readonly bool includeWeight;
private readonly ScoreType type;
- private GetUserScoresRequest request;
public PaginatedScoreContainer(ScoreType type, Bindable user, string header, string missing, bool includeWeight = false)
: base(user, header, missing)
@@ -29,52 +29,27 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks
ItemsContainer.Direction = FillDirection.Vertical;
}
- protected override void ShowMore()
+ protected override void UpdateItems(List items)
{
- request = new GetUserScoresRequest(User.Value.Id, type, VisiblePages++, ItemsPerPage);
- request.Success += scores => Schedule(() =>
- {
- foreach (var s in scores)
- s.Ruleset = Rulesets.GetRuleset(s.RulesetID);
+ foreach (var item in items)
+ item.Ruleset = Rulesets.GetRuleset(item.RulesetID);
- if (!scores.Any() && VisiblePages == 1)
- {
- MoreButton.Hide();
- MoreButton.IsLoading = false;
- MissingText.Show();
- return;
- }
-
- IEnumerable drawableScores;
-
- switch (type)
- {
- default:
- drawableScores = scores.Select(score => new DrawablePerformanceScore(score, includeWeight ? Math.Pow(0.95, ItemsContainer.Count) : (double?)null));
- break;
-
- case ScoreType.Recent:
- drawableScores = scores.Select(score => new DrawableTotalScore(score));
- break;
- }
-
- LoadComponentsAsync(drawableScores, s =>
- {
- MissingText.Hide();
- MoreButton.FadeTo(scores.Count == ItemsPerPage ? 1 : 0);
- MoreButton.IsLoading = false;
-
- ItemsContainer.AddRange(s);
- });
- });
-
- Api.Queue(request);
+ base.UpdateItems(items);
}
- protected override void Dispose(bool isDisposing)
+ protected override APIRequest> CreateRequest() =>
+ new GetUserScoresRequest(User.Value.Id, type, VisiblePages++, ItemsPerPage);
+
+ protected override Drawable CreateDrawableItem(APILegacyScoreInfo model)
{
- base.Dispose(isDisposing);
- request?.Cancel();
+ switch (type)
+ {
+ default:
+ return new DrawablePerformanceScore(model, includeWeight ? Math.Pow(0.95, ItemsContainer.Count) : (double?)null);
+
+ case ScoreType.Recent:
+ return new DrawableTotalScore(model);
+ }
}
}
}
diff --git a/osu.Game/Overlays/Profile/Sections/Recent/PaginatedRecentActivityContainer.cs b/osu.Game/Overlays/Profile/Sections/Recent/PaginatedRecentActivityContainer.cs
index f2a778a874..3f9d4dc93e 100644
--- a/osu.Game/Overlays/Profile/Sections/Recent/PaginatedRecentActivityContainer.cs
+++ b/osu.Game/Overlays/Profile/Sections/Recent/PaginatedRecentActivityContainer.cs
@@ -4,51 +4,24 @@
using osu.Framework.Graphics;
using osu.Game.Online.API.Requests;
using osu.Game.Users;
-using System.Linq;
using osu.Framework.Bindables;
using osu.Game.Online.API.Requests.Responses;
+using osu.Game.Online.API;
+using System.Collections.Generic;
namespace osu.Game.Overlays.Profile.Sections.Recent
{
- public class PaginatedRecentActivityContainer : PaginatedContainer
+ public class PaginatedRecentActivityContainer : PaginatedContainer
{
- private GetUserRecentActivitiesRequest request;
-
public PaginatedRecentActivityContainer(Bindable user, string header, string missing)
: base(user, header, missing)
{
ItemsPerPage = 5;
}
- protected override void ShowMore()
- {
- request = new GetUserRecentActivitiesRequest(User.Value.Id, VisiblePages++, ItemsPerPage);
- request.Success += activities => Schedule(() =>
- {
- MoreButton.FadeTo(activities.Count == ItemsPerPage ? 1 : 0);
- MoreButton.IsLoading = false;
+ protected override APIRequest> CreateRequest() =>
+ new GetUserRecentActivitiesRequest(User.Value.Id, VisiblePages++, ItemsPerPage);
- if (!activities.Any() && VisiblePages == 1)
- {
- MissingText.Show();
- return;
- }
-
- MissingText.Hide();
-
- foreach (APIRecentActivity activity in activities)
- {
- ItemsContainer.Add(new DrawableRecentActivity(activity));
- }
- });
-
- Api.Queue(request);
- }
-
- protected override void Dispose(bool isDisposing)
- {
- base.Dispose(isDisposing);
- request?.Cancel();
- }
+ protected override Drawable CreateDrawableItem(APIRecentActivity model) => new DrawableRecentActivity(model);
}
}
diff --git a/osu.Game/Overlays/Volume/VolumeControlReceptor.cs b/osu.Game/Overlays/Volume/VolumeControlReceptor.cs
index 26235fa280..9cd3aac2cb 100644
--- a/osu.Game/Overlays/Volume/VolumeControlReceptor.cs
+++ b/osu.Game/Overlays/Volume/VolumeControlReceptor.cs
@@ -9,7 +9,7 @@ using osu.Game.Input.Bindings;
namespace osu.Game.Overlays.Volume
{
- public class VolumeControlReceptor : Container, IScrollBindingHandler, IHandleGlobalInput
+ public class VolumeControlReceptor : Container, IScrollBindingHandler, IHandleGlobalKeyboardInput
{
public Func ActionRequested;
public Func ScrollActionRequested;
diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs
index b72a55b9ed..80e70589bd 100644
--- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs
+++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs
@@ -132,6 +132,8 @@ namespace osu.Game.Rulesets.Objects.Drawables
///
public event Action ApplyCustomUpdateState;
+#pragma warning disable 618 // (legacy state management) - can be removed 20200227
+
///
/// Enables automatic transform management of this hitobject. Implementation of transforms should be done in and only. Rewinding and removing previous states is done automatically.
///
@@ -139,6 +141,7 @@ namespace osu.Game.Rulesets.Objects.Drawables
/// Going forward, this is the preferred way of implementing s. Previous functionality
/// is offered as a compatibility layer until all rulesets have been migrated across.
///
+ [Obsolete("Use UpdateInitialTransforms()/UpdateStateTransforms() instead")] // can be removed 20200227
protected virtual bool UseTransformStateManagement => true;
protected override void ClearInternal(bool disposeChildren = true) => throw new InvalidOperationException($"Should never clear a {nameof(DrawableHitObject)}");
@@ -219,10 +222,13 @@ namespace osu.Game.Rulesets.Objects.Drawables
/// Should generally not be used when is true; use instead.
///
/// The new armed state.
+ [Obsolete("Use UpdateInitialTransforms()/UpdateStateTransforms() instead")] // can be removed 20200227
protected virtual void UpdateState(ArmedState state)
{
}
+#pragma warning restore 618
+
#endregion
protected override void SkinChanged(ISkinSource skin, bool allowFallback)
diff --git a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs
index 0a8c61e3d2..97b6a78804 100644
--- a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs
+++ b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs
@@ -220,14 +220,23 @@ namespace osu.Game.Screens.Select.Carousel
public class FilterableGroupedDifficultyIcon : GroupedDifficultyIcon
{
+ private readonly List items;
+
public FilterableGroupedDifficultyIcon(List items, RulesetInfo ruleset)
: base(items.Select(i => i.Beatmap).ToList(), ruleset, Color4.White)
{
- items.ForEach(item => item.Filtered.ValueChanged += _ =>
- {
- // for now, fade the whole group based on the ratio of hidden items.
- this.FadeTo(1 - 0.9f * ((float)items.Count(i => i.Filtered.Value) / items.Count), 100);
- });
+ this.items = items;
+
+ foreach (var item in items)
+ item.Filtered.BindValueChanged(_ => Scheduler.AddOnce(updateFilteredDisplay));
+
+ updateFilteredDisplay();
+ }
+
+ private void updateFilteredDisplay()
+ {
+ // for now, fade the whole group based on the ratio of hidden items.
+ this.FadeTo(1 - 0.9f * ((float)items.Count(i => i.Filtered.Value) / items.Count), 100);
}
}
}
diff --git a/osu.Game/Screens/Select/FilterControl.cs b/osu.Game/Screens/Select/FilterControl.cs
index 84e8e90f54..ed74b01fc9 100644
--- a/osu.Game/Screens/Select/FilterControl.cs
+++ b/osu.Game/Screens/Select/FilterControl.cs
@@ -29,40 +29,14 @@ namespace osu.Game.Screens.Select
private readonly TabControl groupTabs;
- private SortMode sort = SortMode.Title;
+ private Bindable sortMode;
- public SortMode Sort
- {
- get => sort;
- set
- {
- if (sort != value)
- {
- sort = value;
- FilterChanged?.Invoke(CreateCriteria());
- }
- }
- }
-
- private GroupMode group = GroupMode.All;
-
- public GroupMode Group
- {
- get => group;
- set
- {
- if (group != value)
- {
- group = value;
- FilterChanged?.Invoke(CreateCriteria());
- }
- }
- }
+ private Bindable groupMode;
public FilterCriteria CreateCriteria() => new FilterCriteria
{
- Group = group,
- Sort = sort,
+ Group = groupMode.Value,
+ Sort = sortMode.Value,
SearchText = searchTextBox.Text,
AllowConvertedBeatmaps = showConverted.Value,
Ruleset = ruleset.Value
@@ -122,7 +96,6 @@ namespace osu.Game.Screens.Select
Height = 24,
Width = 0.5f,
AutoSort = true,
- Current = { Value = GroupMode.Title }
},
//spriteText = new OsuSpriteText
//{
@@ -141,7 +114,6 @@ namespace osu.Game.Screens.Select
Width = 0.5f,
Height = 24,
AutoSort = true,
- Current = { Value = SortMode.Title }
}
}
},
@@ -153,8 +125,6 @@ namespace osu.Game.Screens.Select
groupTabs.PinItem(GroupMode.All);
groupTabs.PinItem(GroupMode.RecentlyPlayed);
- groupTabs.Current.ValueChanged += group => Group = group.NewValue;
- sortTabs.Current.ValueChanged += sort => Sort = sort.NewValue;
}
public void Deactivate()
@@ -184,7 +154,18 @@ namespace osu.Game.Screens.Select
showConverted.ValueChanged += _ => updateCriteria();
ruleset.BindTo(parentRuleset);
- ruleset.BindValueChanged(_ => updateCriteria(), true);
+ ruleset.BindValueChanged(_ => updateCriteria());
+
+ sortMode = config.GetBindable(OsuSetting.SongSelectSortingMode);
+ groupMode = config.GetBindable(OsuSetting.SongSelectGroupingMode);
+
+ sortTabs.Current.BindTo(sortMode);
+ groupTabs.Current.BindTo(groupMode);
+
+ groupMode.BindValueChanged(_ => updateCriteria());
+ sortMode.BindValueChanged(_ => updateCriteria());
+
+ updateCriteria();
}
private void updateCriteria() => FilterChanged?.Invoke(CreateCriteria());
diff --git a/osu.Game/Skinning/DefaultSkin.cs b/osu.Game/Skinning/DefaultSkin.cs
index c7556dddd5..6072bb64ed 100644
--- a/osu.Game/Skinning/DefaultSkin.cs
+++ b/osu.Game/Skinning/DefaultSkin.cs
@@ -4,6 +4,7 @@
using osu.Framework.Audio.Sample;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Textures;
+using osu.Game.Audio;
namespace osu.Game.Skinning
{
@@ -19,6 +20,6 @@ namespace osu.Game.Skinning
public override Texture GetTexture(string componentName) => null;
- public override SampleChannel GetSample(string sampleName) => null;
+ public override SampleChannel GetSample(ISampleInfo sampleInfo) => null;
}
}
diff --git a/osu.Game/Skinning/ISkin.cs b/osu.Game/Skinning/ISkin.cs
index 0e67a1897c..4867aba0a9 100644
--- a/osu.Game/Skinning/ISkin.cs
+++ b/osu.Game/Skinning/ISkin.cs
@@ -5,6 +5,7 @@ using System;
using osu.Framework.Audio.Sample;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Textures;
+using osu.Game.Audio;
namespace osu.Game.Skinning
{
@@ -17,7 +18,7 @@ namespace osu.Game.Skinning
Texture GetTexture(string componentName);
- SampleChannel GetSample(string sampleName);
+ SampleChannel GetSample(ISampleInfo sampleInfo);
TValue GetValue(Func query) where TConfiguration : SkinConfiguration;
}
diff --git a/osu.Game/Skinning/LegacySkin.cs b/osu.Game/Skinning/LegacySkin.cs
index 7bffe5d321..570ba1ced7 100644
--- a/osu.Game/Skinning/LegacySkin.cs
+++ b/osu.Game/Skinning/LegacySkin.cs
@@ -17,6 +17,7 @@ using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures;
using osu.Framework.IO.Stores;
using osu.Framework.Text;
+using osu.Game.Audio;
using osu.Game.Database;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
@@ -155,16 +156,55 @@ namespace osu.Game.Skinning
// Spacing value was reverse-engineered from the ratio of the rendered sprite size in the visual inspector vs the actual texture size
Spacing = new Vector2(-Configuration.HitCircleOverlap * 0.89f, 0)
};
-
- default:
- string lastPiece = componentName.Split('/').Last();
- componentName = componentName.StartsWith("Gameplay/taiko/") ? "taiko-" + lastPiece : lastPiece;
- break;
}
return getAnimation(componentName, animatable, looping);
}
+ public override Texture GetTexture(string componentName)
+ {
+ componentName = getFallbackName(componentName);
+
+ float ratio = 2;
+ var texture = Textures.Get($"{componentName}@2x");
+
+ if (texture == null)
+ {
+ ratio = 1;
+ texture = Textures.Get(componentName);
+ }
+
+ if (texture != null)
+ texture.ScaleAdjust = ratio;
+
+ return texture;
+ }
+
+ public override SampleChannel GetSample(ISampleInfo sampleInfo)
+ {
+ foreach (var lookup in sampleInfo.LookupNames)
+ {
+ var sample = Samples.Get(getFallbackName(lookup));
+
+ if (sample != null)
+ return sample;
+ }
+
+ if (sampleInfo is HitSampleInfo hsi)
+ // Try fallback to non-bank samples.
+ return Samples.Get(hsi.Name);
+
+ return null;
+ }
+
+ private bool hasFont(string fontName) => GetTexture($"{fontName}-0") != null;
+
+ private string getFallbackName(string componentName)
+ {
+ string lastPiece = componentName.Split('/').Last();
+ return componentName.StartsWith("Gameplay/taiko/") ? "taiko-" + lastPiece : lastPiece;
+ }
+
private Drawable getAnimation(string componentName, bool animatable, bool looping, string animationSeparator = "-")
{
Texture texture;
@@ -200,27 +240,6 @@ namespace osu.Game.Skinning
return null;
}
- public override Texture GetTexture(string componentName)
- {
- float ratio = 2;
- var texture = Textures.Get($"{componentName}@2x");
-
- if (texture == null)
- {
- ratio = 1;
- texture = Textures.Get(componentName);
- }
-
- if (texture != null)
- texture.ScaleAdjust = ratio;
-
- return texture;
- }
-
- public override SampleChannel GetSample(string sampleName) => Samples.Get(sampleName);
-
- private bool hasFont(string fontName) => GetTexture($"{fontName}-0") != null;
-
protected class LegacySkinResourceStore : IResourceStore
where T : INamedFileInfo
{
diff --git a/osu.Game/Skinning/LocalSkinOverrideContainer.cs b/osu.Game/Skinning/LocalSkinOverrideContainer.cs
index 7882e0f31b..fc36d1c8da 100644
--- a/osu.Game/Skinning/LocalSkinOverrideContainer.cs
+++ b/osu.Game/Skinning/LocalSkinOverrideContainer.cs
@@ -8,6 +8,7 @@ using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Textures;
+using osu.Game.Audio;
using osu.Game.Configuration;
namespace osu.Game.Skinning
@@ -49,13 +50,13 @@ namespace osu.Game.Skinning
return fallbackSource.GetTexture(componentName);
}
- public SampleChannel GetSample(string sampleName)
+ public SampleChannel GetSample(ISampleInfo sampleInfo)
{
SampleChannel sourceChannel;
- if (beatmapHitsounds.Value && (sourceChannel = skin?.GetSample(sampleName)) != null)
+ if (beatmapHitsounds.Value && (sourceChannel = skin?.GetSample(sampleInfo)) != null)
return sourceChannel;
- return fallbackSource?.GetSample(sampleName);
+ return fallbackSource?.GetSample(sampleInfo);
}
public TValue GetValue(Func query) where TConfiguration : SkinConfiguration
diff --git a/osu.Game/Skinning/Skin.cs b/osu.Game/Skinning/Skin.cs
index 09c0d3d0bc..027d9df8b8 100644
--- a/osu.Game/Skinning/Skin.cs
+++ b/osu.Game/Skinning/Skin.cs
@@ -5,6 +5,7 @@ using System;
using osu.Framework.Audio.Sample;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Textures;
+using osu.Game.Audio;
namespace osu.Game.Skinning
{
@@ -16,7 +17,7 @@ namespace osu.Game.Skinning
public abstract Drawable GetDrawableComponent(string componentName);
- public abstract SampleChannel GetSample(string sampleName);
+ public abstract SampleChannel GetSample(ISampleInfo sampleInfo);
public abstract Texture GetTexture(string componentName);
diff --git a/osu.Game/Skinning/SkinManager.cs b/osu.Game/Skinning/SkinManager.cs
index 19997e8844..e747a8b1ce 100644
--- a/osu.Game/Skinning/SkinManager.cs
+++ b/osu.Game/Skinning/SkinManager.cs
@@ -15,6 +15,7 @@ using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Textures;
using osu.Framework.Platform;
+using osu.Game.Audio;
using osu.Game.Database;
using osu.Game.IO.Archives;
@@ -120,7 +121,7 @@ namespace osu.Game.Skinning
public Texture GetTexture(string componentName) => CurrentSkin.Value.GetTexture(componentName);
- public SampleChannel GetSample(string sampleName) => CurrentSkin.Value.GetSample(sampleName);
+ public SampleChannel GetSample(ISampleInfo sampleInfo) => CurrentSkin.Value.GetSample(sampleInfo);
public TValue GetValue(Func query) where TConfiguration : SkinConfiguration => CurrentSkin.Value.GetValue(query);
}
diff --git a/osu.Game/Skinning/SkinnableSound.cs b/osu.Game/Skinning/SkinnableSound.cs
index 8e2b5cec98..dcb14b4412 100644
--- a/osu.Game/Skinning/SkinnableSound.cs
+++ b/osu.Game/Skinning/SkinnableSound.cs
@@ -1,7 +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 System;
using System.Collections.Generic;
using System.Linq;
using osu.Framework.Allocation;
@@ -37,34 +36,26 @@ namespace osu.Game.Skinning
public void Play() => channels?.ForEach(c => c.Play());
- public override bool IsPresent => false; // We don't need to receive updates.
+ public override bool IsPresent => Scheduler.HasPendingTasks;
protected override void SkinChanged(ISkinSource skin, bool allowFallback)
{
channels = hitSamples.Select(s =>
{
- var ch = loadChannel(s, skin.GetSample);
+ var ch = skin.GetSample(s);
+
if (ch == null && allowFallback)
- ch = loadChannel(s, audio.Samples.Get);
+ foreach (var lookup in s.LookupNames)
+ if ((ch = audio.Samples.Get($"Gameplay/{lookup}")) != null)
+ break;
+
+ if (ch != null)
+ ch.Volume.Value = s.Volume / 100.0;
+
return ch;
}).Where(c => c != null).ToArray();
}
- private SampleChannel loadChannel(ISampleInfo info, Func getSampleFunction)
- {
- foreach (var lookup in info.LookupNames)
- {
- var ch = getSampleFunction($"Gameplay/{lookup}");
- if (ch == null)
- continue;
-
- ch.Volume.Value = info.Volume / 100.0;
- return ch;
- }
-
- return null;
- }
-
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
diff --git a/osu.Game/Storyboards/Drawables/DrawableStoryboardSample.cs b/osu.Game/Storyboards/Drawables/DrawableStoryboardSample.cs
index ffd238d4e1..b04f1d4518 100644
--- a/osu.Game/Storyboards/Drawables/DrawableStoryboardSample.cs
+++ b/osu.Game/Storyboards/Drawables/DrawableStoryboardSample.cs
@@ -1,7 +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 System.IO;
using osu.Framework.Allocation;
using osu.Framework.Audio.Sample;
using osu.Framework.Bindables;
@@ -17,25 +16,24 @@ namespace osu.Game.Storyboards.Drawables
///
private const double allowable_late_start = 100;
- private readonly StoryboardSample sample;
+ private readonly StoryboardSampleInfo sampleInfo;
private SampleChannel channel;
public override bool RemoveWhenNotAlive => false;
- public DrawableStoryboardSample(StoryboardSample sample)
+ public DrawableStoryboardSample(StoryboardSampleInfo sampleInfo)
{
- this.sample = sample;
- LifetimeStart = sample.StartTime;
+ this.sampleInfo = sampleInfo;
+ LifetimeStart = sampleInfo.StartTime;
}
[BackgroundDependencyLoader]
private void load(IBindable beatmap)
{
- // Try first with the full name, then attempt with no path
- channel = beatmap.Value.Skin.GetSample(sample.Path) ?? beatmap.Value.Skin.GetSample(Path.ChangeExtension(sample.Path, null));
+ channel = beatmap.Value.Skin.GetSample(sampleInfo);
if (channel != null)
- channel.Volume.Value = sample.Volume / 100;
+ channel.Volume.Value = sampleInfo.Volume / 100.0;
}
protected override void Update()
@@ -43,27 +41,27 @@ namespace osu.Game.Storyboards.Drawables
base.Update();
// TODO: this logic will need to be consolidated with other game samples like hit sounds.
- if (Time.Current < sample.StartTime)
+ if (Time.Current < sampleInfo.StartTime)
{
// We've rewound before the start time of the sample
channel?.Stop();
// In the case that the user fast-forwards to a point far beyond the start time of the sample,
// we want to be able to fall into the if-conditional below (therefore we must not have a life time end)
- LifetimeStart = sample.StartTime;
+ LifetimeStart = sampleInfo.StartTime;
LifetimeEnd = double.MaxValue;
}
- else if (Time.Current - Time.Elapsed < sample.StartTime)
+ else if (Time.Current - Time.Elapsed < sampleInfo.StartTime)
{
// We've passed the start time of the sample. We only play the sample if we're within an allowable range
// from the sample's start, to reduce layering if we've been fast-forwarded far into the future
- if (Time.Current - sample.StartTime < allowable_late_start)
+ if (Time.Current - sampleInfo.StartTime < allowable_late_start)
channel?.Play();
// In the case that the user rewinds to a point far behind the start time of the sample,
// we want to be able to fall into the if-conditional above (therefore we must not have a life time start)
LifetimeStart = double.MinValue;
- LifetimeEnd = sample.StartTime;
+ LifetimeEnd = sampleInfo.StartTime;
}
}
}
diff --git a/osu.Game/Storyboards/StoryboardSample.cs b/osu.Game/Storyboards/StoryboardSample.cs
index 24231cdca6..5d6ce215f5 100644
--- a/osu.Game/Storyboards/StoryboardSample.cs
+++ b/osu.Game/Storyboards/StoryboardSample.cs
@@ -1,21 +1,30 @@
// 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 osu.Framework.Graphics;
+using osu.Game.Audio;
using osu.Game.Storyboards.Drawables;
namespace osu.Game.Storyboards
{
- public class StoryboardSample : IStoryboardElement
+ public class StoryboardSampleInfo : IStoryboardElement, ISampleInfo
{
- public string Path { get; set; }
+ public string Path { get; }
public bool IsDrawable => true;
public double StartTime { get; }
- public float Volume;
+ public int Volume { get; }
- public StoryboardSample(string path, double time, float volume)
+ public IEnumerable LookupNames => new[]
+ {
+ // Try first with the full name, then attempt with no path
+ Path,
+ System.IO.Path.ChangeExtension(Path, null),
+ };
+
+ public StoryboardSampleInfo(string path, double time, int volume)
{
Path = path;
StartTime = time;
diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj
index 4fe9119cef..d791909372 100644
--- a/osu.Game/osu.Game.csproj
+++ b/osu.Game/osu.Game.csproj
@@ -15,7 +15,7 @@
-
+
diff --git a/osu.iOS.props b/osu.iOS.props
index 82301549d7..9fc472bf40 100644
--- a/osu.iOS.props
+++ b/osu.iOS.props
@@ -118,8 +118,8 @@
-
-
+
+