From 214154c5124a67670337cfed99b688420b81ac38 Mon Sep 17 00:00:00 2001 From: Aergwyn Date: Thu, 21 Dec 2017 20:23:10 +0100 Subject: [PATCH 001/101] hide unnecessary lines on empty BeatmapInfoWedge adding back deleted line ooops meh --- osu.Game/Screens/Select/BeatmapInfoWedge.cs | 34 +++++++++++---------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/osu.Game/Screens/Select/BeatmapInfoWedge.cs b/osu.Game/Screens/Select/BeatmapInfoWedge.cs index 3ef6ceeaeb..d18aebe43b 100644 --- a/osu.Game/Screens/Select/BeatmapInfoWedge.cs +++ b/osu.Game/Screens/Select/BeatmapInfoWedge.cs @@ -95,7 +95,7 @@ namespace osu.Game.Screens.Select List labels = new List(); - if (beatmap != null) + if (beatmap != null && !(working is DummyWorkingBeatmap)) { HitObject lastObject = beatmap.HitObjects.LastOrDefault(); double endTime = (lastObject as IHasEndTime)?.EndTime ?? lastObject?.StartTime ?? 0; @@ -200,21 +200,7 @@ namespace osu.Game.Screens.Select Margin = new MarginPadding { Top = 10 }, Direction = FillDirection.Horizontal, AutoSizeAxes = Axes.Both, - Children = new[] - { - new OsuSpriteText - { - Font = @"Exo2.0-Medium", - Text = "mapped by ", - TextSize = 15, - }, - new OsuSpriteText - { - Font = @"Exo2.0-Bold", - Text = metadata.Author.Username, - TextSize = 15, - }, - } + Children = working is DummyWorkingBeatmap ? Array.Empty() : getMapper(metadata) }, new FillFlowContainer { @@ -228,6 +214,22 @@ namespace osu.Game.Screens.Select }; } + private OsuSpriteText[] getMapper(BeatmapMetadata metadata) => new[] + { + new OsuSpriteText + { + Font = @"Exo2.0-Medium", + Text = "mapped by ", + TextSize = 15, + }, + new OsuSpriteText + { + Font = @"Exo2.0-Bold", + Text = metadata.Author.Username, + TextSize = 15, + } + }; + private string getBPMRange(Beatmap beatmap) { double bpmMax = beatmap.ControlPointInfo.BPMMaximum; From 07f55a2a606a7d8a12973b637aa7e875c692b105 Mon Sep 17 00:00:00 2001 From: Aergwyn Date: Fri, 22 Dec 2017 10:18:25 +0100 Subject: [PATCH 002/101] remove references to DummyWorkingBeatmap determine content by data that is present instead --- osu.Game/Screens/Select/BeatmapInfoWedge.cs | 106 +++++++++++--------- 1 file changed, 60 insertions(+), 46 deletions(-) diff --git a/osu.Game/Screens/Select/BeatmapInfoWedge.cs b/osu.Game/Screens/Select/BeatmapInfoWedge.cs index d18aebe43b..9b9a009ac0 100644 --- a/osu.Game/Screens/Select/BeatmapInfoWedge.cs +++ b/osu.Game/Screens/Select/BeatmapInfoWedge.cs @@ -89,34 +89,8 @@ namespace osu.Game.Screens.Select [BackgroundDependencyLoader] private void load() { - BeatmapInfo beatmapInfo = working.BeatmapInfo; - BeatmapMetadata metadata = beatmapInfo.Metadata ?? working.BeatmapSetInfo?.Metadata ?? new BeatmapMetadata(); - Beatmap beatmap = working.Beatmap; - - List labels = new List(); - - if (beatmap != null && !(working is DummyWorkingBeatmap)) - { - HitObject lastObject = beatmap.HitObjects.LastOrDefault(); - double endTime = (lastObject as IHasEndTime)?.EndTime ?? lastObject?.StartTime ?? 0; - - labels.Add(new InfoLabel(new BeatmapStatistic - { - Name = "Length", - Icon = FontAwesome.fa_clock_o, - Content = beatmap.HitObjects.Count == 0 ? "-" : TimeSpan.FromMilliseconds(endTime - beatmap.HitObjects.First().StartTime).ToString(@"m\:ss"), - })); - - labels.Add(new InfoLabel(new BeatmapStatistic - { - Name = "BPM", - Icon = FontAwesome.fa_circle, - Content = getBPMRange(beatmap), - })); - - //get statistics from the current ruleset. - labels.AddRange(beatmapInfo.Ruleset.CreateInstance().GetBeatmapStatistics(working).Select(s => new InfoLabel(s))); - } + var beatmapInfo = working.BeatmapInfo; + var metadata = beatmapInfo.Metadata ?? working.BeatmapSetInfo?.Metadata ?? new BeatmapMetadata(); PixelSnapping = true; CacheDrawnFrameBuffer = true; @@ -186,7 +160,7 @@ namespace osu.Game.Screens.Select new OsuSpriteText { Font = @"Exo2.0-MediumItalic", - Text = !string.IsNullOrEmpty(metadata.Source) ? metadata.Source + " — " + metadata.Title : metadata.Title, + Text = string.IsNullOrEmpty(metadata.Source) ? metadata.Title : metadata.Source + " — " + metadata.Title, TextSize = 28, }, new OsuSpriteText @@ -200,46 +174,86 @@ namespace osu.Game.Screens.Select Margin = new MarginPadding { Top = 10 }, Direction = FillDirection.Horizontal, AutoSizeAxes = Axes.Both, - Children = working is DummyWorkingBeatmap ? Array.Empty() : getMapper(metadata) + Children = getMapper(metadata) }, new FillFlowContainer { Margin = new MarginPadding { Top = 20 }, Spacing = new Vector2(20, 0), AutoSizeAxes = Axes.Both, - Children = labels - }, + Children = getInfoLabels() + } } - }, + } }; } - private OsuSpriteText[] getMapper(BeatmapMetadata metadata) => new[] + private InfoLabel[] getInfoLabels() { - new OsuSpriteText + var beatmap = working.Beatmap; + var info = working.BeatmapInfo; + + List labels = new List(); + + if (beatmap?.HitObjects?.Count > 0) { - Font = @"Exo2.0-Medium", - Text = "mapped by ", - TextSize = 15, - }, - new OsuSpriteText - { - Font = @"Exo2.0-Bold", - Text = metadata.Author.Username, - TextSize = 15, + HitObject lastObject = beatmap.HitObjects.LastOrDefault(); + double endTime = (lastObject as IHasEndTime)?.EndTime ?? lastObject?.StartTime ?? 0; + + labels.Add(new InfoLabel(new BeatmapStatistic + { + Name = "Length", + Icon = FontAwesome.fa_clock_o, + Content = beatmap.HitObjects.Count == 0 ? "-" : TimeSpan.FromMilliseconds(endTime - beatmap.HitObjects.First().StartTime).ToString(@"m\:ss"), + })); + + labels.Add(new InfoLabel(new BeatmapStatistic + { + Name = "BPM", + Icon = FontAwesome.fa_circle, + Content = getBPMRange(beatmap), + })); + + //get statistics from the current ruleset. + labels.AddRange(info.Ruleset.CreateInstance().GetBeatmapStatistics(working).Select(s => new InfoLabel(s))); } - }; + + return labels.ToArray(); + } private string getBPMRange(Beatmap beatmap) { double bpmMax = beatmap.ControlPointInfo.BPMMaximum; double bpmMin = beatmap.ControlPointInfo.BPMMinimum; - if (Precision.AlmostEquals(bpmMin, bpmMax)) return $"{bpmMin:0}"; + if (Precision.AlmostEquals(bpmMin, bpmMax)) + return $"{bpmMin:0}"; return $"{bpmMin:0}-{bpmMax:0} (mostly {beatmap.ControlPointInfo.BPMMode:0})"; } + private OsuSpriteText[] getMapper(BeatmapMetadata metadata) + { + if (string.IsNullOrEmpty(metadata.Author?.Username)) + return Array.Empty(); + + return new[] + { + new OsuSpriteText + { + Font = @"Exo2.0-Medium", + Text = "mapped by ", + TextSize = 15, + }, + new OsuSpriteText + { + Font = @"Exo2.0-Bold", + Text = metadata.Author.Username, + TextSize = 15, + } + }; + } + public class InfoLabel : Container, IHasTooltip { public string TooltipText { get; private set; } From ed827d5424fcadfa24e76a13cfbe1100916cfb00 Mon Sep 17 00:00:00 2001 From: Aergwyn Date: Fri, 22 Dec 2017 12:33:52 +0100 Subject: [PATCH 003/101] more visual tests for BeatmapInfoWedge also fix Author showing when not wanted --- .../Visual/TestCaseBeatmapInfoWedge.cs | 117 ++++++++++++++---- osu.Game/Beatmaps/DummyWorkingBeatmap.cs | 3 +- osu.Game/Screens/Select/BeatmapInfoWedge.cs | 25 ++-- 3 files changed, 109 insertions(+), 36 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCaseBeatmapInfoWedge.cs b/osu.Game.Tests/Visual/TestCaseBeatmapInfoWedge.cs index 0168cedc86..353f351a54 100644 --- a/osu.Game.Tests/Visual/TestCaseBeatmapInfoWedge.cs +++ b/osu.Game.Tests/Visual/TestCaseBeatmapInfoWedge.cs @@ -1,36 +1,48 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using System; +using System.Collections.Generic; +using System.Linq; using OpenTK; using osu.Framework.Allocation; using osu.Framework.Configuration; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Beatmaps; +using osu.Game.Graphics.Sprites; +using osu.Game.Rulesets; +using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.Osu; using osu.Game.Screens.Select; +using osu.Game.Tests.Beatmaps; namespace osu.Game.Tests.Visual { public class TestCaseBeatmapInfoWedge : OsuTestCase { - private BeatmapManager beatmaps; - private readonly Random random; - private readonly BeatmapInfoWedge infoWedge; + private TestBeatmapInfoWedge infoWedge; + private readonly List beatmaps = new List(); private readonly Bindable beatmap = new Bindable(); - public TestCaseBeatmapInfoWedge() + [BackgroundDependencyLoader] + private void load(OsuGameBase game, RulesetStore rulesets) { - random = new Random(0123); + beatmap.BindTo(game.Beatmap); - Add(infoWedge = new BeatmapInfoWedge + Add(infoWedge = new TestBeatmapInfoWedge { Size = new Vector2(0.5f, 245), RelativeSizeAxes = Axes.X, Margin = new MarginPadding { Top = 20, - }, + } + }); + + AddStep("hide", () => + { + infoWedge.State = Visibility.Hidden; + Content.FadeOut(100); }); AddStep("show", () => @@ -39,31 +51,88 @@ namespace osu.Game.Tests.Visual infoWedge.State = Visibility.Visible; infoWedge.UpdateBeatmap(beatmap); }); - AddStep("hide", () => + + foreach (var rulesetInfo in rulesets.AvailableRulesets) { - infoWedge.State = Visibility.Hidden; - Content.FadeOut(100); + var ruleset = rulesetInfo.CreateInstance(); + beatmaps.Add(createTestBeatmap(rulesetInfo)); + + var name = rulesetInfo.ShortName; + selectBeatmap(name); + + // TODO: check InfoLabels of other rulesets + switch (ruleset) + { + case OsuRuleset osu: + testOsuBeatmap(osu); + break; + } + } + + testNullBeatmap(); + } + + private void testOsuBeatmap(OsuRuleset ruleset) + { + AddAssert("check version", () => infoWedge.Info.VersionLabel.Text == $"{ruleset.ShortName}Version"); + AddAssert("check title", () => infoWedge.Info.TitleLabel.Text == $"{ruleset.ShortName}Source — {ruleset.ShortName}Title"); + AddAssert("check artist", () => infoWedge.Info.ArtistLabel.Text == $"{ruleset.ShortName}Artist"); + AddAssert("check author", () => infoWedge.Info.MapperContainer.Children.OfType().Any(s => s.Text == $"{ruleset.ShortName}Author")); + // TODO: check InfoLabels + } + + private void testNullBeatmap() + { + selectNullBeatmap(); + AddAssert("check empty version", () => string.IsNullOrEmpty(infoWedge.Info.VersionLabel.Text)); + AddAssert("check default title", () => infoWedge.Info.TitleLabel.Text == beatmap.Default.BeatmapInfo.Metadata.Title); + AddAssert("check default artist", () => infoWedge.Info.ArtistLabel.Text == beatmap.Default.BeatmapInfo.Metadata.Artist); + AddAssert("check empty author", () => !infoWedge.Info.MapperContainer.Children.Any()); + AddAssert("check empty infos", () => !infoWedge.Info.InfoLabelContainer.Children.Any()); + } + + private void selectBeatmap(string name) + { + AddStep($"select {name} beatmap", () => + { + beatmap.Value = new TestWorkingBeatmap(beatmaps.First(b => b.BeatmapInfo.Ruleset.ShortName == name)); + infoWedge.UpdateBeatmap(beatmap); }); - AddStep("random beatmap", randomBeatmap); - AddStep("null beatmap", () => infoWedge.UpdateBeatmap(beatmap.Default)); } - [BackgroundDependencyLoader] - private void load(OsuGameBase game, BeatmapManager beatmaps) + private void selectNullBeatmap() { - this.beatmaps = beatmaps; - beatmap.BindTo(game.Beatmap); + AddStep("select null beatmap", () => + { + beatmap.Value = beatmap.Default; + infoWedge.UpdateBeatmap(beatmap); + }); } - private void randomBeatmap() + private Beatmap createTestBeatmap(RulesetInfo ruleset) { - var sets = beatmaps.GetAllUsableBeatmapSets(); - if (sets.Count == 0) - return; + return new Beatmap + { + BeatmapInfo = new BeatmapInfo + { + Metadata = new BeatmapMetadata + { + AuthorString = $"{ruleset.ShortName}Author", + Artist = $"{ruleset.ShortName}Artist", + Source = $"{ruleset.ShortName}Source", + Title = $"{ruleset.ShortName}Title" + }, + Ruleset = ruleset, + StarDifficulty = 6, + Version = $"{ruleset.ShortName}Version" + }, + HitObjects = new List() // TODO: Fill it with something depending on ruleset? + }; + } - var b = sets[random.Next(0, sets.Count)].Beatmaps[0]; - beatmap.Value = beatmaps.GetWorkingBeatmap(b); - infoWedge.UpdateBeatmap(beatmap); + private class TestBeatmapInfoWedge : BeatmapInfoWedge + { + public new BufferedWedgeInfo Info => base.Info; } } } diff --git a/osu.Game/Beatmaps/DummyWorkingBeatmap.cs b/osu.Game/Beatmaps/DummyWorkingBeatmap.cs index 1434943da0..3ec83ed8d5 100644 --- a/osu.Game/Beatmaps/DummyWorkingBeatmap.cs +++ b/osu.Game/Beatmaps/DummyWorkingBeatmap.cs @@ -21,8 +21,7 @@ namespace osu.Game.Beatmaps Metadata = new BeatmapMetadata { Artist = "please load a beatmap!", - Title = "no beatmaps available!", - AuthorString = "no one", + Title = "no beatmaps available!" }, BeatmapSet = new BeatmapSetInfo(), BaseDifficulty = new BeatmapDifficulty diff --git a/osu.Game/Screens/Select/BeatmapInfoWedge.cs b/osu.Game/Screens/Select/BeatmapInfoWedge.cs index 9b9a009ac0..5d4f950a51 100644 --- a/osu.Game/Screens/Select/BeatmapInfoWedge.cs +++ b/osu.Game/Screens/Select/BeatmapInfoWedge.cs @@ -27,7 +27,7 @@ namespace osu.Game.Screens.Select { private static readonly Vector2 wedged_container_shear = new Vector2(0.15f, 0); - private Drawable info; + protected BufferedWedgeInfo Info; public BeatmapInfoWedge() { @@ -63,23 +63,28 @@ namespace osu.Game.Screens.Select LoadComponentAsync(new BufferedWedgeInfo(beatmap) { Shear = -Shear, - Depth = info?.Depth + 1 ?? 0, + Depth = Info?.Depth + 1 ?? 0, }, newInfo => { // ensure we ourselves are visible if not already. if (!IsPresent) this.FadeIn(250); - info?.FadeOut(250); - info?.Expire(); + Info?.FadeOut(250); + Info?.Expire(); - Add(info = newInfo); + Add(Info = newInfo); }); } public class BufferedWedgeInfo : BufferedContainer { private readonly WorkingBeatmap working; + public OsuSpriteText VersionLabel { get; private set; } + public OsuSpriteText TitleLabel { get; private set; } + public OsuSpriteText ArtistLabel { get; private set; } + public FillFlowContainer MapperContainer { get; private set; } + public FillFlowContainer InfoLabelContainer { get; private set; } public BufferedWedgeInfo(WorkingBeatmap working) { @@ -139,7 +144,7 @@ namespace osu.Game.Screens.Select AutoSizeAxes = Axes.Both, Children = new Drawable[] { - new OsuSpriteText + VersionLabel = new OsuSpriteText { Font = @"Exo2.0-MediumItalic", Text = beatmapInfo.Version, @@ -157,26 +162,26 @@ namespace osu.Game.Screens.Select AutoSizeAxes = Axes.Both, Children = new Drawable[] { - new OsuSpriteText + TitleLabel = new OsuSpriteText { Font = @"Exo2.0-MediumItalic", Text = string.IsNullOrEmpty(metadata.Source) ? metadata.Title : metadata.Source + " — " + metadata.Title, TextSize = 28, }, - new OsuSpriteText + ArtistLabel = new OsuSpriteText { Font = @"Exo2.0-MediumItalic", Text = metadata.Artist, TextSize = 17, }, - new FillFlowContainer + MapperContainer = new FillFlowContainer { Margin = new MarginPadding { Top = 10 }, Direction = FillDirection.Horizontal, AutoSizeAxes = Axes.Both, Children = getMapper(metadata) }, - new FillFlowContainer + InfoLabelContainer = new FillFlowContainer { Margin = new MarginPadding { Top = 20 }, Spacing = new Vector2(20, 0), From 2313ff0ddbe0b04c04beda6fe4df5947ec32711f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 22 Dec 2017 22:19:11 +0900 Subject: [PATCH 004/101] Fix beatmap info wedge not showing up when zero beatmaps are loaded Closes #1722. --- osu.Game/Screens/Select/BeatmapCarousel.cs | 2 +- osu.Game/Screens/Select/BeatmapInfoWedge.cs | 2 ++ osu.Game/Screens/Select/SongSelect.cs | 1 - 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index ff1dd95eac..e0fcba5b3c 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -509,7 +509,7 @@ namespace osu.Game.Screens.Select currentY += DrawHeight / 2; scrollableContent.Height = currentY; - if (selectedBeatmapSet != null && selectedBeatmapSet.State.Value != CarouselItemState.Selected) + if (selectedBeatmapSet == null || selectedBeatmapSet.State.Value != CarouselItemState.Selected) { selectedBeatmapSet = null; SelectionChanged?.Invoke(null); diff --git a/osu.Game/Screens/Select/BeatmapInfoWedge.cs b/osu.Game/Screens/Select/BeatmapInfoWedge.cs index 3ef6ceeaeb..1baacb78ee 100644 --- a/osu.Game/Screens/Select/BeatmapInfoWedge.cs +++ b/osu.Game/Screens/Select/BeatmapInfoWedge.cs @@ -66,6 +66,8 @@ namespace osu.Game.Screens.Select Depth = info?.Depth + 1 ?? 0, }, newInfo => { + State = beatmap == null ? Visibility.Hidden : Visibility.Visible; + // ensure we ourselves are visible if not already. if (!IsPresent) this.FadeIn(250); diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 68ee08e721..9a7dbf002e 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -399,7 +399,6 @@ namespace osu.Game.Screens.Select backgroundModeBeatmap.FadeTo(1, 250); } - beatmapInfoWedge.State = Visibility.Visible; beatmapInfoWedge.UpdateBeatmap(beatmap); } From 6a8fd74e055bd3a35931c1112c86298e4cd6f91f Mon Sep 17 00:00:00 2001 From: Aergwyn Date: Fri, 22 Dec 2017 17:38:22 +0100 Subject: [PATCH 005/101] fix failing tests 1) waiting for loading to finish so Drawables are all present to do asserts on 2) fix NullRef in ResultPage because of removed line in DummyWorkingBeatmap (author one) --- osu.Game.Tests/Visual/TestCaseBeatmapInfoWedge.cs | 8 ++++++++ osu.Game/Screens/Ranking/ResultsPageScore.cs | 9 ++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/TestCaseBeatmapInfoWedge.cs b/osu.Game.Tests/Visual/TestCaseBeatmapInfoWedge.cs index 353f351a54..1ef6291ee4 100644 --- a/osu.Game.Tests/Visual/TestCaseBeatmapInfoWedge.cs +++ b/osu.Game.Tests/Visual/TestCaseBeatmapInfoWedge.cs @@ -20,6 +20,7 @@ namespace osu.Game.Tests.Visual { public class TestCaseBeatmapInfoWedge : OsuTestCase { + private RulesetStore rulesets; private TestBeatmapInfoWedge infoWedge; private readonly List beatmaps = new List(); private readonly Bindable beatmap = new Bindable(); @@ -27,7 +28,14 @@ namespace osu.Game.Tests.Visual [BackgroundDependencyLoader] private void load(OsuGameBase game, RulesetStore rulesets) { + this.rulesets = rulesets; + beatmap.BindTo(game.Beatmap); + } + + protected override void LoadComplete() + { + base.LoadComplete(); Add(infoWedge = new TestBeatmapInfoWedge { diff --git a/osu.Game/Screens/Ranking/ResultsPageScore.cs b/osu.Game/Screens/Ranking/ResultsPageScore.cs index 911b688669..396d7f3c18 100644 --- a/osu.Game/Screens/Ranking/ResultsPageScore.cs +++ b/osu.Game/Screens/Ranking/ResultsPageScore.cs @@ -324,7 +324,14 @@ namespace osu.Game.Screens.Ranking title.Colour = artist.Colour = colours.BlueDarker; versionMapper.Colour = colours.Gray8; - versionMapper.Text = $"{beatmap.Version} - mapped by {beatmap.Metadata.Author.Username}"; + var creator = beatmap.Metadata.Author?.Username; + if (!string.IsNullOrEmpty(creator)) { + versionMapper.Text = $"mapped by {creator}"; + + if (!string.IsNullOrEmpty(beatmap.Version)) + versionMapper.Text = $"{beatmap.Version} - " + versionMapper.Text; + } + title.Current = localisation.GetUnicodePreference(beatmap.Metadata.TitleUnicode, beatmap.Metadata.Title); artist.Current = localisation.GetUnicodePreference(beatmap.Metadata.ArtistUnicode, beatmap.Metadata.Artist); } From 49e855a29ae3d4538d618e7c6de255e4afa29741 Mon Sep 17 00:00:00 2001 From: Aergwyn Date: Sat, 23 Dec 2017 11:56:53 +0100 Subject: [PATCH 006/101] finished up visual tests --- .../Visual/TestCaseBeatmapInfoWedge.cs | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCaseBeatmapInfoWedge.cs b/osu.Game.Tests/Visual/TestCaseBeatmapInfoWedge.cs index 1ef6291ee4..61c904aa60 100644 --- a/osu.Game.Tests/Visual/TestCaseBeatmapInfoWedge.cs +++ b/osu.Game.Tests/Visual/TestCaseBeatmapInfoWedge.cs @@ -68,11 +68,15 @@ namespace osu.Game.Tests.Visual var name = rulesetInfo.ShortName; selectBeatmap(name); - // TODO: check InfoLabels of other rulesets + // TODO: adjust cases once more info is shown for other gamemodes switch (ruleset) { case OsuRuleset osu: testOsuBeatmap(osu); + testInfoLabels(5); + break; + default: + testInfoLabels(2); break; } } @@ -86,7 +90,12 @@ namespace osu.Game.Tests.Visual AddAssert("check title", () => infoWedge.Info.TitleLabel.Text == $"{ruleset.ShortName}Source — {ruleset.ShortName}Title"); AddAssert("check artist", () => infoWedge.Info.ArtistLabel.Text == $"{ruleset.ShortName}Artist"); AddAssert("check author", () => infoWedge.Info.MapperContainer.Children.OfType().Any(s => s.Text == $"{ruleset.ShortName}Author")); - // TODO: check InfoLabels + } + + private void testInfoLabels(int expectedCount) + { + AddAssert("check infolabels exists", () => infoWedge.Info.InfoLabelContainer.Children.Any()); + AddAssert("check infolabels count", () => infoWedge.Info.InfoLabelContainer.Children.Count == expectedCount); } private void testNullBeatmap() @@ -96,7 +105,7 @@ namespace osu.Game.Tests.Visual AddAssert("check default title", () => infoWedge.Info.TitleLabel.Text == beatmap.Default.BeatmapInfo.Metadata.Title); AddAssert("check default artist", () => infoWedge.Info.ArtistLabel.Text == beatmap.Default.BeatmapInfo.Metadata.Artist); AddAssert("check empty author", () => !infoWedge.Info.MapperContainer.Children.Any()); - AddAssert("check empty infos", () => !infoWedge.Info.InfoLabelContainer.Children.Any()); + AddAssert("check no infolabels", () => !infoWedge.Info.InfoLabelContainer.Children.Any()); } private void selectBeatmap(string name) @@ -119,6 +128,10 @@ namespace osu.Game.Tests.Visual private Beatmap createTestBeatmap(RulesetInfo ruleset) { + List objects = new List(); + for (double i = 0; i < 50000; i += 1000) + objects.Add(new HitObject { StartTime = i }); + return new Beatmap { BeatmapInfo = new BeatmapInfo @@ -134,7 +147,7 @@ namespace osu.Game.Tests.Visual StarDifficulty = 6, Version = $"{ruleset.ShortName}Version" }, - HitObjects = new List() // TODO: Fill it with something depending on ruleset? + HitObjects = objects }; } From 68d76d4380f2816088cd7f0344331e79aa4df907 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Sat, 23 Dec 2017 20:58:09 +0900 Subject: [PATCH 007/101] Fix taiko strong hits not being handled --- osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index d960ab6b48..c397ea47ef 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -174,7 +174,7 @@ namespace osu.Game.Rulesets.Objects.Drawables { judgementOccurred = false; - if (AllJudged || State != ArmedState.Idle) + if (AllJudged) return false; if (NestedHitObjects != null) From a6566564039ecb7e809e96eefa4b93d0649737df Mon Sep 17 00:00:00 2001 From: Shawdooow Date: Sat, 23 Dec 2017 22:47:32 -0500 Subject: [PATCH 008/101] the fix --- osu.Game.Rulesets.Osu/Objects/Slider.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/osu.Game.Rulesets.Osu/Objects/Slider.cs b/osu.Game.Rulesets.Osu/Objects/Slider.cs index 4f5a44e61d..01f83ac904 100644 --- a/osu.Game.Rulesets.Osu/Objects/Slider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Slider.cs @@ -117,11 +117,18 @@ namespace osu.Game.Rulesets.Osu.Objects var minDistanceFromEnd = Velocity * 0.01; + bool sliderStart = false; + for (var repeat = 0; repeat < RepeatCount; repeat++) { var repeatStartTime = StartTime + repeat * repeatDuration; var reversed = repeat % 2 == 1; + if (!sliderStart) + sliderStart = true; + else + sliderStart = false; + for (var d = tickDistance; d <= length; d += tickDistance) { if (d > length - minDistanceFromEnd) @@ -130,6 +137,9 @@ namespace osu.Game.Rulesets.Osu.Objects var distanceProgress = d / length; var timeProgress = reversed ? 1 - distanceProgress : distanceProgress; + if (sliderStart) + distanceProgress = 0; + AddNested(new SliderTick { RepeatIndex = repeat, From d333fc5efe4bb28a9d8c548600a15ab31e6a1451 Mon Sep 17 00:00:00 2001 From: Shawdooow Date: Sat, 23 Dec 2017 23:08:55 -0500 Subject: [PATCH 009/101] fix the fix silly me, that was configured for vitaru! --- osu.Game.Rulesets.Osu/Objects/Slider.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Slider.cs b/osu.Game.Rulesets.Osu/Objects/Slider.cs index 01f83ac904..44c7792e9c 100644 --- a/osu.Game.Rulesets.Osu/Objects/Slider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Slider.cs @@ -117,7 +117,7 @@ namespace osu.Game.Rulesets.Osu.Objects var minDistanceFromEnd = Velocity * 0.01; - bool sliderStart = false; + bool sliderStart = true; for (var repeat = 0; repeat < RepeatCount; repeat++) { From af2a2781e7126f7d5eeb40f578cd7c4faf8ecd47 Mon Sep 17 00:00:00 2001 From: Shawdooow Date: Sat, 23 Dec 2017 23:12:10 -0500 Subject: [PATCH 010/101] fix the fix harder --- osu.Game.Rulesets.Osu/Objects/Slider.cs | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Slider.cs b/osu.Game.Rulesets.Osu/Objects/Slider.cs index 44c7792e9c..800573f991 100644 --- a/osu.Game.Rulesets.Osu/Objects/Slider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Slider.cs @@ -117,18 +117,11 @@ namespace osu.Game.Rulesets.Osu.Objects var minDistanceFromEnd = Velocity * 0.01; - bool sliderStart = true; - for (var repeat = 0; repeat < RepeatCount; repeat++) { var repeatStartTime = StartTime + repeat * repeatDuration; var reversed = repeat % 2 == 1; - if (!sliderStart) - sliderStart = true; - else - sliderStart = false; - for (var d = tickDistance; d <= length; d += tickDistance) { if (d > length - minDistanceFromEnd) @@ -137,9 +130,6 @@ namespace osu.Game.Rulesets.Osu.Objects var distanceProgress = d / length; var timeProgress = reversed ? 1 - distanceProgress : distanceProgress; - if (sliderStart) - distanceProgress = 0; - AddNested(new SliderTick { RepeatIndex = repeat, @@ -165,13 +155,20 @@ namespace osu.Game.Rulesets.Osu.Objects var repeatPointDistance = Math.Min(Distance, length); var repeatDuration = length / Velocity; + bool sliderStart = true; + for (var repeat = 1; repeat < RepeatCount; repeat++) { + sliderStart = !sliderStart; + for (var d = repeatPointDistance; d <= length; d += repeatPointDistance) { var repeatStartTime = StartTime + repeat * repeatDuration; var distanceProgress = d / length; + if (sliderStart) + distanceProgress = 0; + AddNested(new RepeatPoint { RepeatIndex = repeat, From 72b5a370da6fbc7702c80857e64476674f061c89 Mon Sep 17 00:00:00 2001 From: Shawdooow Date: Sat, 23 Dec 2017 23:13:53 -0500 Subject: [PATCH 011/101] dont play the same sound twice at once --- osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs index befe84e3e9..d8a22d94ca 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs @@ -117,11 +117,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables progress = slider.ProgressAt(progress); if (repeat > currentRepeat) - { - if (repeat < slider.RepeatCount && ball.Tracking) - PlaySamples(); currentRepeat = repeat; - } //todo: we probably want to reconsider this before adding scoring, but it looks and feels nice. if (!initialCircle.Judgements.Any(j => j.IsHit)) From cf316b3c51661a7a21ae1b47c90b9f169c19b8f6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 24 Dec 2017 15:39:25 +0900 Subject: [PATCH 012/101] Add tests for initial load states of PlaySongSelect --- .../Visual/TestCasePlaySongSelect.cs | 48 ++++++++++++++++--- osu.Game/Screens/Select/BeatmapCarousel.cs | 1 - osu.Game/Screens/Select/SongSelect.cs | 34 ++++++------- 3 files changed, 59 insertions(+), 24 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCasePlaySongSelect.cs b/osu.Game.Tests/Visual/TestCasePlaySongSelect.cs index 6435df7c2c..34b99c6ca6 100644 --- a/osu.Game.Tests/Visual/TestCasePlaySongSelect.cs +++ b/osu.Game.Tests/Visual/TestCasePlaySongSelect.cs @@ -26,6 +26,7 @@ namespace osu.Game.Tests.Visual private RulesetStore rulesets; private DependencyContainer dependencies; + private WorkingBeatmap defaultBeatmap; public override IReadOnlyList RequiredTypes => new[] { @@ -47,10 +48,16 @@ namespace osu.Game.Tests.Visual protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent) => dependencies = new DependencyContainer(parent); + private class TestSongSelect : PlaySongSelect + { + public WorkingBeatmap CurrentBeatmap => Beatmap.Value; + public new BeatmapCarousel Carousel => base.Carousel; + } + [BackgroundDependencyLoader] private void load(BeatmapManager baseManager) { - PlaySongSelect songSelect; + TestSongSelect songSelect = null; if (manager == null) { @@ -64,14 +71,43 @@ namespace osu.Game.Tests.Visual dependencies.Cache(rulesets = new RulesetStore(contextFactory)); dependencies.Cache(manager = new BeatmapManager(storage, contextFactory, rulesets, null) { - DefaultBeatmap = baseManager.GetWorkingBeatmap(null) + DefaultBeatmap = defaultBeatmap = baseManager.GetWorkingBeatmap(null) }); - - for (int i = 0; i < 100; i += 10) - manager.Import(createTestBeatmapSet(i)); } - Add(songSelect = new PlaySongSelect()); + void loadNewSongSelect(bool deleteMaps = false) => AddStep("reload song select", () => + { + if (deleteMaps) manager.DeleteAll(); + + if (songSelect != null) + { + Remove(songSelect); + songSelect.Dispose(); + } + + Add(songSelect = new TestSongSelect()); + }); + + loadNewSongSelect(true); + + AddWaitStep(1); + + AddAssert("dummy selected", () => songSelect.CurrentBeatmap == defaultBeatmap); + + AddStep("import test maps", () => + { + for (int i = 0; i < 100; i += 10) + manager.Import(createTestBeatmapSet(i)); + }); + + AddWaitStep(1); + AddStep("select random", () => songSelect.Carousel.SelectNextRandom()); + + AddWaitStep(1); + AddAssert("random map selected", () => songSelect.CurrentBeatmap != defaultBeatmap); + + loadNewSongSelect(); + AddAssert("random map selected", () => songSelect.CurrentBeatmap != defaultBeatmap); AddStep(@"Sort by Artist", delegate { songSelect.FilterControl.Sort = SortMode.Artist; }); AddStep(@"Sort by Title", delegate { songSelect.FilterControl.Sort = SortMode.Title; }); diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index bfba9a7d6b..b4ca6f10f9 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -142,7 +142,6 @@ namespace osu.Game.Screens.Select if (newSet == null) { itemsCache.Invalidate(); - SelectNext(); return; } diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 9a7dbf002e..a15699d97a 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -55,7 +55,7 @@ namespace osu.Game.Screens.Select protected Container LeftContent; - private readonly BeatmapCarousel carousel; + protected readonly BeatmapCarousel Carousel; private readonly BeatmapInfoWedge beatmapInfoWedge; private DialogOverlay dialogOverlay; private BeatmapManager beatmaps; @@ -103,7 +103,7 @@ namespace osu.Game.Screens.Select Right = left_area_padding * 2, } }, - carousel = new BeatmapCarousel + Carousel = new BeatmapCarousel { RelativeSizeAxes = Axes.Y, Size = new Vector2(carousel_width, 1), @@ -116,7 +116,7 @@ namespace osu.Game.Screens.Select { RelativeSizeAxes = Axes.X, Height = filter_height, - FilterChanged = c => carousel.Filter(c), + FilterChanged = c => Carousel.Filter(c), Exit = Exit, }, beatmapInfoWedge = new BeatmapInfoWedge @@ -130,7 +130,7 @@ namespace osu.Game.Screens.Select Right = left_area_padding, }, }, - new ResetScrollContainer(() => carousel.ScrollToSelected()) + new ResetScrollContainer(() => Carousel.ScrollToSelected()) { RelativeSizeAxes = Axes.Y, Width = 250, @@ -190,15 +190,15 @@ namespace osu.Game.Screens.Select initialAddSetsTask = new CancellationTokenSource(); - carousel.BeatmapSets = this.beatmaps.GetAllUsableBeatmapSets(); + Carousel.BeatmapSets = this.beatmaps.GetAllUsableBeatmapSets(); - Beatmap.DisabledChanged += disabled => carousel.AllowSelection = !disabled; + Beatmap.DisabledChanged += disabled => Carousel.AllowSelection = !disabled; Beatmap.TriggerChange(); Beatmap.ValueChanged += b => { if (IsCurrentScreen) - carousel.SelectBeatmap(b?.BeatmapInfo); + Carousel.SelectBeatmap(b?.BeatmapInfo); }; } @@ -212,9 +212,9 @@ namespace osu.Game.Screens.Select { // if we have a pending filter operation, we want to run it now. // it could change selection (ie. if the ruleset has been changed). - carousel.FlushPendingFilterOperations(); + Carousel.FlushPendingFilterOperations(); - carousel.SelectBeatmap(beatmap); + Carousel.SelectBeatmap(beatmap); if (selectionChangedDebounce?.Completed == false) { @@ -282,9 +282,9 @@ namespace osu.Game.Screens.Select private void triggerRandom() { if (GetContainingInputManager().CurrentState.Keyboard.ShiftPressed) - carousel.SelectPreviousRandom(); + Carousel.SelectPreviousRandom(); else - carousel.SelectNextRandom(); + Carousel.SelectNextRandom(); } protected override void OnEntering(Screen last) @@ -416,17 +416,17 @@ namespace osu.Game.Screens.Select } } - private void onBeatmapSetAdded(BeatmapSetInfo s) => carousel.UpdateBeatmapSet(s); - private void onBeatmapSetRemoved(BeatmapSetInfo s) => carousel.RemoveBeatmapSet(s); - private void onBeatmapRestored(BeatmapInfo b) => carousel.UpdateBeatmapSet(beatmaps.QueryBeatmapSet(s => s.ID == b.BeatmapSetInfoID)); - private void onBeatmapHidden(BeatmapInfo b) => carousel.UpdateBeatmapSet(beatmaps.QueryBeatmapSet(s => s.ID == b.BeatmapSetInfoID)); + private void onBeatmapSetAdded(BeatmapSetInfo s) => Carousel.UpdateBeatmapSet(s); + private void onBeatmapSetRemoved(BeatmapSetInfo s) => Carousel.RemoveBeatmapSet(s); + private void onBeatmapRestored(BeatmapInfo b) => Carousel.UpdateBeatmapSet(beatmaps.QueryBeatmapSet(s => s.ID == b.BeatmapSetInfoID)); + private void onBeatmapHidden(BeatmapInfo b) => Carousel.UpdateBeatmapSet(beatmaps.QueryBeatmapSet(s => s.ID == b.BeatmapSetInfoID)); private void carouselBeatmapsLoaded() { if (Beatmap.Value.BeatmapSetInfo?.DeletePending == false) - carousel.SelectBeatmap(Beatmap.Value.BeatmapInfo); + Carousel.SelectBeatmap(Beatmap.Value.BeatmapInfo); else - carousel.SelectNextRandom(); + Carousel.SelectNextRandom(); } private void delete(BeatmapSetInfo beatmap) From a04ebd0595e423c02e38b57b5e386020d19f7157 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 24 Dec 2017 15:39:44 +0900 Subject: [PATCH 013/101] Update framework --- osu-framework | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu-framework b/osu-framework index 08f85f9bf9..64e04b9ff2 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit 08f85f9bf9a7376aec8dfcde8c7c96d267d8c295 +Subproject commit 64e04b9ff2d5ba53e5c3a46cfa42a79baeffc014 From 482e10966cfb5fd80c892695bfda6f250b6ae4ee Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 24 Dec 2017 17:02:46 +0900 Subject: [PATCH 014/101] Ensure a selection is made on entering song select if no selection is current --- osu.Game.Tests/Visual/TestCasePlaySongSelect.cs | 3 --- osu.Game/Screens/Select/BeatmapCarousel.cs | 4 +++- osu.Game/Screens/Select/SongSelect.cs | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCasePlaySongSelect.cs b/osu.Game.Tests/Visual/TestCasePlaySongSelect.cs index 34b99c6ca6..87f71d215b 100644 --- a/osu.Game.Tests/Visual/TestCasePlaySongSelect.cs +++ b/osu.Game.Tests/Visual/TestCasePlaySongSelect.cs @@ -100,9 +100,6 @@ namespace osu.Game.Tests.Visual manager.Import(createTestBeatmapSet(i)); }); - AddWaitStep(1); - AddStep("select random", () => songSelect.Carousel.SelectNextRandom()); - AddWaitStep(1); AddAssert("random map selected", () => songSelect.CurrentBeatmap != defaultBeatmap); diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index b4ca6f10f9..c33993c68c 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -75,7 +75,8 @@ namespace osu.Game.Screens.Select scrollableContent.Clear(false); itemsCache.Invalidate(); scrollPositionCache.Invalidate(); - BeatmapSetsChanged?.Invoke(); + + Schedule(() => BeatmapSetsChanged?.Invoke()); })); } } @@ -154,6 +155,7 @@ namespace osu.Game.Screens.Select select((CarouselItem)newSet.Beatmaps.FirstOrDefault(b => b.Beatmap.ID == selectedBeatmap?.Beatmap.ID) ?? newSet); itemsCache.Invalidate(); + Schedule(() => BeatmapSetsChanged?.Invoke()); }); } diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index a15699d97a..75c4a68388 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -423,7 +423,7 @@ namespace osu.Game.Screens.Select private void carouselBeatmapsLoaded() { - if (Beatmap.Value.BeatmapSetInfo?.DeletePending == false) + if (!Beatmap.IsDefault && Beatmap.Value.BeatmapSetInfo?.DeletePending == false) Carousel.SelectBeatmap(Beatmap.Value.BeatmapInfo); else Carousel.SelectNextRandom(); From a7ee6985b050fbf6df3f2880c87f7a1085cec863 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 25 Dec 2017 01:06:33 +0900 Subject: [PATCH 015/101] Add wait step --- osu.Game.Tests/Visual/TestCasePlaySongSelect.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game.Tests/Visual/TestCasePlaySongSelect.cs b/osu.Game.Tests/Visual/TestCasePlaySongSelect.cs index 87f71d215b..e27e786a05 100644 --- a/osu.Game.Tests/Visual/TestCasePlaySongSelect.cs +++ b/osu.Game.Tests/Visual/TestCasePlaySongSelect.cs @@ -104,6 +104,7 @@ namespace osu.Game.Tests.Visual AddAssert("random map selected", () => songSelect.CurrentBeatmap != defaultBeatmap); loadNewSongSelect(); + AddWaitStep(1); AddAssert("random map selected", () => songSelect.CurrentBeatmap != defaultBeatmap); AddStep(@"Sort by Artist", delegate { songSelect.FilterControl.Sort = SortMode.Artist; }); From 8529eb1d3a2350da13d8fb445a7d13375afa1c97 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 25 Dec 2017 14:49:39 +0900 Subject: [PATCH 016/101] Make strong hit misses not count as misses --- osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHitStrong.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHitStrong.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHitStrong.cs index 81b23af1a9..07f7b83cef 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHitStrong.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHitStrong.cs @@ -36,7 +36,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables if (!userTriggered) { if (timeOffset > second_hit_window) - AddJudgement(new TaikoStrongHitJudgement { Result = HitResult.Miss }); + AddJudgement(new TaikoStrongHitJudgement { Result = HitResult.None }); return; } From 844e39a9f6f177be8bc4f41fe8ff69425052d622 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 25 Dec 2017 15:04:22 +0900 Subject: [PATCH 017/101] Make Swells play samples while they're being hit --- .../Objects/Drawables/DrawableSwell.cs | 37 ++++++++++++++----- osu.Game.Rulesets.Taiko/Objects/Swell.cs | 28 +++++++++++++- .../Objects/SwellSampleMapping.cs | 28 ++++++++++++++ .../osu.Game.Rulesets.Taiko.csproj | 1 + 4 files changed, 83 insertions(+), 11 deletions(-) create mode 100644 osu.Game.Rulesets.Taiko/Objects/SwellSampleMapping.cs diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs index 738902846b..d657598554 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs @@ -14,6 +14,7 @@ using OpenTK; using OpenTK.Graphics; using osu.Framework.Graphics.Shapes; using osu.Game.Rulesets.Taiko.Judgements; +using osu.Framework.Audio; namespace osu.Game.Rulesets.Taiko.Objects.Drawables { @@ -34,10 +35,6 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables private readonly CircularContainer targetRing; private readonly CircularContainer expandingRing; - private readonly TaikoAction[] rimActions = { TaikoAction.LeftRim, TaikoAction.RightRim }; - private readonly TaikoAction[] centreActions = { TaikoAction.LeftCentre, TaikoAction.RightCentre }; - private TaikoAction[] lastAction; - /// /// The amount of times the user has hit this swell. /// @@ -120,11 +117,14 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables } [BackgroundDependencyLoader] - private void load(OsuColour colours) + private void load(OsuColour colours, AudioManager audio) { MainPiece.AccentColour = colours.YellowDark; expandingRing.Colour = colours.YellowLight; targetRing.BorderColour = colours.YellowDark.Opacity(0.25f); + + foreach (var mapping in HitObject.ProgressionSamples) + mapping.RetrieveChannels(audio); } protected override void LoadComplete() @@ -205,22 +205,39 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables } } + private bool? lastWasCentre; + public override bool OnPressed(TaikoAction action) { // Don't handle keys before the swell starts if (Time.Current < HitObject.StartTime) return false; - // Find the keyset which this key corresponds to - var keySet = rimActions.Contains(action) ? rimActions : centreActions; + var isCentre = action == TaikoAction.LeftCentre || action == TaikoAction.RightCentre; - // Ensure alternating keysets - if (keySet == lastAction) + // Ensure alternating centre and rim hits + if (lastWasCentre == isCentre) return false; - lastAction = keySet; + lastWasCentre = isCentre; UpdateJudgement(true); + if (AllJudged) + return true; + + // While the swell hasn't been fully judged, input is still blocked so it doesn't fall through to other hitobjects + // This causes the playfield to not play sounds, so they need to be handled locally + + var mappingIndex = HitObject.ProgressionSamples.BinarySearch(new SwellSampleMapping { Time = Time.Current }); + if (mappingIndex < 0) + mappingIndex = ~mappingIndex - 1; + + var mapping = HitObject.ProgressionSamples[mappingIndex]; + if (isCentre) + mapping.CentreChannel.Play(); + else + mapping.RimChannel.Play(); + return true; } } diff --git a/osu.Game.Rulesets.Taiko/Objects/Swell.cs b/osu.Game.Rulesets.Taiko/Objects/Swell.cs index f74a543ca9..b4fa736045 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Swell.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Swell.cs @@ -1,6 +1,11 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System.Collections.Generic; +using System.Linq; +using osu.Game.Audio; +using osu.Game.Beatmaps; +using osu.Game.Beatmaps.ControlPoints; using osu.Game.Rulesets.Objects.Types; namespace osu.Game.Rulesets.Taiko.Objects @@ -15,5 +20,26 @@ namespace osu.Game.Rulesets.Taiko.Objects /// The number of hits required to complete the swell successfully. /// public int RequiredHits = 10; + + public List ProgressionSamples = new List(); + + protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) + { + base.ApplyDefaultsToSelf(controlPointInfo, difficulty); + + var progressionSamplePoints = + new[] { controlPointInfo.SamplePointAt(StartTime) } + .Concat(controlPointInfo.SamplePoints.Where(p => p.Time > StartTime && p.Time <= EndTime)); + + foreach (var point in progressionSamplePoints) + { + ProgressionSamples.Add(new SwellSampleMapping + { + Time = point.Time, + Centre = point.GetSampleInfo(), + Rim = point.GetSampleInfo(SampleInfo.HIT_CLAP) + }); + } + } } -} \ No newline at end of file +} diff --git a/osu.Game.Rulesets.Taiko/Objects/SwellSampleMapping.cs b/osu.Game.Rulesets.Taiko/Objects/SwellSampleMapping.cs new file mode 100644 index 0000000000..99d0e1d0fd --- /dev/null +++ b/osu.Game.Rulesets.Taiko/Objects/SwellSampleMapping.cs @@ -0,0 +1,28 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using osu.Framework.Audio; +using osu.Framework.Audio.Sample; +using osu.Game.Audio; + +namespace osu.Game.Rulesets.Taiko.Objects +{ + public class SwellSampleMapping : IComparable + { + public double Time; + public SampleInfo Centre; + public SampleInfo Rim; + + public SampleChannel CentreChannel { get; private set; } + public SampleChannel RimChannel { get; private set; } + + public void RetrieveChannels(AudioManager audio) + { + CentreChannel = Centre.GetChannel(audio.Sample); + RimChannel = Rim.GetChannel(audio.Sample); + } + + public int CompareTo(SwellSampleMapping other) => Time.CompareTo(other.Time); + } +} diff --git a/osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj b/osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj index bb02db62b9..9fa3936153 100644 --- a/osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj +++ b/osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj @@ -74,6 +74,7 @@ + From d288d8a51f370a6f91141c046ad3a67b4a1a6c5a Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 25 Dec 2017 15:35:28 +0900 Subject: [PATCH 018/101] Remove SampleInfoList --- osu.Game.Rulesets.Catch/Objects/JuiceStream.cs | 6 +++--- .../Beatmaps/ManiaBeatmapConverter.cs | 2 +- .../Legacy/DistanceObjectPatternGenerator.cs | 3 ++- .../Legacy/EndTimeObjectPatternGenerator.cs | 3 ++- osu.Game.Rulesets.Osu/Objects/Slider.cs | 6 +++--- .../Beatmaps/TaikoBeatmapConverter.cs | 6 +++--- osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs | 3 ++- .../Tests/TestCaseTaikoPlayfield.cs | 14 ++++++++++++-- osu.Game/Audio/SampleInfoList.cs | 18 ------------------ osu.Game/Rulesets/Objects/HitObject.cs | 2 +- .../Legacy/Catch/ConvertHitObjectParser.cs | 2 +- .../Objects/Legacy/ConvertHitObjectParser.cs | 8 ++++---- .../Rulesets/Objects/Legacy/ConvertSlider.cs | 2 +- .../Legacy/Mania/ConvertHitObjectParser.cs | 2 +- .../Legacy/Osu/ConvertHitObjectParser.cs | 4 ++-- .../Legacy/Taiko/ConvertHitObjectParser.cs | 4 ++-- osu.Game/Rulesets/Objects/Types/IHasRepeats.cs | 2 +- osu.Game/osu.Game.csproj | 1 - 18 files changed, 41 insertions(+), 47 deletions(-) delete mode 100644 osu.Game/Audio/SampleInfoList.cs diff --git a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs index 8e496c3b0c..7d0d80a0ce 100644 --- a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs +++ b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs @@ -86,7 +86,7 @@ namespace osu.Game.Rulesets.Catch.Objects StartTime = lastTickTime, ComboColour = ComboColour, X = Curve.PositionAt(distanceProgress).X / CatchPlayfield.BASE_WIDTH, - Samples = new SampleInfoList(Samples.Select(s => new SampleInfo + Samples = new List(Samples.Select(s => new SampleInfo { Bank = s.Bank, Name = @"slidertick", @@ -108,7 +108,7 @@ namespace osu.Game.Rulesets.Catch.Objects StartTime = repeatStartTime + t, ComboColour = ComboColour, X = Curve.PositionAt(progress).X / CatchPlayfield.BASE_WIDTH, - Samples = new SampleInfoList(Samples.Select(s => new SampleInfo + Samples = new List(Samples.Select(s => new SampleInfo { Bank = s.Bank, Name = @"slidertick", @@ -147,7 +147,7 @@ namespace osu.Game.Rulesets.Catch.Objects set { Curve.ControlPoints = value; } } - public List RepeatSamples { get; set; } = new List(); + public List> RepeatSamples { get; set; } = new List>(); public CurveType CurveType { diff --git a/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs b/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs index d5a799b4ed..407d4db143 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs @@ -192,7 +192,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps /// /// The time to retrieve the sample info list from. /// - private SampleInfoList sampleInfoListAt(double time) + private List sampleInfoListAt(double time) { var curveData = HitObject as IHasCurve; diff --git a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs index 270c264e0c..8251dea5f7 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs @@ -2,6 +2,7 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; +using System.Collections.Generic; using System.Linq; using osu.Game.Audio; using osu.Game.Beatmaps; @@ -435,7 +436,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy /// /// The time to retrieve the sample info list from. /// - private SampleInfoList sampleInfoListAt(double time) + private List sampleInfoListAt(double time) { var curveData = HitObject as IHasCurve; diff --git a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/EndTimeObjectPatternGenerator.cs b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/EndTimeObjectPatternGenerator.cs index 3e9fc1ae27..8e832960df 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/EndTimeObjectPatternGenerator.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/EndTimeObjectPatternGenerator.cs @@ -1,6 +1,7 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System.Collections.Generic; using osu.Game.Beatmaps; using osu.Game.Rulesets.Mania.MathUtils; using osu.Game.Rulesets.Objects; @@ -77,7 +78,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy }; if (hold.Head.Samples == null) - hold.Head.Samples = new SampleInfoList(); + hold.Head.Samples = new List(); hold.Head.Samples.Add(new SampleInfo { Name = SampleInfo.HIT_NORMAL }); diff --git a/osu.Game.Rulesets.Osu/Objects/Slider.cs b/osu.Game.Rulesets.Osu/Objects/Slider.cs index 4f5a44e61d..5f9f11c783 100644 --- a/osu.Game.Rulesets.Osu/Objects/Slider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Slider.cs @@ -57,7 +57,7 @@ namespace osu.Game.Rulesets.Osu.Objects /// internal float LazyTravelDistance; - public List RepeatSamples { get; set; } = new List(); + public List> RepeatSamples { get; set; } = new List>(); public int RepeatCount { get; set; } = 1; private int stackHeight; @@ -138,7 +138,7 @@ namespace osu.Game.Rulesets.Osu.Objects StackHeight = StackHeight, Scale = Scale, ComboColour = ComboColour, - Samples = new SampleInfoList(Samples.Select(s => new SampleInfo + Samples = new List(Samples.Select(s => new SampleInfo { Bank = s.Bank, Name = @"slidertick", @@ -170,7 +170,7 @@ namespace osu.Game.Rulesets.Osu.Objects StackHeight = StackHeight, Scale = Scale, ComboColour = ComboColour, - Samples = new SampleInfoList(RepeatSamples[repeat]) + Samples = new List(RepeatSamples[repeat]) }); } } diff --git a/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs b/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs index 9b4a6c47a9..690b80b12c 100644 --- a/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs +++ b/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs @@ -78,7 +78,7 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps var curveData = obj as IHasCurve; // Old osu! used hit sounding to determine various hit type information - SampleInfoList samples = obj.Samples; + List samples = obj.Samples; bool strong = samples.Any(s => s.Name == SampleInfo.HIT_FINISH); @@ -115,12 +115,12 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps if (!isForCurrentRuleset && tickSpacing > 0 && osuDuration < 2 * speedAdjustedBeatLength) { - List allSamples = curveData != null ? curveData.RepeatSamples : new List(new[] { samples }); + List> allSamples = curveData != null ? curveData.RepeatSamples : new List>(new[] { samples }); int i = 0; for (double j = obj.StartTime; j <= obj.StartTime + taikoDuration + tickSpacing / 8; j += tickSpacing) { - SampleInfoList currentSamples = allSamples[i]; + List currentSamples = allSamples[i]; bool isRim = currentSamples.Any(s => s.Name == SampleInfo.HIT_CLAP || s.Name == SampleInfo.HIT_WHISTLE); strong = currentSamples.Any(s => s.Name == SampleInfo.HIT_FINISH); diff --git a/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs b/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs index 4104b59979..5a566fd091 100644 --- a/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs +++ b/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs @@ -3,6 +3,7 @@ using osu.Game.Rulesets.Objects.Types; using System; +using System.Collections.Generic; using System.Linq; using osu.Game.Audio; using osu.Game.Beatmaps; @@ -75,7 +76,7 @@ namespace osu.Game.Rulesets.Taiko.Objects TickSpacing = tickSpacing, StartTime = t, IsStrong = IsStrong, - Samples = new SampleInfoList(Samples.Select(s => new SampleInfo + Samples = new List(Samples.Select(s => new SampleInfo { Bank = s.Bank, Name = @"slidertick", diff --git a/osu.Game.Rulesets.Taiko/Tests/TestCaseTaikoPlayfield.cs b/osu.Game.Rulesets.Taiko/Tests/TestCaseTaikoPlayfield.cs index bca4806108..b1e6e9c4ce 100644 --- a/osu.Game.Rulesets.Taiko/Tests/TestCaseTaikoPlayfield.cs +++ b/osu.Game.Rulesets.Taiko/Tests/TestCaseTaikoPlayfield.cs @@ -165,11 +165,15 @@ namespace osu.Game.Rulesets.Taiko.Tests private void addSwell(double duration = default_duration) { - rulesetContainer.Playfield.Add(new DrawableSwell(new Swell + var swell = new Swell { StartTime = rulesetContainer.Playfield.Time.Current + scroll_time, Duration = duration, - })); + }; + + swell.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()); + + rulesetContainer.Playfield.Add(new DrawableSwell(swell)); } private void addDrumRoll(bool strong, double duration = default_duration) @@ -184,6 +188,8 @@ namespace osu.Game.Rulesets.Taiko.Tests Duration = duration, }; + d.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()); + rulesetContainer.Playfield.Add(new DrawableDrumRoll(d)); } @@ -195,6 +201,8 @@ namespace osu.Game.Rulesets.Taiko.Tests IsStrong = strong }; + h.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()); + if (strong) rulesetContainer.Playfield.Add(new DrawableCentreHitStrong(h)); else @@ -209,6 +217,8 @@ namespace osu.Game.Rulesets.Taiko.Tests IsStrong = strong }; + h.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()); + if (strong) rulesetContainer.Playfield.Add(new DrawableRimHitStrong(h)); else diff --git a/osu.Game/Audio/SampleInfoList.cs b/osu.Game/Audio/SampleInfoList.cs deleted file mode 100644 index 06dd716a4a..0000000000 --- a/osu.Game/Audio/SampleInfoList.cs +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (c) 2007-2017 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using System.Collections.Generic; - -namespace osu.Game.Audio -{ - public class SampleInfoList : List - { - public SampleInfoList() - { - } - - public SampleInfoList(IEnumerable elements) : base(elements) - { - } - } -} \ No newline at end of file diff --git a/osu.Game/Rulesets/Objects/HitObject.cs b/osu.Game/Rulesets/Objects/HitObject.cs index e950516bf4..56f7a2e1a2 100644 --- a/osu.Game/Rulesets/Objects/HitObject.cs +++ b/osu.Game/Rulesets/Objects/HitObject.cs @@ -32,7 +32,7 @@ namespace osu.Game.Rulesets.Objects /// and can be treated as the default samples for the hit object. /// /// - public SampleInfoList Samples; + public List Samples; [JsonIgnore] public SampleControlPoint SampleControlPoint; diff --git a/osu.Game/Rulesets/Objects/Legacy/Catch/ConvertHitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/Catch/ConvertHitObjectParser.cs index 667f921e04..fbf02f5345 100644 --- a/osu.Game/Rulesets/Objects/Legacy/Catch/ConvertHitObjectParser.cs +++ b/osu.Game/Rulesets/Objects/Legacy/Catch/ConvertHitObjectParser.cs @@ -22,7 +22,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Catch }; } - protected override HitObject CreateSlider(Vector2 position, bool newCombo, List controlPoints, double length, CurveType curveType, int repeatCount, List repeatSamples) + protected override HitObject CreateSlider(Vector2 position, bool newCombo, List controlPoints, double length, CurveType curveType, int repeatCount, List> repeatSamples) { return new ConvertSlider { diff --git a/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs index 0d7d617405..bdbd7a9e65 100644 --- a/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs +++ b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs @@ -127,7 +127,7 @@ namespace osu.Game.Rulesets.Objects.Legacy } // Generate the final per-node samples - var nodeSamples = new List(nodes); + var nodeSamples = new List>(nodes); for (int i = 0; i <= repeatCount; i++) nodeSamples.Add(convertSoundType(nodeSoundTypes[i], nodeBankInfos[i])); @@ -216,7 +216,7 @@ namespace osu.Game.Rulesets.Objects.Legacy /// The slider repeat count. /// The samples to be played when the repeat nodes are hit. This includes the head and tail of the slider. /// The hit object. - protected abstract HitObject CreateSlider(Vector2 position, bool newCombo, List controlPoints, double length, CurveType curveType, int repeatCount, List repeatSamples); + protected abstract HitObject CreateSlider(Vector2 position, bool newCombo, List controlPoints, double length, CurveType curveType, int repeatCount, List> repeatSamples); /// /// Creates a legacy Spinner-type hit object. @@ -234,9 +234,9 @@ namespace osu.Game.Rulesets.Objects.Legacy /// The hold end time. protected abstract HitObject CreateHold(Vector2 position, bool newCombo, double endTime); - private SampleInfoList convertSoundType(LegacySoundType type, SampleBankInfo bankInfo) + private List convertSoundType(LegacySoundType type, SampleBankInfo bankInfo) { - var soundTypes = new SampleInfoList + var soundTypes = new List { new SampleInfo { diff --git a/osu.Game/Rulesets/Objects/Legacy/ConvertSlider.cs b/osu.Game/Rulesets/Objects/Legacy/ConvertSlider.cs index 698b74cc28..6dc8a07630 100644 --- a/osu.Game/Rulesets/Objects/Legacy/ConvertSlider.cs +++ b/osu.Game/Rulesets/Objects/Legacy/ConvertSlider.cs @@ -23,7 +23,7 @@ namespace osu.Game.Rulesets.Objects.Legacy public double Distance { get; set; } - public List RepeatSamples { get; set; } + public List> RepeatSamples { get; set; } public int RepeatCount { get; set; } = 1; public double EndTime => StartTime + RepeatCount * Distance / Velocity; diff --git a/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHitObjectParser.cs index 86dd40b06e..2060b84222 100644 --- a/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHitObjectParser.cs +++ b/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHitObjectParser.cs @@ -22,7 +22,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Mania }; } - protected override HitObject CreateSlider(Vector2 position, bool newCombo, List controlPoints, double length, CurveType curveType, int repeatCount, List repeatSamples) + protected override HitObject CreateSlider(Vector2 position, bool newCombo, List controlPoints, double length, CurveType curveType, int repeatCount, List> repeatSamples) { return new ConvertSlider { diff --git a/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertHitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertHitObjectParser.cs index 24c205db13..0062d29446 100644 --- a/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertHitObjectParser.cs +++ b/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertHitObjectParser.cs @@ -2,9 +2,9 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using OpenTK; -using osu.Game.Audio; using osu.Game.Rulesets.Objects.Types; using System.Collections.Generic; +using osu.Game.Audio; namespace osu.Game.Rulesets.Objects.Legacy.Osu { @@ -22,7 +22,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Osu }; } - protected override HitObject CreateSlider(Vector2 position, bool newCombo, List controlPoints, double length, CurveType curveType, int repeatCount, List repeatSamples) + protected override HitObject CreateSlider(Vector2 position, bool newCombo, List controlPoints, double length, CurveType curveType, int repeatCount, List> repeatSamples) { return new ConvertSlider { diff --git a/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertHitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertHitObjectParser.cs index 0554cfd97d..529a28ac15 100644 --- a/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertHitObjectParser.cs +++ b/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertHitObjectParser.cs @@ -2,9 +2,9 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using OpenTK; -using osu.Game.Audio; using osu.Game.Rulesets.Objects.Types; using System.Collections.Generic; +using osu.Game.Audio; namespace osu.Game.Rulesets.Objects.Legacy.Taiko { @@ -21,7 +21,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Taiko }; } - protected override HitObject CreateSlider(Vector2 position, bool newCombo, List controlPoints, double length, CurveType curveType, int repeatCount, List repeatSamples) + protected override HitObject CreateSlider(Vector2 position, bool newCombo, List controlPoints, double length, CurveType curveType, int repeatCount, List> repeatSamples) { return new ConvertSlider { diff --git a/osu.Game/Rulesets/Objects/Types/IHasRepeats.cs b/osu.Game/Rulesets/Objects/Types/IHasRepeats.cs index 5abad2d661..2fe2424d49 100644 --- a/osu.Game/Rulesets/Objects/Types/IHasRepeats.cs +++ b/osu.Game/Rulesets/Objects/Types/IHasRepeats.cs @@ -19,6 +19,6 @@ namespace osu.Game.Rulesets.Objects.Types /// /// The samples to be played when each repeat node is hit (0 -> first repeat node, 1 -> second repeat node, etc). /// - List RepeatSamples { get; } + List> RepeatSamples { get; } } } diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 94678106bf..1c5d20842d 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -239,7 +239,6 @@ - From 0fb620a8d3c730da1f10d1d5ab45482d783a3b2d Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 25 Dec 2017 16:41:18 +0900 Subject: [PATCH 019/101] Make HitObject.Samples non-nullable --- osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs | 5 +++-- osu.Game/Rulesets/Objects/HitObject.cs | 8 +++++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index c397ea47ef..be161b9ad3 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -84,10 +84,11 @@ namespace osu.Game.Rulesets.Objects.Drawables [BackgroundDependencyLoader] private void load(AudioManager audio) { - if (HitObject.Samples != null) + if (Samples.Count > 0) { if (HitObject.SampleControlPoint == null) - throw new ArgumentNullException(nameof(HitObject.SampleControlPoint), $"{nameof(HitObject)} must always have an attached {nameof(HitObject.SampleControlPoint)}."); + throw new ArgumentNullException(nameof(HitObject.SampleControlPoint), $"{nameof(HitObject)}s must always have an attached {nameof(HitObject.SampleControlPoint)}." + + $" This is an indication that {nameof(HitObject.ApplyDefaults)} has not been invoked on {this}."); foreach (SampleInfo s in HitObject.Samples) { diff --git a/osu.Game/Rulesets/Objects/HitObject.cs b/osu.Game/Rulesets/Objects/HitObject.cs index 56f7a2e1a2..4f06f6afe1 100644 --- a/osu.Game/Rulesets/Objects/HitObject.cs +++ b/osu.Game/Rulesets/Objects/HitObject.cs @@ -25,6 +25,8 @@ namespace osu.Game.Rulesets.Objects /// public virtual double StartTime { get; set; } + private List samples; + /// /// The samples to be played when this hit object is hit. /// @@ -32,7 +34,11 @@ namespace osu.Game.Rulesets.Objects /// and can be treated as the default samples for the hit object. /// /// - public List Samples; + public List Samples + { + get => samples ?? (samples = new List()); + set => samples = value; + } [JsonIgnore] public SampleControlPoint SampleControlPoint; From 8bfdee586b6cde7effbc17b8c3ae6b7ed1ae4dec Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 25 Dec 2017 16:47:29 +0900 Subject: [PATCH 020/101] Rename SwellSampleMapping -> DrumSampleMapping --- .../Audio/DrumSampleMapping.cs | 40 +++++++++++++++++++ .../Objects/Drawables/DrawableSwell.cs | 3 +- osu.Game.Rulesets.Taiko/Objects/Swell.cs | 15 ++----- .../Objects/SwellSampleMapping.cs | 28 ------------- .../osu.Game.Rulesets.Taiko.csproj | 2 +- 5 files changed, 47 insertions(+), 41 deletions(-) create mode 100644 osu.Game.Rulesets.Taiko/Audio/DrumSampleMapping.cs delete mode 100644 osu.Game.Rulesets.Taiko/Objects/SwellSampleMapping.cs diff --git a/osu.Game.Rulesets.Taiko/Audio/DrumSampleMapping.cs b/osu.Game.Rulesets.Taiko/Audio/DrumSampleMapping.cs new file mode 100644 index 0000000000..25fa9951df --- /dev/null +++ b/osu.Game.Rulesets.Taiko/Audio/DrumSampleMapping.cs @@ -0,0 +1,40 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using osu.Framework.Audio; +using osu.Framework.Audio.Sample; +using osu.Game.Audio; +using osu.Game.Beatmaps.ControlPoints; + +namespace osu.Game.Rulesets.Taiko.Audio +{ + public class DrumSampleMapping : IComparable + { + public double Time; + public readonly SampleInfo Centre; + public readonly SampleInfo Rim; + + public SampleChannel CentreChannel { get; private set; } + public SampleChannel RimChannel { get; private set; } + + public DrumSampleMapping() + { + } + + public DrumSampleMapping(SampleControlPoint samplePoint) + { + Time = samplePoint.Time; + Centre = samplePoint.GetSampleInfo(); + Rim = samplePoint.GetSampleInfo(SampleInfo.HIT_CLAP); + } + + public void RetrieveChannels(AudioManager audio) + { + CentreChannel = Centre.GetChannel(audio.Sample); + RimChannel = Rim.GetChannel(audio.Sample); + } + + public int CompareTo(DrumSampleMapping other) => Time.CompareTo(other.Time); + } +} diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs index d657598554..5131572abd 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs @@ -15,6 +15,7 @@ using OpenTK.Graphics; using osu.Framework.Graphics.Shapes; using osu.Game.Rulesets.Taiko.Judgements; using osu.Framework.Audio; +using osu.Game.Rulesets.Taiko.Audio; namespace osu.Game.Rulesets.Taiko.Objects.Drawables { @@ -228,7 +229,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables // While the swell hasn't been fully judged, input is still blocked so it doesn't fall through to other hitobjects // This causes the playfield to not play sounds, so they need to be handled locally - var mappingIndex = HitObject.ProgressionSamples.BinarySearch(new SwellSampleMapping { Time = Time.Current }); + var mappingIndex = HitObject.ProgressionSamples.BinarySearch(new DrumSampleMapping { Time = Time.Current }); if (mappingIndex < 0) mappingIndex = ~mappingIndex - 1; diff --git a/osu.Game.Rulesets.Taiko/Objects/Swell.cs b/osu.Game.Rulesets.Taiko/Objects/Swell.cs index b4fa736045..849c88ee4d 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Swell.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Swell.cs @@ -7,6 +7,7 @@ using osu.Game.Audio; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Rulesets.Objects.Types; +using osu.Game.Rulesets.Taiko.Audio; namespace osu.Game.Rulesets.Taiko.Objects { @@ -21,25 +22,17 @@ namespace osu.Game.Rulesets.Taiko.Objects /// public int RequiredHits = 10; - public List ProgressionSamples = new List(); + public List ProgressionSamples = new List(); protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) { base.ApplyDefaultsToSelf(controlPointInfo, difficulty); - var progressionSamplePoints = - new[] { controlPointInfo.SamplePointAt(StartTime) } + var progressionSamplePoints = new[] { controlPointInfo.SamplePointAt(StartTime) } .Concat(controlPointInfo.SamplePoints.Where(p => p.Time > StartTime && p.Time <= EndTime)); foreach (var point in progressionSamplePoints) - { - ProgressionSamples.Add(new SwellSampleMapping - { - Time = point.Time, - Centre = point.GetSampleInfo(), - Rim = point.GetSampleInfo(SampleInfo.HIT_CLAP) - }); - } + ProgressionSamples.Add(new DrumSampleMapping(point)); } } } diff --git a/osu.Game.Rulesets.Taiko/Objects/SwellSampleMapping.cs b/osu.Game.Rulesets.Taiko/Objects/SwellSampleMapping.cs deleted file mode 100644 index 99d0e1d0fd..0000000000 --- a/osu.Game.Rulesets.Taiko/Objects/SwellSampleMapping.cs +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) 2007-2017 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using System; -using osu.Framework.Audio; -using osu.Framework.Audio.Sample; -using osu.Game.Audio; - -namespace osu.Game.Rulesets.Taiko.Objects -{ - public class SwellSampleMapping : IComparable - { - public double Time; - public SampleInfo Centre; - public SampleInfo Rim; - - public SampleChannel CentreChannel { get; private set; } - public SampleChannel RimChannel { get; private set; } - - public void RetrieveChannels(AudioManager audio) - { - CentreChannel = Centre.GetChannel(audio.Sample); - RimChannel = Rim.GetChannel(audio.Sample); - } - - public int CompareTo(SwellSampleMapping other) => Time.CompareTo(other.Time); - } -} diff --git a/osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj b/osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj index 9fa3936153..f1c29c1a34 100644 --- a/osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj +++ b/osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj @@ -44,6 +44,7 @@ + @@ -74,7 +75,6 @@ - From ac8b345bfebba4530c67bbf9d0087472825ace18 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 25 Dec 2017 17:29:20 +0900 Subject: [PATCH 021/101] Make TaikoPlayfield use the new DrumSampleMapping --- osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs | 37 +++++++++----------- 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs index 2cc95fc981..96ef86e3ce 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs @@ -23,6 +23,7 @@ using osu.Framework.Audio.Sample; using System.Collections.Generic; using osu.Game.Audio; using System; +using osu.Game.Rulesets.Taiko.Audio; namespace osu.Game.Rulesets.Taiko.UI { @@ -62,7 +63,7 @@ namespace osu.Game.Rulesets.Taiko.UI private readonly Box background; private readonly ControlPointInfo controlPointInfo; - private Dictionary drumSampleMappings; + private readonly List drumSampleMappings = new List(); public TaikoPlayfield(ControlPointInfo controlPointInfo) : base(Axes.X) @@ -207,15 +208,16 @@ namespace osu.Game.Rulesets.Taiko.UI [BackgroundDependencyLoader] private void load(OsuColour colours, AudioManager audio) { - drumSampleMappings = new Dictionary(); - foreach (var s in controlPointInfo.SamplePoints) + // We may have 0 sample points, but we need at least the default one + var samplePoints = new[] { controlPointInfo.SamplePointAt(double.MinValue) } + .Concat(controlPointInfo.SamplePoints); + + foreach (var s in samplePoints) { - drumSampleMappings.Add(s, - new DrumSamples - { - Centre = s.GetSampleInfo().GetChannel(audio.Sample), - Rim = s.GetSampleInfo(SampleInfo.HIT_CLAP).GetChannel(audio.Sample) - }); + var mapping = new DrumSampleMapping(s); + mapping.RetrieveChannels(audio); + + drumSampleMappings.Add(mapping); } overlayBackgroundContainer.BorderColour = colours.Gray0; @@ -285,25 +287,20 @@ namespace osu.Game.Rulesets.Taiko.UI public bool OnPressed(TaikoAction action) { - var samplePoint = controlPointInfo.SamplePointAt(Clock.CurrentTime); + var mappingIndex = drumSampleMappings.BinarySearch(new DrumSampleMapping { Time = Time.Current }); + if (mappingIndex < 0) + mappingIndex = ~mappingIndex - 1; - if (!drumSampleMappings.TryGetValue(samplePoint, out var samples)) - throw new InvalidOperationException("Current sample set not found."); + var mapping = drumSampleMappings[mappingIndex]; if (action == TaikoAction.LeftCentre || action == TaikoAction.RightCentre) - samples.Centre.Play(); + mapping.CentreChannel.Play(); else - samples.Rim.Play(); + mapping.RimChannel.Play(); return true; } public bool OnReleased(TaikoAction action) => false; - - private class DrumSamples - { - public SampleChannel Centre; - public SampleChannel Rim; - } } } From affdd81563b21d0fdfec753bc2dcdc46cb417ad9 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 25 Dec 2017 17:29:44 +0900 Subject: [PATCH 022/101] Remove unused usings --- osu.Game.Rulesets.Taiko/Objects/Swell.cs | 1 - osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs | 3 --- 2 files changed, 4 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Objects/Swell.cs b/osu.Game.Rulesets.Taiko/Objects/Swell.cs index 849c88ee4d..714e5d29ee 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Swell.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Swell.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.Linq; -using osu.Game.Audio; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Rulesets.Objects.Types; diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs index 96ef86e3ce..229e44cf27 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs @@ -19,10 +19,7 @@ using osu.Game.Rulesets.Taiko.Objects.Drawables; using osu.Framework.Input.Bindings; using osu.Game.Beatmaps.ControlPoints; using osu.Framework.Audio; -using osu.Framework.Audio.Sample; using System.Collections.Generic; -using osu.Game.Audio; -using System; using osu.Game.Rulesets.Taiko.Audio; namespace osu.Game.Rulesets.Taiko.UI From 320a6b0480036653aa0e3f976918c00422ccedff Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 25 Dec 2017 17:12:21 +0900 Subject: [PATCH 023/101] Reduce notification output when exceptions are encountered --- osu.Game/OsuGame.cs | 40 +++++++++++++++++++++++++++++++--------- 1 file changed, 31 insertions(+), 9 deletions(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 67f6e6f4e2..95a7e696ea 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -220,15 +220,7 @@ namespace osu.Game Depth = -6, }, overlayContent.Add); - Logger.NewEntry += entry => - { - if (entry.Level < LogLevel.Important) return; - - notifications.Post(new SimpleNotification - { - Text = $@"{entry.Level}: {entry.Message}" - }); - }; + forwardLoggedErrorsToNotifications(); dependencies.Cache(settings); dependencies.Cache(social); @@ -290,6 +282,36 @@ namespace osu.Game Cursor.State = Visibility.Hidden; } + private void forwardLoggedErrorsToNotifications() + { + int recentErrorCount = 0; + + const double debounce = 5000; + + Logger.NewEntry += entry => + { + if (entry.Level < LogLevel.Error || entry.Target == null) return; + + if (recentErrorCount < 2) + { + notifications.Post(new SimpleNotification + { + Icon = FontAwesome.fa_bomb, + Text = (recentErrorCount == 0 ? entry.Message : "Subsequent errors occurred and have been logged.") + "\nClick to view log files.", + Activated = () => + { + Host.Storage.GetStorageForDirectory("logs").OpenInNativeExplorer(); + return true; + } + }); + } + + recentErrorCount++; + + Scheduler.AddDelayed(() => recentErrorCount--, debounce); + }; + } + private Task asyncLoadStream; private void loadComponentSingleFile(T d, Action add) From 6f5f4f76e5f548ac35c256122c5b23be3b8a647f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 25 Dec 2017 18:21:15 +0900 Subject: [PATCH 024/101] Use Logger.Error when exceptions are involved --- osu.Game/OsuGameBase.cs | 3 +-- osu.Game/Rulesets/Edit/HitObjectComposer.cs | 2 +- osu.Game/Screens/Play/Player.cs | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 0ddff5e5aa..ea0bf22112 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -177,8 +177,7 @@ namespace osu.Game } catch (MigrationFailedException e) { - Logger.Log((e.InnerException ?? e).ToString(), LoggingTarget.Database, LogLevel.Error); - Logger.Log("Migration failed! We'll be starting with a fresh database.", LoggingTarget.Database, LogLevel.Error); + Logger.Error(e.InnerException ?? e, "Migration failed! We'll be starting with a fresh database.", LoggingTarget.Database); // if we failed, let's delete the database and start fresh. // todo: we probably want a better (non-destructive) migrations/recovery process at a later point than this. diff --git a/osu.Game/Rulesets/Edit/HitObjectComposer.cs b/osu.Game/Rulesets/Edit/HitObjectComposer.cs index 4487f74364..36740b96cb 100644 --- a/osu.Game/Rulesets/Edit/HitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/HitObjectComposer.cs @@ -42,7 +42,7 @@ namespace osu.Game.Rulesets.Edit } catch (Exception e) { - Logger.Log($"Could not load this beatmap sucessfully ({e})!", LoggingTarget.Runtime, LogLevel.Error); + Logger.Error(e, "Could not load beatmap sucessfully!"); return; } diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 340fc39d52..2cbb203c37 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -125,7 +125,7 @@ namespace osu.Game.Screens.Play } catch (Exception e) { - Logger.Log($"Could not load this beatmap sucessfully ({e})!", LoggingTarget.Runtime, LogLevel.Error); + Logger.Error(e, "Could not load beatmap sucessfully!"); //couldn't load, hard abort! Exit(); From 96e4518e606d2282820c7bbceb8057fc049df94c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 25 Dec 2017 18:22:58 +0900 Subject: [PATCH 025/101] Add thread safety --- osu.Game/OsuGame.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 95a7e696ea..750808a291 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -16,6 +16,7 @@ using osu.Game.Screens; using osu.Game.Screens.Menu; using OpenTK; using System.Linq; +using System.Threading; using System.Threading.Tasks; using osu.Framework.Input.Bindings; using osu.Framework.Platform; @@ -306,9 +307,9 @@ namespace osu.Game }); } - recentErrorCount++; + Interlocked.Increment(ref recentErrorCount); - Scheduler.AddDelayed(() => recentErrorCount--, debounce); + Scheduler.AddDelayed(() => Interlocked.Decrement(ref recentErrorCount), debounce); }; } From 40dd66cb974fe56d80cc7de451573a118e8afa6e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 25 Dec 2017 18:31:19 +0900 Subject: [PATCH 026/101] Make TestCaseNotificationOverlay dynamically testable --- osu.Game.Tests/Visual/TestCaseNotificationOverlay.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/osu.Game.Tests/Visual/TestCaseNotificationOverlay.cs b/osu.Game.Tests/Visual/TestCaseNotificationOverlay.cs index b93c2d812f..40d7a77c10 100644 --- a/osu.Game.Tests/Visual/TestCaseNotificationOverlay.cs +++ b/osu.Game.Tests/Visual/TestCaseNotificationOverlay.cs @@ -1,6 +1,7 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System; using System.Collections.Generic; using System.Linq; using osu.Framework.Graphics; @@ -15,6 +16,15 @@ namespace osu.Game.Tests.Visual private readonly NotificationOverlay manager; private readonly List progressingNotifications = new List(); + public override IReadOnlyList RequiredTypes => new[] + { + typeof(Notification), + typeof(ProgressNotification), + typeof(ProgressCompletionNotification), + typeof(SimpleNotification), + typeof(IHasCompletionTarget), + }; + public TestCaseNotificationOverlay() { progressingNotifications.Clear(); From 861bf55773a153a35cc68c190236851608377ec3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 25 Dec 2017 18:31:32 +0900 Subject: [PATCH 027/101] Adjust notification padding a touch --- osu.Game/Overlays/Notifications/Notification.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Notifications/Notification.cs b/osu.Game/Overlays/Notifications/Notification.cs index 422051364e..dc2dcf2d74 100644 --- a/osu.Game/Overlays/Notifications/Notification.cs +++ b/osu.Game/Overlays/Notifications/Notification.cs @@ -91,7 +91,6 @@ namespace osu.Game.Overlays.Notifications AutoSizeAxes = Axes.Y, Padding = new MarginPadding { - Top = 5, Left = 45, Right = 30 }, @@ -261,4 +260,4 @@ namespace osu.Game.Overlays.Notifications } } } -} \ No newline at end of file +} From 71a94d6b44d427f24b8da0391baf7f602a4cdd2a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 25 Dec 2017 18:52:09 +0900 Subject: [PATCH 028/101] Add a bindable Enabled flag to NotificationManager Also better handles delays before notifications are displayed. --- osu.Desktop/Overlays/VersionManager.cs | 2 +- osu.Game/OsuGame.cs | 29 ++++++++++------ osu.Game/Overlays/NotificationOverlay.cs | 43 ++++++++++++++++++++++-- osu.Game/Screens/Edit/Editor.cs | 2 +- osu.Game/Screens/Loader.cs | 2 +- osu.Game/Screens/Menu/ButtonSystem.cs | 14 ++++---- osu.Game/Screens/Menu/Disclaimer.cs | 2 +- osu.Game/Screens/Menu/Intro.cs | 2 +- osu.Game/Screens/Menu/MainMenu.cs | 2 +- osu.Game/Screens/OsuScreen.cs | 14 +++++++- osu.Game/Screens/Play/Player.cs | 2 +- osu.Game/Screens/Play/PlayerLoader.cs | 2 +- osu.Game/Screens/Tournament/Drawings.cs | 2 +- 13 files changed, 89 insertions(+), 29 deletions(-) diff --git a/osu.Desktop/Overlays/VersionManager.cs b/osu.Desktop/Overlays/VersionManager.cs index 9e13003c3f..c46b0e3d12 100644 --- a/osu.Desktop/Overlays/VersionManager.cs +++ b/osu.Desktop/Overlays/VersionManager.cs @@ -110,7 +110,7 @@ namespace osu.Desktop.Overlays // only show a notification if we've previously saved a version to the config file (ie. not the first run). if (!string.IsNullOrEmpty(lastVersion)) - Scheduler.AddDelayed(() => notificationOverlay.Post(new UpdateCompleteNotification(version)), 5000); + notificationOverlay.Post(new UpdateCompleteNotification(version)); } } diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 67f6e6f4e2..391a9ee19a 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -64,6 +64,8 @@ namespace osu.Game public float ToolbarOffset => Toolbar.Position.Y + Toolbar.DrawHeight; + public readonly BindableBool ShowOverlays = new BindableBool(); + private OsuScreen screenStack; private VolumeControl volume; @@ -287,6 +289,21 @@ namespace osu.Game settings.StateChanged += stateChanged; notifications.StateChanged += stateChanged; + notifications.Enabled.BindTo(ShowOverlays); + + ShowOverlays.ValueChanged += visible => + { + //central game screen change logic. + if (!visible) + { + hideAllOverlays(); + musicController.State = Visibility.Hidden; + Toolbar.State = Visibility.Hidden; + } + else + Toolbar.State = Visibility.Visible; + }; + Cursor.State = Visibility.Hidden; } @@ -357,6 +374,8 @@ namespace osu.Game notifications.State = Visibility.Hidden; } + private ScheduledDelegate notificationsEnabler; + private void screenChanged(Screen newScreen) { currentScreen = newScreen as OsuScreen; @@ -367,16 +386,6 @@ namespace osu.Game return; } - //central game screen change logic. - if (!currentScreen.ShowOverlays) - { - hideAllOverlays(); - musicController.State = Visibility.Hidden; - Toolbar.State = Visibility.Hidden; - } - else - Toolbar.State = Visibility.Visible; - ScreenChanged?.Invoke(newScreen); } diff --git a/osu.Game/Overlays/NotificationOverlay.cs b/osu.Game/Overlays/NotificationOverlay.cs index a4b5486596..75e2ad0bdc 100644 --- a/osu.Game/Overlays/NotificationOverlay.cs +++ b/osu.Game/Overlays/NotificationOverlay.cs @@ -2,7 +2,6 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System.Linq; -using osu.Framework.Allocation; using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -11,6 +10,9 @@ using OpenTK.Graphics; using osu.Framework.Graphics.Shapes; using osu.Game.Graphics.Containers; using System; +using osu.Framework.Allocation; +using osu.Framework.Configuration; +using osu.Framework.Threading; namespace osu.Game.Overlays { @@ -20,6 +22,11 @@ namespace osu.Game.Overlays public const float TRANSITION_LENGTH = 600; + /// + /// Whether posted notifications should be processed. + /// + public readonly BindableBool Enabled = new BindableBool(true); + private FlowContainer sections; /// @@ -27,6 +34,27 @@ namespace osu.Game.Overlays /// public Func GetToolbarHeight; + public NotificationOverlay() + { + ScheduledDelegate notificationsEnabler = null; + Enabled.ValueChanged += v => + { + if (!IsLoaded) + { + processingPosts = v; + return; + } + + notificationsEnabler?.Cancel(); + + if (v) + // we want a slight delay before toggling notifications on to avoid the user becoming overwhelmed. + notificationsEnabler = Scheduler.AddDelayed(() => processingPosts = true, 1000); + else + processingPosts = false; + }; + } + [BackgroundDependencyLoader] private void load() { @@ -84,9 +112,13 @@ namespace osu.Game.Overlays State = Visibility.Hidden; } + private readonly Scheduler postScheduler = new Scheduler(); + + private bool processingPosts = true; + public void Post(Notification notification) { - Schedule(() => + postScheduler.Add(() => { State = Visibility.Visible; @@ -104,6 +136,13 @@ namespace osu.Game.Overlays }); } + protected override void Update() + { + base.Update(); + if (processingPosts) + postScheduler.Update(); + } + protected override void PopIn() { base.PopIn(); diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 19d00f3477..76f51d1c33 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -24,7 +24,7 @@ namespace osu.Game.Screens.Edit { protected override BackgroundScreen CreateBackground() => new BackgroundScreenCustom(@"Backgrounds/bg4"); - public override bool ShowOverlays => false; + public override bool ShowOverlaysOnEnter => false; private readonly Box bottomBackground; private readonly Container screenContainer; diff --git a/osu.Game/Screens/Loader.cs b/osu.Game/Screens/Loader.cs index ec2e8e0cb1..c96194f63d 100644 --- a/osu.Game/Screens/Loader.cs +++ b/osu.Game/Screens/Loader.cs @@ -17,7 +17,7 @@ namespace osu.Game.Screens { private bool showDisclaimer; - public override bool ShowOverlays => false; + public override bool ShowOverlaysOnEnter => false; public Loader() { diff --git a/osu.Game/Screens/Menu/ButtonSystem.cs b/osu.Game/Screens/Menu/ButtonSystem.cs index ce7856c5a9..c82d90d16c 100644 --- a/osu.Game/Screens/Menu/ButtonSystem.cs +++ b/osu.Game/Screens/Menu/ButtonSystem.cs @@ -11,12 +11,12 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Input; using osu.Game.Graphics; -using osu.Game.Overlays.Toolbar; using OpenTK; using OpenTK.Graphics; using OpenTK.Input; using osu.Framework.Audio.Sample; using osu.Framework.Audio; +using osu.Framework.Configuration; using osu.Framework.Threading; namespace osu.Game.Screens.Menu @@ -25,6 +25,8 @@ namespace osu.Game.Screens.Menu { public event Action StateChanged; + private readonly BindableBool showOverlays = new BindableBool(); + public Action OnEdit; public Action OnExit; public Action OnDirect; @@ -34,8 +36,6 @@ namespace osu.Game.Screens.Menu public Action OnChart; public Action OnTest; - private Toolbar toolbar; - private readonly FlowContainerWithOrigin buttonFlow; //todo: make these non-internal somehow. @@ -131,9 +131,9 @@ namespace osu.Game.Screens.Menu } [BackgroundDependencyLoader(true)] - private void load(AudioManager audio, OsuGame game = null) + private void load(AudioManager audio, OsuGame game) { - toolbar = game?.Toolbar; + if (game != null) showOverlays.BindTo(game.ShowOverlays); sampleBack = audio.Sample.Get(@"Menu/button-back-select"); } @@ -300,7 +300,7 @@ namespace osu.Game.Screens.Menu logoDelayedAction = Scheduler.AddDelayed(() => { - toolbar?.Hide(); + showOverlays.Value = false; logo.ClearTransforms(targetMember: nameof(Position)); logo.RelativePositionAxes = Axes.Both; @@ -329,7 +329,7 @@ namespace osu.Game.Screens.Menu logoTracking = true; logo.Impact(); - toolbar?.Show(); + showOverlays.Value = true; }, 200); break; default: diff --git a/osu.Game/Screens/Menu/Disclaimer.cs b/osu.Game/Screens/Menu/Disclaimer.cs index 532ee71b72..d0ad613640 100644 --- a/osu.Game/Screens/Menu/Disclaimer.cs +++ b/osu.Game/Screens/Menu/Disclaimer.cs @@ -18,7 +18,7 @@ namespace osu.Game.Screens.Menu private readonly SpriteIcon icon; private Color4 iconColour; - public override bool ShowOverlays => false; + public override bool ShowOverlaysOnEnter => false; public override bool HasLocalCursorDisplayed => true; diff --git a/osu.Game/Screens/Menu/Intro.cs b/osu.Game/Screens/Menu/Intro.cs index d7beb34a2f..a6a1afa320 100644 --- a/osu.Game/Screens/Menu/Intro.cs +++ b/osu.Game/Screens/Menu/Intro.cs @@ -33,7 +33,7 @@ namespace osu.Game.Screens.Menu public override bool HasLocalCursorDisplayed => true; - public override bool ShowOverlays => false; + public override bool ShowOverlaysOnEnter => false; protected override BackgroundScreen CreateBackground() => new BackgroundScreenEmpty(); diff --git a/osu.Game/Screens/Menu/MainMenu.cs b/osu.Game/Screens/Menu/MainMenu.cs index 90f68ba9f1..fac0ec1422 100644 --- a/osu.Game/Screens/Menu/MainMenu.cs +++ b/osu.Game/Screens/Menu/MainMenu.cs @@ -24,7 +24,7 @@ namespace osu.Game.Screens.Menu { private readonly ButtonSystem buttons; - public override bool ShowOverlays => buttons.State != MenuState.Initial; + public override bool ShowOverlaysOnEnter => buttons.State != MenuState.Initial; private readonly BackgroundScreenDefault background; private Screen songSelect; diff --git a/osu.Game/Screens/OsuScreen.cs b/osu.Game/Screens/OsuScreen.cs index 4a27c7f1ea..0013d1a882 100644 --- a/osu.Game/Screens/OsuScreen.cs +++ b/osu.Game/Screens/OsuScreen.cs @@ -28,7 +28,12 @@ namespace osu.Game.Screens /// protected virtual BackgroundScreen CreateBackground() => null; - public virtual bool ShowOverlays => true; + protected BindableBool ShowOverlays = new BindableBool(); + + /// + /// Whether overlays should be shown when this screen is entered or resumed. + /// + public virtual bool ShowOverlaysOnEnter => true; protected new OsuGameBase Game => base.Game as OsuGameBase; @@ -70,7 +75,10 @@ namespace osu.Game.Screens } if (osuGame != null) + { Ruleset.BindTo(osuGame.Ruleset); + ShowOverlays.BindTo(osuGame.ShowOverlays); + } sampleExit = audio.Sample.Get(@"UI/screen-back"); } @@ -94,6 +102,8 @@ namespace osu.Game.Screens base.OnResuming(last); logo.AppendAnimatingAction(() => LogoArriving(logo, true), true); sampleExit?.Play(); + + ShowOverlays.Value = ShowOverlaysOnEnter; } protected override void OnSuspending(Screen next) @@ -139,6 +149,8 @@ namespace osu.Game.Screens logo.AppendAnimatingAction(() => LogoArriving(logo, false), true); base.OnEntering(last); + + ShowOverlays.Value = ShowOverlaysOnEnter; } protected override bool OnExiting(Screen next) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 340fc39d52..d5cd89c386 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -35,7 +35,7 @@ namespace osu.Game.Screens.Play { protected override BackgroundScreen CreateBackground() => new BackgroundScreenBeatmap(Beatmap); - public override bool ShowOverlays => false; + public override bool ShowOverlaysOnEnter => false; public override bool HasLocalCursorDisplayed => !pauseContainer.IsPaused && !HasFailed && RulesetContainer.ProvidingUserCursor; diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index de67bef004..c2a8f13207 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -23,7 +23,7 @@ namespace osu.Game.Screens.Play private BeatmapMetadataDisplay info; private bool showOverlays = true; - public override bool ShowOverlays => showOverlays; + public override bool ShowOverlaysOnEnter => showOverlays; public override bool AllowBeatmapRulesetChange => false; diff --git a/osu.Game/Screens/Tournament/Drawings.cs b/osu.Game/Screens/Tournament/Drawings.cs index 3e7ab56c99..fbf24eb609 100644 --- a/osu.Game/Screens/Tournament/Drawings.cs +++ b/osu.Game/Screens/Tournament/Drawings.cs @@ -29,7 +29,7 @@ namespace osu.Game.Screens.Tournament { private const string results_filename = "drawings_results.txt"; - public override bool ShowOverlays => false; + public override bool ShowOverlaysOnEnter => false; protected override BackgroundScreen CreateBackground() => new BackgroundScreenDefault(); From bb4b5bebf915eaf845d702e10b2285274c510839 Mon Sep 17 00:00:00 2001 From: Aergwyn Date: Mon, 25 Dec 2017 15:25:47 +0100 Subject: [PATCH 029/101] fix supporter icon in profile missing its background also it doesn't show up on profiles without supporter anymore --- osu.Game.Tests/Visual/TestCaseUserProfile.cs | 25 +++++++- osu.Game/Overlays/Profile/ProfileHeader.cs | 31 +++------- osu.Game/Overlays/Profile/SupporterIcon.cs | 61 ++++++++++++++++++++ osu.Game/Overlays/UserProfileOverlay.cs | 8 +-- osu.Game/Users/UserPanel.cs | 50 +--------------- osu.Game/osu.Game.csproj | 1 + 6 files changed, 97 insertions(+), 79 deletions(-) create mode 100644 osu.Game/Overlays/Profile/SupporterIcon.cs diff --git a/osu.Game.Tests/Visual/TestCaseUserProfile.cs b/osu.Game.Tests/Visual/TestCaseUserProfile.cs index 38d59f03b5..88627755f4 100644 --- a/osu.Game.Tests/Visual/TestCaseUserProfile.cs +++ b/osu.Game.Tests/Visual/TestCaseUserProfile.cs @@ -13,6 +13,8 @@ namespace osu.Game.Tests.Visual { public class TestCaseUserProfile : OsuTestCase { + private readonly TestUserProfileOverlay profile; + public override IReadOnlyList RequiredTypes => new[] { typeof(ProfileHeader), @@ -23,8 +25,7 @@ namespace osu.Game.Tests.Visual public TestCaseUserProfile() { - var profile = new UserProfileOverlay(); - Add(profile); + Add(profile = new TestUserProfileOverlay()); AddStep("Show offline dummy", () => profile.ShowUser(new User { @@ -48,6 +49,9 @@ namespace osu.Game.Tests.Visual Data = Enumerable.Range(2345, 45).Concat(Enumerable.Range(2109, 40)).ToArray() } }, false)); + + checkSupporterTag(false); + AddStep("Show ppy", () => profile.ShowUser(new User { Username = @"peppy", @@ -55,6 +59,9 @@ namespace osu.Game.Tests.Visual Country = new Country { FullName = @"Australia", FlagName = @"AU" }, CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c3.jpg" })); + + checkSupporterTag(true); + AddStep("Show flyte", () => profile.ShowUser(new User { Username = @"flyte", @@ -62,8 +69,22 @@ namespace osu.Game.Tests.Visual Country = new Country { FullName = @"Japan", FlagName = @"JP" }, CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c6.jpg" })); + AddStep("Hide", profile.Hide); AddStep("Show without reload", profile.Show); } + + private void checkSupporterTag(bool isSupporter) + { + AddUntilStep(() => profile.Header.User != null, "wait for load"); + if(isSupporter) + AddAssert("is supporter", () => profile.Header.SupporterTag.Alpha == 1); + else + AddAssert("no supporter", () => profile.Header.SupporterTag.Alpha == 0); + } + + private class TestUserProfileOverlay : UserProfileOverlay { + public new ProfileHeader Header => base.Header; + } } } diff --git a/osu.Game/Overlays/Profile/ProfileHeader.cs b/osu.Game/Overlays/Profile/ProfileHeader.cs index a706799664..f000ca74d4 100644 --- a/osu.Game/Overlays/Profile/ProfileHeader.cs +++ b/osu.Game/Overlays/Profile/ProfileHeader.cs @@ -29,7 +29,8 @@ namespace osu.Game.Overlays.Profile private readonly FillFlowContainer scoreText, scoreNumberText; private readonly RankGraph rankGraph; - private readonly Container coverContainer, supporterTag; + public readonly SupporterIcon SupporterTag; + private readonly Container coverContainer; private readonly Sprite levelBadge; private readonly SpriteText levelText; private readonly GradeBadge gradeSSPlus, gradeSS, gradeSPlus, gradeS, gradeA; @@ -94,32 +95,13 @@ namespace osu.Game.Overlays.Profile AutoSizeAxes = Axes.Both, Children = new Drawable[] { - supporterTag = new CircularContainer + SupporterTag = new SupporterIcon { + Alpha = 0, Anchor = Anchor.BottomLeft, Origin = Anchor.BottomLeft, Y = -75, - Size = new Vector2(25, 25), - Masking = true, - BorderThickness = 3, - BorderColour = Color4.White, - Alpha = 0, - Children = new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Alpha = 0, - AlwaysPresent = true - }, - new SpriteIcon - { - Icon = FontAwesome.fa_heart, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Size = new Vector2(12), - } - } + Size = new Vector2(25, 25) }, new LinkFlowContainer.ProfileLink(user) { @@ -328,7 +310,8 @@ namespace osu.Game.Overlays.Profile Depth = float.MaxValue, }, coverContainer.Add); - if (user.IsSupporter) supporterTag.Show(); + if (user.IsSupporter) + SupporterTag.Show(); if (!string.IsNullOrEmpty(user.Colour)) { diff --git a/osu.Game/Overlays/Profile/SupporterIcon.cs b/osu.Game/Overlays/Profile/SupporterIcon.cs new file mode 100644 index 0000000000..570d5a13bb --- /dev/null +++ b/osu.Game/Overlays/Profile/SupporterIcon.cs @@ -0,0 +1,61 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using OpenTK; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Game.Graphics; +using osu.Game.Graphics.Backgrounds; + +namespace osu.Game.Overlays.Profile +{ + public class SupporterIcon : CircularContainer + { + private readonly Box background; + + public SupporterIcon() + { + Masking = true; + Children = new Drawable[] + { + new Box { RelativeSizeAxes = Axes.Both }, + new CircularContainer + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Scale = new Vector2(0.8f), + Masking = true, + Children = new Drawable[] + { + background = new Box { RelativeSizeAxes = Axes.Both }, + new Triangles + { + TriangleScale = 0.2f, + ColourLight = OsuColour.FromHex(@"ff7db7"), + ColourDark = OsuColour.FromHex(@"de5b95"), + RelativeSizeAxes = Axes.Both, + Velocity = 0.3f, + }, + } + }, + new SpriteIcon + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Icon = FontAwesome.fa_heart, + Scale = new Vector2(0.45f), + } + }; + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + background.Colour = colours.Pink; + } + } +} diff --git a/osu.Game/Overlays/UserProfileOverlay.cs b/osu.Game/Overlays/UserProfileOverlay.cs index 7374a9aa44..9aa660147a 100644 --- a/osu.Game/Overlays/UserProfileOverlay.cs +++ b/osu.Game/Overlays/UserProfileOverlay.cs @@ -28,7 +28,7 @@ namespace osu.Game.Overlays private ProfileSection[] sections; private GetUserRequest userReq; private APIAccess api; - private ProfileHeader header; + protected ProfileHeader Header; private SectionsContainer sectionsContainer; private ProfileTabControl tabs; @@ -113,12 +113,12 @@ namespace osu.Game.Overlays Colour = OsuColour.Gray(0.2f) }); - header = new ProfileHeader(user); + Header = new ProfileHeader(user); Add(sectionsContainer = new SectionsContainer { RelativeSizeAxes = Axes.Both, - ExpandableHeader = header, + ExpandableHeader = Header, FixedHeader = tabs, HeaderBackground = new Box { @@ -169,7 +169,7 @@ namespace osu.Game.Overlays private void userLoadComplete(User user) { - header.User = user; + Header.User = user; foreach (string id in user.ProfileOrder) { diff --git a/osu.Game/Users/UserPanel.cs b/osu.Game/Users/UserPanel.cs index d056afcf54..a2cc8e8d49 100644 --- a/osu.Game/Users/UserPanel.cs +++ b/osu.Game/Users/UserPanel.cs @@ -16,8 +16,8 @@ using osu.Game.Overlays; using osu.Framework.Graphics.UserInterface; using osu.Game.Graphics.UserInterface; using osu.Framework.Graphics.Cursor; -using osu.Game.Graphics.Backgrounds; using osu.Game.Graphics.Containers; +using osu.Game.Overlays.Profile; namespace osu.Game.Users { @@ -220,53 +220,5 @@ namespace osu.Game.Users { new OsuMenuItem("View Profile", MenuItemType.Highlighted, ViewProfile), }; - - private class SupporterIcon : CircularContainer - { - private readonly Box background; - - public SupporterIcon() - { - Masking = true; - Children = new Drawable[] - { - new Box { RelativeSizeAxes = Axes.Both }, - new CircularContainer - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Both, - Scale = new Vector2(0.8f), - Masking = true, - Children = new Drawable[] - { - background = new Box { RelativeSizeAxes = Axes.Both }, - new Triangles - { - TriangleScale = 0.2f, - ColourLight = OsuColour.FromHex(@"ff7db7"), - ColourDark = OsuColour.FromHex(@"de5b95"), - RelativeSizeAxes = Axes.Both, - Velocity = 0.3f, - }, - } - }, - new SpriteIcon - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Both, - Icon = FontAwesome.fa_heart, - Scale = new Vector2(0.45f), - } - }; - } - - [BackgroundDependencyLoader] - private void load(OsuColour colours) - { - background.Colour = colours.Pink; - } - } } } diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 94678106bf..18134582f3 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -268,6 +268,7 @@ + From f76878e2fea6b2e7fd23163cd9d42dc6211f623d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 26 Dec 2017 00:34:12 +0900 Subject: [PATCH 030/101] Add a very basic popup testcase --- osu.Game.Tests/Visual/TestCasePopupDialog.cs | 37 ++++++++++++++++++++ osu.Game.Tests/osu.Game.Tests.csproj | 1 + 2 files changed, 38 insertions(+) create mode 100644 osu.Game.Tests/Visual/TestCasePopupDialog.cs diff --git a/osu.Game.Tests/Visual/TestCasePopupDialog.cs b/osu.Game.Tests/Visual/TestCasePopupDialog.cs new file mode 100644 index 0000000000..ed9c47a253 --- /dev/null +++ b/osu.Game.Tests/Visual/TestCasePopupDialog.cs @@ -0,0 +1,37 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Graphics; +using osu.Game.Graphics; +using osu.Game.Overlays.Dialog; + +namespace osu.Game.Tests.Visual +{ + public class TestCasePopupDialog : OsuTestCase + { + public TestCasePopupDialog() + { + var popup = new PopupDialog + { + RelativeSizeAxes = Axes.Both, + State = Framework.Graphics.Containers.Visibility.Visible, + Icon = FontAwesome.fa_assistive_listening_systems, + HeaderText = @"This is a test popup", + BodyText = "I can say lots of stuff and even wrap my words!", + Buttons = new PopupDialogButton[] + { + new PopupDialogCancelButton + { + Text = @"Yes. That you can.", + }, + new PopupDialogOkButton + { + Text = @"You're a fake!", + }, + } + }; + + Add(popup); + } + } +} diff --git a/osu.Game.Tests/osu.Game.Tests.csproj b/osu.Game.Tests/osu.Game.Tests.csproj index ff012bb6e2..134fc4a6ac 100644 --- a/osu.Game.Tests/osu.Game.Tests.csproj +++ b/osu.Game.Tests/osu.Game.Tests.csproj @@ -134,6 +134,7 @@ + From 929633efaa8ad611969e678a9cfe796d4014b86b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 26 Dec 2017 00:34:40 +0900 Subject: [PATCH 031/101] Make body text in popups word wrap properly --- osu.Game/Overlays/Dialog/PopupDialog.cs | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/osu.Game/Overlays/Dialog/PopupDialog.cs b/osu.Game/Overlays/Dialog/PopupDialog.cs index 9b19b8150e..d2bd50cad6 100644 --- a/osu.Game/Overlays/Dialog/PopupDialog.cs +++ b/osu.Game/Overlays/Dialog/PopupDialog.cs @@ -32,7 +32,7 @@ namespace osu.Game.Overlays.Dialog private readonly FillFlowContainer buttonsContainer; private readonly SpriteIcon icon; private readonly SpriteText header; - private readonly SpriteText body; + private readonly TextFlowContainer body; public FontAwesome Icon { @@ -48,7 +48,6 @@ namespace osu.Game.Overlays.Dialog public string BodyText { - get { return body.Text; } set { body.Text = value; } } @@ -220,17 +219,15 @@ namespace osu.Game.Overlays.Dialog { Origin = Anchor.TopCentre, Anchor = Anchor.TopCentre, - Text = @"Header", TextSize = 25, Shadow = true, }, - body = new OsuSpriteText + body = new OsuTextFlowContainer(t => t.TextSize = 18) { - Origin = Anchor.TopCentre, - Anchor = Anchor.TopCentre, - Text = @"Body", - TextSize = 18, - Shadow = true, + Padding = new MarginPadding(15), + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + TextAnchor = Anchor.TopCentre, }, }, }, From 3c1654e5e496d8c22927019ca9a90d0177045b58 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 26 Dec 2017 00:44:35 +0900 Subject: [PATCH 032/101] Fix many instances of non-osu-prefixed text classes being used Results in incorrect default formatting. --- osu.Game/Overlays/BeatmapSet/Info.cs | 3 ++- osu.Game/Overlays/MedalSplash/DrawableMedal.cs | 3 ++- osu.Game/Overlays/Notifications/ProgressNotification.cs | 3 ++- osu.Game/Overlays/Notifications/SimpleNotification.cs | 5 +++-- osu.Game/Overlays/OnScreenDisplay.cs | 7 ++++--- osu.Game/Overlays/Profile/ProfileHeader.cs | 2 +- osu.Game/Overlays/Profile/Sections/Kudosu/KudosuInfo.cs | 3 ++- osu.Game/Screens/Ranking/Results.cs | 9 +++++---- osu.Game/Screens/Ranking/ResultsPageScore.cs | 4 ++-- osu.Game/Screens/Select/BeatmapDetails.cs | 5 +++-- osu.Game/Tests/Visual/TestCasePerformancePoints.cs | 3 +-- osu.sln.DotSettings | 5 +++++ 12 files changed, 32 insertions(+), 20 deletions(-) diff --git a/osu.Game/Overlays/BeatmapSet/Info.cs b/osu.Game/Overlays/BeatmapSet/Info.cs index bd108a193b..b4aea898b2 100644 --- a/osu.Game/Overlays/BeatmapSet/Info.cs +++ b/osu.Game/Overlays/BeatmapSet/Info.cs @@ -8,6 +8,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Game.Beatmaps; using osu.Game.Graphics; +using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using OpenTK; using OpenTK.Graphics; @@ -176,7 +177,7 @@ namespace osu.Game.Overlays.BeatmapSet Shadow = false, Margin = new MarginPadding { Top = 20 }, }, - textFlow = new TextFlowContainer + textFlow = new OsuTextFlowContainer { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, diff --git a/osu.Game/Overlays/MedalSplash/DrawableMedal.cs b/osu.Game/Overlays/MedalSplash/DrawableMedal.cs index 53d77dab6c..c6be428987 100644 --- a/osu.Game/Overlays/MedalSplash/DrawableMedal.cs +++ b/osu.Game/Overlays/MedalSplash/DrawableMedal.cs @@ -10,6 +10,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; using osu.Game.Graphics; +using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Users; @@ -88,7 +89,7 @@ namespace osu.Game.Overlays.MedalSplash Alpha = 0f, Scale = new Vector2(1f / scale_when_full), }, - description = new TextFlowContainer + description = new OsuTextFlowContainer { TextAnchor = Anchor.TopCentre, Anchor = Anchor.TopCentre, diff --git a/osu.Game/Overlays/Notifications/ProgressNotification.cs b/osu.Game/Overlays/Notifications/ProgressNotification.cs index 12c7fe64ba..9211c227f8 100644 --- a/osu.Game/Overlays/Notifications/ProgressNotification.cs +++ b/osu.Game/Overlays/Notifications/ProgressNotification.cs @@ -7,6 +7,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Game.Graphics; +using osu.Game.Graphics.Containers; using OpenTK; using OpenTK.Graphics; @@ -114,7 +115,7 @@ namespace osu.Game.Overlays.Notifications RelativeSizeAxes = Axes.Both, }); - Content.Add(textDrawable = new TextFlowContainer(t => + Content.Add(textDrawable = new OsuTextFlowContainer(t => { t.TextSize = 16; }) diff --git a/osu.Game/Overlays/Notifications/SimpleNotification.cs b/osu.Game/Overlays/Notifications/SimpleNotification.cs index daf1ac838d..0b8b365c48 100644 --- a/osu.Game/Overlays/Notifications/SimpleNotification.cs +++ b/osu.Game/Overlays/Notifications/SimpleNotification.cs @@ -7,6 +7,7 @@ using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Game.Graphics; +using osu.Game.Graphics.Containers; using OpenTK; namespace osu.Game.Overlays.Notifications @@ -58,7 +59,7 @@ namespace osu.Game.Overlays.Notifications } }); - Content.Add(textDrawable = new TextFlowContainer(t => t.TextSize = 16) + Content.Add(textDrawable = new OsuTextFlowContainer(t => t.TextSize = 16) { Colour = OsuColour.Gray(128), AutoSizeAxes = Axes.Y, @@ -87,4 +88,4 @@ namespace osu.Game.Overlays.Notifications } } } -} \ No newline at end of file +} diff --git a/osu.Game/Overlays/OnScreenDisplay.cs b/osu.Game/Overlays/OnScreenDisplay.cs index dcab942522..ce0feeb4c6 100644 --- a/osu.Game/Overlays/OnScreenDisplay.cs +++ b/osu.Game/Overlays/OnScreenDisplay.cs @@ -14,6 +14,7 @@ using osu.Game.Graphics; using OpenTK; using OpenTK.Graphics; using osu.Framework.Extensions.Color4Extensions; +using osu.Game.Graphics.Sprites; namespace osu.Game.Overlays { @@ -63,7 +64,7 @@ namespace osu.Game.Overlays Width = 240, RelativeSizeAxes = Axes.Y, }, - textLine1 = new SpriteText + textLine1 = new OsuSpriteText { Padding = new MarginPadding(10), Font = @"Exo2.0-Black", @@ -72,7 +73,7 @@ namespace osu.Game.Overlays Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, }, - textLine2 = new SpriteText + textLine2 = new OsuSpriteText { TextSize = 24, Font = @"Exo2.0-Light", @@ -97,7 +98,7 @@ namespace osu.Game.Overlays Origin = Anchor.TopCentre, AutoSizeAxes = Axes.Both }, - textLine3 = new SpriteText + textLine3 = new OsuSpriteText { Padding = new MarginPadding { Bottom = 15 }, Font = @"Exo2.0-Bold", diff --git a/osu.Game/Overlays/Profile/ProfileHeader.cs b/osu.Game/Overlays/Profile/ProfileHeader.cs index a706799664..4cdb6ec958 100644 --- a/osu.Game/Overlays/Profile/ProfileHeader.cs +++ b/osu.Game/Overlays/Profile/ProfileHeader.cs @@ -473,7 +473,7 @@ namespace osu.Game.Overlays.Profile Width = width, Height = 26 }); - Add(numberText = new SpriteText + Add(numberText = new OsuSpriteText { Anchor = Anchor.BottomCentre, Origin = Anchor.BottomCentre, diff --git a/osu.Game/Overlays/Profile/Sections/Kudosu/KudosuInfo.cs b/osu.Game/Overlays/Profile/Sections/Kudosu/KudosuInfo.cs index 8a835634b8..904ed609e8 100644 --- a/osu.Game/Overlays/Profile/Sections/Kudosu/KudosuInfo.cs +++ b/osu.Game/Overlays/Profile/Sections/Kudosu/KudosuInfo.cs @@ -10,6 +10,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Input; using osu.Game.Graphics; +using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Users; @@ -120,7 +121,7 @@ namespace osu.Game.Overlays.Profile.Sections.Kudosu } } }, - new TextFlowContainer(t => { t.TextSize = 19; }) + new OsuTextFlowContainer(t => { t.TextSize = 19; }) { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, diff --git a/osu.Game/Screens/Ranking/Results.cs b/osu.Game/Screens/Ranking/Results.cs index 8e27cb235c..406887624c 100644 --- a/osu.Game/Screens/Ranking/Results.cs +++ b/osu.Game/Screens/Ranking/Results.cs @@ -17,6 +17,7 @@ using OpenTK.Graphics; using osu.Game.Graphics; using osu.Game.Graphics.UserInterface; using osu.Framework.Graphics.Shapes; +using osu.Game.Graphics.Sprites; namespace osu.Game.Screens.Ranking { @@ -183,7 +184,7 @@ namespace osu.Game.Screens.Ranking Height = 50, Margin = new MarginPadding { Bottom = 110 }, }, - new SpriteText + new OsuSpriteText { Text = $"{score.MaxCombo}x", TextSize = 40, @@ -194,7 +195,7 @@ namespace osu.Game.Screens.Ranking Anchor = Anchor.CentreLeft, Origin = Anchor.BottomCentre, }, - new SpriteText + new OsuSpriteText { Text = "max combo", TextSize = 20, @@ -204,7 +205,7 @@ namespace osu.Game.Screens.Ranking Anchor = Anchor.CentreLeft, Origin = Anchor.TopCentre, }, - new SpriteText + new OsuSpriteText { Text = $"{score.Accuracy:P2}", TextSize = 40, @@ -215,7 +216,7 @@ namespace osu.Game.Screens.Ranking Anchor = Anchor.CentreLeft, Origin = Anchor.BottomCentre, }, - new SpriteText + new OsuSpriteText { Text = "accuracy", TextSize = 20, diff --git a/osu.Game/Screens/Ranking/ResultsPageScore.cs b/osu.Game/Screens/Ranking/ResultsPageScore.cs index 911b688669..4c776aa7ab 100644 --- a/osu.Game/Screens/Ranking/ResultsPageScore.cs +++ b/osu.Game/Screens/Ranking/ResultsPageScore.cs @@ -201,14 +201,14 @@ namespace osu.Game.Screens.Ranking { Children = new Drawable[] { - new SpriteText { + new OsuSpriteText { Text = statistic.Value.ToString().PadLeft(4, '0'), Colour = colours.Gray7, TextSize = 30, Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, }, - new SpriteText { + new OsuSpriteText { Text = statistic.Key, Colour = colours.Gray7, Font = @"Exo2.0-Bold", diff --git a/osu.Game/Screens/Select/BeatmapDetails.cs b/osu.Game/Screens/Select/BeatmapDetails.cs index a9a778fe17..79d76dd00e 100644 --- a/osu.Game/Screens/Select/BeatmapDetails.cs +++ b/osu.Game/Screens/Select/BeatmapDetails.cs @@ -17,6 +17,7 @@ using osu.Framework.Graphics.Shapes; using osu.Framework.Extensions.Color4Extensions; using osu.Game.Screens.Select.Details; using osu.Game.Beatmaps; +using osu.Game.Graphics.Containers; namespace osu.Game.Screens.Select { @@ -334,7 +335,7 @@ namespace osu.Game.Screens.Select TextSize = 14, }, }, - textFlow = new TextFlowContainer + textFlow = new OsuTextFlowContainer { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, @@ -359,7 +360,7 @@ namespace osu.Game.Screens.Select private void setTextAsync(string text) { - LoadComponentAsync(new TextFlowContainer(s => s.TextSize = 14) + LoadComponentAsync(new OsuTextFlowContainer(s => s.TextSize = 14) { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, diff --git a/osu.Game/Tests/Visual/TestCasePerformancePoints.cs b/osu.Game/Tests/Visual/TestCasePerformancePoints.cs index f71bece279..8984fc843f 100644 --- a/osu.Game/Tests/Visual/TestCasePerformancePoints.cs +++ b/osu.Game/Tests/Visual/TestCasePerformancePoints.cs @@ -12,7 +12,6 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.Shapes; -using osu.Framework.Graphics.Sprites; using osu.Framework.Input; using osu.Game.Beatmaps; using osu.Game.Graphics.Sprites; @@ -224,7 +223,7 @@ namespace osu.Game.Tests.Visual if (!api.IsLoggedIn) { - InternalChild = new SpriteText + InternalChild = new OsuSpriteText { Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, diff --git a/osu.sln.DotSettings b/osu.sln.DotSettings index 2f52881d6d..20007e3306 100644 --- a/osu.sln.DotSettings +++ b/osu.sln.DotSettings @@ -172,6 +172,7 @@ NEXT_LINE NEXT_LINE True + NEVER False False True @@ -655,7 +656,11 @@ Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-frame <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> True + True + True + True True True + True True True From 3c8d30f8e67158ce5b105ce28eff9b726aa09093 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 26 Dec 2017 00:37:50 +0900 Subject: [PATCH 033/101] Add a dialog offering to import beatmaps from stable --- osu.Game/Beatmaps/BeatmapManager.cs | 6 ++-- .../Sections/Maintenance/GeneralSettings.cs | 3 +- .../Screens/Select/ImportFromStablePopup.cs | 33 +++++++++++++++++++ osu.Game/Screens/Select/PlaySongSelect.cs | 15 +++++++-- osu.Game/osu.Game.csproj | 1 + 5 files changed, 52 insertions(+), 6 deletions(-) create mode 100644 osu.Game/Screens/Select/ImportFromStablePopup.cs diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 0325785016..c86860f7b0 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -697,10 +697,12 @@ namespace osu.Game.Beatmaps } } + public bool StableInstallationAvailable => GetStableStorage?.Invoke() != null; + /// /// This is a temporary method and will likely be replaced by a full-fledged (and more correctly placed) migration process in the future. /// - public void ImportFromStable() + public async Task ImportFromStable() { var stable = GetStableStorage?.Invoke(); @@ -710,7 +712,7 @@ namespace osu.Game.Beatmaps return; } - Import(stable.GetDirectories("Songs")); + await Task.Factory.StartNew(() => Import(stable.GetDirectories("Songs")), TaskCreationOptions.LongRunning); } public void DeleteAll() diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs index e288445c6d..9ab4143613 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs @@ -30,8 +30,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance Action = () => { importButton.Enabled.Value = false; - Task.Factory.StartNew(beatmaps.ImportFromStable) - .ContinueWith(t => Schedule(() => importButton.Enabled.Value = true), TaskContinuationOptions.LongRunning); + beatmaps.ImportFromStable().ContinueWith(t => Schedule(() => importButton.Enabled.Value = true)); } }, deleteButton = new DangerousSettingsButton diff --git a/osu.Game/Screens/Select/ImportFromStablePopup.cs b/osu.Game/Screens/Select/ImportFromStablePopup.cs new file mode 100644 index 0000000000..489ab79fa4 --- /dev/null +++ b/osu.Game/Screens/Select/ImportFromStablePopup.cs @@ -0,0 +1,33 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using osu.Game.Graphics; +using osu.Game.Overlays.Dialog; + +namespace osu.Game.Screens.Select +{ + public class ImportFromStablePopup : PopupDialog + { + public ImportFromStablePopup(Action importFromStable) + { + HeaderText = @"You have no beatmaps!"; + BodyText = "An existing copy of osu! was found, though.\nWould you like to import your beatmaps?"; + + Icon = FontAwesome.fa_trash_o; + + Buttons = new PopupDialogButton[] + { + new PopupDialogOkButton + { + Text = @"Yes please!", + Action = importFromStable + }, + new PopupDialogCancelButton + { + Text = @"No, I'd like to start from scratch", + }, + }; + } + } +} diff --git a/osu.Game/Screens/Select/PlaySongSelect.cs b/osu.Game/Screens/Select/PlaySongSelect.cs index 4a0ee31fbb..727cdb9959 100644 --- a/osu.Game/Screens/Select/PlaySongSelect.cs +++ b/osu.Game/Screens/Select/PlaySongSelect.cs @@ -11,6 +11,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Screens; using osu.Game.Beatmaps; using osu.Game.Graphics; +using osu.Game.Overlays; using osu.Game.Overlays.Mods; using osu.Game.Screens.Edit; using osu.Game.Screens.Play; @@ -45,8 +46,8 @@ namespace osu.Game.Screens.Select private SampleChannel sampleConfirm; - [BackgroundDependencyLoader] - private void load(OsuColour colours, AudioManager audio) + [BackgroundDependencyLoader(true)] + private void load(OsuColour colours, AudioManager audio, BeatmapManager beatmaps, DialogOverlay dialogOverlay) { sampleConfirm = audio.Sample.Get(@"SongSelect/confirm-selection"); @@ -59,6 +60,16 @@ namespace osu.Game.Screens.Select ValidForResume = false; Push(new Editor()); }, Key.Number3); + + if (dialogOverlay != null) + { + Schedule(() => + { + // if we have no beatmaps but osu-stable is found, let's prompt the user to import. + if (!beatmaps.GetAllUsableBeatmapSets().Any() && beatmaps.StableInstallationAvailable) + dialogOverlay.Push(new ImportFromStablePopup(() => beatmaps.ImportFromStable())); + }); + } } protected override void UpdateBeatmap(WorkingBeatmap beatmap) diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 94678106bf..fa25fa7048 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -310,6 +310,7 @@ + From 48e55a06865ab8cf50987edfb588c3d6b7ba3d71 Mon Sep 17 00:00:00 2001 From: Aergwyn Date: Mon, 25 Dec 2017 16:52:17 +0100 Subject: [PATCH 034/101] fix formatting and test add missing line --- osu.Game.Tests/Visual/TestCaseUserProfile.cs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCaseUserProfile.cs b/osu.Game.Tests/Visual/TestCaseUserProfile.cs index 88627755f4..13b6509740 100644 --- a/osu.Game.Tests/Visual/TestCaseUserProfile.cs +++ b/osu.Game.Tests/Visual/TestCaseUserProfile.cs @@ -26,6 +26,11 @@ namespace osu.Game.Tests.Visual public TestCaseUserProfile() { Add(profile = new TestUserProfileOverlay()); + } + + protected override void LoadComplete() + { + base.LoadComplete(); AddStep("Show offline dummy", () => profile.ShowUser(new User { @@ -77,13 +82,14 @@ namespace osu.Game.Tests.Visual private void checkSupporterTag(bool isSupporter) { AddUntilStep(() => profile.Header.User != null, "wait for load"); - if(isSupporter) + if (isSupporter) AddAssert("is supporter", () => profile.Header.SupporterTag.Alpha == 1); else AddAssert("no supporter", () => profile.Header.SupporterTag.Alpha == 0); } - private class TestUserProfileOverlay : UserProfileOverlay { + private class TestUserProfileOverlay : UserProfileOverlay + { public new ProfileHeader Header => base.Header; } } From dff082ed940ad1cd93e0a52f62bd8dd46a5546f6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 26 Dec 2017 01:12:46 +0900 Subject: [PATCH 035/101] Make toolbar testable and add the most basic of visual tests --- osu.Game.Tests/Visual/TestCaseToolbar.cs | 25 +++++++++++++++++++ osu.Game.Tests/osu.Game.Tests.csproj | 1 + .../Overlays/Toolbar/ToolbarChatButton.cs | 2 +- .../Overlays/Toolbar/ToolbarDirectButton.cs | 2 +- .../Overlays/Toolbar/ToolbarModeSelector.cs | 7 ++++-- .../Overlays/Toolbar/ToolbarMusicButton.cs | 2 +- .../Toolbar/ToolbarNotificationButton.cs | 2 +- .../Toolbar/ToolbarOverlayToggleButton.cs | 7 ++++-- .../Overlays/Toolbar/ToolbarSettingsButton.cs | 2 +- .../Overlays/Toolbar/ToolbarSocialButton.cs | 2 +- 10 files changed, 42 insertions(+), 10 deletions(-) create mode 100644 osu.Game.Tests/Visual/TestCaseToolbar.cs diff --git a/osu.Game.Tests/Visual/TestCaseToolbar.cs b/osu.Game.Tests/Visual/TestCaseToolbar.cs new file mode 100644 index 0000000000..9045249b9a --- /dev/null +++ b/osu.Game.Tests/Visual/TestCaseToolbar.cs @@ -0,0 +1,25 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using System.Collections.Generic; +using osu.Framework.Graphics.Containers; +using osu.Game.Overlays.Toolbar; + +namespace osu.Game.Tests.Visual +{ + public class TestCaseToolbar : OsuTestCase + { + public override IReadOnlyList RequiredTypes => new[] + { + typeof(ToolbarButton), + typeof(ToolbarModeSelector), + typeof(ToolbarModeButton), + }; + + public TestCaseToolbar() + { + Add(new Toolbar { State = Visibility.Visible }); + } + } +} diff --git a/osu.Game.Tests/osu.Game.Tests.csproj b/osu.Game.Tests/osu.Game.Tests.csproj index ff012bb6e2..71703d264a 100644 --- a/osu.Game.Tests/osu.Game.Tests.csproj +++ b/osu.Game.Tests/osu.Game.Tests.csproj @@ -148,6 +148,7 @@ + diff --git a/osu.Game/Overlays/Toolbar/ToolbarChatButton.cs b/osu.Game/Overlays/Toolbar/ToolbarChatButton.cs index ed206e7e1d..b0171feb30 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarChatButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarChatButton.cs @@ -13,7 +13,7 @@ namespace osu.Game.Overlays.Toolbar SetIcon(FontAwesome.fa_comments); } - [BackgroundDependencyLoader] + [BackgroundDependencyLoader(true)] private void load(ChatOverlay chat) { StateContainer = chat; diff --git a/osu.Game/Overlays/Toolbar/ToolbarDirectButton.cs b/osu.Game/Overlays/Toolbar/ToolbarDirectButton.cs index 7d25440e2c..5c64ae69ec 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarDirectButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarDirectButton.cs @@ -13,7 +13,7 @@ namespace osu.Game.Overlays.Toolbar SetIcon(FontAwesome.fa_osu_chevron_down_o); } - [BackgroundDependencyLoader] + [BackgroundDependencyLoader(true)] private void load(DirectOverlay direct) { StateContainer = direct; diff --git a/osu.Game/Overlays/Toolbar/ToolbarModeSelector.cs b/osu.Game/Overlays/Toolbar/ToolbarModeSelector.cs index 319dd63bc9..f38c772890 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarModeSelector.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarModeSelector.cs @@ -64,7 +64,7 @@ namespace osu.Game.Overlays.Toolbar }; } - [BackgroundDependencyLoader] + [BackgroundDependencyLoader(true)] private void load(RulesetStore rulesets, OsuGame game) { foreach (var r in rulesets.AvailableRulesets) @@ -81,7 +81,10 @@ namespace osu.Game.Overlays.Toolbar ruleset.ValueChanged += rulesetChanged; ruleset.DisabledChanged += disabledChanged; - ruleset.BindTo(game.Ruleset); + if (game != null) + ruleset.BindTo(game.Ruleset); + else + ruleset.Value = rulesets.AvailableRulesets.FirstOrDefault(); } public override bool HandleInput => !ruleset.Disabled; diff --git a/osu.Game/Overlays/Toolbar/ToolbarMusicButton.cs b/osu.Game/Overlays/Toolbar/ToolbarMusicButton.cs index d150aacdf9..81c57a984f 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarMusicButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarMusicButton.cs @@ -13,7 +13,7 @@ namespace osu.Game.Overlays.Toolbar Icon = FontAwesome.fa_music; } - [BackgroundDependencyLoader] + [BackgroundDependencyLoader(true)] private void load(MusicController music) { StateContainer = music; diff --git a/osu.Game/Overlays/Toolbar/ToolbarNotificationButton.cs b/osu.Game/Overlays/Toolbar/ToolbarNotificationButton.cs index e11a22d675..dbe8b48424 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarNotificationButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarNotificationButton.cs @@ -18,7 +18,7 @@ namespace osu.Game.Overlays.Toolbar TooltipSub = "Waiting for 'ya"; } - [BackgroundDependencyLoader] + [BackgroundDependencyLoader(true)] private void load(NotificationOverlay notificationOverlay) { StateContainer = notificationOverlay; diff --git a/osu.Game/Overlays/Toolbar/ToolbarOverlayToggleButton.cs b/osu.Game/Overlays/Toolbar/ToolbarOverlayToggleButton.cs index 69fdd27d5d..59314b8771 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarOverlayToggleButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarOverlayToggleButton.cs @@ -21,8 +21,11 @@ namespace osu.Game.Overlays.Toolbar set { stateContainer = value; - Action = stateContainer.ToggleVisibility; - stateContainer.StateChanged += stateChanged; + if (stateContainer != null) + { + Action = stateContainer.ToggleVisibility; + stateContainer.StateChanged += stateChanged; + } } } diff --git a/osu.Game/Overlays/Toolbar/ToolbarSettingsButton.cs b/osu.Game/Overlays/Toolbar/ToolbarSettingsButton.cs index cf4f664e81..d0d76dd5d2 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarSettingsButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarSettingsButton.cs @@ -15,7 +15,7 @@ namespace osu.Game.Overlays.Toolbar TooltipSub = "Change your settings"; } - [BackgroundDependencyLoader] + [BackgroundDependencyLoader(true)] private void load(SettingsOverlay settings) { StateContainer = settings; diff --git a/osu.Game/Overlays/Toolbar/ToolbarSocialButton.cs b/osu.Game/Overlays/Toolbar/ToolbarSocialButton.cs index 234d6f0f9a..74d1da4384 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarSocialButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarSocialButton.cs @@ -13,7 +13,7 @@ namespace osu.Game.Overlays.Toolbar Icon = FontAwesome.fa_users; } - [BackgroundDependencyLoader] + [BackgroundDependencyLoader(true)] private void load(SocialOverlay chat) { StateContainer = chat; From bb33d0211a5802c6706c3a18570cbc16ffa4c227 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 26 Dec 2017 01:36:58 +0900 Subject: [PATCH 036/101] Add a count of unread notifications to the toolbar --- osu.Game.Tests/Visual/TestCaseToolbar.cs | 16 ++++- .../Toolbar/ToolbarNotificationButton.cs | 64 +++++++++++++++++++ 2 files changed, 79 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/TestCaseToolbar.cs b/osu.Game.Tests/Visual/TestCaseToolbar.cs index 9045249b9a..9f538af09b 100644 --- a/osu.Game.Tests/Visual/TestCaseToolbar.cs +++ b/osu.Game.Tests/Visual/TestCaseToolbar.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Linq; using osu.Framework.Graphics.Containers; using osu.Game.Overlays.Toolbar; @@ -15,11 +16,24 @@ namespace osu.Game.Tests.Visual typeof(ToolbarButton), typeof(ToolbarModeSelector), typeof(ToolbarModeButton), + typeof(ToolbarNotificationButton), }; public TestCaseToolbar() { - Add(new Toolbar { State = Visibility.Visible }); + var toolbar = new Toolbar { State = Visibility.Visible }; + + Add(toolbar); + + var notificationButton = toolbar.Children.OfType().Last().Children.OfType().First(); + + void setNotifications(int count) => AddStep($"set notification count to {count}", () => notificationButton.NotificationCount.Value = count); + + setNotifications(1); + setNotifications(2); + setNotifications(3); + setNotifications(0); + setNotifications(144); } } } diff --git a/osu.Game/Overlays/Toolbar/ToolbarNotificationButton.cs b/osu.Game/Overlays/Toolbar/ToolbarNotificationButton.cs index dbe8b48424..78a04d156a 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarNotificationButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarNotificationButton.cs @@ -2,8 +2,14 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using osu.Framework.Allocation; +using osu.Framework.Configuration; using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using OpenTK; +using OpenTK.Graphics; namespace osu.Game.Overlays.Toolbar { @@ -11,17 +17,75 @@ namespace osu.Game.Overlays.Toolbar { protected override Anchor TooltipAnchor => Anchor.TopRight; + public BindableInt NotificationCount = new BindableInt(); + + private CountCircle countDisplay; + public ToolbarNotificationButton() { Icon = FontAwesome.fa_bars; TooltipMain = "Notifications"; TooltipSub = "Waiting for 'ya"; + + Add(countDisplay = new CountCircle + { + Alpha = 0, + Height = 16, + RelativePositionAxes = Axes.Both, + Origin = Anchor.TopCentre, + Position = new Vector2(0.7f, 0.05f), + }); } [BackgroundDependencyLoader(true)] private void load(NotificationOverlay notificationOverlay) { StateContainer = notificationOverlay; + + NotificationCount.ValueChanged += count => + { + if (count == 0) + countDisplay.FadeOut(200, Easing.OutQuint); + else + countDisplay.FadeIn(200, Easing.OutQuint); + + countDisplay.Count = count; + }; + } + + private class CountCircle : CompositeDrawable + { + private readonly OsuSpriteText count; + + public int Count + { + set { count.Text = value.ToString("#,0"); } + } + + public CountCircle() + { + AutoSizeAxes = Axes.X; + + InternalChildren = new Drawable[] + { + new Circle + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Red + }, + count = new OsuSpriteText + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Y = -1, + TextSize = 14, + Padding = new MarginPadding(5), + Colour = Color4.White, + UseFullGlyphHeight = true, + Font = "Exo2.0-Bold", + } + }; + } } } } From 1fc240f6c594ad7f1469f4276a0778034c59bb2e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 26 Dec 2017 01:50:05 +0900 Subject: [PATCH 037/101] Expose unread notification count --- .../Visual/TestCaseNotificationOverlay.cs | 7 ++++ osu.Game/Overlays/NotificationOverlay.cs | 42 ++++++++++++------- .../Notifications/NotificationSection.cs | 4 +- 3 files changed, 37 insertions(+), 16 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCaseNotificationOverlay.cs b/osu.Game.Tests/Visual/TestCaseNotificationOverlay.cs index b93c2d812f..233914767d 100644 --- a/osu.Game.Tests/Visual/TestCaseNotificationOverlay.cs +++ b/osu.Game.Tests/Visual/TestCaseNotificationOverlay.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Linq; using osu.Framework.Graphics; +using osu.Framework.Graphics.Sprites; using osu.Framework.MathUtils; using osu.Game.Overlays; using osu.Game.Overlays.Notifications; @@ -25,6 +26,12 @@ namespace osu.Game.Tests.Visual Origin = Anchor.TopRight }); + SpriteText displayedCount = new SpriteText(); + + Content.Add(displayedCount); + + manager.UnreadCount.ValueChanged += count => { displayedCount.Text = $"displayed count: {count}"; }; + AddStep(@"toggle", manager.ToggleVisibility); AddStep(@"simple #1", sendHelloNotification); AddStep(@"simple #2", sendAmazingNotification); diff --git a/osu.Game/Overlays/NotificationOverlay.cs b/osu.Game/Overlays/NotificationOverlay.cs index a4b5486596..2f1c3285ef 100644 --- a/osu.Game/Overlays/NotificationOverlay.cs +++ b/osu.Game/Overlays/NotificationOverlay.cs @@ -11,6 +11,7 @@ using OpenTK.Graphics; using osu.Framework.Graphics.Shapes; using osu.Game.Graphics.Containers; using System; +using osu.Framework.Configuration; namespace osu.Game.Overlays { @@ -75,34 +76,38 @@ namespace osu.Game.Overlays }; } + private int totalCount => sections.Select(c => c.DisplayedCount).Sum(); + private int unreadCount => sections.Select(c => c.UnreadCount).Sum(); + + public readonly BindableInt UnreadCount = new BindableInt(); + private int runningDepth; private void notificationClosed() { // hide ourselves if all notifications have been dismissed. - if (sections.Select(c => c.DisplayedCount).Sum() == 0) + if (totalCount == 0) State = Visibility.Hidden; + + updateCounts(); } - public void Post(Notification notification) + public void Post(Notification notification) => Schedule(() => { - Schedule(() => - { - State = Visibility.Visible; + ++runningDepth; + notification.Depth = notification.DisplayOnTop ? runningDepth : -runningDepth; - ++runningDepth; - notification.Depth = notification.DisplayOnTop ? runningDepth : -runningDepth; + notification.Closed += notificationClosed; - notification.Closed += notificationClosed; + var hasCompletionTarget = notification as IHasCompletionTarget; + if (hasCompletionTarget != null) + hasCompletionTarget.CompletionTarget = Post; - var hasCompletionTarget = notification as IHasCompletionTarget; - if (hasCompletionTarget != null) - hasCompletionTarget.CompletionTarget = Post; + var ourType = notification.GetType(); + sections.Children.FirstOrDefault(s => s.AcceptTypes.Any(accept => accept.IsAssignableFrom(ourType)))?.Add(notification); - var ourType = notification.GetType(); - sections.Children.FirstOrDefault(s => s.AcceptTypes.Any(accept => accept.IsAssignableFrom(ourType)))?.Add(notification); - }); - } + updateCounts(); + }); protected override void PopIn() { @@ -122,9 +127,16 @@ namespace osu.Game.Overlays this.FadeTo(0, TRANSITION_LENGTH, Easing.OutQuint); } + private void updateCounts() + { + UnreadCount.Value = unreadCount; + } + private void markAllRead() { sections.Children.ForEach(s => s.MarkAllRead()); + + updateCounts(); } protected override void UpdateAfterChildren() diff --git a/osu.Game/Overlays/Notifications/NotificationSection.cs b/osu.Game/Overlays/Notifications/NotificationSection.cs index 09768ba0ea..2bd0321d12 100644 --- a/osu.Game/Overlays/Notifications/NotificationSection.cs +++ b/osu.Game/Overlays/Notifications/NotificationSection.cs @@ -26,6 +26,8 @@ namespace osu.Game.Overlays.Notifications public int DisplayedCount => notifications.Count(n => !n.WasClosed); + public int UnreadCount => notifications.Count(n => !n.WasClosed && !n.Read); + public void Add(Notification notification) => notifications.Add(notification); public IEnumerable AcceptTypes; @@ -157,4 +159,4 @@ namespace osu.Game.Overlays.Notifications notifications?.Children.ForEach(n => n.Read = true); } } -} \ No newline at end of file +} From 0886107ec911c79d6d3f25317b31c0586ddc0ba2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 26 Dec 2017 01:56:57 +0900 Subject: [PATCH 038/101] Connect counter with button display --- .../Toolbar/ToolbarNotificationButton.cs | 24 +++++++++++++------ 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/osu.Game/Overlays/Toolbar/ToolbarNotificationButton.cs b/osu.Game/Overlays/Toolbar/ToolbarNotificationButton.cs index 78a04d156a..faf802f5e7 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarNotificationButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarNotificationButton.cs @@ -19,7 +19,7 @@ namespace osu.Game.Overlays.Toolbar public BindableInt NotificationCount = new BindableInt(); - private CountCircle countDisplay; + private readonly CountCircle countDisplay; public ToolbarNotificationButton() { @@ -32,8 +32,8 @@ namespace osu.Game.Overlays.Toolbar Alpha = 0, Height = 16, RelativePositionAxes = Axes.Both, - Origin = Anchor.TopCentre, - Position = new Vector2(0.7f, 0.05f), + Origin = Anchor.Centre, + Position = new Vector2(0.7f, 0.25f), }); } @@ -42,24 +42,34 @@ namespace osu.Game.Overlays.Toolbar { StateContainer = notificationOverlay; + if (notificationOverlay != null) + NotificationCount.BindTo(notificationOverlay.UnreadCount); + NotificationCount.ValueChanged += count => { if (count == 0) countDisplay.FadeOut(200, Easing.OutQuint); else + { + countDisplay.Count = count; countDisplay.FadeIn(200, Easing.OutQuint); - - countDisplay.Count = count; + } }; } private class CountCircle : CompositeDrawable { private readonly OsuSpriteText count; + private readonly Circle circle; public int Count { - set { count.Text = value.ToString("#,0"); } + set + { + count.Text = value.ToString("#,0"); + circle.FlashColour(Color4.White, 600, Easing.OutQuint); + this.ScaleTo(1.1f).Then().ScaleTo(1, 600, Easing.OutElastic); + } } public CountCircle() @@ -68,7 +78,7 @@ namespace osu.Game.Overlays.Toolbar InternalChildren = new Drawable[] { - new Circle + circle = new Circle { RelativeSizeAxes = Axes.Both, Colour = Color4.Red From d8f084474216cccb9add01ec3ec40f282bc42bce Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 25 Dec 2017 11:24:13 +0900 Subject: [PATCH 039/101] Fix null reference in release builds Intro may not be initialised yet --- osu.Game/OsuGame.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 67f6e6f4e2..fe7ca77d44 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -272,7 +272,7 @@ namespace osu.Game }; } - Action stateChanged = delegate + void updateScreenOffset() { float offset = 0; @@ -281,11 +281,11 @@ namespace osu.Game if (notifications.State == Visibility.Visible) offset -= ToolbarButton.WIDTH / 2; - intro.MoveToX(offset, SettingsOverlay.TRANSITION_LENGTH, Easing.OutQuint); - }; + screenStack.MoveToX(offset, SettingsOverlay.TRANSITION_LENGTH, Easing.OutQuint); + } - settings.StateChanged += stateChanged; - notifications.StateChanged += stateChanged; + settings.StateChanged += _ => updateScreenOffset(); + notifications.StateChanged += _ => updateScreenOffset(); Cursor.State = Visibility.Hidden; } From 798c2c66667cdb7f5b2c54d59731d3ae71486894 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 25 Dec 2017 12:57:45 +0900 Subject: [PATCH 040/101] Add special logic to song select to avoid obvious clipping when notifications are displayed Not sure if we will keep this going forward (there will likely be an opaque tab control on the notifications overlay similar to options) but let's go with this for now. --- osu.Game/Screens/Select/FilterControl.cs | 4 +- osu.Game/Screens/Select/SongSelect.cs | 48 +++++++++++++++++------- 2 files changed, 37 insertions(+), 15 deletions(-) diff --git a/osu.Game/Screens/Select/FilterControl.cs b/osu.Game/Screens/Select/FilterControl.cs index 1b86cec613..2dbd63f77b 100644 --- a/osu.Game/Screens/Select/FilterControl.cs +++ b/osu.Game/Screens/Select/FilterControl.cs @@ -75,7 +75,7 @@ namespace osu.Game.Screens.Select { Children = new Drawable[] { - new Box + Background = new Box { Colour = Color4.Black, Alpha = 0.8f, @@ -167,6 +167,8 @@ namespace osu.Game.Screens.Select private Bindable showConverted; + public readonly Box Background; + [BackgroundDependencyLoader(permitNulls: true)] private void load(OsuColour colours, OsuGame osu, OsuConfigManager config) { diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 68ee08e721..8189624ce1 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -103,21 +103,41 @@ namespace osu.Game.Screens.Select Right = left_area_padding * 2, } }, - carousel = new BeatmapCarousel + new Container { - RelativeSizeAxes = Axes.Y, - Size = new Vector2(carousel_width, 1), - Anchor = Anchor.CentreRight, - Origin = Anchor.CentreRight, - SelectionChanged = carouselSelectionChanged, - BeatmapSetsChanged = carouselBeatmapsLoaded, - }, - FilterControl = new FilterControl - { - RelativeSizeAxes = Axes.X, - Height = filter_height, - FilterChanged = c => carousel.Filter(c), - Exit = Exit, + RelativeSizeAxes = Axes.Both, + Masking = true, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Width = 2, //avoid horizontal masking so the panels don't clip when screen stack is pushed. + Child = new Container + { + RelativeSizeAxes = Axes.Both, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Width = 0.5f, + Children = new Drawable[] + { + carousel = new BeatmapCarousel + { + Masking = false, + RelativeSizeAxes = Axes.Y, + Size = new Vector2(carousel_width, 1), + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + SelectionChanged = carouselSelectionChanged, + BeatmapSetsChanged = carouselBeatmapsLoaded, + }, + FilterControl = new FilterControl + { + RelativeSizeAxes = Axes.X, + Height = filter_height, + FilterChanged = c => carousel.Filter(c), + Background = { Width = 2 }, + Exit = Exit, + }, + } + }, }, beatmapInfoWedge = new BeatmapInfoWedge { From c737e5245e0442d097d7e9efd6cd6c18cd9dfc60 Mon Sep 17 00:00:00 2001 From: FreezyLemon Date: Tue, 26 Dec 2017 01:50:05 +0100 Subject: [PATCH 041/101] Removed unnecessary SelectNext() call and change to dummy map when no items present --- osu.Game/Screens/Select/BeatmapCarousel.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index be176c1459..802667e6a0 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -142,7 +142,6 @@ namespace osu.Game.Screens.Select if (newSet == null) { itemsCache.Invalidate(); - SelectNext(); return; } @@ -512,7 +511,7 @@ namespace osu.Game.Screens.Select currentY += DrawHeight / 2; scrollableContent.Height = currentY; - if (selectedBeatmapSet != null && selectedBeatmapSet.State.Value != CarouselItemState.Selected) + if (!Items.Any() || selectedBeatmapSet != null && selectedBeatmapSet.State.Value != CarouselItemState.Selected) { selectedBeatmapSet = null; SelectionChanged?.Invoke(null); From c82273572430b6bcefa1b3dbfe45644e543fed2f Mon Sep 17 00:00:00 2001 From: FreezyLemon Date: Tue, 26 Dec 2017 03:57:18 +0100 Subject: [PATCH 042/101] Added tests for hiding diffs (and especially the last visible diff) --- .../Visual/TestCaseBeatmapCarousel.cs | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/osu.Game.Tests/Visual/TestCaseBeatmapCarousel.cs b/osu.Game.Tests/Visual/TestCaseBeatmapCarousel.cs index 639befef74..c09b987407 100644 --- a/osu.Game.Tests/Visual/TestCaseBeatmapCarousel.cs +++ b/osu.Game.Tests/Visual/TestCaseBeatmapCarousel.cs @@ -70,6 +70,7 @@ namespace osu.Game.Tests.Visual testRemoveAll(); testEmptyTraversal(); + testHiding(); } private void ensureRandomFetchSuccess() => @@ -295,6 +296,40 @@ namespace osu.Game.Tests.Visual checkNoSelection(); } + private void testHiding() + { + var hidingSet = createTestBeatmapSet(1); + hidingSet.Beatmaps[1].Hidden = true; + AddStep("Add set with diff 2 hidden", () => carousel.UpdateBeatmapSet(hidingSet)); + setSelected(1, 1); + + checkVisibleItemCount(true, 2); + advanceSelection(true); + checkSelected(1, 3); + + setHidden(3); + checkSelected(1, 1); + + setHidden(2, false); + advanceSelection(true); + checkSelected(1, 2); + + setHidden(1); + checkSelected(1, 2); + + setHidden(2); + checkNoSelection(); + + void setHidden(int diff, bool hidden = true) + { + AddStep((hidden ? "" : "un") + $"hide diff {diff}", () => + { + hidingSet.Beatmaps[diff - 1].Hidden = hidden; + carousel.UpdateBeatmapSet(hidingSet); + }); + } + } + private BeatmapSetInfo createTestBeatmapSet(int i) { return new BeatmapSetInfo From 09ce24a7dba54deb34d629e75eee48978d1f26a8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 26 Dec 2017 13:41:02 +0900 Subject: [PATCH 043/101] Switch to a better way of deciding on null selection This avoids `SelectionChanged` potentially being invoked multiple times after `selectedBeatmapSet` is already `null`. --- osu.Game/Screens/Select/BeatmapCarousel.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index 802667e6a0..87edfe9692 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -511,7 +511,7 @@ namespace osu.Game.Screens.Select currentY += DrawHeight / 2; scrollableContent.Height = currentY; - if (!Items.Any() || selectedBeatmapSet != null && selectedBeatmapSet.State.Value != CarouselItemState.Selected) + if (selectedBeatmapSet != null && (selectedBeatmap == null || selectedBeatmapSet.State.Value != CarouselItemState.Selected)) { selectedBeatmapSet = null; SelectionChanged?.Invoke(null); From 14162b5d46a56f4f8da0e01829c25c67c331b1e9 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 26 Dec 2017 14:18:23 +0900 Subject: [PATCH 044/101] Make InputDrum handle all Normals/Claps, hitobjects all others --- .../Audio/DrumSampleMapping.cs | 47 +++++++++++-------- .../Objects/Drawables/DrawableSwell.cs | 19 -------- .../Drawables/DrawableTaikoHitObject.cs | 7 +++ osu.Game.Rulesets.Taiko/Objects/Swell.cs | 13 ----- osu.Game.Rulesets.Taiko/UI/InputDrum.cs | 36 ++++++++++++-- osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs | 38 ++------------- .../Objects/Drawables/DrawableHitObject.cs | 6 ++- 7 files changed, 72 insertions(+), 94 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Audio/DrumSampleMapping.cs b/osu.Game.Rulesets.Taiko/Audio/DrumSampleMapping.cs index 25fa9951df..9d0037b97a 100644 --- a/osu.Game.Rulesets.Taiko/Audio/DrumSampleMapping.cs +++ b/osu.Game.Rulesets.Taiko/Audio/DrumSampleMapping.cs @@ -1,7 +1,8 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using System; +using System.Collections.Generic; +using System.Linq; using osu.Framework.Audio; using osu.Framework.Audio.Sample; using osu.Game.Audio; @@ -9,32 +10,38 @@ using osu.Game.Beatmaps.ControlPoints; namespace osu.Game.Rulesets.Taiko.Audio { - public class DrumSampleMapping : IComparable + public class DrumSampleMapping { - public double Time; - public readonly SampleInfo Centre; - public readonly SampleInfo Rim; + private readonly ControlPointInfo controlPoints; + private readonly Dictionary mappings = new Dictionary(); - public SampleChannel CentreChannel { get; private set; } - public SampleChannel RimChannel { get; private set; } - - public DrumSampleMapping() + public DrumSampleMapping(ControlPointInfo controlPoints, AudioManager audio) { + this.controlPoints = controlPoints; + + IEnumerable samplePoints; + if (controlPoints.SamplePoints.Count == 0) + // Get the default sample point + samplePoints = new[] { controlPoints.SamplePointAt(double.MinValue) }; + else + samplePoints = controlPoints.SamplePoints; + + foreach (var s in samplePoints.Distinct()) + { + mappings[s] = new DrumSample + { + Centre = s.GetSampleInfo().GetChannel(audio.Sample), + Rim = s.GetSampleInfo(SampleInfo.HIT_CLAP).GetChannel(audio.Sample) + }; + } } - public DrumSampleMapping(SampleControlPoint samplePoint) - { - Time = samplePoint.Time; - Centre = samplePoint.GetSampleInfo(); - Rim = samplePoint.GetSampleInfo(SampleInfo.HIT_CLAP); - } + public DrumSample SampleAt(double time) => mappings[controlPoints.SamplePointAt(time)]; - public void RetrieveChannels(AudioManager audio) + public class DrumSample { - CentreChannel = Centre.GetChannel(audio.Sample); - RimChannel = Rim.GetChannel(audio.Sample); + public SampleChannel Centre; + public SampleChannel Rim; } - - public int CompareTo(DrumSampleMapping other) => Time.CompareTo(other.Time); } } diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs index 5131572abd..3099c6984c 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs @@ -123,9 +123,6 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables MainPiece.AccentColour = colours.YellowDark; expandingRing.Colour = colours.YellowLight; targetRing.BorderColour = colours.YellowDark.Opacity(0.25f); - - foreach (var mapping in HitObject.ProgressionSamples) - mapping.RetrieveChannels(audio); } protected override void LoadComplete() @@ -223,22 +220,6 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables UpdateJudgement(true); - if (AllJudged) - return true; - - // While the swell hasn't been fully judged, input is still blocked so it doesn't fall through to other hitobjects - // This causes the playfield to not play sounds, so they need to be handled locally - - var mappingIndex = HitObject.ProgressionSamples.BinarySearch(new DrumSampleMapping { Time = Time.Current }); - if (mappingIndex < 0) - mappingIndex = ~mappingIndex - 1; - - var mapping = HitObject.ProgressionSamples[mappingIndex]; - if (isCentre) - mapping.CentreChannel.Play(); - else - mapping.RimChannel.Play(); - return true; } } diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs index 7976cbbbc1..cf0df260b1 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs @@ -6,6 +6,10 @@ using osu.Framework.Input.Bindings; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Taiko.Objects.Drawables.Pieces; using OpenTK; +using System; +using System.Linq; +using osu.Game.Audio; +using System.Collections.Generic; namespace osu.Game.Rulesets.Taiko.Objects.Drawables { @@ -35,6 +39,9 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables MainPiece.KiaiMode = HitObject.Kiai; } + // Normal and clap samples are handled by the drum + protected override IEnumerable GetSamples() => HitObject.Samples.Where(s => s.Name != SampleInfo.HIT_NORMAL && s.Name != SampleInfo.HIT_CLAP); + protected virtual TaikoPiece CreateMainPiece() => new CirclePiece(); public abstract bool OnPressed(TaikoAction action); diff --git a/osu.Game.Rulesets.Taiko/Objects/Swell.cs b/osu.Game.Rulesets.Taiko/Objects/Swell.cs index 714e5d29ee..95ea9f8aa4 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Swell.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Swell.cs @@ -20,18 +20,5 @@ namespace osu.Game.Rulesets.Taiko.Objects /// The number of hits required to complete the swell successfully. /// public int RequiredHits = 10; - - public List ProgressionSamples = new List(); - - protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) - { - base.ApplyDefaultsToSelf(controlPointInfo, difficulty); - - var progressionSamplePoints = new[] { controlPointInfo.SamplePointAt(StartTime) } - .Concat(controlPointInfo.SamplePoints.Where(p => p.Time > StartTime && p.Time <= EndTime)); - - foreach (var point in progressionSamplePoints) - ProgressionSamples.Add(new DrumSampleMapping(point)); - } } } diff --git a/osu.Game.Rulesets.Taiko/UI/InputDrum.cs b/osu.Game.Rulesets.Taiko/UI/InputDrum.cs index 5e79166bec..8c02b21733 100644 --- a/osu.Game.Rulesets.Taiko/UI/InputDrum.cs +++ b/osu.Game.Rulesets.Taiko/UI/InputDrum.cs @@ -2,14 +2,20 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; +using System.Collections.Generic; +using System.Linq; using OpenTK; using osu.Framework.Allocation; +using osu.Framework.Audio; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; using osu.Framework.Input.Bindings; +using osu.Game.Audio; +using osu.Game.Beatmaps.ControlPoints; using osu.Game.Graphics; +using osu.Game.Rulesets.Taiko.Audio; namespace osu.Game.Rulesets.Taiko.UI { @@ -18,16 +24,26 @@ namespace osu.Game.Rulesets.Taiko.UI /// internal class InputDrum : Container { - public InputDrum() + private const float middle_split = 0.025f; + + private readonly ControlPointInfo controlPoints; + + public InputDrum(ControlPointInfo controlPoints) { + this.controlPoints = controlPoints; + RelativeSizeAxes = Axes.Both; FillMode = FillMode.Fit; + } - const float middle_split = 0.025f; + [BackgroundDependencyLoader] + private void load(AudioManager audio) + { + var sampleMappings = new DrumSampleMapping(controlPoints, audio); Children = new Drawable[] { - new TaikoHalfDrum(false) + new TaikoHalfDrum(false, sampleMappings) { Name = "Left Half", Anchor = Anchor.Centre, @@ -38,7 +54,7 @@ namespace osu.Game.Rulesets.Taiko.UI RimAction = TaikoAction.LeftRim, CentreAction = TaikoAction.LeftCentre }, - new TaikoHalfDrum(true) + new TaikoHalfDrum(true, sampleMappings) { Name = "Right Half", Anchor = Anchor.Centre, @@ -72,8 +88,12 @@ namespace osu.Game.Rulesets.Taiko.UI private readonly Sprite centre; private readonly Sprite centreHit; - public TaikoHalfDrum(bool flipped) + private readonly DrumSampleMapping sampleMappings; + + public TaikoHalfDrum(bool flipped, DrumSampleMapping sampleMappings) { + this.sampleMappings = sampleMappings; + Masking = true; Children = new Drawable[] @@ -128,15 +148,21 @@ namespace osu.Game.Rulesets.Taiko.UI Drawable target = null; Drawable back = null; + var drumSample = sampleMappings.SampleAt(Time.Current); + if (action == CentreAction) { target = centreHit; back = centre; + + drumSample.Centre.Play(); } else if (action == RimAction) { target = rimHit; back = rim; + + drumSample.Rim.Play(); } if (target != null) diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs index 229e44cf27..14f8de0f48 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs @@ -24,7 +24,7 @@ using osu.Game.Rulesets.Taiko.Audio; namespace osu.Game.Rulesets.Taiko.UI { - public class TaikoPlayfield : ScrollingPlayfield, IKeyBindingHandler + public class TaikoPlayfield : ScrollingPlayfield { /// /// Default height of a when inside a . @@ -59,13 +59,9 @@ namespace osu.Game.Rulesets.Taiko.UI private readonly Box overlayBackground; private readonly Box background; - private readonly ControlPointInfo controlPointInfo; - private readonly List drumSampleMappings = new List(); - - public TaikoPlayfield(ControlPointInfo controlPointInfo) + public TaikoPlayfield(ControlPointInfo controlPoints) : base(Axes.X) { - this.controlPointInfo = controlPointInfo; AddRangeInternal(new Drawable[] { backgroundContainer = new Container @@ -158,7 +154,7 @@ namespace osu.Game.Rulesets.Taiko.UI { RelativeSizeAxes = Axes.Both, }, - new InputDrum + new InputDrum(controlPoints) { Anchor = Anchor.CentreRight, Origin = Anchor.CentreRight, @@ -205,17 +201,7 @@ namespace osu.Game.Rulesets.Taiko.UI [BackgroundDependencyLoader] private void load(OsuColour colours, AudioManager audio) { - // We may have 0 sample points, but we need at least the default one - var samplePoints = new[] { controlPointInfo.SamplePointAt(double.MinValue) } - .Concat(controlPointInfo.SamplePoints); - foreach (var s in samplePoints) - { - var mapping = new DrumSampleMapping(s); - mapping.RetrieveChannels(audio); - - drumSampleMappings.Add(mapping); - } overlayBackgroundContainer.BorderColour = colours.Gray0; overlayBackground.Colour = colours.Gray1; @@ -281,23 +267,5 @@ namespace osu.Game.Rulesets.Taiko.UI kiaiExplosionContainer.Add(new KiaiHitExplosion(judgedObject, isRim)); } } - - public bool OnPressed(TaikoAction action) - { - var mappingIndex = drumSampleMappings.BinarySearch(new DrumSampleMapping { Time = Time.Current }); - if (mappingIndex < 0) - mappingIndex = ~mappingIndex - 1; - - var mapping = drumSampleMappings[mappingIndex]; - - if (action == TaikoAction.LeftCentre || action == TaikoAction.RightCentre) - mapping.CentreChannel.Play(); - else - mapping.RimChannel.Play(); - - return true; - } - - public bool OnReleased(TaikoAction action) => false; } } diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index be161b9ad3..ab4c04be3f 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -72,6 +72,7 @@ namespace osu.Game.Rulesets.Objects.Drawables public IReadOnlyList Judgements => judgements; protected List Samples = new List(); + protected virtual IEnumerable GetSamples() => HitObject.Samples; public readonly Bindable State = new Bindable(); @@ -84,13 +85,14 @@ namespace osu.Game.Rulesets.Objects.Drawables [BackgroundDependencyLoader] private void load(AudioManager audio) { - if (Samples.Count > 0) + var samples = GetSamples(); + if (samples.Any()) { if (HitObject.SampleControlPoint == null) throw new ArgumentNullException(nameof(HitObject.SampleControlPoint), $"{nameof(HitObject)}s must always have an attached {nameof(HitObject.SampleControlPoint)}." + $" This is an indication that {nameof(HitObject.ApplyDefaults)} has not been invoked on {this}."); - foreach (SampleInfo s in HitObject.Samples) + foreach (SampleInfo s in samples) { SampleInfo localSampleInfo = new SampleInfo { From 35d7fa8a81ae017f964c1644ddac3db0b7f94135 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 26 Dec 2017 14:18:38 +0900 Subject: [PATCH 045/101] Cleanup things that are now not needed with these changes --- osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs | 2 +- .../Objects/Drawables/DrawableHitStrong.cs | 2 +- .../Objects/Drawables/DrawableSwell.cs | 4 +--- .../Objects/Drawables/DrawableTaikoHitObject.cs | 1 - osu.Game.Rulesets.Taiko/Objects/Swell.cs | 5 ----- osu.Game.Rulesets.Taiko/UI/InputDrum.cs | 3 --- osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs | 8 +------- 7 files changed, 4 insertions(+), 21 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs index df33aae94e..fd35f0eaec 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs @@ -68,7 +68,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables validKeyPressed = HitActions.Contains(action); // Only count this as handled if the new judgement is a hit - return UpdateJudgement(true) && Judgements.LastOrDefault()?.IsHit == true; + return UpdateJudgement(true); } protected override void Update() diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHitStrong.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHitStrong.cs index 07f7b83cef..cda82afe0e 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHitStrong.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHitStrong.cs @@ -83,7 +83,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables return false; // Assume the intention was to hit the strong hit with both keys only if the first key is still being held down - return firstKeyHeld && UpdateJudgement(true) && Judgements.LastOrDefault()?.IsHit == true; + return firstKeyHeld && UpdateJudgement(true); } } } diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs index 3099c6984c..5ca33aaea2 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs @@ -14,8 +14,6 @@ using OpenTK; using OpenTK.Graphics; using osu.Framework.Graphics.Shapes; using osu.Game.Rulesets.Taiko.Judgements; -using osu.Framework.Audio; -using osu.Game.Rulesets.Taiko.Audio; namespace osu.Game.Rulesets.Taiko.Objects.Drawables { @@ -118,7 +116,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables } [BackgroundDependencyLoader] - private void load(OsuColour colours, AudioManager audio) + private void load(OsuColour colours) { MainPiece.AccentColour = colours.YellowDark; expandingRing.Colour = colours.YellowLight; diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs index cf0df260b1..92da3fe09e 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs @@ -6,7 +6,6 @@ using osu.Framework.Input.Bindings; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Taiko.Objects.Drawables.Pieces; using OpenTK; -using System; using System.Linq; using osu.Game.Audio; using System.Collections.Generic; diff --git a/osu.Game.Rulesets.Taiko/Objects/Swell.cs b/osu.Game.Rulesets.Taiko/Objects/Swell.cs index 95ea9f8aa4..cd2876ea2d 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Swell.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Swell.cs @@ -1,12 +1,7 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using System.Collections.Generic; -using System.Linq; -using osu.Game.Beatmaps; -using osu.Game.Beatmaps.ControlPoints; using osu.Game.Rulesets.Objects.Types; -using osu.Game.Rulesets.Taiko.Audio; namespace osu.Game.Rulesets.Taiko.Objects { diff --git a/osu.Game.Rulesets.Taiko/UI/InputDrum.cs b/osu.Game.Rulesets.Taiko/UI/InputDrum.cs index 8c02b21733..bf1274256b 100644 --- a/osu.Game.Rulesets.Taiko/UI/InputDrum.cs +++ b/osu.Game.Rulesets.Taiko/UI/InputDrum.cs @@ -2,8 +2,6 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; -using System.Collections.Generic; -using System.Linq; using OpenTK; using osu.Framework.Allocation; using osu.Framework.Audio; @@ -12,7 +10,6 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; using osu.Framework.Input.Bindings; -using osu.Game.Audio; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Graphics; using osu.Game.Rulesets.Taiko.Audio; diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs index 14f8de0f48..3fdbd056ce 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs @@ -16,11 +16,7 @@ using osu.Framework.Extensions.Color4Extensions; using System.Linq; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Taiko.Objects.Drawables; -using osu.Framework.Input.Bindings; using osu.Game.Beatmaps.ControlPoints; -using osu.Framework.Audio; -using System.Collections.Generic; -using osu.Game.Rulesets.Taiko.Audio; namespace osu.Game.Rulesets.Taiko.UI { @@ -199,10 +195,8 @@ namespace osu.Game.Rulesets.Taiko.UI } [BackgroundDependencyLoader] - private void load(OsuColour colours, AudioManager audio) + private void load(OsuColour colours) { - - overlayBackgroundContainer.BorderColour = colours.Gray0; overlayBackground.Colour = colours.Gray1; From 9fb958eadc39a914acaec1317ad04339e6e9c51b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 26 Dec 2017 14:00:58 +0900 Subject: [PATCH 046/101] Make TestCasePlayer more usable No results screen crash, no unnecessary leadin time. --- osu.Game/Screens/Play/Player.cs | 9 ++++++++- osu.Game/Tests/Visual/TestCasePlayer.cs | 4 +++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 340fc39d52..531913470f 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -46,6 +46,8 @@ namespace osu.Game.Screens.Play public bool HasFailed { get; private set; } public bool AllowPause { get; set; } = true; + public bool AllowLeadIn { get; set; } = true; + public bool AllowResults { get; set; } = true; public int RestartCount; @@ -136,7 +138,10 @@ namespace osu.Game.Screens.Play decoupledClock = new DecoupleableInterpolatingFramedClock { IsCoupled = false }; var firstObjectTime = RulesetContainer.Objects.First().StartTime; - decoupledClock.Seek(Math.Min(0, firstObjectTime - Math.Max(beatmap.ControlPointInfo.TimingPointAt(firstObjectTime).BeatLength * 4, beatmap.BeatmapInfo.AudioLeadIn))); + decoupledClock.Seek(AllowLeadIn + ? Math.Min(0, firstObjectTime - Math.Max(beatmap.ControlPointInfo.TimingPointAt(firstObjectTime).BeatLength * 4, beatmap.BeatmapInfo.AudioLeadIn)) + : firstObjectTime); + decoupledClock.ProcessFrame(); offsetClock = new FramedOffsetClock(decoupledClock); @@ -273,6 +278,8 @@ namespace osu.Game.Screens.Play ValidForResume = false; + if (!AllowResults) return; + using (BeginDelayedSequence(1000)) { onCompletionEvent = Schedule(delegate diff --git a/osu.Game/Tests/Visual/TestCasePlayer.cs b/osu.Game/Tests/Visual/TestCasePlayer.cs index 106f0fa8f3..c71c1de499 100644 --- a/osu.Game/Tests/Visual/TestCasePlayer.cs +++ b/osu.Game/Tests/Visual/TestCasePlayer.cs @@ -91,7 +91,9 @@ namespace osu.Game.Tests.Visual protected virtual Player CreatePlayer(WorkingBeatmap beatmap, Ruleset ruleset) => new Player { InitialBeatmap = beatmap, - AllowPause = false + AllowPause = false, + AllowLeadIn = false, + AllowResults = false, }; private const string test_beatmap_data = From 99a44e6d79618374318ba0fac8a104603ec6a9e5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 26 Dec 2017 15:02:01 +0900 Subject: [PATCH 047/101] Allow testbrowser's rate adjust to affect TestCasePlayer --- osu.Game/Tests/Beatmaps/TestWorkingBeatmap.cs | 2 +- osu.Game/Tests/Visual/TestCasePlayer.cs | 13 ++++++++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/osu.Game/Tests/Beatmaps/TestWorkingBeatmap.cs b/osu.Game/Tests/Beatmaps/TestWorkingBeatmap.cs index da139775b1..82248c2cb8 100644 --- a/osu.Game/Tests/Beatmaps/TestWorkingBeatmap.cs +++ b/osu.Game/Tests/Beatmaps/TestWorkingBeatmap.cs @@ -19,6 +19,6 @@ namespace osu.Game.Tests.Beatmaps protected override Beatmap GetBeatmap() => beatmap; protected override Texture GetBackground() => null; - protected override Track GetTrack() => null; + protected override Track GetTrack() => new TrackVirtual(); } } diff --git a/osu.Game/Tests/Visual/TestCasePlayer.cs b/osu.Game/Tests/Visual/TestCasePlayer.cs index c71c1de499..933781890f 100644 --- a/osu.Game/Tests/Visual/TestCasePlayer.cs +++ b/osu.Game/Tests/Visual/TestCasePlayer.cs @@ -22,6 +22,8 @@ namespace osu.Game.Tests.Visual protected Player Player; + private TestWorkingBeatmap working; + /// /// Create a TestCase which runs through the Player screen. /// @@ -75,7 +77,7 @@ namespace osu.Game.Tests.Visual var instance = r.CreateInstance(); - WorkingBeatmap working = new TestWorkingBeatmap(beatmap); + working = new TestWorkingBeatmap(beatmap); working.Mods.Value = new[] { instance.GetAllMods().First(m => m is ModNoFail) }; if (Player != null) @@ -88,6 +90,15 @@ namespace osu.Game.Tests.Visual return player; } + protected override void Update() + { + base.Update(); + + if (working != null) + // note that this will override any mod rate application + working.Track.Rate = Clock.Rate; + } + protected virtual Player CreatePlayer(WorkingBeatmap beatmap, Ruleset ruleset) => new Player { InitialBeatmap = beatmap, From 9ccc49c9b5a2b61c73e30a9cea35118614f5f4fb Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 26 Dec 2017 15:32:39 +0900 Subject: [PATCH 048/101] Make selection triggering more liberal --- osu.Game/Screens/Select/BeatmapCarousel.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index e3566f3206..9d7867659d 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -513,7 +513,7 @@ namespace osu.Game.Screens.Select currentY += DrawHeight / 2; scrollableContent.Height = currentY; - if (selectedBeatmapSet != null && (selectedBeatmap == null || selectedBeatmapSet.State.Value != CarouselItemState.Selected)) + if (selectedBeatmapSet == null || selectedBeatmap == null || selectedBeatmapSet.State.Value != CarouselItemState.Selected) { selectedBeatmapSet = null; SelectionChanged?.Invoke(null); From e14ad31a071cacfc10f4ab8668f3d00634776c68 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 26 Dec 2017 15:32:53 +0900 Subject: [PATCH 049/101] Increase wait durations for test stability --- osu.Game.Tests/Visual/TestCasePlaySongSelect.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCasePlaySongSelect.cs b/osu.Game.Tests/Visual/TestCasePlaySongSelect.cs index e27e786a05..69aa371958 100644 --- a/osu.Game.Tests/Visual/TestCasePlaySongSelect.cs +++ b/osu.Game.Tests/Visual/TestCasePlaySongSelect.cs @@ -90,7 +90,7 @@ namespace osu.Game.Tests.Visual loadNewSongSelect(true); - AddWaitStep(1); + AddWaitStep(3); AddAssert("dummy selected", () => songSelect.CurrentBeatmap == defaultBeatmap); @@ -100,11 +100,11 @@ namespace osu.Game.Tests.Visual manager.Import(createTestBeatmapSet(i)); }); - AddWaitStep(1); + AddWaitStep(3); AddAssert("random map selected", () => songSelect.CurrentBeatmap != defaultBeatmap); loadNewSongSelect(); - AddWaitStep(1); + AddWaitStep(3); AddAssert("random map selected", () => songSelect.CurrentBeatmap != defaultBeatmap); AddStep(@"Sort by Artist", delegate { songSelect.FilterControl.Sort = SortMode.Artist; }); From 024d9a6850c9071225cba706b77e8f21d9f426e6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 26 Dec 2017 15:33:02 +0900 Subject: [PATCH 050/101] Remove unnecessary null check --- .../Visual/TestCasePlaySongSelect.cs | 25 ++++++++----------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCasePlaySongSelect.cs b/osu.Game.Tests/Visual/TestCasePlaySongSelect.cs index 69aa371958..18e40db064 100644 --- a/osu.Game.Tests/Visual/TestCasePlaySongSelect.cs +++ b/osu.Game.Tests/Visual/TestCasePlaySongSelect.cs @@ -59,21 +59,18 @@ namespace osu.Game.Tests.Visual { TestSongSelect songSelect = null; - if (manager == null) + var storage = new TestStorage(@"TestCasePlaySongSelect"); + + // this is by no means clean. should be replacing inside of OsuGameBase somehow. + var context = new OsuDbContext(); + + Func contextFactory = () => context; + + dependencies.Cache(rulesets = new RulesetStore(contextFactory)); + dependencies.Cache(manager = new BeatmapManager(storage, contextFactory, rulesets, null) { - var storage = new TestStorage(@"TestCasePlaySongSelect"); - - // this is by no means clean. should be replacing inside of OsuGameBase somehow. - var context = new OsuDbContext(); - - Func contextFactory = () => context; - - dependencies.Cache(rulesets = new RulesetStore(contextFactory)); - dependencies.Cache(manager = new BeatmapManager(storage, contextFactory, rulesets, null) - { - DefaultBeatmap = defaultBeatmap = baseManager.GetWorkingBeatmap(null) - }); - } + DefaultBeatmap = defaultBeatmap = baseManager.GetWorkingBeatmap(null) + }); void loadNewSongSelect(bool deleteMaps = false) => AddStep("reload song select", () => { From ed1df94f778d983933e72183a386e0f3bbd1b11d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 26 Dec 2017 15:48:01 +0900 Subject: [PATCH 051/101] Fix unread light not turning off --- osu.Game/Overlays/Notifications/Notification.cs | 2 +- osu.Game/Overlays/Notifications/SimpleNotification.cs | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Notifications/Notification.cs b/osu.Game/Overlays/Notifications/Notification.cs index 422051364e..b4720e79c4 100644 --- a/osu.Game/Overlays/Notifications/Notification.cs +++ b/osu.Game/Overlays/Notifications/Notification.cs @@ -261,4 +261,4 @@ namespace osu.Game.Overlays.Notifications } } } -} \ No newline at end of file +} diff --git a/osu.Game/Overlays/Notifications/SimpleNotification.cs b/osu.Game/Overlays/Notifications/SimpleNotification.cs index 0b8b365c48..1e691e2a5a 100644 --- a/osu.Game/Overlays/Notifications/SimpleNotification.cs +++ b/osu.Game/Overlays/Notifications/SimpleNotification.cs @@ -83,8 +83,10 @@ namespace osu.Game.Overlays.Notifications set { + if (value == base.Read) return; + base.Read = value; - Light.FadeTo(value ? 1 : 0, 100); + Light.FadeTo(value ? 0 : 1, 100); } } } From 45b3acdd6f1ad89ade0f0abd8564c0fcaa7fefb7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 26 Dec 2017 15:50:59 +0900 Subject: [PATCH 052/101] Fix progress notifications not closing properly when opening their continuation --- osu.Game/Overlays/Notifications/ProgressNotification.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Notifications/ProgressNotification.cs b/osu.Game/Overlays/Notifications/ProgressNotification.cs index 9211c227f8..c39c630858 100644 --- a/osu.Game/Overlays/Notifications/ProgressNotification.cs +++ b/osu.Game/Overlays/Notifications/ProgressNotification.cs @@ -95,7 +95,7 @@ namespace osu.Game.Overlays.Notifications protected virtual void Completed() { - Expire(); + base.Close(); CompletionTarget?.Invoke(CreateCompletionNotification()); } From 24d8d357d07e762fb233411c5e8860400664f151 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 26 Dec 2017 15:52:36 +0900 Subject: [PATCH 053/101] Only bounce and flash notification count when increasing --- .../Toolbar/ToolbarNotificationButton.cs | 21 ++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/osu.Game/Overlays/Toolbar/ToolbarNotificationButton.cs b/osu.Game/Overlays/Toolbar/ToolbarNotificationButton.cs index faf802f5e7..c093767e52 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarNotificationButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarNotificationButton.cs @@ -59,16 +59,27 @@ namespace osu.Game.Overlays.Toolbar private class CountCircle : CompositeDrawable { - private readonly OsuSpriteText count; + private readonly OsuSpriteText countText; private readonly Circle circle; + private int count; + public int Count { + get { return count; } set { - count.Text = value.ToString("#,0"); - circle.FlashColour(Color4.White, 600, Easing.OutQuint); - this.ScaleTo(1.1f).Then().ScaleTo(1, 600, Easing.OutElastic); + if (count == value) + return; + + if (value > count) + { + circle.FlashColour(Color4.White, 600, Easing.OutQuint); + this.ScaleTo(1.1f).Then().ScaleTo(1, 600, Easing.OutElastic); + } + + count = value; + countText.Text = value.ToString("#,0"); } } @@ -83,7 +94,7 @@ namespace osu.Game.Overlays.Toolbar RelativeSizeAxes = Axes.Both, Colour = Color4.Red }, - count = new OsuSpriteText + countText = new OsuSpriteText { Anchor = Anchor.Centre, Origin = Anchor.Centre, From c15b2382a218a7171258f6b3aa0a1013fef9b311 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 26 Dec 2017 15:56:32 +0900 Subject: [PATCH 054/101] Remove unused variable --- osu.Game/OsuGame.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 391a9ee19a..4342b020a8 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -374,8 +374,6 @@ namespace osu.Game notifications.State = Visibility.Hidden; } - private ScheduledDelegate notificationsEnabler; - private void screenChanged(Screen newScreen) { currentScreen = newScreen as OsuScreen; From f737a64189ea85a0e316e9034c5c21749346e375 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 26 Dec 2017 16:09:40 +0900 Subject: [PATCH 055/101] Remove ScreenChanged --- osu.Game/OsuGame.cs | 20 ++------------------ 1 file changed, 2 insertions(+), 18 deletions(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 4342b020a8..b45a9f41ea 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -355,8 +355,6 @@ namespace osu.Game public bool OnReleased(GlobalAction action) => false; - public event Action ScreenChanged; - private Container mainContent; private Container overlayContent; @@ -374,19 +372,6 @@ namespace osu.Game notifications.State = Visibility.Hidden; } - private void screenChanged(Screen newScreen) - { - currentScreen = newScreen as OsuScreen; - - if (currentScreen == null) - { - Exit(); - return; - } - - ScreenChanged?.Invoke(newScreen); - } - protected override bool OnExiting() { if (screenStack.ChildScreen == null) return false; @@ -434,13 +419,12 @@ namespace osu.Game { newScreen.ModePushed += screenAdded; newScreen.Exited += screenRemoved; - - screenChanged(newScreen); } private void screenRemoved(Screen newScreen) { - screenChanged(newScreen); + if (newScreen == null) + Exit(); } } } From 3f1ced618ae6db07f71ad6ba05b81f477c617334 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 26 Dec 2017 16:15:15 +0900 Subject: [PATCH 056/101] Update framework --- osu-framework | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu-framework b/osu-framework index 08f85f9bf9..46d4704b0a 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit 08f85f9bf9a7376aec8dfcde8c7c96d267d8c295 +Subproject commit 46d4704b0a3f140fa8ad10ca0b1553b67d8385ab From 836d807f4ff122480e9a029d0606aae669f62945 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 26 Dec 2017 19:32:20 +0900 Subject: [PATCH 057/101] Give SampleControlPoint a 100% volume by default --- osu.Game/Beatmaps/ControlPoints/SampleControlPoint.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Beatmaps/ControlPoints/SampleControlPoint.cs b/osu.Game/Beatmaps/ControlPoints/SampleControlPoint.cs index 40e45da13c..c2c13e1909 100644 --- a/osu.Game/Beatmaps/ControlPoints/SampleControlPoint.cs +++ b/osu.Game/Beatmaps/ControlPoints/SampleControlPoint.cs @@ -17,7 +17,7 @@ namespace osu.Game.Beatmaps.ControlPoints /// /// The default sample volume at this control point. /// - public int SampleVolume; + public int SampleVolume = 100; /// /// Create a SampleInfo based on the sample settings in this control point. From 3113a55a988be6fe7112f73d1c905edd0cd787ab Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 26 Dec 2017 19:33:01 +0900 Subject: [PATCH 058/101] Make ControlPointInfo return a set default control point --- .../ControlPoints/ControlPointInfo.cs | 27 +++++++++++-------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs b/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs index f031ebe353..5ad6b4ec6b 100644 --- a/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs +++ b/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs @@ -12,6 +12,11 @@ namespace osu.Game.Beatmaps.ControlPoints [Serializable] public class ControlPointInfo { + private static readonly TimingControlPoint default_timing_point = new TimingControlPoint(); + private static readonly DifficultyControlPoint default_difficulty_point = new DifficultyControlPoint(); + private static readonly SampleControlPoint default_sample_point = new SampleControlPoint(); + private static readonly EffectControlPoint default_effect_point = new EffectControlPoint(); + /// /// All timing points. /// @@ -41,68 +46,68 @@ namespace osu.Game.Beatmaps.ControlPoints /// /// The time to find the difficulty control point at. /// The difficulty control point. - public DifficultyControlPoint DifficultyPointAt(double time) => binarySearch(DifficultyPoints, time); + public DifficultyControlPoint DifficultyPointAt(double time) => binarySearch(DifficultyPoints, time, default_difficulty_point); /// /// Finds the effect control point that is active at . /// /// The time to find the effect control point at. /// The effect control point. - public EffectControlPoint EffectPointAt(double time) => binarySearch(EffectPoints, time); + public EffectControlPoint EffectPointAt(double time) => binarySearch(EffectPoints, time, default_effect_point); /// /// Finds the sound control point that is active at . /// /// The time to find the sound control point at. /// The sound control point. - public SampleControlPoint SamplePointAt(double time) => binarySearch(SamplePoints, time, SamplePoints.FirstOrDefault()); + public SampleControlPoint SamplePointAt(double time) => binarySearch(SamplePoints, time, SamplePoints.FirstOrDefault() ?? default_sample_point); /// /// Finds the timing control point that is active at . /// /// The time to find the timing control point at. /// The timing control point. - public TimingControlPoint TimingPointAt(double time) => binarySearch(TimingPoints, time, TimingPoints.FirstOrDefault()); + public TimingControlPoint TimingPointAt(double time) => binarySearch(TimingPoints, time, TimingPoints.FirstOrDefault() ?? default_timing_point); [JsonIgnore] /// /// Finds the maximum BPM represented by any timing control point. /// public double BPMMaximum => - 60000 / (TimingPoints.OrderBy(c => c.BeatLength).FirstOrDefault() ?? new TimingControlPoint()).BeatLength; + 60000 / (TimingPoints.OrderBy(c => c.BeatLength).FirstOrDefault() ?? default_timing_point).BeatLength; [JsonIgnore] /// /// Finds the minimum BPM represented by any timing control point. /// public double BPMMinimum => - 60000 / (TimingPoints.OrderByDescending(c => c.BeatLength).FirstOrDefault() ?? new TimingControlPoint()).BeatLength; + 60000 / (TimingPoints.OrderByDescending(c => c.BeatLength).FirstOrDefault() ?? default_timing_point).BeatLength; [JsonIgnore] /// /// Finds the mode BPM (most common BPM) represented by the control points. /// public double BPMMode => - 60000 / (TimingPoints.GroupBy(c => c.BeatLength).OrderByDescending(grp => grp.Count()).FirstOrDefault()?.FirstOrDefault() ?? new TimingControlPoint()).BeatLength; + 60000 / (TimingPoints.GroupBy(c => c.BeatLength).OrderByDescending(grp => grp.Count()).FirstOrDefault()?.FirstOrDefault() ?? default_timing_point).BeatLength; /// /// Binary searches one of the control point lists to find the active control point at . /// /// The list to search. /// The time to find the control point at. - /// The control point to use when is before any control points. If null, a new control point will be constructed. + /// The control point to use when there is not control point before . /// The active control point at . - private T binarySearch(SortedList list, double time, T prePoint = null) + private T binarySearch(SortedList list, double time, T defaultPoint) where T : ControlPoint, new() { if (list == null) throw new ArgumentNullException(nameof(list)); if (list.Count == 0) - return new T(); + return defaultPoint; if (time < list[0].Time) - return prePoint ?? new T(); + return defaultPoint; int index = list.BinarySearch(new T { Time = time }); From c74561b3d4e1db279f2fc8e24d3648b3f8c61c6d Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 26 Dec 2017 19:33:28 +0900 Subject: [PATCH 059/101] Add test case for InputDrum --- .../Tests/TestCaseInputDrum.cs | 32 +++++++++++++++++++ .../osu.Game.Rulesets.Taiko.csproj | 1 + 2 files changed, 33 insertions(+) create mode 100644 osu.Game.Rulesets.Taiko/Tests/TestCaseInputDrum.cs diff --git a/osu.Game.Rulesets.Taiko/Tests/TestCaseInputDrum.cs b/osu.Game.Rulesets.Taiko/Tests/TestCaseInputDrum.cs new file mode 100644 index 0000000000..7c18ecc34b --- /dev/null +++ b/osu.Game.Rulesets.Taiko/Tests/TestCaseInputDrum.cs @@ -0,0 +1,32 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using NUnit.Framework; +using OpenTK; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Beatmaps.ControlPoints; +using osu.Game.Rulesets.Taiko.UI; +using osu.Game.Tests.Visual; + +namespace osu.Game.Rulesets.Taiko.Tests +{ + [Ignore("getting CI working")] + public class TestCaseInputDrum : OsuTestCase + { + public TestCaseInputDrum() + { + Add(new TaikoInputManager(new RulesetInfo { ID = 1 }) + { + RelativeSizeAxes = Axes.Both, + Child = new Container + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Size = new Vector2(200), + Child = new InputDrum(new ControlPointInfo()) + } + }); + } + } +} diff --git a/osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj b/osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj index f1c29c1a34..bd0d199772 100644 --- a/osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj +++ b/osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj @@ -83,6 +83,7 @@ + From 44fbe7859a0a703f540f2fa6a70b413665bcb75a Mon Sep 17 00:00:00 2001 From: Aergwyn Date: Tue, 26 Dec 2017 11:34:26 +0100 Subject: [PATCH 060/101] move anchor and origin so metadata doesn't move if it's partially empty --- osu.Game/Screens/Select/BeatmapInfoWedge.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Select/BeatmapInfoWedge.cs b/osu.Game/Screens/Select/BeatmapInfoWedge.cs index 5d4f950a51..4f20b50d35 100644 --- a/osu.Game/Screens/Select/BeatmapInfoWedge.cs +++ b/osu.Game/Screens/Select/BeatmapInfoWedge.cs @@ -154,9 +154,10 @@ namespace osu.Game.Screens.Select }, new FillFlowContainer { - Name = "Bottom-aligned metadata", - Anchor = Anchor.BottomLeft, - Origin = Anchor.BottomLeft, + Name = "Centre-aligned metadata", + Anchor = Anchor.CentreLeft, + Origin = Anchor.TopLeft, + Y = -22, Direction = FillDirection.Vertical, Margin = new MarginPadding { Top = 15, Left = 25, Right = 10, Bottom = 20 }, AutoSizeAxes = Axes.Both, From 96905915931336c16d5b808af25c41a4cd7b9a4b Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 26 Dec 2017 19:55:56 +0900 Subject: [PATCH 061/101] Make taiko use namespaced hitsounds This is a temporary solution for now that uses DrawableHitObject.SampleNamespace for the override. We will not want to do this going forward, and instead have the rulesets add their custom resource stores to the games', but that requires deciding where/when to apply/remove such resource stores, and is probably left to skinning. --- osu-resources | 2 +- osu.Game.Rulesets.Taiko/Audio/DrumSampleMapping.cs | 4 ++-- .../Objects/Drawables/DrawableTaikoHitObject.cs | 2 ++ osu.Game.Rulesets.Taiko/Tests/TestCaseInputDrum.cs | 12 ++++++++++++ osu.Game/Audio/SampleInfo.cs | 11 +++++++++-- .../Rulesets/Objects/Drawables/DrawableHitObject.cs | 5 ++++- 6 files changed, 30 insertions(+), 6 deletions(-) diff --git a/osu-resources b/osu-resources index 4287ee8043..e01f71160f 160000 --- a/osu-resources +++ b/osu-resources @@ -1 +1 @@ -Subproject commit 4287ee8043fb1419017359bc3a5db5dc06bc643f +Subproject commit e01f71160fb9b3167efcd177c7d7dba9e5d36604 diff --git a/osu.Game.Rulesets.Taiko/Audio/DrumSampleMapping.cs b/osu.Game.Rulesets.Taiko/Audio/DrumSampleMapping.cs index 9d0037b97a..74e2195e09 100644 --- a/osu.Game.Rulesets.Taiko/Audio/DrumSampleMapping.cs +++ b/osu.Game.Rulesets.Taiko/Audio/DrumSampleMapping.cs @@ -30,8 +30,8 @@ namespace osu.Game.Rulesets.Taiko.Audio { mappings[s] = new DrumSample { - Centre = s.GetSampleInfo().GetChannel(audio.Sample), - Rim = s.GetSampleInfo(SampleInfo.HIT_CLAP).GetChannel(audio.Sample) + Centre = s.GetSampleInfo().GetChannel(audio.Sample, "Taiko"), + Rim = s.GetSampleInfo(SampleInfo.HIT_CLAP).GetChannel(audio.Sample, "Taiko") }; } } diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs index 92da3fe09e..cc7dd2fa0f 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs @@ -41,6 +41,8 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables // Normal and clap samples are handled by the drum protected override IEnumerable GetSamples() => HitObject.Samples.Where(s => s.Name != SampleInfo.HIT_NORMAL && s.Name != SampleInfo.HIT_CLAP); + protected override string SampleNamespace => "Taiko"; + protected virtual TaikoPiece CreateMainPiece() => new CirclePiece(); public abstract bool OnPressed(TaikoAction action); diff --git a/osu.Game.Rulesets.Taiko/Tests/TestCaseInputDrum.cs b/osu.Game.Rulesets.Taiko/Tests/TestCaseInputDrum.cs index 7c18ecc34b..172c6e9d84 100644 --- a/osu.Game.Rulesets.Taiko/Tests/TestCaseInputDrum.cs +++ b/osu.Game.Rulesets.Taiko/Tests/TestCaseInputDrum.cs @@ -1,11 +1,15 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System; +using System.Collections.Generic; using NUnit.Framework; using OpenTK; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Game.Audio; using osu.Game.Beatmaps.ControlPoints; +using osu.Game.Rulesets.Taiko.Audio; using osu.Game.Rulesets.Taiko.UI; using osu.Game.Tests.Visual; @@ -14,6 +18,14 @@ namespace osu.Game.Rulesets.Taiko.Tests [Ignore("getting CI working")] public class TestCaseInputDrum : OsuTestCase { + public override IReadOnlyList RequiredTypes => new[] + { + typeof(InputDrum), + typeof(DrumSampleMapping), + typeof(SampleInfo), + typeof(SampleControlPoint) + }; + public TestCaseInputDrum() { Add(new TaikoInputManager(new RulesetInfo { ID = 1 }) diff --git a/osu.Game/Audio/SampleInfo.cs b/osu.Game/Audio/SampleInfo.cs index 64a9aa50a0..1133dde570 100644 --- a/osu.Game/Audio/SampleInfo.cs +++ b/osu.Game/Audio/SampleInfo.cs @@ -14,9 +14,16 @@ namespace osu.Game.Audio public const string HIT_NORMAL = @"hitnormal"; public const string HIT_CLAP = @"hitclap"; - public SampleChannel GetChannel(SampleManager manager) + public SampleChannel GetChannel(SampleManager manager, string resourceNamespace = null) { - var channel = manager.Get($"Gameplay/{Bank}-{Name}"); + SampleChannel channel = null; + + if (!string.IsNullOrEmpty(resourceNamespace)) + channel = manager.Get($"Gameplay/{resourceNamespace}/{Bank}-{Name}"); + + if (channel == null) + channel = manager.Get($"Gameplay/{Bank}-{Name}"); + channel.Volume.Value = Volume / 100.0; return channel; } diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index ab4c04be3f..c118cd5bee 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -74,6 +74,9 @@ namespace osu.Game.Rulesets.Objects.Drawables protected List Samples = new List(); protected virtual IEnumerable GetSamples() => HitObject.Samples; + // Todo: Rulesets should be overriding the resources instead, but we need to figure out where/when to apply overrides first + protected virtual string SampleNamespace => null; + public readonly Bindable State = new Bindable(); protected DrawableHitObject(TObject hitObject) @@ -101,7 +104,7 @@ namespace osu.Game.Rulesets.Objects.Drawables Volume = s.Volume > 0 ? s.Volume : HitObject.SampleControlPoint.SampleVolume }; - SampleChannel channel = localSampleInfo.GetChannel(audio.Sample); + SampleChannel channel = localSampleInfo.GetChannel(audio.Sample, SampleNamespace); if (channel == null) continue; From 0c4e4012f8a13dcebeaa4f5851c5469cbbaf7d3e Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 26 Dec 2017 19:57:16 +0900 Subject: [PATCH 062/101] Taiko drumroll ticks should just play the playfield samples --- osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs b/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs index 5a566fd091..a39d627cc4 100644 --- a/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs +++ b/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs @@ -3,9 +3,6 @@ using osu.Game.Rulesets.Objects.Types; using System; -using System.Collections.Generic; -using System.Linq; -using osu.Game.Audio; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; @@ -75,13 +72,7 @@ namespace osu.Game.Rulesets.Taiko.Objects FirstTick = first, TickSpacing = tickSpacing, StartTime = t, - IsStrong = IsStrong, - Samples = new List(Samples.Select(s => new SampleInfo - { - Bank = s.Bank, - Name = @"slidertick", - Volume = s.Volume - })) + IsStrong = IsStrong }); first = false; From d479955e20e48b48cf75dbe390a6601cd63e4b89 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 26 Dec 2017 20:01:02 +0900 Subject: [PATCH 063/101] Fix spelling error --- osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs b/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs index 5ad6b4ec6b..234a50d5dd 100644 --- a/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs +++ b/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs @@ -95,7 +95,7 @@ namespace osu.Game.Beatmaps.ControlPoints /// /// The list to search. /// The time to find the control point at. - /// The control point to use when there is not control point before . + /// The control point to use when there is no control point before . /// The active control point at . private T binarySearch(SortedList list, double time, T defaultPoint) where T : ControlPoint, new() From 1c4bcdda96f690123a8eb2ae7a502da9cac11a52 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 26 Dec 2017 20:13:55 +0900 Subject: [PATCH 064/101] Fix test race condition async loads --- osu.Game.Tests/Visual/TestCaseBeatmapInfoWedge.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game.Tests/Visual/TestCaseBeatmapInfoWedge.cs b/osu.Game.Tests/Visual/TestCaseBeatmapInfoWedge.cs index 61c904aa60..53943edfab 100644 --- a/osu.Game.Tests/Visual/TestCaseBeatmapInfoWedge.cs +++ b/osu.Game.Tests/Visual/TestCaseBeatmapInfoWedge.cs @@ -110,11 +110,15 @@ namespace osu.Game.Tests.Visual private void selectBeatmap(string name) { + var infoBefore = infoWedge.Info; + AddStep($"select {name} beatmap", () => { beatmap.Value = new TestWorkingBeatmap(beatmaps.First(b => b.BeatmapInfo.Ruleset.ShortName == name)); infoWedge.UpdateBeatmap(beatmap); }); + + AddUntilStep(() => infoWedge.Info != infoBefore, "wait for async load"); } private void selectNullBeatmap() From 7504cd589dc532f67e1a2c42aac5505732c9c6ee Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 26 Dec 2017 20:18:47 +0900 Subject: [PATCH 065/101] Move alpha handling to state --- .../Visual/TestCaseBeatmapInfoWedge.cs | 20 +++++++++---------- osu.Game/Screens/Select/BeatmapInfoWedge.cs | 9 ++++++--- osu.Game/Screens/Select/SongSelect.cs | 1 - 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCaseBeatmapInfoWedge.cs b/osu.Game.Tests/Visual/TestCaseBeatmapInfoWedge.cs index 53943edfab..3a50e43239 100644 --- a/osu.Game.Tests/Visual/TestCaseBeatmapInfoWedge.cs +++ b/osu.Game.Tests/Visual/TestCaseBeatmapInfoWedge.cs @@ -41,25 +41,23 @@ namespace osu.Game.Tests.Visual { Size = new Vector2(0.5f, 245), RelativeSizeAxes = Axes.X, - Margin = new MarginPadding - { - Top = 20, - } - }); - - AddStep("hide", () => - { - infoWedge.State = Visibility.Hidden; - Content.FadeOut(100); + Margin = new MarginPadding { Top = 20 } }); AddStep("show", () => { - Content.FadeInFromZero(250); infoWedge.State = Visibility.Visible; infoWedge.UpdateBeatmap(beatmap); }); + AddWaitStep(3); + + AddStep("hide", () => { infoWedge.State = Visibility.Hidden; }); + + AddWaitStep(3); + + AddStep("show", () => { infoWedge.State = Visibility.Visible; }); + foreach (var rulesetInfo in rulesets.AvailableRulesets) { var ruleset = rulesetInfo.CreateInstance(); diff --git a/osu.Game/Screens/Select/BeatmapInfoWedge.cs b/osu.Game/Screens/Select/BeatmapInfoWedge.cs index 4f20b50d35..d4f1b90ebf 100644 --- a/osu.Game/Screens/Select/BeatmapInfoWedge.cs +++ b/osu.Game/Screens/Select/BeatmapInfoWedge.cs @@ -35,6 +35,7 @@ namespace osu.Game.Screens.Select Masking = true; BorderColour = new Color4(221, 255, 255, 255); BorderThickness = 2.5f; + Alpha = 0; EdgeEffect = new EdgeEffectParameters { Type = EdgeEffectType.Glow, @@ -50,12 +51,14 @@ namespace osu.Game.Screens.Select { this.MoveToX(0, 800, Easing.OutQuint); this.RotateTo(0, 800, Easing.OutQuint); + this.FadeIn(250); } protected override void PopOut() { - this.MoveToX(-100, 800, Easing.InQuint); - this.RotateTo(10, 800, Easing.InQuint); + this.MoveToX(-100, 800, Easing.In); + this.RotateTo(10, 800, Easing.In); + this.FadeOut(500, Easing.In); } public void UpdateBeatmap(WorkingBeatmap beatmap) @@ -68,7 +71,7 @@ namespace osu.Game.Screens.Select { // ensure we ourselves are visible if not already. if (!IsPresent) - this.FadeIn(250); + State = Visibility.Visible; Info?.FadeOut(250); Info?.Expire(); diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 68ee08e721..a66cd0b3e3 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -121,7 +121,6 @@ namespace osu.Game.Screens.Select }, beatmapInfoWedge = new BeatmapInfoWedge { - Alpha = 0, Size = wedged_container_size, RelativeSizeAxes = Axes.X, Margin = new MarginPadding From d17f6cb5647c03b4fef7f7464ef7cfbfac43fa43 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 27 Dec 2017 11:20:17 +0900 Subject: [PATCH 066/101] Fix crash when starting play mode with no beatmap Closes #1767 --- osu.Game/Screens/Play/PlayerLoader.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index de67bef004..a220dcee0e 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -250,7 +250,7 @@ namespace osu.Game.Screens.Play Origin = Anchor.TopCentre, Anchor = Anchor.TopCentre, }, - new MetadataLine("Mapper", metadata.Author.Username) + new MetadataLine("Mapper", metadata.AuthorString) { Origin = Anchor.TopCentre, Anchor = Anchor.TopCentre, From ae9f08f387dc26ca63eea7e09507e0ed9d4eded0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 27 Dec 2017 11:47:04 +0900 Subject: [PATCH 067/101] Fix crash in editor when trying to seek on a virtual track --- .../Edit/Components/Timelines/Summary/Parts/MarkerPart.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/MarkerPart.cs b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/MarkerPart.cs index 367cf4337d..b2308aca71 100644 --- a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/MarkerPart.cs +++ b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/MarkerPart.cs @@ -47,6 +47,8 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts if (Beatmap.Value == null) return; + if (Beatmap.Value.Track.Length == double.PositiveInfinity) return; + float markerPos = MathHelper.Clamp(ToLocalSpace(screenPosition).X, 0, DrawWidth); seekTo(markerPos / DrawWidth * Beatmap.Value.Track.Length); } From b95d7fc2cdbe07cd219256aedd413798a4728870 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 27 Dec 2017 12:41:59 +0900 Subject: [PATCH 068/101] Revert "Make ControlPointInfo return a set default control point" This reverts commit 3113a55a988be6fe7112f73d1c905edd0cd787ab. --- .../ControlPoints/ControlPointInfo.cs | 27 ++++++++----------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs b/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs index 234a50d5dd..f031ebe353 100644 --- a/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs +++ b/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs @@ -12,11 +12,6 @@ namespace osu.Game.Beatmaps.ControlPoints [Serializable] public class ControlPointInfo { - private static readonly TimingControlPoint default_timing_point = new TimingControlPoint(); - private static readonly DifficultyControlPoint default_difficulty_point = new DifficultyControlPoint(); - private static readonly SampleControlPoint default_sample_point = new SampleControlPoint(); - private static readonly EffectControlPoint default_effect_point = new EffectControlPoint(); - /// /// All timing points. /// @@ -46,68 +41,68 @@ namespace osu.Game.Beatmaps.ControlPoints /// /// The time to find the difficulty control point at. /// The difficulty control point. - public DifficultyControlPoint DifficultyPointAt(double time) => binarySearch(DifficultyPoints, time, default_difficulty_point); + public DifficultyControlPoint DifficultyPointAt(double time) => binarySearch(DifficultyPoints, time); /// /// Finds the effect control point that is active at . /// /// The time to find the effect control point at. /// The effect control point. - public EffectControlPoint EffectPointAt(double time) => binarySearch(EffectPoints, time, default_effect_point); + public EffectControlPoint EffectPointAt(double time) => binarySearch(EffectPoints, time); /// /// Finds the sound control point that is active at . /// /// The time to find the sound control point at. /// The sound control point. - public SampleControlPoint SamplePointAt(double time) => binarySearch(SamplePoints, time, SamplePoints.FirstOrDefault() ?? default_sample_point); + public SampleControlPoint SamplePointAt(double time) => binarySearch(SamplePoints, time, SamplePoints.FirstOrDefault()); /// /// Finds the timing control point that is active at . /// /// The time to find the timing control point at. /// The timing control point. - public TimingControlPoint TimingPointAt(double time) => binarySearch(TimingPoints, time, TimingPoints.FirstOrDefault() ?? default_timing_point); + public TimingControlPoint TimingPointAt(double time) => binarySearch(TimingPoints, time, TimingPoints.FirstOrDefault()); [JsonIgnore] /// /// Finds the maximum BPM represented by any timing control point. /// public double BPMMaximum => - 60000 / (TimingPoints.OrderBy(c => c.BeatLength).FirstOrDefault() ?? default_timing_point).BeatLength; + 60000 / (TimingPoints.OrderBy(c => c.BeatLength).FirstOrDefault() ?? new TimingControlPoint()).BeatLength; [JsonIgnore] /// /// Finds the minimum BPM represented by any timing control point. /// public double BPMMinimum => - 60000 / (TimingPoints.OrderByDescending(c => c.BeatLength).FirstOrDefault() ?? default_timing_point).BeatLength; + 60000 / (TimingPoints.OrderByDescending(c => c.BeatLength).FirstOrDefault() ?? new TimingControlPoint()).BeatLength; [JsonIgnore] /// /// Finds the mode BPM (most common BPM) represented by the control points. /// public double BPMMode => - 60000 / (TimingPoints.GroupBy(c => c.BeatLength).OrderByDescending(grp => grp.Count()).FirstOrDefault()?.FirstOrDefault() ?? default_timing_point).BeatLength; + 60000 / (TimingPoints.GroupBy(c => c.BeatLength).OrderByDescending(grp => grp.Count()).FirstOrDefault()?.FirstOrDefault() ?? new TimingControlPoint()).BeatLength; /// /// Binary searches one of the control point lists to find the active control point at . /// /// The list to search. /// The time to find the control point at. - /// The control point to use when there is no control point before . + /// The control point to use when is before any control points. If null, a new control point will be constructed. /// The active control point at . - private T binarySearch(SortedList list, double time, T defaultPoint) + private T binarySearch(SortedList list, double time, T prePoint = null) where T : ControlPoint, new() { if (list == null) throw new ArgumentNullException(nameof(list)); if (list.Count == 0) - return defaultPoint; + return new T(); if (time < list[0].Time) - return defaultPoint; + return prePoint ?? new T(); int index = list.BinarySearch(new T { Time = time }); From cf9a9762f7f7370c9f2cd1cf39080da5700b1455 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 27 Dec 2017 12:30:30 +0900 Subject: [PATCH 069/101] Fix beatmap wedge appearing with incorrect info on entering song select Closes #1762 --- osu.Game/Screens/Select/BeatmapCarousel.cs | 13 +++++++++++-- osu.Game/Screens/Select/BeatmapInfoWedge.cs | 4 ---- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index 9d7867659d..ffdd1daf72 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -53,6 +53,11 @@ namespace osu.Game.Screens.Select public override bool HandleInput => AllowSelection; + /// + /// Used to avoid firing null selections before the initial baetmaps have been loaded via . + /// + private bool initialLoadComplete; + private IEnumerable beatmapSets => root.Children.OfType(); public IEnumerable BeatmapSets @@ -76,7 +81,11 @@ namespace osu.Game.Screens.Select itemsCache.Invalidate(); scrollPositionCache.Invalidate(); - Schedule(() => BeatmapSetsChanged?.Invoke()); + Schedule(() => + { + BeatmapSetsChanged?.Invoke(); + initialLoadComplete = true; + }); })); } } @@ -513,7 +522,7 @@ namespace osu.Game.Screens.Select currentY += DrawHeight / 2; scrollableContent.Height = currentY; - if (selectedBeatmapSet == null || selectedBeatmap == null || selectedBeatmapSet.State.Value != CarouselItemState.Selected) + if (initialLoadComplete && (selectedBeatmapSet == null || selectedBeatmap == null || selectedBeatmapSet.State.Value != CarouselItemState.Selected)) { selectedBeatmapSet = null; SelectionChanged?.Invoke(null); diff --git a/osu.Game/Screens/Select/BeatmapInfoWedge.cs b/osu.Game/Screens/Select/BeatmapInfoWedge.cs index fa1326de8c..729cb458c2 100644 --- a/osu.Game/Screens/Select/BeatmapInfoWedge.cs +++ b/osu.Game/Screens/Select/BeatmapInfoWedge.cs @@ -71,10 +71,6 @@ namespace osu.Game.Screens.Select { State = beatmap == null ? Visibility.Hidden : Visibility.Visible; - // ensure we ourselves are visible if not already. - if (!IsPresent) - State = Visibility.Visible; - Info?.FadeOut(250); Info?.Expire(); From 519ef72adfa3b44d4a5fe28e904beb2fcd2c8c93 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 27 Dec 2017 13:03:46 +0900 Subject: [PATCH 070/101] Lookup by control point time rather than control point Under some situations, such as when there are no control points, ControlPointInfo will return to us a newly-constructed controlpoint with every call to SamplePointAt, which will fail on this key lookup. Between this and overriding GetHashCode, I think this is the more proper fix for this. --- osu.Game.Rulesets.Taiko/Audio/DrumSampleMapping.cs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Audio/DrumSampleMapping.cs b/osu.Game.Rulesets.Taiko/Audio/DrumSampleMapping.cs index 74e2195e09..982b339d3a 100644 --- a/osu.Game.Rulesets.Taiko/Audio/DrumSampleMapping.cs +++ b/osu.Game.Rulesets.Taiko/Audio/DrumSampleMapping.cs @@ -2,7 +2,6 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System.Collections.Generic; -using System.Linq; using osu.Framework.Audio; using osu.Framework.Audio.Sample; using osu.Game.Audio; @@ -13,7 +12,7 @@ namespace osu.Game.Rulesets.Taiko.Audio public class DrumSampleMapping { private readonly ControlPointInfo controlPoints; - private readonly Dictionary mappings = new Dictionary(); + private readonly Dictionary mappings = new Dictionary(); public DrumSampleMapping(ControlPointInfo controlPoints, AudioManager audio) { @@ -26,9 +25,9 @@ namespace osu.Game.Rulesets.Taiko.Audio else samplePoints = controlPoints.SamplePoints; - foreach (var s in samplePoints.Distinct()) + foreach (var s in samplePoints) { - mappings[s] = new DrumSample + mappings[s.Time] = new DrumSample { Centre = s.GetSampleInfo().GetChannel(audio.Sample, "Taiko"), Rim = s.GetSampleInfo(SampleInfo.HIT_CLAP).GetChannel(audio.Sample, "Taiko") @@ -36,7 +35,7 @@ namespace osu.Game.Rulesets.Taiko.Audio } } - public DrumSample SampleAt(double time) => mappings[controlPoints.SamplePointAt(time)]; + public DrumSample SampleAt(double time) => mappings[controlPoints.SamplePointAt(time).Time]; public class DrumSample { From 18d2be75d54a84dfe1d601c1a3cadab354fce7cc Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 27 Dec 2017 13:04:24 +0900 Subject: [PATCH 071/101] Fix random selection happening more than once on quick imports --- osu.Game/Screens/Select/SongSelect.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index b4494936f4..9e5a2fa633 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -444,7 +444,7 @@ namespace osu.Game.Screens.Select { if (!Beatmap.IsDefault && Beatmap.Value.BeatmapSetInfo?.DeletePending == false) Carousel.SelectBeatmap(Beatmap.Value.BeatmapInfo); - else + else if (Carousel.SelectedBeatmapSet == null) Carousel.SelectNextRandom(); } From 9fa0cfd250b7ed577a0169b2b436bac77fd4bb0c Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 27 Dec 2017 13:06:36 +0900 Subject: [PATCH 072/101] Fix taiko autoplay hitting drumroll ticks with the rims instead of centres Fixes #1772. --- osu.Game.Rulesets.Taiko/Replays/TaikoAutoGenerator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Taiko/Replays/TaikoAutoGenerator.cs b/osu.Game.Rulesets.Taiko/Replays/TaikoAutoGenerator.cs index df1a19267f..c43899ebf1 100644 --- a/osu.Game.Rulesets.Taiko/Replays/TaikoAutoGenerator.cs +++ b/osu.Game.Rulesets.Taiko/Replays/TaikoAutoGenerator.cs @@ -86,7 +86,7 @@ namespace osu.Game.Rulesets.Taiko.Replays { foreach (var tick in drumRoll.NestedHitObjects.OfType()) { - Frames.Add(new ReplayFrame(tick.StartTime, null, null, hitButton ? ReplayButtonState.Left1 : ReplayButtonState.Left2)); + Frames.Add(new ReplayFrame(tick.StartTime, null, null, hitButton ? ReplayButtonState.Right1 : ReplayButtonState.Right2)); hitButton = !hitButton; } } From 5b529511ec6727ccded551c9bce9312027ffa7f0 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 27 Dec 2017 13:18:34 +0900 Subject: [PATCH 073/101] Update OpenTK nuget package Fixes the recent AppVeyor errors --- osu.Desktop/osu.Desktop.csproj | 4 ++-- osu.Desktop/packages.config | 2 +- osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj | 4 ++-- osu.Game.Rulesets.Catch/packages.config | 2 +- osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj | 4 ++-- osu.Game.Rulesets.Mania/packages.config | 2 +- osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj | 4 ++-- osu.Game.Rulesets.Osu/packages.config | 2 +- osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj | 4 ++-- osu.Game.Rulesets.Taiko/packages.config | 2 +- osu.Game.Tests/osu.Game.Tests.csproj | 4 ++-- osu.Game.Tests/packages.config | 2 +- osu.Game/osu.Game.csproj | 4 ++-- osu.Game/packages.config | 2 +- 14 files changed, 21 insertions(+), 21 deletions(-) diff --git a/osu.Desktop/osu.Desktop.csproj b/osu.Desktop/osu.Desktop.csproj index e4e9807754..4a1798feb4 100644 --- a/osu.Desktop/osu.Desktop.csproj +++ b/osu.Desktop/osu.Desktop.csproj @@ -135,8 +135,8 @@ $(SolutionDir)\packages\squirrel.windows.1.7.8\lib\Net45\NuGet.Squirrel.dll True - - $(SolutionDir)\packages\OpenTK.3.0.0-git00009\lib\net20\OpenTK.dll + + $(SolutionDir)\packages\OpenTK.3.0.0-git00021\lib\net20\OpenTK.dll True diff --git a/osu.Desktop/packages.config b/osu.Desktop/packages.config index 6b6361b578..e7233a42ac 100644 --- a/osu.Desktop/packages.config +++ b/osu.Desktop/packages.config @@ -6,7 +6,7 @@ Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/maste - + diff --git a/osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj b/osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj index b03c8d2eea..578d8eb34d 100644 --- a/osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj +++ b/osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj @@ -36,8 +36,8 @@ $(SolutionDir)\packages\NUnit.3.8.1\lib\net45\nunit.framework.dll True - - $(SolutionDir)\packages\OpenTK.3.0.0-git00009\lib\net20\OpenTK.dll + + $(SolutionDir)\packages\OpenTK.3.0.0-git00021\lib\net20\OpenTK.dll True diff --git a/osu.Game.Rulesets.Catch/packages.config b/osu.Game.Rulesets.Catch/packages.config index cde428acea..2369f7529b 100644 --- a/osu.Game.Rulesets.Catch/packages.config +++ b/osu.Game.Rulesets.Catch/packages.config @@ -1,5 +1,5 @@  - + \ No newline at end of file diff --git a/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj b/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj index 26181164f9..bdd6656ed9 100644 --- a/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj +++ b/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj @@ -36,8 +36,8 @@ $(SolutionDir)\packages\NUnit.3.8.1\lib\net45\nunit.framework.dll True - - $(SolutionDir)\packages\OpenTK.3.0.0-git00009\lib\net20\OpenTK.dll + + $(SolutionDir)\packages\OpenTK.3.0.0-git00021\lib\net20\OpenTK.dll True diff --git a/osu.Game.Rulesets.Mania/packages.config b/osu.Game.Rulesets.Mania/packages.config index cde428acea..2369f7529b 100644 --- a/osu.Game.Rulesets.Mania/packages.config +++ b/osu.Game.Rulesets.Mania/packages.config @@ -1,5 +1,5 @@  - + \ No newline at end of file diff --git a/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj b/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj index ec71869adb..6e61d7fb2d 100644 --- a/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj +++ b/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj @@ -37,8 +37,8 @@ $(SolutionDir)\packages\NUnit.3.8.1\lib\net45\nunit.framework.dll True - - $(SolutionDir)\packages\OpenTK.3.0.0-git00009\lib\net20\OpenTK.dll + + $(SolutionDir)\packages\OpenTK.3.0.0-git00021\lib\net20\OpenTK.dll True diff --git a/osu.Game.Rulesets.Osu/packages.config b/osu.Game.Rulesets.Osu/packages.config index cde428acea..2369f7529b 100644 --- a/osu.Game.Rulesets.Osu/packages.config +++ b/osu.Game.Rulesets.Osu/packages.config @@ -1,5 +1,5 @@  - + \ No newline at end of file diff --git a/osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj b/osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj index f1c29c1a34..f73831a952 100644 --- a/osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj +++ b/osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj @@ -36,8 +36,8 @@ $(SolutionDir)\packages\NUnit.3.8.1\lib\net45\nunit.framework.dll True - - $(SolutionDir)\packages\OpenTK.3.0.0-git00009\lib\net20\OpenTK.dll + + $(SolutionDir)\packages\OpenTK.3.0.0-git00021\lib\net20\OpenTK.dll True diff --git a/osu.Game.Rulesets.Taiko/packages.config b/osu.Game.Rulesets.Taiko/packages.config index cde428acea..2369f7529b 100644 --- a/osu.Game.Rulesets.Taiko/packages.config +++ b/osu.Game.Rulesets.Taiko/packages.config @@ -1,5 +1,5 @@  - + \ No newline at end of file diff --git a/osu.Game.Tests/osu.Game.Tests.csproj b/osu.Game.Tests/osu.Game.Tests.csproj index e0b9eb4091..df66896d9b 100644 --- a/osu.Game.Tests/osu.Game.Tests.csproj +++ b/osu.Game.Tests/osu.Game.Tests.csproj @@ -37,8 +37,8 @@ $(SolutionDir)\packages\NUnit.3.8.1\lib\net45\nunit.framework.dll True - - $(SolutionDir)\packages\OpenTK.3.0.0-git00009\lib\net20\OpenTK.dll + + $(SolutionDir)\packages\OpenTK.3.0.0-git00021\lib\net20\OpenTK.dll True diff --git a/osu.Game.Tests/packages.config b/osu.Game.Tests/packages.config index e09f2a07ba..c2056e09a8 100644 --- a/osu.Game.Tests/packages.config +++ b/osu.Game.Tests/packages.config @@ -6,6 +6,6 @@ Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/maste - + \ No newline at end of file diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index b5f93123fd..7d146c0a12 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -143,8 +143,8 @@ $(SolutionDir)\packages\NUnit.3.8.1\lib\net45\nunit.framework.dll True - - $(SolutionDir)\packages\OpenTK.3.0.0-git00009\lib\net20\OpenTK.dll + + $(SolutionDir)\packages\OpenTK.3.0.0-git00021\lib\net20\OpenTK.dll True diff --git a/osu.Game/packages.config b/osu.Game/packages.config index 02ace918de..3ba50388e8 100644 --- a/osu.Game/packages.config +++ b/osu.Game/packages.config @@ -66,7 +66,7 @@ Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/maste - + From 2a7147240f74af787b7f0d217c7c63e250d912e7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 27 Dec 2017 13:25:42 +0900 Subject: [PATCH 074/101] Fix progress notifications not creating their completion notification early enough FIxes notification overlay thinking it has no notifications left and closing. --- osu.Game/Overlays/NotificationOverlay.cs | 9 ++++++--- osu.Game/Overlays/Notifications/ProgressNotification.cs | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/osu.Game/Overlays/NotificationOverlay.cs b/osu.Game/Overlays/NotificationOverlay.cs index 2f1c3285ef..f19a80ef47 100644 --- a/osu.Game/Overlays/NotificationOverlay.cs +++ b/osu.Game/Overlays/NotificationOverlay.cs @@ -85,9 +85,12 @@ namespace osu.Game.Overlays private void notificationClosed() { - // hide ourselves if all notifications have been dismissed. - if (totalCount == 0) - State = Visibility.Hidden; + Schedule(() => + { + // hide ourselves if all notifications have been dismissed. + if (totalCount == 0) + State = Visibility.Hidden; + }); updateCounts(); } diff --git a/osu.Game/Overlays/Notifications/ProgressNotification.cs b/osu.Game/Overlays/Notifications/ProgressNotification.cs index c39c630858..d797372390 100644 --- a/osu.Game/Overlays/Notifications/ProgressNotification.cs +++ b/osu.Game/Overlays/Notifications/ProgressNotification.cs @@ -95,8 +95,8 @@ namespace osu.Game.Overlays.Notifications protected virtual void Completed() { - base.Close(); CompletionTarget?.Invoke(CreateCompletionNotification()); + base.Close(); } public override bool DisplayOnTop => false; From 5ad86d2b757baefcc57b1ac545e4283be8920e3a Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 27 Dec 2017 13:50:54 +0900 Subject: [PATCH 075/101] Update framework --- osu-framework | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu-framework b/osu-framework index 46d4704b0a..b28d4ba82a 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit 46d4704b0a3f140fa8ad10ca0b1553b67d8385ab +Subproject commit b28d4ba82af0138d38ff8b3f4f3392d9d9068da9 From b97d0ce0509566a008cf38153e157222562aebf3 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 27 Dec 2017 14:59:45 +0900 Subject: [PATCH 076/101] Update framework --- osu-framework | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu-framework b/osu-framework index 08f85f9bf9..b28d4ba82a 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit 08f85f9bf9a7376aec8dfcde8c7c96d267d8c295 +Subproject commit b28d4ba82af0138d38ff8b3f4f3392d9d9068da9 From b564215527f506b726d7305411219a34d1a8ba73 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 27 Dec 2017 17:32:19 +0900 Subject: [PATCH 077/101] Update framework --- osu-framework | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu-framework b/osu-framework index 08f85f9bf9..b28d4ba82a 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit 08f85f9bf9a7376aec8dfcde8c7c96d267d8c295 +Subproject commit b28d4ba82af0138d38ff8b3f4f3392d9d9068da9 From b87e6c8b2ae1562045bb7cd3689a3cd9a594e9b0 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 27 Dec 2017 17:33:34 +0900 Subject: [PATCH 078/101] Add a method to get ruleset by name --- osu.Game/Rulesets/RulesetStore.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/osu.Game/Rulesets/RulesetStore.cs b/osu.Game/Rulesets/RulesetStore.cs index 5cdf46ee46..3038c51e64 100644 --- a/osu.Game/Rulesets/RulesetStore.cs +++ b/osu.Game/Rulesets/RulesetStore.cs @@ -38,6 +38,13 @@ namespace osu.Game.Rulesets /// A ruleset, if available, else null. public RulesetInfo GetRuleset(int id) => AvailableRulesets.FirstOrDefault(r => r.ID == id); + /// + /// Retrieve a ruleset using a known short name. + /// + /// The ruleset's short name. + /// A ruleset, if available, else null. + public RulesetInfo GetRuleset(string shortName) => AvailableRulesets.FirstOrDefault(r => r.ShortName == shortName); + /// /// All available rulesets. /// From cb18baa4d86e526d7d8ebf6cf6cb45618b07fe3f Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 27 Dec 2017 17:34:07 +0900 Subject: [PATCH 079/101] Add HitCircle/Slider testcases --- .../Objects/Drawables/DrawableSlider.cs | 5 -- .../Objects/ISliderProgress.cs | 10 +++ .../Tests/TestCaseHitCircle.cs | 51 +++++++++++ osu.Game.Rulesets.Osu/Tests/TestCaseSlider.cs | 88 +++++++++++++++++++ .../osu.Game.Rulesets.Osu.csproj | 3 + 5 files changed, 152 insertions(+), 5 deletions(-) create mode 100644 osu.Game.Rulesets.Osu/Objects/ISliderProgress.cs create mode 100644 osu.Game.Rulesets.Osu/Tests/TestCaseHitCircle.cs create mode 100644 osu.Game.Rulesets.Osu/Tests/TestCaseSlider.cs diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs index d8a22d94ca..41d5ef1b02 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs @@ -167,9 +167,4 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables public override Vector2 SelectionPoint => ToScreenSpace(body.Position); public override Quad SelectionQuad => body.PathDrawQuad; } - - internal interface ISliderProgress - { - void UpdateProgress(double progress, int repeat); - } } diff --git a/osu.Game.Rulesets.Osu/Objects/ISliderProgress.cs b/osu.Game.Rulesets.Osu/Objects/ISliderProgress.cs new file mode 100644 index 0000000000..cb0d177a60 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Objects/ISliderProgress.cs @@ -0,0 +1,10 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +namespace osu.Game.Rulesets.Osu.Objects +{ + public interface ISliderProgress + { + void UpdateProgress(double progress, int repeat); + } +} diff --git a/osu.Game.Rulesets.Osu/Tests/TestCaseHitCircle.cs b/osu.Game.Rulesets.Osu/Tests/TestCaseHitCircle.cs new file mode 100644 index 0000000000..a86101285a --- /dev/null +++ b/osu.Game.Rulesets.Osu/Tests/TestCaseHitCircle.cs @@ -0,0 +1,51 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Beatmaps; +using osu.Game.Beatmaps.ControlPoints; +using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Rulesets.Osu.Objects.Drawables; +using osu.Game.Tests.Visual; +using OpenTK; + +namespace osu.Game.Rulesets.Osu.Tests +{ + public class TestCaseHitCircle : OsuTestCase + { + private readonly Container content; + protected override Container Content => content; + + public TestCaseHitCircle() + { + base.Content.Add(content = new OsuInputManager(new RulesetInfo { ID = 0 })); + + AddStep("Single", addHitCircle); + AddStep("Stream", addStream); + } + + private void addHitCircle() + { + var circle = new HitCircle { StartTime = Time.Current + 1000 }; + circle.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()); + + Add(new DrawableHitCircle(circle) { Anchor = Anchor.Centre }); + } + + private void addStream() + { + Vector2 pos = Vector2.Zero; + + for (int i = 1000; i <= 2000; i += 100) + { + var circle = new HitCircle { StartTime = Time.Current + i, Position = pos }; + circle.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()); + + Add(new DrawableHitCircle(circle) { Anchor = Anchor.Centre, Depth = i}); + + pos += new Vector2(10); + } + } + } +} diff --git a/osu.Game.Rulesets.Osu/Tests/TestCaseSlider.cs b/osu.Game.Rulesets.Osu/Tests/TestCaseSlider.cs new file mode 100644 index 0000000000..c423ca3736 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Tests/TestCaseSlider.cs @@ -0,0 +1,88 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using System.Collections.Generic; +using System.Linq; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Audio; +using osu.Game.Beatmaps; +using osu.Game.Beatmaps.ControlPoints; +using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Rulesets.Osu.Objects.Drawables; +using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces; +using osu.Game.Tests.Visual; +using OpenTK; + +namespace osu.Game.Rulesets.Osu.Tests +{ + public class TestCaseSlider : OsuTestCase + { + public override IReadOnlyList RequiredTypes => new[] { typeof(DrawableSlider) }; + + private readonly Container content; + protected override Container Content => content; + + public TestCaseSlider() + { + base.Content.Add(content = new OsuInputManager(new RulesetInfo { ID = 0 })); + + AddStep("Single", addSingle); + AddStep("Repeated (1)", () => addRepeated(1)); + AddStep("Repeated (2)", () => addRepeated(2)); + AddStep("Repeated (3)", () => addRepeated(3)); + AddStep("Repeated (4)", () => addRepeated(4)); + AddStep("Stream", addStream); + } + + private void addSingle() + { + var slider = new Slider + { + StartTime = Time.Current + 1000, + Position = new Vector2(-200, 0), + ControlPoints = new List + { + new Vector2(-200, 0), + new Vector2(400, 0), + }, + Distance = 400, + Velocity = 1, + TickDistance = 100, + }; + + slider.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()); + + Add(new DrawableSlider(slider) { Anchor = Anchor.Centre }); + } + + private void addRepeated(int repeats) + { + var slider = new Slider + { + StartTime = Time.Current + 1000, + Position = new Vector2(-200, 0), + ControlPoints = new List + { + new Vector2(-200, 0), + new Vector2(400, 0), + }, + Distance = 400, + Velocity = 11, + TickDistance = 100, + RepeatCount = repeats, + RepeatSamples = new List[repeats].ToList() + }; + + slider.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()); + + Add(new DrawableSlider(slider) { Anchor = Anchor.Centre }); + } + + private void addStream() + { + + } + } +} diff --git a/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj b/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj index 6e61d7fb2d..d99f8bc948 100644 --- a/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj +++ b/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj @@ -75,6 +75,7 @@ + @@ -86,8 +87,10 @@ + + From 7d0c94fd01625e81565b530afe4df5e049c4c5ba Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 27 Dec 2017 19:42:44 +0900 Subject: [PATCH 080/101] Fix notification overlay layout and scheduled tasks being delayed Closes #1295 --- .../Visual/TestCaseNotificationOverlay.cs | 49 ++++++++++++++++--- .../Notifications/NotificationSection.cs | 4 ++ 2 files changed, 46 insertions(+), 7 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCaseNotificationOverlay.cs b/osu.Game.Tests/Visual/TestCaseNotificationOverlay.cs index a83cead213..e1711be102 100644 --- a/osu.Game.Tests/Visual/TestCaseNotificationOverlay.cs +++ b/osu.Game.Tests/Visual/TestCaseNotificationOverlay.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.Linq; using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; using osu.Framework.MathUtils; using osu.Game.Overlays; @@ -19,11 +20,12 @@ namespace osu.Game.Tests.Visual public override IReadOnlyList RequiredTypes => new[] { - typeof(Notification), + typeof(NotificationSection), + typeof(SimpleNotification), typeof(ProgressNotification), typeof(ProgressCompletionNotification), - typeof(SimpleNotification), typeof(IHasCompletionTarget), + typeof(Notification) }; public TestCaseNotificationOverlay() @@ -40,17 +42,44 @@ namespace osu.Game.Tests.Visual Content.Add(displayedCount); + void setState(Visibility state) => AddStep(state.ToString(), () => manager.State = state); + void checkProgressingCount(int expected) => AddAssert($"progressing count is {expected}", () => progressingNotifications.Count == expected); + manager.UnreadCount.ValueChanged += count => { displayedCount.Text = $"displayed count: {count}"; }; - AddStep(@"toggle", manager.ToggleVisibility); + + setState(Visibility.Visible); AddStep(@"simple #1", sendHelloNotification); AddStep(@"simple #2", sendAmazingNotification); AddStep(@"progress #1", sendUploadProgress); AddStep(@"progress #2", sendDownloadProgress); - AddStep(@"barrage", () => sendBarrage()); + + checkProgressingCount(2); + + setState(Visibility.Hidden); + + AddRepeatStep(@"add many simple", sendManyNotifications, 3); + AddWaitStep(5); + + checkProgressingCount(0); + + AddStep(@"progress #3", sendUploadProgress); + + checkProgressingCount(1); + + AddAssert("Displayed count is 33", () => manager.UnreadCount.Value == 33); + + AddWaitStep(5); + + checkProgressingCount(0); + + + setState(Visibility.Visible); + + //AddStep(@"barrage", () => sendBarrage()); } - private void sendBarrage(int remaining = 100) + private void sendBarrage(int remaining = 10) { switch (RNG.Next(0, 4)) { @@ -80,7 +109,7 @@ namespace osu.Game.Tests.Visual if (progressingNotifications.Count(n => n.State == ProgressNotificationState.Active) < 3) { - var p = progressingNotifications.FirstOrDefault(n => n.IsAlive && n.State == ProgressNotificationState.Queued); + var p = progressingNotifications.FirstOrDefault(n => n.State == ProgressNotificationState.Queued); if (p != null) p.State = ProgressNotificationState.Active; } @@ -88,7 +117,7 @@ namespace osu.Game.Tests.Visual foreach (var n in progressingNotifications.FindAll(n => n.State == ProgressNotificationState.Active)) { if (n.Progress < 1) - n.Progress += (float)(Time.Elapsed / 2000) * RNG.NextSingle(); + n.Progress += (float)(Time.Elapsed / 200) * RNG.NextSingle(); else n.State = ProgressNotificationState.Completed; } @@ -125,5 +154,11 @@ namespace osu.Game.Tests.Visual { manager.Post(new SimpleNotification { Text = @"Welcome to osu!. Enjoy your stay!" }); } + + private void sendManyNotifications() + { + for (int i = 0; i < 10; i++) + manager.Post(new SimpleNotification { Text = @"Spam incoming!!" }); + } } } diff --git a/osu.Game/Overlays/Notifications/NotificationSection.cs b/osu.Game/Overlays/Notifications/NotificationSection.cs index 2bd0321d12..e6587506aa 100644 --- a/osu.Game/Overlays/Notifications/NotificationSection.cs +++ b/osu.Game/Overlays/Notifications/NotificationSection.cs @@ -20,6 +20,10 @@ namespace osu.Game.Overlays.Notifications private OsuSpriteText titleText; private OsuSpriteText countText; + // this is required to ensure correct layout and scheduling on children. + // the layout portion of this is being tracked as a framework issue (TODO). + protected override bool RequiresChildrenUpdate => true; + private ClearAllButton clearButton; private FlowContainer notifications; From 4d5216da00d63a8830c42d3e7718d912b49fcc6c Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 27 Dec 2017 19:47:42 +0900 Subject: [PATCH 081/101] Finish up implementation of TestCaseSlider --- osu.Game.Rulesets.Osu/Tests/TestCaseSlider.cs | 66 ++++++++++++++----- 1 file changed, 49 insertions(+), 17 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Tests/TestCaseSlider.cs b/osu.Game.Rulesets.Osu/Tests/TestCaseSlider.cs index c423ca3736..5b9047db88 100644 --- a/osu.Game.Rulesets.Osu/Tests/TestCaseSlider.cs +++ b/osu.Game.Rulesets.Osu/Tests/TestCaseSlider.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using System.Linq; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Audio; @@ -11,7 +10,6 @@ using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables; -using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces; using osu.Game.Tests.Visual; using OpenTK; @@ -24,11 +22,18 @@ namespace osu.Game.Rulesets.Osu.Tests private readonly Container content; protected override Container Content => content; + private double speedMultiplier; + private double sliderMultiplier; + private int depthIndex; + public TestCaseSlider() { base.Content.Add(content = new OsuInputManager(new RulesetInfo { ID = 0 })); - AddStep("Single", addSingle); + AddSliderStep("SpeedMultiplier", 0.01, 10, 2, s => speedMultiplier = s); + AddSliderStep("SliderMultiplier", 0.01, 10, 2, s => sliderMultiplier = s); + + AddStep("Single", () => addSingle()); AddStep("Repeated (1)", () => addRepeated(1)); AddStep("Repeated (2)", () => addRepeated(2)); AddStep("Repeated (3)", () => addRepeated(3)); @@ -36,29 +41,44 @@ namespace osu.Game.Rulesets.Osu.Tests AddStep("Stream", addStream); } - private void addSingle() + private void addSingle(double timeOffset = 0, Vector2? positionOffset = null) { + positionOffset = positionOffset ?? Vector2.Zero; + var slider = new Slider { - StartTime = Time.Current + 1000, - Position = new Vector2(-200, 0), + StartTime = Time.Current + 1000 + timeOffset, + Position = new Vector2(-200, 0) + positionOffset.Value, ControlPoints = new List { - new Vector2(-200, 0), - new Vector2(400, 0), + new Vector2(-200, 0) + positionOffset.Value, + new Vector2(400, 0) + positionOffset.Value, }, Distance = 400, - Velocity = 1, - TickDistance = 100, }; - slider.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()); + var cpi = new ControlPointInfo(); + cpi.DifficultyPoints.Add(new DifficultyControlPoint { SpeedMultiplier = speedMultiplier }); - Add(new DrawableSlider(slider) { Anchor = Anchor.Centre }); + var difficulty = new BeatmapDifficulty { SliderMultiplier = (float)sliderMultiplier }; + + slider.ApplyDefaults(cpi, difficulty); + Add(new DrawableSlider(slider) + { + Anchor = Anchor.Centre, + Depth = depthIndex++ + }); } private void addRepeated(int repeats) { + // The first run through the slider is considered a repeat + repeats++; + + var repeatSamples = new List>(); + for (int i = 0; i < repeats; i++) + repeatSamples.Add(new List()); + var slider = new Slider { StartTime = Time.Current + 1000, @@ -69,20 +89,32 @@ namespace osu.Game.Rulesets.Osu.Tests new Vector2(400, 0), }, Distance = 400, - Velocity = 11, - TickDistance = 100, RepeatCount = repeats, - RepeatSamples = new List[repeats].ToList() + RepeatSamples = repeatSamples }; - slider.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()); + var cpi = new ControlPointInfo(); + cpi.DifficultyPoints.Add(new DifficultyControlPoint { SpeedMultiplier = speedMultiplier }); - Add(new DrawableSlider(slider) { Anchor = Anchor.Centre }); + var difficulty = new BeatmapDifficulty { SliderMultiplier = (float)sliderMultiplier }; + + slider.ApplyDefaults(cpi, difficulty); + Add(new DrawableSlider(slider) + { + Anchor = Anchor.Centre, + Depth = depthIndex++ + }); } private void addStream() { + Vector2 pos = Vector2.Zero; + for (int i = 0; i <= 1000; i += 100) + { + addSingle(i, pos); + pos += new Vector2(10); + } } } } From fdafc2107e40b5cd51916e648a3ae7a807491042 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 27 Dec 2017 19:47:55 +0900 Subject: [PATCH 082/101] Cleanups + add auto to TestCaseHitCircle --- .../Tests/TestCaseHitCircle.cs | 37 ++++++++++++++----- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Tests/TestCaseHitCircle.cs b/osu.Game.Rulesets.Osu/Tests/TestCaseHitCircle.cs index a86101285a..dea941fb01 100644 --- a/osu.Game.Rulesets.Osu/Tests/TestCaseHitCircle.cs +++ b/osu.Game.Rulesets.Osu/Tests/TestCaseHitCircle.cs @@ -5,6 +5,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; +using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables; using osu.Game.Tests.Visual; @@ -17,33 +18,49 @@ namespace osu.Game.Rulesets.Osu.Tests private readonly Container content; protected override Container Content => content; + private bool auto; + private int depthIndex; + public TestCaseHitCircle() { base.Content.Add(content = new OsuInputManager(new RulesetInfo { ID = 0 })); - AddStep("Single", addHitCircle); + AddStep("Single", () => addSingle()); AddStep("Stream", addStream); + AddToggleStep("Auto", v => auto = v); } - private void addHitCircle() + private void addSingle(double timeOffset = 0, Vector2? positionOffset = null) { - var circle = new HitCircle { StartTime = Time.Current + 1000 }; + positionOffset = positionOffset ?? Vector2.Zero; + + var circle = new HitCircle + { + StartTime = Time.Current + 1000 + timeOffset, + Position = positionOffset.Value + }; + circle.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()); - Add(new DrawableHitCircle(circle) { Anchor = Anchor.Centre }); + var drawable = new DrawableHitCircle(circle) + { + Anchor = Anchor.Centre, + Depth = depthIndex++ + }; + + if (auto) + drawable.State.Value = ArmedState.Hit; + + Add(drawable); } private void addStream() { Vector2 pos = Vector2.Zero; - for (int i = 1000; i <= 2000; i += 100) + for (int i = 0; i <= 1000; i += 100) { - var circle = new HitCircle { StartTime = Time.Current + i, Position = pos }; - circle.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()); - - Add(new DrawableHitCircle(circle) { Anchor = Anchor.Centre, Depth = i}); - + addSingle(i, pos); pos += new Vector2(10); } } From ccaf63a4378219d4cdef5453500c63acef9a94c0 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 27 Dec 2017 20:01:20 +0900 Subject: [PATCH 083/101] Add a Spinner testcase --- .../Tests/TestCaseSpinner.cs | 43 +++++++++++++++++++ .../osu.Game.Rulesets.Osu.csproj | 1 + 2 files changed, 44 insertions(+) create mode 100644 osu.Game.Rulesets.Osu/Tests/TestCaseSpinner.cs diff --git a/osu.Game.Rulesets.Osu/Tests/TestCaseSpinner.cs b/osu.Game.Rulesets.Osu/Tests/TestCaseSpinner.cs new file mode 100644 index 0000000000..6db9c1a473 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Tests/TestCaseSpinner.cs @@ -0,0 +1,43 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Beatmaps; +using osu.Game.Beatmaps.ControlPoints; +using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Rulesets.Osu.Objects.Drawables; +using osu.Game.Tests.Visual; + +namespace osu.Game.Rulesets.Osu.Tests +{ + public class TestCaseSpinner : OsuTestCase + { + private readonly Container content; + protected override Container Content => content; + + private int depthIndex; + + public TestCaseSpinner() + { + base.Content.Add(content = new OsuInputManager(new RulesetInfo { ID = 0 })); + + AddStep("Single", addSingle); + } + + private void addSingle() + { + var spinner = new Spinner { StartTime = Time.Current + 1000, EndTime = Time.Current + 4000 }; + + spinner.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()); + + var drawable = new DrawableSpinner(spinner) + { + Anchor = Anchor.Centre, + Depth = depthIndex++ + }; + + Add(drawable); + } + } +} diff --git a/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj b/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj index d99f8bc948..ab34d1803f 100644 --- a/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj +++ b/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj @@ -91,6 +91,7 @@ + From 4c032df6770e2372b899929628aa9f48a7876c74 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 27 Dec 2017 20:08:33 +0900 Subject: [PATCH 084/101] Move sliderbars to the end of the testcase buttons --- osu.Game.Rulesets.Osu/Tests/TestCaseSlider.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Tests/TestCaseSlider.cs b/osu.Game.Rulesets.Osu/Tests/TestCaseSlider.cs index 5b9047db88..4f7fa1dada 100644 --- a/osu.Game.Rulesets.Osu/Tests/TestCaseSlider.cs +++ b/osu.Game.Rulesets.Osu/Tests/TestCaseSlider.cs @@ -22,23 +22,23 @@ namespace osu.Game.Rulesets.Osu.Tests private readonly Container content; protected override Container Content => content; - private double speedMultiplier; - private double sliderMultiplier; + private double speedMultiplier = 2; + private double sliderMultiplier = 2; private int depthIndex; public TestCaseSlider() { base.Content.Add(content = new OsuInputManager(new RulesetInfo { ID = 0 })); - AddSliderStep("SpeedMultiplier", 0.01, 10, 2, s => speedMultiplier = s); - AddSliderStep("SliderMultiplier", 0.01, 10, 2, s => sliderMultiplier = s); - AddStep("Single", () => addSingle()); AddStep("Repeated (1)", () => addRepeated(1)); AddStep("Repeated (2)", () => addRepeated(2)); AddStep("Repeated (3)", () => addRepeated(3)); AddStep("Repeated (4)", () => addRepeated(4)); AddStep("Stream", addStream); + + AddSliderStep("SpeedMultiplier", 0.01, 10, 2, s => speedMultiplier = s); + AddSliderStep("SliderMultiplier", 0.01, 10, 2, s => sliderMultiplier = s); } private void addSingle(double timeOffset = 0, Vector2? positionOffset = null) From 5b45d36fef389bbae971bf4e87ea472b9240ea9f Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 27 Dec 2017 20:09:33 +0900 Subject: [PATCH 085/101] Decomission TestCaseHitObjects --- .../Tests/TestCaseHitObjects.cs | 129 ------------------ .../osu.Game.Rulesets.Osu.csproj | 1 - 2 files changed, 130 deletions(-) delete mode 100644 osu.Game.Rulesets.Osu/Tests/TestCaseHitObjects.cs diff --git a/osu.Game.Rulesets.Osu/Tests/TestCaseHitObjects.cs b/osu.Game.Rulesets.Osu/Tests/TestCaseHitObjects.cs deleted file mode 100644 index c4932d7803..0000000000 --- a/osu.Game.Rulesets.Osu/Tests/TestCaseHitObjects.cs +++ /dev/null @@ -1,129 +0,0 @@ -// Copyright (c) 2007-2017 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using System.Collections.Generic; -using NUnit.Framework; -using osu.Framework.Allocation; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Timing; -using osu.Game.Rulesets.Objects.Drawables; -using osu.Game.Rulesets.Osu.Objects; -using osu.Game.Rulesets.Osu.Objects.Drawables; -using osu.Game.Tests.Visual; -using OpenTK; - -namespace osu.Game.Rulesets.Osu.Tests -{ - [TestFixture] - [Ignore("getting CI working")] - public class TestCaseHitObjects : OsuTestCase - { - private FramedClock framedClock; - - private bool auto; - - [BackgroundDependencyLoader] - private void load(RulesetStore rulesets) - { - var rateAdjustClock = new StopwatchClock(true); - framedClock = new FramedClock(rateAdjustClock); - - AddStep(@"circles", () => loadHitobjects(HitObjectType.Circle)); - AddStep(@"slider", () => loadHitobjects(HitObjectType.Slider)); - AddStep(@"spinner", () => loadHitobjects(HitObjectType.Spinner)); - - AddToggleStep("Auto", state => { auto = state; loadHitobjects(mode); }); - AddSliderStep("Playback speed", 0.0, 2.0, 0.5, v => rateAdjustClock.Rate = v); - - framedClock.ProcessFrame(); - - var clockAdjustContainer = new Container - { - RelativeSizeAxes = Axes.Both, - Clock = framedClock, - Children = new[] - { - playfieldContainer = new OsuInputManager(rulesets.GetRuleset(0)) { RelativeSizeAxes = Axes.Both }, - approachContainer = new Container { RelativeSizeAxes = Axes.Both } - } - }; - - Add(clockAdjustContainer); - } - - private HitObjectType mode = HitObjectType.Slider; - - private Container playfieldContainer; - private Container approachContainer; - - private void loadHitobjects(HitObjectType mode) - { - this.mode = mode; - - switch (mode) - { - case HitObjectType.Circle: - const int count = 10; - - for (int i = 0; i < count; i++) - { - var h = new HitCircle - { - StartTime = framedClock.CurrentTime + 600 + i * 80, - Position = new Vector2((i - count / 2) * 14), - }; - - add(new DrawableHitCircle(h)); - } - break; - case HitObjectType.Slider: - add(new DrawableSlider(new Slider - { - StartTime = framedClock.CurrentTime + 600, - ControlPoints = new List - { - new Vector2(-200, 0), - new Vector2(400, 0), - }, - Distance = 400, - Position = new Vector2(-200, 0), - Velocity = 1, - TickDistance = 100, - })); - break; - case HitObjectType.Spinner: - add(new DrawableSpinner(new Spinner - { - StartTime = framedClock.CurrentTime + 600, - EndTime = framedClock.CurrentTime + 1600, - Position = new Vector2(0, 0), - })); - break; - } - } - - private int depth; - - private void add(DrawableOsuHitObject h) - { - h.Anchor = Anchor.Centre; - h.Depth = depth++; - - if (auto) - h.State.Value = ArmedState.Hit; - - playfieldContainer.Add(h); - var proxyable = h as IDrawableHitObjectWithProxiedApproach; - if (proxyable != null) - approachContainer.Add(proxyable.ProxiedLayer.CreateProxy()); - } - - private enum HitObjectType - { - Circle, - Slider, - Spinner - } - } -} diff --git a/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj b/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj index ab34d1803f..245f3eed91 100644 --- a/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj +++ b/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj @@ -88,7 +88,6 @@ - From edab169024fb253470865aaf0fac2216485fb9f9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 27 Dec 2017 20:27:20 +0900 Subject: [PATCH 086/101] Update framework --- osu-framework | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu-framework b/osu-framework index 08f85f9bf9..10cae790c6 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit 08f85f9bf9a7376aec8dfcde8c7c96d267d8c295 +Subproject commit 10cae790c6f1d559c326f9438958d0b012d61dc6 From c18fd5da48fc28f1c4a610e05a19973a99e3db3b Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 27 Dec 2017 20:37:28 +0900 Subject: [PATCH 087/101] Simplify creation of repeat points --- osu.Game.Rulesets.Osu/Objects/Slider.cs | 35 ++++++++----------------- 1 file changed, 11 insertions(+), 24 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Slider.cs b/osu.Game.Rulesets.Osu/Objects/Slider.cs index 2d3a4ed7f0..bfb7801532 100644 --- a/osu.Game.Rulesets.Osu/Objects/Slider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Slider.cs @@ -151,35 +151,22 @@ namespace osu.Game.Rulesets.Osu.Objects private void createRepeatPoints() { - var length = Curve.Distance; - var repeatPointDistance = Math.Min(Distance, length); - var repeatDuration = length / Velocity; - - bool sliderStart = true; + var repeatDuration = Distance / Velocity; for (var repeat = 1; repeat < RepeatCount; repeat++) { - sliderStart = !sliderStart; + var repeatStartTime = StartTime + repeat * repeatDuration; - for (var d = repeatPointDistance; d <= length; d += repeatPointDistance) + AddNested(new RepeatPoint { - var repeatStartTime = StartTime + repeat * repeatDuration; - var distanceProgress = d / length; - - if (sliderStart) - distanceProgress = 0; - - AddNested(new RepeatPoint - { - RepeatIndex = repeat, - StartTime = repeatStartTime, - Position = Curve.PositionAt(distanceProgress), - StackHeight = StackHeight, - Scale = Scale, - ComboColour = ComboColour, - Samples = new List(RepeatSamples[repeat]) - }); - } + RepeatIndex = repeat, + StartTime = repeatStartTime, + Position = Curve.PositionAt(repeat), + StackHeight = StackHeight, + Scale = Scale, + ComboColour = ComboColour, + Samples = new List(RepeatSamples[repeat]) + }); } } } From 1a5cf98e0c51e13f15ac826878eca260d7db7fce Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 27 Dec 2017 20:40:38 +0900 Subject: [PATCH 088/101] Fix repeat points always being placed at end position of th slider PositionAt is clamped to [0, 1] where 0 denotes the beginning of the curve and 1 denotes the end of the curve. It has no concept of repeats. --- osu.Game.Rulesets.Osu/Objects/Slider.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Slider.cs b/osu.Game.Rulesets.Osu/Objects/Slider.cs index bfb7801532..ec51a10345 100644 --- a/osu.Game.Rulesets.Osu/Objects/Slider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Slider.cs @@ -161,7 +161,7 @@ namespace osu.Game.Rulesets.Osu.Objects { RepeatIndex = repeat, StartTime = repeatStartTime, - Position = Curve.PositionAt(repeat), + Position = Curve.PositionAt(repeat % 2), StackHeight = StackHeight, Scale = Scale, ComboColour = ComboColour, From 6fe20bb91099abb437e93c0026ad61a081cc9db3 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 27 Dec 2017 20:41:59 +0900 Subject: [PATCH 089/101] Ignore test cases for CI --- osu.Game.Rulesets.Osu/Tests/TestCaseHitCircle.cs | 2 ++ osu.Game.Rulesets.Osu/Tests/TestCaseSlider.cs | 2 ++ osu.Game.Rulesets.Osu/Tests/TestCaseSpinner.cs | 2 ++ 3 files changed, 6 insertions(+) diff --git a/osu.Game.Rulesets.Osu/Tests/TestCaseHitCircle.cs b/osu.Game.Rulesets.Osu/Tests/TestCaseHitCircle.cs index dea941fb01..5130a976f7 100644 --- a/osu.Game.Rulesets.Osu/Tests/TestCaseHitCircle.cs +++ b/osu.Game.Rulesets.Osu/Tests/TestCaseHitCircle.cs @@ -1,6 +1,7 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using NUnit.Framework; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Beatmaps; @@ -13,6 +14,7 @@ using OpenTK; namespace osu.Game.Rulesets.Osu.Tests { + [Ignore("getting CI working")] public class TestCaseHitCircle : OsuTestCase { private readonly Container content; diff --git a/osu.Game.Rulesets.Osu/Tests/TestCaseSlider.cs b/osu.Game.Rulesets.Osu/Tests/TestCaseSlider.cs index 4f7fa1dada..3e861b0890 100644 --- a/osu.Game.Rulesets.Osu/Tests/TestCaseSlider.cs +++ b/osu.Game.Rulesets.Osu/Tests/TestCaseSlider.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using NUnit.Framework; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Audio; @@ -15,6 +16,7 @@ using OpenTK; namespace osu.Game.Rulesets.Osu.Tests { + [Ignore("getting CI working")] public class TestCaseSlider : OsuTestCase { public override IReadOnlyList RequiredTypes => new[] { typeof(DrawableSlider) }; diff --git a/osu.Game.Rulesets.Osu/Tests/TestCaseSpinner.cs b/osu.Game.Rulesets.Osu/Tests/TestCaseSpinner.cs index 6db9c1a473..fc76170585 100644 --- a/osu.Game.Rulesets.Osu/Tests/TestCaseSpinner.cs +++ b/osu.Game.Rulesets.Osu/Tests/TestCaseSpinner.cs @@ -1,6 +1,7 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using NUnit.Framework; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Beatmaps; @@ -11,6 +12,7 @@ using osu.Game.Tests.Visual; namespace osu.Game.Rulesets.Osu.Tests { + [Ignore("getting CI working")] public class TestCaseSpinner : OsuTestCase { private readonly Container content; From 46ef17354ee1922f30ef2e64d38ee321455e0f2b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 27 Dec 2017 21:05:16 +0900 Subject: [PATCH 090/101] Simplify path construction --- osu.Game/Audio/SampleInfo.cs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/osu.Game/Audio/SampleInfo.cs b/osu.Game/Audio/SampleInfo.cs index 1133dde570..31acb8bc89 100644 --- a/osu.Game/Audio/SampleInfo.cs +++ b/osu.Game/Audio/SampleInfo.cs @@ -2,6 +2,7 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; +using System.IO; using osu.Framework.Audio.Sample; namespace osu.Game.Audio @@ -16,14 +17,7 @@ namespace osu.Game.Audio public SampleChannel GetChannel(SampleManager manager, string resourceNamespace = null) { - SampleChannel channel = null; - - if (!string.IsNullOrEmpty(resourceNamespace)) - channel = manager.Get($"Gameplay/{resourceNamespace}/{Bank}-{Name}"); - - if (channel == null) - channel = manager.Get($"Gameplay/{Bank}-{Name}"); - + SampleChannel channel = manager.Get(Path.Combine("Gameplay", resourceNamespace ?? string.Empty, $"{Bank}-{Name}")); channel.Volume.Value = Volume / 100.0; return channel; } From 3428cf65012e214751349a0a9d5de75a3b65dba4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 27 Dec 2017 20:26:14 +0900 Subject: [PATCH 091/101] Decrease speed of progress notifications --- osu.Game.Tests/Visual/TestCaseNotificationOverlay.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCaseNotificationOverlay.cs b/osu.Game.Tests/Visual/TestCaseNotificationOverlay.cs index e1711be102..46deca073f 100644 --- a/osu.Game.Tests/Visual/TestCaseNotificationOverlay.cs +++ b/osu.Game.Tests/Visual/TestCaseNotificationOverlay.cs @@ -69,7 +69,7 @@ namespace osu.Game.Tests.Visual AddAssert("Displayed count is 33", () => manager.UnreadCount.Value == 33); - AddWaitStep(5); + AddWaitStep(10); checkProgressingCount(0); @@ -117,7 +117,7 @@ namespace osu.Game.Tests.Visual foreach (var n in progressingNotifications.FindAll(n => n.State == ProgressNotificationState.Active)) { if (n.Progress < 1) - n.Progress += (float)(Time.Elapsed / 200) * RNG.NextSingle(); + n.Progress += (float)(Time.Elapsed / 400) * RNG.NextSingle(); else n.State = ProgressNotificationState.Completed; } From 9a4b2f0d1dfe607f7bc773be2b47d707fe98bd85 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 27 Dec 2017 21:19:06 +0900 Subject: [PATCH 092/101] Apply workaround at two levels --- .../Notifications/NotificationSection.cs | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/osu.Game/Overlays/Notifications/NotificationSection.cs b/osu.Game/Overlays/Notifications/NotificationSection.cs index e6587506aa..42fcc3aa0f 100644 --- a/osu.Game/Overlays/Notifications/NotificationSection.cs +++ b/osu.Game/Overlays/Notifications/NotificationSection.cs @@ -15,15 +15,11 @@ using osu.Game.Graphics.Containers; namespace osu.Game.Overlays.Notifications { - public class NotificationSection : FillFlowContainer + public class NotificationSection : AlwaysUpdateFillFlowContainer { private OsuSpriteText titleText; private OsuSpriteText countText; - // this is required to ensure correct layout and scheduling on children. - // the layout portion of this is being tracked as a framework issue (TODO). - protected override bool RequiresChildrenUpdate => true; - private ClearAllButton clearButton; private FlowContainer notifications; @@ -37,6 +33,7 @@ namespace osu.Game.Overlays.Notifications public IEnumerable AcceptTypes; private string clearText; + public string ClearText { get { return clearText; } @@ -114,7 +111,7 @@ namespace osu.Game.Overlays.Notifications }, }, }, - notifications = new FillFlowContainer + notifications = new AlwaysUpdateFillFlowContainer { AutoSizeAxes = Axes.Y, RelativeSizeAxes = Axes.X, @@ -163,4 +160,13 @@ namespace osu.Game.Overlays.Notifications notifications?.Children.ForEach(n => n.Read = true); } } + + public class AlwaysUpdateFillFlowContainer : FillFlowContainer + where T : Drawable + { + // this is required to ensure correct layout and scheduling on children. + // the layout portion of this is being tracked as a framework issue (https://github.com/ppy/osu-framework/issues/1297). + protected override bool RequiresChildrenUpdate => true; + } + } From 3f73a9a693ab6573e7fef09bfca8d7ce1106e720 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 27 Dec 2017 21:44:04 +0900 Subject: [PATCH 093/101] Add better sample fallback logic Also adds support for null channels at InputDrum level. --- osu.Game.Rulesets.Taiko/UI/InputDrum.cs | 4 ++-- osu.Game/Audio/SampleInfo.cs | 14 ++++++++++++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/UI/InputDrum.cs b/osu.Game.Rulesets.Taiko/UI/InputDrum.cs index bf1274256b..9b2ea095d2 100644 --- a/osu.Game.Rulesets.Taiko/UI/InputDrum.cs +++ b/osu.Game.Rulesets.Taiko/UI/InputDrum.cs @@ -152,14 +152,14 @@ namespace osu.Game.Rulesets.Taiko.UI target = centreHit; back = centre; - drumSample.Centre.Play(); + drumSample.Centre?.Play(); } else if (action == RimAction) { target = rimHit; back = rim; - drumSample.Rim.Play(); + drumSample.Rim?.Play(); } if (target != null) diff --git a/osu.Game/Audio/SampleInfo.cs b/osu.Game/Audio/SampleInfo.cs index 31acb8bc89..9597acd902 100644 --- a/osu.Game/Audio/SampleInfo.cs +++ b/osu.Game/Audio/SampleInfo.cs @@ -17,8 +17,18 @@ namespace osu.Game.Audio public SampleChannel GetChannel(SampleManager manager, string resourceNamespace = null) { - SampleChannel channel = manager.Get(Path.Combine("Gameplay", resourceNamespace ?? string.Empty, $"{Bank}-{Name}")); - channel.Volume.Value = Volume / 100.0; + SampleChannel channel = null; + + if (resourceNamespace != null) + channel = manager.Get(Path.Combine("Gameplay", resourceNamespace, $"{Bank}-{Name}")); + + // try without namespace as a fallback. + if (channel == null) + channel = manager.Get(Path.Combine("Gameplay", $"{Bank}-{Name}")); + + if (channel != null) + channel.Volume.Value = Volume / 100.0; + return channel; } From 3a2dadc9d390b2112d201eef4a1b5a16d7409d56 Mon Sep 17 00:00:00 2001 From: Dan Balasescu <1329837+smoogipoo@users.noreply.github.com> Date: Wed, 27 Dec 2017 23:14:48 +0900 Subject: [PATCH 094/101] Fix spelling error --- osu.Game/Screens/Select/BeatmapCarousel.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index ffdd1daf72..e877633ab3 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -54,7 +54,7 @@ namespace osu.Game.Screens.Select public override bool HandleInput => AllowSelection; /// - /// Used to avoid firing null selections before the initial baetmaps have been loaded via . + /// Used to avoid firing null selections before the initial beatmaps have been loaded via . /// private bool initialLoadComplete; From 7b06c16e70882bfbcbb8003da9172259f6dba97f Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 27 Dec 2017 23:44:51 +0900 Subject: [PATCH 095/101] Display larger hitcircles --- osu.Game.Rulesets.Osu/Tests/TestCaseHitCircle.cs | 2 +- osu.Game.Rulesets.Osu/Tests/TestCaseSlider.cs | 12 ++++++++++-- osu.Game.Rulesets.Osu/Tests/TestCaseSpinner.cs | 2 +- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Tests/TestCaseHitCircle.cs b/osu.Game.Rulesets.Osu/Tests/TestCaseHitCircle.cs index 5130a976f7..ef0bffa14e 100644 --- a/osu.Game.Rulesets.Osu/Tests/TestCaseHitCircle.cs +++ b/osu.Game.Rulesets.Osu/Tests/TestCaseHitCircle.cs @@ -42,7 +42,7 @@ namespace osu.Game.Rulesets.Osu.Tests Position = positionOffset.Value }; - circle.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()); + circle.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty { CircleSize = 0 }); var drawable = new DrawableHitCircle(circle) { diff --git a/osu.Game.Rulesets.Osu/Tests/TestCaseSlider.cs b/osu.Game.Rulesets.Osu/Tests/TestCaseSlider.cs index 3e861b0890..7ce9c35bd5 100644 --- a/osu.Game.Rulesets.Osu/Tests/TestCaseSlider.cs +++ b/osu.Game.Rulesets.Osu/Tests/TestCaseSlider.cs @@ -62,7 +62,11 @@ namespace osu.Game.Rulesets.Osu.Tests var cpi = new ControlPointInfo(); cpi.DifficultyPoints.Add(new DifficultyControlPoint { SpeedMultiplier = speedMultiplier }); - var difficulty = new BeatmapDifficulty { SliderMultiplier = (float)sliderMultiplier }; + var difficulty = new BeatmapDifficulty + { + SliderMultiplier = (float)sliderMultiplier, + CircleSize = 0 + }; slider.ApplyDefaults(cpi, difficulty); Add(new DrawableSlider(slider) @@ -98,7 +102,11 @@ namespace osu.Game.Rulesets.Osu.Tests var cpi = new ControlPointInfo(); cpi.DifficultyPoints.Add(new DifficultyControlPoint { SpeedMultiplier = speedMultiplier }); - var difficulty = new BeatmapDifficulty { SliderMultiplier = (float)sliderMultiplier }; + var difficulty = new BeatmapDifficulty + { + SliderMultiplier = (float)sliderMultiplier, + CircleSize = 0 + }; slider.ApplyDefaults(cpi, difficulty); Add(new DrawableSlider(slider) diff --git a/osu.Game.Rulesets.Osu/Tests/TestCaseSpinner.cs b/osu.Game.Rulesets.Osu/Tests/TestCaseSpinner.cs index fc76170585..76cc70effd 100644 --- a/osu.Game.Rulesets.Osu/Tests/TestCaseSpinner.cs +++ b/osu.Game.Rulesets.Osu/Tests/TestCaseSpinner.cs @@ -31,7 +31,7 @@ namespace osu.Game.Rulesets.Osu.Tests { var spinner = new Spinner { StartTime = Time.Current + 1000, EndTime = Time.Current + 4000 }; - spinner.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()); + spinner.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty { CircleSize = 0 }); var drawable = new DrawableSpinner(spinner) { From 7a0662da4b9364963774240d849284cc904cf2be Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 28 Dec 2017 00:38:50 +0900 Subject: [PATCH 096/101] Fix regression during merges --- osu.Game/OsuGame.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 9c852a189a..2bc32794d7 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -440,12 +440,16 @@ namespace osu.Game private void screenAdded(Screen newScreen) { + currentScreen = (OsuScreen)newScreen; + newScreen.ModePushed += screenAdded; newScreen.Exited += screenRemoved; } private void screenRemoved(Screen newScreen) { + currentScreen = (OsuScreen)newScreen; + if (newScreen == null) Exit(); } From 4e6988d21bba51441c9553d12580c1e8e7bfd11f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 28 Dec 2017 01:00:01 +0900 Subject: [PATCH 097/101] As it turns out, native directory separators are not supported --- osu.Game/Audio/SampleInfo.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/osu.Game/Audio/SampleInfo.cs b/osu.Game/Audio/SampleInfo.cs index 9597acd902..71975bf0fa 100644 --- a/osu.Game/Audio/SampleInfo.cs +++ b/osu.Game/Audio/SampleInfo.cs @@ -2,7 +2,6 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; -using System.IO; using osu.Framework.Audio.Sample; namespace osu.Game.Audio @@ -20,11 +19,11 @@ namespace osu.Game.Audio SampleChannel channel = null; if (resourceNamespace != null) - channel = manager.Get(Path.Combine("Gameplay", resourceNamespace, $"{Bank}-{Name}")); + channel = manager.Get($"Gameplay/{resourceNamespace}/{Bank}-{Name}"); // try without namespace as a fallback. if (channel == null) - channel = manager.Get(Path.Combine("Gameplay", $"{Bank}-{Name}")); + channel = manager.Get($"Gameplay/{Bank}-{Name}"); if (channel != null) channel.Volume.Value = Volume / 100.0; From 998f9c090d3cc5167b42611503930fa827d2cc9a Mon Sep 17 00:00:00 2001 From: FreezyLemon Date: Thu, 28 Dec 2017 01:56:10 +0100 Subject: [PATCH 098/101] select pause buttons after mouse move only --- osu.Game/Screens/Play/GameplayMenuOverlay.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/osu.Game/Screens/Play/GameplayMenuOverlay.cs b/osu.Game/Screens/Play/GameplayMenuOverlay.cs index 6969cd915b..094c0331f4 100644 --- a/osu.Game/Screens/Play/GameplayMenuOverlay.cs +++ b/osu.Game/Screens/Play/GameplayMenuOverlay.cs @@ -263,6 +263,14 @@ namespace osu.Game.Screens.Play private class Button : DialogButton { + protected override bool OnHover(InputState state) => true; + + protected override bool OnMouseMove(InputState state) + { + Selected.Value = true; + return base.OnMouseMove(state); + } + protected override bool OnKeyDown(InputState state, KeyDownEventArgs args) { if (args.Repeat || args.Key != Key.Enter || !Selected) From 64d99a75600be3186dc00cfe25852020e2e03ddf Mon Sep 17 00:00:00 2001 From: FreezyLemon Date: Thu, 28 Dec 2017 02:29:58 +0100 Subject: [PATCH 099/101] Fix tests --- osu.Game.Tests/Visual/TestCaseGameplayMenuOverlay.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCaseGameplayMenuOverlay.cs b/osu.Game.Tests/Visual/TestCaseGameplayMenuOverlay.cs index bd5772d3bb..87552c3f17 100644 --- a/osu.Game.Tests/Visual/TestCaseGameplayMenuOverlay.cs +++ b/osu.Game.Tests/Visual/TestCaseGameplayMenuOverlay.cs @@ -73,7 +73,7 @@ namespace osu.Game.Tests.Visual { AddStep("Show overlay", () => failOverlay.Show()); - AddStep("Hover first button", () => failOverlay.Buttons.First().TriggerOnHover(null)); + AddStep("Hover first button", () => failOverlay.Buttons.First().TriggerOnMouseMove(null)); AddStep("Hide overlay", () => failOverlay.Hide()); AddAssert("Overlay state is reset", () => !failOverlay.Buttons.Any(b => b.Selected)); @@ -162,7 +162,7 @@ namespace osu.Game.Tests.Visual var secondButton = pauseOverlay.Buttons.Skip(1).First(); AddStep("Down arrow", () => pauseOverlay.TriggerOnKeyDown(null, new KeyDownEventArgs { Key = Key.Down })); - AddStep("Hover second button", () => secondButton.TriggerOnHover(null)); + AddStep("Hover second button", () => secondButton.TriggerOnMouseMove(null)); AddAssert("First button not selected", () => !pauseOverlay.Buttons.First().Selected); AddAssert("Second button selected", () => secondButton.Selected); @@ -178,7 +178,7 @@ namespace osu.Game.Tests.Visual var secondButton = pauseOverlay.Buttons.Skip(1).First(); - AddStep("Hover second button", () => secondButton.TriggerOnHover(null)); + AddStep("Hover second button", () => secondButton.TriggerOnMouseMove(null)); AddStep("Up arrow", () => pauseOverlay.TriggerOnKeyDown(null, new KeyDownEventArgs { Key = Key.Up })); AddAssert("Second button not selected", () => !secondButton.Selected); AddAssert("First button selected", () => pauseOverlay.Buttons.First().Selected); @@ -195,7 +195,7 @@ namespace osu.Game.Tests.Visual var secondButton = pauseOverlay.Buttons.Skip(1).First(); - AddStep("Hover second button", () => secondButton.TriggerOnHover(null)); + AddStep("Hover second button", () => secondButton.TriggerOnMouseMove(null)); AddStep("Unhover second button", () => secondButton.TriggerOnHoverLost(null)); AddStep("Down arrow", () => pauseOverlay.TriggerOnKeyDown(null, new KeyDownEventArgs { Key = Key.Down })); AddAssert("First button selected", () => pauseOverlay.Buttons.First().Selected); // Initial state condition From 33480b85c85abbc92730e47c6389a725ed8ae4d5 Mon Sep 17 00:00:00 2001 From: FreezyLemon Date: Thu, 28 Dec 2017 03:35:53 +0100 Subject: [PATCH 100/101] fix for Drawables being empty crashing --- osu.Game/Screens/Select/BeatmapCarousel.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index e877633ab3..d0990d2d12 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -194,7 +194,11 @@ namespace osu.Game.Screens.Select if (!Items.Any()) return; - int originalIndex = Items.IndexOf(selectedBeatmap?.Drawables.First()); + var d = selectedBeatmap?.Drawables.FirstOrDefault(); + if (d == null) + return; + + int originalIndex = Items.IndexOf(d); int currentIndex = originalIndex; // local function to increment the index in the required direction, wrapping over extremities. From e4a8402d3ccf861ccda33665c56a6001a2a84253 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 28 Dec 2017 12:38:40 +0900 Subject: [PATCH 101/101] Use better logic We need to still perform selection if selectedBeatmap itself is null --- osu.Game/Screens/Select/BeatmapCarousel.cs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index d0990d2d12..b343998e11 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -194,11 +194,14 @@ namespace osu.Game.Screens.Select if (!Items.Any()) return; - var d = selectedBeatmap?.Drawables.FirstOrDefault(); - if (d == null) + DrawableCarouselItem drawable = null; + + if (selectedBeatmap != null && (drawable = selectedBeatmap.Drawables.FirstOrDefault()) == null) + // if the selected beatmap isn't present yet, we can't correctly change selection. + // we can fix this by changing this method to not reference drawables / Items in the first place. return; - int originalIndex = Items.IndexOf(d); + int originalIndex = Items.IndexOf(drawable); int currentIndex = originalIndex; // local function to increment the index in the required direction, wrapping over extremities.