diff --git a/osu-framework b/osu-framework
index 1490f00327..2234013e59 160000
--- a/osu-framework
+++ b/osu-framework
@@ -1 +1 @@
-Subproject commit 1490f003273d7aab6589e489f6e4b02d204c9f27
+Subproject commit 2234013e59a99116ee9f9e56a95ff8a6667db2a7
diff --git a/osu.Desktop.Deploy/App.config b/osu.Desktop.Deploy/App.config
index d1da144f50..45685a74a8 100644
--- a/osu.Desktop.Deploy/App.config
+++ b/osu.Desktop.Deploy/App.config
@@ -21,4 +21,16 @@ Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/maste
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/osu.Desktop.Deploy/osu.Desktop.Deploy.csproj b/osu.Desktop.Deploy/osu.Desktop.Deploy.csproj
index 7a3719a25b..901117b026 100644
--- a/osu.Desktop.Deploy/osu.Desktop.Deploy.csproj
+++ b/osu.Desktop.Deploy/osu.Desktop.Deploy.csproj
@@ -68,9 +68,8 @@
$(SolutionDir)\packages\Mono.Cecil.0.9.6.4\lib\net45\Mono.Cecil.Rocks.dll
True
-
- $(SolutionDir)\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll
- True
+
+ $(SolutionDir)\packages\Newtonsoft.Json.10.0.2\lib\net45\Newtonsoft.Json.dll
$(SolutionDir)\packages\squirrel.windows.1.5.2\lib\Net45\NuGet.Squirrel.dll
@@ -120,7 +119,7 @@
-
-
-
+
+
diff --git a/osu.Desktop.VisualTests/Tests/TestCaseBeatmapDetails.cs b/osu.Desktop.VisualTests/Tests/TestCaseBeatmapDetails.cs
new file mode 100644
index 0000000000..4a59ad9534
--- /dev/null
+++ b/osu.Desktop.VisualTests/Tests/TestCaseBeatmapDetails.cs
@@ -0,0 +1,65 @@
+// Copyright (c) 2007-2017 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Primitives;
+using osu.Framework.Testing;
+using osu.Game.Database;
+using osu.Game.Screens.Select;
+using System.Linq;
+
+namespace osu.Desktop.VisualTests.Tests
+{
+ internal class TestCaseBeatmapDetails : TestCase
+ {
+ public override string Description => "BeatmapDetails tab of BeatmapDetailArea";
+
+ private BeatmapDetails details;
+
+ public override void Reset()
+ {
+ base.Reset();
+
+ Add(details = new BeatmapDetails
+ {
+ RelativeSizeAxes = Axes.Both,
+ Padding = new MarginPadding(150),
+ Beatmap = new BeatmapInfo
+ {
+ Version = "VisualTest",
+ Metadata = new BeatmapMetadata
+ {
+ Source = "Some guy",
+ Tags = "beatmap metadata example with a very very long list of tags and not much creativity",
+ },
+ Difficulty = new BeatmapDifficulty
+ {
+ CircleSize = 7,
+ ApproachRate = 3.5f,
+ OverallDifficulty = 5.7f,
+ DrainRate = 1,
+ },
+ StarDifficulty = 5.3f,
+ Metrics = new BeatmapMetrics
+ {
+ Ratings = Enumerable.Range(0,10),
+ Fails = Enumerable.Range(lastRange, 100).Select(i => i % 12 - 6),
+ Retries = Enumerable.Range(lastRange - 3, 100).Select(i => i % 12 - 6),
+ },
+ },
+ });
+
+ AddRepeatStep("fail values", newRetryAndFailValues, 10);
+ }
+
+ private int lastRange = 1;
+
+ private void newRetryAndFailValues()
+ {
+ details.Beatmap.Metrics.Fails = Enumerable.Range(lastRange, 100).Select(i => i % 12 - 6);
+ details.Beatmap.Metrics.Retries = Enumerable.Range(lastRange - 3, 100).Select(i => i % 12 - 6);
+ details.Beatmap = details.Beatmap;
+ lastRange += 100;
+ }
+ }
+}
\ No newline at end of file
diff --git a/osu.Desktop.VisualTests/Tests/TestCaseGraph.cs b/osu.Desktop.VisualTests/Tests/TestCaseGraph.cs
new file mode 100644
index 0000000000..7ac795f6f9
--- /dev/null
+++ b/osu.Desktop.VisualTests/Tests/TestCaseGraph.cs
@@ -0,0 +1,42 @@
+// Copyright (c) 2007-2017 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using OpenTK;
+using osu.Framework.Graphics;
+using osu.Framework.Testing;
+using osu.Game.Graphics.UserInterface;
+using System.Linq;
+
+namespace osu.Desktop.VisualTests.Tests
+{
+ internal class TestCaseGraph : TestCase
+ {
+ public override string Description => "graph";
+
+ private BarGraph graph;
+
+ public override void Reset()
+ {
+ base.Reset();
+
+ Children = new[]
+ {
+ graph = new BarGraph
+ {
+ RelativeSizeAxes = Axes.Both,
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ Size = new Vector2(0.5f),
+ },
+ };
+
+ AddStep("values from 1-10", () => graph.Values = Enumerable.Range(1,10).Select(i => (float)i));
+ AddStep("values from 1-100", () => graph.Values = Enumerable.Range(1, 100).Select(i => (float)i));
+ AddStep("reversed values from 1-10", () => graph.Values = Enumerable.Range(1, 10).Reverse().Select(i => (float)i));
+ AddStep("Bottom to top", () => graph.Direction = BarDirection.BottomToTop);
+ AddStep("Top to bottom", () => graph.Direction = BarDirection.TopToBottom);
+ AddStep("Left to right", () => graph.Direction = BarDirection.LeftToRight);
+ AddStep("Right to left", () => graph.Direction = BarDirection.RightToLeft);
+ }
+ }
+}
\ No newline at end of file
diff --git a/osu.Desktop.VisualTests/Tests/TestCasePlayer.cs b/osu.Desktop.VisualTests/Tests/TestCasePlayer.cs
index f36889b02a..624723ed35 100644
--- a/osu.Desktop.VisualTests/Tests/TestCasePlayer.cs
+++ b/osu.Desktop.VisualTests/Tests/TestCasePlayer.cs
@@ -83,10 +83,7 @@ namespace osu.Desktop.VisualTests.Tests
Colour = Color4.Black,
});
- Add(new PlayerLoader(Player = CreatePlayer(beatmap))
- {
- Beatmap = beatmap
- });
+ Add(Player = CreatePlayer(beatmap));
}
protected virtual Player CreatePlayer(WorkingBeatmap beatmap)
diff --git a/osu.Desktop.VisualTests/Tests/TestCaseTaikoPlayfield.cs b/osu.Desktop.VisualTests/Tests/TestCaseTaikoPlayfield.cs
index a8e4382ebb..4e9ff4980e 100644
--- a/osu.Desktop.VisualTests/Tests/TestCaseTaikoPlayfield.cs
+++ b/osu.Desktop.VisualTests/Tests/TestCaseTaikoPlayfield.cs
@@ -27,6 +27,7 @@ namespace osu.Desktop.VisualTests.Tests
private readonly Random rng = new Random(1337);
private TaikoPlayfield playfield;
+ private Container playfieldContainer;
public override void Reset()
{
@@ -48,14 +49,17 @@ namespace osu.Desktop.VisualTests.Tests
AddStep("Height test 3", () => changePlayfieldSize(3));
AddStep("Height test 4", () => changePlayfieldSize(4));
AddStep("Height test 5", () => changePlayfieldSize(5));
+ AddStep("Reset height", () => changePlayfieldSize(6));
var rateAdjustClock = new StopwatchClock(true) { Rate = 1 };
- Add(new Container
+ Add(playfieldContainer = new Container
{
- Clock = new FramedClock(rateAdjustClock),
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
RelativeSizeAxes = Axes.X,
- Y = 200,
+ Height = TaikoPlayfield.DEFAULT_PLAYFIELD_HEIGHT,
+ Clock = new FramedClock(rateAdjustClock),
Children = new[]
{
playfield = new TaikoPlayfield()
@@ -65,6 +69,7 @@ namespace osu.Desktop.VisualTests.Tests
private void changePlayfieldSize(int step)
{
+ // Add new hits
switch (step)
{
case 1:
@@ -81,11 +86,20 @@ namespace osu.Desktop.VisualTests.Tests
break;
case 5:
addSwell(1000);
- playfield.Delay(scroll_time - 100);
+ playfieldContainer.Delay(scroll_time - 100);
break;
}
- playfield.ResizeTo(new Vector2(1, rng.Next(25, 400)), 500);
+ // Tween playfield height
+ switch (step)
+ {
+ default:
+ playfieldContainer.ResizeTo(new Vector2(1, rng.Next(25, 400)), 500);
+ break;
+ case 6:
+ playfieldContainer.ResizeTo(new Vector2(1, TaikoPlayfield.DEFAULT_PLAYFIELD_HEIGHT), 500);
+ break;
+ }
}
private void addHitJudgement()
diff --git a/osu.Desktop.VisualTests/osu.Desktop.VisualTests.csproj b/osu.Desktop.VisualTests/osu.Desktop.VisualTests.csproj
index da068c5557..ffafa219a8 100644
--- a/osu.Desktop.VisualTests/osu.Desktop.VisualTests.csproj
+++ b/osu.Desktop.VisualTests/osu.Desktop.VisualTests.csproj
@@ -83,22 +83,20 @@
-
- $(SolutionDir)\packages\ppy.OpenTK.2.0.50727.1340\lib\net45\OpenTK.dll
- True
+
+ $(SolutionDir)\packages\Newtonsoft.Json.10.0.2\lib\net45\Newtonsoft.Json.dll
-
- ..\packages\SharpCompress.0.15.1\lib\net45\SharpCompress.dll
- True
+
+ $(SolutionDir)\packages\ppy.OpenTK.2.0.50727.1341\lib\net45\OpenTK.dll
+
+
+ $(SolutionDir)\packages\SharpCompress.0.15.2\lib\net45\SharpCompress.dll
False
$(SolutionDir)\packages\SQLite.Net.Core-PCL.3.1.1\lib\portable-win8+net45+wp8+wpa81+MonoAndroid1+MonoTouch1\SQLite.Net.dll
-
- $(SolutionDir)\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll
-
$(SolutionDir)\packages\SQLiteNetExtensions.1.3.0\lib\portable-net45+netcore45+wpa81+wp8+MonoAndroid1+MonoTouch1\SQLiteNetExtensions.dll
@@ -187,8 +185,10 @@
+
+
diff --git a/osu.Desktop.VisualTests/packages.config b/osu.Desktop.VisualTests/packages.config
index 5a30c50600..cad2ffff0d 100644
--- a/osu.Desktop.VisualTests/packages.config
+++ b/osu.Desktop.VisualTests/packages.config
@@ -4,9 +4,9 @@ Copyright (c) 2007-2017 ppy Pty Ltd .
Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-->
-
-
-
+
+
+
diff --git a/osu.Desktop/Overlays/VersionManager.cs b/osu.Desktop/Overlays/VersionManager.cs
index 70925f6cf4..9532652bfe 100644
--- a/osu.Desktop/Overlays/VersionManager.cs
+++ b/osu.Desktop/Overlays/VersionManager.cs
@@ -189,19 +189,24 @@ namespace osu.Desktop.Overlays
private class UpdateProgressNotification : ProgressNotification
{
+ private OsuGame game;
+
protected override Notification CreateCompletionNotification() => new ProgressCompletionNotification()
{
Text = @"Update ready to install. Click to restart!",
Activated = () =>
{
- UpdateManager.RestartApp();
+ UpdateManager.RestartAppWhenExited();
+ game.GracefullyExit();
return true;
}
};
[BackgroundDependencyLoader]
- private void load(OsuColour colours)
+ private void load(OsuColour colours, OsuGame game)
{
+ this.game = game;
+
IconContent.Add(new Drawable[]
{
new Box
diff --git a/osu.Desktop/osu.Desktop.csproj b/osu.Desktop/osu.Desktop.csproj
index fbc342d695..dbd26b4640 100644
--- a/osu.Desktop/osu.Desktop.csproj
+++ b/osu.Desktop/osu.Desktop.csproj
@@ -124,8 +124,7 @@
True
- $(SolutionDir)\packages\ppy.OpenTK.2.0.50727.1340\lib\net45\OpenTK.dll
- True
+ $(SolutionDir)\packages\ppy.OpenTK.2.0.50727.1341\lib\net45\OpenTK.dll
$(SolutionDir)\packages\Splat.2.0.0\lib\Net45\Splat.dll
diff --git a/osu.Desktop/packages.config b/osu.Desktop/packages.config
index be9b65f0c6..60e8182c82 100644
--- a/osu.Desktop/packages.config
+++ b/osu.Desktop/packages.config
@@ -7,7 +7,7 @@ Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/maste
-
+
\ No newline at end of file
diff --git a/osu.Game.Modes.Catch/osu.Game.Modes.Catch.csproj b/osu.Game.Modes.Catch/osu.Game.Modes.Catch.csproj
index 593d8db4f6..50b1a095af 100644
--- a/osu.Game.Modes.Catch/osu.Game.Modes.Catch.csproj
+++ b/osu.Game.Modes.Catch/osu.Game.Modes.Catch.csproj
@@ -33,8 +33,7 @@
- $(SolutionDir)\packages\ppy.OpenTK.2.0.50727.1340\lib\net45\OpenTK.dll
- True
+ $(SolutionDir)\packages\ppy.OpenTK.2.0.50727.1341\lib\net45\OpenTK.dll
@@ -84,7 +83,7 @@
-
-
+
\ No newline at end of file
diff --git a/osu.Game.Modes.Mania/osu.Game.Modes.Mania.csproj b/osu.Game.Modes.Mania/osu.Game.Modes.Mania.csproj
index cc925d417a..896e9c68c6 100644
--- a/osu.Game.Modes.Mania/osu.Game.Modes.Mania.csproj
+++ b/osu.Game.Modes.Mania/osu.Game.Modes.Mania.csproj
@@ -33,8 +33,7 @@
- $(SolutionDir)\packages\ppy.OpenTK.2.0.50727.1340\lib\net45\OpenTK.dll
- True
+ $(SolutionDir)\packages\ppy.OpenTK.2.0.50727.1341\lib\net45\OpenTK.dll
@@ -89,7 +88,7 @@
-
-
+
\ No newline at end of file
diff --git a/osu.Game.Modes.Osu/Scoring/OsuScoreProcessor.cs b/osu.Game.Modes.Osu/Scoring/OsuScoreProcessor.cs
index 00c797e97d..3b798a2fad 100644
--- a/osu.Game.Modes.Osu/Scoring/OsuScoreProcessor.cs
+++ b/osu.Game.Modes.Osu/Scoring/OsuScoreProcessor.cs
@@ -30,6 +30,19 @@ namespace osu.Game.Modes.Osu.Scoring
protected override void OnNewJudgement(OsuJudgement judgement)
{
+ if (judgement != null)
+ {
+ switch (judgement.Result)
+ {
+ case HitResult.Hit:
+ Health.Value += 0.1f;
+ break;
+ case HitResult.Miss:
+ Health.Value -= 0.2f;
+ break;
+ }
+ }
+
int score = 0;
int maxScore = 0;
diff --git a/osu.Game.Modes.Osu/osu.Game.Modes.Osu.csproj b/osu.Game.Modes.Osu/osu.Game.Modes.Osu.csproj
index 55322e855e..21f0f03d8c 100644
--- a/osu.Game.Modes.Osu/osu.Game.Modes.Osu.csproj
+++ b/osu.Game.Modes.Osu/osu.Game.Modes.Osu.csproj
@@ -34,8 +34,7 @@
- $(SolutionDir)\packages\ppy.OpenTK.2.0.50727.1340\lib\net45\OpenTK.dll
- True
+ $(SolutionDir)\packages\ppy.OpenTK.2.0.50727.1341\lib\net45\OpenTK.dll
@@ -104,7 +103,7 @@
-
-
+
\ No newline at end of file
diff --git a/osu.Game.Modes.Taiko/osu.Game.Modes.Taiko.csproj b/osu.Game.Modes.Taiko/osu.Game.Modes.Taiko.csproj
index d0981c2500..19ba5c77e4 100644
--- a/osu.Game.Modes.Taiko/osu.Game.Modes.Taiko.csproj
+++ b/osu.Game.Modes.Taiko/osu.Game.Modes.Taiko.csproj
@@ -33,8 +33,7 @@
- $(SolutionDir)\packages\ppy.OpenTK.2.0.50727.1340\lib\net45\OpenTK.dll
- True
+ $(SolutionDir)\packages\ppy.OpenTK.2.0.50727.1341\lib\net45\OpenTK.dll
@@ -112,7 +111,7 @@
-
-
+
\ No newline at end of file
diff --git a/osu.Game.Tests/osu.Game.Tests.csproj b/osu.Game.Tests/osu.Game.Tests.csproj
index d01aa77e02..2844528d0c 100644
--- a/osu.Game.Tests/osu.Game.Tests.csproj
+++ b/osu.Game.Tests/osu.Game.Tests.csproj
@@ -29,13 +29,11 @@
false
-
- $(SolutionDir)\packages\NUnit.3.5.0\lib\net45\nunit.framework.dll
- True
+
+ $(SolutionDir)\packages\NUnit.3.6.1\lib\net45\nunit.framework.dll
- $(SolutionDir)\packages\ppy.OpenTK.2.0.50727.1340\lib\net45\OpenTK.dll
- True
+ $(SolutionDir)\packages\ppy.OpenTK.2.0.50727.1341\lib\net45\OpenTK.dll
diff --git a/osu.Game.Tests/packages.config b/osu.Game.Tests/packages.config
index ca53ef08b0..9972fb41a1 100644
--- a/osu.Game.Tests/packages.config
+++ b/osu.Game.Tests/packages.config
@@ -1,12 +1,11 @@
-
-
-
+
+
\ No newline at end of file
diff --git a/osu.Game/Database/BeatmapInfo.cs b/osu.Game/Database/BeatmapInfo.cs
index bc6e077633..3e84825919 100644
--- a/osu.Game/Database/BeatmapInfo.cs
+++ b/osu.Game/Database/BeatmapInfo.cs
@@ -41,8 +41,12 @@ namespace osu.Game.Database
[OneToOne(CascadeOperations = CascadeOperation.All)]
public BeatmapDifficulty Difficulty { get; set; }
+ [Ignore]
+ public BeatmapMetrics Metrics { get; set; }
+
public string Path { get; set; }
+ [JsonProperty("file_md5")]
public string Hash { get; set; }
// General
diff --git a/osu.Game/Database/BeatmapMetrics.cs b/osu.Game/Database/BeatmapMetrics.cs
new file mode 100644
index 0000000000..91320110d0
--- /dev/null
+++ b/osu.Game/Database/BeatmapMetrics.cs
@@ -0,0 +1,28 @@
+// Copyright (c) 2007-2017 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using System.Collections.Generic;
+
+namespace osu.Game.Database
+{
+ ///
+ /// Beatmap metrics based on acculumated online data from community plays.
+ ///
+ public class BeatmapMetrics
+ {
+ ///
+ /// Total vote counts of user ratings on a scale of 0..length.
+ ///
+ public IEnumerable Ratings { get; set; }
+
+ ///
+ /// Points of failure on a relative time scale (usually 0..100).
+ ///
+ public IEnumerable Fails { get; set; }
+
+ ///
+ /// Points of retry on a relative time scale (usually 0..100).
+ ///
+ public IEnumerable Retries { get; set; }
+ }
+}
diff --git a/osu.Game/Graphics/Cursor/CursorTrail.cs b/osu.Game/Graphics/Cursor/CursorTrail.cs
index 4b5610e840..09d1b99d13 100644
--- a/osu.Game/Graphics/Cursor/CursorTrail.cs
+++ b/osu.Game/Graphics/Cursor/CursorTrail.cs
@@ -13,6 +13,7 @@ using osu.Framework.Graphics.OpenGL.Buffers;
using OpenTK.Graphics.ES30;
using osu.Framework.Graphics.Primitives;
using osu.Framework.Graphics.Colour;
+using osu.Framework.Timing;
namespace osu.Game.Graphics.Cursor
{
@@ -58,6 +59,9 @@ namespace osu.Game.Graphics.Cursor
public CursorTrail()
{
+ // as we are currently very dependent on having a running clock, let's make our own clock for the time being.
+ Clock = new FramedClock();
+
AlwaysReceiveInput = true;
RelativeSizeAxes = Axes.Both;
@@ -231,4 +235,4 @@ namespace osu.Game.Graphics.Cursor
}
}
}
-}
\ No newline at end of file
+}
diff --git a/osu.Game/Graphics/Cursor/MenuCursor.cs b/osu.Game/Graphics/Cursor/MenuCursor.cs
index 0fb7f59212..ceb3296bdf 100644
--- a/osu.Game/Graphics/Cursor/MenuCursor.cs
+++ b/osu.Game/Graphics/Cursor/MenuCursor.cs
@@ -80,14 +80,12 @@ namespace osu.Game.Graphics.Cursor
protected override void PopIn()
{
ActiveCursor.FadeTo(1, 250, EasingTypes.OutQuint);
- ActiveCursor.ScaleTo(1, 1000, EasingTypes.OutElastic);
+ ActiveCursor.ScaleTo(1, 400, EasingTypes.OutQuint);
}
protected override void PopOut()
{
- ActiveCursor.FadeTo(0, 1400, EasingTypes.OutQuint);
- ActiveCursor.ScaleTo(1.1f, 100, EasingTypes.Out);
- ActiveCursor.Delay(100);
+ ActiveCursor.FadeTo(0, 900, EasingTypes.OutQuint);
ActiveCursor.ScaleTo(0, 500, EasingTypes.In);
}
diff --git a/osu.Game/Graphics/IHasAccentColour.cs b/osu.Game/Graphics/IHasAccentColour.cs
index f959bc8760..e4647f22fd 100644
--- a/osu.Game/Graphics/IHasAccentColour.cs
+++ b/osu.Game/Graphics/IHasAccentColour.cs
@@ -28,7 +28,7 @@ namespace osu.Game.Graphics
/// The tween easing.
public static void FadeAccent(this IHasAccentColour accentedDrawable, Color4 newColour, double duration = 0, EasingTypes easing = EasingTypes.None)
{
- accentedDrawable.TransformTo(accentedDrawable.AccentColour, newColour, duration, easing, new TransformAccent());
+ accentedDrawable.TransformTo(() => accentedDrawable.AccentColour, newColour, duration, easing, new TransformAccent());
}
}
}
diff --git a/osu.Game/Graphics/UserInterface/Bar.cs b/osu.Game/Graphics/UserInterface/Bar.cs
new file mode 100644
index 0000000000..76b75f1084
--- /dev/null
+++ b/osu.Game/Graphics/UserInterface/Bar.cs
@@ -0,0 +1,137 @@
+// Copyright (c) 2007-2017 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using OpenTK;
+using OpenTK.Graphics;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Sprites;
+using System;
+
+namespace osu.Game.Graphics.UserInterface
+{
+ public class Bar : Container, IHasAccentColour
+ {
+ private readonly Box background;
+ private readonly Box bar;
+
+ private const int resize_duration = 250;
+
+ private const EasingTypes easing = EasingTypes.InOutCubic;
+
+ private float length;
+ ///
+ /// Length of the bar, ranges from 0 to 1
+ ///
+ public float Length
+ {
+ get
+ {
+ return length;
+ }
+ set
+ {
+ length = MathHelper.Clamp(value, 0, 1);
+ updateBarLength();
+ }
+ }
+
+ public Color4 BackgroundColour
+ {
+ get
+ {
+ return background.Colour;
+ }
+ set
+ {
+ background.Colour = value;
+ }
+ }
+
+ public Color4 AccentColour
+ {
+ get
+ {
+ return bar.Colour;
+ }
+ set
+ {
+ bar.Colour = value;
+ }
+ }
+
+ private BarDirection direction = BarDirection.LeftToRight;
+ public BarDirection Direction
+ {
+ get
+ {
+ return direction;
+ }
+ set
+ {
+ direction = value;
+ updateBarLength();
+ }
+ }
+
+ public Bar()
+ {
+ Children = new[]
+ {
+ background = new Box
+ {
+ RelativeSizeAxes = Axes.Both,
+ Colour = new Color4(0,0,0,0)
+ },
+ bar = new Box
+ {
+ RelativeSizeAxes = Axes.Both,
+ Width = 0,
+ },
+ };
+ }
+
+ private void updateBarLength()
+ {
+ switch (direction)
+ {
+ case BarDirection.LeftToRight:
+ case BarDirection.RightToLeft:
+ bar.ResizeTo(new Vector2(length, 1), resize_duration, easing);
+ break;
+
+ case BarDirection.TopToBottom:
+ case BarDirection.BottomToTop:
+ bar.ResizeTo(new Vector2(1, length), resize_duration, easing);
+ break;
+ }
+
+ switch (direction)
+ {
+ case BarDirection.LeftToRight:
+ case BarDirection.TopToBottom:
+ bar.Anchor = Anchor.TopLeft;
+ bar.Origin = Anchor.TopLeft;
+ break;
+
+ case BarDirection.RightToLeft:
+ case BarDirection.BottomToTop:
+ bar.Anchor = Anchor.BottomRight;
+ bar.Origin = Anchor.BottomRight;
+ break;
+ }
+ }
+ }
+
+ [Flags]
+ public enum BarDirection
+ {
+ LeftToRight = 1 << 0,
+ RightToLeft = 1 << 1,
+ TopToBottom = 1 << 2,
+ BottomToTop = 1 << 3,
+
+ Vertical = TopToBottom | BottomToTop,
+ Horizontal = LeftToRight | RightToLeft,
+ }
+}
\ No newline at end of file
diff --git a/osu.Game/Graphics/UserInterface/BarGraph.cs b/osu.Game/Graphics/UserInterface/BarGraph.cs
new file mode 100644
index 0000000000..d0965a1861
--- /dev/null
+++ b/osu.Game/Graphics/UserInterface/BarGraph.cs
@@ -0,0 +1,65 @@
+// Copyright (c) 2007-2017 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using OpenTK;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace osu.Game.Graphics.UserInterface
+{
+ public class BarGraph : FillFlowContainer
+ {
+ ///
+ /// Manually sets the max value, if null is instead used
+ ///
+ public float? MaxValue { get; set; }
+
+ private BarDirection direction = BarDirection.BottomToTop;
+ public new BarDirection Direction
+ {
+ get
+ {
+ return direction;
+ }
+ set
+ {
+ direction = value;
+ base.Direction = (direction & BarDirection.Horizontal) > 0 ? FillDirection.Vertical : FillDirection.Horizontal;
+ foreach (var bar in Children)
+ {
+ bar.Size = (direction & BarDirection.Horizontal) > 0 ? new Vector2(1, 1.0f / Children.Count()) : new Vector2(1.0f / Children.Count(), 1);
+ bar.Direction = direction;
+ }
+ }
+ }
+
+ ///
+ /// A list of floats that defines the length of each
+ ///
+ public IEnumerable Values
+ {
+ set
+ {
+ List bars = Children.ToList();
+ foreach (var bar in value.Select((length, index) => new { Value = length, Bar = bars.Count > index ? bars[index] : null }))
+ if (bar.Bar != null)
+ {
+ bar.Bar.Length = bar.Value / (MaxValue ?? value.Max());
+ bar.Bar.Size = (direction & BarDirection.Horizontal) > 0 ? new Vector2(1, 1.0f / value.Count()) : new Vector2(1.0f / value.Count(), 1);
+ }
+ else
+ Add(new Bar
+ {
+ RelativeSizeAxes = Axes.Both,
+ Size = (direction & BarDirection.Horizontal) > 0 ? new Vector2(1, 1.0f / value.Count()) : new Vector2(1.0f / value.Count(), 1),
+ Length = bar.Value / (MaxValue ?? value.Max()),
+ Direction = Direction,
+ });
+ //I'm using ToList() here because Where() returns an Enumerable which can change it's elements afterwards
+ Remove(Children.Where((bar, index) => index >= value.Count()).ToList());
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/osu.Game/Graphics/UserInterface/OsuSliderBar.cs b/osu.Game/Graphics/UserInterface/OsuSliderBar.cs
index 91fb1c672a..180cb88707 100644
--- a/osu.Game/Graphics/UserInterface/OsuSliderBar.cs
+++ b/osu.Game/Graphics/UserInterface/OsuSliderBar.cs
@@ -2,7 +2,6 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK;
-using OpenTK.Input;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Audio.Sample;
@@ -63,15 +62,6 @@ namespace osu.Game.Graphics.UserInterface
rightBox.Colour = colours.Pink;
}
- private void playSample()
- {
- if (Clock == null || Clock.CurrentTime - lastSampleTime <= 50)
- return;
- lastSampleTime = Clock.CurrentTime;
- sample.Frequency.Value = 1 + NormalizedValue * 0.2f;
- sample.Play();
- }
-
protected override bool OnHover(InputState state)
{
nub.Glowing = true;
@@ -84,11 +74,25 @@ namespace osu.Game.Graphics.UserInterface
base.OnHoverLost(state);
}
- protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
+ protected override void OnUserChange()
{
- if (args.Key == Key.Left || args.Key == Key.Right)
- playSample();
- return base.OnKeyDown(state, args);
+ base.OnUserChange();
+ playSample();
+ }
+
+ private void playSample()
+ {
+ if (Clock == null || Clock.CurrentTime - lastSampleTime <= 50)
+ return;
+ lastSampleTime = Clock.CurrentTime;
+ sample.Frequency.Value = 1 + NormalizedValue * 0.2f;
+
+ if (NormalizedValue == 0)
+ sample.Frequency.Value -= 0.4f;
+ else if (NormalizedValue == 1)
+ sample.Frequency.Value += 0.4f;
+
+ sample.Play();
}
protected override bool OnMouseDown(InputState state, MouseDownEventArgs args)
@@ -103,18 +107,6 @@ namespace osu.Game.Graphics.UserInterface
return base.OnMouseUp(state, args);
}
- protected override bool OnClick(InputState state)
- {
- playSample();
- return base.OnClick(state);
- }
-
- protected override bool OnDrag(InputState state)
- {
- playSample();
- return base.OnDrag(state);
- }
-
protected override void UpdateAfterChildren()
{
base.UpdateAfterChildren();
diff --git a/osu.Game/Graphics/UserInterface/RollingCounter.cs b/osu.Game/Graphics/UserInterface/RollingCounter.cs
index f8ab9f0ff3..e98867277a 100644
--- a/osu.Game/Graphics/UserInterface/RollingCounter.cs
+++ b/osu.Game/Graphics/UserInterface/RollingCounter.cs
@@ -115,8 +115,6 @@ namespace osu.Game.Graphics.UserInterface
{
base.LoadComplete();
- Flush(false, TransformType);
-
DisplayedCountSpriteText.Text = FormatCount(Current);
}
@@ -210,8 +208,8 @@ namespace osu.Game.Graphics.UserInterface
? GetProportionalDuration(currentValue, newValue)
: RollingDuration;
- transform.StartTime = Time.Current;
- transform.EndTime = Time.Current + rollingTotalDuration;
+ transform.StartTime = TransformStartTime;
+ transform.EndTime = TransformStartTime + rollingTotalDuration;
transform.StartValue = currentValue;
transform.EndValue = newValue;
transform.Easing = RollingEasing;
diff --git a/osu.Game/Modes/Scoring/Score.cs b/osu.Game/Modes/Scoring/Score.cs
index c998b11f77..b0c123f438 100644
--- a/osu.Game/Modes/Scoring/Score.cs
+++ b/osu.Game/Modes/Scoring/Score.cs
@@ -27,7 +27,24 @@ namespace osu.Game.Modes.Scoring
public int Combo { get; set; }
public Mod[] Mods { get; set; }
- public User User { get; set; }
+ private User user;
+
+ public User User
+ {
+ get
+ {
+ return user ?? new User
+ {
+ Username = LegacyUsername,
+ Id = LegacyUserID
+ };
+ }
+
+ set
+ {
+ user = value;
+ }
+ }
[JsonProperty(@"replay_data")]
public Replay Replay;
@@ -38,10 +55,10 @@ namespace osu.Game.Modes.Scoring
public long OnlineScoreID;
[JsonProperty(@"username")]
- public string Username;
+ public string LegacyUsername;
[JsonProperty(@"user_id")]
- public long UserID;
+ public long LegacyUserID;
[JsonProperty(@"date")]
public DateTime Date;
diff --git a/osu.Game/Modes/UI/HitRenderer.cs b/osu.Game/Modes/UI/HitRenderer.cs
index afc525d686..dd5eff5a95 100644
--- a/osu.Game/Modes/UI/HitRenderer.cs
+++ b/osu.Game/Modes/UI/HitRenderer.cs
@@ -33,6 +33,11 @@ namespace osu.Game.Modes.UI
///
public event Action OnAllJudged;
+ ///
+ /// Whether to apply adjustments to the child based on our own size.
+ ///
+ public bool AspectAdjust = true;
+
///
/// The input manager for this HitRenderer.
///
@@ -168,11 +173,6 @@ namespace osu.Game.Modes.UI
{
public event Action OnJudgement;
- ///
- /// Whether to apply adjustments to the child based on our own size.
- ///
- public bool AspectAdjust = true;
-
public sealed override bool ProvidingUserCursor => !HasReplayLoaded && Playfield.ProvidingUserCursor;
protected override Container Content => content;
diff --git a/osu.Game/Modes/UI/Playfield.cs b/osu.Game/Modes/UI/Playfield.cs
index bf5f0acde5..1e7cf6579c 100644
--- a/osu.Game/Modes/UI/Playfield.cs
+++ b/osu.Game/Modes/UI/Playfield.cs
@@ -39,6 +39,9 @@ namespace osu.Game.Modes.UI
{
AlwaysReceiveInput = true;
+ // Default height since we force relative size axes
+ Size = Vector2.One;
+
AddInternal(ScaledContent = new ScaledContainer
{
CustomWidth = customWidth,
diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs
index 7172aba3be..ccea6ef458 100644
--- a/osu.Game/OsuGame.cs
+++ b/osu.Game/OsuGame.cs
@@ -307,6 +307,18 @@ namespace osu.Game
return base.OnExiting();
}
+ ///
+ /// Use to programatically exit the game as if the user was triggering via alt-f4.
+ /// Will keep persisting until an exit occurs (exit may be blocked multiple times).
+ ///
+ public void GracefullyExit()
+ {
+ if (!OnExiting())
+ Exit();
+ else
+ Scheduler.AddDelayed(GracefullyExit, 2000);
+ }
+
protected override void UpdateAfterChildren()
{
base.UpdateAfterChildren();
diff --git a/osu.Game/Overlays/ChatOverlay.cs b/osu.Game/Overlays/ChatOverlay.cs
index 0bb3d3dc71..fc12789b05 100644
--- a/osu.Game/Overlays/ChatOverlay.cs
+++ b/osu.Game/Overlays/ChatOverlay.cs
@@ -93,7 +93,7 @@ namespace osu.Game.Overlays
{
var postText = sender.Text;
- if (!string.IsNullOrEmpty(postText))
+ if (!string.IsNullOrEmpty(postText) && api.LocalUser.Value != null)
{
//todo: actually send to server
careChannels.FirstOrDefault()?.AddNewMessages(new[]
diff --git a/osu.Game/Overlays/DragBar.cs b/osu.Game/Overlays/DragBar.cs
index 90991bb195..53a01c9e9c 100644
--- a/osu.Game/Overlays/DragBar.cs
+++ b/osu.Game/Overlays/DragBar.cs
@@ -65,7 +65,7 @@ namespace osu.Game.Overlays
private void updatePosition(float position)
{
position = MathHelper.Clamp(position, 0, 1);
- fill.TransformTo(fill.Width, position, 200, EasingTypes.OutQuint, new TransformSeek());
+ fill.TransformTo(() => fill.Width, position, 200, EasingTypes.OutQuint, new TransformSeek());
}
protected override bool OnMouseDown(InputState state, MouseDownEventArgs args)
diff --git a/osu.Game/Screens/Play/FailOverlay.cs b/osu.Game/Screens/Play/FailOverlay.cs
index 7a32e19338..faff687ddb 100644
--- a/osu.Game/Screens/Play/FailOverlay.cs
+++ b/osu.Game/Screens/Play/FailOverlay.cs
@@ -1,31 +1,19 @@
// Copyright (c) 2007-2017 ppy Pty Ltd .
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-using osu.Framework.Graphics.Containers;
using osu.Framework.Input;
using OpenTK.Input;
using osu.Game.Graphics;
using OpenTK.Graphics;
using osu.Framework.Allocation;
+using System.Linq;
namespace osu.Game.Screens.Play
{
public class FailOverlay : MenuOverlay
{
-
public override string Header => "failed";
public override string Description => "you're dead, try again?";
- protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
- {
- if (args.Key == Key.Escape)
- {
- if (State == Visibility.Hidden) return false;
- OnQuit();
- return true;
- }
-
- return base.OnKeyDown(state, args);
- }
[BackgroundDependencyLoader]
private void load(OsuColour colours)
@@ -33,5 +21,16 @@ namespace osu.Game.Screens.Play
AddButton("Retry", colours.YellowDark, OnRetry);
AddButton("Quit", new Color4(170, 27, 39, 255), OnQuit);
}
+
+ protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
+ {
+ if (!args.Repeat && args.Key == Key.Escape)
+ {
+ Buttons.Children.Last().TriggerClick();
+ return true;
+ }
+
+ return base.OnKeyDown(state, args);
+ }
}
}
diff --git a/osu.Game/Screens/Play/MenuOverlay.cs b/osu.Game/Screens/Play/MenuOverlay.cs
index ede49065a7..738e5cc35d 100644
--- a/osu.Game/Screens/Play/MenuOverlay.cs
+++ b/osu.Game/Screens/Play/MenuOverlay.cs
@@ -13,10 +13,11 @@ using OpenTK;
using OpenTK.Graphics;
using osu.Game.Graphics;
using osu.Framework.Allocation;
+using osu.Game.Graphics.UserInterface;
namespace osu.Game.Screens.Play
{
- public abstract class MenuOverlay : OverlayContainer
+ public abstract class MenuOverlay : OverlayContainer, IRequireHighFrequencyMousePosition
{
private const int transition_duration = 200;
private const int button_height = 70;
@@ -30,7 +31,7 @@ namespace osu.Game.Screens.Play
public abstract string Header { get; }
public abstract string Description { get; }
- private FillFlowContainer buttons;
+ protected FillFlowContainer Buttons;
public int Retries
{
@@ -80,11 +81,13 @@ namespace osu.Game.Screens.Play
// Don't let mouse down events through the overlay or people can click circles while paused.
protected override bool OnMouseDown(InputState state, MouseDownEventArgs args) => true;
+ protected override bool OnMouseUp(InputState state, MouseUpEventArgs args) => true;
+
protected override bool OnMouseMove(InputState state) => true;
protected void AddButton(string text, Color4 colour, Action action)
{
- buttons.Add(new PauseButton
+ Buttons.Add(new PauseButton
{
Text = text,
ButtonColour = colour,
@@ -151,7 +154,7 @@ namespace osu.Game.Screens.Play
}
}
},
- buttons = new FillFlowContainer
+ Buttons = new FillFlowContainer
{
Origin = Anchor.TopCentre,
Anchor = Anchor.TopCentre,
diff --git a/osu.Game/Screens/Play/PauseOverlay.cs b/osu.Game/Screens/Play/PauseOverlay.cs
index f9706d263e..9561979751 100644
--- a/osu.Game/Screens/Play/PauseOverlay.cs
+++ b/osu.Game/Screens/Play/PauseOverlay.cs
@@ -2,10 +2,10 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
+using System.Linq;
using osu.Framework.Input;
using osu.Game.Graphics;
using OpenTK.Input;
-using osu.Framework.Graphics.Containers;
using OpenTK.Graphics;
using osu.Framework.Allocation;
@@ -20,10 +20,9 @@ namespace osu.Game.Screens.Play
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
{
- if (args.Key == Key.Escape)
+ if (!args.Repeat && args.Key == Key.Escape)
{
- if (State == Visibility.Hidden) return false;
- OnResume();
+ Buttons.Children.First().TriggerClick();
return true;
}
@@ -39,4 +38,3 @@ namespace osu.Game.Screens.Play
}
}
}
-
\ No newline at end of file
diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs
index a7108eda1b..01d5d0770a 100644
--- a/osu.Game/Screens/Play/Player.cs
+++ b/osu.Game/Screens/Play/Player.cs
@@ -35,7 +35,7 @@ namespace osu.Game.Screens.Play
public BeatmapInfo BeatmapInfo;
- public bool IsPaused { get; private set; }
+ public bool IsPaused => !interpolatedSourceClock.IsRunning;
public bool HasFailed { get; private set; }
@@ -44,7 +44,7 @@ namespace osu.Game.Screens.Play
private const double pause_cooldown = 1000;
private double lastPauseActionTime;
- private bool canPause => Time.Current >= lastPauseActionTime + pause_cooldown;
+ private bool canPause => ValidForResume && !HasFailed && Time.Current >= lastPauseActionTime + pause_cooldown;
private IAdjustableClock sourceClock;
private IFrameBasedClock interpolatedSourceClock;
@@ -116,7 +116,12 @@ namespace osu.Game.Screens.Play
scoreProcessor = HitRenderer.CreateScoreProcessor();
- hudOverlay = new StandardHudOverlay();
+ hudOverlay = new StandardHudOverlay()
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre
+ };
+
hudOverlay.KeyCounter.Add(ruleset.CreateGameplayKeys());
hudOverlay.BindProcessor(scoreProcessor);
hudOverlay.BindHitRenderer(HitRenderer);
@@ -160,7 +165,12 @@ namespace osu.Game.Screens.Play
},
new HotkeyRetryOverlay
{
- Action = Restart,
+ Action = () => {
+ //we want to hide the hitrenderer immediately (looks better).
+ //we may be able to remove this once the mouse cursor trail is improved.
+ HitRenderer?.Hide();
+ Restart();
+ },
}
};
}
@@ -194,19 +204,30 @@ namespace osu.Game.Screens.Play
public void Pause(bool force = false)
{
- if (canPause || force)
+ if (!canPause && !force) return;
+
+ // the actual pausing is potentially happening on a different thread.
+ // we want to wait for the source clock to stop so we can be sure all components are in a stable state.
+ if (!IsPaused)
{
+ sourceClock.Stop();
+
+ Schedule(() => Pause(force));
+ return;
+ }
+
+ // we need to do a final check after all of our children have processed up to the paused clock time.
+ // this is to cover cases where, for instance, the player fails in the last processed frame (which would change canPause).
+ // as the scheduler runs before children updates, let's schedule for the next frame.
+ Schedule(() =>
+ {
+ if (!canPause) return;
+
lastPauseActionTime = Time.Current;
hudOverlay.KeyCounter.IsCounting = false;
pauseOverlay.Retries = RestartCount;
pauseOverlay.Show();
- sourceClock.Stop();
- IsPaused = true;
- }
- else
- {
- IsPaused = false;
- }
+ });
}
public void Resume()
@@ -215,13 +236,6 @@ namespace osu.Game.Screens.Play
hudOverlay.KeyCounter.IsCounting = true;
pauseOverlay.Hide();
sourceClock.Start();
- IsPaused = false;
- }
-
- public void TogglePaused()
- {
- IsPaused = !IsPaused;
- if (IsPaused) Pause(); else Resume();
}
public void Restart()
@@ -230,11 +244,11 @@ namespace osu.Game.Screens.Play
var newPlayer = new Player();
+ ValidForResume = false;
+
LoadComponentAsync(newPlayer, delegate
{
newPlayer.RestartCount = RestartCount + 1;
- ValidForResume = false;
-
if (!Push(newPlayer))
{
// Error(?)
@@ -250,10 +264,11 @@ namespace osu.Game.Screens.Play
if (scoreProcessor.HasFailed || onCompletionEvent != null)
return;
+ ValidForResume = false;
+
Delay(1000);
onCompletionEvent = Schedule(delegate
{
- ValidForResume = false;
Push(new Results
{
Score = scoreProcessor.CreateScore()
@@ -265,8 +280,6 @@ namespace osu.Game.Screens.Play
{
sourceClock.Stop();
- Delay(500);
-
HasFailed = true;
failOverlay.Retries = RestartCount;
failOverlay.Show();
@@ -304,36 +317,46 @@ namespace osu.Game.Screens.Play
protected override void OnSuspending(Screen next)
{
- Content.FadeOut(350);
- Content.ScaleTo(0.7f, 750, EasingTypes.InQuint);
+ fadeOut();
base.OnSuspending(next);
}
protected override bool OnExiting(Screen next)
{
+ if (HasFailed || !ValidForResume)
+ return false;
+
if (pauseOverlay != null && !HitRenderer.HasReplayLoaded)
{
//pause screen override logic.
if (pauseOverlay?.State == Visibility.Hidden && !canPause) return true;
- if (!IsPaused && sourceClock.IsRunning) // For if the user presses escape quickly when entering the map
+ if (!IsPaused) // For if the user presses escape quickly when entering the map
{
Pause();
return true;
}
}
- HitRenderer?.FadeOut(60);
-
- FadeOut(250);
- Content.ScaleTo(0.7f, 750, EasingTypes.InQuint);
- Background?.FadeTo(1f, 200);
+ fadeOut();
return base.OnExiting(next);
}
+ private void fadeOut()
+ {
+ const float fade_out_duration = 250;
+
+ HitRenderer?.FadeOut(fade_out_duration);
+ Content.FadeOut(fade_out_duration);
+
+ hudOverlay.ScaleTo(0.7f, fade_out_duration * 3, EasingTypes.In);
+
+ Background?.FadeTo(1f, fade_out_duration);
+ }
+
private Bindable mouseWheelDisabled;
protected override bool OnWheel(InputState state) => mouseWheelDisabled.Value && !IsPaused;
}
-}
\ No newline at end of file
+}
diff --git a/osu.Game/Screens/Select/BeatmapDetailArea.cs b/osu.Game/Screens/Select/BeatmapDetailArea.cs
index dae909f2b7..ae117254fa 100644
--- a/osu.Game/Screens/Select/BeatmapDetailArea.cs
+++ b/osu.Game/Screens/Select/BeatmapDetailArea.cs
@@ -1,13 +1,10 @@
// Copyright (c) 2007-2017 ppy Pty Ltd .
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Primitives;
using osu.Game.Beatmaps;
-using osu.Game.Online.API;
-using osu.Game.Online.API.Requests;
using osu.Game.Screens.Select.Leaderboards;
namespace osu.Game.Screens.Select
@@ -17,11 +14,9 @@ namespace osu.Game.Screens.Select
private readonly Container content;
protected override Container Content => content;
- public readonly Container Details; //todo: replace with a real details view when added
+ public readonly BeatmapDetails Details;
public readonly Leaderboard Leaderboard;
- private APIAccess api;
-
private WorkingBeatmap beatmap;
public WorkingBeatmap Beatmap
{
@@ -32,7 +27,8 @@ namespace osu.Game.Screens.Select
set
{
beatmap = value;
- if (IsLoaded) Schedule(updateScores);
+ Leaderboard.Beatmap = beatmap?.BeatmapInfo;
+ Details.Beatmap = beatmap?.Beatmap.BeatmapInfo;
}
}
@@ -51,14 +47,12 @@ namespace osu.Game.Screens.Select
Details.Show();
Leaderboard.Hide();
break;
+
default:
Details.Hide();
Leaderboard.Show();
break;
}
-
- //for now let's always update scores.
- updateScores();
},
},
content = new Container
@@ -70,42 +64,18 @@ namespace osu.Game.Screens.Select
Add(new Drawable[]
{
- Details = new Container
+ Details = new BeatmapDetails
{
RelativeSizeAxes = Axes.Both,
+ Padding = new MarginPadding(5),
+ Alpha = 0,
},
Leaderboard = new Leaderboard
{
RelativeSizeAxes = Axes.Both,
+
}
});
}
-
- protected override void LoadComplete()
- {
- base.LoadComplete();
- updateScores();
- }
-
- [BackgroundDependencyLoader(permitNulls: true)]
- private void load(APIAccess api)
- {
- this.api = api;
- }
-
- private GetScoresRequest getScoresRequest;
- private void updateScores()
- {
- if (!IsLoaded) return;
-
- Leaderboard.Scores = null;
- getScoresRequest?.Cancel();
-
- if (api == null || beatmap?.BeatmapInfo == null || !Leaderboard.IsPresent) return;
-
- getScoresRequest = new GetScoresRequest(beatmap.BeatmapInfo);
- getScoresRequest.Success += r => Leaderboard.Scores = r.Scores;
- api.Queue(getScoresRequest);
- }
}
-}
+}
\ No newline at end of file
diff --git a/osu.Game/Screens/Select/BeatmapDetails.cs b/osu.Game/Screens/Select/BeatmapDetails.cs
new file mode 100644
index 0000000000..a0d15101e0
--- /dev/null
+++ b/osu.Game/Screens/Select/BeatmapDetails.cs
@@ -0,0 +1,434 @@
+// Copyright (c) 2007-2017 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using OpenTK;
+using OpenTK.Graphics;
+using osu.Framework.Allocation;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Primitives;
+using osu.Framework.Graphics.Sprites;
+using osu.Game.Database;
+using osu.Game.Graphics;
+using osu.Game.Graphics.Sprites;
+using osu.Game.Graphics.UserInterface;
+using System.Globalization;
+using System.Linq;
+
+namespace osu.Game.Screens.Select
+{
+ public class BeatmapDetails : Container
+ {
+ private readonly MetadataSegment description;
+ private readonly MetadataSegment source;
+ private readonly MetadataSegment tags;
+
+ private readonly DifficultyRow circleSize;
+ private readonly DifficultyRow drainRate;
+ private readonly DifficultyRow overallDifficulty;
+ private readonly DifficultyRow approachRate;
+ private readonly DifficultyRow stars;
+
+ private readonly Container ratingsContainer;
+ private readonly Bar ratingsBar;
+ private readonly OsuSpriteText negativeRatings;
+ private readonly OsuSpriteText positiveRatings;
+ private readonly BarGraph ratingsGraph;
+
+ private readonly FillFlowContainer retryFailContainer;
+ private readonly BarGraph retryGraph;
+ private readonly BarGraph failGraph;
+
+ private BeatmapInfo beatmap;
+ public BeatmapInfo Beatmap
+ {
+ get
+ {
+ return beatmap;
+ }
+ set
+ {
+ beatmap = value;
+ if (beatmap == null) return;
+
+ description.Text = beatmap.Version;
+ source.Text = beatmap.Metadata.Source;
+ tags.Text = beatmap.Metadata.Tags;
+
+ circleSize.Value = beatmap.Difficulty.CircleSize;
+ drainRate.Value = beatmap.Difficulty.DrainRate;
+ overallDifficulty.Value = beatmap.Difficulty.OverallDifficulty;
+ approachRate.Value = beatmap.Difficulty.ApproachRate;
+ stars.Value = (float)beatmap.StarDifficulty;
+
+ if (beatmap.Metrics?.Ratings.Any() ?? false)
+ {
+ var ratings = beatmap.Metrics.Ratings.ToList();
+ ratingsContainer.Show();
+
+ negativeRatings.Text = ratings.GetRange(0, ratings.Count / 2).Sum().ToString();
+ positiveRatings.Text = ratings.GetRange(ratings.Count / 2, ratings.Count / 2).Sum().ToString();
+ ratingsBar.Length = (float)ratings.GetRange(0, ratings.Count / 2).Sum() / ratings.Sum();
+
+ ratingsGraph.Values = ratings.Select(rating => (float)rating);
+ }
+ else
+ ratingsContainer.Hide();
+
+ if ((beatmap.Metrics?.Retries.Any() ?? false) && beatmap.Metrics.Fails.Any())
+ {
+ var retries = beatmap.Metrics.Retries;
+ var fails = beatmap.Metrics.Fails;
+ retryFailContainer.Show();
+
+ float maxValue = fails.Zip(retries, (fail, retry) => fail + retry).Max();
+ failGraph.MaxValue = maxValue;
+ retryGraph.MaxValue = maxValue;
+
+ failGraph.Values = fails.Select(fail => (float)fail);
+ retryGraph.Values = retries.Zip(fails, (retry, fail) => retry + MathHelper.Clamp(fail, 0, maxValue));
+ }
+ else
+ retryFailContainer.Hide();
+ }
+ }
+
+ public BeatmapDetails()
+ {
+ Children = new Drawable[]
+ {
+ new Box
+ {
+ RelativeSizeAxes = Axes.Both,
+ Colour = Color4.Black,
+ Alpha = 0.5f,
+ },
+ new FillFlowContainer()
+ {
+ Anchor = Anchor.TopRight,
+ Origin = Anchor.TopRight,
+ RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y,
+ Width = 0.4f,
+ Direction = FillDirection.Vertical,
+ LayoutDuration = 200,
+ LayoutEasing = EasingTypes.OutQuint,
+ Padding = new MarginPadding(10) { Top = 25 },
+ Children = new []
+ {
+ description = new MetadataSegment("Description"),
+ source = new MetadataSegment("Source"),
+ tags = new MetadataSegment("Tags")
+ },
+ },
+ new FillFlowContainer
+ {
+ RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y,
+ Width = 0.6f,
+ Direction = FillDirection.Vertical,
+ Spacing = new Vector2(0, 15),
+ Padding = new MarginPadding(10) { Top = 0 },
+ Children = new Drawable[]
+ {
+ new Container
+ {
+ RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y,
+ Children = new Drawable[]
+ {
+ new Box
+ {
+ RelativeSizeAxes = Axes.Both,
+ Colour = Color4.Black,
+ Alpha = 0.5f,
+ },
+ new FillFlowContainer
+ {
+ RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y,
+ Direction = FillDirection.Vertical,
+ Spacing = new Vector2(0,10),
+ Padding = new MarginPadding(15) { Top = 25 },
+ Children = new []
+ {
+ circleSize = new DifficultyRow("Circle Size", 7),
+ drainRate = new DifficultyRow("HP Drain"),
+ overallDifficulty = new DifficultyRow("Accuracy"),
+ approachRate = new DifficultyRow("Approach Rate"),
+ stars = new DifficultyRow("Star Diffculty"),
+ },
+ },
+ },
+ },
+ ratingsContainer = new Container
+ {
+ RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y,
+ Alpha = 0,
+ AlwaysPresent = true,
+ Children = new Drawable[]
+ {
+ new Box
+ {
+ RelativeSizeAxes = Axes.Both,
+ Colour = Color4.Black,
+ Alpha = 0.5f,
+ },
+ new FillFlowContainer
+ {
+ RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y,
+ Direction = FillDirection.Vertical,
+ Padding = new MarginPadding
+ {
+ Top = 25,
+ Left = 15,
+ Right = 15,
+ },
+ Children = new Drawable[]
+ {
+ new OsuSpriteText
+ {
+ Text = "User Rating",
+ Font = @"Exo2.0-Medium",
+ Anchor = Anchor.TopCentre,
+ Origin = Anchor.TopCentre,
+ },
+ ratingsBar = new Bar
+ {
+ RelativeSizeAxes = Axes.X,
+ Height = 5,
+ },
+ new Container
+ {
+ RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y,
+ Children = new[]
+ {
+ negativeRatings = new OsuSpriteText
+ {
+ Font = @"Exo2.0-Regular",
+ Text = "0",
+ },
+ positiveRatings = new OsuSpriteText
+ {
+ Font = @"Exo2.0-Regular",
+ Text = "0",
+ Anchor = Anchor.TopRight,
+ Origin = Anchor.TopRight,
+ },
+ },
+ },
+ new OsuSpriteText
+ {
+ Text = "Rating Spread",
+ TextSize = 14,
+ Font = @"Exo2.0-Regular",
+ Anchor = Anchor.TopCentre,
+ Origin = Anchor.TopCentre,
+ },
+ ratingsGraph = new BarGraph
+ {
+ RelativeSizeAxes = Axes.X,
+ Height = 50,
+ },
+ },
+ },
+ },
+ },
+ retryFailContainer = new FillFlowContainer
+ {
+ RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y,
+ Alpha = 0,
+ Children = new Drawable[]
+ {
+ new OsuSpriteText
+ {
+ Text = "Points of Failure",
+ Font = @"Exo2.0-Regular",
+ },
+ new Container
+ {
+ RelativeSizeAxes = Axes.X,
+ Size = new Vector2(1/0.6f, 50),
+ Children = new[]
+ {
+ retryGraph = new BarGraph
+ {
+ RelativeSizeAxes = Axes.Both,
+ },
+ failGraph = new BarGraph
+ {
+ RelativeSizeAxes = Axes.Both,
+ },
+ },
+ },
+ }
+ },
+ },
+ }
+ };
+ }
+
+ [BackgroundDependencyLoader]
+ private void load(OsuColour colour)
+ {
+ description.AccentColour = colour.GrayB;
+ source.AccentColour = colour.GrayB;
+ tags.AccentColour = colour.YellowLight;
+
+ stars.AccentColour = colour.Yellow;
+
+ ratingsBar.BackgroundColour = colour.Green;
+ ratingsBar.AccentColour = colour.YellowDark;
+ ratingsGraph.Colour = colour.BlueDark;
+
+ failGraph.Colour = colour.YellowDarker;
+ retryGraph.Colour = colour.Yellow;
+ }
+
+ private class DifficultyRow : Container, IHasAccentColour
+ {
+ private readonly OsuSpriteText name;
+ private readonly Bar bar;
+ private readonly OsuSpriteText valueText;
+
+ private readonly float maxValue;
+
+ private float difficultyValue;
+ public float Value
+ {
+ get
+ {
+ return difficultyValue;
+ }
+ set
+ {
+ difficultyValue = value;
+ bar.Length = value / maxValue;
+ valueText.Text = value.ToString(CultureInfo.InvariantCulture);
+ }
+ }
+
+ public Color4 AccentColour
+ {
+ get
+ {
+ return bar.AccentColour;
+ }
+ set
+ {
+ bar.AccentColour = value;
+ }
+ }
+
+ public DifficultyRow(string difficultyName, float maxValue = 10)
+ {
+ this.maxValue = maxValue;
+ RelativeSizeAxes = Axes.X;
+ AutoSizeAxes = Axes.Y;
+ Children = new Drawable[]
+ {
+ name = new OsuSpriteText
+ {
+ Font = @"Exo2.0-Regular",
+ Text = difficultyName,
+ },
+ bar = new Bar
+ {
+ Origin = Anchor.CentreLeft,
+ Anchor = Anchor.CentreLeft,
+ RelativeSizeAxes = Axes.Both,
+ Size = new Vector2(1, 0.35f),
+ Padding = new MarginPadding { Left = 100, Right = 25 },
+ },
+ valueText = new OsuSpriteText
+ {
+ Anchor = Anchor.TopRight,
+ Origin = Anchor.TopRight,
+ Font = @"Exo2.0-Regular",
+ },
+ };
+ }
+
+ [BackgroundDependencyLoader]
+ private void load(OsuColour colour)
+ {
+ name.Colour = colour.GrayB;
+ bar.BackgroundColour = colour.Gray7;
+ valueText.Colour = colour.GrayB;
+ }
+ }
+
+ private class MetadataSegment : Container, IHasAccentColour
+ {
+ private readonly OsuSpriteText header;
+ private readonly FillFlowContainer content;
+
+ public string Text
+ {
+ set
+ {
+ if (string.IsNullOrEmpty(value))
+ Hide();
+ else
+ {
+ Show();
+ if (header.Text == "Tags")
+ content.Children = value.Split(' ').Select(text => new OsuSpriteText
+ {
+ Text = text,
+ Font = "Exo2.0-Regular",
+ });
+ else
+ content.Children = new[]
+ {
+ new OsuSpriteText
+ {
+ Text = value,
+ Font = "Exo2.0-Regular",
+ }
+ };
+ }
+ }
+ }
+
+ public Color4 AccentColour
+ {
+ get
+ {
+ return content.Colour;
+ }
+ set
+ {
+ content.Colour = value;
+ }
+ }
+
+ public MetadataSegment(string headerText)
+ {
+ RelativeSizeAxes = Axes.X;
+ AutoSizeAxes = Axes.Y;
+ Margin = new MarginPadding { Top = 10 };
+ Children = new Drawable[]
+ {
+ header = new OsuSpriteText
+ {
+ Font = @"Exo2.0-Bold",
+ Text = headerText,
+ },
+ content = new FillFlowContainer
+ {
+ RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y,
+ Direction = FillDirection.Full,
+ Spacing = new Vector2(5,0),
+ Margin = new MarginPadding { Top = header.TextSize }
+ }
+ };
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/osu.Game/Screens/Select/FilterCriteria.cs b/osu.Game/Screens/Select/FilterCriteria.cs
index acf0954418..2654129a44 100644
--- a/osu.Game/Screens/Select/FilterCriteria.cs
+++ b/osu.Game/Screens/Select/FilterCriteria.cs
@@ -31,7 +31,9 @@ namespace osu.Game.Screens.Select
|| (set.Metadata.Artist ?? string.Empty).IndexOf(SearchText, StringComparison.InvariantCultureIgnoreCase) != -1
|| (set.Metadata.ArtistUnicode ?? string.Empty).IndexOf(SearchText, StringComparison.InvariantCultureIgnoreCase) != -1
|| (set.Metadata.Title ?? string.Empty).IndexOf(SearchText, StringComparison.InvariantCultureIgnoreCase) != -1
- || (set.Metadata.TitleUnicode ?? string.Empty).IndexOf(SearchText, StringComparison.InvariantCultureIgnoreCase) != -1;
+ || (set.Metadata.TitleUnicode ?? string.Empty).IndexOf(SearchText, StringComparison.InvariantCultureIgnoreCase) != -1
+ || (set.Metadata.Tags ?? string.Empty).IndexOf(SearchText, StringComparison.InvariantCultureIgnoreCase) != -1
+ || (set.Metadata.Source ?? string.Empty).IndexOf(SearchText, StringComparison.InvariantCultureIgnoreCase) != -1;
switch (g.State)
{
diff --git a/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs b/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs
index 12ff096d16..315611a60c 100644
--- a/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs
+++ b/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs
@@ -10,7 +10,11 @@ using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Primitives;
using System;
+using osu.Framework.Allocation;
+using osu.Game.Database;
using osu.Game.Modes.Scoring;
+using osu.Game.Online.API;
+using osu.Game.Online.API.Requests;
namespace osu.Game.Screens.Select.Leaderboards
{
@@ -26,6 +30,7 @@ namespace osu.Game.Screens.Select.Leaderboards
set
{
scores = value;
+ getScoresRequest?.Cancel();
int i = 150;
if (scores == null)
@@ -81,6 +86,41 @@ namespace osu.Game.Screens.Select.Leaderboards
};
}
+ private APIAccess api;
+
+ private BeatmapInfo beatmap;
+
+ public BeatmapInfo Beatmap
+ {
+ get { return beatmap; }
+ set
+ {
+ beatmap = value;
+ Schedule(updateScores);
+ }
+ }
+
+ [BackgroundDependencyLoader(permitNulls: true)]
+ private void load(APIAccess api)
+ {
+ this.api = api;
+ }
+
+ private GetScoresRequest getScoresRequest;
+ private void updateScores()
+ {
+ if (!IsLoaded) return;
+
+ Scores = null;
+ getScoresRequest?.Cancel();
+
+ if (api == null || Beatmap == null) return;
+
+ getScoresRequest = new GetScoresRequest(Beatmap);
+ getScoresRequest.Success += r => Scores = r.Scores;
+ api.Queue(getScoresRequest);
+ }
+
protected override void Update()
{
base.Update();
diff --git a/osu.Game/Screens/Select/Leaderboards/LeaderboardScore.cs b/osu.Game/Screens/Select/Leaderboards/LeaderboardScore.cs
index 2bac387c5c..493f351b75 100644
--- a/osu.Game/Screens/Select/Leaderboards/LeaderboardScore.cs
+++ b/osu.Game/Screens/Select/Leaderboards/LeaderboardScore.cs
@@ -142,7 +142,7 @@ namespace osu.Game.Screens.Select.Leaderboards
Children = new Drawable[]
{
avatar = new DelayedLoadWrapper(
- new Avatar(Score.User ?? new User { Id = Score.UserID })
+ new Avatar(Score.User)
{
RelativeSizeAxes = Axes.Both,
CornerRadius = corner_radius,
@@ -169,7 +169,7 @@ namespace osu.Game.Screens.Select.Leaderboards
{
nameLabel = new OsuSpriteText
{
- Text = Score.User?.Username ?? Score.Username,
+ Text = Score.User.Username,
Font = @"Exo2.0-BoldItalic",
TextSize = 23,
},
diff --git a/osu.Game/Screens/Tournament/ScrollingTeamContainer.cs b/osu.Game/Screens/Tournament/ScrollingTeamContainer.cs
index b80f76d281..08f270741c 100644
--- a/osu.Game/Screens/Tournament/ScrollingTeamContainer.cs
+++ b/osu.Game/Screens/Tournament/ScrollingTeamContainer.cs
@@ -298,7 +298,7 @@ namespace osu.Game.Screens.Tournament
private void speedTo(float value, double duration = 0, EasingTypes easing = EasingTypes.None)
{
DelayReset();
- TransformTo(speed, value, duration, easing, new TransformScrollSpeed());
+ TransformTo(() => speed, value, duration, easing, new TransformScrollSpeed());
}
private enum ScrollState
diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj
index 7b9d41a4e1..b9b80ac5b9 100644
--- a/osu.Game/osu.Game.csproj
+++ b/osu.Game/osu.Game.csproj
@@ -35,17 +35,14 @@
false
-
- $(SolutionDir)\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll
- True
+
+ $(SolutionDir)\packages\Newtonsoft.Json.10.0.2\lib\net45\Newtonsoft.Json.dll
- $(SolutionDir)\packages\ppy.OpenTK.2.0.50727.1340\lib\net45\OpenTK.dll
- True
+ $(SolutionDir)\packages\ppy.OpenTK.2.0.50727.1341\lib\net45\OpenTK.dll
-
- ..\packages\SharpCompress.0.15.1\lib\net45\SharpCompress.dll
- True
+
+ $(SolutionDir)\packages\SharpCompress.0.15.2\lib\net45\SharpCompress.dll
$(SolutionDir)\packages\SQLite.Net.Core-PCL.3.1.1\lib\portable-win8+net45+wp8+wpa81+MonoAndroid1+MonoTouch1\SQLite.Net.dll
@@ -79,6 +76,7 @@
+
@@ -87,6 +85,7 @@
+
@@ -206,6 +205,8 @@
+
+
@@ -390,7 +391,7 @@
-
-
-
-
+
+
+