diff --git a/osu.Android.props b/osu.Android.props
index 98f9bf1a42..9aa5e631ad 100644
--- a/osu.Android.props
+++ b/osu.Android.props
@@ -63,6 +63,6 @@
-
+
diff --git a/osu.Game.Rulesets.Osu.Tests/OsuDifficultyCalculatorTest.cs b/osu.Game.Rulesets.Osu.Tests/OsuDifficultyCalculatorTest.cs
index e55dc1f902..693faee3b7 100644
--- a/osu.Game.Rulesets.Osu.Tests/OsuDifficultyCalculatorTest.cs
+++ b/osu.Game.Rulesets.Osu.Tests/OsuDifficultyCalculatorTest.cs
@@ -15,6 +15,7 @@ namespace osu.Game.Rulesets.Osu.Tests
protected override string ResourceAssembly => "osu.Game.Rulesets.Osu";
[TestCase(6.931145117263422, "diffcalc-test")]
+ [TestCase(1.0736587013228804d, "zero-length-sliders")]
public void Test(double expected, string name)
=> base.Test(expected, name);
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs
index f372cb65ce..4533e08a2b 100644
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs
@@ -29,6 +29,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
ShakeDuration = 30,
RelativeSizeAxes = Axes.Both
});
+
Alpha = 0;
}
@@ -38,6 +39,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
protected override void ClearInternal(bool disposeChildren = true) => shakeContainer.Clear(disposeChildren);
protected override bool RemoveInternal(Drawable drawable) => shakeContainer.Remove(drawable);
+ protected sealed override double InitialLifetimeOffset => HitObject.TimePreempt;
+
protected sealed override void UpdateState(ArmedState state)
{
double transformTime = HitObject.StartTime - HitObject.TimePreempt;
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs
index 05cb42d853..4d67c9ae34 100644
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs
@@ -156,6 +156,12 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
}
}
+ public override void OnKilled()
+ {
+ base.OnKilled();
+ Body.RecyclePath();
+ }
+
protected override void SkinChanged(ISkinSource skin, bool allowFallback)
{
base.SkinChanged(skin, allowFallback);
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBody.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBody.cs
index 33b3667c4f..97c7c9cec5 100644
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBody.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBody.cs
@@ -13,7 +13,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
{
public const float DEFAULT_BORDER_SIZE = 1;
- private readonly SliderPath path;
+ private SliderPath path;
+
protected Path Path => path;
public float PathRadius
@@ -77,6 +78,22 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
InternalChild = path = new SliderPath();
}
+ ///
+ /// Initialises a new , releasing all resources retained by the old one.
+ ///
+ public void RecyclePath()
+ {
+ InternalChild = path = new SliderPath
+ {
+ Position = path.Position,
+ PathRadius = path.PathRadius,
+ AccentColour = path.AccentColour,
+ BorderColour = path.BorderColour,
+ BorderSize = path.BorderSize,
+ Vertices = path.Vertices
+ };
+ }
+
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => path.ReceivePositionalInputAt(screenSpacePos);
///
diff --git a/osu.Game.Rulesets.Osu/Resources/Testing/Beatmaps/zero-length-sliders.osu b/osu.Game.Rulesets.Osu/Resources/Testing/Beatmaps/zero-length-sliders.osu
new file mode 100644
index 0000000000..18736043b5
--- /dev/null
+++ b/osu.Game.Rulesets.Osu/Resources/Testing/Beatmaps/zero-length-sliders.osu
@@ -0,0 +1,28 @@
+osu file format v14
+
+[Difficulty]
+HPDrainRate:3
+CircleSize:3
+OverallDifficulty:3
+ApproachRate:4.5
+SliderMultiplier:0.799999999999999
+SliderTickRate:1
+
+[TimingPoints]
+800,260.869565217391,3,2,10,60,1,0
+
+[HitObjects]
+// Linear
+78,193,2365,2,0,L|330:193,1,0
+78,193,3669,2,0,L|330:193,1,0
+78,193,4973,2,0,L|330:193,1,0
+
+// Perfect-curve
+151,206,6278,2,0,P|293:75|345:204,1,0
+151,206,8104,2,0,P|293:75|345:204,1,0
+151,206,9930,2,0,P|293:75|345:204,1,0
+
+// Bezier
+76,191,11756,2,0,B|176:59|358:340|438:190,1,0
+76,191,13582,2,0,B|176:59|358:340|438:190,1,0
+76,191,15408,2,0,B|176:59|358:340|438:190,1,0
diff --git a/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs b/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs
index b986076593..05eb0ffdbf 100644
--- a/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs
+++ b/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs
@@ -162,7 +162,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
private readonly TrailPart[] parts = new TrailPart[max_sprites];
private Vector2 size;
- private readonly VertexBatch vertexBatch = new QuadBatch(max_sprites, 1);
+ private readonly TrailBatch vertexBatch = new TrailBatch(max_sprites, 1);
public TrailDrawNode(CursorTrail source)
: base(source)
@@ -196,21 +196,16 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
for (int i = 0; i < parts.Length; ++i)
{
+ vertexBatch.DrawTime = parts[i].Time;
+
Vector2 pos = parts[i].Position;
- float localTime = parts[i].Time;
DrawQuad(
texture,
new Quad(pos.X - size.X / 2, pos.Y - size.Y / 2, size.X, size.Y),
DrawColourInfo.Colour,
null,
- v => vertexBatch.Add(new TexturedTrailVertex
- {
- Position = v.Position,
- TexturePosition = v.TexturePosition,
- Time = localTime + 1,
- Colour = v.Colour,
- }));
+ vertexBatch.AddAction);
}
shader.Unbind();
@@ -222,6 +217,25 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
vertexBatch.Dispose();
}
+
+ // Todo: This shouldn't exist, but is currently used to reduce allocations by caching variable-capturing closures.
+ private class TrailBatch : QuadBatch
+ {
+ public new readonly Action AddAction;
+ public float DrawTime;
+
+ public TrailBatch(int size, int maxBuffers)
+ : base(size, maxBuffers)
+ {
+ AddAction = v => Add(new TexturedTrailVertex
+ {
+ Position = v.Position,
+ TexturePosition = v.TexturePosition,
+ Time = DrawTime + 1,
+ Colour = v.Colour,
+ });
+ }
+ }
}
[StructLayout(LayoutKind.Sequential)]
diff --git a/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs b/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs
index 0cbe0cca85..9037faf606 100644
--- a/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs
+++ b/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs
@@ -12,6 +12,7 @@ using osu.Game.Rulesets.UI;
using System.Linq;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Osu.UI.Cursor;
+using osu.Game.Skinning;
namespace osu.Game.Rulesets.Osu.UI
{
@@ -39,7 +40,13 @@ namespace osu.Game.Rulesets.Osu.UI
RelativeSizeAxes = Axes.Both,
Depth = 1,
},
- HitObjectContainer,
+ // Todo: This should not exist, but currently helps to reduce LOH allocations due to unbinding skin source events on judgement disposal
+ // Todo: Remove when hitobjects are properly pooled
+ new LocalSkinOverrideContainer(null)
+ {
+ RelativeSizeAxes = Axes.Both,
+ Child = HitObjectContainer,
+ },
approachCircles = new ApproachCircleProxyContainer
{
RelativeSizeAxes = Axes.Both,
diff --git a/osu.Game/Graphics/Backgrounds/Background.cs b/osu.Game/Graphics/Backgrounds/Background.cs
index 526b3da8a6..d13475189d 100644
--- a/osu.Game/Graphics/Backgrounds/Background.cs
+++ b/osu.Game/Graphics/Backgrounds/Background.cs
@@ -16,7 +16,7 @@ namespace osu.Game.Graphics.Backgrounds
///
public class Background : CompositeDrawable
{
- public Sprite Sprite;
+ public readonly Sprite Sprite;
private readonly string textureName;
@@ -51,7 +51,7 @@ namespace osu.Game.Graphics.Backgrounds
/// A to which further transforms can be added.
public void BlurTo(Vector2 newBlurSigma, double duration = 0, Easing easing = Easing.None)
{
- if (bufferedContainer == null)
+ if (bufferedContainer == null && newBlurSigma != Vector2.Zero)
{
RemoveInternal(Sprite);
@@ -63,7 +63,7 @@ namespace osu.Game.Graphics.Backgrounds
});
}
- bufferedContainer.BlurTo(newBlurSigma, duration, easing);
+ bufferedContainer?.BlurTo(newBlurSigma, duration, easing);
}
}
}
diff --git a/osu.Game/Online/Leaderboards/Leaderboard.cs b/osu.Game/Online/Leaderboards/Leaderboard.cs
index 35f7ba1c1b..18c827707a 100644
--- a/osu.Game/Online/Leaderboards/Leaderboard.cs
+++ b/osu.Game/Online/Leaderboards/Leaderboard.cs
@@ -51,7 +51,6 @@ namespace osu.Game.Online.Leaderboards
loading.Hide();
- // schedule because we may not be loaded yet (LoadComponentAsync complains).
showScoresDelegate?.Cancel();
showScoresCancellationSource?.Cancel();
@@ -61,28 +60,22 @@ namespace osu.Game.Online.Leaderboards
// ensure placeholder is hidden when displaying scores
PlaceholderState = PlaceholderState.Successful;
- scrollFlow = CreateScoreFlow();
- scrollFlow.ChildrenEnumerable = scores.Select((s, index) => CreateDrawableScore(s, index + 1));
+ var sf = CreateScoreFlow();
+ sf.ChildrenEnumerable = scores.Select((s, index) => CreateDrawableScore(s, index + 1));
- if (!IsLoaded)
- showScoresDelegate = Schedule(showScores);
- else
- showScores();
-
- void showScores() => LoadComponentAsync(scrollFlow, _ =>
+ // schedule because we may not be loaded yet (LoadComponentAsync complains).
+ showScoresDelegate = Schedule(() => LoadComponentAsync(sf, _ =>
{
- scrollContainer.Add(scrollFlow);
+ scrollContainer.Add(scrollFlow = sf);
int i = 0;
foreach (var s in scrollFlow.Children)
- {
using (s.BeginDelayedSequence(i++ * 50, true))
s.Show();
- }
scrollContainer.ScrollTo(0f, false);
- }, (showScoresCancellationSource = new CancellationTokenSource()).Token);
+ }, (showScoresCancellationSource = new CancellationTokenSource()).Token));
}
}
diff --git a/osu.Game/Overlays/BeatmapSet/Scores/TopScoreUserSection.cs b/osu.Game/Overlays/BeatmapSet/Scores/TopScoreUserSection.cs
index a15d3c5fd1..ffc39e5af2 100644
--- a/osu.Game/Overlays/BeatmapSet/Scores/TopScoreUserSection.cs
+++ b/osu.Game/Overlays/BeatmapSet/Scores/TopScoreUserSection.cs
@@ -62,7 +62,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
},
}
},
- avatar = new UpdateableAvatar(hideImmediately: true)
+ avatar = new UpdateableAvatar
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
@@ -99,7 +99,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
Origin = Anchor.CentreLeft,
Font = OsuFont.GetFont(size: 15, weight: FontWeight.Bold)
},
- flag = new UpdateableFlag(hideImmediately: true)
+ flag = new UpdateableFlag
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
diff --git a/osu.Game/Overlays/Direct/DirectRulesetSelector.cs b/osu.Game/Overlays/Direct/DirectRulesetSelector.cs
index fdab9f1b90..106aaa616b 100644
--- a/osu.Game/Overlays/Direct/DirectRulesetSelector.cs
+++ b/osu.Game/Overlays/Direct/DirectRulesetSelector.cs
@@ -26,8 +26,13 @@ namespace osu.Game.Overlays.Direct
TabContainer.Masking = false;
TabContainer.Spacing = new Vector2(10, 0);
AutoSizeAxes = Axes.Both;
+ }
- Current.DisabledChanged += value => SelectedTab.FadeColour(value ? Color4.DarkGray : Color4.White, 200, Easing.OutQuint);
+ protected override void LoadComplete()
+ {
+ base.LoadComplete();
+
+ Current.BindDisabledChanged(value => SelectedTab.FadeColour(value ? Color4.DarkGray : Color4.White, 200, Easing.OutQuint), true);
}
protected override TabItem CreateTabItem(RulesetInfo value) => new DirectRulesetTabItem(value);
diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs
index 1f6ca4dd73..e61fac679e 100644
--- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs
+++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs
@@ -7,7 +7,6 @@ using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Extensions.TypeExtensions;
-using osu.Framework.Graphics;
using osu.Framework.Graphics.Primitives;
using osu.Game.Audio;
using osu.Game.Graphics;
@@ -179,6 +178,39 @@ namespace osu.Game.Rulesets.Objects.Drawables
UpdateResult(false);
}
+ private double? lifetimeStart;
+
+ public override double LifetimeStart
+ {
+ get => lifetimeStart ?? (HitObject.StartTime - InitialLifetimeOffset);
+ set
+ {
+ base.LifetimeStart = value;
+ lifetimeStart = value;
+ }
+ }
+
+ ///
+ /// A safe offset prior to the start time of at which this may begin displaying contents.
+ /// By default, s are assumed to display their contents within 10 seconds prior to the start time of .
+ ///
+ ///
+ /// This is only used as an optimisation to delay the initial update of this and may be tuned more aggressively if required.
+ /// A more accurate should be set inside for an state.
+ ///
+ protected virtual double InitialLifetimeOffset => 10000;
+
+ ///
+ /// Will be called at least once after this has become not alive.
+ ///
+ public virtual void OnKilled()
+ {
+ foreach (var nested in NestedHitObjects)
+ nested.OnKilled();
+
+ UpdateResult(false);
+ }
+
protected virtual void AddNested(DrawableHitObject h)
{
h.OnNewResult += (d, r) => OnNewResult?.Invoke(d, r);
@@ -223,16 +255,6 @@ namespace osu.Game.Rulesets.Objects.Drawables
OnNewResult?.Invoke(this, Result);
}
- ///
- /// Will called at least once after the of this has been passed.
- ///
- internal void OnLifetimeEnd()
- {
- foreach (var nested in NestedHitObjects)
- nested.OnLifetimeEnd();
- UpdateResult(false);
- }
-
///
/// Processes this , checking if a scoring result has occurred.
///
diff --git a/osu.Game/Rulesets/Objects/Legacy/Catch/ConvertHitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/Catch/ConvertHitObjectParser.cs
index 6e79d0b766..71e321f205 100644
--- a/osu.Game/Rulesets/Objects/Legacy/Catch/ConvertHitObjectParser.cs
+++ b/osu.Game/Rulesets/Objects/Legacy/Catch/ConvertHitObjectParser.cs
@@ -37,7 +37,8 @@ namespace osu.Game.Rulesets.Objects.Legacy.Catch
};
}
- protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, Vector2[] controlPoints, double length, PathType pathType, int repeatCount, List> nodeSamples)
+ protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, Vector2[] controlPoints, double? length, PathType pathType, int repeatCount,
+ List> nodeSamples)
{
newCombo |= forceNewCombo;
comboOffset += extraComboOffset;
diff --git a/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs
index f5b1cbcebf..d70c1bf7d3 100644
--- a/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs
+++ b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs
@@ -72,7 +72,7 @@ namespace osu.Game.Rulesets.Objects.Legacy
else if (type.HasFlag(ConvertHitObjectType.Slider))
{
PathType pathType = PathType.Catmull;
- double length = 0;
+ double? length = null;
string[] pointSplit = split[5].Split('|');
@@ -130,7 +130,11 @@ namespace osu.Game.Rulesets.Objects.Legacy
repeatCount = Math.Max(0, repeatCount - 1);
if (split.Length > 7)
+ {
length = Math.Max(0, Parsing.ParseDouble(split[7]));
+ if (length == 0)
+ length = null;
+ }
if (split.Length > 10)
readCustomSampleBanks(split[10], bankInfo);
@@ -291,7 +295,8 @@ namespace osu.Game.Rulesets.Objects.Legacy
/// The slider repeat count.
/// The samples to be played when the slider nodes are hit. This includes the head and tail of the slider.
/// The hit object.
- protected abstract HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, Vector2[] controlPoints, double length, PathType pathType, int repeatCount, List> nodeSamples);
+ protected abstract HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, Vector2[] controlPoints, double? length, PathType pathType, int repeatCount,
+ List> nodeSamples);
///
/// Creates a legacy Spinner-type hit object.
diff --git a/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHitObjectParser.cs
index b20a027e78..94aba95e90 100644
--- a/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHitObjectParser.cs
+++ b/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHitObjectParser.cs
@@ -26,7 +26,8 @@ namespace osu.Game.Rulesets.Objects.Legacy.Mania
};
}
- protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, Vector2[] controlPoints, double length, PathType pathType, int repeatCount, List> nodeSamples)
+ protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, Vector2[] controlPoints, double? length, PathType pathType, int repeatCount,
+ List> nodeSamples)
{
return new ConvertSlider
{
diff --git a/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertHitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertHitObjectParser.cs
index 0a4e38df02..65102f1e89 100644
--- a/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertHitObjectParser.cs
+++ b/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertHitObjectParser.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 osuTK;
using osu.Game.Rulesets.Objects.Types;
using System.Collections.Generic;
@@ -38,7 +37,8 @@ namespace osu.Game.Rulesets.Objects.Legacy.Osu
};
}
- protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, Vector2[] controlPoints, double length, PathType pathType, int repeatCount, List> nodeSamples)
+ protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, Vector2[] controlPoints, double? length, PathType pathType, int repeatCount,
+ List> nodeSamples)
{
newCombo |= forceNewCombo;
comboOffset += extraComboOffset;
@@ -51,7 +51,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Osu
Position = position,
NewCombo = FirstObject || newCombo,
ComboOffset = comboOffset,
- Path = new SliderPath(pathType, controlPoints, Math.Max(0, length)),
+ Path = new SliderPath(pathType, controlPoints, length),
NodeSamples = nodeSamples,
RepeatCount = repeatCount
};
diff --git a/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertHitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertHitObjectParser.cs
index 7c1514c1eb..eb598f1368 100644
--- a/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertHitObjectParser.cs
+++ b/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertHitObjectParser.cs
@@ -23,7 +23,8 @@ namespace osu.Game.Rulesets.Objects.Legacy.Taiko
return new ConvertHit();
}
- protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, Vector2[] controlPoints, double length, PathType pathType, int repeatCount, List> nodeSamples)
+ protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, Vector2[] controlPoints, double? length, PathType pathType, int repeatCount,
+ List> nodeSamples)
{
return new ConvertSlider
{
diff --git a/osu.Game/Rulesets/UI/HitObjectContainer.cs b/osu.Game/Rulesets/UI/HitObjectContainer.cs
index 2f3a384e95..9485189433 100644
--- a/osu.Game/Rulesets/UI/HitObjectContainer.cs
+++ b/osu.Game/Rulesets/UI/HitObjectContainer.cs
@@ -34,8 +34,14 @@ namespace osu.Game.Rulesets.UI
protected override void OnChildLifetimeBoundaryCrossed(LifetimeBoundaryCrossedEvent e)
{
- if (e.Kind == LifetimeBoundaryKind.End && e.Direction == LifetimeBoundaryCrossingDirection.Forward && e.Child is DrawableHitObject hitObject)
- hitObject.OnLifetimeEnd();
+ if (!(e.Child is DrawableHitObject hitObject))
+ return;
+
+ if ((e.Kind == LifetimeBoundaryKind.End && e.Direction == LifetimeBoundaryCrossingDirection.Forward)
+ || (e.Kind == LifetimeBoundaryKind.Start && e.Direction == LifetimeBoundaryCrossingDirection.Backward))
+ {
+ hitObject.OnKilled();
+ }
}
}
}
diff --git a/osu.Game/Screens/Backgrounds/BackgroundScreenBeatmap.cs b/osu.Game/Screens/Backgrounds/BackgroundScreenBeatmap.cs
index 08f1881038..5225740d0b 100644
--- a/osu.Game/Screens/Backgrounds/BackgroundScreenBeatmap.cs
+++ b/osu.Game/Screens/Backgrounds/BackgroundScreenBeatmap.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;
@@ -168,6 +168,12 @@ namespace osu.Game.Screens.Backgrounds
private void load(OsuConfigManager config)
{
userBlurLevel = config.GetBindable(OsuSetting.BlurLevel);
+ }
+
+ protected override void LoadComplete()
+ {
+ base.LoadComplete();
+
userBlurLevel.ValueChanged += _ => UpdateVisuals();
BlurAmount.ValueChanged += _ => UpdateVisuals();
}
diff --git a/osu.Game/Screens/Ranking/Results.cs b/osu.Game/Screens/Ranking/Results.cs
index f53fb75e1a..cac26b3dbf 100644
--- a/osu.Game/Screens/Ranking/Results.cs
+++ b/osu.Game/Screens/Ranking/Results.cs
@@ -256,9 +256,12 @@ namespace osu.Game.Screens.Ranking
}
};
- foreach (var t in CreateResultPages())
- modeChangeButtons.AddItem(t);
- modeChangeButtons.Current.Value = modeChangeButtons.Items.FirstOrDefault();
+ var pages = CreateResultPages();
+
+ foreach (var p in pages)
+ modeChangeButtons.AddItem(p);
+
+ modeChangeButtons.Current.Value = pages.FirstOrDefault();
modeChangeButtons.Current.BindValueChanged(page =>
{
diff --git a/osu.Game/Screens/Select/FooterButtonMods.cs b/osu.Game/Screens/Select/FooterButtonMods.cs
index c96c5022c0..fce4d1b2e2 100644
--- a/osu.Game/Screens/Select/FooterButtonMods.cs
+++ b/osu.Game/Screens/Select/FooterButtonMods.cs
@@ -9,18 +9,25 @@ using osu.Game.Rulesets.Mods;
using System.Collections.Generic;
using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions;
+using osu.Framework.Graphics.UserInterface;
using osu.Game.Graphics;
using osuTK;
using osuTK.Input;
namespace osu.Game.Screens.Select
{
- public class FooterButtonMods : FooterButton
+ public class FooterButtonMods : FooterButton, IHasCurrentValue>
{
- public FooterButtonMods(Bindable> mods)
+ public Bindable> Current
{
- FooterModDisplay modDisplay;
+ get => modDisplay.Current;
+ set => modDisplay.Current = value;
+ }
+ private readonly FooterModDisplay modDisplay;
+
+ public FooterButtonMods()
+ {
Add(new Container
{
Anchor = Anchor.CentreLeft,
@@ -33,9 +40,6 @@ namespace osu.Game.Screens.Select
AutoSizeAxes = Axes.Both,
Margin = new MarginPadding { Left = 70 }
});
-
- if (mods != null)
- modDisplay.Current = mods;
}
[BackgroundDependencyLoader]
diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs
index b3c3925a26..20dbcf2693 100644
--- a/osu.Game/Screens/Select/SongSelect.cs
+++ b/osu.Game/Screens/Select/SongSelect.cs
@@ -221,11 +221,9 @@ namespace osu.Game.Screens.Select
[BackgroundDependencyLoader(true)]
private void load(BeatmapManager beatmaps, AudioManager audio, DialogOverlay dialog, OsuColour colours, SkinManager skins, ScoreManager scores)
{
- mods.BindTo(Mods);
-
if (Footer != null)
{
- Footer.AddButton(new FooterButtonMods(mods), ModSelect);
+ Footer.AddButton(new FooterButtonMods { Current = mods }, ModSelect);
Footer.AddButton(new FooterButtonRandom { Action = triggerRandom });
Footer.AddButton(new FooterButtonOptions(), BeatmapOptions);
@@ -253,7 +251,7 @@ namespace osu.Game.Screens.Select
Schedule(() =>
{
// if we have no beatmaps but osu-stable is found, let's prompt the user to import.
- if (!beatmaps.GetAllUsableBeatmapSets().Any() && beatmaps.StableInstallationAvailable)
+ if (!beatmaps.GetAllUsableBeatmapSetsEnumerable().Any() && beatmaps.StableInstallationAvailable)
dialogOverlay.Push(new ImportFromStablePopup(() =>
{
Task.Run(beatmaps.ImportFromStableAsync).ContinueWith(_ => scores.ImportFromStableAsync(), TaskContinuationOptions.OnlyOnRanToCompletion);
@@ -263,6 +261,13 @@ namespace osu.Game.Screens.Select
}
}
+ protected override void LoadComplete()
+ {
+ base.LoadComplete();
+
+ mods.BindTo(Mods);
+ }
+
private DependencyContainer dependencies;
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
diff --git a/osu.Game/Skinning/LocalSkinOverrideContainer.cs b/osu.Game/Skinning/LocalSkinOverrideContainer.cs
index 37f4cc28a2..7882e0f31b 100644
--- a/osu.Game/Skinning/LocalSkinOverrideContainer.cs
+++ b/osu.Game/Skinning/LocalSkinOverrideContainer.cs
@@ -34,7 +34,7 @@ namespace osu.Game.Skinning
public Drawable GetDrawableComponent(string componentName)
{
Drawable sourceDrawable;
- if (beatmapSkins.Value && (sourceDrawable = skin.GetDrawableComponent(componentName)) != null)
+ if (beatmapSkins.Value && (sourceDrawable = skin?.GetDrawableComponent(componentName)) != null)
return sourceDrawable;
return fallbackSource?.GetDrawableComponent(componentName);
@@ -43,7 +43,7 @@ namespace osu.Game.Skinning
public Texture GetTexture(string componentName)
{
Texture sourceTexture;
- if (beatmapSkins.Value && (sourceTexture = skin.GetTexture(componentName)) != null)
+ if (beatmapSkins.Value && (sourceTexture = skin?.GetTexture(componentName)) != null)
return sourceTexture;
return fallbackSource.GetTexture(componentName);
@@ -52,7 +52,7 @@ namespace osu.Game.Skinning
public SampleChannel GetSample(string sampleName)
{
SampleChannel sourceChannel;
- if (beatmapHitsounds.Value && (sourceChannel = skin.GetSample(sampleName)) != null)
+ if (beatmapHitsounds.Value && (sourceChannel = skin?.GetSample(sampleName)) != null)
return sourceChannel;
return fallbackSource?.GetSample(sampleName);
diff --git a/osu.Game/Users/Drawables/UpdateableAvatar.cs b/osu.Game/Users/Drawables/UpdateableAvatar.cs
index a49f2d079b..795b90ba11 100644
--- a/osu.Game/Users/Drawables/UpdateableAvatar.cs
+++ b/osu.Game/Users/Drawables/UpdateableAvatar.cs
@@ -5,7 +5,6 @@ using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Effects;
-using osu.Framework.Graphics.Transforms;
namespace osu.Game.Users.Drawables
{
@@ -38,8 +37,6 @@ namespace osu.Game.Users.Drawables
set => base.EdgeEffect = value;
}
- protected override bool TransformImmediately { get; }
-
///
/// Whether to show a default guest representation on null user (as opposed to nothing).
///
@@ -50,14 +47,11 @@ namespace osu.Game.Users.Drawables
///
public readonly BindableBool OpenOnClick = new BindableBool(true);
- public UpdateableAvatar(User user = null, bool hideImmediately = false)
+ public UpdateableAvatar(User user = null)
{
- TransformImmediately = hideImmediately;
User = user;
}
- protected override TransformSequence ApplyHideTransforms(Drawable drawable) => TransformImmediately ? drawable?.FadeOut() : base.ApplyHideTransforms(drawable);
-
protected override Drawable CreateDrawable(User user)
{
if (user == null && !ShowGuestOnNull)
diff --git a/osu.Game/Users/Drawables/UpdateableFlag.cs b/osu.Game/Users/Drawables/UpdateableFlag.cs
index 78d1a8de20..abc16b2390 100644
--- a/osu.Game/Users/Drawables/UpdateableFlag.cs
+++ b/osu.Game/Users/Drawables/UpdateableFlag.cs
@@ -3,7 +3,6 @@
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
-using osu.Framework.Graphics.Transforms;
namespace osu.Game.Users.Drawables
{
@@ -15,21 +14,16 @@ namespace osu.Game.Users.Drawables
set => Model = value;
}
- protected override bool TransformImmediately { get; }
-
///
/// Whether to show a place holder on null country.
///
public bool ShowPlaceholderOnNull = true;
- public UpdateableFlag(Country country = null, bool hideImmediately = false)
+ public UpdateableFlag(Country country = null)
{
- TransformImmediately = hideImmediately;
Country = country;
}
- protected override TransformSequence ApplyHideTransforms(Drawable drawable) => TransformImmediately ? drawable?.FadeOut() : base.ApplyHideTransforms(drawable);
-
protected override Drawable CreateDrawable(Country country)
{
if (country == null && !ShowPlaceholderOnNull)
diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj
index 436ba90a88..86a68d2159 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 c24349bcb5..712effcc39 100644
--- a/osu.iOS.props
+++ b/osu.iOS.props
@@ -105,8 +105,8 @@
-
-
+
+