diff --git a/osu-framework b/osu-framework index a9eb6eaab7..5e26808ec7 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit a9eb6eaab7cd77f881acfdc23664df45e5d31105 +Subproject commit 5e26808ec77a8fd600cb1cdca3a4b2f62fd0c653 diff --git a/osu-resources b/osu-resources index 1e2d394e01..1750ab8f67 160000 --- a/osu-resources +++ b/osu-resources @@ -1 +1 @@ -Subproject commit 1e2d394e017d98f086271ae07fb61859b5d8fadf +Subproject commit 1750ab8f6761ab35592fd46da71fbe0c141bfd93 diff --git a/osu.Desktop.Deploy/Program.cs b/osu.Desktop.Deploy/Program.cs index d52be70b6e..54fb50d0f8 100644 --- a/osu.Desktop.Deploy/Program.cs +++ b/osu.Desktop.Deploy/Program.cs @@ -390,7 +390,7 @@ namespace osu.Desktop.Deploy public static void AuthenticatedBlockingPerform(this WebRequest r) { - r.Headers.Add("Authorization", $"token {GitHubAccessToken}"); + r.AddHeader("Authorization", $"token {GitHubAccessToken}"); r.Perform(); } } diff --git a/osu.Game.Tests/Visual/TestCaseIntroSequence.cs b/osu.Game.Tests/Visual/TestCaseIntroSequence.cs new file mode 100644 index 0000000000..ba5cf8ef46 --- /dev/null +++ b/osu.Game.Tests/Visual/TestCaseIntroSequence.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 System; +using System.Collections.Generic; +using OpenTK.Graphics; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Timing; +using osu.Game.Screens.Menu; + +namespace osu.Game.Tests.Visual +{ + public class TestCaseIntroSequence : OsuTestCase + { + public override IReadOnlyList RequiredTypes => new[] + { + typeof(OsuLogo), + }; + + public TestCaseIntroSequence() + { + OsuLogo logo; + + var rateAdjustClock = new StopwatchClock(true); + var framedClock = new FramedClock(rateAdjustClock); + framedClock.ProcessFrame(); + + Add(new Container + { + RelativeSizeAxes = Axes.Both, + Clock = framedClock, + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Black, + }, + logo = new OsuLogo + { + Anchor = Anchor.Centre, + } + } + }); + + AddStep(@"Restart", logo.PlayIntro); + AddSliderStep("Playback speed", 0.0, 2.0, 1, v => rateAdjustClock.Rate = v); + } + } +} diff --git a/osu.Game.Tests/Visual/TestCaseOsuGame.cs b/osu.Game.Tests/Visual/TestCaseOsuGame.cs new file mode 100644 index 0000000000..3f869e7378 --- /dev/null +++ b/osu.Game.Tests/Visual/TestCaseOsuGame.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 System; +using System.Collections.Generic; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Timing; +using osu.Game.Screens; +using osu.Game.Screens.Menu; +using OpenTK.Graphics; + +namespace osu.Game.Tests.Visual +{ + public class TestCaseOsuGame : OsuTestCase + { + public override IReadOnlyList RequiredTypes => new[] + { + typeof(OsuLogo), + }; + + public TestCaseOsuGame() + { + var rateAdjustClock = new StopwatchClock(true); + var framedClock = new FramedClock(rateAdjustClock); + framedClock.ProcessFrame(); + + Add(new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Black, + }); + + Add(new Loader()); + + AddSliderStep("Playback speed", 0.0, 2.0, 1, v => rateAdjustClock.Rate = v); + } + } +} diff --git a/osu.Game.Tests/Visual/TestCaseUserRanks.cs b/osu.Game.Tests/Visual/TestCaseUserRanks.cs index 9667897a7d..e17f0e1a46 100644 --- a/osu.Game.Tests/Visual/TestCaseUserRanks.cs +++ b/osu.Game.Tests/Visual/TestCaseUserRanks.cs @@ -41,7 +41,7 @@ namespace osu.Game.Tests.Visual } }); - AddStep("Show cookiezi", () => ranks.User = new User { Id = 124493 }); + AddStep("Show cookiezi", () => ranks.User.Value = new User { Id = 124493 }); } } } diff --git a/osu.Game.Tests/osu.Game.Tests.csproj b/osu.Game.Tests/osu.Game.Tests.csproj index e0e9fb7b5e..b1081890c8 100644 --- a/osu.Game.Tests/osu.Game.Tests.csproj +++ b/osu.Game.Tests/osu.Game.Tests.csproj @@ -110,6 +110,7 @@ + @@ -121,6 +122,7 @@ + diff --git a/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs b/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs index e7035880dd..e46eb8e20a 100644 --- a/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs +++ b/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs @@ -1,6 +1,7 @@ // 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.Lists; @@ -85,6 +86,9 @@ namespace osu.Game.Beatmaps.ControlPoints private T binarySearch(SortedList list, double time, T prePoint = null) where T : ControlPoint, new() { + if (list == null) + throw new ArgumentNullException(nameof(list)); + if (list.Count == 0) return new T(); diff --git a/osu.Game/Beatmaps/Drawables/BeatmapBackgroundSprite.cs b/osu.Game/Beatmaps/Drawables/BeatmapBackgroundSprite.cs index 9b897b4912..0ac8d12591 100644 --- a/osu.Game/Beatmaps/Drawables/BeatmapBackgroundSprite.cs +++ b/osu.Game/Beatmaps/Drawables/BeatmapBackgroundSprite.cs @@ -1,6 +1,7 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System; using osu.Framework.Allocation; using osu.Framework.Graphics.Sprites; @@ -12,6 +13,9 @@ namespace osu.Game.Beatmaps.Drawables public BeatmapBackgroundSprite(WorkingBeatmap working) { + if (working == null) + throw new ArgumentNullException(nameof(working)); + this.working = working; } diff --git a/osu.Game/Beatmaps/Drawables/BeatmapGroup.cs b/osu.Game/Beatmaps/Drawables/BeatmapGroup.cs index 6e5af29799..163dd7fbe9 100644 --- a/osu.Game/Beatmaps/Drawables/BeatmapGroup.cs +++ b/osu.Game/Beatmaps/Drawables/BeatmapGroup.cs @@ -72,6 +72,11 @@ namespace osu.Game.Beatmaps.Drawables public BeatmapGroup(BeatmapSetInfo beatmapSet, BeatmapManager manager) { + if (beatmapSet == null) + throw new ArgumentNullException(nameof(beatmapSet)); + if (manager == null) + throw new ArgumentNullException(nameof(manager)); + BeatmapSet = beatmapSet; WorkingBeatmap beatmap = manager.GetWorkingBeatmap(BeatmapSet.Beatmaps.FirstOrDefault()); diff --git a/osu.Game/Beatmaps/Drawables/BeatmapPanel.cs b/osu.Game/Beatmaps/Drawables/BeatmapPanel.cs index c0705d8f61..e6bf08eb9f 100644 --- a/osu.Game/Beatmaps/Drawables/BeatmapPanel.cs +++ b/osu.Game/Beatmaps/Drawables/BeatmapPanel.cs @@ -73,6 +73,9 @@ namespace osu.Game.Beatmaps.Drawables public BeatmapPanel(BeatmapInfo beatmap) { + if (beatmap == null) + throw new ArgumentNullException(nameof(beatmap)); + Beatmap = beatmap; Height *= 0.60f; diff --git a/osu.Game/Beatmaps/Drawables/BeatmapSetCover.cs b/osu.Game/Beatmaps/Drawables/BeatmapSetCover.cs index df7e0905d0..614ebc236b 100644 --- a/osu.Game/Beatmaps/Drawables/BeatmapSetCover.cs +++ b/osu.Game/Beatmaps/Drawables/BeatmapSetCover.cs @@ -1,6 +1,7 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System; using osu.Framework.Allocation; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; @@ -12,6 +13,9 @@ namespace osu.Game.Beatmaps.Drawables private readonly BeatmapSetInfo set; public BeatmapSetCover(BeatmapSetInfo set) { + if (set == null) + throw new ArgumentNullException(nameof(set)); + this.set = set; } diff --git a/osu.Game/Beatmaps/Drawables/BeatmapSetHeader.cs b/osu.Game/Beatmaps/Drawables/BeatmapSetHeader.cs index ee75b77747..8a589ccd30 100644 --- a/osu.Game/Beatmaps/Drawables/BeatmapSetHeader.cs +++ b/osu.Game/Beatmaps/Drawables/BeatmapSetHeader.cs @@ -36,6 +36,9 @@ namespace osu.Game.Beatmaps.Drawables public BeatmapSetHeader(WorkingBeatmap beatmap) { + if (beatmap == null) + throw new ArgumentNullException(nameof(beatmap)); + this.beatmap = beatmap; Children = new Drawable[] @@ -88,6 +91,9 @@ namespace osu.Game.Beatmaps.Drawables [BackgroundDependencyLoader] private void load(LocalisationEngine localisation) { + if (localisation == null) + throw new ArgumentNullException(nameof(localisation)); + title.Current = localisation.GetUnicodePreference(beatmap.Metadata.TitleUnicode, beatmap.Metadata.Title); artist.Current = localisation.GetUnicodePreference(beatmap.Metadata.ArtistUnicode, beatmap.Metadata.Artist); } @@ -154,6 +160,9 @@ namespace osu.Game.Beatmaps.Drawables public void AddDifficultyIcons(IEnumerable panels) { + if (panels == null) + throw new ArgumentNullException(nameof(panels)); + foreach (var p in panels) difficultyIcons.Add(new DifficultyIcon(p.Beatmap)); } diff --git a/osu.Game/Beatmaps/Drawables/DifficultyColouredContainer.cs b/osu.Game/Beatmaps/Drawables/DifficultyColouredContainer.cs index 41b77f6584..57a5abc4c7 100644 --- a/osu.Game/Beatmaps/Drawables/DifficultyColouredContainer.cs +++ b/osu.Game/Beatmaps/Drawables/DifficultyColouredContainer.cs @@ -1,6 +1,7 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System; using osu.Framework.Allocation; using osu.Framework.Graphics.Containers; using osu.Game.Graphics; @@ -23,6 +24,9 @@ namespace osu.Game.Beatmaps.Drawables [BackgroundDependencyLoader] private void load(OsuColour palette) { + if (palette == null) + throw new ArgumentNullException(nameof(palette)); + this.palette = palette; AccentColour = getColour(beatmap); } @@ -39,6 +43,9 @@ namespace osu.Game.Beatmaps.Drawables private DifficultyRating getDifficultyRating(BeatmapInfo beatmap) { + if (beatmap == null) + throw new ArgumentNullException(nameof(beatmap)); + var rating = beatmap.StarDifficulty; if (rating < 1.5) return DifficultyRating.Easy; diff --git a/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs b/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs index 1aff764ede..8259da9492 100644 --- a/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs +++ b/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs @@ -1,6 +1,7 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Game.Graphics; @@ -15,6 +16,9 @@ namespace osu.Game.Beatmaps.Drawables public DifficultyIcon(BeatmapInfo beatmap) : base(beatmap) { + if (beatmap == null) + throw new ArgumentNullException(nameof(beatmap)); + this.beatmap = beatmap; Size = new Vector2(20); } diff --git a/osu.Game/Beatmaps/Formats/BeatmapDecoder.cs b/osu.Game/Beatmaps/Formats/BeatmapDecoder.cs index 962c6ad49a..7e1a87085c 100644 --- a/osu.Game/Beatmaps/Formats/BeatmapDecoder.cs +++ b/osu.Game/Beatmaps/Formats/BeatmapDecoder.cs @@ -18,6 +18,9 @@ namespace osu.Game.Beatmaps.Formats public static BeatmapDecoder GetDecoder(StreamReader stream) { + if (stream == null) + throw new ArgumentNullException(nameof(stream)); + string line; do { line = stream.ReadLine()?.Trim(); } while (line != null && line.Length == 0); diff --git a/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs b/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs index d775ab409b..11631e9447 100644 --- a/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs +++ b/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs @@ -70,6 +70,11 @@ namespace osu.Game.Beatmaps.Formats private void handleGeneral(Beatmap beatmap, string line) { + if (beatmap == null) + throw new ArgumentNullException(nameof(beatmap)); + if (line == null) + throw new ArgumentNullException(nameof(line)); + var pair = splitKeyVal(line, ':'); var metadata = beatmap.BeatmapInfo.Metadata; @@ -129,6 +134,11 @@ namespace osu.Game.Beatmaps.Formats private void handleEditor(Beatmap beatmap, string line) { + if (beatmap == null) + throw new ArgumentNullException(nameof(beatmap)); + if (line == null) + throw new ArgumentNullException(nameof(line)); + var pair = splitKeyVal(line, ':'); switch (pair.Key) @@ -153,6 +163,11 @@ namespace osu.Game.Beatmaps.Formats private void handleMetadata(Beatmap beatmap, string line) { + if (beatmap == null) + throw new ArgumentNullException(nameof(beatmap)); + if (line == null) + throw new ArgumentNullException(nameof(line)); + var pair = splitKeyVal(line, ':'); var metadata = beatmap.BeatmapInfo.Metadata; @@ -194,6 +209,11 @@ namespace osu.Game.Beatmaps.Formats private void handleDifficulty(Beatmap beatmap, string line) { + if (beatmap == null) + throw new ArgumentNullException(nameof(beatmap)); + if (line == null) + throw new ArgumentNullException(nameof(line)); + var pair = splitKeyVal(line, ':'); var difficulty = beatmap.BeatmapInfo.BaseDifficulty; @@ -226,6 +246,9 @@ namespace osu.Game.Beatmaps.Formats /// The line which may contains variables. private void decodeVariables(ref string line) { + if (line == null) + throw new ArgumentNullException(nameof(line)); + while (line.IndexOf('$') >= 0) { string origLine = line; @@ -244,6 +267,11 @@ namespace osu.Game.Beatmaps.Formats private void handleEvents(Beatmap beatmap, string line, ref StoryboardSprite storyboardSprite, ref CommandTimelineGroup timelineGroup) { + if (line == null) + throw new ArgumentNullException(nameof(line)); + if (beatmap == null) + throw new ArgumentNullException(nameof(beatmap)); + var depth = 0; while (line.StartsWith(" ") || line.StartsWith("_")) { @@ -469,6 +497,11 @@ namespace osu.Game.Beatmaps.Formats private void handleTimingPoints(Beatmap beatmap, string line) { + if (beatmap == null) + throw new ArgumentNullException(nameof(beatmap)); + if (line == null) + throw new ArgumentNullException(nameof(line)); + string[] split = line.Split(','); double time = double.Parse(split[0].Trim(), NumberFormatInfo.InvariantInfo); @@ -555,6 +588,11 @@ namespace osu.Game.Beatmaps.Formats private void handleColours(Beatmap beatmap, string line, ref bool hasCustomColours) { + if (beatmap == null) + throw new ArgumentNullException(nameof(beatmap)); + if (line == null) + throw new ArgumentNullException(nameof(line)); + var pair = splitKeyVal(line, ':'); string[] split = pair.Value.Split(','); @@ -587,6 +625,9 @@ namespace osu.Game.Beatmaps.Formats private void handleVariables(string line) { + if (line == null) + throw new ArgumentNullException(nameof(line)); + var pair = splitKeyVal(line, '='); variables[pair.Key] = pair.Value; } @@ -603,6 +644,11 @@ namespace osu.Game.Beatmaps.Formats protected override void ParseFile(StreamReader stream, Beatmap beatmap) { + if (beatmap == null) + throw new ArgumentNullException(nameof(beatmap)); + if (stream == null) + throw new ArgumentNullException(nameof(stream)); + beatmap.BeatmapInfo.BeatmapVersion = beatmapVersion; Section section = Section.None; @@ -679,6 +725,9 @@ namespace osu.Game.Beatmaps.Formats private KeyValuePair splitKeyVal(string line, char separator) { + if (line == null) + throw new ArgumentNullException(nameof(line)); + var split = line.Trim().Split(new[] { separator }, 2); return new KeyValuePair diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs index b341c4413b..b3e99fce06 100644 --- a/osu.Game/Configuration/OsuConfigManager.cs +++ b/osu.Game/Configuration/OsuConfigManager.cs @@ -16,12 +16,12 @@ namespace osu.Game.Configuration 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.DisplayStarsMinimum, 0.0, 0, 10, 0.1); + Set(OsuSetting.DisplayStarsMaximum, 10.0, 0, 10, 0.1); Set(OsuSetting.SelectionRandomType, SelectionRandomType.RandomPermutation); - Set(OsuSetting.ChatDisplayHeight, ChatOverlay.DEFAULT_HEIGHT, 0.2, 1); + Set(OsuSetting.ChatDisplayHeight, ChatOverlay.DEFAULT_HEIGHT, 0.2, 1, 0.01); // Online settings Set(OsuSetting.Username, string.Empty); @@ -41,11 +41,11 @@ namespace osu.Game.Configuration Set(OsuSetting.MenuVoice, true); Set(OsuSetting.MenuMusic, true); - Set(OsuSetting.AudioOffset, 0, -500.0, 500.0); + Set(OsuSetting.AudioOffset, 0, -500.0, 500.0, 1); // Input - Set(OsuSetting.MenuCursorSize, 1.0, 0.5f, 2); - Set(OsuSetting.GameplayCursorSize, 1.0, 0.5f, 2); + Set(OsuSetting.MenuCursorSize, 1.0, 0.5f, 2, 0.01); + Set(OsuSetting.GameplayCursorSize, 1.0, 0.5f, 2, 0.01); Set(OsuSetting.AutoCursorSize, false); Set(OsuSetting.MouseDisableButtons, false); @@ -63,7 +63,7 @@ namespace osu.Game.Configuration Set(OsuSetting.SnakingOutSliders, true); // Gameplay - Set(OsuSetting.DimLevel, 0.3, 0, 1); + Set(OsuSetting.DimLevel, 0.3, 0, 1, 0.01); Set(OsuSetting.ShowInterface, true); Set(OsuSetting.KeyOverlay, false); diff --git a/osu.Game/Graphics/Containers/ParallaxContainer.cs b/osu.Game/Graphics/Containers/ParallaxContainer.cs index 3e0ed4b059..362563507b 100644 --- a/osu.Game/Graphics/Containers/ParallaxContainer.cs +++ b/osu.Game/Graphics/Containers/ParallaxContainer.cs @@ -11,7 +11,7 @@ using osu.Framework.Configuration; namespace osu.Game.Graphics.Containers { - internal class ParallaxContainer : Container, IRequireHighFrequencyMousePosition + public class ParallaxContainer : Container, IRequireHighFrequencyMousePosition { public float ParallaxAmount = 0.02f; diff --git a/osu.Game/Online/API/APIAccess.cs b/osu.Game/Online/API/APIAccess.cs index 4e26b1b850..daf56657d2 100644 --- a/osu.Game/Online/API/APIAccess.cs +++ b/osu.Game/Online/API/APIAccess.cs @@ -118,6 +118,7 @@ namespace osu.Game.Online.API //NotificationOverlay.ShowMessage("Login failed!"); log.Add(@"Login failed!"); Password = null; + authentication.Clear(); continue; } diff --git a/osu.Game/Online/API/APIRequest.cs b/osu.Game/Online/API/APIRequest.cs index 9a8180778d..71b18103b0 100644 --- a/osu.Game/Online/API/APIRequest.cs +++ b/osu.Game/Online/API/APIRequest.cs @@ -36,7 +36,7 @@ namespace osu.Game.Online.API return request; } - private void request_Progress(WebRequest request, long current, long total) => API.Scheduler.Add(delegate { Progress?.Invoke(current, total); }); + private void request_Progress(long current, long total) => API.Scheduler.Add(delegate { Progress?.Invoke(current, total); }); protected APIDownloadRequest() { @@ -99,8 +99,8 @@ namespace osu.Game.Online.API throw new TimeoutException(@"API request timeout hit"); WebRequest = CreateWebRequest(); - WebRequest.RetryCount = 0; - WebRequest.Headers[@"Authorization"] = $@"Bearer {api.AccessToken}"; + WebRequest.AllowRetryOnTimeout = false; + WebRequest.AddHeader("Authorization", $"Bearer {api.AccessToken}"); if (checkAndProcessFailure()) return; diff --git a/osu.Game/Online/API/OAuth.cs b/osu.Game/Online/API/OAuth.cs index 445688f2ce..ca38f72904 100644 --- a/osu.Game/Online/API/OAuth.cs +++ b/osu.Game/Online/API/OAuth.cs @@ -27,6 +27,9 @@ namespace osu.Game.Online.API internal bool AuthenticateWithLogin(string username, string password) { + if (string.IsNullOrEmpty(username)) return false; + if (string.IsNullOrEmpty(password)) return false; + using (var req = new AccessTokenRequestPassword(username, password) { Url = $@"{endpoint}/oauth/token", @@ -127,7 +130,8 @@ namespace osu.Game.Online.API protected override void PrePerform() { - Parameters[@"refresh_token"] = RefreshToken; + AddParameter("refresh_token", RefreshToken); + base.PrePerform(); } } @@ -146,8 +150,9 @@ namespace osu.Game.Online.API protected override void PrePerform() { - Parameters[@"username"] = Username; - Parameters[@"password"] = Password; + AddParameter("username", Username); + AddParameter("password", Password); + base.PrePerform(); } } @@ -161,9 +166,10 @@ namespace osu.Game.Online.API protected override void PrePerform() { - Parameters[@"grant_type"] = GrantType; - Parameters[@"client_id"] = ClientId; - Parameters[@"client_secret"] = ClientSecret; + AddParameter("grant_type", GrantType); + AddParameter("client_id", ClientId); + AddParameter("client_secret", ClientSecret); + base.PrePerform(); } } diff --git a/osu.Game/Overlays/BeatmapSet/Details.cs b/osu.Game/Overlays/BeatmapSet/Details.cs index 2fd0a55d9e..128ea7d2d3 100644 --- a/osu.Game/Overlays/BeatmapSet/Details.cs +++ b/osu.Game/Overlays/BeatmapSet/Details.cs @@ -88,6 +88,8 @@ namespace osu.Game.Overlays.BeatmapSet }; } + public void StopPreview() => preview.Playing.Value = false; + private class DetailBox : Container { private readonly Container content; diff --git a/osu.Game/Overlays/BeatmapSet/Header.cs b/osu.Game/Overlays/BeatmapSet/Header.cs index a93ccbf704..d4514cbaed 100644 --- a/osu.Game/Overlays/BeatmapSet/Header.cs +++ b/osu.Game/Overlays/BeatmapSet/Header.cs @@ -27,7 +27,7 @@ namespace osu.Game.Overlays.BeatmapSet private readonly Container coverContainer; private readonly OsuSpriteText title, artist; private readonly AuthorInfo author; - private readonly Details details; + public Details Details; private DelayedLoadWrapper cover; @@ -42,7 +42,7 @@ namespace osu.Game.Overlays.BeatmapSet if (value == beatmapSet) return; beatmapSet = value; - Picker.BeatmapSet = author.BeatmapSet = details.BeatmapSet = BeatmapSet; + Picker.BeatmapSet = author.BeatmapSet = Details.BeatmapSet = BeatmapSet; title.Text = BeatmapSet.Metadata.Title; artist.Text = BeatmapSet.Metadata.Artist; @@ -192,7 +192,7 @@ namespace osu.Game.Overlays.BeatmapSet }, }, }, - details = new Details + Details = new Details { Anchor = Anchor.BottomRight, Origin = Anchor.BottomRight, @@ -204,7 +204,7 @@ namespace osu.Game.Overlays.BeatmapSet Picker.Beatmap.ValueChanged += b => { - details.Beatmap = b; + Details.Beatmap = b; if (b.OnlineInfo.HasVideo) { diff --git a/osu.Game/Overlays/BeatmapSet/PreviewButton.cs b/osu.Game/Overlays/BeatmapSet/PreviewButton.cs index f77a1f4a0a..52edd1714f 100644 --- a/osu.Game/Overlays/BeatmapSet/PreviewButton.cs +++ b/osu.Game/Overlays/BeatmapSet/PreviewButton.cs @@ -26,7 +26,7 @@ namespace osu.Game.Overlays.BeatmapSet private readonly PlayButton playButton; private Track preview => playButton.Preview; - private Bindable playing => playButton.Playing; + public Bindable Playing => playButton.Playing; public BeatmapSetInfo BeatmapSet { @@ -66,8 +66,8 @@ namespace osu.Game.Overlays.BeatmapSet }, }; - Action = () => playing.Value = !playing.Value; - playing.ValueChanged += newValue => progress.FadeTo(newValue ? 1 : 0, 100); + Action = () => Playing.Value = !Playing.Value; + Playing.ValueChanged += newValue => progress.FadeTo(newValue ? 1 : 0, 100); } [BackgroundDependencyLoader] @@ -80,7 +80,7 @@ namespace osu.Game.Overlays.BeatmapSet { base.Update(); - if (playing.Value && preview != null) + if (Playing.Value && preview != null) { progress.Width = (float)(preview.CurrentTime / preview.Length); } @@ -88,7 +88,7 @@ namespace osu.Game.Overlays.BeatmapSet protected override void Dispose(bool isDisposing) { - playing.Value = false; + Playing.Value = false; base.Dispose(isDisposing); } diff --git a/osu.Game/Overlays/BeatmapSetOverlay.cs b/osu.Game/Overlays/BeatmapSetOverlay.cs index a60429f737..ddd146bcb6 100644 --- a/osu.Game/Overlays/BeatmapSetOverlay.cs +++ b/osu.Game/Overlays/BeatmapSetOverlay.cs @@ -98,6 +98,7 @@ namespace osu.Game.Overlays protected override void PopOut() { base.PopOut(); + header.Details.StopPreview(); FadeEdgeEffectTo(0, DISAPPEAR_DURATION, Easing.Out); } diff --git a/osu.Game/Overlays/Profile/ProfileSection.cs b/osu.Game/Overlays/Profile/ProfileSection.cs index df7c0e117f..99178570a6 100644 --- a/osu.Game/Overlays/Profile/ProfileSection.cs +++ b/osu.Game/Overlays/Profile/ProfileSection.cs @@ -9,6 +9,7 @@ using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Users; using OpenTK.Graphics; +using osu.Framework.Configuration; namespace osu.Game.Overlays.Profile { @@ -22,13 +23,7 @@ namespace osu.Game.Overlays.Profile protected override Container Content => content; - public virtual User User - { - get { return user; } - set { user = value; } - } - - private User user; + public readonly Bindable User = new Bindable(); protected ProfileSection() { diff --git a/osu.Game/Overlays/Profile/RankChart.cs b/osu.Game/Overlays/Profile/RankChart.cs index 2e2286098a..5bd6d30b42 100644 --- a/osu.Game/Overlays/Profile/RankChart.cs +++ b/osu.Game/Overlays/Profile/RankChart.cs @@ -2,7 +2,6 @@ // 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 osu.Framework.Allocation; @@ -33,6 +32,9 @@ namespace osu.Game.Overlays.Profile { this.user = user; + int[] userRanks = user.RankHistory?.Data ?? new[] { user.Statistics.Rank }; + ranks = userRanks.SkipWhile(x => x == 0).ToArray(); + Padding = new MarginPadding { Vertical = padding }; Children = new Drawable[] { @@ -58,19 +60,21 @@ namespace osu.Game.Overlays.Profile Font = @"Exo2.0-RegularItalic", TextSize = secondary_textsize }, - graph = new RankChartLineGraph + }; + + if (ranks.Length > 0) + { + Add(graph = new RankChartLineGraph { Anchor = Anchor.BottomCentre, Origin = Anchor.BottomCentre, RelativeSizeAxes = Axes.X, Y = -secondary_textsize, - DefaultValueCount = 90, - BallRelease = updateRankTexts, - BallMove = showHistoryRankTexts - } - }; + DefaultValueCount = ranks.Length, + }); - ranks = user.RankHistory?.Data ?? new[] { user.Statistics.Rank }; + graph.OnBallMove += showHistoryRankTexts; + } } private void updateRankTexts() @@ -82,7 +86,8 @@ namespace osu.Game.Overlays.Profile private void showHistoryRankTexts(int dayIndex) { - rankText.Text = ranks[dayIndex] > 0 ? $"#{ranks[dayIndex]:#,0}" : "no rank"; + rankText.Text = $"#{ranks[dayIndex]:#,0}"; + dayIndex++; relativeText.Text = dayIndex == ranks.Length ? "Now" : $"{ranks.Length - dayIndex} days ago"; //plural should be handled in a general way } @@ -90,14 +95,15 @@ namespace osu.Game.Overlays.Profile [BackgroundDependencyLoader] private void load(OsuColour colours) { - graph.Colour = colours.Yellow; - - if (user.Statistics.Rank > 0) + if (graph != null) { + graph.Colour = colours.Yellow; // use logarithmic coordinates graph.Values = ranks.Select(x => -(float)Math.Log(x)); - graph.ResetBall(); + graph.SetStaticBallPosition(); } + + updateRankTexts(); } public override bool Invalidate(Invalidation invalidation = Invalidation.All, Drawable source = null, bool shallPropagate = true) @@ -110,67 +116,78 @@ namespace osu.Game.Overlays.Profile return base.Invalidate(invalidation, source, shallPropagate); } + protected override bool OnHover(InputState state) + { + graph?.UpdateBallPosition(state.Mouse.Position.X); + graph?.ShowBall(); + return base.OnHover(state); + } + + protected override bool OnMouseMove(InputState state) + { + graph?.UpdateBallPosition(state.Mouse.Position.X); + return base.OnMouseMove(state); + } + + protected override void OnHoverLost(InputState state) + { + if (graph != null) + { + graph.HideBall(); + updateRankTexts(); + } + base.OnHoverLost(state); + } + private class RankChartLineGraph : LineGraph { - private readonly CircularContainer ball; - private bool ballShown; + private const double fade_duration = 200; - private const double transform_duration = 100; + private readonly CircularContainer staticBall; + private readonly CircularContainer movingBall; - public Action BallMove; - public Action BallRelease; + public Action OnBallMove; public RankChartLineGraph() { - Add(ball = new CircularContainer + Add(staticBall = new CircularContainer { + Origin = Anchor.Centre, Size = new Vector2(8), Masking = true, - Origin = Anchor.Centre, - Alpha = 0, RelativePositionAxes = Axes.Both, - Children = new Drawable[] - { - new Box { RelativeSizeAxes = Axes.Both } - } + Child = new Box { RelativeSizeAxes = Axes.Both } + }); + Add(movingBall = new CircularContainer + { + Origin = Anchor.Centre, + Size = new Vector2(8), + Alpha = 0, + Masking = true, + RelativePositionAxes = Axes.Both, + Child = new Box { RelativeSizeAxes = Axes.Both } }); } - public void ResetBall() + public void SetStaticBallPosition() => staticBall.Position = new Vector2(1, GetYPosition(Values.Last())); + + public void UpdateBallPosition(float mouseXPosition) { - ball.MoveTo(new Vector2(1, GetYPosition(Values.Last())), ballShown ? transform_duration : 0, Easing.OutQuint); - ball.Show(); - BallRelease(); - ballShown = true; + int index = calculateIndex(mouseXPosition); + movingBall.Position = calculateBallPosition(index); + OnBallMove.Invoke(index); } - protected override bool OnMouseMove(InputState state) - { - if (ballShown) - { - var values = (IList)Values; - var position = ToLocalSpace(state.Mouse.NativeState.Position); - int count = Math.Max(values.Count, DefaultValueCount); - int index = (int)Math.Round(position.X / DrawWidth * (count - 1)); - if (index >= count - values.Count) - { - int i = index + values.Count - count; - float y = GetYPosition(values[i]); - if (Math.Abs(y * DrawHeight - position.Y) <= 8f) - { - ball.MoveTo(new Vector2(index / (float)(count - 1), y), transform_duration, Easing.OutQuint); - BallMove(i); - } - } - } - return base.OnMouseMove(state); - } + public void ShowBall() => movingBall.FadeIn(fade_duration); - protected override void OnHoverLost(InputState state) + public void HideBall() => movingBall.FadeOut(fade_duration); + + private int calculateIndex(float mouseXPosition) => (int)Math.Round(mouseXPosition / DrawWidth * (DefaultValueCount - 1)); + + private Vector2 calculateBallPosition(int index) { - if (ballShown) - ResetBall(); - base.OnHoverLost(state); + float y = GetYPosition(Values.ElementAt(index)); + return new Vector2(index / (float)(DefaultValueCount - 1), y); } } } diff --git a/osu.Game/Overlays/Profile/Sections/HistoricalSection.cs b/osu.Game/Overlays/Profile/Sections/HistoricalSection.cs index 78ed6bf846..d25407f4a3 100644 --- a/osu.Game/Overlays/Profile/Sections/HistoricalSection.cs +++ b/osu.Game/Overlays/Profile/Sections/HistoricalSection.cs @@ -1,6 +1,9 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using osu.Game.Online.API.Requests; +using osu.Game.Overlays.Profile.Sections.Ranks; + namespace osu.Game.Overlays.Profile.Sections { public class HistoricalSection : ProfileSection @@ -8,5 +11,10 @@ namespace osu.Game.Overlays.Profile.Sections public override string Title => "Historical"; public override string Identifier => "historical"; + + public HistoricalSection() + { + Child = new PaginatedScoreContainer(ScoreType.Recent, User, "Recent Plays (24h)"); + } } } diff --git a/osu.Game/Overlays/Profile/Sections/Ranks/DrawablePerformanceScore.cs b/osu.Game/Overlays/Profile/Sections/Ranks/DrawablePerformanceScore.cs new file mode 100644 index 0000000000..0380b6c4b7 --- /dev/null +++ b/osu.Game/Overlays/Profile/Sections/Ranks/DrawablePerformanceScore.cs @@ -0,0 +1,49 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osu.Game.Rulesets.Scoring; + +namespace osu.Game.Overlays.Profile.Sections.Ranks +{ + public class DrawablePerformanceScore : DrawableScore + { + private readonly double? weight; + + public DrawablePerformanceScore(Score score, double? weight = null) + : base(score) + { + this.weight = weight; + } + + [BackgroundDependencyLoader] + private new void load(OsuColour colour) + { + double pp = Score.PP ?? 0; + Stats.Add(new OsuSpriteText + { + Text = $"{pp:0}pp", + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + TextSize = 18, + Font = "Exo2.0-BoldItalic", + }); + + if (weight.HasValue) + { + Stats.Add(new OsuSpriteText + { + Text = $"weighted: {pp * weight:0}pp ({weight:P0})", + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + Colour = colour.GrayA, + TextSize = 11, + Font = "Exo2.0-RegularItalic", + }); + } + } + } +} diff --git a/osu.Game/Overlays/Profile/Sections/Ranks/DrawableScore.cs b/osu.Game/Overlays/Profile/Sections/Ranks/DrawableScore.cs index af336c2529..91f5650b92 100644 --- a/osu.Game/Overlays/Profile/Sections/Ranks/DrawableScore.cs +++ b/osu.Game/Overlays/Profile/Sections/Ranks/DrawableScore.cs @@ -18,18 +18,16 @@ using osu.Game.Rulesets.UI; namespace osu.Game.Overlays.Profile.Sections.Ranks { - public class DrawableScore : Container + public abstract class DrawableScore : Container { - private readonly FillFlowContainer stats; + protected readonly FillFlowContainer Stats; private readonly FillFlowContainer metadata; private readonly ModContainer modContainer; - private readonly Score score; - private readonly double? weight; + protected readonly Score Score; - public DrawableScore(Score score, double? weight = null) + protected DrawableScore(Score score) { - this.score = score; - this.weight = weight; + Score = score; Children = new Drawable[] { @@ -39,7 +37,7 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks Width = 60, FillMode = FillMode.Fit, }, - stats = new FillFlowContainer + Stats = new FillFlowContainer { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, @@ -74,40 +72,18 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks }; } - [BackgroundDependencyLoader] + [BackgroundDependencyLoader(true)] private void load(OsuColour colour, LocalisationEngine locale, BeatmapSetOverlay beatmapSetOverlay) { - double pp = score.PP ?? 0; - stats.Add(new OsuSpriteText + Stats.Add(new OsuSpriteText { - Text = $"{pp:0}pp", - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, - TextSize = 18, - Font = "Exo2.0-BoldItalic", - }); - - if (weight.HasValue) - { - stats.Add(new OsuSpriteText - { - Text = $"weighted: {pp * weight:0}pp ({weight:P0})", - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, - Colour = colour.GrayA, - TextSize = 11, - Font = "Exo2.0-RegularItalic", - }); - } - - stats.Add(new OsuSpriteText - { - Text = $"accuracy: {score.Accuracy:P2}", + Text = $"accuracy: {Score.Accuracy:P2}", Anchor = Anchor.TopRight, Origin = Anchor.TopRight, Colour = colour.GrayA, TextSize = 11, Font = "Exo2.0-RegularItalic", + Depth = -1, }); metadata.Add(new OsuHoverContainer @@ -115,7 +91,7 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks AutoSizeAxes = Axes.Both, Action = () => { - if (score.Beatmap.OnlineBeatmapSetID.HasValue) beatmapSetOverlay.ShowBeatmapSet(score.Beatmap.OnlineBeatmapSetID.Value); + if (Score.Beatmap.OnlineBeatmapSetID.HasValue) beatmapSetOverlay?.ShowBeatmapSet(Score.Beatmap.OnlineBeatmapSetID.Value); }, Child = new FillFlowContainer { @@ -125,15 +101,15 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks new OsuSpriteText { Current = locale.GetUnicodePreference( - $"{score.Beatmap.Metadata.TitleUnicode ?? score.Beatmap.Metadata.Title} [{score.Beatmap.Version}] ", - $"{score.Beatmap.Metadata.Title ?? score.Beatmap.Metadata.TitleUnicode} [{score.Beatmap.Version}] " + $"{Score.Beatmap.Metadata.TitleUnicode ?? Score.Beatmap.Metadata.Title} [{Score.Beatmap.Version}] ", + $"{Score.Beatmap.Metadata.Title ?? Score.Beatmap.Metadata.TitleUnicode} [{Score.Beatmap.Version}] " ), TextSize = 15, Font = "Exo2.0-SemiBoldItalic", }, new OsuSpriteText { - Current = locale.GetUnicodePreference(score.Beatmap.Metadata.ArtistUnicode, score.Beatmap.Metadata.Artist), + Current = locale.GetUnicodePreference(Score.Beatmap.Metadata.ArtistUnicode, Score.Beatmap.Metadata.Artist), TextSize = 12, Padding = new MarginPadding { Top = 3 }, Font = "Exo2.0-RegularItalic", @@ -142,7 +118,7 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks }, }); - foreach (Mod mod in score.Mods) + foreach (Mod mod in Score.Mods) modContainer.Add(new ModIcon(mod) { AutoSizeAxes = Axes.Both, diff --git a/osu.Game/Overlays/Profile/Sections/Ranks/DrawableTotalScore.cs b/osu.Game/Overlays/Profile/Sections/Ranks/DrawableTotalScore.cs new file mode 100644 index 0000000000..7aa9d75f02 --- /dev/null +++ b/osu.Game/Overlays/Profile/Sections/Ranks/DrawableTotalScore.cs @@ -0,0 +1,31 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Game.Graphics.Sprites; +using osu.Game.Rulesets.Scoring; + +namespace osu.Game.Overlays.Profile.Sections.Ranks +{ + public class DrawableTotalScore : DrawableScore + { + public DrawableTotalScore(Score score) + : base(score) + { + } + + [BackgroundDependencyLoader] + private new void load() + { + Stats.Add(new OsuSpriteText + { + Text = Score.TotalScore.ToString("#,###"), + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + TextSize = 18, + Font = "Exo2.0-BoldItalic", + }); + } + } +} diff --git a/osu.Game/Overlays/Profile/Sections/Ranks/PaginatedScoreContainer.cs b/osu.Game/Overlays/Profile/Sections/Ranks/PaginatedScoreContainer.cs new file mode 100644 index 0000000000..060bb03014 --- /dev/null +++ b/osu.Game/Overlays/Profile/Sections/Ranks/PaginatedScoreContainer.cs @@ -0,0 +1,153 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using OpenTK; +using osu.Framework.Allocation; +using osu.Framework.Configuration; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Graphics.Containers; +using osu.Game.Graphics.Sprites; +using osu.Game.Graphics.UserInterface; +using osu.Game.Online.API; +using osu.Game.Online.API.Requests; +using osu.Game.Rulesets; +using osu.Game.Users; +using System; +using System.Linq; + +namespace osu.Game.Overlays.Profile.Sections.Ranks +{ + public class PaginatedScoreContainer : FillFlowContainer + { + private readonly FillFlowContainer scoreContainer; + private readonly OsuSpriteText missing; + private readonly OsuHoverContainer showMoreButton; + private readonly LoadingAnimation showMoreLoading; + + private readonly bool includeWeight; + private readonly ScoreType type; + private int visiblePages; + + private readonly Bindable user = new Bindable(); + + private RulesetStore rulesets; + private APIAccess api; + + public PaginatedScoreContainer(ScoreType type, Bindable user, string header, bool includeWeight = false) + { + this.type = type; + this.includeWeight = includeWeight; + this.user.BindTo(user); + + RelativeSizeAxes = Axes.X; + AutoSizeAxes = Axes.Y; + Direction = FillDirection.Vertical; + + Children = new Drawable[] + { + new OsuSpriteText + { + TextSize = 15, + Text = header, + Font = "Exo2.0-RegularItalic", + Margin = new MarginPadding { Top = 10, Bottom = 10 }, + }, + scoreContainer = new FillFlowContainer + { + AutoSizeAxes = Axes.Y, + RelativeSizeAxes = Axes.X, + Direction = FillDirection.Vertical, + }, + showMoreButton = new OsuHoverContainer + { + Alpha = 0, + Action = showMore, + AutoSizeAxes = Axes.Both, + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Child = new OsuSpriteText + { + TextSize = 14, + Text = "show more", + } + }, + showMoreLoading = new LoadingAnimation + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Size = new Vector2(14), + }, + missing = new OsuSpriteText + { + TextSize = 14, + Text = type == ScoreType.Recent ? "No performance records. :(" : "No awesome performance records yet. :(", + }, + }; + } + + [BackgroundDependencyLoader] + private void load(APIAccess api, RulesetStore rulesets) + { + this.api = api; + this.rulesets = rulesets; + + user.ValueChanged += user_ValueChanged; + user.TriggerChange(); + } + + private void user_ValueChanged(User newUser) + { + visiblePages = 0; + scoreContainer.Clear(); + showMoreButton.Hide(); + missing.Show(); + + if (newUser != null) + showMore(); + } + + private void showMore() + { + var req = new GetUserScoresRequest(user.Value.Id, type, visiblePages++ * 5); + + showMoreLoading.Show(); + showMoreButton.Hide(); + + req.Success += scores => + { + foreach (var s in scores) + s.ApplyRuleset(rulesets.GetRuleset(s.OnlineRulesetID)); + + showMoreButton.FadeTo(scores.Count == 5 ? 1 : 0); + showMoreLoading.Hide(); + + if (!scores.Any()) return; + + missing.Hide(); + + foreach (OnlineScore score in scores) + { + DrawableScore drawableScore; + + switch (type) + { + default: + drawableScore = new DrawablePerformanceScore(score, includeWeight ? Math.Pow(0.95, scoreContainer.Count) : (double?)null); + break; + case ScoreType.Recent: + drawableScore = new DrawableTotalScore(score); + break; + } + + drawableScore.RelativeSizeAxes = Axes.X; + drawableScore.Height = 60; + + scoreContainer.Add(drawableScore); + } + }; + + api.Queue(req); + } + } +} diff --git a/osu.Game/Overlays/Profile/Sections/RanksSection.cs b/osu.Game/Overlays/Profile/Sections/RanksSection.cs index 3b2c9d83ed..553691ef77 100644 --- a/osu.Game/Overlays/Profile/Sections/RanksSection.cs +++ b/osu.Game/Overlays/Profile/Sections/RanksSection.cs @@ -1,20 +1,8 @@ // 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.Game.Graphics.Containers; -using osu.Game.Graphics.Sprites; using osu.Game.Overlays.Profile.Sections.Ranks; -using System; -using System.Linq; -using osu.Game.Online.API; using osu.Game.Online.API.Requests; -using osu.Game.Rulesets; -using osu.Game.Users; -using osu.Game.Graphics.UserInterface; -using OpenTK; -using osu.Framework.Allocation; namespace osu.Game.Overlays.Profile.Sections { @@ -24,147 +12,13 @@ namespace osu.Game.Overlays.Profile.Sections public override string Identifier => "top_ranks"; - private readonly ScoreContainer best, first; - public RanksSection() { - Children = new Drawable[] + Children = new[] { - best = new ScoreContainer(ScoreType.Best, "Best Performance", true), - first = new ScoreContainer(ScoreType.Firsts, "First Place Ranks"), + new PaginatedScoreContainer(ScoreType.Best, User, "Best Performance", true), + new PaginatedScoreContainer(ScoreType.Firsts, User, "First Place Ranks"), }; } - - public override User User - { - get - { - return base.User; - } - - set - { - base.User = value; - best.User = value; - first.User = value; - } - } - - private class ScoreContainer : FillFlowContainer - { - private readonly FillFlowContainer scoreContainer; - private readonly OsuSpriteText missing; - private readonly OsuHoverContainer showMoreButton; - private readonly LoadingAnimation showMoreLoading; - - private readonly ScoreType type; - private int visiblePages; - private User user; - private readonly bool includeWeigth; - - private RulesetStore rulesets; - private APIAccess api; - - public User User - { - set - { - user = value; - visiblePages = 0; - scoreContainer.Clear(); - showMoreButton.Hide(); - missing.Show(); - showMore(); - } - } - - public ScoreContainer(ScoreType type, string header, bool includeWeigth = false) - { - this.type = type; - this.includeWeigth = includeWeigth; - - RelativeSizeAxes = Axes.X; - AutoSizeAxes = Axes.Y; - Direction = FillDirection.Vertical; - - Children = new Drawable[] - { - new OsuSpriteText - { - TextSize = 15, - Text = header, - Font = "Exo2.0-RegularItalic", - Margin = new MarginPadding { Top = 10, Bottom = 10 }, - }, - scoreContainer = new FillFlowContainer - { - AutoSizeAxes = Axes.Y, - RelativeSizeAxes = Axes.X, - Direction = FillDirection.Vertical, - }, - showMoreButton = new OsuHoverContainer - { - Alpha = 0, - Action = showMore, - AutoSizeAxes = Axes.Both, - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - Child = new OsuSpriteText - { - TextSize = 14, - Text = "show more", - } - }, - showMoreLoading = new LoadingAnimation - { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - Size = new Vector2(14), - }, - missing = new OsuSpriteText - { - TextSize = 14, - Text = "No awesome performance records yet. :(", - }, - }; - } - - [BackgroundDependencyLoader] - private void load(APIAccess api, RulesetStore rulesets) - { - this.api = api; - this.rulesets = rulesets; - } - - private void showMore() - { - var req = new GetUserScoresRequest(user.Id, type, visiblePages++ * 5); - - showMoreLoading.Show(); - showMoreButton.Hide(); - - req.Success += scores => - { - foreach (var s in scores) - s.ApplyRuleset(rulesets.GetRuleset(s.OnlineRulesetID)); - - showMoreButton.FadeTo(scores.Count == 5 ? 1 : 0); - showMoreLoading.Hide(); - - if (scores.Any()) - { - missing.Hide(); - foreach (OnlineScore score in scores) - scoreContainer.Add(new DrawableScore(score, includeWeigth ? Math.Pow(0.95, scoreContainer.Count) : (double?)null) - { - RelativeSizeAxes = Axes.X, - Height = 60, - }); - } - }; - - Schedule(() => { api.Queue(req); }); - } - } } } diff --git a/osu.Game/Overlays/Settings/SettingsItem.cs b/osu.Game/Overlays/Settings/SettingsItem.cs index 5a0f25f7e0..e03fc91aa7 100644 --- a/osu.Game/Overlays/Settings/SettingsItem.cs +++ b/osu.Game/Overlays/Settings/SettingsItem.cs @@ -80,7 +80,7 @@ namespace osu.Game.Overlays.Settings controlWithCurrent?.Current.BindTo(bindable); if (ShowsDefaultIndicator) { - restoreDefaultValueButton.Bindable.BindTo(bindable); + restoreDefaultValueButton.Bindable = bindable.GetBoundCopy(); restoreDefaultValueButton.Bindable.TriggerChange(); } } @@ -134,7 +134,17 @@ namespace osu.Game.Overlays.Settings private class RestoreDefaultValueButton : Box, IHasTooltip { - internal readonly Bindable Bindable = new Bindable(); + private Bindable bindable; + internal Bindable Bindable + { + get { return bindable; } + set + { + bindable = value; + bindable.ValueChanged += newValue => UpdateState(); + bindable.DisabledChanged += disabled => UpdateState(); + } + } private Color4 buttonColour; @@ -142,9 +152,6 @@ namespace osu.Game.Overlays.Settings public RestoreDefaultValueButton() { - Bindable.ValueChanged += value => UpdateState(); - Bindable.DisabledChanged += disabled => UpdateState(); - RelativeSizeAxes = Axes.Y; Width = SettingsOverlay.CONTENT_MARGINS; Alpha = 0f; @@ -160,8 +167,8 @@ namespace osu.Game.Overlays.Settings protected override bool OnClick(InputState state) { - if (!Bindable.Disabled) - Bindable.SetDefault(); + if (bindable != null && !bindable.Disabled) + bindable.SetDefault(); return true; } @@ -186,8 +193,10 @@ namespace osu.Game.Overlays.Settings internal void UpdateState() { - var colour = Bindable.Disabled ? Color4.Gray : buttonColour; - this.FadeTo(Bindable.IsDefault ? 0f : hovering && !Bindable.Disabled ? 1f : 0.5f, 200, Easing.OutQuint); + if (bindable == null) + return; + var colour = bindable.Disabled ? Color4.Gray : buttonColour; + this.FadeTo(bindable.IsDefault ? 0f : hovering && !bindable.Disabled ? 1f : 0.5f, 200, Easing.OutQuint); this.FadeColour(ColourInfo.GradientHorizontal(colour.Opacity(0.8f), colour.Opacity(0)), 200, Easing.OutQuint); } } diff --git a/osu.Game/Overlays/UserProfileOverlay.cs b/osu.Game/Overlays/UserProfileOverlay.cs index e6c45f6826..5032f2d55b 100644 --- a/osu.Game/Overlays/UserProfileOverlay.cs +++ b/osu.Game/Overlays/UserProfileOverlay.cs @@ -95,7 +95,7 @@ namespace osu.Game.Overlays //new RecentSection(), new RanksSection(), //new MedalsSection(), - //new HistoricalSection(), + new HistoricalSection(), //new BeatmapsSection(), //new KudosuSection() }; @@ -175,7 +175,7 @@ namespace osu.Game.Overlays var sec = sections.FirstOrDefault(s => s.Identifier == id); if (sec != null) { - sec.User = user; + sec.User.Value = user; sectionsContainer.Add(sec); tabs.AddItem(sec); diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index c610a24e22..74e55e58ad 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -24,7 +24,7 @@ namespace osu.Game.Screens.Edit { protected override BackgroundScreen CreateBackground() => new BackgroundScreenCustom(@"Backgrounds/bg4"); - internal override bool ShowOverlays => false; + public override bool ShowOverlays => false; private readonly Box bottomBackground; private readonly Container screenContainer; diff --git a/osu.Game/Screens/Loader.cs b/osu.Game/Screens/Loader.cs index af084e740b..3afaa02824 100644 --- a/osu.Game/Screens/Loader.cs +++ b/osu.Game/Screens/Loader.cs @@ -2,26 +2,62 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using osu.Framework.Allocation; +using osu.Framework.Graphics; using osu.Game.Screens.Menu; +using OpenTK; +using osu.Framework.Screens; namespace osu.Game.Screens { - internal class Loader : OsuScreen + public class Loader : OsuScreen { - internal override bool ShowOverlays => false; + private bool showDisclaimer; + + public override bool ShowOverlays => false; public Loader() { ValidForResume = false; } - [BackgroundDependencyLoader] - private void load(OsuGame game) + protected override void LogoArriving(OsuLogo logo, bool resuming) { - if (game.IsDeployedBuild) + base.LogoArriving(logo, resuming); + + logo.RelativePositionAxes = Axes.None; + logo.Triangles = false; + logo.Origin = Anchor.BottomRight; + logo.Anchor = Anchor.BottomRight; + logo.Position = new Vector2(-40); + logo.Scale = new Vector2(0.2f); + + logo.FadeInFromZero(5000, Easing.OutQuint); + } + + protected override void OnEntering(Screen last) + { + base.OnEntering(last); + + if (showDisclaimer) LoadComponentAsync(new Disclaimer(), d => Push(d)); else LoadComponentAsync(new Intro(), d => Push(d)); } + + protected override void LogoSuspending(OsuLogo logo) + { + base.LogoSuspending(logo); + logo.FadeOut(100).OnComplete(l => + { + l.Anchor = Anchor.TopLeft; + l.Origin = Anchor.Centre; + }); + } + + [BackgroundDependencyLoader] + private void load(OsuGameBase game) + { + showDisclaimer = game.IsDeployedBuild; + } } } diff --git a/osu.Game/Screens/Menu/ButtonSystem.cs b/osu.Game/Screens/Menu/ButtonSystem.cs index e4dbe00a80..af16fbd71c 100644 --- a/osu.Game/Screens/Menu/ButtonSystem.cs +++ b/osu.Game/Screens/Menu/ButtonSystem.cs @@ -39,12 +39,25 @@ namespace osu.Game.Screens.Menu //todo: make these non-internal somehow. internal const float BUTTON_AREA_HEIGHT = 100; + internal const float BUTTON_WIDTH = 140f; internal const float WEDGE_WIDTH = 20; - public const int EXIT_DELAY = 3000; + private OsuLogo logo; + + public void SetOsuLogo(OsuLogo logo) + { + this.logo = logo; + + if (this.logo != null) + { + this.logo.Action = onOsuLogo; + + // osuLogo.SizeForFlow relies on loading to be complete. + buttonFlow.Position = new Vector2(WEDGE_WIDTH * 2 - (BUTTON_WIDTH + this.logo.SizeForFlow / 4), 0); + } + } - private readonly OsuLogo osuLogo; private readonly Drawable iconFacade; private readonly Container buttonArea; private readonly Box buttonAreaBackground; @@ -99,12 +112,6 @@ namespace osu.Game.Screens.Menu } } }, - osuLogo = new OsuLogo - { - Action = onOsuLogo, - Origin = Anchor.Centre, - Anchor = Anchor.Centre, - } }; buttonsPlay.Add(new Button(@"solo", @"select-6", FontAwesome.fa_user, new Color4(102, 68, 204, 255), () => OnSolo?.Invoke(), WEDGE_WIDTH, Key.P)); @@ -127,14 +134,6 @@ namespace osu.Game.Screens.Menu sampleBack = audio.Sample.Get(@"Menu/select-4"); } - protected override void LoadComplete() - { - base.LoadComplete(); - - // osuLogo.SizeForFlow relies on loading to be complete. - buttonFlow.Position = new Vector2(WEDGE_WIDTH * 2 - (BUTTON_WIDTH + osuLogo.SizeForFlow / 4), 0); - } - protected override bool OnKeyDown(InputState state, KeyDownEventArgs args) { if (args.Repeat) return false; @@ -142,7 +141,7 @@ namespace osu.Game.Screens.Menu switch (args.Key) { case Key.Space: - osuLogo.TriggerOnClick(state); + logo?.TriggerOnClick(state); return true; case Key.Escape: switch (State) @@ -215,24 +214,31 @@ namespace osu.Game.Screens.Menu backButton.ContractStyle = 0; settingsButton.ContractStyle = 0; - bool fromInitial = lastState == MenuState.Initial; - if (state == MenuState.TopLevel) buttonArea.FinishTransforms(true); - using (buttonArea.BeginDelayedSequence(fromInitial ? 150 : 0, true)) + using (buttonArea.BeginDelayedSequence(lastState == MenuState.Initial ? 150 : 0, true)) { switch (state) { case MenuState.Exit: case MenuState.Initial: + trackingPosition = false; + buttonAreaBackground.ScaleTo(Vector2.One, 500, Easing.Out); buttonArea.FadeOut(300); - osuLogo.Delay(150) - .Schedule(() => toolbar?.Hide()) - .ScaleTo(1, 800, Easing.OutExpo) - .MoveTo(Vector2.Zero, 800, Easing.OutExpo); + logo?.Delay(150) + .Schedule(() => + { + toolbar?.Hide(); + + logo.ClearTransforms(targetMember: nameof(Position)); + logo.RelativePositionAxes = Axes.Both; + + logo.MoveTo(new Vector2(0.5f), 800, Easing.OutExpo); + logo.ScaleTo(1, 800, Easing.OutExpo); + }); foreach (Button b in buttonsTopLevel) b.State = ButtonState.Contracted; @@ -240,27 +246,38 @@ namespace osu.Game.Screens.Menu foreach (Button b in buttonsPlay) b.State = ButtonState.Contracted; - if (state == MenuState.Exit) - { - osuLogo.RotateTo(20, EXIT_DELAY * 1.5f); - osuLogo.FadeOut(EXIT_DELAY); - } - else if (lastState == MenuState.TopLevel) + if (state != MenuState.Exit && lastState == MenuState.TopLevel) sampleBack?.Play(); break; case MenuState.TopLevel: buttonAreaBackground.ScaleTo(Vector2.One, 200, Easing.Out); - var sequence = osuLogo - .ScaleTo(0.5f, 200, Easing.In) - .MoveTo(buttonFlow.DrawPosition, 200, Easing.In); + logo.ClearTransforms(targetMember: nameof(Position)); + logo.RelativePositionAxes = Axes.None; - if (fromInitial && osuLogo.Scale.X > 0.5f) - sequence.OnComplete(o => - { - o.Impact(); - toolbar?.Show(); - }); + trackingPosition = true; + + switch (lastState) + { + case MenuState.Initial: + logo.ScaleTo(0.5f, 200, Easing.In); + + trackingPosition = false; + + logo + .MoveTo(iconTrackingPosition, lastState == MenuState.EnteringMode ? 0 : 200, Easing.In) + .OnComplete(o => + { + trackingPosition = true; + + o.Impact(); + toolbar?.Show(); + }); + break; + default: + logo.ScaleTo(0.5f, 200, Easing.OutQuint); + break; + } buttonArea.FadeIn(300); @@ -280,6 +297,8 @@ namespace osu.Game.Screens.Menu case MenuState.EnteringMode: buttonAreaBackground.ScaleTo(new Vector2(2, 0), 300, Easing.InSine); + trackingPosition = true; + buttonsTopLevel.ForEach(b => b.ContractStyle = 1); buttonsPlay.ForEach(b => b.ContractStyle = 1); backButton.ContractStyle = 1; @@ -301,15 +320,24 @@ namespace osu.Game.Screens.Menu } } + private Vector2 iconTrackingPosition => logo.Parent.ToLocalSpace(iconFacade.ScreenSpaceDrawQuad.Centre); + + private bool trackingPosition; + protected override void Update() { //if (OsuGame.IdleTime > 6000 && State != MenuState.Exit) // State = MenuState.Initial; - osuLogo.Interactive = Alpha > 0.2f; - - iconFacade.Width = osuLogo.SizeForFlow * 0.5f; base.Update(); + + if (logo != null) + { + if (trackingPosition) + logo.Position = iconTrackingPosition; + + iconFacade.Width = logo.SizeForFlow * 0.5f; + } } } diff --git a/osu.Game/Screens/Menu/Disclaimer.cs b/osu.Game/Screens/Menu/Disclaimer.cs index 1ac5823ec4..532ee71b72 100644 --- a/osu.Game/Screens/Menu/Disclaimer.cs +++ b/osu.Game/Screens/Menu/Disclaimer.cs @@ -12,15 +12,15 @@ using OpenTK.Graphics; namespace osu.Game.Screens.Menu { - internal class Disclaimer : OsuScreen + public class Disclaimer : OsuScreen { private Intro intro; private readonly SpriteIcon icon; private Color4 iconColour; - internal override bool ShowOverlays => false; + public override bool ShowOverlays => false; - internal override bool HasLocalCursorDisplayed => true; + public override bool HasLocalCursorDisplayed => true; public Disclaimer() { diff --git a/osu.Game/Screens/Menu/Intro.cs b/osu.Game/Screens/Menu/Intro.cs index ee84cf2d30..0445733b23 100644 --- a/osu.Game/Screens/Menu/Intro.cs +++ b/osu.Game/Screens/Menu/Intro.cs @@ -14,13 +14,14 @@ using osu.Game.Beatmaps.IO; using osu.Game.Configuration; using osu.Game.Graphics.Containers; using osu.Game.Screens.Backgrounds; +using OpenTK; using OpenTK.Graphics; namespace osu.Game.Screens.Menu { public class Intro : OsuScreen { - private readonly OsuLogo logo; + private readonly IntroSequence introSequence; private const string menu_music_beatmap_hash = "3c8b1fcc9434dbb29e2fb613d3b9eada9d7bb6c125ceb32396c3b53437280c83"; @@ -33,38 +34,16 @@ namespace osu.Game.Screens.Menu private SampleChannel welcome; private SampleChannel seeya; - internal override bool HasLocalCursorDisplayed => true; + public override bool HasLocalCursorDisplayed => true; - internal override bool ShowOverlays => false; + public override bool ShowOverlays => false; protected override BackgroundScreen CreateBackground() => new BackgroundScreenEmpty(); - public Intro() - { - Children = new Drawable[] - { - new ParallaxContainer - { - ParallaxAmount = 0.01f, - Children = new Drawable[] - { - logo = new OsuLogo - { - Alpha = 0, - Triangles = false, - Blending = BlendingMode.Additive, - Interactive = false, - Colour = Color4.DarkGray, - Ripple = false - } - } - } - }; - } - private Bindable menuVoice; private Bindable menuMusic; private Track track; + private readonly ParallaxContainer parallax; [BackgroundDependencyLoader] private void load(AudioManager audio, OsuConfigManager config, BeatmapManager beatmaps, Framework.Game game) @@ -99,7 +78,9 @@ namespace osu.Game.Screens.Menu welcome = audio.Sample.Get(@"welcome"); seeya = audio.Sample.Get(@"seeya"); - beatmaps.Delete(setInfo); + + if (setInfo.Protected) + beatmaps.Delete(setInfo); } protected override void OnEntering(Screen last) @@ -121,14 +102,48 @@ namespace osu.Game.Screens.Menu { DidLoadMenu = true; Push(mainMenu); - }, 2300); - }, 600); + }, delay_step_one); + }, delay_step_two); + } - logo.ScaleTo(0.4f); - logo.FadeOut(); + private const double delay_step_one = 2300; + private const double delay_step_two = 600; - logo.ScaleTo(1, 4400, Easing.OutQuint); - logo.FadeIn(20000, Easing.OutQuint); + public const int EXIT_DELAY = 3000; + + protected override void LogoArriving(OsuLogo logo, bool resuming) + { + base.LogoArriving(logo, resuming); + + logo.RelativePositionAxes = Axes.Both; + logo.Colour = Color4.White; + logo.Ripple = false; + + const int quick_appear = 350; + + int initialMovementTime = logo.Alpha > 0.2f ? quick_appear : 0; + + logo.MoveTo(new Vector2(0.5f), initialMovementTime, Easing.OutQuint); + + if (!resuming) + { + logo.Triangles = true; + + logo.ScaleTo(1); + logo.FadeIn(); + logo.PlayIntro(); + } + else + { + logo.Triangles = false; + + logo + .ScaleTo(1, initialMovementTime, Easing.OutQuint) + .FadeIn(quick_appear, Easing.OutQuint) + .Then() + .RotateTo(20, EXIT_DELAY * 1.5f) + .FadeOut(EXIT_DELAY); + } } protected override void OnSuspending(Screen next) @@ -148,7 +163,7 @@ namespace osu.Game.Screens.Menu if (!(last is MainMenu)) Content.FadeIn(300); - double fadeOutTime = 2000; + double fadeOutTime = EXIT_DELAY; //we also handle the exit transition. if (menuVoice) seeya.Play(); diff --git a/osu.Game/Screens/Menu/IntroSequence.cs b/osu.Game/Screens/Menu/IntroSequence.cs new file mode 100644 index 0000000000..5fca389708 --- /dev/null +++ b/osu.Game/Screens/Menu/IntroSequence.cs @@ -0,0 +1,297 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using System.Linq; +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.Game.Graphics; +using osu.Game.Graphics.Sprites; + +namespace osu.Game.Screens.Menu +{ + public class IntroSequence : Container + { + private const float logo_size = 460; //todo: this should probably be 480 + + private OsuSpriteText welcomeText; + + private Container lines; + + private Box lineTopLeft; + private Box lineBottomLeft; + private Box lineTopRight; + private Box lineBottomRight; + + private Ring smallRing; + private Ring mediumRing; + private Ring bigRing; + + private Box backgroundFill; + private Box foregroundFill; + + private CircularContainer pinkCircle; + private CircularContainer blueCircle; + private CircularContainer yellowCircle; + private CircularContainer purpleCircle; + + public IntroSequence() + { + RelativeSizeAxes = Axes.Both; + } + + [BackgroundDependencyLoader] + private void load() + { + const int line_offset = 80; + const int circle_offset = 250; + + Children = new Drawable[] + { + lines = new Container + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + AutoSizeAxes = Axes.Both, + Children = new [] + { + lineTopLeft = new Box + { + Origin = Anchor.CentreLeft, + Anchor = Anchor.Centre, + Position = new Vector2(-line_offset, -line_offset), + Rotation = 45, + Colour = Color4.White.Opacity(180), + }, + lineTopRight = new Box + { + Origin = Anchor.CentreRight, + Anchor = Anchor.Centre, + Position = new Vector2(line_offset, -line_offset), + Rotation = -45, + Colour = Color4.White.Opacity(80), + }, + lineBottomLeft = new Box + { + Origin = Anchor.CentreLeft, + Anchor = Anchor.Centre, + Position = new Vector2(-line_offset, line_offset), + Rotation = -45, + Colour = Color4.White.Opacity(230), + }, + lineBottomRight = new Box + { + Origin = Anchor.CentreRight, + Anchor = Anchor.Centre, + Position = new Vector2(line_offset, line_offset), + Rotation = 45, + Colour = Color4.White.Opacity(130), + }, + } + }, + bigRing = new Ring(OsuColour.FromHex(@"B6C5E9"), 0.85f), + mediumRing = new Ring(Color4.White.Opacity(130), 0.7f), + smallRing = new Ring(Color4.White, 0.6f), + welcomeText = new OsuSpriteText + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Text = "welcome", + Padding = new MarginPadding { Bottom = 10 }, + Font = @"Exo2.0-Light", + Alpha = 0, + TextSize = 42, + Spacing = new Vector2(5), + }, + new CircularContainer + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Size = new Vector2(logo_size), + Masking = true, + Children = new Drawable[] + { + backgroundFill = new Box + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Height = 0, + Colour = OsuColour.FromHex(@"C6D8FF").Opacity(160), + }, + foregroundFill = new Box + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Size = Vector2.Zero, + RelativeSizeAxes = Axes.Both, + Width = 0, + Colour = Color4.White, + }, + } + }, + purpleCircle = new Circle + { + Anchor = Anchor.Centre, + Origin = Anchor.TopCentre, + Position = new Vector2(0, circle_offset), + Colour = OsuColour.FromHex(@"AA92FF"), + }, + blueCircle = new Circle + { + Anchor = Anchor.Centre, + Origin = Anchor.CentreRight, + Position = new Vector2(-circle_offset, 0), + Colour = OsuColour.FromHex(@"8FE5FE"), + }, + yellowCircle = new Circle + { + Anchor = Anchor.Centre, + Origin = Anchor.BottomCentre, + Position = new Vector2(0, -circle_offset), + Colour = OsuColour.FromHex(@"FFD64C"), + }, + pinkCircle = new Circle + { + Anchor = Anchor.Centre, + Origin = Anchor.CentreLeft, + Position = new Vector2(circle_offset, 0), + Colour = OsuColour.FromHex(@"e967a1"), + }, + }; + + foreach (var line in lines) + { + line.Size = new Vector2(105, 1.5f); + line.Alpha = 0; + } + + Scale = new Vector2(0.5f); + } + + public void Start(double length) + { + if (Children.Any()) + { + // restart if we were already run previously. + FinishTransforms(true); + load(); + } + + smallRing.ResizeTo(logo_size * 0.086f, 400, Easing.InOutQuint); + + mediumRing.ResizeTo(130, 340, Easing.OutQuad); + mediumRing.Foreground.ResizeTo(1, 880, Easing.Out); + + Func remainingTime = () => length - TransformDelay; + + using (BeginDelayedSequence(250, true)) + { + welcomeText.FadeIn(700); + welcomeText.TransformSpacingTo(new Vector2(20, 0), remainingTime(), Easing.Out); + + const int line_duration = 700; + const int line_resize = 150; + + foreach (var line in lines) + { + line.FadeIn(40).ResizeWidthTo(0, line_duration - line_resize, Easing.OutQuint); + } + + const int line_end_offset = 120; + + smallRing.Foreground.ResizeTo(1, line_duration, Easing.OutQuint); + + lineTopLeft.MoveTo(new Vector2(-line_end_offset, -line_end_offset), line_duration, Easing.OutQuint); + lineTopRight.MoveTo(new Vector2(line_end_offset, -line_end_offset), line_duration, Easing.OutQuint); + lineBottomLeft.MoveTo(new Vector2(-line_end_offset, line_end_offset), line_duration, Easing.OutQuint); + lineBottomRight.MoveTo(new Vector2(line_end_offset, line_end_offset), line_duration, Easing.OutQuint); + + using (BeginDelayedSequence(length * 0.56, true)) + { + bigRing.ResizeTo(logo_size, 500, Easing.InOutQuint); + bigRing.Foreground.Delay(250).ResizeTo(1, 850, Easing.OutQuint); + + using (BeginDelayedSequence(250, true)) + { + backgroundFill.ResizeHeightTo(1, remainingTime(), Easing.InOutQuart); + backgroundFill.RotateTo(-90, remainingTime(), Easing.InOutQuart); + + using (BeginDelayedSequence(50, true)) + { + foregroundFill.ResizeWidthTo(1, remainingTime(), Easing.InOutQuart); + foregroundFill.RotateTo(-90, remainingTime(), Easing.InOutQuart); + } + + this.ScaleTo(1, remainingTime(), Easing.InOutCubic); + + const float circle_size = logo_size * 0.9f; + + const int rotation_delay = 110; + const int appear_delay = 80; + + purpleCircle.MoveToY(circle_size / 2, remainingTime(), Easing.InOutQuart); + purpleCircle.Delay(rotation_delay).RotateTo(-180, remainingTime() - rotation_delay, Easing.InOutQuart); + purpleCircle.ResizeTo(circle_size, remainingTime(), Easing.InOutQuart); + + using (BeginDelayedSequence(appear_delay, true)) + { + yellowCircle.MoveToY(-circle_size / 2, remainingTime(), Easing.InOutQuart); + yellowCircle.Delay(rotation_delay).RotateTo(-180, remainingTime() - rotation_delay, Easing.InOutQuart); + yellowCircle.ResizeTo(circle_size, remainingTime(), Easing.InOutQuart); + + using (BeginDelayedSequence(appear_delay, true)) + { + blueCircle.MoveToX(-circle_size / 2, remainingTime(), Easing.InOutQuart); + blueCircle.Delay(rotation_delay).RotateTo(-180, remainingTime() - rotation_delay, Easing.InOutQuart); + blueCircle.ResizeTo(circle_size, remainingTime(), Easing.InOutQuart); + + using (BeginDelayedSequence(appear_delay, true)) + { + pinkCircle.MoveToX(circle_size / 2, remainingTime(), Easing.InOutQuart); + pinkCircle.Delay(rotation_delay).RotateTo(-180, remainingTime() - rotation_delay, Easing.InOutQuart); + pinkCircle.ResizeTo(circle_size, remainingTime(), Easing.InOutQuart); + } + } + } + } + } + } + } + + private class Ring : Container + { + public readonly Circle Foreground; + + public Ring(Color4 ringColour, float foregroundSize) + { + Anchor = Anchor.Centre; + Origin = Anchor.Centre; + Children = new[] + { + new Circle + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Scale = new Vector2(0.98f), + Colour = ringColour, + }, + Foreground = new Circle + { + Size = new Vector2(foregroundSize), + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Colour = Color4.Black, + } + }; + } + } + } +} diff --git a/osu.Game/Screens/Menu/LogoVisualisation.cs b/osu.Game/Screens/Menu/LogoVisualisation.cs index 4b8942349d..3e7662a441 100644 --- a/osu.Game/Screens/Menu/LogoVisualisation.cs +++ b/osu.Game/Screens/Menu/LogoVisualisation.cs @@ -19,7 +19,7 @@ using osu.Framework.Allocation; namespace osu.Game.Screens.Menu { - internal class LogoVisualisation : Drawable, IHasAccentColour + public class LogoVisualisation : Drawable, IHasAccentColour { private readonly Bindable beatmap = new Bindable(); diff --git a/osu.Game/Screens/Menu/MainMenu.cs b/osu.Game/Screens/Menu/MainMenu.cs index 1c82d15f50..b0170edfe1 100644 --- a/osu.Game/Screens/Menu/MainMenu.cs +++ b/osu.Game/Screens/Menu/MainMenu.cs @@ -2,6 +2,7 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using OpenTK; +using OpenTK.Graphics; using OpenTK.Input; using osu.Framework.Allocation; using osu.Framework.Graphics; @@ -23,7 +24,7 @@ namespace osu.Game.Screens.Menu { private readonly ButtonSystem buttons; - internal override bool ShowOverlays => buttons.State != MenuState.Initial; + public override bool ShowOverlays => buttons.State != MenuState.Initial; private readonly BackgroundScreenDefault background; private Screen songSelect; @@ -58,13 +59,16 @@ namespace osu.Game.Screens.Menu }; } - [BackgroundDependencyLoader] - private void load(OsuGame game) + [BackgroundDependencyLoader(true)] + private void load(OsuGame game = null) { LoadComponentAsync(background); - buttons.OnSettings = game.ToggleSettings; - buttons.OnDirect = game.ToggleDirect; + if (game != null) + { + buttons.OnSettings = game.ToggleSettings; + buttons.OnDirect = game.ToggleDirect; + } preloadSongSelect(); } @@ -102,6 +106,38 @@ namespace osu.Game.Screens.Menu Beatmap.ValueChanged += beatmap_ValueChanged; } + protected override void LogoArriving(OsuLogo logo, bool resuming) + { + base.LogoArriving(logo, resuming); + + buttons.SetOsuLogo(logo); + + logo.Triangles = true; + logo.Ripple = false; + + logo.FadeColour(Color4.White, 100, Easing.OutQuint); + logo.FadeIn(100, Easing.OutQuint); + + if (resuming) + { + buttons.State = MenuState.TopLevel; + + const float length = 300; + + Content.FadeIn(length, Easing.OutQuint); + Content.MoveTo(new Vector2(0, 0), length, Easing.OutQuint); + + sideFlashes.Delay(length).FadeIn(64, Easing.InQuint); + } + } + + protected override void LogoSuspending(OsuLogo logo) + { + logo.FadeOut(300, Easing.InSine) + .ScaleTo(0.2f, 300, Easing.InSine) + .OnComplete(l => buttons.SetOsuLogo(null)); + } + private void beatmap_ValueChanged(WorkingBeatmap newValue) { if (!IsCurrentScreen) @@ -121,7 +157,7 @@ namespace osu.Game.Screens.Menu Content.FadeOut(length, Easing.InSine); Content.MoveTo(new Vector2(-800, 0), length, Easing.InSine); - sideFlashes.FadeOut(length / 4, Easing.OutQuint); + sideFlashes.FadeOut(64, Easing.OutQuint); } protected override void OnResuming(Screen last) @@ -132,15 +168,6 @@ namespace osu.Game.Screens.Menu //we may have consumed our preloaded instance, so let's make another. preloadSongSelect(); - - const float length = 300; - - buttons.State = MenuState.TopLevel; - - Content.FadeIn(length, Easing.OutQuint); - Content.MoveTo(new Vector2(0, 0), length, Easing.OutQuint); - - sideFlashes.FadeIn(length / 4, Easing.InQuint); } protected override bool OnExiting(Screen next) diff --git a/osu.Game/Screens/Menu/OsuLogo.cs b/osu.Game/Screens/Menu/OsuLogo.cs index 6f4a46b10b..dccb910d86 100644 --- a/osu.Game/Screens/Menu/OsuLogo.cs +++ b/osu.Game/Screens/Menu/OsuLogo.cs @@ -29,6 +29,8 @@ namespace osu.Game.Screens.Menu { public readonly Color4 OsuPink = OsuColour.FromHex(@"e967a1"); + private const double transition_length = 300; + private readonly Sprite logo; private readonly CircularContainer logoContainer; private readonly Container logoBounceContainer; @@ -37,6 +39,8 @@ namespace osu.Game.Screens.Menu private readonly Container logoHoverContainer; private readonly LogoVisualisation visualizer; + private readonly IntroSequence intro; + private SampleChannel sampleClick; private SampleChannel sampleBeat; @@ -54,7 +58,7 @@ namespace osu.Game.Screens.Menu public bool Triangles { - set { colourAndTriangles.Alpha = value ? 1 : 0; } + set { colourAndTriangles.FadeTo(value ? 1 : 0, transition_length, Easing.OutQuint); } } public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => logoContainer.ReceiveMouseInputAt(screenSpacePos); @@ -62,10 +66,9 @@ namespace osu.Game.Screens.Menu public bool Ripple { get { return rippleContainer.Alpha > 0; } - set { rippleContainer.Alpha = value ? 1 : 0; } + set { rippleContainer.FadeTo(value ? 1 : 0, transition_length, Easing.OutQuint); } } - public bool Interactive = true; private readonly Box flashLayer; private readonly Container impactContainer; @@ -76,17 +79,23 @@ namespace osu.Game.Screens.Menu public OsuLogo() { + // Required to make Schedule calls run in OsuScreen even when we are not visible. + AlwaysPresent = true; + EarlyActivationMilliseconds = early_activation; Size = new Vector2(default_size); - Anchor = Anchor.Centre; Origin = Anchor.Centre; AutoSizeAxes = Axes.Both; Children = new Drawable[] { + intro = new IntroSequence + { + RelativeSizeAxes = Axes.Both, + }, logoHoverContainer = new Container { AutoSizeAxes = Axes.Both, @@ -266,6 +275,17 @@ namespace osu.Game.Screens.Menu } } + public void PlayIntro() + { + const double length = 3150; + const double fade = 200; + + logoHoverContainer.FadeOut().Delay(length).FadeIn(fade); + intro.Show(); + intro.Start(length); + intro.Delay(length + fade).FadeOut(); + } + protected override void Update() { base.Update(); @@ -290,9 +310,11 @@ namespace osu.Game.Screens.Menu } } + private bool interactive => Action != null && Alpha > 0.2f; + protected override bool OnMouseDown(InputState state, MouseDownEventArgs args) { - if (!Interactive) return false; + if (!interactive) return false; logoBounceContainer.ScaleTo(0.9f, 1000, Easing.Out); return true; @@ -306,7 +328,7 @@ namespace osu.Game.Screens.Menu protected override bool OnClick(InputState state) { - if (!Interactive) return false; + if (!interactive) return false; sampleClick.Play(); @@ -320,7 +342,7 @@ namespace osu.Game.Screens.Menu protected override bool OnHover(InputState state) { - if (!Interactive) return false; + if (!interactive) return false; logoHoverContainer.ScaleTo(1.1f, 500, Easing.OutElastic); return true; diff --git a/osu.Game/Screens/OsuScreen.cs b/osu.Game/Screens/OsuScreen.cs index ae10d8828b..3dd175ca88 100644 --- a/osu.Game/Screens/OsuScreen.cs +++ b/osu.Game/Screens/OsuScreen.cs @@ -10,13 +10,15 @@ using osu.Game.Graphics.Containers; using OpenTK; using osu.Framework.Audio.Sample; using osu.Framework.Audio; +using osu.Framework.Graphics; using osu.Game.Rulesets; +using osu.Game.Screens.Menu; namespace osu.Game.Screens { public abstract class OsuScreen : Screen { - internal BackgroundScreen Background { get; private set; } + public BackgroundScreen Background { get; private set; } /// /// Override to create a BackgroundMode for the current screen. @@ -24,17 +26,19 @@ namespace osu.Game.Screens /// protected virtual BackgroundScreen CreateBackground() => null; - internal virtual bool ShowOverlays => true; + public virtual bool ShowOverlays => true; protected new OsuGameBase Game => base.Game as OsuGameBase; - internal virtual bool HasLocalCursorDisplayed => false; + public virtual bool HasLocalCursorDisplayed => false; + + private OsuLogo logo; /// /// Whether the beatmap or ruleset should be allowed to be changed by the user or game. /// Used to mark exclusive areas where this is strongly prohibited, like gameplay. /// - internal virtual bool AllowBeatmapRulesetChange => true; + public virtual bool AllowBeatmapRulesetChange => true; protected readonly Bindable Beatmap = new Bindable(); @@ -72,9 +76,16 @@ namespace osu.Game.Screens protected override void OnResuming(Screen last) { base.OnResuming(last); + logo.DelayUntilTransformsFinished().Schedule(() => LogoArriving(logo, true)); sampleExit?.Play(); } + protected override void OnSuspending(Screen next) + { + base.OnSuspending(next); + onSuspendingLogo(); + } + protected override void OnEntering(Screen last) { OsuScreen lastOsu = last as OsuScreen; @@ -106,11 +117,19 @@ namespace osu.Game.Screens }); } + if ((logo = lastOsu?.logo) == null) + AddInternal(logo = new OsuLogo()); + base.OnEntering(last); + + logo.DelayUntilTransformsFinished().Schedule(() => LogoArriving(logo, false)); } protected override bool OnExiting(Screen next) { + if (ValidForResume && logo != null) + onExitingLogo(); + OsuScreen nextOsu = next as OsuScreen; if (Background != null && !Background.Equals(nextOsu?.Background)) @@ -128,5 +147,40 @@ namespace osu.Game.Screens Beatmap.UnbindAll(); return false; } + + /// + /// Fired when this screen was entered or resumed and the logo state is required to be adjusted. + /// + protected virtual void LogoArriving(OsuLogo logo, bool resuming) + { + logo.Action = null; + logo.FadeOut(300, Easing.OutQuint); + } + + private void onExitingLogo() + { + logo.ClearTransforms(); + LogoExiting(logo); + } + + /// + /// Fired when this screen was exited to add any outwards transition to the logo. + /// + protected virtual void LogoExiting(OsuLogo logo) + { + } + + private void onSuspendingLogo() + { + logo.ClearTransforms(); + LogoSuspending(logo); + } + + /// + /// Fired when this screen was suspended to add any outwards transition to the logo. + /// + protected virtual void LogoSuspending(OsuLogo logo) + { + } } } diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index c0a50b1a6f..2daf8f0765 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -17,6 +17,8 @@ using osu.Game.Rulesets.UI; using osu.Game.Screens.Backgrounds; using System; using System.Linq; +using System.Threading; +using System.Threading.Tasks; using osu.Framework.Threading; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Scoring; @@ -34,13 +36,13 @@ namespace osu.Game.Screens.Play { protected override BackgroundScreen CreateBackground() => new BackgroundScreenBeatmap(Beatmap); - internal override bool ShowOverlays => false; + public override bool ShowOverlays => false; - internal override bool HasLocalCursorDisplayed => !pauseContainer.IsPaused && !HasFailed && RulesetContainer.ProvidingUserCursor; + public override bool HasLocalCursorDisplayed => !pauseContainer.IsPaused && !HasFailed && RulesetContainer.ProvidingUserCursor; public Action RestartRequested; - internal override bool AllowBeatmapRulesetChange => false; + public override bool AllowBeatmapRulesetChange => false; public bool HasFailed { get; private set; } @@ -143,16 +145,23 @@ namespace osu.Game.Screens.Play userAudioOffset.ValueChanged += v => offsetClock.Offset = v; userAudioOffset.TriggerChange(); - Schedule(() => + Task.Run(() => { adjustableSourceClock.Reset(); - foreach (var mod in working.Mods.Value.OfType()) - mod.ApplyToClock(adjustableSourceClock); + // this is temporary until we have blocking (async.Wait()) audio component methods. + // then we can call ResetAsync().Wait() or the blocking version above. + while (adjustableSourceClock.IsRunning) + Thread.Sleep(1); - clockRate = adjustableSourceClock.Rate; + Schedule(() => + { + decoupledClock.ChangeSource(adjustableSourceClock); + foreach (var mod in working.Mods.Value.OfType()) + mod.ApplyToClock(adjustableSourceClock); - decoupledClock.ChangeSource(adjustableSourceClock); + clockRate = adjustableSourceClock.Rate; + }); }); Children = new Drawable[] diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index a5248acbe4..53a2dcc41f 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -10,9 +10,9 @@ using osu.Game.Beatmaps; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Screens.Backgrounds; -using osu.Game.Screens.Menu; using OpenTK; using osu.Framework.Localisation; +using osu.Game.Screens.Menu; namespace osu.Game.Screens.Play { @@ -20,13 +20,12 @@ namespace osu.Game.Screens.Play { private Player player; - private readonly OsuLogo logo; private BeatmapMetadataDisplay info; private bool showOverlays = true; - internal override bool ShowOverlays => showOverlays; + public override bool ShowOverlays => showOverlays; - internal override bool AllowBeatmapRulesetChange => false; + public override bool AllowBeatmapRulesetChange => false; protected override BackgroundScreen CreateBackground() => new BackgroundScreenBeatmap(Beatmap); @@ -39,15 +38,6 @@ namespace osu.Game.Screens.Play showOverlays = false; ValidForResume = true; }; - - Children = new Drawable[] - { - logo = new OsuLogo - { - Scale = new Vector2(0.15f), - Interactive = false, - }, - }; } [BackgroundDependencyLoader] @@ -101,11 +91,24 @@ namespace osu.Game.Screens.Play contentIn(); - logo.Delay(500).MoveToOffset(new Vector2(0, -180), 500, Easing.InOutExpo); info.Delay(750).FadeIn(500); this.Delay(2150).Schedule(pushWhenLoaded); } + protected override void LogoArriving(OsuLogo logo, bool resuming) + { + base.LogoArriving(logo, resuming); + + logo.ClearTransforms(targetMember: nameof(Position)); + logo.RelativePositionAxes = Axes.Both; + + logo.ScaleTo(new Vector2(0.15f), 300, Easing.In); + logo.MoveTo(new Vector2(0.5f), 300, Easing.In); + logo.FadeIn(350); + + logo.Delay(resuming ? 0 : 500).MoveToOffset(new Vector2(0, -0.24f), 500, Easing.InOutExpo); + } + private void pushWhenLoaded() { if (player.LoadState != LoadState.Ready) diff --git a/osu.Game/Screens/Ranking/Results.cs b/osu.Game/Screens/Ranking/Results.cs index 60ad484673..8e27cb235c 100644 --- a/osu.Game/Screens/Ranking/Results.cs +++ b/osu.Game/Screens/Ranking/Results.cs @@ -31,7 +31,7 @@ namespace osu.Game.Screens.Ranking private ResultModeTabControl modeChangeButtons; - internal override bool AllowBeatmapRulesetChange => false; + public override bool AllowBeatmapRulesetChange => false; private Container currentPage; diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index 0cfe07628a..f4dcf9a69e 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -186,13 +186,18 @@ namespace osu.Game.Screens.Select public Action HideDifficultyRequested; + private void selectNullBeatmap() + { + selectedGroup = null; + selectedPanel = null; + SelectionChanged?.Invoke(null); + } + public void SelectNext(int direction = 1, bool skipDifficulties = true) { if (groups.All(g => g.State == BeatmapGroupState.Hidden)) { - selectedGroup = null; - selectedPanel = null; - SelectionChanged?.Invoke(null); + selectNullBeatmap(); return; } @@ -383,6 +388,14 @@ namespace osu.Game.Screens.Select if (group == null) return; + if (selectedGroup == group) + { + if (getVisibleGroups().Count() == 1) + selectNullBeatmap(); + else + SelectNext(); + } + groups.Remove(group); panels.Remove(group.Header); foreach (var p in group.BeatmapPanels) @@ -391,9 +404,6 @@ namespace osu.Game.Screens.Select scrollableContent.Remove(group.Header); scrollableContent.RemoveRange(group.BeatmapPanels); - if (selectedGroup == group) - SelectNext(); - computeYPositions(); } diff --git a/osu.Game/Screens/Select/Footer.cs b/osu.Game/Screens/Select/Footer.cs index 00f311e522..40c3cf0fd4 100644 --- a/osu.Game/Screens/Select/Footer.cs +++ b/osu.Game/Screens/Select/Footer.cs @@ -13,7 +13,6 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Input; using osu.Game.Graphics.UserInterface; -using osu.Game.Screens.Menu; namespace osu.Game.Screens.Select { @@ -31,12 +30,9 @@ namespace osu.Game.Screens.Select private const float padding = 80; public Action OnBack; - public Action OnStart; private readonly FillFlowContainer buttons; - public OsuLogo StartButton; - /// Text on the button. /// Colour of the button. /// Hotkey of the button. @@ -106,13 +102,6 @@ namespace osu.Game.Screens.Select Height = 3, Position = new Vector2(0, -3), }, - StartButton = new OsuLogo - { - Anchor = Anchor.BottomRight, - Scale = new Vector2(0.4f), - Position = new Vector2(-70, -25), - Action = () => OnStart?.Invoke() - }, new BackButton { Anchor = Anchor.BottomLeft, @@ -143,8 +132,6 @@ namespace osu.Game.Screens.Select updateModeLight(); } - public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => base.ReceiveMouseInputAt(screenSpacePos) || StartButton.ReceiveMouseInputAt(screenSpacePos); - protected override bool OnMouseDown(InputState state, MouseDownEventArgs args) => true; protected override bool OnClick(InputState state) => true; diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index e11eed7040..121a53f699 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -20,6 +20,7 @@ using osu.Game.Graphics.Containers; using osu.Game.Overlays; using osu.Game.Screens.Backgrounds; using osu.Game.Screens.Edit; +using osu.Game.Screens.Menu; using osu.Game.Screens.Select.Options; namespace osu.Game.Screens.Select @@ -153,7 +154,6 @@ namespace osu.Game.Screens.Select Add(Footer = new Footer { OnBack = Exit, - OnStart = () => carouselRaisedStart(), }); FooterPanels.Add(BeatmapOptions = new BeatmapOptionsOverlay()); @@ -309,6 +309,41 @@ namespace osu.Game.Screens.Select FilterControl.Activate(); } + private const double logo_transition = 250; + + protected override void LogoArriving(OsuLogo logo, bool resuming) + { + base.LogoArriving(logo, resuming); + + logo.ClearTransforms(); + logo.RelativePositionAxes = Axes.Both; + + Vector2 position = new Vector2(0.95f, 0.96f); + + if (logo.Alpha > 0.8f) + { + logo.MoveTo(position, 500, Easing.OutQuint); + } + else + { + logo.Hide(); + logo.ScaleTo(0.2f); + logo.MoveTo(position); + } + + logo.FadeIn(logo_transition, Easing.OutQuint); + logo.ScaleTo(0.4f, logo_transition, Easing.OutQuint); + + logo.Action = () => carouselRaisedStart(); + } + + protected override void LogoExiting(OsuLogo logo) + { + base.LogoExiting(logo); + logo.ScaleTo(0.2f, logo_transition / 2, Easing.Out); + logo.FadeOut(logo_transition / 2, Easing.Out); + } + private void beatmap_ValueChanged(WorkingBeatmap beatmap) { if (!IsCurrentScreen) return; @@ -350,6 +385,7 @@ namespace osu.Game.Screens.Select Content.FadeOut(100); FilterControl.Deactivate(); + return base.OnExiting(next); } diff --git a/osu.Game/Screens/Tournament/Drawings.cs b/osu.Game/Screens/Tournament/Drawings.cs index 3d27552212..e540782fc1 100644 --- a/osu.Game/Screens/Tournament/Drawings.cs +++ b/osu.Game/Screens/Tournament/Drawings.cs @@ -29,7 +29,7 @@ namespace osu.Game.Screens.Tournament { private const string results_filename = "drawings_results.txt"; - internal override bool ShowOverlays => false; + public override bool ShowOverlays => false; protected override BackgroundScreen CreateBackground() => new BackgroundScreenDefault(); diff --git a/osu.Game/Users/Avatar.cs b/osu.Game/Users/Avatar.cs index 111c901ca0..7ced0305fd 100644 --- a/osu.Game/Users/Avatar.cs +++ b/osu.Game/Users/Avatar.cs @@ -1,6 +1,7 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -25,6 +26,9 @@ namespace osu.Game.Users [BackgroundDependencyLoader] private void load(TextureStore textures) { + if (textures == null) + throw new ArgumentNullException(nameof(textures)); + Texture texture = null; if (user != null && user.Id > 1) texture = textures.Get($@"https://a.ppy.sh/{user.Id}"); if (texture == null) texture = textures.Get(@"Online/avatar-guest"); diff --git a/osu.Game/Users/Country.cs b/osu.Game/Users/Country.cs index bf06d9f8bc..0c0d12c1cc 100644 --- a/osu.Game/Users/Country.cs +++ b/osu.Game/Users/Country.cs @@ -1,6 +1,7 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System; using Newtonsoft.Json; using osu.Framework.Allocation; using osu.Framework.Graphics; @@ -45,6 +46,9 @@ namespace osu.Game.Users [BackgroundDependencyLoader] private void load(TextureStore ts) { + if (ts == null) + throw new ArgumentNullException(nameof(ts)); + textures = ts; sprite.Texture = textures.Get($@"Flags/{flagName}"); } diff --git a/osu.Game/Users/UpdateableAvatar.cs b/osu.Game/Users/UpdateableAvatar.cs index 7d304e3bbc..7c020fce91 100644 --- a/osu.Game/Users/UpdateableAvatar.cs +++ b/osu.Game/Users/UpdateableAvatar.cs @@ -40,11 +40,11 @@ namespace osu.Game.Users { displayedAvatar?.FadeOut(300); displayedAvatar?.Expire(); - Add(displayedAvatar = new AsyncLoadWrapper(new Avatar(user) + Add(displayedAvatar = new DelayedLoadWrapper(new Avatar(user) { RelativeSizeAxes = Axes.Both, OnLoadComplete = d => d.FadeInFromZero(200), })); } } -} \ No newline at end of file +} diff --git a/osu.Game/Users/UserCoverBackground.cs b/osu.Game/Users/UserCoverBackground.cs index c0f0d09d9d..68c97fc8fd 100644 --- a/osu.Game/Users/UserCoverBackground.cs +++ b/osu.Game/Users/UserCoverBackground.cs @@ -1,6 +1,7 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System; using osu.Framework.Allocation; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; @@ -19,6 +20,9 @@ namespace osu.Game.Users [BackgroundDependencyLoader] private void load(TextureStore textures) { + if (textures == null) + throw new ArgumentNullException(nameof(textures)); + if (!string.IsNullOrEmpty(user.CoverUrl)) Texture = textures.Get(user.CoverUrl); } diff --git a/osu.Game/Users/UserPanel.cs b/osu.Game/Users/UserPanel.cs index e5518b5845..706ad86bfc 100644 --- a/osu.Game/Users/UserPanel.cs +++ b/osu.Game/Users/UserPanel.cs @@ -38,6 +38,9 @@ namespace osu.Game.Users public UserPanel(User user) { + if (user == null) + throw new ArgumentNullException(nameof(user)); + this.user = user; Height = height - status_height; @@ -173,6 +176,9 @@ namespace osu.Game.Users [BackgroundDependencyLoader(permitNulls: true)] private void load(OsuColour colours, UserProfileOverlay profile) { + if (colours == null) + throw new ArgumentNullException(nameof(colours)); + Status.ValueChanged += displayStatus; Status.ValueChanged += status => statusBg.FadeColour(status?.GetAppropriateColour(colours) ?? colours.Gray5, 500, Easing.OutQuint); diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index c0e08fd83e..7faa395e8a 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -83,21 +83,6 @@ - - true - bin\Debug\ - TRACE;DEBUG - true - 0 - true - full - AnyCPU - false - 6 - prompt - --tests - false - $(SolutionDir)\packages\DotNetZip.1.10.1\lib\net20\DotNetZip.dll @@ -294,6 +279,9 @@ + + + @@ -667,6 +655,7 @@ + @@ -821,4 +810,4 @@ - + \ No newline at end of file diff --git a/osu.sln b/osu.sln index b1341051f9..356ec4cc7b 100644 --- a/osu.sln +++ b/osu.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 14 -VisualStudioVersion = 14.0.25420.1 +# Visual Studio 15 +VisualStudioVersion = 15.0.27004.2006 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "osu.Game", "osu.Game\osu.Game.csproj", "{2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}" EndProject @@ -34,8 +34,8 @@ Global {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.Debug|Any CPU.Build.0 = Debug|Any CPU {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.Release|Any CPU.ActiveCfg = Release|Any CPU {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.Release|Any CPU.Build.0 = Release|Any CPU - {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.VisualTests|Any CPU.ActiveCfg = VisualTests|Any CPU - {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.VisualTests|Any CPU.Build.0 = VisualTests|Any CPU + {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.VisualTests|Any CPU.ActiveCfg = Debug|Any CPU + {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.VisualTests|Any CPU.Build.0 = Debug|Any CPU {C76BF5B3-985E-4D39-95FE-97C9C879B83A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {C76BF5B3-985E-4D39-95FE-97C9C879B83A}.Debug|Any CPU.Build.0 = Debug|Any CPU {C76BF5B3-985E-4D39-95FE-97C9C879B83A}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -85,12 +85,15 @@ Global {419659FD-72EA-4678-9EB8-B22A746CED70}.Debug|Any CPU.Build.0 = Debug|Any CPU {419659FD-72EA-4678-9EB8-B22A746CED70}.Release|Any CPU.ActiveCfg = Release|Any CPU {419659FD-72EA-4678-9EB8-B22A746CED70}.Release|Any CPU.Build.0 = Release|Any CPU - {419659FD-72EA-4678-9EB8-B22A746CED70}.VisualTests|Any CPU.ActiveCfg = Debug|Any CPU - {419659FD-72EA-4678-9EB8-B22A746CED70}.VisualTests|Any CPU.Build.0 = Debug|Any CPU + {419659FD-72EA-4678-9EB8-B22A746CED70}.VisualTests|Any CPU.ActiveCfg = VisualTests|Any CPU + {419659FD-72EA-4678-9EB8-B22A746CED70}.VisualTests|Any CPU.Build.0 = VisualTests|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {671B0BEC-2403-45B0-9357-2C97CC517668} + EndGlobalSection GlobalSection(MonoDevelopProperties) = preSolution Policies = $0 $0.TextStylePolicy = $1