diff --git a/appveyor.yml b/appveyor.yml
index cc6dfb9c88..b26a895788 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -20,4 +20,4 @@ build:
verbosity: minimal
after_build:
- cmd: inspectcode /o="inspectcodereport.xml" /caches-home="inspectcode" osu.sln
- - cmd: NVika parsereport "inspectcodereport.xml"
\ No newline at end of file
+ - cmd: NVika parsereport "inspectcodereport.xml" --treatwarningsaserrors
\ No newline at end of file
diff --git a/osu-framework b/osu-framework
index 0f3db5da09..97ff3376d1 160000
--- a/osu-framework
+++ b/osu-framework
@@ -1 +1 @@
-Subproject commit 0f3db5da09d0e7c4d2ef3057030e018f34ba536e
+Subproject commit 97ff3376d1bdac3703d442e62f5ee6a36eb3b73f
diff --git a/osu-resources b/osu-resources
index 9f46a456dc..10fda22522 160000
--- a/osu-resources
+++ b/osu-resources
@@ -1 +1 @@
-Subproject commit 9f46a456dc3a56dcbff09671a3f588b16a464106
+Subproject commit 10fda22522ffadbdbc43fa0f3683a065e536f7d1
diff --git a/osu.Desktop.Deploy/App.config b/osu.Desktop.Deploy/App.config
index 45685a74a8..6711f9c54e 100644
--- a/osu.Desktop.Deploy/App.config
+++ b/osu.Desktop.Deploy/App.config
@@ -31,6 +31,10 @@ 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 1f9726b573..c6474eae5a 100644
--- a/osu.Desktop.Deploy/osu.Desktop.Deploy.csproj
+++ b/osu.Desktop.Deploy/osu.Desktop.Deploy.csproj
@@ -49,10 +49,6 @@
$(SolutionDir)\packages\DeltaCompressionDotNet.1.1.0\lib\net20\DeltaCompressionDotNet.PatchApi.dll
True
-
- $(SolutionDir)\packages\squirrel.windows.1.5.2\lib\Net45\ICSharpCode.SharpZipLib.dll
- True
-
$(SolutionDir)\packages\Mono.Cecil.0.9.6.4\lib\net45\Mono.Cecil.dll
True
@@ -73,15 +69,19 @@
$(SolutionDir)\packages\Newtonsoft.Json.10.0.2\lib\net45\Newtonsoft.Json.dll
- $(SolutionDir)\packages\squirrel.windows.1.5.2\lib\Net45\NuGet.Squirrel.dll
+ $(SolutionDir)\packages\squirrel.windows.1.7.5\lib\Net45\NuGet.Squirrel.dll
+ True
+
+
+ $(SolutionDir)\packages\SharpCompress.0.17.1\lib\net45\SharpCompress.dll
True
$(SolutionDir)\packages\Splat.2.0.0\lib\Net45\Splat.dll
True
-
- $(SolutionDir)\packages\squirrel.windows.1.5.2\lib\Net45\Squirrel.dll
+
+ $(SolutionDir)\packages\squirrel.windows.1.7.5\lib\Net45\Squirrel.dll
True
diff --git a/osu.Desktop.Deploy/packages.config b/osu.Desktop.Deploy/packages.config
index 4878297be9..3c5ca9f9a3 100644
--- a/osu.Desktop.Deploy/packages.config
+++ b/osu.Desktop.Deploy/packages.config
@@ -7,7 +7,8 @@ Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/maste
-
+
+
-
+
\ No newline at end of file
diff --git a/osu.Desktop.Tests/app.config b/osu.Desktop.Tests/app.config
new file mode 100644
index 0000000000..faeaf001de
--- /dev/null
+++ b/osu.Desktop.Tests/app.config
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/osu.Desktop.Tests/osu.Desktop.Tests.csproj b/osu.Desktop.Tests/osu.Desktop.Tests.csproj
index f0620c98ef..f940e4be9e 100644
--- a/osu.Desktop.Tests/osu.Desktop.Tests.csproj
+++ b/osu.Desktop.Tests/osu.Desktop.Tests.csproj
@@ -37,8 +37,9 @@
$(SolutionDir)\packages\Newtonsoft.Json.10.0.2\lib\net45\Newtonsoft.Json.dll
-
- $(SolutionDir)\packages\NUnit.3.6.1\lib\net45\nunit.framework.dll
+
+ $(SolutionDir)\packages\NUnit.3.7.1\lib\net45\nunit.framework.dll
+ True
False
@@ -100,6 +101,7 @@
osu.licenseheader
+
diff --git a/osu.Desktop.Tests/packages.config b/osu.Desktop.Tests/packages.config
index ad51a60195..7bd35a3abe 100644
--- a/osu.Desktop.Tests/packages.config
+++ b/osu.Desktop.Tests/packages.config
@@ -5,7 +5,7 @@ Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/maste
-->
-
+
diff --git a/osu.Desktop.VisualTests/Tests/TestCaseBeatmapDetails.cs b/osu.Desktop.VisualTests/Tests/TestCaseBeatmapDetails.cs
index 58cbad936a..df80ffdf53 100644
--- a/osu.Desktop.VisualTests/Tests/TestCaseBeatmapDetails.cs
+++ b/osu.Desktop.VisualTests/Tests/TestCaseBeatmapDetails.cs
@@ -41,7 +41,7 @@ namespace osu.Desktop.VisualTests.Tests
StarDifficulty = 5.3f,
Metrics = new BeatmapMetrics
{
- Ratings = Enumerable.Range(0,10),
+ 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),
},
diff --git a/osu.Desktop.VisualTests/Tests/TestCaseContextMenu.cs b/osu.Desktop.VisualTests/Tests/TestCaseContextMenu.cs
new file mode 100644
index 0000000000..808e9b5d19
--- /dev/null
+++ b/osu.Desktop.VisualTests/Tests/TestCaseContextMenu.cs
@@ -0,0 +1,125 @@
+// 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.Cursor;
+using osu.Framework.Graphics.Shapes;
+using osu.Framework.Graphics.Transforms;
+using osu.Framework.Graphics.UserInterface;
+using osu.Framework.Testing;
+using osu.Game.Graphics.UserInterface;
+
+namespace osu.Desktop.VisualTests.Tests
+{
+ internal class TestCaseContextMenu : TestCase
+ {
+ public override string Description => @"Menu visible on right click";
+
+ private const int start_time = 0;
+ private const int duration = 1000;
+
+ private MyContextMenuContainer container;
+
+ public override void Reset()
+ {
+ base.Reset();
+
+ Add(container = new MyContextMenuContainer
+ {
+ Size = new Vector2(200),
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ Children = new Drawable[]
+ {
+ new Box
+ {
+ RelativeSizeAxes = Axes.Both,
+ Colour = Color4.Green,
+ }
+ }
+ });
+
+ Add(new AnotherContextMenuContainer
+ {
+ Size = new Vector2(200),
+ Anchor = Anchor.CentreLeft,
+ Origin = Anchor.CentreLeft,
+ Children = new Drawable[]
+ {
+ new Box
+ {
+ RelativeSizeAxes = Axes.Both,
+ Colour = Color4.Red,
+ }
+ }
+ });
+
+ container.Transforms.Add(new TransformPosition
+ {
+ StartValue = Vector2.Zero,
+ EndValue = new Vector2(0, 100),
+ StartTime = start_time,
+ EndTime = start_time + duration,
+ LoopCount = -1,
+ LoopDelay = duration * 3
+ });
+ container.Transforms.Add(new TransformPosition
+ {
+ StartValue = new Vector2(0, 100),
+ EndValue = new Vector2(100, 100),
+ StartTime = start_time + duration,
+ EndTime = start_time + duration * 2,
+ LoopCount = -1,
+ LoopDelay = duration * 3
+ });
+ container.Transforms.Add(new TransformPosition
+ {
+ StartValue = new Vector2(100, 100),
+ EndValue = new Vector2(100, 0),
+ StartTime = start_time + duration * 2,
+ EndTime = start_time + duration * 3,
+ LoopCount = -1,
+ LoopDelay = duration * 3
+ });
+ container.Transforms.Add(new TransformPosition
+ {
+ StartValue = new Vector2(100, 0),
+ EndValue = Vector2.Zero,
+ StartTime = start_time + duration * 3,
+ EndTime = start_time + duration * 4,
+ LoopCount = -1,
+ LoopDelay = duration * 3
+ });
+ }
+
+ private class MyContextMenuContainer : Container, IHasContextMenu
+ {
+ public ContextMenuItem[] ContextMenuItems => new ContextMenuItem[]
+ {
+ new OsuContextMenuItem(@"Some option"),
+ new OsuContextMenuItem(@"Highlighted option", MenuItemType.Highlighted),
+ new OsuContextMenuItem(@"Another option"),
+ new OsuContextMenuItem(@"Choose me please"),
+ new OsuContextMenuItem(@"And me too"),
+ new OsuContextMenuItem(@"Trying to fill"),
+ new OsuContextMenuItem(@"Destructive option", MenuItemType.Destructive),
+ };
+ }
+
+ private class AnotherContextMenuContainer : Container, IHasContextMenu
+ {
+ public ContextMenuItem[] ContextMenuItems => new ContextMenuItem[]
+ {
+ new OsuContextMenuItem(@"Simple option"),
+ new OsuContextMenuItem(@"Simple very very long option"),
+ new OsuContextMenuItem(@"Change width", MenuItemType.Highlighted) { Action = () => ResizeWidthTo(Width * 2, 100, EasingTypes.OutQuint) },
+ new OsuContextMenuItem(@"Change height", MenuItemType.Highlighted) { Action = () => ResizeHeightTo(Height * 2, 100, EasingTypes.OutQuint) },
+ new OsuContextMenuItem(@"Change width back", MenuItemType.Destructive) { Action = () => ResizeWidthTo(Width / 2, 100, EasingTypes.OutQuint) },
+ new OsuContextMenuItem(@"Change height back", MenuItemType.Destructive) { Action = () => ResizeHeightTo(Height / 2, 100, EasingTypes.OutQuint) },
+ };
+ }
+ }
+}
diff --git a/osu.Desktop.VisualTests/Tests/TestCaseDrawableRoom.cs b/osu.Desktop.VisualTests/Tests/TestCaseDrawableRoom.cs
index 32af330f44..43a8069720 100644
--- a/osu.Desktop.VisualTests/Tests/TestCaseDrawableRoom.cs
+++ b/osu.Desktop.VisualTests/Tests/TestCaseDrawableRoom.cs
@@ -36,7 +36,7 @@ namespace osu.Desktop.VisualTests.Tests
});
first.Room.Name.Value = @"Great Room Right Here";
- first.Room.Host.Value = new User { Username = @"Naeferith", Id = 9492835, Country = new Country { FlagName = @"FR" }};
+ first.Room.Host.Value = new User { Username = @"Naeferith", Id = 9492835, Country = new Country { FlagName = @"FR" } };
first.Room.Status.Value = new RoomStatusOpen();
first.Room.Beatmap.Value = new BeatmapInfo
{
@@ -48,7 +48,7 @@ namespace osu.Desktop.VisualTests.Tests
};
second.Room.Name.Value = @"Relax It's The Weekend";
- second.Room.Host.Value = new User { Username = @"peppy", Id = 2, Country = new Country { FlagName = @"AU" }};
+ second.Room.Host.Value = new User { Username = @"peppy", Id = 2, Country = new Country { FlagName = @"AU" } };
second.Room.Status.Value = new RoomStatusPlaying();
second.Room.Beatmap.Value = new BeatmapInfo
{
diff --git a/osu.Desktop.VisualTests/Tests/TestCaseGraph.cs b/osu.Desktop.VisualTests/Tests/TestCaseGraph.cs
index 7ac795f6f9..f653e2b9b4 100644
--- a/osu.Desktop.VisualTests/Tests/TestCaseGraph.cs
+++ b/osu.Desktop.VisualTests/Tests/TestCaseGraph.cs
@@ -30,7 +30,7 @@ namespace osu.Desktop.VisualTests.Tests
},
};
- AddStep("values from 1-10", () => graph.Values = Enumerable.Range(1,10).Select(i => (float)i));
+ 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);
diff --git a/osu.Desktop.VisualTests/Tests/TestCaseKeyCounter.cs b/osu.Desktop.VisualTests/Tests/TestCaseKeyCounter.cs
index b1b9ddbcda..a28176b512 100644
--- a/osu.Desktop.VisualTests/Tests/TestCaseKeyCounter.cs
+++ b/osu.Desktop.VisualTests/Tests/TestCaseKeyCounter.cs
@@ -10,6 +10,7 @@ using osu.Framework.Graphics.Containers;
using OpenTK;
using OpenTK.Graphics;
using osu.Framework.MathUtils;
+using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
using osu.Game.Screens.Play;
@@ -54,7 +55,7 @@ namespace osu.Desktop.VisualTests.Tests
Children = new Drawable[]
{
new SpriteText { Text = "FadeTime" },
- sliderBar =new TestSliderBar
+ sliderBar = new TestSliderBar
{
Width = 150,
Height = 10,
diff --git a/osu.Desktop.VisualTests/Tests/TestCaseManiaHitObjects.cs b/osu.Desktop.VisualTests/Tests/TestCaseManiaHitObjects.cs
index 3113b63db1..c66b0b4db4 100644
--- a/osu.Desktop.VisualTests/Tests/TestCaseManiaHitObjects.cs
+++ b/osu.Desktop.VisualTests/Tests/TestCaseManiaHitObjects.cs
@@ -40,7 +40,7 @@ namespace osu.Desktop.VisualTests.Tests
{
Name = "Timing section",
RelativeSizeAxes = Axes.Both,
- RelativeCoordinateSpace = new Vector2(1, 10000),
+ RelativeChildSize = new Vector2(1, 10000),
Children = new[]
{
new DrawableNote(new Note { StartTime = 5000 }) { AccentColour = Color4.Red },
@@ -62,7 +62,7 @@ namespace osu.Desktop.VisualTests.Tests
{
Name = "Timing section",
RelativeSizeAxes = Axes.Both,
- RelativeCoordinateSpace = new Vector2(1, 10000),
+ RelativeChildSize = new Vector2(1, 10000),
Children = new[]
{
new DrawableHoldNote(new HoldNote
diff --git a/osu.Desktop.VisualTests/Tests/TestCaseManiaPlayfield.cs b/osu.Desktop.VisualTests/Tests/TestCaseManiaPlayfield.cs
index 95287c3199..352b6cdc81 100644
--- a/osu.Desktop.VisualTests/Tests/TestCaseManiaPlayfield.cs
+++ b/osu.Desktop.VisualTests/Tests/TestCaseManiaPlayfield.cs
@@ -6,14 +6,16 @@ using osu.Framework.Testing;
using osu.Framework.Graphics;
using osu.Game.Rulesets.Mania.UI;
using System;
-using System.Collections.Generic;
using OpenTK;
using osu.Game.Rulesets.Mania.Objects.Drawables;
using osu.Game.Rulesets.Mania.Objects;
-using osu.Game.Rulesets.Mania.Timing;
using osu.Framework.Configuration;
using OpenTK.Input;
using osu.Framework.Timing;
+using osu.Framework.Extensions.IEnumerableExtensions;
+using System.Linq;
+using osu.Game.Rulesets.Mania.Timing;
+using osu.Game.Rulesets.Timing;
namespace osu.Desktop.VisualTests.Tests
{
@@ -30,7 +32,7 @@ namespace osu.Desktop.VisualTests.Tests
Action createPlayfield = (cols, pos) =>
{
Clear();
- Add(new ManiaPlayfield(cols, new List())
+ Add(new ManiaPlayfield(cols)
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
@@ -39,37 +41,22 @@ namespace osu.Desktop.VisualTests.Tests
});
};
- Action createPlayfieldWithNotes = (cols, pos) =>
+ const double start_time = 500;
+ const double duration = 500;
+
+ Func createTimingChange = (time, gravity) => new ManiaSpeedAdjustmentContainer(new MultiplierControlPoint(time)
+ {
+ TimingPoint = { BeatLength = 1000 }
+ }, gravity ? ScrollingAlgorithm.Gravity : ScrollingAlgorithm.Basic);
+
+ Action createPlayfieldWithNotes = gravity =>
{
Clear();
- ManiaPlayfield playField;
- Add(playField = new ManiaPlayfield(cols, new List { new TimingChange { BeatLength = 200 } })
- {
- Anchor = Anchor.Centre,
- Origin = Anchor.Centre,
- SpecialColumnPosition = pos,
- Scale = new Vector2(1, -1)
- });
-
- for (int i = 0; i < cols; i++)
- {
- playField.Add(new DrawableNote(new Note
- {
- StartTime = Time.Current + 1000,
- Column = i
- }));
- }
- };
-
- Action createPlayfieldWithNotesAcceptingInput = () =>
- {
- Clear();
-
- var rateAdjustClock = new StopwatchClock(true) { Rate = 0.5 };
+ var rateAdjustClock = new StopwatchClock(true) { Rate = 1 };
ManiaPlayfield playField;
- Add(playField = new ManiaPlayfield(4, new List { new TimingChange { BeatLength = 200 } })
+ Add(playField = new ManiaPlayfield(4)
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
@@ -77,14 +64,23 @@ namespace osu.Desktop.VisualTests.Tests
Clock = new FramedClock(rateAdjustClock)
});
- for (int t = 1000; t <= 2000; t += 100)
+ if (!gravity)
+ playField.Columns.ForEach(c => c.Add(createTimingChange(0, false)));
+
+ for (double t = start_time; t <= start_time + duration; t += 100)
{
+ if (gravity)
+ playField.Columns.ElementAt(0).Add(createTimingChange(t, true));
+
playField.Add(new DrawableNote(new Note
{
StartTime = t,
Column = 0
}, new Bindable(Key.D)));
+ if (gravity)
+ playField.Columns.ElementAt(3).Add(createTimingChange(t, true));
+
playField.Add(new DrawableNote(new Note
{
StartTime = t,
@@ -92,17 +88,23 @@ namespace osu.Desktop.VisualTests.Tests
}, new Bindable(Key.K)));
}
- playField.Add(new DrawableHoldNote(new HoldNote
- {
- StartTime = 1000,
- Duration = 1000,
- Column = 1
- }, new Bindable(Key.F)));
+ if (gravity)
+ playField.Columns.ElementAt(1).Add(createTimingChange(start_time, true));
playField.Add(new DrawableHoldNote(new HoldNote
{
- StartTime = 1000,
- Duration = 1000,
+ StartTime = start_time,
+ Duration = duration,
+ Column = 1
+ }, new Bindable(Key.F)));
+
+ if (gravity)
+ playField.Columns.ElementAt(2).Add(createTimingChange(start_time, true));
+
+ playField.Add(new DrawableHoldNote(new HoldNote
+ {
+ StartTime = start_time,
+ Duration = duration,
Column = 2
}, new Bindable(Key.J)));
};
@@ -116,16 +118,11 @@ namespace osu.Desktop.VisualTests.Tests
AddStep("Left special style", () => createPlayfield(8, SpecialColumnPosition.Left));
AddStep("Right special style", () => createPlayfield(8, SpecialColumnPosition.Right));
- AddStep("Normal special style", () => createPlayfield(4, SpecialColumnPosition.Normal));
+ AddStep("Notes with input", () => createPlayfieldWithNotes(false));
+ AddWaitStep((int)Math.Ceiling((start_time + duration) / TimePerAction));
- AddStep("Notes", () => createPlayfieldWithNotes(4, SpecialColumnPosition.Normal));
- AddWaitStep(10);
- AddStep("Left special style", () => createPlayfieldWithNotes(4, SpecialColumnPosition.Left));
- AddWaitStep(10);
- AddStep("Right special style", () => createPlayfieldWithNotes(4, SpecialColumnPosition.Right));
- AddWaitStep(10);
-
- AddStep("Notes with input", () => createPlayfieldWithNotesAcceptingInput());
+ AddStep("Notes with gravity", () => createPlayfieldWithNotes(true));
+ AddWaitStep((int)Math.Ceiling((start_time + duration) / TimePerAction));
}
private void triggerKeyDown(Column column)
diff --git a/osu.Desktop.VisualTests/Tests/TestCaseMenuButtonSystem.cs b/osu.Desktop.VisualTests/Tests/TestCaseMenuButtonSystem.cs
index ddb62598cf..0caa518a0b 100644
--- a/osu.Desktop.VisualTests/Tests/TestCaseMenuButtonSystem.cs
+++ b/osu.Desktop.VisualTests/Tests/TestCaseMenuButtonSystem.cs
@@ -3,9 +3,9 @@
using osu.Framework.Testing;
using osu.Framework.Graphics.Colour;
-using osu.Framework.Graphics.Sprites;
using osu.Game.Screens.Menu;
using OpenTK.Graphics;
+using osu.Framework.Graphics.Shapes;
namespace osu.Desktop.VisualTests.Tests
{
diff --git a/osu.Desktop.VisualTests/Tests/TestCaseMenuOverlays.cs b/osu.Desktop.VisualTests/Tests/TestCaseMenuOverlays.cs
index 23fe8f16db..4de8b297eb 100644
--- a/osu.Desktop.VisualTests/Tests/TestCaseMenuOverlays.cs
+++ b/osu.Desktop.VisualTests/Tests/TestCaseMenuOverlays.cs
@@ -35,7 +35,7 @@ namespace osu.Desktop.VisualTests.Tests
});
AddStep(@"Pause", delegate {
- if(failOverlay.State == Visibility.Visible)
+ if (failOverlay.State == Visibility.Visible)
{
failOverlay.Hide();
}
diff --git a/osu.Desktop.VisualTests/Tests/TestCasePlayer.cs b/osu.Desktop.VisualTests/Tests/TestCasePlayer.cs
index f28cdd6a7e..d922f3bb4b 100644
--- a/osu.Desktop.VisualTests/Tests/TestCasePlayer.cs
+++ b/osu.Desktop.VisualTests/Tests/TestCasePlayer.cs
@@ -7,7 +7,6 @@ using osu.Framework.Allocation;
using osu.Framework.Testing;
using osu.Game.Beatmaps;
using OpenTK;
-using osu.Framework.Graphics.Sprites;
using osu.Game.Database;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Osu.Objects;
@@ -15,6 +14,7 @@ using osu.Game.Screens.Play;
using OpenTK.Graphics;
using osu.Desktop.VisualTests.Beatmaps;
using osu.Game.Rulesets.Osu.UI;
+using osu.Framework.Graphics.Shapes;
namespace osu.Desktop.VisualTests.Tests
{
diff --git a/osu.Desktop.VisualTests/Tests/TestCaseReplaySettingsOverlay.cs b/osu.Desktop.VisualTests/Tests/TestCaseReplaySettingsOverlay.cs
new file mode 100644
index 0000000000..b2c211b7f0
--- /dev/null
+++ b/osu.Desktop.VisualTests/Tests/TestCaseReplaySettingsOverlay.cs
@@ -0,0 +1,55 @@
+// 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.Testing;
+using osu.Game.Graphics.UserInterface;
+using osu.Game.Screens.Play;
+using osu.Game.Screens.Play.ReplaySettings;
+
+namespace osu.Desktop.VisualTests.Tests
+{
+ internal class TestCaseReplaySettingsOverlay : TestCase
+ {
+ public override string Description => @"Settings visible in replay/auto";
+
+ private ExampleContainer container;
+
+ public override void Reset()
+ {
+ base.Reset();
+
+ Add(new ReplaySettingsOverlay()
+ {
+ Anchor = Anchor.TopRight,
+ Origin = Anchor.TopRight,
+ });
+
+ Add(container = new ExampleContainer());
+
+ AddStep(@"Add button", () => container.Add(new OsuButton
+ {
+ RelativeSizeAxes = Axes.X,
+ Text = @"Button",
+ }));
+
+ AddStep(@"Add checkbox", () => container.Add(new ReplayCheckbox
+ {
+ LabelText = "Checkbox",
+ }));
+
+ AddStep(@"Add textbox", () => container.Add(new FocusedTextBox
+ {
+ RelativeSizeAxes = Axes.X,
+ Height = 30,
+ PlaceholderText = "Textbox",
+ HoldFocus = false,
+ }));
+ }
+
+ private class ExampleContainer : ReplayGroup
+ {
+ protected override string Title => @"example";
+ }
+ }
+}
diff --git a/osu.Desktop.VisualTests/Tests/TestCaseScoreCounter.cs b/osu.Desktop.VisualTests/Tests/TestCaseScoreCounter.cs
index f86fa4dab5..45ae82109f 100644
--- a/osu.Desktop.VisualTests/Tests/TestCaseScoreCounter.cs
+++ b/osu.Desktop.VisualTests/Tests/TestCaseScoreCounter.cs
@@ -79,7 +79,8 @@ namespace osu.Desktop.VisualTests.Tests
{
score.Current.Value += 300 + (ulong)(300.0 * (comboCounter.Current > 0 ? comboCounter.Current - 1 : 0) / 25.0);
comboCounter.Increment();
- numerator++; denominator++;
+ numerator++;
+ denominator++;
accuracyCounter.SetFraction(numerator, denominator);
});
diff --git a/osu.Desktop.VisualTests/Tests/TestCaseScrollingHitObjects.cs b/osu.Desktop.VisualTests/Tests/TestCaseScrollingHitObjects.cs
new file mode 100644
index 0000000000..4ddc35eb84
--- /dev/null
+++ b/osu.Desktop.VisualTests/Tests/TestCaseScrollingHitObjects.cs
@@ -0,0 +1,211 @@
+// 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.Configuration;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Shapes;
+using osu.Framework.Graphics.Sprites;
+using osu.Framework.Graphics.UserInterface;
+using osu.Framework.Testing;
+using osu.Game.Graphics.Sprites;
+using osu.Game.Rulesets.Objects;
+using osu.Game.Rulesets.Objects.Drawables;
+using osu.Game.Rulesets.Timing;
+
+namespace osu.Desktop.VisualTests.Tests
+{
+ public class TestCaseScrollingHitObjects : TestCase
+ {
+ public override string Description => "SpeedAdjustmentContainer/DrawableTimingSection";
+
+ private SpeedAdjustmentCollection adjustmentCollection;
+
+ private BindableDouble timeRangeBindable;
+ private OsuSpriteText timeRangeText;
+ private OsuSpriteText bottomLabel;
+ private SpriteText topTime, bottomTime;
+
+ public override void Reset()
+ {
+ base.Reset();
+
+ timeRangeBindable = new BindableDouble(2000)
+ {
+ MinValue = 200,
+ MaxValue = 4000,
+ };
+
+ SliderBar timeRange;
+ Add(timeRange = new BasicSliderBar
+ {
+ Size = new Vector2(200, 20),
+ SelectionColor = Color4.Pink,
+ KeyboardStep = 100
+ });
+
+ Add(timeRangeText = new OsuSpriteText
+ {
+ X = 210,
+ TextSize = 16,
+ });
+
+ timeRange.Current.BindTo(timeRangeBindable);
+ timeRangeBindable.ValueChanged += v => timeRangeText.Text = $"Visible Range: {v:#,#.#}";
+ timeRangeBindable.ValueChanged += v => bottomLabel.Text = $"t minus {v:#,#}";
+
+ Add(new Drawable[]
+ {
+ new Container
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ Size = new Vector2(100, 500),
+ Children = new Drawable[]
+ {
+ new Box
+ {
+ RelativeSizeAxes = Axes.Both,
+ Alpha = 0.25f
+ },
+ adjustmentCollection = new SpeedAdjustmentCollection(Axes.Y)
+ {
+ RelativeSizeAxes = Axes.Both,
+ VisibleTimeRange = timeRangeBindable,
+ Masking = true,
+ },
+ new OsuSpriteText
+ {
+ Text = "t minus 0",
+ Margin = new MarginPadding(2),
+ TextSize = 14,
+ Anchor = Anchor.TopRight,
+ },
+ bottomLabel = new OsuSpriteText
+ {
+ Text = "t minus x",
+ Margin = new MarginPadding(2),
+ TextSize = 14,
+ Anchor = Anchor.BottomRight,
+ Origin = Anchor.BottomLeft,
+ },
+ topTime = new OsuSpriteText
+ {
+ Margin = new MarginPadding(2),
+ TextSize = 14,
+ Anchor = Anchor.TopLeft,
+ Origin = Anchor.TopRight,
+ },
+ bottomTime = new OsuSpriteText
+ {
+ Margin = new MarginPadding(2),
+ TextSize = 14,
+ Anchor = Anchor.BottomLeft,
+ Origin = Anchor.BottomRight,
+ },
+ }
+ }
+ });
+
+ timeRangeBindable.TriggerChange();
+
+ adjustmentCollection.Add(new TestSpeedAdjustmentContainer(new MultiplierControlPoint()));
+
+ AddStep("Add hit object", () => adjustmentCollection.Add(new TestDrawableHitObject(new HitObject { StartTime = Time.Current + 2000 })));
+ }
+
+ protected override void Update()
+ {
+ base.Update();
+
+ topTime.Text = Time.Current.ToString("#,#");
+ bottomTime.Text = (Time.Current + timeRangeBindable.Value).ToString("#,#");
+ }
+
+ private class TestSpeedAdjustmentContainer : SpeedAdjustmentContainer
+ {
+ public override bool RemoveWhenNotAlive => false;
+
+ public TestSpeedAdjustmentContainer(MultiplierControlPoint controlPoint)
+ : base(controlPoint)
+ {
+ }
+
+ protected override DrawableTimingSection CreateTimingSection() => new TestDrawableTimingSection(ControlPoint);
+
+ private class TestDrawableTimingSection : DrawableTimingSection
+ {
+ private readonly MultiplierControlPoint controlPoint;
+
+ public TestDrawableTimingSection(MultiplierControlPoint controlPoint)
+ {
+ this.controlPoint = controlPoint;
+ }
+
+ protected override void Update()
+ {
+ base.Update();
+
+ Y = (float)(controlPoint.StartTime - Time.Current);
+ }
+ }
+ }
+
+ private class TestDrawableHitObject : DrawableHitObject, IScrollingHitObject
+ {
+ private readonly Box background;
+ private const float height = 14;
+
+ public BindableDouble LifetimeOffset { get; } = new BindableDouble();
+
+ public TestDrawableHitObject(HitObject hitObject)
+ : base(hitObject)
+ {
+ AutoSizeAxes = Axes.Y;
+ RelativeSizeAxes = Axes.X;
+ RelativePositionAxes = Axes.Y;
+
+ Y = (float)hitObject.StartTime;
+
+ Children = new Drawable[]
+ {
+ background = new Box
+ {
+ RelativeSizeAxes = Axes.X,
+ Height = height,
+ },
+ new Box
+ {
+ RelativeSizeAxes = Axes.X,
+ Colour = Color4.Cyan,
+ Height = 1,
+ },
+ new OsuSpriteText
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ Colour = Color4.Black,
+ TextSize = height,
+ Font = @"Exo2.0-BoldItalic",
+ Text = $"{hitObject.StartTime:#,#}"
+ }
+ };
+ }
+
+ protected override void LoadComplete()
+ {
+ base.LoadComplete();
+ FadeInFromZero(250, EasingTypes.OutQuint);
+ }
+
+ protected override void Update()
+ {
+ base.Update();
+ if (Time.Current >= HitObject.StartTime)
+ background.Colour = Color4.Red;
+ }
+ }
+ }
+}
diff --git a/osu.Desktop.VisualTests/Tests/TestCaseSkipButton.cs b/osu.Desktop.VisualTests/Tests/TestCaseSkipButton.cs
new file mode 100644
index 0000000000..fb5be719c1
--- /dev/null
+++ b/osu.Desktop.VisualTests/Tests/TestCaseSkipButton.cs
@@ -0,0 +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.Testing;
+using osu.Game.Screens.Play;
+
+namespace osu.Desktop.VisualTests.Tests
+{
+ internal class TestCaseSkipButton : TestCase
+ {
+ public override string Description => @"Skip skip skippediskip";
+
+ public override void Reset()
+ {
+ base.Reset();
+ Add(new SkipButton(Clock.CurrentTime + 5000));
+ }
+ }
+}
diff --git a/osu.Desktop.VisualTests/Tests/TestCaseSocial.cs b/osu.Desktop.VisualTests/Tests/TestCaseSocial.cs
new file mode 100644
index 0000000000..eb7df96355
--- /dev/null
+++ b/osu.Desktop.VisualTests/Tests/TestCaseSocial.cs
@@ -0,0 +1,85 @@
+// Copyright (c) 2007-2017 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using osu.Framework.Testing;
+using osu.Game.Overlays;
+using osu.Game.Users;
+
+namespace osu.Desktop.VisualTests.Tests
+{
+ public class TestCaseSocial : TestCase
+ {
+ public override string Description => @"social browser overlay";
+
+ public override void Reset()
+ {
+ base.Reset();
+
+ SocialOverlay s = new SocialOverlay
+ {
+ Users = new[]
+ {
+ new User
+ {
+ Username = @"flyte",
+ Id = 3103765,
+ Country = new Country { FlagName = @"JP" },
+ CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c1.jpg",
+ },
+ new User
+ {
+ Username = @"Cookiezi",
+ Id = 124493,
+ Country = new Country { FlagName = @"KR" },
+ CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c2.jpg",
+ },
+ new User
+ {
+ Username = @"Angelsim",
+ Id = 1777162,
+ Country = new Country { FlagName = @"KR" },
+ CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c3.jpg",
+ },
+ new User
+ {
+ Username = @"Rafis",
+ Id = 2558286,
+ Country = new Country { FlagName = @"PL" },
+ CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c4.jpg",
+ },
+ new User
+ {
+ Username = @"hvick225",
+ Id = 50265,
+ Country = new Country { FlagName = @"TW" },
+ CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c5.jpg",
+ },
+ new User
+ {
+ Username = @"peppy",
+ Id = 2,
+ Country = new Country { FlagName = @"AU" },
+ CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c6.jpg"
+ },
+ new User
+ {
+ Username = @"filsdelama",
+ Id = 2831793,
+ Country = new Country { FlagName = @"FR" },
+ CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c7.jpg"
+ },
+ new User
+ {
+ Username = @"_index",
+ Id = 652457,
+ Country = new Country { FlagName = @"RU" },
+ CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c8.jpg"
+ },
+ },
+ };
+ Add(s);
+
+ AddStep(@"toggle", s.ToggleVisibility);
+ }
+ }
+}
diff --git a/osu.Desktop.VisualTests/Tests/TestCaseTooltip.cs b/osu.Desktop.VisualTests/Tests/TestCaseTooltip.cs
deleted file mode 100644
index c536672314..0000000000
--- a/osu.Desktop.VisualTests/Tests/TestCaseTooltip.cs
+++ /dev/null
@@ -1,92 +0,0 @@
-// 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.Containers;
-using osu.Framework.Testing;
-using osu.Game.Graphics.Sprites;
-using osu.Game.Graphics.UserInterface;
-using osu.Framework.Configuration;
-using OpenTK;
-using osu.Game.Graphics;
-
-namespace osu.Desktop.VisualTests.Tests
-{
- internal class TestCaseTooltip : TestCase
- {
- public override string Description => "tests tooltips on various elements";
-
- public override void Reset()
- {
- base.Reset();
- OsuSliderBar slider;
- OsuSliderBar sliderDouble;
-
- const float width = 400;
-
- Children = new Drawable[]
- {
- new FillFlowContainer
- {
- RelativeSizeAxes = Axes.Both,
- Direction = FillDirection.Vertical,
- Spacing = new Vector2(0, 10),
- Children = new Drawable[]
- {
- new TooltipTextContainer("text with a tooltip"),
- new TooltipTextContainer("more text with another tooltip"),
- new TooltipTextbox
- {
- Text = "a textbox with a tooltip",
- Size = new Vector2(width,30),
- },
- slider = new OsuSliderBar
- {
- Width = width,
- },
- sliderDouble = new OsuSliderBar
- {
- Width = width,
- },
- },
- },
- };
-
- slider.Current.BindTo(new BindableInt(5)
- {
- MaxValue = 10,
- MinValue = 0
- });
-
- sliderDouble.Current.BindTo(new BindableDouble(0.5)
- {
- MaxValue = 1,
- MinValue = 0
- });
- }
-
- private class TooltipTextContainer : Container, IHasTooltip
- {
- private readonly OsuSpriteText text;
-
- public string TooltipText => text.Text;
-
- public TooltipTextContainer(string tooltipText)
- {
- AutoSizeAxes = Axes.Both;
- Children = new[]
- {
- text = new OsuSpriteText
- {
- Text = tooltipText,
- }
- };
- }
- }
-
- private class TooltipTextbox : OsuTextBox, IHasTooltip
- {
- public string TooltipText => Text;
- }
- }
-}
diff --git a/osu.Desktop.VisualTests/Tests/TestCaseTwoLayerButton.cs b/osu.Desktop.VisualTests/Tests/TestCaseTwoLayerButton.cs
index ba17cfc3d8..2decb4c469 100644
--- a/osu.Desktop.VisualTests/Tests/TestCaseTwoLayerButton.cs
+++ b/osu.Desktop.VisualTests/Tests/TestCaseTwoLayerButton.cs
@@ -3,20 +3,18 @@
using osu.Framework.Testing;
using osu.Game.Graphics.UserInterface;
-using osu.Game.Screens.Play;
namespace osu.Desktop.VisualTests.Tests
{
internal class TestCaseTwoLayerButton : TestCase
{
- public override string Description => @"Back and skip and what not";
+ public override string Description => @"Mostly back button";
public override void Reset()
{
base.Reset();
Add(new BackButton());
- Add(new SkipButton(Clock.CurrentTime + 5000));
}
}
}
diff --git a/osu.Desktop.VisualTests/osu.Desktop.VisualTests.csproj b/osu.Desktop.VisualTests/osu.Desktop.VisualTests.csproj
index 466c9336f0..b21a0d10b8 100644
--- a/osu.Desktop.VisualTests/osu.Desktop.VisualTests.csproj
+++ b/osu.Desktop.VisualTests/osu.Desktop.VisualTests.csproj
@@ -87,11 +87,13 @@
$(SolutionDir)\packages\Newtonsoft.Json.10.0.2\lib\net45\Newtonsoft.Json.dll
-
- $(SolutionDir)\packages\ppy.OpenTK.2.0.50727.1341\lib\net45\OpenTK.dll
+
+ $(SolutionDir)\packages\ppy.OpenTK.3.0\lib\net45\OpenTK.dll
+ True
-
- $(SolutionDir)\packages\SharpCompress.0.15.2\lib\net45\SharpCompress.dll
+
+ $(SolutionDir)\packages\SharpCompress.0.17.1\lib\net45\SharpCompress.dll
+ True
False
@@ -187,6 +189,7 @@
+
@@ -196,6 +199,7 @@
+
@@ -203,12 +207,13 @@
+
+
-
@@ -223,6 +228,7 @@
+
diff --git a/osu.Desktop.VisualTests/packages.config b/osu.Desktop.VisualTests/packages.config
index cad2ffff0d..2fb1023253 100644
--- a/osu.Desktop.VisualTests/packages.config
+++ b/osu.Desktop.VisualTests/packages.config
@@ -5,8 +5,8 @@ Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/maste
-->
-
-
+
+
diff --git a/osu.Desktop/Overlays/VersionManager.cs b/osu.Desktop/Overlays/VersionManager.cs
index 9532652bfe..b53c4ab3d4 100644
--- a/osu.Desktop/Overlays/VersionManager.cs
+++ b/osu.Desktop/Overlays/VersionManager.cs
@@ -10,6 +10,7 @@ using osu.Game.Graphics.Sprites;
using osu.Game.Overlays;
using osu.Game.Overlays.Notifications;
using Squirrel;
+using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures;
using osu.Game.Graphics;
diff --git a/osu.Desktop/osu.Desktop.csproj b/osu.Desktop/osu.Desktop.csproj
index 4f66dfd3eb..5ac888b515 100644
--- a/osu.Desktop/osu.Desktop.csproj
+++ b/osu.Desktop/osu.Desktop.csproj
@@ -121,18 +121,23 @@
- $(SolutionDir)\packages\squirrel.windows.1.5.2\lib\Net45\NuGet.Squirrel.dll
+ $(SolutionDir)\packages\squirrel.windows.1.7.5\lib\Net45\NuGet.Squirrel.dll
True
-
- $(SolutionDir)\packages\ppy.OpenTK.2.0.50727.1341\lib\net45\OpenTK.dll
+
+ $(SolutionDir)\packages\ppy.OpenTK.3.0\lib\net45\OpenTK.dll
+ True
+
+
+ $(SolutionDir)\packages\SharpCompress.0.17.1\lib\net45\SharpCompress.dll
+ True
$(SolutionDir)\packages\Splat.2.0.0\lib\Net45\Splat.dll
True
-
- $(SolutionDir)\packages\squirrel.windows.1.5.2\lib\Net45\Squirrel.dll
+
+ $(SolutionDir)\packages\squirrel.windows.1.7.5\lib\Net45\Squirrel.dll
True
diff --git a/osu.Desktop/packages.config b/osu.Desktop/packages.config
index 60e8182c82..3ad2106d2b 100644
--- a/osu.Desktop/packages.config
+++ b/osu.Desktop/packages.config
@@ -7,7 +7,8 @@ Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/maste
-
+
+
-
+
\ No newline at end of file
diff --git a/osu.Game.Rulesets.Catch/CatchRuleset.cs b/osu.Game.Rulesets.Catch/CatchRuleset.cs
index 53449fd5f5..df212f7df7 100644
--- a/osu.Game.Rulesets.Catch/CatchRuleset.cs
+++ b/osu.Game.Rulesets.Catch/CatchRuleset.cs
@@ -28,7 +28,14 @@ namespace osu.Game.Rulesets.Catch
{
new CatchModEasy(),
new CatchModNoFail(),
- new CatchModHalfTime(),
+ new MultiMod
+ {
+ Mods = new Mod[]
+ {
+ new CatchModHalfTime(),
+ new CatchModDaycore(),
+ },
+ },
};
case ModType.DifficultyIncrease:
diff --git a/osu.Game.Rulesets.Catch/Mods/CatchMod.cs b/osu.Game.Rulesets.Catch/Mods/CatchMod.cs
index 64a0c51b72..b0880d7e1d 100644
--- a/osu.Game.Rulesets.Catch/Mods/CatchMod.cs
+++ b/osu.Game.Rulesets.Catch/Mods/CatchMod.cs
@@ -32,6 +32,11 @@ namespace osu.Game.Rulesets.Catch.Mods
}
+ public class CatchModDaycore : ModDaycore
+ {
+ public override double ScoreMultiplier => 0.5;
+ }
+
public class CatchModDoubleTime : ModDoubleTime
{
public override double ScoreMultiplier => 1.06;
diff --git a/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs b/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs
index 4b1e6e93cd..8be52150fc 100644
--- a/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs
+++ b/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs
@@ -2,7 +2,7 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Graphics;
-using osu.Framework.Graphics.Sprites;
+using osu.Framework.Graphics.Shapes;
using osu.Game.Rulesets.Catch.Objects;
using osu.Game.Rulesets.UI;
using OpenTK;
diff --git a/osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj b/osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj
index 281d2b5a79..83996df41a 100644
--- a/osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj
+++ b/osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj
@@ -33,8 +33,9 @@
false
-
- $(SolutionDir)\packages\ppy.OpenTK.2.0.50727.1341\lib\net45\OpenTK.dll
+
+ $(SolutionDir)\packages\ppy.OpenTK.3.0\lib\net45\OpenTK.dll
+ True
diff --git a/osu.Game.Rulesets.Catch/packages.config b/osu.Game.Rulesets.Catch/packages.config
index 634d0b51f6..fa6edb9c8f 100644
--- a/osu.Game.Rulesets.Catch/packages.config
+++ b/osu.Game.Rulesets.Catch/packages.config
@@ -5,5 +5,5 @@ Copyright (c) 2007-2017 ppy Pty Ltd .
Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-->
-
+
\ No newline at end of file
diff --git a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs
index 2d1f75e196..7e9615a703 100644
--- a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs
+++ b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs
@@ -448,7 +448,6 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
return curveData.RepeatSamples[index];
}
-
///
/// Constructs and adds a note to a pattern.
///
@@ -480,7 +479,6 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
Tail = { Samples = sampleInfoListAt(endTime) }
};
-
newObject = holdNote;
}
diff --git a/osu.Game.Rulesets.Mania/ManiaRuleset.cs b/osu.Game.Rulesets.Mania/ManiaRuleset.cs
index 30d1846746..8be3870ebe 100644
--- a/osu.Game.Rulesets.Mania/ManiaRuleset.cs
+++ b/osu.Game.Rulesets.Mania/ManiaRuleset.cs
@@ -27,7 +27,14 @@ namespace osu.Game.Rulesets.Mania
{
new ManiaModEasy(),
new ManiaModNoFail(),
- new ManiaModHalfTime(),
+ new MultiMod
+ {
+ Mods = new Mod[]
+ {
+ new ManiaModHalfTime(),
+ new ManiaModDaycore(),
+ },
+ },
};
case ModType.DifficultyIncrease:
@@ -89,6 +96,7 @@ namespace osu.Game.Rulesets.Mania
new ModCinema(),
},
},
+ new ManiaModGravity()
};
default:
diff --git a/osu.Game.Rulesets.Mania/MathUtils/FastRandom.cs b/osu.Game.Rulesets.Mania/MathUtils/FastRandom.cs
index ff3fd8e4b7..f31873d1c8 100644
--- a/osu.Game.Rulesets.Mania/MathUtils/FastRandom.cs
+++ b/osu.Game.Rulesets.Mania/MathUtils/FastRandom.cs
@@ -87,6 +87,5 @@ namespace osu.Game.Rulesets.Mania.MathUtils
bitIndex++;
return ((bitBuffer >>= 1) & 1) == 1;
}
-
}
}
diff --git a/osu.Game.Rulesets.Mania/Mods/IGenerateSpeedAdjustments.cs b/osu.Game.Rulesets.Mania/Mods/IGenerateSpeedAdjustments.cs
new file mode 100644
index 0000000000..f179aa2ff8
--- /dev/null
+++ b/osu.Game.Rulesets.Mania/Mods/IGenerateSpeedAdjustments.cs
@@ -0,0 +1,23 @@
+// Copyright (c) 2007-2017 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using System.Collections.Generic;
+using osu.Game.Rulesets.Mania.UI;
+using osu.Game.Rulesets.Timing;
+
+namespace osu.Game.Rulesets.Mania.Mods
+{
+ ///
+ /// A type of mod which generates speed adjustments that scroll the hit objects and bar lines.
+ ///
+ internal interface IGenerateSpeedAdjustments
+ {
+ ///
+ /// Applies this mod to a hit renderer.
+ ///
+ /// The hit renderer to apply to.
+ /// The per-column list of speed adjustments for hit objects.
+ /// The list of speed adjustments for bar lines.
+ void ApplyToHitRenderer(ManiaHitRenderer hitRenderer, ref List[] hitObjectTimingChanges, ref List barlineTimingChanges);
+ }
+}
diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaMod.cs b/osu.Game.Rulesets.Mania/Mods/ManiaMod.cs
index b402d3a010..f44ad6fd60 100644
--- a/osu.Game.Rulesets.Mania/Mods/ManiaMod.cs
+++ b/osu.Game.Rulesets.Mania/Mods/ManiaMod.cs
@@ -34,6 +34,11 @@ namespace osu.Game.Rulesets.Mania.Mods
}
+ public class ManiaModDaycore : ModDaycore
+ {
+ public override double ScoreMultiplier => 0.3;
+ }
+
public class ManiaModDoubleTime : ModDoubleTime
{
public override double ScoreMultiplier => 1.0;
diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModGravity.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModGravity.cs
new file mode 100644
index 0000000000..1ba8ac4710
--- /dev/null
+++ b/osu.Game.Rulesets.Mania/Mods/ManiaModGravity.cs
@@ -0,0 +1,46 @@
+// Copyright (c) 2007-2017 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using System.Collections.Generic;
+using osu.Game.Rulesets.Mania.Objects;
+using osu.Game.Rulesets.Mania.UI;
+using osu.Game.Rulesets.Mods;
+using osu.Game.Graphics;
+using osu.Game.Rulesets.Mania.Timing;
+using osu.Game.Rulesets.Timing;
+using osu.Game.Rulesets.Mania.Objects.Drawables;
+
+namespace osu.Game.Rulesets.Mania.Mods
+{
+ public class ManiaModGravity : Mod, IGenerateSpeedAdjustments
+ {
+ public override string Name => "Gravity";
+
+ public override double ScoreMultiplier => 0;
+
+ public override FontAwesome Icon => FontAwesome.fa_sort_desc;
+
+ public void ApplyToHitRenderer(ManiaHitRenderer hitRenderer, ref List[] hitObjectTimingChanges, ref List barlineTimingChanges)
+ {
+ // We have to generate one speed adjustment per hit object for gravity
+ foreach (ManiaHitObject obj in hitRenderer.Objects)
+ {
+ MultiplierControlPoint controlPoint = hitRenderer.CreateControlPointAt(obj.StartTime);
+ // Beat length has too large of an effect for gravity, so we'll force it to a constant value for now
+ controlPoint.TimingPoint.BeatLength = 1000;
+
+ hitObjectTimingChanges[obj.Column].Add(new ManiaSpeedAdjustmentContainer(controlPoint, ScrollingAlgorithm.Gravity));
+ }
+
+ // Like with hit objects, we need to generate one speed adjustment per bar line
+ foreach (DrawableBarLine barLine in hitRenderer.BarLines)
+ {
+ var controlPoint = hitRenderer.CreateControlPointAt(barLine.HitObject.StartTime);
+ // Beat length has too large of an effect for gravity, so we'll force it to a constant value for now
+ controlPoint.TimingPoint.BeatLength = 1000;
+
+ barlineTimingChanges.Add(new ManiaSpeedAdjustmentContainer(controlPoint, ScrollingAlgorithm.Gravity));
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableBarLine.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableBarLine.cs
index 0b4d8b2d4e..fc5ea4e116 100644
--- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableBarLine.cs
+++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableBarLine.cs
@@ -3,7 +3,7 @@
using OpenTK;
using osu.Framework.Graphics;
-using osu.Framework.Graphics.Sprites;
+using osu.Framework.Graphics.Shapes;
using osu.Game.Rulesets.Objects.Drawables;
namespace osu.Game.Rulesets.Mania.Objects.Drawables
diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs
index 5d7f3314cd..e52fb1362f 100644
--- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs
+++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs
@@ -55,7 +55,8 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
tickContainer = new Container
{
RelativeSizeAxes = Axes.Both,
- RelativeCoordinateSpace = new Vector2(1, (float)HitObject.Duration)
+ RelativeChildOffset = new Vector2(0, (float)HitObject.StartTime),
+ RelativeChildSize = new Vector2(1, (float)HitObject.Duration)
},
head = new DrawableHeadNote(this, key)
{
@@ -76,9 +77,6 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
HoldStartTime = () => holdStartTime
};
- // To make the ticks relative to ourselves we need to offset them backwards
- drawableTick.Y -= (float)HitObject.StartTime;
-
tickContainer.Add(drawableTick);
AddNested(drawableTick);
}
diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNoteTick.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNoteTick.cs
index 9ecc77d3fc..39abbb6b3d 100644
--- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNoteTick.cs
+++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNoteTick.cs
@@ -7,9 +7,9 @@ using OpenTK.Graphics;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
-using osu.Framework.Graphics.Sprites;
using osu.Game.Rulesets.Mania.Judgements;
using osu.Game.Rulesets.Objects.Drawables;
+using osu.Framework.Graphics.Shapes;
namespace osu.Game.Rulesets.Mania.Objects.Drawables
{
@@ -70,7 +70,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
{
base.AccentColour = value;
- glowContainer.EdgeEffect = new EdgeEffect
+ glowContainer.EdgeEffect = new EdgeEffectParameters
{
Type = EdgeEffectType.Glow,
Radius = 2f,
diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableManiaHitObject.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableManiaHitObject.cs
index 4e276fddb7..cb1352fc4a 100644
--- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableManiaHitObject.cs
+++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableManiaHitObject.cs
@@ -10,7 +10,7 @@ using osu.Game.Rulesets.Objects.Drawables;
namespace osu.Game.Rulesets.Mania.Objects.Drawables
{
- public abstract class DrawableManiaHitObject : DrawableHitObject
+ public abstract class DrawableManiaHitObject : DrawableScrollingHitObject
where TObject : ManiaHitObject
{
///
diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableNote.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableNote.cs
index 658d409bb8..9322fed3eb 100644
--- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableNote.cs
+++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableNote.cs
@@ -23,7 +23,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
public DrawableNote(Note hitObject, Bindable key = null)
: base(hitObject, key)
{
- RelativeSizeAxes = Axes.Both;
+ RelativeSizeAxes = Axes.X;
Height = 100;
Add(headPiece = new NotePiece
diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/BodyPiece.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/BodyPiece.cs
index c10aa9994b..04e8df4ae2 100644
--- a/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/BodyPiece.cs
+++ b/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/BodyPiece.cs
@@ -4,7 +4,7 @@
using OpenTK.Graphics;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
-using osu.Framework.Graphics.Sprites;
+using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics;
namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces
diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/NotePiece.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/NotePiece.cs
index e01199e929..3df085c346 100644
--- a/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/NotePiece.cs
+++ b/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/NotePiece.cs
@@ -5,7 +5,7 @@ using OpenTK.Graphics;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
-using osu.Framework.Graphics.Sprites;
+using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics;
namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces
diff --git a/osu.Game.Rulesets.Mania/Timing/BasicScrollingDrawableTimingSection.cs b/osu.Game.Rulesets.Mania/Timing/BasicScrollingDrawableTimingSection.cs
new file mode 100644
index 0000000000..e485581d9f
--- /dev/null
+++ b/osu.Game.Rulesets.Mania/Timing/BasicScrollingDrawableTimingSection.cs
@@ -0,0 +1,27 @@
+// Copyright (c) 2007-2017 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using osu.Game.Rulesets.Timing;
+
+namespace osu.Game.Rulesets.Mania.Timing
+{
+ ///
+ /// A which scrolls relative to the control point start time.
+ ///
+ internal class BasicScrollingDrawableTimingSection : DrawableTimingSection
+ {
+ private readonly MultiplierControlPoint controlPoint;
+
+ public BasicScrollingDrawableTimingSection(MultiplierControlPoint controlPoint)
+ {
+ this.controlPoint = controlPoint;
+ }
+
+ protected override void Update()
+ {
+ base.Update();
+
+ Y = (float)(controlPoint.StartTime - Time.Current);
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Mania/Timing/ControlPointContainer.cs b/osu.Game.Rulesets.Mania/Timing/ControlPointContainer.cs
deleted file mode 100644
index 0a8bc2d44a..0000000000
--- a/osu.Game.Rulesets.Mania/Timing/ControlPointContainer.cs
+++ /dev/null
@@ -1,156 +0,0 @@
-// Copyright (c) 2007-2017 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using osu.Framework.Graphics;
-using osu.Framework.Graphics.Containers;
-using OpenTK;
-using osu.Game.Beatmaps.ControlPoints;
-using osu.Game.Rulesets.Objects;
-
-namespace osu.Game.Rulesets.Mania.Timing
-{
- ///
- /// A container in which added drawables are put into a relative coordinate space spanned by a length of time.
- ///
- /// This container contains s which scroll inside this container.
- /// Drawables added to this container are moved inside the relevant ,
- /// and as such, will scroll along with the s.
- ///
- ///
- public class ControlPointContainer : Container
- {
- ///
- /// The amount of time which this container spans.
- ///
- public double TimeSpan { get; set; }
-
- private readonly List drawableControlPoints;
-
- public ControlPointContainer(IEnumerable timingChanges)
- {
- drawableControlPoints = timingChanges.Select(t => new DrawableControlPoint(t)).ToList();
- Children = drawableControlPoints;
- }
-
- ///
- /// Adds a drawable to this container. Note that the drawable added must have its Y-position be
- /// an absolute unit of time that is _not_ relative to .
- ///
- /// The drawable to add.
- public override void Add(Drawable drawable)
- {
- // Always add timing sections to ourselves
- if (drawable is DrawableControlPoint)
- {
- base.Add(drawable);
- return;
- }
-
- var controlPoint = drawableControlPoints.LastOrDefault(t => t.CanContain(drawable)) ?? drawableControlPoints.FirstOrDefault();
-
- if (controlPoint == null)
- throw new InvalidOperationException("Could not find suitable timing section to add object to.");
-
- controlPoint.Add(drawable);
- }
-
- ///
- /// A container that contains drawables within the time span of a timing section.
- ///
- /// The content of this container will scroll relative to the current time.
- ///
- ///
- private class DrawableControlPoint : Container
- {
- private readonly TimingChange timingChange;
-
- protected override Container Content => content;
- private readonly Container content;
-
- ///
- /// Creates a drawable control point. The height of this container will be proportional
- /// to the beat length of the control point it is initialized with such that, e.g. a beat length
- /// of 500ms results in this container being twice as high as its parent, which further means that
- /// the content container will scroll at twice the normal rate.
- ///
- /// The control point to create the drawable control point for.
- public DrawableControlPoint(TimingChange timingChange)
- {
- this.timingChange = timingChange;
-
- RelativeSizeAxes = Axes.Both;
-
- AddInternal(content = new AutoTimeRelativeContainer
- {
- RelativeSizeAxes = Axes.Both,
- RelativePositionAxes = Axes.Both,
- Y = (float)timingChange.Time
- });
- }
-
- protected override void Update()
- {
- var parent = (ControlPointContainer)Parent;
-
- // Adjust our height to account for the speed changes
- Height = (float)(1000 / timingChange.BeatLength / timingChange.SpeedMultiplier);
- RelativeCoordinateSpace = new Vector2(1, (float)parent.TimeSpan);
-
- // Scroll the content
- content.Y = (float)(timingChange.Time - Time.Current);
- }
-
- public override void Add(Drawable drawable)
- {
- // The previously relatively-positioned drawable will now become relative to content, but since the drawable has no knowledge of content,
- // we need to offset it back by content's position position so that it becomes correctly relatively-positioned to content
- // This can be removed if hit objects were stored such that either their StartTime or their "beat offset" was relative to the timing change
- // they belonged to, but this requires a radical change to the beatmap format which we're not ready to do just yet
- drawable.Y -= (float)timingChange.Time;
-
- base.Add(drawable);
- }
-
- ///
- /// Whether this control point can contain a drawable. This control point can contain a drawable if the drawable is positioned "after" this control point.
- ///
- /// The drawable to check.
- public bool CanContain(Drawable drawable) => content.Y <= drawable.Y;
-
- ///
- /// A container which always keeps its height and relative coordinate space "auto-sized" to its children.
- ///
- /// This is used in the case where children are relatively positioned/sized to time values (e.g. notes/bar lines) to keep
- /// such children wrapped inside a container, otherwise they would disappear due to container flattening.
- ///
- ///
- private class AutoTimeRelativeContainer : Container
- {
- protected override IComparer DepthComparer => new HitObjectReverseStartTimeComparer();
-
- public override void InvalidateFromChild(Invalidation invalidation)
- {
- // We only want to re-compute our size when a child's size or position has changed
- if ((invalidation & Invalidation.Geometry) == 0)
- {
- base.InvalidateFromChild(invalidation);
- return;
- }
-
- if (!Children.Any())
- return;
-
- float height = Children.Select(child => child.Y + child.Height).Max();
-
- Height = height;
- RelativeCoordinateSpace = new Vector2(1, height);
-
- base.InvalidateFromChild(invalidation);
- }
- }
- }
- }
-}
\ No newline at end of file
diff --git a/osu.Game.Rulesets.Mania/Timing/GravityScrollingDrawableTimingSection.cs b/osu.Game.Rulesets.Mania/Timing/GravityScrollingDrawableTimingSection.cs
new file mode 100644
index 0000000000..730daa9ffd
--- /dev/null
+++ b/osu.Game.Rulesets.Mania/Timing/GravityScrollingDrawableTimingSection.cs
@@ -0,0 +1,60 @@
+// Copyright (c) 2007-2017 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using osu.Game.Rulesets.Timing;
+
+namespace osu.Game.Rulesets.Mania.Timing
+{
+ ///
+ /// A that emulates a form of gravity where hit objects speed up over time.
+ ///
+ internal class GravityScrollingDrawableTimingSection : DrawableTimingSection
+ {
+ private readonly MultiplierControlPoint controlPoint;
+
+ public GravityScrollingDrawableTimingSection(MultiplierControlPoint controlPoint)
+ {
+ this.controlPoint = controlPoint;
+ }
+
+ protected override void UpdateAfterChildren()
+ {
+ base.UpdateAfterChildren();
+
+ // The gravity-adjusted start position
+ float startPos = (float)computeGravityTime(controlPoint.StartTime);
+ // The gravity-adjusted end position
+ float endPos = (float)computeGravityTime(controlPoint.StartTime + RelativeChildSize.Y);
+
+ Y = startPos;
+ Height = endPos - startPos;
+ }
+
+ ///
+ /// Applies gravity to a time value based on the current time.
+ ///
+ /// The time value gravity should be applied to.
+ /// The time after gravity is applied to .
+ private double computeGravityTime(double time)
+ {
+ double relativeTime = relativeTimeAt(time);
+
+ // The sign of the relative time, this is used to apply backwards acceleration leading into startTime
+ double sign = relativeTime < 0 ? -1 : 1;
+
+ return VisibleTimeRange - acceleration * relativeTime * relativeTime * sign;
+ }
+
+ ///
+ /// The acceleration due to "gravity" of the content of this container.
+ ///
+ private double acceleration => 1 / VisibleTimeRange;
+
+ ///
+ /// Computes the current time relative to , accounting for .
+ ///
+ /// The non-offset time.
+ /// The current time relative to - .
+ private double relativeTimeAt(double time) => Time.Current - time + VisibleTimeRange;
+ }
+}
diff --git a/osu.Game.Rulesets.Mania/Timing/ManiaSpeedAdjustmentContainer.cs b/osu.Game.Rulesets.Mania/Timing/ManiaSpeedAdjustmentContainer.cs
new file mode 100644
index 0000000000..ed22264d74
--- /dev/null
+++ b/osu.Game.Rulesets.Mania/Timing/ManiaSpeedAdjustmentContainer.cs
@@ -0,0 +1,30 @@
+// Copyright (c) 2007-2017 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using osu.Game.Rulesets.Timing;
+
+namespace osu.Game.Rulesets.Mania.Timing
+{
+ public class ManiaSpeedAdjustmentContainer : SpeedAdjustmentContainer
+ {
+ private readonly ScrollingAlgorithm scrollingAlgorithm;
+
+ public ManiaSpeedAdjustmentContainer(MultiplierControlPoint timingSection, ScrollingAlgorithm scrollingAlgorithm)
+ : base(timingSection)
+ {
+ this.scrollingAlgorithm = scrollingAlgorithm;
+ }
+
+ protected override DrawableTimingSection CreateTimingSection()
+ {
+ switch (scrollingAlgorithm)
+ {
+ default:
+ case ScrollingAlgorithm.Basic:
+ return new BasicScrollingDrawableTimingSection(ControlPoint);
+ case ScrollingAlgorithm.Gravity:
+ return new GravityScrollingDrawableTimingSection(ControlPoint);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/osu.Game.Rulesets.Mania/Timing/ScrollingAlgorithm.cs b/osu.Game.Rulesets.Mania/Timing/ScrollingAlgorithm.cs
new file mode 100644
index 0000000000..72e096f5aa
--- /dev/null
+++ b/osu.Game.Rulesets.Mania/Timing/ScrollingAlgorithm.cs
@@ -0,0 +1,17 @@
+// Copyright (c) 2007-2017 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+namespace osu.Game.Rulesets.Mania.Timing
+{
+ public enum ScrollingAlgorithm
+ {
+ ///
+ /// Basic scrolling algorithm based on the timing section time. This is the default algorithm.
+ ///
+ Basic,
+ ///
+ /// Emulating a form of gravity where hit objects speed up over time.
+ ///
+ Gravity
+ }
+}
diff --git a/osu.Game.Rulesets.Mania/Timing/TimingChange.cs b/osu.Game.Rulesets.Mania/Timing/TimingChange.cs
deleted file mode 100644
index 9153ba6991..0000000000
--- a/osu.Game.Rulesets.Mania/Timing/TimingChange.cs
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright (c) 2007-2017 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-
-namespace osu.Game.Rulesets.Mania.Timing
-{
- public class TimingChange
- {
- ///
- /// The time at which this timing change happened.
- ///
- public double Time;
-
- ///
- /// The beat length.
- ///
- public double BeatLength = 500;
-
- ///
- /// The speed multiplier.
- ///
- public double SpeedMultiplier = 1;
- }
-}
\ No newline at end of file
diff --git a/osu.Game.Rulesets.Mania/UI/Column.cs b/osu.Game.Rulesets.Mania/UI/Column.cs
index 6dfd5000d4..12b6f61a12 100644
--- a/osu.Game.Rulesets.Mania/UI/Column.cs
+++ b/osu.Game.Rulesets.Mania/UI/Column.cs
@@ -7,17 +7,14 @@ using OpenTK.Input;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
-using osu.Framework.Graphics.Sprites;
+using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Colour;
using osu.Framework.Input;
using osu.Game.Graphics;
-using osu.Game.Rulesets.Mania.Timing;
-using System.Collections.Generic;
using osu.Game.Rulesets.Objects.Drawables;
-using osu.Game.Rulesets.Mania.Objects;
-using osu.Game.Rulesets.Mania.Judgements;
using System;
using osu.Framework.Configuration;
+using osu.Game.Rulesets.Timing;
namespace osu.Game.Rulesets.Mania.UI
{
@@ -33,6 +30,13 @@ namespace osu.Game.Rulesets.Mania.UI
private const float column_width = 45;
private const float special_column_width = 70;
+ private readonly BindableDouble visibleTimeRange = new BindableDouble();
+ public BindableDouble VisibleTimeRange
+ {
+ get { return visibleTimeRange; }
+ set { visibleTimeRange.BindTo(value); }
+ }
+
///
/// The key that will trigger input actions for this column and hit objects contained inside it.
///
@@ -42,9 +46,9 @@ namespace osu.Game.Rulesets.Mania.UI
private readonly Container hitTargetBar;
private readonly Container keyIcon;
- public readonly ControlPointContainer ControlPointContainer;
+ private readonly SpeedAdjustmentCollection speedAdjustments;
- public Column(IEnumerable timingChanges)
+ public Column()
{
RelativeSizeAxes = Axes.Y;
Width = column_width;
@@ -61,7 +65,7 @@ namespace osu.Game.Rulesets.Mania.UI
{
Name = "Hit target + hit objects",
RelativeSizeAxes = Axes.Both,
- Padding = new MarginPadding { Top = ManiaPlayfield.HIT_TARGET_POSITION},
+ Padding = new MarginPadding { Top = ManiaPlayfield.HIT_TARGET_POSITION },
Children = new Drawable[]
{
new Container
@@ -93,10 +97,11 @@ namespace osu.Game.Rulesets.Mania.UI
}
}
},
- ControlPointContainer = new ControlPointContainer(timingChanges)
+ speedAdjustments = new SpeedAdjustmentCollection(Axes.Y)
{
Name = "Hit objects",
RelativeSizeAxes = Axes.Both,
+ VisibleTimeRange = VisibleTimeRange
},
// For column lighting, we need to capture input events before the notes
new InputTarget
@@ -171,14 +176,14 @@ namespace osu.Game.Rulesets.Mania.UI
background.Colour = accentColour;
- hitTargetBar.EdgeEffect = new EdgeEffect
+ hitTargetBar.EdgeEffect = new EdgeEffectParameters
{
Type = EdgeEffectType.Glow,
Radius = 5,
Colour = accentColour.Opacity(0.5f),
};
- keyIcon.EdgeEffect = new EdgeEffect
+ keyIcon.EdgeEffect = new EdgeEffectParameters
{
Type = EdgeEffectType.Glow,
Radius = 5,
@@ -187,10 +192,11 @@ namespace osu.Game.Rulesets.Mania.UI
}
}
- public void Add(DrawableHitObject hitObject)
+ public void Add(SpeedAdjustmentContainer speedAdjustment) => speedAdjustments.Add(speedAdjustment);
+ public void Add(DrawableHitObject hitObject)
{
hitObject.AccentColour = AccentColour;
- ControlPointContainer.Add(hitObject);
+ speedAdjustments.Add(hitObject);
}
private bool onKeyDown(InputState state, KeyDownEventArgs args)
diff --git a/osu.Game.Rulesets.Mania/UI/ManiaHitRenderer.cs b/osu.Game.Rulesets.Mania/UI/ManiaHitRenderer.cs
index 57477147d5..dcb2a29556 100644
--- a/osu.Game.Rulesets.Mania/UI/ManiaHitRenderer.cs
+++ b/osu.Game.Rulesets.Mania/UI/ManiaHitRenderer.cs
@@ -8,6 +8,7 @@ using OpenTK;
using OpenTK.Input;
using osu.Framework.Allocation;
using osu.Framework.Configuration;
+using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Graphics;
using osu.Framework.Lists;
using osu.Framework.MathUtils;
@@ -16,6 +17,7 @@ using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Rulesets.Beatmaps;
using osu.Game.Rulesets.Mania.Beatmaps;
using osu.Game.Rulesets.Mania.Judgements;
+using osu.Game.Rulesets.Mania.Mods;
using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Mania.Objects.Drawables;
using osu.Game.Rulesets.Mania.Scoring;
@@ -23,78 +25,44 @@ using osu.Game.Rulesets.Mania.Timing;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Objects.Types;
using osu.Game.Rulesets.Scoring;
+using osu.Game.Rulesets.Timing;
using osu.Game.Rulesets.UI;
namespace osu.Game.Rulesets.Mania.UI
{
- public class ManiaHitRenderer : HitRenderer
+ public class ManiaHitRenderer : SpeedAdjustedHitRenderer
{
- public int? Columns;
+ ///
+ /// Preferred column count. This will only have an effect during the initialization of the play field.
+ ///
+ public int PreferredColumns;
+
+ public IEnumerable BarLines;
+
+ ///
+ /// Per-column timing changes.
+ ///
+ private readonly List[] hitObjectSpeedAdjustments;
+
+ ///
+ /// Bar line timing changes.
+ ///
+ private readonly List barLineSpeedAdjustments = new List();
public ManiaHitRenderer(WorkingBeatmap beatmap, bool isForCurrentRuleset)
: base(beatmap, isForCurrentRuleset)
{
- }
-
- protected override Playfield CreatePlayfield()
- {
- double lastSpeedMultiplier = 1;
- double lastBeatLength = 500;
-
- // Merge timing + difficulty points
- var allPoints = new SortedList(Comparer.Default);
- allPoints.AddRange(Beatmap.ControlPointInfo.TimingPoints);
- allPoints.AddRange(Beatmap.ControlPointInfo.DifficultyPoints);
-
- // Generate the timing points, making non-timing changes use the previous timing change
- var timingChanges = allPoints.Select(c =>
- {
- var timingPoint = c as TimingControlPoint;
- var difficultyPoint = c as DifficultyControlPoint;
-
- if (timingPoint != null)
- lastBeatLength = timingPoint.BeatLength;
-
- if (difficultyPoint != null)
- lastSpeedMultiplier = difficultyPoint.SpeedMultiplier;
-
- return new TimingChange
- {
- Time = c.Time,
- BeatLength = lastBeatLength,
- SpeedMultiplier = lastSpeedMultiplier
- };
- });
-
- double lastObjectTime = (Objects.LastOrDefault() as IHasEndTime)?.EndTime ?? Objects.LastOrDefault()?.StartTime ?? double.MaxValue;
-
- // Perform some post processing of the timing changes
- timingChanges = timingChanges
- // Collapse sections after the last hit object
- .Where(s => s.Time <= lastObjectTime)
- // Collapse sections with the same start time
- .GroupBy(s => s.Time).Select(g => g.Last()).OrderBy(s => s.Time)
- // Collapse sections with the same beat length
- .GroupBy(s => s.BeatLength * s.SpeedMultiplier).Select(g => g.First())
- .ToList();
-
- return new ManiaPlayfield(Columns ?? (int)Math.Round(Beatmap.BeatmapInfo.Difficulty.CircleSize), timingChanges)
- {
- Anchor = Anchor.Centre,
- Origin = Anchor.Centre,
- // Invert by default for now (should be moved to config/skin later)
- Scale = new Vector2(1, -1)
- };
- }
-
- [BackgroundDependencyLoader]
- private void load()
- {
- var maniaPlayfield = (ManiaPlayfield)Playfield;
+ // Generate the speed adjustment container lists
+ hitObjectSpeedAdjustments = new List[PreferredColumns];
+ for (int i = 0; i < PreferredColumns; i++)
+ hitObjectSpeedAdjustments[i] = new List();
+ // Generate the bar lines
double lastObjectTime = (Objects.LastOrDefault() as IHasEndTime)?.EndTime ?? Objects.LastOrDefault()?.StartTime ?? double.MaxValue;
SortedList timingPoints = Beatmap.ControlPointInfo.TimingPoints;
+ var barLines = new List();
+
for (int i = 0; i < timingPoints.Count; i++)
{
TimingControlPoint point = timingPoints[i];
@@ -105,7 +73,7 @@ namespace osu.Game.Rulesets.Mania.UI
int index = 0;
for (double t = timingPoints[i].Time; Precision.DefinitelyBigger(endTime, t); t += point.BeatLength, index++)
{
- maniaPlayfield.Add(new DrawableBarLine(new BarLine
+ barLines.Add(new DrawableBarLine(new BarLine
{
StartTime = t,
ControlPoint = point,
@@ -113,17 +81,78 @@ namespace osu.Game.Rulesets.Mania.UI
}));
}
}
+
+ BarLines = barLines;
+
+ // Generate speed adjustments from mods first
+ bool useDefaultSpeedAdjustments = true;
+
+ if (Mods != null)
+ {
+ foreach (var speedAdjustmentMod in Mods.OfType())
+ {
+ useDefaultSpeedAdjustments = false;
+ speedAdjustmentMod.ApplyToHitRenderer(this, ref hitObjectSpeedAdjustments, ref barLineSpeedAdjustments);
+ }
+ }
+
+ // Generate the default speed adjustments
+ if (useDefaultSpeedAdjustments)
+ generateDefaultSpeedAdjustments();
}
+ [BackgroundDependencyLoader]
+ private void load()
+ {
+ var maniaPlayfield = (ManiaPlayfield)Playfield;
+
+ BarLines.ForEach(maniaPlayfield.Add);
+ }
+
+ protected override void ApplyBeatmap()
+ {
+ base.ApplyBeatmap();
+
+ PreferredColumns = (int)Math.Round(Beatmap.BeatmapInfo.Difficulty.CircleSize);
+ }
+
+ protected override void ApplySpeedAdjustments()
+ {
+ var maniaPlayfield = (ManiaPlayfield)Playfield;
+
+ for (int i = 0; i < PreferredColumns; i++)
+ foreach (var change in hitObjectSpeedAdjustments[i])
+ maniaPlayfield.Columns.ElementAt(i).Add(change);
+
+ foreach (var change in barLineSpeedAdjustments)
+ maniaPlayfield.Add(change);
+ }
+
+ private void generateDefaultSpeedAdjustments()
+ {
+ DefaultControlPoints.ForEach(c =>
+ {
+ foreach (List t in hitObjectSpeedAdjustments)
+ t.Add(new ManiaSpeedAdjustmentContainer(c, ScrollingAlgorithm.Basic));
+ barLineSpeedAdjustments.Add(new ManiaSpeedAdjustmentContainer(c, ScrollingAlgorithm.Basic));
+ });
+ }
+
+ protected sealed override Playfield CreatePlayfield() => new ManiaPlayfield(PreferredColumns)
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ // Invert by default for now (should be moved to config/skin later)
+ Scale = new Vector2(1, -1)
+ };
+
public override ScoreProcessor CreateScoreProcessor() => new ManiaScoreProcessor(this);
protected override BeatmapConverter CreateBeatmapConverter() => new ManiaBeatmapConverter();
protected override DrawableHitObject GetVisualRepresentation(ManiaHitObject h)
{
- var maniaPlayfield = Playfield as ManiaPlayfield;
- if (maniaPlayfield == null)
- return null;
+ var maniaPlayfield = (ManiaPlayfield)Playfield;
Bindable key = maniaPlayfield.Columns.ElementAt(h.Column).Key;
diff --git a/osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs b/osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs
index 2e6b63579e..a0c683143c 100644
--- a/osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs
+++ b/osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs
@@ -2,7 +2,6 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Graphics;
-using osu.Framework.Graphics.Sprites;
using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.UI;
using OpenTK;
@@ -15,13 +14,14 @@ using osu.Framework.Allocation;
using OpenTK.Input;
using System.Linq;
using System.Collections.Generic;
-using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Game.Rulesets.Objects.Drawables;
-using osu.Game.Rulesets.Mania.Timing;
using osu.Framework.Input;
using osu.Framework.Graphics.Transforms;
using osu.Framework.MathUtils;
using osu.Game.Rulesets.Mania.Objects.Drawables;
+using osu.Game.Rulesets.Timing;
+using osu.Framework.Configuration;
+using osu.Framework.Graphics.Shapes;
namespace osu.Game.Rulesets.Mania.UI
{
@@ -29,10 +29,10 @@ namespace osu.Game.Rulesets.Mania.UI
{
public const float HIT_TARGET_POSITION = 50;
- private const float time_span_default = 5000;
- private const float time_span_min = 10;
- private const float time_span_max = 50000;
- private const float time_span_step = 200;
+ private const double time_span_default = 1500;
+ private const double time_span_min = 50;
+ private const double time_span_max = 10000;
+ private const double time_span_step = 50;
///
/// Default column keys, expanding outwards from the middle as more column are added.
@@ -58,14 +58,20 @@ namespace osu.Game.Rulesets.Mania.UI
private readonly FlowContainer columns;
public IEnumerable Columns => columns.Children;
- private readonly ControlPointContainer barLineContainer;
+ private readonly BindableDouble visibleTimeRange = new BindableDouble(time_span_default)
+ {
+ MinValue = time_span_min,
+ MaxValue = time_span_max
+ };
+
+ private readonly SpeedAdjustmentCollection barLineContainer;
private List normalColumnColours = new List();
private Color4 specialColumnColour;
private readonly int columnCount;
- public ManiaPlayfield(int columnCount, IEnumerable timingChanges)
+ public ManiaPlayfield(int columnCount)
{
this.columnCount = columnCount;
@@ -116,12 +122,13 @@ namespace osu.Game.Rulesets.Mania.UI
Padding = new MarginPadding { Top = HIT_TARGET_POSITION },
Children = new[]
{
- barLineContainer = new ControlPointContainer(timingChanges)
+ barLineContainer = new SpeedAdjustmentCollection(Axes.Y)
{
Name = "Bar lines",
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
- RelativeSizeAxes = Axes.Y
+ RelativeSizeAxes = Axes.Y,
+ VisibleTimeRange = visibleTimeRange
// Width is set in the Update method
}
}
@@ -131,9 +138,7 @@ namespace osu.Game.Rulesets.Mania.UI
};
for (int i = 0; i < columnCount; i++)
- columns.Add(new Column(timingChanges));
-
- TimeSpan = time_span_default;
+ columns.Add(new Column { VisibleTimeRange = visibleTimeRange });
}
[BackgroundDependencyLoader]
@@ -208,6 +213,7 @@ namespace osu.Game.Rulesets.Mania.UI
public override void Add(DrawableHitObject h) => Columns.ElementAt(h.HitObject.Column).Add(h);
public void Add(DrawableBarLine barline) => barLineContainer.Add(barline);
+ public void Add(SpeedAdjustmentContainer speedAdjustment) => barLineContainer.Add(speedAdjustment);
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
{
@@ -216,10 +222,10 @@ namespace osu.Game.Rulesets.Mania.UI
switch (args.Key)
{
case Key.Minus:
- transformTimeSpanTo(TimeSpan + time_span_step, 200, EasingTypes.OutQuint);
+ transformVisibleTimeRangeTo(visibleTimeRange + time_span_step, 200, EasingTypes.OutQuint);
break;
case Key.Plus:
- transformTimeSpanTo(TimeSpan - time_span_step, 200, EasingTypes.OutQuint);
+ transformVisibleTimeRangeTo(visibleTimeRange - time_span_step, 200, EasingTypes.OutQuint);
break;
}
}
@@ -227,29 +233,9 @@ namespace osu.Game.Rulesets.Mania.UI
return false;
}
- private double timeSpan;
- ///
- /// The amount of time which the length of the playfield spans.
- ///
- public double TimeSpan
+ private void transformVisibleTimeRangeTo(double newTimeRange, double duration = 0, EasingTypes easing = EasingTypes.None)
{
- get { return timeSpan; }
- set
- {
- if (timeSpan == value)
- return;
- timeSpan = value;
-
- timeSpan = MathHelper.Clamp(timeSpan, time_span_min, time_span_max);
-
- barLineContainer.TimeSpan = value;
- Columns.ForEach(c => c.ControlPointContainer.TimeSpan = value);
- }
- }
-
- private void transformTimeSpanTo(double newTimeSpan, double duration = 0, EasingTypes easing = EasingTypes.None)
- {
- TransformTo(() => TimeSpan, newTimeSpan, duration, easing, new TransformTimeSpan());
+ TransformTo(() => visibleTimeRange.Value, newTimeRange, duration, easing, new TransformTimeSpan());
}
protected override void Update()
@@ -259,7 +245,7 @@ namespace osu.Game.Rulesets.Mania.UI
barLineContainer.Width = columns.Width;
}
- private class TransformTimeSpan : Transform
+ private class TransformTimeSpan : Transform
{
public override double CurrentValue
{
@@ -278,7 +264,7 @@ namespace osu.Game.Rulesets.Mania.UI
base.Apply(d);
var p = (ManiaPlayfield)d;
- p.TimeSpan = CurrentValue;
+ p.visibleTimeRange.Value = (float)CurrentValue;
}
}
}
diff --git a/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj b/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj
index 3d5614bd90..88d1ad7ad8 100644
--- a/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj
+++ b/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj
@@ -33,8 +33,9 @@
false
-
- $(SolutionDir)\packages\ppy.OpenTK.2.0.50727.1341\lib\net45\OpenTK.dll
+
+ $(SolutionDir)\packages\ppy.OpenTK.3.0\lib\net45\OpenTK.dll
+ True
@@ -62,6 +63,7 @@
+
@@ -77,14 +79,17 @@
+
+
+
+
-
-
+
diff --git a/osu.Game.Rulesets.Mania/packages.config b/osu.Game.Rulesets.Mania/packages.config
index 634d0b51f6..8add43d5d5 100644
--- a/osu.Game.Rulesets.Mania/packages.config
+++ b/osu.Game.Rulesets.Mania/packages.config
@@ -1,9 +1,8 @@
-
-
+
\ No newline at end of file
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuMod.cs b/osu.Game.Rulesets.Osu/Mods/OsuMod.cs
index cc06946d38..3b0cfc1ef1 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuMod.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuMod.cs
@@ -39,6 +39,11 @@ namespace osu.Game.Rulesets.Osu.Mods
public override Type[] IncompatibleMods => base.IncompatibleMods.Concat(new[] { typeof(OsuModAutopilot) }).ToArray();
}
+ public class OsuModDaycore : ModDaycore
+ {
+ public override double ScoreMultiplier => 0.5;
+ }
+
public class OsuModDoubleTime : ModDoubleTime
{
public override double ScoreMultiplier => 1.12;
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPoint.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPoint.cs
index 9f8ff17853..30e6172802 100644
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPoint.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPoint.cs
@@ -6,7 +6,7 @@ using OpenTK.Graphics;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
-using osu.Framework.Graphics.Sprites;
+using osu.Framework.Graphics.Shapes;
namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
{
@@ -21,7 +21,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
Masking = true;
AutoSizeAxes = Axes.Both;
CornerRadius = width / 2;
- EdgeEffect = new EdgeEffect
+ EdgeEffect = new EdgeEffectParameters
{
Type = EdgeEffectType.Glow,
Colour = Color4.White.Opacity(0.2f),
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTick.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTick.cs
index 6b4d40e080..28fbf46a92 100644
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTick.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTick.cs
@@ -3,11 +3,11 @@
using System;
using osu.Framework.Graphics;
-using osu.Framework.Graphics.Sprites;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Osu.Judgements;
using OpenTK;
using OpenTK.Graphics;
+using osu.Framework.Graphics.Shapes;
namespace osu.Game.Rulesets.Osu.Objects.Drawables
{
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/FlashPiece.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/FlashPiece.cs
index 68ffb756d4..97d7de35cf 100644
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/FlashPiece.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/FlashPiece.cs
@@ -3,8 +3,8 @@
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
-using osu.Framework.Graphics.Sprites;
using OpenTK;
+using osu.Framework.Graphics.Shapes;
namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
{
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/NumberPiece.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/NumberPiece.cs
index 07b21657a5..28e54c3b4e 100644
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/NumberPiece.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/NumberPiece.cs
@@ -7,6 +7,7 @@ using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Game.Graphics.Sprites;
using OpenTK.Graphics;
+using osu.Framework.Graphics.Shapes;
namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
{
@@ -31,7 +32,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
{
Masking = true,
Origin = Anchor.Centre,
- EdgeEffect = new EdgeEffect
+ EdgeEffect = new EdgeEffectParameters
{
Type = EdgeEffectType.Glow,
Radius = 60,
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/RingPiece.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/RingPiece.cs
index a04d3e7a0a..f66099e1c3 100644
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/RingPiece.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/RingPiece.cs
@@ -3,9 +3,9 @@
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
-using osu.Framework.Graphics.Sprites;
using OpenTK;
using OpenTK.Graphics;
+using osu.Framework.Graphics.Shapes;
namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
{
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBall.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBall.cs
index 4cffc1def3..4857f5c0d2 100644
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBall.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBall.cs
@@ -3,7 +3,7 @@
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
-using osu.Framework.Graphics.Sprites;
+using osu.Framework.Graphics.Shapes;
using osu.Framework.Input;
using OpenTK.Graphics;
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerBackground.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerBackground.cs
index 66cf7758b9..bdd5b71211 100644
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerBackground.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerBackground.cs
@@ -4,7 +4,7 @@
using OpenTK.Graphics;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
-using osu.Framework.Graphics.Sprites;
+using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics;
namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
@@ -25,7 +25,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
{
Disc.Colour = value;
- EdgeEffect = new EdgeEffect
+ EdgeEffect = new EdgeEffectParameters
{
Hollow = true,
Type = EdgeEffectType.Glow,
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerTicks.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerTicks.cs
index 4dbb6bd4d6..fc0d436788 100644
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerTicks.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerTicks.cs
@@ -5,9 +5,9 @@ using System;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
-using osu.Framework.Graphics.Sprites;
using OpenTK;
using OpenTK.Graphics;
+using osu.Framework.Graphics.Shapes;
namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
{
@@ -27,7 +27,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
{
Colour = Color4.Black,
Alpha = 0.4f,
- EdgeEffect = new EdgeEffect
+ EdgeEffect = new EdgeEffectParameters
{
Type = EdgeEffectType.Glow,
Radius = 10,
diff --git a/osu.Game.Rulesets.Osu/Objects/OsuHitObjectDifficulty.cs b/osu.Game.Rulesets.Osu/Objects/OsuHitObjectDifficulty.cs
deleted file mode 100644
index 1786771dca..0000000000
--- a/osu.Game.Rulesets.Osu/Objects/OsuHitObjectDifficulty.cs
+++ /dev/null
@@ -1,201 +0,0 @@
-// Copyright (c) 2007-2017 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-
-using OpenTK;
-using System;
-using System.Diagnostics;
-using System.Linq;
-
-namespace osu.Game.Rulesets.Osu.Objects
-{
- internal class OsuHitObjectDifficulty
- {
- ///
- /// Factor by how much speed / aim strain decays per second.
- ///
- ///
- /// These values are results of tweaking a lot and taking into account general feedback.
- /// Opinionated observation: Speed is easier to maintain than accurate jumps.
- ///
- internal static readonly double[] DECAY_BASE = { 0.3, 0.15 };
-
- ///
- /// Pseudo threshold values to distinguish between "singles" and "streams"
- ///
- ///
- /// Of course the border can not be defined clearly, therefore the algorithm has a smooth transition between those values.
- /// They also are based on tweaking and general feedback.
- ///
- private const double stream_spacing_threshold = 110,
- single_spacing_threshold = 125;
-
- ///
- /// Scaling values for weightings to keep aim and speed difficulty in balance.
- ///
- ///
- /// Found from testing a very large map pool (containing all ranked maps) and keeping the average values the same.
- ///
- private static readonly double[] spacing_weight_scaling = { 1400, 26.25 };
-
- ///
- /// Almost the normed diameter of a circle (104 osu pixel). That is -after- position transforming.
- ///
- private const double almost_diameter = 90;
-
- internal OsuHitObject BaseHitObject;
- internal double[] Strains = { 1, 1 };
-
- internal int MaxCombo = 1;
-
- private readonly float scalingFactor;
- private float lazySliderLength;
-
- private readonly Vector2 startPosition;
- private readonly Vector2 endPosition;
-
- internal OsuHitObjectDifficulty(OsuHitObject baseHitObject)
- {
- BaseHitObject = baseHitObject;
- float circleRadius = baseHitObject.Scale * 64;
-
- Slider slider = BaseHitObject as Slider;
- if (slider != null)
- MaxCombo += slider.Ticks.Count();
-
- // We will scale everything by this factor, so we can assume a uniform CircleSize among beatmaps.
- scalingFactor = 52.0f / circleRadius;
- if (circleRadius < 30)
- {
- float smallCircleBonus = Math.Min(30.0f - circleRadius, 5.0f) / 50.0f;
- scalingFactor *= 1.0f + smallCircleBonus;
- }
-
- lazySliderLength = 0;
- startPosition = baseHitObject.StackedPosition;
-
- // Calculate approximation of lazy movement on the slider
- if (slider != null)
- {
- float sliderFollowCircleRadius = circleRadius * 3; // Not sure if this is correct, but here we do not need 100% exact values. This comes pretty darn close in my tests.
-
- // For simplifying this step we use actual osu! coordinates and simply scale the length, that we obtain by the ScalingFactor later
- Vector2 cursorPos = startPosition;
-
- Action addSliderVertex = delegate (Vector2 pos)
- {
- Vector2 difference = pos - cursorPos;
- float distance = difference.Length;
-
- // Did we move away too far?
- if (distance > sliderFollowCircleRadius)
- {
- // Yep, we need to move the cursor
- difference.Normalize(); // Obtain the direction of difference. We do no longer need the actual difference
- distance -= sliderFollowCircleRadius;
- cursorPos += difference * distance; // We move the cursor just as far as needed to stay in the follow circle
- lazySliderLength += distance;
- }
- };
-
- // Actual computation of the first lazy curve
- foreach (var tick in slider.Ticks)
- addSliderVertex(tick.StackedPosition);
-
- addSliderVertex(baseHitObject.StackedEndPosition);
-
- lazySliderLength *= scalingFactor;
- endPosition = cursorPos;
- }
- // We have a normal HitCircle or a spinner
- else
- endPosition = startPosition;
- }
-
- internal void CalculateStrains(OsuHitObjectDifficulty previousHitObject, double timeRate)
- {
- calculateSpecificStrain(previousHitObject, OsuDifficultyCalculator.DifficultyType.Speed, timeRate);
- calculateSpecificStrain(previousHitObject, OsuDifficultyCalculator.DifficultyType.Aim, timeRate);
- }
-
- // Caution: The subjective values are strong with this one
- private static double spacingWeight(double distance, OsuDifficultyCalculator.DifficultyType type)
- {
- switch (type)
- {
- case OsuDifficultyCalculator.DifficultyType.Speed:
- if (distance > single_spacing_threshold)
- return 2.5;
- else if (distance > stream_spacing_threshold)
- return 1.6 + 0.9 * (distance - stream_spacing_threshold) / (single_spacing_threshold - stream_spacing_threshold);
- else if (distance > almost_diameter)
- return 1.2 + 0.4 * (distance - almost_diameter) / (stream_spacing_threshold - almost_diameter);
- else if (distance > almost_diameter / 2)
- return 0.95 + 0.25 * (distance - almost_diameter / 2) / (almost_diameter / 2);
- else
- return 0.95;
-
- case OsuDifficultyCalculator.DifficultyType.Aim:
- return Math.Pow(distance, 0.99);
- }
-
- Debug.Assert(false, "Invalid osu difficulty hit object type.");
- return 0;
- }
-
- private void calculateSpecificStrain(OsuHitObjectDifficulty previousHitObject, OsuDifficultyCalculator.DifficultyType type, double timeRate)
- {
- double addition = 0;
- double timeElapsed = (BaseHitObject.StartTime - previousHitObject.BaseHitObject.StartTime) / timeRate;
- double decay = Math.Pow(DECAY_BASE[(int)type], timeElapsed / 1000);
-
- if (BaseHitObject is Spinner)
- {
- // Do nothing for spinners
- }
- else if (BaseHitObject is Slider)
- {
- switch (type)
- {
- case OsuDifficultyCalculator.DifficultyType.Speed:
-
- // For speed strain we treat the whole slider as a single spacing entity, since "Speed" is about how hard it is to click buttons fast.
- // The spacing weight exists to differentiate between being able to easily alternate or having to single.
- addition =
- spacingWeight(previousHitObject.lazySliderLength +
- DistanceTo(previousHitObject), type) *
- spacing_weight_scaling[(int)type];
-
- break;
- case OsuDifficultyCalculator.DifficultyType.Aim:
-
- // For Aim strain we treat each slider segment and the jump after the end of the slider as separate jumps, since movement-wise there is no difference
- // to multiple jumps.
- addition =
- (
- spacingWeight(previousHitObject.lazySliderLength, type) +
- spacingWeight(DistanceTo(previousHitObject), type)
- ) *
- spacing_weight_scaling[(int)type];
-
- break;
- }
- }
- else if (BaseHitObject is HitCircle)
- {
- addition = spacingWeight(DistanceTo(previousHitObject), type) * spacing_weight_scaling[(int)type];
- }
-
- // Scale addition by the time, that elapsed. Filter out HitObjects that are too close to be played anyway to avoid crazy values by division through close to zero.
- // You will never find maps that require this amongst ranked maps.
- addition /= Math.Max(timeElapsed, 50);
-
- Strains[(int)type] = previousHitObject.Strains[(int)type] * decay + addition;
- }
-
- internal double DistanceTo(OsuHitObjectDifficulty other)
- {
- // Scale the distance by circle size.
- return (startPosition - other.endPosition).Length * scalingFactor;
- }
- }
-}
diff --git a/osu.Game.Rulesets.Osu/OsuDifficulty/OsuDifficultyCalculator.cs b/osu.Game.Rulesets.Osu/OsuDifficulty/OsuDifficultyCalculator.cs
new file mode 100644
index 0000000000..a164566263
--- /dev/null
+++ b/osu.Game.Rulesets.Osu/OsuDifficulty/OsuDifficultyCalculator.cs
@@ -0,0 +1,73 @@
+// Copyright (c) 2007-2017 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using System;
+using System.Collections.Generic;
+using osu.Game.Beatmaps;
+using osu.Game.Rulesets.Beatmaps;
+using osu.Game.Rulesets.Osu.Beatmaps;
+using osu.Game.Rulesets.Osu.Objects;
+using osu.Game.Rulesets.Osu.OsuDifficulty.Preprocessing;
+using osu.Game.Rulesets.Osu.OsuDifficulty.Skills;
+
+namespace osu.Game.Rulesets.Osu.OsuDifficulty
+{
+ public class OsuDifficultyCalculator : DifficultyCalculator
+ {
+ private const int section_length = 400;
+ private const double difficulty_multiplier = 0.0675;
+
+ public OsuDifficultyCalculator(Beatmap beatmap) : base(beatmap)
+ {
+ }
+
+ protected override void PreprocessHitObjects()
+ {
+ foreach (OsuHitObject h in Objects)
+ (h as Slider)?.Curve?.Calculate();
+ }
+
+ protected override double CalculateInternal(Dictionary categoryDifficulty)
+ {
+ OsuDifficultyBeatmap beatmap = new OsuDifficultyBeatmap(Objects);
+ Skill[] skills =
+ {
+ new Aim(),
+ new Speed()
+ };
+
+ double sectionEnd = section_length / TimeRate;
+ foreach (OsuDifficultyHitObject h in beatmap)
+ {
+ while (h.BaseObject.StartTime > sectionEnd)
+ {
+ foreach (Skill s in skills)
+ {
+ s.SaveCurrentPeak();
+ s.StartNewSectionFrom(sectionEnd);
+ }
+
+ sectionEnd += section_length;
+ }
+
+ foreach (Skill s in skills)
+ s.Process(h);
+ }
+
+ double aimRating = Math.Sqrt(skills[0].DifficultyValue()) * difficulty_multiplier;
+ double speedRating = Math.Sqrt(skills[1].DifficultyValue()) * difficulty_multiplier;
+
+ double starRating = aimRating + speedRating + Math.Abs(aimRating - speedRating) / 2;
+
+ if (categoryDifficulty != null)
+ {
+ categoryDifficulty.Add("Aim", aimRating.ToString("0.00"));
+ categoryDifficulty.Add("Speed", speedRating.ToString("0.00"));
+ }
+
+ return starRating;
+ }
+
+ protected override BeatmapConverter CreateBeatmapConverter() => new OsuBeatmapConverter();
+ }
+}
diff --git a/osu.Game.Rulesets.Osu/OsuDifficulty/Preprocessing/OsuDifficultyBeatmap.cs b/osu.Game.Rulesets.Osu/OsuDifficulty/Preprocessing/OsuDifficultyBeatmap.cs
new file mode 100644
index 0000000000..72ba421344
--- /dev/null
+++ b/osu.Game.Rulesets.Osu/OsuDifficulty/Preprocessing/OsuDifficultyBeatmap.cs
@@ -0,0 +1,93 @@
+// Copyright (c) 2007-2017 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using System.Collections;
+using System.Collections.Generic;
+using osu.Game.Rulesets.Osu.Objects;
+
+namespace osu.Game.Rulesets.Osu.OsuDifficulty.Preprocessing
+{
+ ///
+ /// An enumerable container wrapping input as
+ /// which contains extra data required for difficulty calculation.
+ ///
+ public class OsuDifficultyBeatmap : IEnumerable
+ {
+ private readonly IEnumerator difficultyObjects;
+ private readonly Queue onScreen = new Queue();
+
+ ///
+ /// Creates an enumerator, which preprocesses a list of s recieved as input, wrapping them as
+ /// which contains extra data required for difficulty calculation.
+ ///
+ public OsuDifficultyBeatmap(List objects)
+ {
+ // Sort OsuHitObjects by StartTime - they are not correctly ordered in some cases.
+ // This should probably happen before the objects reach the difficulty calculator.
+ objects.Sort((a, b) => a.StartTime.CompareTo(b.StartTime));
+ difficultyObjects = createDifficultyObjectEnumerator(objects);
+ }
+
+ ///
+ /// Returns an enumerator that enumerates all s in the .
+ /// The inner loop adds objects that appear on screen into a queue until we need to hit the next object.
+ /// The outer loop returns objects from this queue one at a time, only after they had to be hit, and should no longer be on screen.
+ /// This means that we can loop through every object that is on screen at the time when a new one appears,
+ /// allowing us to determine a reading strain for the object that just appeared.
+ ///
+ public IEnumerator GetEnumerator()
+ {
+ while (true)
+ {
+ // Add upcoming objects to the queue until we have at least one object that had been hit and can be dequeued.
+ // This means there is always at least one object in the queue unless we reached the end of the map.
+ do
+ {
+ if (!difficultyObjects.MoveNext())
+ break; // New objects can't be added anymore, but we still need to dequeue and return the ones already on screen.
+
+ OsuDifficultyHitObject latest = difficultyObjects.Current;
+ // Calculate flow values here
+
+ foreach (OsuDifficultyHitObject h in onScreen)
+ {
+ h.TimeUntilHit -= latest.DeltaTime;
+ // Calculate reading strain here
+ }
+
+ onScreen.Enqueue(latest);
+ }
+ while (onScreen.Peek().TimeUntilHit > 0); // Keep adding new objects on screen while there is still time before we have to hit the next one.
+
+ if (onScreen.Count == 0) break; // We have reached the end of the map and enumerated all the objects.
+ yield return onScreen.Dequeue(); // Remove and return objects one by one that had to be hit before the latest one appeared.
+ }
+ }
+
+ IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
+
+ private IEnumerator createDifficultyObjectEnumerator(List objects)
+ {
+ // We will process OsuHitObjects in groups of three to form a triangle, so we can calculate an angle for each object.
+ OsuHitObject[] triangle = new OsuHitObject[3];
+
+ // OsuDifficultyHitObject construction requires three components, an extra copy of the first OsuHitObject is used at the beginning.
+ if (objects.Count > 1)
+ {
+ triangle[1] = objects[0]; // This copy will get shifted to the last spot in the triangle.
+ triangle[0] = objects[0]; // This component corresponds to the real first OsuHitOject.
+ }
+
+ // The final component of the first triangle will be the second OsuHitOject of the map, which forms the first jump.
+ // If the map has less than two OsuHitObjects, the enumerator will not return anything.
+ for (int i = 1; i < objects.Count; ++i)
+ {
+ triangle[2] = triangle[1];
+ triangle[1] = triangle[0];
+ triangle[0] = objects[i];
+
+ yield return new OsuDifficultyHitObject(triangle);
+ }
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Osu/OsuDifficulty/Preprocessing/OsuDifficultyHitObject.cs b/osu.Game.Rulesets.Osu/OsuDifficulty/Preprocessing/OsuDifficultyHitObject.cs
new file mode 100644
index 0000000000..bdeb62df3e
--- /dev/null
+++ b/osu.Game.Rulesets.Osu/OsuDifficulty/Preprocessing/OsuDifficultyHitObject.cs
@@ -0,0 +1,70 @@
+// Copyright (c) 2007-2017 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using System;
+using osu.Game.Rulesets.Osu.Objects;
+
+namespace osu.Game.Rulesets.Osu.OsuDifficulty.Preprocessing
+{
+ ///
+ /// A wrapper around extending it with additional data required for difficulty calculation.
+ ///
+ public class OsuDifficultyHitObject
+ {
+ ///
+ /// The this refers to.
+ ///
+ public OsuHitObject BaseObject { get; }
+
+ ///
+ /// Normalized distance from the of the previous .
+ ///
+ public double Distance { get; private set; }
+
+ ///
+ /// Milliseconds elapsed since the StartTime of the previous .
+ ///
+ public double DeltaTime { get; private set; }
+
+ ///
+ /// Number of milliseconds until the has to be hit.
+ ///
+ public double TimeUntilHit { get; set; }
+
+ private const int normalized_radius = 52;
+
+ private readonly OsuHitObject[] t;
+
+ ///
+ /// Initializes the object calculating extra data required for difficulty calculation.
+ ///
+ public OsuDifficultyHitObject(OsuHitObject[] triangle)
+ {
+ t = triangle;
+ BaseObject = t[0];
+ setDistances();
+ setTimingValues();
+ // Calculate angle here
+ }
+
+ private void setDistances()
+ {
+ // We will scale distances by this factor, so we can assume a uniform CircleSize among beatmaps.
+ double scalingFactor = normalized_radius / BaseObject.Radius;
+ if (BaseObject.Radius < 30)
+ {
+ double smallCircleBonus = Math.Min(30 - BaseObject.Radius, 5) / 50;
+ scalingFactor *= 1 + smallCircleBonus;
+ }
+
+ Distance = (t[0].StackedPosition - t[1].StackedPosition).Length * scalingFactor;
+ }
+
+ private void setTimingValues()
+ {
+ // Every timing inverval is hard capped at the equivalent of 375 BPM streaming speed as a safety measure.
+ DeltaTime = Math.Max(40, t[0].StartTime - t[1].StartTime);
+ TimeUntilHit = 450; // BaseObject.PreEmpt;
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Osu/OsuDifficulty/Skills/Aim.cs b/osu.Game.Rulesets.Osu/OsuDifficulty/Skills/Aim.cs
new file mode 100644
index 0000000000..aad53f6fe8
--- /dev/null
+++ b/osu.Game.Rulesets.Osu/OsuDifficulty/Skills/Aim.cs
@@ -0,0 +1,19 @@
+// Copyright (c) 2007-2017 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using System;
+using osu.Game.Rulesets.Osu.OsuDifficulty.Preprocessing;
+
+namespace osu.Game.Rulesets.Osu.OsuDifficulty.Skills
+{
+ ///
+ /// Represents the skill required to correctly aim at every object in the map with a uniform CircleSize and normalized distances.
+ ///
+ public class Aim : Skill
+ {
+ protected override double SkillMultiplier => 26.25;
+ protected override double StrainDecayBase => 0.15;
+
+ protected override double StrainValueOf(OsuDifficultyHitObject current) => Math.Pow(current.Distance, 0.99) / current.DeltaTime;
+ }
+}
diff --git a/osu.Game.Rulesets.Osu/OsuDifficulty/Skills/Skill.cs b/osu.Game.Rulesets.Osu/OsuDifficulty/Skills/Skill.cs
new file mode 100644
index 0000000000..b9632e18e2
--- /dev/null
+++ b/osu.Game.Rulesets.Osu/OsuDifficulty/Skills/Skill.cs
@@ -0,0 +1,100 @@
+// Copyright (c) 2007-2017 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using System;
+using System.Collections.Generic;
+using osu.Game.Rulesets.Osu.Objects;
+using osu.Game.Rulesets.Osu.OsuDifficulty.Preprocessing;
+using osu.Game.Rulesets.Osu.OsuDifficulty.Utils;
+
+namespace osu.Game.Rulesets.Osu.OsuDifficulty.Skills
+{
+ ///
+ /// Used to processes strain values of s, keep track of strain levels caused by the processed objects
+ /// and to calculate a final difficulty value representing the difficulty of hitting all the processed objects.
+ ///
+ public abstract class Skill
+ {
+ ///
+ /// Strain values are multiplied by this number for the given skill. Used to balance the value of different skills between each other.
+ ///
+ protected abstract double SkillMultiplier { get; }
+
+ ///
+ /// Determines how quickly strain decays for the given skill.
+ /// For example a value of 0.15 indicates that strain decays to 15% of its original value in one second.
+ ///
+ protected abstract double StrainDecayBase { get; }
+
+ ///
+ /// s that were processed previously. They can affect the strain values of the following objects.
+ ///
+ protected readonly History Previous = new History(2); // Contained objects not used yet
+
+ private double currentStrain = 1; // We keep track of the strain level at all times throughout the beatmap.
+ private double currentSectionPeak = 1; // We also keep track of the peak strain level in the current section.
+ private readonly List strainPeaks = new List();
+
+ ///
+ /// Process an and update current strain values accordingly.
+ ///
+ public void Process(OsuDifficultyHitObject current)
+ {
+ currentStrain *= strainDecay(current.DeltaTime);
+ if (!(current.BaseObject is Spinner))
+ currentStrain += StrainValueOf(current) * SkillMultiplier;
+
+ currentSectionPeak = Math.Max(currentStrain, currentSectionPeak);
+
+ Previous.Push(current);
+ }
+
+ ///
+ /// Saves the current peak strain level to the list of strain peaks, which will be used to calculate an overall difficulty.
+ ///
+ public void SaveCurrentPeak()
+ {
+ if (Previous.Count > 0)
+ strainPeaks.Add(currentSectionPeak);
+ }
+
+ ///
+ /// Sets the initial strain level for a new section.
+ ///
+ /// The beginning of the new section in milliseconds
+ public void StartNewSectionFrom(double offset)
+ {
+ // The maximum strain of the new section is not zero by default, strain decays as usual regardless of section boundaries.
+ // This means we need to capture the strain level at the beginning of the new section, and use that as the initial peak level.
+ if (Previous.Count > 0)
+ currentSectionPeak = currentStrain * strainDecay(offset - Previous[0].BaseObject.StartTime);
+ }
+
+ ///
+ /// Returns the calculated difficulty value representing all processed s.
+ ///
+ public double DifficultyValue()
+ {
+ strainPeaks.Sort((a, b) => b.CompareTo(a)); // Sort from highest to lowest strain.
+
+ double difficulty = 0;
+ double weight = 1;
+
+ // Difficulty is the weighted sum of the highest strains from every section.
+ foreach (double strain in strainPeaks)
+ {
+ difficulty += strain * weight;
+ weight *= 0.9;
+ }
+
+ return difficulty;
+ }
+
+ ///
+ /// Calculates the strain value of an . This value is affected by previously processed objects.
+ ///
+ protected abstract double StrainValueOf(OsuDifficultyHitObject current);
+
+ private double strainDecay(double ms) => Math.Pow(StrainDecayBase, ms / 1000);
+ }
+}
diff --git a/osu.Game.Rulesets.Osu/OsuDifficulty/Skills/Speed.cs b/osu.Game.Rulesets.Osu/OsuDifficulty/Skills/Speed.cs
new file mode 100644
index 0000000000..6c43c53e35
--- /dev/null
+++ b/osu.Game.Rulesets.Osu/OsuDifficulty/Skills/Speed.cs
@@ -0,0 +1,39 @@
+// Copyright (c) 2007-2017 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using osu.Game.Rulesets.Osu.OsuDifficulty.Preprocessing;
+
+namespace osu.Game.Rulesets.Osu.OsuDifficulty.Skills
+{
+ ///
+ /// Represents the skill required to press keys with regards to keeping up with the speed at which objects need to be hit.
+ ///
+ public class Speed : Skill
+ {
+ protected override double SkillMultiplier => 1400;
+ protected override double StrainDecayBase => 0.3;
+
+ private const double single_spacing_threshold = 125;
+ private const double stream_spacing_threshold = 110;
+ private const double almost_diameter = 90;
+
+ protected override double StrainValueOf(OsuDifficultyHitObject current)
+ {
+ double distance = current.Distance;
+
+ double speedValue;
+ if (distance > single_spacing_threshold)
+ speedValue = 2.5;
+ else if (distance > stream_spacing_threshold)
+ speedValue = 1.6 + 0.9 * (distance - stream_spacing_threshold) / (single_spacing_threshold - stream_spacing_threshold);
+ else if (distance > almost_diameter)
+ speedValue = 1.2 + 0.4 * (distance - almost_diameter) / (stream_spacing_threshold - almost_diameter);
+ else if (distance > almost_diameter / 2)
+ speedValue = 0.95 + 0.25 * (distance - almost_diameter / 2) / (almost_diameter / 2);
+ else
+ speedValue = 0.95;
+
+ return speedValue / current.DeltaTime;
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Osu/OsuDifficulty/Utils/History.cs b/osu.Game.Rulesets.Osu/OsuDifficulty/Utils/History.cs
new file mode 100644
index 0000000000..d2c2e1d774
--- /dev/null
+++ b/osu.Game.Rulesets.Osu/OsuDifficulty/Utils/History.cs
@@ -0,0 +1,86 @@
+// Copyright (c) 2007-2017 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+
+namespace osu.Game.Rulesets.Osu.OsuDifficulty.Utils
+{
+ ///
+ /// An indexed stack with Push() only, which disposes items at the bottom after the capacity is full.
+ /// Indexing starts at the top of the stack.
+ ///
+ public class History : IEnumerable
+ {
+ public int Count { get; private set; }
+
+ private readonly T[] array;
+ private readonly int capacity;
+ private int marker; // Marks the position of the most recently added item.
+
+ ///
+ /// Initializes a new instance of the History class that is empty and has the specified capacity.
+ ///
+ /// The number of items the History can hold.
+ public History(int capacity)
+ {
+ if (capacity < 0)
+ throw new ArgumentOutOfRangeException();
+
+ this.capacity = capacity;
+ array = new T[capacity];
+ marker = capacity; // Set marker to the end of the array, outside of the indexed range by one.
+ }
+
+ ///
+ /// The most recently added item is returned at index 0.
+ ///
+ public T this[int i]
+ {
+ get
+ {
+ if (i < 0 || i > Count - 1)
+ throw new IndexOutOfRangeException();
+
+ i += marker;
+ if (i > capacity - 1)
+ i -= capacity;
+
+ return array[i];
+ }
+ }
+
+ ///
+ /// Adds the item as the most recent one in the history.
+ /// The oldest item is disposed if the history is full.
+ ///
+ public void Push(T item) // Overwrite the oldest item instead of shifting every item by one with every addition.
+ {
+ if (marker == 0)
+ marker = capacity - 1;
+ else
+ --marker;
+
+ array[marker] = item;
+
+ if (Count < capacity)
+ ++Count;
+ }
+
+ ///
+ /// Returns an enumerator which enumerates items in the history starting from the most recently added one.
+ ///
+ public IEnumerator GetEnumerator()
+ {
+ for (int i = marker; i < capacity; ++i)
+ yield return array[i];
+
+ if (Count == capacity)
+ for (int i = 0; i < marker; ++i)
+ yield return array[i];
+ }
+
+ IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
+ }
+}
diff --git a/osu.Game.Rulesets.Osu/OsuDifficultyCalculator.cs b/osu.Game.Rulesets.Osu/OsuDifficultyCalculator.cs
deleted file mode 100644
index 5669993e67..0000000000
--- a/osu.Game.Rulesets.Osu/OsuDifficultyCalculator.cs
+++ /dev/null
@@ -1,192 +0,0 @@
-// Copyright (c) 2007-2017 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-
-using osu.Game.Beatmaps;
-using osu.Game.Rulesets.Beatmaps;
-using osu.Game.Rulesets.Osu.Beatmaps;
-using osu.Game.Rulesets.Osu.Objects;
-using System;
-using System.Collections.Generic;
-
-namespace osu.Game.Rulesets.Osu
-{
- public class OsuDifficultyCalculator : DifficultyCalculator
- {
- private const double star_scaling_factor = 0.0675;
- private const double extreme_scaling_factor = 0.5;
-
- ///
- /// HitObjects are stored as a member variable.
- ///
- internal List DifficultyHitObjects = new List();
-
- public OsuDifficultyCalculator(Beatmap beatmap) : base(beatmap)
- {
- }
-
- protected override void PreprocessHitObjects()
- {
- foreach (var h in Objects)
- (h as Slider)?.Curve?.Calculate();
- }
-
- protected override double CalculateInternal(Dictionary categoryDifficulty)
- {
- // Fill our custom DifficultyHitObject class, that carries additional information
- DifficultyHitObjects.Clear();
-
- foreach (var hitObject in Objects)
- DifficultyHitObjects.Add(new OsuHitObjectDifficulty(hitObject));
-
- // Sort DifficultyHitObjects by StartTime of the HitObjects - just to make sure.
- DifficultyHitObjects.Sort((a, b) => a.BaseHitObject.StartTime.CompareTo(b.BaseHitObject.StartTime));
-
- if (!CalculateStrainValues()) return 0;
-
- double speedDifficulty = CalculateDifficulty(DifficultyType.Speed);
- double aimDifficulty = CalculateDifficulty(DifficultyType.Aim);
-
- // OverallDifficulty is not considered in this algorithm and neither is HpDrainRate. That means, that in this form the algorithm determines how hard it physically is
- // to play the map, assuming, that too much of an error will not lead to a death.
- // It might be desirable to include OverallDifficulty into map difficulty, but in my personal opinion it belongs more to the weighting of the actual peformance
- // and is superfluous in the beatmap difficulty rating.
- // If it were to be considered, then I would look at the hit window of normal HitCircles only, since Sliders and Spinners are (almost) "free" 300s and take map length
- // into account as well.
-
- // The difficulty can be scaled by any desired metric.
- // In osu!tp it gets squared to account for the rapid increase in difficulty as the limit of a human is approached. (Of course it also gets scaled afterwards.)
- // It would not be suitable for a star rating, therefore:
-
- // The following is a proposal to forge a star rating from 0 to 5. It consists of taking the square root of the difficulty, since by simply scaling the easier
- // 5-star maps would end up with one star.
- double speedStars = Math.Sqrt(speedDifficulty) * star_scaling_factor;
- double aimStars = Math.Sqrt(aimDifficulty) * star_scaling_factor;
-
- if (categoryDifficulty != null)
- {
- categoryDifficulty.Add("Aim", aimStars.ToString("0.00"));
- categoryDifficulty.Add("Speed", speedStars.ToString("0.00"));
-
- double hitWindow300 = 30/*HitObjectManager.HitWindow300*/ / TimeRate;
- double preEmpt = 450/*HitObjectManager.PreEmpt*/ / TimeRate;
-
- categoryDifficulty.Add("OD", (-(hitWindow300 - 80.0) / 6.0).ToString("0.00"));
- categoryDifficulty.Add("AR", (preEmpt > 1200.0 ? -(preEmpt - 1800.0) / 120.0 : -(preEmpt - 1200.0) / 150.0 + 5.0).ToString("0.00"));
-
- int maxCombo = 0;
- foreach (OsuHitObjectDifficulty hitObject in DifficultyHitObjects)
- maxCombo += hitObject.MaxCombo;
-
- categoryDifficulty.Add("Max combo", maxCombo.ToString());
- }
-
- // Again, from own observations and from the general opinion of the community a map with high speed and low aim (or vice versa) difficulty is harder,
- // than a map with mediocre difficulty in both. Therefore we can not just add both difficulties together, but will introduce a scaling that favors extremes.
- double starRating = speedStars + aimStars + Math.Abs(speedStars - aimStars) * extreme_scaling_factor;
- // Another approach to this would be taking Speed and Aim separately to a chosen power, which again would be equivalent. This would be more convenient if
- // the hit window size is to be considered as well.
-
- // Note: The star rating is tuned extremely tight! Airman (/b/104229) and Freedom Dive (/b/126645), two of the hardest ranked maps, both score ~4.66 stars.
- // Expect the easier kind of maps that officially get 5 stars to obtain around 2 by this metric. The tutorial still scores about half a star.
- // Tune by yourself as you please. ;)
-
- return starRating;
- }
-
- protected bool CalculateStrainValues()
- {
- // Traverse hitObjects in pairs to calculate the strain value of NextHitObject from the strain value of CurrentHitObject and environment.
- using (List.Enumerator hitObjectsEnumerator = DifficultyHitObjects.GetEnumerator())
- {
-
- if (!hitObjectsEnumerator.MoveNext()) return false;
-
- OsuHitObjectDifficulty current = hitObjectsEnumerator.Current;
-
- // First hitObject starts at strain 1. 1 is the default for strain values, so we don't need to set it here. See DifficultyHitObject.
- while (hitObjectsEnumerator.MoveNext())
- {
- var next = hitObjectsEnumerator.Current;
- next?.CalculateStrains(current, TimeRate);
- current = next;
- }
-
- return true;
- }
- }
-
- ///
- /// In milliseconds. For difficulty calculation we will only look at the highest strain value in each time interval of size STRAIN_STEP.
- /// This is to eliminate higher influence of stream over aim by simply having more HitObjects with high strain.
- /// The higher this value, the less strains there will be, indirectly giving long beatmaps an advantage.
- ///
- protected const double STRAIN_STEP = 400;
-
- ///
- /// The weighting of each strain value decays to this number * it's previous value
- ///
- protected const double DECAY_WEIGHT = 0.9;
-
- protected double CalculateDifficulty(DifficultyType type)
- {
- double actualStrainStep = STRAIN_STEP * TimeRate;
-
- // Find the highest strain value within each strain step
- List highestStrains = new List();
- double intervalEndTime = actualStrainStep;
- double maximumStrain = 0; // We need to keep track of the maximum strain in the current interval
-
- OsuHitObjectDifficulty previousHitObject = null;
- foreach (OsuHitObjectDifficulty hitObject in DifficultyHitObjects)
- {
- // While we are beyond the current interval push the currently available maximum to our strain list
- while (hitObject.BaseHitObject.StartTime > intervalEndTime)
- {
- highestStrains.Add(maximumStrain);
-
- // The maximum strain of the next interval is not zero by default! We need to take the last hitObject we encountered, take its strain and apply the decay
- // until the beginning of the next interval.
- if (previousHitObject == null)
- {
- maximumStrain = 0;
- }
- else
- {
- double decay = Math.Pow(OsuHitObjectDifficulty.DECAY_BASE[(int)type], (intervalEndTime - previousHitObject.BaseHitObject.StartTime) / 1000);
- maximumStrain = previousHitObject.Strains[(int)type] * decay;
- }
-
- // Go to the next time interval
- intervalEndTime += actualStrainStep;
- }
-
- // Obtain maximum strain
- maximumStrain = Math.Max(hitObject.Strains[(int)type], maximumStrain);
-
- previousHitObject = hitObject;
- }
-
- // Build the weighted sum over the highest strains for each interval
- double difficulty = 0;
- double weight = 1;
- highestStrains.Sort((a, b) => b.CompareTo(a)); // Sort from highest to lowest strain.
-
- foreach (double strain in highestStrains)
- {
- difficulty += weight * strain;
- weight *= DECAY_WEIGHT;
- }
-
- return difficulty;
- }
-
- protected override BeatmapConverter CreateBeatmapConverter() => new OsuBeatmapConverter();
-
- // Those values are used as array indices. Be careful when changing them!
- public enum DifficultyType
- {
- Speed = 0,
- Aim,
- };
- }
-}
diff --git a/osu.Game.Rulesets.Osu/OsuRuleset.cs b/osu.Game.Rulesets.Osu/OsuRuleset.cs
index af4a099e0d..63fe6aaa59 100644
--- a/osu.Game.Rulesets.Osu/OsuRuleset.cs
+++ b/osu.Game.Rulesets.Osu/OsuRuleset.cs
@@ -7,6 +7,7 @@ using osu.Game.Graphics;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Rulesets.Osu.Objects;
+using osu.Game.Rulesets.Osu.OsuDifficulty;
using osu.Game.Rulesets.Osu.UI;
using osu.Game.Rulesets.UI;
using osu.Game.Screens.Play;
@@ -46,7 +47,14 @@ namespace osu.Game.Rulesets.Osu
{
new OsuModEasy(),
new OsuModNoFail(),
- new OsuModHalfTime(),
+ new MultiMod
+ {
+ Mods = new Mod[]
+ {
+ new OsuModHalfTime(),
+ new OsuModDaycore(),
+ },
+ },
};
case ModType.DifficultyIncrease:
diff --git a/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj b/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj
index b91bdc6a78..f6f565c502 100644
--- a/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj
+++ b/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj
@@ -34,8 +34,9 @@
false
-
- $(SolutionDir)\packages\ppy.OpenTK.2.0.50727.1341\lib\net45\OpenTK.dll
+
+ $(SolutionDir)\packages\ppy.OpenTK.3.0\lib\net45\OpenTK.dll
+ True
@@ -68,9 +69,14 @@
-
-
+
+
+
+
+
+
+
diff --git a/osu.Game.Rulesets.Osu/packages.config b/osu.Game.Rulesets.Osu/packages.config
index 634d0b51f6..fa6edb9c8f 100644
--- a/osu.Game.Rulesets.Osu/packages.config
+++ b/osu.Game.Rulesets.Osu/packages.config
@@ -5,5 +5,5 @@ Copyright (c) 2007-2017 ppy Pty Ltd .
Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-->
-
+
\ No newline at end of file
diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoMod.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoMod.cs
index 8b7a099b9a..abaa8c1bc1 100644
--- a/osu.Game.Rulesets.Taiko/Mods/TaikoMod.cs
+++ b/osu.Game.Rulesets.Taiko/Mods/TaikoMod.cs
@@ -37,6 +37,11 @@ namespace osu.Game.Rulesets.Taiko.Mods
}
+ public class TaikoModDaycore : ModDaycore
+ {
+ public override double ScoreMultiplier => 0.5;
+ }
+
public class TaikoModDoubleTime : ModDoubleTime
{
public override double ScoreMultiplier => 1.12;
diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableBarLine.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableBarLine.cs
index 4c83e08bab..5d627f2b50 100644
--- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableBarLine.cs
+++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableBarLine.cs
@@ -3,7 +3,7 @@
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
-using osu.Framework.Graphics.Sprites;
+using osu.Framework.Graphics.Shapes;
using OpenTK;
namespace osu.Game.Rulesets.Taiko.Objects.Drawables
diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableBarLineMajor.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableBarLineMajor.cs
index e64682a1e4..c07be915d5 100644
--- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableBarLineMajor.cs
+++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableBarLineMajor.cs
@@ -3,8 +3,8 @@
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
-using osu.Framework.Graphics.Sprites;
using OpenTK;
+using osu.Framework.Graphics.Shapes;
namespace osu.Game.Rulesets.Taiko.Objects.Drawables
{
diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs
index 37efd8aba4..1c72f2a7dd 100644
--- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs
+++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs
@@ -7,7 +7,6 @@ using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
-using osu.Framework.Graphics.Sprites;
using osu.Game.Graphics;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Taiko.Judgements;
@@ -15,6 +14,7 @@ using osu.Game.Rulesets.Taiko.Objects.Drawables.Pieces;
using OpenTK;
using OpenTK.Graphics;
using OpenTK.Input;
+using osu.Framework.Graphics.Shapes;
namespace osu.Game.Rulesets.Taiko.Objects.Drawables
{
@@ -68,7 +68,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
Size = new Vector2(TaikoHitObject.DEFAULT_CIRCLE_DIAMETER),
BlendingMode = BlendingMode.Additive,
Masking = true,
- Children = new []
+ Children = new[]
{
new Box
{
@@ -119,7 +119,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
- Children = new []
+ Children = new[]
{
symbol = new SwellSymbolPiece()
}
diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/Pieces/CentreHitSymbolPiece.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/Pieces/CentreHitSymbolPiece.cs
index ddf1492ecc..cc88105e03 100644
--- a/osu.Game.Rulesets.Taiko/Objects/Drawables/Pieces/CentreHitSymbolPiece.cs
+++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/Pieces/CentreHitSymbolPiece.cs
@@ -3,8 +3,8 @@
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
-using osu.Framework.Graphics.Sprites;
using OpenTK;
+using osu.Framework.Graphics.Shapes;
namespace osu.Game.Rulesets.Taiko.Objects.Drawables.Pieces
{
diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/Pieces/CirclePiece.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/Pieces/CirclePiece.cs
index 3ea05b6558..709343d086 100644
--- a/osu.Game.Rulesets.Taiko/Objects/Drawables/Pieces/CirclePiece.cs
+++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/Pieces/CirclePiece.cs
@@ -4,7 +4,7 @@
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
-using osu.Framework.Graphics.Sprites;
+using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics.Backgrounds;
using OpenTK.Graphics;
using osu.Game.Beatmaps.ControlPoints;
@@ -148,7 +148,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables.Pieces
private void resetEdgeEffects()
{
- background.EdgeEffect = new EdgeEffect
+ background.EdgeEffect = new EdgeEffectParameters
{
Type = EdgeEffectType.Glow,
Colour = AccentColour.Opacity(KiaiMode ? edge_alpha_kiai : 1f),
diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/Pieces/RimHitSymbolPiece.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/Pieces/RimHitSymbolPiece.cs
index 4146edbdf7..704a27a96d 100644
--- a/osu.Game.Rulesets.Taiko/Objects/Drawables/Pieces/RimHitSymbolPiece.cs
+++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/Pieces/RimHitSymbolPiece.cs
@@ -3,9 +3,9 @@
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
-using osu.Framework.Graphics.Sprites;
using OpenTK;
using OpenTK.Graphics;
+using osu.Framework.Graphics.Shapes;
namespace osu.Game.Rulesets.Taiko.Objects.Drawables.Pieces
{
diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/Pieces/TickPiece.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/Pieces/TickPiece.cs
index 1a0d0156e8..2af65f2ed7 100644
--- a/osu.Game.Rulesets.Taiko/Objects/Drawables/Pieces/TickPiece.cs
+++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/Pieces/TickPiece.cs
@@ -3,9 +3,9 @@
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
-using osu.Framework.Graphics.Sprites;
using OpenTK;
using OpenTK.Graphics;
+using osu.Framework.Graphics.Shapes;
namespace osu.Game.Rulesets.Taiko.Objects.Drawables.Pieces
{
diff --git a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs
index 7c169f820b..303d936fb9 100644
--- a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs
+++ b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs
@@ -28,7 +28,14 @@ namespace osu.Game.Rulesets.Taiko
{
new TaikoModEasy(),
new TaikoModNoFail(),
- new TaikoModHalfTime(),
+ new MultiMod
+ {
+ Mods = new Mod[]
+ {
+ new TaikoModHalfTime(),
+ new TaikoModDaycore(),
+ },
+ },
};
case ModType.DifficultyIncrease:
diff --git a/osu.Game.Rulesets.Taiko/UI/HitExplosion.cs b/osu.Game.Rulesets.Taiko/UI/HitExplosion.cs
index c0c329c870..4d39ba0ead 100644
--- a/osu.Game.Rulesets.Taiko/UI/HitExplosion.cs
+++ b/osu.Game.Rulesets.Taiko/UI/HitExplosion.cs
@@ -6,7 +6,7 @@ using OpenTK.Graphics;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
-using osu.Framework.Graphics.Sprites;
+using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics;
using osu.Game.Rulesets.Taiko.Judgements;
using osu.Game.Rulesets.Taiko.Objects;
diff --git a/osu.Game.Rulesets.Taiko/UI/HitTarget.cs b/osu.Game.Rulesets.Taiko/UI/HitTarget.cs
index fde2623246..1ca6e4eb34 100644
--- a/osu.Game.Rulesets.Taiko/UI/HitTarget.cs
+++ b/osu.Game.Rulesets.Taiko/UI/HitTarget.cs
@@ -5,7 +5,7 @@ using OpenTK;
using OpenTK.Graphics;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
-using osu.Framework.Graphics.Sprites;
+using osu.Framework.Graphics.Shapes;
using osu.Game.Rulesets.Taiko.Objects;
namespace osu.Game.Rulesets.Taiko.UI
diff --git a/osu.Game.Rulesets.Taiko/UI/KiaiHitExplosion.cs b/osu.Game.Rulesets.Taiko/UI/KiaiHitExplosion.cs
index e0da3ed3db..b4aec7057b 100644
--- a/osu.Game.Rulesets.Taiko/UI/KiaiHitExplosion.cs
+++ b/osu.Game.Rulesets.Taiko/UI/KiaiHitExplosion.cs
@@ -5,7 +5,7 @@ using OpenTK;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
-using osu.Framework.Graphics.Sprites;
+using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics;
using osu.Game.Rulesets.Taiko.Judgements;
using osu.Game.Rulesets.Taiko.Objects;
@@ -47,7 +47,7 @@ namespace osu.Game.Rulesets.Taiko.UI
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
- EdgeEffect = new EdgeEffect
+ EdgeEffect = new EdgeEffectParameters
{
Type = EdgeEffectType.Glow,
Colour = isRim ? colours.BlueDarker : colours.PinkDarker,
diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs
index c7bd4a6704..0ad7969c78 100644
--- a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs
+++ b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs
@@ -3,7 +3,7 @@
using osu.Framework.Allocation;
using osu.Framework.Graphics;
-using osu.Framework.Graphics.Sprites;
+using osu.Framework.Graphics.Shapes;
using osu.Game.Rulesets.Taiko.Objects;
using osu.Game.Rulesets.UI;
using OpenTK;
@@ -68,7 +68,7 @@ namespace osu.Game.Rulesets.Taiko.UI
RelativeSizeAxes = Axes.Both,
BorderThickness = 2,
Masking = true,
- EdgeEffect = new EdgeEffect
+ EdgeEffect = new EdgeEffectParameters
{
Type = EdgeEffectType.Shadow,
Colour = Color4.Black.Opacity(0.2f),
@@ -229,7 +229,6 @@ namespace osu.Game.Rulesets.Taiko.UI
if (judgedObject.HitObject.Kiai)
kiaiExplosionContainer.Add(new KiaiHitExplosion(judgedObject.Judgement, isRim));
-
}
else
hitExplosionContainer.Children.FirstOrDefault(e => e.Judgement == judgedObject.Judgement)?.VisualiseSecondHit();
diff --git a/osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj b/osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj
index 8d6fcb503c..f719f2002b 100644
--- a/osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj
+++ b/osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj
@@ -33,8 +33,9 @@
false
-
- $(SolutionDir)\packages\ppy.OpenTK.2.0.50727.1341\lib\net45\OpenTK.dll
+
+ $(SolutionDir)\packages\ppy.OpenTK.3.0\lib\net45\OpenTK.dll
+ True
diff --git a/osu.Game.Rulesets.Taiko/packages.config b/osu.Game.Rulesets.Taiko/packages.config
index dc059c684b..8add43d5d5 100644
--- a/osu.Game.Rulesets.Taiko/packages.config
+++ b/osu.Game.Rulesets.Taiko/packages.config
@@ -4,5 +4,5 @@ Copyright (c) 2007-2017 ppy Pty Ltd .
Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-->
-
+
\ No newline at end of file
diff --git a/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs b/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs
index 0e456941a1..4a6b972f4a 100644
--- a/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs
+++ b/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs
@@ -56,7 +56,7 @@ namespace osu.Game.Tests.Beatmaps.IO
Assert.IsTrue(File.Exists(temp));
var importer = new BeatmapIPCChannel(client);
- if (!importer.ImportAsync(temp).Wait(5000))
+ if (!importer.ImportAsync(temp).Wait(10000))
Assert.Fail(@"IPC took too long to send");
ensureLoaded(host);
@@ -166,4 +166,3 @@ namespace osu.Game.Tests.Beatmaps.IO
}
}
}
-
diff --git a/osu.Game.Tests/Beatmaps/IO/OszArchiveReaderTest.cs b/osu.Game.Tests/Beatmaps/IO/OszArchiveReaderTest.cs
index 03d09e24e0..c9b3b1b922 100644
--- a/osu.Game.Tests/Beatmaps/IO/OszArchiveReaderTest.cs
+++ b/osu.Game.Tests/Beatmaps/IO/OszArchiveReaderTest.cs
@@ -86,4 +86,3 @@ namespace osu.Game.Tests.Beatmaps.IO
}
}
}
-
diff --git a/osu.Game.Tests/osu.Game.Tests.csproj b/osu.Game.Tests/osu.Game.Tests.csproj
index b8fcb80aaf..8ec68b41be 100644
--- a/osu.Game.Tests/osu.Game.Tests.csproj
+++ b/osu.Game.Tests/osu.Game.Tests.csproj
@@ -30,11 +30,13 @@
false
-
- $(SolutionDir)\packages\NUnit.3.6.1\lib\net45\nunit.framework.dll
+
+ $(SolutionDir)\packages\NUnit.3.7.1\lib\net45\nunit.framework.dll
+ True
-
- $(SolutionDir)\packages\ppy.OpenTK.2.0.50727.1341\lib\net45\OpenTK.dll
+
+ $(SolutionDir)\packages\ppy.OpenTK.3.0\lib\net45\OpenTK.dll
+ True
diff --git a/osu.Game.Tests/packages.config b/osu.Game.Tests/packages.config
index 9972fb41a1..9ad76308d7 100644
--- a/osu.Game.Tests/packages.config
+++ b/osu.Game.Tests/packages.config
@@ -4,8 +4,8 @@ Copyright (c) 2007-2017 ppy Pty Ltd .
Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-->
-
-
+
+
\ No newline at end of file
diff --git a/osu.Game/Beatmaps/ControlPoints/TimingControlPoint.cs b/osu.Game/Beatmaps/ControlPoints/TimingControlPoint.cs
index 6f7e38c163..c7bdbb5dd6 100644
--- a/osu.Game/Beatmaps/ControlPoints/TimingControlPoint.cs
+++ b/osu.Game/Beatmaps/ControlPoints/TimingControlPoint.cs
@@ -15,6 +15,6 @@ namespace osu.Game.Beatmaps.ControlPoints
///
/// The beat length at this control point.
///
- public double BeatLength = 500;
+ public double BeatLength = 1000;
}
}
\ No newline at end of file
diff --git a/osu.Game/Beatmaps/Drawables/BeatmapPanel.cs b/osu.Game/Beatmaps/Drawables/BeatmapPanel.cs
index cb929dcca5..f4ac01c0f1 100644
--- a/osu.Game/Beatmaps/Drawables/BeatmapPanel.cs
+++ b/osu.Game/Beatmaps/Drawables/BeatmapPanel.cs
@@ -14,6 +14,7 @@ using OpenTK;
using OpenTK.Graphics;
using osu.Framework.Input;
using osu.Game.Graphics.Sprites;
+using osu.Framework.Graphics.Shapes;
namespace osu.Game.Beatmaps.Drawables
{
diff --git a/osu.Game/Beatmaps/Drawables/BeatmapSetHeader.cs b/osu.Game/Beatmaps/Drawables/BeatmapSetHeader.cs
index 2ab5487082..1ac6261621 100644
--- a/osu.Game/Beatmaps/Drawables/BeatmapSetHeader.cs
+++ b/osu.Game/Beatmaps/Drawables/BeatmapSetHeader.cs
@@ -12,6 +12,7 @@ using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Localisation;
using osu.Game.Graphics.Sprites;
+using osu.Framework.Graphics.Shapes;
namespace osu.Game.Beatmaps.Drawables
{
diff --git a/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs b/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs
index 9df1f0f284..14298c4172 100644
--- a/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs
+++ b/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs
@@ -10,7 +10,6 @@ using OpenTK.Graphics;
namespace osu.Game.Beatmaps.Drawables
{
-
public class DifficultyIcon : DifficultyColouredContainer
{
private readonly BeatmapInfo beatmap;
diff --git a/osu.Game/Beatmaps/Drawables/Panel.cs b/osu.Game/Beatmaps/Drawables/Panel.cs
index f7349d981a..3dac50732c 100644
--- a/osu.Game/Beatmaps/Drawables/Panel.cs
+++ b/osu.Game/Beatmaps/Drawables/Panel.cs
@@ -88,7 +88,7 @@ namespace osu.Game.Beatmaps.Drawables
protected virtual void Selected()
{
nestedContainer.BorderThickness = 2.5f;
- nestedContainer.EdgeEffect = new EdgeEffect
+ nestedContainer.EdgeEffect = new EdgeEffectParameters
{
Type = EdgeEffectType.Glow,
Colour = new Color4(130, 204, 255, 150),
@@ -100,7 +100,7 @@ namespace osu.Game.Beatmaps.Drawables
protected virtual void Deselected()
{
nestedContainer.BorderThickness = 0;
- nestedContainer.EdgeEffect = new EdgeEffect
+ nestedContainer.EdgeEffect = new EdgeEffectParameters
{
Type = EdgeEffectType.Shadow,
Offset = new Vector2(1),
diff --git a/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs b/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs
index c6aac3bb71..4c540fa8cf 100644
--- a/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs
+++ b/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs
@@ -2,6 +2,7 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
+using System.Collections.Generic;
using System.Globalization;
using System.IO;
using OpenTK.Graphics;
@@ -31,6 +32,8 @@ namespace osu.Game.Beatmaps.Formats
private ConvertHitObjectParser parser;
+ private readonly Dictionary variables = new Dictionary();
+
private LegacySampleBank defaultSampleBank;
private int defaultSampleVolume = 100;
@@ -56,36 +59,39 @@ namespace osu.Game.Beatmaps.Formats
TimingPoints,
Colours,
HitObjects,
+ Variables,
}
- private void handleGeneral(Beatmap beatmap, string key, string val)
+ private void handleGeneral(Beatmap beatmap, string line)
{
+ var pair = splitKeyVal(line, ':');
+
var metadata = beatmap.BeatmapInfo.Metadata;
- switch (key)
+ switch (pair.Key)
{
case @"AudioFilename":
- metadata.AudioFile = val;
+ metadata.AudioFile = pair.Value;
break;
case @"AudioLeadIn":
- beatmap.BeatmapInfo.AudioLeadIn = int.Parse(val);
+ beatmap.BeatmapInfo.AudioLeadIn = int.Parse(pair.Value);
break;
case @"PreviewTime":
- metadata.PreviewTime = int.Parse(val);
+ metadata.PreviewTime = int.Parse(pair.Value);
break;
case @"Countdown":
- beatmap.BeatmapInfo.Countdown = int.Parse(val) == 1;
+ beatmap.BeatmapInfo.Countdown = int.Parse(pair.Value) == 1;
break;
case @"SampleSet":
- defaultSampleBank = (LegacySampleBank)Enum.Parse(typeof(LegacySampleBank), val);
+ defaultSampleBank = (LegacySampleBank)Enum.Parse(typeof(LegacySampleBank), pair.Value);
break;
case @"SampleVolume":
- defaultSampleVolume = int.Parse(val);
+ defaultSampleVolume = int.Parse(pair.Value);
break;
case @"StackLeniency":
- beatmap.BeatmapInfo.StackLeniency = float.Parse(val, NumberFormatInfo.InvariantInfo);
+ beatmap.BeatmapInfo.StackLeniency = float.Parse(pair.Value, NumberFormatInfo.InvariantInfo);
break;
case @"Mode":
- beatmap.BeatmapInfo.RulesetID = int.Parse(val);
+ beatmap.BeatmapInfo.RulesetID = int.Parse(pair.Value);
switch (beatmap.BeatmapInfo.RulesetID)
{
@@ -104,107 +110,135 @@ namespace osu.Game.Beatmaps.Formats
}
break;
case @"LetterboxInBreaks":
- beatmap.BeatmapInfo.LetterboxInBreaks = int.Parse(val) == 1;
+ beatmap.BeatmapInfo.LetterboxInBreaks = int.Parse(pair.Value) == 1;
break;
case @"SpecialStyle":
- beatmap.BeatmapInfo.SpecialStyle = int.Parse(val) == 1;
+ beatmap.BeatmapInfo.SpecialStyle = int.Parse(pair.Value) == 1;
break;
case @"WidescreenStoryboard":
- beatmap.BeatmapInfo.WidescreenStoryboard = int.Parse(val) == 1;
+ beatmap.BeatmapInfo.WidescreenStoryboard = int.Parse(pair.Value) == 1;
break;
}
}
- private void handleEditor(Beatmap beatmap, string key, string val)
+ private void handleEditor(Beatmap beatmap, string line)
{
- switch (key)
+ var pair = splitKeyVal(line, ':');
+
+ switch (pair.Key)
{
case @"Bookmarks":
- beatmap.BeatmapInfo.StoredBookmarks = val;
+ beatmap.BeatmapInfo.StoredBookmarks = pair.Value;
break;
case @"DistanceSpacing":
- beatmap.BeatmapInfo.DistanceSpacing = double.Parse(val, NumberFormatInfo.InvariantInfo);
+ beatmap.BeatmapInfo.DistanceSpacing = double.Parse(pair.Value, NumberFormatInfo.InvariantInfo);
break;
case @"BeatDivisor":
- beatmap.BeatmapInfo.BeatDivisor = int.Parse(val);
+ beatmap.BeatmapInfo.BeatDivisor = int.Parse(pair.Value);
break;
case @"GridSize":
- beatmap.BeatmapInfo.GridSize = int.Parse(val);
+ beatmap.BeatmapInfo.GridSize = int.Parse(pair.Value);
break;
case @"TimelineZoom":
- beatmap.BeatmapInfo.TimelineZoom = double.Parse(val, NumberFormatInfo.InvariantInfo);
+ beatmap.BeatmapInfo.TimelineZoom = double.Parse(pair.Value, NumberFormatInfo.InvariantInfo);
break;
}
}
- private void handleMetadata(Beatmap beatmap, string key, string val)
+ private void handleMetadata(Beatmap beatmap, string line)
{
+ var pair = splitKeyVal(line, ':');
+
var metadata = beatmap.BeatmapInfo.Metadata;
- switch (key)
+ switch (pair.Key)
{
case @"Title":
- metadata.Title = val;
+ metadata.Title = pair.Value;
break;
case @"TitleUnicode":
- metadata.TitleUnicode = val;
+ metadata.TitleUnicode = pair.Value;
break;
case @"Artist":
- metadata.Artist = val;
+ metadata.Artist = pair.Value;
break;
case @"ArtistUnicode":
- metadata.ArtistUnicode = val;
+ metadata.ArtistUnicode = pair.Value;
break;
case @"Creator":
- metadata.Author = val;
+ metadata.Author = pair.Value;
break;
case @"Version":
- beatmap.BeatmapInfo.Version = val;
+ beatmap.BeatmapInfo.Version = pair.Value;
break;
case @"Source":
- beatmap.BeatmapInfo.Metadata.Source = val;
+ beatmap.BeatmapInfo.Metadata.Source = pair.Value;
break;
case @"Tags":
- beatmap.BeatmapInfo.Metadata.Tags = val;
+ beatmap.BeatmapInfo.Metadata.Tags = pair.Value;
break;
case @"BeatmapID":
- beatmap.BeatmapInfo.OnlineBeatmapID = int.Parse(val);
+ beatmap.BeatmapInfo.OnlineBeatmapID = int.Parse(pair.Value);
break;
case @"BeatmapSetID":
- beatmap.BeatmapInfo.OnlineBeatmapSetID = int.Parse(val);
- metadata.OnlineBeatmapSetID = int.Parse(val);
+ beatmap.BeatmapInfo.OnlineBeatmapSetID = int.Parse(pair.Value);
+ metadata.OnlineBeatmapSetID = int.Parse(pair.Value);
break;
}
}
- private void handleDifficulty(Beatmap beatmap, string key, string val)
+ private void handleDifficulty(Beatmap beatmap, string line)
{
+ var pair = splitKeyVal(line, ':');
+
var difficulty = beatmap.BeatmapInfo.Difficulty;
- switch (key)
+ switch (pair.Key)
{
case @"HPDrainRate":
- difficulty.DrainRate = float.Parse(val, NumberFormatInfo.InvariantInfo);
+ difficulty.DrainRate = float.Parse(pair.Value, NumberFormatInfo.InvariantInfo);
break;
case @"CircleSize":
- difficulty.CircleSize = float.Parse(val, NumberFormatInfo.InvariantInfo);
+ difficulty.CircleSize = float.Parse(pair.Value, NumberFormatInfo.InvariantInfo);
break;
case @"OverallDifficulty":
- difficulty.OverallDifficulty = float.Parse(val, NumberFormatInfo.InvariantInfo);
+ difficulty.OverallDifficulty = float.Parse(pair.Value, NumberFormatInfo.InvariantInfo);
break;
case @"ApproachRate":
- difficulty.ApproachRate = float.Parse(val, NumberFormatInfo.InvariantInfo);
+ difficulty.ApproachRate = float.Parse(pair.Value, NumberFormatInfo.InvariantInfo);
break;
case @"SliderMultiplier":
- difficulty.SliderMultiplier = float.Parse(val, NumberFormatInfo.InvariantInfo);
+ difficulty.SliderMultiplier = float.Parse(pair.Value, NumberFormatInfo.InvariantInfo);
break;
case @"SliderTickRate":
- difficulty.SliderTickRate = float.Parse(val, NumberFormatInfo.InvariantInfo);
+ difficulty.SliderTickRate = float.Parse(pair.Value, NumberFormatInfo.InvariantInfo);
break;
}
}
- private void handleEvents(Beatmap beatmap, string val)
+ ///
+ /// Decodes any beatmap variables present in a line into their real values.
+ ///
+ /// The line which may contains variables.
+ private void decodeVariables(ref string line)
{
- string[] split = val.Split(',');
+ while (line.IndexOf('$') >= 0)
+ {
+ string[] split = line.Split(',');
+ for (int i = 0; i < split.Length; i++)
+ {
+ var item = split[i];
+ if (item.StartsWith("$") && variables.ContainsKey(item))
+ split[i] = variables[item];
+ }
+
+ line = string.Join(",", split);
+ }
+ }
+
+ private void handleEvents(Beatmap beatmap, string line)
+ {
+ decodeVariables(ref line);
+
+ string[] split = line.Split(',');
EventType type;
if (!Enum.TryParse(split[0], out type))
@@ -236,9 +270,9 @@ namespace osu.Game.Beatmaps.Formats
}
}
- private void handleTimingPoints(Beatmap beatmap, string val)
+ private void handleTimingPoints(Beatmap beatmap, string line)
{
- string[] split = val.Split(',');
+ string[] split = line.Split(',');
double time = double.Parse(split[0].Trim(), NumberFormatInfo.InvariantInfo);
double beatLength = double.Parse(split[1].Trim(), NumberFormatInfo.InvariantInfo);
@@ -321,12 +355,14 @@ namespace osu.Game.Beatmaps.Formats
}
}
- private void handleColours(Beatmap beatmap, string key, string val, ref bool hasCustomColours)
+ private void handleColours(Beatmap beatmap, string line, ref bool hasCustomColours)
{
- string[] split = val.Split(',');
+ var pair = splitKeyVal(line, ':');
+
+ string[] split = pair.Value.Split(',');
if (split.Length != 3)
- throw new InvalidOperationException($@"Color specified in incorrect format (should be R,G,B): {val}");
+ throw new InvalidOperationException($@"Color specified in incorrect format (should be R,G,B): {pair.Value}");
byte r, g, b;
if (!byte.TryParse(split[0], out r) || !byte.TryParse(split[1], out g) || !byte.TryParse(split[2], out b))
@@ -339,7 +375,7 @@ namespace osu.Game.Beatmaps.Formats
}
// Note: the combo index specified in the beatmap is discarded
- if (key.StartsWith(@"Combo"))
+ if (pair.Key.StartsWith(@"Combo"))
{
beatmap.ComboColors.Add(new Color4
{
@@ -351,6 +387,12 @@ namespace osu.Game.Beatmaps.Formats
}
}
+ private void handleVariables(string line)
+ {
+ var pair = splitKeyVal(line, '=');
+ variables[pair.Key] = pair.Value;
+ }
+
protected override Beatmap ParseFile(StreamReader stream)
{
return new LegacyBeatmap(base.ParseFile(stream));
@@ -390,42 +432,39 @@ namespace osu.Game.Beatmaps.Formats
continue;
}
- string val = line, key = null;
- if (section != Section.Events && section != Section.TimingPoints && section != Section.HitObjects)
- {
- key = val.Remove(val.IndexOf(':')).Trim();
- val = val.Substring(val.IndexOf(':') + 1).Trim();
- }
switch (section)
{
case Section.General:
- handleGeneral(beatmap, key, val);
+ handleGeneral(beatmap, line);
break;
case Section.Editor:
- handleEditor(beatmap, key, val);
+ handleEditor(beatmap, line);
break;
case Section.Metadata:
- handleMetadata(beatmap, key, val);
+ handleMetadata(beatmap, line);
break;
case Section.Difficulty:
- handleDifficulty(beatmap, key, val);
+ handleDifficulty(beatmap, line);
break;
case Section.Events:
- handleEvents(beatmap, val);
+ handleEvents(beatmap, line);
break;
case Section.TimingPoints:
- handleTimingPoints(beatmap, val);
+ handleTimingPoints(beatmap, line);
break;
case Section.Colours:
- handleColours(beatmap, key, val, ref hasCustomColours);
+ handleColours(beatmap, line, ref hasCustomColours);
break;
case Section.HitObjects:
- var obj = parser.Parse(val);
+ var obj = parser.Parse(line);
if (obj != null)
beatmap.HitObjects.Add(obj);
break;
+ case Section.Variables:
+ handleVariables(line);
+ break;
}
}
@@ -433,6 +472,15 @@ namespace osu.Game.Beatmaps.Formats
hitObject.ApplyDefaults(beatmap.ControlPointInfo, beatmap.BeatmapInfo.Difficulty);
}
+ private KeyValuePair splitKeyVal(string line, char separator)
+ {
+ return new KeyValuePair
+ (
+ line.Remove(line.IndexOf(separator)).Trim(),
+ line.Substring(line.IndexOf(separator) + 1).Trim()
+ );
+ }
+
internal enum LegacySampleBank
{
None = 0,
diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs
index 8f177d6b56..6b07d5c967 100644
--- a/osu.Game/Configuration/OsuConfigManager.cs
+++ b/osu.Game/Configuration/OsuConfigManager.cs
@@ -13,17 +13,17 @@ namespace osu.Game.Configuration
protected override void InitialiseDefaults()
{
// UI/selection defaults
-
Set(OsuSetting.Ruleset, 0, 0, int.MaxValue);
Set(OsuSetting.BeatmapDetailTab, BeatmapDetailTab.Details);
Set(OsuSetting.DisplayStarsMinimum, 0.0, 0, 10);
Set(OsuSetting.DisplayStarsMaximum, 10.0, 0, 10);
+ Set(OsuSetting.SelectionRandomType, SelectionRandomType.RandomPermutation);
+
Set(OsuSetting.ChatDisplayHeight, ChatOverlay.DEFAULT_HEIGHT, 0.2, 1);
// Online settings
-
Set(OsuSetting.Username, string.Empty);
Set(OsuSetting.Token, string.Empty);
@@ -38,14 +38,12 @@ namespace osu.Game.Configuration
};
// Audio
-
Set(OsuSetting.MenuVoice, true);
Set(OsuSetting.MenuMusic, true);
Set(OsuSetting.AudioOffset, 0, -500.0, 500.0);
// Input
-
Set(OsuSetting.MenuCursorSize, 1.0, 0.5f, 2);
Set(OsuSetting.GameplayCursorSize, 1.0, 0.5f, 2);
Set(OsuSetting.AutoCursorSize, false);
@@ -54,7 +52,6 @@ namespace osu.Game.Configuration
Set(OsuSetting.MouseDisableWheel, false);
// Graphics
-
Set(OsuSetting.ShowFpsDisplay, false);
Set(OsuSetting.MenuParallax, true);
@@ -63,14 +60,15 @@ namespace osu.Game.Configuration
Set(OsuSetting.SnakingOutSliders, true);
// Gameplay
-
Set(OsuSetting.DimLevel, 0.3, 0, 1);
Set(OsuSetting.ShowInterface, true);
Set(OsuSetting.KeyOverlay, false);
- // Update
+ Set(OsuSetting.FloatingComments, false);
+ Set(OsuSetting.PlaybackSpeed, 1.0, 0.5f, 2);
+ // Update
Set(OsuSetting.ReleaseStream, ReleaseStream.Lazer);
}
@@ -88,6 +86,8 @@ namespace osu.Game.Configuration
AutoCursorSize,
DimLevel,
KeyOverlay,
+ FloatingComments,
+ PlaybackSpeed,
ShowInterface,
MouseDisableButtons,
MouseDisableWheel,
@@ -102,6 +102,7 @@ namespace osu.Game.Configuration
SaveUsername,
DisplayStarsMinimum,
DisplayStarsMaximum,
+ SelectionRandomType,
SnakingInSliders,
SnakingOutSliders,
ShowFpsDisplay,
diff --git a/osu.Game/Configuration/SelectionRandomType.cs b/osu.Game/Configuration/SelectionRandomType.cs
new file mode 100644
index 0000000000..298ee71e36
--- /dev/null
+++ b/osu.Game/Configuration/SelectionRandomType.cs
@@ -0,0 +1,15 @@
+// Copyright (c) 2007-2017 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using System.ComponentModel;
+
+namespace osu.Game.Configuration
+{
+ public enum SelectionRandomType
+ {
+ [Description("Never repeat")]
+ RandomPermutation,
+ [Description("Random")]
+ Random
+ }
+}
\ No newline at end of file
diff --git a/osu.Game/Database/BeatmapDifficulty.cs b/osu.Game/Database/BeatmapDifficulty.cs
index cf1305f705..87c651aa88 100644
--- a/osu.Game/Database/BeatmapDifficulty.cs
+++ b/osu.Game/Database/BeatmapDifficulty.cs
@@ -39,4 +39,3 @@ namespace osu.Game.Database
}
}
}
-
diff --git a/osu.Game/Database/BeatmapSetInfo.cs b/osu.Game/Database/BeatmapSetInfo.cs
index 0875d3c01f..aa5fa21394 100644
--- a/osu.Game/Database/BeatmapSetInfo.cs
+++ b/osu.Game/Database/BeatmapSetInfo.cs
@@ -36,4 +36,3 @@ namespace osu.Game.Database
public string StoryboardFile { get; set; }
}
}
-
diff --git a/osu.Game/Graphics/Backgrounds/Triangles.cs b/osu.Game/Graphics/Backgrounds/Triangles.cs
index 7a2345a80c..08745ce6ba 100644
--- a/osu.Game/Graphics/Backgrounds/Triangles.cs
+++ b/osu.Game/Graphics/Backgrounds/Triangles.cs
@@ -2,12 +2,10 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Graphics;
-using osu.Framework.Graphics.Containers;
using osu.Framework.MathUtils;
using OpenTK;
using OpenTK.Graphics;
using System;
-using osu.Framework.Graphics.OpenGL;
using osu.Framework.Graphics.Shaders;
using osu.Framework.Graphics.Textures;
using OpenTK.Graphics.ES30;
@@ -16,6 +14,7 @@ using osu.Framework.Graphics.Primitives;
using osu.Framework.Allocation;
using System.Collections.Generic;
using osu.Framework.Graphics.Batches;
+using osu.Framework.Graphics.OpenGL.Vertices;
using osu.Framework.Lists;
namespace osu.Game.Graphics.Backgrounds
@@ -56,7 +55,7 @@ namespace osu.Game.Graphics.Backgrounds
///
/// Whether we should drop-off alpha values of triangles more quickly to improve
/// the visual appearance of fading. This defaults to on as it is generally more
- /// aesthetically pleasing, but should be turned off in s.
+ /// aesthetically pleasing, but should be turned off in buffered containers.
///
public bool HideAlphaDiscrepancies = true;
diff --git a/osu.Game/Graphics/Containers/ReverseDepthFillFlowContainer.cs b/osu.Game/Graphics/Containers/ReverseDepthFillFlowContainer.cs
index 2b52b06abc..0b38bf5fe0 100644
--- a/osu.Game/Graphics/Containers/ReverseDepthFillFlowContainer.cs
+++ b/osu.Game/Graphics/Containers/ReverseDepthFillFlowContainer.cs
@@ -10,7 +10,7 @@ namespace osu.Game.Graphics.Containers
{
public class ReverseDepthFillFlowContainer : FillFlowContainer where T : Drawable
{
- protected override IComparer DepthComparer => new ReverseCreationOrderDepthComparer();
- protected override IEnumerable FlowingChildren => base.FlowingChildren.Reverse();
+ protected override IComparer DepthComparer => new ReverseCreationOrderDepthComparer();
+ protected override IEnumerable FlowingChildren => base.FlowingChildren.Reverse();
}
}
diff --git a/osu.Game/Graphics/Cursor/CursorTrail.cs b/osu.Game/Graphics/Cursor/CursorTrail.cs
index 11475a0f19..183679fbd3 100644
--- a/osu.Game/Graphics/Cursor/CursorTrail.cs
+++ b/osu.Game/Graphics/Cursor/CursorTrail.cs
@@ -8,13 +8,13 @@ using osu.Framework.Graphics.Textures;
using osu.Framework.Input;
using OpenTK;
using System;
-using osu.Framework.Graphics.OpenGL;
using osu.Framework.Graphics.OpenGL.Buffers;
using OpenTK.Graphics.ES30;
using osu.Framework.Graphics.Primitives;
using osu.Framework.Graphics.Colour;
using osu.Framework.Timing;
using System.Diagnostics;
+using osu.Framework.Graphics.OpenGL.Vertices;
namespace osu.Game.Graphics.Cursor
{
diff --git a/osu.Game/Graphics/Cursor/GameplayCursor.cs b/osu.Game/Graphics/Cursor/GameplayCursor.cs
index 801fe1d011..da3975f606 100644
--- a/osu.Game/Graphics/Cursor/GameplayCursor.cs
+++ b/osu.Game/Graphics/Cursor/GameplayCursor.cs
@@ -9,7 +9,7 @@ using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Cursor;
-using osu.Framework.Graphics.Sprites;
+using osu.Framework.Graphics.Shapes;
using osu.Framework.Input;
using osu.Game.Beatmaps;
using osu.Game.Configuration;
@@ -67,7 +67,7 @@ namespace osu.Game.Graphics.Cursor
Masking = true,
BorderThickness = Size.X / 6,
BorderColour = Color4.White,
- EdgeEffect = new EdgeEffect
+ EdgeEffect = new EdgeEffectParameters
{
Type = EdgeEffectType.Shadow,
Colour = Color4.Pink.Opacity(0.5f),
diff --git a/osu.Game/Graphics/Cursor/MenuCursor.cs b/osu.Game/Graphics/Cursor/MenuCursor.cs
index b48ab879a6..82ae424ab0 100644
--- a/osu.Game/Graphics/Cursor/MenuCursor.cs
+++ b/osu.Game/Graphics/Cursor/MenuCursor.cs
@@ -93,6 +93,7 @@ namespace osu.Game.Graphics.Cursor
{
private Container cursorContainer;
private Bindable cursorScale;
+ private const float base_scale = 0.15f;
public Sprite AdditiveLayer;
@@ -108,17 +109,15 @@ namespace osu.Game.Graphics.Cursor
{
cursorContainer = new Container
{
- Size = new Vector2(32),
+ AutoSizeAxes = Axes.Both,
Children = new Drawable[]
{
new Sprite
{
- FillMode = FillMode.Fit,
Texture = textures.Get(@"Cursor/menu-cursor"),
},
AdditiveLayer = new Sprite
{
- FillMode = FillMode.Fit,
BlendingMode = BlendingMode.Additive,
Colour = colour.Pink,
Alpha = 0,
@@ -129,7 +128,7 @@ namespace osu.Game.Graphics.Cursor
};
cursorScale = config.GetBindable(OsuSetting.MenuCursorSize);
- cursorScale.ValueChanged += newScale => cursorContainer.Scale = new Vector2((float)newScale);
+ cursorScale.ValueChanged += newScale => cursorContainer.Scale = new Vector2((float)newScale * base_scale);
cursorScale.TriggerChange();
}
}
diff --git a/osu.Game/Graphics/Cursor/OsuContextMenuContainer.cs b/osu.Game/Graphics/Cursor/OsuContextMenuContainer.cs
new file mode 100644
index 0000000000..2cc6c3a46a
--- /dev/null
+++ b/osu.Game/Graphics/Cursor/OsuContextMenuContainer.cs
@@ -0,0 +1,18 @@
+// Copyright (c) 2007-2017 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using osu.Framework.Graphics.Cursor;
+using osu.Framework.Graphics.UserInterface;
+using osu.Game.Graphics.UserInterface;
+
+namespace osu.Game.Graphics.Cursor
+{
+ public class OsuContextMenuContainer : ContextMenuContainer
+ {
+ protected override ContextMenu CreateContextMenu() => new OsuContextMenu();
+
+ public OsuContextMenuContainer(CursorContainer cursor) : base(cursor)
+ {
+ }
+ }
+}
\ No newline at end of file
diff --git a/osu.Game/Graphics/Cursor/OsuCursorContainer.cs b/osu.Game/Graphics/Cursor/OsuCursorContainer.cs
deleted file mode 100644
index 8b71182263..0000000000
--- a/osu.Game/Graphics/Cursor/OsuCursorContainer.cs
+++ /dev/null
@@ -1,129 +0,0 @@
-// 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.Configuration;
-using osu.Framework.Extensions.Color4Extensions;
-using osu.Framework.Graphics;
-using osu.Framework.Graphics.Containers;
-using osu.Framework.Graphics.Cursor;
-using osu.Framework.Graphics.Sprites;
-using osu.Framework.Graphics.Transforms;
-using osu.Framework.Input;
-using osu.Game.Configuration;
-using System;
-
-namespace osu.Game.Graphics.Cursor
-{
- public class OsuCursorContainer : CursorContainer
- {
- protected override Drawable CreateCursor() => new OsuCursor();
-
- public OsuCursorContainer()
- {
- Add(new CursorTrail { Depth = 1 });
- }
-
- protected override bool OnMouseDown(InputState state, MouseDownEventArgs args)
- {
- ActiveCursor.Scale = new Vector2(1);
- ActiveCursor.ScaleTo(1.2f, 100, EasingTypes.OutQuad);
- return base.OnMouseDown(state, args);
- }
-
- protected override bool OnMouseUp(InputState state, MouseUpEventArgs args)
- {
- if (!state.Mouse.HasMainButtonPressed)
- ActiveCursor.ScaleTo(1, 200, EasingTypes.OutQuad);
- return base.OnMouseUp(state, args);
- }
-
- public class OsuCursor : Container
- {
- private Container cursorContainer;
- private Bindable cursorScale;
-
- public OsuCursor()
- {
- Origin = Anchor.Centre;
- Size = new Vector2(42);
- }
-
- [BackgroundDependencyLoader]
- private void load(OsuConfigManager config)
- {
- cursorScale = config.GetBindable(OsuConfig.CursorSize);
-
- Children = new Drawable[]
- {
- cursorContainer = new CircularContainer
- {
- Origin = Anchor.Centre,
- Anchor = Anchor.Centre,
- RelativeSizeAxes = Axes.Both,
- Scale = new Vector2((float)cursorScale),
- Masking = true,
- BorderThickness = Size.X / 6,
- BorderColour = Color4.White,
- EdgeEffect = new EdgeEffect {
- Type = EdgeEffectType.Shadow,
- Colour = Color4.Pink.Opacity(0.5f),
- Radius = 5,
- },
- Children = new Drawable[]
- {
- new Box
- {
- RelativeSizeAxes = Axes.Both,
- Alpha = 0,
- AlwaysPresent = true,
- },
- new CircularContainer
- {
- Origin = Anchor.Centre,
- Anchor = Anchor.Centre,
- RelativeSizeAxes = Axes.Both,
- Masking = true,
- BorderThickness = Size.X / 3,
- BorderColour = Color4.White.Opacity(0.5f),
- Children = new Drawable[]
- {
- new Box
- {
- RelativeSizeAxes = Axes.Both,
- Alpha = 0,
- AlwaysPresent = true,
- },
- },
- },
- new CircularContainer
- {
- Origin = Anchor.Centre,
- Anchor = Anchor.Centre,
- RelativeSizeAxes = Axes.Both,
- Scale = new Vector2(0.1f),
- Masking = true,
- Children = new Drawable[]
- {
- new Box
- {
- RelativeSizeAxes = Axes.Both,
- Colour = Color4.White,
- },
- },
- },
- }
- },
- };
- cursorScale.ValueChanged += scaleChanged;
- }
-
- private void scaleChanged(object sender, EventArgs e)
- {
- cursorContainer.Scale = new Vector2((float)cursorScale);
- }
- }
- }
-}
diff --git a/osu.Game/Graphics/Cursor/OsuTooltipContainer.cs b/osu.Game/Graphics/Cursor/OsuTooltipContainer.cs
new file mode 100644
index 0000000000..133caf8040
--- /dev/null
+++ b/osu.Game/Graphics/Cursor/OsuTooltipContainer.cs
@@ -0,0 +1,109 @@
+// 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.Extensions.Color4Extensions;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Cursor;
+using osu.Framework.Graphics.Shapes;
+using osu.Game.Graphics.Sprites;
+
+namespace osu.Game.Graphics.Cursor
+{
+ public class OsuTooltipContainer : TooltipContainer
+ {
+ protected override Tooltip CreateTooltip() => new OsuTooltip();
+
+ public OsuTooltipContainer(CursorContainer cursor) : base(cursor)
+ {
+ }
+
+ public class OsuTooltip : Tooltip
+ {
+ private readonly Box background;
+ private readonly OsuSpriteText text;
+ private bool instantMovement = true;
+
+ public override string TooltipText
+ {
+ set
+ {
+ if (value == text.Text) return;
+
+ text.Text = value;
+ if (IsPresent)
+ {
+ AutoSizeDuration = 250;
+ background.FlashColour(OsuColour.Gray(0.4f), 1000, EasingTypes.OutQuint);
+ }
+ else
+ AutoSizeDuration = 0;
+ }
+ }
+
+ private const float text_size = 16;
+
+ public OsuTooltip()
+ {
+ AutoSizeEasing = EasingTypes.OutQuint;
+
+ CornerRadius = 5;
+ Masking = true;
+ EdgeEffect = new EdgeEffectParameters
+ {
+ Type = EdgeEffectType.Shadow,
+ Colour = Color4.Black.Opacity(40),
+ Radius = 5,
+ };
+ Children = new Drawable[]
+ {
+ background = new Box
+ {
+ RelativeSizeAxes = Axes.Both,
+ Alpha = 0.9f,
+ },
+ text = new OsuSpriteText
+ {
+ TextSize = text_size,
+ Padding = new MarginPadding(5),
+ Font = @"Exo2.0-Regular",
+ }
+ };
+ }
+
+ [BackgroundDependencyLoader]
+ private void load(OsuColour colour)
+ {
+ background.Colour = colour.Gray3;
+ }
+
+ protected override void PopIn()
+ {
+ instantMovement |= !IsPresent;
+ FadeIn(500, EasingTypes.OutQuint);
+ }
+
+ protected override void PopOut()
+ {
+ using (BeginDelayedSequence(150))
+ FadeOut(500, EasingTypes.OutQuint);
+ }
+
+ public override void Move(Vector2 pos)
+ {
+ if (instantMovement)
+ {
+ Position = pos;
+ instantMovement = false;
+ }
+ else
+ {
+ MoveTo(pos, 200, EasingTypes.OutQuint);
+ }
+ }
+ }
+ }
+}
diff --git a/osu.Game/Graphics/Cursor/TooltipContainer.cs b/osu.Game/Graphics/Cursor/TooltipContainer.cs
deleted file mode 100644
index c5b8382816..0000000000
--- a/osu.Game/Graphics/Cursor/TooltipContainer.cs
+++ /dev/null
@@ -1,157 +0,0 @@
-// 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.Extensions.Color4Extensions;
-using osu.Framework.Graphics;
-using osu.Framework.Graphics.Containers;
-using osu.Framework.Graphics.Cursor;
-using osu.Framework.Graphics.Sprites;
-using osu.Framework.Input;
-using osu.Framework.Threading;
-using osu.Game.Graphics.Sprites;
-using System.Linq;
-
-namespace osu.Game.Graphics.Cursor
-{
- public class TooltipContainer : Container
- {
- private readonly CursorContainer cursor;
- private readonly Tooltip tooltip;
-
- private ScheduledDelegate findTooltipTask;
- private UserInputManager inputManager;
-
- private const int default_appear_delay = 220;
-
- private IHasTooltip currentlyDisplayed;
-
- public TooltipContainer(CursorContainer cursor)
- {
- this.cursor = cursor;
- AlwaysPresent = true;
- RelativeSizeAxes = Axes.Both;
- Add(tooltip = new Tooltip { Alpha = 0 });
- }
-
- [BackgroundDependencyLoader]
- private void load(UserInputManager input)
- {
- inputManager = input;
- }
-
- protected override void Update()
- {
- if (tooltip.IsPresent)
- {
- if (currentlyDisplayed != null)
- tooltip.TooltipText = currentlyDisplayed.TooltipText;
-
- //update the position of the displayed tooltip.
- tooltip.Position = ToLocalSpace(cursor.ActiveCursor.ScreenSpaceDrawQuad.Centre) + new Vector2(10);
- }
- }
-
- protected override bool OnMouseUp(InputState state, MouseUpEventArgs args)
- {
- updateTooltipState(state);
- return base.OnMouseUp(state, args);
- }
-
- protected override bool OnMouseMove(InputState state)
- {
- updateTooltipState(state);
- return base.OnMouseMove(state);
- }
-
- private void updateTooltipState(InputState state)
- {
- if (currentlyDisplayed?.Hovering != true)
- {
- if (currentlyDisplayed != null && !state.Mouse.HasMainButtonPressed)
- {
- tooltip.Delay(150);
- tooltip.FadeOut(500, EasingTypes.OutQuint);
- currentlyDisplayed = null;
- }
-
- findTooltipTask?.Cancel();
- findTooltipTask = Scheduler.AddDelayed(delegate
- {
- var tooltipTarget = inputManager.HoveredDrawables.OfType().FirstOrDefault();
-
- if (tooltipTarget == null) return;
-
- tooltip.TooltipText = tooltipTarget.TooltipText;
- tooltip.FadeIn(500, EasingTypes.OutQuint);
-
- currentlyDisplayed = tooltipTarget;
- }, (1 - tooltip.Alpha) * default_appear_delay);
- }
- }
-
- public class Tooltip : Container
- {
- private readonly Box background;
- private readonly OsuSpriteText text;
-
- public string TooltipText
- {
- set
- {
- if (value == text.Text) return;
-
- text.Text = value;
- if (Alpha > 0)
- {
- AutoSizeDuration = 250;
- background.FlashColour(OsuColour.Gray(0.4f), 1000, EasingTypes.OutQuint);
- }
- else
- AutoSizeDuration = 0;
- }
- }
-
- public override bool HandleInput => false;
-
- private const float text_size = 16;
-
- public Tooltip()
- {
- AutoSizeEasing = EasingTypes.OutQuint;
- AutoSizeAxes = Axes.Both;
-
- CornerRadius = 5;
- Masking = true;
- EdgeEffect = new EdgeEffect
- {
- Type = EdgeEffectType.Shadow,
- Colour = Color4.Black.Opacity(40),
- Radius = 5,
- };
- Children = new Drawable[]
- {
- background = new Box
- {
- RelativeSizeAxes = Axes.Both,
- Alpha = 0.9f,
- },
- text = new OsuSpriteText
- {
- TextSize = text_size,
- Padding = new MarginPadding(5),
- Font = @"Exo2.0-Regular",
- }
- };
- }
-
- [BackgroundDependencyLoader]
- private void load(OsuColour colour)
- {
- background.Colour = colour.Gray3;
- }
- }
- }
-}
diff --git a/osu.Game/Graphics/IHasAccentColour.cs b/osu.Game/Graphics/IHasAccentColour.cs
index e4647f22fd..672c59a935 100644
--- a/osu.Game/Graphics/IHasAccentColour.cs
+++ b/osu.Game/Graphics/IHasAccentColour.cs
@@ -3,6 +3,7 @@
using OpenTK.Graphics;
using osu.Framework.Graphics;
+using osu.Framework.Graphics.Transforms;
using osu.Game.Graphics.Transforms;
namespace osu.Game.Graphics
@@ -26,7 +27,8 @@ namespace osu.Game.Graphics
/// The new accent colour.
/// The tween duration.
/// The tween easing.
- public static void FadeAccent(this IHasAccentColour accentedDrawable, Color4 newColour, double duration = 0, EasingTypes easing = EasingTypes.None)
+ public static void FadeAccent(this T accentedDrawable, Color4 newColour, double duration = 0, EasingTypes easing = EasingTypes.None)
+ where T : Transformable, IHasAccentColour
{
accentedDrawable.TransformTo(() => accentedDrawable.AccentColour, newColour, duration, easing, new TransformAccent());
}
diff --git a/osu.Game/Graphics/IHasTooltip.cs b/osu.Game/Graphics/IHasTooltip.cs
deleted file mode 100644
index dd51d68c41..0000000000
--- a/osu.Game/Graphics/IHasTooltip.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-// Copyright (c) 2007-2017 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-
-using osu.Framework.Graphics;
-
-namespace osu.Game.Graphics
-{
- public interface IHasTooltip : IDrawable
- {
- ///
- /// Tooltip that shows when hovering the drawable
- ///
- string TooltipText { get; }
- }
-}
diff --git a/osu.Game/Graphics/OsuColour.cs b/osu.Game/Graphics/OsuColour.cs
index 3d83668d07..d2f4d4768c 100644
--- a/osu.Game/Graphics/OsuColour.cs
+++ b/osu.Game/Graphics/OsuColour.cs
@@ -87,5 +87,7 @@ namespace osu.Game.Graphics
public readonly Color4 RedDarker = FromHex(@"870000");
public readonly Color4 ChatBlue = FromHex(@"17292e");
+
+ public readonly Color4 ContextMenuGray = FromHex(@"223034");
}
}
diff --git a/osu.Game/Graphics/Transforms/TransformAccent.cs b/osu.Game/Graphics/Transforms/TransformAccent.cs
index 406d1ea9eb..d49f969c20 100644
--- a/osu.Game/Graphics/Transforms/TransformAccent.cs
+++ b/osu.Game/Graphics/Transforms/TransformAccent.cs
@@ -8,7 +8,7 @@ using osu.Framework.MathUtils;
namespace osu.Game.Graphics.Transforms
{
- public class TransformAccent : Transform
+ public class TransformAccent : Transform
{
///
/// Current value of the transformed colour in linear colour space.
diff --git a/osu.Game/Graphics/UserInterface/Bar.cs b/osu.Game/Graphics/UserInterface/Bar.cs
index 76b75f1084..1da73a60a2 100644
--- a/osu.Game/Graphics/UserInterface/Bar.cs
+++ b/osu.Game/Graphics/UserInterface/Bar.cs
@@ -5,7 +5,7 @@ using OpenTK;
using OpenTK.Graphics;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
-using osu.Framework.Graphics.Sprites;
+using osu.Framework.Graphics.Shapes;
using System;
namespace osu.Game.Graphics.UserInterface
@@ -81,7 +81,7 @@ namespace osu.Game.Graphics.UserInterface
background = new Box
{
RelativeSizeAxes = Axes.Both,
- Colour = new Color4(0,0,0,0)
+ Colour = new Color4(0, 0, 0, 0)
},
bar = new Box
{
diff --git a/osu.Game/Graphics/UserInterface/DialogButton.cs b/osu.Game/Graphics/UserInterface/DialogButton.cs
index c935d58a4b..10c821e9bd 100644
--- a/osu.Game/Graphics/UserInterface/DialogButton.cs
+++ b/osu.Game/Graphics/UserInterface/DialogButton.cs
@@ -5,6 +5,7 @@ using OpenTK;
using OpenTK.Graphics;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Colour;
+using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Containers;
using osu.Framework.Audio.Sample;
@@ -222,7 +223,7 @@ namespace osu.Game.Graphics.UserInterface
Width = 0.8f,
Masking = true,
MaskingSmoothness = 2,
- EdgeEffect = new EdgeEffect
+ EdgeEffect = new EdgeEffectParameters
{
Type = EdgeEffectType.Shadow,
Colour = Color4.Black.Opacity(0.2f),
diff --git a/osu.Game/Graphics/UserInterface/FocusedTextBox.cs b/osu.Game/Graphics/UserInterface/FocusedTextBox.cs
index fe1d255bba..42fff0f258 100644
--- a/osu.Game/Graphics/UserInterface/FocusedTextBox.cs
+++ b/osu.Game/Graphics/UserInterface/FocusedTextBox.cs
@@ -37,11 +37,10 @@ namespace osu.Game.Graphics.UserInterface
this.inputManager = inputManager;
}
- protected override bool OnFocus(InputState state)
+ protected override void OnFocus(InputState state)
{
- var result = base.OnFocus(state);
+ base.OnFocus(state);
BorderThickness = 0;
- return result;
}
protected override void OnFocusLost(InputState state)
@@ -56,6 +55,6 @@ namespace osu.Game.Graphics.UserInterface
base.OnFocusLost(state);
}
- public override bool RequestingFocus => HoldFocus;
+ public override bool RequestsFocus => HoldFocus;
}
}
diff --git a/osu.Game/Graphics/UserInterface/IconButton.cs b/osu.Game/Graphics/UserInterface/IconButton.cs
new file mode 100644
index 0000000000..8540b35702
--- /dev/null
+++ b/osu.Game/Graphics/UserInterface/IconButton.cs
@@ -0,0 +1,114 @@
+// 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.Extensions.Color4Extensions;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Shapes;
+using osu.Framework.Input;
+
+namespace osu.Game.Graphics.UserInterface
+{
+ public class IconButton : ClickableContainer
+ {
+ private readonly TextAwesome icon;
+ private readonly Box hover;
+ private readonly Container content;
+
+ public FontAwesome Icon
+ {
+ get { return icon.Icon; }
+ set { icon.Icon = value; }
+ }
+
+ private const float button_size = 30;
+ private Color4 flashColour;
+
+ public Vector2 IconScale
+ {
+ get { return icon.Scale; }
+ set { icon.Scale = value; }
+ }
+
+ public IconButton()
+ {
+ AutoSizeAxes = Axes.Both;
+
+ Origin = Anchor.Centre;
+ Anchor = Anchor.Centre;
+
+ Children = new Drawable[]
+ {
+ content = new Container
+ {
+ Origin = Anchor.Centre,
+ Anchor = Anchor.Centre,
+ Size = new Vector2 (button_size),
+
+ CornerRadius = 5,
+ Masking = true,
+ EdgeEffect = new EdgeEffectParameters
+ {
+ Colour = Color4.Black.Opacity(0.04f),
+ Type = EdgeEffectType.Shadow,
+ Radius = 5,
+ },
+ Children = new Drawable[]
+ {
+ hover = new Box
+ {
+ RelativeSizeAxes = Axes.Both,
+ Alpha = 0,
+ },
+ icon = new TextAwesome
+ {
+ Origin = Anchor.Centre,
+ Anchor = Anchor.Centre,
+ TextSize = 18,
+ }
+ }
+ }
+ };
+ }
+
+ [BackgroundDependencyLoader]
+ private void load(OsuColour colours)
+ {
+ hover.Colour = colours.Yellow.Opacity(0.6f);
+ flashColour = colours.Yellow;
+ }
+
+ protected override bool OnHover(InputState state)
+ {
+ hover.FadeIn(500, EasingTypes.OutQuint);
+ return base.OnHover(state);
+ }
+
+ protected override void OnHoverLost(InputState state)
+ {
+ hover.FadeOut(500, EasingTypes.OutQuint);
+ base.OnHoverLost(state);
+ }
+
+ protected override bool OnClick(InputState state)
+ {
+ hover.FlashColour(flashColour, 800, EasingTypes.OutQuint);
+ return base.OnClick(state);
+ }
+
+ protected override bool OnMouseDown(InputState state, MouseDownEventArgs args)
+ {
+ content.ScaleTo(0.75f, 2000, EasingTypes.OutQuint);
+ return base.OnMouseDown(state, args);
+ }
+
+ protected override bool OnMouseUp(InputState state, MouseUpEventArgs args)
+ {
+ content.ScaleTo(1, 1000, EasingTypes.OutElastic);
+ return base.OnMouseUp(state, args);
+ }
+ }
+}
diff --git a/osu.Game/Graphics/UserInterface/LoadingAnimation.cs b/osu.Game/Graphics/UserInterface/LoadingAnimation.cs
index 61ec859b44..27a888f0b5 100644
--- a/osu.Game/Graphics/UserInterface/LoadingAnimation.cs
+++ b/osu.Game/Graphics/UserInterface/LoadingAnimation.cs
@@ -1,15 +1,48 @@
// Copyright (c) 2007-2017 ppy Pty Ltd .
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-using osu.Framework.Graphics.Sprites;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using OpenTK;
namespace osu.Game.Graphics.UserInterface
{
- public class LoadingAnimation : SpriteText
+ public class LoadingAnimation : VisibilityContainer
{
+ private readonly TextAwesome spinner;
+
public LoadingAnimation()
{
- Text = "Loading";
+ Size = new Vector2(20);
+
+ Anchor = Anchor.Centre;
+ Origin = Anchor.Centre;
+
+ Children = new Drawable[]
+ {
+ spinner = new TextAwesome
+ {
+ TextSize = 20,
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ Icon = FontAwesome.fa_spinner
+ }
+ };
}
+
+ protected override void LoadComplete()
+ {
+ base.LoadComplete();
+
+ spinner.RotateTo(360, 2000);
+ using (spinner.BeginDelayedSequence(2000))
+ spinner.Loop();
+ }
+
+ private const float transition_duration = 500;
+
+ protected override void PopIn() => FadeIn(transition_duration * 5, EasingTypes.OutQuint);
+
+ protected override void PopOut() => FadeOut(transition_duration, EasingTypes.OutQuint);
}
-}
\ No newline at end of file
+}
diff --git a/osu.Game/Screens/Menu/MenuVisualisation.cs b/osu.Game/Graphics/UserInterface/MenuItemType.cs
similarity index 54%
rename from osu.Game/Screens/Menu/MenuVisualisation.cs
rename to osu.Game/Graphics/UserInterface/MenuItemType.cs
index 85c65b460d..bd89dbfced 100644
--- a/osu.Game/Screens/Menu/MenuVisualisation.cs
+++ b/osu.Game/Graphics/UserInterface/MenuItemType.cs
@@ -1,11 +1,12 @@
// Copyright (c) 2007-2017 ppy Pty Ltd .
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-using osu.Framework.Graphics;
-
-namespace osu.Game.Screens.Menu
+namespace osu.Game.Graphics.UserInterface
{
- internal class MenuVisualisation : Drawable
+ public enum MenuItemType
{
+ Standard,
+ Highlighted,
+ Destructive,
}
-}
+}
\ No newline at end of file
diff --git a/osu.Game/Graphics/UserInterface/Nub.cs b/osu.Game/Graphics/UserInterface/Nub.cs
index 82ede8f079..d5059945c6 100644
--- a/osu.Game/Graphics/UserInterface/Nub.cs
+++ b/osu.Game/Graphics/UserInterface/Nub.cs
@@ -7,18 +7,17 @@ using osu.Framework.Allocation;
using osu.Framework.Configuration;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
-using osu.Framework.Graphics.Sprites;
+using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.UserInterface;
namespace osu.Game.Graphics.UserInterface
{
- public class Nub : CircularContainer, IHasCurrentValue
+ public class Nub : CircularContainer, IHasCurrentValue, IHasAccentColour
{
public const float COLLAPSED_SIZE = 20;
public const float EXPANDED_SIZE = 40;
private const float border_width = 3;
- private Color4 glowingColour, idleColour;
public Nub()
{
@@ -53,33 +52,41 @@ namespace osu.Game.Graphics.UserInterface
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
- Colour = idleColour = colours.Pink;
- glowingColour = colours.PinkLighter;
+ AccentColour = colours.Pink;
+ GlowingAccentColour = colours.PinkLighter;
+ GlowColour = colours.PinkDarker;
- EdgeEffect = new EdgeEffect
+ EdgeEffect = new EdgeEffectParameters
{
- Colour = colours.PinkDarker,
+ Colour = GlowColour,
Type = EdgeEffectType.Glow,
Radius = 10,
Roundness = 8,
};
+ }
+ protected override void LoadComplete()
+ {
FadeEdgeEffectTo(0);
}
+ private bool glowing;
public bool Glowing
{
+ get { return glowing; }
set
{
+ glowing = value;
+
if (value)
{
- FadeColour(glowingColour, 500, EasingTypes.OutQuint);
+ FadeColour(GlowingAccentColour, 500, EasingTypes.OutQuint);
FadeEdgeEffectTo(1, 500, EasingTypes.OutQuint);
}
else
{
FadeEdgeEffectTo(0, 500);
- FadeColour(idleColour, 500);
+ FadeColour(AccentColour, 500);
}
}
}
@@ -93,5 +100,43 @@ namespace osu.Game.Graphics.UserInterface
}
public Bindable Current { get; } = new Bindable();
+
+ private Color4 accentColour;
+ public Color4 AccentColour
+ {
+ get { return accentColour; }
+ set
+ {
+ accentColour = value;
+ if (!Glowing)
+ Colour = value;
+ }
+ }
+
+ private Color4 glowingAccentColour;
+ public Color4 GlowingAccentColour
+ {
+ get { return glowingAccentColour; }
+ set
+ {
+ glowingAccentColour = value;
+ if (Glowing)
+ Colour = value;
+ }
+ }
+
+ private Color4 glowColour;
+ public Color4 GlowColour
+ {
+ get { return glowColour; }
+ set
+ {
+ glowColour = value;
+
+ var effect = EdgeEffect;
+ effect.Colour = value;
+ EdgeEffect = effect;
+ }
+ }
}
}
diff --git a/osu.Game/Graphics/UserInterface/OsuButton.cs b/osu.Game/Graphics/UserInterface/OsuButton.cs
index bee12133ff..7bd58d38a5 100644
--- a/osu.Game/Graphics/UserInterface/OsuButton.cs
+++ b/osu.Game/Graphics/UserInterface/OsuButton.cs
@@ -5,6 +5,7 @@ using OpenTK.Graphics;
using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
+using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.UserInterface;
using osu.Framework.Input;
diff --git a/osu.Game/Graphics/UserInterface/OsuCheckbox.cs b/osu.Game/Graphics/UserInterface/OsuCheckbox.cs
index 85231ffab9..198a01b5a4 100644
--- a/osu.Game/Graphics/UserInterface/OsuCheckbox.cs
+++ b/osu.Game/Graphics/UserInterface/OsuCheckbox.cs
@@ -51,7 +51,8 @@ namespace osu.Game.Graphics.UserInterface
}
}
- private readonly Nub nub;
+ protected readonly Nub Nub;
+
private readonly SpriteText labelSpriteText;
private SampleChannel sampleChecked;
private SampleChannel sampleUnchecked;
@@ -64,7 +65,7 @@ namespace osu.Game.Graphics.UserInterface
Children = new Drawable[]
{
labelSpriteText = new OsuSpriteText(),
- nub = new Nub
+ Nub = new Nub
{
Anchor = Anchor.CentreRight,
Origin = Anchor.CentreRight,
@@ -72,7 +73,7 @@ namespace osu.Game.Graphics.UserInterface
}
};
- nub.Current.BindTo(Current);
+ Nub.Current.BindTo(Current);
Current.ValueChanged += newValue =>
{
@@ -90,15 +91,15 @@ namespace osu.Game.Graphics.UserInterface
protected override bool OnHover(InputState state)
{
- nub.Glowing = true;
- nub.Expanded = true;
+ Nub.Glowing = true;
+ Nub.Expanded = true;
return base.OnHover(state);
}
protected override void OnHoverLost(InputState state)
{
- nub.Glowing = false;
- nub.Expanded = false;
+ Nub.Glowing = false;
+ Nub.Expanded = false;
base.OnHoverLost(state);
}
diff --git a/osu.Game/Graphics/UserInterface/OsuContextMenu.cs b/osu.Game/Graphics/UserInterface/OsuContextMenu.cs
new file mode 100644
index 0000000000..e17ce2a5b2
--- /dev/null
+++ b/osu.Game/Graphics/UserInterface/OsuContextMenu.cs
@@ -0,0 +1,52 @@
+// 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.Extensions.Color4Extensions;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.UserInterface;
+
+namespace osu.Game.Graphics.UserInterface
+{
+ public class OsuContextMenu : ContextMenu
+ where TItem : ContextMenuItem
+ {
+ protected override Menu CreateMenu() => new CustomMenu();
+
+ public class CustomMenu : Menu
+ {
+ private const int fade_duration = 250;
+
+ public CustomMenu()
+ {
+ CornerRadius = 5;
+ ItemsContainer.Padding = new MarginPadding { Vertical = OsuContextMenuItem.MARGIN_VERTICAL };
+ Masking = true;
+ EdgeEffect = new EdgeEffectParameters
+ {
+ Type = EdgeEffectType.Shadow,
+ Colour = Color4.Black.Opacity(0.1f),
+ Radius = 4,
+ };
+ }
+
+ [BackgroundDependencyLoader]
+ private void load(OsuColour colours)
+ {
+ Background.Colour = colours.ContextMenuGray;
+ }
+
+ protected override void AnimateOpen() => FadeIn(fade_duration, EasingTypes.OutQuint);
+ protected override void AnimateClose() => FadeOut(fade_duration, EasingTypes.OutQuint);
+
+ protected override void UpdateContentHeight()
+ {
+ var actualHeight = (RelativeSizeAxes & Axes.Y) > 0 ? 1 : ContentHeight;
+ ResizeTo(new Vector2(1, State == MenuState.Opened ? actualHeight : 0), 300, EasingTypes.OutQuint);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/osu.Game/Graphics/UserInterface/OsuContextMenuItem.cs b/osu.Game/Graphics/UserInterface/OsuContextMenuItem.cs
new file mode 100644
index 0000000000..769df18566
--- /dev/null
+++ b/osu.Game/Graphics/UserInterface/OsuContextMenuItem.cs
@@ -0,0 +1,114 @@
+// Copyright (c) 2007-2017 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using OpenTK.Graphics;
+using osu.Framework.Allocation;
+using osu.Framework.Audio;
+using osu.Framework.Audio.Sample;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.UserInterface;
+using osu.Framework.Input;
+using osu.Game.Graphics.Sprites;
+
+namespace osu.Game.Graphics.UserInterface
+{
+ public class OsuContextMenuItem : ContextMenuItem
+ {
+ private const int transition_length = 80;
+ private const int margin_horizontal = 17;
+ public const int MARGIN_VERTICAL = 4;
+ private const int text_size = 17;
+
+ private OsuSpriteText text;
+ private OsuSpriteText textBold;
+
+ private SampleChannel sampleClick;
+ private SampleChannel sampleHover;
+
+ private readonly MenuItemType type;
+
+ protected override Container CreateTextContainer(string title) => new Container
+ {
+ AutoSizeAxes = Axes.Both,
+ Anchor = Anchor.CentreLeft,
+ Origin = Anchor.CentreLeft,
+ Children = new Drawable[]
+ {
+ text = new OsuSpriteText
+ {
+ Anchor = Anchor.CentreLeft,
+ Origin = Anchor.CentreLeft,
+ TextSize = text_size,
+ Text = title,
+ Margin = new MarginPadding { Horizontal = margin_horizontal, Vertical = MARGIN_VERTICAL },
+ },
+ textBold = new OsuSpriteText
+ {
+ AlwaysPresent = true,
+ Alpha = 0,
+ Anchor = Anchor.CentreLeft,
+ Origin = Anchor.CentreLeft,
+ TextSize = text_size,
+ Text = title,
+ Font = @"Exo2.0-Bold",
+ Margin = new MarginPadding { Horizontal = margin_horizontal, Vertical = MARGIN_VERTICAL },
+ }
+ }
+ };
+
+ public OsuContextMenuItem(string title, MenuItemType type = MenuItemType.Standard) : base(title)
+ {
+ this.type = type;
+ }
+
+ [BackgroundDependencyLoader]
+ private void load(AudioManager audio)
+ {
+ sampleHover = audio.Sample.Get(@"Menu/menuclick");
+ sampleClick = audio.Sample.Get(@"Menu/menuback");
+
+ BackgroundColour = Color4.Transparent;
+ BackgroundColourHover = OsuColour.FromHex(@"172023");
+
+ updateTextColour();
+ }
+
+ private void updateTextColour()
+ {
+ switch (type)
+ {
+ case MenuItemType.Standard:
+ textBold.Colour = text.Colour = Color4.White;
+ break;
+ case MenuItemType.Destructive:
+ textBold.Colour = text.Colour = Color4.Red;
+ break;
+ case MenuItemType.Highlighted:
+ textBold.Colour = text.Colour = OsuColour.FromHex(@"ffcc22");
+ break;
+ }
+ }
+
+ protected override bool OnHover(InputState state)
+ {
+ sampleHover.Play();
+ textBold.FadeIn(transition_length, EasingTypes.OutQuint);
+ text.FadeOut(transition_length, EasingTypes.OutQuint);
+ return base.OnHover(state);
+ }
+
+ protected override void OnHoverLost(InputState state)
+ {
+ textBold.FadeOut(transition_length, EasingTypes.OutQuint);
+ text.FadeIn(transition_length, EasingTypes.OutQuint);
+ base.OnHoverLost(state);
+ }
+
+ protected override bool OnClick(InputState state)
+ {
+ sampleClick.Play();
+ return base.OnClick(state);
+ }
+ }
+}
\ No newline at end of file
diff --git a/osu.Game/Graphics/UserInterface/OsuDropdown.cs b/osu.Game/Graphics/UserInterface/OsuDropdown.cs
index 14483f3bfb..6dadd63ac4 100644
--- a/osu.Game/Graphics/UserInterface/OsuDropdown.cs
+++ b/osu.Game/Graphics/UserInterface/OsuDropdown.cs
@@ -72,7 +72,7 @@ namespace osu.Game.Graphics.UserInterface
Origin = Anchor.CentreLeft,
Anchor = Anchor.CentreLeft,
},
- new OsuSpriteText {
+ Label = new OsuSpriteText {
Text = text,
Origin = Anchor.CentreLeft,
Anchor = Anchor.CentreLeft,
@@ -85,6 +85,7 @@ namespace osu.Game.Graphics.UserInterface
private Color4? accentColour;
protected readonly TextAwesome Chevron;
+ protected readonly OsuSpriteText Label;
protected override void FormatForeground(bool hover = false)
{
@@ -170,4 +171,4 @@ namespace osu.Game.Graphics.UserInterface
}
}
}
-}
\ No newline at end of file
+}
diff --git a/osu.Game/Graphics/UserInterface/OsuEnumDropdown.cs b/osu.Game/Graphics/UserInterface/OsuEnumDropdown.cs
index 5de6507bb3..bf835f0165 100644
--- a/osu.Game/Graphics/UserInterface/OsuEnumDropdown.cs
+++ b/osu.Game/Graphics/UserInterface/OsuEnumDropdown.cs
@@ -16,7 +16,7 @@ namespace osu.Game.Graphics.UserInterface
throw new InvalidOperationException("OsuEnumDropdown only supports enums as the generic type argument");
List> items = new List>();
- foreach(var val in (T[])Enum.GetValues(typeof(T)))
+ foreach (var val in (T[])Enum.GetValues(typeof(T)))
{
var field = typeof(T).GetField(Enum.GetName(typeof(T), val));
items.Add(
diff --git a/osu.Game/Graphics/UserInterface/OsuPasswordTextBox.cs b/osu.Game/Graphics/UserInterface/OsuPasswordTextBox.cs
index 904aa14aa7..dc52fd0f62 100644
--- a/osu.Game/Graphics/UserInterface/OsuPasswordTextBox.cs
+++ b/osu.Game/Graphics/UserInterface/OsuPasswordTextBox.cs
@@ -3,9 +3,9 @@
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
-using osu.Framework.Graphics.Sprites;
using OpenTK;
using OpenTK.Graphics;
+using osu.Framework.Graphics.Shapes;
namespace osu.Game.Graphics.UserInterface
{
diff --git a/osu.Game/Graphics/UserInterface/OsuSliderBar.cs b/osu.Game/Graphics/UserInterface/OsuSliderBar.cs
index 6cf7b2dfa5..4f0ac28731 100644
--- a/osu.Game/Graphics/UserInterface/OsuSliderBar.cs
+++ b/osu.Game/Graphics/UserInterface/OsuSliderBar.cs
@@ -3,25 +3,27 @@
using System;
using OpenTK;
+using OpenTK.Graphics;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Audio.Sample;
using osu.Framework.Configuration;
using osu.Framework.Graphics;
-using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.UserInterface;
using osu.Framework.Input;
+using osu.Framework.Graphics.Cursor;
+using osu.Framework.Graphics.Shapes;
namespace osu.Game.Graphics.UserInterface
{
- public class OsuSliderBar : SliderBar, IHasTooltip
+ public class OsuSliderBar : SliderBar, IHasTooltip, IHasAccentColour
where T : struct, IEquatable
{
private SampleChannel sample;
private double lastSampleTime;
private T lastSampleValue;
- private readonly Nub nub;
+ protected readonly Nub Nub;
private readonly Box leftBox;
private readonly Box rightBox;
@@ -45,6 +47,18 @@ namespace osu.Game.Graphics.UserInterface
}
}
+ private Color4 accentColour;
+ public Color4 AccentColour
+ {
+ get { return accentColour; }
+ set
+ {
+ accentColour = value;
+ leftBox.Colour = value;
+ rightBox.Colour = value;
+ }
+ }
+
public OsuSliderBar()
{
Height = 12;
@@ -70,7 +84,7 @@ namespace osu.Game.Graphics.UserInterface
Origin = Anchor.CentreRight,
Alpha = 0.5f,
},
- nub = new Nub
+ Nub = new Nub
{
Origin = Anchor.TopCentre,
Expanded = true,
@@ -87,19 +101,18 @@ namespace osu.Game.Graphics.UserInterface
private void load(AudioManager audio, OsuColour colours)
{
sample = audio.Sample.Get(@"Sliderbar/sliderbar");
- leftBox.Colour = colours.Pink;
- rightBox.Colour = colours.Pink;
+ AccentColour = colours.Pink;
}
protected override bool OnHover(InputState state)
{
- nub.Glowing = true;
+ Nub.Glowing = true;
return base.OnHover(state);
}
protected override void OnHoverLost(InputState state)
{
- nub.Glowing = false;
+ Nub.Glowing = false;
base.OnHoverLost(state);
}
@@ -132,13 +145,13 @@ namespace osu.Game.Graphics.UserInterface
protected override bool OnMouseDown(InputState state, MouseDownEventArgs args)
{
- nub.Current.Value = true;
+ Nub.Current.Value = true;
return base.OnMouseDown(state, args);
}
protected override bool OnMouseUp(InputState state, MouseUpEventArgs args)
{
- nub.Current.Value = false;
+ Nub.Current.Value = false;
return base.OnMouseUp(state, args);
}
@@ -146,14 +159,14 @@ namespace osu.Game.Graphics.UserInterface
{
base.UpdateAfterChildren();
leftBox.Scale = new Vector2(MathHelper.Clamp(
- nub.DrawPosition.X - nub.DrawWidth / 2, 0, DrawWidth), 1);
+ Nub.DrawPosition.X - Nub.DrawWidth / 2, 0, DrawWidth), 1);
rightBox.Scale = new Vector2(MathHelper.Clamp(
- DrawWidth - nub.DrawPosition.X - nub.DrawWidth / 2, 0, DrawWidth), 1);
+ DrawWidth - Nub.DrawPosition.X - Nub.DrawWidth / 2, 0, DrawWidth), 1);
}
protected override void UpdateValue(float value)
{
- nub.MoveToX(RangePadding + UsableWidth * value, 250, EasingTypes.OutQuint);
+ Nub.MoveToX(RangePadding + UsableWidth * value, 250, EasingTypes.OutQuint);
}
}
}
diff --git a/osu.Game/Graphics/UserInterface/OsuTabControl.cs b/osu.Game/Graphics/UserInterface/OsuTabControl.cs
index 4bbae4efd1..37bf30646d 100644
--- a/osu.Game/Graphics/UserInterface/OsuTabControl.cs
+++ b/osu.Game/Graphics/UserInterface/OsuTabControl.cs
@@ -9,6 +9,7 @@ using osu.Framework.Allocation;
using osu.Framework.Extensions;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
+using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.UserInterface;
using osu.Framework.Input;
@@ -74,21 +75,6 @@ namespace osu.Game.Graphics.UserInterface
}
}
- public override bool Active
- {
- get { return base.Active; }
- set
- {
- if (Active == value) return;
-
- if (value)
- fadeActive();
- else
- fadeInactive();
- base.Active = value;
- }
- }
-
private const float transition_length = 500;
private void fadeActive()
@@ -150,6 +136,10 @@ namespace osu.Game.Graphics.UserInterface
}
};
}
+
+ protected override void OnActivated() => fadeActive();
+
+ protected override void OnDeactivated() => fadeInactive();
}
private class OsuTabDropdown : OsuDropdown
diff --git a/osu.Game/Graphics/UserInterface/OsuTabControlCheckbox.cs b/osu.Game/Graphics/UserInterface/OsuTabControlCheckbox.cs
index 6fc3875f61..940d9b4943 100644
--- a/osu.Game/Graphics/UserInterface/OsuTabControlCheckbox.cs
+++ b/osu.Game/Graphics/UserInterface/OsuTabControlCheckbox.cs
@@ -6,10 +6,11 @@ using OpenTK.Graphics;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Shapes;
+using osu.Game.Graphics.Sprites;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.UserInterface;
using osu.Framework.Input;
-using osu.Game.Graphics.Sprites;
namespace osu.Game.Graphics.UserInterface
{
diff --git a/osu.Game/Graphics/UserInterface/OsuTextBox.cs b/osu.Game/Graphics/UserInterface/OsuTextBox.cs
index 97c38f6b85..3512b4cdb1 100644
--- a/osu.Game/Graphics/UserInterface/OsuTextBox.cs
+++ b/osu.Game/Graphics/UserInterface/OsuTextBox.cs
@@ -45,11 +45,10 @@ namespace osu.Game.Graphics.UserInterface
BorderColour = colour.Yellow;
}
- protected override bool OnFocus(InputState state)
+ protected override void OnFocus(InputState state)
{
BorderThickness = 3;
-
- return base.OnFocus(state);
+ base.OnFocus(state);
}
protected override void OnFocusLost(InputState state)
diff --git a/osu.Game/Overlays/Direct/SortTabControl.cs b/osu.Game/Graphics/UserInterface/PageTabControl.cs
similarity index 67%
rename from osu.Game/Overlays/Direct/SortTabControl.cs
rename to osu.Game/Graphics/UserInterface/PageTabControl.cs
index 4d4e02d875..7f2e6c9c8c 100644
--- a/osu.Game/Overlays/Direct/SortTabControl.cs
+++ b/osu.Game/Graphics/UserInterface/PageTabControl.cs
@@ -7,46 +7,29 @@ using OpenTK.Graphics;
using osu.Framework.Allocation;
using osu.Framework.Extensions;
using osu.Framework.Graphics;
-using osu.Framework.Graphics.Sprites;
+using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.UserInterface;
using osu.Framework.Input;
-using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
-using osu.Game.Graphics.UserInterface;
-namespace osu.Game.Overlays.Direct
+namespace osu.Game.Graphics.UserInterface
{
- public class SortTabControl : OsuTabControl
+ public class PageTabControl : OsuTabControl
{
- protected override TabItem CreateTabItem(SortCriteria value) => new SortTabItem(value);
+ protected override TabItem CreateTabItem(T value) => new PageTabItem(value);
- public SortTabControl()
+ public PageTabControl()
{
Height = 30;
}
- private class SortTabItem : TabItem
+ private class PageTabItem : TabItem
{
private const float transition_duration = 100;
private readonly Box box;
- public override bool Active
- {
- get { return base.Active; }
- set
- {
- if (Active == value) return;
-
- if (value)
- slideActive();
- else
- slideInactive();
- base.Active = value;
- }
- }
-
- public SortTabItem(SortCriteria value) : base(value)
+ public PageTabItem(T value) : base(value)
{
AutoSizeAxes = Axes.X;
RelativeSizeAxes = Axes.Y;
@@ -102,16 +85,10 @@ namespace osu.Game.Overlays.Direct
{
box.ScaleTo(new Vector2(1f, 0f), transition_duration);
}
+
+ protected override void OnActivated() => slideActive();
+
+ protected override void OnDeactivated() => slideInactive();
}
}
-
- public enum SortCriteria
- {
- Title,
- Artist,
- Creator,
- Difficulty,
- Ranked,
- Rating,
- }
}
diff --git a/osu.Game/Graphics/UserInterface/PercentageCounter.cs b/osu.Game/Graphics/UserInterface/PercentageCounter.cs
index c32b654840..79cdc9effe 100644
--- a/osu.Game/Graphics/UserInterface/PercentageCounter.cs
+++ b/osu.Game/Graphics/UserInterface/PercentageCounter.cs
@@ -45,7 +45,7 @@ namespace osu.Game.Graphics.UserInterface
Current.Value = Current + amount;
}
- protected class TransformAccuracy : Transform
+ protected class TransformAccuracy : Transform
{
public override double CurrentValue
{
diff --git a/osu.Game/Graphics/UserInterface/RollingCounter.cs b/osu.Game/Graphics/UserInterface/RollingCounter.cs
index bdb2054ca4..4338dd23eb 100644
--- a/osu.Game/Graphics/UserInterface/RollingCounter.cs
+++ b/osu.Game/Graphics/UserInterface/RollingCounter.cs
@@ -27,7 +27,7 @@ namespace osu.Game.Graphics.UserInterface
///
/// Must be a subclass of Transform(T)
///
- protected virtual Type TransformType => typeof(Transform);
+ protected virtual Type TransformType => typeof(Transform);
protected SpriteText DisplayedCountSpriteText;
@@ -181,17 +181,17 @@ namespace osu.Game.Graphics.UserInterface
protected virtual void TransformCount(T currentValue, T newValue)
{
Debug.Assert(
- typeof(Transform).IsAssignableFrom(TransformType),
+ typeof(Transform).IsAssignableFrom(TransformType),
@"transformType should be a subclass of Transform."
);
- TransformCount((Transform)Activator.CreateInstance(TransformType), currentValue, newValue);
+ TransformCount((Transform)Activator.CreateInstance(TransformType), currentValue, newValue);
}
///
/// Intended to be used by TransformCount(T currentValue, T newValue).
///
- protected void TransformCount(Transform transform, T currentValue, T newValue)
+ protected void TransformCount(Transform transform, T currentValue, T newValue)
{
Type type = transform.GetType();
diff --git a/osu.Game/Graphics/UserInterface/ScoreCounter.cs b/osu.Game/Graphics/UserInterface/ScoreCounter.cs
index 3e01b9e4f4..f98e84852a 100644
--- a/osu.Game/Graphics/UserInterface/ScoreCounter.cs
+++ b/osu.Game/Graphics/UserInterface/ScoreCounter.cs
@@ -56,7 +56,7 @@ namespace osu.Game.Graphics.UserInterface
Current.Value = Current + amount;
}
- protected class TransformScore : Transform
+ protected class TransformScore : Transform
{
public override double CurrentValue
{
diff --git a/osu.Game/Graphics/UserInterface/SearchTextBox.cs b/osu.Game/Graphics/UserInterface/SearchTextBox.cs
index 0a37024d0f..39db8d8be7 100644
--- a/osu.Game/Graphics/UserInterface/SearchTextBox.cs
+++ b/osu.Game/Graphics/UserInterface/SearchTextBox.cs
@@ -45,6 +45,7 @@ namespace osu.Game.Graphics.UserInterface
case Key.Up:
case Key.Down:
return false;
+ case Key.KeypadEnter:
case Key.Enter:
if (!AllowCommit) return false;
break;
diff --git a/osu.Game/Graphics/UserInterface/SimpleComboCounter.cs b/osu.Game/Graphics/UserInterface/SimpleComboCounter.cs
index 8537e80f63..bee1a71894 100644
--- a/osu.Game/Graphics/UserInterface/SimpleComboCounter.cs
+++ b/osu.Game/Graphics/UserInterface/SimpleComboCounter.cs
@@ -37,7 +37,7 @@ namespace osu.Game.Graphics.UserInterface
Current.Value = Current + amount;
}
- private class TransformCounterCount : Transform
+ private class TransformCounterCount : Transform
{
public override int CurrentValue
{
diff --git a/osu.Game/Graphics/UserInterface/TwoLayerButton.cs b/osu.Game/Graphics/UserInterface/TwoLayerButton.cs
index ebaef661c4..b504c70be7 100644
--- a/osu.Game/Graphics/UserInterface/TwoLayerButton.cs
+++ b/osu.Game/Graphics/UserInterface/TwoLayerButton.cs
@@ -14,6 +14,7 @@ using osu.Game.Graphics.Containers;
using osu.Game.Beatmaps.ControlPoints;
using osu.Framework.Audio.Track;
using System;
+using osu.Framework.Graphics.Shapes;
namespace osu.Game.Graphics.UserInterface
{
@@ -62,8 +63,12 @@ namespace osu.Game.Graphics.UserInterface
X = (value & Anchor.x2) > 0 ? SIZE_RETRACTED.X * shear * 0.5f : 0;
+ Remove(c1);
+ Remove(c2);
c1.Depth = (value & Anchor.x2) > 0 ? 0 : 1;
c2.Depth = (value & Anchor.x2) > 0 ? 1 : 0;
+ Add(c1);
+ Add(c2);
}
}
@@ -79,18 +84,21 @@ namespace osu.Game.Graphics.UserInterface
Width = 0.4f,
Children = new Drawable[]
{
- new Container {
+ new Container
+ {
RelativeSizeAxes = Axes.Both,
Shear = new Vector2(shear, 0),
Masking = true,
MaskingSmoothness = 2,
- EdgeEffect = new EdgeEffect {
+ EdgeEffect = new EdgeEffectParameters
+ {
Type = EdgeEffectType.Shadow,
Colour = Color4.Black.Opacity(0.2f),
Offset = new Vector2(2, 0),
Radius = 2,
},
- Children = new [] {
+ Children = new[]
+ {
IconLayer = new Box
{
RelativeSizeAxes = Axes.Both,
@@ -113,18 +121,21 @@ namespace osu.Game.Graphics.UserInterface
Width = 0.6f,
Children = new Drawable[]
{
- new Container {
+ new Container
+ {
RelativeSizeAxes = Axes.Both,
Shear = new Vector2(shear, 0),
Masking = true,
MaskingSmoothness = 2,
- EdgeEffect = new EdgeEffect {
+ EdgeEffect = new EdgeEffectParameters
+ {
Type = EdgeEffectType.Shadow,
Colour = Color4.Black.Opacity(0.2f),
Offset = new Vector2(2, 0),
Radius = 2,
},
- Children = new [] {
+ Children = new[]
+ {
TextLayer = new Box
{
Origin = Anchor.TopLeft,
diff --git a/osu.Game/Graphics/UserInterface/Volume/VolumeMeter.cs b/osu.Game/Graphics/UserInterface/Volume/VolumeMeter.cs
index fd1d890330..57eea71086 100644
--- a/osu.Game/Graphics/UserInterface/Volume/VolumeMeter.cs
+++ b/osu.Game/Graphics/UserInterface/Volume/VolumeMeter.cs
@@ -4,11 +4,11 @@
using osu.Framework.Configuration;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
-using osu.Framework.Graphics.Sprites;
using osu.Framework.Input;
using osu.Game.Graphics.Sprites;
using OpenTK;
using OpenTK.Graphics;
+using osu.Framework.Graphics.Shapes;
namespace osu.Game.Graphics.UserInterface.Volume
{
diff --git a/osu.Game/Online/API/OAuthToken.cs b/osu.Game/Online/API/OAuthToken.cs
index 328888ab8a..1788adbf56 100644
--- a/osu.Game/Online/API/OAuthToken.cs
+++ b/osu.Game/Online/API/OAuthToken.cs
@@ -59,7 +59,6 @@ namespace osu.Game.Online.API
{
}
-
return null;
}
}
diff --git a/osu.Game/Online/API/Requests/GetUsersRequest.cs b/osu.Game/Online/API/Requests/GetUsersRequest.cs
new file mode 100644
index 0000000000..5fb8606e1e
--- /dev/null
+++ b/osu.Game/Online/API/Requests/GetUsersRequest.cs
@@ -0,0 +1,20 @@
+// Copyright (c) 2007-2017 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using System.Collections.Generic;
+using Newtonsoft.Json;
+using osu.Game.Users;
+
+namespace osu.Game.Online.API.Requests
+{
+ public class GetUsersRequest : APIRequest>
+ {
+ protected override string Target => @"rankings/osu/performance";
+ }
+
+ public class RankingEntry
+ {
+ [JsonProperty]
+ public User User;
+ }
+}
diff --git a/osu.Game/Online/Chat/Channel.cs b/osu.Game/Online/Chat/Channel.cs
index 93fd0a8956..01685cc7dc 100644
--- a/osu.Game/Online/Chat/Channel.cs
+++ b/osu.Game/Online/Chat/Channel.cs
@@ -5,6 +5,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
+using osu.Framework.Configuration;
using osu.Framework.Lists;
namespace osu.Game.Online.Chat
@@ -25,7 +26,7 @@ namespace osu.Game.Online.Chat
public readonly SortedList Messages = new SortedList(Comparer.Default);
- //internal bool Joined;
+ public Bindable Joined = new Bindable();
public bool ReadOnly => Name != "#lazer";
diff --git a/osu.Game/Online/Multiplayer/GameType.cs b/osu.Game/Online/Multiplayer/GameType.cs
index 2f4c92d289..4d1a6c4839 100644
--- a/osu.Game/Online/Multiplayer/GameType.cs
+++ b/osu.Game/Online/Multiplayer/GameType.cs
@@ -5,7 +5,7 @@ using OpenTK;
using OpenTK.Graphics;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
-using osu.Framework.Graphics.Sprites;
+using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics;
namespace osu.Game.Online.Multiplayer
diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs
index 2c952ee514..7e5b913d10 100644
--- a/osu.Game/OsuGame.cs
+++ b/osu.Game/OsuGame.cs
@@ -43,6 +43,8 @@ namespace osu.Game
private DirectOverlay direct;
+ private SocialOverlay social;
+
private Intro intro
{
get
@@ -75,8 +77,10 @@ namespace osu.Game
public void ToggleDirect() => direct.ToggleVisibility();
[BackgroundDependencyLoader]
- private void load()
+ private void load(FrameworkConfigManager frameworkConfig)
{
+ this.frameworkConfig = frameworkConfig;
+
if (!Host.IsPrimaryInstance)
{
Logger.Log(@"osu! does not support multiple running instances.", LoggingTarget.Runtime, LogLevel.Error);
@@ -148,7 +152,7 @@ namespace osu.Game
RelativeSizeAxes = Axes.Both,
},
volume = new VolumeControl(),
- overlayContent = new Container{ RelativeSizeAxes = Axes.Both },
+ overlayContent = new Container { RelativeSizeAxes = Axes.Both },
new OnScreenDisplay(),
new GlobalHotkeys //exists because UserInputManager is at a level below us.
{
@@ -165,6 +169,7 @@ namespace osu.Game
//overlay elements
LoadComponentAsync(direct = new DirectOverlay { Depth = -1 }, mainContent.Add);
+ LoadComponentAsync(social = new SocialOverlay { Depth = -1 }, mainContent.Add);
LoadComponentAsync(chat = new ChatOverlay { Depth = -1 }, mainContent.Add);
LoadComponentAsync(settings = new SettingsOverlay { Depth = -1 }, overlayContent.Add);
LoadComponentAsync(musicController = new MusicController
@@ -198,11 +203,16 @@ namespace osu.Game
};
Dependencies.Cache(settings);
+ Dependencies.Cache(social);
Dependencies.Cache(chat);
Dependencies.Cache(musicController);
Dependencies.Cache(notificationManager);
Dependencies.Cache(dialogOverlay);
+ // ensure both overlays aren't presented at the same time
+ chat.StateChanged += (container, state) => social.State = state == Visibility.Visible ? Visibility.Hidden : social.State;
+ social.StateChanged += (container, state) => chat.State = state == Visibility.Visible ? Visibility.Hidden : chat.State;
+
LoadComponentAsync(Toolbar = new Toolbar
{
Depth = -3,
@@ -234,6 +244,9 @@ namespace osu.Game
case Key.F8:
chat.ToggleVisibility();
return true;
+ case Key.F9:
+ social.ToggleVisibility();
+ return true;
case Key.PageUp:
case Key.PageDown:
var swClock = (Clock as ThrottledFrameClock)?.Source as StopwatchClock;
@@ -248,6 +261,19 @@ namespace osu.Game
{
switch (args.Key)
{
+ case Key.R:
+ if (state.Keyboard.AltPressed)
+ {
+ var sensitivity = frameworkConfig.GetBindable(FrameworkSetting.CursorSensitivity);
+
+ sensitivity.Disabled = false;
+ sensitivity.Value = 1;
+ sensitivity.Disabled = true;
+
+ frameworkConfig.Set(FrameworkSetting.ActiveInputHandlers, string.Empty);
+ return true;
+ }
+ break;
case Key.T:
Toolbar.ToggleVisibility();
return true;
@@ -273,6 +299,7 @@ namespace osu.Game
private Container overlayContent;
private OsuScreen currentScreen;
+ private FrameworkConfigManager frameworkConfig;
private void screenChanged(Screen newScreen)
{
@@ -292,6 +319,7 @@ namespace osu.Game
musicController.State = Visibility.Hidden;
chat.State = Visibility.Hidden;
direct.State = Visibility.Hidden;
+ social.State = Visibility.Hidden;
}
else
{
diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs
index 2c39a82245..306cdaddf0 100644
--- a/osu.Game/OsuGameBase.cs
+++ b/osu.Game/OsuGameBase.cs
@@ -158,7 +158,8 @@ namespace osu.Game
Children = new Drawable[]
{
Cursor = new MenuCursor(),
- new TooltipContainer(Cursor) { Depth = -1 },
+ new OsuContextMenuContainer(Cursor) { Depth = -2 },
+ new OsuTooltipContainer(Cursor) { Depth = -1 },
}
},
}
diff --git a/osu.Game/Overlays/Chat/ChannelListItem.cs b/osu.Game/Overlays/Chat/ChannelListItem.cs
new file mode 100644
index 0000000000..9aa11cdd4f
--- /dev/null
+++ b/osu.Game/Overlays/Chat/ChannelListItem.cs
@@ -0,0 +1,188 @@
+// Copyright (c) 2007-2017 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using System;
+using OpenTK;
+using OpenTK.Graphics;
+using osu.Framework.Allocation;
+using osu.Framework.Configuration;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Input;
+using osu.Game.Graphics;
+using osu.Game.Graphics.Sprites;
+using osu.Game.Online.Chat;
+
+namespace osu.Game.Overlays.Chat
+{
+ public class ChannelListItem : ClickableContainer, IFilterable
+ {
+ private const float width_padding = 5;
+ private const float channel_width = 150;
+ private const float text_size = 15;
+ private const float transition_duration = 100;
+
+ private readonly Channel channel;
+
+ private readonly Bindable joinedBind = new Bindable();
+ private readonly OsuSpriteText name;
+ private readonly OsuSpriteText topic;
+ private readonly TextAwesome joinedCheckmark;
+
+ private Color4 joinedColour;
+ private Color4 topicColour;
+ private Color4 hoverColour;
+
+ public string[] FilterTerms => new[] { channel.Name };
+ public bool MatchingFilter
+ {
+ set
+ {
+ FadeTo(value ? 1f : 0f, 100);
+ }
+ }
+
+ public Action OnRequestJoin;
+ public Action OnRequestLeave;
+
+ public ChannelListItem(Channel channel)
+ {
+ this.channel = channel;
+
+ RelativeSizeAxes = Axes.X;
+ AutoSizeAxes = Axes.Y;
+
+ Action = () => { (channel.Joined ? OnRequestLeave : OnRequestJoin)?.Invoke(channel); };
+
+ Children = new Drawable[]
+ {
+ new FillFlowContainer
+ {
+ RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y,
+ Direction = FillDirection.Horizontal,
+ Children = new Drawable[]
+ {
+ new Container
+ {
+ Children = new[]
+ {
+ joinedCheckmark = new TextAwesome
+ {
+ Anchor = Anchor.TopRight,
+ Origin = Anchor.TopRight,
+ Icon = FontAwesome.fa_check_circle,
+ TextSize = text_size,
+ Shadow = false,
+ Margin = new MarginPadding { Right = 10f },
+ Alpha = 0f,
+ },
+ },
+ },
+ new Container
+ {
+ Width = channel_width,
+ AutoSizeAxes = Axes.Y,
+ Children = new[]
+ {
+ name = new OsuSpriteText
+ {
+ Text = channel.ToString(),
+ TextSize = text_size,
+ Font = @"Exo2.0-Bold",
+ Shadow = false,
+ },
+ },
+ },
+ new Container
+ {
+ RelativeSizeAxes = Axes.X,
+ Width = 0.7f,
+ AutoSizeAxes = Axes.Y,
+ Margin = new MarginPadding { Left = width_padding },
+ Children = new[]
+ {
+ topic = new OsuSpriteText
+ {
+ Text = channel.Topic,
+ TextSize = text_size,
+ Font = @"Exo2.0-SemiBold",
+ Shadow = false,
+ Alpha = 0.8f,
+ },
+ },
+ },
+ new FillFlowContainer
+ {
+ AutoSizeAxes = Axes.Both,
+ Direction = FillDirection.Horizontal,
+ Margin = new MarginPadding { Left = width_padding },
+ Spacing = new Vector2(3f, 0f),
+ Children = new Drawable[]
+ {
+ new TextAwesome
+ {
+ Icon = FontAwesome.fa_user,
+ TextSize = text_size - 2,
+ Shadow = false,
+ Margin = new MarginPadding { Top = 1 },
+ },
+ new OsuSpriteText
+ {
+ Text = @"0",
+ TextSize = text_size,
+ Font = @"Exo2.0-SemiBold",
+ Shadow = false,
+ },
+ },
+ },
+ },
+ },
+ };
+ }
+
+ [BackgroundDependencyLoader]
+ private void load(OsuColour colours)
+ {
+ topicColour = colours.Gray9;
+ joinedColour = colours.Blue;
+ hoverColour = colours.Yellow;
+
+ joinedBind.ValueChanged += updateColour;
+ joinedBind.BindTo(channel.Joined);
+ }
+
+ protected override bool OnHover(InputState state)
+ {
+ if (!channel.Joined.Value)
+ name.FadeColour(hoverColour, 50, EasingTypes.OutQuint);
+
+ return base.OnHover(state);
+ }
+
+ protected override void OnHoverLost(InputState state)
+ {
+ if (!channel.Joined.Value)
+ name.FadeColour(Color4.White, transition_duration);
+ }
+
+ private void updateColour(bool joined)
+ {
+ if (joined)
+ {
+ name.FadeColour(Color4.White, transition_duration);
+ joinedCheckmark.FadeTo(1f, transition_duration);
+ topic.FadeTo(0.8f, transition_duration);
+ topic.FadeColour(Color4.White, transition_duration);
+ FadeColour(joinedColour, transition_duration);
+ }
+ else
+ {
+ joinedCheckmark.FadeTo(0f, transition_duration);
+ topic.FadeTo(1f, transition_duration);
+ topic.FadeColour(topicColour, transition_duration);
+ FadeColour(Color4.White, transition_duration);
+ }
+ }
+ }
+}
diff --git a/osu.Game/Overlays/Chat/ChannelSection.cs b/osu.Game/Overlays/Chat/ChannelSection.cs
new file mode 100644
index 0000000000..f12ec53605
--- /dev/null
+++ b/osu.Game/Overlays/Chat/ChannelSection.cs
@@ -0,0 +1,63 @@
+// Copyright (c) 2007-2017 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using System.Collections.Generic;
+using System.Linq;
+using OpenTK;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Game.Graphics.Sprites;
+using osu.Game.Online.Chat;
+
+namespace osu.Game.Overlays.Chat
+{
+ public class ChannelSection : Container, IHasFilterableChildren
+ {
+ private readonly OsuSpriteText header;
+
+ public readonly FillFlowContainer ChannelFlow;
+
+ public IEnumerable FilterableChildren => ChannelFlow.Children;
+ public string[] FilterTerms => new[] { Header };
+ public bool MatchingFilter
+ {
+ set
+ {
+ FadeTo(value ? 1f : 0f, 100);
+ }
+ }
+
+ public string Header
+ {
+ get { return header.Text; }
+ set { header.Text = value.ToUpper(); }
+ }
+
+ public IEnumerable Channels
+ {
+ set { ChannelFlow.Children = value.Select(c => new ChannelListItem(c)); }
+ }
+
+ public ChannelSection()
+ {
+ RelativeSizeAxes = Axes.X;
+ AutoSizeAxes = Axes.Y;
+
+ Children = new Drawable[]
+ {
+ header = new OsuSpriteText
+ {
+ TextSize = 15,
+ Font = @"Exo2.0-Bold",
+ },
+ ChannelFlow = new FillFlowContainer
+ {
+ RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y,
+ Margin = new MarginPadding { Top = 25 },
+ Spacing = new Vector2(0f, 5f),
+ },
+ };
+ }
+ }
+}
diff --git a/osu.Game/Overlays/Chat/ChannelSelectionOverlay.cs b/osu.Game/Overlays/Chat/ChannelSelectionOverlay.cs
new file mode 100644
index 0000000000..6ff3cc7be5
--- /dev/null
+++ b/osu.Game/Overlays/Chat/ChannelSelectionOverlay.cs
@@ -0,0 +1,184 @@
+// Copyright (c) 2007-2017 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using System;
+using System.Collections.Generic;
+using OpenTK;
+using OpenTK.Graphics;
+using osu.Framework.Allocation;
+using osu.Framework.Extensions.Color4Extensions;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Shapes;
+using osu.Framework.Input;
+using osu.Game.Graphics;
+using osu.Game.Graphics.Backgrounds;
+using osu.Game.Graphics.Sprites;
+using osu.Game.Graphics.UserInterface;
+using osu.Game.Online.Chat;
+
+namespace osu.Game.Overlays.Chat
+{
+ public class ChannelSelectionOverlay : FocusedOverlayContainer
+ {
+ public static readonly float WIDTH_PADDING = 170;
+
+ private const float transition_duration = 500;
+
+ private readonly Box bg;
+ private readonly Triangles triangles;
+ private readonly Box headerBg;
+ private readonly SearchTextBox search;
+ private readonly SearchContainer sectionsFlow;
+
+ public Action OnRequestJoin;
+ public Action OnRequestLeave;
+
+ public IEnumerable Sections
+ {
+ set
+ {
+ sectionsFlow.Children = value;
+
+ foreach (ChannelSection s in sectionsFlow.Children)
+ {
+ foreach (ChannelListItem c in s.ChannelFlow.Children)
+ {
+ c.OnRequestJoin = channel => { OnRequestJoin?.Invoke(channel); };
+ c.OnRequestLeave = channel => { OnRequestLeave?.Invoke(channel); };
+ }
+ }
+ }
+ }
+
+ public ChannelSelectionOverlay()
+ {
+ RelativeSizeAxes = Axes.X;
+
+ Children = new Drawable[]
+ {
+ new Container
+ {
+ RelativeSizeAxes = Axes.Both,
+ Masking = true,
+ Children = new Drawable[]
+ {
+ bg = new Box
+ {
+ RelativeSizeAxes = Axes.Both,
+ },
+ triangles = new Triangles
+ {
+ RelativeSizeAxes = Axes.Both,
+ TriangleScale = 5,
+ },
+ },
+ },
+ new Container
+ {
+ RelativeSizeAxes = Axes.Both,
+ Padding = new MarginPadding { Top = 85, Right = WIDTH_PADDING },
+ Children = new[]
+ {
+ new ScrollContainer
+ {
+ RelativeSizeAxes = Axes.Both,
+ Children = new[]
+ {
+ sectionsFlow = new SearchContainer
+ {
+ RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y,
+ Direction = FillDirection.Vertical,
+ LayoutDuration = 200,
+ LayoutEasing = EasingTypes.OutQuint,
+ Spacing = new Vector2(0f, 20f),
+ Padding = new MarginPadding { Vertical = 20, Left = WIDTH_PADDING },
+ },
+ },
+ },
+ },
+ },
+ new Container
+ {
+ RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y,
+ Children = new Drawable[]
+ {
+ headerBg = new Box
+ {
+ RelativeSizeAxes = Axes.Both,
+ },
+ new FillFlowContainer
+ {
+ RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y,
+ Direction = FillDirection.Vertical,
+ Spacing = new Vector2(0f, 10f),
+ Padding = new MarginPadding { Top = 10f, Bottom = 10f, Left = WIDTH_PADDING, Right = WIDTH_PADDING },
+ Children = new Drawable[]
+ {
+ new OsuSpriteText
+ {
+ Text = @"Chat Channels",
+ TextSize = 20,
+ Shadow = false,
+ },
+ search = new HeaderSearchTextBox
+ {
+ RelativeSizeAxes = Axes.X,
+ PlaceholderText = @"Search",
+ Exit = Hide,
+ },
+ },
+ },
+ },
+ },
+ };
+
+ search.Current.ValueChanged += newValue => sectionsFlow.SearchTerm = newValue;
+ }
+
+ [BackgroundDependencyLoader]
+ private void load(OsuColour colours)
+ {
+ bg.Colour = colours.Gray3;
+ triangles.ColourDark = colours.Gray3;
+ triangles.ColourLight = OsuColour.FromHex(@"353535");
+
+ headerBg.Colour = colours.Gray2.Opacity(0.75f);
+ }
+
+ protected override void OnFocus(InputState state)
+ {
+ InputManager.ChangeFocus(search);
+ base.OnFocus(state);
+ }
+
+ protected override void PopIn()
+ {
+ if (Alpha == 0) MoveToY(DrawHeight);
+
+ FadeIn(transition_duration, EasingTypes.OutQuint);
+ MoveToY(0, transition_duration, EasingTypes.OutQuint);
+
+ search.HoldFocus = true;
+ base.PopIn();
+ }
+
+ protected override void PopOut()
+ {
+ FadeOut(transition_duration, EasingTypes.InSine);
+ MoveToY(DrawHeight, transition_duration, EasingTypes.InSine);
+
+ search.HoldFocus = false;
+ base.PopOut();
+ }
+
+ private class HeaderSearchTextBox : SearchTextBox
+ {
+ protected override Color4 BackgroundFocused => Color4.Black.Opacity(0.2f);
+ protected override Color4 BackgroundUnfocused => Color4.Black.Opacity(0.2f);
+ }
+ }
+}
diff --git a/osu.Game/Overlays/Chat/ChatTabControl.cs b/osu.Game/Overlays/Chat/ChatTabControl.cs
index a281cff7db..92147db57f 100644
--- a/osu.Game/Overlays/Chat/ChatTabControl.cs
+++ b/osu.Game/Overlays/Chat/ChatTabControl.cs
@@ -5,6 +5,7 @@ using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.UserInterface;
using osu.Framework.Input;
@@ -26,6 +27,8 @@ namespace osu.Game.Overlays.Chat
public readonly Bindable ChannelSelectorActive = new Bindable();
+ private readonly ChannelTabItem.ChannelSelectorTabItem selectorTab;
+
public ChatTabControl()
{
TabContainer.Margin = new MarginPadding { Left = 50 };
@@ -41,7 +44,22 @@ namespace osu.Game.Overlays.Chat
Padding = new MarginPadding(10),
});
- AddTabItem(new ChannelTabItem.ChannelSelectorTabItem(new Channel { Name = "+" }, ChannelSelectorActive));
+ AddTabItem(selectorTab = new ChannelTabItem.ChannelSelectorTabItem(new Channel { Name = "+" }));
+
+ ChannelSelectorActive.BindTo(selectorTab.Active);
+ }
+
+ protected override void SelectTab(TabItem tab)
+ {
+ if (tab is ChannelTabItem.ChannelSelectorTabItem)
+ {
+ tab.Active.Toggle();
+ return;
+ }
+
+ selectorTab.Active.Value = false;
+
+ base.SelectTab(tab);
}
private class ChannelTabItem : TabItem
@@ -56,18 +74,6 @@ namespace osu.Game.Overlays.Chat
private readonly Box highlightBox;
private readonly TextAwesome icon;
- public override bool Active
- {
- get { return base.Active; }
- set
- {
- if (Active == value) return;
-
- base.Active = value;
- updateState();
- }
- }
-
private void updateState()
{
if (Active)
@@ -141,7 +147,7 @@ namespace osu.Game.Overlays.Chat
Shear = new Vector2(shear_width / ChatOverlay.TAB_AREA_HEIGHT, 0);
Masking = true;
- EdgeEffect = new EdgeEffect
+ EdgeEffect = new EdgeEffectParameters
{
Type = EdgeEffectType.Shadow,
Radius = 10,
@@ -205,21 +211,8 @@ namespace osu.Game.Overlays.Chat
public class ChannelSelectorTabItem : ChannelTabItem
{
- public override bool Active
+ public ChannelSelectorTabItem(Channel value) : base(value)
{
- get { return base.Active; }
- set
- {
- activeBindable.Value = value;
- base.Active = value;
- }
- }
-
- private readonly Bindable activeBindable;
-
- public ChannelSelectorTabItem(Channel value, Bindable active) : base(value)
- {
- activeBindable = active;
Depth = float.MaxValue;
Width = 45;
@@ -236,6 +229,10 @@ namespace osu.Game.Overlays.Chat
backgroundActive = colour.Gray3;
}
}
+
+ protected override void OnActivated() => updateState();
+
+ protected override void OnDeactivated() => updateState();
}
}
}
diff --git a/osu.Game/Overlays/Chat/DrawableChannel.cs b/osu.Game/Overlays/Chat/DrawableChannel.cs
index 50c849f00e..e8bde11a3c 100644
--- a/osu.Game/Overlays/Chat/DrawableChannel.cs
+++ b/osu.Game/Overlays/Chat/DrawableChannel.cs
@@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Online.Chat;
@@ -43,11 +44,15 @@ namespace osu.Game.Overlays.Chat
channel.NewMessagesArrived += newMessagesArrived;
}
+ [BackgroundDependencyLoader]
+ private void load()
+ {
+ newMessagesArrived(Channel.Messages);
+ }
+
protected override void LoadComplete()
{
base.LoadComplete();
-
- newMessagesArrived(Channel.Messages);
scrollToEnd();
}
@@ -59,13 +64,13 @@ namespace osu.Game.Overlays.Chat
private void newMessagesArrived(IEnumerable newMessages)
{
- if (!IsLoaded) return;
-
var displayMessages = newMessages.Skip(Math.Max(0, newMessages.Count() - Channel.MAX_HISTORY));
//up to last Channel.MAX_HISTORY messages
flow.Add(displayMessages.Select(m => new ChatLine(m)));
+ if (!IsLoaded) return;
+
if (scroll.IsScrolledToEnd(10) || !flow.Children.Any())
scrollToEnd();
@@ -81,6 +86,6 @@ namespace osu.Game.Overlays.Chat
}
}
- private void scrollToEnd() => Scheduler.AddDelayed(() => scroll.ScrollToEnd(), 50);
+ private void scrollToEnd() => ScheduleAfterChildren(() => scroll.ScrollToEnd());
}
}
diff --git a/osu.Game/Overlays/ChatOverlay.cs b/osu.Game/Overlays/ChatOverlay.cs
index 5b2c01151c..23b8aac6a7 100644
--- a/osu.Game/Overlays/ChatOverlay.cs
+++ b/osu.Game/Overlays/ChatOverlay.cs
@@ -10,9 +10,8 @@ using osu.Framework.Allocation;
using osu.Framework.Configuration;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
-using osu.Framework.Graphics.Sprites;
+using osu.Framework.Graphics.Shapes;
using osu.Framework.Threading;
-using osu.Game.Graphics.Sprites;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests;
using osu.Game.Online.Chat;
@@ -29,10 +28,13 @@ namespace osu.Game.Overlays
public class ChatOverlay : FocusedOverlayContainer, IOnlineComponent
{
private const float textbox_height = 60;
+ private const float channel_selection_min_height = 0.3f;
private ScheduledDelegate messageRequest;
- private readonly Container currentChannelContainer;
+ private readonly Container currentChannelContainer;
+
+ private readonly LoadingAnimation loading;
private readonly FocusedTextBox inputTextBox;
@@ -48,16 +50,21 @@ namespace osu.Game.Overlays
private readonly ChatTabControl channelTabs;
+ private readonly Container chatContainer;
private readonly Box chatBackground;
private readonly Box tabBackground;
private Bindable chatHeight;
+ private readonly Container channelSelectionContainer;
+ private readonly ChannelSelectionOverlay channelSelection;
+
+ protected override bool InternalContains(Vector2 screenSpacePos) => chatContainer.Contains(screenSpacePos) || channelSelection.State == Visibility.Visible && channelSelection.Contains(screenSpacePos);
+
public ChatOverlay()
{
RelativeSizeAxes = Axes.Both;
RelativePositionAxes = Axes.Both;
- Size = new Vector2(1, DEFAULT_HEIGHT);
Anchor = Anchor.BottomLeft;
Origin = Anchor.BottomLeft;
@@ -65,74 +72,121 @@ namespace osu.Game.Overlays
Children = new Drawable[]
{
- new Container
+ channelSelectionContainer = new Container
{
- Name = @"chat area",
RelativeSizeAxes = Axes.Both,
- Padding = new MarginPadding { Top = TAB_AREA_HEIGHT },
- Children = new Drawable[]
+ Height = 1f - DEFAULT_HEIGHT,
+ Masking = true,
+ Children = new[]
{
- chatBackground = new Box
+ channelSelection = new ChannelSelectionOverlay
{
RelativeSizeAxes = Axes.Both,
},
- currentChannelContainer = new Container
+ },
+ },
+ chatContainer = new Container
+ {
+ Name = @"chat container",
+ Anchor = Anchor.BottomLeft,
+ Origin = Anchor.BottomLeft,
+ RelativeSizeAxes = Axes.Both,
+ Height = DEFAULT_HEIGHT,
+ Children = new[]
+ {
+ new Container
{
+ Name = @"chat area",
RelativeSizeAxes = Axes.Both,
- Padding = new MarginPadding
+ Padding = new MarginPadding { Top = TAB_AREA_HEIGHT },
+ Children = new Drawable[]
{
- Bottom = textbox_height + padding
- },
+ chatBackground = new Box
+ {
+ RelativeSizeAxes = Axes.Both,
+ },
+ currentChannelContainer = new Container
+ {
+ RelativeSizeAxes = Axes.Both,
+ Padding = new MarginPadding
+ {
+ Bottom = textbox_height + padding
+ },
+ },
+ new Container
+ {
+ Anchor = Anchor.BottomLeft,
+ Origin = Anchor.BottomLeft,
+ RelativeSizeAxes = Axes.X,
+ Height = textbox_height,
+ Padding = new MarginPadding
+ {
+ Top = padding * 2,
+ Bottom = padding * 2,
+ Left = ChatLine.LEFT_PADDING + padding * 2,
+ Right = padding * 2,
+ },
+ Children = new Drawable[]
+ {
+ inputTextBox = new FocusedTextBox
+ {
+ RelativeSizeAxes = Axes.Both,
+ Height = 1,
+ PlaceholderText = "type your message",
+ Exit = () => State = Visibility.Hidden,
+ OnCommit = postMessage,
+ ReleaseFocusOnCommit = false,
+ HoldFocus = true,
+ }
+ }
+ },
+ loading = new LoadingAnimation(),
+ }
},
new Container
{
- Anchor = Anchor.BottomLeft,
- Origin = Anchor.BottomLeft,
+ Name = @"tabs area",
RelativeSizeAxes = Axes.X,
- Height = textbox_height,
- Padding = new MarginPadding
- {
- Top = padding * 2,
- Bottom = padding * 2,
- Left = ChatLine.LEFT_PADDING + padding * 2,
- Right = padding * 2,
- },
+ Height = TAB_AREA_HEIGHT,
Children = new Drawable[]
{
- inputTextBox = new FocusedTextBox
+ tabBackground = new Box
{
RelativeSizeAxes = Axes.Both,
- Height = 1,
- PlaceholderText = "type your message",
- Exit = () => State = Visibility.Hidden,
- OnCommit = postMessage,
- HoldFocus = true,
- }
+ Colour = Color4.Black,
+ },
+ channelTabs = new ChatTabControl
+ {
+ RelativeSizeAxes = Axes.Both,
+ },
}
- }
- }
- },
- new Container
- {
- Name = @"tabs area",
- RelativeSizeAxes = Axes.X,
- Height = TAB_AREA_HEIGHT,
- Children = new Drawable[]
- {
- tabBackground = new Box
- {
- RelativeSizeAxes = Axes.Both,
- Colour = Color4.Black,
},
- channelTabs = new ChatTabControl
- {
- RelativeSizeAxes = Axes.Both,
- },
- }
+ },
},
};
channelTabs.Current.ValueChanged += newChannel => CurrentChannel = newChannel;
+ channelTabs.ChannelSelectorActive.ValueChanged += value => channelSelection.State = value ? Visibility.Visible : Visibility.Hidden;
+ channelSelection.StateChanged += (overlay, state) =>
+ {
+ channelTabs.ChannelSelectorActive.Value = state == Visibility.Visible;
+
+ if (state == Visibility.Visible)
+ {
+ inputTextBox.HoldFocus = false;
+ if (1f - chatHeight.Value < channel_selection_min_height)
+ {
+ chatContainer.ResizeHeightTo(1f - channel_selection_min_height, 800, EasingTypes.OutQuint);
+ channelSelectionContainer.ResizeHeightTo(channel_selection_min_height, 800, EasingTypes.OutQuint);
+ channelSelection.Show();
+ chatHeight.Value = 1f - channel_selection_min_height;
+ }
+ }
+ else
+ {
+ inputTextBox.HoldFocus = true;
+ }
+ };
}
private double startDragChatHeight;
@@ -167,11 +221,15 @@ namespace osu.Game.Overlays
}
}
- protected override bool OnFocus(InputState state)
+ public override bool AcceptsFocus => true;
+
+ protected override bool OnClick(InputState state) => true;
+
+ protected override void OnFocus(InputState state)
{
//this is necessary as inputTextBox is masked away and therefore can't get focus :(
InputManager.ChangeFocus(inputTextBox);
- return false;
+ base.OnFocus(state);
}
protected override void PopIn()
@@ -201,8 +259,9 @@ namespace osu.Game.Overlays
chatHeight = config.GetBindable(OsuSetting.ChatDisplayHeight);
chatHeight.ValueChanged += h =>
{
- Height = (float)h;
- tabBackground.FadeTo(Height == 1 ? 1 : 0.8f, 200);
+ chatContainer.Height = (float)h;
+ channelSelectionContainer.Height = 1f - (float)h;
+ tabBackground.FadeTo(h == 1 ? 1 : 0.8f, 200);
};
chatHeight.TriggerChange();
@@ -217,14 +276,7 @@ namespace osu.Game.Overlays
private void initializeChannels()
{
- SpriteText loading;
- Add(loading = new OsuSpriteText
- {
- Text = @"initialising chat...",
- Anchor = Anchor.Centre,
- Origin = Anchor.Centre,
- TextSize = 40,
- });
+ loading.Show();
messageRequest?.Cancel();
@@ -233,12 +285,19 @@ namespace osu.Game.Overlays
{
Scheduler.Add(delegate
{
- loading.FadeOut(100);
- loading.Expire();
-
addChannel(channels.Find(c => c.Name == @"#lazer"));
addChannel(channels.Find(c => c.Name == @"#osu"));
addChannel(channels.Find(c => c.Name == @"#lobby"));
+
+ channelSelection.OnRequestJoin = addChannel;
+ channelSelection.Sections = new[]
+ {
+ new ChannelSection
+ {
+ Header = "All Channels",
+ Channels = channels,
+ },
+ };
});
messageRequest = Scheduler.AddDelayed(fetchNewMessages, 1000, true);
@@ -258,24 +317,36 @@ namespace osu.Game.Overlays
set
{
- if (currentChannel == value) return;
-
- if (channelTabs.ChannelSelectorActive) return;
-
- if (currentChannel != null)
- currentChannelContainer.Clear(false);
+ if (currentChannel == value || value == null) return;
currentChannel = value;
+ inputTextBox.Current.Disabled = currentChannel.ReadOnly;
+ channelTabs.Current.Value = value;
+
var loaded = loadedChannels.Find(d => d.Channel == value);
if (loaded == null)
- loadedChannels.Add(loaded = new DrawableChannel(currentChannel));
+ {
+ currentChannelContainer.FadeOut(500, EasingTypes.OutQuint);
+ loading.Show();
- inputTextBox.Current.Disabled = currentChannel.ReadOnly;
+ loaded = new DrawableChannel(currentChannel);
+ loadedChannels.Add(loaded);
+ LoadComponentAsync(loaded, l =>
+ {
+ if (currentChannel.Messages.Any())
+ loading.Hide();
- currentChannelContainer.Add(loaded);
-
- channelTabs.Current.Value = value;
+ currentChannelContainer.Clear(false);
+ currentChannelContainer.Add(loaded);
+ currentChannelContainer.FadeIn(500, EasingTypes.OutQuint);
+ });
+ }
+ else
+ {
+ currentChannelContainer.Clear(false);
+ currentChannelContainer.Add(loaded);
+ }
}
}
@@ -292,7 +363,6 @@ namespace osu.Game.Overlays
}
else
{
-
careChannels.Add(channel);
channelTabs.AddItem(channel);
}
@@ -302,6 +372,8 @@ namespace osu.Game.Overlays
if (CurrentChannel == null)
CurrentChannel = channel;
+
+ channel.Joined.Value = true;
}
private void fetchInitialMessages(Channel channel)
@@ -310,6 +382,7 @@ namespace osu.Game.Overlays
req.Success += delegate (List messages)
{
+ loading.Hide();
channel.AddNewMessages(messages.ToArray());
Debug.Write("success!");
};
diff --git a/osu.Game/Overlays/Dialog/PopupDialog.cs b/osu.Game/Overlays/Dialog/PopupDialog.cs
index 42819f7f87..c8ca50823f 100644
--- a/osu.Game/Overlays/Dialog/PopupDialog.cs
+++ b/osu.Game/Overlays/Dialog/PopupDialog.cs
@@ -14,6 +14,7 @@ using osu.Game.Graphics.Sprites;
using OpenTK;
using OpenTK.Graphics;
using OpenTK.Input;
+using osu.Framework.Graphics.Shapes;
namespace osu.Game.Overlays.Dialog
{
@@ -78,7 +79,7 @@ namespace osu.Game.Overlays.Dialog
{
if (args.Repeat) return false;
- if (args.Key == Key.Enter)
+ if (args.Key == Key.Enter || args.Key == Key.KeypadEnter)
{
Buttons.OfType().FirstOrDefault()?.TriggerOnClick();
return true;
@@ -145,7 +146,7 @@ namespace osu.Game.Overlays.Dialog
{
RelativeSizeAxes = Axes.Both,
Masking = true,
- EdgeEffect = new EdgeEffect
+ EdgeEffect = new EdgeEffectParameters
{
Type = EdgeEffectType.Shadow,
Colour = Color4.Black.Opacity(0.5f),
diff --git a/osu.Game/Overlays/DialogOverlay.cs b/osu.Game/Overlays/DialogOverlay.cs
index 9454272728..757781a4ab 100644
--- a/osu.Game/Overlays/DialogOverlay.cs
+++ b/osu.Game/Overlays/DialogOverlay.cs
@@ -4,9 +4,9 @@
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
-using osu.Framework.Graphics.Sprites;
using osu.Game.Overlays.Dialog;
using OpenTK.Graphics;
+using osu.Framework.Graphics.Shapes;
namespace osu.Game.Overlays
{
@@ -29,7 +29,7 @@ namespace osu.Game.Overlays
State = Visibility.Visible;
}
- private void onDialogOnStateChanged(OverlayContainer dialog, Visibility v)
+ private void onDialogOnStateChanged(VisibilityContainer dialog, Visibility v)
{
if (v != Visibility.Hidden) return;
diff --git a/osu.Game/Overlays/Direct/DirectGridPanel.cs b/osu.Game/Overlays/Direct/DirectGridPanel.cs
index 4be68157d7..a670b27540 100644
--- a/osu.Game/Overlays/Direct/DirectGridPanel.cs
+++ b/osu.Game/Overlays/Direct/DirectGridPanel.cs
@@ -8,12 +8,12 @@ using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
-using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures;
using osu.Framework.Localisation;
using osu.Game.Database;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
+using osu.Framework.Graphics.Shapes;
namespace osu.Game.Overlays.Direct
{
@@ -30,7 +30,7 @@ namespace osu.Game.Overlays.Direct
CornerRadius = 4;
Masking = true;
- EdgeEffect = new EdgeEffect
+ EdgeEffect = new EdgeEffectParameters
{
Type = EdgeEffectType.Shadow,
Offset = new Vector2(0f, 1f),
diff --git a/osu.Game/Overlays/Direct/DirectListPanel.cs b/osu.Game/Overlays/Direct/DirectListPanel.cs
index 48636a5228..2cede1e574 100644
--- a/osu.Game/Overlays/Direct/DirectListPanel.cs
+++ b/osu.Game/Overlays/Direct/DirectListPanel.cs
@@ -6,7 +6,6 @@ using OpenTK.Graphics;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
-using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Colour;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
@@ -16,6 +15,7 @@ using osu.Framework.Localisation;
using osu.Framework.Graphics.Textures;
using System.Linq;
using osu.Framework.Input;
+using osu.Framework.Graphics.Shapes;
namespace osu.Game.Overlays.Direct
{
@@ -31,7 +31,7 @@ namespace osu.Game.Overlays.Direct
Height = height;
CornerRadius = 5;
Masking = true;
- EdgeEffect = new EdgeEffect
+ EdgeEffect = new EdgeEffectParameters
{
Type = EdgeEffectType.Shadow,
Offset = new Vector2(0f, 1f),
diff --git a/osu.Game/Overlays/Direct/FilterControl.cs b/osu.Game/Overlays/Direct/FilterControl.cs
index 735e14b8c1..455d0ab77b 100644
--- a/osu.Game/Overlays/Direct/FilterControl.cs
+++ b/osu.Game/Overlays/Direct/FilterControl.cs
@@ -5,117 +5,35 @@ using OpenTK;
using OpenTK.Graphics;
using osu.Framework.Allocation;
using osu.Framework.Configuration;
-using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
-using osu.Framework.Graphics.Sprites;
using osu.Game.Database;
using osu.Game.Graphics;
-using osu.Game.Graphics.UserInterface;
+using osu.Game.Overlays.SearchableList;
namespace osu.Game.Overlays.Direct
{
- public class FilterControl : Container
+ public class FilterControl : SearchableListFilterControl
{
- public static readonly float HEIGHT = 35 + 32 + 30 + padding * 2; // search + mode toggle buttons + sort tabs + padding
+ private FillFlowContainer modeButtons;
- private const float padding = 10;
-
- private readonly Box tabStrip;
- private readonly FillFlowContainer modeButtons;
-
- public readonly SearchTextBox Search;
- public readonly SortTabControl SortTabs;
- public readonly OsuEnumDropdown RankStatusDropdown;
- public readonly Bindable DisplayStyle = new Bindable();
-
- protected override bool InternalContains(Vector2 screenSpacePos) => base.InternalContains(screenSpacePos) || RankStatusDropdown.Contains(screenSpacePos);
-
- public FilterControl()
+ protected override Color4 BackgroundColour => OsuColour.FromHex(@"384552");
+ protected override DirectSortCritera DefaultTab => DirectSortCritera.Title;
+ protected override Drawable CreateSupplementaryControls()
{
- RelativeSizeAxes = Axes.X;
- Height = HEIGHT;
- DisplayStyle.Value = DirectOverlay.PanelDisplayStyle.Grid;
-
- Children = new Drawable[]
+ modeButtons = new FillFlowContainer
{
- new Box
- {
- RelativeSizeAxes = Axes.Both,
- Colour = OsuColour.FromHex(@"384552"),
- Alpha = 0.9f,
- },
- tabStrip = new Box
- {
- Anchor = Anchor.BottomLeft,
- Origin = Anchor.TopLeft,
- RelativeSizeAxes = Axes.X,
- Height = 1,
- },
- new FillFlowContainer
- {
- RelativeSizeAxes = Axes.X,
- AutoSizeAxes = Axes.Y,
- Padding = new MarginPadding { Left = DirectOverlay.WIDTH_PADDING, Right = DirectOverlay.WIDTH_PADDING },
- Children = new Drawable[]
- {
- Search = new DirectSearchTextBox
- {
- RelativeSizeAxes = Axes.X,
- Margin = new MarginPadding { Top = padding },
- },
- modeButtons = new FillFlowContainer
- {
- AutoSizeAxes = Axes.Both,
- Spacing = new Vector2(padding, 0f),
- Margin = new MarginPadding { Top = padding },
- },
- SortTabs = new SortTabControl
- {
- RelativeSizeAxes = Axes.X,
- },
- },
- },
- new FillFlowContainer
- {
- AutoSizeAxes = Axes.Both,
- Anchor = Anchor.TopRight,
- Origin = Anchor.TopRight,
- Spacing = new Vector2(10f, 0f),
- Direction = FillDirection.Horizontal,
- Margin = new MarginPadding { Top = HEIGHT - SlimEnumDropdown.HEIGHT - padding, Right = DirectOverlay.WIDTH_PADDING },
- Children = new Drawable[]
- {
- new FillFlowContainer
- {
- AutoSizeAxes = Axes.Both,
- Spacing = new Vector2(5f, 0f),
- Direction = FillDirection.Horizontal,
- Children = new[]
- {
- new DisplayStyleToggleButton(FontAwesome.fa_th_large, DirectOverlay.PanelDisplayStyle.Grid, DisplayStyle),
- new DisplayStyleToggleButton(FontAwesome.fa_list_ul, DirectOverlay.PanelDisplayStyle.List, DisplayStyle),
- },
- },
- RankStatusDropdown = new SlimEnumDropdown
- {
- RelativeSizeAxes = Axes.None,
- Width = 160f,
- },
- },
- },
+ AutoSizeAxes = Axes.Both,
+ Spacing = new Vector2(10f, 0f),
};
- RankStatusDropdown.Current.Value = RankStatus.RankedApproved;
- SortTabs.Current.Value = SortCriteria.Title;
- SortTabs.Current.TriggerChange();
+ return modeButtons;
}
[BackgroundDependencyLoader(true)]
private void load(OsuGame game, RulesetDatabase rulesets, OsuColour colours)
{
- tabStrip.Colour = colours.Yellow;
- RankStatusDropdown.AccentColour = colours.BlueDark;
+ DisplayStyleControl.Dropdown.AccentColour = colours.BlueDark;
var b = new Bindable(); //backup bindable incase the game is null
foreach (var r in rulesets.AllRulesets)
@@ -124,20 +42,6 @@ namespace osu.Game.Overlays.Direct
}
}
- private class DirectSearchTextBox : SearchTextBox
- {
- protected override Color4 BackgroundUnfocused => backgroundColour;
- protected override Color4 BackgroundFocused => backgroundColour;
-
- private Color4 backgroundColour;
-
- [BackgroundDependencyLoader]
- private void load(OsuColour colours)
- {
- backgroundColour = colours.Gray2.Opacity(0.9f);
- }
- }
-
private class RulesetToggleButton : ClickableContainer
{
private readonly TextAwesome icon;
@@ -188,46 +92,15 @@ namespace osu.Game.Overlays.Direct
base.Dispose(isDisposing);
}
}
+ }
- private class DisplayStyleToggleButton : ClickableContainer
- {
- private readonly TextAwesome icon;
- private readonly DirectOverlay.PanelDisplayStyle style;
- private readonly Bindable bindable;
-
- public DisplayStyleToggleButton(FontAwesome icon, DirectOverlay.PanelDisplayStyle style, Bindable bindable)
- {
- this.bindable = bindable;
- this.style = style;
- Size = new Vector2(SlimEnumDropdown.HEIGHT);
-
- Children = new Drawable[]
- {
- this.icon = new TextAwesome
- {
- Anchor = Anchor.Centre,
- Origin = Anchor.Centre,
- Icon = icon,
- TextSize = 18,
- UseFullGlyphHeight = false,
- Alpha = 0.5f,
- },
- };
-
- bindable.ValueChanged += Bindable_ValueChanged;
- Bindable_ValueChanged(bindable.Value);
- Action = () => bindable.Value = this.style;
- }
-
- private void Bindable_ValueChanged(DirectOverlay.PanelDisplayStyle style)
- {
- icon.FadeTo(style == this.style ? 1.0f : 0.5f, 100);
- }
-
- protected override void Dispose(bool isDisposing)
- {
- bindable.ValueChanged -= Bindable_ValueChanged;
- }
- }
+ public enum DirectSortCritera
+ {
+ Title,
+ Artist,
+ Creator,
+ Difficulty,
+ Ranked,
+ Rating,
}
}
diff --git a/osu.Game/Overlays/Direct/Header.cs b/osu.Game/Overlays/Direct/Header.cs
index 8e4ede48d5..000ef473cc 100644
--- a/osu.Game/Overlays/Direct/Header.cs
+++ b/osu.Game/Overlays/Direct/Header.cs
@@ -2,113 +2,28 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.ComponentModel;
-using OpenTK;
using OpenTK.Graphics;
-using osu.Framework.Allocation;
using osu.Framework.Graphics;
-using osu.Framework.Graphics.Containers;
-using osu.Framework.Graphics.Sprites;
-using osu.Framework.Graphics.UserInterface;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
-using osu.Game.Graphics.UserInterface;
-
-using Container = osu.Framework.Graphics.Containers.Container;
+using osu.Game.Overlays.SearchableList;
namespace osu.Game.Overlays.Direct
{
- public class Header : Container
+ public class Header : SearchableListHeader
{
- public static readonly float HEIGHT = 90;
+ protected override Color4 BackgroundColour => OsuColour.FromHex(@"252f3a");
+ protected override float TabStripWidth => 298;
- private readonly Box tabStrip;
-
- public readonly OsuTabControl Tabs;
+ protected override DirectTab DefaultTab => DirectTab.Search;
+ protected override Drawable CreateHeaderText() => new OsuSpriteText { Text = @"osu!direct", TextSize = 25 };
+ protected override FontAwesome Icon => FontAwesome.fa_osu_chevron_down_o;
public Header()
{
- Height = HEIGHT;
-
- Children = new Drawable[]
- {
- new Box
- {
- RelativeSizeAxes = Axes.Both,
- Colour = OsuColour.FromHex(@"252f3a"),
- },
- new Container
- {
- RelativeSizeAxes = Axes.Both,
- Padding = new MarginPadding { Left = DirectOverlay.WIDTH_PADDING, Right = DirectOverlay.WIDTH_PADDING },
- Children = new Drawable[]
- {
- new FillFlowContainer
- {
- Anchor = Anchor.CentreLeft,
- Origin = Anchor.BottomLeft,
- Position = new Vector2(-35f, 5f),
- AutoSizeAxes = Axes.Both,
- Direction = FillDirection.Horizontal,
- Spacing = new Vector2(10f, 0f),
- Children = new Drawable[]
- {
- new TextAwesome
- {
- TextSize = 25,
- Icon = FontAwesome.fa_osu_chevron_down_o,
- },
- new OsuSpriteText
- {
- TextSize = 25,
- Text = @"osu!direct",
- },
- },
- },
- tabStrip = new Box
- {
- Anchor = Anchor.BottomLeft,
- Origin = Anchor.BottomLeft,
- Width = 282, //todo: make this actually match the tab control's width instead of hardcoding
- Height = 1,
- },
- Tabs = new DirectTabControl
- {
- Anchor = Anchor.BottomLeft,
- Origin = Anchor.BottomLeft,
- RelativeSizeAxes = Axes.X,
- },
- },
- },
- };
-
Tabs.Current.Value = DirectTab.Search;
Tabs.Current.TriggerChange();
}
-
- [BackgroundDependencyLoader]
- private void load(OsuColour colours)
- {
- tabStrip.Colour = colours.Green;
- }
-
- private class DirectTabControl : OsuTabControl
- {
- protected override TabItem CreateTabItem(DirectTab value) => new DirectTabItem(value);
-
- public DirectTabControl()
- {
- Height = 25;
- AccentColour = Color4.White;
- }
-
- private class DirectTabItem : OsuTabItem
- {
- public DirectTabItem(DirectTab value) : base(value)
- {
- Text.TextSize = 15;
- }
- }
- }
}
public enum DirectTab
diff --git a/osu.Game/Overlays/DirectOverlay.cs b/osu.Game/Overlays/DirectOverlay.cs
index b1bc7e0c04..93c440384b 100644
--- a/osu.Game/Overlays/DirectOverlay.cs
+++ b/osu.Game/Overlays/DirectOverlay.cs
@@ -7,28 +7,30 @@ using OpenTK;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
-using osu.Framework.Graphics.Sprites;
-using osu.Framework.Input;
using osu.Game.Database;
using osu.Game.Graphics;
-using osu.Game.Graphics.Backgrounds;
using osu.Game.Graphics.Sprites;
using osu.Game.Overlays.Direct;
-
-using Container = osu.Framework.Graphics.Containers.Container;
+using osu.Game.Overlays.SearchableList;
+using OpenTK.Graphics;
namespace osu.Game.Overlays
{
- public class DirectOverlay : WaveOverlayContainer
+ public class DirectOverlay : SearchableListOverlay
{
- public static readonly int WIDTH_PADDING = 80;
private const float panel_padding = 10f;
- private readonly FilterControl filter;
private readonly FillFlowContainer resultCountsContainer;
private readonly OsuSpriteText resultCountsText;
private readonly FillFlowContainer panels;
+ protected override Color4 BackgroundColour => OsuColour.FromHex(@"485e74");
+ protected override Color4 TrianglesColourLight => OsuColour.FromHex(@"465b71");
+ protected override Color4 TrianglesColourDark => OsuColour.FromHex(@"3f5265");
+
+ protected override SearchableListHeader CreateHeader() => new Header();
+ protected override SearchableListFilterControl CreateFilterControl() => new FilterControl();
+
private IEnumerable beatmapSets;
public IEnumerable BeatmapSets
{
@@ -38,7 +40,7 @@ namespace osu.Game.Overlays
if (beatmapSets?.Equals(value) ?? false) return;
beatmapSets = value;
- recreatePanels(filter.DisplayStyle.Value);
+ recreatePanels(Filter.DisplayStyleControl.DisplayStyle.Value);
}
}
@@ -66,96 +68,39 @@ namespace osu.Game.Overlays
ThirdWaveColour = OsuColour.FromHex(@"005774");
FourthWaveColour = OsuColour.FromHex(@"003a4e");
- Header header;
- Children = new Drawable[]
+ ScrollFlow.Children = new Drawable[]
{
- new Box
+ resultCountsContainer = new FillFlowContainer
{
- RelativeSizeAxes = Axes.Both,
- Colour = OsuColour.FromHex(@"485e74"),
- },
- new Container
- {
- RelativeSizeAxes = Axes.Both,
- Masking = true,
- Children = new[]
+ AutoSizeAxes = Axes.Both,
+ Direction = FillDirection.Horizontal,
+ Margin = new MarginPadding { Top = 5 },
+ Children = new Drawable[]
{
- new Triangles
+ new OsuSpriteText
{
- RelativeSizeAxes = Axes.Both,
- TriangleScale = 5,
- ColourLight = OsuColour.FromHex(@"465b71"),
- ColourDark = OsuColour.FromHex(@"3f5265"),
+ Text = "Found ",
+ TextSize = 15,
},
- },
- },
- new Container
- {
- RelativeSizeAxes = Axes.Both,
- Padding = new MarginPadding { Top = Header.HEIGHT + FilterControl.HEIGHT },
- Children = new[]
- {
- new ScrollContainer
+ resultCountsText = new OsuSpriteText
{
- RelativeSizeAxes = Axes.Both,
- ScrollDraggerVisible = false,
- Children = new Drawable[]
- {
- new FillFlowContainer
- {
- RelativeSizeAxes = Axes.X,
- AutoSizeAxes = Axes.Y,
- Direction = FillDirection.Vertical,
- Children = new Drawable[]
- {
- resultCountsContainer = new FillFlowContainer
- {
- AutoSizeAxes = Axes.Both,
- Direction = FillDirection.Horizontal,
- Margin = new MarginPadding { Left = WIDTH_PADDING, Top = 6 },
- Children = new Drawable[]
- {
- new OsuSpriteText
- {
- Text = "Found ",
- TextSize = 15,
- },
- resultCountsText = new OsuSpriteText
- {
- TextSize = 15,
- Font = @"Exo2.0-Bold",
- },
- }
- },
- panels = new FillFlowContainer
- {
- RelativeSizeAxes = Axes.X,
- AutoSizeAxes = Axes.Y,
- Padding = new MarginPadding { Top = panel_padding, Bottom = panel_padding, Left = WIDTH_PADDING, Right = WIDTH_PADDING },
- Spacing = new Vector2(panel_padding),
- },
- },
- },
- },
+ TextSize = 15,
+ Font = @"Exo2.0-Bold",
},
- },
+ }
},
- filter = new FilterControl
- {
- RelativeSizeAxes = Axes.X,
- Margin = new MarginPadding { Top = Header.HEIGHT },
- },
- header = new Header
+ panels = new FillFlowContainer
{
RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y,
+ Spacing = new Vector2(panel_padding),
+ Margin = new MarginPadding { Top = 10 },
},
};
- header.Tabs.Current.ValueChanged += tab => { if (tab != DirectTab.Search) filter.Search.Current.Value = string.Empty; };
-
- filter.Search.Exit = Hide;
- filter.Search.Current.ValueChanged += text => { if (text != string.Empty) header.Tabs.Current.Value = DirectTab.Search; };
- filter.DisplayStyle.ValueChanged += recreatePanels;
+ Header.Tabs.Current.ValueChanged += tab => { if (tab != DirectTab.Search) Filter.Search.Text = string.Empty; };
+ Filter.Search.Current.ValueChanged += text => { if (text != string.Empty) Header.Tabs.Current.Value = DirectTab.Search; };
+ Filter.DisplayStyleControl.DisplayStyle.ValueChanged += recreatePanels;
updateResultCounts();
}
@@ -187,26 +132,6 @@ namespace osu.Game.Overlays
panels.Children = BeatmapSets.Select(b => displayStyle == PanelDisplayStyle.Grid ? (DirectPanel)new DirectGridPanel(b) { Width = 400 } : new DirectListPanel(b));
}
- protected override bool OnFocus(InputState state)
- {
- InputManager.ChangeFocus(filter.Search);
- return false;
- }
-
- protected override void PopIn()
- {
- base.PopIn();
-
- filter.Search.HoldFocus = true;
- }
-
- protected override void PopOut()
- {
- base.PopOut();
-
- filter.Search.HoldFocus = false;
- }
-
public class ResultCounts
{
public readonly int Artists;
@@ -220,11 +145,5 @@ namespace osu.Game.Overlays
Tags = tags;
}
}
-
- public enum PanelDisplayStyle
- {
- Grid,
- List,
- }
}
}
diff --git a/osu.Game/Overlays/DragBar.cs b/osu.Game/Overlays/DragBar.cs
index bb28f08553..07e0c76396 100644
--- a/osu.Game/Overlays/DragBar.cs
+++ b/osu.Game/Overlays/DragBar.cs
@@ -4,10 +4,10 @@
using System;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
-using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Transforms;
using osu.Framework.Input;
using OpenTK;
+using osu.Framework.Graphics.Shapes;
namespace osu.Game.Overlays
{
@@ -98,7 +98,7 @@ namespace osu.Game.Overlays
return true;
}
- private class TransformSeek : TransformFloat
+ private class TransformSeek : TransformFloat
{
public override void Apply(Drawable d)
{
diff --git a/osu.Game/Overlays/LoginOverlay.cs b/osu.Game/Overlays/LoginOverlay.cs
index c3f41270ce..b688bafd4d 100644
--- a/osu.Game/Overlays/LoginOverlay.cs
+++ b/osu.Game/Overlays/LoginOverlay.cs
@@ -4,10 +4,10 @@
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
-using osu.Framework.Graphics.Sprites;
using osu.Game.Graphics;
using osu.Game.Overlays.Settings.Sections.General;
using OpenTK.Graphics;
+using osu.Framework.Graphics.Shapes;
namespace osu.Game.Overlays
{
@@ -27,7 +27,8 @@ namespace osu.Game.Overlays
{
Children = new Drawable[]
{
- new Box {
+ new Box
+ {
RelativeSizeAxes = Axes.Both,
Colour = Color4.Black,
Alpha = 0.6f,
diff --git a/osu.Game/Overlays/Mods/ModButton.cs b/osu.Game/Overlays/Mods/ModButton.cs
index f7df67b66d..8a04d91cfb 100644
--- a/osu.Game/Overlays/Mods/ModButton.cs
+++ b/osu.Game/Overlays/Mods/ModButton.cs
@@ -16,11 +16,10 @@ using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.UI;
using System;
using System.Linq;
-using osu.Game.Graphics;
+using osu.Framework.Graphics.Cursor;
namespace osu.Game.Overlays.Mods
{
-
///
/// Represents a clickable button which can cycle through one of more mods.
///
@@ -80,7 +79,7 @@ namespace osu.Game.Overlays.Mods
backgroundIcon.RotateTo(-rotate_angle * direction, mod_switch_duration, mod_switch_easing);
backgroundIcon.Icon = modAfter.Icon;
- using (iconsContainer.BeginDelayedSequence(mod_switch_duration, true))
+ using (BeginDelayedSequence(mod_switch_duration, true))
{
foregroundIcon.RotateTo(-rotate_angle * direction);
foregroundIcon.RotateTo(0f, mod_switch_duration, mod_switch_easing);
@@ -88,7 +87,7 @@ namespace osu.Game.Overlays.Mods
backgroundIcon.RotateTo(rotate_angle * direction);
backgroundIcon.RotateTo(0f, mod_switch_duration, mod_switch_easing);
- iconsContainer.Schedule(() => displayMod(modAfter));
+ Schedule(() => displayMod(modAfter));
}
}
diff --git a/osu.Game/Overlays/Mods/ModSelectOverlay.cs b/osu.Game/Overlays/Mods/ModSelectOverlay.cs
index c001d613e4..ca74189c86 100644
--- a/osu.Game/Overlays/Mods/ModSelectOverlay.cs
+++ b/osu.Game/Overlays/Mods/ModSelectOverlay.cs
@@ -8,7 +8,6 @@ using osu.Framework.Configuration;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
-using osu.Framework.Graphics.Sprites;
using osu.Game.Graphics;
using osu.Game.Graphics.Backgrounds;
using osu.Game.Graphics.Sprites;
@@ -17,6 +16,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using osu.Game.Database;
+using osu.Framework.Graphics.Shapes;
namespace osu.Game.Overlays.Mods
{
diff --git a/osu.Game/Overlays/Music/CollectionsDropdown.cs b/osu.Game/Overlays/Music/CollectionsDropdown.cs
new file mode 100644
index 0000000000..f6016fd1db
--- /dev/null
+++ b/osu.Game/Overlays/Music/CollectionsDropdown.cs
@@ -0,0 +1,73 @@
+// 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.Extensions.Color4Extensions;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.UserInterface;
+using osu.Game.Graphics;
+using osu.Game.Graphics.UserInterface;
+
+namespace osu.Game.Overlays.Music
+{
+ public class CollectionsDropdown : OsuDropdown
+ {
+ protected override DropdownHeader CreateHeader() => new CollectionsHeader { AccentColour = AccentColour };
+ protected override Menu CreateMenu() => new CollectionsMenu();
+
+ [BackgroundDependencyLoader]
+ private void load(OsuColour colours)
+ {
+ AccentColour = colours.Gray6;
+ }
+
+ private class CollectionsHeader : OsuDropdownHeader
+ {
+ [BackgroundDependencyLoader]
+ private void load(OsuColour colours)
+ {
+ BackgroundColour = colours.Gray4;
+ }
+
+ public CollectionsHeader()
+ {
+ CornerRadius = 5;
+ Height = 30;
+ Icon.TextSize = 14;
+ Icon.Margin = new MarginPadding(0);
+ Foreground.Padding = new MarginPadding { Top = 4, Bottom = 4, Left = 10, Right = 10 };
+ EdgeEffect = new EdgeEffectParameters
+ {
+ Type = EdgeEffectType.Shadow,
+ Colour = Color4.Black.Opacity(0.3f),
+ Radius = 3,
+ Offset = new Vector2(0f, 1f),
+ };
+ }
+ }
+
+ private class CollectionsMenu : OsuMenu
+ {
+ [BackgroundDependencyLoader]
+ private void load(OsuColour colours)
+ {
+ Background.Colour = colours.Gray4;
+ }
+
+ public CollectionsMenu()
+ {
+ CornerRadius = 5;
+ EdgeEffect = new EdgeEffectParameters
+ {
+ Type = EdgeEffectType.Shadow,
+ Colour = Color4.Black.Opacity(0.3f),
+ Radius = 3,
+ Offset = new Vector2(0f, 1f),
+ };
+ }
+ }
+ }
+}
diff --git a/osu.Game/Overlays/Music/FilterControl.cs b/osu.Game/Overlays/Music/FilterControl.cs
index 6d8790a9e8..56cd6e864b 100644
--- a/osu.Game/Overlays/Music/FilterControl.cs
+++ b/osu.Game/Overlays/Music/FilterControl.cs
@@ -3,10 +3,8 @@
using System.Collections.Generic;
using osu.Framework.Allocation;
-using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
-using osu.Framework.Graphics.UserInterface;
using osu.Game.Graphics;
using osu.Game.Graphics.UserInterface;
using OpenTK;
@@ -74,63 +72,5 @@ namespace osu.Game.Overlays.Music
backgroundColour = colours.Gray2;
}
}
-
- private class CollectionsDropdown : OsuDropdown
- {
- protected override DropdownHeader CreateHeader() => new CollectionsHeader { AccentColour = AccentColour };
- protected override Menu CreateMenu() => new CollectionsMenu();
-
- [BackgroundDependencyLoader]
- private void load(OsuColour colours)
- {
- AccentColour = colours.Gray6;
- }
-
- private class CollectionsHeader : OsuDropdownHeader
- {
- [BackgroundDependencyLoader]
- private void load(OsuColour colours)
- {
- BackgroundColour = colours.Gray4;
- }
-
- public CollectionsHeader()
- {
- CornerRadius = 5;
- Height = 30;
- Icon.TextSize = 14;
- Icon.Margin = new MarginPadding(0);
- Foreground.Padding = new MarginPadding { Top = 4, Bottom = 4, Left = 10, Right = 10 };
- EdgeEffect = new EdgeEffect
- {
- Type = EdgeEffectType.Shadow,
- Colour = Color4.Black.Opacity(0.3f),
- Radius = 3,
- Offset = new Vector2(0f, 1f),
- };
- }
- }
-
- private class CollectionsMenu : OsuMenu
- {
- [BackgroundDependencyLoader]
- private void load(OsuColour colours)
- {
- Background.Colour = colours.Gray4;
- }
-
- public CollectionsMenu()
- {
- CornerRadius = 5;
- EdgeEffect = new EdgeEffect
- {
- Type = EdgeEffectType.Shadow,
- Colour = Color4.Black.Opacity(0.3f),
- Radius = 3,
- Offset = new Vector2(0f, 1f),
- };
- }
- }
- }
}
}
diff --git a/osu.Game/Overlays/Music/PlaylistItem.cs b/osu.Game/Overlays/Music/PlaylistItem.cs
index 9b72cfce42..69cb9c3464 100644
--- a/osu.Game/Overlays/Music/PlaylistItem.cs
+++ b/osu.Game/Overlays/Music/PlaylistItem.cs
@@ -22,7 +22,7 @@ namespace osu.Game.Overlays.Music
private Color4 artistColour;
private TextAwesome handle;
- private Paragraph text;
+ private TextFlowContainer text;
private IEnumerable titleSprites;
private UnicodeBindableString titleBind;
private UnicodeBindableString artistBind;
@@ -77,7 +77,7 @@ namespace osu.Game.Overlays.Music
Margin = new MarginPadding { Left = 5 },
Padding = new MarginPadding { Top = 2 },
},
- text = new Paragraph
+ text = new TextFlowContainer
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
@@ -135,8 +135,9 @@ namespace osu.Game.Overlays.Music
private bool matching = true;
- public bool MatchingCurrentFilter
+ public bool MatchingFilter
{
+ get { return matching; }
set
{
if (matching == value) return;
@@ -145,10 +146,6 @@ namespace osu.Game.Overlays.Music
FadeTo(matching ? 1 : 0, 200);
}
- get
- {
- return matching;
- }
}
}
}
diff --git a/osu.Game/Overlays/Music/PlaylistList.cs b/osu.Game/Overlays/Music/PlaylistList.cs
index ffe59a9d93..eeb072fb00 100644
--- a/osu.Game/Overlays/Music/PlaylistList.cs
+++ b/osu.Game/Overlays/Music/PlaylistList.cs
@@ -22,7 +22,7 @@ namespace osu.Game.Overlays.Music
}
}
- public BeatmapSetInfo FirstVisibleSet => items.Children.FirstOrDefault(i => i.MatchingCurrentFilter)?.BeatmapSetInfo;
+ public BeatmapSetInfo FirstVisibleSet => items.Children.FirstOrDefault(i => i.MatchingFilter)?.BeatmapSetInfo;
private void itemSelected(BeatmapSetInfo b)
{
@@ -75,7 +75,7 @@ namespace osu.Game.Overlays.Music
private class ItemSearchContainer : FillFlowContainer, IHasFilterableChildren
{
public string[] FilterTerms => new string[] { };
- public bool MatchingCurrentFilter
+ public bool MatchingFilter
{
set
{
diff --git a/osu.Game/Overlays/Music/PlaylistOverlay.cs b/osu.Game/Overlays/Music/PlaylistOverlay.cs
index 82596252b3..e5dc66fc75 100644
--- a/osu.Game/Overlays/Music/PlaylistOverlay.cs
+++ b/osu.Game/Overlays/Music/PlaylistOverlay.cs
@@ -10,7 +10,6 @@ using osu.Framework.Configuration;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
-using osu.Framework.Graphics.Sprites;
using osu.Game.Beatmaps;
using osu.Game.Database;
using osu.Game.Graphics;
@@ -18,6 +17,7 @@ using OpenTK;
using OpenTK.Graphics;
using osu.Framework.Extensions;
using osu.Framework.Input;
+using osu.Framework.Graphics.Shapes;
namespace osu.Game.Overlays.Music
{
@@ -52,7 +52,7 @@ namespace osu.Game.Overlays.Music
RelativeSizeAxes = Axes.Both,
CornerRadius = 5,
Masking = true,
- EdgeEffect = new EdgeEffect
+ EdgeEffect = new EdgeEffectParameters
{
Type = EdgeEffectType.Shadow,
Colour = Color4.Black.Opacity(40),
diff --git a/osu.Game/Overlays/MusicController.cs b/osu.Game/Overlays/MusicController.cs
index f1be55801f..e1e920ec0f 100644
--- a/osu.Game/Overlays/MusicController.cs
+++ b/osu.Game/Overlays/MusicController.cs
@@ -22,6 +22,8 @@ using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Framework.Threading;
using osu.Game.Overlays.Music;
+using osu.Game.Graphics.UserInterface;
+using osu.Framework.Graphics.Shapes;
namespace osu.Game.Overlays
{
@@ -38,8 +40,8 @@ namespace osu.Game.Overlays
private Drawable currentBackground;
private DragBar progressBar;
- private Button playButton;
- private Button playlistButton;
+ private IconButton playButton;
+ private IconButton playlistButton;
private SpriteText title, artist;
@@ -105,7 +107,7 @@ namespace osu.Game.Overlays
Height = player_height,
Masking = true,
CornerRadius = 5,
- EdgeEffect = new EdgeEffect
+ EdgeEffect = new EdgeEffectParameters
{
Type = EdgeEffectType.Shadow,
Colour = Color4.Black.Opacity(40),
@@ -143,7 +145,7 @@ namespace osu.Game.Overlays
Anchor = Anchor.BottomCentre,
Children = new Drawable[]
{
- new FillFlowContainer