diff --git a/README.md b/README.md
index 2c330e403c..52fc29cb98 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,5 @@
-
+
# osu!
@@ -100,7 +100,7 @@ Before starting, please make sure you are familiar with the [development and tes
Note that while we already have certain standards in place, nothing is set in stone. If you have an issue with the way code is structured; with any libraries we are using; with any processes involved with contributing, *please* bring it up. We welcome all feedback so we can make contributing to this project as pain-free as possible.
-For those interested, we love to reward quality contributions via bounties, paid out via paypal or osu! supporter tags. Don't hesitate to [request a bounty](https://docs.google.com/forms/d/e/1FAIpQLSet_8iFAgPMG526pBZ2Kic6HSh7XPM3fE8xPcnWNkMzINDdYg/viewform) for your work on this project.
+For those interested, we love to reward quality contributions via [bounties](https://docs.google.com/spreadsheets/d/1jNXfj_S3Pb5PErA-czDdC9DUu4IgUbe1Lt8E7CYUJuE/view?&rm=minimal#gid=523803337), paid out via paypal or osu! supporter tags. Don't hesitate to [request a bounty](https://docs.google.com/forms/d/e/1FAIpQLSet_8iFAgPMG526pBZ2Kic6HSh7XPM3fE8xPcnWNkMzINDdYg/viewform) for your work on this project.
## Licence
diff --git a/assets/lazer.png b/assets/lazer.png
index 075a8e7184..1e40e844cc 100644
Binary files a/assets/lazer.png and b/assets/lazer.png differ
diff --git a/osu.Android.props b/osu.Android.props
index 5ee0573c58..6744590f0d 100644
--- a/osu.Android.props
+++ b/osu.Android.props
@@ -63,6 +63,6 @@
-
+
diff --git a/osu.Android/Resources/drawable/lazer.png b/osu.Android/Resources/drawable/lazer.png
index 075a8e7184..fc7aa8a092 100644
Binary files a/osu.Android/Resources/drawable/lazer.png and b/osu.Android/Resources/drawable/lazer.png differ
diff --git a/osu.Desktop/Program.cs b/osu.Desktop/Program.cs
index cb488fea52..141b2cdbbc 100644
--- a/osu.Desktop/Program.cs
+++ b/osu.Desktop/Program.cs
@@ -29,29 +29,36 @@ namespace osu.Desktop
if (!host.IsPrimaryInstance)
{
- var importer = new ArchiveImportIPCChannel(host);
- // Restore the cwd so relative paths given at the command line work correctly
- Directory.SetCurrentDirectory(cwd);
-
- foreach (var file in args)
+ if (args.Length > 0 && args[0].Contains('.')) // easy way to check for a file import in args
{
- Console.WriteLine(@"Importing {0}", file);
- if (!importer.ImportAsync(Path.GetFullPath(file)).Wait(3000))
- throw new TimeoutException(@"IPC took too long to send");
+ var importer = new ArchiveImportIPCChannel(host);
+ // Restore the cwd so relative paths given at the command line work correctly
+ Directory.SetCurrentDirectory(cwd);
+
+ foreach (var file in args)
+ {
+ Console.WriteLine(@"Importing {0}", file);
+ if (!importer.ImportAsync(Path.GetFullPath(file)).Wait(3000))
+ throw new TimeoutException(@"IPC took too long to send");
+ }
+
+ return 0;
}
+
+ // we want to allow multiple instances to be started when in debug.
+ if (!DebugUtils.IsDebugBuild)
+ return 0;
}
- else
- {
- switch (args.FirstOrDefault() ?? string.Empty)
- {
- default:
- host.Run(new OsuGameDesktop(args));
- break;
- case "--tournament":
- host.Run(new TournamentGame());
- break;
- }
+ switch (args.FirstOrDefault() ?? string.Empty)
+ {
+ default:
+ host.Run(new OsuGameDesktop(args));
+ break;
+
+ case "--tournament":
+ host.Run(new TournamentGame());
+ break;
}
return 0;
diff --git a/osu.Desktop/lazer.ico b/osu.Desktop/lazer.ico
old mode 100644
new mode 100755
index 0c894dca41..a6aa8abb9f
Binary files a/osu.Desktop/lazer.ico and b/osu.Desktop/lazer.ico differ
diff --git a/osu.Game.Rulesets.Catch.Tests.iOS/Application.cs b/osu.Game.Rulesets.Catch.Tests.iOS/Application.cs
index 44817c1304..beca477943 100644
--- a/osu.Game.Rulesets.Catch.Tests.iOS/Application.cs
+++ b/osu.Game.Rulesets.Catch.Tests.iOS/Application.cs
@@ -9,7 +9,7 @@ namespace osu.Game.Rulesets.Catch.Tests.iOS
{
public static void Main(string[] args)
{
- UIApplication.Main(args, null, "AppDelegate");
+ UIApplication.Main(args, "GameUIApplication", "AppDelegate");
}
}
}
diff --git a/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj b/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj
index 265ecb7688..9acf47a67c 100644
--- a/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj
+++ b/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj
@@ -2,7 +2,7 @@
-
+
diff --git a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableCatchHitObject.cs b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableCatchHitObject.cs
index 5785d9a9ca..a1279e8443 100644
--- a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableCatchHitObject.cs
+++ b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableCatchHitObject.cs
@@ -3,12 +3,10 @@
using System;
using osuTK;
-using osuTK.Graphics;
using osu.Framework.Graphics;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Objects.Types;
using osu.Game.Rulesets.Scoring;
-using osu.Game.Skinning;
namespace osu.Game.Rulesets.Catch.Objects.Drawable
{
@@ -60,16 +58,11 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
ApplyResult(r => r.Type = CheckPosition.Invoke(HitObject) ? HitResult.Perfect : HitResult.Miss);
}
- protected override void SkinChanged(ISkinSource skin, bool allowFallback)
- {
- base.SkinChanged(skin, allowFallback);
-
- if (HitObject is IHasComboInformation combo)
- AccentColour = skin.GetValue(s => s.ComboColours.Count > 0 ? s.ComboColours[combo.ComboIndex % s.ComboColours.Count] : (Color4?)null) ?? Color4.White;
- }
+ protected override bool UseTransformStateManagement => false;
protected override void UpdateState(ArmedState state)
{
+ // TODO: update to use new state management.
using (BeginAbsoluteSequence(HitObject.StartTime - HitObject.TimePreempt))
this.FadeIn(200);
diff --git a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableDroplet.cs b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableDroplet.cs
index 9cabdc3dd9..059310d671 100644
--- a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableDroplet.cs
+++ b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableDroplet.cs
@@ -5,7 +5,6 @@ using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Game.Rulesets.Catch.Objects.Drawable.Pieces;
using osuTK;
-using osuTK.Graphics;
namespace osu.Game.Rulesets.Catch.Objects.Drawable
{
@@ -27,16 +26,8 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
private void load()
{
AddInternal(pulp = new Pulp { Size = Size });
- }
- public override Color4 AccentColour
- {
- get => base.AccentColour;
- set
- {
- base.AccentColour = value;
- pulp.AccentColour = AccentColour;
- }
+ AccentColour.BindValueChanged(colour => { pulp.AccentColour = colour.NewValue; }, true);
}
}
}
diff --git a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableFruit.cs b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableFruit.cs
index 77407def54..ce2daebbf1 100644
--- a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableFruit.cs
+++ b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableFruit.cs
@@ -41,7 +41,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
private void load()
{
// todo: this should come from the skin.
- AccentColour = colourForRepresentation(HitObject.VisualRepresentation);
+ AccentColour.Value = colourForRepresentation(HitObject.VisualRepresentation);
AddRangeInternal(new[]
{
@@ -53,7 +53,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
Hollow = !HitObject.HyperDash,
Type = EdgeEffectType.Glow,
Radius = 4 * radius_adjust,
- Colour = HitObject.HyperDash ? Color4.Red : AccentColour.Darken(1).Opacity(0.6f)
+ Colour = HitObject.HyperDash ? Color4.Red : AccentColour.Value.Darken(1).Opacity(0.6f)
},
Size = new Vector2(Height),
Anchor = Anchor.Centre,
@@ -65,7 +65,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
new Box
{
AlwaysPresent = true,
- Colour = AccentColour,
+ Colour = AccentColour.Value,
Alpha = 0,
RelativeSizeAxes = Axes.Both
}
@@ -115,32 +115,32 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
{
new Pulp
{
- AccentColour = AccentColour,
+ AccentColour = AccentColour.Value,
Size = new Vector2(small_pulp),
Y = -0.34f,
},
new Pulp
{
- AccentColour = AccentColour,
+ AccentColour = AccentColour.Value,
Size = new Vector2(large_pulp_4),
Position = positionAt(0, distance_from_centre_4),
},
new Pulp
{
- AccentColour = AccentColour,
+ AccentColour = AccentColour.Value,
Size = new Vector2(large_pulp_4),
Position = positionAt(90, distance_from_centre_4),
},
new Pulp
{
- AccentColour = AccentColour,
+ AccentColour = AccentColour.Value,
Size = new Vector2(large_pulp_4),
Position = positionAt(180, distance_from_centre_4),
},
new Pulp
{
Size = new Vector2(large_pulp_4),
- AccentColour = AccentColour,
+ AccentColour = AccentColour.Value,
Position = positionAt(270, distance_from_centre_4),
},
}
@@ -154,32 +154,32 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
{
new Pulp
{
- AccentColour = AccentColour,
+ AccentColour = AccentColour.Value,
Size = new Vector2(small_pulp),
Y = -0.3f,
},
new Pulp
{
- AccentColour = AccentColour,
+ AccentColour = AccentColour.Value,
Size = new Vector2(large_pulp_4),
Position = positionAt(45, distance_from_centre_4),
},
new Pulp
{
- AccentColour = AccentColour,
+ AccentColour = AccentColour.Value,
Size = new Vector2(large_pulp_4),
Position = positionAt(135, distance_from_centre_4),
},
new Pulp
{
- AccentColour = AccentColour,
+ AccentColour = AccentColour.Value,
Size = new Vector2(large_pulp_4),
Position = positionAt(225, distance_from_centre_4),
},
new Pulp
{
Size = new Vector2(large_pulp_4),
- AccentColour = AccentColour,
+ AccentColour = AccentColour.Value,
Position = positionAt(315, distance_from_centre_4),
},
}
@@ -193,26 +193,26 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
{
new Pulp
{
- AccentColour = AccentColour,
+ AccentColour = AccentColour.Value,
Size = new Vector2(small_pulp),
Y = -0.33f,
},
new Pulp
{
- AccentColour = AccentColour,
+ AccentColour = AccentColour.Value,
Size = new Vector2(large_pulp_3),
Position = positionAt(60, distance_from_centre_3),
},
new Pulp
{
- AccentColour = AccentColour,
+ AccentColour = AccentColour.Value,
Size = new Vector2(large_pulp_3),
Position = positionAt(180, distance_from_centre_3),
},
new Pulp
{
Size = new Vector2(large_pulp_3),
- AccentColour = AccentColour,
+ AccentColour = AccentColour.Value,
Position = positionAt(300, distance_from_centre_3),
},
}
@@ -226,26 +226,26 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
{
new Pulp
{
- AccentColour = AccentColour,
+ AccentColour = AccentColour.Value,
Size = new Vector2(small_pulp),
Y = -0.25f,
},
new Pulp
{
- AccentColour = AccentColour,
+ AccentColour = AccentColour.Value,
Size = new Vector2(large_pulp_3),
Position = positionAt(0, distance_from_centre_3),
},
new Pulp
{
- AccentColour = AccentColour,
+ AccentColour = AccentColour.Value,
Size = new Vector2(large_pulp_3),
Position = positionAt(120, distance_from_centre_3),
},
new Pulp
{
Size = new Vector2(large_pulp_3),
- AccentColour = AccentColour,
+ AccentColour = AccentColour.Value,
Position = positionAt(240, distance_from_centre_3),
},
}
@@ -259,13 +259,13 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
{
new Pulp
{
- AccentColour = AccentColour,
+ AccentColour = AccentColour.Value,
Size = new Vector2(small_pulp),
Y = -0.3f
},
new Pulp
{
- AccentColour = AccentColour,
+ AccentColour = AccentColour.Value,
Size = new Vector2(large_pulp_4 * 0.8f, large_pulp_4 * 2.5f),
Y = 0.05f,
},
diff --git a/osu.Game.Rulesets.Mania.Tests.iOS/Application.cs b/osu.Game.Rulesets.Mania.Tests.iOS/Application.cs
index d47ac4643f..0362402320 100644
--- a/osu.Game.Rulesets.Mania.Tests.iOS/Application.cs
+++ b/osu.Game.Rulesets.Mania.Tests.iOS/Application.cs
@@ -9,7 +9,7 @@ namespace osu.Game.Rulesets.Mania.Tests.iOS
{
public static void Main(string[] args)
{
- UIApplication.Main(args, null, "AppDelegate");
+ UIApplication.Main(args, "GameUIApplication", "AppDelegate");
}
}
}
diff --git a/osu.Game.Rulesets.Mania.Tests/TestSceneHoldNoteSelectionBlueprint.cs b/osu.Game.Rulesets.Mania.Tests/TestSceneHoldNoteSelectionBlueprint.cs
index 04c5724f93..622d840a0c 100644
--- a/osu.Game.Rulesets.Mania.Tests/TestSceneHoldNoteSelectionBlueprint.cs
+++ b/osu.Game.Rulesets.Mania.Tests/TestSceneHoldNoteSelectionBlueprint.cs
@@ -36,7 +36,7 @@ namespace osu.Game.Rulesets.Mania.Tests
Child = drawableObject = new DrawableHoldNote(holdNote)
{
Height = 300,
- AccentColour = OsuColour.Gray(0.3f)
+ AccentColour = { Value = OsuColour.Gray(0.3f) }
}
};
}
diff --git a/osu.Game.Rulesets.Mania.Tests/TestSceneNotes.cs b/osu.Game.Rulesets.Mania.Tests/TestSceneNotes.cs
index b2613a59d5..031abb08e2 100644
--- a/osu.Game.Rulesets.Mania.Tests/TestSceneNotes.cs
+++ b/osu.Game.Rulesets.Mania.Tests/TestSceneNotes.cs
@@ -70,7 +70,7 @@ namespace osu.Game.Rulesets.Mania.Tests
AutoSizeAxes = Axes.Both,
Child = new NoteContainer(direction, $"note {identifier}, scrolling {direction.ToString().ToLowerInvariant()}")
{
- Child = hitObject = new DrawableNote(note) { AccentColour = Color4.OrangeRed }
+ Child = hitObject = new DrawableNote(note) { AccentColour = { Value = Color4.OrangeRed } }
}
};
}
@@ -88,7 +88,7 @@ namespace osu.Game.Rulesets.Mania.Tests
Child = hitObject = new DrawableHoldNote(note)
{
RelativeSizeAxes = Axes.Both,
- AccentColour = Color4.OrangeRed,
+ AccentColour = { Value = Color4.OrangeRed },
}
}
};
diff --git a/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj b/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj
index dbade6ff8d..df5131dd8b 100644
--- a/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj
+++ b/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj
@@ -2,7 +2,7 @@
-
+
diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs
index 9368af987d..952c6e128e 100644
--- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs
+++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs
@@ -6,7 +6,6 @@ using osu.Framework.Bindables;
using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Graphics;
using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
-using osuTK.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Input.Bindings;
using osu.Game.Rulesets.Scoring;
@@ -36,11 +35,10 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
///
private bool hasBroken;
- private readonly Container tickContainer;
-
public DrawableHoldNote(HoldNote hitObject)
: base(hitObject)
{
+ Container tickContainer;
RelativeSizeAxes = Axes.X;
AddRangeInternal(new Drawable[]
@@ -74,6 +72,14 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
AddNested(Head);
AddNested(Tail);
+
+ AccentColour.BindValueChanged(colour =>
+ {
+ bodyPiece.AccentColour = colour.NewValue;
+ Head.AccentColour.Value = colour.NewValue;
+ Tail.AccentColour.Value = colour.NewValue;
+ tickContainer.ForEach(t => t.AccentColour.Value = colour.NewValue);
+ }, true);
}
protected override void OnDirectionChanged(ValueChangedEvent e)
@@ -83,20 +89,6 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
bodyPiece.Anchor = bodyPiece.Origin = e.NewValue == ScrollingDirection.Up ? Anchor.TopLeft : Anchor.BottomLeft;
}
- public override Color4 AccentColour
- {
- get => base.AccentColour;
- set
- {
- base.AccentColour = value;
-
- bodyPiece.AccentColour = value;
- Head.AccentColour = value;
- Tail.AccentColour = value;
- tickContainer.ForEach(t => t.AccentColour = value);
- }
- }
-
protected override void CheckForResult(bool userTriggered, double timeOffset)
{
if (Tail.AllJudged)
diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNoteTick.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNoteTick.cs
index 9a29273282..9b0322a6cd 100644
--- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNoteTick.cs
+++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNoteTick.cs
@@ -3,7 +3,6 @@
using System;
using osuTK;
-using osuTK.Graphics;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
@@ -23,11 +22,11 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
///
public Func HoldStartTime;
- private readonly Container glowContainer;
-
public DrawableHoldNoteTick(HoldNoteTick hitObject)
: base(hitObject)
{
+ Container glowContainer;
+
Anchor = Anchor.TopCentre;
Origin = Anchor.TopCentre;
@@ -53,23 +52,17 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
}
}
});
- }
- public override Color4 AccentColour
- {
- get => base.AccentColour;
- set
+ AccentColour.BindValueChanged(colour =>
{
- base.AccentColour = value;
-
glowContainer.EdgeEffect = new EdgeEffectParameters
{
Type = EdgeEffectType.Glow,
Radius = 2f,
Roundness = 15f,
- Colour = value.Opacity(0.3f)
+ Colour = colour.NewValue.Opacity(0.3f)
};
- }
+ }, true);
}
protected override void CheckForResult(bool userTriggered, double timeOffset)
diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableManiaHitObject.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableManiaHitObject.cs
index 0873f753be..db6b53e76d 100644
--- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableManiaHitObject.cs
+++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableManiaHitObject.cs
@@ -58,8 +58,11 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
HitObject = hitObject;
}
+ protected override bool UseTransformStateManagement => false;
+
protected override void UpdateState(ArmedState state)
{
+ // TODO: update to use new state management.
switch (state)
{
case ArmedState.Miss:
diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableNote.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableNote.cs
index afd7777861..dccff7f6ac 100644
--- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableNote.cs
+++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableNote.cs
@@ -3,7 +3,6 @@
using osu.Framework.Bindables;
using osu.Framework.Extensions.Color4Extensions;
-using osuTK.Graphics;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Effects;
using osu.Framework.Input.Bindings;
@@ -30,6 +29,18 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
Masking = true;
AddInternal(headPiece = new NotePiece());
+
+ AccentColour.BindValueChanged(colour =>
+ {
+ headPiece.AccentColour = colour.NewValue;
+
+ EdgeEffect = new EdgeEffectParameters
+ {
+ Type = EdgeEffectType.Glow,
+ Colour = colour.NewValue.Lighten(1f).Opacity(0.6f),
+ Radius = 10,
+ };
+ }, true);
}
protected override void OnDirectionChanged(ValueChangedEvent e)
@@ -39,23 +50,6 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
headPiece.Anchor = headPiece.Origin = e.NewValue == ScrollingDirection.Up ? Anchor.TopCentre : Anchor.BottomCentre;
}
- public override Color4 AccentColour
- {
- get => base.AccentColour;
- set
- {
- base.AccentColour = value;
- headPiece.AccentColour = AccentColour;
-
- EdgeEffect = new EdgeEffectParameters
- {
- Type = EdgeEffectType.Glow,
- Colour = AccentColour.Lighten(1f).Opacity(0.6f),
- Radius = 10,
- };
- }
- }
-
protected override void CheckForResult(bool userTriggered, double timeOffset)
{
if (!userTriggered)
diff --git a/osu.Game.Rulesets.Mania/UI/Column.cs b/osu.Game.Rulesets.Mania/UI/Column.cs
index c59bed4ea7..91dd236ab1 100644
--- a/osu.Game.Rulesets.Mania/UI/Column.cs
+++ b/osu.Game.Rulesets.Mania/UI/Column.cs
@@ -143,7 +143,7 @@ namespace osu.Game.Rulesets.Mania.UI
/// The DrawableHitObject to add.
public override void Add(DrawableHitObject hitObject)
{
- hitObject.AccentColour = AccentColour;
+ hitObject.AccentColour.Value = AccentColour;
hitObject.OnNewResult += OnNewResult;
HitObjectContainer.Add(hitObject);
diff --git a/osu.Game.Rulesets.Mania/UI/HitExplosion.cs b/osu.Game.Rulesets.Mania/UI/HitExplosion.cs
index 0ec1fc38d2..48470add8b 100644
--- a/osu.Game.Rulesets.Mania/UI/HitExplosion.cs
+++ b/osu.Game.Rulesets.Mania/UI/HitExplosion.cs
@@ -44,7 +44,7 @@ namespace osu.Game.Rulesets.Mania.UI
EdgeEffect = new EdgeEffectParameters
{
Type = EdgeEffectType.Glow,
- Colour = Interpolation.ValueAt(0.1f, judgedObject.AccentColour, Color4.White, 0, 1),
+ Colour = Interpolation.ValueAt(0.1f, judgedObject.AccentColour.Value, Color4.White, 0, 1),
Radius = 100,
},
Child = new Box
diff --git a/osu.Game.Rulesets.Osu.Tests.iOS/Application.cs b/osu.Game.Rulesets.Osu.Tests.iOS/Application.cs
index 7a0797a909..3718264a42 100644
--- a/osu.Game.Rulesets.Osu.Tests.iOS/Application.cs
+++ b/osu.Game.Rulesets.Osu.Tests.iOS/Application.cs
@@ -9,7 +9,7 @@ namespace osu.Game.Rulesets.Osu.Tests.iOS
{
public static void Main(string[] args)
{
- UIApplication.Main(args, null, "AppDelegate");
+ UIApplication.Main(args, "GameUIApplication", "AppDelegate");
}
}
}
diff --git a/osu.Game.Rulesets.Osu.Tests/OsuDifficultyCalculatorTest.cs b/osu.Game.Rulesets.Osu.Tests/OsuDifficultyCalculatorTest.cs
index e55dc1f902..693faee3b7 100644
--- a/osu.Game.Rulesets.Osu.Tests/OsuDifficultyCalculatorTest.cs
+++ b/osu.Game.Rulesets.Osu.Tests/OsuDifficultyCalculatorTest.cs
@@ -15,6 +15,7 @@ namespace osu.Game.Rulesets.Osu.Tests
protected override string ResourceAssembly => "osu.Game.Rulesets.Osu";
[TestCase(6.931145117263422, "diffcalc-test")]
+ [TestCase(1.0736587013228804d, "zero-length-sliders")]
public void Test(double expected, string name)
=> base.Test(expected, name);
diff --git a/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj b/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj
index a99a93c3e9..bb3e5a66f3 100644
--- a/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj
+++ b/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj
@@ -2,7 +2,7 @@
-
+
diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/Components/HitCirclePiece.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/Components/HitCirclePiece.cs
index 7f6a60c400..fe11ead94d 100644
--- a/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/Components/HitCirclePiece.cs
+++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/Components/HitCirclePiece.cs
@@ -20,7 +20,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components
this.hitCircle = hitCircle;
Origin = Anchor.Centre;
- Size = new Vector2((float)OsuHitObject.OBJECT_RADIUS * 2);
+ Size = new Vector2(OsuHitObject.OBJECT_RADIUS * 2);
Scale = new Vector2(hitCircle.Scale);
CornerRadius = Size.X / 2;
diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderBodyPiece.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderBodyPiece.cs
index 957550a051..f1f55731b6 100644
--- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderBodyPiece.cs
+++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderBodyPiece.cs
@@ -24,7 +24,6 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
InternalChild = body = new ManualSliderBody
{
AccentColour = Color4.Transparent,
- PathRadius = slider.Scale * 64
};
}
@@ -34,7 +33,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
body.BorderColour = colours.Yellow;
PositionBindable.BindValueChanged(_ => updatePosition(), true);
- ScaleBindable.BindValueChanged(scale => body.PathRadius = scale.NewValue * 64, true);
+ ScaleBindable.BindValueChanged(scale => body.PathRadius = scale.NewValue * OsuHitObject.OBJECT_RADIUS, true);
}
private void updatePosition() => Position = slider.StackedPosition;
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs b/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs
index bc5d02258f..5625028707 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs
@@ -13,13 +13,11 @@ using static osu.Game.Input.Handlers.ReplayInputHandler;
namespace osu.Game.Rulesets.Osu.Mods
{
- public class OsuModRelax : ModRelax, IApplicableFailOverride, IUpdatableByPlayfield, IApplicableToDrawableRuleset
+ public class OsuModRelax : ModRelax, IUpdatableByPlayfield, IApplicableToDrawableRuleset
{
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();
- public bool AllowFail => false;
-
public void Update(Playfield playfield)
{
bool requiresHold = false;
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModTouchDevice.cs b/osu.Game.Rulesets.Osu/Mods/OsuModTouchDevice.cs
index 571756d056..f0db548e74 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModTouchDevice.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModTouchDevice.cs
@@ -11,6 +11,8 @@ namespace osu.Game.Rulesets.Osu.Mods
public override string Acronym => "TD";
public override double ScoreMultiplier => 1;
+ public override ModType Type => ModType.System;
+
public override bool Ranked => true;
}
}
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs
index fef0bfdc2c..d3d763daf3 100644
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs
@@ -10,7 +10,6 @@ using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces;
using osuTK;
using osu.Game.Rulesets.Scoring;
-using osuTK.Graphics;
namespace osu.Game.Rulesets.Osu.Objects.Drawables
{
@@ -98,19 +97,14 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
positionBindable.BindTo(HitObject.PositionBindable);
stackHeightBindable.BindTo(HitObject.StackHeightBindable);
scaleBindable.BindTo(HitObject.ScaleBindable);
- }
- public override Color4 AccentColour
- {
- get => base.AccentColour;
- set
+ AccentColour.BindValueChanged(colour =>
{
- base.AccentColour = value;
- explode.Colour = AccentColour;
- glow.Colour = AccentColour;
- circle.Colour = AccentColour;
- ApproachCircle.Colour = AccentColour;
- }
+ explode.Colour = colour.NewValue;
+ glow.Colour = colour.NewValue;
+ circle.Colour = colour.NewValue;
+ ApproachCircle.Colour = colour.NewValue;
+ }, true);
}
protected override void CheckForResult(bool userTriggered, double timeOffset)
@@ -134,16 +128,16 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
ApplyResult(r => r.Type = result);
}
- protected override void UpdatePreemptState()
+ protected override void UpdateInitialTransforms()
{
- base.UpdatePreemptState();
+ base.UpdateInitialTransforms();
ApproachCircle.FadeIn(Math.Min(HitObject.TimeFadeIn * 2, HitObject.TimePreempt));
ApproachCircle.ScaleTo(1.1f, HitObject.TimePreempt);
ApproachCircle.Expire(true);
}
- protected override void UpdateCurrentState(ArmedState state)
+ protected override void UpdateStateTransforms(ArmedState state)
{
glow.FadeOut(400);
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs
index f372cb65ce..579f16e0d4 100644
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs
@@ -1,15 +1,10 @@
-// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-using System;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Framework.Graphics;
using osu.Game.Rulesets.Judgements;
-using osu.Game.Rulesets.Objects.Types;
using osu.Game.Rulesets.Osu.Judgements;
-using osu.Game.Rulesets.Scoring;
-using osu.Game.Skinning;
-using osuTK.Graphics;
using osu.Game.Graphics.Containers;
namespace osu.Game.Rulesets.Osu.Objects.Drawables
@@ -29,6 +24,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
ShakeDuration = 30,
RelativeSizeAxes = Axes.Both
});
+
Alpha = 0;
}
@@ -38,47 +34,9 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
protected override void ClearInternal(bool disposeChildren = true) => shakeContainer.Clear(disposeChildren);
protected override bool RemoveInternal(Drawable drawable) => shakeContainer.Remove(drawable);
- protected sealed override void UpdateState(ArmedState state)
- {
- double transformTime = HitObject.StartTime - HitObject.TimePreempt;
+ protected sealed override double InitialLifetimeOffset => HitObject.TimePreempt;
- base.ApplyTransformsAt(transformTime, true);
- base.ClearTransformsAfter(transformTime, true);
-
- using (BeginAbsoluteSequence(transformTime, true))
- {
- UpdatePreemptState();
-
- var judgementOffset = Math.Min(HitObject.HitWindows.HalfWindowFor(HitResult.Miss), Result?.TimeOffset ?? 0);
-
- using (BeginDelayedSequence(HitObject.TimePreempt + judgementOffset, true))
- UpdateCurrentState(state);
- }
- }
-
- protected override void SkinChanged(ISkinSource skin, bool allowFallback)
- {
- base.SkinChanged(skin, allowFallback);
-
- if (HitObject is IHasComboInformation combo)
- AccentColour = skin.GetValue(s => s.ComboColours.Count > 0 ? s.ComboColours[combo.ComboIndex % s.ComboColours.Count] : (Color4?)null) ?? Color4.White;
- }
-
- protected virtual void UpdatePreemptState() => this.FadeIn(HitObject.TimeFadeIn);
-
- protected virtual void UpdateCurrentState(ArmedState state)
- {
- }
-
- // Todo: At some point we need to move these to DrawableHitObject after ensuring that all other Rulesets apply
- // transforms in the same way and don't rely on them not being cleared
- public override void ClearTransformsAfter(double time, bool propagateChildren = false, string targetMember = null)
- {
- }
-
- public override void ApplyTransformsAt(double time, bool propagateChildren = false)
- {
- }
+ protected override void UpdateInitialTransforms() => this.FadeIn(HitObject.TimeFadeIn);
private OsuInputManager osuActionInputManager;
internal OsuInputManager OsuActionInputManager => osuActionInputManager ?? (osuActionInputManager = GetContainingInputManager() as OsuInputManager);
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableRepeatPoint.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableRepeatPoint.cs
index cce6dfe106..1e2c0ae59f 100644
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableRepeatPoint.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableRepeatPoint.cs
@@ -47,7 +47,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
ApplyResult(r => r.Type = drawableSlider.Tracking.Value ? HitResult.Great : HitResult.Miss);
}
- protected override void UpdatePreemptState()
+ protected override void UpdateInitialTransforms()
{
animDuration = Math.Min(150, repeatPoint.SpanDuration / 2);
@@ -57,7 +57,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
);
}
- protected override void UpdateCurrentState(ArmedState state)
+ protected override void UpdateStateTransforms(ArmedState state)
{
switch (state)
{
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs
index 05cb42d853..4a6bd45007 100644
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs
@@ -50,7 +50,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
{
Body = new SnakingSliderBody(s)
{
- PathRadius = s.Scale * 64,
+ PathRadius = s.Scale * OsuHitObject.OBJECT_RADIUS,
},
ticks = new Container { RelativeSizeAxes = Axes.Both },
repeatPoints = new Container { RelativeSizeAxes = Axes.Both },
@@ -114,20 +114,15 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
pathBindable.BindTo(slider.PathBindable);
pathBindable.BindValueChanged(_ => Body.Refresh());
- }
- public override Color4 AccentColour
- {
- get => base.AccentColour;
- set
+ AccentColour.BindValueChanged(colour =>
{
- base.AccentColour = value;
- Body.AccentColour = AccentColour;
- Ball.AccentColour = AccentColour;
+ Body.AccentColour = colour.NewValue;
+ Ball.AccentColour = colour.NewValue;
foreach (var drawableHitObject in NestedHitObjects)
- drawableHitObject.AccentColour = AccentColour;
- }
+ drawableHitObject.AccentColour.Value = colour.NewValue;
+ }, true);
}
public readonly Bindable Tracking = new Bindable();
@@ -156,14 +151,20 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
}
}
+ public override void OnKilled()
+ {
+ base.OnKilled();
+ Body.RecyclePath();
+ }
+
protected override void SkinChanged(ISkinSource skin, bool allowFallback)
{
base.SkinChanged(skin, allowFallback);
Body.BorderSize = skin.GetValue(s => s.SliderBorderSize) ?? SliderBody.DEFAULT_BORDER_SIZE;
- Body.AccentColour = skin.GetValue(s => s.CustomColours.ContainsKey("SliderTrackOverride") ? s.CustomColours["SliderTrackOverride"] : (Color4?)null) ?? AccentColour;
+ Body.AccentColour = skin.GetValue(s => s.CustomColours.ContainsKey("SliderTrackOverride") ? s.CustomColours["SliderTrackOverride"] : (Color4?)null) ?? AccentColour.Value;
Body.BorderColour = skin.GetValue(s => s.CustomColours.ContainsKey("SliderBorder") ? s.CustomColours["SliderBorder"] : (Color4?)null) ?? Color4.White;
- Ball.AccentColour = skin.GetValue(s => s.CustomColours.ContainsKey("SliderBall") ? s.CustomColours["SliderBall"] : (Color4?)null) ?? AccentColour;
+ Ball.AccentColour = skin.GetValue(s => s.CustomColours.ContainsKey("SliderBall") ? s.CustomColours["SliderBall"] : (Color4?)null) ?? AccentColour.Value;
}
protected override void CheckForResult(bool userTriggered, double timeOffset)
@@ -189,7 +190,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
});
}
- protected override void UpdateCurrentState(ArmedState state)
+ protected override void UpdateStateTransforms(ArmedState state)
{
Ball.FadeIn();
Ball.ScaleTo(HitObject.Scale);
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTick.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTick.cs
index 72b648bfd0..f5f92dd05d 100644
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTick.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTick.cs
@@ -34,14 +34,12 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
RelativeSizeAxes = Axes.Both,
Origin = Anchor.Centre,
CornerRadius = Size.X / 2,
-
BorderThickness = 2,
BorderColour = Color4.White,
-
Child = new Box
{
RelativeSizeAxes = Axes.Both,
- Colour = AccentColour,
+ Colour = AccentColour.Value,
Alpha = 0.3f,
}
}, restrictSize: false)
@@ -54,13 +52,13 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
ApplyResult(r => r.Type = Tracking ? HitResult.Great : HitResult.Miss);
}
- protected override void UpdatePreemptState()
+ protected override void UpdateInitialTransforms()
{
this.FadeOut().FadeIn(ANIM_DURATION);
this.ScaleTo(0.5f).ScaleTo(1f, ANIM_DURATION * 4, Easing.OutElasticHalf);
}
- protected override void UpdateCurrentState(ArmedState state)
+ protected override void UpdateStateTransforms(ArmedState state)
{
switch (state)
{
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs
index 1794da54b7..a0bd301fdb 100644
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs
@@ -196,9 +196,9 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
symbol.RotateTo(Disc.Rotation / 2, 500, Easing.OutQuint);
}
- protected override void UpdatePreemptState()
+ protected override void UpdateInitialTransforms()
{
- base.UpdatePreemptState();
+ base.UpdateInitialTransforms();
circleContainer.ScaleTo(Spinner.Scale * 0.3f);
circleContainer.ScaleTo(Spinner.Scale, HitObject.TimePreempt / 1.4f, Easing.OutQuint);
@@ -213,7 +213,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
.ScaleTo(1, 500, Easing.OutQuint);
}
- protected override void UpdateCurrentState(ArmedState state)
+ protected override void UpdateStateTransforms(ArmedState state)
{
var sequence = this.Delay(Spinner.Duration).FadeOut(160);
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/CirclePiece.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/CirclePiece.cs
index 786cac7198..dc0b149140 100644
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/CirclePiece.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/CirclePiece.cs
@@ -21,7 +21,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
public CirclePiece()
{
- Size = new Vector2((float)OsuHitObject.OBJECT_RADIUS * 2);
+ Size = new Vector2(OsuHitObject.OBJECT_RADIUS * 2);
Masking = true;
CornerRadius = Size.X / 2;
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/ExplodePiece.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/ExplodePiece.cs
index b960f40578..8ff16f8b84 100644
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/ExplodePiece.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/ExplodePiece.cs
@@ -12,7 +12,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
{
public ExplodePiece()
{
- Size = new Vector2(128);
+ Size = new Vector2(OsuHitObject.OBJECT_RADIUS * 2);
Anchor = Anchor.Centre;
Origin = Anchor.Centre;
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/FlashPiece.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/FlashPiece.cs
index 8e5eb886aa..c22073f56c 100644
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/FlashPiece.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/FlashPiece.cs
@@ -1,4 +1,4 @@
-// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Graphics;
@@ -13,7 +13,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
{
public FlashPiece()
{
- Size = new Vector2(128);
+ Size = new Vector2(OsuHitObject.OBJECT_RADIUS * 2);
Anchor = Anchor.Centre;
Origin = Anchor.Centre;
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/RingPiece.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/RingPiece.cs
index 28180a7f71..575f2c92c5 100644
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/RingPiece.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/RingPiece.cs
@@ -1,4 +1,4 @@
-// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Graphics;
@@ -14,7 +14,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
{
public RingPiece()
{
- Size = new Vector2(128);
+ Size = new Vector2(OsuHitObject.OBJECT_RADIUS * 2);
Anchor = Anchor.Centre;
Origin = Anchor.Centre;
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBall.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBall.cs
index 7d1d77ae96..9ba8ad3474 100644
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBall.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBall.cs
@@ -17,8 +17,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
{
public class SliderBall : CircularContainer, ISliderProgress, IRequireHighFrequencyMousePosition
{
- private const float width = 128;
-
private Color4 accentColour = Color4.Black;
public Func GetInitialHitAction;
@@ -57,8 +55,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
{
Origin = Anchor.Centre,
Anchor = Anchor.Centre,
- Width = width,
- Height = width,
+ Width = OsuHitObject.OBJECT_RADIUS * 2,
+ Height = OsuHitObject.OBJECT_RADIUS * 2,
Alpha = 0,
Child = new SkinnableDrawable("Play/osu/sliderfollowcircle", _ => new CircularContainer
{
@@ -84,8 +82,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
Alpha = 1,
Child = new Container
{
- Width = width,
- Height = width,
+ Width = OsuHitObject.OBJECT_RADIUS * 2,
+ Height = OsuHitObject.OBJECT_RADIUS * 2,
// TODO: support skin filename animation (sliderb0, sliderb1...)
Child = new SkinnableDrawable("Play/osu/sliderb", _ => new CircularContainer
{
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBody.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBody.cs
index 33b3667c4f..6bc19ee3b5 100644
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBody.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBody.cs
@@ -1,6 +1,7 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
+using System;
using System.Collections.Generic;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Lines;
@@ -13,7 +14,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
{
public const float DEFAULT_BORDER_SIZE = 1;
- private readonly SliderPath path;
+ private SliderPath path;
+
protected Path Path => path;
public float PathRadius
@@ -74,7 +76,23 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
protected SliderBody()
{
- InternalChild = path = new SliderPath();
+ RecyclePath();
+ }
+
+ ///
+ /// Initialises a new , releasing all resources retained by the old one.
+ ///
+ public virtual void RecyclePath()
+ {
+ InternalChild = path = new SliderPath
+ {
+ Position = path?.Position ?? Vector2.Zero,
+ PathRadius = path?.PathRadius ?? 10,
+ AccentColour = path?.AccentColour ?? Color4.White,
+ BorderColour = path?.BorderColour ?? Color4.White,
+ BorderSize = path?.BorderSize ?? DEFAULT_BORDER_SIZE,
+ Vertices = path?.Vertices ?? Array.Empty()
+ };
}
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => path.ReceivePositionalInputAt(screenSpacePos);
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SnakingSliderBody.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SnakingSliderBody.cs
index 73b184bffe..a3d3893c8b 100644
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SnakingSliderBody.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SnakingSliderBody.cs
@@ -5,6 +5,7 @@ using System;
using System.Collections.Generic;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
+using osu.Framework.Graphics;
using osu.Game.Rulesets.Objects.Types;
using osuTK;
@@ -78,9 +79,12 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
slider.Path.GetPathToProgress(CurrentCurve, 0, 1);
SetVertices(CurrentCurve);
- // The body is sized to the full path size to avoid excessive autosize computations
+ // Force the body to be the final path size to avoid excessive autosize computations
+ Path.AutoSizeAxes = Axes.Both;
Size = Path.Size;
+ updatePathSize();
+
snakedPosition = Path.PositionInBoundingBox(Vector2.Zero);
snakedPathOffset = Path.PositionInBoundingBox(Path.Vertices[0]);
@@ -93,6 +97,19 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
setRange(lastSnakedStart, lastSnakedEnd);
}
+ public override void RecyclePath()
+ {
+ base.RecyclePath();
+ updatePathSize();
+ }
+
+ private void updatePathSize()
+ {
+ // Force the path to its final size to avoid excessive framebuffer resizes
+ Path.AutoSizeAxes = Axes.None;
+ Path.Size = Size;
+ }
+
private void setRange(double p0, double p1)
{
if (p0 > p1)
diff --git a/osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs b/osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs
index 364c182dd4..d1221fd2d3 100644
--- a/osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs
+++ b/osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs
@@ -12,7 +12,7 @@ namespace osu.Game.Rulesets.Osu.Objects
{
public abstract class OsuHitObject : HitObject, IHasComboInformation, IHasPosition
{
- public const double OBJECT_RADIUS = 64;
+ public const float OBJECT_RADIUS = 64;
public double TimePreempt = 600;
public double TimeFadeIn = 400;
diff --git a/osu.Game.Rulesets.Osu/OsuRuleset.cs b/osu.Game.Rulesets.Osu/OsuRuleset.cs
index baa4aff413..8df0f77629 100644
--- a/osu.Game.Rulesets.Osu/OsuRuleset.cs
+++ b/osu.Game.Rulesets.Osu/OsuRuleset.cs
@@ -138,6 +138,12 @@ namespace osu.Game.Rulesets.Osu
new MultiMod(new ModWindUp(), new ModWindDown()),
};
+ case ModType.System:
+ return new Mod[]
+ {
+ new OsuModTouchDevice(),
+ };
+
default:
return new Mod[] { };
}
diff --git a/osu.Game.Rulesets.Osu/Resources/Testing/Beatmaps/zero-length-sliders.osu b/osu.Game.Rulesets.Osu/Resources/Testing/Beatmaps/zero-length-sliders.osu
new file mode 100644
index 0000000000..18736043b5
--- /dev/null
+++ b/osu.Game.Rulesets.Osu/Resources/Testing/Beatmaps/zero-length-sliders.osu
@@ -0,0 +1,28 @@
+osu file format v14
+
+[Difficulty]
+HPDrainRate:3
+CircleSize:3
+OverallDifficulty:3
+ApproachRate:4.5
+SliderMultiplier:0.799999999999999
+SliderTickRate:1
+
+[TimingPoints]
+800,260.869565217391,3,2,10,60,1,0
+
+[HitObjects]
+// Linear
+78,193,2365,2,0,L|330:193,1,0
+78,193,3669,2,0,L|330:193,1,0
+78,193,4973,2,0,L|330:193,1,0
+
+// Perfect-curve
+151,206,6278,2,0,P|293:75|345:204,1,0
+151,206,8104,2,0,P|293:75|345:204,1,0
+151,206,9930,2,0,P|293:75|345:204,1,0
+
+// Bezier
+76,191,11756,2,0,B|176:59|358:340|438:190,1,0
+76,191,13582,2,0,B|176:59|358:340|438:190,1,0
+76,191,15408,2,0,B|176:59|358:340|438:190,1,0
diff --git a/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs b/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs
index b986076593..05eb0ffdbf 100644
--- a/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs
+++ b/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs
@@ -162,7 +162,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
private readonly TrailPart[] parts = new TrailPart[max_sprites];
private Vector2 size;
- private readonly VertexBatch vertexBatch = new QuadBatch(max_sprites, 1);
+ private readonly TrailBatch vertexBatch = new TrailBatch(max_sprites, 1);
public TrailDrawNode(CursorTrail source)
: base(source)
@@ -196,21 +196,16 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
for (int i = 0; i < parts.Length; ++i)
{
+ vertexBatch.DrawTime = parts[i].Time;
+
Vector2 pos = parts[i].Position;
- float localTime = parts[i].Time;
DrawQuad(
texture,
new Quad(pos.X - size.X / 2, pos.Y - size.Y / 2, size.X, size.Y),
DrawColourInfo.Colour,
null,
- v => vertexBatch.Add(new TexturedTrailVertex
- {
- Position = v.Position,
- TexturePosition = v.TexturePosition,
- Time = localTime + 1,
- Colour = v.Colour,
- }));
+ vertexBatch.AddAction);
}
shader.Unbind();
@@ -222,6 +217,25 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
vertexBatch.Dispose();
}
+
+ // Todo: This shouldn't exist, but is currently used to reduce allocations by caching variable-capturing closures.
+ private class TrailBatch : QuadBatch
+ {
+ public new readonly Action AddAction;
+ public float DrawTime;
+
+ public TrailBatch(int size, int maxBuffers)
+ : base(size, maxBuffers)
+ {
+ AddAction = v => Add(new TexturedTrailVertex
+ {
+ Position = v.Position,
+ TexturePosition = v.TexturePosition,
+ Time = DrawTime + 1,
+ Colour = v.Colour,
+ });
+ }
+ }
}
[StructLayout(LayoutKind.Sequential)]
diff --git a/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs b/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs
index 0cbe0cca85..9037faf606 100644
--- a/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs
+++ b/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs
@@ -12,6 +12,7 @@ using osu.Game.Rulesets.UI;
using System.Linq;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Osu.UI.Cursor;
+using osu.Game.Skinning;
namespace osu.Game.Rulesets.Osu.UI
{
@@ -39,7 +40,13 @@ namespace osu.Game.Rulesets.Osu.UI
RelativeSizeAxes = Axes.Both,
Depth = 1,
},
- HitObjectContainer,
+ // Todo: This should not exist, but currently helps to reduce LOH allocations due to unbinding skin source events on judgement disposal
+ // Todo: Remove when hitobjects are properly pooled
+ new LocalSkinOverrideContainer(null)
+ {
+ RelativeSizeAxes = Axes.Both,
+ Child = HitObjectContainer,
+ },
approachCircles = new ApproachCircleProxyContainer
{
RelativeSizeAxes = Axes.Both,
diff --git a/osu.Game.Rulesets.Taiko.Tests.iOS/Application.cs b/osu.Game.Rulesets.Taiko.Tests.iOS/Application.cs
index 6613e9e2b4..330cb42901 100644
--- a/osu.Game.Rulesets.Taiko.Tests.iOS/Application.cs
+++ b/osu.Game.Rulesets.Taiko.Tests.iOS/Application.cs
@@ -9,7 +9,7 @@ namespace osu.Game.Rulesets.Taiko.Tests.iOS
{
public static void Main(string[] args)
{
- UIApplication.Main(args, null, "AppDelegate");
+ UIApplication.Main(args, "GameUIApplication", "AppDelegate");
}
}
}
diff --git a/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj b/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj
index 216cc0222f..5510c3a9d9 100644
--- a/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj
+++ b/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj
@@ -2,7 +2,7 @@
-
+
diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs
index 4c8d5d5204..34ae7db984 100644
--- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs
+++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs
@@ -94,6 +94,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
protected override void UpdateState(ArmedState state)
{
+ // TODO: update to use new state management.
var circlePiece = MainPiece as CirclePiece;
circlePiece?.FlashBox.FinishTransforms();
diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs
index bd45b52d7b..b46738c69a 100644
--- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs
+++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs
@@ -121,6 +121,8 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
}
}
+ protected override bool UseTransformStateManagement => false;
+
// Normal and clap samples are handled by the drum
protected override IEnumerable GetSamples() => HitObject.Samples.Where(s => s.Name != HitSampleInfo.HIT_NORMAL && s.Name != HitSampleInfo.HIT_CLAP);
diff --git a/osu.Game.Tests.iOS/Application.cs b/osu.Game.Tests.iOS/Application.cs
index a23fe4e129..d96a3e27a4 100644
--- a/osu.Game.Tests.iOS/Application.cs
+++ b/osu.Game.Tests.iOS/Application.cs
@@ -9,7 +9,7 @@ namespace osu.Game.Tests.iOS
{
public static void Main(string[] args)
{
- UIApplication.Main(args, null, "AppDelegate");
+ UIApplication.Main(args, "GameUIApplication", "AppDelegate");
}
}
}
diff --git a/osu.Game.Tests/NonVisual/FramedReplayinputHandlerTest.cs b/osu.Game.Tests/NonVisual/FramedReplayInputHandlerTest.cs
similarity index 94%
rename from osu.Game.Tests/NonVisual/FramedReplayinputHandlerTest.cs
rename to osu.Game.Tests/NonVisual/FramedReplayInputHandlerTest.cs
index 73387fa5ab..18cbd4e7c5 100644
--- a/osu.Game.Tests/NonVisual/FramedReplayinputHandlerTest.cs
+++ b/osu.Game.Tests/NonVisual/FramedReplayInputHandlerTest.cs
@@ -1,6 +1,7 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
+using System;
using System.Collections.Generic;
using NUnit.Framework;
using osu.Game.Replays;
@@ -9,7 +10,7 @@ using osu.Game.Rulesets.Replays;
namespace osu.Game.Tests.NonVisual
{
[TestFixture]
- public class FramedReplayinputHandlerTest
+ public class FramedReplayInputHandlerTest
{
private Replay replay;
private TestInputHandler handler;
@@ -160,10 +161,7 @@ namespace osu.Game.Tests.NonVisual
[Test]
public void TestRewindInsideImportantSection()
{
- // fast forward to important section
- while (handler.SetFrameFromTime(3000) != null)
- {
- }
+ fastForwardToPoint(3000);
setTime(4000, 4000);
confirmCurrentFrame(4);
@@ -205,10 +203,7 @@ namespace osu.Game.Tests.NonVisual
[Test]
public void TestRewindOutOfImportantSection()
{
- // fast forward to important section
- while (handler.SetFrameFromTime(3500) != null)
- {
- }
+ fastForwardToPoint(3500);
confirmCurrentFrame(3);
confirmNextFrame(4);
@@ -227,6 +222,15 @@ namespace osu.Game.Tests.NonVisual
confirmNextFrame(2);
}
+ private void fastForwardToPoint(double destination)
+ {
+ for (int i = 0; i < 1000; i++)
+ if (handler.SetFrameFromTime(destination) == null)
+ return;
+
+ throw new TimeoutException("Seek was never fulfilled");
+ }
+
private void setTime(double set, double? expect)
{
Assert.AreEqual(expect, handler.SetFrameFromTime(set));
@@ -274,6 +278,7 @@ namespace osu.Game.Tests.NonVisual
public TestInputHandler(Replay replay)
: base(replay)
{
+ FrameAccuratePlayback = true;
}
protected override double AllowedImportantTimeSpan => 1000;
diff --git a/osu.Game.Tests/Visual/Background/TestSceneBackgroundScreenBeatmap.cs b/osu.Game.Tests/Visual/Background/TestSceneUserDimContainer.cs
similarity index 90%
rename from osu.Game.Tests/Visual/Background/TestSceneBackgroundScreenBeatmap.cs
rename to osu.Game.Tests/Visual/Background/TestSceneUserDimContainer.cs
index 8b941e4633..dc4ceed59e 100644
--- a/osu.Game.Tests/Visual/Background/TestSceneBackgroundScreenBeatmap.cs
+++ b/osu.Game.Tests/Visual/Background/TestSceneUserDimContainer.cs
@@ -10,6 +10,7 @@ using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
+using osu.Framework.Graphics.Sprites;
using osu.Framework.Input.Events;
using osu.Framework.Input.States;
using osu.Framework.Platform;
@@ -36,7 +37,7 @@ using osuTK.Graphics;
namespace osu.Game.Tests.Visual.Background
{
[TestFixture]
- public class TestSceneBackgroundScreenBeatmap : ManualInputManagerTestScene
+ public class TestSceneUserDimContainer : ManualInputManagerTestScene
{
public override IReadOnlyList RequiredTypes => new[]
{
@@ -137,14 +138,14 @@ namespace osu.Game.Tests.Visual.Background
player.StoryboardEnabled.Value = true;
});
waitForDim();
- AddAssert("Background is invisible, storyboard is visible", () => songSelect.IsBackgroundInvisible() && player.IsStoryboardVisible());
+ AddAssert("Background is invisible, storyboard is visible", () => songSelect.IsBackgroundInvisible() && player.IsStoryboardVisible);
AddStep("Storyboard Disabled", () =>
{
player.ReplacesBackground.Value = false;
player.StoryboardEnabled.Value = false;
});
waitForDim();
- AddAssert("Background is visible, storyboard is invisible", () => songSelect.IsBackgroundVisible() && player.IsStoryboardInvisible());
+ AddAssert("Background is visible, storyboard is invisible", () => songSelect.IsBackgroundVisible() && !player.IsStoryboardVisible);
}
///
@@ -241,14 +242,15 @@ namespace osu.Game.Tests.Visual.Background
{
player.StoryboardEnabled.Value = false;
player.ReplacesBackground.Value = false;
- player.CurrentStoryboardContainer.Add(new OsuSpriteText
+ player.DimmableStoryboard.Add(new OsuSpriteText
{
- Size = new Vector2(250, 50),
+ Size = new Vector2(500, 50),
Alpha = 1,
- Colour = Color4.Tomato,
+ Colour = Color4.White,
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Text = "THIS IS A STORYBOARD",
+ Font = new FontUsage(size: 50)
});
});
@@ -300,7 +302,7 @@ namespace osu.Game.Tests.Visual.Background
public bool IsBackgroundUndimmed() => ((FadeAccessibleBackground)Background).CurrentColour == Color4.White;
- public bool IsUserBlurApplied() => ((FadeAccessibleBackground)Background).CurrentBlur == new Vector2((float)BlurLevel.Value * 25);
+ public bool IsUserBlurApplied() => ((FadeAccessibleBackground)Background).CurrentBlur == new Vector2((float)BlurLevel.Value * BackgroundScreenBeatmap.USER_BLUR_FACTOR);
public bool IsUserBlurDisabled() => ((FadeAccessibleBackground)Background).CurrentBlur == new Vector2(0);
@@ -333,17 +335,7 @@ namespace osu.Game.Tests.Visual.Background
{
protected override BackgroundScreen CreateBackground() => new FadeAccessibleBackground(Beatmap.Value);
- protected override UserDimContainer CreateStoryboardContainer()
- {
- return new TestUserDimContainer(true)
- {
- RelativeSizeAxes = Axes.Both,
- Alpha = 1,
- EnableUserDim = { Value = true }
- };
- }
-
- public UserDimContainer CurrentStoryboardContainer => StoryboardContainer;
+ public new DimmableStoryboard DimmableStoryboard => base.DimmableStoryboard;
// Whether or not the player should be allowed to load.
public bool BlockLoad;
@@ -357,9 +349,7 @@ namespace osu.Game.Tests.Visual.Background
{
}
- public bool IsStoryboardVisible() => ((TestUserDimContainer)CurrentStoryboardContainer).CurrentAlpha == 1;
-
- public bool IsStoryboardInvisible() => ((TestUserDimContainer)CurrentStoryboardContainer).CurrentAlpha <= 1;
+ public bool IsStoryboardVisible => DimmableStoryboard.ContentDisplayed;
[BackgroundDependencyLoader]
private void load(OsuConfigManager config, CancellationToken token)
@@ -392,15 +382,15 @@ namespace osu.Game.Tests.Visual.Background
private class FadeAccessibleBackground : BackgroundScreenBeatmap
{
- protected override UserDimContainer CreateFadeContainer() => fadeContainer = new TestUserDimContainer { RelativeSizeAxes = Axes.Both };
+ protected override DimmableBackground CreateFadeContainer() => dimmable = new TestDimmableBackground { RelativeSizeAxes = Axes.Both };
- public Color4 CurrentColour => fadeContainer.CurrentColour;
+ public Color4 CurrentColour => dimmable.CurrentColour;
- public float CurrentAlpha => fadeContainer.CurrentAlpha;
+ public float CurrentAlpha => dimmable.CurrentAlpha;
public Vector2 CurrentBlur => Background.BlurSigma;
- private TestUserDimContainer fadeContainer;
+ private TestDimmableBackground dimmable;
public FadeAccessibleBackground(WorkingBeatmap beatmap)
: base(beatmap)
@@ -408,15 +398,10 @@ namespace osu.Game.Tests.Visual.Background
}
}
- private class TestUserDimContainer : UserDimContainer
+ private class TestDimmableBackground : BackgroundScreenBeatmap.DimmableBackground
{
- public Color4 CurrentColour => DimContainer.Colour;
- public float CurrentAlpha => DimContainer.Alpha;
-
- public TestUserDimContainer(bool isStoryboard = false)
- : base(isStoryboard)
- {
- }
+ public Color4 CurrentColour => Content.Colour;
+ public float CurrentAlpha => Content.Alpha;
}
}
}
diff --git a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs
index daee3a520c..ab519360ac 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs
@@ -9,6 +9,7 @@ using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
+using osu.Framework.MathUtils;
using osu.Framework.Screens;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Osu;
@@ -16,12 +17,13 @@ using osu.Game.Rulesets.Scoring;
using osu.Game.Scoring;
using osu.Game.Screens;
using osu.Game.Screens.Play;
+using osu.Game.Screens.Play.PlayerSettings;
namespace osu.Game.Tests.Visual.Gameplay
{
public class TestScenePlayerLoader : ManualInputManagerTestScene
{
- private PlayerLoader loader;
+ private TestPlayerLoader loader;
private OsuScreenStack stack;
[SetUp]
@@ -31,19 +33,29 @@ namespace osu.Game.Tests.Visual.Gameplay
Beatmap.Value = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo);
});
+ [Test]
+ public void TestBlockLoadViaMouseMovement()
+ {
+ AddStep("load dummy beatmap", () => stack.Push(loader = new TestPlayerLoader(() => new TestPlayer(false, false))));
+ AddUntilStep("wait for current", () => loader.IsCurrentScreen());
+ AddRepeatStep("move mouse", () => InputManager.MoveMouseTo(loader.VisualSettings.ScreenSpaceDrawQuad.TopLeft + (loader.VisualSettings.ScreenSpaceDrawQuad.BottomRight - loader.VisualSettings.ScreenSpaceDrawQuad.TopLeft) * RNG.NextSingle()), 20);
+ AddAssert("loader still active", () => loader.IsCurrentScreen());
+ AddUntilStep("loads after idle", () => !loader.IsCurrentScreen());
+ }
+
[Test]
public void TestLoadContinuation()
{
Player player = null;
SlowLoadPlayer slowPlayer = null;
- AddStep("load dummy beatmap", () => stack.Push(loader = new PlayerLoader(() => player = new TestPlayer(false, false))));
+ AddStep("load dummy beatmap", () => stack.Push(loader = new TestPlayerLoader(() => player = new TestPlayer(false, false))));
AddUntilStep("wait for current", () => loader.IsCurrentScreen());
AddStep("mouse in centre", () => InputManager.MoveMouseTo(loader.ScreenSpaceDrawQuad.Centre));
AddUntilStep("wait for player to be current", () => player.IsCurrentScreen());
AddStep("load slow dummy beatmap", () =>
{
- stack.Push(loader = new PlayerLoader(() => slowPlayer = new SlowLoadPlayer(false, false)));
+ stack.Push(loader = new TestPlayerLoader(() => slowPlayer = new SlowLoadPlayer(false, false)));
Scheduler.AddDelayed(() => slowPlayer.AllowLoad.Set(), 5000);
});
@@ -61,7 +73,7 @@ namespace osu.Game.Tests.Visual.Gameplay
AddStep("load player", () =>
{
Mods.Value = new[] { gameMod = new TestMod() };
- stack.Push(loader = new PlayerLoader(() => player = new TestPlayer()));
+ stack.Push(loader = new TestPlayerLoader(() => player = new TestPlayer()));
});
AddUntilStep("wait for loader to become current", () => loader.IsCurrentScreen());
@@ -85,6 +97,16 @@ namespace osu.Game.Tests.Visual.Gameplay
AddAssert("player mods applied", () => playerMod2.Applied);
}
+ private class TestPlayerLoader : PlayerLoader
+ {
+ public new VisualSettings VisualSettings => base.VisualSettings;
+
+ public TestPlayerLoader(Func createPlayer)
+ : base(createPlayer)
+ {
+ }
+ }
+
private class TestMod : Mod, IApplicableToScoreProcessor
{
public override string Name => string.Empty;
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkipOverlay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkipOverlay.cs
index 0519660477..b152c21454 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkipOverlay.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkipOverlay.cs
@@ -1,19 +1,88 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
+using System.Linq;
using NUnit.Framework;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Timing;
using osu.Game.Screens.Play;
+using osuTK;
+using osuTK.Input;
namespace osu.Game.Tests.Visual.Gameplay
{
[TestFixture]
- public class TestSceneSkipOverlay : OsuTestScene
+ public class TestSceneSkipOverlay : ManualInputManagerTestScene
{
- protected override void LoadComplete()
- {
- base.LoadComplete();
+ private SkipOverlay skip;
+ private int requestCount;
- Add(new SkipOverlay(Clock.CurrentTime + 5000));
+ [SetUp]
+ public void SetUp() => Schedule(() =>
+ {
+ requestCount = 0;
+ Child = new Container
+ {
+ RelativeSizeAxes = Axes.Both,
+ Clock = new FramedOffsetClock(Clock)
+ {
+ Offset = -Clock.CurrentTime,
+ },
+ Children = new Drawable[]
+ {
+ skip = new SkipOverlay(6000)
+ {
+ RequestSeek = _ => requestCount++
+ }
+ },
+ };
+ });
+
+ [Test]
+ public void TestFadeOnIdle()
+ {
+ AddStep("move mouse", () => InputManager.MoveMouseTo(Vector2.Zero));
+ AddUntilStep("fully visible", () => skip.Children.First().Alpha == 1);
+ AddUntilStep("wait for fade", () => skip.Children.First().Alpha < 1);
+
+ AddStep("move mouse", () => InputManager.MoveMouseTo(skip.ScreenSpaceDrawQuad.Centre));
+ AddUntilStep("fully visible", () => skip.Children.First().Alpha == 1);
+ AddUntilStep("wait for fade", () => skip.Children.First().Alpha < 1);
}
+
+ [Test]
+ public void TestClickableAfterFade()
+ {
+ AddStep("move mouse", () => InputManager.MoveMouseTo(skip.ScreenSpaceDrawQuad.Centre));
+ AddUntilStep("wait for fade", () => skip.Children.First().Alpha == 0);
+ AddStep("click", () => InputManager.Click(MouseButton.Left));
+ checkRequestCount(1);
+ }
+
+ [Test]
+ public void TestClickOnlyActuatesOnce()
+ {
+ AddStep("move mouse", () => InputManager.MoveMouseTo(skip.ScreenSpaceDrawQuad.Centre));
+ AddStep("click", () => InputManager.Click(MouseButton.Left));
+ AddStep("click", () => InputManager.Click(MouseButton.Left));
+ AddStep("click", () => InputManager.Click(MouseButton.Left));
+ AddStep("click", () => InputManager.Click(MouseButton.Left));
+ checkRequestCount(1);
+ }
+
+ [Test]
+ public void TestDoesntFadeOnMouseDown()
+ {
+ AddStep("move mouse", () => InputManager.MoveMouseTo(skip.ScreenSpaceDrawQuad.Centre));
+ AddStep("button down", () => InputManager.PressButton(MouseButton.Left));
+ AddUntilStep("wait for overlay disapper", () => !skip.IsAlive);
+ AddAssert("ensure button didn't disappear", () => skip.Children.First().Alpha > 0);
+ AddStep("button up", () => InputManager.ReleaseButton(MouseButton.Left));
+ checkRequestCount(0);
+ }
+
+ private void checkRequestCount(int expected) =>
+ AddAssert($"request count is {expected}", () => requestCount == expected);
}
}
diff --git a/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs
index a9c44c9020..daee419b52 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs
@@ -108,6 +108,7 @@ namespace osu.Game.Tests.Visual.Online
{
StarDifficulty = 9.99,
Version = @"TEST",
+ Length = 456000,
Ruleset = maniaRuleset,
BaseDifficulty = new BeatmapDifficulty
{
@@ -118,7 +119,6 @@ namespace osu.Game.Tests.Visual.Online
},
OnlineInfo = new BeatmapOnlineInfo
{
- Length = 456000,
CircleCount = 111,
SliderCount = 12,
PlayCount = 222,
@@ -181,6 +181,7 @@ namespace osu.Game.Tests.Visual.Online
{
StarDifficulty = 5.67,
Version = @"ANOTHER TEST",
+ Length = 123000,
Ruleset = taikoRuleset,
BaseDifficulty = new BeatmapDifficulty
{
@@ -191,7 +192,6 @@ namespace osu.Game.Tests.Visual.Online
},
OnlineInfo = new BeatmapOnlineInfo
{
- Length = 123000,
CircleCount = 123,
SliderCount = 45,
PlayCount = 567,
diff --git a/osu.Game.Tests/Visual/Online/TestSceneChangelogOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneChangelogOverlay.cs
index 0655611230..cf8bac7642 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneChangelogOverlay.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneChangelogOverlay.cs
@@ -24,6 +24,7 @@ namespace osu.Game.Tests.Visual.Online
typeof(ChangelogListing),
typeof(ChangelogSingleBuild),
typeof(ChangelogBuild),
+ typeof(Comments),
};
protected override void LoadComplete()
diff --git a/osu.Game.Tests/Visual/Online/TestSceneChannelTabControl.cs b/osu.Game.Tests/Visual/Online/TestSceneChannelTabControl.cs
index 364c986723..16e47c5df9 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneChannelTabControl.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneChannelTabControl.cs
@@ -70,7 +70,7 @@ namespace osu.Game.Tests.Visual.Online
});
channelTabControl.OnRequestLeave += channel => channelTabControl.RemoveChannel(channel);
- channelTabControl.Current.ValueChanged += channel => currentText.Text = "Currently selected channel: " + channel.NewValue.ToString();
+ channelTabControl.Current.ValueChanged += channel => currentText.Text = "Currently selected channel: " + channel.NewValue;
AddStep("Add random private channel", addRandomPrivateChannel);
AddAssert("There is only one channels", () => channelTabControl.Items.Count() == 2);
diff --git a/osu.Game.Tests/Visual/Online/TestSceneHistoricalSection.cs b/osu.Game.Tests/Visual/Online/TestSceneHistoricalSection.cs
index 883f0c5e3f..838347800f 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneHistoricalSection.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneHistoricalSection.cs
@@ -22,7 +22,7 @@ namespace osu.Game.Tests.Visual.Online
{
typeof(HistoricalSection),
typeof(PaginatedMostPlayedBeatmapContainer),
- typeof(DrawableMostPlayedRow),
+ typeof(DrawableMostPlayedBeatmap),
typeof(DrawableProfileRow)
};
diff --git a/osu.Game.Tests/Visual/Online/TestSceneScoresContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneScoresContainer.cs
index 06414af865..b26de1984a 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneScoresContainer.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneScoresContainer.cs
@@ -3,19 +3,18 @@
using System;
using System.Collections.Generic;
-using System.Linq;
-using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.MathUtils;
-using osu.Game.Graphics;
+using osu.Game.Online.API.Requests.Responses;
using osu.Game.Overlays.BeatmapSet.Scores;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Rulesets.Scoring;
using osu.Game.Scoring;
using osu.Game.Users;
+using osuTK.Graphics;
namespace osu.Game.Tests.Visual.Online
{
@@ -30,11 +29,9 @@ namespace osu.Game.Tests.Visual.Online
typeof(ScoreTableRowBackground),
};
- private readonly Box background;
-
public TestSceneScoresContainer()
{
- ScoresContainer scoresContainer;
+ TestScoresContainer scoresContainer;
Child = new Container
{
@@ -44,108 +41,137 @@ namespace osu.Game.Tests.Visual.Online
Width = 0.8f,
Children = new Drawable[]
{
- background = new Box { RelativeSizeAxes = Axes.Both },
- scoresContainer = new ScoresContainer(),
+ new Box
+ {
+ RelativeSizeAxes = Axes.Both,
+ Colour = Color4.Black,
+ },
+ scoresContainer = new TestScoresContainer(),
}
};
- var scores = new List
+ var allScores = new APILegacyScores
{
- new ScoreInfo
+ Scores = new List
{
- User = new User
+ new APILegacyScoreInfo
{
- Id = 6602580,
- Username = @"waaiiru",
- Country = new Country
+ User = new User
{
- FullName = @"Spain",
- FlagName = @"ES",
+ Id = 6602580,
+ Username = @"waaiiru",
+ Country = new Country
+ {
+ FullName = @"Spain",
+ FlagName = @"ES",
+ },
},
- },
- Mods = new Mod[]
- {
- new OsuModDoubleTime(),
- new OsuModHidden(),
- new OsuModFlashlight(),
- new OsuModHardRock(),
- },
- Rank = ScoreRank.XH,
- PP = 200,
- MaxCombo = 1234,
- TotalScore = 1234567890,
- Accuracy = 1,
- },
- new ScoreInfo
- {
- User = new User
- {
- Id = 4608074,
- Username = @"Skycries",
- Country = new Country
+ Mods = new Mod[]
{
- FullName = @"Brazil",
- FlagName = @"BR",
+ new OsuModDoubleTime(),
+ new OsuModHidden(),
+ new OsuModFlashlight(),
+ new OsuModHardRock(),
},
+ Rank = ScoreRank.XH,
+ PP = 200,
+ MaxCombo = 1234,
+ TotalScore = 1234567890,
+ Accuracy = 1,
},
- Mods = new Mod[]
+ new APILegacyScoreInfo
{
- new OsuModDoubleTime(),
- new OsuModHidden(),
- new OsuModFlashlight(),
- },
- Rank = ScoreRank.S,
- PP = 190,
- MaxCombo = 1234,
- TotalScore = 1234789,
- Accuracy = 0.9997,
- },
- new ScoreInfo
- {
- User = new User
- {
- Id = 1014222,
- Username = @"eLy",
- Country = new Country
+ User = new User
{
- FullName = @"Japan",
- FlagName = @"JP",
+ Id = 4608074,
+ Username = @"Skycries",
+ Country = new Country
+ {
+ FullName = @"Brazil",
+ FlagName = @"BR",
+ },
},
- },
- Mods = new Mod[]
- {
- new OsuModDoubleTime(),
- new OsuModHidden(),
- },
- Rank = ScoreRank.B,
- PP = 180,
- MaxCombo = 1234,
- TotalScore = 12345678,
- Accuracy = 0.9854,
- },
- new ScoreInfo
- {
- User = new User
- {
- Id = 1541390,
- Username = @"Toukai",
- Country = new Country
+ Mods = new Mod[]
{
- FullName = @"Canada",
- FlagName = @"CA",
+ new OsuModDoubleTime(),
+ new OsuModHidden(),
+ new OsuModFlashlight(),
},
+ Rank = ScoreRank.S,
+ PP = 190,
+ MaxCombo = 1234,
+ TotalScore = 1234789,
+ Accuracy = 0.9997,
},
- Mods = new Mod[]
+ new APILegacyScoreInfo
{
- new OsuModDoubleTime(),
+ User = new User
+ {
+ Id = 1014222,
+ Username = @"eLy",
+ Country = new Country
+ {
+ FullName = @"Japan",
+ FlagName = @"JP",
+ },
+ },
+ Mods = new Mod[]
+ {
+ new OsuModDoubleTime(),
+ new OsuModHidden(),
+ },
+ Rank = ScoreRank.B,
+ PP = 180,
+ MaxCombo = 1234,
+ TotalScore = 12345678,
+ Accuracy = 0.9854,
},
- Rank = ScoreRank.C,
- PP = 170,
- MaxCombo = 1234,
- TotalScore = 1234567,
- Accuracy = 0.8765,
- },
- new ScoreInfo
+ new APILegacyScoreInfo
+ {
+ User = new User
+ {
+ Id = 1541390,
+ Username = @"Toukai",
+ Country = new Country
+ {
+ FullName = @"Canada",
+ FlagName = @"CA",
+ },
+ },
+ Mods = new Mod[]
+ {
+ new OsuModDoubleTime(),
+ },
+ Rank = ScoreRank.C,
+ PP = 170,
+ MaxCombo = 1234,
+ TotalScore = 1234567,
+ Accuracy = 0.8765,
+ },
+ new APILegacyScoreInfo
+ {
+ User = new User
+ {
+ Id = 7151382,
+ Username = @"Mayuri Hana",
+ Country = new Country
+ {
+ FullName = @"Thailand",
+ FlagName = @"TH",
+ },
+ },
+ Rank = ScoreRank.D,
+ PP = 160,
+ MaxCombo = 1234,
+ TotalScore = 123456,
+ Accuracy = 0.6543,
+ },
+ }
+ };
+
+ var myBestScore = new APILegacyUserTopScoreInfo
+ {
+ Score = new APILegacyScoreInfo
{
User = new User
{
@@ -163,9 +189,42 @@ namespace osu.Game.Tests.Visual.Online
TotalScore = 123456,
Accuracy = 0.6543,
},
+ Position = 1337,
};
- foreach (var s in scores)
+ var oneScore = new APILegacyScores
+ {
+ Scores = new List
+ {
+ new APILegacyScoreInfo
+ {
+ User = new User
+ {
+ Id = 6602580,
+ Username = @"waaiiru",
+ Country = new Country
+ {
+ FullName = @"Spain",
+ FlagName = @"ES",
+ },
+ },
+ Mods = new Mod[]
+ {
+ new OsuModDoubleTime(),
+ new OsuModHidden(),
+ new OsuModFlashlight(),
+ new OsuModHardRock(),
+ },
+ Rank = ScoreRank.XH,
+ PP = 200,
+ MaxCombo = 1234,
+ TotalScore = 1234567890,
+ Accuracy = 1,
+ }
+ }
+ };
+
+ foreach (var s in allScores.Scores)
{
s.Statistics.Add(HitResult.Great, RNG.Next(2000));
s.Statistics.Add(HitResult.Good, RNG.Next(2000));
@@ -173,15 +232,26 @@ namespace osu.Game.Tests.Visual.Online
s.Statistics.Add(HitResult.Miss, RNG.Next(2000));
}
- AddStep("Load all scores", () => scoresContainer.Scores = scores);
+ AddStep("Load all scores", () =>
+ {
+ allScores.UserScore = null;
+ scoresContainer.Scores = allScores;
+ });
AddStep("Load null scores", () => scoresContainer.Scores = null);
- AddStep("Load only one score", () => scoresContainer.Scores = new[] { scores.First() });
+ AddStep("Load only one score", () => scoresContainer.Scores = oneScore);
+ AddStep("Load scores with my best", () =>
+ {
+ allScores.UserScore = myBestScore;
+ scoresContainer.Scores = allScores;
+ });
}
- [BackgroundDependencyLoader]
- private void load(OsuColour colours)
+ private class TestScoresContainer : ScoresContainer
{
- background.Colour = colours.Gray2;
+ public new APILegacyScores Scores
+ {
+ set => base.Scores = value;
+ }
}
}
}
diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneLeaderboard.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneLeaderboard.cs
index 157e572606..8e358a77db 100644
--- a/osu.Game.Tests/Visual/SongSelect/TestSceneLeaderboard.cs
+++ b/osu.Game.Tests/Visual/SongSelect/TestSceneLeaderboard.cs
@@ -4,12 +4,9 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
-using System.Linq;
-using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Game.Beatmaps;
using osu.Game.Online.Leaderboards;
-using osu.Game.Rulesets;
using osu.Game.Scoring;
using osu.Game.Screens.Select.Leaderboards;
using osu.Game.Users;
@@ -27,8 +24,6 @@ namespace osu.Game.Tests.Visual.SongSelect
typeof(RetrievalFailurePlaceholder),
};
- private RulesetStore rulesets;
-
private readonly FailableLeaderboard leaderboard;
public TestSceneLeaderboard()
@@ -47,13 +42,8 @@ namespace osu.Game.Tests.Visual.SongSelect
AddStep(@"No supporter", () => leaderboard.SetRetrievalState(PlaceholderState.NotSupporter));
AddStep(@"Not logged in", () => leaderboard.SetRetrievalState(PlaceholderState.NotLoggedIn));
AddStep(@"Unavailable", () => leaderboard.SetRetrievalState(PlaceholderState.Unavailable));
- AddStep(@"Real beatmap", realBeatmap);
- }
-
- [BackgroundDependencyLoader]
- private void load(RulesetStore rulesets)
- {
- this.rulesets = rulesets;
+ foreach (BeatmapSetOnlineStatus status in Enum.GetValues(typeof(BeatmapSetOnlineStatus)))
+ AddStep($"{status} beatmap", () => showBeatmapWithStatus(status));
}
private void newScores()
@@ -245,34 +235,12 @@ namespace osu.Game.Tests.Visual.SongSelect
leaderboard.Scores = scores;
}
- private void realBeatmap()
+ private void showBeatmapWithStatus(BeatmapSetOnlineStatus status)
{
leaderboard.Beatmap = new BeatmapInfo
{
- StarDifficulty = 1.36,
- Version = @"BASIC",
OnlineBeatmapID = 1113057,
- Ruleset = rulesets.GetRuleset(0),
- BaseDifficulty = new BeatmapDifficulty
- {
- CircleSize = 4,
- DrainRate = 6.5f,
- OverallDifficulty = 6.5f,
- ApproachRate = 5,
- },
- OnlineInfo = new BeatmapOnlineInfo
- {
- Length = 115000,
- CircleCount = 265,
- SliderCount = 71,
- PlayCount = 47906,
- PassCount = 19899,
- },
- Metrics = new BeatmapMetrics
- {
- Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(),
- Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(),
- },
+ Status = status,
};
}
diff --git a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs
index 962e0fb362..f3255814f2 100644
--- a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs
+++ b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs
@@ -133,6 +133,9 @@ namespace osu.Game.Tests.Visual.SongSelect
AddStep(@"Sort by Artist", delegate { songSelect.FilterControl.Sort = SortMode.Artist; });
AddStep(@"Sort by Title", delegate { songSelect.FilterControl.Sort = SortMode.Title; });
AddStep(@"Sort by Author", delegate { songSelect.FilterControl.Sort = SortMode.Author; });
+ AddStep(@"Sort by DateAdded", delegate { songSelect.FilterControl.Sort = SortMode.DateAdded; });
+ AddStep(@"Sort by BPM", delegate { songSelect.FilterControl.Sort = SortMode.BPM; });
+ AddStep(@"Sort by Length", delegate { songSelect.FilterControl.Sort = SortMode.Length; });
AddStep(@"Sort by Difficulty", delegate { songSelect.FilterControl.Sort = SortMode.Difficulty; });
}
@@ -265,16 +268,21 @@ namespace osu.Game.Tests.Visual.SongSelect
{
int beatmapId = setId * 10 + i;
+ int length = RNG.Next(30000, 200000);
+ double bpm = RNG.NextSingle(80, 200);
+
beatmaps.Add(new BeatmapInfo
{
Ruleset = getRuleset(),
OnlineBeatmapID = beatmapId,
Path = "normal.osu",
- Version = $"{beatmapId}",
+ Version = $"{beatmapId} (length {TimeSpan.FromMilliseconds(length):m\\:ss}, bpm {bpm:0.#})",
+ Length = length,
+ BPM = bpm,
BaseDifficulty = new BeatmapDifficulty
{
OverallDifficulty = 3.5f,
- }
+ },
});
}
@@ -286,10 +294,11 @@ namespace osu.Game.Tests.Visual.SongSelect
{
// Create random metadata, then we can check if sorting works based on these
Artist = "Some Artist " + RNG.Next(0, 9),
- Title = $"Some Song (set id {setId})",
+ Title = $"Some Song (set id {setId}, max bpm {beatmaps.Max(b => b.BPM):0.#})",
AuthorString = "Some Guy " + RNG.Next(0, 9),
},
- Beatmaps = beatmaps
+ Beatmaps = beatmaps,
+ DateAdded = DateTimeOffset.UtcNow,
};
}
}
diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneBackButton.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneBackButton.cs
index 867b3130c9..38a9af05d8 100644
--- a/osu.Game.Tests/Visual/UserInterface/TestSceneBackButton.cs
+++ b/osu.Game.Tests/Visual/UserInterface/TestSceneBackButton.cs
@@ -14,8 +14,6 @@ namespace osu.Game.Tests.Visual.UserInterface
{
public class TestSceneBackButton : OsuTestScene
{
- private readonly BackButton button;
-
public override IReadOnlyList RequiredTypes => new[]
{
typeof(TwoLayerButton)
@@ -23,6 +21,8 @@ namespace osu.Game.Tests.Visual.UserInterface
public TestSceneBackButton()
{
+ BackButton button;
+
Child = new Container
{
Anchor = Anchor.Centre,
@@ -40,11 +40,12 @@ namespace osu.Game.Tests.Visual.UserInterface
{
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
- Action = () => button.Hide(),
}
}
};
+ button.Action = () => button.Hide();
+
AddStep("show button", () => button.Show());
AddStep("hide button", () => button.Hide());
}
diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneButtonSystem.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneButtonSystem.cs
index c8cc864089..f0e1c38525 100644
--- a/osu.Game.Tests/Visual/UserInterface/TestSceneButtonSystem.cs
+++ b/osu.Game.Tests/Visual/UserInterface/TestSceneButtonSystem.cs
@@ -9,6 +9,7 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Shapes;
using osu.Game.Screens.Menu;
+using osuTK;
using osuTK.Graphics;
namespace osu.Game.Tests.Visual.UserInterface
@@ -23,11 +24,12 @@ namespace osu.Game.Tests.Visual.UserInterface
typeof(Button)
};
- public TestSceneButtonSystem()
- {
- OsuLogo logo;
- ButtonSystem buttons;
+ private OsuLogo logo;
+ private ButtonSystem buttons;
+ [SetUp]
+ public void SetUp() => Schedule(() =>
+ {
Children = new Drawable[]
{
new Box
@@ -36,13 +38,47 @@ namespace osu.Game.Tests.Visual.UserInterface
RelativeSizeAxes = Axes.Both,
},
buttons = new ButtonSystem(),
- logo = new OsuLogo { RelativePositionAxes = Axes.Both }
+ logo = new OsuLogo
+ {
+ RelativePositionAxes = Axes.Both,
+ Position = new Vector2(0.5f)
+ }
};
buttons.SetOsuLogo(logo);
+ });
+ [Test]
+ public void TestAllStates()
+ {
foreach (var s in Enum.GetValues(typeof(ButtonSystemState)).OfType().Skip(1))
AddStep($"State to {s}", () => buttons.State = s);
+
+ AddStep("Enter mode", performEnterMode);
+
+ AddStep("Return to menu", () =>
+ {
+ buttons.State = ButtonSystemState.Play;
+ buttons.FadeIn(MainMenu.FADE_IN_DURATION, Easing.OutQuint);
+ buttons.MoveTo(new Vector2(0), MainMenu.FADE_IN_DURATION, Easing.OutQuint);
+ logo.FadeColour(Color4.White, 100, Easing.OutQuint);
+ logo.FadeIn(100, Easing.OutQuint);
+ });
+ }
+
+ [Test]
+ public void TestSmoothExit()
+ {
+ AddStep("Enter mode", performEnterMode);
+ }
+
+ private void performEnterMode()
+ {
+ buttons.State = ButtonSystemState.EnteringMode;
+ buttons.FadeOut(MainMenu.FADE_OUT_DURATION, Easing.InSine);
+ buttons.MoveTo(new Vector2(-800, 0), MainMenu.FADE_OUT_DURATION, Easing.InSine);
+ logo.FadeOut(300, Easing.InSine)
+ .ScaleTo(0.2f, 300, Easing.InSine);
}
}
}
diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneScreenBreadcrumbControl.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneScreenBreadcrumbControl.cs
index 9c83fdf96c..0cb8683d72 100644
--- a/osu.Game.Tests/Visual/UserInterface/TestSceneScreenBreadcrumbControl.cs
+++ b/osu.Game.Tests/Visual/UserInterface/TestSceneScreenBreadcrumbControl.cs
@@ -48,7 +48,7 @@ namespace osu.Game.Tests.Visual.UserInterface
},
};
- breadcrumbs.Current.ValueChanged += screen => titleText.Text = $"Changed to {screen.NewValue.ToString()}";
+ breadcrumbs.Current.ValueChanged += screen => titleText.Text = $"Changed to {screen.NewValue}";
breadcrumbs.Current.TriggerChange();
waitForCurrent();
diff --git a/osu.Game.Tests/osu.Game.Tests.csproj b/osu.Game.Tests/osu.Game.Tests.csproj
index 11d70ee7be..659f5415c3 100644
--- a/osu.Game.Tests/osu.Game.Tests.csproj
+++ b/osu.Game.Tests/osu.Game.Tests.csproj
@@ -3,7 +3,7 @@
-
+
diff --git a/osu.Game.Tournament.Tests/osu.Game.Tournament.Tests.csproj b/osu.Game.Tournament.Tests/osu.Game.Tournament.Tests.csproj
index 1c169184fb..dad2fe0877 100644
--- a/osu.Game.Tournament.Tests/osu.Game.Tournament.Tests.csproj
+++ b/osu.Game.Tournament.Tests/osu.Game.Tournament.Tests.csproj
@@ -5,9 +5,9 @@
-
+
-
+
WinExe
diff --git a/osu.Game.Tournament/Components/SongBar.cs b/osu.Game.Tournament/Components/SongBar.cs
index c07882ddd0..7005c068ae 100644
--- a/osu.Game.Tournament/Components/SongBar.cs
+++ b/osu.Game.Tournament/Components/SongBar.cs
@@ -159,7 +159,7 @@ namespace osu.Game.Tournament.Components
}
var bpm = beatmap.BeatmapSet.OnlineInfo.BPM;
- var length = beatmap.OnlineInfo.Length;
+ var length = beatmap.Length;
string hardRockExtra = "";
string srExtra = "";
@@ -180,7 +180,7 @@ namespace osu.Game.Tournament.Components
panelContents.Children = new Drawable[]
{
- new DiffPiece(("Length", TimeSpan.FromSeconds(length).ToString(@"mm\:ss")))
+ new DiffPiece(("Length", TimeSpan.FromMilliseconds(length).ToString(@"mm\:ss")))
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.BottomLeft,
diff --git a/osu.Game.Tournament/Screens/MapPool/MapPoolScreen.cs b/osu.Game.Tournament/Screens/MapPool/MapPoolScreen.cs
index 46d4cfa98c..d32c0d6156 100644
--- a/osu.Game.Tournament/Screens/MapPool/MapPoolScreen.cs
+++ b/osu.Game.Tournament/Screens/MapPool/MapPoolScreen.cs
@@ -47,8 +47,8 @@ namespace osu.Game.Tournament.Screens.MapPool
mapFlows = new FillFlowContainer>
{
Y = 100,
- Spacing = new Vector2(10, 20),
- Padding = new MarginPadding(50),
+ Spacing = new Vector2(10, 10),
+ Padding = new MarginPadding(25),
Direction = FillDirection.Vertical,
RelativeSizeAxes = Axes.Both,
},
@@ -218,7 +218,7 @@ namespace osu.Game.Tournament.Screens.MapPool
{
mapFlows.Add(currentFlow = new FillFlowContainer
{
- Spacing = new Vector2(10, 20),
+ Spacing = new Vector2(10, 5),
Direction = FillDirection.Full,
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y
diff --git a/osu.Game.Tournament/Screens/Showcase/ShowcaseScreen.cs b/osu.Game.Tournament/Screens/Showcase/ShowcaseScreen.cs
index d809dfc994..20928499bf 100644
--- a/osu.Game.Tournament/Screens/Showcase/ShowcaseScreen.cs
+++ b/osu.Game.Tournament/Screens/Showcase/ShowcaseScreen.cs
@@ -10,7 +10,7 @@ namespace osu.Game.Tournament.Screens.Showcase
[BackgroundDependencyLoader]
private void load()
{
- AddInternal(new TournamentLogo());
+ AddInternal(new TournamentLogo(false));
}
}
}
diff --git a/osu.Game.Tournament/Screens/TeamWin/TeamWinScreen.cs b/osu.Game.Tournament/Screens/TeamWin/TeamWinScreen.cs
index efe4ee92fc..a0216c5db3 100644
--- a/osu.Game.Tournament/Screens/TeamWin/TeamWinScreen.cs
+++ b/osu.Game.Tournament/Screens/TeamWin/TeamWinScreen.cs
@@ -45,7 +45,7 @@ namespace osu.Game.Tournament.Screens.TeamWin
RelativeSizeAxes = Axes.Both,
Loop = true,
},
- new TournamentLogo
+ new TournamentLogo(false)
{
Y = 40,
},
diff --git a/osu.Game/Beatmaps/BeatmapInfo.cs b/osu.Game/Beatmaps/BeatmapInfo.cs
index 3c082bb71e..8042f6b4b9 100644
--- a/osu.Game/Beatmaps/BeatmapInfo.cs
+++ b/osu.Game/Beatmaps/BeatmapInfo.cs
@@ -51,6 +51,16 @@ namespace osu.Game.Beatmaps
[NotMapped]
public BeatmapOnlineInfo OnlineInfo { get; set; }
+ ///
+ /// The playable length in milliseconds of this beatmap.
+ ///
+ public double Length { get; set; }
+
+ ///
+ /// The most common BPM of this beatmap.
+ ///
+ public double BPM { get; set; }
+
public string Path { get; set; }
[JsonProperty("file_sha2")]
diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs
index 7ef50da7d3..166ba5111c 100644
--- a/osu.Game/Beatmaps/BeatmapManager.cs
+++ b/osu.Game/Beatmaps/BeatmapManager.cs
@@ -23,6 +23,7 @@ using osu.Game.IO.Archives;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests;
using osu.Game.Rulesets;
+using osu.Game.Rulesets.Objects.Types;
namespace osu.Game.Beatmaps
{
@@ -180,19 +181,18 @@ namespace osu.Game.Beatmaps
lock (workingCache)
{
- var cached = workingCache.FirstOrDefault(w => w.BeatmapInfo?.ID == beatmapInfo.ID);
+ var working = workingCache.FirstOrDefault(w => w.BeatmapInfo?.ID == beatmapInfo.ID);
- if (cached != null)
- return cached;
+ if (working == null)
+ {
+ if (beatmapInfo.Metadata == null)
+ beatmapInfo.Metadata = beatmapInfo.BeatmapSet.Metadata;
- if (beatmapInfo.Metadata == null)
- beatmapInfo.Metadata = beatmapInfo.BeatmapSet.Metadata;
-
- WorkingBeatmap working = new BeatmapManagerWorkingBeatmap(Files.Store, new LargeTextureStore(host?.CreateTextureLoaderStore(Files.Store)), beatmapInfo, audioManager);
+ workingCache.Add(working = new BeatmapManagerWorkingBeatmap(Files.Store,
+ new LargeTextureStore(host?.CreateTextureLoaderStore(Files.Store)), beatmapInfo, audioManager));
+ }
previous?.TransferTo(working);
- workingCache.Add(working);
-
return working;
}
}
@@ -302,6 +302,8 @@ namespace osu.Game.Beatmaps
beatmap.BeatmapInfo.Ruleset = ruleset;
// TODO: this should be done in a better place once we actually need to dynamically update it.
beatmap.BeatmapInfo.StarDifficulty = ruleset?.CreateInstance().CreateDifficultyCalculator(new DummyConversionBeatmap(beatmap)).Calculate().StarRating ?? 0;
+ beatmap.BeatmapInfo.Length = calculateLength(beatmap);
+ beatmap.BeatmapInfo.BPM = beatmap.ControlPointInfo.BPMMode;
beatmapInfos.Add(beatmap.BeatmapInfo);
}
@@ -310,6 +312,19 @@ namespace osu.Game.Beatmaps
return beatmapInfos;
}
+ private double calculateLength(IBeatmap b)
+ {
+ if (!b.HitObjects.Any())
+ return 0;
+
+ var lastObject = b.HitObjects.Last();
+
+ double endTime = (lastObject as IHasEndTime)?.EndTime ?? lastObject.StartTime;
+ double startTime = b.HitObjects.First().StartTime;
+
+ return endTime - startTime;
+ }
+
///
/// A dummy WorkingBeatmap for the purpose of retrieving a beatmap for star difficulty calculation.
///
@@ -371,7 +386,7 @@ namespace osu.Game.Beatmaps
beatmap.OnlineBeatmapID = res.OnlineBeatmapID;
};
- req.Failure += e => { LogForModel(set, $"Online retrieval failed for {beatmap}", e); };
+ req.Failure += e => { LogForModel(set, $"Online retrieval failed for {beatmap} ({e.Message})"); };
// intentionally blocking to limit web request concurrency
req.Perform(api);
diff --git a/osu.Game/Beatmaps/BeatmapOnlineInfo.cs b/osu.Game/Beatmaps/BeatmapOnlineInfo.cs
index faae74db88..bfeacd9bfc 100644
--- a/osu.Game/Beatmaps/BeatmapOnlineInfo.cs
+++ b/osu.Game/Beatmaps/BeatmapOnlineInfo.cs
@@ -8,11 +8,6 @@ namespace osu.Game.Beatmaps
///
public class BeatmapOnlineInfo
{
- ///
- /// The length in milliseconds of this beatmap's song.
- ///
- public double Length { get; set; }
-
///
/// The amount of circles in this beatmap.
///
diff --git a/osu.Game/Beatmaps/BeatmapSetInfo.cs b/osu.Game/Beatmaps/BeatmapSetInfo.cs
index 524ed0ed56..03bc7c7312 100644
--- a/osu.Game/Beatmaps/BeatmapSetInfo.cs
+++ b/osu.Game/Beatmaps/BeatmapSetInfo.cs
@@ -35,8 +35,21 @@ namespace osu.Game.Beatmaps
[NotMapped]
public BeatmapSetMetrics Metrics { get; set; }
+ ///
+ /// The maximum star difficulty of all beatmaps in this set.
+ ///
public double MaxStarDifficulty => Beatmaps?.Max(b => b.StarDifficulty) ?? 0;
+ ///
+ /// The maximum playable length in milliseconds of all beatmaps in this set.
+ ///
+ public double MaxLength => Beatmaps?.Max(b => b.Length) ?? 0;
+
+ ///
+ /// The maximum BPM of all beatmaps in this set.
+ ///
+ public double MaxBPM => Beatmaps?.Max(b => b.BPM) ?? 0;
+
[NotMapped]
public bool DeletePending { get; set; }
diff --git a/osu.Game/Beatmaps/BeatmapSetOnlineInfo.cs b/osu.Game/Beatmaps/BeatmapSetOnlineInfo.cs
index ea3f0b61b9..df3a45d1cc 100644
--- a/osu.Game/Beatmaps/BeatmapSetOnlineInfo.cs
+++ b/osu.Game/Beatmaps/BeatmapSetOnlineInfo.cs
@@ -66,6 +66,11 @@ namespace osu.Game.Beatmaps
///
public int FavouriteCount { get; set; }
+ ///
+ /// Whether this beatmap set has been favourited by the current user.
+ ///
+ public bool HasFavourited { get; set; }
+
///
/// The availability of this beatmap set.
///
diff --git a/osu.Game/Beatmaps/Drawables/UpdateableBeatmapBackgroundSprite.cs b/osu.Game/Beatmaps/Drawables/UpdateableBeatmapBackgroundSprite.cs
index 1fd3502799..30346a8a96 100644
--- a/osu.Game/Beatmaps/Drawables/UpdateableBeatmapBackgroundSprite.cs
+++ b/osu.Game/Beatmaps/Drawables/UpdateableBeatmapBackgroundSprite.cs
@@ -35,15 +35,15 @@ namespace osu.Game.Beatmaps.Drawables
protected override DelayedLoadWrapper CreateDelayedLoadWrapper(Func createContentFunc, double timeBeforeLoad)
=> new DelayedLoadUnloadWrapper(createContentFunc, timeBeforeLoad, UnloadDelay);
+ protected override double TransformDuration => 400;
+
protected override Drawable CreateDrawable(BeatmapInfo model)
{
- Drawable drawable = getDrawableForModel(model);
-
+ var drawable = getDrawableForModel(model);
drawable.RelativeSizeAxes = Axes.Both;
drawable.Anchor = Anchor.Centre;
drawable.Origin = Anchor.Centre;
drawable.FillMode = FillMode.Fill;
- drawable.OnLoadComplete += d => d.FadeInFromZero(400);
return drawable;
}
diff --git a/osu.Game/Beatmaps/WorkingBeatmap.cs b/osu.Game/Beatmaps/WorkingBeatmap.cs
index 37aa0024da..949a2aab6f 100644
--- a/osu.Game/Beatmaps/WorkingBeatmap.cs
+++ b/osu.Game/Beatmaps/WorkingBeatmap.cs
@@ -247,7 +247,7 @@ namespace osu.Game.Beatmaps
// cancelling the beatmap load is safe for now since the retrieval is a synchronous
// operation. if we add an async retrieval method this may need to be reconsidered.
- beatmapCancellation.Cancel();
+ beatmapCancellation?.Cancel();
total_count.Value--;
}
diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs
index 795f0b43f7..1da7c7ec1d 100644
--- a/osu.Game/Configuration/OsuConfigManager.cs
+++ b/osu.Game/Configuration/OsuConfigManager.cs
@@ -77,6 +77,7 @@ namespace osu.Game.Configuration
Set(OsuSetting.BlurLevel, 0, 0, 1, 0.01);
Set(OsuSetting.ShowInterface, true);
+ Set(OsuSetting.ShowHealthDisplayWhenCantFail, true);
Set(OsuSetting.KeyOverlay, false);
Set(OsuSetting.FloatingComments, false);
@@ -131,6 +132,7 @@ namespace osu.Game.Configuration
KeyOverlay,
FloatingComments,
ShowInterface,
+ ShowHealthDisplayWhenCantFail,
MouseDisableButtons,
MouseDisableWheel,
AudioOffset,
diff --git a/osu.Game/Database/OsuDbContext.cs b/osu.Game/Database/OsuDbContext.cs
index 538ec41b3d..ea3318598f 100644
--- a/osu.Game/Database/OsuDbContext.cs
+++ b/osu.Game/Database/OsuDbContext.cs
@@ -41,6 +41,9 @@ namespace osu.Game.Database
{
// required to initialise native SQLite libraries on some platforms.
SQLitePCL.Batteries_V2.Init();
+
+ // https://github.com/aspnet/EntityFrameworkCore/issues/9994#issuecomment-508588678
+ SQLitePCL.raw.sqlite3_config(2 /*SQLITE_CONFIG_MULTITHREAD*/);
}
///
diff --git a/osu.Game/Graphics/Backgrounds/Background.cs b/osu.Game/Graphics/Backgrounds/Background.cs
index 526b3da8a6..d13475189d 100644
--- a/osu.Game/Graphics/Backgrounds/Background.cs
+++ b/osu.Game/Graphics/Backgrounds/Background.cs
@@ -16,7 +16,7 @@ namespace osu.Game.Graphics.Backgrounds
///
public class Background : CompositeDrawable
{
- public Sprite Sprite;
+ public readonly Sprite Sprite;
private readonly string textureName;
@@ -51,7 +51,7 @@ namespace osu.Game.Graphics.Backgrounds
/// A to which further transforms can be added.
public void BlurTo(Vector2 newBlurSigma, double duration = 0, Easing easing = Easing.None)
{
- if (bufferedContainer == null)
+ if (bufferedContainer == null && newBlurSigma != Vector2.Zero)
{
RemoveInternal(Sprite);
@@ -63,7 +63,7 @@ namespace osu.Game.Graphics.Backgrounds
});
}
- bufferedContainer.BlurTo(newBlurSigma, duration, easing);
+ bufferedContainer?.BlurTo(newBlurSigma, duration, easing);
}
}
}
diff --git a/osu.Game/Graphics/Backgrounds/Triangles.cs b/osu.Game/Graphics/Backgrounds/Triangles.cs
index 29113e0e2f..2b68e8530d 100644
--- a/osu.Game/Graphics/Backgrounds/Triangles.cs
+++ b/osu.Game/Graphics/Backgrounds/Triangles.cs
@@ -8,7 +8,6 @@ using osuTK.Graphics;
using System;
using osu.Framework.Graphics.Shaders;
using osu.Framework.Graphics.Textures;
-using osuTK.Graphics.ES30;
using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Primitives;
using osu.Framework.Allocation;
@@ -137,11 +136,13 @@ namespace osu.Game.Graphics.Backgrounds
}
}
+ protected int AimCount;
+
private void addTriangles(bool randomY)
{
- int aimTriangleCount = (int)(DrawWidth * DrawHeight * 0.002f / (triangleScale * triangleScale) * SpawnRatio);
+ AimCount = (int)(DrawWidth * DrawHeight * 0.002f / (triangleScale * triangleScale) * SpawnRatio);
- for (int i = 0; i < aimTriangleCount - parts.Count; i++)
+ for (int i = 0; i < AimCount - parts.Count; i++)
parts.Add(createTriangle(randomY));
}
@@ -190,7 +191,7 @@ namespace osu.Game.Graphics.Backgrounds
private readonly List parts = new List();
private Vector2 size;
- private readonly LinearBatch vertexBatch = new LinearBatch(100 * 3, 10, PrimitiveType.Triangles);
+ private TriangleBatch vertexBatch;
public TrianglesDrawNode(Triangles source)
: base(source)
@@ -213,6 +214,12 @@ namespace osu.Game.Graphics.Backgrounds
{
base.Draw(vertexAction);
+ if (Source.AimCount > 0 && (vertexBatch == null || vertexBatch.Size != Source.AimCount))
+ {
+ vertexBatch?.Dispose();
+ vertexBatch = new TriangleBatch(Source.AimCount, 1);
+ }
+
shader.Bind();
Vector2 localInflationAmount = edge_smoothness * DrawInfo.MatrixInverse.ExtractScale().Xy;
@@ -246,7 +253,7 @@ namespace osu.Game.Graphics.Backgrounds
{
base.Dispose(isDisposing);
- vertexBatch.Dispose();
+ vertexBatch?.Dispose();
}
}
diff --git a/osu.Game/Graphics/Containers/UserDimContainer.cs b/osu.Game/Graphics/Containers/UserDimContainer.cs
index fe9eb7baf4..03de5f651f 100644
--- a/osu.Game/Graphics/Containers/UserDimContainer.cs
+++ b/osu.Game/Graphics/Containers/UserDimContainer.cs
@@ -1,31 +1,26 @@
// 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 osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Configuration;
-using osu.Game.Graphics.Backgrounds;
-using osu.Game.Screens.Play;
-using osuTK;
using osuTK.Graphics;
namespace osu.Game.Graphics.Containers
{
///
/// A container that applies user-configured visual settings to its contents.
- /// This container specifies behavior that applies to both Storyboards and Backgrounds.
///
- public class UserDimContainer : Container
+ public abstract class UserDimContainer : Container
{
- private const float background_fade_duration = 800;
+ protected const float BACKGROUND_FADE_DURATION = 800;
///
/// Whether or not user-configured dim levels should be applied to the container.
///
- public readonly Bindable EnableUserDim = new Bindable();
+ public readonly Bindable EnableUserDim = new Bindable(true);
///
/// Whether or not the storyboard loaded should completely hide the background behind it.
@@ -33,103 +28,58 @@ namespace osu.Game.Graphics.Containers
public readonly Bindable StoryboardReplacesBackground = new Bindable();
///
- /// The amount of blur to be applied to the background in addition to user-specified blur.
+ /// Whether the content of this container is currently being displayed.
///
- ///
- /// Used in contexts where there can potentially be both user and screen-specified blurring occuring at the same time, such as in
- ///
- public readonly Bindable BlurAmount = new Bindable();
+ public bool ContentDisplayed { get; private set; }
- private Bindable userDimLevel { get; set; }
+ protected Bindable UserDimLevel { get; private set; }
- private Bindable userBlurLevel { get; set; }
+ protected Bindable ShowStoryboard { get; private set; }
- private Bindable showStoryboard { get; set; }
+ protected override Container Content => dimContent;
- protected Container DimContainer { get; }
-
- protected override Container Content => DimContainer;
-
- private readonly bool isStoryboard;
-
- ///
- /// As an optimisation, we add the two blur portions to be applied rather than actually applying two separate blurs.
- ///
- private Vector2 blurTarget => EnableUserDim.Value
- ? new Vector2(BlurAmount.Value + (float)userBlurLevel.Value * 25)
- : new Vector2(BlurAmount.Value);
+ private Container dimContent { get; }
///
/// Creates a new .
///
- /// Whether or not this instance contains a storyboard.
- ///
- /// While both backgrounds and storyboards allow user dim levels to be applied, storyboards can be toggled via
- /// and can cause backgrounds to become hidden via . Storyboards are also currently unable to be blurred.
- ///
- ///
- public UserDimContainer(bool isStoryboard = false)
+ protected UserDimContainer()
{
- this.isStoryboard = isStoryboard;
- AddInternal(DimContainer = new Container { RelativeSizeAxes = Axes.Both });
- }
-
- private Background background;
-
- public Background Background
- {
- get => background;
- set
- {
- base.Add(background = value);
- background.BlurTo(blurTarget, 0, Easing.OutQuint);
- }
- }
-
- public override void Add(Drawable drawable)
- {
- if (drawable is Background)
- throw new InvalidOperationException($"Use {nameof(Background)} to set a background.");
-
- base.Add(drawable);
+ AddInternal(dimContent = new Container { RelativeSizeAxes = Axes.Both });
}
[BackgroundDependencyLoader]
private void load(OsuConfigManager config)
{
- userDimLevel = config.GetBindable(OsuSetting.DimLevel);
- userBlurLevel = config.GetBindable(OsuSetting.BlurLevel);
- showStoryboard = config.GetBindable(OsuSetting.ShowStoryboard);
+ UserDimLevel = config.GetBindable(OsuSetting.DimLevel);
+ ShowStoryboard = config.GetBindable(OsuSetting.ShowStoryboard);
- EnableUserDim.ValueChanged += _ => updateVisuals();
- userDimLevel.ValueChanged += _ => updateVisuals();
- userBlurLevel.ValueChanged += _ => updateVisuals();
- showStoryboard.ValueChanged += _ => updateVisuals();
- StoryboardReplacesBackground.ValueChanged += _ => updateVisuals();
- BlurAmount.ValueChanged += _ => updateVisuals();
+ EnableUserDim.ValueChanged += _ => UpdateVisuals();
+ UserDimLevel.ValueChanged += _ => UpdateVisuals();
+ ShowStoryboard.ValueChanged += _ => UpdateVisuals();
+ StoryboardReplacesBackground.ValueChanged += _ => UpdateVisuals();
}
protected override void LoadComplete()
{
base.LoadComplete();
- updateVisuals();
+ UpdateVisuals();
}
- private void updateVisuals()
+ ///
+ /// Whether the content of this container should currently be visible.
+ ///
+ protected virtual bool ShowDimContent => true;
+
+ ///
+ /// Should be invoked when any dependent dim level or user setting is changed and bring the visual state up-to-date.
+ ///
+ protected virtual void UpdateVisuals()
{
- if (isStoryboard)
- {
- DimContainer.FadeTo(!showStoryboard.Value || userDimLevel.Value == 1 ? 0 : 1, background_fade_duration, Easing.OutQuint);
- }
- else
- {
- // The background needs to be hidden in the case of it being replaced by the storyboard
- DimContainer.FadeTo(showStoryboard.Value && StoryboardReplacesBackground.Value ? 0 : 1, background_fade_duration, Easing.OutQuint);
+ ContentDisplayed = ShowDimContent;
- Background?.BlurTo(blurTarget, background_fade_duration, Easing.OutQuint);
- }
-
- DimContainer.FadeColour(EnableUserDim.Value ? OsuColour.Gray(1 - (float)userDimLevel.Value) : Color4.White, background_fade_duration, Easing.OutQuint);
+ dimContent.FadeTo((ContentDisplayed) ? 1 : 0, BACKGROUND_FADE_DURATION, Easing.OutQuint);
+ dimContent.FadeColour(EnableUserDim.Value ? OsuColour.Gray(1 - (float)UserDimLevel.Value) : Color4.White, BACKGROUND_FADE_DURATION, Easing.OutQuint);
}
}
}
diff --git a/osu.Game/Graphics/OpenGL/Vertices/PositionAndColourVertex.cs b/osu.Game/Graphics/OpenGL/Vertices/PositionAndColourVertex.cs
new file mode 100644
index 0000000000..8714138322
--- /dev/null
+++ b/osu.Game/Graphics/OpenGL/Vertices/PositionAndColourVertex.cs
@@ -0,0 +1,26 @@
+// 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.Runtime.InteropServices;
+using osu.Framework.Graphics.OpenGL.Vertices;
+using osuTK;
+using osuTK.Graphics;
+using osuTK.Graphics.ES30;
+
+namespace osu.Game.Graphics.OpenGL.Vertices
+{
+ [StructLayout(LayoutKind.Sequential)]
+ public struct PositionAndColourVertex : IEquatable, IVertex
+ {
+ [VertexMember(2, VertexAttribPointerType.Float)]
+ public Vector2 Position;
+
+ [VertexMember(4, VertexAttribPointerType.Float)]
+ public Color4 Colour;
+
+ public bool Equals(PositionAndColourVertex other)
+ => Position.Equals(other.Position)
+ && Colour.Equals(other.Colour);
+ }
+}
diff --git a/osu.Game/Graphics/Sprites/GlowingSpriteText.cs b/osu.Game/Graphics/Sprites/GlowingSpriteText.cs
new file mode 100644
index 0000000000..74e387d60e
--- /dev/null
+++ b/osu.Game/Graphics/Sprites/GlowingSpriteText.cs
@@ -0,0 +1,80 @@
+// 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.Colour;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Sprites;
+using osuTK;
+
+namespace osu.Game.Graphics.Sprites
+{
+ public class GlowingSpriteText : Container, IHasText
+ {
+ private readonly OsuSpriteText spriteText, blurredText;
+
+ public string Text
+ {
+ get => spriteText.Text;
+ set => blurredText.Text = spriteText.Text = value;
+ }
+
+ public FontUsage Font
+ {
+ get => spriteText.Font;
+ set => blurredText.Font = spriteText.Font = value.With(fixedWidth: true);
+ }
+
+ public Vector2 TextSize
+ {
+ get => spriteText.Size;
+ set => blurredText.Size = spriteText.Size = value;
+ }
+
+ public ColourInfo TextColour
+ {
+ get => spriteText.Colour;
+ set => spriteText.Colour = value;
+ }
+
+ public ColourInfo GlowColour
+ {
+ get => blurredText.Colour;
+ set => blurredText.Colour = value;
+ }
+
+ public GlowingSpriteText()
+ {
+ AutoSizeAxes = Axes.Both;
+
+ Children = new Drawable[]
+ {
+ new BufferedContainer
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ BlurSigma = new Vector2(4),
+ CacheDrawnFrameBuffer = true,
+ RelativeSizeAxes = Axes.Both,
+ Blending = BlendingMode.Additive,
+ Size = new Vector2(3f),
+ Children = new[]
+ {
+ blurredText = new OsuSpriteText
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ Shadow = false,
+ },
+ },
+ },
+ spriteText = new OsuSpriteText
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ Shadow = false,
+ },
+ };
+ }
+ }
+}
diff --git a/osu.Game/Graphics/UserInterface/LineGraph.cs b/osu.Game/Graphics/UserInterface/LineGraph.cs
index 757a9a349c..714e953816 100644
--- a/osu.Game/Graphics/UserInterface/LineGraph.cs
+++ b/osu.Game/Graphics/UserInterface/LineGraph.cs
@@ -76,7 +76,12 @@ namespace osu.Game.Graphics.UserInterface
{
Masking = true,
RelativeSizeAxes = Axes.Both,
- Child = path = new SmoothPath { RelativeSizeAxes = Axes.Both, PathRadius = 1 }
+ Child = path = new SmoothPath
+ {
+ AutoSizeAxes = Axes.None,
+ RelativeSizeAxes = Axes.Both,
+ PathRadius = 1
+ }
});
}
diff --git a/osu.Game/Graphics/UserInterface/OsuTabControlCheckbox.cs b/osu.Game/Graphics/UserInterface/OsuTabControlCheckbox.cs
index 8134cfb42d..d158186899 100644
--- a/osu.Game/Graphics/UserInterface/OsuTabControlCheckbox.cs
+++ b/osu.Game/Graphics/UserInterface/OsuTabControlCheckbox.cs
@@ -64,7 +64,7 @@ namespace osu.Game.Graphics.UserInterface
Direction = FillDirection.Horizontal,
Children = new Drawable[]
{
- text = new OsuSpriteText { Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold) },
+ text = new OsuSpriteText { Font = OsuFont.GetFont(size: 14) },
icon = new SpriteIcon
{
Size = new Vector2(14),
@@ -84,7 +84,11 @@ namespace osu.Game.Graphics.UserInterface
}
};
- Current.ValueChanged += selected => { icon.Icon = selected.NewValue ? FontAwesome.Regular.CheckCircle : FontAwesome.Regular.Circle; };
+ Current.ValueChanged += selected =>
+ {
+ icon.Icon = selected.NewValue ? FontAwesome.Regular.CheckCircle : FontAwesome.Regular.Circle;
+ text.Font = text.Font.With(weight: selected.NewValue ? FontWeight.Bold : FontWeight.Medium);
+ };
}
[BackgroundDependencyLoader]
diff --git a/osu.Game/Graphics/UserInterface/SearchTextBox.cs b/osu.Game/Graphics/UserInterface/SearchTextBox.cs
index 7023711aaa..c3efe2ed45 100644
--- a/osu.Game/Graphics/UserInterface/SearchTextBox.cs
+++ b/osu.Game/Graphics/UserInterface/SearchTextBox.cs
@@ -3,6 +3,7 @@
using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites;
+using osu.Framework.Input;
using osu.Framework.Input.Events;
using osuTK;
using osuTK.Input;
@@ -33,6 +34,17 @@ namespace osu.Game.Graphics.UserInterface
PlaceholderText = "type to search";
}
+ public override bool OnPressed(PlatformAction action)
+ {
+ // Shift+delete is handled via PlatformAction on macOS. this is not so useful in the context of a SearchTextBox
+ // as we do not allow arrow key navigation in the first place (ie. the care should always be at the end of text)
+ // Avoid handling it here to allow other components to potentially consume the shortcut.
+ if (action.ActionType == PlatformActionType.CharNext && action.ActionMethod == PlatformActionMethod.Delete)
+ return false;
+
+ return base.OnPressed(action);
+ }
+
protected override bool OnKeyDown(KeyDownEvent e)
{
if (!e.ControlPressed && !e.ShiftPressed)
diff --git a/osu.Game/Input/Bindings/GlobalActionContainer.cs b/osu.Game/Input/Bindings/GlobalActionContainer.cs
index cdd821c173..8c927c2bc6 100644
--- a/osu.Game/Input/Bindings/GlobalActionContainer.cs
+++ b/osu.Game/Input/Bindings/GlobalActionContainer.cs
@@ -39,7 +39,7 @@ namespace osu.Game.Input.Bindings
new KeyBinding(InputKey.F4, GlobalAction.ToggleMute),
new KeyBinding(InputKey.Escape, GlobalAction.Back),
- new KeyBinding(InputKey.MouseButton1, GlobalAction.Back),
+ new KeyBinding(InputKey.ExtraMouseButton1, GlobalAction.Back),
new KeyBinding(InputKey.Space, GlobalAction.Select),
new KeyBinding(InputKey.Enter, GlobalAction.Select),
diff --git a/osu.Game/Migrations/20190708070844_AddBPMAndLengthColumns.Designer.cs b/osu.Game/Migrations/20190708070844_AddBPMAndLengthColumns.Designer.cs
new file mode 100644
index 0000000000..c5fcc16f84
--- /dev/null
+++ b/osu.Game/Migrations/20190708070844_AddBPMAndLengthColumns.Designer.cs
@@ -0,0 +1,504 @@
+//
+using System;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using osu.Game.Database;
+
+namespace osu.Game.Migrations
+{
+ [DbContext(typeof(OsuDbContext))]
+ [Migration("20190708070844_AddBPMAndLengthColumns")]
+ partial class AddBPMAndLengthColumns
+ {
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "2.2.4-servicing-10062");
+
+ modelBuilder.Entity("osu.Game.Beatmaps.BeatmapDifficulty", b =>
+ {
+ b.Property("ID")
+ .ValueGeneratedOnAdd();
+
+ b.Property("ApproachRate");
+
+ b.Property("CircleSize");
+
+ b.Property("DrainRate");
+
+ b.Property("OverallDifficulty");
+
+ b.Property("SliderMultiplier");
+
+ b.Property("SliderTickRate");
+
+ b.HasKey("ID");
+
+ b.ToTable("BeatmapDifficulty");
+ });
+
+ modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b =>
+ {
+ b.Property("ID")
+ .ValueGeneratedOnAdd();
+
+ b.Property("AudioLeadIn");
+
+ b.Property("BPM");
+
+ b.Property("BaseDifficultyID");
+
+ b.Property("BeatDivisor");
+
+ b.Property("BeatmapSetInfoID");
+
+ b.Property("Countdown");
+
+ b.Property("DistanceSpacing");
+
+ b.Property("GridSize");
+
+ b.Property("Hash");
+
+ b.Property("Hidden");
+
+ b.Property("Length");
+
+ b.Property("LetterboxInBreaks");
+
+ b.Property("MD5Hash");
+
+ b.Property("MetadataID");
+
+ b.Property("OnlineBeatmapID");
+
+ b.Property("Path");
+
+ b.Property("RulesetID");
+
+ b.Property("SpecialStyle");
+
+ b.Property("StackLeniency");
+
+ b.Property("StarDifficulty");
+
+ b.Property("Status");
+
+ b.Property("StoredBookmarks");
+
+ b.Property("TimelineZoom");
+
+ b.Property("Version");
+
+ b.Property("WidescreenStoryboard");
+
+ b.HasKey("ID");
+
+ b.HasIndex("BaseDifficultyID");
+
+ b.HasIndex("BeatmapSetInfoID");
+
+ b.HasIndex("Hash");
+
+ b.HasIndex("MD5Hash");
+
+ b.HasIndex("MetadataID");
+
+ b.HasIndex("OnlineBeatmapID")
+ .IsUnique();
+
+ b.HasIndex("RulesetID");
+
+ b.ToTable("BeatmapInfo");
+ });
+
+ modelBuilder.Entity("osu.Game.Beatmaps.BeatmapMetadata", b =>
+ {
+ b.Property("ID")
+ .ValueGeneratedOnAdd();
+
+ b.Property("Artist");
+
+ b.Property("ArtistUnicode");
+
+ b.Property("AudioFile");
+
+ b.Property("AuthorString")
+ .HasColumnName("Author");
+
+ b.Property("BackgroundFile");
+
+ b.Property("PreviewTime");
+
+ b.Property("Source");
+
+ b.Property("Tags");
+
+ b.Property("Title");
+
+ b.Property("TitleUnicode");
+
+ b.HasKey("ID");
+
+ b.ToTable("BeatmapMetadata");
+ });
+
+ modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b =>
+ {
+ b.Property("ID")
+ .ValueGeneratedOnAdd();
+
+ b.Property("BeatmapSetInfoID");
+
+ b.Property("FileInfoID");
+
+ b.Property("Filename")
+ .IsRequired();
+
+ b.HasKey("ID");
+
+ b.HasIndex("BeatmapSetInfoID");
+
+ b.HasIndex("FileInfoID");
+
+ b.ToTable("BeatmapSetFileInfo");
+ });
+
+ modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b =>
+ {
+ b.Property("ID")
+ .ValueGeneratedOnAdd();
+
+ b.Property("DateAdded");
+
+ b.Property("DeletePending");
+
+ b.Property("Hash");
+
+ b.Property("MetadataID");
+
+ b.Property("OnlineBeatmapSetID");
+
+ b.Property("Protected");
+
+ b.Property("Status");
+
+ b.HasKey("ID");
+
+ b.HasIndex("DeletePending");
+
+ b.HasIndex("Hash")
+ .IsUnique();
+
+ b.HasIndex("MetadataID");
+
+ b.HasIndex("OnlineBeatmapSetID")
+ .IsUnique();
+
+ b.ToTable("BeatmapSetInfo");
+ });
+
+ modelBuilder.Entity("osu.Game.Configuration.DatabasedSetting", b =>
+ {
+ b.Property("ID")
+ .ValueGeneratedOnAdd();
+
+ b.Property("Key")
+ .HasColumnName("Key");
+
+ b.Property("RulesetID");
+
+ b.Property("SkinInfoID");
+
+ b.Property("StringValue")
+ .HasColumnName("Value");
+
+ b.Property("Variant");
+
+ b.HasKey("ID");
+
+ b.HasIndex("SkinInfoID");
+
+ b.HasIndex("RulesetID", "Variant");
+
+ b.ToTable("Settings");
+ });
+
+ modelBuilder.Entity("osu.Game.IO.FileInfo", b =>
+ {
+ b.Property("ID")
+ .ValueGeneratedOnAdd();
+
+ b.Property("Hash");
+
+ b.Property("ReferenceCount");
+
+ b.HasKey("ID");
+
+ b.HasIndex("Hash")
+ .IsUnique();
+
+ b.HasIndex("ReferenceCount");
+
+ b.ToTable("FileInfo");
+ });
+
+ modelBuilder.Entity("osu.Game.Input.Bindings.DatabasedKeyBinding", b =>
+ {
+ b.Property("ID")
+ .ValueGeneratedOnAdd();
+
+ b.Property("IntAction")
+ .HasColumnName("Action");
+
+ b.Property("KeysString")
+ .HasColumnName("Keys");
+
+ b.Property("RulesetID");
+
+ b.Property("Variant");
+
+ b.HasKey("ID");
+
+ b.HasIndex("IntAction");
+
+ b.HasIndex("RulesetID", "Variant");
+
+ b.ToTable("KeyBinding");
+ });
+
+ modelBuilder.Entity("osu.Game.Rulesets.RulesetInfo", b =>
+ {
+ b.Property("ID")
+ .ValueGeneratedOnAdd();
+
+ b.Property("Available");
+
+ b.Property("InstantiationInfo");
+
+ b.Property("Name");
+
+ b.Property("ShortName");
+
+ b.HasKey("ID");
+
+ b.HasIndex("Available");
+
+ b.HasIndex("ShortName")
+ .IsUnique();
+
+ b.ToTable("RulesetInfo");
+ });
+
+ modelBuilder.Entity("osu.Game.Scoring.ScoreFileInfo", b =>
+ {
+ b.Property("ID")
+ .ValueGeneratedOnAdd();
+
+ b.Property("FileInfoID");
+
+ b.Property("Filename")
+ .IsRequired();
+
+ b.Property("ScoreInfoID");
+
+ b.HasKey("ID");
+
+ b.HasIndex("FileInfoID");
+
+ b.HasIndex("ScoreInfoID");
+
+ b.ToTable("ScoreFileInfo");
+ });
+
+ modelBuilder.Entity("osu.Game.Scoring.ScoreInfo", b =>
+ {
+ b.Property("ID")
+ .ValueGeneratedOnAdd();
+
+ b.Property("Accuracy")
+ .HasColumnType("DECIMAL(1,4)");
+
+ b.Property("BeatmapInfoID");
+
+ b.Property("Combo");
+
+ b.Property("Date");
+
+ b.Property("DeletePending");
+
+ b.Property("Hash");
+
+ b.Property("MaxCombo");
+
+ b.Property("ModsJson")
+ .HasColumnName("Mods");
+
+ b.Property("OnlineScoreID");
+
+ b.Property("PP");
+
+ b.Property("Rank");
+
+ b.Property("RulesetID");
+
+ b.Property("StatisticsJson")
+ .HasColumnName("Statistics");
+
+ b.Property("TotalScore");
+
+ b.Property("UserID")
+ .HasColumnName("UserID");
+
+ b.Property("UserString")
+ .HasColumnName("User");
+
+ b.HasKey("ID");
+
+ b.HasIndex("BeatmapInfoID");
+
+ b.HasIndex("OnlineScoreID")
+ .IsUnique();
+
+ b.HasIndex("RulesetID");
+
+ b.ToTable("ScoreInfo");
+ });
+
+ modelBuilder.Entity("osu.Game.Skinning.SkinFileInfo", b =>
+ {
+ b.Property("ID")
+ .ValueGeneratedOnAdd();
+
+ b.Property("FileInfoID");
+
+ b.Property("Filename")
+ .IsRequired();
+
+ b.Property("SkinInfoID");
+
+ b.HasKey("ID");
+
+ b.HasIndex("FileInfoID");
+
+ b.HasIndex("SkinInfoID");
+
+ b.ToTable("SkinFileInfo");
+ });
+
+ modelBuilder.Entity("osu.Game.Skinning.SkinInfo", b =>
+ {
+ b.Property("ID")
+ .ValueGeneratedOnAdd();
+
+ b.Property("Creator");
+
+ b.Property("DeletePending");
+
+ b.Property("Hash");
+
+ b.Property("Name");
+
+ b.HasKey("ID");
+
+ b.HasIndex("DeletePending");
+
+ b.HasIndex("Hash")
+ .IsUnique();
+
+ b.ToTable("SkinInfo");
+ });
+
+ modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b =>
+ {
+ b.HasOne("osu.Game.Beatmaps.BeatmapDifficulty", "BaseDifficulty")
+ .WithMany()
+ .HasForeignKey("BaseDifficultyID")
+ .OnDelete(DeleteBehavior.Cascade);
+
+ b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo", "BeatmapSet")
+ .WithMany("Beatmaps")
+ .HasForeignKey("BeatmapSetInfoID")
+ .OnDelete(DeleteBehavior.Cascade);
+
+ b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata")
+ .WithMany("Beatmaps")
+ .HasForeignKey("MetadataID");
+
+ b.HasOne("osu.Game.Rulesets.RulesetInfo", "Ruleset")
+ .WithMany()
+ .HasForeignKey("RulesetID")
+ .OnDelete(DeleteBehavior.Cascade);
+ });
+
+ modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b =>
+ {
+ b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo")
+ .WithMany("Files")
+ .HasForeignKey("BeatmapSetInfoID")
+ .OnDelete(DeleteBehavior.Cascade);
+
+ b.HasOne("osu.Game.IO.FileInfo", "FileInfo")
+ .WithMany()
+ .HasForeignKey("FileInfoID")
+ .OnDelete(DeleteBehavior.Cascade);
+ });
+
+ modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b =>
+ {
+ b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata")
+ .WithMany("BeatmapSets")
+ .HasForeignKey("MetadataID");
+ });
+
+ modelBuilder.Entity("osu.Game.Configuration.DatabasedSetting", b =>
+ {
+ b.HasOne("osu.Game.Skinning.SkinInfo")
+ .WithMany("Settings")
+ .HasForeignKey("SkinInfoID");
+ });
+
+ modelBuilder.Entity("osu.Game.Scoring.ScoreFileInfo", b =>
+ {
+ b.HasOne("osu.Game.IO.FileInfo", "FileInfo")
+ .WithMany()
+ .HasForeignKey("FileInfoID")
+ .OnDelete(DeleteBehavior.Cascade);
+
+ b.HasOne("osu.Game.Scoring.ScoreInfo")
+ .WithMany("Files")
+ .HasForeignKey("ScoreInfoID");
+ });
+
+ modelBuilder.Entity("osu.Game.Scoring.ScoreInfo", b =>
+ {
+ b.HasOne("osu.Game.Beatmaps.BeatmapInfo", "Beatmap")
+ .WithMany("Scores")
+ .HasForeignKey("BeatmapInfoID")
+ .OnDelete(DeleteBehavior.Cascade);
+
+ b.HasOne("osu.Game.Rulesets.RulesetInfo", "Ruleset")
+ .WithMany()
+ .HasForeignKey("RulesetID")
+ .OnDelete(DeleteBehavior.Cascade);
+ });
+
+ modelBuilder.Entity("osu.Game.Skinning.SkinFileInfo", b =>
+ {
+ b.HasOne("osu.Game.IO.FileInfo", "FileInfo")
+ .WithMany()
+ .HasForeignKey("FileInfoID")
+ .OnDelete(DeleteBehavior.Cascade);
+
+ b.HasOne("osu.Game.Skinning.SkinInfo")
+ .WithMany("Files")
+ .HasForeignKey("SkinInfoID")
+ .OnDelete(DeleteBehavior.Cascade);
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/osu.Game/Migrations/20190708070844_AddBPMAndLengthColumns.cs b/osu.Game/Migrations/20190708070844_AddBPMAndLengthColumns.cs
new file mode 100644
index 0000000000..f5963ebf5e
--- /dev/null
+++ b/osu.Game/Migrations/20190708070844_AddBPMAndLengthColumns.cs
@@ -0,0 +1,33 @@
+using Microsoft.EntityFrameworkCore.Migrations;
+
+namespace osu.Game.Migrations
+{
+ public partial class AddBPMAndLengthColumns : Migration
+ {
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.AddColumn(
+ name: "BPM",
+ table: "BeatmapInfo",
+ nullable: false,
+ defaultValue: 0.0);
+
+ migrationBuilder.AddColumn(
+ name: "Length",
+ table: "BeatmapInfo",
+ nullable: false,
+ defaultValue: 0.0);
+ }
+
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropColumn(
+ name: "BPM",
+ table: "BeatmapInfo");
+
+ migrationBuilder.DropColumn(
+ name: "Length",
+ table: "BeatmapInfo");
+ }
+ }
+}
diff --git a/osu.Game/Migrations/OsuDbContextModelSnapshot.cs b/osu.Game/Migrations/OsuDbContextModelSnapshot.cs
index 11b032a941..761dca2801 100644
--- a/osu.Game/Migrations/OsuDbContextModelSnapshot.cs
+++ b/osu.Game/Migrations/OsuDbContextModelSnapshot.cs
@@ -45,6 +45,8 @@ namespace osu.Game.Migrations
b.Property("AudioLeadIn");
+ b.Property("BPM");
+
b.Property("BaseDifficultyID");
b.Property("BeatDivisor");
@@ -61,6 +63,8 @@ namespace osu.Game.Migrations
b.Property("Hidden");
+ b.Property("Length");
+
b.Property("LetterboxInBreaks");
b.Property("MD5Hash");
diff --git a/osu.Game/Online/API/Requests/GetScoresRequest.cs b/osu.Game/Online/API/Requests/GetScoresRequest.cs
index e56df05570..50844fa256 100644
--- a/osu.Game/Online/API/Requests/GetScoresRequest.cs
+++ b/osu.Game/Online/API/Requests/GetScoresRequest.cs
@@ -5,8 +5,10 @@ using System;
using osu.Game.Beatmaps;
using osu.Game.Rulesets;
using osu.Game.Screens.Select.Leaderboards;
-using osu.Framework.IO.Network;
using osu.Game.Online.API.Requests.Responses;
+using osu.Game.Rulesets.Mods;
+using System.Text;
+using System.Collections.Generic;
namespace osu.Game.Online.API.Requests
{
@@ -15,8 +17,9 @@ namespace osu.Game.Online.API.Requests
private readonly BeatmapInfo beatmap;
private readonly BeatmapLeaderboardScope scope;
private readonly RulesetInfo ruleset;
+ private readonly IEnumerable mods;
- public GetScoresRequest(BeatmapInfo beatmap, RulesetInfo ruleset, BeatmapLeaderboardScope scope = BeatmapLeaderboardScope.Global)
+ public GetScoresRequest(BeatmapInfo beatmap, RulesetInfo ruleset, BeatmapLeaderboardScope scope = BeatmapLeaderboardScope.Global, IEnumerable mods = null)
{
if (!beatmap.OnlineBeatmapID.HasValue)
throw new InvalidOperationException($"Cannot lookup a beatmap's scores without having a populated {nameof(BeatmapInfo.OnlineBeatmapID)}.");
@@ -27,6 +30,7 @@ namespace osu.Game.Online.API.Requests
this.beatmap = beatmap;
this.scope = scope;
this.ruleset = ruleset ?? throw new ArgumentNullException(nameof(ruleset));
+ this.mods = mods ?? Array.Empty();
Success += onSuccess;
}
@@ -38,19 +42,29 @@ namespace osu.Game.Online.API.Requests
score.Beatmap = beatmap;
score.Ruleset = ruleset;
}
+
+ var userScore = r.UserScore;
+
+ if (userScore != null)
+ {
+ userScore.Score.Beatmap = beatmap;
+ userScore.Score.Ruleset = ruleset;
+ }
}
- protected override WebRequest CreateWebRequest()
+ protected override string Target => $@"beatmaps/{beatmap.OnlineBeatmapID}/scores{createQueryParameters()}";
+
+ private string createQueryParameters()
{
- var req = base.CreateWebRequest();
+ StringBuilder query = new StringBuilder(@"?");
- req.Timeout = 30000;
- req.AddParameter(@"type", scope.ToString().ToLowerInvariant());
- req.AddParameter(@"mode", ruleset.ShortName);
+ query.Append($@"type={scope.ToString().ToLowerInvariant()}");
+ query.Append($@"&mode={ruleset.ShortName}");
- return req;
+ foreach (var mod in mods)
+ query.Append($@"&mods[]={mod.Acronym}");
+
+ return query.ToString();
}
-
- protected override string Target => $@"beatmaps/{beatmap.OnlineBeatmapID}/scores";
}
}
diff --git a/osu.Game/Online/API/Requests/GetUserBeatmapsRequest.cs b/osu.Game/Online/API/Requests/GetUserBeatmapsRequest.cs
index 45d751f00e..f3384163b8 100644
--- a/osu.Game/Online/API/Requests/GetUserBeatmapsRequest.cs
+++ b/osu.Game/Online/API/Requests/GetUserBeatmapsRequest.cs
@@ -7,21 +7,20 @@ using osu.Game.Online.API.Requests.Responses;
namespace osu.Game.Online.API.Requests
{
- public class GetUserBeatmapsRequest : APIRequest>
+ public class GetUserBeatmapsRequest : PaginatedAPIRequest>
{
private readonly long userId;
- private readonly int offset;
+
private readonly BeatmapSetType type;
- public GetUserBeatmapsRequest(long userId, BeatmapSetType type, int offset = 0)
+ public GetUserBeatmapsRequest(long userId, BeatmapSetType type, int page = 0, int itemsPerPage = 6)
+ : base(page, itemsPerPage)
{
this.userId = userId;
- this.offset = offset;
this.type = type;
}
- // ReSharper disable once ImpureMethodCallOnReadonlyValueField
- protected override string Target => $@"users/{userId}/beatmapsets/{type.ToString().Underscore()}?offset={offset}";
+ protected override string Target => $@"users/{userId}/beatmapsets/{type.ToString().Underscore()}";
}
public enum BeatmapSetType
diff --git a/osu.Game/Online/API/Requests/GetUserMostPlayedBeatmapsRequest.cs b/osu.Game/Online/API/Requests/GetUserMostPlayedBeatmapsRequest.cs
index 40e52bdaf6..9f094e51c4 100644
--- a/osu.Game/Online/API/Requests/GetUserMostPlayedBeatmapsRequest.cs
+++ b/osu.Game/Online/API/Requests/GetUserMostPlayedBeatmapsRequest.cs
@@ -6,17 +6,16 @@ using osu.Game.Online.API.Requests.Responses;
namespace osu.Game.Online.API.Requests
{
- public class GetUserMostPlayedBeatmapsRequest : APIRequest>
+ public class GetUserMostPlayedBeatmapsRequest : PaginatedAPIRequest>
{
private readonly long userId;
- private readonly int offset;
- public GetUserMostPlayedBeatmapsRequest(long userId, int offset = 0)
+ public GetUserMostPlayedBeatmapsRequest(long userId, int page = 0, int itemsPerPage = 5)
+ : base(page, itemsPerPage)
{
this.userId = userId;
- this.offset = offset;
}
- protected override string Target => $@"users/{userId}/beatmapsets/most_played?offset={offset}";
+ protected override string Target => $@"users/{userId}/beatmapsets/most_played";
}
}
diff --git a/osu.Game/Online/API/Requests/GetUserRecentActivitiesRequest.cs b/osu.Game/Online/API/Requests/GetUserRecentActivitiesRequest.cs
index 9f80180e70..4908e5ecc2 100644
--- a/osu.Game/Online/API/Requests/GetUserRecentActivitiesRequest.cs
+++ b/osu.Game/Online/API/Requests/GetUserRecentActivitiesRequest.cs
@@ -6,18 +6,17 @@ using osu.Game.Online.API.Requests.Responses;
namespace osu.Game.Online.API.Requests
{
- public class GetUserRecentActivitiesRequest : APIRequest>
+ public class GetUserRecentActivitiesRequest : PaginatedAPIRequest>
{
private readonly long userId;
- private readonly int offset;
- public GetUserRecentActivitiesRequest(long userId, int offset = 0)
+ public GetUserRecentActivitiesRequest(long userId, int page = 0, int itemsPerPage = 5)
+ : base(page, itemsPerPage)
{
this.userId = userId;
- this.offset = offset;
}
- protected override string Target => $"users/{userId}/recent_activity?offset={offset}";
+ protected override string Target => $"users/{userId}/recent_activity";
}
public enum RecentActivityType
diff --git a/osu.Game/Online/API/Requests/GetUserScoresRequest.cs b/osu.Game/Online/API/Requests/GetUserScoresRequest.cs
index 48a43bbbad..d41966fe1b 100644
--- a/osu.Game/Online/API/Requests/GetUserScoresRequest.cs
+++ b/osu.Game/Online/API/Requests/GetUserScoresRequest.cs
@@ -6,21 +6,19 @@ using osu.Game.Online.API.Requests.Responses;
namespace osu.Game.Online.API.Requests
{
- public class GetUserScoresRequest : APIRequest>
+ public class GetUserScoresRequest : PaginatedAPIRequest>
{
private readonly long userId;
private readonly ScoreType type;
- private readonly int offset;
- public GetUserScoresRequest(long userId, ScoreType type, int offset = 0)
+ public GetUserScoresRequest(long userId, ScoreType type, int page = 0, int itemsPerPage = 5)
+ : base(page, itemsPerPage)
{
this.userId = userId;
this.type = type;
- this.offset = offset;
}
- // ReSharper disable once ImpureMethodCallOnReadonlyValueField
- protected override string Target => $@"users/{userId}/scores/{type.ToString().ToLowerInvariant()}?offset={offset}";
+ protected override string Target => $@"users/{userId}/scores/{type.ToString().ToLowerInvariant()}";
}
public enum ScoreType
diff --git a/osu.Game/Online/API/Requests/PaginatedAPIRequest.cs b/osu.Game/Online/API/Requests/PaginatedAPIRequest.cs
new file mode 100644
index 0000000000..52e12f04ee
--- /dev/null
+++ b/osu.Game/Online/API/Requests/PaginatedAPIRequest.cs
@@ -0,0 +1,30 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System.Globalization;
+using osu.Framework.IO.Network;
+
+namespace osu.Game.Online.API.Requests
+{
+ public abstract class PaginatedAPIRequest : APIRequest
+ {
+ private readonly int page;
+ private readonly int itemsPerPage;
+
+ protected PaginatedAPIRequest(int page, int itemsPerPage)
+ {
+ this.page = page;
+ this.itemsPerPage = itemsPerPage;
+ }
+
+ protected override WebRequest CreateWebRequest()
+ {
+ var req = base.CreateWebRequest();
+
+ req.AddParameter("offset", (page * itemsPerPage).ToString(CultureInfo.InvariantCulture));
+ req.AddParameter("limit", itemsPerPage.ToString(CultureInfo.InvariantCulture));
+
+ return req;
+ }
+ }
+}
diff --git a/osu.Game/Online/API/Requests/Responses/APIBeatmap.cs b/osu.Game/Online/API/Requests/Responses/APIBeatmap.cs
index bcbe060f82..f4d67a56aa 100644
--- a/osu.Game/Online/API/Requests/Responses/APIBeatmap.cs
+++ b/osu.Game/Online/API/Requests/Responses/APIBeatmap.cs
@@ -1,6 +1,7 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
+using System;
using Newtonsoft.Json;
using osu.Game.Beatmaps;
using osu.Game.Rulesets;
@@ -71,6 +72,7 @@ namespace osu.Game.Online.API.Requests.Responses
StarDifficulty = starDifficulty,
OnlineBeatmapID = OnlineBeatmapID,
Version = version,
+ Length = TimeSpan.FromSeconds(length).TotalMilliseconds,
Status = Status,
BeatmapSet = set,
Metrics = metrics,
@@ -85,7 +87,6 @@ namespace osu.Game.Online.API.Requests.Responses
{
PlayCount = playCount,
PassCount = passCount,
- Length = length,
CircleCount = circleCount,
SliderCount = sliderCount,
},
diff --git a/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs b/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs
index 200a705500..e5bfde8f8f 100644
--- a/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs
+++ b/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs
@@ -30,6 +30,9 @@ namespace osu.Game.Online.API.Requests.Responses
[JsonProperty(@"preview_url")]
private string preview { get; set; }
+ [JsonProperty(@"has_favourited")]
+ private bool hasFavourited { get; set; }
+
[JsonProperty(@"play_count")]
private int playCount { get; set; }
@@ -91,6 +94,7 @@ namespace osu.Game.Online.API.Requests.Responses
Ranked = ranked,
LastUpdated = lastUpdated,
Availability = availability,
+ HasFavourited = hasFavourited,
},
Beatmaps = beatmaps?.Select(b => b.ToBeatmap(rulesets)).ToList(),
};
diff --git a/osu.Game/Online/API/Requests/Responses/APIChangelogBuild.cs b/osu.Game/Online/API/Requests/Responses/APIChangelogBuild.cs
index 36407c7b0e..56005e15f8 100644
--- a/osu.Game/Online/API/Requests/Responses/APIChangelogBuild.cs
+++ b/osu.Game/Online/API/Requests/Responses/APIChangelogBuild.cs
@@ -33,6 +33,8 @@ namespace osu.Game.Online.API.Requests.Responses
[JsonProperty("versions")]
public VersionNavigation Versions { get; set; }
+ public string Url => $"https://osu.ppy.sh/home/changelog/{UpdateStream.Name}/{Version}";
+
public class VersionNavigation
{
[JsonProperty("next")]
diff --git a/osu.Game/Online/API/Requests/Responses/APILegacyScores.cs b/osu.Game/Online/API/Requests/Responses/APILegacyScores.cs
index c629caaa6f..318fcb00de 100644
--- a/osu.Game/Online/API/Requests/Responses/APILegacyScores.cs
+++ b/osu.Game/Online/API/Requests/Responses/APILegacyScores.cs
@@ -10,5 +10,17 @@ namespace osu.Game.Online.API.Requests.Responses
{
[JsonProperty(@"scores")]
public List Scores;
+
+ [JsonProperty(@"userScore")]
+ public APILegacyUserTopScoreInfo UserScore;
+ }
+
+ public class APILegacyUserTopScoreInfo
+ {
+ [JsonProperty(@"position")]
+ public int Position;
+
+ [JsonProperty(@"score")]
+ public APILegacyScoreInfo Score;
}
}
diff --git a/osu.Game/Online/Leaderboards/Leaderboard.cs b/osu.Game/Online/Leaderboards/Leaderboard.cs
index dea2ff1a21..98f15599fc 100644
--- a/osu.Game/Online/Leaderboards/Leaderboard.cs
+++ b/osu.Game/Online/Leaderboards/Leaderboard.cs
@@ -51,7 +51,6 @@ namespace osu.Game.Online.Leaderboards
loading.Hide();
- // schedule because we may not be loaded yet (LoadComponentAsync complains).
showScoresDelegate?.Cancel();
showScoresCancellationSource?.Cancel();
@@ -61,28 +60,22 @@ namespace osu.Game.Online.Leaderboards
// ensure placeholder is hidden when displaying scores
PlaceholderState = PlaceholderState.Successful;
- scrollFlow = CreateScoreFlow();
- scrollFlow.ChildrenEnumerable = scores.Select((s, index) => CreateDrawableScore(s, index + 1));
+ var sf = CreateScoreFlow();
+ sf.ChildrenEnumerable = scores.Select((s, index) => CreateDrawableScore(s, index + 1));
- if (!IsLoaded)
- showScoresDelegate = Schedule(showScores);
- else
- showScores();
-
- void showScores() => LoadComponentAsync(scrollFlow, _ =>
+ // schedule because we may not be loaded yet (LoadComponentAsync complains).
+ showScoresDelegate = Schedule(() => LoadComponentAsync(sf, _ =>
{
- scrollContainer.Add(scrollFlow);
+ scrollContainer.Add(scrollFlow = sf);
int i = 0;
foreach (var s in scrollFlow.Children)
- {
using (s.BeginDelayedSequence(i++ * 50, true))
s.Show();
- }
scrollContainer.ScrollTo(0f, false);
- }, (showScoresCancellationSource = new CancellationTokenSource()).Token);
+ }, (showScoresCancellationSource = new CancellationTokenSource()).Token));
}
}
@@ -201,10 +194,19 @@ namespace osu.Game.Online.Leaderboards
private APIRequest getScoresRequest;
+ protected abstract bool IsOnlineScope { get; }
+
public void APIStateChanged(IAPIProvider api, APIState state)
{
- if (state == APIState.Online)
- UpdateScores();
+ switch (state)
+ {
+ case APIState.Online:
+ case APIState.Offline:
+ if (IsOnlineScope)
+ UpdateScores();
+
+ break;
+ }
}
protected void UpdateScores()
diff --git a/osu.Game/Online/Leaderboards/LeaderboardScore.cs b/osu.Game/Online/Leaderboards/LeaderboardScore.cs
index 9840b59805..008f8208eb 100644
--- a/osu.Game/Online/Leaderboards/LeaderboardScore.cs
+++ b/osu.Game/Online/Leaderboards/LeaderboardScore.cs
@@ -187,7 +187,13 @@ namespace osu.Game.Online.Leaderboards
Spacing = new Vector2(5f, 0f),
Children = new Drawable[]
{
- scoreLabel = new GlowingSpriteText(score.TotalScore.ToString(@"N0"), OsuFont.Numeric.With(size: 23), Color4.White, OsuColour.FromHex(@"83ccfa")),
+ scoreLabel = new GlowingSpriteText
+ {
+ TextColour = Color4.White,
+ GlowColour = OsuColour.FromHex(@"83ccfa"),
+ Text = score.TotalScore.ToString(@"N0"),
+ Font = OsuFont.Numeric.With(size: 23),
+ },
RankContainer = new Container
{
Size = new Vector2(40f, 20f),
@@ -275,49 +281,6 @@ namespace osu.Game.Online.Leaderboards
base.OnHoverLost(e);
}
- private class GlowingSpriteText : Container
- {
- public GlowingSpriteText(string text, FontUsage font, Color4 textColour, Color4 glowColour)
- {
- AutoSizeAxes = Axes.Both;
-
- Children = new Drawable[]
- {
- new BufferedContainer
- {
- Anchor = Anchor.Centre,
- Origin = Anchor.Centre,
- BlurSigma = new Vector2(4),
- CacheDrawnFrameBuffer = true,
- RelativeSizeAxes = Axes.Both,
- Blending = BlendingMode.Additive,
- Size = new Vector2(3f),
- Children = new[]
- {
- new OsuSpriteText
- {
- Anchor = Anchor.Centre,
- Origin = Anchor.Centre,
- Font = font.With(fixedWidth: true),
- Text = text,
- Colour = glowColour,
- Shadow = false,
- },
- },
- },
- new OsuSpriteText
- {
- Anchor = Anchor.Centre,
- Origin = Anchor.Centre,
- Font = font.With(fixedWidth: true),
- Text = text,
- Colour = textColour,
- Shadow = false,
- },
- };
- }
- }
-
private class ScoreComponentLabel : Container, IHasTooltip
{
private const float icon_size = 20;
@@ -367,10 +330,14 @@ namespace osu.Game.Online.Leaderboards
},
},
},
- new GlowingSpriteText(statistic.Value, OsuFont.GetFont(size: 17, weight: FontWeight.Bold), Color4.White, OsuColour.FromHex(@"83ccfa"))
+ new GlowingSpriteText
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
+ TextColour = Color4.White,
+ GlowColour = OsuColour.FromHex(@"83ccfa"),
+ Text = statistic.Value,
+ Font = OsuFont.GetFont(size: 17, weight: FontWeight.Bold),
},
},
};
diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs
index dde87cd2ed..d19d8828c1 100644
--- a/osu.Game/OsuGame.cs
+++ b/osu.Game/OsuGame.cs
@@ -20,6 +20,7 @@ using System.Threading;
using System.Threading.Tasks;
using osu.Framework.Audio;
using osu.Framework.Bindables;
+using osu.Framework.Development;
using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Input;
@@ -155,7 +156,7 @@ namespace osu.Game
{
this.frameworkConfig = frameworkConfig;
- if (!Host.IsPrimaryInstance)
+ if (!Host.IsPrimaryInstance && !DebugUtils.IsDebugBuild)
{
Logger.Log(@"osu! does not support multiple running instances.", LoggingTarget.Runtime, LogLevel.Error);
Environment.Exit(0);
@@ -250,7 +251,7 @@ namespace osu.Game
}
// Use first beatmap available for current ruleset, else switch ruleset.
- var first = databasedSet.Beatmaps.Find(b => b.Ruleset == Ruleset.Value) ?? databasedSet.Beatmaps.First();
+ var first = databasedSet.Beatmaps.Find(b => b.Ruleset.Equals(Ruleset.Value)) ?? databasedSet.Beatmaps.First();
Ruleset.Value = first.Ruleset;
Beatmap.Value = BeatmapManager.GetWorkingBeatmap(first);
@@ -284,11 +285,9 @@ namespace osu.Game
performFromMainMenu(() =>
{
- Ruleset.Value = databasedScoreInfo.Ruleset;
Beatmap.Value = BeatmapManager.GetWorkingBeatmap(databasedBeatmap);
- Mods.Value = databasedScoreInfo.Mods;
- menuScreen.Push(new PlayerLoader(() => new ReplayPlayer(databasedScore)));
+ menuScreen.Push(new ReplayPlayerLoader(databasedScore));
}, $"watch {databasedScoreInfo}", bypassScreenAllowChecks: true);
}
@@ -592,7 +591,7 @@ namespace osu.Game
{
int recentLogCount = 0;
- const double debounce = 5000;
+ const double debounce = 60000;
Logger.NewEntry += entry =>
{
diff --git a/osu.Game/Overlays/BeatmapSet/BasicStats.cs b/osu.Game/Overlays/BeatmapSet/BasicStats.cs
index 6a583baf38..5b10c4e0bb 100644
--- a/osu.Game/Overlays/BeatmapSet/BasicStats.cs
+++ b/osu.Game/Overlays/BeatmapSet/BasicStats.cs
@@ -60,7 +60,7 @@ namespace osu.Game.Overlays.BeatmapSet
}
else
{
- length.Value = TimeSpan.FromSeconds(beatmap.OnlineInfo.Length).ToString(@"m\:ss");
+ length.Value = TimeSpan.FromMilliseconds(beatmap.Length).ToString(@"m\:ss");
circleCount.Value = beatmap.OnlineInfo.CircleCount.ToString();
sliderCount.Value = beatmap.OnlineInfo.SliderCount.ToString();
}
diff --git a/osu.Game/Overlays/BeatmapSet/Buttons/FavouriteButton.cs b/osu.Game/Overlays/BeatmapSet/Buttons/FavouriteButton.cs
index 7207739646..11f56bc163 100644
--- a/osu.Game/Overlays/BeatmapSet/Buttons/FavouriteButton.cs
+++ b/osu.Game/Overlays/BeatmapSet/Buttons/FavouriteButton.cs
@@ -7,6 +7,7 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
+using osu.Game.Beatmaps;
using osu.Game.Graphics;
using osu.Game.Graphics.Backgrounds;
using osuTK;
@@ -15,7 +16,9 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons
{
public class FavouriteButton : HeaderButton
{
- public readonly Bindable Favourited = new Bindable();
+ public readonly Bindable BeatmapSet = new Bindable();
+
+ private readonly Bindable favourited = new Bindable();
[BackgroundDependencyLoader]
private void load()
@@ -54,7 +57,15 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons
},
});
- Favourited.ValueChanged += favourited =>
+ BeatmapSet.BindValueChanged(setInfo =>
+ {
+ if (setInfo.NewValue?.OnlineInfo?.HasFavourited == null)
+ return;
+
+ favourited.Value = setInfo.NewValue.OnlineInfo.HasFavourited;
+ });
+
+ favourited.ValueChanged += favourited =>
{
if (favourited.NewValue)
{
@@ -67,8 +78,6 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons
icon.Icon = FontAwesome.Regular.Heart;
}
};
-
- Action = () => Favourited.Value = !Favourited.Value;
}
protected override void UpdateAfterChildren()
diff --git a/osu.Game/Overlays/BeatmapSet/Header.cs b/osu.Game/Overlays/BeatmapSet/Header.cs
index b50eac2c1a..260a989628 100644
--- a/osu.Game/Overlays/BeatmapSet/Header.cs
+++ b/osu.Game/Overlays/BeatmapSet/Header.cs
@@ -161,7 +161,10 @@ namespace osu.Game.Overlays.BeatmapSet
Margin = new MarginPadding { Top = 10 },
Children = new Drawable[]
{
- favouriteButton = new FavouriteButton(),
+ favouriteButton = new FavouriteButton
+ {
+ BeatmapSet = { BindTarget = BeatmapSet }
+ },
downloadButtonsContainer = new FillFlowContainer
{
RelativeSizeAxes = Axes.Both,
diff --git a/osu.Game/Overlays/BeatmapSet/Scores/DrawableTopScore.cs b/osu.Game/Overlays/BeatmapSet/Scores/DrawableTopScore.cs
index 8e806c6747..d263483046 100644
--- a/osu.Game/Overlays/BeatmapSet/Scores/DrawableTopScore.cs
+++ b/osu.Game/Overlays/BeatmapSet/Scores/DrawableTopScore.cs
@@ -23,10 +23,8 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
private Color4 backgroundHoveredColour;
private readonly Box background;
- private readonly TopScoreUserSection userSection;
- private readonly TopScoreStatisticsSection statisticsSection;
- public DrawableTopScore()
+ public DrawableTopScore(ScoreInfo score, int position = 1)
{
RelativeSizeAxes = Axes.X;
AutoSizeAxes = Axes.Y;
@@ -61,16 +59,19 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
{
new Drawable[]
{
- userSection = new TopScoreUserSection
+ new TopScoreUserSection
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
+ Score = score,
+ ScorePosition = position,
},
null,
- statisticsSection = new TopScoreStatisticsSection
+ new TopScoreStatisticsSection
{
Anchor = Anchor.CentreRight,
Origin = Anchor.CentreRight,
+ Score = score,
}
},
},
@@ -91,18 +92,6 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
background.Colour = backgroundIdleColour;
}
- ///
- /// Sets the score to be displayed.
- ///
- public ScoreInfo Score
- {
- set
- {
- userSection.Score = value;
- statisticsSection.Score = value;
- }
- }
-
protected override bool OnHover(HoverEvent e)
{
background.FadeColour(backgroundHoveredColour, fade_duration, Easing.OutQuint);
diff --git a/osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs b/osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs
index 15816be327..347522fb48 100644
--- a/osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs
+++ b/osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs
@@ -59,7 +59,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
Content = null;
backgroundFlow.Clear();
- if (value == null || !value.Any())
+ if (value?.Any() != true)
return;
for (int i = 0; i < value.Count; i++)
diff --git a/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs b/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs
index 3e6c938802..a6cc2b0500 100644
--- a/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs
+++ b/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs
@@ -5,37 +5,80 @@ using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
-using osu.Game.Beatmaps;
using osu.Game.Graphics;
using osu.Game.Graphics.UserInterface;
+using osuTK;
+using System.Linq;
+using osu.Game.Online.API.Requests.Responses;
+using osu.Game.Beatmaps;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests;
-using osuTK;
-using System.Collections.Generic;
-using System.Linq;
-using osu.Game.Scoring;
namespace osu.Game.Overlays.BeatmapSet.Scores
{
public class ScoresContainer : CompositeDrawable
{
private const int spacing = 15;
- private const int fade_duration = 200;
private readonly Box background;
private readonly ScoreTable scoreTable;
-
- private readonly DrawableTopScore topScore;
+ private readonly FillFlowContainer topScoresContainer;
private readonly LoadingAnimation loadingAnimation;
[Resolved]
private IAPIProvider api { get; set; }
+ private GetScoresRequest getScoresRequest;
+
+ private BeatmapInfo beatmap;
+
+ public BeatmapInfo Beatmap
+ {
+ get => beatmap;
+ set
+ {
+ if (beatmap == value)
+ return;
+
+ beatmap = value;
+
+ getScores(beatmap);
+ }
+ }
+
+ protected APILegacyScores Scores
+ {
+ set
+ {
+ Schedule(() =>
+ {
+ topScoresContainer.Clear();
+
+ if (value?.Scores.Any() != true)
+ {
+ scoreTable.Scores = null;
+ scoreTable.Hide();
+ return;
+ }
+
+ scoreTable.Scores = value.Scores;
+ scoreTable.Show();
+
+ var topScore = value.Scores.First();
+ var userScore = value.UserScore;
+
+ topScoresContainer.Add(new DrawableTopScore(topScore));
+
+ if (userScore != null && userScore.Score.OnlineScoreID != topScore.OnlineScoreID)
+ topScoresContainer.Add(new DrawableTopScore(userScore.Score, userScore.Position));
+ });
+ }
+ }
+
public ScoresContainer()
{
RelativeSizeAxes = Axes.X;
AutoSizeAxes = Axes.Y;
-
InternalChildren = new Drawable[]
{
background = new Box
@@ -54,7 +97,13 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
Margin = new MarginPadding { Vertical = spacing },
Children = new Drawable[]
{
- topScore = new DrawableTopScore(),
+ topScoresContainer = new FillFlowContainer
+ {
+ RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y,
+ Direction = FillDirection.Vertical,
+ Spacing = new Vector2(0, 5),
+ },
scoreTable = new ScoreTable
{
Anchor = Anchor.TopCentre,
@@ -65,7 +114,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
loadingAnimation = new LoadingAnimation
{
Alpha = 0,
- Margin = new MarginPadding(20)
+ Margin = new MarginPadding(20),
},
};
}
@@ -74,70 +123,26 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
private void load(OsuColour colours)
{
background.Colour = colours.Gray2;
- updateDisplay();
}
- private bool loading
- {
- set => loadingAnimation.FadeTo(value ? 1 : 0, fade_duration);
- }
-
- private GetScoresRequest getScoresRequest;
- private IReadOnlyList scores;
-
- public IReadOnlyList Scores
- {
- get => scores;
- set
- {
- getScoresRequest?.Cancel();
- scores = value;
-
- updateDisplay();
- }
- }
-
- private BeatmapInfo beatmap;
-
- public BeatmapInfo Beatmap
- {
- get => beatmap;
- set
- {
- beatmap = value;
-
- Scores = null;
-
- if (beatmap?.OnlineBeatmapID.HasValue != true)
- return;
-
- loading = true;
-
- getScoresRequest = new GetScoresRequest(beatmap, beatmap.Ruleset);
- getScoresRequest.Success += r => Schedule(() => Scores = r.Scores);
- api.Queue(getScoresRequest);
- }
- }
-
- private void updateDisplay()
- {
- loading = false;
-
- scoreTable.Scores = scores?.Count > 1 ? scores : new List();
- scoreTable.FadeTo(scores?.Count > 1 ? 1 : 0);
-
- if (scores?.Any() == true)
- {
- topScore.Score = scores.FirstOrDefault();
- topScore.Show();
- }
- else
- topScore.Hide();
- }
-
- protected override void Dispose(bool isDisposing)
+ private void getScores(BeatmapInfo beatmap)
{
getScoresRequest?.Cancel();
+ getScoresRequest = null;
+
+ Scores = null;
+
+ if (beatmap?.OnlineBeatmapID.HasValue != true)
+ return;
+
+ loadingAnimation.Show();
+ getScoresRequest = new GetScoresRequest(beatmap, beatmap.Ruleset);
+ getScoresRequest.Success += scores =>
+ {
+ loadingAnimation.Hide();
+ Scores = scores;
+ };
+ api.Queue(getScoresRequest);
}
}
}
diff --git a/osu.Game/Overlays/BeatmapSet/Scores/TopScoreUserSection.cs b/osu.Game/Overlays/BeatmapSet/Scores/TopScoreUserSection.cs
index 1d9c4e7fc8..ffc39e5af2 100644
--- a/osu.Game/Overlays/BeatmapSet/Scores/TopScoreUserSection.cs
+++ b/osu.Game/Overlays/BeatmapSet/Scores/TopScoreUserSection.cs
@@ -39,21 +39,30 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
Spacing = new Vector2(10, 0),
Children = new Drawable[]
{
- rankText = new OsuSpriteText
+ new FillFlowContainer
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
- Text = "#1",
- Font = OsuFont.GetFont(size: 30, weight: FontWeight.Bold, italics: true)
+ AutoSizeAxes = Axes.Both,
+ Direction = FillDirection.Vertical,
+ Children = new Drawable[]
+ {
+ rankText = new OsuSpriteText
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ Font = OsuFont.GetFont(size: 24, weight: FontWeight.Bold, italics: true)
+ },
+ rank = new UpdateableRank(ScoreRank.D)
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ Size = new Vector2(40),
+ FillMode = FillMode.Fit,
+ },
+ }
},
- rank = new UpdateableRank(ScoreRank.D)
- {
- Anchor = Anchor.Centre,
- Origin = Anchor.Centre,
- Size = new Vector2(40),
- FillMode = FillMode.Fit,
- },
- avatar = new UpdateableAvatar(hideImmediately: true)
+ avatar = new UpdateableAvatar
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
@@ -90,7 +99,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
Origin = Anchor.CentreLeft,
Font = OsuFont.GetFont(size: 15, weight: FontWeight.Bold)
},
- flag = new UpdateableFlag(hideImmediately: true)
+ flag = new UpdateableFlag
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
@@ -109,6 +118,11 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
rankText.Colour = colours.Yellow;
}
+ public int ScorePosition
+ {
+ set => rankText.Text = $"#{value}";
+ }
+
///
/// Sets the score to be displayed.
///
diff --git a/osu.Game/Overlays/BeatmapSetOverlay.cs b/osu.Game/Overlays/BeatmapSetOverlay.cs
index 19f6a3f692..c20e6368d8 100644
--- a/osu.Game/Overlays/BeatmapSetOverlay.cs
+++ b/osu.Game/Overlays/BeatmapSetOverlay.cs
@@ -21,12 +21,9 @@ namespace osu.Game.Overlays
{
public class BeatmapSetOverlay : FullscreenOverlay
{
- private const int fade_duration = 300;
-
public const float X_PADDING = 40;
public const float TOP_PADDING = 25;
public const float RIGHT_WIDTH = 275;
-
protected readonly Header Header;
private RulesetStore rulesets;
@@ -40,7 +37,7 @@ namespace osu.Game.Overlays
{
OsuScrollContainer scroll;
Info info;
- ScoresContainer scores;
+ ScoresContainer scoreContainer;
Children = new Drawable[]
{
@@ -62,7 +59,7 @@ namespace osu.Game.Overlays
{
Header = new Header(),
info = new Info(),
- scores = new ScoresContainer(),
+ scoreContainer = new ScoresContainer(),
},
},
},
@@ -74,7 +71,7 @@ namespace osu.Game.Overlays
Header.Picker.Beatmap.ValueChanged += b =>
{
info.Beatmap = b.NewValue;
- scores.Beatmap = b.NewValue;
+ scoreContainer.Beatmap = b.NewValue;
scroll.ScrollToStart();
};
@@ -101,6 +98,7 @@ namespace osu.Game.Overlays
public void FetchAndShowBeatmap(int beatmapId)
{
beatmapSet.Value = null;
+
var req = new GetBeatmapSetRequest(beatmapId, BeatmapSetLookupType.BeatmapId);
req.Success += res =>
{
@@ -108,15 +106,18 @@ namespace osu.Game.Overlays
Header.Picker.Beatmap.Value = Header.BeatmapSet.Value.Beatmaps.First(b => b.OnlineBeatmapID == beatmapId);
};
API.Queue(req);
+
Show();
}
public void FetchAndShowBeatmapSet(int beatmapSetId)
{
beatmapSet.Value = null;
+
var req = new GetBeatmapSetRequest(beatmapSetId);
req.Success += res => beatmapSet.Value = res.ToBeatmapSet(rulesets);
API.Queue(req);
+
Show();
}
diff --git a/osu.Game/Overlays/Changelog/ChangelogSingleBuild.cs b/osu.Game/Overlays/Changelog/ChangelogSingleBuild.cs
index 36ae5a756c..9c3504f477 100644
--- a/osu.Game/Overlays/Changelog/ChangelogSingleBuild.cs
+++ b/osu.Game/Overlays/Changelog/ChangelogSingleBuild.cs
@@ -58,7 +58,11 @@ namespace osu.Game.Overlays.Changelog
}
if (build != null)
- Child = new ChangelogBuildWithNavigation(build) { SelectBuild = SelectBuild };
+ Children = new Drawable[]
+ {
+ new ChangelogBuildWithNavigation(build) { SelectBuild = SelectBuild },
+ new Comments(build)
+ };
}
public class ChangelogBuildWithNavigation : ChangelogBuild
@@ -88,24 +92,16 @@ namespace osu.Game.Overlays.Changelog
});
}
- NavigationIconButton left, right;
-
- fill.AddRange(new[]
+ fill.Insert(-1, new NavigationIconButton(Build.Versions?.Previous)
{
- left = new NavigationIconButton(Build.Versions?.Previous)
- {
- Icon = FontAwesome.Solid.ChevronLeft,
- SelectBuild = b => SelectBuild(b)
- },
- right = new NavigationIconButton(Build.Versions?.Next)
- {
- Icon = FontAwesome.Solid.ChevronRight,
- SelectBuild = b => SelectBuild(b)
- },
+ Icon = FontAwesome.Solid.ChevronLeft,
+ SelectBuild = b => SelectBuild(b)
+ });
+ fill.Insert(1, new NavigationIconButton(Build.Versions?.Next)
+ {
+ Icon = FontAwesome.Solid.ChevronRight,
+ SelectBuild = b => SelectBuild(b)
});
-
- fill.SetLayoutPosition(left, -1);
- fill.SetLayoutPosition(right, 1);
return fill;
}
diff --git a/osu.Game/Overlays/Changelog/Comments.cs b/osu.Game/Overlays/Changelog/Comments.cs
new file mode 100644
index 0000000000..4cf39e7b44
--- /dev/null
+++ b/osu.Game/Overlays/Changelog/Comments.cs
@@ -0,0 +1,79 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Framework.Allocation;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Shapes;
+using osu.Framework.Graphics.Sprites;
+using osu.Game.Graphics;
+using osu.Game.Graphics.Containers;
+using osu.Game.Online.API.Requests.Responses;
+using osuTK.Graphics;
+
+namespace osu.Game.Overlays.Changelog
+{
+ public class Comments : CompositeDrawable
+ {
+ private readonly APIChangelogBuild build;
+
+ public Comments(APIChangelogBuild build)
+ {
+ this.build = build;
+
+ RelativeSizeAxes = Axes.X;
+ AutoSizeAxes = Axes.Y;
+
+ Padding = new MarginPadding
+ {
+ Horizontal = 50,
+ Vertical = 20,
+ };
+ }
+
+ [BackgroundDependencyLoader]
+ private void load(OsuColour colours)
+ {
+ LinkFlowContainer text;
+
+ InternalChildren = new Drawable[]
+ {
+ new Container
+ {
+ RelativeSizeAxes = Axes.Both,
+ Masking = true,
+ CornerRadius = 10,
+ Child = new Box
+ {
+ RelativeSizeAxes = Axes.Both,
+ Colour = colours.GreyVioletDarker
+ },
+ },
+ text = new LinkFlowContainer(t =>
+ {
+ t.Colour = colours.PinkLighter;
+ t.Font = OsuFont.Default.With(size: 14);
+ })
+ {
+ Padding = new MarginPadding(20),
+ RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y,
+ }
+ };
+
+ text.AddParagraph("Got feedback?", t =>
+ {
+ t.Colour = Color4.White;
+ t.Font = OsuFont.Default.With(italics: true, size: 20);
+ t.Padding = new MarginPadding { Bottom = 20 };
+ });
+
+ text.AddParagraph("We would love to hear what you think of this update! ");
+ text.AddIcon(FontAwesome.Regular.GrinHearts);
+
+ text.AddParagraph("Please visit the ");
+ text.AddLink("web version", $"{build.Url}#comments");
+ text.AddText(" of this changelog to leave any comments.");
+ }
+ }
+}
diff --git a/osu.Game/Overlays/Chat/ChatLine.cs b/osu.Game/Overlays/Chat/ChatLine.cs
index e29216dffd..2576b38ec8 100644
--- a/osu.Game/Overlays/Chat/ChatLine.cs
+++ b/osu.Game/Overlays/Chat/ChatLine.cs
@@ -85,6 +85,7 @@ namespace osu.Game.Overlays.Chat
Drawable effectedUsername = username = new OsuSpriteText
{
+ Shadow = false,
Colour = hasBackground ? customUsernameColour : username_colours[message.Sender.Id % username_colours.Length],
Font = OsuFont.GetFont(size: TextSize, weight: FontWeight.Bold, italics: true)
};
@@ -133,6 +134,7 @@ namespace osu.Game.Overlays.Chat
{
timestamp = new OsuSpriteText
{
+ Shadow = false,
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
Font = OsuFont.GetFont(size: TextSize * 0.75f, weight: FontWeight.SemiBold, fixedWidth: true)
@@ -155,6 +157,8 @@ namespace osu.Game.Overlays.Chat
{
contentFlow = new LinkFlowContainer(t =>
{
+ t.Shadow = false;
+
if (Message.IsAction)
{
t.Font = OsuFont.GetFont(italics: true);
diff --git a/osu.Game/Overlays/Chat/Tabs/ChannelTabItem.cs b/osu.Game/Overlays/Chat/Tabs/ChannelTabItem.cs
index 7f820e4ff7..2a3dd55c71 100644
--- a/osu.Game/Overlays/Chat/Tabs/ChannelTabItem.cs
+++ b/osu.Game/Overlays/Chat/Tabs/ChannelTabItem.cs
@@ -16,6 +16,7 @@ using osu.Game.Graphics.Sprites;
using osu.Game.Online.Chat;
using osuTK;
using osuTK.Graphics;
+using osuTK.Input;
namespace osu.Game.Overlays.Chat.Tabs
{
@@ -138,6 +139,19 @@ namespace osu.Game.Overlays.Chat.Tabs
updateState();
}
+ protected override bool OnMouseUp(MouseUpEvent e)
+ {
+ switch (e.Button)
+ {
+ case MouseButton.Middle:
+ CloseButton.Click();
+ return true;
+
+ default:
+ return false;
+ }
+ }
+
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
diff --git a/osu.Game/Overlays/Direct/DirectRulesetSelector.cs b/osu.Game/Overlays/Direct/DirectRulesetSelector.cs
index fdab9f1b90..106aaa616b 100644
--- a/osu.Game/Overlays/Direct/DirectRulesetSelector.cs
+++ b/osu.Game/Overlays/Direct/DirectRulesetSelector.cs
@@ -26,8 +26,13 @@ namespace osu.Game.Overlays.Direct
TabContainer.Masking = false;
TabContainer.Spacing = new Vector2(10, 0);
AutoSizeAxes = Axes.Both;
+ }
- Current.DisabledChanged += value => SelectedTab.FadeColour(value ? Color4.DarkGray : Color4.White, 200, Easing.OutQuint);
+ protected override void LoadComplete()
+ {
+ base.LoadComplete();
+
+ Current.BindDisabledChanged(value => SelectedTab.FadeColour(value ? Color4.DarkGray : Color4.White, 200, Easing.OutQuint), true);
}
protected override TabItem CreateTabItem(RulesetInfo value) => new DirectRulesetTabItem(value);
diff --git a/osu.Game/Overlays/Music/PlaylistList.cs b/osu.Game/Overlays/Music/PlaylistList.cs
index 07040f166d..539601c359 100644
--- a/osu.Game/Overlays/Music/PlaylistList.cs
+++ b/osu.Game/Overlays/Music/PlaylistList.cs
@@ -85,10 +85,7 @@ namespace osu.Game.Overlays.Music
private void addBeatmapSet(BeatmapSetInfo obj) => Schedule(() =>
{
- var newItem = new PlaylistItem(obj) { OnSelect = set => Selected?.Invoke(set) };
-
- items.Add(newItem);
- items.SetLayoutPosition(newItem, items.Count - 1);
+ items.Insert(items.Count - 1, new PlaylistItem(obj) { OnSelect = set => Selected?.Invoke(set) });
});
private void removeBeatmapSet(BeatmapSetInfo obj) => Schedule(() =>
diff --git a/osu.Game/Overlays/MusicController.cs b/osu.Game/Overlays/MusicController.cs
index 618187069d..724be21957 100644
--- a/osu.Game/Overlays/MusicController.cs
+++ b/osu.Game/Overlays/MusicController.cs
@@ -55,6 +55,8 @@ namespace osu.Game.Overlays
private Container dragContainer;
private Container playerContainer;
+ public bool IsUserPaused { get; private set; }
+
[Resolved]
private Bindable beatmap { get; set; }
@@ -157,7 +159,7 @@ namespace osu.Game.Overlays
Origin = Anchor.Centre,
Scale = new Vector2(1.4f),
IconScale = new Vector2(1.4f),
- Action = play,
+ Action = togglePause,
Icon = FontAwesome.Regular.PlayCircle,
},
nextButton = new MusicIconButton
@@ -276,7 +278,7 @@ namespace osu.Game.Overlays
}
}
- private void play()
+ private void togglePause()
{
var track = current?.Track;
@@ -288,9 +290,15 @@ namespace osu.Game.Overlays
}
if (track.IsRunning)
+ {
+ IsUserPaused = true;
track.Stop();
+ }
else
+ {
track.Start();
+ IsUserPaused = false;
+ }
}
private void prev()
diff --git a/osu.Game/Overlays/Notifications/NotificationSection.cs b/osu.Game/Overlays/Notifications/NotificationSection.cs
index f9278bbbd2..17a2d4cf9f 100644
--- a/osu.Game/Overlays/Notifications/NotificationSection.cs
+++ b/osu.Game/Overlays/Notifications/NotificationSection.cs
@@ -26,8 +26,7 @@ namespace osu.Game.Overlays.Notifications
public void Add(Notification notification, float position)
{
- notifications.Add(notification);
- notifications.SetLayoutPosition(notification, position);
+ notifications.Insert((int)position, notification);
}
public IEnumerable AcceptTypes;
diff --git a/osu.Game/Overlays/OSD/Toast.cs b/osu.Game/Overlays/OSD/Toast.cs
index 67c9b46c77..db5e6e4a6a 100644
--- a/osu.Game/Overlays/OSD/Toast.cs
+++ b/osu.Game/Overlays/OSD/Toast.cs
@@ -65,6 +65,7 @@ namespace osu.Game.Overlays.OSD
Anchor = Anchor.BottomCentre,
Origin = Anchor.BottomCentre,
Name = "Shortcut",
+ Alpha = 0.3f,
Margin = new MarginPadding { Bottom = 15 },
Font = OsuFont.GetFont(size: 12, weight: FontWeight.Bold),
Text = string.IsNullOrEmpty(keybinding) ? "NO KEY BOUND" : keybinding.ToUpperInvariant()
diff --git a/osu.Game/Overlays/OSD/TrackedSettingToast.cs b/osu.Game/Overlays/OSD/TrackedSettingToast.cs
index 9812dcd797..0f4bd34779 100644
--- a/osu.Game/Overlays/OSD/TrackedSettingToast.cs
+++ b/osu.Game/Overlays/OSD/TrackedSettingToast.cs
@@ -17,6 +17,8 @@ namespace osu.Game.Overlays.OSD
{
public class TrackedSettingToast : Toast
{
+ private const int lights_bottom_margin = 40;
+
public TrackedSettingToast(SettingDescription description)
: base(description.Name, description.Value, description.Shortcut)
{
@@ -24,17 +26,16 @@ namespace osu.Game.Overlays.OSD
Children = new Drawable[]
{
- new FillFlowContainer
+ new Container
{
- Anchor = Anchor.TopCentre,
- Origin = Anchor.TopCentre,
- Direction = FillDirection.Vertical,
- Margin = new MarginPadding { Top = 70 },
+ Anchor = Anchor.BottomCentre,
+ Origin = Anchor.BottomCentre,
+ Margin = new MarginPadding { Bottom = lights_bottom_margin },
Children = new Drawable[]
{
optionLights = new FillFlowContainer
{
- Padding = new MarginPadding { Bottom = 5 },
+ Margin = new MarginPadding { Bottom = 5 },
Spacing = new Vector2(5, 0),
Direction = FillDirection.Horizontal,
Anchor = Anchor.TopCentre,
diff --git a/osu.Game/Overlays/Profile/Header/MedalHeaderContainer.cs b/osu.Game/Overlays/Profile/Header/MedalHeaderContainer.cs
index 67229a80c0..45bc60f794 100644
--- a/osu.Game/Overlays/Profile/Header/MedalHeaderContainer.cs
+++ b/osu.Game/Overlays/Profile/Header/MedalHeaderContainer.cs
@@ -78,10 +78,8 @@ namespace osu.Game.Overlays.Profile.Header
int displayIndex = index;
LoadComponentAsync(new DrawableBadge(badges[index]), asyncBadge =>
{
- badgeFlowContainer.Add(asyncBadge);
-
// load in stable order regardless of async load order.
- badgeFlowContainer.SetLayoutPosition(asyncBadge, displayIndex);
+ badgeFlowContainer.Insert(displayIndex, asyncBadge);
});
}
}
diff --git a/osu.Game/Overlays/Profile/Sections/BeatmapMetadataContainer.cs b/osu.Game/Overlays/Profile/Sections/BeatmapMetadataContainer.cs
index 16326900f1..13b547eed3 100644
--- a/osu.Game/Overlays/Profile/Sections/BeatmapMetadataContainer.cs
+++ b/osu.Game/Overlays/Profile/Sections/BeatmapMetadataContainer.cs
@@ -4,26 +4,23 @@
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
-using osu.Framework.Localisation;
using osu.Game.Beatmaps;
-using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
-using osu.Game.Graphics.Sprites;
namespace osu.Game.Overlays.Profile.Sections
{
///
/// Display artist/title/mapper information, commonly used as the left portion of a profile or score display row (see ).
///
- public class BeatmapMetadataContainer : OsuHoverContainer
+ public abstract class BeatmapMetadataContainer : OsuHoverContainer
{
private readonly BeatmapInfo beatmap;
- public BeatmapMetadataContainer(BeatmapInfo beatmap)
+ protected BeatmapMetadataContainer(BeatmapInfo beatmap)
{
this.beatmap = beatmap;
+
AutoSizeAxes = Axes.Both;
- TooltipText = $"{beatmap.Metadata.Artist} - {beatmap.Metadata.Title}";
}
[BackgroundDependencyLoader(true)]
@@ -40,23 +37,10 @@ namespace osu.Game.Overlays.Profile.Sections
Child = new FillFlowContainer
{
AutoSizeAxes = Axes.Both,
- Children = new Drawable[]
- {
- new OsuSpriteText
- {
- Text = new LocalisedString((
- $"{beatmap.Metadata.TitleUnicode ?? beatmap.Metadata.Title} [{beatmap.Version}] ",
- $"{beatmap.Metadata.Title ?? beatmap.Metadata.TitleUnicode} [{beatmap.Version}] ")),
- Font = OsuFont.GetFont(size: 15, weight: FontWeight.SemiBold, italics: true)
- },
- new OsuSpriteText
- {
- Text = new LocalisedString((beatmap.Metadata.ArtistUnicode, beatmap.Metadata.Artist)),
- Padding = new MarginPadding { Top = 3 },
- Font = OsuFont.GetFont(size: 12, weight: FontWeight.Regular, italics: true)
- },
- },
+ Children = CreateText(beatmap),
};
}
+
+ protected abstract Drawable[] CreateText(BeatmapInfo beatmap);
}
}
diff --git a/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs b/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs
index b6b0e605d7..1b6c1c99a6 100644
--- a/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs
+++ b/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs
@@ -29,7 +29,7 @@ namespace osu.Game.Overlays.Profile.Sections.Beatmaps
protected override void ShowMore()
{
- request = new GetUserBeatmapsRequest(User.Value.Id, type, VisiblePages++ * ItemsPerPage);
+ request = new GetUserBeatmapsRequest(User.Value.Id, type, VisiblePages++, ItemsPerPage);
request.Success += sets => Schedule(() =>
{
MoreButton.FadeTo(sets.Count == ItemsPerPage ? 1 : 0);
diff --git a/osu.Game/Overlays/Profile/Sections/Historical/DrawableMostPlayedBeatmap.cs b/osu.Game/Overlays/Profile/Sections/Historical/DrawableMostPlayedBeatmap.cs
new file mode 100644
index 0000000000..0206c4e13b
--- /dev/null
+++ b/osu.Game/Overlays/Profile/Sections/Historical/DrawableMostPlayedBeatmap.cs
@@ -0,0 +1,182 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Framework.Allocation;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Shapes;
+using osu.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 System.Collections.Generic;
+using osu.Framework.Graphics.Cursor;
+
+namespace osu.Game.Overlays.Profile.Sections.Historical
+{
+ public class DrawableMostPlayedBeatmap : OsuHoverContainer
+ {
+ private const int cover_width = 100;
+ private const int corner_radius = 6;
+ private const int height = 50;
+
+ private readonly BeatmapInfo beatmap;
+ private readonly int playCount;
+
+ private Box background;
+
+ protected override IEnumerable EffectTargets => new[] { background };
+
+ public DrawableMostPlayedBeatmap(BeatmapInfo beatmap, int playCount)
+ {
+ this.beatmap = beatmap;
+ this.playCount = playCount;
+ Enabled.Value = true; //manually enabled, because we have no action
+
+ RelativeSizeAxes = Axes.X;
+ Height = height;
+
+ Masking = true;
+ CornerRadius = corner_radius;
+ }
+
+ [BackgroundDependencyLoader]
+ private void load(OsuColour colours)
+ {
+ IdleColour = colours.GreySeafoam;
+ HoverColour = colours.GreySeafoamLight;
+
+ Children = new Drawable[]
+ {
+ new UpdateableBeatmapSetCover
+ {
+ RelativeSizeAxes = Axes.Y,
+ Width = cover_width,
+ BeatmapSet = beatmap.BeatmapSet,
+ CoverType = BeatmapSetCoverType.List,
+ },
+ new Container
+ {
+ RelativeSizeAxes = Axes.Both,
+ Padding = new MarginPadding { Left = cover_width - corner_radius },
+ Children = new Drawable[]
+ {
+ new Container
+ {
+ RelativeSizeAxes = Axes.Both,
+ Masking = true,
+ CornerRadius = corner_radius,
+ Children = new Drawable[]
+ {
+ background = new Box { RelativeSizeAxes = Axes.Both },
+ new Container
+ {
+ RelativeSizeAxes = Axes.Both,
+ Padding = new MarginPadding(10),
+ Children = new Drawable[]
+ {
+ new FillFlowContainer
+ {
+ Anchor = Anchor.CentreLeft,
+ Origin = Anchor.CentreLeft,
+ AutoSizeAxes = Axes.Both,
+ Direction = FillDirection.Vertical,
+ Children = new Drawable[]
+ {
+ new MostPlayedBeatmapMetadataContainer(beatmap),
+ new LinkFlowContainer(t => t.Font = OsuFont.GetFont(size: 12, weight: FontWeight.Regular))
+ {
+ AutoSizeAxes = Axes.Both,
+ Direction = FillDirection.Horizontal,
+ Colour = colours.GreySeafoamLighter
+ }.With(d =>
+ {
+ d.AddText("mapped by ");
+ d.AddUserLink(beatmap.Metadata.Author);
+ }),
+ }
+ },
+ new PlayCountText(playCount)
+ {
+ Anchor = Anchor.CentreRight,
+ Origin = Anchor.CentreRight
+ },
+ }
+ },
+ }
+ }
+ }
+ }
+ };
+ }
+
+ private class MostPlayedBeatmapMetadataContainer : BeatmapMetadataContainer
+ {
+ public MostPlayedBeatmapMetadataContainer(BeatmapInfo beatmap)
+ : base(beatmap)
+ {
+ }
+
+ protected override Drawable[] CreateText(BeatmapInfo beatmap) => new Drawable[]
+ {
+ new OsuSpriteText
+ {
+ Text = new LocalisedString((
+ $"{beatmap.Metadata.TitleUnicode ?? beatmap.Metadata.Title} [{beatmap.Version}] ",
+ $"{beatmap.Metadata.Title ?? beatmap.Metadata.TitleUnicode} [{beatmap.Version}] ")),
+ Font = OsuFont.GetFont(weight: FontWeight.Bold)
+ },
+ new OsuSpriteText
+ {
+ Text = "by " + new LocalisedString((beatmap.Metadata.ArtistUnicode, beatmap.Metadata.Artist)),
+ Font = OsuFont.GetFont(weight: FontWeight.Regular)
+ },
+ };
+ }
+
+ private class PlayCountText : CompositeDrawable, IHasTooltip
+ {
+ public string TooltipText => "times played";
+
+ public PlayCountText(int playCount)
+ {
+ AutoSizeAxes = Axes.Both;
+
+ InternalChild = new FillFlowContainer
+ {
+ Anchor = Anchor.CentreRight,
+ Origin = Anchor.CentreRight,
+ AutoSizeAxes = Axes.Both,
+ Spacing = new Vector2(5, 0),
+ Children = new Drawable[]
+ {
+ new SpriteIcon
+ {
+ Origin = Anchor.Centre,
+ Anchor = Anchor.Centre,
+ Size = new Vector2(12),
+ Icon = FontAwesome.Solid.Play,
+ },
+ new OsuSpriteText
+ {
+ Origin = Anchor.Centre,
+ Anchor = Anchor.Centre,
+ Text = playCount.ToString(),
+ Font = OsuFont.GetFont(size: 20, weight: FontWeight.Regular),
+ },
+ }
+ };
+ }
+
+ [BackgroundDependencyLoader]
+ private void load(OsuColour colours)
+ {
+ Colour = colours.Yellow;
+ }
+ }
+ }
+}
diff --git a/osu.Game/Overlays/Profile/Sections/Historical/DrawableMostPlayedRow.cs b/osu.Game/Overlays/Profile/Sections/Historical/DrawableMostPlayedRow.cs
deleted file mode 100644
index 1b286f92d3..0000000000
--- a/osu.Game/Overlays/Profile/Sections/Historical/DrawableMostPlayedRow.cs
+++ /dev/null
@@ -1,77 +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.Graphics;
-using osu.Framework.Graphics.Containers;
-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;
-
-namespace osu.Game.Overlays.Profile.Sections.Historical
-{
- public class DrawableMostPlayedRow : DrawableProfileRow
- {
- private readonly BeatmapInfo beatmap;
- private readonly int playCount;
-
- public DrawableMostPlayedRow(BeatmapInfo beatmap, int playCount)
- {
- this.beatmap = beatmap;
- this.playCount = playCount;
- }
-
- protected override Drawable CreateLeftVisual() => new UpdateableBeatmapSetCover
- {
- Anchor = Anchor.CentreLeft,
- Origin = Anchor.CentreLeft,
- Size = new Vector2(80, 50),
- BeatmapSet = beatmap.BeatmapSet,
- CoverType = BeatmapSetCoverType.List,
- };
-
- [BackgroundDependencyLoader]
- private void load()
- {
- LeftFlowContainer.Add(new BeatmapMetadataContainer(beatmap));
- LeftFlowContainer.Add(new LinkFlowContainer(t => t.Font = OsuFont.GetFont(size: 12))
- {
- RelativeSizeAxes = Axes.X,
- AutoSizeAxes = Axes.Y,
- Direction = FillDirection.Horizontal,
- }.With(d =>
- {
- d.AddText("mapped by ");
- d.AddUserLink(beatmap.Metadata.Author);
- }));
-
- RightFlowContainer.Add(new FillFlowContainer
- {
- Anchor = Anchor.TopRight,
- Origin = Anchor.TopRight,
- AutoSizeAxes = Axes.Both,
- Direction = FillDirection.Horizontal,
- Children = new[]
- {
- new OsuSpriteText
- {
- Anchor = Anchor.BottomRight,
- Origin = Anchor.BottomRight,
- Text = playCount.ToString(),
- Font = OsuFont.GetFont(size: 18, weight: FontWeight.SemiBold, italics: true)
- },
- new OsuSpriteText
- {
- Anchor = Anchor.BottomRight,
- Origin = Anchor.BottomRight,
- Text = @"times played ",
- Font = OsuFont.GetFont(size: 12, weight: FontWeight.Regular, italics: true)
- },
- }
- });
- }
- }
-}
diff --git a/osu.Game/Overlays/Profile/Sections/Historical/PaginatedMostPlayedBeatmapContainer.cs b/osu.Game/Overlays/Profile/Sections/Historical/PaginatedMostPlayedBeatmapContainer.cs
index 6085b0bc05..23072f8d90 100644
--- a/osu.Game/Overlays/Profile/Sections/Historical/PaginatedMostPlayedBeatmapContainer.cs
+++ b/osu.Game/Overlays/Profile/Sections/Historical/PaginatedMostPlayedBeatmapContainer.cs
@@ -24,7 +24,7 @@ namespace osu.Game.Overlays.Profile.Sections.Historical
protected override void ShowMore()
{
- request = new GetUserMostPlayedBeatmapsRequest(User.Value.Id, VisiblePages++ * ItemsPerPage);
+ request = new GetUserMostPlayedBeatmapsRequest(User.Value.Id, VisiblePages++, ItemsPerPage);
request.Success += beatmaps => Schedule(() =>
{
MoreButton.FadeTo(beatmaps.Count == ItemsPerPage ? 1 : 0);
@@ -40,7 +40,7 @@ namespace osu.Game.Overlays.Profile.Sections.Historical
foreach (var beatmap in beatmaps)
{
- ItemsContainer.Add(new DrawableMostPlayedRow(beatmap.GetBeatmapInfo(Rulesets), beatmap.PlayCount));
+ ItemsContainer.Add(new DrawableMostPlayedBeatmap(beatmap.GetBeatmapInfo(Rulesets), beatmap.PlayCount));
}
});
diff --git a/osu.Game/Overlays/Profile/Sections/Ranks/DrawableProfileScore.cs b/osu.Game/Overlays/Profile/Sections/Ranks/DrawableProfileScore.cs
index 0a90c9b135..e54ce44ca2 100644
--- a/osu.Game/Overlays/Profile/Sections/Ranks/DrawableProfileScore.cs
+++ b/osu.Game/Overlays/Profile/Sections/Ranks/DrawableProfileScore.cs
@@ -10,6 +10,8 @@ using osu.Game.Online.Leaderboards;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.UI;
using osu.Game.Scoring;
+using osu.Game.Beatmaps;
+using osu.Framework.Localisation;
namespace osu.Game.Overlays.Profile.Sections.Ranks
{
@@ -49,10 +51,9 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks
Font = OsuFont.GetFont(size: 11, weight: FontWeight.Regular, italics: true)
};
- RightFlowContainer.Add(text);
- RightFlowContainer.SetLayoutPosition(text, 1);
+ RightFlowContainer.Insert(1, text);
- LeftFlowContainer.Add(new BeatmapMetadataContainer(Score.Beatmap));
+ LeftFlowContainer.Add(new ProfileScoreBeatmapMetadataContainer(Score.Beatmap));
LeftFlowContainer.Add(new DrawableDate(Score.Date));
foreach (Mod mod in Score.Mods)
@@ -65,5 +66,30 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks
Width = 60,
FillMode = FillMode.Fit,
};
+
+ private class ProfileScoreBeatmapMetadataContainer : BeatmapMetadataContainer
+ {
+ public ProfileScoreBeatmapMetadataContainer(BeatmapInfo beatmap)
+ : base(beatmap)
+ {
+ }
+
+ protected override Drawable[] CreateText(BeatmapInfo beatmap) => new Drawable[]
+ {
+ new OsuSpriteText
+ {
+ Text = new LocalisedString((
+ $"{beatmap.Metadata.TitleUnicode ?? beatmap.Metadata.Title} [{beatmap.Version}] ",
+ $"{beatmap.Metadata.Title ?? beatmap.Metadata.TitleUnicode} [{beatmap.Version}] ")),
+ Font = OsuFont.GetFont(size: 15, weight: FontWeight.SemiBold, italics: true)
+ },
+ new OsuSpriteText
+ {
+ Text = new LocalisedString((beatmap.Metadata.ArtistUnicode, beatmap.Metadata.Artist)),
+ Padding = new MarginPadding { Top = 3 },
+ Font = OsuFont.GetFont(size: 12, weight: FontWeight.Regular, italics: true)
+ },
+ };
+ }
}
}
diff --git a/osu.Game/Overlays/Profile/Sections/Ranks/PaginatedScoreContainer.cs b/osu.Game/Overlays/Profile/Sections/Ranks/PaginatedScoreContainer.cs
index a149cfa12e..4a9ac6e5c7 100644
--- a/osu.Game/Overlays/Profile/Sections/Ranks/PaginatedScoreContainer.cs
+++ b/osu.Game/Overlays/Profile/Sections/Ranks/PaginatedScoreContainer.cs
@@ -31,7 +31,7 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks
protected override void ShowMore()
{
- request = new GetUserScoresRequest(User.Value.Id, type, VisiblePages++ * ItemsPerPage);
+ request = new GetUserScoresRequest(User.Value.Id, type, VisiblePages++, ItemsPerPage);
request.Success += scores => Schedule(() =>
{
foreach (var s in scores)
diff --git a/osu.Game/Overlays/Profile/Sections/Recent/PaginatedRecentActivityContainer.cs b/osu.Game/Overlays/Profile/Sections/Recent/PaginatedRecentActivityContainer.cs
index b72aec7a44..f2a778a874 100644
--- a/osu.Game/Overlays/Profile/Sections/Recent/PaginatedRecentActivityContainer.cs
+++ b/osu.Game/Overlays/Profile/Sections/Recent/PaginatedRecentActivityContainer.cs
@@ -22,7 +22,7 @@ namespace osu.Game.Overlays.Profile.Sections.Recent
protected override void ShowMore()
{
- request = new GetUserRecentActivitiesRequest(User.Value.Id, VisiblePages++ * ItemsPerPage);
+ request = new GetUserRecentActivitiesRequest(User.Value.Id, VisiblePages++, ItemsPerPage);
request.Success += activities => Schedule(() =>
{
MoreButton.FadeTo(activities.Count == ItemsPerPage ? 1 : 0);
diff --git a/osu.Game/Overlays/Settings/Sections/Gameplay/GeneralSettings.cs b/osu.Game/Overlays/Settings/Sections/Gameplay/GeneralSettings.cs
index 997d1354b3..9142492610 100644
--- a/osu.Game/Overlays/Settings/Sections/Gameplay/GeneralSettings.cs
+++ b/osu.Game/Overlays/Settings/Sections/Gameplay/GeneralSettings.cs
@@ -35,6 +35,11 @@ namespace osu.Game.Overlays.Settings.Sections.Gameplay
Bindable = config.GetBindable(OsuSetting.ShowInterface)
},
new SettingsCheckbox
+ {
+ LabelText = "Show health display even when you can't fail",
+ Bindable = config.GetBindable(OsuSetting.ShowHealthDisplayWhenCantFail),
+ },
+ new SettingsCheckbox
{
LabelText = "Always show key overlay",
Bindable = config.GetBindable(OsuSetting.KeyOverlay)
diff --git a/osu.Game/Overlays/Settings/SettingsItem.cs b/osu.Game/Overlays/Settings/SettingsItem.cs
index ae840c8c00..d48c0b6b66 100644
--- a/osu.Game/Overlays/Settings/SettingsItem.cs
+++ b/osu.Game/Overlays/Settings/SettingsItem.cs
@@ -46,8 +46,7 @@ namespace osu.Game.Overlays.Settings
if (text == null)
{
// construct lazily for cases where the label is not needed (may be provided by the Control).
- Add(text = new OsuSpriteText());
- FlowContent.SetLayoutPosition(text, -1);
+ FlowContent.Insert(-1, text = new OsuSpriteText());
}
text.Text = value;
diff --git a/osu.Game/Overlays/Toolbar/ToolbarRulesetSelector.cs b/osu.Game/Overlays/Toolbar/ToolbarRulesetSelector.cs
index f4272ab15c..2c79f5bc0e 100644
--- a/osu.Game/Overlays/Toolbar/ToolbarRulesetSelector.cs
+++ b/osu.Game/Overlays/Toolbar/ToolbarRulesetSelector.cs
@@ -71,16 +71,11 @@ namespace osu.Game.Overlays.Toolbar
// Scheduled to allow the flow layout to be computed before the line position is updated
private void moveLineToCurrent() => ScheduleAfterChildren(() =>
{
- foreach (var tabItem in TabContainer)
+ if (SelectedTab != null)
{
- if (tabItem.Value == Current.Value)
- {
- ModeButtonLine.MoveToX(tabItem.DrawPosition.X, !hasInitialPosition ? 0 : 200, Easing.OutQuint);
- break;
- }
+ ModeButtonLine.MoveToX(SelectedTab.DrawPosition.X, !hasInitialPosition ? 0 : 200, Easing.OutQuint);
+ hasInitialPosition = true;
}
-
- hasInitialPosition = true;
});
public override bool HandleNonPositionalInput => !Current.Disabled && base.HandleNonPositionalInput;
diff --git a/osu.Game/Rulesets/Mods/IApplicableToHUD.cs b/osu.Game/Rulesets/Mods/IApplicableToHUD.cs
new file mode 100644
index 0000000000..4fb535a0b3
--- /dev/null
+++ b/osu.Game/Rulesets/Mods/IApplicableToHUD.cs
@@ -0,0 +1,18 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Game.Screens.Play;
+
+namespace osu.Game.Rulesets.Mods
+{
+ ///
+ /// An interface for mods that apply changes to the .
+ ///
+ public interface IApplicableToHUD : IApplicableMod
+ {
+ ///
+ /// Provide a . Called once on initialisation of a play instance.
+ ///
+ void ApplyToHUD(HUDOverlay overlay);
+ }
+}
diff --git a/osu.Game/Rulesets/Mods/ModBlockFail.cs b/osu.Game/Rulesets/Mods/ModBlockFail.cs
new file mode 100644
index 0000000000..26efc3932d
--- /dev/null
+++ b/osu.Game/Rulesets/Mods/ModBlockFail.cs
@@ -0,0 +1,29 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Framework.Bindables;
+using osu.Game.Configuration;
+using osu.Game.Screens.Play;
+
+namespace osu.Game.Rulesets.Mods
+{
+ public abstract class ModBlockFail : Mod, IApplicableFailOverride, IApplicableToHUD, IReadFromConfig
+ {
+ private Bindable showHealthBar;
+
+ ///
+ /// We never fail, 'yo.
+ ///
+ public bool AllowFail => false;
+
+ public void ReadFromConfig(OsuConfigManager config)
+ {
+ showHealthBar = config.GetBindable(OsuSetting.ShowHealthDisplayWhenCantFail);
+ }
+
+ public void ApplyToHUD(HUDOverlay overlay)
+ {
+ overlay.ShowHealthbar.BindTo(showHealthBar);
+ }
+ }
+}
diff --git a/osu.Game/Rulesets/Mods/ModFlashlight.cs b/osu.Game/Rulesets/Mods/ModFlashlight.cs
index 405d21c711..cb0c2fafe5 100644
--- a/osu.Game/Rulesets/Mods/ModFlashlight.cs
+++ b/osu.Game/Rulesets/Mods/ModFlashlight.cs
@@ -6,6 +6,7 @@ using System.Collections.Generic;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
+using osu.Framework.Graphics.Batches;
using osu.Framework.Graphics.OpenGL.Vertices;
using osu.Framework.Graphics.Primitives;
using osu.Framework.Graphics.Shaders;
@@ -13,6 +14,7 @@ using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures;
using osu.Game.Beatmaps.Timing;
using osu.Game.Graphics;
+using osu.Game.Graphics.OpenGL.Vertices;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.UI;
@@ -153,9 +155,17 @@ namespace osu.Game.Rulesets.Mods
private Vector2 flashlightSize;
private float flashlightDim;
+ private readonly VertexBatch quadBatch = new QuadBatch(1, 1);
+ private readonly Action addAction;
+
public FlashlightDrawNode(Flashlight source)
: base(source)
{
+ addAction = v => quadBatch.Add(new PositionAndColourVertex
+ {
+ Position = v.Position,
+ Colour = v.Colour
+ });
}
public override void ApplyState()
@@ -179,7 +189,7 @@ namespace osu.Game.Rulesets.Mods
shader.GetUniform("flashlightSize").UpdateValue(ref flashlightSize);
shader.GetUniform("flashlightDim").UpdateValue(ref flashlightDim);
- DrawQuad(Texture.WhitePixel, screenSpaceDrawQuad, DrawColourInfo.Colour, vertexAction: vertexAction);
+ DrawQuad(Texture.WhitePixel, screenSpaceDrawQuad, DrawColourInfo.Colour, vertexAction: addAction);
shader.Unbind();
}
diff --git a/osu.Game/Rulesets/Mods/ModNoFail.cs b/osu.Game/Rulesets/Mods/ModNoFail.cs
index 1ee1f92d8c..49ee3354c3 100644
--- a/osu.Game/Rulesets/Mods/ModNoFail.cs
+++ b/osu.Game/Rulesets/Mods/ModNoFail.cs
@@ -7,7 +7,7 @@ using osu.Game.Graphics;
namespace osu.Game.Rulesets.Mods
{
- public abstract class ModNoFail : Mod, IApplicableFailOverride
+ public abstract class ModNoFail : ModBlockFail
{
public override string Name => "No Fail";
public override string Acronym => "NF";
@@ -17,10 +17,5 @@ namespace osu.Game.Rulesets.Mods
public override double ScoreMultiplier => 0.5;
public override bool Ranked => true;
public override Type[] IncompatibleMods => new[] { typeof(ModRelax), typeof(ModSuddenDeath), typeof(ModAutoplay) };
-
- ///
- /// We never fail, 'yo.
- ///
- public bool AllowFail => false;
}
}
diff --git a/osu.Game/Rulesets/Mods/ModRelax.cs b/osu.Game/Rulesets/Mods/ModRelax.cs
index 4feb89186c..7c355577d4 100644
--- a/osu.Game/Rulesets/Mods/ModRelax.cs
+++ b/osu.Game/Rulesets/Mods/ModRelax.cs
@@ -7,7 +7,7 @@ using osu.Game.Graphics;
namespace osu.Game.Rulesets.Mods
{
- public abstract class ModRelax : Mod
+ public abstract class ModRelax : ModBlockFail
{
public override string Name => "Relax";
public override string Acronym => "RX";
diff --git a/osu.Game/Rulesets/Mods/ModType.cs b/osu.Game/Rulesets/Mods/ModType.cs
index cd649728cf..e3c82e42f5 100644
--- a/osu.Game/Rulesets/Mods/ModType.cs
+++ b/osu.Game/Rulesets/Mods/ModType.cs
@@ -9,6 +9,7 @@ namespace osu.Game.Rulesets.Mods
DifficultyIncrease,
Conversion,
Automation,
- Fun
+ Fun,
+ System
}
}
diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs
index 1f6ca4dd73..181ae37a8b 100644
--- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs
+++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs
@@ -7,10 +7,8 @@ using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Extensions.TypeExtensions;
-using osu.Framework.Graphics;
using osu.Framework.Graphics.Primitives;
using osu.Game.Audio;
-using osu.Game.Graphics;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Objects.Types;
using osu.Game.Rulesets.Scoring;
@@ -19,14 +17,14 @@ using osuTK.Graphics;
namespace osu.Game.Rulesets.Objects.Drawables
{
- public abstract class DrawableHitObject : SkinReloadableDrawable, IHasAccentColour
+ public abstract class DrawableHitObject : SkinReloadableDrawable
{
public readonly HitObject HitObject;
///
/// The colour used for various elements of this DrawableHitObject.
///
- public virtual Color4 AccentColour { get; set; } = Color4.Gray;
+ public readonly Bindable AccentColour = new Bindable(Color4.Gray);
// Todo: Rulesets should be overriding the resources instead, but we need to figure out where/when to apply overrides first
protected virtual string SampleNamespace => null;
@@ -83,7 +81,9 @@ namespace osu.Game.Rulesets.Objects.Drawables
public override bool IsPresent => base.IsPresent || (State.Value == ArmedState.Idle && Clock?.CurrentTime >= LifetimeStart);
- public readonly Bindable State = new Bindable();
+ private readonly Bindable state = new Bindable();
+
+ public IBindable State => state;
protected DrawableHitObject(HitObject hitObject)
{
@@ -118,33 +118,120 @@ namespace osu.Game.Rulesets.Objects.Drawables
}
}
- protected override void ClearInternal(bool disposeChildren = true) => throw new InvalidOperationException($"Should never clear a {nameof(DrawableHitObject)}");
-
protected override void LoadComplete()
{
base.LoadComplete();
-
- State.ValueChanged += armed =>
- {
- UpdateState(armed.NewValue);
-
- // apply any custom state overrides
- ApplyCustomUpdateState?.Invoke(this, armed.NewValue);
-
- if (armed.NewValue == ArmedState.Hit)
- PlaySamples();
- };
-
- State.TriggerChange();
+ updateState(ArmedState.Idle, true);
}
- protected abstract void UpdateState(ArmedState state);
+ #region State / Transform Management
///
/// Bind to apply a custom state which can override the default implementation.
///
public event Action ApplyCustomUpdateState;
+ ///
+ /// Enables automatic transform management of this hitobject. Implementation of transforms should be done in and only. Rewinding and removing previous states is done automatically.
+ ///
+ ///
+ /// Going forward, this is the preferred way of implementing s. Previous functionality
+ /// is offered as a compatibility layer until all rulesets have been migrated across.
+ ///
+ protected virtual bool UseTransformStateManagement => true;
+
+ protected override void ClearInternal(bool disposeChildren = true) => throw new InvalidOperationException($"Should never clear a {nameof(DrawableHitObject)}");
+
+ private void updateState(ArmedState newState, bool force = false)
+ {
+ if (State.Value == newState && !force)
+ return;
+
+ if (UseTransformStateManagement)
+ {
+ double transformTime = HitObject.StartTime - InitialLifetimeOffset;
+
+ base.ApplyTransformsAt(transformTime, true);
+ base.ClearTransformsAfter(transformTime, true);
+
+ using (BeginAbsoluteSequence(transformTime, true))
+ {
+ UpdateInitialTransforms();
+
+ var judgementOffset = Math.Min(HitObject.HitWindows?.HalfWindowFor(HitResult.Miss) ?? double.MaxValue, Result?.TimeOffset ?? 0);
+
+ using (BeginDelayedSequence(InitialLifetimeOffset + judgementOffset, true))
+ {
+ UpdateStateTransforms(newState);
+ state.Value = newState;
+ }
+ }
+ }
+ else
+ state.Value = newState;
+
+ UpdateState(newState);
+
+ // apply any custom state overrides
+ ApplyCustomUpdateState?.Invoke(this, newState);
+
+ if (newState == ArmedState.Hit)
+ PlaySamples();
+ }
+
+ ///
+ /// Apply (generally fade-in) transforms leading into the start time.
+ /// The local drawable hierarchy is recursively delayed to for convenience.
+ ///
+ ///
+ /// This is called once before every . This is to ensure a good state in the case
+ /// the was negative and potentially altered the pre-hit transforms.
+ ///
+ protected virtual void UpdateInitialTransforms()
+ {
+ }
+
+ ///
+ /// Apply transforms based on the current . Previous states are automatically cleared.
+ ///
+ /// The new armed state.
+ protected virtual void UpdateStateTransforms(ArmedState state)
+ {
+ }
+
+ public override void ClearTransformsAfter(double time, bool propagateChildren = false, string targetMember = null)
+ {
+ // When we are using automatic state management, parent calls to this should be blocked for safety.
+ if (!UseTransformStateManagement)
+ base.ClearTransformsAfter(time, propagateChildren, targetMember);
+ }
+
+ public override void ApplyTransformsAt(double time, bool propagateChildren = false)
+ {
+ // When we are using automatic state management, parent calls to this should be blocked for safety.
+ if (!UseTransformStateManagement)
+ base.ApplyTransformsAt(time, propagateChildren);
+ }
+
+ ///
+ /// Legacy method to handle state changes.
+ /// Should generally not be used when is true; use instead.
+ ///
+ /// The new armed state.
+ protected virtual void UpdateState(ArmedState state)
+ {
+ }
+
+ #endregion
+
+ protected override void SkinChanged(ISkinSource skin, bool allowFallback)
+ {
+ base.SkinChanged(skin, allowFallback);
+
+ if (HitObject is IHasComboInformation combo)
+ AccentColour.Value = skin.GetValue(s => s.ComboColours.Count > 0 ? s.ComboColours[combo.ComboIndex % s.ComboColours.Count] : (Color4?)null) ?? Color4.White;
+ }
+
///
/// Plays all the hit sounds for this .
/// This is invoked automatically when this is hit.
@@ -165,7 +252,8 @@ namespace osu.Game.Rulesets.Objects.Drawables
Result.TimeOffset = 0;
Result.Type = HitResult.None;
- State.Value = ArmedState.Idle;
+
+ updateState(ArmedState.Idle);
}
}
}
@@ -179,6 +267,40 @@ namespace osu.Game.Rulesets.Objects.Drawables
UpdateResult(false);
}
+ private double? lifetimeStart;
+
+ public override double LifetimeStart
+ {
+ get => lifetimeStart ?? (HitObject.StartTime - InitialLifetimeOffset);
+ set
+ {
+ base.LifetimeStart = value;
+ lifetimeStart = value;
+ }
+ }
+
+ ///
+ /// A safe offset prior to the start time of at which this may begin displaying contents.
+ /// By default, s are assumed to display their contents within 10 seconds prior to the start time of .
+ ///
+ ///
+ /// This is only used as an optimisation to delay the initial update of this and may be tuned more aggressively if required.
+ /// It is indirectly used to decide the automatic transform offset provided to .
+ /// A more accurate should be set inside for an state.
+ ///
+ protected virtual double InitialLifetimeOffset => 10000;
+
+ ///
+ /// Will be called at least once after this has become not alive.
+ ///
+ public virtual void OnKilled()
+ {
+ foreach (var nested in NestedHitObjects)
+ nested.OnKilled();
+
+ UpdateResult(false);
+ }
+
protected virtual void AddNested(DrawableHitObject h)
{
h.OnNewResult += (d, r) => OnNewResult?.Invoke(d, r);
@@ -212,27 +334,17 @@ namespace osu.Game.Rulesets.Objects.Drawables
break;
case HitResult.Miss:
- State.Value = ArmedState.Miss;
+ updateState(ArmedState.Miss);
break;
default:
- State.Value = ArmedState.Hit;
+ updateState(ArmedState.Hit);
break;
}
OnNewResult?.Invoke(this, Result);
}
- ///
- /// Will called at least once after the of this has been passed.
- ///
- internal void OnLifetimeEnd()
- {
- foreach (var nested in NestedHitObjects)
- nested.OnLifetimeEnd();
- UpdateResult(false);
- }
-
///
/// Processes this , checking if a scoring result has occurred.
///
diff --git a/osu.Game/Rulesets/Objects/Legacy/Catch/ConvertHitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/Catch/ConvertHitObjectParser.cs
index 6e79d0b766..71e321f205 100644
--- a/osu.Game/Rulesets/Objects/Legacy/Catch/ConvertHitObjectParser.cs
+++ b/osu.Game/Rulesets/Objects/Legacy/Catch/ConvertHitObjectParser.cs
@@ -37,7 +37,8 @@ namespace osu.Game.Rulesets.Objects.Legacy.Catch
};
}
- protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, Vector2[] controlPoints, double length, PathType pathType, int repeatCount, List> nodeSamples)
+ protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, Vector2[] controlPoints, double? length, PathType pathType, int repeatCount,
+ List> nodeSamples)
{
newCombo |= forceNewCombo;
comboOffset += extraComboOffset;
diff --git a/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs
index f5b1cbcebf..d70c1bf7d3 100644
--- a/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs
+++ b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs
@@ -72,7 +72,7 @@ namespace osu.Game.Rulesets.Objects.Legacy
else if (type.HasFlag(ConvertHitObjectType.Slider))
{
PathType pathType = PathType.Catmull;
- double length = 0;
+ double? length = null;
string[] pointSplit = split[5].Split('|');
@@ -130,7 +130,11 @@ namespace osu.Game.Rulesets.Objects.Legacy
repeatCount = Math.Max(0, repeatCount - 1);
if (split.Length > 7)
+ {
length = Math.Max(0, Parsing.ParseDouble(split[7]));
+ if (length == 0)
+ length = null;
+ }
if (split.Length > 10)
readCustomSampleBanks(split[10], bankInfo);
@@ -291,7 +295,8 @@ namespace osu.Game.Rulesets.Objects.Legacy
/// The slider repeat count.
/// The samples to be played when the slider nodes are hit. This includes the head and tail of the slider.
/// The hit object.
- protected abstract HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, Vector2[] controlPoints, double length, PathType pathType, int repeatCount, List> nodeSamples);
+ protected abstract HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, Vector2[] controlPoints, double? length, PathType pathType, int repeatCount,
+ List> nodeSamples);
///
/// Creates a legacy Spinner-type hit object.
diff --git a/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHitObjectParser.cs
index b20a027e78..94aba95e90 100644
--- a/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHitObjectParser.cs
+++ b/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHitObjectParser.cs
@@ -26,7 +26,8 @@ namespace osu.Game.Rulesets.Objects.Legacy.Mania
};
}
- protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, Vector2[] controlPoints, double length, PathType pathType, int repeatCount, List> nodeSamples)
+ protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, Vector2[] controlPoints, double? length, PathType pathType, int repeatCount,
+ List> nodeSamples)
{
return new ConvertSlider
{
diff --git a/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertHitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertHitObjectParser.cs
index 0a4e38df02..65102f1e89 100644
--- a/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertHitObjectParser.cs
+++ b/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertHitObjectParser.cs
@@ -1,7 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-using System;
using osuTK;
using osu.Game.Rulesets.Objects.Types;
using System.Collections.Generic;
@@ -38,7 +37,8 @@ namespace osu.Game.Rulesets.Objects.Legacy.Osu
};
}
- protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, Vector2[] controlPoints, double length, PathType pathType, int repeatCount, List> nodeSamples)
+ protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, Vector2[] controlPoints, double? length, PathType pathType, int repeatCount,
+ List> nodeSamples)
{
newCombo |= forceNewCombo;
comboOffset += extraComboOffset;
@@ -51,7 +51,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Osu
Position = position,
NewCombo = FirstObject || newCombo,
ComboOffset = comboOffset,
- Path = new SliderPath(pathType, controlPoints, Math.Max(0, length)),
+ Path = new SliderPath(pathType, controlPoints, length),
NodeSamples = nodeSamples,
RepeatCount = repeatCount
};
diff --git a/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertHitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertHitObjectParser.cs
index 7c1514c1eb..eb598f1368 100644
--- a/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertHitObjectParser.cs
+++ b/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertHitObjectParser.cs
@@ -23,7 +23,8 @@ namespace osu.Game.Rulesets.Objects.Legacy.Taiko
return new ConvertHit();
}
- protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, Vector2[] controlPoints, double length, PathType pathType, int repeatCount, List