diff --git a/osu.Android.props b/osu.Android.props
index 43c1302e54..8b31be3f12 100644
--- a/osu.Android.props
+++ b/osu.Android.props
@@ -62,6 +62,6 @@
-
+
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/NumberPiece.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/NumberPiece.cs
index 62c4ba5ee3..7c94568835 100644
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/NumberPiece.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/NumberPiece.cs
@@ -7,7 +7,6 @@ using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Effects;
using osu.Game.Graphics.Sprites;
using osuTK.Graphics;
-using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics;
using osu.Game.Skinning;
@@ -30,17 +29,15 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
Children = new Drawable[]
{
- new CircularContainer
+ new Container
{
Masking = true,
- Origin = Anchor.Centre,
EdgeEffect = new EdgeEffectParameters
{
Type = EdgeEffectType.Glow,
Radius = 60,
Colour = Color4.White.Opacity(0.5f),
},
- Child = new Box()
},
number = new SkinnableSpriteText(new OsuSkinComponent(OsuSkinComponents.HitCircleText), _ => new OsuSpriteText
{
diff --git a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs
index 7317771bac..cf084e838e 100644
--- a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs
+++ b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs
@@ -262,6 +262,21 @@ namespace osu.Game.Tests.Beatmaps.Formats
}
}
+ [Test]
+ public void TestTimingPointResetsSpeedMultiplier()
+ {
+ var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false };
+
+ using (var resStream = TestResources.OpenResource("timingpoint-speedmultiplier-reset.osu"))
+ using (var stream = new LineBufferedReader(resStream))
+ {
+ var controlPoints = decoder.Decode(stream).ControlPointInfo;
+
+ Assert.That(controlPoints.DifficultyPointAt(0).SpeedMultiplier, Is.EqualTo(0.5).Within(0.1));
+ Assert.That(controlPoints.DifficultyPointAt(2000).SpeedMultiplier, Is.EqualTo(1).Within(0.1));
+ }
+ }
+
[Test]
public void TestDecodeBeatmapColours()
{
@@ -362,6 +377,23 @@ namespace osu.Game.Tests.Beatmaps.Formats
}
}
+ [Test]
+ public void TestDecodeControlPointDifficultyChange()
+ {
+ var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false };
+
+ using (var resStream = TestResources.OpenResource("controlpoint-difficulty-multiplier.osu"))
+ using (var stream = new LineBufferedReader(resStream))
+ {
+ var controlPointInfo = decoder.Decode(stream).ControlPointInfo;
+
+ Assert.That(controlPointInfo.DifficultyPointAt(5).SpeedMultiplier, Is.EqualTo(1));
+ Assert.That(controlPointInfo.DifficultyPointAt(1000).SpeedMultiplier, Is.EqualTo(10));
+ Assert.That(controlPointInfo.DifficultyPointAt(2000).SpeedMultiplier, Is.EqualTo(1.8518518518518519d));
+ Assert.That(controlPointInfo.DifficultyPointAt(3000).SpeedMultiplier, Is.EqualTo(0.5));
+ }
+ }
+
[Test]
public void TestDecodeControlPointCustomSampleBank()
{
diff --git a/osu.Game.Tests/Resources/controlpoint-difficulty-multiplier.osu b/osu.Game.Tests/Resources/controlpoint-difficulty-multiplier.osu
new file mode 100644
index 0000000000..5f06fc33c8
--- /dev/null
+++ b/osu.Game.Tests/Resources/controlpoint-difficulty-multiplier.osu
@@ -0,0 +1,8 @@
+osu file format v7
+
+[TimingPoints]
+0,100,4,2,0,100,1,0
+12,500,4,2,0,100,1,0
+1000,-10,4,2,0,100,0,0
+2000,-54,4,2,0,100,0,0
+3000,-200,4,2,0,100,0,0
diff --git a/osu.Game.Tests/Resources/timingpoint-speedmultiplier-reset.osu b/osu.Game.Tests/Resources/timingpoint-speedmultiplier-reset.osu
new file mode 100644
index 0000000000..4512903c68
--- /dev/null
+++ b/osu.Game.Tests/Resources/timingpoint-speedmultiplier-reset.osu
@@ -0,0 +1,5 @@
+osu file format v14
+
+[TimingPoints]
+0,-200,4,1,0,100,0,0
+2000,100,1,1,0,100,1,0
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneReplaySettingsOverlay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneReplaySettingsOverlay.cs
index 944480243d..cdfb3beb19 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneReplaySettingsOverlay.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneReplaySettingsOverlay.cs
@@ -3,6 +3,7 @@
using NUnit.Framework;
using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
using osu.Game.Graphics.UserInterface;
using osu.Game.Screens.Play.HUD;
using osu.Game.Screens.Play.PlayerSettings;
@@ -20,6 +21,7 @@ namespace osu.Game.Tests.Visual.Gameplay
{
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
+ State = { Value = Visibility.Visible }
});
Add(container = new ExampleContainer());
diff --git a/osu.Game.Tests/Visual/Menus/TestSceneLoaderAnimation.cs b/osu.Game.Tests/Visual/Menus/TestSceneLoaderAnimation.cs
index 000832b784..61fed3013e 100644
--- a/osu.Game.Tests/Visual/Menus/TestSceneLoaderAnimation.cs
+++ b/osu.Game.Tests/Visual/Menus/TestSceneLoaderAnimation.cs
@@ -33,23 +33,15 @@ namespace osu.Game.Tests.Visual.Menus
[Test]
public void TestInstantLoad()
{
- bool logoVisible = false;
+ // visual only, very impossible to test this using asserts.
- AddStep("begin loading", () =>
+ AddStep("load immediately", () =>
{
loader = new TestLoader();
loader.AllowLoad.Set();
LoadScreen(loader);
});
-
- AddUntilStep("loaded", () =>
- {
- logoVisible = loader.Logo?.Alpha > 0;
- return loader.Logo != null && loader.ScreenLoaded;
- });
-
- AddAssert("logo was not visible", () => !logoVisible);
}
[Test]
@@ -58,7 +50,7 @@ namespace osu.Game.Tests.Visual.Menus
AddStep("begin loading", () => LoadScreen(loader = new TestLoader()));
AddUntilStep("wait for logo visible", () => loader.Logo?.Alpha > 0);
AddStep("finish loading", () => loader.AllowLoad.Set());
- AddAssert("loaded", () => loader.Logo != null && loader.ScreenLoaded);
+ AddUntilStep("loaded", () => loader.Logo != null && loader.ScreenLoaded);
AddUntilStep("logo gone", () => loader.Logo?.Alpha == 0);
}
diff --git a/osu.Game.Tests/Visual/Online/TestSceneStandAloneChatDisplay.cs b/osu.Game.Tests/Visual/Online/TestSceneStandAloneChatDisplay.cs
index 39c2fbfcc9..01400bf1d9 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneStandAloneChatDisplay.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneStandAloneChatDisplay.cs
@@ -7,6 +7,10 @@ using osu.Game.Online.Chat;
using osu.Game.Users;
using osuTK;
using System;
+using System.Linq;
+using osu.Framework.Graphics.Containers;
+using osu.Game.Graphics.Containers;
+using osu.Game.Overlays.Chat;
namespace osu.Game.Tests.Visual.Online
{
@@ -42,14 +46,14 @@ namespace osu.Game.Tests.Visual.Online
[Cached]
private ChannelManager channelManager = new ChannelManager();
- private readonly StandAloneChatDisplay chatDisplay;
- private readonly StandAloneChatDisplay chatDisplay2;
+ private readonly TestStandAloneChatDisplay chatDisplay;
+ private readonly TestStandAloneChatDisplay chatDisplay2;
public TestSceneStandAloneChatDisplay()
{
Add(channelManager);
- Add(chatDisplay = new StandAloneChatDisplay
+ Add(chatDisplay = new TestStandAloneChatDisplay
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
@@ -57,7 +61,7 @@ namespace osu.Game.Tests.Visual.Online
Size = new Vector2(400, 80)
});
- Add(chatDisplay2 = new StandAloneChatDisplay(true)
+ Add(chatDisplay2 = new TestStandAloneChatDisplay(true)
{
Anchor = Anchor.CentreRight,
Origin = Anchor.CentreRight,
@@ -119,6 +123,49 @@ namespace osu.Game.Tests.Visual.Online
Content = "Message from the future!",
Timestamp = DateTimeOffset.Now
}));
+
+ AddUntilStep("ensure still scrolled to bottom", () => chatDisplay.ScrolledToBottom);
+
+ const int messages_per_call = 10;
+ AddRepeatStep("add many messages", () =>
+ {
+ for (int i = 0; i < messages_per_call; i++)
+ testChannel.AddNewMessages(new Message(sequence++)
+ {
+ Sender = longUsernameUser,
+ Content = "Many messages! " + Guid.NewGuid(),
+ Timestamp = DateTimeOffset.Now
+ });
+ }, Channel.MAX_HISTORY / messages_per_call + 5);
+
+ AddAssert("Ensure no adjacent day separators", () =>
+ {
+ var indices = chatDisplay.FillFlow.OfType().Select(ds => chatDisplay.FillFlow.IndexOf(ds));
+
+ foreach (var i in indices)
+ if (i < chatDisplay.FillFlow.Count && chatDisplay.FillFlow[i + 1] is DrawableChannel.DaySeparator)
+ return false;
+
+ return true;
+ });
+
+ AddUntilStep("ensure still scrolled to bottom", () => chatDisplay.ScrolledToBottom);
+ }
+
+ private class TestStandAloneChatDisplay : StandAloneChatDisplay
+ {
+ public TestStandAloneChatDisplay(bool textbox = false)
+ : base(textbox)
+ {
+ }
+
+ protected DrawableChannel DrawableChannel => InternalChildren.OfType().First();
+
+ protected OsuScrollContainer ScrollContainer => (OsuScrollContainer)((Container)DrawableChannel.Child).Child;
+
+ public FillFlowContainer FillFlow => (FillFlowContainer)ScrollContainer.Child;
+
+ public bool ScrolledToBottom => ScrollContainer.IsScrolledToEnd(1);
}
}
}
diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs
index f87d6ebebb..8b82567a8d 100644
--- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs
+++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs
@@ -245,6 +245,28 @@ namespace osu.Game.Tests.Visual.SongSelect
AddAssert($"Check #{set_count} is at bottom", () => carousel.BeatmapSets.Last().Metadata.Title.EndsWith($"#{set_count}!"));
}
+ [Test]
+ public void TestSortingStability()
+ {
+ var sets = new List();
+
+ for (int i = 0; i < 20; i++)
+ {
+ var set = createTestBeatmapSet(i);
+ set.Metadata.Artist = "same artist";
+ set.Metadata.Title = "same title";
+ sets.Add(set);
+ }
+
+ loadBeatmaps(sets);
+
+ AddStep("Sort by artist", () => carousel.Filter(new FilterCriteria { Sort = SortMode.Artist }, false));
+ AddAssert("Items remain in original order", () => carousel.BeatmapSets.Select((set, index) => set.ID == index).All(b => b));
+
+ AddStep("Sort by title", () => carousel.Filter(new FilterCriteria { Sort = SortMode.Title }, false));
+ AddAssert("Items remain in original order", () => carousel.BeatmapSets.Select((set, index) => set.ID == index).All(b => b));
+ }
+
[Test]
public void TestSortingWithFiltered()
{
diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneBeatSyncedContainer.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneBeatSyncedContainer.cs
index b6df559686..ed44d82bce 100644
--- a/osu.Game.Tests/Visual/UserInterface/TestSceneBeatSyncedContainer.cs
+++ b/osu.Game.Tests/Visual/UserInterface/TestSceneBeatSyncedContainer.cs
@@ -3,7 +3,7 @@
using System;
using System.Collections.Generic;
-using Microsoft.EntityFrameworkCore.Internal;
+using System.Linq;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Audio.Track;
@@ -153,7 +153,7 @@ namespace osu.Game.Tests.Visual.UserInterface
};
}
- private IReadOnlyList timingPoints => Beatmap.Value.Beatmap.ControlPointInfo.TimingPoints;
+ private List timingPoints => Beatmap.Value.Beatmap.ControlPointInfo.TimingPoints.ToList();
private TimingControlPoint getNextTimingPoint(TimingControlPoint current)
{
diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledComponent.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledDrawable.cs
similarity index 82%
rename from osu.Game.Tests/Visual/UserInterface/TestSceneLabelledComponent.cs
rename to osu.Game.Tests/Visual/UserInterface/TestSceneLabelledDrawable.cs
index 700adad9cb..8179f92ffc 100644
--- a/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledComponent.cs
+++ b/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledDrawable.cs
@@ -11,7 +11,7 @@ using osuTK.Graphics;
namespace osu.Game.Tests.Visual.UserInterface
{
- public class TestSceneLabelledComponent : OsuTestScene
+ public class TestSceneLabelledDrawable : OsuTestScene
{
[TestCase(false)]
[TestCase(true)]
@@ -25,7 +25,7 @@ namespace osu.Game.Tests.Visual.UserInterface
{
AddStep("create component", () =>
{
- LabelledComponent component;
+ LabelledDrawable component;
Child = new Container
{
@@ -33,7 +33,7 @@ namespace osu.Game.Tests.Visual.UserInterface
Origin = Anchor.Centre,
Width = 500,
AutoSizeAxes = Axes.Y,
- Child = component = padded ? (LabelledComponent)new PaddedLabelledComponent() : new NonPaddedLabelledComponent(),
+ Child = component = padded ? (LabelledDrawable)new PaddedLabelledDrawable() : new NonPaddedLabelledDrawable(),
};
component.Label = "a sample component";
@@ -41,9 +41,9 @@ namespace osu.Game.Tests.Visual.UserInterface
});
}
- private class PaddedLabelledComponent : LabelledComponent
+ private class PaddedLabelledDrawable : LabelledDrawable
{
- public PaddedLabelledComponent()
+ public PaddedLabelledDrawable()
: base(true)
{
}
@@ -57,9 +57,9 @@ namespace osu.Game.Tests.Visual.UserInterface
};
}
- private class NonPaddedLabelledComponent : LabelledComponent
+ private class NonPaddedLabelledDrawable : LabelledDrawable
{
- public NonPaddedLabelledComponent()
+ public NonPaddedLabelledDrawable()
: base(false)
{
}
diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledTextBox.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledTextBox.cs
index 53a2bfabbc..8208b55952 100644
--- a/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledTextBox.cs
+++ b/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledTextBox.cs
@@ -7,7 +7,6 @@ using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
-using osu.Game.Graphics.UserInterface;
using osu.Game.Graphics.UserInterfaceV2;
namespace osu.Game.Tests.Visual.UserInterface
@@ -28,7 +27,7 @@ namespace osu.Game.Tests.Visual.UserInterface
{
AddStep("create component", () =>
{
- LabelledComponent component;
+ LabelledTextBox component;
Child = new Container
{
diff --git a/osu.Game.Tournament/Screens/SetupScreen.cs b/osu.Game.Tournament/Screens/SetupScreen.cs
index 091a837745..a67daa2756 100644
--- a/osu.Game.Tournament/Screens/SetupScreen.cs
+++ b/osu.Game.Tournament/Screens/SetupScreen.cs
@@ -89,7 +89,7 @@ namespace osu.Game.Tournament.Screens
};
}
- private class ActionableInfo : LabelledComponent
+ private class ActionableInfo : LabelledDrawable
{
private OsuButton button;
diff --git a/osu.Game/Beatmaps/ControlPoints/DifficultyControlPoint.cs b/osu.Game/Beatmaps/ControlPoints/DifficultyControlPoint.cs
index 42651fd0ca..8b21098a51 100644
--- a/osu.Game/Beatmaps/ControlPoints/DifficultyControlPoint.cs
+++ b/osu.Game/Beatmaps/ControlPoints/DifficultyControlPoint.cs
@@ -1,24 +1,33 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-using osuTK;
+using osu.Framework.Bindables;
namespace osu.Game.Beatmaps.ControlPoints
{
public class DifficultyControlPoint : ControlPoint
{
+ ///
+ /// The speed multiplier at this control point.
+ ///
+ public readonly BindableDouble SpeedMultiplierBindable = new BindableDouble(1)
+ {
+ Precision = 0.1,
+ Default = 1,
+ MinValue = 0.1,
+ MaxValue = 10
+ };
+
///
/// The speed multiplier at this control point.
///
public double SpeedMultiplier
{
- get => speedMultiplier;
- set => speedMultiplier = MathHelper.Clamp(value, 0.1, 10);
+ get => SpeedMultiplierBindable.Value;
+ set => SpeedMultiplierBindable.Value = value;
}
- private double speedMultiplier = 1;
-
public override bool EquivalentTo(ControlPoint other) =>
- other is DifficultyControlPoint otherTyped && otherTyped.SpeedMultiplier.Equals(speedMultiplier);
+ other is DifficultyControlPoint otherTyped && otherTyped.SpeedMultiplier.Equals(SpeedMultiplier);
}
}
diff --git a/osu.Game/Beatmaps/ControlPoints/EffectControlPoint.cs b/osu.Game/Beatmaps/ControlPoints/EffectControlPoint.cs
index 928f2a51ad..369b93ff3d 100644
--- a/osu.Game/Beatmaps/ControlPoints/EffectControlPoint.cs
+++ b/osu.Game/Beatmaps/ControlPoints/EffectControlPoint.cs
@@ -1,19 +1,39 @@
// 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.Bindables;
+
namespace osu.Game.Beatmaps.ControlPoints
{
public class EffectControlPoint : ControlPoint
{
///
- /// Whether this control point enables Kiai mode.
+ /// Whether the first bar line of this control point is ignored.
///
- public bool KiaiMode;
+ public readonly BindableBool OmitFirstBarLineBindable = new BindableBool();
///
/// Whether the first bar line of this control point is ignored.
///
- public bool OmitFirstBarLine;
+ public bool OmitFirstBarLine
+ {
+ get => OmitFirstBarLineBindable.Value;
+ set => OmitFirstBarLineBindable.Value = value;
+ }
+
+ ///
+ /// Whether this control point enables Kiai mode.
+ ///
+ public readonly BindableBool KiaiModeBindable = new BindableBool();
+
+ ///
+ /// Whether this control point enables Kiai mode.
+ ///
+ public bool KiaiMode
+ {
+ get => KiaiModeBindable.Value;
+ set => KiaiModeBindable.Value = value;
+ }
public override bool EquivalentTo(ControlPoint other) =>
other is EffectControlPoint otherTyped &&
diff --git a/osu.Game/Beatmaps/ControlPoints/SampleControlPoint.cs b/osu.Game/Beatmaps/ControlPoints/SampleControlPoint.cs
index 07f5aa6c90..42865c686c 100644
--- a/osu.Game/Beatmaps/ControlPoints/SampleControlPoint.cs
+++ b/osu.Game/Beatmaps/ControlPoints/SampleControlPoint.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.Framework.Bindables;
using osu.Game.Audio;
namespace osu.Game.Beatmaps.ControlPoints
@@ -12,12 +13,35 @@ namespace osu.Game.Beatmaps.ControlPoints
///
/// The default sample bank at this control point.
///
- public string SampleBank = DEFAULT_BANK;
+ public readonly Bindable SampleBankBindable = new Bindable(DEFAULT_BANK) { Default = DEFAULT_BANK };
+
+ ///
+ /// The speed multiplier at this control point.
+ ///
+ public string SampleBank
+ {
+ get => SampleBankBindable.Value;
+ set => SampleBankBindable.Value = value;
+ }
+
+ ///
+ /// The default sample bank at this control point.
+ ///
+ public readonly BindableInt SampleVolumeBindable = new BindableInt(100)
+ {
+ MinValue = 0,
+ MaxValue = 100,
+ Default = 100
+ };
///
/// The default sample volume at this control point.
///
- public int SampleVolume = 100;
+ public int SampleVolume
+ {
+ get => SampleVolumeBindable.Value;
+ set => SampleVolumeBindable.Value = value;
+ }
///
/// Create a SampleInfo based on the sample settings in this control point.
diff --git a/osu.Game/Beatmaps/ControlPoints/TimingControlPoint.cs b/osu.Game/Beatmaps/ControlPoints/TimingControlPoint.cs
index e3451892bf..d9328d1636 100644
--- a/osu.Game/Beatmaps/ControlPoints/TimingControlPoint.cs
+++ b/osu.Game/Beatmaps/ControlPoints/TimingControlPoint.cs
@@ -1,7 +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 osuTK;
+using osu.Framework.Bindables;
using osu.Game.Beatmaps.Timing;
namespace osu.Game.Beatmaps.ControlPoints
@@ -11,17 +11,35 @@ namespace osu.Game.Beatmaps.ControlPoints
///
/// The time signature at this control point.
///
- public TimeSignatures TimeSignature = TimeSignatures.SimpleQuadruple;
+ public readonly Bindable TimeSignatureBindable = new Bindable(TimeSignatures.SimpleQuadruple) { Default = TimeSignatures.SimpleQuadruple };
+
+ ///
+ /// The time signature at this control point.
+ ///
+ public TimeSignatures TimeSignature
+ {
+ get => TimeSignatureBindable.Value;
+ set => TimeSignatureBindable.Value = value;
+ }
public const double DEFAULT_BEAT_LENGTH = 1000;
///
/// The beat length at this control point.
///
- public virtual double BeatLength
+ public readonly BindableDouble BeatLengthBindable = new BindableDouble(DEFAULT_BEAT_LENGTH)
{
- get => beatLength;
- set => beatLength = MathHelper.Clamp(value, 6, 60000);
+ Default = DEFAULT_BEAT_LENGTH,
+ MinValue = 6,
+ MaxValue = 60000
+ };
+
+ /// The beat length at this control point.
+ ///
+ public double BeatLength
+ {
+ get => BeatLengthBindable.Value;
+ set => BeatLengthBindable.Value = value;
}
///
@@ -29,10 +47,8 @@ namespace osu.Game.Beatmaps.ControlPoints
///
public double BPM => 60000 / BeatLength;
- private double beatLength = DEFAULT_BEAT_LENGTH;
-
public override bool EquivalentTo(ControlPoint other) =>
other is TimingControlPoint otherTyped
- && TimeSignature == otherTyped.TimeSignature && beatLength.Equals(otherTyped.beatLength);
+ && TimeSignature == otherTyped.TimeSignature && BeatLength.Equals(otherTyped.BeatLength);
}
}
diff --git a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs
index 5589aecc19..aeb5df46f8 100644
--- a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs
+++ b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs
@@ -379,7 +379,7 @@ namespace osu.Game.Beatmaps.Formats
addControlPoint(time, controlPoint, true);
}
- addControlPoint(time, new DifficultyControlPoint
+ addControlPoint(time, new LegacyDifficultyControlPoint
{
SpeedMultiplier = speedMultiplier,
}, timingChange);
@@ -411,15 +411,15 @@ namespace osu.Game.Beatmaps.Formats
private void addControlPoint(double time, ControlPoint point, bool timingChange)
{
+ if (time != pendingControlPointsTime)
+ flushPendingPoints();
+
if (timingChange)
{
beatmap.ControlPointInfo.Add(time, point);
return;
}
- if (time != pendingControlPointsTime)
- flushPendingPoints();
-
pendingControlPoints.Add(point);
pendingControlPointsTime = time;
}
diff --git a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs
index a5a4380d4a..2b914669cb 100644
--- a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs
+++ b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs
@@ -189,6 +189,14 @@ namespace osu.Game.Beatmaps.Formats
Foreground = 3
}
+ internal class LegacyDifficultyControlPoint : DifficultyControlPoint
+ {
+ public LegacyDifficultyControlPoint()
+ {
+ SpeedMultiplierBindable.Precision = double.Epsilon;
+ }
+ }
+
internal class LegacySampleControlPoint : SampleControlPoint
{
public int CustomSampleBank;
diff --git a/osu.Game/Beatmaps/Formats/LegacyDifficultyCalculatorBeatmapDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyDifficultyCalculatorBeatmapDecoder.cs
index 238187bf8f..527f520172 100644
--- a/osu.Game/Beatmaps/Formats/LegacyDifficultyCalculatorBeatmapDecoder.cs
+++ b/osu.Game/Beatmaps/Formats/LegacyDifficultyCalculatorBeatmapDecoder.cs
@@ -28,11 +28,15 @@ namespace osu.Game.Beatmaps.Formats
}
protected override TimingControlPoint CreateTimingControlPoint()
- => new LegacyDifficultyCalculatorControlPoint();
+ => new LegacyDifficultyCalculatorTimingControlPoint();
- private class LegacyDifficultyCalculatorControlPoint : TimingControlPoint
+ private class LegacyDifficultyCalculatorTimingControlPoint : TimingControlPoint
{
- public override double BeatLength { get; set; } = DEFAULT_BEAT_LENGTH;
+ public LegacyDifficultyCalculatorTimingControlPoint()
+ {
+ BeatLengthBindable.MinValue = double.MinValue;
+ BeatLengthBindable.MaxValue = double.MaxValue;
+ }
}
}
}
diff --git a/osu.Game/Database/ArchiveModelManager.cs b/osu.Game/Database/ArchiveModelManager.cs
index b567f0c0e3..9fed8e03ac 100644
--- a/osu.Game/Database/ArchiveModelManager.cs
+++ b/osu.Game/Database/ArchiveModelManager.cs
@@ -108,7 +108,7 @@ namespace osu.Game.Database
return Import(notification, paths);
}
- protected async Task Import(ProgressNotification notification, params string[] paths)
+ protected async Task> Import(ProgressNotification notification, params string[] paths)
{
notification.Progress = 0;
notification.Text = $"{HumanisedModelName.Humanize(LetterCasing.Title)} import is initialising...";
@@ -168,6 +168,8 @@ namespace osu.Game.Database
notification.State = ProgressNotificationState.Completed;
}
+
+ return imported;
}
///
diff --git a/osu.Game/Database/DownloadableArchiveModelManager.cs b/osu.Game/Database/DownloadableArchiveModelManager.cs
index 78c0837ce9..e3c6ad25e6 100644
--- a/osu.Game/Database/DownloadableArchiveModelManager.cs
+++ b/osu.Game/Database/DownloadableArchiveModelManager.cs
@@ -76,7 +76,12 @@ namespace osu.Game.Database
Task.Factory.StartNew(async () =>
{
// This gets scheduled back to the update thread, but we want the import to run in the background.
- await Import(notification, filename);
+ var imported = await Import(notification, filename);
+
+ // for now a failed import will be marked as a failed download for simplicity.
+ if (!imported.Any())
+ DownloadFailed?.Invoke(request);
+
currentDownloads.Remove(request);
}, TaskCreationOptions.LongRunning);
};
diff --git a/osu.Game/Database/OsuDbContext.cs b/osu.Game/Database/OsuDbContext.cs
index ea3318598f..2ae07b3cf8 100644
--- a/osu.Game/Database/OsuDbContext.cs
+++ b/osu.Game/Database/OsuDbContext.cs
@@ -166,19 +166,6 @@ namespace osu.Game.Database
// no-op. called by tooling.
}
- private class OsuDbLoggerProvider : ILoggerProvider
- {
- #region Disposal
-
- public void Dispose()
- {
- }
-
- #endregion
-
- public ILogger CreateLogger(string categoryName) => new OsuDbLogger();
- }
-
private class OsuDbLogger : ILogger
{
public void Log(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func formatter)
diff --git a/osu.Game/Graphics/UserInterface/OsuButton.cs b/osu.Game/Graphics/UserInterface/OsuButton.cs
index c1810800a0..4124d2ad58 100644
--- a/osu.Game/Graphics/UserInterface/OsuButton.cs
+++ b/osu.Game/Graphics/UserInterface/OsuButton.cs
@@ -59,7 +59,7 @@ namespace osu.Game.Graphics.UserInterface
protected override bool OnHover(HoverEvent e)
{
hover.FadeIn(200);
- return base.OnHover(e);
+ return true;
}
protected override void OnHoverLost(HoverLostEvent e)
diff --git a/osu.Game/Graphics/UserInterfaceV2/LabelledComponent.cs b/osu.Game/Graphics/UserInterfaceV2/LabelledComponent.cs
index 2e659825b7..1819b36667 100644
--- a/osu.Game/Graphics/UserInterfaceV2/LabelledComponent.cs
+++ b/osu.Game/Graphics/UserInterfaceV2/LabelledComponent.cs
@@ -1,132 +1,24 @@
// 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.Allocation;
+using osu.Framework.Bindables;
using osu.Framework.Graphics;
-using osu.Framework.Graphics.Containers;
-using osu.Framework.Graphics.Shapes;
-using osu.Game.Graphics.Containers;
-using osuTK;
+using osu.Framework.Graphics.UserInterface;
namespace osu.Game.Graphics.UserInterfaceV2
{
- public abstract class LabelledComponent : CompositeDrawable
- where T : Drawable
+ public abstract class LabelledComponent : LabelledDrawable, IHasCurrentValue
+ where T : Drawable, IHasCurrentValue
{
- protected const float CONTENT_PADDING_VERTICAL = 10;
- protected const float CONTENT_PADDING_HORIZONTAL = 15;
- protected const float CORNER_RADIUS = 15;
-
- ///
- /// The component that is being displayed.
- ///
- protected readonly T Component;
-
- private readonly OsuTextFlowContainer labelText;
- private readonly OsuTextFlowContainer descriptionText;
-
- ///
- /// Creates a new .
- ///
- /// Whether the component should be padded or should be expanded to the bounds of this .
protected LabelledComponent(bool padded)
+ : base(padded)
{
- RelativeSizeAxes = Axes.X;
- AutoSizeAxes = Axes.Y;
-
- CornerRadius = CORNER_RADIUS;
- Masking = true;
-
- InternalChildren = new Drawable[]
- {
- new Box
- {
- RelativeSizeAxes = Axes.Both,
- Colour = OsuColour.FromHex("1c2125"),
- },
- new FillFlowContainer
- {
- RelativeSizeAxes = Axes.X,
- AutoSizeAxes = Axes.Y,
- Direction = FillDirection.Vertical,
- Padding = padded
- ? new MarginPadding { Horizontal = CONTENT_PADDING_HORIZONTAL, Vertical = CONTENT_PADDING_VERTICAL }
- : new MarginPadding { Left = CONTENT_PADDING_HORIZONTAL },
- Spacing = new Vector2(0, 12),
- Children = new Drawable[]
- {
- new GridContainer
- {
- RelativeSizeAxes = Axes.X,
- AutoSizeAxes = Axes.Y,
- Content = new[]
- {
- new Drawable[]
- {
- labelText = new OsuTextFlowContainer(s => s.Font = OsuFont.GetFont(weight: FontWeight.Bold))
- {
- Anchor = Anchor.CentreLeft,
- Origin = Anchor.CentreLeft,
- AutoSizeAxes = Axes.Both,
- Padding = new MarginPadding { Right = 20 }
- },
- new Container
- {
- Anchor = Anchor.CentreRight,
- Origin = Anchor.CentreRight,
- RelativeSizeAxes = Axes.X,
- AutoSizeAxes = Axes.Y,
- Child = Component = CreateComponent().With(d =>
- {
- d.Anchor = Anchor.CentreRight;
- d.Origin = Anchor.CentreRight;
- })
- }
- },
- },
- RowDimensions = new[] { new Dimension(GridSizeMode.AutoSize) },
- ColumnDimensions = new[] { new Dimension(GridSizeMode.AutoSize) }
- },
- descriptionText = new OsuTextFlowContainer(s => s.Font = OsuFont.GetFont(size: 12, weight: FontWeight.Bold, italics: true))
- {
- RelativeSizeAxes = Axes.X,
- AutoSizeAxes = Axes.Y,
- Padding = new MarginPadding { Bottom = padded ? 0 : CONTENT_PADDING_VERTICAL },
- Alpha = 0,
- }
- }
- }
- };
}
- [BackgroundDependencyLoader]
- private void load(OsuColour osuColour)
+ public Bindable Current
{
- descriptionText.Colour = osuColour.Yellow;
+ get => Component.Current;
+ set => Component.Current = value;
}
-
- public string Label
- {
- set => labelText.Text = value;
- }
-
- public string Description
- {
- set
- {
- descriptionText.Text = value;
-
- if (!string.IsNullOrEmpty(value))
- descriptionText.Show();
- else
- descriptionText.Hide();
- }
- }
-
- ///
- /// Creates the component that should be displayed.
- ///
- /// The component.
- protected abstract T CreateComponent();
}
}
diff --git a/osu.Game/Graphics/UserInterfaceV2/LabelledDrawable.cs b/osu.Game/Graphics/UserInterfaceV2/LabelledDrawable.cs
new file mode 100644
index 0000000000..f44bd72aee
--- /dev/null
+++ b/osu.Game/Graphics/UserInterfaceV2/LabelledDrawable.cs
@@ -0,0 +1,132 @@
+// 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.Allocation;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Shapes;
+using osu.Game.Graphics.Containers;
+using osuTK;
+
+namespace osu.Game.Graphics.UserInterfaceV2
+{
+ public abstract class LabelledDrawable : CompositeDrawable
+ where T : Drawable
+ {
+ protected const float CONTENT_PADDING_VERTICAL = 10;
+ protected const float CONTENT_PADDING_HORIZONTAL = 15;
+ protected const float CORNER_RADIUS = 15;
+
+ ///
+ /// The component that is being displayed.
+ ///
+ protected readonly T Component;
+
+ private readonly OsuTextFlowContainer labelText;
+ private readonly OsuTextFlowContainer descriptionText;
+
+ ///
+ /// Creates a new .
+ ///
+ /// Whether the component should be padded or should be expanded to the bounds of this .
+ protected LabelledDrawable(bool padded)
+ {
+ RelativeSizeAxes = Axes.X;
+ AutoSizeAxes = Axes.Y;
+
+ CornerRadius = CORNER_RADIUS;
+ Masking = true;
+
+ InternalChildren = new Drawable[]
+ {
+ new Box
+ {
+ RelativeSizeAxes = Axes.Both,
+ Colour = OsuColour.FromHex("1c2125"),
+ },
+ new FillFlowContainer
+ {
+ RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y,
+ Direction = FillDirection.Vertical,
+ Padding = padded
+ ? new MarginPadding { Horizontal = CONTENT_PADDING_HORIZONTAL, Vertical = CONTENT_PADDING_VERTICAL }
+ : new MarginPadding { Left = CONTENT_PADDING_HORIZONTAL },
+ Spacing = new Vector2(0, 12),
+ Children = new Drawable[]
+ {
+ new GridContainer
+ {
+ RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y,
+ Content = new[]
+ {
+ new Drawable[]
+ {
+ labelText = new OsuTextFlowContainer(s => s.Font = OsuFont.GetFont(weight: FontWeight.Bold))
+ {
+ Anchor = Anchor.CentreLeft,
+ Origin = Anchor.CentreLeft,
+ AutoSizeAxes = Axes.Both,
+ Padding = new MarginPadding { Right = 20 }
+ },
+ new Container
+ {
+ Anchor = Anchor.CentreRight,
+ Origin = Anchor.CentreRight,
+ RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y,
+ Child = Component = CreateComponent().With(d =>
+ {
+ d.Anchor = Anchor.CentreRight;
+ d.Origin = Anchor.CentreRight;
+ })
+ }
+ },
+ },
+ RowDimensions = new[] { new Dimension(GridSizeMode.AutoSize) },
+ ColumnDimensions = new[] { new Dimension(GridSizeMode.AutoSize) }
+ },
+ descriptionText = new OsuTextFlowContainer(s => s.Font = OsuFont.GetFont(size: 12, weight: FontWeight.Bold, italics: true))
+ {
+ RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y,
+ Padding = new MarginPadding { Bottom = padded ? 0 : CONTENT_PADDING_VERTICAL },
+ Alpha = 0,
+ }
+ }
+ }
+ };
+ }
+
+ [BackgroundDependencyLoader]
+ private void load(OsuColour osuColour)
+ {
+ descriptionText.Colour = osuColour.Yellow;
+ }
+
+ public string Label
+ {
+ set => labelText.Text = value;
+ }
+
+ public string Description
+ {
+ set
+ {
+ descriptionText.Text = value;
+
+ if (!string.IsNullOrEmpty(value))
+ descriptionText.Show();
+ else
+ descriptionText.Hide();
+ }
+ }
+
+ ///
+ /// Creates the component that should be displayed.
+ ///
+ /// The component.
+ protected abstract T CreateComponent();
+ }
+}
diff --git a/osu.Game/Graphics/UserInterfaceV2/LabelledSwitchButton.cs b/osu.Game/Graphics/UserInterfaceV2/LabelledSwitchButton.cs
index c973f1d13e..c374d80830 100644
--- a/osu.Game/Graphics/UserInterfaceV2/LabelledSwitchButton.cs
+++ b/osu.Game/Graphics/UserInterfaceV2/LabelledSwitchButton.cs
@@ -3,7 +3,7 @@
namespace osu.Game.Graphics.UserInterfaceV2
{
- public class LabelledSwitchButton : LabelledComponent
+ public class LabelledSwitchButton : LabelledComponent
{
public LabelledSwitchButton()
: base(true)
diff --git a/osu.Game/Graphics/UserInterfaceV2/LabelledTextBox.cs b/osu.Game/Graphics/UserInterfaceV2/LabelledTextBox.cs
index 50d2a14482..2cbe095d0b 100644
--- a/osu.Game/Graphics/UserInterfaceV2/LabelledTextBox.cs
+++ b/osu.Game/Graphics/UserInterfaceV2/LabelledTextBox.cs
@@ -8,7 +8,7 @@ using osu.Game.Graphics.UserInterface;
namespace osu.Game.Graphics.UserInterfaceV2
{
- public class LabelledTextBox : LabelledComponent
+ public class LabelledTextBox : LabelledComponent
{
public event TextBox.OnCommitHandler OnCommit;
diff --git a/osu.Game/Online/Chat/Channel.cs b/osu.Game/Online/Chat/Channel.cs
index 9ec39c5cb1..451174a73c 100644
--- a/osu.Game/Online/Chat/Channel.cs
+++ b/osu.Game/Online/Chat/Channel.cs
@@ -14,7 +14,7 @@ namespace osu.Game.Online.Chat
{
public class Channel
{
- public readonly int MaxHistory = 300;
+ public const int MAX_HISTORY = 300;
///
/// Contains every joined user except the current logged in user. Currently only returned for PM channels.
@@ -80,8 +80,6 @@ namespace osu.Game.Online.Chat
///
public Bindable Joined = new Bindable();
- public const int MAX_HISTORY = 300;
-
[JsonConstructor]
public Channel()
{
@@ -162,8 +160,8 @@ namespace osu.Game.Online.Chat
{
// never purge local echos
int messageCount = Messages.Count - pendingMessages.Count;
- if (messageCount > MaxHistory)
- Messages.RemoveRange(0, messageCount - MaxHistory);
+ if (messageCount > MAX_HISTORY)
+ Messages.RemoveRange(0, messageCount - MAX_HISTORY);
}
}
}
diff --git a/osu.Game/Overlays/Chat/DrawableChannel.cs b/osu.Game/Overlays/Chat/DrawableChannel.cs
index 6cdbfabe0f..427bd8dcde 100644
--- a/osu.Game/Overlays/Chat/DrawableChannel.cs
+++ b/osu.Game/Overlays/Chat/DrawableChannel.cs
@@ -1,4 +1,4 @@
-// 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 System;
@@ -89,8 +89,10 @@ namespace osu.Game.Overlays.Chat
private void newMessagesArrived(IEnumerable newMessages)
{
+ bool shouldScrollToEnd = scroll.IsScrolledToEnd(10) || !chatLines.Any() || newMessages.Any(m => m is LocalMessage);
+
// Add up to last Channel.MAX_HISTORY messages
- var displayMessages = newMessages.Skip(Math.Max(0, newMessages.Count() - Channel.MaxHistory));
+ var displayMessages = newMessages.Skip(Math.Max(0, newMessages.Count() - Channel.MAX_HISTORY));
Message lastMessage = chatLines.LastOrDefault()?.Message;
@@ -103,19 +105,32 @@ namespace osu.Game.Overlays.Chat
lastMessage = message;
}
- if (scroll.IsScrolledToEnd(10) || !chatLines.Any() || newMessages.Any(m => m is LocalMessage))
- scrollToEnd();
-
var staleMessages = chatLines.Where(c => c.LifetimeEnd == double.MaxValue).ToArray();
- int count = staleMessages.Length - Channel.MaxHistory;
+ int count = staleMessages.Length - Channel.MAX_HISTORY;
- for (int i = 0; i < count; i++)
+ if (count > 0)
{
- var d = staleMessages[i];
- if (!scroll.IsScrolledToEnd(10))
+ void expireAndAdjustScroll(Drawable d)
+ {
scroll.OffsetScrollPosition(-d.DrawHeight);
- d.Expire();
+ d.Expire();
+ }
+
+ for (int i = 0; i < count; i++)
+ expireAndAdjustScroll(staleMessages[i]);
+
+ // remove all adjacent day separators after stale message removal
+ for (int i = 0; i < ChatLineFlow.Count - 1; i++)
+ {
+ if (!(ChatLineFlow[i] is DaySeparator)) break;
+ if (!(ChatLineFlow[i + 1] is DaySeparator)) break;
+
+ expireAndAdjustScroll(ChatLineFlow[i]);
+ }
}
+
+ if (shouldScrollToEnd)
+ scrollToEnd();
}
private void pendingMessageResolved(Message existing, Message updated)
@@ -141,7 +156,7 @@ namespace osu.Game.Overlays.Chat
private void scrollToEnd() => ScheduleAfterChildren(() => scroll.ScrollToEnd());
- protected class DaySeparator : Container
+ public class DaySeparator : Container
{
public float TextSize
{
diff --git a/osu.Game/Overlays/Settings/Sections/General/LoginSettings.cs b/osu.Game/Overlays/Settings/Sections/General/LoginSettings.cs
index b02b1a5489..a8bbccb168 100644
--- a/osu.Game/Overlays/Settings/Sections/General/LoginSettings.cs
+++ b/osu.Game/Overlays/Settings/Sections/General/LoginSettings.cs
@@ -200,6 +200,7 @@ namespace osu.Game.Overlays.Settings.Sections.General
{
private TextBox username;
private TextBox password;
+ private ShakeContainer shakeSignIn;
private IAPIProvider api;
public Action RequestHide;
@@ -208,6 +209,8 @@ namespace osu.Game.Overlays.Settings.Sections.General
{
if (!string.IsNullOrEmpty(username.Text) && !string.IsNullOrEmpty(password.Text))
api.Login(username.Text, password.Text);
+ else
+ shakeSignIn.Shake();
}
[BackgroundDependencyLoader(permitNulls: true)]
@@ -244,10 +247,23 @@ namespace osu.Game.Overlays.Settings.Sections.General
LabelText = "Stay signed in",
Bindable = config.GetBindable(OsuSetting.SavePassword),
},
- new SettingsButton
+ new Container
{
- Text = "Sign in",
- Action = performLogin
+ RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y,
+ Children = new Drawable[]
+ {
+ shakeSignIn = new ShakeContainer
+ {
+ RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y,
+ Child = new SettingsButton
+ {
+ Text = "Sign in",
+ Action = performLogin
+ },
+ }
+ }
},
new SettingsButton
{
diff --git a/osu.Game/Screens/Edit/EditorClock.cs b/osu.Game/Screens/Edit/EditorClock.cs
index 1cfb123f25..f674a62a3a 100644
--- a/osu.Game/Screens/Edit/EditorClock.cs
+++ b/osu.Game/Screens/Edit/EditorClock.cs
@@ -3,7 +3,6 @@
using System;
using System.Linq;
-using Microsoft.EntityFrameworkCore.Internal;
using osu.Framework.MathUtils;
using osu.Framework.Timing;
using osu.Game.Beatmaps;
@@ -88,7 +87,17 @@ namespace osu.Game.Screens.Edit
if (direction < 0 && timingPoint.Time == CurrentTime)
{
// When going backwards and we're at the boundary of two timing points, we compute the seek distance with the timing point which we are seeking into
- int activeIndex = ControlPointInfo.TimingPoints.IndexOf(timingPoint);
+ int activeIndex = -1;
+
+ for (int i = 0; i < ControlPointInfo.TimingPoints.Count; i++)
+ {
+ if (ControlPointInfo.TimingPoints[i] == timingPoint)
+ {
+ activeIndex = i;
+ break;
+ }
+ }
+
while (activeIndex > 0 && CurrentTime == timingPoint.Time)
timingPoint = ControlPointInfo.TimingPoints[--activeIndex];
}
diff --git a/osu.Game/Screens/Menu/IntroSequence.cs b/osu.Game/Screens/Menu/IntroSequence.cs
index 093d01f12d..e2dd14b18c 100644
--- a/osu.Game/Screens/Menu/IntroSequence.cs
+++ b/osu.Game/Screens/Menu/IntroSequence.cs
@@ -42,6 +42,7 @@ namespace osu.Game.Screens.Menu
public IntroSequence()
{
RelativeSizeAxes = Axes.Both;
+ Alpha = 0;
}
[BackgroundDependencyLoader]
diff --git a/osu.Game/Screens/Play/HUD/PlayerSettingsOverlay.cs b/osu.Game/Screens/Play/HUD/PlayerSettingsOverlay.cs
index b2c3952f38..d201b5d30e 100644
--- a/osu.Game/Screens/Play/HUD/PlayerSettingsOverlay.cs
+++ b/osu.Game/Screens/Play/HUD/PlayerSettingsOverlay.cs
@@ -45,8 +45,6 @@ namespace osu.Game.Screens.Play.HUD
VisualSettings = new VisualSettings { Expanded = false }
}
};
-
- Show();
}
protected override void PopIn() => this.FadeIn(fade_duration);
diff --git a/osu.Game/Screens/Play/SongProgress.cs b/osu.Game/Screens/Play/SongProgress.cs
index 6642efdf8b..3df06ebfa8 100644
--- a/osu.Game/Screens/Play/SongProgress.cs
+++ b/osu.Game/Screens/Play/SongProgress.cs
@@ -106,6 +106,8 @@ namespace osu.Game.Screens.Play
protected override void LoadComplete()
{
+ base.LoadComplete();
+
Show();
replayLoaded.ValueChanged += loaded => AllowSeeking = loaded.NewValue;
diff --git a/osu.Game/Screens/Select/Carousel/CarouselGroup.cs b/osu.Game/Screens/Select/Carousel/CarouselGroup.cs
index 09b728abeb..aa48d1a04e 100644
--- a/osu.Game/Screens/Select/Carousel/CarouselGroup.cs
+++ b/osu.Game/Screens/Select/Carousel/CarouselGroup.cs
@@ -2,6 +2,7 @@
// See the LICENCE file in the repository root for full licence text.
using System.Collections.Generic;
+using System.Linq;
namespace osu.Game.Screens.Select.Carousel
{
@@ -81,12 +82,10 @@ namespace osu.Game.Screens.Select.Carousel
{
base.Filter(criteria);
- var children = new List(InternalChildren);
-
- children.ForEach(c => c.Filter(criteria));
- children.Sort((x, y) => x.CompareTo(criteria, y));
-
- InternalChildren = children;
+ InternalChildren.ForEach(c => c.Filter(criteria));
+ // IEnumerable.OrderBy() is used instead of List.Sort() to ensure sorting stability
+ var criteriaComparer = Comparer.Create((x, y) => x.CompareTo(criteria, y));
+ InternalChildren = InternalChildren.OrderBy(c => c, criteriaComparer).ToList();
}
protected virtual void ChildItemStateChanged(CarouselItem item, CarouselItemState value)
diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj
index e898a001de..0cb09d9b14 100644
--- a/osu.Game/osu.Game.csproj
+++ b/osu.Game/osu.Game.csproj
@@ -26,7 +26,7 @@
-
+
diff --git a/osu.iOS.props b/osu.iOS.props
index 656c60543e..719aced705 100644
--- a/osu.iOS.props
+++ b/osu.iOS.props
@@ -118,8 +118,8 @@
-
-
+
+