diff --git a/osu.Android.props b/osu.Android.props
index b24493665e..6744590f0d 100644
--- a/osu.Android.props
+++ b/osu.Android.props
@@ -63,6 +63,6 @@
-
+
diff --git a/osu.Desktop/Updater/SquirrelUpdateManager.cs b/osu.Desktop/Updater/SquirrelUpdateManager.cs
index 78a1e680ec..fa41c061b5 100644
--- a/osu.Desktop/Updater/SquirrelUpdateManager.cs
+++ b/osu.Desktop/Updater/SquirrelUpdateManager.cs
@@ -27,6 +27,8 @@ namespace osu.Desktop.Updater
public Task PrepareUpdateAsync() => UpdateManager.RestartAppWhenExited();
+ private static readonly Logger logger = Logger.GetLogger("updater");
+
[BackgroundDependencyLoader]
private void load(NotificationOverlay notification, OsuGameBase game)
{
@@ -77,7 +79,7 @@ namespace osu.Desktop.Updater
{
if (useDeltaPatching)
{
- Logger.Error(e, @"delta patching failed!");
+ logger.Add(@"delta patching failed; will attempt full download!");
//could fail if deltas are unavailable for full update path (https://github.com/Squirrel/Squirrel.Windows/issues/959)
//try again without deltas.
@@ -163,16 +165,11 @@ namespace osu.Desktop.Updater
{
public LogLevel Level { get; set; } = LogLevel.Info;
- private Logger logger;
-
public void Write(string message, LogLevel logLevel)
{
if (logLevel < Level)
return;
- if (logger == null)
- logger = Logger.GetLogger("updater");
-
logger.Add(message);
}
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModHidden.cs b/osu.Game.Rulesets.Osu/Mods/OsuModHidden.cs
index ddf708d0f1..2d940479f3 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModHidden.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModHidden.cs
@@ -17,6 +17,7 @@ namespace osu.Game.Rulesets.Osu.Mods
{
public override string Description => @"Play with no approach circles and fading circles/sliders.";
public override double ScoreMultiplier => 1.06;
+ public override Type[] IncompatibleMods => new[] { typeof(OsuModSpinIn) };
private const double fade_in_duration_multiplier = 0.4;
private const double fade_out_duration_multiplier = 0.3;
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModSpinIn.cs b/osu.Game.Rulesets.Osu/Mods/OsuModSpinIn.cs
new file mode 100644
index 0000000000..62b5ecfd58
--- /dev/null
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModSpinIn.cs
@@ -0,0 +1,92 @@
+// 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.Bindables;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Sprites;
+using osu.Game.Configuration;
+using osu.Game.Rulesets.Mods;
+using osu.Game.Rulesets.Objects.Drawables;
+using osu.Game.Rulesets.Osu.Objects;
+using osu.Game.Rulesets.Osu.Objects.Drawables;
+using osuTK;
+
+namespace osu.Game.Rulesets.Osu.Mods
+{
+ public class OsuModSpinIn : Mod, IApplicableToDrawableHitObjects, IReadFromConfig
+ {
+ public override string Name => "Spin In";
+ public override string Acronym => "SI";
+ public override IconUsage Icon => FontAwesome.Solid.Undo;
+ public override ModType Type => ModType.Fun;
+ public override string Description => "Circles spin in. No approach circles.";
+ public override double ScoreMultiplier => 1;
+
+ // todo: this mod should be able to be compatible with hidden with a bit of further implementation.
+ public override Type[] IncompatibleMods => new[] { typeof(OsuModeObjectScaleTween), typeof(OsuModHidden) };
+
+ private const int rotate_offset = 360;
+ private const float rotate_starting_width = 2;
+
+ private Bindable increaseFirstObjectVisibility = new Bindable();
+
+ public void ReadFromConfig(OsuConfigManager config)
+ {
+ increaseFirstObjectVisibility = config.GetBindable(OsuSetting.IncreaseFirstObjectVisibility);
+ }
+
+ public void ApplyToDrawableHitObjects(IEnumerable drawables)
+ {
+ foreach (var drawable in drawables.Skip(increaseFirstObjectVisibility.Value ? 1 : 0))
+ {
+ switch (drawable)
+ {
+ case DrawableSpinner _:
+ continue;
+
+ default:
+ drawable.ApplyCustomUpdateState += applyZoomState;
+ break;
+ }
+ }
+ }
+
+ private void applyZoomState(DrawableHitObject drawable, ArmedState state)
+ {
+ var h = (OsuHitObject)drawable.HitObject;
+
+ switch (drawable)
+ {
+ case DrawableHitCircle circle:
+ using (circle.BeginAbsoluteSequence(h.StartTime - h.TimePreempt, true))
+ {
+ circle.ApproachCircle.Hide();
+
+ circle.RotateTo(rotate_offset).Then().RotateTo(0, h.TimePreempt, Easing.InOutSine);
+ circle.ScaleTo(new Vector2(rotate_starting_width, 0)).Then().ScaleTo(1, h.TimePreempt, Easing.InOutSine);
+
+ // bypass fade in.
+ if (state == ArmedState.Idle)
+ circle.FadeIn();
+ }
+
+ break;
+
+ case DrawableSlider slider:
+ using (slider.BeginAbsoluteSequence(h.StartTime - h.TimePreempt))
+ {
+ slider.ScaleTo(0).Then().ScaleTo(1, h.TimePreempt, Easing.InOutSine);
+
+ // bypass fade in.
+ if (state == ArmedState.Idle)
+ slider.FadeIn();
+ }
+
+ break;
+ }
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModeObjectScaleTween.cs b/osu.Game.Rulesets.Osu/Mods/OsuModeObjectScaleTween.cs
index ad6a15718a..e926ade41b 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModeObjectScaleTween.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModeObjectScaleTween.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 System;
using System.Collections.Generic;
using System.Linq;
using osu.Framework.Bindables;
@@ -28,6 +29,8 @@ namespace osu.Game.Rulesets.Osu.Mods
private Bindable increaseFirstObjectVisibility = new Bindable();
+ public override Type[] IncompatibleMods => new[] { typeof(OsuModSpinIn) };
+
public void ReadFromConfig(OsuConfigManager config)
{
increaseFirstObjectVisibility = config.GetBindable(OsuSetting.IncreaseFirstObjectVisibility);
@@ -64,7 +67,7 @@ namespace osu.Game.Rulesets.Osu.Mods
case DrawableSlider _:
case DrawableHitCircle _:
{
- using (drawable.BeginAbsoluteSequence(h.StartTime - h.TimePreempt, true))
+ using (drawable.BeginAbsoluteSequence(h.StartTime - h.TimePreempt))
drawable.ScaleTo(StartScale).Then().ScaleTo(EndScale, h.TimePreempt, Easing.OutSine);
break;
}
@@ -75,7 +78,7 @@ namespace osu.Game.Rulesets.Osu.Mods
{
case DrawableHitCircle circle:
// we don't want to see the approach circle
- using (circle.BeginAbsoluteSequence(h.StartTime - h.TimePreempt, true))
+ using (circle.BeginAbsoluteSequence(h.StartTime - h.TimePreempt))
circle.ApproachCircle.Hide();
break;
}
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPointRenderer.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPointRenderer.cs
index 7569626230..a269b87c75 100644
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPointRenderer.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPointRenderer.cs
@@ -97,13 +97,13 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
Position = pointStartPosition,
Rotation = rotation,
Alpha = 0,
- Scale = new Vector2(1.5f),
+ Scale = new Vector2(1.5f * currHitObject.Scale),
});
using (fp.BeginAbsoluteSequence(fadeInTime))
{
fp.FadeIn(currHitObject.TimeFadeIn);
- fp.ScaleTo(1, currHitObject.TimeFadeIn, Easing.Out);
+ fp.ScaleTo(currHitObject.Scale, currHitObject.TimeFadeIn, Easing.Out);
fp.MoveTo(pointEndPosition, currHitObject.TimeFadeIn, Easing.Out);
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs
index d3d763daf3..f0127e30ec 100644
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs
@@ -133,7 +133,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
base.UpdateInitialTransforms();
ApproachCircle.FadeIn(Math.Min(HitObject.TimeFadeIn * 2, HitObject.TimePreempt));
- ApproachCircle.ScaleTo(1.1f, HitObject.TimePreempt);
+ ApproachCircle.ScaleTo(1f, HitObject.TimePreempt);
ApproachCircle.Expire(true);
}
@@ -169,6 +169,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
.FadeOut(100);
explode.FadeIn(flash_in);
+ explodeContainer.ScaleTo(1.5f, 400, Easing.OutQuad);
using (BeginDelayedSequence(flash_in, true))
{
@@ -178,7 +179,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
number.FadeOut();
this.FadeOut(800);
- explodeContainer.ScaleTo(1.5f, 400, Easing.OutQuad);
}
Expire();
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableRepeatPoint.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableRepeatPoint.cs
index 2e6e7e03ac..f75b62eecf 100644
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableRepeatPoint.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableRepeatPoint.cs
@@ -3,6 +3,8 @@
using System;
using System.Collections.Generic;
+using osu.Framework.Allocation;
+using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites;
using osu.Framework.MathUtils;
@@ -20,27 +22,40 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
private double animDuration;
+ private readonly SkinnableDrawable scaleContainer;
+
public DrawableRepeatPoint(RepeatPoint repeatPoint, DrawableSlider drawableSlider)
: base(repeatPoint)
{
this.repeatPoint = repeatPoint;
this.drawableSlider = drawableSlider;
- Size = new Vector2(45 * repeatPoint.Scale);
+ Size = new Vector2(OsuHitObject.OBJECT_RADIUS * 2);
Blending = BlendingMode.Additive;
Origin = Anchor.Centre;
- InternalChildren = new Drawable[]
+ InternalChild = scaleContainer = new SkinnableDrawable("Play/osu/reversearrow", _ => new SpriteIcon
{
- new SkinnableDrawable("Play/osu/reversearrow", _ => new SpriteIcon
- {
- RelativeSizeAxes = Axes.Both,
- Icon = FontAwesome.Solid.ChevronRight
- })
+ RelativeSizeAxes = Axes.Both,
+ Icon = FontAwesome.Solid.ChevronRight,
+ Size = new Vector2(0.35f)
+ }, confineMode: ConfineMode.NoScaling)
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
};
}
+ private readonly IBindable scaleBindable = new Bindable();
+
+ [BackgroundDependencyLoader]
+ private void load()
+ {
+ scaleBindable.BindValueChanged(scale => scaleContainer.Scale = new Vector2(scale.NewValue), true);
+ scaleBindable.BindTo(HitObject.ScaleBindable);
+ }
+
protected override void CheckForResult(bool userTriggered, double timeOffset)
{
if (repeatPoint.StartTime <= Time.Current)
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTick.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTick.cs
index c8062b67b5..653e73ac3f 100644
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTick.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTick.cs
@@ -1,6 +1,8 @@
// 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.Game.Rulesets.Objects.Drawables;
using osuTK;
@@ -16,36 +18,49 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
{
public const double ANIM_DURATION = 150;
+ private const float default_tick_size = 16;
+
public bool Tracking { get; set; }
public override bool DisplayResult => false;
+ private readonly SkinnableDrawable scaleContainer;
+
public DrawableSliderTick(SliderTick sliderTick)
: base(sliderTick)
{
- Size = new Vector2(16 * sliderTick.Scale);
+ Size = new Vector2(OsuHitObject.OBJECT_RADIUS * 2);
Origin = Anchor.Centre;
- InternalChildren = new Drawable[]
+ InternalChild = scaleContainer = new SkinnableDrawable("Play/osu/sliderscorepoint", _ => new CircularContainer
{
- new SkinnableDrawable("Play/osu/sliderscorepoint", _ => new Container
+ Masking = true,
+ Origin = Anchor.Centre,
+ Size = new Vector2(default_tick_size),
+ BorderThickness = default_tick_size / 4,
+ BorderColour = Color4.White,
+ Child = new Box
{
- Masking = true,
RelativeSizeAxes = Axes.Both,
- Origin = Anchor.Centre,
- CornerRadius = Size.X / 2,
- BorderThickness = 2,
- BorderColour = Color4.White,
- Child = new Box
- {
- RelativeSizeAxes = Axes.Both,
- Colour = AccentColour.Value,
- Alpha = 0.3f,
- }
- })
+ Colour = AccentColour.Value,
+ Alpha = 0.3f,
+ }
+ })
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
};
}
+ private readonly IBindable scaleBindable = new Bindable();
+
+ [BackgroundDependencyLoader]
+ private void load()
+ {
+ scaleBindable.BindValueChanged(scale => scaleContainer.Scale = new Vector2(scale.NewValue), true);
+ scaleBindable.BindTo(HitObject.ScaleBindable);
+ }
+
protected override void CheckForResult(bool userTriggered, double timeOffset)
{
if (timeOffset >= 0)
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/ApproachCircle.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/ApproachCircle.cs
index 9981585f9e..5813197336 100644
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/ApproachCircle.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/ApproachCircle.cs
@@ -6,6 +6,7 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Textures;
using osu.Game.Skinning;
+using osuTK;
namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
{
@@ -24,7 +25,26 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
[BackgroundDependencyLoader]
private void load(TextureStore textures)
{
- Child = new SkinnableSprite("Play/osu/approachcircle");
+ Child = new SkinnableApproachCircle();
+ }
+
+ private class SkinnableApproachCircle : SkinnableSprite
+ {
+ public SkinnableApproachCircle()
+ : base("Play/osu/approachcircle")
+ {
+ }
+
+ protected override Drawable CreateDefault(string name)
+ {
+ var drawable = base.CreateDefault(name);
+
+ // account for the sprite being used for the default approach circle being taken from stable,
+ // when hitcircles have 5px padding on each size. this should be removed if we update the sprite.
+ drawable.Scale = new Vector2(128 / 118f);
+
+ return drawable;
+ }
}
}
}
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBody.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBody.cs
index 97c7c9cec5..6bc19ee3b5 100644
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBody.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBody.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 System;
using System.Collections.Generic;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Lines;
@@ -75,22 +76,22 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
protected SliderBody()
{
- InternalChild = path = new SliderPath();
+ RecyclePath();
}
///
/// Initialises a new , releasing all resources retained by the old one.
///
- public void RecyclePath()
+ public virtual void RecyclePath()
{
InternalChild = path = new SliderPath
{
- Position = path.Position,
- PathRadius = path.PathRadius,
- AccentColour = path.AccentColour,
- BorderColour = path.BorderColour,
- BorderSize = path.BorderSize,
- Vertices = path.Vertices
+ Position = path?.Position ?? Vector2.Zero,
+ PathRadius = path?.PathRadius ?? 10,
+ AccentColour = path?.AccentColour ?? Color4.White,
+ BorderColour = path?.BorderColour ?? Color4.White,
+ BorderSize = path?.BorderSize ?? DEFAULT_BORDER_SIZE,
+ Vertices = path?.Vertices ?? Array.Empty()
};
}
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SnakingSliderBody.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SnakingSliderBody.cs
index 73b184bffe..a3d3893c8b 100644
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SnakingSliderBody.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SnakingSliderBody.cs
@@ -5,6 +5,7 @@ using System;
using System.Collections.Generic;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
+using osu.Framework.Graphics;
using osu.Game.Rulesets.Objects.Types;
using osuTK;
@@ -78,9 +79,12 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
slider.Path.GetPathToProgress(CurrentCurve, 0, 1);
SetVertices(CurrentCurve);
- // The body is sized to the full path size to avoid excessive autosize computations
+ // Force the body to be the final path size to avoid excessive autosize computations
+ Path.AutoSizeAxes = Axes.Both;
Size = Path.Size;
+ updatePathSize();
+
snakedPosition = Path.PositionInBoundingBox(Vector2.Zero);
snakedPathOffset = Path.PositionInBoundingBox(Path.Vertices[0]);
@@ -93,6 +97,19 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
setRange(lastSnakedStart, lastSnakedEnd);
}
+ public override void RecyclePath()
+ {
+ base.RecyclePath();
+ updatePathSize();
+ }
+
+ private void updatePathSize()
+ {
+ // Force the path to its final size to avoid excessive framebuffer resizes
+ Path.AutoSizeAxes = Axes.None;
+ Path.Size = Size;
+ }
+
private void setRange(double p0, double p1)
{
if (p0 > p1)
diff --git a/osu.Game.Rulesets.Osu/OsuRuleset.cs b/osu.Game.Rulesets.Osu/OsuRuleset.cs
index 8df0f77629..7f45fbe1dd 100644
--- a/osu.Game.Rulesets.Osu/OsuRuleset.cs
+++ b/osu.Game.Rulesets.Osu/OsuRuleset.cs
@@ -134,6 +134,7 @@ namespace osu.Game.Rulesets.Osu
{
new OsuModTransform(),
new OsuModWiggle(),
+ new OsuModSpinIn(),
new MultiMod(new OsuModGrow(), new OsuModDeflate()),
new MultiMod(new ModWindUp(), new ModWindDown()),
};
diff --git a/osu.Game.Rulesets.Osu/UI/OsuPlayfieldAdjustmentContainer.cs b/osu.Game.Rulesets.Osu/UI/OsuPlayfieldAdjustmentContainer.cs
index 8b6b483618..f7888f8022 100644
--- a/osu.Game.Rulesets.Osu/UI/OsuPlayfieldAdjustmentContainer.cs
+++ b/osu.Game.Rulesets.Osu/UI/OsuPlayfieldAdjustmentContainer.cs
@@ -18,6 +18,7 @@ namespace osu.Game.Rulesets.Osu.UI
Anchor = Anchor.Centre;
Origin = Anchor.Centre;
+ // Calculated from osu!stable as 512 (default gamefield size) / 640 (default window size)
Size = new Vector2(0.8f);
InternalChild = new Container
diff --git a/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs
index 4d3992ce13..9196513a55 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs
@@ -35,7 +35,7 @@ namespace osu.Game.Tests.Visual.Online
private TestChatOverlay chatOverlay;
private ChannelManager channelManager;
- private readonly Channel channel1 = new Channel(new User()) { Name = "test1" };
+ private readonly Channel channel1 = new Channel(new User()) { Name = "test really long username" };
private readonly Channel channel2 = new Channel(new User()) { Name = "test2" };
[SetUp]
diff --git a/osu.Game.Tournament/Screens/MapPool/MapPoolScreen.cs b/osu.Game.Tournament/Screens/MapPool/MapPoolScreen.cs
index 46d4cfa98c..d32c0d6156 100644
--- a/osu.Game.Tournament/Screens/MapPool/MapPoolScreen.cs
+++ b/osu.Game.Tournament/Screens/MapPool/MapPoolScreen.cs
@@ -47,8 +47,8 @@ namespace osu.Game.Tournament.Screens.MapPool
mapFlows = new FillFlowContainer>
{
Y = 100,
- Spacing = new Vector2(10, 20),
- Padding = new MarginPadding(50),
+ Spacing = new Vector2(10, 10),
+ Padding = new MarginPadding(25),
Direction = FillDirection.Vertical,
RelativeSizeAxes = Axes.Both,
},
@@ -218,7 +218,7 @@ namespace osu.Game.Tournament.Screens.MapPool
{
mapFlows.Add(currentFlow = new FillFlowContainer
{
- Spacing = new Vector2(10, 20),
+ Spacing = new Vector2(10, 5),
Direction = FillDirection.Full,
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y
diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs
index 65efcaa949..166ba5111c 100644
--- a/osu.Game/Beatmaps/BeatmapManager.cs
+++ b/osu.Game/Beatmaps/BeatmapManager.cs
@@ -386,7 +386,7 @@ namespace osu.Game.Beatmaps
beatmap.OnlineBeatmapID = res.OnlineBeatmapID;
};
- req.Failure += e => { LogForModel(set, $"Online retrieval failed for {beatmap}", e); };
+ req.Failure += e => { LogForModel(set, $"Online retrieval failed for {beatmap} ({e.Message})"); };
// intentionally blocking to limit web request concurrency
req.Perform(api);
diff --git a/osu.Game/Database/ArchiveModelManager.cs b/osu.Game/Database/ArchiveModelManager.cs
index ed65bdc069..efb76deff8 100644
--- a/osu.Game/Database/ArchiveModelManager.cs
+++ b/osu.Game/Database/ArchiveModelManager.cs
@@ -253,7 +253,7 @@ namespace osu.Game.Database
using (Stream s = reader.GetStream(file))
s.CopyTo(hashable);
- return hashable.ComputeSHA2Hash();
+ return hashable.Length > 0 ? hashable.ComputeSHA2Hash() : null;
}
///
diff --git a/osu.Game/Graphics/UserInterface/LineGraph.cs b/osu.Game/Graphics/UserInterface/LineGraph.cs
index 757a9a349c..714e953816 100644
--- a/osu.Game/Graphics/UserInterface/LineGraph.cs
+++ b/osu.Game/Graphics/UserInterface/LineGraph.cs
@@ -76,7 +76,12 @@ namespace osu.Game.Graphics.UserInterface
{
Masking = true,
RelativeSizeAxes = Axes.Both,
- Child = path = new SmoothPath { RelativeSizeAxes = Axes.Both, PathRadius = 1 }
+ Child = path = new SmoothPath
+ {
+ AutoSizeAxes = Axes.None,
+ RelativeSizeAxes = Axes.Both,
+ PathRadius = 1
+ }
});
}
diff --git a/osu.Game/Graphics/UserInterface/OsuTabControlCheckbox.cs b/osu.Game/Graphics/UserInterface/OsuTabControlCheckbox.cs
index 8134cfb42d..d158186899 100644
--- a/osu.Game/Graphics/UserInterface/OsuTabControlCheckbox.cs
+++ b/osu.Game/Graphics/UserInterface/OsuTabControlCheckbox.cs
@@ -64,7 +64,7 @@ namespace osu.Game.Graphics.UserInterface
Direction = FillDirection.Horizontal,
Children = new Drawable[]
{
- text = new OsuSpriteText { Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold) },
+ text = new OsuSpriteText { Font = OsuFont.GetFont(size: 14) },
icon = new SpriteIcon
{
Size = new Vector2(14),
@@ -84,7 +84,11 @@ namespace osu.Game.Graphics.UserInterface
}
};
- Current.ValueChanged += selected => { icon.Icon = selected.NewValue ? FontAwesome.Regular.CheckCircle : FontAwesome.Regular.Circle; };
+ Current.ValueChanged += selected =>
+ {
+ icon.Icon = selected.NewValue ? FontAwesome.Regular.CheckCircle : FontAwesome.Regular.Circle;
+ text.Font = text.Font.With(weight: selected.NewValue ? FontWeight.Bold : FontWeight.Medium);
+ };
}
[BackgroundDependencyLoader]
diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs
index 41b67f343a..ceaf0c3d5e 100644
--- a/osu.Game/OsuGame.cs
+++ b/osu.Game/OsuGame.cs
@@ -589,7 +589,7 @@ namespace osu.Game
{
int recentLogCount = 0;
- const double debounce = 5000;
+ const double debounce = 60000;
Logger.NewEntry += entry =>
{
diff --git a/osu.Game/Overlays/Chat/Tabs/ChannelSelectorTabItem.cs b/osu.Game/Overlays/Chat/Tabs/ChannelSelectorTabItem.cs
index 7386bffb1a..d5d9a6c2ce 100644
--- a/osu.Game/Overlays/Chat/Tabs/ChannelSelectorTabItem.cs
+++ b/osu.Game/Overlays/Chat/Tabs/ChannelSelectorTabItem.cs
@@ -13,6 +13,8 @@ namespace osu.Game.Overlays.Chat.Tabs
public override bool IsSwitchable => false;
+ protected override bool IsBoldWhenActive => false;
+
public ChannelSelectorTabItem()
: base(new ChannelSelectorTabChannel())
{
@@ -22,7 +24,7 @@ namespace osu.Game.Overlays.Chat.Tabs
Icon.Alpha = 0;
Text.Font = Text.Font.With(size: 45);
- TextBold.Font = Text.Font.With(size: 45);
+ Text.Truncate = false;
}
[BackgroundDependencyLoader]
diff --git a/osu.Game/Overlays/Chat/Tabs/ChannelTabItem.cs b/osu.Game/Overlays/Chat/Tabs/ChannelTabItem.cs
index 7f820e4ff7..266e68f17e 100644
--- a/osu.Game/Overlays/Chat/Tabs/ChannelTabItem.cs
+++ b/osu.Game/Overlays/Chat/Tabs/ChannelTabItem.cs
@@ -16,6 +16,7 @@ using osu.Game.Graphics.Sprites;
using osu.Game.Online.Chat;
using osuTK;
using osuTK.Graphics;
+using osuTK.Input;
namespace osu.Game.Overlays.Chat.Tabs
{
@@ -28,7 +29,6 @@ namespace osu.Game.Overlays.Chat.Tabs
public override bool IsRemovable => !Pinned;
protected readonly SpriteText Text;
- protected readonly SpriteText TextBold;
protected readonly ClickableContainer CloseButton;
private readonly Box box;
private readonly Box highlightBox;
@@ -87,20 +87,17 @@ namespace osu.Game.Overlays.Chat.Tabs
},
Text = new OsuSpriteText
{
- Margin = new MarginPadding(5),
Origin = Anchor.CentreLeft,
Anchor = Anchor.CentreLeft,
Text = value.ToString(),
- Font = OsuFont.GetFont(size: 18)
- },
- TextBold = new OsuSpriteText
- {
- Alpha = 0,
- Margin = new MarginPadding(5),
- Origin = Anchor.CentreLeft,
- Anchor = Anchor.CentreLeft,
- Text = value.ToString(),
- Font = OsuFont.GetFont(size: 18, weight: FontWeight.Bold)
+ Font = OsuFont.GetFont(size: 18),
+ Padding = new MarginPadding(5)
+ {
+ Left = LeftTextPadding,
+ Right = RightTextPadding,
+ },
+ RelativeSizeAxes = Axes.X,
+ Truncate = true,
},
CloseButton = new TabCloseButton
{
@@ -118,10 +115,16 @@ namespace osu.Game.Overlays.Chat.Tabs
};
}
+ protected virtual float LeftTextPadding => 5;
+
+ protected virtual float RightTextPadding => IsRemovable ? 40 : 5;
+
protected virtual IconUsage DisplayIcon => FontAwesome.Solid.Hashtag;
protected virtual bool ShowCloseOnHover => true;
+ protected virtual bool IsBoldWhenActive => true;
+
protected override bool OnHover(HoverEvent e)
{
if (IsRemovable && ShowCloseOnHover)
@@ -138,6 +141,19 @@ namespace osu.Game.Overlays.Chat.Tabs
updateState();
}
+ protected override bool OnMouseUp(MouseUpEvent e)
+ {
+ switch (e.Button)
+ {
+ case MouseButton.Middle:
+ CloseButton.Click();
+ return true;
+
+ default:
+ return false;
+ }
+ }
+
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
@@ -189,8 +205,7 @@ namespace osu.Game.Overlays.Chat.Tabs
box.FadeColour(BackgroundActive, TRANSITION_LENGTH, Easing.OutQuint);
highlightBox.FadeIn(TRANSITION_LENGTH, Easing.OutQuint);
- Text.FadeOut(TRANSITION_LENGTH, Easing.OutQuint);
- TextBold.FadeIn(TRANSITION_LENGTH, Easing.OutQuint);
+ if (IsBoldWhenActive) Text.Font = Text.Font.With(weight: FontWeight.Bold);
}
protected virtual void FadeInactive()
@@ -202,8 +217,7 @@ namespace osu.Game.Overlays.Chat.Tabs
box.FadeColour(BackgroundInactive, TRANSITION_LENGTH, Easing.OutQuint);
highlightBox.FadeOut(TRANSITION_LENGTH, Easing.OutQuint);
- Text.FadeIn(TRANSITION_LENGTH, Easing.OutQuint);
- TextBold.FadeOut(TRANSITION_LENGTH, Easing.OutQuint);
+ Text.Font = Text.Font.With(weight: FontWeight.Medium);
}
protected override void OnActivated() => updateState();
diff --git a/osu.Game/Overlays/Chat/Tabs/PrivateChannelTabItem.cs b/osu.Game/Overlays/Chat/Tabs/PrivateChannelTabItem.cs
index 9e87bae864..1413b8fe78 100644
--- a/osu.Game/Overlays/Chat/Tabs/PrivateChannelTabItem.cs
+++ b/osu.Game/Overlays/Chat/Tabs/PrivateChannelTabItem.cs
@@ -62,11 +62,10 @@ namespace osu.Game.Overlays.Chat.Tabs
});
avatar.OnLoadComplete += d => d.FadeInFromZero(300, Easing.OutQuint);
-
- Text.X = ChatOverlay.TAB_AREA_HEIGHT;
- TextBold.X = ChatOverlay.TAB_AREA_HEIGHT;
}
+ protected override float LeftTextPadding => base.LeftTextPadding + ChatOverlay.TAB_AREA_HEIGHT;
+
protected override bool ShowCloseOnHover => false;
protected override void FadeActive()
diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs
index 1d9d885527..b72a55b9ed 100644
--- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs
+++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs
@@ -17,6 +17,7 @@ using osuTK.Graphics;
namespace osu.Game.Rulesets.Objects.Drawables
{
+ [Cached(typeof(DrawableHitObject))]
public abstract class DrawableHitObject : SkinReloadableDrawable
{
public readonly HitObject HitObject;
@@ -147,12 +148,6 @@ namespace osu.Game.Rulesets.Objects.Drawables
if (State.Value == newState && !force)
return;
- // apply any custom state overrides
- ApplyCustomUpdateState?.Invoke(this, newState);
-
- if (newState == ArmedState.Hit)
- PlaySamples();
-
if (UseTransformStateManagement)
{
double transformTime = HitObject.StartTime - InitialLifetimeOffset;
@@ -177,6 +172,12 @@ namespace osu.Game.Rulesets.Objects.Drawables
state.Value = newState;
UpdateState(newState);
+
+ // apply any custom state overrides
+ ApplyCustomUpdateState?.Invoke(this, newState);
+
+ if (newState == ArmedState.Hit)
+ PlaySamples();
}
///
diff --git a/osu.Game/Screens/Multi/Multiplayer.cs b/osu.Game/Screens/Multi/Multiplayer.cs
index 9ffd620e55..90806bab6e 100644
--- a/osu.Game/Screens/Multi/Multiplayer.cs
+++ b/osu.Game/Screens/Multi/Multiplayer.cs
@@ -212,7 +212,7 @@ namespace osu.Game.Screens.Multi
public override bool OnExiting(IScreen next)
{
- if (!(screenStack.CurrentScreen is LoungeSubScreen))
+ if (screenStack.CurrentScreen != null && !(screenStack.CurrentScreen is LoungeSubScreen))
{
screenStack.Exit();
return true;
diff --git a/osu.Game/Screens/Play/BreakOverlay.cs b/osu.Game/Screens/Play/BreakOverlay.cs
index d390787090..2b401778a6 100644
--- a/osu.Game/Screens/Play/BreakOverlay.cs
+++ b/osu.Game/Screens/Play/BreakOverlay.cs
@@ -19,11 +19,11 @@ namespace osu.Game.Screens.Play
private const float remaining_time_container_max_size = 0.3f;
private const int vertical_margin = 25;
- private List breaks;
-
private readonly Container fadeContainer;
- public List Breaks
+ private IReadOnlyList breaks;
+
+ public IReadOnlyList Breaks
{
get => breaks;
set
diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs
index 16354534f4..cf88b697d9 100644
--- a/osu.Game/Screens/Select/BeatmapCarousel.cs
+++ b/osu.Game/Screens/Select/BeatmapCarousel.cs
@@ -26,6 +26,9 @@ namespace osu.Game.Screens.Select
{
public class BeatmapCarousel : OsuScrollContainer
{
+ private const float bleed_top = FilterControl.HEIGHT;
+ private const float bleed_bottom = Footer.HEIGHT;
+
///
/// Triggered when the loaded change and are completely loaded.
///
@@ -81,7 +84,8 @@ namespace osu.Game.Screens.Select
itemsCache.Invalidate();
scrollPositionCache.Invalidate();
- Schedule(() =>
+ // Run on late scheduler want to ensure this runs after all pending UpdateBeatmapSet / RemoveBeatmapSet operations are run.
+ SchedulerAfterChildren.Add(() =>
{
BeatmapSetsChanged?.Invoke();
BeatmapSetsLoaded = true;
@@ -129,19 +133,16 @@ namespace osu.Game.Screens.Select
loadBeatmapSets(beatmaps.GetAllUsableBeatmapSetsEnumerable());
}
- public void RemoveBeatmapSet(BeatmapSetInfo beatmapSet)
+ public void RemoveBeatmapSet(BeatmapSetInfo beatmapSet) => Schedule(() =>
{
- Schedule(() =>
- {
- var existingSet = beatmapSets.FirstOrDefault(b => b.BeatmapSet.ID == beatmapSet.ID);
+ var existingSet = beatmapSets.FirstOrDefault(b => b.BeatmapSet.ID == beatmapSet.ID);
- if (existingSet == null)
- return;
+ if (existingSet == null)
+ return;
- root.RemoveChild(existingSet);
- itemsCache.Invalidate();
- });
- }
+ root.RemoveChild(existingSet);
+ itemsCache.Invalidate();
+ });
public void UpdateBeatmapSet(BeatmapSetInfo beatmapSet) => Schedule(() =>
{
@@ -338,6 +339,25 @@ namespace osu.Game.Screens.Select
public bool AllowSelection = true;
+ ///
+ /// Half the height of the visible content.
+ ///
+ /// This is different from the height of , since
+ /// the beatmap carousel bleeds into the and the
+ ///
+ ///
+ private float visibleHalfHeight => (DrawHeight + bleed_bottom + bleed_top) / 2;
+
+ ///
+ /// The position of the lower visible bound with respect to the current scroll position.
+ ///
+ private float visibleBottomBound => Current + DrawHeight + bleed_bottom;
+
+ ///
+ /// The position of the upper visible bound with respect to the current scroll position.
+ ///
+ private float visibleUpperBound => Current - bleed_top;
+
public void FlushPendingFilterOperations()
{
if (PendingFilter?.Completed == false)
@@ -414,6 +434,8 @@ namespace osu.Game.Screens.Select
return true;
}
+ protected override bool ReceivePositionalInputAtSubTree(Vector2 screenSpacePos) => ReceivePositionalInputAt(screenSpacePos);
+
protected override void Update()
{
base.Update();
@@ -424,17 +446,15 @@ namespace osu.Game.Screens.Select
if (!scrollPositionCache.IsValid)
updateScrollPosition();
- float drawHeight = DrawHeight;
-
// Remove all items that should no longer be on-screen
- scrollableContent.RemoveAll(p => p.Y < Current - p.DrawHeight || p.Y > Current + drawHeight || !p.IsPresent);
+ scrollableContent.RemoveAll(p => p.Y < visibleUpperBound - p.DrawHeight || p.Y > visibleBottomBound || !p.IsPresent);
// Find index range of all items that should be on-screen
Trace.Assert(Items.Count == yPositions.Count);
- int firstIndex = yPositions.BinarySearch(Current - DrawableCarouselItem.MAX_HEIGHT);
+ int firstIndex = yPositions.BinarySearch(visibleUpperBound - DrawableCarouselItem.MAX_HEIGHT);
if (firstIndex < 0) firstIndex = ~firstIndex;
- int lastIndex = yPositions.BinarySearch(Current + drawHeight);
+ int lastIndex = yPositions.BinarySearch(visibleBottomBound);
if (lastIndex < 0) lastIndex = ~lastIndex;
int notVisibleCount = 0;
@@ -486,9 +506,8 @@ namespace osu.Game.Screens.Select
// Update externally controlled state of currently visible items
// (e.g. x-offset and opacity).
- float halfHeight = drawHeight / 2;
foreach (DrawableCarouselItem p in scrollableContent.Children)
- updateItem(p, halfHeight);
+ updateItem(p);
}
protected override void Dispose(bool isDisposing)
@@ -542,7 +561,7 @@ namespace osu.Game.Screens.Select
yPositions.Clear();
- float currentY = DrawHeight / 2;
+ float currentY = visibleHalfHeight;
DrawableCarouselBeatmapSet lastSet = null;
scrollTarget = null;
@@ -575,7 +594,6 @@ namespace osu.Game.Screens.Select
float? setY = null;
if (!d.IsLoaded || beatmap.Alpha == 0) // can't use IsPresent due to DrawableCarouselItem override.
- // ReSharper disable once PossibleNullReferenceException (resharper broken?)
setY = lastSet.Y + lastSet.DrawHeight + 5;
if (d.IsLoaded)
@@ -596,7 +614,7 @@ namespace osu.Game.Screens.Select
currentY += d.DrawHeight + 5;
}
- currentY += DrawHeight / 2;
+ currentY += visibleHalfHeight;
scrollableContent.Height = currentY;
if (BeatmapSetsLoaded && (selectedBeatmapSet == null || selectedBeatmap == null || selectedBeatmapSet.State.Value != CarouselItemState.Selected))
@@ -637,18 +655,15 @@ namespace osu.Game.Screens.Select
/// the current scroll position.
///
/// The item to be updated.
- /// Half the draw height of the carousel container.
- private void updateItem(DrawableCarouselItem p, float halfHeight)
+ private void updateItem(DrawableCarouselItem p)
{
- var height = p.IsPresent ? p.DrawHeight : 0;
-
- float itemDrawY = p.Position.Y - Current + height / 2;
- float dist = Math.Abs(1f - itemDrawY / halfHeight);
+ float itemDrawY = p.Position.Y - visibleUpperBound + p.DrawHeight / 2;
+ float dist = Math.Abs(1f - itemDrawY / visibleHalfHeight);
// Setting the origin position serves as an additive position on top of potential
// local transformation we may want to apply (e.g. when a item gets selected, we
// may want to smoothly transform it leftwards.)
- p.OriginPosition = new Vector2(-offsetX(dist, halfHeight), 0);
+ p.OriginPosition = new Vector2(-offsetX(dist, visibleHalfHeight), 0);
// We are applying a multiplicative alpha (which is internally done by nesting an
// additional container and setting that container's alpha) such that we can
diff --git a/osu.Game/Screens/Select/BeatmapDetailAreaTabControl.cs b/osu.Game/Screens/Select/BeatmapDetailAreaTabControl.cs
index f66cd2b29a..7f82d3cc12 100644
--- a/osu.Game/Screens/Select/BeatmapDetailAreaTabControl.cs
+++ b/osu.Game/Screens/Select/BeatmapDetailAreaTabControl.cs
@@ -25,22 +25,6 @@ namespace osu.Game.Screens.Select
private Bindable selectedTab;
- private void invokeOnFilter()
- {
- OnFilter?.Invoke(tabs.Current.Value, modsCheckbox.Current.Value);
- }
-
- [BackgroundDependencyLoader]
- private void load(OsuColour colour, OsuConfigManager config)
- {
- modsCheckbox.AccentColour = tabs.AccentColour = colour.YellowLight;
-
- selectedTab = config.GetBindable(OsuSetting.BeatmapDetailTab);
-
- tabs.Current.BindTo(selectedTab);
- tabs.Current.TriggerChange();
- }
-
public BeatmapDetailAreaTabControl()
{
Height = HEIGHT;
@@ -66,12 +50,31 @@ namespace osu.Game.Screens.Select
Anchor = Anchor.BottomRight,
Origin = Anchor.BottomRight,
Text = @"Mods",
+ Alpha = 0,
},
};
tabs.Current.ValueChanged += _ => invokeOnFilter();
modsCheckbox.Current.ValueChanged += _ => invokeOnFilter();
}
+
+ [BackgroundDependencyLoader]
+ private void load(OsuColour colour, OsuConfigManager config)
+ {
+ modsCheckbox.AccentColour = tabs.AccentColour = colour.YellowLight;
+
+ selectedTab = config.GetBindable(OsuSetting.BeatmapDetailTab);
+
+ tabs.Current.BindTo(selectedTab);
+ tabs.Current.TriggerChange();
+ }
+
+ private void invokeOnFilter()
+ {
+ OnFilter?.Invoke(tabs.Current.Value, modsCheckbox.Current.Value);
+
+ modsCheckbox.FadeTo(tabs.Current.Value == BeatmapDetailTab.Details ? 0 : 1, 200, Easing.OutQuint);
+ }
}
public enum BeatmapDetailTab
diff --git a/osu.Game/Screens/Select/FilterControl.cs b/osu.Game/Screens/Select/FilterControl.cs
index 57fe15fd99..84e8e90f54 100644
--- a/osu.Game/Screens/Select/FilterControl.cs
+++ b/osu.Game/Screens/Select/FilterControl.cs
@@ -14,7 +14,6 @@ using osu.Game.Graphics.UserInterface;
using osu.Game.Screens.Select.Filter;
using Container = osu.Framework.Graphics.Containers.Container;
using osu.Framework.Graphics.Shapes;
-using osu.Framework.Input.Events;
using osu.Game.Configuration;
using osu.Game.Rulesets;
@@ -22,6 +21,8 @@ namespace osu.Game.Screens.Select
{
public class FilterControl : Container
{
+ public const float HEIGHT = 100;
+
public Action FilterChanged;
private readonly OsuTabControl sortTabs;
@@ -187,11 +188,5 @@ namespace osu.Game.Screens.Select
}
private void updateCriteria() => FilterChanged?.Invoke(CreateCriteria());
-
- protected override bool OnMouseDown(MouseDownEvent e) => true;
-
- protected override bool OnMouseMove(MouseMoveEvent e) => true;
-
- protected override bool OnClick(ClickEvent e) => true;
}
}
diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs
index 20dbcf2693..7dd934f91a 100644
--- a/osu.Game/Screens/Select/SongSelect.cs
+++ b/osu.Game/Screens/Select/SongSelect.cs
@@ -121,7 +121,7 @@ namespace osu.Game.Screens.Select
Size = new Vector2(wedged_container_size.X, 1),
Padding = new MarginPadding
{
- Bottom = 50,
+ Bottom = Footer.HEIGHT,
Top = wedged_container_size.Y + left_area_padding,
Left = left_area_padding,
Right = left_area_padding * 2,
@@ -147,20 +147,29 @@ namespace osu.Game.Screens.Select
Width = 0.5f,
Children = new Drawable[]
{
- Carousel = new BeatmapCarousel
+ new Container
{
- Masking = false,
RelativeSizeAxes = Axes.Both,
- Size = new Vector2(1 - wedged_container_size.X, 1),
- Anchor = Anchor.CentreRight,
- Origin = Anchor.CentreRight,
- SelectionChanged = updateSelectedBeatmap,
- BeatmapSetsChanged = carouselBeatmapsLoaded,
+ Padding = new MarginPadding
+ {
+ Top = FilterControl.HEIGHT,
+ Bottom = Footer.HEIGHT
+ },
+ Child = Carousel = new BeatmapCarousel
+ {
+ Masking = false,
+ RelativeSizeAxes = Axes.Both,
+ Size = new Vector2(1 - wedged_container_size.X, 1),
+ Anchor = Anchor.CentreRight,
+ Origin = Anchor.CentreRight,
+ SelectionChanged = updateSelectedBeatmap,
+ BeatmapSetsChanged = carouselBeatmapsLoaded,
+ },
},
FilterControl = new FilterControl
{
RelativeSizeAxes = Axes.X,
- Height = 100,
+ Height = FilterControl.HEIGHT,
FilterChanged = c => Carousel.Filter(c),
Background = { Width = 2 },
Exit = () =>
diff --git a/osu.Game/Skinning/SkinReloadableDrawable.cs b/osu.Game/Skinning/SkinReloadableDrawable.cs
index c09d5b1f92..4bbdeafba5 100644
--- a/osu.Game/Skinning/SkinReloadableDrawable.cs
+++ b/osu.Game/Skinning/SkinReloadableDrawable.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;
@@ -36,12 +36,15 @@ namespace osu.Game.Skinning
skin.SourceChanged += onChange;
}
- private void onChange() => SkinChanged(skin, allowDefaultFallback);
+ private void onChange() =>
+ // schedule required to avoid calls after disposed.
+ // note that this has the side-effect of components only performing a skin change when they are alive.
+ Scheduler.AddOnce(() => SkinChanged(skin, allowDefaultFallback));
protected override void LoadAsyncComplete()
{
base.LoadAsyncComplete();
- onChange();
+ SkinChanged(skin, allowDefaultFallback);
}
///
diff --git a/osu.Game/Skinning/SkinnableDrawable.cs b/osu.Game/Skinning/SkinnableDrawable.cs
index eb0508b568..0c635a3d2f 100644
--- a/osu.Game/Skinning/SkinnableDrawable.cs
+++ b/osu.Game/Skinning/SkinnableDrawable.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;
@@ -8,23 +8,13 @@ using osuTK;
namespace osu.Game.Skinning
{
- public class SkinnableDrawable : SkinnableDrawable
- {
- public SkinnableDrawable(string name, Func defaultImplementation, Func allowFallback = null, ConfineMode confineMode = ConfineMode.ScaleDownToFit)
- : base(name, defaultImplementation, allowFallback, confineMode)
- {
- }
- }
-
///
/// A drawable which can be skinned via an .
///
- /// The type of drawable.
- public class SkinnableDrawable : SkinReloadableDrawable
- where T : Drawable
+ public class SkinnableDrawable : SkinReloadableDrawable
{
///
- /// The displayed component. May or may not be a type- member.
+ /// The displayed component.
///
protected Drawable Drawable { get; private set; }
@@ -39,7 +29,7 @@ namespace osu.Game.Skinning
/// A function to create the default skin implementation of this element.
/// A conditional to decide whether to allow fallback to the default implementation if a skinned element is not present.
/// How (if at all) the should be resize to fit within our own bounds.
- public SkinnableDrawable(string name, Func defaultImplementation, Func allowFallback = null, ConfineMode confineMode = ConfineMode.ScaleDownToFit)
+ public SkinnableDrawable(string name, Func defaultImplementation, Func allowFallback = null, ConfineMode confineMode = ConfineMode.ScaleDownToFit)
: this(name, allowFallback, confineMode)
{
createDefault = defaultImplementation;
@@ -54,13 +44,13 @@ namespace osu.Game.Skinning
RelativeSizeAxes = Axes.Both;
}
- private readonly Func createDefault;
+ private readonly Func createDefault;
private readonly Cached scaling = new Cached();
private bool isDefault;
- protected virtual T CreateDefault(string name) => createDefault(name);
+ protected virtual Drawable CreateDefault(string name) => createDefault(name);
///
/// Whether to apply size restrictions (specified via ) to the default implementation.
diff --git a/osu.Game/Skinning/SkinnableSprite.cs b/osu.Game/Skinning/SkinnableSprite.cs
index 1716ec71de..07ba48d6ae 100644
--- a/osu.Game/Skinning/SkinnableSprite.cs
+++ b/osu.Game/Skinning/SkinnableSprite.cs
@@ -3,6 +3,7 @@
using System;
using osu.Framework.Allocation;
+using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures;
@@ -11,7 +12,7 @@ namespace osu.Game.Skinning
///
/// A skinnable element which uses a stable sprite and can therefore share implementation logic.
///
- public class SkinnableSprite : SkinnableDrawable
+ public class SkinnableSprite : SkinnableDrawable
{
protected override bool ApplySizeRestrictionsToDefault => true;
@@ -23,6 +24,6 @@ namespace osu.Game.Skinning
{
}
- protected override Sprite CreateDefault(string name) => new Sprite { Texture = textures.Get(name) };
+ protected override Drawable CreateDefault(string name) => new Sprite { Texture = textures.Get(name) };
}
}
diff --git a/osu.Game/Skinning/SkinnableSpriteText.cs b/osu.Game/Skinning/SkinnableSpriteText.cs
index d12a6f74f7..5af6df15e1 100644
--- a/osu.Game/Skinning/SkinnableSpriteText.cs
+++ b/osu.Game/Skinning/SkinnableSpriteText.cs
@@ -6,7 +6,7 @@ using osu.Framework.Graphics.Sprites;
namespace osu.Game.Skinning
{
- public class SkinnableSpriteText : SkinnableDrawable, IHasText
+ public class SkinnableSpriteText : SkinnableDrawable, IHasText
{
public SkinnableSpriteText(string name, Func defaultImplementation, Func allowFallback = null, ConfineMode confineMode = ConfineMode.ScaleDownToFit)
: base(name, defaultImplementation, allowFallback, confineMode)
diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj
index c05cc6f9dd..0b2baa982b 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 3b18039600..55d1afa645 100644
--- a/osu.iOS.props
+++ b/osu.iOS.props
@@ -105,8 +105,8 @@
-
-
+
+
diff --git a/osu.iOS/AppDelegate.cs b/osu.iOS/AppDelegate.cs
index 058e246ed8..9ef21e014c 100644
--- a/osu.iOS/AppDelegate.cs
+++ b/osu.iOS/AppDelegate.cs
@@ -1,15 +1,25 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
+using System.Threading.Tasks;
using Foundation;
using osu.Framework.iOS;
using osu.Game;
+using UIKit;
namespace osu.iOS
{
[Register("AppDelegate")]
public class AppDelegate : GameAppDelegate
{
- protected override Framework.Game CreateGame() => new OsuGameIOS();
+ private OsuGameIOS game;
+
+ protected override Framework.Game CreateGame() => game = new OsuGameIOS();
+
+ public override bool OpenUrl(UIApplication application, NSUrl url, string sourceApplication, NSObject annotation)
+ {
+ Task.Run(() => game.Import(url.Path));
+ return true;
+ }
}
}
diff --git a/osu.iOS/Info.plist b/osu.iOS/Info.plist
index d7992353cf..0775d1522d 100644
--- a/osu.iOS/Info.plist
+++ b/osu.iOS/Info.plist
@@ -40,5 +40,70 @@
XSAppIconAssets
Assets.xcassets/AppIcon.appiconset
+ UTExportedTypeDeclarations
+
+
+ UTTypeConformsTo
+
+
+
+ UTTypeIdentifier
+ sh.ppy.osu.items
+ UTTypeTagSpecification
+
+
+
+ UTTypeConformsTo
+
+ sh.ppy.osu.items
+
+ UTTypeIdentifier
+ sh.ppy.osu.osr
+ UTTypeTagSpecification
+
+ public.filename-extension
+ osr
+
+
+
+ UTTypeConformsTo
+
+ sh.ppy.osu.items
+
+ UTTypeIdentifier
+ sh.ppy.osu.osk
+ UTTypeTagSpecification
+
+ public.filename-extension
+ osk
+
+
+
+ UTTypeConformsTo
+
+ sh.ppy.osu.items
+
+ UTTypeIdentifier
+ sh.ppy.osu.osz
+ UTTypeTagSpecification
+
+ public.filename-extension
+ osz
+
+
+
+ CFBundleDocumentTypes
+
+
+ LSHandlerRank
+ Owner
+ CFBundleTypeName
+ Supported osu! files
+ LSItemContentTypes
+
+ sh.ppy.osu.items
+
+
+