diff --git a/osu-framework b/osu-framework index e1352a8b0b..5f3a7fe4d0 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit e1352a8b0b5d1ba8acd9335a56c714d2ccc2f6a6 +Subproject commit 5f3a7fe4d0537820a33b817a41623b4b22a3ec59 diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs index 44a6af841c..42474ce80b 100644 --- a/osu.Game/Configuration/OsuConfigManager.cs +++ b/osu.Game/Configuration/OsuConfigManager.cs @@ -54,6 +54,8 @@ namespace osu.Game.Configuration // Graphics Set(OsuSetting.ShowFpsDisplay, false); + Set(OsuSetting.CursorRotation, true); + Set(OsuSetting.MenuParallax, true); Set(OsuSetting.SnakingInSliders, true); @@ -96,6 +98,7 @@ namespace osu.Game.Configuration AudioOffset, MenuMusic, MenuVoice, + CursorRotation, MenuParallax, BeatmapDetailTab, Username, diff --git a/osu.Game/Graphics/Cursor/MenuCursor.cs b/osu.Game/Graphics/Cursor/MenuCursor.cs index 36f23d1ae9..da117a94c1 100644 --- a/osu.Game/Graphics/Cursor/MenuCursor.cs +++ b/osu.Game/Graphics/Cursor/MenuCursor.cs @@ -20,13 +20,14 @@ namespace osu.Game.Graphics.Cursor { protected override Drawable CreateCursor() => new Cursor(); + private Bindable cursorRotate; private bool dragging; private bool startRotation; protected override bool OnMouseMove(InputState state) { - if (dragging) + if (cursorRotate && dragging) { Debug.Assert(state.Mouse.PositionMouseDown != null); @@ -102,6 +103,12 @@ namespace osu.Game.Graphics.Cursor ActiveCursor.ScaleTo(0, 500, Easing.In); } + [BackgroundDependencyLoader] + private void load(OsuConfigManager config) + { + cursorRotate = config.GetBindable(OsuSetting.CursorRotation); + } + public class Cursor : Container { private Container cursorContainer; diff --git a/osu.Game/IO/Legacy/SerializationReader.cs b/osu.Game/IO/Legacy/SerializationReader.cs index bad143fa6c..c7ea884821 100644 --- a/osu.Game/IO/Legacy/SerializationReader.cs +++ b/osu.Game/IO/Legacy/SerializationReader.cs @@ -49,7 +49,7 @@ namespace osu.Game.IO.Legacy int len = ReadInt32(); if (len > 0) return ReadBytes(len); if (len < 0) return null; - return new byte[0]; + return Array.Empty(); } /// Reads a char array from the buffer, handling nulls and the array length. @@ -58,7 +58,7 @@ namespace osu.Game.IO.Legacy int len = ReadInt32(); if (len > 0) return ReadChars(len); if (len < 0) return null; - return new char[0]; + return Array.Empty(); } /// Reads a DateTime from the buffer. diff --git a/osu.Game/Online/API/APIRequest.cs b/osu.Game/Online/API/APIRequest.cs index 307afb2d2b..37903f924f 100644 --- a/osu.Game/Online/API/APIRequest.cs +++ b/osu.Game/Online/API/APIRequest.cs @@ -2,7 +2,6 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; -using osu.Framework.Extensions; using osu.Framework.IO.Network; namespace osu.Game.Online.API @@ -70,13 +69,11 @@ namespace osu.Game.Online.API protected virtual string Uri => $@"{API.Endpoint}/api/v2/{Target}"; - private double remainingTime => Math.Max(0, Timeout - (DateTime.Now.TotalMilliseconds() - (startTime ?? 0))); + private double remainingTime => Math.Max(0, Timeout - (DateTimeOffset.UtcNow - (startTime ?? DateTimeOffset.MinValue)).TotalMilliseconds); public bool ExceededTimeout => remainingTime == 0; - private double? startTime; - - public double StartTime => startTime ?? -1; + private DateTimeOffset? startTime; protected APIAccess API; protected WebRequest WebRequest; @@ -96,7 +93,7 @@ namespace osu.Game.Online.API return; if (startTime == null) - startTime = DateTime.Now.TotalMilliseconds(); + startTime = DateTimeOffset.UtcNow; if (remainingTime <= 0) throw new TimeoutException(@"API request timeout hit"); diff --git a/osu.Game/Online/API/OAuthToken.cs b/osu.Game/Online/API/OAuthToken.cs index 1788adbf56..2abd7b6c1f 100644 --- a/osu.Game/Online/API/OAuthToken.cs +++ b/osu.Game/Online/API/OAuthToken.cs @@ -4,7 +4,6 @@ using System; using System.Globalization; using Newtonsoft.Json; -using osu.Framework.Extensions; namespace osu.Game.Online.API { @@ -22,12 +21,12 @@ namespace osu.Game.Online.API { get { - return AccessTokenExpiry - DateTime.Now.ToUnixTimestamp(); + return AccessTokenExpiry - DateTimeOffset.UtcNow.ToUnixTimeSeconds(); } set { - AccessTokenExpiry = DateTime.Now.AddSeconds(value).ToUnixTimestamp(); + AccessTokenExpiry = DateTimeOffset.Now.AddSeconds(value).ToUnixTimeSeconds(); } } diff --git a/osu.Game/Online/API/Requests/GetBeatmapDetailsRequest.cs b/osu.Game/Online/API/Requests/GetBeatmapDetailsRequest.cs index 15e20a3d55..934ef7ffa2 100644 --- a/osu.Game/Online/API/Requests/GetBeatmapDetailsRequest.cs +++ b/osu.Game/Online/API/Requests/GetBeatmapDetailsRequest.cs @@ -10,7 +10,7 @@ namespace osu.Game.Online.API.Requests { private readonly BeatmapInfo beatmap; - private string lookupString => beatmap.OnlineBeatmapID > 0 ? beatmap.OnlineBeatmapID.ToString() : $@"lookup?checksum={beatmap.Hash}&filename={beatmap.Path}"; + private string lookupString => beatmap.OnlineBeatmapID > 0 ? beatmap.OnlineBeatmapID.ToString() : $@"lookup?checksum={beatmap.Hash}&filename={System.Uri.EscapeUriString(beatmap.Path)}"; public GetBeatmapDetailsRequest(BeatmapInfo beatmap) { diff --git a/osu.Game/Overlays/Mods/ModButton.cs b/osu.Game/Overlays/Mods/ModButton.cs index 3ca4a204a5..6bfe70d873 100644 --- a/osu.Game/Overlays/Mods/ModButton.cs +++ b/osu.Game/Overlays/Mods/ModButton.cs @@ -127,7 +127,7 @@ namespace osu.Game.Overlays.Mods if (mod == null) { - Mods = new Mod[0]; + Mods = Array.Empty(); Alpha = 0; } else diff --git a/osu.Game/Overlays/Settings/Sections/Graphics/DetailSettings.cs b/osu.Game/Overlays/Settings/Sections/Graphics/DetailSettings.cs index c068da8129..0e348f3791 100644 --- a/osu.Game/Overlays/Settings/Sections/Graphics/DetailSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Graphics/DetailSettings.cs @@ -1,10 +1,25 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using osu.Framework.Allocation; +using osu.Game.Configuration; namespace osu.Game.Overlays.Settings.Sections.Graphics { public class DetailSettings : SettingsSubsection { protected override string Header => "Detail Settings"; + + [BackgroundDependencyLoader] + private void load(OsuConfigManager config) + { + Children = new[] + { + new SettingsCheckbox + { + LabelText = "Rotate cursor when dragging", + Bindable = config.GetBindable(OsuSetting.CursorRotation) + }, + }; + } } } diff --git a/osu.Game/Screens/Menu/Button.cs b/osu.Game/Screens/Menu/Button.cs index 6952f66f95..ccd61643ce 100644 --- a/osu.Game/Screens/Menu/Button.cs +++ b/osu.Game/Screens/Menu/Button.cs @@ -121,13 +121,14 @@ namespace osu.Game.Screens.Menu }; } + private bool rightward; + protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, TrackAmplitudes amplitudes) { base.OnNewBeat(beatIndex, timingPoint, effectPoint, amplitudes); if (!IsHovered) return; - bool rightward = beatIndex % 2 == 1; double duration = timingPoint.BeatLength / 2; icon.RotateTo(rightward ? 10 : -10, duration * 2, Easing.InOutSine); @@ -139,6 +140,8 @@ namespace osu.Game.Screens.Menu i => i.MoveToY(0, duration, Easing.In), i => i.ScaleTo(new Vector2(1, 0.9f), duration, Easing.In) ); + + rightward = !rightward; } protected override bool OnHover(InputState state) @@ -152,7 +155,7 @@ namespace osu.Game.Screens.Menu double duration = TimeUntilNextBeat; icon.ClearTransforms(); - icon.RotateTo(10, duration, Easing.InOutSine); + icon.RotateTo(rightward ? -10 : 10, duration, Easing.InOutSine); icon.ScaleTo(new Vector2(1, 0.9f), duration, Easing.Out); return true; } diff --git a/osu.Game/Screens/Select/Footer.cs b/osu.Game/Screens/Select/Footer.cs index bb6d16da0f..00f311e522 100644 --- a/osu.Game/Screens/Select/Footer.cs +++ b/osu.Game/Screens/Select/Footer.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.Linq; using OpenTK; using OpenTK.Graphics; @@ -58,6 +59,31 @@ namespace osu.Game.Screens.Select Action = action, }); + private readonly List overlays = new List(); + + /// Text on the button. + /// Colour of the button. + /// Hotkey of the button. + /// The to be toggled by this button. + /// + /// Higher depth to be put on the left, and lower to be put on the right. + /// Notice this is different to ! + /// + public void AddButton(string text, Color4 colour, OverlayContainer overlay, Key? hotkey = null, float depth = 0) + { + overlays.Add(overlay); + AddButton(text, colour, () => + { + foreach (var o in overlays) + { + if (o == overlay) + o.ToggleVisibility(); + else + o.Hide(); + } + }, hotkey, depth); + } + private void updateModeLight() => modeLight.FadeColour(buttons.FirstOrDefault(b => b.IsHovered)?.SelectedColour ?? Color4.Transparent, TRANSITION_LENGTH, Easing.OutQuint); public Footer() diff --git a/osu.Game/Screens/Select/PlaySongSelect.cs b/osu.Game/Screens/Select/PlaySongSelect.cs index 7e03707d18..e0a3693371 100644 --- a/osu.Game/Screens/Select/PlaySongSelect.cs +++ b/osu.Game/Screens/Select/PlaySongSelect.cs @@ -45,7 +45,7 @@ namespace osu.Game.Screens.Select [BackgroundDependencyLoader] private void load(OsuColour colours) { - Footer.AddButton(@"mods", colours.Yellow, modSelect.ToggleVisibility, Key.F1, float.MaxValue); + Footer.AddButton(@"mods", colours.Yellow, modSelect, Key.F1, float.MaxValue); BeatmapOptions.AddButton(@"Remove", @"from unplayed", FontAwesome.fa_times_circle_o, colours.Purple, null, Key.Number1); BeatmapOptions.AddButton(@"Clear", @"local scores", FontAwesome.fa_eraser, colours.Purple, null, Key.Number2); diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 84457b77a7..836ed465c3 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -164,7 +164,7 @@ namespace osu.Game.Screens.Select if (Footer != null) { Footer.AddButton(@"random", colours.Green, triggerRandom, Key.F2); - Footer.AddButton(@"options", colours.Blue, BeatmapOptions.ToggleVisibility, Key.F3); + Footer.AddButton(@"options", colours.Blue, BeatmapOptions, Key.F3); BeatmapOptions.AddButton(@"Delete", @"Beatmap", FontAwesome.fa_trash, colours.Pink, () => promptDelete(Beatmap.Value.BeatmapSetInfo), Key.Number4, float.MaxValue); }