diff --git a/osu.Android.props b/osu.Android.props
index d2bdbc8b61..25942863c5 100644
--- a/osu.Android.props
+++ b/osu.Android.props
@@ -52,6 +52,6 @@
-
+
diff --git a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs
index fbdf437b7b..57930a21fa 100644
--- a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs
+++ b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs
@@ -72,8 +72,7 @@ namespace osu.Game.Rulesets.Catch.Difficulty
protected override Skill[] CreateSkills(IBeatmap beatmap)
{
- using (var catcher = new Catcher(new Container(), beatmap.BeatmapInfo.BaseDifficulty))
- halfCatcherWidth = catcher.CatchWidth * 0.5f;
+ halfCatcherWidth = Catcher.CalculateCatchWidth(beatmap.BeatmapInfo.BaseDifficulty) * 0.5f;
return new Skill[]
{
diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModRelax.cs b/osu.Game.Rulesets.Catch/Mods/CatchModRelax.cs
index 1ef235f764..16414261a5 100644
--- a/osu.Game.Rulesets.Catch/Mods/CatchModRelax.cs
+++ b/osu.Game.Rulesets.Catch/Mods/CatchModRelax.cs
@@ -9,17 +9,26 @@ using osu.Game.Rulesets.Catch.Objects;
using osu.Game.Rulesets.Catch.UI;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.UI;
+using osu.Game.Screens.Play;
using osuTK;
namespace osu.Game.Rulesets.Catch.Mods
{
- public class CatchModRelax : ModRelax, IApplicableToDrawableRuleset
+ public class CatchModRelax : ModRelax, IApplicableToDrawableRuleset, IApplicableToPlayer
{
public override string Description => @"Use the mouse to control the catcher.";
+ private DrawableRuleset drawableRuleset;
+
public void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset)
{
- drawableRuleset.Cursor.Add(new MouseInputHelper((CatchPlayfield)drawableRuleset.Playfield));
+ this.drawableRuleset = drawableRuleset;
+ }
+
+ public void ApplyToPlayer(Player player)
+ {
+ if (!drawableRuleset.HasReplayLoaded.Value)
+ drawableRuleset.Cursor.Add(new MouseInputHelper((CatchPlayfield)drawableRuleset.Playfield));
}
private class MouseInputHelper : Drawable, IKeyBindingHandler, IRequireHighFrequencyMousePosition
diff --git a/osu.Game.Rulesets.Catch/UI/Catcher.cs b/osu.Game.Rulesets.Catch/UI/Catcher.cs
index 08e438db56..2022cffb40 100644
--- a/osu.Game.Rulesets.Catch/UI/Catcher.cs
+++ b/osu.Game.Rulesets.Catch/UI/Catcher.cs
@@ -66,11 +66,6 @@ namespace osu.Game.Rulesets.Catch.UI
///
private const float allowed_catch_range = 0.8f;
- ///
- /// Width of the area that can be used to attempt catches during gameplay.
- ///
- internal float CatchWidth => CatcherArea.CATCHER_SIZE * Math.Abs(Scale.X) * allowed_catch_range;
-
///
/// The drawable catcher for .
///
@@ -91,6 +86,11 @@ namespace osu.Game.Rulesets.Catch.UI
}
}
+ ///
+ /// Width of the area that can be used to attempt catches during gameplay.
+ ///
+ private readonly float catchWidth;
+
private Container caughtFruit;
private CatcherSprite catcherIdle;
@@ -119,7 +119,9 @@ namespace osu.Game.Rulesets.Catch.UI
Size = new Vector2(CatcherArea.CATCHER_SIZE);
if (difficulty != null)
- Scale = new Vector2(1.0f - 0.7f * (difficulty.CircleSize - 5) / 5);
+ Scale = calculateScale(difficulty);
+
+ catchWidth = CalculateCatchWidth(Scale);
}
[BackgroundDependencyLoader]
@@ -154,6 +156,26 @@ namespace osu.Game.Rulesets.Catch.UI
updateCatcher();
}
+ ///
+ /// Calculates the scale of the catcher based off the provided beatmap difficulty.
+ ///
+ private static Vector2 calculateScale(BeatmapDifficulty difficulty)
+ => new Vector2(1.0f - 0.7f * (difficulty.CircleSize - 5) / 5);
+
+ ///
+ /// Calculates the width of the area used for attempting catches in gameplay.
+ ///
+ /// The scale of the catcher.
+ internal static float CalculateCatchWidth(Vector2 scale)
+ => CatcherArea.CATCHER_SIZE * Math.Abs(scale.X) * allowed_catch_range;
+
+ ///
+ /// Calculates the width of the area used for attempting catches in gameplay.
+ ///
+ /// The beatmap difficulty.
+ internal static float CalculateCatchWidth(BeatmapDifficulty difficulty)
+ => CalculateCatchWidth(calculateScale(difficulty));
+
///
/// Add a caught fruit to the catcher's stack.
///
@@ -192,7 +214,7 @@ namespace osu.Game.Rulesets.Catch.UI
/// Whether the catch is possible.
public bool AttemptCatch(CatchHitObject fruit)
{
- var halfCatchWidth = CatchWidth * 0.5f;
+ var halfCatchWidth = catchWidth * 0.5f;
// this stuff wil disappear once we move fruit to non-relative coordinate space in the future.
var catchObjectPosition = fruit.X * CatchPlayfield.BASE_WIDTH;
diff --git a/osu.Game.Rulesets.Mania.Tests/Resources/special-skin/mania-key1@2x.png b/osu.Game.Rulesets.Mania.Tests/Resources/special-skin/mania-key1@2x.png
new file mode 100644
index 0000000000..aa681f6f22
Binary files /dev/null and b/osu.Game.Rulesets.Mania.Tests/Resources/special-skin/mania-key1@2x.png differ
diff --git a/osu.Game.Rulesets.Mania.Tests/Resources/special-skin/skin.ini b/osu.Game.Rulesets.Mania.Tests/Resources/special-skin/skin.ini
new file mode 100644
index 0000000000..56564776b3
--- /dev/null
+++ b/osu.Game.Rulesets.Mania.Tests/Resources/special-skin/skin.ini
@@ -0,0 +1,6 @@
+[General]
+Version: 2.4
+
+[Mania]
+Keys: 4
+ColumnLineWidth: 3,1,3,1,1
\ No newline at end of file
diff --git a/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneColumnBackground.cs b/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneColumnBackground.cs
index d6bacbe59e..bde323f187 100644
--- a/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneColumnBackground.cs
+++ b/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneColumnBackground.cs
@@ -37,7 +37,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Skinning
{
RelativeSizeAxes = Axes.Both,
Width = 0.5f,
- Child = new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.ColumnBackground, 0), _ => new DefaultColumnBackground())
+ Child = new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.ColumnBackground, 1), _ => new DefaultColumnBackground())
{
RelativeSizeAxes = Axes.Both
}
diff --git a/osu.Game.Rulesets.Mania/Skinning/LegacyColumnBackground.cs b/osu.Game.Rulesets.Mania/Skinning/LegacyColumnBackground.cs
index 6504321bb2..1a097405ac 100644
--- a/osu.Game.Rulesets.Mania/Skinning/LegacyColumnBackground.cs
+++ b/osu.Game.Rulesets.Mania/Skinning/LegacyColumnBackground.cs
@@ -67,6 +67,7 @@ namespace osu.Game.Rulesets.Mania.Skinning
{
RelativeSizeAxes = Axes.Y,
Width = leftLineWidth,
+ Scale = new Vector2(0.740f, 1),
Colour = lineColour,
Alpha = hasLeftLine ? 1 : 0
},
@@ -76,6 +77,7 @@ namespace osu.Game.Rulesets.Mania.Skinning
Origin = Anchor.TopRight,
RelativeSizeAxes = Axes.Y,
Width = rightLineWidth,
+ Scale = new Vector2(0.740f, 1),
Colour = lineColour,
Alpha = hasRightLine ? 1 : 0
},
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs b/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs
index 9b0759d9d2..7b1941b7f9 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs
@@ -11,11 +11,12 @@ using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Osu.Objects.Drawables;
using osu.Game.Rulesets.Replays;
using osu.Game.Rulesets.UI;
+using osu.Game.Screens.Play;
using static osu.Game.Input.Handlers.ReplayInputHandler;
namespace osu.Game.Rulesets.Osu.Mods
{
- public class OsuModRelax : ModRelax, IUpdatableByPlayfield, IApplicableToDrawableRuleset
+ public class OsuModRelax : ModRelax, IUpdatableByPlayfield, IApplicableToDrawableRuleset, IApplicableToPlayer
{
public override string Description => @"You don't need to click. Give your clicking/tapping fingers a break from the heat of things.";
public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(OsuModAutopilot)).ToArray();
@@ -33,15 +34,30 @@ namespace osu.Game.Rulesets.Osu.Mods
private ReplayState state;
private double lastStateChangeTime;
+ private bool hasReplay;
+
public void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset)
{
// grab the input manager for future use.
osuInputManager = (OsuInputManager)drawableRuleset.KeyBindingInputManager;
+ }
+
+ public void ApplyToPlayer(Player player)
+ {
+ if (osuInputManager.ReplayInputHandler != null)
+ {
+ hasReplay = true;
+ return;
+ }
+
osuInputManager.AllowUserPresses = false;
}
public void Update(Playfield playfield)
{
+ if (hasReplay)
+ return;
+
bool requiresHold = false;
bool requiresHit = false;
diff --git a/osu.Game.Rulesets.Taiko.Tests/Resources/metrics-skin/approachcircle@2x.png b/osu.Game.Rulesets.Taiko.Tests/Resources/metrics-skin/approachcircle@2x.png
new file mode 100644
index 0000000000..72ef665478
Binary files /dev/null and b/osu.Game.Rulesets.Taiko.Tests/Resources/metrics-skin/approachcircle@2x.png differ
diff --git a/osu.Game.Rulesets.Taiko.Tests/Resources/metrics-skin/taikobigcircle@2x.png b/osu.Game.Rulesets.Taiko.Tests/Resources/metrics-skin/taikobigcircle@2x.png
new file mode 100644
index 0000000000..440e5b55e5
Binary files /dev/null and b/osu.Game.Rulesets.Taiko.Tests/Resources/metrics-skin/taikobigcircle@2x.png differ
diff --git a/osu.Game.Rulesets.Taiko.Tests/Resources/old-skin/approachcircle.png b/osu.Game.Rulesets.Taiko.Tests/Resources/old-skin/approachcircle.png
new file mode 100755
index 0000000000..5aba688756
Binary files /dev/null and b/osu.Game.Rulesets.Taiko.Tests/Resources/old-skin/approachcircle.png differ
diff --git a/osu.Game.Rulesets.Taiko.Tests/Resources/special-skin/approachcircle.png b/osu.Game.Rulesets.Taiko.Tests/Resources/special-skin/approachcircle.png
new file mode 100644
index 0000000000..56d6d34c1a
Binary files /dev/null and b/osu.Game.Rulesets.Taiko.Tests/Resources/special-skin/approachcircle.png differ
diff --git a/osu.Game.Rulesets.Taiko.Tests/Resources/special-skin/taikobigcircle@2x.png b/osu.Game.Rulesets.Taiko.Tests/Resources/special-skin/taikobigcircle@2x.png
new file mode 100644
index 0000000000..5d8b60da9e
Binary files /dev/null and b/osu.Game.Rulesets.Taiko.Tests/Resources/special-skin/taikobigcircle@2x.png differ
diff --git a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneTaikoPlayfield.cs b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneTaikoPlayfield.cs
new file mode 100644
index 0000000000..730eed0e0f
--- /dev/null
+++ b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneTaikoPlayfield.cs
@@ -0,0 +1,42 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using osu.Framework.Allocation;
+using osu.Framework.Graphics;
+using osu.Game.Beatmaps.ControlPoints;
+using osu.Game.Rulesets.Taiko.Skinning;
+using osu.Game.Rulesets.Taiko.UI;
+using osu.Game.Rulesets.UI.Scrolling;
+using osu.Game.Tests.Visual;
+
+namespace osu.Game.Rulesets.Taiko.Tests.Skinning
+{
+ public class TestSceneTaikoPlayfield : TaikoSkinnableTestScene
+ {
+ public override IReadOnlyList RequiredTypes => base.RequiredTypes.Concat(new[]
+ {
+ typeof(HitTarget),
+ typeof(LegacyHitTarget),
+ }).ToList();
+
+ [Cached(typeof(IScrollingInfo))]
+ private ScrollingTestContainer.TestScrollingInfo info = new ScrollingTestContainer.TestScrollingInfo
+ {
+ Direction = { Value = ScrollingDirection.Left },
+ TimeRange = { Value = 5000 },
+ };
+
+ public TestSceneTaikoPlayfield()
+ {
+ AddStep("Load playfield", () => SetContents(() => new TaikoPlayfield(new ControlPointInfo())
+ {
+ Height = 0.4f,
+ Anchor = Anchor.CentreLeft,
+ Origin = Anchor.CentreLeft,
+ }));
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoPlayfield.cs b/osu.Game.Rulesets.Taiko.Tests/TestSceneHits.cs
similarity index 99%
rename from osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoPlayfield.cs
rename to osu.Game.Rulesets.Taiko.Tests/TestSceneHits.cs
index 0d9e813c60..c2ca578dfa 100644
--- a/osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoPlayfield.cs
+++ b/osu.Game.Rulesets.Taiko.Tests/TestSceneHits.cs
@@ -24,7 +24,7 @@ using osuTK;
namespace osu.Game.Rulesets.Taiko.Tests
{
[TestFixture]
- public class TestSceneTaikoPlayfield : OsuTestScene
+ public class TestSceneHits : OsuTestScene
{
private const double default_duration = 1000;
private const float scroll_time = 1000;
diff --git a/osu.Game.Rulesets.Taiko/Skinning/LegacyHitTarget.cs b/osu.Game.Rulesets.Taiko/Skinning/LegacyHitTarget.cs
new file mode 100644
index 0000000000..51aea9b9ab
--- /dev/null
+++ b/osu.Game.Rulesets.Taiko/Skinning/LegacyHitTarget.cs
@@ -0,0 +1,41 @@
+// 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.Sprites;
+using osu.Game.Skinning;
+using osuTK;
+
+namespace osu.Game.Rulesets.Taiko.Skinning
+{
+ public class LegacyHitTarget : CompositeDrawable
+ {
+ [BackgroundDependencyLoader]
+ private void load(ISkinSource skin)
+ {
+ RelativeSizeAxes = Axes.Both;
+
+ InternalChildren = new Drawable[]
+ {
+ new Sprite
+ {
+ Texture = skin.GetTexture("approachcircle"),
+ Scale = new Vector2(0.73f),
+ Alpha = 0.7f,
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ },
+ new Sprite
+ {
+ Texture = skin.GetTexture("taikobigcircle"),
+ Scale = new Vector2(0.7f),
+ Alpha = 0.5f,
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ },
+ };
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Taiko/Skinning/TaikoLegacySkinTransformer.cs b/osu.Game.Rulesets.Taiko/Skinning/TaikoLegacySkinTransformer.cs
index 3af7df07c4..6b59718173 100644
--- a/osu.Game.Rulesets.Taiko/Skinning/TaikoLegacySkinTransformer.cs
+++ b/osu.Game.Rulesets.Taiko/Skinning/TaikoLegacySkinTransformer.cs
@@ -49,6 +49,12 @@ namespace osu.Game.Rulesets.Taiko.Skinning
case TaikoSkinComponents.DrumRollTick:
return this.GetAnimation("sliderscorepoint", false, false);
+
+ case TaikoSkinComponents.HitTarget:
+ if (GetTexture("taikobigcircle") != null)
+ return new LegacyHitTarget();
+
+ return null;
}
return source.GetDrawableComponent(component);
diff --git a/osu.Game.Rulesets.Taiko/TaikoSkinComponents.cs b/osu.Game.Rulesets.Taiko/TaikoSkinComponents.cs
index 156ea71c16..775eeb4e38 100644
--- a/osu.Game.Rulesets.Taiko/TaikoSkinComponents.cs
+++ b/osu.Game.Rulesets.Taiko/TaikoSkinComponents.cs
@@ -10,6 +10,7 @@ namespace osu.Game.Rulesets.Taiko
RimHit,
DrumRollBody,
DrumRollTick,
- Swell
+ Swell,
+ HitTarget
}
}
diff --git a/osu.Game.Rulesets.Taiko/UI/HitTarget.cs b/osu.Game.Rulesets.Taiko/UI/HitTarget.cs
index 2bb208bd1d..88886508af 100644
--- a/osu.Game.Rulesets.Taiko/UI/HitTarget.cs
+++ b/osu.Game.Rulesets.Taiko/UI/HitTarget.cs
@@ -22,6 +22,8 @@ namespace osu.Game.Rulesets.Taiko.UI
public HitTarget()
{
+ RelativeSizeAxes = Axes.Both;
+
Children = new Drawable[]
{
new Box
diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs
index bde9085c23..375d9995c0 100644
--- a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs
+++ b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs
@@ -17,6 +17,7 @@ using osu.Game.Rulesets.UI.Scrolling;
using osu.Game.Rulesets.Taiko.Objects.Drawables;
using osu.Game.Rulesets.Taiko.Judgements;
using osu.Game.Rulesets.Taiko.Objects;
+using osu.Game.Skinning;
using osuTK;
using osuTK.Graphics;
@@ -42,7 +43,7 @@ namespace osu.Game.Rulesets.Taiko.UI
private readonly Container hitExplosionContainer;
private readonly Container kiaiExplosionContainer;
private readonly JudgementContainer judgementContainer;
- internal readonly HitTarget HitTarget;
+ internal readonly Drawable HitTarget;
private readonly ProxyContainer topLevelHitContainer;
private readonly ProxyContainer barlineContainer;
@@ -90,7 +91,7 @@ namespace osu.Game.Rulesets.Taiko.UI
RelativeSizeAxes = Axes.Both,
Padding = new MarginPadding { Left = HIT_TARGET_OFFSET },
Masking = true,
- Children = new Drawable[]
+ Children = new[]
{
hitExplosionContainer = new Container
{
@@ -98,7 +99,7 @@ namespace osu.Game.Rulesets.Taiko.UI
FillMode = FillMode.Fit,
Blending = BlendingParameters.Additive,
},
- HitTarget = new HitTarget
+ HitTarget = new SkinnableDrawable(new TaikoSkinComponent(TaikoSkinComponents.HitTarget), _ => new HitTarget())
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.Centre,
diff --git a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapEncoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapEncoderTest.cs
index f2b3a16f68..bcc873b0b7 100644
--- a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapEncoderTest.cs
+++ b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapEncoderTest.cs
@@ -1,14 +1,23 @@
// 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;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using NUnit.Framework;
+using osu.Framework.Audio.Track;
+using osu.Framework.Graphics.Textures;
using osu.Game.Beatmaps;
+using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Beatmaps.Formats;
using osu.Game.IO;
using osu.Game.IO.Serialization;
+using osu.Game.Rulesets.Catch;
+using osu.Game.Rulesets.Mania;
+using osu.Game.Rulesets.Osu;
+using osu.Game.Rulesets.Taiko;
using osu.Game.Tests.Resources;
namespace osu.Game.Tests.Beatmaps.Formats
@@ -16,39 +25,91 @@ namespace osu.Game.Tests.Beatmaps.Formats
[TestFixture]
public class LegacyBeatmapEncoderTest
{
- private const string normal = "Soleily - Renatus (Gamu) [Insane].osu";
-
private static IEnumerable allBeatmaps => TestResources.GetStore().GetAvailableResources().Where(res => res.EndsWith(".osu"));
[TestCaseSource(nameof(allBeatmaps))]
- public void TestDecodeEncodedBeatmap(string name)
+ public void TestBeatmap(string name)
{
- var decoded = decode(normal, out var encoded);
+ var decoded = decode(name, out var encoded);
+
+ sort(decoded);
+ sort(encoded);
- Assert.That(decoded.HitObjects.Count, Is.EqualTo(encoded.HitObjects.Count));
Assert.That(encoded.Serialize(), Is.EqualTo(decoded.Serialize()));
}
- private Beatmap decode(string filename, out Beatmap encoded)
+ private void sort(IBeatmap beatmap)
{
- using (var stream = TestResources.OpenResource(filename))
+ // Sort control points to ensure a sane ordering, as they may be parsed in different orders. This works because each group contains only uniquely-typed control points.
+ foreach (var g in beatmap.ControlPointInfo.Groups)
+ {
+ ArrayList.Adapter((IList)g.ControlPoints).Sort(
+ Comparer.Create((c1, c2) => string.Compare(c1.GetType().ToString(), c2.GetType().ToString(), StringComparison.Ordinal)));
+ }
+ }
+
+ private IBeatmap decode(string filename, out IBeatmap encoded)
+ {
+ using (var stream = TestResources.GetStore().GetStream(filename))
using (var sr = new LineBufferedReader(stream))
{
- var legacyDecoded = new LegacyBeatmapDecoder { ApplyOffsets = false }.Decode(sr);
+ var legacyDecoded = convert(new LegacyBeatmapDecoder { ApplyOffsets = false }.Decode(sr));
using (var ms = new MemoryStream())
using (var sw = new StreamWriter(ms))
- using (var sr2 = new LineBufferedReader(ms))
+ using (var sr2 = new LineBufferedReader(ms, true))
{
new LegacyBeatmapEncoder(legacyDecoded).Encode(sw);
- sw.Flush();
+ sw.Flush();
ms.Position = 0;
- encoded = new LegacyBeatmapDecoder { ApplyOffsets = false }.Decode(sr2);
+ encoded = convert(new LegacyBeatmapDecoder { ApplyOffsets = false }.Decode(sr2));
+
return legacyDecoded;
}
}
}
+
+ private IBeatmap convert(IBeatmap beatmap)
+ {
+ switch (beatmap.BeatmapInfo.RulesetID)
+ {
+ case 0:
+ beatmap.BeatmapInfo.Ruleset = new OsuRuleset().RulesetInfo;
+ break;
+
+ case 1:
+ beatmap.BeatmapInfo.Ruleset = new TaikoRuleset().RulesetInfo;
+ break;
+
+ case 2:
+ beatmap.BeatmapInfo.Ruleset = new CatchRuleset().RulesetInfo;
+ break;
+
+ case 3:
+ beatmap.BeatmapInfo.Ruleset = new ManiaRuleset().RulesetInfo;
+ break;
+ }
+
+ return new TestWorkingBeatmap(beatmap).GetPlayableBeatmap(beatmap.BeatmapInfo.Ruleset);
+ }
+
+ private class TestWorkingBeatmap : WorkingBeatmap
+ {
+ private readonly IBeatmap beatmap;
+
+ public TestWorkingBeatmap(IBeatmap beatmap)
+ : base(beatmap.BeatmapInfo, null)
+ {
+ this.beatmap = beatmap;
+ }
+
+ protected override IBeatmap GetBeatmap() => beatmap;
+
+ protected override Texture GetBackground() => throw new NotImplementedException();
+
+ protected override Track GetTrack() => throw new NotImplementedException();
+ }
}
}
diff --git a/osu.Game.Tests/Beatmaps/ToStringFormattingTest.cs b/osu.Game.Tests/Beatmaps/ToStringFormattingTest.cs
new file mode 100644
index 0000000000..c477bbd9cf
--- /dev/null
+++ b/osu.Game.Tests/Beatmaps/ToStringFormattingTest.cs
@@ -0,0 +1,61 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using NUnit.Framework;
+using osu.Game.Beatmaps;
+using osu.Game.Users;
+
+namespace osu.Game.Tests.Beatmaps
+{
+ [TestFixture]
+ public class ToStringFormattingTest
+ {
+ [Test]
+ public void TestArtistTitle()
+ {
+ var beatmap = new BeatmapInfo
+ {
+ Metadata = new BeatmapMetadata
+ {
+ Artist = "artist",
+ Title = "title"
+ }
+ };
+
+ Assert.That(beatmap.ToString(), Is.EqualTo("artist - title"));
+ }
+
+ [Test]
+ public void TestArtistTitleCreator()
+ {
+ var beatmap = new BeatmapInfo
+ {
+ Metadata = new BeatmapMetadata
+ {
+ Artist = "artist",
+ Title = "title",
+ Author = new User { Username = "creator" }
+ }
+ };
+
+ Assert.That(beatmap.ToString(), Is.EqualTo("artist - title (creator)"));
+ }
+
+ [Test]
+ public void TestArtistTitleCreatorDifficulty()
+ {
+ var beatmap = new BeatmapInfo
+ {
+ Metadata = new BeatmapMetadata
+ {
+ Artist = "artist",
+ Title = "title",
+ Author = new User { Username = "creator" }
+ },
+ Version = "difficulty"
+ };
+
+ Assert.That(beatmap.ToString(), Is.EqualTo("artist - title (creator) [difficulty]"));
+ }
+ }
+}
diff --git a/osu.Game.Tests/Resources/hitobject-combo-offset.osu b/osu.Game.Tests/Resources/hitobject-combo-offset.osu
index c1f0dab8e9..d39a3e8548 100644
--- a/osu.Game.Tests/Resources/hitobject-combo-offset.osu
+++ b/osu.Game.Tests/Resources/hitobject-combo-offset.osu
@@ -5,27 +5,27 @@ osu file format v14
255,193,1000,49,0,0:0:0:0:
// Combo index = 4
-// Slider with new combo followed by circle with no new combo
+// Spinner with new combo followed by circle with no new combo
256,192,2000,12,0,2000,0:0:0:0:
255,193,3000,1,0,0:0:0:0:
// Combo index = 5
-// Slider without new combo followed by circle with no new combo
+// Spinner without new combo followed by circle with no new combo
256,192,4000,8,0,5000,0:0:0:0:
255,193,6000,1,0,0:0:0:0:
// Combo index = 5
-// Slider without new combo followed by circle with new combo
+// Spinner without new combo followed by circle with new combo
256,192,7000,8,0,8000,0:0:0:0:
255,193,9000,5,0,0:0:0:0:
// Combo index = 6
-// Slider with new combo and offset (1) followed by circle with new combo and offset (3)
+// Spinner with new combo and offset (1) followed by circle with new combo and offset (3)
256,192,10000,28,0,11000,0:0:0:0:
255,193,12000,53,0,0:0:0:0:
// Combo index = 11
-// Slider with new combo and offset (2) followed by slider with no new combo followed by circle with no new combo
+// Spinner with new combo and offset (2) followed by slider with no new combo followed by circle with no new combo
256,192,13000,44,0,14000,0:0:0:0:
256,192,15000,8,0,16000,0:0:0:0:
255,193,17000,1,0,0:0:0:0:
diff --git a/osu.Game.Tests/Resources/sample-beatmap-osu.osu b/osu.Game.Tests/Resources/sample-beatmap-osu.osu
new file mode 100644
index 0000000000..27c96077e6
--- /dev/null
+++ b/osu.Game.Tests/Resources/sample-beatmap-osu.osu
@@ -0,0 +1,32 @@
+osu file format v14
+
+[General]
+SampleSet: Normal
+StackLeniency: 0.7
+Mode: 0
+
+[Difficulty]
+HPDrainRate:3
+CircleSize:5
+OverallDifficulty:8
+ApproachRate:8
+SliderMultiplier:3.59999990463257
+SliderTickRate:2
+
+[TimingPoints]
+24,352.941176470588,4,1,1,100,1,0
+6376,-50,4,1,1,100,0,0
+
+[HitObjects]
+98,69,24,1,0,0:0:0:0:
+419,72,200,1,2,0:0:0:0:
+81,314,376,1,6,0:0:0:0:
+423,321,553,1,12,0:0:0:0:
+86,192,729,2,0,P|459:193|460:193,1,359.999990463257
+86,192,1259,2,0,P|246:82|453:203,1,449.999988079071
+86,192,1876,2,0,B|256:30|257:313|464:177,1,359.999990463257
+86,55,2406,2,12,B|447:51|447:51|452:348|452:348|78:344,1,989.999973773957,14|2,0:0|0:0,0:0:0:0:
+256,192,3553,12,0,4259,0:0:0:0:
+67,57,4435,5,0,0:0:0:0:
+440,52,4612,5,0,0:0:0:0:
+86,181,4788,6,0,L|492:183,1,359.999990463257
\ No newline at end of file
diff --git a/osu.Game.Tests/Visual/Editor/TestSceneEditorChangeStates.cs b/osu.Game.Tests/Visual/Editor/TestSceneEditorChangeStates.cs
index dd1b6cf6aa..efc2a6f552 100644
--- a/osu.Game.Tests/Visual/Editor/TestSceneEditorChangeStates.cs
+++ b/osu.Game.Tests/Visual/Editor/TestSceneEditorChangeStates.cs
@@ -10,24 +10,22 @@ using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Screens.Edit;
using osu.Game.Screens.Edit.Compose.Components.Timeline;
-using osuTK.Input;
namespace osu.Game.Tests.Visual.Editor
{
public class TestSceneEditorChangeStates : ScreenTestScene
{
private EditorBeatmap editorBeatmap;
+ private TestEditor editor;
public override void SetUpSteps()
{
base.SetUpSteps();
- Screens.Edit.Editor editor = null;
-
AddStep("load editor", () =>
{
Beatmap.Value = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo);
- LoadScreen(editor = new Screens.Edit.Editor());
+ LoadScreen(editor = new TestEditor());
});
AddUntilStep("wait for editor to load", () => editor.ChildrenOfType().FirstOrDefault()?.IsLoaded == true
@@ -160,36 +158,15 @@ namespace osu.Game.Tests.Visual.Editor
AddAssert("no hitobject added", () => addedObject == null);
}
- private void addUndoSteps()
+ private void addUndoSteps() => AddStep("undo", () => editor.Undo());
+
+ private void addRedoSteps() => AddStep("redo", () => editor.Redo());
+
+ private class TestEditor : Screens.Edit.Editor
{
- AddStep("press undo", () =>
- {
- InputManager.PressKey(Key.LControl);
- InputManager.PressKey(Key.Z);
- });
+ public new void Undo() => base.Undo();
- AddStep("release keys", () =>
- {
- InputManager.ReleaseKey(Key.LControl);
- InputManager.ReleaseKey(Key.Z);
- });
- }
-
- private void addRedoSteps()
- {
- AddStep("press redo", () =>
- {
- InputManager.PressKey(Key.LControl);
- InputManager.PressKey(Key.LShift);
- InputManager.PressKey(Key.Z);
- });
-
- AddStep("release keys", () =>
- {
- InputManager.ReleaseKey(Key.LControl);
- InputManager.ReleaseKey(Key.LShift);
- InputManager.ReleaseKey(Key.Z);
- });
+ public new void Redo() => base.Redo();
}
}
}
diff --git a/osu.Game.Tests/Visual/Online/TestSceneDirectDownloadButton.cs b/osu.Game.Tests/Visual/Online/TestSceneDirectDownloadButton.cs
index f612992bf6..9fe873cb6a 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneDirectDownloadButton.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneDirectDownloadButton.cs
@@ -9,7 +9,7 @@ using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Game.Beatmaps;
using osu.Game.Online;
-using osu.Game.Overlays.Direct;
+using osu.Game.Overlays.BeatmapListing.Panels;
using osu.Game.Rulesets.Osu;
using osu.Game.Tests.Resources;
using osuTK;
@@ -20,7 +20,7 @@ namespace osu.Game.Tests.Visual.Online
{
public override IReadOnlyList RequiredTypes => new[]
{
- typeof(PanelDownloadButton)
+ typeof(BeatmapPanelDownloadButton)
};
private TestDownloadButton downloadButton;
@@ -143,7 +143,7 @@ namespace osu.Game.Tests.Visual.Online
return beatmap;
}
- private class TestDownloadButton : PanelDownloadButton
+ private class TestDownloadButton : BeatmapPanelDownloadButton
{
public new bool DownloadEnabled => base.DownloadEnabled;
diff --git a/osu.Game.Tests/Visual/Online/TestSceneDirectOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneDirectOverlay.cs
deleted file mode 100644
index d9873ea243..0000000000
--- a/osu.Game.Tests/Visual/Online/TestSceneDirectOverlay.cs
+++ /dev/null
@@ -1,215 +0,0 @@
-// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
-// See the LICENCE file in the repository root for full licence text.
-
-using System.Collections.Generic;
-using NUnit.Framework;
-using osu.Game.Beatmaps;
-using osu.Game.Overlays;
-
-namespace osu.Game.Tests.Visual.Online
-{
- [TestFixture]
- public class TestSceneDirectOverlay : OsuTestScene
- {
- private DirectOverlay direct;
-
- protected override bool UseOnlineAPI => true;
-
- protected override void LoadComplete()
- {
- base.LoadComplete();
-
- Add(direct = new DirectOverlay());
- newBeatmaps();
-
- AddStep(@"toggle", direct.ToggleVisibility);
- AddStep(@"result counts", () => direct.ResultAmounts = new DirectOverlay.ResultCounts(1, 4, 13));
- AddStep(@"trigger disabled", () => Ruleset.Disabled = !Ruleset.Disabled);
- }
-
- private void newBeatmaps()
- {
- direct.BeatmapSets = new[]
- {
- new BeatmapSetInfo
- {
- OnlineBeatmapSetID = 578332,
- Metadata = new BeatmapMetadata
- {
- Title = @"OrVid",
- Artist = @"An",
- AuthorString = @"RLC",
- Source = @"",
- Tags = @"acuticnotes an-fillnote revid tear tearvid encrpted encryption axi axivid quad her hervid recoll",
- },
- OnlineInfo = new BeatmapSetOnlineInfo
- {
- Covers = new BeatmapSetOnlineCovers
- {
- Card = @"https://assets.ppy.sh/beatmaps/578332/covers/card.jpg?1494591390",
- Cover = @"https://assets.ppy.sh/beatmaps/578332/covers/cover.jpg?1494591390",
- },
- Preview = @"https://b.ppy.sh/preview/578332.mp3",
- PlayCount = 97,
- FavouriteCount = 72,
- },
- Beatmaps = new List
- {
- new BeatmapInfo
- {
- Ruleset = Ruleset.Value,
- StarDifficulty = 5.35f,
- Metadata = new BeatmapMetadata(),
- },
- },
- },
- new BeatmapSetInfo
- {
- OnlineBeatmapSetID = 599627,
- Metadata = new BeatmapMetadata
- {
- Title = @"tiny lamp",
- Artist = @"fhana",
- AuthorString = @"Sotarks",
- Source = @"ぎんぎつね",
- Tags = @"lantis junichi sato yuxuki waga kevin mitsunaga towana gingitsune opening op full ver version kalibe collab collaboration",
- },
- OnlineInfo = new BeatmapSetOnlineInfo
- {
- Covers = new BeatmapSetOnlineCovers
- {
- Card = @"https://assets.ppy.sh/beatmaps/599627/covers/card.jpg?1494539318",
- Cover = @"https://assets.ppy.sh/beatmaps/599627/covers/cover.jpg?1494539318",
- },
- Preview = @"https//b.ppy.sh/preview/599627.mp3",
- PlayCount = 3082,
- FavouriteCount = 14,
- },
- Beatmaps = new List
- {
- new BeatmapInfo
- {
- Ruleset = Ruleset.Value,
- StarDifficulty = 5.81f,
- Metadata = new BeatmapMetadata(),
- },
- },
- },
- new BeatmapSetInfo
- {
- OnlineBeatmapSetID = 513268,
- Metadata = new BeatmapMetadata
- {
- Title = @"At Gwanghwamun",
- Artist = @"KYUHYUN",
- AuthorString = @"Cerulean Veyron",
- Source = @"",
- Tags = @"soul ballad kh super junior sj suju 슈퍼주니어 kt뮤직 sm엔터테인먼트 s.m.entertainment kt music 1st mini album ep",
- },
- OnlineInfo = new BeatmapSetOnlineInfo
- {
- Covers = new BeatmapSetOnlineCovers
- {
- Card = @"https://assets.ppy.sh/beatmaps/513268/covers/card.jpg?1494502863",
- Cover = @"https://assets.ppy.sh/beatmaps/513268/covers/cover.jpg?1494502863",
- },
- Preview = @"https//b.ppy.sh/preview/513268.mp3",
- PlayCount = 2762,
- FavouriteCount = 15,
- },
- Beatmaps = new List
- {
- new BeatmapInfo
- {
- Ruleset = Ruleset.Value,
- StarDifficulty = 0.9f,
- Metadata = new BeatmapMetadata(),
- },
- new BeatmapInfo
- {
- Ruleset = Ruleset.Value,
- StarDifficulty = 1.1f,
- },
- new BeatmapInfo
- {
- Ruleset = Ruleset.Value,
- StarDifficulty = 2.02f,
- },
- new BeatmapInfo
- {
- Ruleset = Ruleset.Value,
- StarDifficulty = 3.49f,
- },
- },
- },
- new BeatmapSetInfo
- {
- OnlineBeatmapSetID = 586841,
- Metadata = new BeatmapMetadata
- {
- Title = @"RHAPSODY OF BLUE SKY",
- Artist = @"fhana",
- AuthorString = @"[Kamiya]",
- Source = @"小林さんちのメイドラゴン",
- Tags = @"kobayashi san chi no maidragon aozora no opening anime maid dragon oblivion karen dynamix imoutosan pata-mon gxytcgxytc",
- },
- OnlineInfo = new BeatmapSetOnlineInfo
- {
- Covers = new BeatmapSetOnlineCovers
- {
- Card = @"https://assets.ppy.sh/beatmaps/586841/covers/card.jpg?1494052741",
- Cover = @"https://assets.ppy.sh/beatmaps/586841/covers/cover.jpg?1494052741",
- },
- Preview = @"https//b.ppy.sh/preview/586841.mp3",
- PlayCount = 62317,
- FavouriteCount = 161,
- },
- Beatmaps = new List
- {
- new BeatmapInfo
- {
- Ruleset = Ruleset.Value,
- StarDifficulty = 1.26f,
- Metadata = new BeatmapMetadata(),
- },
- new BeatmapInfo
- {
- Ruleset = Ruleset.Value,
- StarDifficulty = 2.01f,
- },
- new BeatmapInfo
- {
- Ruleset = Ruleset.Value,
- StarDifficulty = 2.87f,
- },
- new BeatmapInfo
- {
- Ruleset = Ruleset.Value,
- StarDifficulty = 3.76f,
- },
- new BeatmapInfo
- {
- Ruleset = Ruleset.Value,
- StarDifficulty = 3.93f,
- },
- new BeatmapInfo
- {
- Ruleset = Ruleset.Value,
- StarDifficulty = 4.37f,
- },
- new BeatmapInfo
- {
- Ruleset = Ruleset.Value,
- StarDifficulty = 5.13f,
- },
- new BeatmapInfo
- {
- Ruleset = Ruleset.Value,
- StarDifficulty = 5.42f,
- },
- },
- },
- };
- }
- }
-}
diff --git a/osu.Game.Tests/Visual/Online/TestSceneDirectPanel.cs b/osu.Game.Tests/Visual/Online/TestSceneDirectPanel.cs
index cb08cded37..d6ed654bac 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneDirectPanel.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneDirectPanel.cs
@@ -8,7 +8,7 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Audio;
using osu.Game.Beatmaps;
-using osu.Game.Overlays.Direct;
+using osu.Game.Overlays.BeatmapListing.Panels;
using osu.Game.Rulesets;
using osu.Game.Users;
using osuTK;
@@ -20,8 +20,8 @@ namespace osu.Game.Tests.Visual.Online
{
public override IReadOnlyList RequiredTypes => new[]
{
- typeof(DirectGridPanel),
- typeof(DirectListPanel),
+ typeof(GridBeatmapPanel),
+ typeof(ListBeatmapPanel),
typeof(IconPill)
};
@@ -126,12 +126,12 @@ namespace osu.Game.Tests.Visual.Online
Spacing = new Vector2(5, 20),
Children = new Drawable[]
{
- new DirectGridPanel(normal),
- new DirectGridPanel(undownloadable),
- new DirectGridPanel(manyDifficulties),
- new DirectListPanel(normal),
- new DirectListPanel(undownloadable),
- new DirectListPanel(manyDifficulties),
+ new GridBeatmapPanel(normal),
+ new GridBeatmapPanel(undownloadable),
+ new GridBeatmapPanel(manyDifficulties),
+ new ListBeatmapPanel(normal),
+ new ListBeatmapPanel(undownloadable),
+ new ListBeatmapPanel(manyDifficulties),
},
},
};
diff --git a/osu.Game.Tests/Visual/TestSceneOsuGame.cs b/osu.Game.Tests/Visual/TestSceneOsuGame.cs
index 8793d880e3..2eaac2a45f 100644
--- a/osu.Game.Tests/Visual/TestSceneOsuGame.cs
+++ b/osu.Game.Tests/Visual/TestSceneOsuGame.cs
@@ -47,7 +47,7 @@ namespace osu.Game.Tests.Visual
typeof(IdleTracker),
typeof(OnScreenDisplay),
typeof(NotificationOverlay),
- typeof(DirectOverlay),
+ typeof(BeatmapListingOverlay),
typeof(DashboardOverlay),
typeof(ChannelManager),
typeof(ChatOverlay),
diff --git a/osu.Game/Beatmaps/BeatmapInfo.cs b/osu.Game/Beatmaps/BeatmapInfo.cs
index 68d113ce40..90c100db05 100644
--- a/osu.Game/Beatmaps/BeatmapInfo.cs
+++ b/osu.Game/Beatmaps/BeatmapInfo.cs
@@ -149,7 +149,12 @@ namespace osu.Game.Beatmaps
}
}
- public override string ToString() => $"{Metadata} [{Version}]".Trim();
+ public override string ToString()
+ {
+ string version = string.IsNullOrEmpty(Version) ? string.Empty : $"[{Version}]";
+
+ return $"{Metadata} {version}".Trim();
+ }
public bool Equals(BeatmapInfo other)
{
diff --git a/osu.Game/Beatmaps/BeatmapMetadata.cs b/osu.Game/Beatmaps/BeatmapMetadata.cs
index 001f319307..775d78f1fb 100644
--- a/osu.Game/Beatmaps/BeatmapMetadata.cs
+++ b/osu.Game/Beatmaps/BeatmapMetadata.cs
@@ -53,7 +53,11 @@ namespace osu.Game.Beatmaps
public string AudioFile { get; set; }
public string BackgroundFile { get; set; }
- public override string ToString() => $"{Artist} - {Title} ({Author})";
+ public override string ToString()
+ {
+ string author = Author == null ? string.Empty : $"({Author})";
+ return $"{Artist} - {Title} {author}".Trim();
+ }
[JsonIgnore]
public string[] SearchableTerms => new[]
diff --git a/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs b/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs
index fe63eec3f9..44ccbb350d 100644
--- a/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs
+++ b/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs
@@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
+using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
@@ -10,6 +11,7 @@ using osu.Game.Audio;
using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Beatmaps.Legacy;
using osu.Game.Rulesets.Objects;
+using osu.Game.Rulesets.Objects.Legacy;
using osu.Game.Rulesets.Objects.Types;
namespace osu.Game.Beatmaps.Formats
@@ -48,7 +50,7 @@ namespace osu.Game.Beatmaps.Formats
handleEvents(writer);
writer.WriteLine();
- handleTimingPoints(writer);
+ handleControlPoints(writer);
writer.WriteLine();
handleHitObjects(writer);
@@ -58,7 +60,7 @@ namespace osu.Game.Beatmaps.Formats
{
writer.WriteLine("[General]");
- writer.WriteLine(FormattableString.Invariant($"AudioFilename: {Path.GetFileName(beatmap.Metadata.AudioFile)}"));
+ if (beatmap.Metadata.AudioFile != null) writer.WriteLine(FormattableString.Invariant($"AudioFilename: {Path.GetFileName(beatmap.Metadata.AudioFile)}"));
writer.WriteLine(FormattableString.Invariant($"AudioLeadIn: {beatmap.BeatmapInfo.AudioLeadIn}"));
writer.WriteLine(FormattableString.Invariant($"PreviewTime: {beatmap.Metadata.PreviewTime}"));
// Todo: Not all countdown types are supported by lazer yet
@@ -103,15 +105,15 @@ namespace osu.Game.Beatmaps.Formats
writer.WriteLine("[Metadata]");
writer.WriteLine(FormattableString.Invariant($"Title: {beatmap.Metadata.Title}"));
- writer.WriteLine(FormattableString.Invariant($"TitleUnicode: {beatmap.Metadata.TitleUnicode}"));
+ if (beatmap.Metadata.TitleUnicode != null) writer.WriteLine(FormattableString.Invariant($"TitleUnicode: {beatmap.Metadata.TitleUnicode}"));
writer.WriteLine(FormattableString.Invariant($"Artist: {beatmap.Metadata.Artist}"));
- writer.WriteLine(FormattableString.Invariant($"ArtistUnicode: {beatmap.Metadata.ArtistUnicode}"));
+ if (beatmap.Metadata.ArtistUnicode != null) writer.WriteLine(FormattableString.Invariant($"ArtistUnicode: {beatmap.Metadata.ArtistUnicode}"));
writer.WriteLine(FormattableString.Invariant($"Creator: {beatmap.Metadata.AuthorString}"));
writer.WriteLine(FormattableString.Invariant($"Version: {beatmap.BeatmapInfo.Version}"));
- writer.WriteLine(FormattableString.Invariant($"Source: {beatmap.Metadata.Source}"));
- writer.WriteLine(FormattableString.Invariant($"Tags: {beatmap.Metadata.Tags}"));
- writer.WriteLine(FormattableString.Invariant($"BeatmapID: {beatmap.BeatmapInfo.OnlineBeatmapID ?? 0}"));
- writer.WriteLine(FormattableString.Invariant($"BeatmapSetID: {beatmap.BeatmapInfo.BeatmapSet?.OnlineBeatmapSetID ?? -1}"));
+ if (beatmap.Metadata.Source != null) writer.WriteLine(FormattableString.Invariant($"Source: {beatmap.Metadata.Source}"));
+ if (beatmap.Metadata.Tags != null) writer.WriteLine(FormattableString.Invariant($"Tags: {beatmap.Metadata.Tags}"));
+ if (beatmap.BeatmapInfo.OnlineBeatmapID != null) writer.WriteLine(FormattableString.Invariant($"BeatmapID: {beatmap.BeatmapInfo.OnlineBeatmapID}"));
+ if (beatmap.BeatmapInfo.BeatmapSet?.OnlineBeatmapSetID != null) writer.WriteLine(FormattableString.Invariant($"BeatmapSetID: {beatmap.BeatmapInfo.BeatmapSet.OnlineBeatmapSetID}"));
}
private void handleDifficulty(TextWriter writer)
@@ -137,7 +139,7 @@ namespace osu.Game.Beatmaps.Formats
writer.WriteLine(FormattableString.Invariant($"{(int)LegacyEventType.Break},{b.StartTime},{b.EndTime}"));
}
- private void handleTimingPoints(TextWriter writer)
+ private void handleControlPoints(TextWriter writer)
{
if (beatmap.ControlPointInfo.Groups.Count == 0)
return;
@@ -146,20 +148,30 @@ namespace osu.Game.Beatmaps.Formats
foreach (var group in beatmap.ControlPointInfo.Groups)
{
- var timingPoint = group.ControlPoints.OfType().FirstOrDefault();
- var difficultyPoint = beatmap.ControlPointInfo.DifficultyPointAt(group.Time);
- var samplePoint = beatmap.ControlPointInfo.SamplePointAt(group.Time);
- var effectPoint = beatmap.ControlPointInfo.EffectPointAt(group.Time);
+ var groupTimingPoint = group.ControlPoints.OfType().FirstOrDefault();
- // Convert beat length the legacy format
- double beatLength;
- if (timingPoint != null)
- beatLength = timingPoint.BeatLength;
- else
- beatLength = -100 / difficultyPoint.SpeedMultiplier;
+ // If the group contains a timing control point, it needs to be output separately.
+ if (groupTimingPoint != null)
+ {
+ writer.Write(FormattableString.Invariant($"{groupTimingPoint.Time},"));
+ writer.Write(FormattableString.Invariant($"{groupTimingPoint.BeatLength},"));
+ outputControlPointEffectsAt(groupTimingPoint.Time, true);
+ }
+
+ // Output any remaining effects as secondary non-timing control point.
+ var difficultyPoint = beatmap.ControlPointInfo.DifficultyPointAt(group.Time);
+ writer.Write(FormattableString.Invariant($"{group.Time},"));
+ writer.Write(FormattableString.Invariant($"{-100 / difficultyPoint.SpeedMultiplier},"));
+ outputControlPointEffectsAt(group.Time, false);
+ }
+
+ void outputControlPointEffectsAt(double time, bool isTimingPoint)
+ {
+ var samplePoint = beatmap.ControlPointInfo.SamplePointAt(time);
+ var effectPoint = beatmap.ControlPointInfo.EffectPointAt(time);
// Apply the control point to a hit sample to uncover legacy properties (e.g. suffix)
- HitSampleInfo tempHitSample = samplePoint.ApplyTo(new HitSampleInfo());
+ HitSampleInfo tempHitSample = samplePoint.ApplyTo(new ConvertHitObjectParser.LegacyHitSampleInfo());
// Convert effect flags to the legacy format
LegacyEffectFlags effectFlags = LegacyEffectFlags.None;
@@ -168,13 +180,11 @@ namespace osu.Game.Beatmaps.Formats
if (effectPoint.OmitFirstBarLine)
effectFlags |= LegacyEffectFlags.OmitFirstBarLine;
- writer.Write(FormattableString.Invariant($"{group.Time},"));
- writer.Write(FormattableString.Invariant($"{beatLength},"));
- writer.Write(FormattableString.Invariant($"{(int)beatmap.ControlPointInfo.TimingPointAt(group.Time).TimeSignature},"));
+ writer.Write(FormattableString.Invariant($"{(int)beatmap.ControlPointInfo.TimingPointAt(time).TimeSignature},"));
writer.Write(FormattableString.Invariant($"{(int)toLegacySampleBank(tempHitSample.Bank)},"));
- writer.Write(FormattableString.Invariant($"{toLegacyCustomSampleBank(tempHitSample.Suffix)},"));
+ writer.Write(FormattableString.Invariant($"{toLegacyCustomSampleBank(tempHitSample)},"));
writer.Write(FormattableString.Invariant($"{tempHitSample.Volume},"));
- writer.Write(FormattableString.Invariant($"{(timingPoint != null ? '1' : '0')},"));
+ writer.Write(FormattableString.Invariant($"{(isTimingPoint ? '1' : '0')},"));
writer.Write(FormattableString.Invariant($"{(int)effectFlags}"));
writer.WriteLine();
}
@@ -240,7 +250,7 @@ namespace osu.Game.Beatmaps.Formats
break;
case IHasEndTime _:
- type |= LegacyHitObjectType.Spinner | LegacyHitObjectType.NewCombo;
+ type |= LegacyHitObjectType.Spinner;
break;
default:
@@ -326,7 +336,7 @@ namespace osu.Game.Beatmaps.Formats
if (!banksOnly)
{
- string customSampleBank = toLegacyCustomSampleBank(samples.FirstOrDefault(s => !string.IsNullOrEmpty(s.Name))?.Suffix);
+ string customSampleBank = toLegacyCustomSampleBank(samples.FirstOrDefault(s => !string.IsNullOrEmpty(s.Name)));
string sampleFilename = samples.FirstOrDefault(s => string.IsNullOrEmpty(s.Name))?.LookupNames.First() ?? string.Empty;
int volume = samples.FirstOrDefault()?.Volume ?? 100;
@@ -382,6 +392,15 @@ namespace osu.Game.Beatmaps.Formats
}
}
- private string toLegacyCustomSampleBank(string sampleSuffix) => string.IsNullOrEmpty(sampleSuffix) ? "0" : sampleSuffix;
+ private string toLegacyCustomSampleBank(HitSampleInfo hitSampleInfo)
+ {
+ if (hitSampleInfo == null)
+ return "0";
+
+ if (hitSampleInfo is ConvertHitObjectParser.LegacyHitSampleInfo legacy)
+ return legacy.CustomSampleBank.ToString(CultureInfo.InvariantCulture);
+
+ return "0";
+ }
}
}
diff --git a/osu.Game/IO/Serialization/Converters/TypedListConverter.cs b/osu.Game/IO/Serialization/Converters/TypedListConverter.cs
index 6d244bff60..64f1ebeb1a 100644
--- a/osu.Game/IO/Serialization/Converters/TypedListConverter.cs
+++ b/osu.Game/IO/Serialization/Converters/TypedListConverter.cs
@@ -43,13 +43,13 @@ namespace osu.Game.IO.Serialization.Converters
var list = new List();
var obj = JObject.Load(reader);
- var lookupTable = serializer.Deserialize>(obj["lookup_table"].CreateReader());
+ var lookupTable = serializer.Deserialize>(obj["$lookup_table"].CreateReader());
- foreach (var tok in obj["items"])
+ foreach (var tok in obj["$items"])
{
var itemReader = tok.CreateReader();
- var typeName = lookupTable[(int)tok["type"]];
+ var typeName = lookupTable[(int)tok["$type"]];
var instance = (T)Activator.CreateInstance(Type.GetType(typeName));
serializer.Populate(itemReader, instance);
@@ -61,7 +61,7 @@ namespace osu.Game.IO.Serialization.Converters
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
- var list = (List)value;
+ var list = (IEnumerable)value;
var lookupTable = new List();
var objects = new List();
@@ -84,16 +84,16 @@ namespace osu.Game.IO.Serialization.Converters
}
var itemObject = JObject.FromObject(item, serializer);
- itemObject.AddFirst(new JProperty("type", typeId));
+ itemObject.AddFirst(new JProperty("$type", typeId));
objects.Add(itemObject);
}
writer.WriteStartObject();
- writer.WritePropertyName("lookup_table");
+ writer.WritePropertyName("$lookup_table");
serializer.Serialize(writer, lookupTable);
- writer.WritePropertyName("items");
+ writer.WritePropertyName("$items");
serializer.Serialize(writer, objects);
writer.WriteEndObject();
diff --git a/osu.Game/Online/API/Requests/SearchBeatmapSetsRequest.cs b/osu.Game/Online/API/Requests/SearchBeatmapSetsRequest.cs
index 8345be5f82..047496b473 100644
--- a/osu.Game/Online/API/Requests/SearchBeatmapSetsRequest.cs
+++ b/osu.Game/Online/API/Requests/SearchBeatmapSetsRequest.cs
@@ -4,7 +4,6 @@
using osu.Framework.IO.Network;
using osu.Game.Overlays;
using osu.Game.Overlays.BeatmapListing;
-using osu.Game.Overlays.Direct;
using osu.Game.Rulesets;
namespace osu.Game.Online.API.Requests
@@ -13,7 +12,7 @@ namespace osu.Game.Online.API.Requests
{
public SearchCategory SearchCategory { get; set; }
- public DirectSortCriteria SortCriteria { get; set; }
+ public SortCriteria SortCriteria { get; set; }
public SortDirection SortDirection { get; set; }
@@ -32,7 +31,7 @@ namespace osu.Game.Online.API.Requests
this.ruleset = ruleset;
SearchCategory = SearchCategory.Any;
- SortCriteria = DirectSortCriteria.Ranked;
+ SortCriteria = SortCriteria.Ranked;
SortDirection = SortDirection.Descending;
Genre = SearchGenre.Any;
Language = SearchLanguage.Any;
diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs
index c861b84835..f5f7d0cef4 100644
--- a/osu.Game/OsuGame.cs
+++ b/osu.Game/OsuGame.cs
@@ -65,7 +65,7 @@ namespace osu.Game
private NowPlayingOverlay nowPlaying;
- private DirectOverlay direct;
+ private BeatmapListingOverlay beatmapListing;
private DashboardOverlay dashboard;
@@ -610,7 +610,7 @@ namespace osu.Game
loadComponentSingleFile(screenshotManager, Add);
//overlay elements
- loadComponentSingleFile(direct = new DirectOverlay(), overlayContent.Add, true);
+ loadComponentSingleFile(beatmapListing = new BeatmapListingOverlay(), overlayContent.Add, true);
loadComponentSingleFile(dashboard = new DashboardOverlay(), overlayContent.Add, true);
var rankingsOverlay = loadComponentSingleFile(new RankingsOverlay(), overlayContent.Add, true);
loadComponentSingleFile(channelManager = new ChannelManager(), AddInternal, true);
@@ -670,7 +670,7 @@ namespace osu.Game
}
// ensure only one of these overlays are open at once.
- var singleDisplayOverlays = new OverlayContainer[] { chatOverlay, dashboard, direct, changelogOverlay, rankingsOverlay };
+ var singleDisplayOverlays = new OverlayContainer[] { chatOverlay, dashboard, beatmapListing, changelogOverlay, rankingsOverlay };
foreach (var overlay in singleDisplayOverlays)
{
@@ -865,7 +865,7 @@ namespace osu.Game
return true;
case GlobalAction.ToggleDirect:
- direct.ToggleVisibility();
+ beatmapListing.ToggleVisibility();
return true;
case GlobalAction.ToggleGameplayMouseButtons:
diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs
index 5487bd9320..609b6ce98e 100644
--- a/osu.Game/OsuGameBase.cs
+++ b/osu.Game/OsuGameBase.cs
@@ -168,7 +168,7 @@ namespace osu.Game
var defaultBeatmap = new DummyWorkingBeatmap(Audio, Textures);
- dependencies.Cache(RulesetStore = new RulesetStore(contextFactory));
+ dependencies.Cache(RulesetStore = new RulesetStore(contextFactory, Storage));
dependencies.Cache(FileStore = new FileStore(contextFactory, Storage));
// ordering is important here to ensure foreign keys rules are not broken in ModelStore.Cleanup()
diff --git a/osu.Game/Overlays/Direct/BeatmapDownloadTrackingComposite.cs b/osu.Game/Overlays/BeatmapDownloadTrackingComposite.cs
similarity index 94%
rename from osu.Game/Overlays/Direct/BeatmapDownloadTrackingComposite.cs
rename to osu.Game/Overlays/BeatmapDownloadTrackingComposite.cs
index fd04a1541e..f6b5b181c3 100644
--- a/osu.Game/Overlays/Direct/BeatmapDownloadTrackingComposite.cs
+++ b/osu.Game/Overlays/BeatmapDownloadTrackingComposite.cs
@@ -5,7 +5,7 @@ using osu.Framework.Bindables;
using osu.Game.Beatmaps;
using osu.Game.Online;
-namespace osu.Game.Overlays.Direct
+namespace osu.Game.Overlays
{
public abstract class BeatmapDownloadTrackingComposite : DownloadTrackingComposite
{
diff --git a/osu.Game/Overlays/BeatmapListing/BeatmapListingFilterControl.cs b/osu.Game/Overlays/BeatmapListing/BeatmapListingFilterControl.cs
index 8817031bce..4dd60c7113 100644
--- a/osu.Game/Overlays/BeatmapListing/BeatmapListingFilterControl.cs
+++ b/osu.Game/Overlays/BeatmapListing/BeatmapListingFilterControl.cs
@@ -14,7 +14,6 @@ using osu.Framework.Threading;
using osu.Game.Beatmaps;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests;
-using osu.Game.Overlays.Direct;
using osu.Game.Rulesets;
using osuTK;
using osuTK.Graphics;
@@ -101,7 +100,7 @@ namespace osu.Game.Overlays.BeatmapListing
searchControl.Query.BindValueChanged(query =>
{
- sortCriteria.Value = string.IsNullOrEmpty(query.NewValue) ? DirectSortCriteria.Ranked : DirectSortCriteria.Relevance;
+ sortCriteria.Value = string.IsNullOrEmpty(query.NewValue) ? SortCriteria.Ranked : SortCriteria.Relevance;
sortDirection.Value = SortDirection.Descending;
queueUpdateSearch(true);
});
@@ -159,5 +158,7 @@ namespace osu.Game.Overlays.BeatmapListing
base.Dispose(isDisposing);
}
+
+ public void TakeFocus() => searchControl.TakeFocus();
}
}
diff --git a/osu.Game/Overlays/BeatmapListing/BeatmapListingSearchControl.cs b/osu.Game/Overlays/BeatmapListing/BeatmapListingSearchControl.cs
index 2ecdb18667..29c4fe0d2e 100644
--- a/osu.Game/Overlays/BeatmapListing/BeatmapListingSearchControl.cs
+++ b/osu.Game/Overlays/BeatmapListing/BeatmapListingSearchControl.cs
@@ -121,6 +121,8 @@ namespace osu.Game.Overlays.BeatmapListing
background.Colour = colourProvider.Dark6;
}
+ public void TakeFocus() => textBox.TakeFocus();
+
private class BeatmapSearchTextBox : SearchTextBox
{
protected override Color4 SelectionColour => Color4.Gray;
diff --git a/osu.Game/Overlays/BeatmapListing/BeatmapListingSortTabControl.cs b/osu.Game/Overlays/BeatmapListing/BeatmapListingSortTabControl.cs
index 27c43b092a..4c77a736ac 100644
--- a/osu.Game/Overlays/BeatmapListing/BeatmapListingSortTabControl.cs
+++ b/osu.Game/Overlays/BeatmapListing/BeatmapListingSortTabControl.cs
@@ -8,17 +8,16 @@ using osu.Framework.Graphics;
using osuTK.Graphics;
using osuTK;
using osu.Framework.Input.Events;
-using osu.Game.Overlays.Direct;
namespace osu.Game.Overlays.BeatmapListing
{
- public class BeatmapListingSortTabControl : OverlaySortTabControl
+ public class BeatmapListingSortTabControl : OverlaySortTabControl
{
public readonly Bindable SortDirection = new Bindable(Overlays.SortDirection.Descending);
public BeatmapListingSortTabControl()
{
- Current.Value = DirectSortCriteria.Ranked;
+ Current.Value = SortCriteria.Ranked;
}
protected override SortTabControl CreateControl() => new BeatmapSortTabControl
@@ -30,7 +29,7 @@ namespace osu.Game.Overlays.BeatmapListing
{
public readonly Bindable SortDirection = new Bindable();
- protected override TabItem CreateTabItem(DirectSortCriteria value) => new BeatmapSortTabItem(value)
+ protected override TabItem CreateTabItem(SortCriteria value) => new BeatmapSortTabItem(value)
{
SortDirection = { BindTarget = SortDirection }
};
@@ -40,12 +39,12 @@ namespace osu.Game.Overlays.BeatmapListing
{
public readonly Bindable SortDirection = new Bindable();
- public BeatmapSortTabItem(DirectSortCriteria value)
+ public BeatmapSortTabItem(SortCriteria value)
: base(value)
{
}
- protected override TabButton CreateTabButton(DirectSortCriteria value) => new BeatmapTabButton(value)
+ protected override TabButton CreateTabButton(SortCriteria value) => new BeatmapTabButton(value)
{
Active = { BindTarget = Active },
SortDirection = { BindTarget = SortDirection }
@@ -67,7 +66,7 @@ namespace osu.Game.Overlays.BeatmapListing
private readonly SpriteIcon icon;
- public BeatmapTabButton(DirectSortCriteria value)
+ public BeatmapTabButton(SortCriteria value)
: base(value)
{
Add(icon = new SpriteIcon
diff --git a/osu.Game/Overlays/Direct/DirectPanel.cs b/osu.Game/Overlays/BeatmapListing/Panels/BeatmapPanel.cs
similarity index 96%
rename from osu.Game/Overlays/Direct/DirectPanel.cs
rename to osu.Game/Overlays/BeatmapListing/Panels/BeatmapPanel.cs
index 4ad8e95512..88c15776cd 100644
--- a/osu.Game/Overlays/Direct/DirectPanel.cs
+++ b/osu.Game/Overlays/BeatmapListing/Panels/BeatmapPanel.cs
@@ -26,9 +26,9 @@ using osu.Game.Graphics.UserInterface;
using osuTK;
using osuTK.Graphics;
-namespace osu.Game.Overlays.Direct
+namespace osu.Game.Overlays.BeatmapListing.Panels
{
- public abstract class DirectPanel : OsuClickableContainer, IHasContextMenu
+ public abstract class BeatmapPanel : OsuClickableContainer, IHasContextMenu
{
public readonly BeatmapSetInfo SetInfo;
@@ -49,7 +49,7 @@ namespace osu.Game.Overlays.Direct
protected Action ViewBeatmap;
- protected DirectPanel(BeatmapSetInfo setInfo)
+ protected BeatmapPanel(BeatmapSetInfo setInfo)
{
Debug.Assert(setInfo.OnlineBeatmapSetID != null);
@@ -148,7 +148,7 @@ namespace osu.Game.Overlays.Direct
if (SetInfo.Beatmaps.Count > maximum_difficulty_icons)
{
foreach (var ruleset in SetInfo.Beatmaps.Select(b => b.Ruleset).Distinct())
- icons.Add(new GroupedDifficultyIcon(SetInfo.Beatmaps.FindAll(b => b.Ruleset.Equals(ruleset)), ruleset, this is DirectListPanel ? Color4.White : colours.Gray5));
+ icons.Add(new GroupedDifficultyIcon(SetInfo.Beatmaps.FindAll(b => b.Ruleset.Equals(ruleset)), ruleset, this is ListBeatmapPanel ? Color4.White : colours.Gray5));
}
else
{
diff --git a/osu.Game/Overlays/Direct/PanelDownloadButton.cs b/osu.Game/Overlays/BeatmapListing/Panels/BeatmapPanelDownloadButton.cs
similarity index 93%
rename from osu.Game/Overlays/Direct/PanelDownloadButton.cs
rename to osu.Game/Overlays/BeatmapListing/Panels/BeatmapPanelDownloadButton.cs
index 387ced6acb..589f2d5072 100644
--- a/osu.Game/Overlays/Direct/PanelDownloadButton.cs
+++ b/osu.Game/Overlays/BeatmapListing/Panels/BeatmapPanelDownloadButton.cs
@@ -11,9 +11,9 @@ using osu.Game.Graphics.Containers;
using osu.Game.Graphics.UserInterface;
using osu.Game.Online;
-namespace osu.Game.Overlays.Direct
+namespace osu.Game.Overlays.BeatmapListing.Panels
{
- public class PanelDownloadButton : BeatmapDownloadTrackingComposite
+ public class BeatmapPanelDownloadButton : BeatmapDownloadTrackingComposite
{
protected bool DownloadEnabled => button.Enabled.Value;
@@ -26,7 +26,7 @@ namespace osu.Game.Overlays.Direct
private readonly DownloadButton button;
private Bindable noVideoSetting;
- public PanelDownloadButton(BeatmapSetInfo beatmapSet)
+ public BeatmapPanelDownloadButton(BeatmapSetInfo beatmapSet)
: base(beatmapSet)
{
InternalChild = shakeContainer = new ShakeContainer
diff --git a/osu.Game/Overlays/Direct/DownloadProgressBar.cs b/osu.Game/Overlays/BeatmapListing/Panels/DownloadProgressBar.cs
similarity index 97%
rename from osu.Game/Overlays/Direct/DownloadProgressBar.cs
rename to osu.Game/Overlays/BeatmapListing/Panels/DownloadProgressBar.cs
index 9a8644efd2..93cf8799b5 100644
--- a/osu.Game/Overlays/Direct/DownloadProgressBar.cs
+++ b/osu.Game/Overlays/BeatmapListing/Panels/DownloadProgressBar.cs
@@ -10,7 +10,7 @@ using osu.Game.Graphics.UserInterface;
using osu.Game.Online;
using osuTK.Graphics;
-namespace osu.Game.Overlays.Direct
+namespace osu.Game.Overlays.BeatmapListing.Panels
{
public class DownloadProgressBar : BeatmapDownloadTrackingComposite
{
diff --git a/osu.Game/Overlays/Direct/DirectGridPanel.cs b/osu.Game/Overlays/BeatmapListing/Panels/GridBeatmapPanel.cs
similarity index 97%
rename from osu.Game/Overlays/Direct/DirectGridPanel.cs
rename to osu.Game/Overlays/BeatmapListing/Panels/GridBeatmapPanel.cs
index 2528ccec41..84d35da096 100644
--- a/osu.Game/Overlays/Direct/DirectGridPanel.cs
+++ b/osu.Game/Overlays/BeatmapListing/Panels/GridBeatmapPanel.cs
@@ -1,25 +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 osuTK;
-using osuTK.Graphics;
using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
-using osu.Game.Graphics;
-using osu.Game.Graphics.Sprites;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Input.Events;
using osu.Framework.Localisation;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Drawables;
+using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
+using osu.Game.Graphics.Sprites;
+using osuTK;
+using osuTK.Graphics;
-namespace osu.Game.Overlays.Direct
+namespace osu.Game.Overlays.BeatmapListing.Panels
{
- public class DirectGridPanel : DirectPanel
+ public class GridBeatmapPanel : BeatmapPanel
{
private const float horizontal_padding = 10;
private const float vertical_padding = 5;
@@ -31,7 +31,7 @@ namespace osu.Game.Overlays.Direct
protected override PlayButton PlayButton => playButton;
protected override Box PreviewBar => progressBar;
- public DirectGridPanel(BeatmapSetInfo beatmap)
+ public GridBeatmapPanel(BeatmapSetInfo beatmap)
: base(beatmap)
{
Width = 380;
@@ -156,7 +156,7 @@ namespace osu.Game.Overlays.Direct
},
},
},
- new PanelDownloadButton(SetInfo)
+ new BeatmapPanelDownloadButton(SetInfo)
{
Size = new Vector2(50, 30),
Margin = new MarginPadding(horizontal_padding),
diff --git a/osu.Game/Overlays/Direct/IconPill.cs b/osu.Game/Overlays/BeatmapListing/Panels/IconPill.cs
similarity index 96%
rename from osu.Game/Overlays/Direct/IconPill.cs
rename to osu.Game/Overlays/BeatmapListing/Panels/IconPill.cs
index d63bb2a292..1cb6c84f13 100644
--- a/osu.Game/Overlays/Direct/IconPill.cs
+++ b/osu.Game/Overlays/BeatmapListing/Panels/IconPill.cs
@@ -8,7 +8,7 @@ using osu.Framework.Graphics.Sprites;
using osuTK;
using osuTK.Graphics;
-namespace osu.Game.Overlays.Direct
+namespace osu.Game.Overlays.BeatmapListing.Panels
{
public class IconPill : CircularContainer
{
diff --git a/osu.Game/Overlays/Direct/DirectListPanel.cs b/osu.Game/Overlays/BeatmapListing/Panels/ListBeatmapPanel.cs
similarity index 97%
rename from osu.Game/Overlays/Direct/DirectListPanel.cs
rename to osu.Game/Overlays/BeatmapListing/Panels/ListBeatmapPanel.cs
index b64142dfe7..433ea37f06 100644
--- a/osu.Game/Overlays/Direct/DirectListPanel.cs
+++ b/osu.Game/Overlays/BeatmapListing/Panels/ListBeatmapPanel.cs
@@ -1,25 +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 osuTK;
-using osuTK.Graphics;
+using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
-using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Colour;
-using osu.Game.Graphics;
-using osu.Game.Graphics.Sprites;
-using osu.Framework.Allocation;
+using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Localisation;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Drawables;
+using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
+using osu.Game.Graphics.Sprites;
+using osuTK;
+using osuTK.Graphics;
-namespace osu.Game.Overlays.Direct
+namespace osu.Game.Overlays.BeatmapListing.Panels
{
- public class DirectListPanel : DirectPanel
+ public class ListBeatmapPanel : BeatmapPanel
{
private const float transition_duration = 120;
private const float horizontal_padding = 10;
@@ -27,7 +27,7 @@ namespace osu.Game.Overlays.Direct
private const float height = 70;
private FillFlowContainer statusContainer;
- protected PanelDownloadButton DownloadButton;
+ protected BeatmapPanelDownloadButton DownloadButton;
private PlayButton playButton;
private Box progressBar;
@@ -36,7 +36,7 @@ namespace osu.Game.Overlays.Direct
protected override PlayButton PlayButton => playButton;
protected override Box PreviewBar => progressBar;
- public DirectListPanel(BeatmapSetInfo beatmap)
+ public ListBeatmapPanel(BeatmapSetInfo beatmap)
: base(beatmap)
{
RelativeSizeAxes = Axes.X;
@@ -151,7 +151,7 @@ namespace osu.Game.Overlays.Direct
Anchor = Anchor.CentreRight,
Origin = Anchor.CentreRight,
AutoSizeAxes = Axes.Both,
- Child = DownloadButton = new PanelDownloadButton(SetInfo)
+ Child = DownloadButton = new BeatmapPanelDownloadButton(SetInfo)
{
Size = new Vector2(height - vertical_padding * 3),
Margin = new MarginPadding { Left = vertical_padding * 2, Right = vertical_padding },
diff --git a/osu.Game/Overlays/Direct/PlayButton.cs b/osu.Game/Overlays/BeatmapListing/Panels/PlayButton.cs
similarity index 98%
rename from osu.Game/Overlays/Direct/PlayButton.cs
rename to osu.Game/Overlays/BeatmapListing/Panels/PlayButton.cs
index d9f335b6a7..e95fdeecf4 100644
--- a/osu.Game/Overlays/Direct/PlayButton.cs
+++ b/osu.Game/Overlays/BeatmapListing/Panels/PlayButton.cs
@@ -14,7 +14,7 @@ using osu.Game.Graphics.UserInterface;
using osuTK;
using osuTK.Graphics;
-namespace osu.Game.Overlays.Direct
+namespace osu.Game.Overlays.BeatmapListing.Panels
{
public class PlayButton : Container
{
diff --git a/osu.Game/Overlays/BeatmapListing/SortCriteria.cs b/osu.Game/Overlays/BeatmapListing/SortCriteria.cs
new file mode 100644
index 0000000000..e409cbdda7
--- /dev/null
+++ b/osu.Game/Overlays/BeatmapListing/SortCriteria.cs
@@ -0,0 +1,17 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+namespace osu.Game.Overlays.BeatmapListing
+{
+ public enum SortCriteria
+ {
+ Title,
+ Artist,
+ Difficulty,
+ Ranked,
+ Rating,
+ Plays,
+ Favourites,
+ Relevance
+ }
+}
diff --git a/osu.Game/Overlays/BeatmapListingOverlay.cs b/osu.Game/Overlays/BeatmapListingOverlay.cs
index e16924464d..f680f7c67b 100644
--- a/osu.Game/Overlays/BeatmapListingOverlay.cs
+++ b/osu.Game/Overlays/BeatmapListingOverlay.cs
@@ -10,13 +10,14 @@ using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures;
+using osu.Framework.Input.Events;
using osu.Game.Audio;
using osu.Game.Beatmaps;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterface;
using osu.Game.Overlays.BeatmapListing;
-using osu.Game.Overlays.Direct;
+using osu.Game.Overlays.BeatmapListing.Panels;
using osuTK;
namespace osu.Game.Overlays
@@ -35,6 +36,8 @@ namespace osu.Game.Overlays
{
}
+ private BeatmapListingFilterControl filterControl;
+
[BackgroundDependencyLoader]
private void load()
{
@@ -57,7 +60,7 @@ namespace osu.Game.Overlays
Children = new Drawable[]
{
new BeatmapListingHeader(),
- new BeatmapListingFilterControl
+ filterControl = new BeatmapListingFilterControl
{
SearchStarted = onSearchStarted,
SearchFinished = onSearchFinished,
@@ -88,6 +91,13 @@ namespace osu.Game.Overlays
};
}
+ protected override void OnFocus(FocusEvent e)
+ {
+ base.OnFocus(e);
+
+ filterControl.TakeFocus();
+ }
+
private CancellationTokenSource cancellationToken;
private void onSearchStarted()
@@ -108,14 +118,14 @@ namespace osu.Game.Overlays
return;
}
- var newPanels = new FillFlowContainer
+ var newPanels = new FillFlowContainer
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Spacing = new Vector2(10),
Alpha = 0,
Margin = new MarginPadding { Vertical = 15 },
- ChildrenEnumerable = beatmaps.Select(b => new DirectGridPanel(b)
+ ChildrenEnumerable = beatmaps.Select(b => new GridBeatmapPanel(b)
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
diff --git a/osu.Game/Overlays/BeatmapSet/Buttons/HeaderDownloadButton.cs b/osu.Game/Overlays/BeatmapSet/Buttons/HeaderDownloadButton.cs
index e64256b850..56c0052bfe 100644
--- a/osu.Game/Overlays/BeatmapSet/Buttons/HeaderDownloadButton.cs
+++ b/osu.Game/Overlays/BeatmapSet/Buttons/HeaderDownloadButton.cs
@@ -13,7 +13,7 @@ using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Sprites;
using osu.Game.Online;
using osu.Game.Online.API;
-using osu.Game.Overlays.Direct;
+using osu.Game.Overlays.BeatmapListing.Panels;
using osu.Game.Users;
using osuTK;
using osuTK.Graphics;
diff --git a/osu.Game/Overlays/BeatmapSet/Buttons/PreviewButton.cs b/osu.Game/Overlays/BeatmapSet/Buttons/PreviewButton.cs
index 7eae05e4a9..6accce7d77 100644
--- a/osu.Game/Overlays/BeatmapSet/Buttons/PreviewButton.cs
+++ b/osu.Game/Overlays/BeatmapSet/Buttons/PreviewButton.cs
@@ -11,7 +11,7 @@ using osu.Game.Audio;
using osu.Game.Beatmaps;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
-using osu.Game.Overlays.Direct;
+using osu.Game.Overlays.BeatmapListing.Panels;
using osuTK;
namespace osu.Game.Overlays.BeatmapSet.Buttons
diff --git a/osu.Game/Overlays/BeatmapSet/Header.cs b/osu.Game/Overlays/BeatmapSet/Header.cs
index 11dc424183..17fa689cd2 100644
--- a/osu.Game/Overlays/BeatmapSet/Header.cs
+++ b/osu.Game/Overlays/BeatmapSet/Header.cs
@@ -15,8 +15,8 @@ using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterface;
using osu.Game.Online;
+using osu.Game.Overlays.BeatmapListing.Panels;
using osu.Game.Overlays.BeatmapSet.Buttons;
-using osu.Game.Overlays.Direct;
using osu.Game.Rulesets;
using osuTK;
using osuTK.Graphics;
@@ -274,7 +274,7 @@ namespace osu.Game.Overlays.BeatmapSet
{
case DownloadState.LocallyAvailable:
// temporary for UX until new design is implemented.
- downloadButtonsContainer.Child = new PanelDownloadButton(BeatmapSet.Value)
+ downloadButtonsContainer.Child = new BeatmapPanelDownloadButton(BeatmapSet.Value)
{
Width = 50,
RelativeSizeAxes = Axes.Y,
diff --git a/osu.Game/Overlays/Direct/DirectRulesetSelector.cs b/osu.Game/Overlays/Direct/DirectRulesetSelector.cs
deleted file mode 100644
index 106aaa616b..0000000000
--- a/osu.Game/Overlays/Direct/DirectRulesetSelector.cs
+++ /dev/null
@@ -1,93 +0,0 @@
-// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
-// See the LICENCE file in the repository root for full licence text.
-
-using osu.Framework.Graphics;
-using osu.Framework.Graphics.Containers;
-using osu.Framework.Graphics.UserInterface;
-using osu.Framework.Input.Events;
-using osu.Game.Graphics.Containers;
-using osu.Game.Graphics.UserInterface;
-using osu.Game.Rulesets;
-using osuTK;
-using osuTK.Graphics;
-
-namespace osu.Game.Overlays.Direct
-{
- public class DirectRulesetSelector : RulesetSelector
- {
- public override bool HandleNonPositionalInput => !Current.Disabled && base.HandleNonPositionalInput;
-
- public override bool HandlePositionalInput => !Current.Disabled && base.HandlePositionalInput;
-
- public override bool PropagatePositionalInputSubTree => !Current.Disabled && base.PropagatePositionalInputSubTree;
-
- public DirectRulesetSelector()
- {
- TabContainer.Masking = false;
- TabContainer.Spacing = new Vector2(10, 0);
- AutoSizeAxes = Axes.Both;
- }
-
- 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);
-
- protected override TabFillFlowContainer CreateTabFlow() => new TabFillFlowContainer
- {
- Direction = FillDirection.Horizontal,
- AutoSizeAxes = Axes.Both,
- };
-
- private class DirectRulesetTabItem : TabItem
- {
- private readonly ConstrainedIconContainer iconContainer;
-
- public DirectRulesetTabItem(RulesetInfo value)
- : base(value)
- {
- AutoSizeAxes = Axes.Both;
-
- Children = new Drawable[]
- {
- iconContainer = new ConstrainedIconContainer
- {
- Icon = value.CreateInstance().CreateIcon(),
- Size = new Vector2(32),
- },
- new HoverClickSounds()
- };
- }
-
- protected override void LoadComplete()
- {
- base.LoadComplete();
-
- updateState();
- }
-
- protected override bool OnHover(HoverEvent e)
- {
- base.OnHover(e);
- updateState();
- return true;
- }
-
- protected override void OnHoverLost(HoverLostEvent e)
- {
- base.OnHoverLost(e);
- updateState();
- }
-
- protected override void OnActivated() => updateState();
-
- protected override void OnDeactivated() => updateState();
-
- private void updateState() => iconContainer.FadeColour(IsHovered || Active.Value ? Color4.White : Color4.Gray, 120, Easing.InQuad);
- }
- }
-}
diff --git a/osu.Game/Overlays/Direct/FilterControl.cs b/osu.Game/Overlays/Direct/FilterControl.cs
deleted file mode 100644
index 4ab5544550..0000000000
--- a/osu.Game/Overlays/Direct/FilterControl.cs
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
-// See the LICENCE file in the repository root for full licence text.
-
-using osu.Framework.Allocation;
-using osu.Framework.Bindables;
-using osu.Framework.Extensions.Color4Extensions;
-using osu.Framework.Graphics;
-using osu.Game.Graphics;
-using osu.Game.Overlays.BeatmapListing;
-using osu.Game.Overlays.SearchableList;
-using osu.Game.Rulesets;
-using osuTK.Graphics;
-
-namespace osu.Game.Overlays.Direct
-{
- public class FilterControl : SearchableListFilterControl
- {
- private DirectRulesetSelector rulesetSelector;
-
- protected override Color4 BackgroundColour => Color4Extensions.FromHex(@"384552");
- protected override DirectSortCriteria DefaultTab => DirectSortCriteria.Ranked;
- protected override SearchCategory DefaultCategory => SearchCategory.Leaderboard;
-
- protected override Drawable CreateSupplementaryControls() => rulesetSelector = new DirectRulesetSelector();
-
- public Bindable Ruleset => rulesetSelector.Current;
-
- [BackgroundDependencyLoader(true)]
- private void load(OsuColour colours, Bindable ruleset)
- {
- DisplayStyleControl.Dropdown.AccentColour = colours.BlueDark;
- rulesetSelector.Current.BindTo(ruleset);
- }
- }
-
- public enum DirectSortCriteria
- {
- Title,
- Artist,
- Difficulty,
- Ranked,
- Rating,
- Plays,
- Favourites,
- Relevance,
- }
-}
diff --git a/osu.Game/Overlays/Direct/Header.cs b/osu.Game/Overlays/Direct/Header.cs
deleted file mode 100644
index 5b3e394a18..0000000000
--- a/osu.Game/Overlays/Direct/Header.cs
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
-// See the LICENCE file in the repository root for full licence text.
-
-using System.ComponentModel;
-using osu.Framework.Extensions.Color4Extensions;
-using osuTK.Graphics;
-using osu.Framework.Graphics;
-using osu.Framework.Graphics.Sprites;
-using osu.Game.Graphics;
-using osu.Game.Graphics.Sprites;
-using osu.Game.Overlays.SearchableList;
-
-namespace osu.Game.Overlays.Direct
-{
- public class Header : SearchableListHeader
- {
- protected override Color4 BackgroundColour => Color4Extensions.FromHex(@"252f3a");
-
- protected override DirectTab DefaultTab => DirectTab.Search;
- protected override Drawable CreateHeaderText() => new OsuSpriteText { Text = @"osu!direct", Font = OsuFont.GetFont(size: 25) };
- protected override IconUsage Icon => OsuIcon.ChevronDownCircle;
-
- public Header()
- {
- Tabs.Current.Value = DirectTab.NewestMaps;
- Tabs.Current.TriggerChange();
- }
- }
-
- public enum DirectTab
- {
- Search,
-
- [Description("Newest Maps")]
- NewestMaps = DirectSortCriteria.Ranked,
-
- [Description("Top Rated")]
- TopRated = DirectSortCriteria.Rating,
-
- [Description("Most Played")]
- MostPlayed = DirectSortCriteria.Plays,
- }
-}
diff --git a/osu.Game/Overlays/DirectOverlay.cs b/osu.Game/Overlays/DirectOverlay.cs
deleted file mode 100644
index 5ed39af0dc..0000000000
--- a/osu.Game/Overlays/DirectOverlay.cs
+++ /dev/null
@@ -1,299 +0,0 @@
-// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
-// See the LICENCE file in the repository root for full licence text.
-
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading.Tasks;
-using Humanizer;
-using osu.Framework.Allocation;
-using osu.Framework.Bindables;
-using osu.Framework.Extensions.Color4Extensions;
-using osu.Framework.Graphics;
-using osu.Framework.Graphics.Containers;
-using osu.Framework.Threading;
-using osu.Game.Audio;
-using osu.Game.Beatmaps;
-using osu.Game.Graphics;
-using osu.Game.Graphics.Sprites;
-using osu.Game.Online.API.Requests;
-using osu.Game.Overlays.BeatmapListing;
-using osu.Game.Overlays.Direct;
-using osu.Game.Overlays.SearchableList;
-using osu.Game.Rulesets;
-using osuTK;
-using osuTK.Graphics;
-
-namespace osu.Game.Overlays
-{
- public class DirectOverlay : SearchableListOverlay
- {
- private const float panel_padding = 10f;
-
- [Resolved]
- private RulesetStore rulesets { get; set; }
-
- private readonly FillFlowContainer resultCountsContainer;
- private readonly OsuSpriteText resultCountsText;
- private FillFlowContainer panels;
-
- protected override Color4 BackgroundColour => Color4Extensions.FromHex(@"485e74");
- protected override Color4 TrianglesColourLight => Color4Extensions.FromHex(@"465b71");
- protected override Color4 TrianglesColourDark => Color4Extensions.FromHex(@"3f5265");
-
- protected override SearchableListHeader CreateHeader() => new Header();
- protected override SearchableListFilterControl CreateFilterControl() => new FilterControl();
-
- private IEnumerable beatmapSets;
-
- public IEnumerable BeatmapSets
- {
- get => beatmapSets;
- set
- {
- if (ReferenceEquals(beatmapSets, value)) return;
-
- beatmapSets = value?.ToList();
-
- if (beatmapSets == null) return;
-
- var artists = new List();
- var songs = new List();
- var tags = new List();
-
- foreach (var s in beatmapSets)
- {
- artists.Add(s.Metadata.Artist);
- songs.Add(s.Metadata.Title);
- tags.AddRange(s.Metadata.Tags.Split(' '));
- }
-
- ResultAmounts = new ResultCounts(distinctCount(artists), distinctCount(songs), distinctCount(tags));
- }
- }
-
- private ResultCounts resultAmounts;
-
- public ResultCounts ResultAmounts
- {
- get => resultAmounts;
- set
- {
- if (value == ResultAmounts) return;
-
- resultAmounts = value;
-
- updateResultCounts();
- }
- }
-
- public DirectOverlay()
- : base(OverlayColourScheme.Blue)
- {
- ScrollFlow.Children = new Drawable[]
- {
- resultCountsContainer = new FillFlowContainer
- {
- AutoSizeAxes = Axes.Both,
- Direction = FillDirection.Horizontal,
- Margin = new MarginPadding { Top = 5 },
- Children = new Drawable[]
- {
- new OsuSpriteText
- {
- Text = "Found ",
- Font = OsuFont.GetFont(size: 15)
- },
- resultCountsText = new OsuSpriteText
- {
- Font = OsuFont.GetFont(size: 15, weight: FontWeight.Bold)
- },
- }
- },
- };
-
- Filter.Search.Current.ValueChanged += text =>
- {
- if (!string.IsNullOrEmpty(text.NewValue))
- {
- Header.Tabs.Current.Value = DirectTab.Search;
-
- if (Filter.Tabs.Current.Value == DirectSortCriteria.Ranked)
- Filter.Tabs.Current.Value = DirectSortCriteria.Relevance;
- }
- else
- {
- Header.Tabs.Current.Value = DirectTab.NewestMaps;
-
- if (Filter.Tabs.Current.Value == DirectSortCriteria.Relevance)
- Filter.Tabs.Current.Value = DirectSortCriteria.Ranked;
- }
- };
- ((FilterControl)Filter).Ruleset.ValueChanged += _ => queueUpdateSearch();
- Filter.DisplayStyleControl.DisplayStyle.ValueChanged += style => recreatePanels(style.NewValue);
- Filter.DisplayStyleControl.Dropdown.Current.ValueChanged += _ => queueUpdateSearch();
-
- Header.Tabs.Current.ValueChanged += tab =>
- {
- if (tab.NewValue != DirectTab.Search)
- {
- currentQuery.Value = string.Empty;
- Filter.Tabs.Current.Value = (DirectSortCriteria)Header.Tabs.Current.Value;
- queueUpdateSearch();
- }
- };
-
- currentQuery.ValueChanged += text => queueUpdateSearch(!string.IsNullOrEmpty(text.NewValue));
-
- currentQuery.BindTo(Filter.Search.Current);
-
- Filter.Tabs.Current.ValueChanged += tab =>
- {
- if (Header.Tabs.Current.Value != DirectTab.Search && tab.NewValue != (DirectSortCriteria)Header.Tabs.Current.Value)
- Header.Tabs.Current.Value = DirectTab.Search;
-
- queueUpdateSearch();
- };
-
- updateResultCounts();
- }
-
- [BackgroundDependencyLoader]
- private void load(OsuColour colours)
- {
- resultCountsContainer.Colour = colours.Yellow;
- }
-
- private void updateResultCounts()
- {
- resultCountsContainer.FadeTo(ResultAmounts == null ? 0f : 1f, 200, Easing.OutQuint);
- if (ResultAmounts == null) return;
-
- resultCountsText.Text = "Artist".ToQuantity(ResultAmounts.Artists) + ", " +
- "Song".ToQuantity(ResultAmounts.Songs) + ", " +
- "Tag".ToQuantity(ResultAmounts.Tags);
- }
-
- private void recreatePanels(PanelDisplayStyle displayStyle)
- {
- if (panels != null)
- {
- panels.FadeOut(200);
- panels.Expire();
- panels = null;
- }
-
- if (BeatmapSets == null) return;
-
- var newPanels = new FillFlowContainer
- {
- RelativeSizeAxes = Axes.X,
- AutoSizeAxes = Axes.Y,
- Spacing = new Vector2(panel_padding),
- Margin = new MarginPadding { Top = 10 },
- ChildrenEnumerable = BeatmapSets.Select(b =>
- {
- switch (displayStyle)
- {
- case PanelDisplayStyle.Grid:
- return new DirectGridPanel(b)
- {
- Anchor = Anchor.TopCentre,
- Origin = Anchor.TopCentre,
- };
-
- default:
- return new DirectListPanel(b);
- }
- })
- };
-
- LoadComponentAsync(newPanels, p =>
- {
- if (panels != null) ScrollFlow.Remove(panels);
- ScrollFlow.Add(panels = newPanels);
- });
- }
-
- protected override void PopIn()
- {
- base.PopIn();
-
- // Queries are allowed to be run only on the first pop-in
- if (getSetsRequest == null)
- queueUpdateSearch();
- }
-
- private SearchBeatmapSetsRequest getSetsRequest;
-
- private readonly Bindable currentQuery = new Bindable(string.Empty);
-
- private ScheduledDelegate queryChangedDebounce;
-
- [Resolved]
- private PreviewTrackManager previewTrackManager { get; set; }
-
- private void queueUpdateSearch(bool queryTextChanged = false)
- {
- BeatmapSets = null;
- ResultAmounts = null;
-
- getSetsRequest?.Cancel();
-
- queryChangedDebounce?.Cancel();
- queryChangedDebounce = Scheduler.AddDelayed(updateSearch, queryTextChanged ? 500 : 100);
- }
-
- private void updateSearch()
- {
- if (!IsLoaded)
- return;
-
- if (State.Value == Visibility.Hidden)
- return;
-
- if (API == null)
- return;
-
- previewTrackManager.StopAnyPlaying(this);
-
- getSetsRequest = new SearchBeatmapSetsRequest(currentQuery.Value, ((FilterControl)Filter).Ruleset.Value)
- {
- SearchCategory = Filter.DisplayStyleControl.Dropdown.Current.Value,
- SortCriteria = Filter.Tabs.Current.Value
- };
-
- getSetsRequest.Success += response =>
- {
- Task.Run(() =>
- {
- var sets = response.BeatmapSets.Select(r => r.ToBeatmapSet(rulesets)).ToList();
-
- // may not need scheduling; loads async internally.
- Schedule(() =>
- {
- BeatmapSets = sets;
- recreatePanels(Filter.DisplayStyleControl.DisplayStyle.Value);
- });
- });
- };
-
- API.Queue(getSetsRequest);
- }
-
- private int distinctCount(List list) => list.Distinct().ToArray().Length;
-
- public class ResultCounts
- {
- public readonly int Artists;
- public readonly int Songs;
- public readonly int Tags;
-
- public ResultCounts(int artists, int songs, int tags)
- {
- Artists = artists;
- Songs = songs;
- Tags = tags;
- }
- }
- }
-}
diff --git a/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs b/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs
index fcd12e2b54..191f3c908a 100644
--- a/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs
+++ b/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs
@@ -7,7 +7,7 @@ using osu.Framework.Graphics;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests;
using osu.Game.Online.API.Requests.Responses;
-using osu.Game.Overlays.Direct;
+using osu.Game.Overlays.BeatmapListing.Panels;
using osu.Game.Users;
using osuTK;
@@ -33,7 +33,7 @@ namespace osu.Game.Overlays.Profile.Sections.Beatmaps
protected override Drawable CreateDrawableItem(APIBeatmapSet model) => !model.OnlineBeatmapSetID.HasValue
? null
- : new DirectGridPanel(model.ToBeatmapSet(Rulesets))
+ : new GridBeatmapPanel(model.ToBeatmapSet(Rulesets))
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
diff --git a/osu.Game/Overlays/Rankings/SpotlightsLayout.cs b/osu.Game/Overlays/Rankings/SpotlightsLayout.cs
index 6f06eecd6e..917509e842 100644
--- a/osu.Game/Overlays/Rankings/SpotlightsLayout.cs
+++ b/osu.Game/Overlays/Rankings/SpotlightsLayout.cs
@@ -12,10 +12,10 @@ using osu.Game.Online.API;
using osu.Game.Online.API.Requests;
using osu.Game.Overlays.Rankings.Tables;
using System.Linq;
-using osu.Game.Overlays.Direct;
using System.Threading;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.UserInterface;
+using osu.Game.Overlays.BeatmapListing.Panels;
namespace osu.Game.Overlays.Rankings
{
@@ -140,7 +140,7 @@ namespace osu.Game.Overlays.Rankings
AutoSizeAxes = Axes.Y,
RelativeSizeAxes = Axes.X,
Spacing = new Vector2(10),
- Children = response.BeatmapSets.Select(b => new DirectGridPanel(b.ToBeatmapSet(rulesets))
+ Children = response.BeatmapSets.Select(b => new GridBeatmapPanel(b.ToBeatmapSet(rulesets))
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
diff --git a/osu.Game/Overlays/SocialOverlay.cs b/osu.Game/Overlays/SocialOverlay.cs
index 02f7c9b0d3..9548573b4f 100644
--- a/osu.Game/Overlays/SocialOverlay.cs
+++ b/osu.Game/Overlays/SocialOverlay.cs
@@ -239,10 +239,4 @@ namespace osu.Game.Overlays
}
}
}
-
- public enum SortDirection
- {
- Ascending,
- Descending
- }
}
diff --git a/osu.Game/Overlays/SortDirection.cs b/osu.Game/Overlays/SortDirection.cs
new file mode 100644
index 0000000000..3af9614972
--- /dev/null
+++ b/osu.Game/Overlays/SortDirection.cs
@@ -0,0 +1,11 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+namespace osu.Game.Overlays
+{
+ public enum SortDirection
+ {
+ Ascending,
+ Descending
+ }
+}
diff --git a/osu.Game/Overlays/Toolbar/Toolbar.cs b/osu.Game/Overlays/Toolbar/Toolbar.cs
index 897587d198..227347112c 100644
--- a/osu.Game/Overlays/Toolbar/Toolbar.cs
+++ b/osu.Game/Overlays/Toolbar/Toolbar.cs
@@ -71,7 +71,7 @@ namespace osu.Game.Overlays.Toolbar
{
new ToolbarChangelogButton(),
new ToolbarRankingsButton(),
- new ToolbarDirectButton(),
+ new ToolbarBeatmapListingButton(),
new ToolbarChatButton(),
new ToolbarSocialButton(),
new ToolbarMusicButton(),
diff --git a/osu.Game/Overlays/Toolbar/ToolbarDirectButton.cs b/osu.Game/Overlays/Toolbar/ToolbarBeatmapListingButton.cs
similarity index 63%
rename from osu.Game/Overlays/Toolbar/ToolbarDirectButton.cs
rename to osu.Game/Overlays/Toolbar/ToolbarBeatmapListingButton.cs
index 1d07a3ae70..eecb368ee9 100644
--- a/osu.Game/Overlays/Toolbar/ToolbarDirectButton.cs
+++ b/osu.Game/Overlays/Toolbar/ToolbarBeatmapListingButton.cs
@@ -6,17 +6,17 @@ using osu.Game.Graphics;
namespace osu.Game.Overlays.Toolbar
{
- public class ToolbarDirectButton : ToolbarOverlayToggleButton
+ public class ToolbarBeatmapListingButton : ToolbarOverlayToggleButton
{
- public ToolbarDirectButton()
+ public ToolbarBeatmapListingButton()
{
SetIcon(OsuIcon.ChevronDownCircle);
}
[BackgroundDependencyLoader(true)]
- private void load(DirectOverlay direct)
+ private void load(BeatmapListingOverlay beatmapListing)
{
- StateContainer = direct;
+ StateContainer = beatmapListing;
}
}
}
diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs
index e847dcec40..0047142cbd 100644
--- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs
+++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs
@@ -4,7 +4,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
-using System.Reflection;
using JetBrains.Annotations;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
@@ -180,11 +179,6 @@ namespace osu.Game.Rulesets.Objects.Drawables
private void apply(HitObject hitObject)
{
-#pragma warning disable 618 // can be removed 20200417
- if (GetType().GetMethod(nameof(AddNested), BindingFlags.NonPublic | BindingFlags.Instance)?.DeclaringType != typeof(DrawableHitObject))
- return;
-#pragma warning restore 618
-
if (nestedHitObjects.IsValueCreated)
{
nestedHitObjects.Value.Clear();
@@ -195,7 +189,11 @@ namespace osu.Game.Rulesets.Objects.Drawables
{
var drawableNested = CreateNestedHitObject(h) ?? throw new InvalidOperationException($"{nameof(CreateNestedHitObject)} returned null for {h.GetType().ReadableName()}.");
- addNested(drawableNested);
+ drawableNested.OnNewResult += (d, r) => OnNewResult?.Invoke(d, r);
+ drawableNested.OnRevertResult += (d, r) => OnRevertResult?.Invoke(d, r);
+ drawableNested.ApplyCustomUpdateState += (d, j) => ApplyCustomUpdateState?.Invoke(d, j);
+
+ nestedHitObjects.Value.Add(drawableNested);
AddNestedHitObject(drawableNested);
}
}
@@ -208,13 +206,6 @@ namespace osu.Game.Rulesets.Objects.Drawables
{
}
- ///
- /// Adds a nested . This should not be used except for legacy nested usages.
- ///
- ///
- [Obsolete("Use AddNestedHitObject() / ClearNestedHitObjects() / CreateNestedHitObject() instead.")] // can be removed 20200417
- protected virtual void AddNested(DrawableHitObject h) => addNested(h);
-
///
/// Invoked by the base to remove all previously-added nested s.
///
@@ -229,17 +220,6 @@ namespace osu.Game.Rulesets.Objects.Drawables
/// The drawable representation for .
protected virtual DrawableHitObject CreateNestedHitObject(HitObject hitObject) => null;
- private void addNested(DrawableHitObject hitObject)
- {
- // Todo: Exists for legacy purposes, can be removed 20200417
-
- hitObject.OnNewResult += (d, r) => OnNewResult?.Invoke(d, r);
- hitObject.OnRevertResult += (d, r) => OnRevertResult?.Invoke(d, r);
- hitObject.ApplyCustomUpdateState += (d, j) => ApplyCustomUpdateState?.Invoke(d, j);
-
- nestedHitObjects.Value.Add(hitObject);
- }
-
#region State / Transform Management
///
diff --git a/osu.Game/Rulesets/RulesetStore.cs b/osu.Game/Rulesets/RulesetStore.cs
index a389d4ff75..543134cfb4 100644
--- a/osu.Game/Rulesets/RulesetStore.cs
+++ b/osu.Game/Rulesets/RulesetStore.cs
@@ -7,6 +7,7 @@ using System.IO;
using System.Linq;
using System.Reflection;
using osu.Framework.Logging;
+using osu.Framework.Platform;
using osu.Game.Database;
namespace osu.Game.Rulesets
@@ -17,16 +18,24 @@ namespace osu.Game.Rulesets
private readonly Dictionary loadedAssemblies = new Dictionary();
- public RulesetStore(IDatabaseContextFactory factory)
+ private readonly Storage rulesetStorage;
+
+ public RulesetStore(IDatabaseContextFactory factory, Storage storage = null)
: base(factory)
{
+ rulesetStorage = storage?.GetStorageForDirectory("rulesets");
+
// On android in release configuration assemblies are loaded from the apk directly into memory.
// We cannot read assemblies from cwd, so should check loaded assemblies instead.
loadFromAppDomain();
loadFromDisk();
- addMissingRulesets();
- AppDomain.CurrentDomain.AssemblyResolve += resolveRulesetAssembly;
+ // the event handler contains code for resolving dependency on the game assembly for rulesets located outside the base game directory.
+ // It needs to be attached to the assembly lookup event before the actual call to loadUserRulesets() else rulesets located out of the base game directory will fail
+ // to load as unable to locate the game core assembly.
+ AppDomain.CurrentDomain.AssemblyResolve += resolveRulesetDependencyAssembly;
+ loadUserRulesets();
+ addMissingRulesets();
}
///
@@ -48,7 +57,21 @@ namespace osu.Game.Rulesets
///
public IEnumerable AvailableRulesets { get; private set; }
- private Assembly resolveRulesetAssembly(object sender, ResolveEventArgs args) => loadedAssemblies.Keys.FirstOrDefault(a => a.FullName == args.Name);
+ private Assembly resolveRulesetDependencyAssembly(object sender, ResolveEventArgs args)
+ {
+ var asm = new AssemblyName(args.Name);
+
+ // the requesting assembly may be located out of the executable's base directory, thus requiring manual resolving of its dependencies.
+ // this attempts resolving the ruleset dependencies on game core and framework assemblies by returning assemblies with the same assembly name
+ // already loaded in the AppDomain.
+ foreach (var curAsm in AppDomain.CurrentDomain.GetAssemblies())
+ {
+ if (asm.Name.Equals(curAsm.GetName().Name, StringComparison.Ordinal))
+ return curAsm;
+ }
+
+ return loadedAssemblies.Keys.FirstOrDefault(a => a.FullName == asm.FullName);
+ }
private void addMissingRulesets()
{
@@ -120,6 +143,16 @@ namespace osu.Game.Rulesets
}
}
+ private void loadUserRulesets()
+ {
+ if (rulesetStorage == null) return;
+
+ var rulesets = rulesetStorage.GetFiles(".", $"{ruleset_library_prefix}.*.dll");
+
+ foreach (var ruleset in rulesets.Where(f => !f.Contains("Tests")))
+ loadRulesetFromFile(rulesetStorage.GetFullPath(ruleset));
+ }
+
private void loadFromDisk()
{
try
@@ -175,7 +208,7 @@ namespace osu.Game.Rulesets
protected virtual void Dispose(bool disposing)
{
- AppDomain.CurrentDomain.AssemblyResolve -= resolveRulesetAssembly;
+ AppDomain.CurrentDomain.AssemblyResolve -= resolveRulesetDependencyAssembly;
}
}
}
diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs
index 9a1f450dc6..54e4af94a4 100644
--- a/osu.Game/Screens/Edit/Editor.cs
+++ b/osu.Game/Screens/Edit/Editor.cs
@@ -22,6 +22,7 @@ using osu.Game.Screens.Edit.Design;
using osuTK.Input;
using System.Collections.Generic;
using osu.Framework;
+using osu.Framework.Input;
using osu.Framework.Input.Bindings;
using osu.Framework.Logging;
using osu.Game.Beatmaps;
@@ -37,7 +38,7 @@ using osu.Game.Users;
namespace osu.Game.Screens.Edit
{
[Cached(typeof(IBeatSnapProvider))]
- public class Editor : ScreenWithBeatmapBackground, IKeyBindingHandler, IBeatSnapProvider
+ public class Editor : ScreenWithBeatmapBackground, IKeyBindingHandler, IKeyBindingHandler, IBeatSnapProvider
{
public override float BackgroundParallaxAmount => 0.1f;
@@ -157,8 +158,8 @@ namespace osu.Game.Screens.Edit
{
Items = new[]
{
- undoMenuItem = new EditorMenuItem("Undo", MenuItemType.Standard, undo),
- redoMenuItem = new EditorMenuItem("Redo", MenuItemType.Standard, redo)
+ undoMenuItem = new EditorMenuItem("Undo", MenuItemType.Standard, Undo),
+ redoMenuItem = new EditorMenuItem("Redo", MenuItemType.Standard, Redo)
}
}
}
@@ -230,6 +231,30 @@ namespace osu.Game.Screens.Edit
clock.ProcessFrame();
}
+ public bool OnPressed(PlatformAction action)
+ {
+ switch (action.ActionType)
+ {
+ case PlatformActionType.Undo:
+ Undo();
+ return true;
+
+ case PlatformActionType.Redo:
+ Redo();
+ return true;
+
+ case PlatformActionType.Save:
+ saveBeatmap();
+ return true;
+ }
+
+ return false;
+ }
+
+ public void OnReleased(PlatformAction action)
+ {
+ }
+
protected override bool OnKeyDown(KeyDownEvent e)
{
switch (e.Key)
@@ -241,28 +266,6 @@ namespace osu.Game.Screens.Edit
case Key.Right:
seek(e, 1);
return true;
-
- case Key.S:
- if (e.ControlPressed)
- {
- saveBeatmap();
- return true;
- }
-
- break;
-
- case Key.Z:
- if (e.ControlPressed)
- {
- if (e.ShiftPressed)
- redo();
- else
- undo();
-
- return true;
- }
-
- break;
}
return base.OnKeyDown(e);
@@ -326,9 +329,9 @@ namespace osu.Game.Screens.Edit
return base.OnExiting(next);
}
- private void undo() => changeHandler.RestoreState(-1);
+ protected void Undo() => changeHandler.RestoreState(-1);
- private void redo() => changeHandler.RestoreState(1);
+ protected void Redo() => changeHandler.RestoreState(1);
private void resetTrack(bool seekToStart = false)
{
diff --git a/osu.Game/Screens/Menu/ButtonSystem.cs b/osu.Game/Screens/Menu/ButtonSystem.cs
index fe538728e3..30e5e9702e 100644
--- a/osu.Game/Screens/Menu/ButtonSystem.cs
+++ b/osu.Game/Screens/Menu/ButtonSystem.cs
@@ -39,7 +39,7 @@ namespace osu.Game.Screens.Menu
public Action OnEdit;
public Action OnExit;
- public Action OnDirect;
+ public Action OnBeatmapListing;
public Action OnSolo;
public Action OnSettings;
public Action OnMulti;
@@ -130,7 +130,7 @@ namespace osu.Game.Screens.Menu
buttonsTopLevel.Add(new Button(@"play", @"button-play-select", OsuIcon.Logo, new Color4(102, 68, 204, 255), () => State = ButtonSystemState.Play, WEDGE_WIDTH, Key.P));
buttonsTopLevel.Add(new Button(@"osu!editor", @"button-generic-select", OsuIcon.EditCircle, new Color4(238, 170, 0, 255), () => OnEdit?.Invoke(), 0, Key.E));
- buttonsTopLevel.Add(new Button(@"osu!direct", @"button-direct-select", OsuIcon.ChevronDownCircle, new Color4(165, 204, 0, 255), () => OnDirect?.Invoke(), 0, Key.D));
+ buttonsTopLevel.Add(new Button(@"osu!direct", @"button-direct-select", OsuIcon.ChevronDownCircle, new Color4(165, 204, 0, 255), () => OnBeatmapListing?.Invoke(), 0, Key.D));
if (host.CanExit)
buttonsTopLevel.Add(new Button(@"exit", string.Empty, OsuIcon.CrossCircle, new Color4(238, 51, 153, 255), () => OnExit?.Invoke(), 0, Key.Q));
diff --git a/osu.Game/Screens/Menu/MainMenu.cs b/osu.Game/Screens/Menu/MainMenu.cs
index 174eadfe26..0589e4d12b 100644
--- a/osu.Game/Screens/Menu/MainMenu.cs
+++ b/osu.Game/Screens/Menu/MainMenu.cs
@@ -72,7 +72,7 @@ namespace osu.Game.Screens.Menu
private SongTicker songTicker;
[BackgroundDependencyLoader(true)]
- private void load(DirectOverlay direct, SettingsOverlay settings, RankingsOverlay rankings, OsuConfigManager config, SessionStatics statics)
+ private void load(BeatmapListingOverlay beatmapListing, SettingsOverlay settings, RankingsOverlay rankings, OsuConfigManager config, SessionStatics statics)
{
holdDelay = config.GetBindable(OsuSetting.UIHoldActivationDelay);
loginDisplayed = statics.GetBindable(Static.LoginOverlayDisplayed);
@@ -133,7 +133,7 @@ namespace osu.Game.Screens.Menu
};
buttons.OnSettings = () => settings?.ToggleVisibility();
- buttons.OnDirect = () => direct?.ToggleVisibility();
+ buttons.OnBeatmapListing = () => beatmapListing?.ToggleVisibility();
buttons.OnChart = () => rankings?.ShowSpotlights();
LoadComponentAsync(background = new BackgroundScreenDefault());
diff --git a/osu.Game/Screens/Multi/DrawableRoomPlaylistItem.cs b/osu.Game/Screens/Multi/DrawableRoomPlaylistItem.cs
index d7dcca9809..c024304856 100644
--- a/osu.Game/Screens/Multi/DrawableRoomPlaylistItem.cs
+++ b/osu.Game/Screens/Multi/DrawableRoomPlaylistItem.cs
@@ -21,7 +21,7 @@ using osu.Game.Graphics.UserInterface;
using osu.Game.Online;
using osu.Game.Online.Chat;
using osu.Game.Online.Multiplayer;
-using osu.Game.Overlays.Direct;
+using osu.Game.Overlays.BeatmapListing.Panels;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Mods;
using osu.Game.Screens.Play.HUD;
@@ -210,7 +210,7 @@ namespace osu.Game.Screens.Multi
return true;
}
- private class PlaylistDownloadButton : PanelDownloadButton
+ private class PlaylistDownloadButton : BeatmapPanelDownloadButton
{
public PlaylistDownloadButton(BeatmapSetInfo beatmapSet)
: base(beatmapSet)
diff --git a/osu.Game/Skinning/LegacyManiaSkinDecoder.cs b/osu.Game/Skinning/LegacyManiaSkinDecoder.cs
index 2db902c182..a988bd589f 100644
--- a/osu.Game/Skinning/LegacyManiaSkinDecoder.cs
+++ b/osu.Game/Skinning/LegacyManiaSkinDecoder.cs
@@ -74,7 +74,7 @@ namespace osu.Game.Skinning
switch (pair.Key)
{
case "ColumnLineWidth":
- parseArrayValue(pair.Value, currentConfig.ColumnLineWidth);
+ parseArrayValue(pair.Value, currentConfig.ColumnLineWidth, false);
break;
case "ColumnSpacing":
@@ -124,7 +124,7 @@ namespace osu.Game.Skinning
pendingLines.Clear();
}
- private void parseArrayValue(string value, float[] output)
+ private void parseArrayValue(string value, float[] output, bool applyScaleFactor = true)
{
string[] values = value.Split(',');
@@ -133,7 +133,7 @@ namespace osu.Game.Skinning
if (i >= output.Length)
break;
- output[i] = float.Parse(values[i], CultureInfo.InvariantCulture) * LegacyManiaSkinConfiguration.POSITION_SCALE_FACTOR;
+ output[i] = float.Parse(values[i], CultureInfo.InvariantCulture) * (applyScaleFactor ? LegacyManiaSkinConfiguration.POSITION_SCALE_FACTOR : 1);
}
}
}
diff --git a/osu.Game/Skinning/LegacySkin.cs b/osu.Game/Skinning/LegacySkin.cs
index 91f970d19f..003fa24d5b 100644
--- a/osu.Game/Skinning/LegacySkin.cs
+++ b/osu.Game/Skinning/LegacySkin.cs
@@ -249,6 +249,14 @@ namespace osu.Game.Skinning
case LegacyManiaSkinConfigurationLookups.RightStageImage:
return SkinUtils.As(getManiaImage(existing, "StageRight"));
+
+ case LegacyManiaSkinConfigurationLookups.LeftLineWidth:
+ Debug.Assert(maniaLookup.TargetColumn != null);
+ return SkinUtils.As(new Bindable(existing.ColumnLineWidth[maniaLookup.TargetColumn.Value]));
+
+ case LegacyManiaSkinConfigurationLookups.RightLineWidth:
+ Debug.Assert(maniaLookup.TargetColumn != null);
+ return SkinUtils.As(new Bindable(existing.ColumnLineWidth[maniaLookup.TargetColumn.Value + 1]));
}
return null;
diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj
index 35ee0864e1..9c17c453a6 100644
--- a/osu.Game/osu.Game.csproj
+++ b/osu.Game/osu.Game.csproj
@@ -23,7 +23,7 @@
-
+
diff --git a/osu.iOS.props b/osu.iOS.props
index 0200fca9a3..07ea4b9c2a 100644
--- a/osu.iOS.props
+++ b/osu.iOS.props
@@ -70,7 +70,7 @@
-
+
@@ -80,7 +80,7 @@
-
+