From 31ade986a707fd41880ccea73a3ab5bf932cb0b9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 30 Mar 2018 14:57:13 +0900 Subject: [PATCH 01/45] Scren async changes in line with framework changes Makes editor not stutter on load, amongst other screens. --- osu-framework | 2 +- osu.Game/Screens/BackgroundScreen.cs | 6 ++---- osu.Game/Screens/Edit/Editor.cs | 2 +- osu.Game/Screens/Play/PlayerLoader.cs | 13 +++++-------- 4 files changed, 9 insertions(+), 14 deletions(-) diff --git a/osu-framework b/osu-framework index 85b3494117..d4cb1117fb 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit 85b3494117ccef1b396b70957e1cffaba06e2b54 +Subproject commit d4cb1117fb23453c20e7a8116f1c1f99d9a13611 diff --git a/osu.Game/Screens/BackgroundScreen.cs b/osu.Game/Screens/BackgroundScreen.cs index c5e5883b99..b232cc25cf 100644 --- a/osu.Game/Screens/BackgroundScreen.cs +++ b/osu.Game/Screens/BackgroundScreen.cs @@ -26,14 +26,14 @@ namespace osu.Game.Screens return false; } - public override bool Push(Screen screen) + public override void Push(Screen screen) { // When trying to push a non-loaded screen, load it asynchronously and re-invoke Push // once it's done. if (screen.LoadState == LoadState.NotLoaded) { LoadComponentAsync(screen, d => Push((BackgroundScreen)d)); - return true; + return; } // Make sure the in-progress loading is complete before pushing the screen. @@ -41,8 +41,6 @@ namespace osu.Game.Screens Thread.Sleep(1); base.Push(screen); - - return true; } protected override void Update() diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 8b651000fd..0fcdd79916 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -173,7 +173,7 @@ namespace osu.Game.Screens.Edit } currentScreen.Beatmap.BindTo(Beatmap); - screenContainer.Add(currentScreen); + LoadComponentAsync(currentScreen, screenContainer.Add); } protected override void OnResuming(Screen last) diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index 6d55cdb9ca..9ec8f0a52e 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -159,14 +159,11 @@ namespace osu.Game.Screens.Play loadTask = null; - if (!Push(player)) - Exit(); - else - { - //By default, we want to load the player and never be returned to. - //Note that this may change if the player we load requested a re-run. - ValidForResume = false; - } + //By default, we want to load the player and never be returned to. + //Note that this may change if the player we load requested a re-run. + ValidForResume = false; + + Push(player); }); }, 500); } From c304c1eecf9713602ed2fa55caa343d8d2b67bfc Mon Sep 17 00:00:00 2001 From: naoey Date: Fri, 9 Mar 2018 19:46:16 +0530 Subject: [PATCH 02/45] Make LinkFlowContainer handle beatmap id lookup in game. --- .../Graphics/Containers/LinkFlowContainer.cs | 6 +++--- .../API/Requests/GetBeatmapSetRequest.cs | 16 ++++++++++++---- osu.Game/OsuGame.cs | 6 ++++++ osu.Game/Overlays/BeatmapSetOverlay.cs | 18 ++++++++++++++++++ 4 files changed, 39 insertions(+), 7 deletions(-) diff --git a/osu.Game/Graphics/Containers/LinkFlowContainer.cs b/osu.Game/Graphics/Containers/LinkFlowContainer.cs index 1d231ada23..0631d24f87 100644 --- a/osu.Game/Graphics/Containers/LinkFlowContainer.cs +++ b/osu.Game/Graphics/Containers/LinkFlowContainer.cs @@ -71,9 +71,9 @@ namespace osu.Game.Graphics.Containers switch (linkType) { case LinkAction.OpenBeatmap: - // todo: replace this with overlay.ShowBeatmap(id) once an appropriate API call is implemented. - if (int.TryParse(linkArgument, out int beatmapId)) - Process.Start($"https://osu.ppy.sh/b/{beatmapId}"); + // TODO: proper query params handling + if (int.TryParse(linkArgument.Contains('?') ? linkArgument.Split('?')[0] : linkArgument, out int beatmapId)) + game?.ShowBeatmap(beatmapId); break; case LinkAction.OpenBeatmapSet: if (int.TryParse(linkArgument, out int setId)) diff --git a/osu.Game/Online/API/Requests/GetBeatmapSetRequest.cs b/osu.Game/Online/API/Requests/GetBeatmapSetRequest.cs index cba1d9471c..645c54ad6b 100644 --- a/osu.Game/Online/API/Requests/GetBeatmapSetRequest.cs +++ b/osu.Game/Online/API/Requests/GetBeatmapSetRequest.cs @@ -5,13 +5,21 @@ namespace osu.Game.Online.API.Requests { public class GetBeatmapSetRequest : APIRequest { - private readonly int beatmapSetId; + private readonly int id; + private readonly BeatmapSetLookupType type; - public GetBeatmapSetRequest(int beatmapSetId) + public GetBeatmapSetRequest(int id, BeatmapSetLookupType type = BeatmapSetLookupType.SetId) { - this.beatmapSetId = beatmapSetId; + this.id = id; + this.type = type; } - protected override string Target => $@"beatmapsets/{beatmapSetId}"; + protected override string Target => type == BeatmapSetLookupType.SetId ? $@"beatmapsets/{id}" : $@"beatmapsets/lookup?beatmap_id={id}"; + } + + public enum BeatmapSetLookupType + { + SetId, + BeatmapId, } } diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 89447b8ed6..a1f42fbfdd 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -160,6 +160,12 @@ namespace osu.Game /// The user to display. public void ShowUser(long userId) => userProfile.ShowUser(userId); + /// + /// Show a beatmap's set as an overlay, displaying the given beatmap. + /// + /// The beatmap to show. + public void ShowBeatmap(int beatmapId) => beatmapSetOverlay.ShowBeatmap(beatmapId); + protected void LoadScore(Score s) { scoreLoad?.Cancel(); diff --git a/osu.Game/Overlays/BeatmapSetOverlay.cs b/osu.Game/Overlays/BeatmapSetOverlay.cs index f0f8a6ef10..c7c8a4d50e 100644 --- a/osu.Game/Overlays/BeatmapSetOverlay.cs +++ b/osu.Game/Overlays/BeatmapSetOverlay.cs @@ -17,6 +17,7 @@ using osu.Game.Online.API.Requests; using osu.Game.Overlays.BeatmapSet; using osu.Game.Rulesets; using osu.Game.Overlays.BeatmapSet.Scores; +using System.Linq; namespace osu.Game.Overlays { @@ -139,6 +140,23 @@ namespace osu.Game.Overlays return true; } + public void ShowBeatmap(int beatmapId) + { + var req = new GetBeatmapSetRequest(beatmapId, BeatmapSetLookupType.BeatmapId); + req.Success += res => + { + ShowBeatmapSet(res.ToBeatmapSet(rulesets)); + header.Picker.Beatmap.Value = header.BeatmapSet.Beatmaps.First(b => b.OnlineBeatmapID == beatmapId); + }; + api.Queue(req); + } + + public void ShowBeatmap(BeatmapInfo beatmap) + { + ShowBeatmapSet(beatmap.BeatmapSet); + header.Picker.Beatmap.Value = beatmap; + } + public void ShowBeatmapSet(int beatmapSetId) { // todo: display the overlay while we are loading here. we need to support setting BeatmapSet to null for this to work. From 7482d5986a6fa6312e4c33f6336afe8137b6ee51 Mon Sep 17 00:00:00 2001 From: naoey Date: Sat, 10 Mar 2018 11:25:26 +0530 Subject: [PATCH 03/45] Add a loading state to BeatmapSetOverlay. - Handle null value in header and info sections - Add item to context menu for carousel beatmaps to show details --- .../Visual/TestCaseBeatmapSetOverlay.cs | 1 + osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs | 2 +- osu.Game/Overlays/BeatmapSet/Header.cs | 3 + osu.Game/Overlays/BeatmapSet/Info.cs | 3 + osu.Game/Overlays/BeatmapSetOverlay.cs | 55 ++++++++++++++++--- .../Carousel/DrawableCarouselBeatmap.cs | 11 +++- 6 files changed, 64 insertions(+), 11 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCaseBeatmapSetOverlay.cs b/osu.Game.Tests/Visual/TestCaseBeatmapSetOverlay.cs index 6605c61026..09e76c6354 100644 --- a/osu.Game.Tests/Visual/TestCaseBeatmapSetOverlay.cs +++ b/osu.Game.Tests/Visual/TestCaseBeatmapSetOverlay.cs @@ -374,6 +374,7 @@ namespace osu.Game.Tests.Visual AddStep(@"hide", overlay.Hide); AddStep(@"show without reload", overlay.Show); + AddStep(@"show loading", () => overlay.BeatmapSet = null); } } } diff --git a/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs b/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs index b09e151ebc..2ac232f2ce 100644 --- a/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs +++ b/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs @@ -150,7 +150,7 @@ namespace osu.Game.Overlays.BeatmapSet Beatmap.TriggerChange(); } - private void showBeatmap(BeatmapInfo beatmap) => version.Text = beatmap.Version; + private void showBeatmap(BeatmapInfo beatmap) => version.Text = beatmap?.Version; private void updateDifficultyButtons() { diff --git a/osu.Game/Overlays/BeatmapSet/Header.cs b/osu.Game/Overlays/BeatmapSet/Header.cs index b9a35ec1f0..bbf385fe0f 100644 --- a/osu.Game/Overlays/BeatmapSet/Header.cs +++ b/osu.Game/Overlays/BeatmapSet/Header.cs @@ -48,6 +48,9 @@ namespace osu.Game.Overlays.BeatmapSet if (value == beatmapSet) return; beatmapSet = value; + if (beatmapSet == null) + return; + Picker.BeatmapSet = author.BeatmapSet = Details.BeatmapSet = BeatmapSet; title.Text = BeatmapSet.Metadata.Title; artist.Text = BeatmapSet.Metadata.Artist; diff --git a/osu.Game/Overlays/BeatmapSet/Info.cs b/osu.Game/Overlays/BeatmapSet/Info.cs index a0b6d9cefa..2d0a97aafb 100644 --- a/osu.Game/Overlays/BeatmapSet/Info.cs +++ b/osu.Game/Overlays/BeatmapSet/Info.cs @@ -34,6 +34,9 @@ namespace osu.Game.Overlays.BeatmapSet if (value == beatmapSet) return; beatmapSet = value; + if (beatmapSet == null) + return; + source.Text = BeatmapSet.Metadata.Source; tags.Text = BeatmapSet.Metadata.Tags; } diff --git a/osu.Game/Overlays/BeatmapSetOverlay.cs b/osu.Game/Overlays/BeatmapSetOverlay.cs index c7c8a4d50e..c431ce7561 100644 --- a/osu.Game/Overlays/BeatmapSetOverlay.cs +++ b/osu.Game/Overlays/BeatmapSetOverlay.cs @@ -18,17 +18,22 @@ using osu.Game.Overlays.BeatmapSet; using osu.Game.Rulesets; using osu.Game.Overlays.BeatmapSet.Scores; using System.Linq; +using osu.Framework.Configuration; +using osu.Game.Graphics.UserInterface; namespace osu.Game.Overlays { public class BeatmapSetOverlay : WaveOverlayContainer { + private const int fade_duration = 300; + public const float X_PADDING = 40; public const float RIGHT_WIDTH = 275; private readonly Header header; private readonly Info info; private readonly ScoresContainer scores; + private readonly LoadingAnimation loading; private APIAccess api; private RulesetStore rulesets; @@ -36,6 +41,31 @@ namespace osu.Game.Overlays private readonly ScrollContainer scroll; + private BeatmapSetInfo beatmapSet; + + public BeatmapSetInfo BeatmapSet + { + get => beatmapSet; + set + { + if (value == beatmapSet) + return; + + beatmapSet = value; + + if (beatmapSet == null) + { + scroll.FadeOut(fade_duration); + loading.FadeIn(fade_duration); + return; + } + + header.BeatmapSet = info.BeatmapSet = beatmapSet; + loading.FadeOut(fade_duration); + scroll.FadeIn(fade_duration); + } + } + // receive input outside our bounds so we can trigger a close event on ourselves. public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => true; @@ -67,10 +97,17 @@ namespace osu.Game.Overlays RelativeSizeAxes = Axes.Both, Colour = OsuColour.Gray(0.2f) }, + loading = new LoadingAnimation + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Alpha = 1, + }, scroll = new ScrollContainer { RelativeSizeAxes = Axes.Both, ScrollbarVisible = false, + Alpha = 0, Child = new ReverseChildIDFillFlowContainer { RelativeSizeAxes = Axes.X, @@ -89,7 +126,9 @@ namespace osu.Game.Overlays header.Picker.Beatmap.ValueChanged += b => { info.Beatmap = b; - updateScores(b); + + if (b != null) + updateScores(b); }; } @@ -132,6 +171,7 @@ namespace osu.Game.Overlays base.PopOut(); header.Details.StopPreview(); FadeEdgeEffectTo(0, DISAPPEAR_DURATION, Easing.Out); + BeatmapSet = null; } protected override bool OnClick(InputState state) @@ -142,6 +182,7 @@ namespace osu.Game.Overlays public void ShowBeatmap(int beatmapId) { + BeatmapSet = null; var req = new GetBeatmapSetRequest(beatmapId, BeatmapSetLookupType.BeatmapId); req.Success += res => { @@ -149,25 +190,21 @@ namespace osu.Game.Overlays header.Picker.Beatmap.Value = header.BeatmapSet.Beatmaps.First(b => b.OnlineBeatmapID == beatmapId); }; api.Queue(req); - } - - public void ShowBeatmap(BeatmapInfo beatmap) - { - ShowBeatmapSet(beatmap.BeatmapSet); - header.Picker.Beatmap.Value = beatmap; + Show(); } public void ShowBeatmapSet(int beatmapSetId) { - // todo: display the overlay while we are loading here. we need to support setting BeatmapSet to null for this to work. + BeatmapSet = null; var req = new GetBeatmapSetRequest(beatmapSetId); req.Success += res => ShowBeatmapSet(res.ToBeatmapSet(rulesets)); api.Queue(req); + Show(); } public void ShowBeatmapSet(BeatmapSetInfo set) { - header.BeatmapSet = info.BeatmapSet = set; + BeatmapSet = set; Show(); scroll.ScrollTo(0); } diff --git a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs index 38cb5fc5d8..c0cb469e15 100644 --- a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs +++ b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs @@ -17,6 +17,7 @@ using osu.Game.Graphics; using osu.Game.Graphics.Backgrounds; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; +using osu.Game.Overlays; using OpenTK; using OpenTK.Graphics; @@ -35,6 +36,8 @@ namespace osu.Game.Screens.Select.Carousel private Triangles triangles; private StarCounter starCounter; + private BeatmapSetOverlay beatmapOverlay; + public DrawableCarouselBeatmap(CarouselBeatmap panel) : base(panel) { beatmap = panel.Beatmap; @@ -42,8 +45,10 @@ namespace osu.Game.Screens.Select.Carousel } [BackgroundDependencyLoader(true)] - private void load(SongSelect songSelect, BeatmapManager manager) + private void load(SongSelect songSelect, BeatmapManager manager, BeatmapSetOverlay beatmapOverlay) { + this.beatmapOverlay = beatmapOverlay; + if (songSelect != null) { startRequested = songSelect.FinaliseSelection; @@ -171,6 +176,10 @@ namespace osu.Game.Screens.Select.Carousel new OsuMenuItem("Play", MenuItemType.Highlighted, () => startRequested?.Invoke(beatmap)), new OsuMenuItem("Edit", MenuItemType.Standard, () => editRequested?.Invoke(beatmap)), new OsuMenuItem("Hide", MenuItemType.Destructive, () => hideRequested?.Invoke(beatmap)), + new OsuMenuItem("Details", MenuItemType.Standard, () => + { + if (beatmap.OnlineBeatmapID.HasValue) beatmapOverlay?.ShowBeatmap(beatmap.OnlineBeatmapID.Value); + }), }; } } From ca4299c6fe0ae4f5d6b8da646b1bf8456a7ea0f4 Mon Sep 17 00:00:00 2001 From: naoey Date: Wed, 4 Apr 2018 22:02:45 +0530 Subject: [PATCH 04/45] Remove unused using and fix possible nullref. --- osu.Game/Graphics/Containers/LinkFlowContainer.cs | 2 +- osu.Game/Overlays/BeatmapSetOverlay.cs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game/Graphics/Containers/LinkFlowContainer.cs b/osu.Game/Graphics/Containers/LinkFlowContainer.cs index 0631d24f87..df780cf242 100644 --- a/osu.Game/Graphics/Containers/LinkFlowContainer.cs +++ b/osu.Game/Graphics/Containers/LinkFlowContainer.cs @@ -72,7 +72,7 @@ namespace osu.Game.Graphics.Containers { case LinkAction.OpenBeatmap: // TODO: proper query params handling - if (int.TryParse(linkArgument.Contains('?') ? linkArgument.Split('?')[0] : linkArgument, out int beatmapId)) + if (linkArgument != null && int.TryParse(linkArgument.Contains('?') ? linkArgument.Split('?')[0] : linkArgument, out int beatmapId)) game?.ShowBeatmap(beatmapId); break; case LinkAction.OpenBeatmapSet: diff --git a/osu.Game/Overlays/BeatmapSetOverlay.cs b/osu.Game/Overlays/BeatmapSetOverlay.cs index c431ce7561..c144e03bcb 100644 --- a/osu.Game/Overlays/BeatmapSetOverlay.cs +++ b/osu.Game/Overlays/BeatmapSetOverlay.cs @@ -18,7 +18,6 @@ using osu.Game.Overlays.BeatmapSet; using osu.Game.Rulesets; using osu.Game.Overlays.BeatmapSet.Scores; using System.Linq; -using osu.Framework.Configuration; using osu.Game.Graphics.UserInterface; namespace osu.Game.Overlays From cea3e1c7f5b62eab2d7de8c3e4da17f03bbdc97f Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 9 Apr 2018 18:44:50 +0900 Subject: [PATCH 05/45] Remove now unnecessary approachcircle proxy disables Prereqs: - [ ] ppy/osu-framework#1505 --- osu.Game.Rulesets.Osu/Edit/OsuEditPlayfield.cs | 1 - osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs | 5 +---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/OsuEditPlayfield.cs b/osu.Game.Rulesets.Osu/Edit/OsuEditPlayfield.cs index 46a3d8575f..22ce433eec 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuEditPlayfield.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuEditPlayfield.cs @@ -7,7 +7,6 @@ namespace osu.Game.Rulesets.Osu.Edit { public class OsuEditPlayfield : OsuPlayfield { - protected override bool ProxyApproachCircles => false; protected override bool DisplayJudgements => false; } } diff --git a/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs b/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs index 9010f66acb..3e894e609a 100644 --- a/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs +++ b/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs @@ -21,9 +21,6 @@ namespace osu.Game.Rulesets.Osu.UI private readonly JudgementContainer judgementLayer; private readonly ConnectionRenderer connectionLayer; - // Todo: This should not be a thing, but is currently required for the editor - // https://github.com/ppy/osu-framework/issues/1283 - protected virtual bool ProxyApproachCircles => true; protected virtual bool DisplayJudgements => true; public static readonly Vector2 BASE_SIZE = new Vector2(512, 384); @@ -59,7 +56,7 @@ namespace osu.Game.Rulesets.Osu.UI h.OnJudgement += onJudgement; var c = h as IDrawableHitObjectWithProxiedApproach; - if (c != null && ProxyApproachCircles) + if (c != null) approachCircles.Add(c.ProxiedLayer.CreateProxy()); base.Add(h); From d851446acaad3a2b5bd9ca41b913ec6ff0316a8d Mon Sep 17 00:00:00 2001 From: naoey Date: Tue, 10 Apr 2018 19:15:37 +0530 Subject: [PATCH 06/45] Remove redundant anchor and use Show/Hide instead of FadeIn/Out. --- osu.Game/Overlays/BeatmapSetOverlay.cs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/osu.Game/Overlays/BeatmapSetOverlay.cs b/osu.Game/Overlays/BeatmapSetOverlay.cs index c144e03bcb..98466ed986 100644 --- a/osu.Game/Overlays/BeatmapSetOverlay.cs +++ b/osu.Game/Overlays/BeatmapSetOverlay.cs @@ -55,12 +55,12 @@ namespace osu.Game.Overlays if (beatmapSet == null) { scroll.FadeOut(fade_duration); - loading.FadeIn(fade_duration); + loading.Show(); return; } header.BeatmapSet = info.BeatmapSet = beatmapSet; - loading.FadeOut(fade_duration); + loading.Hide(); scroll.FadeIn(fade_duration); } } @@ -98,9 +98,7 @@ namespace osu.Game.Overlays }, loading = new LoadingAnimation { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Alpha = 1, + State = Visibility.Visible, }, scroll = new ScrollContainer { From ea0683adb2369489c0684a11f2e6c1437538aa31 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 16 Apr 2018 20:18:33 +0900 Subject: [PATCH 07/45] Fix hitobject lengths not being calculated for overlapping speed changes Fixes #2359 --- .../OverlappingSpeedChangeVisualiser.cs | 28 +++++++++++++++---- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/osu.Game/Rulesets/UI/Scrolling/Visualisers/OverlappingSpeedChangeVisualiser.cs b/osu.Game/Rulesets/UI/Scrolling/Visualisers/OverlappingSpeedChangeVisualiser.cs index 2365582645..c5e91c6929 100644 --- a/osu.Game/Rulesets/UI/Scrolling/Visualisers/OverlappingSpeedChangeVisualiser.cs +++ b/osu.Game/Rulesets/UI/Scrolling/Visualisers/OverlappingSpeedChangeVisualiser.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using osu.Framework.Lists; using osu.Game.Rulesets.Objects.Drawables; +using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Timing; using OpenTK; @@ -22,8 +23,24 @@ namespace osu.Game.Rulesets.UI.Scrolling.Visualisers { foreach (var obj in hitObjects) { - var controlPoint = controlPointAt(obj.HitObject.StartTime); - obj.LifetimeStart = obj.HitObject.StartTime - timeRange / controlPoint.Multiplier; + obj.LifetimeStart = obj.HitObject.StartTime - timeRange / controlPointAt(obj.HitObject.StartTime).Multiplier; + + if (obj.HitObject is IHasEndTime endTime) + { + var diff = -positionAt(endTime.EndTime, obj, timeRange); + + switch (direction) + { + case ScrollingDirection.Up: + case ScrollingDirection.Down: + obj.Height = (float)(diff * length.Y); + break; + case ScrollingDirection.Left: + case ScrollingDirection.Right: + obj.Width = (float)(diff * length.X); + break; + } + } if (obj.HasNestedHitObjects) { @@ -37,9 +54,7 @@ namespace osu.Game.Rulesets.UI.Scrolling.Visualisers { foreach (var obj in hitObjects) { - var controlPoint = controlPointAt(obj.HitObject.StartTime); - - var position = (obj.HitObject.StartTime - currentTime) * controlPoint.Multiplier / timeRange; + var position = positionAt(currentTime, obj, timeRange); switch (direction) { @@ -59,6 +74,9 @@ namespace osu.Game.Rulesets.UI.Scrolling.Visualisers } } + private double positionAt(double time, DrawableHitObject obj, double timeRange) + => (obj.HitObject.StartTime - time) * controlPointAt(obj.HitObject.StartTime).Multiplier / timeRange; + private readonly MultiplierControlPoint searchPoint = new MultiplierControlPoint(); private MultiplierControlPoint controlPointAt(double time) { From 1728dd65021b3627b131f16b79d9895886b312ff Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 18 Apr 2018 15:58:45 +0900 Subject: [PATCH 08/45] Make BeatmapSetOverlay accept nulls everywhere --- .../Visual/TestCaseBeatmapScoresContainer.cs | 4 +- .../Visual/TestCaseBeatmapSetOverlay.cs | 27 +++++ osu.Game/OsuGame.cs | 4 +- osu.Game/Overlays/BeatmapSet/AuthorInfo.cs | 56 ++++++---- osu.Game/Overlays/BeatmapSet/BasicStats.cs | 27 ++++- osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs | 33 ++++-- .../{ => Buttons}/DownloadButton.cs | 2 +- .../{ => Buttons}/FavouriteButton.cs | 2 +- .../BeatmapSet/{ => Buttons}/HeaderButton.cs | 4 +- .../BeatmapSet/{ => Buttons}/PreviewButton.cs | 8 +- osu.Game/Overlays/BeatmapSet/Details.cs | 20 +++- osu.Game/Overlays/BeatmapSet/Header.cs | 39 +++++-- osu.Game/Overlays/BeatmapSet/Info.cs | 14 ++- .../BeatmapSet/Scores/ScoresContainer.cs | 102 +++++++++++------- osu.Game/Overlays/BeatmapSet/SuccessRate.cs | 26 +++-- osu.Game/Overlays/BeatmapSetOverlay.cs | 52 +-------- osu.Game/Overlays/Direct/PlayButton.cs | 16 +-- .../Sections/BeatmapMetadataContainer.cs | 2 +- .../Carousel/DrawableCarouselBeatmap.cs | 2 +- .../Carousel/DrawableCarouselBeatmapSet.cs | 2 +- .../Screens/Select/Details/AdvancedStats.cs | 8 +- .../Screens/Select/Details/FailRetryGraph.cs | 6 +- .../Screens/Select/Details/UserRatings.cs | 25 +++-- osu.Game/Users/UpdateableAvatar.cs | 22 ++-- 24 files changed, 312 insertions(+), 191 deletions(-) rename osu.Game/Overlays/BeatmapSet/{ => Buttons}/DownloadButton.cs (97%) rename osu.Game/Overlays/BeatmapSet/{ => Buttons}/FavouriteButton.cs (98%) rename osu.Game/Overlays/BeatmapSet/{ => Buttons}/HeaderButton.cs (94%) rename osu.Game/Overlays/BeatmapSet/{ => Buttons}/PreviewButton.cs (97%) diff --git a/osu.Game.Tests/Visual/TestCaseBeatmapScoresContainer.cs b/osu.Game.Tests/Visual/TestCaseBeatmapScoresContainer.cs index 6cb6a342a8..85f3364039 100644 --- a/osu.Game.Tests/Visual/TestCaseBeatmapScoresContainer.cs +++ b/osu.Game.Tests/Visual/TestCaseBeatmapScoresContainer.cs @@ -47,9 +47,7 @@ namespace osu.Game.Tests.Visual AddStep("scores pack 1", () => scoresContainer.Scores = scores); AddStep("scores pack 2", () => scoresContainer.Scores = anotherScores); AddStep("only top score", () => scoresContainer.Scores = new[] { topScore }); - AddStep("remove scores", scoresContainer.CleanAllScores); - AddStep("turn on loading", () => scoresContainer.IsLoading = true); - AddStep("turn off loading", () => scoresContainer.IsLoading = false); + AddStep("remove scores", () => scoresContainer.Scores = null); AddStep("resize to big", () => container.ResizeWidthTo(1, 300)); AddStep("resize to normal", () => container.ResizeWidthTo(0.8f, 300)); diff --git a/osu.Game.Tests/Visual/TestCaseBeatmapSetOverlay.cs b/osu.Game.Tests/Visual/TestCaseBeatmapSetOverlay.cs index c2b61e4d74..4154dbde47 100644 --- a/osu.Game.Tests/Visual/TestCaseBeatmapSetOverlay.cs +++ b/osu.Game.Tests/Visual/TestCaseBeatmapSetOverlay.cs @@ -8,6 +8,9 @@ using NUnit.Framework; using osu.Framework.Allocation; using osu.Game.Beatmaps; using osu.Game.Overlays; +using osu.Game.Overlays.BeatmapSet; +using osu.Game.Overlays.BeatmapSet.Buttons; +using osu.Game.Overlays.BeatmapSet.Scores; using osu.Game.Rulesets; using osu.Game.Users; @@ -18,6 +21,26 @@ namespace osu.Game.Tests.Visual { private readonly BeatmapSetOverlay overlay; + public override IReadOnlyList RequiredTypes => new[] + { + typeof(Header), + typeof(ClickableUsername), + typeof(DrawableScore), + typeof(DrawableTopScore), + typeof(ScoresContainer), + typeof(AuthorInfo), + typeof(BasicStats), + typeof(BeatmapPicker), + typeof(Details), + typeof(DownloadButton), + typeof(FavouriteButton), + typeof(Header), + typeof(HeaderButton), + typeof(Info), + typeof(PreviewButton), + typeof(SuccessRate), + }; + public TestCaseBeatmapSetOverlay() { Add(overlay = new BeatmapSetOverlay()); @@ -29,6 +52,10 @@ namespace osu.Game.Tests.Visual var mania = rulesets.GetRuleset(3); var taiko = rulesets.GetRuleset(1); + AddStep(@"show loading", () => overlay.ShowBeatmapSet(null)); + + AddStep(@"show online", () => overlay.FetchAndShowBeatmapSet(55)); + AddStep(@"show first", () => { overlay.ShowBeatmapSet(new BeatmapSetInfo diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index d740302a12..3852580c49 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -158,7 +158,7 @@ namespace osu.Game /// Show a beatmap set as an overlay. /// /// The set to display. - public void ShowBeatmapSet(int setId) => beatmapSetOverlay.ShowBeatmapSet(setId); + public void ShowBeatmapSet(int setId) => beatmapSetOverlay.FetchAndShowBeatmapSet(setId); /// /// Show a user's profile as an overlay. @@ -170,7 +170,7 @@ namespace osu.Game /// Show a beatmap's set as an overlay, displaying the given beatmap. /// /// The beatmap to show. - public void ShowBeatmap(int beatmapId) => beatmapSetOverlay.ShowBeatmap(beatmapId); + public void ShowBeatmap(int beatmapId) => beatmapSetOverlay.FetchAndShowBeatmap(beatmapId); protected void LoadScore(Score s) { diff --git a/osu.Game/Overlays/BeatmapSet/AuthorInfo.cs b/osu.Game/Overlays/BeatmapSet/AuthorInfo.cs index 8b19bca671..66e3148065 100644 --- a/osu.Game/Overlays/BeatmapSet/AuthorInfo.cs +++ b/osu.Game/Overlays/BeatmapSet/AuthorInfo.cs @@ -23,9 +23,8 @@ namespace osu.Game.Overlays.BeatmapSet private readonly ClickableArea clickableArea; private readonly FillFlowContainer fields; - private UserProfileOverlay profile; - private BeatmapSetInfo beatmapSet; + public BeatmapSetInfo BeatmapSet { get { return beatmapSet; } @@ -34,28 +33,36 @@ namespace osu.Game.Overlays.BeatmapSet if (value == beatmapSet) return; beatmapSet = value; - var i = BeatmapSet.OnlineInfo; + updateDisplay(); + } + } - avatar.User = BeatmapSet.Metadata.Author; - clickableArea.Action = () => profile?.ShowUser(avatar.User); + private void updateDisplay() + { + avatar.User = BeatmapSet?.Metadata.Author; - fields.Children = new Drawable[] - { - new Field("made by", BeatmapSet.Metadata.Author.Username, @"Exo2.0-RegularItalic"), - new Field("submitted on", i.Submitted.ToString(@"MMM d, yyyy"), @"Exo2.0-Bold") - { - Margin = new MarginPadding { Top = 5 }, - }, - }; + fields.Clear(); + if (BeatmapSet == null) + return; - if (i.Ranked.HasValue) + var online = BeatmapSet.OnlineInfo; + + fields.Children = new Drawable[] + { + new Field("made by", BeatmapSet.Metadata.Author.Username, @"Exo2.0-RegularItalic"), + new Field("submitted on", online.Submitted.ToString(@"MMM d, yyyy"), @"Exo2.0-Bold") { - fields.Add(new Field("ranked on ", i.Ranked.Value.ToString(@"MMM d, yyyy"), @"Exo2.0-Bold")); - } - else if (i.LastUpdated.HasValue) - { - fields.Add(new Field("last updated on ", i.LastUpdated.Value.ToString(@"MMM d, yyyy"), @"Exo2.0-Bold")); - } + Margin = new MarginPadding { Top = 5 }, + }, + }; + + if (online.Ranked.HasValue) + { + fields.Add(new Field("ranked on ", online.Ranked.Value.ToString(@"MMM d, yyyy"), @"Exo2.0-Bold")); + } + else if (online.LastUpdated.HasValue) + { + fields.Add(new Field("last updated on ", online.LastUpdated.Value.ToString(@"MMM d, yyyy"), @"Exo2.0-Bold")); } } @@ -73,6 +80,7 @@ namespace osu.Game.Overlays.BeatmapSet Masking = true, Child = avatar = new UpdateableAvatar { + ShowGuestOnNull = false, Size = new Vector2(height), }, EdgeEffect = new EdgeEffectParameters @@ -95,8 +103,12 @@ namespace osu.Game.Overlays.BeatmapSet [BackgroundDependencyLoader(true)] private void load(UserProfileOverlay profile) { - this.profile = profile; - clickableArea.Action = () => profile?.ShowUser(avatar.User); + clickableArea.Action = () => + { + if (avatar.User != null) profile?.ShowUser(avatar.User); + }; + + updateDisplay(); } private class Field : FillFlowContainer diff --git a/osu.Game/Overlays/BeatmapSet/BasicStats.cs b/osu.Game/Overlays/BeatmapSet/BasicStats.cs index 8fd34914a7..a7b6b16dcc 100644 --- a/osu.Game/Overlays/BeatmapSet/BasicStats.cs +++ b/osu.Game/Overlays/BeatmapSet/BasicStats.cs @@ -18,6 +18,7 @@ namespace osu.Game.Overlays.BeatmapSet private readonly Statistic length, bpm, circleCount, sliderCount; private BeatmapSetInfo beatmapSet; + public BeatmapSetInfo BeatmapSet { get { return beatmapSet; } @@ -26,11 +27,12 @@ namespace osu.Game.Overlays.BeatmapSet if (value == beatmapSet) return; beatmapSet = value; - bpm.Value = BeatmapSet.OnlineInfo.BPM.ToString(@"0.##"); + updateDisplay(); } } private BeatmapInfo beatmap; + public BeatmapInfo Beatmap { get { return beatmap; } @@ -39,6 +41,22 @@ namespace osu.Game.Overlays.BeatmapSet if (value == beatmap) return; beatmap = value; + updateDisplay(); + } + } + + private void updateDisplay() + { + bpm.Value = BeatmapSet?.OnlineInfo.BPM.ToString(@"0.##") ?? "-"; + + if (beatmap == null) + { + length.Value = string.Empty; + circleCount.Value = string.Empty; + sliderCount.Value = string.Empty; + } + else + { length.Value = TimeSpan.FromSeconds(beatmap.OnlineInfo.Length).ToString(@"m\:ss"); circleCount.Value = beatmap.OnlineInfo.CircleCount.ToString(); sliderCount.Value = beatmap.OnlineInfo.SliderCount.ToString(); @@ -62,12 +80,19 @@ namespace osu.Game.Overlays.BeatmapSet }; } + [BackgroundDependencyLoader] + private void load() + { + updateDisplay(); + } + private class Statistic : Container, IHasTooltip { private readonly string name; private readonly OsuSpriteText value; public string TooltipText => name; + public string Value { get { return value.Text; } diff --git a/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs b/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs index d8ec804646..6b75ac095d 100644 --- a/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs +++ b/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs @@ -41,9 +41,16 @@ namespace osu.Game.Overlays.BeatmapSet if (value == beatmapSet) return; beatmapSet = value; - Beatmap.Value = BeatmapSet.Beatmaps.First(); - plays.Value = BeatmapSet.OnlineInfo.PlayCount; - favourites.Value = BeatmapSet.OnlineInfo.FavouriteCount; + updateDisplay(); + } + } + + private void updateDisplay() + { + difficulties.Clear(); + + if (BeatmapSet != null) + { difficulties.ChildrenEnumerable = BeatmapSet.Beatmaps.OrderBy(beatmap => beatmap.StarDifficulty).Select(b => new DifficultySelectorButton(b) { State = DifficultySelectorState.NotSelected, @@ -53,14 +60,16 @@ namespace osu.Game.Overlays.BeatmapSet starRating.Text = beatmap.StarDifficulty.ToString("Star Difficulty 0.##"); starRating.FadeIn(100); }, - OnClicked = beatmap => - { - Beatmap.Value = beatmap; - }, + OnClicked = beatmap => { Beatmap.Value = beatmap; }, }); - - updateDifficultyButtons(); } + + starRating.FadeOut(100); + Beatmap.Value = BeatmapSet?.Beatmaps.FirstOrDefault(); + plays.Value = BeatmapSet?.OnlineInfo.PlayCount ?? 0; + favourites.Value = BeatmapSet?.OnlineInfo.FavouriteCount ?? 0; + + updateDifficultyButtons(); } public BeatmapPicker() @@ -140,6 +149,7 @@ namespace osu.Game.Overlays.BeatmapSet private void load(OsuColour colours) { starRating.Colour = colours.Yellow; + updateDisplay(); } protected override void LoadComplete() @@ -150,7 +160,10 @@ namespace osu.Game.Overlays.BeatmapSet Beatmap.TriggerChange(); } - private void showBeatmap(BeatmapInfo beatmap) => version.Text = beatmap?.Version; + private void showBeatmap(BeatmapInfo beatmap) + { + version.Text = beatmap?.Version; + } private void updateDifficultyButtons() { diff --git a/osu.Game/Overlays/BeatmapSet/DownloadButton.cs b/osu.Game/Overlays/BeatmapSet/Buttons/DownloadButton.cs similarity index 97% rename from osu.Game/Overlays/BeatmapSet/DownloadButton.cs rename to osu.Game/Overlays/BeatmapSet/Buttons/DownloadButton.cs index 0c6414c718..c699ae2328 100644 --- a/osu.Game/Overlays/BeatmapSet/DownloadButton.cs +++ b/osu.Game/Overlays/BeatmapSet/Buttons/DownloadButton.cs @@ -7,7 +7,7 @@ using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using OpenTK; -namespace osu.Game.Overlays.BeatmapSet +namespace osu.Game.Overlays.BeatmapSet.Buttons { public class DownloadButton : HeaderButton { diff --git a/osu.Game/Overlays/BeatmapSet/FavouriteButton.cs b/osu.Game/Overlays/BeatmapSet/Buttons/FavouriteButton.cs similarity index 98% rename from osu.Game/Overlays/BeatmapSet/FavouriteButton.cs rename to osu.Game/Overlays/BeatmapSet/Buttons/FavouriteButton.cs index 29bc00038c..3821c96369 100644 --- a/osu.Game/Overlays/BeatmapSet/FavouriteButton.cs +++ b/osu.Game/Overlays/BeatmapSet/Buttons/FavouriteButton.cs @@ -10,7 +10,7 @@ using osu.Game.Graphics; using osu.Game.Graphics.Backgrounds; using OpenTK; -namespace osu.Game.Overlays.BeatmapSet +namespace osu.Game.Overlays.BeatmapSet.Buttons { public class FavouriteButton : HeaderButton { diff --git a/osu.Game/Overlays/BeatmapSet/HeaderButton.cs b/osu.Game/Overlays/BeatmapSet/Buttons/HeaderButton.cs similarity index 94% rename from osu.Game/Overlays/BeatmapSet/HeaderButton.cs rename to osu.Game/Overlays/BeatmapSet/Buttons/HeaderButton.cs index e1c4f5cc67..b46b5d2a0e 100644 --- a/osu.Game/Overlays/BeatmapSet/HeaderButton.cs +++ b/osu.Game/Overlays/BeatmapSet/Buttons/HeaderButton.cs @@ -1,12 +1,12 @@ // Copyright (c) 2007-2018 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.UserInterface; -using osu.Framework.Allocation; -namespace osu.Game.Overlays.BeatmapSet +namespace osu.Game.Overlays.BeatmapSet.Buttons { public class HeaderButton : TriangleButton { diff --git a/osu.Game/Overlays/BeatmapSet/PreviewButton.cs b/osu.Game/Overlays/BeatmapSet/Buttons/PreviewButton.cs similarity index 97% rename from osu.Game/Overlays/BeatmapSet/PreviewButton.cs rename to osu.Game/Overlays/BeatmapSet/Buttons/PreviewButton.cs index 6b5ffa57ad..08a99f1aea 100644 --- a/osu.Game/Overlays/BeatmapSet/PreviewButton.cs +++ b/osu.Game/Overlays/BeatmapSet/Buttons/PreviewButton.cs @@ -3,6 +3,7 @@ using osu.Framework.Allocation; using osu.Framework.Audio.Track; +using osu.Framework.Configuration; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -11,12 +12,11 @@ using osu.Framework.Input; using osu.Game.Beatmaps; using osu.Game.Graphics; using osu.Game.Graphics.Containers; +using osu.Game.Overlays.Direct; using OpenTK; using OpenTK.Graphics; -using osu.Game.Overlays.Direct; -using osu.Framework.Configuration; -namespace osu.Game.Overlays.BeatmapSet +namespace osu.Game.Overlays.BeatmapSet.Buttons { public class PreviewButton : OsuClickableContainer { @@ -85,6 +85,8 @@ namespace osu.Game.Overlays.BeatmapSet // prevent negative (potential infinite) width if a track without length was loaded progress.Width = preview.Length > 0 ? (float)(preview.CurrentTime / preview.Length) : 0f; } + else + progress.Width = 0; } protected override void Dispose(bool isDisposing) diff --git a/osu.Game/Overlays/BeatmapSet/Details.cs b/osu.Game/Overlays/BeatmapSet/Details.cs index 7f3b6d1584..5264caf936 100644 --- a/osu.Game/Overlays/BeatmapSet/Details.cs +++ b/osu.Game/Overlays/BeatmapSet/Details.cs @@ -1,11 +1,13 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +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.Beatmaps; +using osu.Game.Overlays.BeatmapSet.Buttons; using osu.Game.Screens.Select.Details; using OpenTK; using OpenTK.Graphics; @@ -20,6 +22,7 @@ namespace osu.Game.Overlays.BeatmapSet private readonly UserRatings ratings; private BeatmapSetInfo beatmapSet; + public BeatmapSetInfo BeatmapSet { get { return beatmapSet; } @@ -33,19 +36,24 @@ namespace osu.Game.Overlays.BeatmapSet } private BeatmapInfo beatmap; + public BeatmapInfo Beatmap { get { return beatmap; } set { if (value == beatmap) return; - beatmap = value; - basic.Beatmap = advanced.Beatmap = Beatmap; - ratings.Metrics = Beatmap.Metrics; + basic.Beatmap = advanced.Beatmap = beatmap = value; + updateDisplay(); } } + private void updateDisplay() + { + ratings.Metrics = Beatmap?.Metrics; + } + public Details() { Width = BeatmapSetOverlay.RIGHT_WIDTH; @@ -88,6 +96,12 @@ namespace osu.Game.Overlays.BeatmapSet }; } + [BackgroundDependencyLoader] + private void load() + { + updateDisplay(); + } + public void StopPreview() => preview.Playing.Value = false; private class DetailBox : Container diff --git a/osu.Game/Overlays/BeatmapSet/Header.cs b/osu.Game/Overlays/BeatmapSet/Header.cs index ab3a981e77..9b25d61f58 100644 --- a/osu.Game/Overlays/BeatmapSet/Header.cs +++ b/osu.Game/Overlays/BeatmapSet/Header.cs @@ -11,6 +11,7 @@ using osu.Game.Beatmaps; using osu.Game.Beatmaps.Drawables; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; +using osu.Game.Overlays.BeatmapSet.Buttons; using OpenTK; using OpenTK.Graphics; @@ -18,7 +19,7 @@ namespace osu.Game.Overlays.BeatmapSet { public class Header : Container { - private const float transition_duration = 250; + private const float transition_duration = 200; private const float tabs_height = 50; private const float buttons_height = 45; private const float buttons_spacing = 5; @@ -34,12 +35,13 @@ namespace osu.Game.Overlays.BeatmapSet public Details Details; private BeatmapManager beatmaps; - private DelayedLoadWrapper cover; public readonly BeatmapPicker Picker; private BeatmapSetInfo beatmapSet; + private readonly FavouriteButton favouriteButton; + public BeatmapSetInfo BeatmapSet { get { return beatmapSet; } @@ -48,19 +50,27 @@ namespace osu.Game.Overlays.BeatmapSet if (value == beatmapSet) return; beatmapSet = value; - if (beatmapSet == null) - return; - Picker.BeatmapSet = author.BeatmapSet = Details.BeatmapSet = BeatmapSet; - title.Text = BeatmapSet.Metadata.Title; - artist.Text = BeatmapSet.Metadata.Artist; - onlineStatusPill.Status = BeatmapSet.OnlineInfo.Status; - downloadButtonsContainer.FadeIn(); + updateDisplay(); + } + } + + private void updateDisplay() + { + title.Text = BeatmapSet?.Metadata.Title ?? string.Empty; + artist.Text = BeatmapSet?.Metadata.Artist ?? string.Empty; + onlineStatusPill.Status = BeatmapSet?.OnlineInfo.Status ?? BeatmapSetOnlineStatus.None; + + cover?.FadeOut(400, Easing.Out); + if (BeatmapSet != null) + { + downloadButtonsContainer.FadeIn(transition_duration); + favouriteButton.FadeIn(transition_duration); + noVideoButtons.FadeTo(BeatmapSet.OnlineInfo.HasVideo ? 0 : 1, transition_duration); videoButtons.FadeTo(BeatmapSet.OnlineInfo.HasVideo ? 1 : 0, transition_duration); - cover?.FadeOut(400, Easing.Out); coverContainer.Add(cover = new DelayedLoadWrapper( new BeatmapSetCover(BeatmapSet) { @@ -74,6 +84,11 @@ namespace osu.Game.Overlays.BeatmapSet RelativeSizeAxes = Axes.Both, }); } + else + { + downloadButtonsContainer.FadeOut(transition_duration); + favouriteButton.FadeOut(transition_duration); + } } public Header() @@ -169,7 +184,7 @@ namespace osu.Game.Overlays.BeatmapSet Margin = new MarginPadding { Top = 10 }, Children = new Drawable[] { - new FavouriteButton(), + favouriteButton = new FavouriteButton(), downloadButtonsContainer = new Container { RelativeSizeAxes = Axes.Both, @@ -241,6 +256,8 @@ namespace osu.Game.Overlays.BeatmapSet this.beatmaps = beatmaps; beatmaps.ItemAdded += handleBeatmapAdd; + + updateDisplay(); } protected override void Dispose(bool isDisposing) diff --git a/osu.Game/Overlays/BeatmapSet/Info.cs b/osu.Game/Overlays/BeatmapSet/Info.cs index 48485a8835..cd0b7386e8 100644 --- a/osu.Game/Overlays/BeatmapSet/Info.cs +++ b/osu.Game/Overlays/BeatmapSet/Info.cs @@ -34,14 +34,16 @@ namespace osu.Game.Overlays.BeatmapSet if (value == beatmapSet) return; beatmapSet = value; - if (beatmapSet == null) - return; - - source.Text = BeatmapSet.Metadata.Source; - tags.Text = BeatmapSet.Metadata.Tags; + updateDisplay(); } } + private void updateDisplay() + { + source.Text = BeatmapSet?.Metadata.Source ?? string.Empty; + tags.Text = BeatmapSet?.Metadata.Tags ?? string.Empty; + } + public BeatmapInfo Beatmap { get { return successRate.Beatmap; } @@ -135,6 +137,8 @@ namespace osu.Game.Overlays.BeatmapSet successRateBackground.Colour = colours.GrayE; source.TextColour = description.TextColour = colours.Gray5; tags.TextColour = colours.BlueDark; + + updateDisplay(); } private class MetadataSection : FillFlowContainer diff --git a/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs b/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs index d5c5bd8ddd..185282bec9 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs @@ -2,15 +2,15 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using OpenTK; -using OpenTK.Graphics; -using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; using osu.Game.Graphics.UserInterface; using osu.Game.Online.API.Requests; using System.Collections.Generic; using System.Linq; +using osu.Framework.Allocation; +using osu.Game.Beatmaps; +using osu.Game.Online.API; namespace osu.Game.Overlays.BeatmapSet.Scores { @@ -22,49 +22,75 @@ namespace osu.Game.Overlays.BeatmapSet.Scores private readonly FillFlowContainer flow; private readonly DrawableTopScore topScore; private readonly LoadingAnimation loadingAnimation; - private readonly Box foreground; - private bool isLoading; - public bool IsLoading + private bool loading { - get { return isLoading; } - set - { - if (isLoading == value) return; - isLoading = value; - - foreground.FadeTo(isLoading ? 1 : 0, fade_duration); - loadingAnimation.FadeTo(isLoading ? 1 : 0, fade_duration); - } + set => loadingAnimation.FadeTo(value ? 1 : 0, fade_duration); } private IEnumerable scores; + private BeatmapInfo beatmap; + public IEnumerable Scores { get { return scores; } set { + getScoresRequest?.Cancel(); scores = value; - var scoresAmount = scores.Count(); - if (scoresAmount == 0) - { - CleanAllScores(); - return; - } - topScore.Score = scores.FirstOrDefault(); - topScore.Show(); - - flow.Clear(); - - if (scoresAmount < 2) - return; - - for (int i = 1; i < scoresAmount; i++) - flow.Add(new DrawableScore(i, scores.ElementAt(i))); + updateDisplay(); } } + private GetScoresRequest getScoresRequest; + private APIAccess api; + + public BeatmapInfo Beatmap + { + get => beatmap; + set + { + beatmap = value; + + Scores = null; + + if (beatmap?.OnlineBeatmapID.HasValue != true) + return; + + loading = true; + + getScoresRequest = new GetScoresRequest(beatmap, beatmap.Ruleset); + getScoresRequest.Success += r => Scores = r.Scores; + api.Queue(getScoresRequest); + } + } + + private void updateDisplay() + { + loading = false; + + var scoreCount = scores?.Count() ?? 0; + + if (scoreCount == 0) + { + topScore.Hide(); + flow.Clear(); + return; + } + + topScore.Score = scores.FirstOrDefault(); + topScore.Show(); + + flow.Clear(); + + if (scoreCount < 2) + return; + + for (int i = 1; i < scoreCount; i++) + flow.Add(new DrawableScore(i, scores.ElementAt(i))); + } + public ScoresContainer() { RelativeSizeAxes = Axes.X; @@ -93,23 +119,19 @@ namespace osu.Game.Overlays.BeatmapSet.Scores }, } }, - foreground = new Box - { - RelativeSizeAxes = Axes.Both, - Colour = Color4.Black.Opacity(0.7f), - Alpha = 0, - }, loadingAnimation = new LoadingAnimation { Alpha = 0, + Margin = new MarginPadding(20) }, }; } - public void CleanAllScores() + [BackgroundDependencyLoader] + private void load(APIAccess api) { - topScore.Hide(); - flow.Clear(); + this.api = api; + updateDisplay(); } } } diff --git a/osu.Game/Overlays/BeatmapSet/SuccessRate.cs b/osu.Game/Overlays/BeatmapSet/SuccessRate.cs index c64d3988a6..6572e520bd 100644 --- a/osu.Game/Overlays/BeatmapSet/SuccessRate.cs +++ b/osu.Game/Overlays/BeatmapSet/SuccessRate.cs @@ -29,18 +29,23 @@ namespace osu.Game.Overlays.BeatmapSet if (value == beatmap) return; beatmap = value; - int passCount = beatmap.OnlineInfo.PassCount; - int playCount = beatmap.OnlineInfo.PlayCount; - - var rate = playCount != 0 ? (float)passCount / playCount : 0; - successPercent.Text = rate.ToString("P0"); - successRate.Length = rate; - percentContainer.ResizeWidthTo(successRate.Length, 250, Easing.InOutCubic); - - graph.Metrics = Beatmap.Metrics; + updateDisplay(); } } + private void updateDisplay() + { + int passCount = beatmap?.OnlineInfo.PassCount ?? 0; + int playCount = beatmap?.OnlineInfo.PlayCount ?? 0; + + var rate = playCount != 0 ? (float)passCount / playCount : 0; + successPercent.Text = rate.ToString("P0"); + successRate.Length = rate; + percentContainer.ResizeWidthTo(successRate.Length, 250, Easing.InOutCubic); + + graph.Metrics = beatmap?.Metrics; + } + public SuccessRate() { Children = new Drawable[] @@ -74,7 +79,6 @@ namespace osu.Game.Overlays.BeatmapSet { Anchor = Anchor.TopRight, Origin = Anchor.TopCentre, - Text = @"0%", TextSize = 13, }, }, @@ -103,6 +107,8 @@ namespace osu.Game.Overlays.BeatmapSet successRateLabel.Colour = successPercent.Colour = graphLabel.Colour = colours.Gray5; successRate.AccentColour = colours.Green; successRate.BackgroundColour = colours.GrayD; + + updateDisplay(); } protected override void UpdateAfterChildren() diff --git a/osu.Game/Overlays/BeatmapSetOverlay.cs b/osu.Game/Overlays/BeatmapSetOverlay.cs index 3be635ca00..5a3bbf69ad 100644 --- a/osu.Game/Overlays/BeatmapSetOverlay.cs +++ b/osu.Game/Overlays/BeatmapSetOverlay.cs @@ -18,7 +18,6 @@ using osu.Game.Overlays.BeatmapSet; using osu.Game.Rulesets; using osu.Game.Overlays.BeatmapSet.Scores; using System.Linq; -using osu.Game.Graphics.UserInterface; namespace osu.Game.Overlays { @@ -31,12 +30,9 @@ namespace osu.Game.Overlays private readonly Header header; private readonly Info info; - private readonly ScoresContainer scores; - private readonly LoadingAnimation loading; private APIAccess api; private RulesetStore rulesets; - private GetScoresRequest getScoresRequest; private readonly ScrollContainer scroll; @@ -50,18 +46,7 @@ namespace osu.Game.Overlays if (value == beatmapSet) return; - beatmapSet = value; - - if (beatmapSet == null) - { - scroll.FadeOut(fade_duration); - loading.Show(); - return; - } - - header.BeatmapSet = info.BeatmapSet = beatmapSet; - loading.Hide(); - scroll.FadeIn(fade_duration); + header.BeatmapSet = info.BeatmapSet = beatmapSet = value; } } @@ -70,6 +55,7 @@ namespace osu.Game.Overlays public BeatmapSetOverlay() { + ScoresContainer scores; Waves.FirstWaveColour = OsuColour.Gray(0.4f); Waves.SecondWaveColour = OsuColour.Gray(0.3f); Waves.ThirdWaveColour = OsuColour.Gray(0.2f); @@ -96,15 +82,10 @@ namespace osu.Game.Overlays RelativeSizeAxes = Axes.Both, Colour = OsuColour.Gray(0.2f) }, - loading = new LoadingAnimation - { - State = Visibility.Visible, - }, scroll = new ScrollContainer { RelativeSizeAxes = Axes.Both, ScrollbarVisible = false, - Alpha = 0, Child = new ReverseChildIDFillFlowContainer { RelativeSizeAxes = Axes.X, @@ -123,33 +104,10 @@ namespace osu.Game.Overlays header.Picker.Beatmap.ValueChanged += b => { info.Beatmap = b; - - if (b != null) - updateScores(b); + scores.Beatmap = b; }; } - private void updateScores(BeatmapInfo beatmap) - { - getScoresRequest?.Cancel(); - - if (!beatmap.OnlineBeatmapID.HasValue) - { - scores.CleanAllScores(); - return; - } - - scores.IsLoading = true; - - getScoresRequest = new GetScoresRequest(beatmap, beatmap.Ruleset); - getScoresRequest.Success += r => - { - scores.Scores = r.Scores; - scores.IsLoading = false; - }; - api.Queue(getScoresRequest); - } - [BackgroundDependencyLoader] private void load(APIAccess api, RulesetStore rulesets) { @@ -178,7 +136,7 @@ namespace osu.Game.Overlays return true; } - public void ShowBeatmap(int beatmapId) + public void FetchAndShowBeatmap(int beatmapId) { BeatmapSet = null; var req = new GetBeatmapSetRequest(beatmapId, BeatmapSetLookupType.BeatmapId); @@ -191,7 +149,7 @@ namespace osu.Game.Overlays Show(); } - public void ShowBeatmapSet(int beatmapSetId) + public void FetchAndShowBeatmapSet(int beatmapSetId) { BeatmapSet = null; var req = new GetBeatmapSetRequest(beatmapSetId); diff --git a/osu.Game/Overlays/Direct/PlayButton.cs b/osu.Game/Overlays/Direct/PlayButton.cs index 44e24d8157..4913b11ae1 100644 --- a/osu.Game/Overlays/Direct/PlayButton.cs +++ b/osu.Game/Overlays/Direct/PlayButton.cs @@ -78,12 +78,7 @@ namespace osu.Game.Overlays.Direct loadingAnimation = new LoadingAnimation(), }); - Playing.ValueChanged += playing => - { - icon.Icon = playing ? FontAwesome.fa_pause : FontAwesome.fa_play; - icon.FadeColour(playing || IsHovered ? hoverColour : Color4.White, 120, Easing.InOutQuint); - updatePreviewTrack(playing); - }; + Playing.ValueChanged += updatePreviewTrack; } [BackgroundDependencyLoader] @@ -125,6 +120,15 @@ namespace osu.Game.Overlays.Direct private void updatePreviewTrack(bool playing) { + if (playing && BeatmapSet == null) + { + Playing.Value = false; + return; + } + + icon.Icon = playing ? FontAwesome.fa_pause : FontAwesome.fa_play; + icon.FadeColour(playing || IsHovered ? hoverColour : Color4.White, 120, Easing.InOutQuint); + if (playing) { if (Preview == null) diff --git a/osu.Game/Overlays/Profile/Sections/BeatmapMetadataContainer.cs b/osu.Game/Overlays/Profile/Sections/BeatmapMetadataContainer.cs index da08c08179..97079c77f3 100644 --- a/osu.Game/Overlays/Profile/Sections/BeatmapMetadataContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/BeatmapMetadataContainer.cs @@ -32,7 +32,7 @@ namespace osu.Game.Overlays.Profile.Sections { Action = () => { - if (beatmap.OnlineBeatmapSetID.HasValue) beatmapSetOverlay?.ShowBeatmapSet(beatmap.OnlineBeatmapSetID.Value); + if (beatmap.OnlineBeatmapSetID.HasValue) beatmapSetOverlay?.FetchAndShowBeatmapSet(beatmap.OnlineBeatmapSetID.Value); }; Child = new FillFlowContainer diff --git a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs index d60e7669a5..f39952dc31 100644 --- a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs +++ b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs @@ -178,7 +178,7 @@ namespace osu.Game.Screens.Select.Carousel new OsuMenuItem("Hide", MenuItemType.Destructive, () => hideRequested?.Invoke(beatmap)), new OsuMenuItem("Details", MenuItemType.Standard, () => { - if (beatmap.OnlineBeatmapID.HasValue) beatmapOverlay?.ShowBeatmap(beatmap.OnlineBeatmapID.Value); + if (beatmap.OnlineBeatmapID.HasValue) beatmapOverlay?.FetchAndShowBeatmap(beatmap.OnlineBeatmapID.Value); }), }; } diff --git a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs index ad7588edde..d554a22735 100644 --- a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs +++ b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs @@ -46,7 +46,7 @@ namespace osu.Game.Screens.Select.Carousel restoreHiddenRequested = s => s.Beatmaps.ForEach(manager.Restore); dialogOverlay = overlay; if (beatmapOverlay != null) - viewDetails = beatmapOverlay.ShowBeatmapSet; + viewDetails = beatmapOverlay.FetchAndShowBeatmapSet; Children = new Drawable[] { diff --git a/osu.Game/Screens/Select/Details/AdvancedStats.cs b/osu.Game/Screens/Select/Details/AdvancedStats.cs index cad7ed7d81..852e4f190f 100644 --- a/osu.Game/Screens/Select/Details/AdvancedStats.cs +++ b/osu.Game/Screens/Select/Details/AdvancedStats.cs @@ -40,10 +40,10 @@ namespace osu.Game.Screens.Select.Details firstValue.Value = Beatmap?.BaseDifficulty?.CircleSize ?? 0; } - hpDrain.Value = beatmap.BaseDifficulty?.DrainRate ?? 0; - accuracy.Value = beatmap.BaseDifficulty?.OverallDifficulty ?? 0; - approachRate.Value = beatmap.BaseDifficulty?.ApproachRate ?? 0; - starDifficulty.Value = (float)beatmap.StarDifficulty; + hpDrain.Value = Beatmap?.BaseDifficulty?.DrainRate ?? 0; + accuracy.Value = Beatmap?.BaseDifficulty?.OverallDifficulty ?? 0; + approachRate.Value = Beatmap?.BaseDifficulty?.ApproachRate ?? 0; + starDifficulty.Value = (float)(Beatmap?.StarDifficulty ?? 0); } } diff --git a/osu.Game/Screens/Select/Details/FailRetryGraph.cs b/osu.Game/Screens/Select/Details/FailRetryGraph.cs index a33cee21ed..bf4eb07108 100644 --- a/osu.Game/Screens/Select/Details/FailRetryGraph.cs +++ b/osu.Game/Screens/Select/Details/FailRetryGraph.cs @@ -25,10 +25,10 @@ namespace osu.Game.Screens.Select.Details if (value == metrics) return; metrics = value; - var retries = Metrics.Retries; - var fails = Metrics.Fails; + var retries = Metrics?.Retries ?? new int[0]; + var fails = Metrics?.Fails ?? new int[0]; - float maxValue = fails.Zip(retries, (fail, retry) => fail + retry).Max(); + float maxValue = fails.Any() ? fails.Zip(retries, (fail, retry) => fail + retry).Max() : 0; failGraph.MaxValue = maxValue; retryGraph.MaxValue = maxValue; diff --git a/osu.Game/Screens/Select/Details/UserRatings.cs b/osu.Game/Screens/Select/Details/UserRatings.cs index bf50217048..787b22f965 100644 --- a/osu.Game/Screens/Select/Details/UserRatings.cs +++ b/osu.Game/Screens/Select/Details/UserRatings.cs @@ -21,6 +21,7 @@ namespace osu.Game.Screens.Select.Details private readonly BarGraph graph; private BeatmapMetrics metrics; + public BeatmapMetrics Metrics { get { return metrics; } @@ -31,15 +32,25 @@ namespace osu.Game.Screens.Select.Details const int rating_range = 10; - var ratings = Metrics.Ratings.Skip(1).Take(rating_range); // adjust for API returning weird empty data at 0. + if (metrics == null) + { + negativeRatings.Text = "0"; + positiveRatings.Text = "0"; + ratingsBar.Length = 0; + graph.Values = new float[rating_range]; + } + else + { + var ratings = Metrics.Ratings.Skip(1).Take(rating_range); // adjust for API returning weird empty data at 0. - var negativeCount = ratings.Take(rating_range / 2).Sum(); - var totalCount = ratings.Sum(); + var negativeCount = ratings.Take(rating_range / 2).Sum(); + var totalCount = ratings.Sum(); - negativeRatings.Text = negativeCount.ToString(); - positiveRatings.Text = (totalCount - negativeCount).ToString(); - ratingsBar.Length = totalCount == 0 ? 0 : (float)negativeCount / totalCount; - graph.Values = ratings.Take(rating_range).Select(r => (float)r); + negativeRatings.Text = negativeCount.ToString(); + positiveRatings.Text = (totalCount - negativeCount).ToString(); + ratingsBar.Length = totalCount == 0 ? 0 : (float)negativeCount / totalCount; + graph.Values = ratings.Take(rating_range).Select(r => (float)r); + } } } diff --git a/osu.Game/Users/UpdateableAvatar.cs b/osu.Game/Users/UpdateableAvatar.cs index 31455801da..6c0b841abf 100644 --- a/osu.Game/Users/UpdateableAvatar.cs +++ b/osu.Game/Users/UpdateableAvatar.cs @@ -15,6 +15,11 @@ namespace osu.Game.Users private User user; + /// + /// Whether to show a default guest representation on null user (as opposed to nothing). + /// + public bool ShowGuestOnNull = true; + public User User { get { return user; } @@ -40,13 +45,16 @@ namespace osu.Game.Users { displayedAvatar?.FadeOut(300); displayedAvatar?.Expire(); - Add(displayedAvatar = new DelayedLoadWrapper( - new Avatar(user) - { - RelativeSizeAxes = Axes.Both, - OnLoadComplete = d => d.FadeInFromZero(300, Easing.OutQuint), - }) - ); + if (user != null || ShowGuestOnNull) + { + Add(displayedAvatar = new DelayedLoadWrapper( + new Avatar(user) + { + RelativeSizeAxes = Axes.Both, + OnLoadComplete = d => d.FadeInFromZero(300, Easing.OutQuint), + }) + ); + } } } } From 54fa725309b01e940c93f966d41ed86e216d65ad Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 20 Apr 2018 12:46:45 +0900 Subject: [PATCH 09/45] Remove unnecessary test --- osu.Game.Tests/Visual/TestCaseBeatmapSetOverlay.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game.Tests/Visual/TestCaseBeatmapSetOverlay.cs b/osu.Game.Tests/Visual/TestCaseBeatmapSetOverlay.cs index 4154dbde47..025562f75f 100644 --- a/osu.Game.Tests/Visual/TestCaseBeatmapSetOverlay.cs +++ b/osu.Game.Tests/Visual/TestCaseBeatmapSetOverlay.cs @@ -401,7 +401,6 @@ namespace osu.Game.Tests.Visual AddStep(@"hide", overlay.Hide); AddStep(@"show without reload", overlay.Show); - AddStep(@"show loading", () => overlay.BeatmapSet = null); } } } From 8eefd04fcb9dd1ef25431726402b0edb20b509e0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 20 Apr 2018 12:47:23 +0900 Subject: [PATCH 10/45] Don't return overlay to null until it has been completely hidden --- osu.Game/Overlays/BeatmapSetOverlay.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game/Overlays/BeatmapSetOverlay.cs b/osu.Game/Overlays/BeatmapSetOverlay.cs index 5a3bbf69ad..096f7bb63c 100644 --- a/osu.Game/Overlays/BeatmapSetOverlay.cs +++ b/osu.Game/Overlays/BeatmapSetOverlay.cs @@ -126,8 +126,7 @@ namespace osu.Game.Overlays base.PopOut(); header.Details.StopPreview(); - FadeEdgeEffectTo(0, WaveContainer.DISAPPEAR_DURATION, Easing.Out); - BeatmapSet = null; + FadeEdgeEffectTo(0, WaveContainer.DISAPPEAR_DURATION, Easing.Out).OnComplete(_ => BeatmapSet = null); } protected override bool OnClick(InputState state) From 1bab601cbc85318eff49efc6ca049ec9fab4198a Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 20 Apr 2018 13:51:36 +0900 Subject: [PATCH 11/45] Comments + xmldocs --- .../OverlappingSpeedChangeVisualiser.cs | 31 ++++++++++++++++--- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/osu.Game/Rulesets/UI/Scrolling/Visualisers/OverlappingSpeedChangeVisualiser.cs b/osu.Game/Rulesets/UI/Scrolling/Visualisers/OverlappingSpeedChangeVisualiser.cs index c5e91c6929..6045ab50e7 100644 --- a/osu.Game/Rulesets/UI/Scrolling/Visualisers/OverlappingSpeedChangeVisualiser.cs +++ b/osu.Game/Rulesets/UI/Scrolling/Visualisers/OverlappingSpeedChangeVisualiser.cs @@ -23,21 +23,24 @@ namespace osu.Game.Rulesets.UI.Scrolling.Visualisers { foreach (var obj in hitObjects) { + // For optimal lifetimes, the speed of the hitobject is factored into the time range obj.LifetimeStart = obj.HitObject.StartTime - timeRange / controlPointAt(obj.HitObject.StartTime).Multiplier; if (obj.HitObject is IHasEndTime endTime) { - var diff = -positionAt(endTime.EndTime, obj, timeRange); + // At the hitobject's end time, the hitobject will be positioned such that its end rests at the origin. + // This results in a negative-position value, and the absolute of it indicates the length of the hitobject. + var hitObjectLength = -hitObjectPositionAt(obj, endTime.EndTime, timeRange); switch (direction) { case ScrollingDirection.Up: case ScrollingDirection.Down: - obj.Height = (float)(diff * length.Y); + obj.Height = (float)(hitObjectLength * length.Y); break; case ScrollingDirection.Left: case ScrollingDirection.Right: - obj.Width = (float)(diff * length.X); + obj.Width = (float)(hitObjectLength * length.X); break; } } @@ -45,6 +48,8 @@ namespace osu.Game.Rulesets.UI.Scrolling.Visualisers if (obj.HasNestedHitObjects) { ComputeInitialStates(obj.NestedHitObjects, direction, timeRange, length); + + // Nested hitobjects don't need to scroll, but they do need accurate positions ComputePositions(obj.NestedHitObjects, direction, obj.HitObject.StartTime, timeRange, length); } } @@ -54,7 +59,7 @@ namespace osu.Game.Rulesets.UI.Scrolling.Visualisers { foreach (var obj in hitObjects) { - var position = positionAt(currentTime, obj, timeRange); + var position = hitObjectPositionAt(obj, currentTime, timeRange); switch (direction) { @@ -74,10 +79,26 @@ namespace osu.Game.Rulesets.UI.Scrolling.Visualisers } } - private double positionAt(double time, DrawableHitObject obj, double timeRange) + /// + /// Computes the position of a at a point in time.
+ /// At t < startTime, position > 0.
+ /// At t = startTime, position = 0.
+ /// At t > startTime, position < 0. + ///
+ /// The . + /// The time to find the position of at. + /// The amount of time visualised by the scrolling area. + /// The position of in the scrolling area at time = . + private double hitObjectPositionAt(DrawableHitObject obj, double time, double timeRange) => (obj.HitObject.StartTime - time) * controlPointAt(obj.HitObject.StartTime).Multiplier / timeRange; private readonly MultiplierControlPoint searchPoint = new MultiplierControlPoint(); + + /// + /// Finds the which affects the speed of hitobjects at a specific time. + /// + /// The time which the should affect. + /// The . private MultiplierControlPoint controlPointAt(double time) { if (controlPoints.Count == 0) From 48b421b4b417ec2113980b8561c76482bc66fbbf Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 20 Apr 2018 14:16:30 +0900 Subject: [PATCH 12/45] Add comments to SequentialSpeedChangeVisualiser --- .../OverlappingSpeedChangeVisualiser.cs | 4 ++- .../SequentialSpeedChangeVisualiser.cs | 29 ++++++++++++++++--- 2 files changed, 28 insertions(+), 5 deletions(-) diff --git a/osu.Game/Rulesets/UI/Scrolling/Visualisers/OverlappingSpeedChangeVisualiser.cs b/osu.Game/Rulesets/UI/Scrolling/Visualisers/OverlappingSpeedChangeVisualiser.cs index 6045ab50e7..e45e391dbc 100644 --- a/osu.Game/Rulesets/UI/Scrolling/Visualisers/OverlappingSpeedChangeVisualiser.cs +++ b/osu.Game/Rulesets/UI/Scrolling/Visualisers/OverlappingSpeedChangeVisualiser.cs @@ -80,10 +80,12 @@ namespace osu.Game.Rulesets.UI.Scrolling.Visualisers } /// - /// Computes the position of a at a point in time.
+ /// Computes the position of a at a point in time. + /// /// At t < startTime, position > 0.
/// At t = startTime, position = 0.
/// At t > startTime, position < 0. + ///
///
/// The . /// The time to find the position of at. diff --git a/osu.Game/Rulesets/UI/Scrolling/Visualisers/SequentialSpeedChangeVisualiser.cs b/osu.Game/Rulesets/UI/Scrolling/Visualisers/SequentialSpeedChangeVisualiser.cs index 708a2f173b..c8725fab56 100644 --- a/osu.Game/Rulesets/UI/Scrolling/Visualisers/SequentialSpeedChangeVisualiser.cs +++ b/osu.Game/Rulesets/UI/Scrolling/Visualisers/SequentialSpeedChangeVisualiser.cs @@ -25,23 +25,25 @@ namespace osu.Game.Rulesets.UI.Scrolling.Visualisers { foreach (var obj in hitObjects) { + // To reduce iterations when updating hitobject positions later on, their initial positions are cached var startPosition = hitObjectPositions[obj] = positionAt(obj.HitObject.StartTime, timeRange); + // Todo: This is approximate and will be incorrect in the case of extreme speed changes obj.LifetimeStart = obj.HitObject.StartTime - timeRange - 1000; if (obj.HitObject is IHasEndTime endTime) { - var diff = positionAt(endTime.EndTime, timeRange) - startPosition; + var hitObjectLength = positionAt(endTime.EndTime, timeRange) - startPosition; switch (direction) { case ScrollingDirection.Up: case ScrollingDirection.Down: - obj.Height = (float)(diff * length.Y); + obj.Height = (float)(hitObjectLength * length.Y); break; case ScrollingDirection.Left: case ScrollingDirection.Right: - obj.Width = (float)(diff * length.X); + obj.Width = (float)(hitObjectLength * length.X); break; } } @@ -49,6 +51,8 @@ namespace osu.Game.Rulesets.UI.Scrolling.Visualisers if (obj.HasNestedHitObjects) { ComputeInitialStates(obj.NestedHitObjects, direction, timeRange, length); + + // Nested hitobjects don't need to scroll, but they do need accurate positions ComputePositions(obj.NestedHitObjects, direction, obj.HitObject.StartTime, timeRange, length); } } @@ -80,21 +84,38 @@ namespace osu.Game.Rulesets.UI.Scrolling.Visualisers } } + /// + /// Finds the position which corresponds to a point in time. + /// This is a non-linear operation that depends on all the control points up to and including the one active at the time value. + /// + /// The time to find the position at. + /// The amount of time visualised by the scrolling area. + /// A positive value indicating the position at . private double positionAt(double time, double timeRange) { double length = 0; + + // We need to consider all timing points until the specified time and not just the currently-active one, + // since each timing point individually affects the positions of _all_ hitobjects after its start time for (int i = 0; i < controlPoints.Count; i++) { var current = controlPoints[i]; var next = i < controlPoints.Count - 1 ? controlPoints[i + 1] : null; + // We don't need to consider any control points beyond the current time, since it will not yet + // affect any hitobjects if (i > 0 && current.StartTime > time) continue; // Duration of the current control point var currentDuration = (next?.StartTime ?? double.PositiveInfinity) - current.StartTime; - length += Math.Min(currentDuration, time - current.StartTime) * current.Multiplier / timeRange; + // We want to consider the minimal amount of time that this control point has affected, + // which may be either its duration, or the amount of time that has passed within it + var durationInCurrent = Math.Min(currentDuration, time - current.StartTime); + + // Figure out how much of the time range the duration represents, and adjust it by the speed multiplier + length += durationInCurrent / timeRange * current.Multiplier; } return length; From f3fddcc82cf3dbb92f3290fba90792d2522a56da Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 20 Apr 2018 14:20:04 +0900 Subject: [PATCH 13/45] Reorder parameter for consistency --- .../Scrolling/Visualisers/OverlappingSpeedChangeVisualiser.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/UI/Scrolling/Visualisers/OverlappingSpeedChangeVisualiser.cs b/osu.Game/Rulesets/UI/Scrolling/Visualisers/OverlappingSpeedChangeVisualiser.cs index e45e391dbc..eaac10873e 100644 --- a/osu.Game/Rulesets/UI/Scrolling/Visualisers/OverlappingSpeedChangeVisualiser.cs +++ b/osu.Game/Rulesets/UI/Scrolling/Visualisers/OverlappingSpeedChangeVisualiser.cs @@ -92,7 +92,7 @@ namespace osu.Game.Rulesets.UI.Scrolling.Visualisers /// The amount of time visualised by the scrolling area. /// The position of in the scrolling area at time = . private double hitObjectPositionAt(DrawableHitObject obj, double time, double timeRange) - => (obj.HitObject.StartTime - time) * controlPointAt(obj.HitObject.StartTime).Multiplier / timeRange; + => (obj.HitObject.StartTime - time) / timeRange * controlPointAt(obj.HitObject.StartTime).Multiplier; private readonly MultiplierControlPoint searchPoint = new MultiplierControlPoint(); From 52e3ffff303327052c0ab962682c2574c7f3a572 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 20 Apr 2018 14:20:16 +0900 Subject: [PATCH 14/45] Add some more commenting to lifetime calculation --- .../Visualisers/OverlappingSpeedChangeVisualiser.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/osu.Game/Rulesets/UI/Scrolling/Visualisers/OverlappingSpeedChangeVisualiser.cs b/osu.Game/Rulesets/UI/Scrolling/Visualisers/OverlappingSpeedChangeVisualiser.cs index eaac10873e..d0dc65fe33 100644 --- a/osu.Game/Rulesets/UI/Scrolling/Visualisers/OverlappingSpeedChangeVisualiser.cs +++ b/osu.Game/Rulesets/UI/Scrolling/Visualisers/OverlappingSpeedChangeVisualiser.cs @@ -23,8 +23,10 @@ namespace osu.Game.Rulesets.UI.Scrolling.Visualisers { foreach (var obj in hitObjects) { - // For optimal lifetimes, the speed of the hitobject is factored into the time range - obj.LifetimeStart = obj.HitObject.StartTime - timeRange / controlPointAt(obj.HitObject.StartTime).Multiplier; + // The total amount of time that the hitobject will remain visible within the timeRange, which decreases as the speed multiplier increases + double visibleDuration = timeRange / controlPointAt(obj.HitObject.StartTime).Multiplier; + + obj.LifetimeStart = obj.HitObject.StartTime - visibleDuration; if (obj.HitObject is IHasEndTime endTime) { From 11b943c820280282b276dcd3b923abaf9376f072 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 20 Apr 2018 14:22:48 +0900 Subject: [PATCH 15/45] ComputePositions -> UpdatePositions --- .../UI/Scrolling/ScrollingHitObjectContainer.cs | 2 +- .../Scrolling/Visualisers/ISpeedChangeVisualiser.cs | 13 ++++++------- .../Visualisers/OverlappingSpeedChangeVisualiser.cs | 4 ++-- .../Visualisers/SequentialSpeedChangeVisualiser.cs | 4 ++-- 4 files changed, 11 insertions(+), 12 deletions(-) diff --git a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs index edfea57e94..36c6b07f54 100644 --- a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs +++ b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs @@ -110,7 +110,7 @@ namespace osu.Game.Rulesets.UI.Scrolling base.UpdateAfterChildrenLife(); // We need to calculate this as soon as possible after lifetimes so that hitobjects get the final say in their positions - speedChangeVisualiser.ComputePositions(AliveObjects, direction, Time.Current, TimeRange, DrawSize); + speedChangeVisualiser.UpdatePositions(AliveObjects, direction, Time.Current, TimeRange, DrawSize); } } } diff --git a/osu.Game/Rulesets/UI/Scrolling/Visualisers/ISpeedChangeVisualiser.cs b/osu.Game/Rulesets/UI/Scrolling/Visualisers/ISpeedChangeVisualiser.cs index 02791e0517..097e28b2dc 100644 --- a/osu.Game/Rulesets/UI/Scrolling/Visualisers/ISpeedChangeVisualiser.cs +++ b/osu.Game/Rulesets/UI/Scrolling/Visualisers/ISpeedChangeVisualiser.cs @@ -10,24 +10,23 @@ namespace osu.Game.Rulesets.UI.Scrolling.Visualisers public interface ISpeedChangeVisualiser { /// - /// Computes the states of s that are constant, such as lifetime and spatial length. + /// Computes the states of s that remain constant while scrolling, such as lifetime and spatial length. /// This is invoked once whenever or changes. /// /// The s whose states should be computed. /// The scrolling direction. - /// The duration required to scroll through one length of the screen before any control point adjustments. + /// The duration required to scroll through one length of the screen before any speed adjustments. /// The length of the screen that is scrolled through. void ComputeInitialStates(IEnumerable hitObjects, ScrollingDirection direction, double timeRange, Vector2 length); /// - /// Computes the states of s that change depending on , such as position. - /// This is invoked once per frame. + /// Updates the positions of s, depending on the current time. This is invoked once per frame. /// - /// The s whose states should be computed. + /// The s whose positions should be computed. /// The scrolling direction. /// The current time. - /// The duration required to scroll through one length of the screen before any control point adjustments. + /// The duration required to scroll through one length of the screen before any speed adjustments. /// The length of the screen that is scrolled through. - void ComputePositions(IEnumerable hitObjects, ScrollingDirection direction, double currentTime, double timeRange, Vector2 length); + void UpdatePositions(IEnumerable hitObjects, ScrollingDirection direction, double currentTime, double timeRange, Vector2 length); } } diff --git a/osu.Game/Rulesets/UI/Scrolling/Visualisers/OverlappingSpeedChangeVisualiser.cs b/osu.Game/Rulesets/UI/Scrolling/Visualisers/OverlappingSpeedChangeVisualiser.cs index d0dc65fe33..35a91275a7 100644 --- a/osu.Game/Rulesets/UI/Scrolling/Visualisers/OverlappingSpeedChangeVisualiser.cs +++ b/osu.Game/Rulesets/UI/Scrolling/Visualisers/OverlappingSpeedChangeVisualiser.cs @@ -52,12 +52,12 @@ namespace osu.Game.Rulesets.UI.Scrolling.Visualisers ComputeInitialStates(obj.NestedHitObjects, direction, timeRange, length); // Nested hitobjects don't need to scroll, but they do need accurate positions - ComputePositions(obj.NestedHitObjects, direction, obj.HitObject.StartTime, timeRange, length); + UpdatePositions(obj.NestedHitObjects, direction, obj.HitObject.StartTime, timeRange, length); } } } - public void ComputePositions(IEnumerable hitObjects, ScrollingDirection direction, double currentTime, double timeRange, Vector2 length) + public void UpdatePositions(IEnumerable hitObjects, ScrollingDirection direction, double currentTime, double timeRange, Vector2 length) { foreach (var obj in hitObjects) { diff --git a/osu.Game/Rulesets/UI/Scrolling/Visualisers/SequentialSpeedChangeVisualiser.cs b/osu.Game/Rulesets/UI/Scrolling/Visualisers/SequentialSpeedChangeVisualiser.cs index c8725fab56..e353c07e9f 100644 --- a/osu.Game/Rulesets/UI/Scrolling/Visualisers/SequentialSpeedChangeVisualiser.cs +++ b/osu.Game/Rulesets/UI/Scrolling/Visualisers/SequentialSpeedChangeVisualiser.cs @@ -53,12 +53,12 @@ namespace osu.Game.Rulesets.UI.Scrolling.Visualisers ComputeInitialStates(obj.NestedHitObjects, direction, timeRange, length); // Nested hitobjects don't need to scroll, but they do need accurate positions - ComputePositions(obj.NestedHitObjects, direction, obj.HitObject.StartTime, timeRange, length); + UpdatePositions(obj.NestedHitObjects, direction, obj.HitObject.StartTime, timeRange, length); } } } - public void ComputePositions(IEnumerable hitObjects, ScrollingDirection direction, double currentTime, double timeRange, Vector2 length) + public void UpdatePositions(IEnumerable hitObjects, ScrollingDirection direction, double currentTime, double timeRange, Vector2 length) { var timelinePosition = positionAt(currentTime, timeRange); From de424648d27bd82d9d00f55a9da62b6d23d25af4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 20 Apr 2018 14:41:57 +0900 Subject: [PATCH 16/45] Update to .NET 4.7.1 Resolves #2368. --- .../RulesetTests__catch_.xml | 22 ++++++++ .../RulesetTests__mania_.xml | 22 ++++++++ .../runConfigurations/RulesetTests__osu__.xml | 22 ++++++++ .../RulesetTests__taiko_.xml | 22 ++++++++ ...__net461_.xml => VisualTests__net471_.xml} | 6 +-- .../{osu___net461_.xml => osu___net471_.xml} | 6 +-- .vscode/launch.json | 16 +++--- .vscode/tasks.json | 6 +-- README.md | 2 +- appveyor.yml | 52 +++++++++---------- appveyor_deploy.yml | 6 +-- osu-framework | 2 +- osu.Desktop.Deploy/.vscode/launch.json | 4 +- osu.Desktop.Deploy/osu.Desktop.Deploy.csproj | 4 +- osu.Desktop/osu.Desktop.csproj | 6 +-- .../.vscode/launch.json | 8 +-- .../.vscode/tasks.json | 6 +-- .../osu.Game.Rulesets.Catch.Tests.csproj | 2 +- .../.vscode/launch.json | 8 +-- .../.vscode/tasks.json | 6 +-- .../osu.Game.Rulesets.Mania.Tests.csproj | 2 +- .../.vscode/launch.json | 8 +-- .../.vscode/tasks.json | 6 +-- .../osu.Game.Rulesets.Osu.Tests.csproj | 2 +- .../.vscode/launch.json | 8 +-- .../.vscode/tasks.json | 6 +-- .../osu.Game.Rulesets.Taiko.Tests.csproj | 2 +- .../Beatmaps/Formats/OsuJsonDecoderTest.cs | 17 ++++-- osu.Game.Tests/osu.Game.Tests.csproj | 2 +- 29 files changed, 188 insertions(+), 93 deletions(-) create mode 100644 .idea/.idea.osu/.idea/runConfigurations/RulesetTests__catch_.xml create mode 100644 .idea/.idea.osu/.idea/runConfigurations/RulesetTests__mania_.xml create mode 100644 .idea/.idea.osu/.idea/runConfigurations/RulesetTests__osu__.xml create mode 100644 .idea/.idea.osu/.idea/runConfigurations/RulesetTests__taiko_.xml rename .idea/.idea.osu/.idea/runConfigurations/{VisualTests__net461_.xml => VisualTests__net471_.xml} (82%) rename .idea/.idea.osu/.idea/runConfigurations/{osu___net461_.xml => osu___net471_.xml} (83%) diff --git a/.idea/.idea.osu/.idea/runConfigurations/RulesetTests__catch_.xml b/.idea/.idea.osu/.idea/runConfigurations/RulesetTests__catch_.xml new file mode 100644 index 0000000000..f8003ae339 --- /dev/null +++ b/.idea/.idea.osu/.idea/runConfigurations/RulesetTests__catch_.xml @@ -0,0 +1,22 @@ + + + + \ No newline at end of file diff --git a/.idea/.idea.osu/.idea/runConfigurations/RulesetTests__mania_.xml b/.idea/.idea.osu/.idea/runConfigurations/RulesetTests__mania_.xml new file mode 100644 index 0000000000..417ab1529b --- /dev/null +++ b/.idea/.idea.osu/.idea/runConfigurations/RulesetTests__mania_.xml @@ -0,0 +1,22 @@ + + + + \ No newline at end of file diff --git a/.idea/.idea.osu/.idea/runConfigurations/RulesetTests__osu__.xml b/.idea/.idea.osu/.idea/runConfigurations/RulesetTests__osu__.xml new file mode 100644 index 0000000000..df93422f50 --- /dev/null +++ b/.idea/.idea.osu/.idea/runConfigurations/RulesetTests__osu__.xml @@ -0,0 +1,22 @@ + + + + \ No newline at end of file diff --git a/.idea/.idea.osu/.idea/runConfigurations/RulesetTests__taiko_.xml b/.idea/.idea.osu/.idea/runConfigurations/RulesetTests__taiko_.xml new file mode 100644 index 0000000000..bb913778cc --- /dev/null +++ b/.idea/.idea.osu/.idea/runConfigurations/RulesetTests__taiko_.xml @@ -0,0 +1,22 @@ + + + + \ No newline at end of file diff --git a/.idea/.idea.osu/.idea/runConfigurations/VisualTests__net461_.xml b/.idea/.idea.osu/.idea/runConfigurations/VisualTests__net471_.xml similarity index 82% rename from .idea/.idea.osu/.idea/runConfigurations/VisualTests__net461_.xml rename to .idea/.idea.osu/.idea/runConfigurations/VisualTests__net471_.xml index cf4bccfe60..20a15f985f 100644 --- a/.idea/.idea.osu/.idea/runConfigurations/VisualTests__net461_.xml +++ b/.idea/.idea.osu/.idea/runConfigurations/VisualTests__net471_.xml @@ -1,6 +1,6 @@ - - \ No newline at end of file diff --git a/.idea/.idea.osu/.idea/runConfigurations/osu___net461_.xml b/.idea/.idea.osu/.idea/runConfigurations/osu___net471_.xml similarity index 83% rename from .idea/.idea.osu/.idea/runConfigurations/osu___net461_.xml rename to .idea/.idea.osu/.idea/runConfigurations/osu___net471_.xml index 971868a81b..7196e486d2 100644 --- a/.idea/.idea.osu/.idea/runConfigurations/osu___net461_.xml +++ b/.idea/.idea.osu/.idea/runConfigurations/osu___net471_.xml @@ -1,6 +1,6 @@ - - \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json index 624e584f10..df5b11f63a 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -2,13 +2,13 @@ "version": "0.2.0", "configurations": [ { - "name": "VisualTests (Debug, net461)", + "name": "VisualTests (Debug, net471)", "windows": { "type": "clr" }, "type": "mono", "request": "launch", - "program": "${workspaceRoot}/osu.Game.Tests/bin/Debug/net461/osu.Game.Tests.exe", + "program": "${workspaceRoot}/osu.Game.Tests/bin/Debug/net471/osu.Game.Tests.exe", "cwd": "${workspaceRoot}", "preLaunchTask": "Build (Debug, msbuild)", "runtimeExecutable": null, @@ -16,13 +16,13 @@ "console": "internalConsole" }, { - "name": "VisualTests (Release, net461)", + "name": "VisualTests (Release, net471)", "windows": { "type": "clr" }, "type": "mono", "request": "launch", - "program": "${workspaceRoot}/osu.Game.Tests/bin/Debug/net461/osu.Game.Tests.exe", + "program": "${workspaceRoot}/osu.Game.Tests/bin/Debug/net471/osu.Game.Tests.exe", "cwd": "${workspaceRoot}", "preLaunchTask": "Build (Release, msbuild)", "runtimeExecutable": null, @@ -30,13 +30,13 @@ "console": "internalConsole" }, { - "name": "osu! (Debug, net461)", + "name": "osu! (Debug, net471)", "windows": { "type": "clr" }, "type": "mono", "request": "launch", - "program": "${workspaceRoot}/osu.Desktop/bin/Debug/net461/osu!.exe", + "program": "${workspaceRoot}/osu.Desktop/bin/Debug/net471/osu!.exe", "cwd": "${workspaceRoot}", "preLaunchTask": "Build (Debug, msbuild)", "runtimeExecutable": null, @@ -44,13 +44,13 @@ "console": "internalConsole" }, { - "name": "osu! (Release, net461)", + "name": "osu! (Release, net471)", "windows": { "type": "clr" }, "type": "mono", "request": "launch", - "program": "${workspaceRoot}/osu.Desktop/bin/Release/net461/osu!.exe", + "program": "${workspaceRoot}/osu.Desktop/bin/Release/net471/osu!.exe", "cwd": "${workspaceRoot}", "preLaunchTask": "Build (Release, msbuild)", "runtimeExecutable": null, diff --git a/.vscode/tasks.json b/.vscode/tasks.json index b1d2c6b57d..7144a584f3 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -8,7 +8,7 @@ "type": "shell", "command": "msbuild", "args": [ - "/p:TargetFramework=net461", + "/p:TargetFramework=net471", "/p:GenerateFullPaths=true", "/m", "/verbosity:m" @@ -22,7 +22,7 @@ "command": "msbuild", "args": [ "/p:Configuration=Release", - "/p:TargetFramework=net461", + "/p:TargetFramework=net471", "/p:GenerateFullPaths=true", "/m", "/verbosity:m" @@ -64,7 +64,7 @@ "problemMatcher": "$msCompile" }, { - "label": "Restore (net461)", + "label": "Restore (net471)", "type": "shell", "command": "nuget", "args": [ diff --git a/README.md b/README.md index 47df86f57e..9d19f16ebd 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ This is still heavily under development and is not intended for end-user use. Th # Requirements -- A desktop platform that can compile .NET 4.6.1. We recommend using [Visual Studio Community Edition](https://www.visualstudio.com/) (Windows), [Visual Studio for Mac](https://www.visualstudio.com/vs/visual-studio-mac/) (macOS) or [MonoDevelop](http://www.monodevelop.com/download/) (Linux), all of which are free. [Visual Studio Code](https://code.visualstudio.com/) may also be used but requires further setup steps which are not covered here. +- A desktop platform that can compile .NET 4.7.1. We recommend using [Visual Studio Community Edition](https://www.visualstudio.com/) (Windows), [Visual Studio for Mac](https://www.visualstudio.com/vs/visual-studio-mac/) (macOS) or [MonoDevelop](http://www.monodevelop.com/download/) (Linux), all of which are free. [Visual Studio Code](https://code.visualstudio.com/) may also be used but requires further setup steps which are not covered here. # Getting Started - Clone the repository including submodules (`git clone --recurse-submodules https://github.com/ppy/osu`) diff --git a/appveyor.yml b/appveyor.yml index 4c4b70827f..c25c2a659e 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,27 +1,27 @@ -# 2017-09-14 -clone_depth: 1 -version: '{branch}-{build}' -image: Visual Studio 2017 -configuration: Debug -cache: - - C:\ProgramData\chocolatey\bin -> appveyor.yml - - C:\ProgramData\chocolatey\lib -> appveyor.yml - - inspectcode -> appveyor.yml - - packages -> **\packages.config -install: - - cmd: git submodule update --init --recursive --depth=5 - - cmd: choco install resharper-clt -y - - cmd: choco install nvika -y - - cmd: appveyor DownloadFile https://github.com/peppy/CodeFileSanity/releases/download/v0.2.4/CodeFileSanity.exe -before_build: - - cmd: CodeFileSanity.exe - - cmd: nuget restore -verbosity quiet -environment: - TargetFramework: net461 -build: - project: osu.sln - parallel: true - verbosity: minimal -after_build: - - cmd: inspectcode --o="inspectcodereport.xml" --projects:osu.Game* --caches-home="inspectcode" osu.sln > NUL +# 2017-09-14 +clone_depth: 1 +version: '{branch}-{build}' +image: Visual Studio 2017 +configuration: Debug +cache: + - C:\ProgramData\chocolatey\bin -> appveyor.yml + - C:\ProgramData\chocolatey\lib -> appveyor.yml + - inspectcode -> appveyor.yml + - packages -> **\packages.config +install: + - cmd: git submodule update --init --recursive --depth=5 + - cmd: choco install resharper-clt -y + - cmd: choco install nvika -y + - cmd: appveyor DownloadFile https://github.com/peppy/CodeFileSanity/releases/download/v0.2.4/CodeFileSanity.exe +before_build: + - cmd: CodeFileSanity.exe + - cmd: nuget restore -verbosity quiet +environment: + TargetFramework: net471 +build: + project: osu.sln + parallel: true + verbosity: minimal +after_build: + - cmd: inspectcode --o="inspectcodereport.xml" --projects:osu.Game* --caches-home="inspectcode" osu.sln > NUL - cmd: NVika parsereport "inspectcodereport.xml" --treatwarningsaserrors \ No newline at end of file diff --git a/appveyor_deploy.yml b/appveyor_deploy.yml index cd241eb88f..dc43a9cb13 100644 --- a/appveyor_deploy.yml +++ b/appveyor_deploy.yml @@ -17,11 +17,11 @@ after_build: - appveyor DownloadFile https://puu.sh/A6g5K/4d08705438.enc # signing certificate - cmd: appveyor-tools\secure-file -decrypt 4d08705438.enc -secret %decode_secret% -out %HOMEPATH%\deanherbert.pfx - appveyor DownloadFile https://puu.sh/A6g75/fdc6f19b04.enc # deploy configuration - - cmd: appveyor-tools\secure-file -decrypt fdc6f19b04.enc -secret %decode_secret% -out osu.Desktop.Deploy\bin\Debug\net461\osu.Desktop.Deploy.exe.config - - cd osu.Desktop.Deploy\bin\Debug\net461\ + - cmd: appveyor-tools\secure-file -decrypt fdc6f19b04.enc -secret %decode_secret% -out osu.Desktop.Deploy\bin\Debug\net471\osu.Desktop.Deploy.exe.config + - cd osu.Desktop.Deploy\bin\Debug\net471\ - osu.Desktop.Deploy.exe %code_signing_password% environment: - TargetFramework: net461 + TargetFramework: net471 decode_secret: secure: i67IC2xj6DjjxmA6Oj2jing3+MwzLkq6CbGsjfZ7rdY= code_signing_password: diff --git a/osu-framework b/osu-framework index 16e6a453db..a5e5b64a92 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit 16e6a453db9a8f4454238a2911eb5f1444b7ec2a +Subproject commit a5e5b64a9270df6704e7d78126e7b1541064f209 diff --git a/osu.Desktop.Deploy/.vscode/launch.json b/osu.Desktop.Deploy/.vscode/launch.json index 82cd6b4c13..8c35d211bd 100644 --- a/osu.Desktop.Deploy/.vscode/launch.json +++ b/osu.Desktop.Deploy/.vscode/launch.json @@ -7,7 +7,7 @@ "name": "Deploy (Debug)", "request": "launch", "type": "mono", - "program": "${workspaceRoot}/bin/Debug/net461/osu.Desktop.Deploy.exe", + "program": "${workspaceRoot}/bin/Debug/net471/osu.Desktop.Deploy.exe", "cwd": "${workspaceRoot}", "preLaunchTask": "Build (Debug)", "runtimeExecutable": null, @@ -18,7 +18,7 @@ "name": "Deploy (Release)", "request": "launch", "type": "clr", - "program": "${workspaceRoot}/bin/Release/net461/osu.Desktop.Deploy.exe", + "program": "${workspaceRoot}/bin/Release/net471/osu.Desktop.Deploy.exe", "cwd": "${workspaceRoot}", "preLaunchTask": "Build (Release)", "runtimeExecutable": null, diff --git a/osu.Desktop.Deploy/osu.Desktop.Deploy.csproj b/osu.Desktop.Deploy/osu.Desktop.Deploy.csproj index 6b7509a381..d3f6a4aed5 100644 --- a/osu.Desktop.Deploy/osu.Desktop.Deploy.csproj +++ b/osu.Desktop.Deploy/osu.Desktop.Deploy.csproj @@ -1,7 +1,7 @@ - net461 + net471 Exe AnyCPU true @@ -12,7 +12,7 @@ - + \ No newline at end of file diff --git a/osu.Desktop/osu.Desktop.csproj b/osu.Desktop/osu.Desktop.csproj index 2ad7b67842..27bc3f7597 100644 --- a/osu.Desktop/osu.Desktop.csproj +++ b/osu.Desktop/osu.Desktop.csproj @@ -1,7 +1,7 @@  - net461;netcoreapp2.0 + net471;netcoreapp2.0 WinExe AnyCPU true @@ -14,7 +14,7 @@ 0.0.0.0 - $(DefineConstants);NET_FRAMEWORK + $(DefineConstants);NET_FRAMEWORK osu.Desktop.Program @@ -31,7 +31,7 @@ - + diff --git a/osu.Game.Rulesets.Catch.Tests/.vscode/launch.json b/osu.Game.Rulesets.Catch.Tests/.vscode/launch.json index 5098b78a42..eb80f4474c 100644 --- a/osu.Game.Rulesets.Catch.Tests/.vscode/launch.json +++ b/osu.Game.Rulesets.Catch.Tests/.vscode/launch.json @@ -2,13 +2,13 @@ "version": "0.2.0", "configurations": [ { - "name": "VisualTests (Debug, net461)", + "name": "VisualTests (Debug, net471)", "windows": { "type": "clr" }, "type": "mono", "request": "launch", - "program": "${workspaceRoot}/bin/Debug/net461/osu.Game.Rulesets.Catch.Tests.exe", + "program": "${workspaceRoot}/bin/Debug/net471/osu.Game.Rulesets.Catch.Tests.exe", "cwd": "${workspaceRoot}", "preLaunchTask": "Build (Debug, msbuild)", "runtimeExecutable": null, @@ -16,13 +16,13 @@ "console": "internalConsole" }, { - "name": "VisualTests (Release, net461)", + "name": "VisualTests (Release, net471)", "windows": { "type": "clr" }, "type": "mono", "request": "launch", - "program": "${workspaceRoot}/bin/Debug/net461/osu.Game.Rulesets.Catch.Tests.exe", + "program": "${workspaceRoot}/bin/Debug/net471/osu.Game.Rulesets.Catch.Tests.exe", "cwd": "${workspaceRoot}", "preLaunchTask": "Build (Release, msbuild)", "runtimeExecutable": null, diff --git a/osu.Game.Rulesets.Catch.Tests/.vscode/tasks.json b/osu.Game.Rulesets.Catch.Tests/.vscode/tasks.json index d21bb8a69a..41ae88f425 100644 --- a/osu.Game.Rulesets.Catch.Tests/.vscode/tasks.json +++ b/osu.Game.Rulesets.Catch.Tests/.vscode/tasks.json @@ -9,7 +9,7 @@ "command": "msbuild", "args": [ "osu.Game.Rulesets.Catch.Tests.csproj", - "/p:TargetFramework=net461", + "/p:TargetFramework=net471", "/p:GenerateFullPaths=true", "/m", "/verbosity:m" @@ -24,7 +24,7 @@ "args": [ "osu.Game.Rulesets.Catch.Tests.csproj", "/p:Configuration=Release", - "/p:TargetFramework=net461", + "/p:TargetFramework=net471", "/p:GenerateFullPaths=true", "/m", "/verbosity:m" @@ -66,7 +66,7 @@ "problemMatcher": "$msCompile" }, { - "label": "Restore (net461)", + "label": "Restore (net471)", "type": "shell", "command": "nuget", "args": [ diff --git a/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj b/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj index 7a4c7b3f1c..3797edde61 100644 --- a/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj +++ b/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj @@ -2,7 +2,7 @@ WinExe - netcoreapp2.0;net461 + netcoreapp2.0;net471 diff --git a/osu.Game.Rulesets.Mania.Tests/.vscode/launch.json b/osu.Game.Rulesets.Mania.Tests/.vscode/launch.json index c71178059b..fceb403f30 100644 --- a/osu.Game.Rulesets.Mania.Tests/.vscode/launch.json +++ b/osu.Game.Rulesets.Mania.Tests/.vscode/launch.json @@ -2,13 +2,13 @@ "version": "0.2.0", "configurations": [ { - "name": "VisualTests (Debug, net461)", + "name": "VisualTests (Debug, net471)", "windows": { "type": "clr" }, "type": "mono", "request": "launch", - "program": "${workspaceRoot}/bin/Debug/net461/osu.Game.Rulesets.Mania.Tests.exe", + "program": "${workspaceRoot}/bin/Debug/net471/osu.Game.Rulesets.Mania.Tests.exe", "cwd": "${workspaceRoot}", "preLaunchTask": "Build (Debug, msbuild)", "runtimeExecutable": null, @@ -16,13 +16,13 @@ "console": "internalConsole" }, { - "name": "VisualTests (Release, net461)", + "name": "VisualTests (Release, net471)", "windows": { "type": "clr" }, "type": "mono", "request": "launch", - "program": "${workspaceRoot}/bin/Debug/net461/osu.Game.Rulesets.Mania.Tests.exe", + "program": "${workspaceRoot}/bin/Debug/net471/osu.Game.Rulesets.Mania.Tests.exe", "cwd": "${workspaceRoot}", "preLaunchTask": "Build (Release, msbuild)", "runtimeExecutable": null, diff --git a/osu.Game.Rulesets.Mania.Tests/.vscode/tasks.json b/osu.Game.Rulesets.Mania.Tests/.vscode/tasks.json index 781e89598f..b04b068b0d 100644 --- a/osu.Game.Rulesets.Mania.Tests/.vscode/tasks.json +++ b/osu.Game.Rulesets.Mania.Tests/.vscode/tasks.json @@ -9,7 +9,7 @@ "command": "msbuild", "args": [ "osu.Game.Rulesets.Mania.Tests.csproj", - "/p:TargetFramework=net461", + "/p:TargetFramework=net471", "/p:GenerateFullPaths=true", "/m", "/verbosity:m" @@ -24,7 +24,7 @@ "args": [ "osu.Game.Rulesets.Mania.Tests.csproj", "/p:Configuration=Release", - "/p:TargetFramework=net461", + "/p:TargetFramework=net471", "/p:GenerateFullPaths=true", "/m", "/verbosity:m" @@ -66,7 +66,7 @@ "problemMatcher": "$msCompile" }, { - "label": "Restore (net461)", + "label": "Restore (net471)", "type": "shell", "command": "nuget", "args": [ diff --git a/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj b/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj index 02040fd23f..e90155568e 100644 --- a/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj +++ b/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj @@ -2,7 +2,7 @@ WinExe - netcoreapp2.0;net461 + netcoreapp2.0;net471 diff --git a/osu.Game.Rulesets.Osu.Tests/.vscode/launch.json b/osu.Game.Rulesets.Osu.Tests/.vscode/launch.json index 24431eb8de..714fb6db6f 100644 --- a/osu.Game.Rulesets.Osu.Tests/.vscode/launch.json +++ b/osu.Game.Rulesets.Osu.Tests/.vscode/launch.json @@ -2,13 +2,13 @@ "version": "0.2.0", "configurations": [ { - "name": "VisualTests (Debug, net461)", + "name": "VisualTests (Debug, net471)", "windows": { "type": "clr" }, "type": "mono", "request": "launch", - "program": "${workspaceRoot}/bin/Debug/net461/osu.Game.Rulesets.Osu.Tests.exe", + "program": "${workspaceRoot}/bin/Debug/net471/osu.Game.Rulesets.Osu.Tests.exe", "cwd": "${workspaceRoot}", "preLaunchTask": "Build (Debug, msbuild)", "runtimeExecutable": null, @@ -16,13 +16,13 @@ "console": "internalConsole" }, { - "name": "VisualTests (Release, net461)", + "name": "VisualTests (Release, net471)", "windows": { "type": "clr" }, "type": "mono", "request": "launch", - "program": "${workspaceRoot}/bin/Debug/net461/osu.Game.Rulesets.Osu.Tests.exe", + "program": "${workspaceRoot}/bin/Debug/net471/osu.Game.Rulesets.Osu.Tests.exe", "cwd": "${workspaceRoot}", "preLaunchTask": "Build (Release, msbuild)", "runtimeExecutable": null, diff --git a/osu.Game.Rulesets.Osu.Tests/.vscode/tasks.json b/osu.Game.Rulesets.Osu.Tests/.vscode/tasks.json index 734e15353b..657fe07e1a 100644 --- a/osu.Game.Rulesets.Osu.Tests/.vscode/tasks.json +++ b/osu.Game.Rulesets.Osu.Tests/.vscode/tasks.json @@ -9,7 +9,7 @@ "command": "msbuild", "args": [ "osu.Game.Rulesets.Osu.Tests.csproj", - "/p:TargetFramework=net461", + "/p:TargetFramework=net471", "/p:GenerateFullPaths=true", "/m", "/verbosity:m" @@ -24,7 +24,7 @@ "args": [ "osu.Game.Rulesets.Osu.Tests.csproj", "/p:Configuration=Release", - "/p:TargetFramework=net461", + "/p:TargetFramework=net471", "/p:GenerateFullPaths=true", "/m", "/verbosity:m" @@ -66,7 +66,7 @@ "problemMatcher": "$msCompile" }, { - "label": "Restore (net461)", + "label": "Restore (net471)", "type": "shell", "command": "nuget", "args": [ diff --git a/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj b/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj index 49c5f15713..1695ceacee 100644 --- a/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj +++ b/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj @@ -2,7 +2,7 @@ WinExe - netcoreapp2.0;net461 + netcoreapp2.0;net471 diff --git a/osu.Game.Rulesets.Taiko.Tests/.vscode/launch.json b/osu.Game.Rulesets.Taiko.Tests/.vscode/launch.json index caa90c32ce..e1df54e99b 100644 --- a/osu.Game.Rulesets.Taiko.Tests/.vscode/launch.json +++ b/osu.Game.Rulesets.Taiko.Tests/.vscode/launch.json @@ -2,13 +2,13 @@ "version": "0.2.0", "configurations": [ { - "name": "VisualTests (Debug, net461)", + "name": "VisualTests (Debug, net471)", "windows": { "type": "clr" }, "type": "mono", "request": "launch", - "program": "${workspaceRoot}/bin/Debug/net461/osu.Game.Rulesets.Taiko.Tests.exe", + "program": "${workspaceRoot}/bin/Debug/net471/osu.Game.Rulesets.Taiko.Tests.exe", "cwd": "${workspaceRoot}", "preLaunchTask": "Build (Debug, msbuild)", "runtimeExecutable": null, @@ -16,13 +16,13 @@ "console": "internalConsole" }, { - "name": "VisualTests (Release, net461)", + "name": "VisualTests (Release, net471)", "windows": { "type": "clr" }, "type": "mono", "request": "launch", - "program": "${workspaceRoot}/bin/Debug/net461/osu.Game.Rulesets.Taiko.Tests.exe", + "program": "${workspaceRoot}/bin/Debug/net471/osu.Game.Rulesets.Taiko.Tests.exe", "cwd": "${workspaceRoot}", "preLaunchTask": "Build (Release, msbuild)", "runtimeExecutable": null, diff --git a/osu.Game.Rulesets.Taiko.Tests/.vscode/tasks.json b/osu.Game.Rulesets.Taiko.Tests/.vscode/tasks.json index 13044e1ccb..8bdbcd8e8e 100644 --- a/osu.Game.Rulesets.Taiko.Tests/.vscode/tasks.json +++ b/osu.Game.Rulesets.Taiko.Tests/.vscode/tasks.json @@ -9,7 +9,7 @@ "command": "msbuild", "args": [ "osu.Game.Rulesets.Taiko.Tests.csproj", - "/p:TargetFramework=net461", + "/p:TargetFramework=net471", "/p:GenerateFullPaths=true", "/m", "/verbosity:m" @@ -24,7 +24,7 @@ "args": [ "osu.Game.Rulesets.Taiko.Tests.csproj", "/p:Configuration=Release", - "/p:TargetFramework=net461", + "/p:TargetFramework=net471", "/p:GenerateFullPaths=true", "/m", "/verbosity:m" @@ -66,7 +66,7 @@ "problemMatcher": "$msCompile" }, { - "label": "Restore (net461)", + "label": "Restore (net471)", "type": "shell", "command": "nuget", "args": [ diff --git a/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj b/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj index ccd69c574d..1221584a2b 100644 --- a/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj +++ b/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj @@ -2,7 +2,7 @@ WinExe - netcoreapp2.0;net461 + netcoreapp2.0;net471 diff --git a/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs index 9c9589f398..6e0cf6be2e 100644 --- a/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs @@ -116,8 +116,8 @@ namespace osu.Game.Tests.Beatmaps.Formats // [TestCase(with_sb)] public void TestParity(string beatmap) { - var beatmaps = decode(beatmap); - beatmaps.jsonDecoded.ShouldDeepEqual(beatmaps.legacyDecoded); + var legacy = decode(beatmap, out Beatmap json); + json.ShouldDeepEqual(legacy); } /// @@ -126,15 +126,20 @@ namespace osu.Game.Tests.Beatmaps.Formats /// /// The .osu file to decode. /// The after being decoded by an . - private Beatmap decodeAsJson(string filename) => decode(filename).jsonDecoded; + private Beatmap decodeAsJson(string filename) + { + decode(filename, out Beatmap jsonDecoded); + return jsonDecoded; + } /// /// Reads a .osu file first with a , serializes the resulting to JSON /// and then deserializes the result back into a through an . /// /// The .osu file to decode. + /// The after being decoded by an . /// The after being decoded by an . - private (Beatmap legacyDecoded, Beatmap jsonDecoded) decode(string filename) + private Beatmap decode(string filename, out Beatmap jsonDecoded) { using (var stream = Resource.OpenResource(filename)) using (var sr = new StreamReader(stream)) @@ -149,7 +154,9 @@ namespace osu.Game.Tests.Beatmaps.Formats sw.Flush(); ms.Position = 0; - return (legacyDecoded, new JsonBeatmapDecoder().Decode(sr2)); + + jsonDecoded = new JsonBeatmapDecoder().Decode(sr2); + return legacyDecoded; } } } diff --git a/osu.Game.Tests/osu.Game.Tests.csproj b/osu.Game.Tests/osu.Game.Tests.csproj index 2646e953cf..057c2c2de1 100644 --- a/osu.Game.Tests/osu.Game.Tests.csproj +++ b/osu.Game.Tests/osu.Game.Tests.csproj @@ -2,7 +2,7 @@ WinExe - netcoreapp2.0;net461 + netcoreapp2.0;net471 From 0b993561d807a74969e5f76df9afddb91d4e0391 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 20 Apr 2018 16:05:34 +0900 Subject: [PATCH 17/45] Fix BadgeContainer being unsable to handle null badges This fixes a failing test (hidden becaues the test wasn't being run). - [ ] Merge osu-framework#1530 first. --- .../Overlays/Profile/Header/BadgeContainer.cs | 20 ++++++++----------- 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/osu.Game/Overlays/Profile/Header/BadgeContainer.cs b/osu.Game/Overlays/Profile/Header/BadgeContainer.cs index 291db45e97..36a9a9b01a 100644 --- a/osu.Game/Overlays/Profile/Header/BadgeContainer.cs +++ b/osu.Game/Overlays/Profile/Header/BadgeContainer.cs @@ -92,22 +92,18 @@ namespace osu.Game.Overlays.Profile.Header public void ShowBadges(Badge[] badges) { - switch (badges.Length) + if (badges == null || badges.Length == 0) { - case 0: - Hide(); - return; - case 1: - badgeCountText.Hide(); - break; - default: - badgeCountText.Show(); - badgeCountText.Text = $"{badges.Length} badges"; - break; + Hide(); + return; } - Show(); badgeCount = badges.Length; + + badgeCountText.FadeTo(badgeCount > 1 ? 1 : 0); + badgeCountText.Text = $"{badges.Length} badges"; + + Show(); visibleBadge = 0; badgeFlowContainer.Clear(); From 8bf25542cbdff7e9aed769ed7ded18f1991fde15 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 20 Apr 2018 17:30:27 +0900 Subject: [PATCH 18/45] Add PlayerLoader TestCase and fix dummy beatmap load procedure --- osu.Game.Tests/Visual/TestCasePlayerLoader.cs | 24 +++++++++++++++++++ osu.Game/Screens/Play/Player.cs | 16 ++++++------- osu.Game/Screens/Play/PlayerLoader.cs | 5 +++- 3 files changed, 35 insertions(+), 10 deletions(-) create mode 100644 osu.Game.Tests/Visual/TestCasePlayerLoader.cs diff --git a/osu.Game.Tests/Visual/TestCasePlayerLoader.cs b/osu.Game.Tests/Visual/TestCasePlayerLoader.cs new file mode 100644 index 0000000000..1e7618232d --- /dev/null +++ b/osu.Game.Tests/Visual/TestCasePlayerLoader.cs @@ -0,0 +1,24 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Allocation; +using osu.Game.Beatmaps; +using osu.Game.Screens.Play; + +namespace osu.Game.Tests.Visual +{ + public class TestCasePlayerLoader : OsuTestCase + { + [BackgroundDependencyLoader] + private void load(OsuGameBase game) + { + AddStep("load dummy beatmap", () => Add(new PlayerLoader(new Player + { + InitialBeatmap = new DummyWorkingBeatmap(game), + AllowPause = false, + AllowLeadIn = false, + AllowResults = false, + }))); + } + } +} diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index ec7c1a1009..83958b2912 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -77,7 +77,7 @@ namespace osu.Game.Screens.Play private DrawableStoryboard storyboard; private Container storyboardContainer; - private bool loadedSuccessfully => RulesetContainer?.Objects.Any() == true; + public bool LoadedBeatmapSuccessfully => RulesetContainer?.Objects.Any() == true; [BackgroundDependencyLoader] private void load(AudioManager audio, APIAccess api, OsuConfigManager config) @@ -86,10 +86,7 @@ namespace osu.Game.Screens.Play WorkingBeatmap working = Beatmap.Value; if (working is DummyWorkingBeatmap) - { - Exit(); return; - } sampleRestart = audio.Sample.Get(@"Gameplay/restart"); @@ -122,14 +119,15 @@ namespace osu.Game.Screens.Play } if (!RulesetContainer.Objects.Any()) - throw new InvalidOperationException("Beatmap contains no hit objects!"); + { + Logger.Error(new InvalidOperationException("Beatmap contains no hit objects!"), "Beatmap contains no hit objects!"); + return; + } } catch (Exception e) { Logger.Error(e, "Could not load beatmap sucessfully!"); - //couldn't load, hard abort! - Exit(); return; } @@ -293,7 +291,7 @@ namespace osu.Game.Screens.Play { base.OnEntering(last); - if (!loadedSuccessfully) + if (!LoadedBeatmapSuccessfully) return; Content.Alpha = 0; @@ -343,7 +341,7 @@ namespace osu.Game.Screens.Play return base.OnExiting(next); } - if (loadedSuccessfully) + if (LoadedBeatmapSuccessfully) pauseContainer?.Pause(); return true; diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index c31c64a95d..56fbd7b6e7 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -163,7 +163,10 @@ namespace osu.Game.Screens.Play //Note that this may change if the player we load requested a re-run. ValidForResume = false; - Push(player); + if (player.LoadedBeatmapSuccessfully) + Push(player); + else + Exit(); }); }, 500); } From 0dce7a5b614b49d14cb2fca6995da8ebf5012292 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 20 Apr 2018 18:19:17 +0900 Subject: [PATCH 19/45] Update framework + fix CI errors --- osu-framework | 2 +- osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs | 2 +- .../Screens/Edit/Screens/Compose/Layers/HitObjectMaskLayer.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu-framework b/osu-framework index 02d7a0fa47..f1751c27ff 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit 02d7a0fa4798d197cd08570ee48951edbb7c7860 +Subproject commit f1751c27ffe2c5febece74129368596b5ad3a4e2 diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs index f9d21ea5bb..10539f85a2 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs @@ -83,7 +83,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables Anchor = Anchor.Centre, Origin = Anchor.Centre, RelativeSizeAxes = Axes.Y, - Children = new Drawable[] + Children = new[] { Background = new SpinnerBackground { diff --git a/osu.Game/Screens/Edit/Screens/Compose/Layers/HitObjectMaskLayer.cs b/osu.Game/Screens/Edit/Screens/Compose/Layers/HitObjectMaskLayer.cs index ede98d986a..b9a8e9914a 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Layers/HitObjectMaskLayer.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Layers/HitObjectMaskLayer.cs @@ -46,7 +46,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers var dragLayer = new DragLayer(maskContainer.Select); dragLayer.DragEnd += () => maskSelection.UpdateVisibility(); - InternalChildren = new Drawable[] + InternalChildren = new[] { dragLayer, maskSelection, From b16e25c3e98b1d4cea1f88a532578cc36debf79c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 20 Apr 2018 18:32:24 +0900 Subject: [PATCH 20/45] Add error handling on a per-line level in LegacyDecoder Resolves #2306. --- osu.Game/Beatmaps/Formats/Decoder.cs | 2 +- osu.Game/Beatmaps/Formats/JsonBeatmapDecoder.cs | 8 ++++---- osu.Game/Beatmaps/Formats/LegacyDecoder.cs | 13 ++++++++++--- osu.Game/Skinning/LegacySkinDecoder.cs | 8 ++++---- 4 files changed, 19 insertions(+), 12 deletions(-) diff --git a/osu.Game/Beatmaps/Formats/Decoder.cs b/osu.Game/Beatmaps/Formats/Decoder.cs index bcd11f1fc8..2927654f62 100644 --- a/osu.Game/Beatmaps/Formats/Decoder.cs +++ b/osu.Game/Beatmaps/Formats/Decoder.cs @@ -21,7 +21,7 @@ namespace osu.Game.Beatmaps.Formats return output; } - protected abstract void ParseStreamInto(StreamReader stream, TOutput beatmap); + protected abstract void ParseStreamInto(StreamReader stream, TOutput output); } public abstract class Decoder diff --git a/osu.Game/Beatmaps/Formats/JsonBeatmapDecoder.cs b/osu.Game/Beatmaps/Formats/JsonBeatmapDecoder.cs index e5574cd82e..fba89b8ac1 100644 --- a/osu.Game/Beatmaps/Formats/JsonBeatmapDecoder.cs +++ b/osu.Game/Beatmaps/Formats/JsonBeatmapDecoder.cs @@ -13,15 +13,15 @@ namespace osu.Game.Beatmaps.Formats AddDecoder("{", m => new JsonBeatmapDecoder()); } - protected override void ParseStreamInto(StreamReader stream, Beatmap beatmap) + protected override void ParseStreamInto(StreamReader stream, Beatmap output) { stream.BaseStream.Position = 0; stream.DiscardBufferedData(); - stream.ReadToEnd().DeserializeInto(beatmap); + stream.ReadToEnd().DeserializeInto(output); - foreach (var hitObject in beatmap.HitObjects) - hitObject.ApplyDefaults(beatmap.ControlPointInfo, beatmap.BeatmapInfo.BaseDifficulty); + foreach (var hitObject in output.HitObjects) + hitObject.ApplyDefaults(output.ControlPointInfo, output.BeatmapInfo.BaseDifficulty); } } } diff --git a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs index 06160a87e0..e77efd8508 100644 --- a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs @@ -19,7 +19,7 @@ namespace osu.Game.Beatmaps.Formats FormatVersion = version; } - protected override void ParseStreamInto(StreamReader stream, T beatmap) + protected override void ParseStreamInto(StreamReader stream, T output) { Section section = Section.None; @@ -33,14 +33,21 @@ namespace osu.Game.Beatmaps.Formats { if (!Enum.TryParse(line.Substring(1, line.Length - 2), out section)) { - Logger.Log($"Unknown section \"{line}\" in {beatmap}"); + Logger.Log($"Unknown section \"{line}\" in {output}"); section = Section.None; } continue; } - ParseLine(beatmap, section, line); + try + { + ParseLine(output, section, line); + } + catch (Exception e) + { + Logger.Error(e, $"Failed to process line \"{line}\" into {output}"); + } } } diff --git a/osu.Game/Skinning/LegacySkinDecoder.cs b/osu.Game/Skinning/LegacySkinDecoder.cs index 995518af0a..0ef54c7310 100644 --- a/osu.Game/Skinning/LegacySkinDecoder.cs +++ b/osu.Game/Skinning/LegacySkinDecoder.cs @@ -12,7 +12,7 @@ namespace osu.Game.Skinning { } - protected override void ParseLine(SkinConfiguration output, Section section, string line) + protected override void ParseLine(SkinConfiguration skin, Section section, string line) { switch (section) { @@ -22,17 +22,17 @@ namespace osu.Game.Skinning switch (pair.Key) { case @"Name": - output.SkinInfo.Name = pair.Value; + skin.SkinInfo.Name = pair.Value; break; case @"Author": - output.SkinInfo.Creator = pair.Value; + skin.SkinInfo.Creator = pair.Value; break; } break; } - base.ParseLine(output, section, line); + base.ParseLine(skin, section, line); } } } From 19e270062f464b2735f1bd59f7688e85bee99507 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 20 Apr 2018 19:12:47 +0900 Subject: [PATCH 21/45] Only build on correct branch --- appveyor.yml | 1 - appveyor_deploy.yml | 6 +++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 4c4b70827f..bf90cfd200 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,3 @@ -# 2017-09-14 clone_depth: 1 version: '{branch}-{build}' image: Visual Studio 2017 diff --git a/appveyor_deploy.yml b/appveyor_deploy.yml index cd241eb88f..422aaa55b6 100644 --- a/appveyor_deploy.yml +++ b/appveyor_deploy.yml @@ -1,4 +1,8 @@ -# 2017-09-14 +branches: + only: + - release +skip_tags: true +skip_branch_with_pr: true clone_depth: 1 version: '{branch}-{build}' image: Visual Studio 2017 From 1cad6f7a8ec1149da16277e02ea96c837a558c19 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 20 Apr 2018 19:17:11 +0900 Subject: [PATCH 22/45] Add support for updating AppVeyor version --- osu.Desktop.Deploy/Program.cs | 21 ++++++++++++++++++++ osu.Desktop.Deploy/osu.Desktop.Deploy.csproj | 3 ++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/osu.Desktop.Deploy/Program.cs b/osu.Desktop.Deploy/Program.cs index 8c460f03cf..16bbf90cd4 100644 --- a/osu.Desktop.Deploy/Program.cs +++ b/osu.Desktop.Deploy/Program.cs @@ -7,6 +7,7 @@ using System.Configuration; using System.Diagnostics; using System.IO; using System.Linq; +using System.Management.Automation; using Newtonsoft.Json; using osu.Framework.IO.Network; using FileWebRequest = osu.Framework.IO.Network.FileWebRequest; @@ -99,6 +100,7 @@ namespace osu.Desktop.Deploy write("Updating AssemblyInfo..."); updateCsprojVersion(version); + updateAppveyorVersion(version); write("Running build process..."); foreach (string targetName in TargetNames.Split(',')) @@ -404,6 +406,25 @@ namespace osu.Desktop.Deploy Console.WriteLine(); } + private static bool updateAppveyorVersion(string version) + { + try + { + using (PowerShell ps = PowerShell.Create()) + { + ps.AddScript($"Update-AppveyorBuild -Version \"{version}\""); + ps.Invoke(); + } + return true; + } + catch + { + // we don't have appveyor and don't care + } + + return false; + } + private static void write(string message, ConsoleColor col = ConsoleColor.Gray) { if (sw.ElapsedMilliseconds > 0) diff --git a/osu.Desktop.Deploy/osu.Desktop.Deploy.csproj b/osu.Desktop.Deploy/osu.Desktop.Deploy.csproj index 6b7509a381..96dcf2a0d0 100644 --- a/osu.Desktop.Deploy/osu.Desktop.Deploy.csproj +++ b/osu.Desktop.Deploy/osu.Desktop.Deploy.csproj @@ -1,4 +1,4 @@ - + net461 @@ -14,5 +14,6 @@ + \ No newline at end of file From 7dd07503b24f08bfca01f7daba28d8f8043414b4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 20 Apr 2018 21:08:41 +0900 Subject: [PATCH 23/45] Fix wrong targets on ruleset test configuration --- .../.idea/runConfigurations/RulesetTests__catch_.xml | 2 +- .../.idea/runConfigurations/RulesetTests__mania_.xml | 2 +- .../.idea.osu/.idea/runConfigurations/RulesetTests__osu__.xml | 4 ++-- .../.idea/runConfigurations/RulesetTests__taiko_.xml | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.idea/.idea.osu/.idea/runConfigurations/RulesetTests__catch_.xml b/.idea/.idea.osu/.idea/runConfigurations/RulesetTests__catch_.xml index f8003ae339..be69e92748 100644 --- a/.idea/.idea.osu/.idea/runConfigurations/RulesetTests__catch_.xml +++ b/.idea/.idea.osu/.idea/runConfigurations/RulesetTests__catch_.xml @@ -1,6 +1,6 @@ -