From 8e685a98d47a5f094c8ce0555508552b6caae5a9 Mon Sep 17 00:00:00 2001 From: Jorolf Date: Wed, 26 Jul 2017 18:55:37 +0200 Subject: [PATCH 0001/1263] add RanksSection --- .../Tests/TestCaseUserRanks.cs | 100 +++++++++ .../osu.Desktop.VisualTests.csproj | 1 + .../Profile/Sections/Ranks/DrawablePlay.cs | 211 ++++++++++++++++++ .../Overlays/Profile/Sections/Ranks/Play.cs | 21 ++ .../Overlays/Profile/Sections/RanksSection.cs | 68 ++++++ osu.Game/osu.Game.csproj | 2 + 6 files changed, 403 insertions(+) create mode 100644 osu.Desktop.VisualTests/Tests/TestCaseUserRanks.cs create mode 100644 osu.Game/Overlays/Profile/Sections/Ranks/DrawablePlay.cs create mode 100644 osu.Game/Overlays/Profile/Sections/Ranks/Play.cs diff --git a/osu.Desktop.VisualTests/Tests/TestCaseUserRanks.cs b/osu.Desktop.VisualTests/Tests/TestCaseUserRanks.cs new file mode 100644 index 0000000000..651c39ede4 --- /dev/null +++ b/osu.Desktop.VisualTests/Tests/TestCaseUserRanks.cs @@ -0,0 +1,100 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Testing; +using osu.Game.Database; +using osu.Game.Graphics; +using osu.Game.Overlays.Profile.Sections; +using osu.Game.Overlays.Profile.Sections.Ranks; +using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Osu.Mods; +using osu.Game.Rulesets.Scoring; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace osu.Desktop.VisualTests.Tests +{ + public class TestCaseUserRanks : TestCase + { + public override string Description => "showing your latest achievements"; + + public TestCaseUserRanks() + { + RanksSection ranks; + + Add(new Container + { + AutoSizeAxes = Axes.Y, + RelativeSizeAxes = Axes.X, + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = OsuColour.Gray(0.2f) + }, + ranks = new RanksSection(), + } + }); + + AddStep("Add First Place", () => ranks.FirstPlacePlays = new[] + { + new Play + { + Rank = ScoreRank.A, + PerformancePoints = 666, + Accuracy = 0.735, + Date = DateTimeOffset.UtcNow, + Mods = new Mod[] { new ModAutoplay(), new ModDoubleTime() }, + Beatmap = new BeatmapInfo + { + Metadata = new BeatmapMetadata + { + Title = "FREEDOM DiVE", + Artist = "xi" + }, + Version = "FOUR DIMENSIONS", + OnlineBeatmapID = 129891, + } + } + }); + + AddStep("Add Best Performances", () => + { + List plays = new List(); + Mod[] availableMods = { new OsuModHidden(), new OsuModFlashlight(), new OsuModHardRock(), new OsuModDoubleTime(), new OsuModPerfect() }; + List selectedMods = new List(availableMods); + for (int i = 0; i <= availableMods.Length; i++) + { + plays.Add(new Play + { + Rank = (ScoreRank) Enum.GetValues(typeof(ScoreRank)).GetValue(Enum.GetValues(typeof(ScoreRank)).Length - 1 - i), + PerformancePoints = (int)(Math.Pow(0.50, i) * 800), + Accuracy = Math.Pow(0.99, i), + Date = DateTimeOffset.UtcNow.AddDays(-Math.Pow(i, 2)), + Mods = selectedMods.ToList(), + Beatmap = new BeatmapInfo + { + Metadata = new BeatmapMetadata + { + Title = "Highscore", + Artist = "Panda Eyes & Teminite" + }, + Version = "Game Over", + OnlineBeatmapID = 736215, + } + }); + if(i < availableMods.Length) + selectedMods.Remove(availableMods[i]); + } + ranks.BestPlays = plays; + }); + } + } +} diff --git a/osu.Desktop.VisualTests/osu.Desktop.VisualTests.csproj b/osu.Desktop.VisualTests/osu.Desktop.VisualTests.csproj index 4974f0c0d1..00bcaca1e8 100644 --- a/osu.Desktop.VisualTests/osu.Desktop.VisualTests.csproj +++ b/osu.Desktop.VisualTests/osu.Desktop.VisualTests.csproj @@ -217,6 +217,7 @@ + diff --git a/osu.Game/Overlays/Profile/Sections/Ranks/DrawablePlay.cs b/osu.Game/Overlays/Profile/Sections/Ranks/DrawablePlay.cs new file mode 100644 index 0000000000..66588462f3 --- /dev/null +++ b/osu.Game/Overlays/Profile/Sections/Ranks/DrawablePlay.cs @@ -0,0 +1,211 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System.Collections.Generic; +using OpenTK; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Graphics; +using osu.Game.Graphics.Containers; +using osu.Game.Graphics.Sprites; +using osu.Game.Rulesets.Mods; +using osu.Game.Screens.Select.Leaderboards; +using System.Linq; +using OpenTK.Graphics; +using System.Diagnostics; +using osu.Framework.Input; +using osu.Framework.Localisation; + +namespace osu.Game.Overlays.Profile.Sections.Ranks +{ + public class DrawablePlay : Container + { + private readonly FillFlowContainer stats; + private readonly FillFlowContainer metadata; + private readonly ModContainer modContainer; + private readonly Play play; + private readonly double weight; + + public DrawablePlay(Play play, double weight = -1) + { + this.play = play; + this.weight = weight; + + Children = new Drawable[] + { + new DrawableRank(play.Rank) + { + RelativeSizeAxes = Axes.Y, + Width = 60, + FillMode = FillMode.Fit, + }, + stats = new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + Direction = FillDirection.Vertical, + }, + metadata = new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Margin = new MarginPadding { Left = 70 }, + Direction = FillDirection.Vertical, + Child = new OsuSpriteText + { + Text = play.Date.LocalDateTime.ToShortDateString(), + TextSize = 11, + Colour = OsuColour.Gray(0xAA), + Depth = -1, + }, + }, + modContainer = new ModContainer + { + AutoSizeAxes = Axes.Y, + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + Width = 60, + Margin = new MarginPadding{ Right = 140 } + } + }; + } + + [BackgroundDependencyLoader] + private void load(OsuColour colour, LocalisationEngine locale) + { + stats.Add(new OsuSpriteText { + Text = play.PerformancePoints + "pp", + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + TextSize = 18, + Font = "Exo2.0-BoldItalic", + }); + if(weight != -1) + { + stats.Add(new OsuSpriteText + { + Text = $"weighted: {(int)(play.PerformancePoints * weight)}pp ({weight.ToString("0%")})", + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + Colour = colour.GrayA, + TextSize = 11, + Font = "Exo2.0-RegularItalic", + }); + } + stats.Add(new OsuSpriteText { + Text = "accuracy: " + play.Accuracy.ToString("0.00%"), + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + Colour = colour.GrayA, + TextSize = 11, + Font = "Exo2.0-RegularItalic", + }); + + metadata.Add(new LinkContainer + { + AutoSizeAxes = Axes.Both, + Url = $"https://osu.ppy.sh/beatmaps/{play.Beatmap.OnlineBeatmapID}", + Child = new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Children = new Drawable[] + { + new OsuSpriteText + { + Current = locale.GetUnicodePreference($"{play.Beatmap.Metadata.TitleUnicode ?? play.Beatmap.Metadata.Title} [{play.Beatmap.Version}] ", $"{play.Beatmap.Metadata.Title ?? play.Beatmap.Metadata.TitleUnicode} [{play.Beatmap.Version}] "), + TextSize = 15, + Font = "Exo2.0-SemiBoldItalic", + }, + new OsuSpriteText + { + Current = locale.GetUnicodePreference(play.Beatmap.Metadata.ArtistUnicode, play.Beatmap.Metadata.Artist), + TextSize = 12, + Padding = new MarginPadding { Top = 3 }, + Font = "Exo2.0-RegularItalic", + }, + }, + }, + }); + + foreach (Mod mod in play.Mods) + modContainer.Add(new ModIcon(mod.Icon, colour.Yellow)); + } + + private class ModContainer : FlowContainer + { + protected override IEnumerable ComputeLayoutPositions() + { + int count = FlowingChildren.Count(); + for (int i = 0; i < count; i++) + yield return new Vector2(DrawWidth * i * (count == 1 ? 0 : 1f / (count - 1)), 0); + } + } + + private class ModIcon : Container + { + public ModIcon(FontAwesome icon, Color4 colour) + { + AutoSizeAxes = Axes.Both; + + Children = new[] + { + new TextAwesome + { + Origin = Anchor.Centre, + Anchor = Anchor.Centre, + Icon = FontAwesome.fa_osu_mod_bg, + Colour = colour, + Shadow = true, + TextSize = 30, + UseFullGlyphHeight = false, + }, + new TextAwesome + { + Origin = Anchor.Centre, + Anchor = Anchor.Centre, + Icon = icon, + Colour = OsuColour.Gray(84), + TextSize = 18, + Position = new Vector2(0f, 2f), + UseFullGlyphHeight = false, + }, + }; + } + } + + private class LinkContainer : OsuClickableContainer + { + public string Url; + + private Color4 hoverColour; + + public LinkContainer() + { + Action = () => Process.Start(Url); + } + + protected override bool OnHover(InputState state) + { + this.FadeColour(hoverColour, 500, Easing.OutQuint); + return base.OnHover(state); + } + + protected override void OnHoverLost(InputState state) + { + this.FadeColour(Color4.White, 500, Easing.OutQuint); + base.OnHoverLost(state); + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + hoverColour = colours.Yellow; + } + } + } +} diff --git a/osu.Game/Overlays/Profile/Sections/Ranks/Play.cs b/osu.Game/Overlays/Profile/Sections/Ranks/Play.cs new file mode 100644 index 0000000000..a9cbbcbef4 --- /dev/null +++ b/osu.Game/Overlays/Profile/Sections/Ranks/Play.cs @@ -0,0 +1,21 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Game.Database; +using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Scoring; +using System; +using System.Collections.Generic; + +namespace osu.Game.Overlays.Profile.Sections.Ranks +{ + public class Play + { + public ScoreRank Rank; + public BeatmapInfo Beatmap; + public DateTimeOffset Date; + public IEnumerable Mods; + public int PerformancePoints; + public double Accuracy; + } +} diff --git a/osu.Game/Overlays/Profile/Sections/RanksSection.cs b/osu.Game/Overlays/Profile/Sections/RanksSection.cs index 5ea135fcac..f19de5356c 100644 --- a/osu.Game/Overlays/Profile/Sections/RanksSection.cs +++ b/osu.Game/Overlays/Profile/Sections/RanksSection.cs @@ -1,6 +1,13 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Graphics.Sprites; +using osu.Game.Overlays.Profile.Sections.Ranks; +using System; +using System.Collections.Generic; + namespace osu.Game.Overlays.Profile.Sections { public class RanksSection : ProfileSection @@ -8,5 +15,66 @@ namespace osu.Game.Overlays.Profile.Sections public override string Title => "Ranks"; public override string Identifier => "top_ranks"; + + private readonly FillFlowContainer best, firstPlace; + + public RanksSection() + { + Children = new Drawable[] + { + new OsuSpriteText { + TextSize = 15, + Text = "Best Performance", + Font = "Exo2.0-RegularItalic", + }, + best = new FillFlowContainer + { + AutoSizeAxes = Axes.Y, + RelativeSizeAxes = Axes.X, + Direction = FillDirection.Vertical, + }, + new OsuSpriteText { + TextSize = 15, + Text = "First Place Ranks", + Font = "Exo2.0-RegularItalic", + }, + firstPlace = new FillFlowContainer + { + AutoSizeAxes = Axes.Y, + RelativeSizeAxes = Axes.X, + Direction = FillDirection.Vertical, + }, + }; + } + + public IEnumerable BestPlays + { + set + { + int i = 0; + foreach (Play play in value) + { + best.Add(new DrawablePlay(play, Math.Pow(0.95, i)) + { + RelativeSizeAxes = Axes.X, + Height = 60, + }); + i++; + } + } + } + + public IEnumerable FirstPlacePlays + { + set + { + foreach (Play play in value) + firstPlace.Add(new DrawablePlay(play) + { + RelativeSizeAxes = Axes.X, + Height = 60, + }); + } + } } } diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 6031304b26..b63ad6a271 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -98,6 +98,8 @@ + + From 7b8997cfc2ea6bd9f11d72c8dc49c84d9519d680 Mon Sep 17 00:00:00 2001 From: Jorolf Date: Wed, 26 Jul 2017 19:42:34 +0200 Subject: [PATCH 0002/1263] CI stuff --- osu.Desktop.VisualTests/Tests/TestCaseUserRanks.cs | 2 -- osu.Game/Overlays/Profile/Sections/Ranks/DrawablePlay.cs | 3 ++- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/osu.Desktop.VisualTests/Tests/TestCaseUserRanks.cs b/osu.Desktop.VisualTests/Tests/TestCaseUserRanks.cs index 651c39ede4..d3d0ae4577 100644 --- a/osu.Desktop.VisualTests/Tests/TestCaseUserRanks.cs +++ b/osu.Desktop.VisualTests/Tests/TestCaseUserRanks.cs @@ -15,8 +15,6 @@ using osu.Game.Rulesets.Scoring; using System; using System.Collections.Generic; using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace osu.Desktop.VisualTests.Tests { diff --git a/osu.Game/Overlays/Profile/Sections/Ranks/DrawablePlay.cs b/osu.Game/Overlays/Profile/Sections/Ranks/DrawablePlay.cs index 66588462f3..5b3bbff3ca 100644 --- a/osu.Game/Overlays/Profile/Sections/Ranks/DrawablePlay.cs +++ b/osu.Game/Overlays/Profile/Sections/Ranks/DrawablePlay.cs @@ -16,6 +16,7 @@ using OpenTK.Graphics; using System.Diagnostics; using osu.Framework.Input; using osu.Framework.Localisation; +using System.Globalization; namespace osu.Game.Overlays.Profile.Sections.Ranks { @@ -89,7 +90,7 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks { stats.Add(new OsuSpriteText { - Text = $"weighted: {(int)(play.PerformancePoints * weight)}pp ({weight.ToString("0%")})", + Text = $"weighted: {(int)(play.PerformancePoints * weight)}pp ({weight.ToString("0%", CultureInfo.CurrentCulture)})", Anchor = Anchor.TopRight, Origin = Anchor.TopRight, Colour = colour.GrayA, From 0fc36065f4be114dac08559d7ee265d4dcda6118 Mon Sep 17 00:00:00 2001 From: Jorolf Date: Sat, 29 Jul 2017 00:31:52 +0200 Subject: [PATCH 0003/1263] replace `Play` with `Score` --- .../Tests/TestCaseUserRanks.cs | 14 +++++----- .../Profile/Sections/Ranks/DrawablePlay.cs | 27 ++++++++++--------- .../Overlays/Profile/Sections/Ranks/Play.cs | 21 --------------- .../Overlays/Profile/Sections/RanksSection.cs | 19 ++++++------- osu.Game/Rulesets/Scoring/Score.cs | 2 ++ osu.Game/osu.Game.csproj | 1 - 6 files changed, 32 insertions(+), 52 deletions(-) delete mode 100644 osu.Game/Overlays/Profile/Sections/Ranks/Play.cs diff --git a/osu.Desktop.VisualTests/Tests/TestCaseUserRanks.cs b/osu.Desktop.VisualTests/Tests/TestCaseUserRanks.cs index d3d0ae4577..9eacde0b97 100644 --- a/osu.Desktop.VisualTests/Tests/TestCaseUserRanks.cs +++ b/osu.Desktop.VisualTests/Tests/TestCaseUserRanks.cs @@ -41,12 +41,11 @@ namespace osu.Desktop.VisualTests.Tests } }); - AddStep("Add First Place", () => ranks.FirstPlacePlays = new[] + AddStep("Add First Place", () => ranks.FirstPlaceScores = new[] { - new Play + new Score { Rank = ScoreRank.A, - PerformancePoints = 666, Accuracy = 0.735, Date = DateTimeOffset.UtcNow, Mods = new Mod[] { new ModAutoplay(), new ModDoubleTime() }, @@ -65,18 +64,17 @@ namespace osu.Desktop.VisualTests.Tests AddStep("Add Best Performances", () => { - List plays = new List(); + List scores = new List(); Mod[] availableMods = { new OsuModHidden(), new OsuModFlashlight(), new OsuModHardRock(), new OsuModDoubleTime(), new OsuModPerfect() }; List selectedMods = new List(availableMods); for (int i = 0; i <= availableMods.Length; i++) { - plays.Add(new Play + scores.Add(new Score { Rank = (ScoreRank) Enum.GetValues(typeof(ScoreRank)).GetValue(Enum.GetValues(typeof(ScoreRank)).Length - 1 - i), - PerformancePoints = (int)(Math.Pow(0.50, i) * 800), Accuracy = Math.Pow(0.99, i), Date = DateTimeOffset.UtcNow.AddDays(-Math.Pow(i, 2)), - Mods = selectedMods.ToList(), + Mods = selectedMods.ToArray(), Beatmap = new BeatmapInfo { Metadata = new BeatmapMetadata @@ -91,7 +89,7 @@ namespace osu.Desktop.VisualTests.Tests if(i < availableMods.Length) selectedMods.Remove(availableMods[i]); } - ranks.BestPlays = plays; + ranks.BestScores = scores; }); } } diff --git a/osu.Game/Overlays/Profile/Sections/Ranks/DrawablePlay.cs b/osu.Game/Overlays/Profile/Sections/Ranks/DrawablePlay.cs index 5b3bbff3ca..f74b6792ad 100644 --- a/osu.Game/Overlays/Profile/Sections/Ranks/DrawablePlay.cs +++ b/osu.Game/Overlays/Profile/Sections/Ranks/DrawablePlay.cs @@ -17,25 +17,26 @@ using System.Diagnostics; using osu.Framework.Input; using osu.Framework.Localisation; using System.Globalization; +using osu.Game.Rulesets.Scoring; namespace osu.Game.Overlays.Profile.Sections.Ranks { - public class DrawablePlay : Container + public class DrawableScore : Container { private readonly FillFlowContainer stats; private readonly FillFlowContainer metadata; private readonly ModContainer modContainer; - private readonly Play play; + private readonly Score score; private readonly double weight; - public DrawablePlay(Play play, double weight = -1) + public DrawableScore(Score score, double weight = -1) { - this.play = play; + this.score = score; this.weight = weight; Children = new Drawable[] { - new DrawableRank(play.Rank) + new DrawableRank(score.Rank) { RelativeSizeAxes = Axes.Y, Width = 60, @@ -59,7 +60,7 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks Direction = FillDirection.Vertical, Child = new OsuSpriteText { - Text = play.Date.LocalDateTime.ToShortDateString(), + Text = score.Date.LocalDateTime.ToShortDateString(), TextSize = 11, Colour = OsuColour.Gray(0xAA), Depth = -1, @@ -80,7 +81,7 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks private void load(OsuColour colour, LocalisationEngine locale) { stats.Add(new OsuSpriteText { - Text = play.PerformancePoints + "pp", + Text = score.PP + "pp", Anchor = Anchor.TopRight, Origin = Anchor.TopRight, TextSize = 18, @@ -90,7 +91,7 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks { stats.Add(new OsuSpriteText { - Text = $"weighted: {(int)(play.PerformancePoints * weight)}pp ({weight.ToString("0%", CultureInfo.CurrentCulture)})", + Text = $"weighted: {(int)(score.PP * weight)}pp ({weight.ToString("0%", CultureInfo.CurrentCulture)})", Anchor = Anchor.TopRight, Origin = Anchor.TopRight, Colour = colour.GrayA, @@ -99,7 +100,7 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks }); } stats.Add(new OsuSpriteText { - Text = "accuracy: " + play.Accuracy.ToString("0.00%"), + Text = "accuracy: " + score.Accuracy.ToString("0.00%"), Anchor = Anchor.TopRight, Origin = Anchor.TopRight, Colour = colour.GrayA, @@ -110,7 +111,7 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks metadata.Add(new LinkContainer { AutoSizeAxes = Axes.Both, - Url = $"https://osu.ppy.sh/beatmaps/{play.Beatmap.OnlineBeatmapID}", + Url = $"https://osu.ppy.sh/beatmaps/{score.Beatmap.OnlineBeatmapID}", Child = new FillFlowContainer { AutoSizeAxes = Axes.Both, @@ -118,13 +119,13 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks { new OsuSpriteText { - Current = locale.GetUnicodePreference($"{play.Beatmap.Metadata.TitleUnicode ?? play.Beatmap.Metadata.Title} [{play.Beatmap.Version}] ", $"{play.Beatmap.Metadata.Title ?? play.Beatmap.Metadata.TitleUnicode} [{play.Beatmap.Version}] "), + Current = locale.GetUnicodePreference($"{score.Beatmap.Metadata.TitleUnicode ?? score.Beatmap.Metadata.Title} [{score.Beatmap.Version}] ", $"{score.Beatmap.Metadata.Title ?? score.Beatmap.Metadata.TitleUnicode} [{score.Beatmap.Version}] "), TextSize = 15, Font = "Exo2.0-SemiBoldItalic", }, new OsuSpriteText { - Current = locale.GetUnicodePreference(play.Beatmap.Metadata.ArtistUnicode, play.Beatmap.Metadata.Artist), + Current = locale.GetUnicodePreference(score.Beatmap.Metadata.ArtistUnicode, score.Beatmap.Metadata.Artist), TextSize = 12, Padding = new MarginPadding { Top = 3 }, Font = "Exo2.0-RegularItalic", @@ -133,7 +134,7 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks }, }); - foreach (Mod mod in play.Mods) + foreach (Mod mod in score.Mods) modContainer.Add(new ModIcon(mod.Icon, colour.Yellow)); } diff --git a/osu.Game/Overlays/Profile/Sections/Ranks/Play.cs b/osu.Game/Overlays/Profile/Sections/Ranks/Play.cs deleted file mode 100644 index a9cbbcbef4..0000000000 --- a/osu.Game/Overlays/Profile/Sections/Ranks/Play.cs +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) 2007-2017 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using osu.Game.Database; -using osu.Game.Rulesets.Mods; -using osu.Game.Rulesets.Scoring; -using System; -using System.Collections.Generic; - -namespace osu.Game.Overlays.Profile.Sections.Ranks -{ - public class Play - { - public ScoreRank Rank; - public BeatmapInfo Beatmap; - public DateTimeOffset Date; - public IEnumerable Mods; - public int PerformancePoints; - public double Accuracy; - } -} diff --git a/osu.Game/Overlays/Profile/Sections/RanksSection.cs b/osu.Game/Overlays/Profile/Sections/RanksSection.cs index f19de5356c..846f0e0e47 100644 --- a/osu.Game/Overlays/Profile/Sections/RanksSection.cs +++ b/osu.Game/Overlays/Profile/Sections/RanksSection.cs @@ -5,6 +5,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Overlays.Profile.Sections.Ranks; +using osu.Game.Rulesets.Scoring; using System; using System.Collections.Generic; @@ -16,7 +17,7 @@ namespace osu.Game.Overlays.Profile.Sections public override string Identifier => "top_ranks"; - private readonly FillFlowContainer best, firstPlace; + private readonly FillFlowContainer best, firstPlace; public RanksSection() { @@ -27,7 +28,7 @@ namespace osu.Game.Overlays.Profile.Sections Text = "Best Performance", Font = "Exo2.0-RegularItalic", }, - best = new FillFlowContainer + best = new FillFlowContainer { AutoSizeAxes = Axes.Y, RelativeSizeAxes = Axes.X, @@ -38,7 +39,7 @@ namespace osu.Game.Overlays.Profile.Sections Text = "First Place Ranks", Font = "Exo2.0-RegularItalic", }, - firstPlace = new FillFlowContainer + firstPlace = new FillFlowContainer { AutoSizeAxes = Axes.Y, RelativeSizeAxes = Axes.X, @@ -47,14 +48,14 @@ namespace osu.Game.Overlays.Profile.Sections }; } - public IEnumerable BestPlays + public IEnumerable BestScores { set { int i = 0; - foreach (Play play in value) + foreach (Score score in value) { - best.Add(new DrawablePlay(play, Math.Pow(0.95, i)) + best.Add(new DrawableScore(score, Math.Pow(0.95, i)) { RelativeSizeAxes = Axes.X, Height = 60, @@ -64,12 +65,12 @@ namespace osu.Game.Overlays.Profile.Sections } } - public IEnumerable FirstPlacePlays + public IEnumerable FirstPlaceScores { set { - foreach (Play play in value) - firstPlace.Add(new DrawablePlay(play) + foreach (Score score in value) + firstPlace.Add(new DrawableScore(score) { RelativeSizeAxes = Axes.X, Height = 60, diff --git a/osu.Game/Rulesets/Scoring/Score.cs b/osu.Game/Rulesets/Scoring/Score.cs index 2cca0f54af..d77baaa8f3 100644 --- a/osu.Game/Rulesets/Scoring/Score.cs +++ b/osu.Game/Rulesets/Scoring/Score.cs @@ -22,6 +22,8 @@ namespace osu.Game.Rulesets.Scoring public double Health { get; set; } = 1; + public double PP { get; set; } + [JsonProperty(@"max_combo")] public int MaxCombo { get; set; } diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index b63ad6a271..6888ecc220 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -99,7 +99,6 @@ - From 88f206cfe40bd9055299ce51e0eabff27d69c58c Mon Sep 17 00:00:00 2001 From: Jorolf Date: Sat, 29 Jul 2017 00:34:16 +0200 Subject: [PATCH 0004/1263] rename file --- .../Sections/Ranks/{DrawablePlay.cs => DrawableScore.cs} | 0 osu.Game/osu.Game.csproj | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename osu.Game/Overlays/Profile/Sections/Ranks/{DrawablePlay.cs => DrawableScore.cs} (100%) diff --git a/osu.Game/Overlays/Profile/Sections/Ranks/DrawablePlay.cs b/osu.Game/Overlays/Profile/Sections/Ranks/DrawableScore.cs similarity index 100% rename from osu.Game/Overlays/Profile/Sections/Ranks/DrawablePlay.cs rename to osu.Game/Overlays/Profile/Sections/Ranks/DrawableScore.cs diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 6888ecc220..859b52596f 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -98,7 +98,7 @@ - + From 33ce8737cc726cbdb58eb822250ae99664e08440 Mon Sep 17 00:00:00 2001 From: Jorolf Date: Sat, 29 Jul 2017 00:47:23 +0200 Subject: [PATCH 0005/1263] fix merge --- osu.Desktop.VisualTests/Tests/TestCaseUserRanks.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Desktop.VisualTests/Tests/TestCaseUserRanks.cs b/osu.Desktop.VisualTests/Tests/TestCaseUserRanks.cs index 9eacde0b97..1ae6281928 100644 --- a/osu.Desktop.VisualTests/Tests/TestCaseUserRanks.cs +++ b/osu.Desktop.VisualTests/Tests/TestCaseUserRanks.cs @@ -5,7 +5,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Testing; -using osu.Game.Database; +using osu.Game.Beatmaps; using osu.Game.Graphics; using osu.Game.Overlays.Profile.Sections; using osu.Game.Overlays.Profile.Sections.Ranks; @@ -47,6 +47,7 @@ namespace osu.Desktop.VisualTests.Tests { Rank = ScoreRank.A, Accuracy = 0.735, + PP = 666, Date = DateTimeOffset.UtcNow, Mods = new Mod[] { new ModAutoplay(), new ModDoubleTime() }, Beatmap = new BeatmapInfo @@ -73,6 +74,7 @@ namespace osu.Desktop.VisualTests.Tests { Rank = (ScoreRank) Enum.GetValues(typeof(ScoreRank)).GetValue(Enum.GetValues(typeof(ScoreRank)).Length - 1 - i), Accuracy = Math.Pow(0.99, i), + PP = Math.Pow(0.5, i) * 800, Date = DateTimeOffset.UtcNow.AddDays(-Math.Pow(i, 2)), Mods = selectedMods.ToArray(), Beatmap = new BeatmapInfo From c02165c82072c4f1d68a8988224dd62c2cade688 Mon Sep 17 00:00:00 2001 From: Jorolf Date: Sat, 29 Jul 2017 00:52:32 +0200 Subject: [PATCH 0006/1263] remove unused usings --- osu.Desktop.VisualTests/Tests/TestCaseUserRanks.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Desktop.VisualTests/Tests/TestCaseUserRanks.cs b/osu.Desktop.VisualTests/Tests/TestCaseUserRanks.cs index 1ae6281928..54e6b660f5 100644 --- a/osu.Desktop.VisualTests/Tests/TestCaseUserRanks.cs +++ b/osu.Desktop.VisualTests/Tests/TestCaseUserRanks.cs @@ -8,13 +8,11 @@ using osu.Framework.Testing; using osu.Game.Beatmaps; using osu.Game.Graphics; using osu.Game.Overlays.Profile.Sections; -using osu.Game.Overlays.Profile.Sections.Ranks; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu.Mods; using osu.Game.Rulesets.Scoring; using System; using System.Collections.Generic; -using System.Linq; namespace osu.Desktop.VisualTests.Tests { From cca49d6ed5936dea16370167d42674a9692f6a23 Mon Sep 17 00:00:00 2001 From: Jorolf Date: Sat, 29 Jul 2017 15:06:46 +0200 Subject: [PATCH 0007/1263] some renaming, a show more button and a placeholder if no scores exist --- .../Tests/TestCaseUserRanks.cs | 4 +- .../Overlays/Profile/Sections/RanksSection.cs | 164 +++++++++++++++--- 2 files changed, 143 insertions(+), 25 deletions(-) diff --git a/osu.Desktop.VisualTests/Tests/TestCaseUserRanks.cs b/osu.Desktop.VisualTests/Tests/TestCaseUserRanks.cs index 54e6b660f5..607a6b9a91 100644 --- a/osu.Desktop.VisualTests/Tests/TestCaseUserRanks.cs +++ b/osu.Desktop.VisualTests/Tests/TestCaseUserRanks.cs @@ -39,7 +39,7 @@ namespace osu.Desktop.VisualTests.Tests } }); - AddStep("Add First Place", () => ranks.FirstPlaceScores = new[] + AddStep("Add First Place", () => ranks.ScoresFirst = new[] { new Score { @@ -89,7 +89,7 @@ namespace osu.Desktop.VisualTests.Tests if(i < availableMods.Length) selectedMods.Remove(availableMods[i]); } - ranks.BestScores = scores; + ranks.ScoresBest = scores.ToArray(); }); } } diff --git a/osu.Game/Overlays/Profile/Sections/RanksSection.cs b/osu.Game/Overlays/Profile/Sections/RanksSection.cs index 846f0e0e47..b0f5e2080a 100644 --- a/osu.Game/Overlays/Profile/Sections/RanksSection.cs +++ b/osu.Game/Overlays/Profile/Sections/RanksSection.cs @@ -1,13 +1,17 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using OpenTK.Graphics; +using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Input; +using osu.Game.Graphics; +using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Overlays.Profile.Sections.Ranks; using osu.Game.Rulesets.Scoring; using System; -using System.Collections.Generic; namespace osu.Game.Overlays.Profile.Sections { @@ -17,64 +21,178 @@ namespace osu.Game.Overlays.Profile.Sections public override string Identifier => "top_ranks"; - private readonly FillFlowContainer best, firstPlace; + private readonly ScoreFlowContainer best, first; + private readonly OsuSpriteText bestMissing, firstMissing; public RanksSection() { Children = new Drawable[] { - new OsuSpriteText { + new OsuSpriteText + { TextSize = 15, Text = "Best Performance", Font = "Exo2.0-RegularItalic", + Margin = new MarginPadding { Top = 10, Bottom = 10 }, }, - best = new FillFlowContainer + best = new ScoreFlowContainer { AutoSizeAxes = Axes.Y, RelativeSizeAxes = Axes.X, - Direction = FillDirection.Vertical, }, - new OsuSpriteText { + bestMissing = new OsuSpriteText + { + TextSize = 14, + Text = "No awesome performance records yet. :(", + }, + new OsuSpriteText + { TextSize = 15, Text = "First Place Ranks", Font = "Exo2.0-RegularItalic", + Margin = new MarginPadding { Top = 20, Bottom = 10 }, }, - firstPlace = new FillFlowContainer + first = new ScoreFlowContainer { AutoSizeAxes = Axes.Y, RelativeSizeAxes = Axes.X, - Direction = FillDirection.Vertical, + }, + firstMissing = new OsuSpriteText + { + TextSize = 14, + Text = "No awesome performance records yet. :(", }, }; } - public IEnumerable BestScores + public Score[] ScoresBest { set { - int i = 0; - foreach (Score score in value) + best.Clear(); + if (value.Length == 0) { - best.Add(new DrawableScore(score, Math.Pow(0.95, i)) - { - RelativeSizeAxes = Axes.X, - Height = 60, - }); - i++; + bestMissing.Show(); } + else + { + bestMissing.Hide(); + int i = 0; + foreach (Score score in value) + { + best.Add(new DrawableScore(score, Math.Pow(0.95, i)) + { + RelativeSizeAxes = Axes.X, + Height = 60, + }); + i++; + } + } + best.ShowMore(); } } - public IEnumerable FirstPlaceScores + public Score[] ScoresFirst { set { - foreach (Score score in value) - firstPlace.Add(new DrawableScore(score) + first.Clear(); + if (value.Length == 0) + { + firstMissing.Show(); + } + else + { + firstMissing.Hide(); + foreach (Score score in value) + first.Add(new DrawableScore(score) + { + RelativeSizeAxes = Axes.X, + Height = 60, + }); + } + first.ShowMore(); + } + } + + private class ScoreFlowContainer : Container + { + private readonly FillFlowContainer scores; + private readonly OsuClickableContainer showMoreText; + + protected override Container Content => scores; + + private int shownScores; + + public ScoreFlowContainer() + { + InternalChild = new FillFlowContainer + { + AutoSizeAxes = Axes.Y, + RelativeSizeAxes = Axes.X, + Direction = FillDirection.Vertical, + Children = new Drawable[] { - RelativeSizeAxes = Axes.X, - Height = 60, - }); + scores = new FillFlowContainer() + { + AutoSizeAxes = Axes.Y, + RelativeSizeAxes = Axes.X, + Direction = FillDirection.Vertical, + }, + showMoreText = new ShowMoreContainer + { + Action = ShowMore, + AutoSizeAxes = Axes.Both, + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Alpha = 0, + Child = new OsuSpriteText + { + TextSize = 14, + Text = "show more", + } + } + }, + }; + } + + public override void Clear(bool disposeChildren) + { + base.Clear(disposeChildren); + shownScores = 0; + showMoreText.Show(); + } + + public void ShowMore() + { + shownScores = Math.Min(Children.Count, shownScores + 5); + int i = 0; + foreach(DrawableScore score in Children) + score.FadeTo(i++ < shownScores ? 1 : 0); + showMoreText.FadeTo(shownScores == Children.Count ? 0 : 1); + } + + private class ShowMoreContainer : OsuClickableContainer + { + private Color4 hoverColour; + + protected override bool OnHover(InputState state) + { + this.FadeColour(hoverColour, 500, Easing.OutQuint); + return base.OnHover(state); + } + + protected override void OnHoverLost(InputState state) + { + this.FadeColour(Color4.White, 500, Easing.OutQuint); + base.OnHoverLost(state); + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + hoverColour = colours.Yellow; + } } } } From 02a22e3f774eb8e9400da1ff28ecf13ae7c1d202 Mon Sep 17 00:00:00 2001 From: Jorolf Date: Sat, 29 Jul 2017 15:16:31 +0200 Subject: [PATCH 0008/1263] remove empty argument list --- osu.Game/Overlays/Profile/Sections/RanksSection.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Profile/Sections/RanksSection.cs b/osu.Game/Overlays/Profile/Sections/RanksSection.cs index b0f5e2080a..a99aceb893 100644 --- a/osu.Game/Overlays/Profile/Sections/RanksSection.cs +++ b/osu.Game/Overlays/Profile/Sections/RanksSection.cs @@ -133,7 +133,7 @@ namespace osu.Game.Overlays.Profile.Sections Direction = FillDirection.Vertical, Children = new Drawable[] { - scores = new FillFlowContainer() + scores = new FillFlowContainer { AutoSizeAxes = Axes.Y, RelativeSizeAxes = Axes.X, From 1c2329f111bf750d98baab189f58b0c3e76cde88 Mon Sep 17 00:00:00 2001 From: Jorolf Date: Tue, 8 Aug 2017 23:11:46 +0200 Subject: [PATCH 0009/1263] generalize the hover code --- .../Graphics/Containers/OsuHoverContainer.cs | 32 ++++++++++++++++ osu.Game/Overlays/Profile/ProfileHeader.cs | 38 +++++++++---------- osu.Game/osu.Game.csproj | 1 + 3 files changed, 50 insertions(+), 21 deletions(-) create mode 100644 osu.Game/Graphics/Containers/OsuHoverContainer.cs diff --git a/osu.Game/Graphics/Containers/OsuHoverContainer.cs b/osu.Game/Graphics/Containers/OsuHoverContainer.cs new file mode 100644 index 0000000000..b4ce162086 --- /dev/null +++ b/osu.Game/Graphics/Containers/OsuHoverContainer.cs @@ -0,0 +1,32 @@ + +using OpenTK.Graphics; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Input; + +namespace osu.Game.Graphics.Containers +{ + + public class OsuHoverContainer : OsuClickableContainer + { + private Color4 hoverColour; + + protected override bool OnHover(InputState state) + { + this.FadeColour(hoverColour, 500, Easing.OutQuint); + return base.OnHover(state); + } + + protected override void OnHoverLost(InputState state) + { + this.FadeColour(Color4.White, 500, Easing.OutQuint); + base.OnHoverLost(state); + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + hoverColour = colours.Yellow; + } + } +} diff --git a/osu.Game/Overlays/Profile/ProfileHeader.cs b/osu.Game/Overlays/Profile/ProfileHeader.cs index 93044315cc..891487cfa7 100644 --- a/osu.Game/Overlays/Profile/ProfileHeader.cs +++ b/osu.Game/Overlays/Profile/ProfileHeader.cs @@ -19,6 +19,7 @@ using osu.Game.Graphics.Sprites; using osu.Game.Users; using System.Diagnostics; using System.Globalization; +using System.Collections.Generic; namespace osu.Game.Overlays.Profile { @@ -509,34 +510,29 @@ namespace osu.Game.Overlays.Profile public class LinkText : OsuSpriteText { - public override bool HandleInput => Url != null; + private readonly OsuHoverContainer content; - public string Url; + public override bool HandleInput => content.Action != null; - private Color4 hoverColour; + protected override Container Content => content ?? (Container)this; - protected override bool OnHover(InputState state) + protected override IEnumerable FlowingChildren => Children; + + public string Url { - this.FadeColour(hoverColour, 500, Easing.OutQuint); - return base.OnHover(state); + set + { + if(value != null) + content.Action = () => Process.Start(value); + } } - protected override void OnHoverLost(InputState state) + public LinkText() { - this.FadeColour(Color4.White, 500, Easing.OutQuint); - base.OnHoverLost(state); - } - - protected override bool OnClick(InputState state) - { - Process.Start(Url); - return true; - } - - [BackgroundDependencyLoader] - private void load(OsuColour colours) - { - hoverColour = colours.Yellow; + AddInternal(content = new OsuHoverContainer + { + AutoSizeAxes = Axes.Both, + }); } } } diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 8312a1a319..8cbaee3072 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -92,6 +92,7 @@ + From 9f005488f7dca56b135340419ba892862a542066 Mon Sep 17 00:00:00 2001 From: Jorolf Date: Wed, 9 Aug 2017 01:43:52 +0200 Subject: [PATCH 0010/1263] make it work again after merge --- .../Visual}/TestCaseUserRanks.cs | 0 osu.Desktop.Tests/osu.Desktop.Tests.csproj | 1 + osu.Desktop.VisualTests/osu.Desktop.VisualTests.csproj | 1 - osu.Game/Overlays/Profile/Sections/Ranks/DrawableScore.cs | 8 ++------ 4 files changed, 3 insertions(+), 7 deletions(-) rename {osu.Desktop.VisualTests/Tests => osu.Desktop.Tests/Visual}/TestCaseUserRanks.cs (100%) diff --git a/osu.Desktop.VisualTests/Tests/TestCaseUserRanks.cs b/osu.Desktop.Tests/Visual/TestCaseUserRanks.cs similarity index 100% rename from osu.Desktop.VisualTests/Tests/TestCaseUserRanks.cs rename to osu.Desktop.Tests/Visual/TestCaseUserRanks.cs diff --git a/osu.Desktop.Tests/osu.Desktop.Tests.csproj b/osu.Desktop.Tests/osu.Desktop.Tests.csproj index aa862498d1..9210b5eb3a 100644 --- a/osu.Desktop.Tests/osu.Desktop.Tests.csproj +++ b/osu.Desktop.Tests/osu.Desktop.Tests.csproj @@ -109,6 +109,7 @@ + diff --git a/osu.Desktop.VisualTests/osu.Desktop.VisualTests.csproj b/osu.Desktop.VisualTests/osu.Desktop.VisualTests.csproj index 64fe3d4b95..8bba59207f 100644 --- a/osu.Desktop.VisualTests/osu.Desktop.VisualTests.csproj +++ b/osu.Desktop.VisualTests/osu.Desktop.VisualTests.csproj @@ -186,7 +186,6 @@ - diff --git a/osu.Game/Overlays/Profile/Sections/Ranks/DrawableScore.cs b/osu.Game/Overlays/Profile/Sections/Ranks/DrawableScore.cs index f74b6792ad..9279bd0156 100644 --- a/osu.Game/Overlays/Profile/Sections/Ranks/DrawableScore.cs +++ b/osu.Game/Overlays/Profile/Sections/Ranks/DrawableScore.cs @@ -156,25 +156,21 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks Children = new[] { - new TextAwesome + new SpriteIcon { Origin = Anchor.Centre, Anchor = Anchor.Centre, Icon = FontAwesome.fa_osu_mod_bg, Colour = colour, Shadow = true, - TextSize = 30, - UseFullGlyphHeight = false, }, - new TextAwesome + new SpriteIcon { Origin = Anchor.Centre, Anchor = Anchor.Centre, Icon = icon, Colour = OsuColour.Gray(84), - TextSize = 18, Position = new Vector2(0f, 2f), - UseFullGlyphHeight = false, }, }; } From 274ebbd1f7f1ff197c8212f7ca6655fa33f7befe Mon Sep 17 00:00:00 2001 From: Jorolf Date: Wed, 9 Aug 2017 18:45:37 +0200 Subject: [PATCH 0011/1263] remove duplicated code and "simplify" ShowMore logic --- osu.Desktop.Tests/Visual/TestCaseUserRanks.cs | 2 +- .../Profile/Sections/Ranks/DrawableScore.cs | 71 ++++--------------- .../Overlays/Profile/Sections/RanksSection.cs | 44 ++---------- 3 files changed, 19 insertions(+), 98 deletions(-) diff --git a/osu.Desktop.Tests/Visual/TestCaseUserRanks.cs b/osu.Desktop.Tests/Visual/TestCaseUserRanks.cs index 607a6b9a91..d8e3449b1e 100644 --- a/osu.Desktop.Tests/Visual/TestCaseUserRanks.cs +++ b/osu.Desktop.Tests/Visual/TestCaseUserRanks.cs @@ -47,7 +47,7 @@ namespace osu.Desktop.VisualTests.Tests Accuracy = 0.735, PP = 666, Date = DateTimeOffset.UtcNow, - Mods = new Mod[] { new ModAutoplay(), new ModDoubleTime() }, + Mods = new Mod[] { new ModAutoplay(), new ModDoubleTime(), new OsuModEasy() }, Beatmap = new BeatmapInfo { Metadata = new BeatmapMetadata diff --git a/osu.Game/Overlays/Profile/Sections/Ranks/DrawableScore.cs b/osu.Game/Overlays/Profile/Sections/Ranks/DrawableScore.cs index 9279bd0156..9318798ec3 100644 --- a/osu.Game/Overlays/Profile/Sections/Ranks/DrawableScore.cs +++ b/osu.Game/Overlays/Profile/Sections/Ranks/DrawableScore.cs @@ -12,12 +12,11 @@ using osu.Game.Graphics.Sprites; using osu.Game.Rulesets.Mods; using osu.Game.Screens.Select.Leaderboards; using System.Linq; -using OpenTK.Graphics; using System.Diagnostics; -using osu.Framework.Input; using osu.Framework.Localisation; using System.Globalization; using osu.Game.Rulesets.Scoring; +using osu.Framework.Graphics.Cursor; namespace osu.Game.Overlays.Profile.Sections.Ranks { @@ -72,7 +71,7 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks Anchor = Anchor.CentreRight, Origin = Anchor.CentreRight, Width = 60, - Margin = new MarginPadding{ Right = 140 } + Margin = new MarginPadding{ Right = 150 } } }; } @@ -108,10 +107,10 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks Font = "Exo2.0-RegularItalic", }); - metadata.Add(new LinkContainer + metadata.Add(new OsuHoverContainer { AutoSizeAxes = Axes.Both, - Url = $"https://osu.ppy.sh/beatmaps/{score.Beatmap.OnlineBeatmapID}", + Action = () => Process.Start($"https://osu.ppy.sh/beatmaps/{score.Beatmap.OnlineBeatmapID}"), Child = new FillFlowContainer { AutoSizeAxes = Axes.Both, @@ -135,7 +134,11 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks }); foreach (Mod mod in score.Mods) - modContainer.Add(new ModIcon(mod.Icon, colour.Yellow)); + modContainer.Add(new ModIcon(mod) + { + AutoSizeAxes = Axes.Both, + Scale = new Vector2(0.5f), + }); } private class ModContainer : FlowContainer @@ -148,62 +151,14 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks } } - private class ModIcon : Container + private class ModIcon : Rulesets.UI.ModIcon, IHasTooltip { - public ModIcon(FontAwesome icon, Color4 colour) + public ModIcon(Mod mod) : base(mod) { - AutoSizeAxes = Axes.Both; - - Children = new[] - { - new SpriteIcon - { - Origin = Anchor.Centre, - Anchor = Anchor.Centre, - Icon = FontAwesome.fa_osu_mod_bg, - Colour = colour, - Shadow = true, - }, - new SpriteIcon - { - Origin = Anchor.Centre, - Anchor = Anchor.Centre, - Icon = icon, - Colour = OsuColour.Gray(84), - Position = new Vector2(0f, 2f), - }, - }; - } - } - - private class LinkContainer : OsuClickableContainer - { - public string Url; - - private Color4 hoverColour; - - public LinkContainer() - { - Action = () => Process.Start(Url); + TooltipText = mod.Name; } - protected override bool OnHover(InputState state) - { - this.FadeColour(hoverColour, 500, Easing.OutQuint); - return base.OnHover(state); - } - - protected override void OnHoverLost(InputState state) - { - this.FadeColour(Color4.White, 500, Easing.OutQuint); - base.OnHoverLost(state); - } - - [BackgroundDependencyLoader] - private void load(OsuColour colours) - { - hoverColour = colours.Yellow; - } + public string TooltipText { get; } } } } diff --git a/osu.Game/Overlays/Profile/Sections/RanksSection.cs b/osu.Game/Overlays/Profile/Sections/RanksSection.cs index a99aceb893..e9cc0bc00c 100644 --- a/osu.Game/Overlays/Profile/Sections/RanksSection.cs +++ b/osu.Game/Overlays/Profile/Sections/RanksSection.cs @@ -1,17 +1,14 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using OpenTK.Graphics; -using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Input; -using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Overlays.Profile.Sections.Ranks; using osu.Game.Rulesets.Scoring; using System; +using System.Linq; namespace osu.Game.Overlays.Profile.Sections { @@ -84,6 +81,7 @@ namespace osu.Game.Overlays.Profile.Sections { RelativeSizeAxes = Axes.X, Height = 60, + Alpha = 0, }); i++; } @@ -109,6 +107,7 @@ namespace osu.Game.Overlays.Profile.Sections { RelativeSizeAxes = Axes.X, Height = 60, + Alpha = 0, }); } first.ShowMore(); @@ -122,8 +121,6 @@ namespace osu.Game.Overlays.Profile.Sections protected override Container Content => scores; - private int shownScores; - public ScoreFlowContainer() { InternalChild = new FillFlowContainer @@ -139,7 +136,7 @@ namespace osu.Game.Overlays.Profile.Sections RelativeSizeAxes = Axes.X, Direction = FillDirection.Vertical, }, - showMoreText = new ShowMoreContainer + showMoreText = new OsuHoverContainer { Action = ShowMore, AutoSizeAxes = Axes.Both, @@ -159,41 +156,10 @@ namespace osu.Game.Overlays.Profile.Sections public override void Clear(bool disposeChildren) { base.Clear(disposeChildren); - shownScores = 0; showMoreText.Show(); } - public void ShowMore() - { - shownScores = Math.Min(Children.Count, shownScores + 5); - int i = 0; - foreach(DrawableScore score in Children) - score.FadeTo(i++ < shownScores ? 1 : 0); - showMoreText.FadeTo(shownScores == Children.Count ? 0 : 1); - } - - private class ShowMoreContainer : OsuClickableContainer - { - private Color4 hoverColour; - - protected override bool OnHover(InputState state) - { - this.FadeColour(hoverColour, 500, Easing.OutQuint); - return base.OnHover(state); - } - - protected override void OnHoverLost(InputState state) - { - this.FadeColour(Color4.White, 500, Easing.OutQuint); - base.OnHoverLost(state); - } - - [BackgroundDependencyLoader] - private void load(OsuColour colours) - { - hoverColour = colours.Yellow; - } - } + public void ShowMore() => showMoreText.Alpha = Children.Where(d => !d.IsPresent).Where((d, i) => (d.Alpha = (i < 5 ? 1 : 0)) == 0).Any() ? 1 : 0; } } } From 8631c469fcc69eb4886caf69574c45495632e2af Mon Sep 17 00:00:00 2001 From: Jorolf Date: Wed, 9 Aug 2017 18:50:44 +0200 Subject: [PATCH 0012/1263] add license header --- osu.Game/Graphics/Containers/OsuHoverContainer.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game/Graphics/Containers/OsuHoverContainer.cs b/osu.Game/Graphics/Containers/OsuHoverContainer.cs index b4ce162086..efac292c76 100644 --- a/osu.Game/Graphics/Containers/OsuHoverContainer.cs +++ b/osu.Game/Graphics/Containers/OsuHoverContainer.cs @@ -1,4 +1,6 @@ - +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + using OpenTK.Graphics; using osu.Framework.Allocation; using osu.Framework.Graphics; From c2c9095b0235c2284ad91925f80a709a21972014 Mon Sep 17 00:00:00 2001 From: Jorolf Date: Wed, 9 Aug 2017 18:57:55 +0200 Subject: [PATCH 0013/1263] fix CI issues --- osu.Desktop.Tests/Visual/TestCaseUserRanks.cs | 2 +- osu.Game/Overlays/Profile/ProfileHeader.cs | 1 - osu.Game/Overlays/Profile/Sections/RanksSection.cs | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/osu.Desktop.Tests/Visual/TestCaseUserRanks.cs b/osu.Desktop.Tests/Visual/TestCaseUserRanks.cs index d8e3449b1e..a561559fdc 100644 --- a/osu.Desktop.Tests/Visual/TestCaseUserRanks.cs +++ b/osu.Desktop.Tests/Visual/TestCaseUserRanks.cs @@ -14,7 +14,7 @@ using osu.Game.Rulesets.Scoring; using System; using System.Collections.Generic; -namespace osu.Desktop.VisualTests.Tests +namespace osu.Desktop.Tests.Visual { public class TestCaseUserRanks : TestCase { diff --git a/osu.Game/Overlays/Profile/ProfileHeader.cs b/osu.Game/Overlays/Profile/ProfileHeader.cs index f3e8dc5562..b6d691e549 100644 --- a/osu.Game/Overlays/Profile/ProfileHeader.cs +++ b/osu.Game/Overlays/Profile/ProfileHeader.cs @@ -12,7 +12,6 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; -using osu.Framework.Input; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; diff --git a/osu.Game/Overlays/Profile/Sections/RanksSection.cs b/osu.Game/Overlays/Profile/Sections/RanksSection.cs index e9cc0bc00c..6c3814a75f 100644 --- a/osu.Game/Overlays/Profile/Sections/RanksSection.cs +++ b/osu.Game/Overlays/Profile/Sections/RanksSection.cs @@ -159,7 +159,7 @@ namespace osu.Game.Overlays.Profile.Sections showMoreText.Show(); } - public void ShowMore() => showMoreText.Alpha = Children.Where(d => !d.IsPresent).Where((d, i) => (d.Alpha = (i < 5 ? 1 : 0)) == 0).Any() ? 1 : 0; + public void ShowMore() => showMoreText.Alpha = Children.Where(d => !d.IsPresent).Where((d, i) => (d.Alpha = i < 5 ? 1 : 0) == 0).Any() ? 1 : 0; } } } From c877a5a8b73b7c59d41038850c4d8169c0fe45ca Mon Sep 17 00:00:00 2001 From: Jorolf Date: Wed, 9 Aug 2017 19:20:41 +0200 Subject: [PATCH 0014/1263] update TestCase --- osu.Desktop.Tests/Visual/TestCaseUserRanks.cs | 46 ++++++++++--------- .../Graphics/Containers/OsuHoverContainer.cs | 1 - .../Overlays/Profile/Sections/RanksSection.cs | 2 +- 3 files changed, 25 insertions(+), 24 deletions(-) diff --git a/osu.Desktop.Tests/Visual/TestCaseUserRanks.cs b/osu.Desktop.Tests/Visual/TestCaseUserRanks.cs index a561559fdc..278f3408bf 100644 --- a/osu.Desktop.Tests/Visual/TestCaseUserRanks.cs +++ b/osu.Desktop.Tests/Visual/TestCaseUserRanks.cs @@ -39,28 +39,6 @@ namespace osu.Desktop.Tests.Visual } }); - AddStep("Add First Place", () => ranks.ScoresFirst = new[] - { - new Score - { - Rank = ScoreRank.A, - Accuracy = 0.735, - PP = 666, - Date = DateTimeOffset.UtcNow, - Mods = new Mod[] { new ModAutoplay(), new ModDoubleTime(), new OsuModEasy() }, - Beatmap = new BeatmapInfo - { - Metadata = new BeatmapMetadata - { - Title = "FREEDOM DiVE", - Artist = "xi" - }, - Version = "FOUR DIMENSIONS", - OnlineBeatmapID = 129891, - } - } - }); - AddStep("Add Best Performances", () => { List scores = new List(); @@ -91,6 +69,30 @@ namespace osu.Desktop.Tests.Visual } ranks.ScoresBest = scores.ToArray(); }); + + AddStep("Add First Place", () => ranks.ScoresFirst = new[] + { + new Score + { + Rank = ScoreRank.A, + Accuracy = 0.735, + PP = 666, + Date = DateTimeOffset.UtcNow, + Mods = new Mod[] { new ModAutoplay(), new ModDoubleTime(), new OsuModEasy() }, + Beatmap = new BeatmapInfo + { + Metadata = new BeatmapMetadata + { + Title = "FREEDOM DiVE", + Artist = "xi" + }, + Version = "FOUR DIMENSIONS", + OnlineBeatmapID = 129891, + } + } + }); + + AddStep("Show More", ((RanksSection.ScoreFlowContainer)ranks.Children[1]).ShowMore); } } } diff --git a/osu.Game/Graphics/Containers/OsuHoverContainer.cs b/osu.Game/Graphics/Containers/OsuHoverContainer.cs index efac292c76..3f82ad2179 100644 --- a/osu.Game/Graphics/Containers/OsuHoverContainer.cs +++ b/osu.Game/Graphics/Containers/OsuHoverContainer.cs @@ -8,7 +8,6 @@ using osu.Framework.Input; namespace osu.Game.Graphics.Containers { - public class OsuHoverContainer : OsuClickableContainer { private Color4 hoverColour; diff --git a/osu.Game/Overlays/Profile/Sections/RanksSection.cs b/osu.Game/Overlays/Profile/Sections/RanksSection.cs index 6c3814a75f..e7c32f76e4 100644 --- a/osu.Game/Overlays/Profile/Sections/RanksSection.cs +++ b/osu.Game/Overlays/Profile/Sections/RanksSection.cs @@ -114,7 +114,7 @@ namespace osu.Game.Overlays.Profile.Sections } } - private class ScoreFlowContainer : Container + public class ScoreFlowContainer : Container { private readonly FillFlowContainer scores; private readonly OsuClickableContainer showMoreText; From bb8374b4fef83d7b98df2d6e11f407d9c87ce78a Mon Sep 17 00:00:00 2001 From: Jorolf Date: Wed, 9 Aug 2017 19:47:51 +0200 Subject: [PATCH 0015/1263] override LoadComplete instead of using the constructor --- osu.Desktop.Tests/Visual/TestCaseUserRanks.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Desktop.Tests/Visual/TestCaseUserRanks.cs b/osu.Desktop.Tests/Visual/TestCaseUserRanks.cs index 278f3408bf..867e62859d 100644 --- a/osu.Desktop.Tests/Visual/TestCaseUserRanks.cs +++ b/osu.Desktop.Tests/Visual/TestCaseUserRanks.cs @@ -20,8 +20,9 @@ namespace osu.Desktop.Tests.Visual { public override string Description => "showing your latest achievements"; - public TestCaseUserRanks() + protected override void LoadComplete() { + base.LoadComplete(); RanksSection ranks; Add(new Container From acc9b20b0f32ade24a06b62438f275820ddde69c Mon Sep 17 00:00:00 2001 From: Jorolf Date: Wed, 9 Aug 2017 22:37:05 +0200 Subject: [PATCH 0016/1263] move another thing to LoadComplete instead of the constructor --- osu.Game/Overlays/Profile/Sections/RanksSection.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/Profile/Sections/RanksSection.cs b/osu.Game/Overlays/Profile/Sections/RanksSection.cs index e7c32f76e4..2d8da5b1f0 100644 --- a/osu.Game/Overlays/Profile/Sections/RanksSection.cs +++ b/osu.Game/Overlays/Profile/Sections/RanksSection.cs @@ -116,12 +116,12 @@ namespace osu.Game.Overlays.Profile.Sections public class ScoreFlowContainer : Container { - private readonly FillFlowContainer scores; - private readonly OsuClickableContainer showMoreText; + private FillFlowContainer scores; + private OsuClickableContainer showMoreText; protected override Container Content => scores; - public ScoreFlowContainer() + protected override void LoadComplete() { InternalChild = new FillFlowContainer { From 15e4e487e2aa1ee321ac855adbc5b7820f9271c2 Mon Sep 17 00:00:00 2001 From: Jorolf Date: Wed, 9 Aug 2017 22:58:06 +0200 Subject: [PATCH 0017/1263] I hope this works --- osu.Desktop.Tests/Visual/TestCaseUserRanks.cs | 3 +- .../Overlays/Profile/Sections/RanksSection.cs | 29 ++++++++++--------- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/osu.Desktop.Tests/Visual/TestCaseUserRanks.cs b/osu.Desktop.Tests/Visual/TestCaseUserRanks.cs index 867e62859d..41f3a37e94 100644 --- a/osu.Desktop.Tests/Visual/TestCaseUserRanks.cs +++ b/osu.Desktop.Tests/Visual/TestCaseUserRanks.cs @@ -16,13 +16,14 @@ using System.Collections.Generic; namespace osu.Desktop.Tests.Visual { - public class TestCaseUserRanks : TestCase + internal class TestCaseUserRanks : TestCase { public override string Description => "showing your latest achievements"; protected override void LoadComplete() { base.LoadComplete(); + RanksSection ranks; Add(new Container diff --git a/osu.Game/Overlays/Profile/Sections/RanksSection.cs b/osu.Game/Overlays/Profile/Sections/RanksSection.cs index 2d8da5b1f0..f6590140ec 100644 --- a/osu.Game/Overlays/Profile/Sections/RanksSection.cs +++ b/osu.Game/Overlays/Profile/Sections/RanksSection.cs @@ -136,19 +136,6 @@ namespace osu.Game.Overlays.Profile.Sections RelativeSizeAxes = Axes.X, Direction = FillDirection.Vertical, }, - showMoreText = new OsuHoverContainer - { - Action = ShowMore, - AutoSizeAxes = Axes.Both, - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - Alpha = 0, - Child = new OsuSpriteText - { - TextSize = 14, - Text = "show more", - } - } }, }; } @@ -156,7 +143,21 @@ namespace osu.Game.Overlays.Profile.Sections public override void Clear(bool disposeChildren) { base.Clear(disposeChildren); - showMoreText.Show(); + if (showMoreText == null) + ((FillFlowContainer)InternalChild).Add(showMoreText = new OsuHoverContainer + { + Action = ShowMore, + AutoSizeAxes = Axes.Both, + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Child = new OsuSpriteText + { + TextSize = 14, + Text = "show more", + } + }); + else + showMoreText.Show(); } public void ShowMore() => showMoreText.Alpha = Children.Where(d => !d.IsPresent).Where((d, i) => (d.Alpha = i < 5 ? 1 : 0) == 0).Any() ? 1 : 0; From 98b847b025ce1c9e8199c1635dce6ece2efd7905 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 14 Sep 2017 20:05:43 +0900 Subject: [PATCH 0018/1263] Add API retrieval support --- .../Online/API/Requests/GetScoresRequest.cs | 23 ++++++- .../API/Requests/GetUserScoresRequest.cs | 28 +++++++++ osu.Game/Overlays/Profile/ProfileSection.cs | 10 +++ .../Profile/Sections/Ranks/DrawableScore.cs | 14 +++-- .../Overlays/Profile/Sections/RanksSection.cs | 62 +++++++++++++++++-- osu.Game/Overlays/UserProfileOverlay.cs | 2 + osu.Game/Rulesets/Scoring/Score.cs | 4 +- osu.Game/osu.Game.csproj | 1 + 8 files changed, 131 insertions(+), 13 deletions(-) create mode 100644 osu.Game/Online/API/Requests/GetUserScoresRequest.cs diff --git a/osu.Game/Online/API/Requests/GetScoresRequest.cs b/osu.Game/Online/API/Requests/GetScoresRequest.cs index ef9ee85d25..dfe1310325 100644 --- a/osu.Game/Online/API/Requests/GetScoresRequest.cs +++ b/osu.Game/Online/API/Requests/GetScoresRequest.cs @@ -7,6 +7,7 @@ using System.Linq; using Newtonsoft.Json; using osu.Framework.IO.Network; using osu.Game.Beatmaps; +using osu.Game.Rulesets; using osu.Game.Users; using osu.Game.Rulesets.Replays; using osu.Game.Rulesets.Scoring; @@ -73,6 +74,9 @@ namespace osu.Game.Online.API.Requests set { Replay = value; } } + [JsonProperty(@"mode_int")] + public int OnlineRulesetID { get; set; } + [JsonProperty(@"score_id")] private long onlineScoreID { @@ -85,6 +89,18 @@ namespace osu.Game.Online.API.Requests set { Date = value; } } + [JsonProperty(@"beatmap")] + private BeatmapInfo beatmap + { + set { Beatmap = value; } + } + + [JsonProperty(@"beatmapset")] + private BeatmapMetadata metadata + { + set { Beatmap.Metadata = value; } + } + [JsonProperty(@"statistics")] private Dictionary jsonStats { @@ -122,7 +138,12 @@ namespace osu.Game.Online.API.Requests public void ApplyBeatmap(BeatmapInfo beatmap) { Beatmap = beatmap; - Ruleset = beatmap.Ruleset; + ApplyRuleset(beatmap.Ruleset); + } + + public void ApplyRuleset(RulesetInfo ruleset) + { + Ruleset = ruleset; // Evaluate the mod string Mods = Ruleset.CreateInstance().GetAllMods().Where(mod => modStrings.Contains(mod.ShortenedName)).ToArray(); diff --git a/osu.Game/Online/API/Requests/GetUserScoresRequest.cs b/osu.Game/Online/API/Requests/GetUserScoresRequest.cs new file mode 100644 index 0000000000..20597aecc1 --- /dev/null +++ b/osu.Game/Online/API/Requests/GetUserScoresRequest.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.Collections.Generic; + +namespace osu.Game.Online.API.Requests +{ + public class GetUserScoresRequest : APIRequest> + { + private readonly long userId; + private readonly ScoreType type; + + public GetUserScoresRequest(long userId, ScoreType type) + { + this.userId = userId; + this.type = type; + } + + protected override string Target => $@"users/{userId}/scores/{type.ToString().ToLower()}"; + } + + public enum ScoreType + { + Best, + Firsts, + Recent + } +} \ No newline at end of file diff --git a/osu.Game/Overlays/Profile/ProfileSection.cs b/osu.Game/Overlays/Profile/ProfileSection.cs index 2b5084e321..df7c0e117f 100644 --- a/osu.Game/Overlays/Profile/ProfileSection.cs +++ b/osu.Game/Overlays/Profile/ProfileSection.cs @@ -7,6 +7,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; +using osu.Game.Users; using OpenTK.Graphics; namespace osu.Game.Overlays.Profile @@ -18,8 +19,17 @@ namespace osu.Game.Overlays.Profile public abstract string Identifier { get; } private readonly FillFlowContainer content; + protected override Container Content => content; + public virtual User User + { + get { return user; } + set { user = value; } + } + + private User user; + protected ProfileSection() { Direction = FillDirection.Vertical; diff --git a/osu.Game/Overlays/Profile/Sections/Ranks/DrawableScore.cs b/osu.Game/Overlays/Profile/Sections/Ranks/DrawableScore.cs index 9318798ec3..d92ebf6dca 100644 --- a/osu.Game/Overlays/Profile/Sections/Ranks/DrawableScore.cs +++ b/osu.Game/Overlays/Profile/Sections/Ranks/DrawableScore.cs @@ -79,26 +79,28 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks [BackgroundDependencyLoader] private void load(OsuColour colour, LocalisationEngine locale) { - stats.Add(new OsuSpriteText { - Text = score.PP + "pp", + stats.Add(new OsuSpriteText + { + Text = $"{score.PP ?? 0}pp", Anchor = Anchor.TopRight, Origin = Anchor.TopRight, TextSize = 18, Font = "Exo2.0-BoldItalic", }); - if(weight != -1) + if (weight != -1) { stats.Add(new OsuSpriteText { - Text = $"weighted: {(int)(score.PP * weight)}pp ({weight.ToString("0%", CultureInfo.CurrentCulture)})", + Text = $"weighted: {(int)(score?.PP * weight ?? 0)}pp ({weight.ToString("0%", CultureInfo.CurrentCulture)})", Anchor = Anchor.TopRight, Origin = Anchor.TopRight, Colour = colour.GrayA, TextSize = 11, Font = "Exo2.0-RegularItalic", - }); + }); } - stats.Add(new OsuSpriteText { + stats.Add(new OsuSpriteText + { Text = "accuracy: " + score.Accuracy.ToString("0.00%"), Anchor = Anchor.TopRight, Origin = Anchor.TopRight, diff --git a/osu.Game/Overlays/Profile/Sections/RanksSection.cs b/osu.Game/Overlays/Profile/Sections/RanksSection.cs index f6590140ec..4f9470bd6e 100644 --- a/osu.Game/Overlays/Profile/Sections/RanksSection.cs +++ b/osu.Game/Overlays/Profile/Sections/RanksSection.cs @@ -8,7 +8,13 @@ using osu.Game.Graphics.Sprites; using osu.Game.Overlays.Profile.Sections.Ranks; using osu.Game.Rulesets.Scoring; using System; +using System.Collections.Generic; using System.Linq; +using osu.Framework.Allocation; +using osu.Game.Online.API; +using osu.Game.Online.API.Requests; +using osu.Game.Rulesets; +using osu.Game.Users; namespace osu.Game.Overlays.Profile.Sections { @@ -21,6 +27,9 @@ namespace osu.Game.Overlays.Profile.Sections private readonly ScoreFlowContainer best, first; private readonly OsuSpriteText bestMissing, firstMissing; + private APIAccess api; + private RulesetStore rulesets; + public RanksSection() { Children = new Drawable[] @@ -62,12 +71,57 @@ namespace osu.Game.Overlays.Profile.Sections }; } - public Score[] ScoresBest + [BackgroundDependencyLoader] + private void load(APIAccess api, RulesetStore rulesets) + { + this.api = api; + this.rulesets = rulesets; + } + + public override User User + { + get + { + return base.User; + } + + set + { + base.User = value; + + // fetch online ranks + foreach (ScoreType m in new[] { ScoreType.Best, ScoreType.Firsts }) + { + ScoreType thisType = m; + var req = new GetUserScoresRequest(User.Id, m); + req.Success += scores => + { + foreach (var s in scores) + s.ApplyRuleset(rulesets.GetRuleset(s.OnlineRulesetID)); + + switch (thisType) + { + case ScoreType.Best: + ScoresBest = scores; + break; + case ScoreType.Firsts: + ScoresFirst = scores; + break; + } + }; + + Schedule(() => { api.Queue(req); }); + } + } + } + + + public IEnumerable ScoresBest { set { best.Clear(); - if (value.Length == 0) + if (!value.Any()) { bestMissing.Show(); } @@ -90,12 +144,12 @@ namespace osu.Game.Overlays.Profile.Sections } } - public Score[] ScoresFirst + public IEnumerable ScoresFirst { set { first.Clear(); - if (value.Length == 0) + if (!value.Any()) { firstMissing.Show(); } diff --git a/osu.Game/Overlays/UserProfileOverlay.cs b/osu.Game/Overlays/UserProfileOverlay.cs index f03ef3f1ed..034d956366 100644 --- a/osu.Game/Overlays/UserProfileOverlay.cs +++ b/osu.Game/Overlays/UserProfileOverlay.cs @@ -174,6 +174,8 @@ namespace osu.Game.Overlays var sec = sections.FirstOrDefault(s => s.Identifier == id); if (sec != null) { + sec.User = user; + sectionsContainer.Add(sec); tabs.AddItem(sec); } diff --git a/osu.Game/Rulesets/Scoring/Score.cs b/osu.Game/Rulesets/Scoring/Score.cs index 69ed9197d7..2af6509f09 100644 --- a/osu.Game/Rulesets/Scoring/Score.cs +++ b/osu.Game/Rulesets/Scoring/Score.cs @@ -20,7 +20,7 @@ namespace osu.Game.Rulesets.Scoring public double Health { get; set; } = 1; - public double PP { get; set; } + public double? PP { get; set; } public int MaxCombo { get; set; } @@ -28,7 +28,7 @@ namespace osu.Game.Rulesets.Scoring public RulesetInfo Ruleset { get; set; } - public Mod[] Mods { get; set; } + public Mod[] Mods { get; set; } = { }; public User User; diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 4046c0f9a1..a18087b856 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -81,6 +81,7 @@ + From 740e766201ccedccfa191a80a51ebc2c01a62352 Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Fri, 15 Sep 2017 19:39:55 +0300 Subject: [PATCH 0019/1263] BreakOverlay and LetterboxOverlay implementation --- .../Visual/TestCaseBreakOverlay.cs | 74 +++++++++++++++++++ osu.Desktop.Tests/osu.Desktop.Tests.csproj | 1 + osu.Game/Beatmaps/Timing/BreakPeriod.cs | 6 +- osu.Game/Screens/Play/BreakOverlay.cs | 64 ++++++++++++++++ osu.Game/Screens/Play/LetterboxOverlay.cs | 63 ++++++++++++++++ osu.Game/Screens/Play/Player.cs | 14 ++-- osu.Game/osu.Game.csproj | 2 + 7 files changed, 216 insertions(+), 8 deletions(-) create mode 100644 osu.Desktop.Tests/Visual/TestCaseBreakOverlay.cs create mode 100644 osu.Game/Screens/Play/BreakOverlay.cs create mode 100644 osu.Game/Screens/Play/LetterboxOverlay.cs diff --git a/osu.Desktop.Tests/Visual/TestCaseBreakOverlay.cs b/osu.Desktop.Tests/Visual/TestCaseBreakOverlay.cs new file mode 100644 index 0000000000..2c77b1ca39 --- /dev/null +++ b/osu.Desktop.Tests/Visual/TestCaseBreakOverlay.cs @@ -0,0 +1,74 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using OpenTK.Graphics; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Timing; +using osu.Game.Beatmaps.Timing; +using osu.Game.Screens.Play; +using System.Collections.Generic; + +namespace osu.Desktop.Tests.Visual +{ + internal class TestCaseBreakOverlay : OsuTestCase + { + public override string Description => @"Tests breaks behavior"; + + private readonly BreakOverlay breakOverlay; + + public TestCaseBreakOverlay() + { + Clock = new FramedClock(); + + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.White, + }, + breakOverlay = new BreakOverlay(true) + }; + + AddStep("Add 2s break", () => startBreak(2000)); + AddStep("Add 5s break", () => startBreak(5000)); + AddStep("Add 2 breaks (2s each)", startMultipleBreaks); + } + + private void startBreak(double duration) + { + breakOverlay.Breaks = new List + { + new BreakPeriod + { + StartTime = Clock.CurrentTime, + EndTime = Clock.CurrentTime + duration, + } + }; + + breakOverlay.InitializeBreaks(); + } + + private void startMultipleBreaks() + { + double currentTime = Clock.CurrentTime; + + breakOverlay.Breaks = new List + { + new BreakPeriod + { + StartTime = currentTime, + EndTime = currentTime + 2000, + }, + new BreakPeriod + { + StartTime = currentTime + 4000, + EndTime = currentTime + 6000, + } + }; + + breakOverlay.InitializeBreaks(); + } + } +} \ No newline at end of file diff --git a/osu.Desktop.Tests/osu.Desktop.Tests.csproj b/osu.Desktop.Tests/osu.Desktop.Tests.csproj index f894b25f06..5882578b79 100644 --- a/osu.Desktop.Tests/osu.Desktop.Tests.csproj +++ b/osu.Desktop.Tests/osu.Desktop.Tests.csproj @@ -72,6 +72,7 @@ + diff --git a/osu.Game/Beatmaps/Timing/BreakPeriod.cs b/osu.Game/Beatmaps/Timing/BreakPeriod.cs index fb307b7144..0cf4a0c65b 100644 --- a/osu.Game/Beatmaps/Timing/BreakPeriod.cs +++ b/osu.Game/Beatmaps/Timing/BreakPeriod.cs @@ -8,7 +8,7 @@ namespace osu.Game.Beatmaps.Timing /// /// The minimum duration required for a break to have any effect. /// - private const double min_break_duration = 650; + public const double MIN_BREAK_DURATION = 650; /// /// The break start time. @@ -28,6 +28,6 @@ namespace osu.Game.Beatmaps.Timing /// /// Whether the break has any effect. Breaks that are too short are culled before they are added to the beatmap. /// - public bool HasEffect => Duration >= min_break_duration; + public bool HasEffect => Duration >= MIN_BREAK_DURATION; } -} +} \ No newline at end of file diff --git a/osu.Game/Screens/Play/BreakOverlay.cs b/osu.Game/Screens/Play/BreakOverlay.cs new file mode 100644 index 0000000000..2cbf6fd3c8 --- /dev/null +++ b/osu.Game/Screens/Play/BreakOverlay.cs @@ -0,0 +1,64 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics; +using System.Collections.Generic; +using osu.Game.Beatmaps.Timing; + +namespace osu.Game.Screens.Play +{ + public class BreakOverlay : VisibilityContainer + { + private const double fade_duration = BreakPeriod.MIN_BREAK_DURATION / 2; + + public List Breaks; + + private readonly bool letterboxing; + private readonly LetterboxOverlay letterboxOverlay; + + public BreakOverlay(bool letterboxing) + { + this.letterboxing = letterboxing; + + RelativeSizeAxes = Axes.Both; + Child = letterboxOverlay = new LetterboxOverlay(); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + InitializeBreaks(); + } + + public void InitializeBreaks() + { + if (Breaks != null) + { + foreach (var b in Breaks) + { + if (b.HasEffect) + { + using (BeginAbsoluteSequence(b.StartTime, true)) + { + Show(); + + using (BeginDelayedSequence(b.Duration, true)) + Hide(); + } + } + } + } + } + + protected override void PopIn() + { + if (letterboxing) letterboxOverlay.FadeIn(fade_duration); + } + + protected override void PopOut() + { + if (letterboxing) letterboxOverlay.FadeOut(fade_duration); + } + } +} diff --git a/osu.Game/Screens/Play/LetterboxOverlay.cs b/osu.Game/Screens/Play/LetterboxOverlay.cs new file mode 100644 index 0000000000..6672b947e7 --- /dev/null +++ b/osu.Game/Screens/Play/LetterboxOverlay.cs @@ -0,0 +1,63 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using OpenTK.Graphics; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Colour; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; + +namespace osu.Game.Screens.Play +{ + public class LetterboxOverlay : Container + { + private const int letterbox_height = 350; + + private Color4 transparentBlack => new Color4(0, 0, 0, 0); + + public LetterboxOverlay() + { + RelativeSizeAxes = Axes.Both; + Alpha = 0; + Children = new Drawable[] + { + new Container + { + Anchor = Anchor.TopLeft, + Origin = Anchor.TopLeft, + RelativeSizeAxes = Axes.X, + Height = letterbox_height, + Child = new Box + { + RelativeSizeAxes = Axes.Both, + Colour = new ColourInfo + { + TopLeft = Color4.Black, + TopRight = Color4.Black, + BottomLeft = transparentBlack, + BottomRight = transparentBlack, + } + } + }, + new Container + { + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + RelativeSizeAxes = Axes.X, + Height = letterbox_height, + Child = new Box + { + RelativeSizeAxes = Axes.Both, + Colour = new ColourInfo + { + TopLeft = transparentBlack, + TopRight = transparentBlack, + BottomLeft = Color4.Black, + BottomRight = Color4.Black, + } + } + } + }; + } + } +} \ No newline at end of file diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 593abb7d26..f7b5da97e9 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -161,21 +161,25 @@ namespace osu.Game.Screens.Play }, Children = new Drawable[] { - new SkipButton(firstObjectTime) { AudioClock = decoupledClock }, new Container { RelativeSizeAxes = Axes.Both, Clock = offsetClock, - Children = new Drawable[] - { - RulesetContainer, - } + Child = RulesetContainer, }, hudOverlay = new HUDOverlay { Anchor = Anchor.Centre, Origin = Anchor.Centre }, + new BreakOverlay(beatmap.BeatmapInfo.LetterboxInBreaks) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Breaks = beatmap.Breaks, + Clock = decoupledClock + }, + new SkipButton(firstObjectTime) { AudioClock = decoupledClock }, } }, failOverlay = new FailOverlay diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 92bcaf90f0..19b32669f5 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -81,6 +81,8 @@ + + From be1e868a2a6570a8c33dc7643c89280e13fd2f9c Mon Sep 17 00:00:00 2001 From: Jorolf Date: Sun, 17 Sep 2017 22:39:34 +0200 Subject: [PATCH 0020/1263] add previews to osu!direct --- osu.Game/Overlays/Direct/DirectGridPanel.cs | 34 +++++++ osu.Game/Overlays/Direct/DirectListPanel.cs | 83 +++++++++++++--- osu.Game/Overlays/Direct/DirectPanel.cs | 7 ++ osu.Game/Overlays/Direct/PlayButton.cs | 105 ++++++++++++++++++++ osu.Game/Overlays/DirectOverlay.cs | 18 ++++ osu.Game/osu.Game.csproj | 1 + 6 files changed, 232 insertions(+), 16 deletions(-) create mode 100644 osu.Game/Overlays/Direct/PlayButton.cs diff --git a/osu.Game/Overlays/Direct/DirectGridPanel.cs b/osu.Game/Overlays/Direct/DirectGridPanel.cs index 3a9e75bd38..b638e21c4b 100644 --- a/osu.Game/Overlays/Direct/DirectGridPanel.cs +++ b/osu.Game/Overlays/Direct/DirectGridPanel.cs @@ -13,6 +13,8 @@ using osu.Game.Graphics.Sprites; using osu.Framework.Graphics.Shapes; using osu.Game.Beatmaps; using osu.Framework.Input; +using osu.Framework.Audio; +using osu.Framework.Configuration; namespace osu.Game.Overlays.Direct { @@ -22,6 +24,11 @@ namespace osu.Game.Overlays.Direct private const float vertical_padding = 5; private FillFlowContainer bottomPanel; + private PlayButton playButton; + private Box progressBar; + + protected override PlayButton PlayButton => playButton; + public override Bindable PreviewPlaying { get; } = new Bindable(); public DirectGridPanel(BeatmapSetInfo beatmap) : base(beatmap) { @@ -88,6 +95,15 @@ namespace osu.Game.Overlays.Direct { RelativeSizeAxes = Axes.Both, }, + progressBar = new Box + { + Origin = Anchor.BottomLeft, + RelativeSizeAxes = Axes.X, + BypassAutoSizeAxes = Axes.Both, + Size = new Vector2(0, 3), + Alpha = 0, + Colour = colours.Yellow, + }, new FillFlowContainer { RelativeSizeAxes = Axes.X, @@ -170,7 +186,25 @@ namespace osu.Game.Overlays.Direct new Statistic(FontAwesome.fa_heart, SetInfo.OnlineInfo?.FavouriteCount ?? 0), }, }, + playButton = new PlayButton(PreviewPlaying) + { + Margin = new MarginPadding { Top = 5, Left = 10 }, + Size = new Vector2(30), + Alpha = 0, + TrackURL = "https://b.ppy.sh/preview/" + SetInfo.OnlineBeatmapSetID + ".mp3", + }, }); + + PreviewPlaying.ValueChanged += newValue => playButton.FadeTo(newValue || IsHovered ? 1 : 0, 120, Easing.InOutQuint); + PreviewPlaying.ValueChanged += newValue => progressBar.FadeTo(newValue ? 1 : 0, 120, Easing.InOutQuint); + } + + protected override void Update() + { + base.Update(); + + if (PreviewPlaying && playButton.Track != null) + progressBar.Width = (float)(playButton.Track.CurrentTime / playButton.Track.Length); } protected override bool OnClick(InputState state) diff --git a/osu.Game/Overlays/Direct/DirectListPanel.cs b/osu.Game/Overlays/Direct/DirectListPanel.cs index b3502b0827..7f233f2113 100644 --- a/osu.Game/Overlays/Direct/DirectListPanel.cs +++ b/osu.Game/Overlays/Direct/DirectListPanel.cs @@ -15,6 +15,8 @@ using osu.Framework.Input; using osu.Framework.Graphics.Shapes; using osu.Game.Beatmaps; using osu.Game.Graphics.Containers; +using osu.Framework.Configuration; +using osu.Framework.Audio; namespace osu.Game.Overlays.Direct { @@ -30,8 +32,14 @@ namespace osu.Game.Overlays.Direct Height = height; } + private PlayButton playButton; + private Box progressBar; + + protected override PlayButton PlayButton => playButton; + public override Bindable PreviewPlaying { get; } = new Bindable(); + [BackgroundDependencyLoader] - private void load(LocalisationEngine localisation) + private void load(LocalisationEngine localisation, OsuColour colours) { Content.CornerRadius = 5; @@ -50,29 +58,51 @@ namespace osu.Game.Overlays.Direct { new FillFlowContainer { + Origin = Anchor.CentreLeft, + Anchor = Anchor.CentreLeft, AutoSizeAxes = Axes.Both, - Direction = FillDirection.Vertical, + Direction = FillDirection.Horizontal, + LayoutEasing = Easing.OutQuint, + LayoutDuration = 120, + Spacing = new Vector2(10, 0), Children = new Drawable[] { - new OsuSpriteText + playButton = new PlayButton(PreviewPlaying) { - Current = localisation.GetUnicodePreference(SetInfo.Metadata.TitleUnicode, SetInfo.Metadata.Title), - TextSize = 18, - Font = @"Exo2.0-BoldItalic", - }, - new OsuSpriteText - { - Current = localisation.GetUnicodePreference(SetInfo.Metadata.ArtistUnicode, SetInfo.Metadata.Artist), - Font = @"Exo2.0-BoldItalic", + Origin = Anchor.CentreLeft, + Anchor = Anchor.CentreLeft, + Size = new Vector2(height / 2), + FillMode = FillMode.Fit, + Alpha = 0, + TrackURL = "https://b.ppy.sh/preview/" + SetInfo.OnlineBeatmapSetID + ".mp3", }, new FillFlowContainer { - AutoSizeAxes = Axes.X, - Height = 20, - Margin = new MarginPadding { Top = vertical_padding, Bottom = vertical_padding }, - Children = GetDifficultyIcons(), + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Vertical, + Children = new Drawable[] + { + new OsuSpriteText + { + Current = localisation.GetUnicodePreference(SetInfo.Metadata.TitleUnicode, SetInfo.Metadata.Title), + TextSize = 18, + Font = @"Exo2.0-BoldItalic", + }, + new OsuSpriteText + { + Current = localisation.GetUnicodePreference(SetInfo.Metadata.ArtistUnicode, SetInfo.Metadata.Artist), + Font = @"Exo2.0-BoldItalic", + }, + new FillFlowContainer + { + AutoSizeAxes = Axes.X, + Height = 20, + Margin = new MarginPadding { Top = vertical_padding, Bottom = vertical_padding }, + Children = GetDifficultyIcons(), + }, + }, }, - }, + } }, new FillFlowContainer { @@ -128,7 +158,28 @@ namespace osu.Game.Overlays.Direct }, }, }, + progressBar = new Box + { + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + RelativeSizeAxes = Axes.X, + BypassAutoSizeAxes = Axes.Y, + Size = new Vector2(0, 3), + Alpha = 0, + Colour = colours.Yellow, + }, }); + + PreviewPlaying.ValueChanged += newValue => playButton.FadeTo(newValue || IsHovered ? 1 : 0, 120, Easing.InOutQuint); + PreviewPlaying.ValueChanged += newValue => progressBar.FadeTo(newValue ? 1 : 0, 120, Easing.InOutQuint); + } + + protected override void Update() + { + base.Update(); + + if (PreviewPlaying && playButton.Track != null) + progressBar.Width = (float)(playButton.Track.CurrentTime / playButton.Track.Length); } private class DownloadButton : OsuClickableContainer diff --git a/osu.Game/Overlays/Direct/DirectPanel.cs b/osu.Game/Overlays/Direct/DirectPanel.cs index 6f1f581d0b..24cd8dc54e 100644 --- a/osu.Game/Overlays/Direct/DirectPanel.cs +++ b/osu.Game/Overlays/Direct/DirectPanel.cs @@ -20,6 +20,7 @@ using osu.Game.Online.API; using osu.Framework.Logging; using osu.Game.Overlays.Notifications; using osu.Game.Online.API.Requests; +using osu.Framework.Configuration; namespace osu.Game.Overlays.Direct { @@ -38,6 +39,9 @@ namespace osu.Game.Overlays.Direct private BeatmapManager beatmaps; private NotificationOverlay notifications; + public abstract Bindable PreviewPlaying { get; } + protected abstract PlayButton PlayButton { get; } + protected override Container Content => content; protected DirectPanel(BeatmapSetInfo setInfo) @@ -106,6 +110,7 @@ namespace osu.Game.Overlays.Direct { content.TweenEdgeEffectTo(edgeEffectHovered, hover_transition_time, Easing.OutQuint); content.MoveToY(-4, hover_transition_time, Easing.OutQuint); + PlayButton.FadeIn(120, Easing.InOutQuint); return base.OnHover(state); } @@ -114,6 +119,8 @@ namespace osu.Game.Overlays.Direct { content.TweenEdgeEffectTo(edgeEffectNormal, hover_transition_time, Easing.OutQuint); content.MoveToY(0, hover_transition_time, Easing.OutQuint); + if (!PreviewPlaying) + PlayButton.FadeOut(120, Easing.InOutQuint); base.OnHoverLost(state); } diff --git a/osu.Game/Overlays/Direct/PlayButton.cs b/osu.Game/Overlays/Direct/PlayButton.cs new file mode 100644 index 0000000000..8cfe1a30cb --- /dev/null +++ b/osu.Game/Overlays/Direct/PlayButton.cs @@ -0,0 +1,105 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using OpenTK.Graphics; +using osu.Framework.Allocation; +using osu.Framework.Audio; +using osu.Framework.Audio.Track; +using osu.Framework.Configuration; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Input; +using osu.Game.Beatmaps; +using osu.Game.Graphics; +using System.Threading.Tasks; + +namespace osu.Game.Overlays.Direct +{ + public class PlayButton : Container + { + public string TrackURL; + + public Bindable Playing; + + public Track Track; + private Bindable gameBeatmap; + private AudioManager audio; + + private Color4 hoverColour; + private readonly SpriteIcon icon; + + public PlayButton(Bindable playing) + { + Playing = playing; + Add(icon = new SpriteIcon() + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + FillMode = FillMode.Fit, + RelativeSizeAxes = Axes.Both, + Icon = FontAwesome.fa_play, + }); + + Playing.ValueChanged += newValue => icon.Icon = newValue ? (Track == null ? FontAwesome.fa_spinner : FontAwesome.fa_pause) : FontAwesome.fa_play; + + Playing.ValueChanged += newValue => + { + if (newValue) + Track?.Start(); + else + Track?.Stop(); + }; + + Playing.ValueChanged += newValue => icon.FadeColour(newValue || IsHovered ? hoverColour : Color4.White, 120, Easing.InOutQuint); + } + + [BackgroundDependencyLoader] + private void load(OsuColour colour, OsuGameBase game, AudioManager audio) + { + hoverColour = colour.Yellow; + gameBeatmap = game.Beatmap; + this.audio = audio; + } + + private Task loadTask; + + protected override bool OnClick(InputState state) + { + gameBeatmap.Value.Track.Stop(); + + Playing.Value = !Playing.Value; + + if (loadTask == null) + { + icon.Spin(2000, RotationDirection.Clockwise); + + loadTask = Task.Run(() => + { + Track = audio.Track.Get(TrackURL); + Track.Looping = true; + if (Playing) + Track.Start(); + + icon.ClearTransforms(); + icon.Rotation = 0; + Playing.TriggerChange(); + }); + } + + return true; + } + + protected override bool OnHover(InputState state) + { + icon.FadeColour(hoverColour, 120, Easing.InOutQuint); + return base.OnHover(state); + } + + protected override void OnHoverLost(InputState state) + { + if(!Playing) + icon.FadeColour(Color4.White, 120, Easing.InOutQuint); + base.OnHoverLost(state); + } + } +} diff --git a/osu.Game/Overlays/DirectOverlay.cs b/osu.Game/Overlays/DirectOverlay.cs index 9c07e1087f..9bb2afe127 100644 --- a/osu.Game/Overlays/DirectOverlay.cs +++ b/osu.Game/Overlays/DirectOverlay.cs @@ -32,6 +32,7 @@ namespace osu.Game.Overlays private readonly FillFlowContainer resultCountsContainer; private readonly OsuSpriteText resultCountsText; private FillFlowContainer panels; + private DirectPanel playing; protected override Color4 BackgroundColour => OsuColour.FromHex(@"485e74"); protected override Color4 TrianglesColourLight => OsuColour.FromHex(@"465b71"); @@ -201,6 +202,12 @@ namespace osu.Game.Overlays panels.FadeOut(200); panels.Expire(); panels = null; + + if (playing != null) + { + playing.PreviewPlaying.Value = false; + playing = null; + } } if (BeatmapSets == null) return; @@ -223,6 +230,17 @@ namespace osu.Game.Overlays }) }; + foreach (DirectPanel panel in newPanels.Children) + panel.PreviewPlaying.ValueChanged += newValue => + { + if (newValue) + { + if (playing != null && playing != panel) + playing.PreviewPlaying.Value = false; + playing = panel; + } + }; + LoadComponentAsync(newPanels, p => { if (panels != null) ScrollFlow.Remove(panels); diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 65ec7d31b3..f75db14f52 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -105,6 +105,7 @@ + From 3e8ae93b340093b89724ecc34c95e2e0a9676929 Mon Sep 17 00:00:00 2001 From: Jorolf Date: Sun, 17 Sep 2017 22:54:23 +0200 Subject: [PATCH 0021/1263] appveyor --- osu.Game/Overlays/Direct/DirectGridPanel.cs | 3 +-- osu.Game/Overlays/Direct/DirectListPanel.cs | 3 +-- osu.Game/Overlays/Direct/PlayButton.cs | 6 +++--- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/osu.Game/Overlays/Direct/DirectGridPanel.cs b/osu.Game/Overlays/Direct/DirectGridPanel.cs index b638e21c4b..24ccd8b7eb 100644 --- a/osu.Game/Overlays/Direct/DirectGridPanel.cs +++ b/osu.Game/Overlays/Direct/DirectGridPanel.cs @@ -13,7 +13,6 @@ using osu.Game.Graphics.Sprites; using osu.Framework.Graphics.Shapes; using osu.Game.Beatmaps; using osu.Framework.Input; -using osu.Framework.Audio; using osu.Framework.Configuration; namespace osu.Game.Overlays.Direct @@ -191,7 +190,7 @@ namespace osu.Game.Overlays.Direct Margin = new MarginPadding { Top = 5, Left = 10 }, Size = new Vector2(30), Alpha = 0, - TrackURL = "https://b.ppy.sh/preview/" + SetInfo.OnlineBeatmapSetID + ".mp3", + TrackUrl = "https://b.ppy.sh/preview/" + SetInfo.OnlineBeatmapSetID + ".mp3", }, }); diff --git a/osu.Game/Overlays/Direct/DirectListPanel.cs b/osu.Game/Overlays/Direct/DirectListPanel.cs index 7f233f2113..7112e927bd 100644 --- a/osu.Game/Overlays/Direct/DirectListPanel.cs +++ b/osu.Game/Overlays/Direct/DirectListPanel.cs @@ -16,7 +16,6 @@ using osu.Framework.Graphics.Shapes; using osu.Game.Beatmaps; using osu.Game.Graphics.Containers; using osu.Framework.Configuration; -using osu.Framework.Audio; namespace osu.Game.Overlays.Direct { @@ -74,7 +73,7 @@ namespace osu.Game.Overlays.Direct Size = new Vector2(height / 2), FillMode = FillMode.Fit, Alpha = 0, - TrackURL = "https://b.ppy.sh/preview/" + SetInfo.OnlineBeatmapSetID + ".mp3", + TrackUrl = "https://b.ppy.sh/preview/" + SetInfo.OnlineBeatmapSetID + ".mp3", }, new FillFlowContainer { diff --git a/osu.Game/Overlays/Direct/PlayButton.cs b/osu.Game/Overlays/Direct/PlayButton.cs index 8cfe1a30cb..b0d011a81c 100644 --- a/osu.Game/Overlays/Direct/PlayButton.cs +++ b/osu.Game/Overlays/Direct/PlayButton.cs @@ -17,7 +17,7 @@ namespace osu.Game.Overlays.Direct { public class PlayButton : Container { - public string TrackURL; + public string TrackUrl; public Bindable Playing; @@ -31,7 +31,7 @@ namespace osu.Game.Overlays.Direct public PlayButton(Bindable playing) { Playing = playing; - Add(icon = new SpriteIcon() + Add(icon = new SpriteIcon { Anchor = Anchor.Centre, Origin = Anchor.Centre, @@ -75,7 +75,7 @@ namespace osu.Game.Overlays.Direct loadTask = Task.Run(() => { - Track = audio.Track.Get(TrackURL); + Track = audio.Track.Get(TrackUrl); Track.Looping = true; if (Playing) Track.Start(); From c59d398aa527ae0beeacab2f44351fa9ec8477f6 Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Tue, 19 Sep 2017 17:26:17 +0300 Subject: [PATCH 0022/1263] Fix includes --- osu.Game/osu.Game.csproj | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 9301002958..5af2e18753 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -277,22 +277,6 @@ - - - - - - - - - - - - - - - - From 85b990c088c0eada760f850ef9706b72ad13def9 Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Tue, 19 Sep 2017 17:28:10 +0300 Subject: [PATCH 0023/1263] Remove useless file --- osu.Desktop.Tests/osu.Desktop.Tests.csproj | 179 --------------------- 1 file changed, 179 deletions(-) delete mode 100644 osu.Desktop.Tests/osu.Desktop.Tests.csproj diff --git a/osu.Desktop.Tests/osu.Desktop.Tests.csproj b/osu.Desktop.Tests/osu.Desktop.Tests.csproj deleted file mode 100644 index 5882578b79..0000000000 --- a/osu.Desktop.Tests/osu.Desktop.Tests.csproj +++ /dev/null @@ -1,179 +0,0 @@ - - - - - Debug - AnyCPU - {230AC4F3-7783-49FB-9AEC-B83CDA3B9F3D} - Library - Properties - osu.Desktop.Tests - osu.Desktop.Tests - v4.6.1 - 512 - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - false - 6 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - false - - - - - $(SolutionDir)\packages\Newtonsoft.Json.10.0.3\lib\net45\Newtonsoft.Json.dll - True - - - $(SolutionDir)\packages\NUnit.3.8.1\lib\net45\nunit.framework.dll - True - - - $(SolutionDir)\packages\OpenTK.3.0.0-git00009\lib\net20\OpenTK.dll - True - - - False - $(SolutionDir)\packages\SQLite.Net.Core-PCL.3.1.1\lib\portable-win8+net45+wp8+wpa81+MonoAndroid1+MonoTouch1\SQLite.Net.dll - - - - $(SolutionDir)\packages\SQLiteNetExtensions.1.3.0\lib\portable-net45+netcore45+wpa81+wp8+MonoAndroid1+MonoTouch1\SQLiteNetExtensions.dll - - - $(SolutionDir)\packages\SQLite.Net-PCL.3.1.1\lib\net4\SQLite.Net.Platform.Win32.dll - - - $(SolutionDir)\packages\SQLite.Net-PCL.3.1.1\lib\net40\SQLite.Net.Platform.Generic.dll - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {65DC628F-A640-4111-AB35-3A5652BC1E17} - osu.Framework.Desktop - - - {007b2356-ab6f-4bd9-96d5-116fc2dce69a} - osu.Framework.Testing - - - {C76BF5B3-985E-4D39-95FE-97C9C879B83A} - osu.Framework - - - {d9a367c9-4c1a-489f-9b05-a0cea2b53b58} - osu.Game.Resources - - - {58F6C80C-1253-4A0E-A465-B8C85EBEADF3} - osu.Game.Rulesets.Catch - - - {48F4582B-7687-4621-9CBE-5C24197CB536} - osu.Game.Rulesets.Mania - - - {C92A607B-1FDD-4954-9F92-03FF547D9080} - osu.Game.Rulesets.Osu - - - {F167E17A-7DE6-4AF5-B920-A5112296C695} - osu.Game.Rulesets.Taiko - - - {0D3FBF8A-7464-4CF7-8C90-3E7886DF2D4D} - osu.Game - - - - - osu.licenseheader - - - - - - - - - - - - - - \ No newline at end of file From 4cf88c72bfece5cfca8dd9b728fd3aa1fd7ffa65 Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Tue, 19 Sep 2017 17:37:34 +0300 Subject: [PATCH 0024/1263] Move testcase to the correct project --- .../Tests}/Visual/TestCaseBreakOverlay.cs | 2 +- osu.Game/osu.Game.csproj | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) rename {osu.Desktop.Tests => osu.Game/Tests}/Visual/TestCaseBreakOverlay.cs (95%) diff --git a/osu.Desktop.Tests/Visual/TestCaseBreakOverlay.cs b/osu.Game/Tests/Visual/TestCaseBreakOverlay.cs similarity index 95% rename from osu.Desktop.Tests/Visual/TestCaseBreakOverlay.cs rename to osu.Game/Tests/Visual/TestCaseBreakOverlay.cs index 2c77b1ca39..5bf558f79c 100644 --- a/osu.Desktop.Tests/Visual/TestCaseBreakOverlay.cs +++ b/osu.Game/Tests/Visual/TestCaseBreakOverlay.cs @@ -9,7 +9,7 @@ using osu.Game.Beatmaps.Timing; using osu.Game.Screens.Play; using System.Collections.Generic; -namespace osu.Desktop.Tests.Visual +namespace osu.Game.Tests.Visual { internal class TestCaseBreakOverlay : OsuTestCase { diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 5af2e18753..fef9683cc8 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -728,6 +728,7 @@ + From 0f04d8c6a7dd2584542eb40e538636e96f0f582a Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Wed, 20 Sep 2017 15:58:28 +0300 Subject: [PATCH 0025/1263] Add remaining time container --- osu.Game/Screens/Play/BreakOverlay.cs | 38 +++++++++++++++---- osu.Game/Tests/Visual/TestCaseBreakOverlay.cs | 10 +---- 2 files changed, 32 insertions(+), 16 deletions(-) diff --git a/osu.Game/Screens/Play/BreakOverlay.cs b/osu.Game/Screens/Play/BreakOverlay.cs index 2cbf6fd3c8..5162aa8007 100644 --- a/osu.Game/Screens/Play/BreakOverlay.cs +++ b/osu.Game/Screens/Play/BreakOverlay.cs @@ -5,24 +5,45 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics; using System.Collections.Generic; using osu.Game.Beatmaps.Timing; +using OpenTK; +using osu.Framework.Graphics.Shapes; +using OpenTK.Graphics; namespace osu.Game.Screens.Play { - public class BreakOverlay : VisibilityContainer + public class BreakOverlay : Container { private const double fade_duration = BreakPeriod.MIN_BREAK_DURATION / 2; + private const int remaining_time_container_max_size = 500; public List Breaks; private readonly bool letterboxing; private readonly LetterboxOverlay letterboxOverlay; + private readonly Container remainingTimeContainer; public BreakOverlay(bool letterboxing) { this.letterboxing = letterboxing; RelativeSizeAxes = Axes.Both; - Child = letterboxOverlay = new LetterboxOverlay(); + Children = new Drawable[] + { + letterboxOverlay = new LetterboxOverlay(), + remainingTimeContainer = new Container + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Size = new Vector2(0, 8), + CornerRadius = 4, + Masking = true, + Child = new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.White, + } + } + }; } protected override void LoadComplete() @@ -41,22 +62,25 @@ namespace osu.Game.Screens.Play { using (BeginAbsoluteSequence(b.StartTime, true)) { - Show(); + onBreakIn(b); using (BeginDelayedSequence(b.Duration, true)) - Hide(); + onBreakOut(); } } } } } - protected override void PopIn() + private void onBreakIn(BreakPeriod b) { - if (letterboxing) letterboxOverlay.FadeIn(fade_duration); + if (letterboxing) + letterboxOverlay.FadeIn(fade_duration); + + remainingTimeContainer.ResizeWidthTo(remaining_time_container_max_size, fade_duration, Easing.OutQuint).Then().ResizeWidthTo(0, b.Duration); } - protected override void PopOut() + private void onBreakOut() { if (letterboxing) letterboxOverlay.FadeOut(fade_duration); } diff --git a/osu.Game/Tests/Visual/TestCaseBreakOverlay.cs b/osu.Game/Tests/Visual/TestCaseBreakOverlay.cs index 5bf558f79c..1f59a96de2 100644 --- a/osu.Game/Tests/Visual/TestCaseBreakOverlay.cs +++ b/osu.Game/Tests/Visual/TestCaseBreakOverlay.cs @@ -21,15 +21,7 @@ namespace osu.Game.Tests.Visual { Clock = new FramedClock(); - Children = new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = Color4.White, - }, - breakOverlay = new BreakOverlay(true) - }; + Child = breakOverlay = new BreakOverlay(true); AddStep("Add 2s break", () => startBreak(2000)); AddStep("Add 5s break", () => startBreak(5000)); From eb93706c26baec129a0f33d5833e30611ac636aa Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Wed, 20 Sep 2017 16:03:31 +0300 Subject: [PATCH 0026/1263] Remove useless usings --- osu.Game/Tests/Visual/TestCaseBreakOverlay.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/osu.Game/Tests/Visual/TestCaseBreakOverlay.cs b/osu.Game/Tests/Visual/TestCaseBreakOverlay.cs index 1f59a96de2..2f7a4a2425 100644 --- a/osu.Game/Tests/Visual/TestCaseBreakOverlay.cs +++ b/osu.Game/Tests/Visual/TestCaseBreakOverlay.cs @@ -1,9 +1,6 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using OpenTK.Graphics; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Shapes; using osu.Framework.Timing; using osu.Game.Beatmaps.Timing; using osu.Game.Screens.Play; From 8d7db52200ec08817b46cb70596e5d80f085fd74 Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Wed, 20 Sep 2017 19:45:38 +0300 Subject: [PATCH 0027/1263] Add remaining time counter --- osu.Game/Screens/Play/BreakOverlay.cs | 86 +++++++++++++++++++++++++-- 1 file changed, 82 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Play/BreakOverlay.cs b/osu.Game/Screens/Play/BreakOverlay.cs index 5162aa8007..fe7edf36ff 100644 --- a/osu.Game/Screens/Play/BreakOverlay.cs +++ b/osu.Game/Screens/Play/BreakOverlay.cs @@ -8,6 +8,9 @@ using osu.Game.Beatmaps.Timing; using OpenTK; using osu.Framework.Graphics.Shapes; using OpenTK.Graphics; +using osu.Game.Graphics.Sprites; +using System; +using osu.Framework.Timing; namespace osu.Game.Screens.Play { @@ -18,9 +21,19 @@ namespace osu.Game.Screens.Play public List Breaks; + public override IFrameBasedClock Clock + { + set + { + base.Clock = remainingTimeCounter.Clock = value; + } + get { return base.Clock; } + } + private readonly bool letterboxing; private readonly LetterboxOverlay letterboxOverlay; - private readonly Container remainingTimeContainer; + private readonly Container remainingTimeBox; + private readonly RemainingTimeCounter remainingTimeCounter; public BreakOverlay(bool letterboxing) { @@ -30,7 +43,7 @@ namespace osu.Game.Screens.Play Children = new Drawable[] { letterboxOverlay = new LetterboxOverlay(), - remainingTimeContainer = new Container + remainingTimeBox = new Container { Anchor = Anchor.Centre, Origin = Anchor.Centre, @@ -42,6 +55,12 @@ namespace osu.Game.Screens.Play RelativeSizeAxes = Axes.Both, Colour = Color4.White, } + }, + remainingTimeCounter = new RemainingTimeCounter + { + Anchor = Anchor.Centre, + Origin = Anchor.BottomCentre, + Margin = new MarginPadding { Bottom = 25 }, } }; } @@ -77,12 +96,71 @@ namespace osu.Game.Screens.Play if (letterboxing) letterboxOverlay.FadeIn(fade_duration); - remainingTimeContainer.ResizeWidthTo(remaining_time_container_max_size, fade_duration, Easing.OutQuint).Then().ResizeWidthTo(0, b.Duration); + remainingTimeBox + .ResizeWidthTo(remaining_time_container_max_size, fade_duration, Easing.OutQuint) + .Then() + .ResizeWidthTo(0, b.Duration); + + Scheduler.AddDelayed(() => remainingTimeCounter.StartCounting(b.EndTime), b.StartTime - Clock.CurrentTime); + remainingTimeCounter.FadeIn(fade_duration); } private void onBreakOut() { - if (letterboxing) letterboxOverlay.FadeOut(fade_duration); + if (letterboxing) + letterboxOverlay.FadeOut(fade_duration); + + remainingTimeCounter.FadeOut(fade_duration); + } + + private class RemainingTimeCounter : Container + { + private readonly OsuSpriteText counter; + + private int? previousSecond; + + private double remainingTime; + + private bool isCounting; + + public RemainingTimeCounter() + { + AutoSizeAxes = Axes.Both; + Alpha = 0; + Child = counter = new OsuSpriteText + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + TextSize = 35, + Font = "Venera", + }; + } + + public void StartCounting(double remainingTime) + { + this.remainingTime = remainingTime; + isCounting = true; + } + + protected override void Update() + { + base.Update(); + + if (isCounting) + { + var currentTime = Clock.CurrentTime; + if (currentTime < remainingTime) + { + int currentSecond = (int)Math.Floor((remainingTime - Clock.CurrentTime) / 1000.0) + 1; + if (currentSecond != previousSecond) + { + counter.Text = currentSecond.ToString(); + previousSecond = currentSecond; + } + } + else isCounting = false; + } + } } } } From 4699a4460821d8c318de574b395abf77a35d136e Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Wed, 20 Sep 2017 20:50:14 +0300 Subject: [PATCH 0028/1263] Add info container --- osu.Game/Screens/Play/BreakOverlay.cs | 100 +++++++++++++++++++++++--- 1 file changed, 92 insertions(+), 8 deletions(-) diff --git a/osu.Game/Screens/Play/BreakOverlay.cs b/osu.Game/Screens/Play/BreakOverlay.cs index fe7edf36ff..87dd86b90c 100644 --- a/osu.Game/Screens/Play/BreakOverlay.cs +++ b/osu.Game/Screens/Play/BreakOverlay.cs @@ -11,13 +11,16 @@ using OpenTK.Graphics; using osu.Game.Graphics.Sprites; using System; using osu.Framework.Timing; +using osu.Framework.Allocation; +using osu.Game.Graphics; namespace osu.Game.Screens.Play { public class BreakOverlay : Container { private const double fade_duration = BreakPeriod.MIN_BREAK_DURATION / 2; - private const int remaining_time_container_max_size = 500; + private const int remaining_time_container_max_size = 450; + private const int element_margin = 25; public List Breaks; @@ -34,6 +37,7 @@ namespace osu.Game.Screens.Play private readonly LetterboxOverlay letterboxOverlay; private readonly Container remainingTimeBox; private readonly RemainingTimeCounter remainingTimeCounter; + private readonly InfoContainer info; public BreakOverlay(bool letterboxing) { @@ -50,17 +54,19 @@ namespace osu.Game.Screens.Play Size = new Vector2(0, 8), CornerRadius = 4, Masking = true, - Child = new Box - { - RelativeSizeAxes = Axes.Both, - Colour = Color4.White, - } + Child = new Box { RelativeSizeAxes = Axes.Both } }, remainingTimeCounter = new RemainingTimeCounter { Anchor = Anchor.Centre, Origin = Anchor.BottomCentre, - Margin = new MarginPadding { Bottom = 25 }, + Margin = new MarginPadding { Bottom = element_margin }, + }, + info = new InfoContainer + { + Anchor = Anchor.Centre, + Origin = Anchor.TopCentre, + Margin = new MarginPadding { Top = element_margin }, } }; } @@ -103,6 +109,8 @@ namespace osu.Game.Screens.Play Scheduler.AddDelayed(() => remainingTimeCounter.StartCounting(b.EndTime), b.StartTime - Clock.CurrentTime); remainingTimeCounter.FadeIn(fade_duration); + + info.FadeIn(fade_duration); } private void onBreakOut() @@ -111,6 +119,82 @@ namespace osu.Game.Screens.Play letterboxOverlay.FadeOut(fade_duration); remainingTimeCounter.FadeOut(fade_duration); + info.FadeOut(fade_duration); + } + + private class InfoContainer : FillFlowContainer + { + public InfoContainer() + { + AutoSizeAxes = Axes.Both; + Alpha = 0; + Direction = FillDirection.Vertical; + Spacing = new Vector2(5); + Children = new Drawable[] + { + new OsuSpriteText + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Text = @"current progress".ToUpper(), + TextSize = 15, + Font = "Exo2.0-Black", + }, + new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Origin = Anchor.TopCentre, + Anchor = Anchor.TopCentre, + Direction = FillDirection.Vertical, + Children = new InfoLine[] + { + new InfoLine(@"Accuracy", @"88.54%"), + new InfoLine(@"Rank", @"#6584"), + new InfoLine(@"Grade", @"A"), + }, + } + }; + } + + private class InfoLine : Container + { + private const int margin = 2; + + private readonly OsuSpriteText text; + private readonly OsuSpriteText valueText; + + public InfoLine(string name, string value) + { + AutoSizeAxes = Axes.Y; + Children = new Drawable[] + { + text = new OsuSpriteText + { + Anchor = Anchor.Centre, + Origin = Anchor.CentreRight, + Text = name, + TextSize = 17, + Margin = new MarginPadding { Right = margin } + }, + valueText = new OsuSpriteText + { + Anchor = Anchor.Centre, + Origin = Anchor.CentreLeft, + Text = value, + TextSize = 17, + Font = "Exo2.0-Bold", + Margin = new MarginPadding { Left = margin } + } + }; + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + text.Colour = colours.Yellow; + valueText.Colour = colours.YellowLight; + } + } } private class RemainingTimeCounter : Container @@ -131,7 +215,7 @@ namespace osu.Game.Screens.Play { Anchor = Anchor.Centre, Origin = Anchor.Centre, - TextSize = 35, + TextSize = 33, Font = "Venera", }; } From 581689a84d37ef44d26a91590adb45faf95e71ff Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Wed, 20 Sep 2017 20:58:20 +0300 Subject: [PATCH 0029/1263] CI fixes --- osu.Game/Screens/Play/BreakOverlay.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game/Screens/Play/BreakOverlay.cs b/osu.Game/Screens/Play/BreakOverlay.cs index 87dd86b90c..da7ba12a6e 100644 --- a/osu.Game/Screens/Play/BreakOverlay.cs +++ b/osu.Game/Screens/Play/BreakOverlay.cs @@ -7,7 +7,6 @@ using System.Collections.Generic; using osu.Game.Beatmaps.Timing; using OpenTK; using osu.Framework.Graphics.Shapes; -using OpenTK.Graphics; using osu.Game.Graphics.Sprites; using System; using osu.Framework.Timing; @@ -146,7 +145,7 @@ namespace osu.Game.Screens.Play Origin = Anchor.TopCentre, Anchor = Anchor.TopCentre, Direction = FillDirection.Vertical, - Children = new InfoLine[] + Children = new [] { new InfoLine(@"Accuracy", @"88.54%"), new InfoLine(@"Rank", @"#6584"), From 18a714df74a8e8ef75cf50b8d64a292a269626c1 Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Wed, 20 Sep 2017 22:33:07 +0300 Subject: [PATCH 0030/1263] Move every class to it's own file --- osu.Game/Screens/Play/BreakOverlay.cs | 249 ------------------ .../Play/BreaksOverlay/BreakOverlay.cs | 120 +++++++++ .../Play/BreaksOverlay/InfoContainer.cs | 87 ++++++ .../BreaksOverlay/RemainingTimeCounter.cs | 60 +++++ osu.Game/Screens/Play/Player.cs | 1 + osu.Game/Tests/Visual/TestCaseBreakOverlay.cs | 4 +- osu.Game/osu.Game.csproj | 4 +- 7 files changed, 274 insertions(+), 251 deletions(-) delete mode 100644 osu.Game/Screens/Play/BreakOverlay.cs create mode 100644 osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs create mode 100644 osu.Game/Screens/Play/BreaksOverlay/InfoContainer.cs create mode 100644 osu.Game/Screens/Play/BreaksOverlay/RemainingTimeCounter.cs diff --git a/osu.Game/Screens/Play/BreakOverlay.cs b/osu.Game/Screens/Play/BreakOverlay.cs deleted file mode 100644 index da7ba12a6e..0000000000 --- a/osu.Game/Screens/Play/BreakOverlay.cs +++ /dev/null @@ -1,249 +0,0 @@ -// Copyright (c) 2007-2017 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics; -using System.Collections.Generic; -using osu.Game.Beatmaps.Timing; -using OpenTK; -using osu.Framework.Graphics.Shapes; -using osu.Game.Graphics.Sprites; -using System; -using osu.Framework.Timing; -using osu.Framework.Allocation; -using osu.Game.Graphics; - -namespace osu.Game.Screens.Play -{ - public class BreakOverlay : Container - { - private const double fade_duration = BreakPeriod.MIN_BREAK_DURATION / 2; - private const int remaining_time_container_max_size = 450; - private const int element_margin = 25; - - public List Breaks; - - public override IFrameBasedClock Clock - { - set - { - base.Clock = remainingTimeCounter.Clock = value; - } - get { return base.Clock; } - } - - private readonly bool letterboxing; - private readonly LetterboxOverlay letterboxOverlay; - private readonly Container remainingTimeBox; - private readonly RemainingTimeCounter remainingTimeCounter; - private readonly InfoContainer info; - - public BreakOverlay(bool letterboxing) - { - this.letterboxing = letterboxing; - - RelativeSizeAxes = Axes.Both; - Children = new Drawable[] - { - letterboxOverlay = new LetterboxOverlay(), - remainingTimeBox = new Container - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Size = new Vector2(0, 8), - CornerRadius = 4, - Masking = true, - Child = new Box { RelativeSizeAxes = Axes.Both } - }, - remainingTimeCounter = new RemainingTimeCounter - { - Anchor = Anchor.Centre, - Origin = Anchor.BottomCentre, - Margin = new MarginPadding { Bottom = element_margin }, - }, - info = new InfoContainer - { - Anchor = Anchor.Centre, - Origin = Anchor.TopCentre, - Margin = new MarginPadding { Top = element_margin }, - } - }; - } - - protected override void LoadComplete() - { - base.LoadComplete(); - InitializeBreaks(); - } - - public void InitializeBreaks() - { - if (Breaks != null) - { - foreach (var b in Breaks) - { - if (b.HasEffect) - { - using (BeginAbsoluteSequence(b.StartTime, true)) - { - onBreakIn(b); - - using (BeginDelayedSequence(b.Duration, true)) - onBreakOut(); - } - } - } - } - } - - private void onBreakIn(BreakPeriod b) - { - if (letterboxing) - letterboxOverlay.FadeIn(fade_duration); - - remainingTimeBox - .ResizeWidthTo(remaining_time_container_max_size, fade_duration, Easing.OutQuint) - .Then() - .ResizeWidthTo(0, b.Duration); - - Scheduler.AddDelayed(() => remainingTimeCounter.StartCounting(b.EndTime), b.StartTime - Clock.CurrentTime); - remainingTimeCounter.FadeIn(fade_duration); - - info.FadeIn(fade_duration); - } - - private void onBreakOut() - { - if (letterboxing) - letterboxOverlay.FadeOut(fade_duration); - - remainingTimeCounter.FadeOut(fade_duration); - info.FadeOut(fade_duration); - } - - private class InfoContainer : FillFlowContainer - { - public InfoContainer() - { - AutoSizeAxes = Axes.Both; - Alpha = 0; - Direction = FillDirection.Vertical; - Spacing = new Vector2(5); - Children = new Drawable[] - { - new OsuSpriteText - { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - Text = @"current progress".ToUpper(), - TextSize = 15, - Font = "Exo2.0-Black", - }, - new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Origin = Anchor.TopCentre, - Anchor = Anchor.TopCentre, - Direction = FillDirection.Vertical, - Children = new [] - { - new InfoLine(@"Accuracy", @"88.54%"), - new InfoLine(@"Rank", @"#6584"), - new InfoLine(@"Grade", @"A"), - }, - } - }; - } - - private class InfoLine : Container - { - private const int margin = 2; - - private readonly OsuSpriteText text; - private readonly OsuSpriteText valueText; - - public InfoLine(string name, string value) - { - AutoSizeAxes = Axes.Y; - Children = new Drawable[] - { - text = new OsuSpriteText - { - Anchor = Anchor.Centre, - Origin = Anchor.CentreRight, - Text = name, - TextSize = 17, - Margin = new MarginPadding { Right = margin } - }, - valueText = new OsuSpriteText - { - Anchor = Anchor.Centre, - Origin = Anchor.CentreLeft, - Text = value, - TextSize = 17, - Font = "Exo2.0-Bold", - Margin = new MarginPadding { Left = margin } - } - }; - } - - [BackgroundDependencyLoader] - private void load(OsuColour colours) - { - text.Colour = colours.Yellow; - valueText.Colour = colours.YellowLight; - } - } - } - - private class RemainingTimeCounter : Container - { - private readonly OsuSpriteText counter; - - private int? previousSecond; - - private double remainingTime; - - private bool isCounting; - - public RemainingTimeCounter() - { - AutoSizeAxes = Axes.Both; - Alpha = 0; - Child = counter = new OsuSpriteText - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - TextSize = 33, - Font = "Venera", - }; - } - - public void StartCounting(double remainingTime) - { - this.remainingTime = remainingTime; - isCounting = true; - } - - protected override void Update() - { - base.Update(); - - if (isCounting) - { - var currentTime = Clock.CurrentTime; - if (currentTime < remainingTime) - { - int currentSecond = (int)Math.Floor((remainingTime - Clock.CurrentTime) / 1000.0) + 1; - if (currentSecond != previousSecond) - { - counter.Text = currentSecond.ToString(); - previousSecond = currentSecond; - } - } - else isCounting = false; - } - } - } - } -} diff --git a/osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs b/osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs new file mode 100644 index 0000000000..aec96c10ac --- /dev/null +++ b/osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs @@ -0,0 +1,120 @@ +// 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.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Timing; +using osu.Game.Beatmaps.Timing; +using System.Collections.Generic; + +namespace osu.Game.Screens.Play.BreaksOverlay +{ + public class BreakOverlay : Container + { + private const double fade_duration = BreakPeriod.MIN_BREAK_DURATION / 2; + private const int remaining_time_container_max_size = 450; + private const int element_margin = 25; + + public List Breaks; + + public override IFrameBasedClock Clock + { + set + { + base.Clock = remainingTimeCounter.Clock = value; + } + get { return base.Clock; } + } + + private readonly bool letterboxing; + private readonly LetterboxOverlay letterboxOverlay; + private readonly Container remainingTimeBox; + private readonly RemainingTimeCounter remainingTimeCounter; + private readonly InfoContainer info; + + public BreakOverlay(bool letterboxing) + { + this.letterboxing = letterboxing; + + RelativeSizeAxes = Axes.Both; + Children = new Drawable[] + { + letterboxOverlay = new LetterboxOverlay(), + remainingTimeBox = new Container + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Size = new Vector2(0, 8), + CornerRadius = 4, + Masking = true, + Child = new Box { RelativeSizeAxes = Axes.Both } + }, + remainingTimeCounter = new RemainingTimeCounter + { + Anchor = Anchor.Centre, + Origin = Anchor.BottomCentre, + Margin = new MarginPadding { Bottom = element_margin }, + }, + info = new InfoContainer + { + Anchor = Anchor.Centre, + Origin = Anchor.TopCentre, + Margin = new MarginPadding { Top = element_margin }, + } + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + InitializeBreaks(); + } + + public void InitializeBreaks() + { + if (Breaks != null) + { + foreach (var b in Breaks) + { + if (b.HasEffect) + { + using (BeginAbsoluteSequence(b.StartTime, true)) + { + onBreakIn(b); + + using (BeginDelayedSequence(b.Duration, true)) + onBreakOut(); + } + } + } + } + } + + private void onBreakIn(BreakPeriod b) + { + if (letterboxing) + letterboxOverlay.FadeIn(fade_duration); + + remainingTimeBox + .ResizeWidthTo(remaining_time_container_max_size, fade_duration, Easing.OutQuint) + .Then() + .ResizeWidthTo(0, b.Duration); + + Scheduler.AddDelayed(() => remainingTimeCounter.StartCounting(b.EndTime), b.StartTime - Clock.CurrentTime); + remainingTimeCounter.FadeIn(fade_duration); + + info.FadeIn(fade_duration); + } + + private void onBreakOut() + { + if (letterboxing) + letterboxOverlay.FadeOut(fade_duration); + + remainingTimeCounter.FadeOut(fade_duration); + info.FadeOut(fade_duration); + } + } +} diff --git a/osu.Game/Screens/Play/BreaksOverlay/InfoContainer.cs b/osu.Game/Screens/Play/BreaksOverlay/InfoContainer.cs new file mode 100644 index 0000000000..75fcfcba0e --- /dev/null +++ b/osu.Game/Screens/Play/BreaksOverlay/InfoContainer.cs @@ -0,0 +1,87 @@ +// 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.Game.Graphics; +using osu.Game.Graphics.Sprites; + +namespace osu.Game.Screens.Play.BreaksOverlay +{ + public class InfoContainer : FillFlowContainer + { + public InfoContainer() + { + AutoSizeAxes = Axes.Both; + Alpha = 0; + Direction = FillDirection.Vertical; + Spacing = new Vector2(5); + Children = new Drawable[] + { + new OsuSpriteText + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Text = @"current progress".ToUpper(), + TextSize = 15, + Font = "Exo2.0-Black", + }, + new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Origin = Anchor.TopCentre, + Anchor = Anchor.TopCentre, + Direction = FillDirection.Vertical, + Children = new [] + { + new InfoLine(@"Accuracy", @"-"), + new InfoLine(@"Rank", @"-"), + new InfoLine(@"Grade", @"-"), + }, + } + }; + } + + private class InfoLine : Container + { + private const int margin = 2; + + private readonly OsuSpriteText text; + private readonly OsuSpriteText valueText; + + public InfoLine(string name, string value) + { + AutoSizeAxes = Axes.Y; + Children = new Drawable[] + { + text = new OsuSpriteText + { + Anchor = Anchor.Centre, + Origin = Anchor.CentreRight, + Text = name, + TextSize = 17, + Margin = new MarginPadding { Right = margin } + }, + valueText = new OsuSpriteText + { + Anchor = Anchor.Centre, + Origin = Anchor.CentreLeft, + Text = value, + TextSize = 17, + Font = "Exo2.0-Bold", + Margin = new MarginPadding { Left = margin } + } + }; + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + text.Colour = colours.Yellow; + valueText.Colour = colours.YellowLight; + } + } + } +} diff --git a/osu.Game/Screens/Play/BreaksOverlay/RemainingTimeCounter.cs b/osu.Game/Screens/Play/BreaksOverlay/RemainingTimeCounter.cs new file mode 100644 index 0000000000..fbf3e10688 --- /dev/null +++ b/osu.Game/Screens/Play/BreaksOverlay/RemainingTimeCounter.cs @@ -0,0 +1,60 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Graphics.Containers; +using osu.Game.Graphics.Sprites; +using osu.Framework.Graphics; +using System; + +namespace osu.Game.Screens.Play.BreaksOverlay +{ + public class RemainingTimeCounter : Container + { + private readonly OsuSpriteText counter; + + private int? previousSecond; + + private double remainingTime; + + private bool isCounting; + + public RemainingTimeCounter() + { + AutoSizeAxes = Axes.Both; + Alpha = 0; + Child = counter = new OsuSpriteText + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + TextSize = 33, + Font = "Venera", + }; + } + + public void StartCounting(double remainingTime) + { + this.remainingTime = remainingTime; + isCounting = true; + } + + protected override void Update() + { + base.Update(); + + if (isCounting) + { + var currentTime = Clock.CurrentTime; + if (currentTime < remainingTime) + { + int currentSecond = (int)Math.Floor((remainingTime - Clock.CurrentTime) / 1000.0) + 1; + if (currentSecond != previousSecond) + { + counter.Text = currentSecond.ToString(); + previousSecond = currentSecond; + } + } + else isCounting = false; + } + } + } +} diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index f7b5da97e9..86aa00875c 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -24,6 +24,7 @@ using osu.Game.Screens.Ranking; using osu.Framework.Audio.Sample; using osu.Game.Beatmaps; using osu.Game.Online.API; +using osu.Game.Screens.Play.BreaksOverlay; namespace osu.Game.Screens.Play { diff --git a/osu.Game/Tests/Visual/TestCaseBreakOverlay.cs b/osu.Game/Tests/Visual/TestCaseBreakOverlay.cs index 2f7a4a2425..055a2bc5c4 100644 --- a/osu.Game/Tests/Visual/TestCaseBreakOverlay.cs +++ b/osu.Game/Tests/Visual/TestCaseBreakOverlay.cs @@ -3,7 +3,7 @@ using osu.Framework.Timing; using osu.Game.Beatmaps.Timing; -using osu.Game.Screens.Play; +using osu.Game.Screens.Play.BreaksOverlay; using System.Collections.Generic; namespace osu.Game.Tests.Visual @@ -22,6 +22,8 @@ namespace osu.Game.Tests.Visual AddStep("Add 2s break", () => startBreak(2000)); AddStep("Add 5s break", () => startBreak(5000)); + AddStep("Add 10s break", () => startBreak(10000)); + AddStep("Add 15s break", () => startBreak(15000)); AddStep("Add 2 breaks (2s each)", startMultipleBreaks); } diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index fef9683cc8..406867c656 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -275,7 +275,9 @@ - + + + From c79568135a44d1889c6a2f204bf6f12589049427 Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Thu, 21 Sep 2017 01:44:30 +0300 Subject: [PATCH 0031/1263] Add arrows --- .../Screens/Play/BreaksOverlay/BlurredIcon.cs | 40 ++++++++++ .../Play/BreaksOverlay/BreakOverlay.cs | 60 +++++++++++++-- .../Screens/Play/BreaksOverlay/GlowingIcon.cs | 74 +++++++++++++++++++ .../{ => BreaksOverlay}/LetterboxOverlay.cs | 4 +- osu.Game/osu.Game.csproj | 4 +- 5 files changed, 173 insertions(+), 9 deletions(-) create mode 100644 osu.Game/Screens/Play/BreaksOverlay/BlurredIcon.cs create mode 100644 osu.Game/Screens/Play/BreaksOverlay/GlowingIcon.cs rename osu.Game/Screens/Play/{ => BreaksOverlay}/LetterboxOverlay.cs (95%) diff --git a/osu.Game/Screens/Play/BreaksOverlay/BlurredIcon.cs b/osu.Game/Screens/Play/BreaksOverlay/BlurredIcon.cs new file mode 100644 index 0000000000..582bd818bd --- /dev/null +++ b/osu.Game/Screens/Play/BreaksOverlay/BlurredIcon.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 OpenTK; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics; +using osu.Game.Graphics; + +namespace osu.Game.Screens.Play.BreaksOverlay +{ + public class BlurredIcon : BufferedContainer + { + private const int icon_size = 130; + + private readonly GlowingIcon icon; + + public FontAwesome Icon + { + set { icon.Icon = value; } + get { return icon.Icon; } + } + + public BlurredIcon() + { + Anchor = Anchor.CentreLeft; + RelativePositionAxes = Axes.X; + Size = new Vector2(icon_size * 1.7f); + Masking = true; + BlurSigma = new Vector2(20); + Alpha = 0.6f; + CacheDrawnFrameBuffer = true; + Child = icon = new GlowingIcon + { + Origin = Anchor.Centre, + Anchor = Anchor.Centre, + Size = new Vector2(icon_size), + }; + } + } +} diff --git a/osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs b/osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs index aec96c10ac..7e245a33d9 100644 --- a/osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs +++ b/osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs @@ -14,8 +14,11 @@ namespace osu.Game.Screens.Play.BreaksOverlay public class BreakOverlay : Container { private const double fade_duration = BreakPeriod.MIN_BREAK_DURATION / 2; - private const int remaining_time_container_max_size = 450; - private const int element_margin = 25; + private const float remaining_time_container_max_size = 0.35f; + private const int vertical_margin = 25; + private const float glowing_x_offset = 0.13f; + private const float glowing_x_final = 0.22f; + private const float blurred_x_offset = 0.2f; public List Breaks; @@ -34,6 +37,12 @@ namespace osu.Game.Screens.Play.BreaksOverlay private readonly RemainingTimeCounter remainingTimeCounter; private readonly InfoContainer info; + private readonly GlowingIcon leftGlowingIcon; + private readonly GlowingIcon rightGlowingIcon; + + private readonly BlurredIcon leftBlurredIcon; + private readonly BlurredIcon rightBlurredIcon; + public BreakOverlay(bool letterboxing) { this.letterboxing = letterboxing; @@ -41,11 +50,16 @@ namespace osu.Game.Screens.Play.BreaksOverlay RelativeSizeAxes = Axes.Both; Children = new Drawable[] { - letterboxOverlay = new LetterboxOverlay(), + letterboxOverlay = new LetterboxOverlay + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }, remainingTimeBox = new Container { Anchor = Anchor.Centre, Origin = Anchor.Centre, + RelativeSizeAxes = Axes.X, Size = new Vector2(0, 8), CornerRadius = 4, Masking = true, @@ -55,13 +69,35 @@ namespace osu.Game.Screens.Play.BreaksOverlay { Anchor = Anchor.Centre, Origin = Anchor.BottomCentre, - Margin = new MarginPadding { Bottom = element_margin }, + Margin = new MarginPadding { Bottom = vertical_margin }, }, info = new InfoContainer { Anchor = Anchor.Centre, Origin = Anchor.TopCentre, - Margin = new MarginPadding { Top = element_margin }, + Margin = new MarginPadding { Top = vertical_margin }, + }, + leftGlowingIcon = new GlowingIcon + { + Origin = Anchor.CentreRight, + Icon = Graphics.FontAwesome.fa_chevron_left, + Size = new Vector2(60), + }, + rightGlowingIcon = new GlowingIcon + { + Origin = Anchor.CentreLeft, + Icon = Graphics.FontAwesome.fa_chevron_right, + Size = new Vector2(60), + }, + leftBlurredIcon = new BlurredIcon + { + Origin = Anchor.CentreRight, + Icon = Graphics.FontAwesome.fa_chevron_left, + }, + rightBlurredIcon = new BlurredIcon + { + Origin = Anchor.CentreLeft, + Icon = Graphics.FontAwesome.fa_chevron_right, } }; } @@ -102,10 +138,16 @@ namespace osu.Game.Screens.Play.BreaksOverlay .Then() .ResizeWidthTo(0, b.Duration); - Scheduler.AddDelayed(() => remainingTimeCounter.StartCounting(b.EndTime), b.StartTime - Clock.CurrentTime); + Scheduler.AddDelayed(() => remainingTimeCounter.StartCounting(b.EndTime), b.StartTime); remainingTimeCounter.FadeIn(fade_duration); info.FadeIn(fade_duration); + + leftGlowingIcon.MoveToX(1 - glowing_x_final, fade_duration, Easing.OutQuint); + rightGlowingIcon.MoveToX(glowing_x_final, fade_duration, Easing.OutQuint); + + leftBlurredIcon.MoveToX(1, fade_duration, Easing.OutQuint); + rightBlurredIcon.MoveToX(0, fade_duration, Easing.OutQuint); } private void onBreakOut() @@ -115,6 +157,12 @@ namespace osu.Game.Screens.Play.BreaksOverlay remainingTimeCounter.FadeOut(fade_duration); info.FadeOut(fade_duration); + + leftGlowingIcon.MoveToX(1 + glowing_x_offset, fade_duration, Easing.OutQuint); + rightGlowingIcon.MoveToX(-glowing_x_offset, fade_duration, Easing.OutQuint); + + leftBlurredIcon.MoveToX(1 + blurred_x_offset, fade_duration, Easing.OutQuint); + rightBlurredIcon.MoveToX(-blurred_x_offset, fade_duration, Easing.OutQuint); } } } diff --git a/osu.Game/Screens/Play/BreaksOverlay/GlowingIcon.cs b/osu.Game/Screens/Play/BreaksOverlay/GlowingIcon.cs new file mode 100644 index 0000000000..fe08a81c5a --- /dev/null +++ b/osu.Game/Screens/Play/BreaksOverlay/GlowingIcon.cs @@ -0,0 +1,74 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using OpenTK; +using OpenTK.Graphics; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Graphics; + +namespace osu.Game.Screens.Play.BreaksOverlay +{ + public class GlowingIcon : Container + { + private readonly SpriteIcon icon; + private readonly SpriteIcon glow; + private readonly BufferedContainer glowContainer; + + public FontAwesome Icon + { + set { icon.Icon = glow.Icon = value; } + get { return icon.Icon; } + } + + public override Vector2 Size + { + set + { + glow.Size = icon.Size = value; + glowContainer.Size = value * 1.5f; + } + get + { + return glow.Size; + } + } + + public GlowingIcon() + { + Anchor = Anchor.CentreLeft; + RelativePositionAxes = Axes.X; + AutoSizeAxes = Axes.Both; + Children = new Drawable[] + { + glowContainer = new BufferedContainer + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Masking = true, + BlurSigma = new Vector2(10), + CacheDrawnFrameBuffer = true, + Child = glow = new SpriteIcon + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Shadow = false, + }, + }, + icon = new SpriteIcon + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Shadow = false, + } + }; + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + glow.Colour = colours.Blue; + } + } +} diff --git a/osu.Game/Screens/Play/LetterboxOverlay.cs b/osu.Game/Screens/Play/BreaksOverlay/LetterboxOverlay.cs similarity index 95% rename from osu.Game/Screens/Play/LetterboxOverlay.cs rename to osu.Game/Screens/Play/BreaksOverlay/LetterboxOverlay.cs index 6672b947e7..c95b15ef3a 100644 --- a/osu.Game/Screens/Play/LetterboxOverlay.cs +++ b/osu.Game/Screens/Play/BreaksOverlay/LetterboxOverlay.cs @@ -7,7 +7,7 @@ using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; -namespace osu.Game.Screens.Play +namespace osu.Game.Screens.Play.BreaksOverlay { public class LetterboxOverlay : Container { @@ -60,4 +60,4 @@ namespace osu.Game.Screens.Play }; } } -} \ No newline at end of file +} diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 406867c656..904e7800b8 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -275,10 +275,12 @@ + + + - From e051bcc6dfd1895bbbca61dac269a5e59e1cf2bd Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Thu, 21 Sep 2017 01:51:40 +0300 Subject: [PATCH 0032/1263] Fix wrong arrows position on startup --- osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs b/osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs index 7e245a33d9..d603298262 100644 --- a/osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs +++ b/osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs @@ -82,22 +82,26 @@ namespace osu.Game.Screens.Play.BreaksOverlay Origin = Anchor.CentreRight, Icon = Graphics.FontAwesome.fa_chevron_left, Size = new Vector2(60), + X = 1 + glowing_x_offset, }, rightGlowingIcon = new GlowingIcon { Origin = Anchor.CentreLeft, Icon = Graphics.FontAwesome.fa_chevron_right, Size = new Vector2(60), + X = -glowing_x_offset, }, leftBlurredIcon = new BlurredIcon { Origin = Anchor.CentreRight, Icon = Graphics.FontAwesome.fa_chevron_left, + X = 1 + blurred_x_offset, }, rightBlurredIcon = new BlurredIcon { Origin = Anchor.CentreLeft, Icon = Graphics.FontAwesome.fa_chevron_right, + X = -blurred_x_offset, } }; } From 9667270336263be0894280dd0becb12186b4e602 Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Thu, 21 Sep 2017 01:56:50 +0300 Subject: [PATCH 0033/1263] Remove using --- osu.Game/Screens/Play/BreaksOverlay/GlowingIcon.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Screens/Play/BreaksOverlay/GlowingIcon.cs b/osu.Game/Screens/Play/BreaksOverlay/GlowingIcon.cs index fe08a81c5a..c92b0121c9 100644 --- a/osu.Game/Screens/Play/BreaksOverlay/GlowingIcon.cs +++ b/osu.Game/Screens/Play/BreaksOverlay/GlowingIcon.cs @@ -2,7 +2,6 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using OpenTK; -using OpenTK.Graphics; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; From 22ab2c5e5dfd6e26e5050e2a220a23072c451224 Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Thu, 21 Sep 2017 22:54:46 +0300 Subject: [PATCH 0034/1263] Apply suggested changes --- .../Play/BreaksOverlay/BreakOverlay.cs | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs b/osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs index d603298262..970e8c7d49 100644 --- a/osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs +++ b/osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs @@ -114,20 +114,20 @@ namespace osu.Game.Screens.Play.BreaksOverlay public void InitializeBreaks() { - if (Breaks != null) - { - foreach (var b in Breaks) - { - if (b.HasEffect) - { - using (BeginAbsoluteSequence(b.StartTime, true)) - { - onBreakIn(b); + if (Breaks == null) + return; - using (BeginDelayedSequence(b.Duration, true)) - onBreakOut(); - } - } + foreach (var b in Breaks) + { + if (!b.HasEffect) + continue; + + using (BeginAbsoluteSequence(b.StartTime, true)) + { + onBreakIn(b); + + using (BeginDelayedSequence(b.Duration, true)) + onBreakOut(); } } } From 5383e33f3d5616431fa03ebed2598e60a0317f8e Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Thu, 21 Sep 2017 22:58:49 +0300 Subject: [PATCH 0035/1263] Remove useless clock assignment --- osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs b/osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs index 970e8c7d49..29b24f1f87 100644 --- a/osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs +++ b/osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs @@ -5,7 +5,6 @@ using OpenTK; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; -using osu.Framework.Timing; using osu.Game.Beatmaps.Timing; using System.Collections.Generic; @@ -22,15 +21,6 @@ namespace osu.Game.Screens.Play.BreaksOverlay public List Breaks; - public override IFrameBasedClock Clock - { - set - { - base.Clock = remainingTimeCounter.Clock = value; - } - get { return base.Clock; } - } - private readonly bool letterboxing; private readonly LetterboxOverlay letterboxOverlay; private readonly Container remainingTimeBox; From 72141935e84f8edd224c94224d1d18f917ff123d Mon Sep 17 00:00:00 2001 From: Jorolf Date: Thu, 21 Sep 2017 22:07:23 +0200 Subject: [PATCH 0036/1263] make pagination work and remove duplication in RanksSection --- osu.Desktop.Tests/Visual/TestCaseUserRanks.cs | 100 -------- osu.Game/Beatmaps/BeatmapInfo.cs | 2 + .../API/Requests/GetUserScoresRequest.cs | 6 +- .../Profile/Sections/Ranks/DrawableScore.cs | 5 +- .../Overlays/Profile/Sections/RanksSection.cs | 236 ++++++++---------- osu.Game/Tests/Visual/TestCaseUserRanks.cs | 75 +----- osu.Game/osu.Game.csproj | 2 - 7 files changed, 121 insertions(+), 305 deletions(-) delete mode 100644 osu.Desktop.Tests/Visual/TestCaseUserRanks.cs diff --git a/osu.Desktop.Tests/Visual/TestCaseUserRanks.cs b/osu.Desktop.Tests/Visual/TestCaseUserRanks.cs deleted file mode 100644 index 41f3a37e94..0000000000 --- a/osu.Desktop.Tests/Visual/TestCaseUserRanks.cs +++ /dev/null @@ -1,100 +0,0 @@ -// Copyright (c) 2007-2017 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; -using osu.Framework.Testing; -using osu.Game.Beatmaps; -using osu.Game.Graphics; -using osu.Game.Overlays.Profile.Sections; -using osu.Game.Rulesets.Mods; -using osu.Game.Rulesets.Osu.Mods; -using osu.Game.Rulesets.Scoring; -using System; -using System.Collections.Generic; - -namespace osu.Desktop.Tests.Visual -{ - internal class TestCaseUserRanks : TestCase - { - public override string Description => "showing your latest achievements"; - - protected override void LoadComplete() - { - base.LoadComplete(); - - RanksSection ranks; - - Add(new Container - { - AutoSizeAxes = Axes.Y, - RelativeSizeAxes = Axes.X, - Children = new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = OsuColour.Gray(0.2f) - }, - ranks = new RanksSection(), - } - }); - - AddStep("Add Best Performances", () => - { - List scores = new List(); - Mod[] availableMods = { new OsuModHidden(), new OsuModFlashlight(), new OsuModHardRock(), new OsuModDoubleTime(), new OsuModPerfect() }; - List selectedMods = new List(availableMods); - for (int i = 0; i <= availableMods.Length; i++) - { - scores.Add(new Score - { - Rank = (ScoreRank) Enum.GetValues(typeof(ScoreRank)).GetValue(Enum.GetValues(typeof(ScoreRank)).Length - 1 - i), - Accuracy = Math.Pow(0.99, i), - PP = Math.Pow(0.5, i) * 800, - Date = DateTimeOffset.UtcNow.AddDays(-Math.Pow(i, 2)), - Mods = selectedMods.ToArray(), - Beatmap = new BeatmapInfo - { - Metadata = new BeatmapMetadata - { - Title = "Highscore", - Artist = "Panda Eyes & Teminite" - }, - Version = "Game Over", - OnlineBeatmapID = 736215, - } - }); - if(i < availableMods.Length) - selectedMods.Remove(availableMods[i]); - } - ranks.ScoresBest = scores.ToArray(); - }); - - AddStep("Add First Place", () => ranks.ScoresFirst = new[] - { - new Score - { - Rank = ScoreRank.A, - Accuracy = 0.735, - PP = 666, - Date = DateTimeOffset.UtcNow, - Mods = new Mod[] { new ModAutoplay(), new ModDoubleTime(), new OsuModEasy() }, - Beatmap = new BeatmapInfo - { - Metadata = new BeatmapMetadata - { - Title = "FREEDOM DiVE", - Artist = "xi" - }, - Version = "FOUR DIMENSIONS", - OnlineBeatmapID = 129891, - } - } - }); - - AddStep("Show More", ((RanksSection.ScoreFlowContainer)ranks.Children[1]).ShowMore); - } - } -} diff --git a/osu.Game/Beatmaps/BeatmapInfo.cs b/osu.Game/Beatmaps/BeatmapInfo.cs index 0776669811..5775299ffb 100644 --- a/osu.Game/Beatmaps/BeatmapInfo.cs +++ b/osu.Game/Beatmaps/BeatmapInfo.cs @@ -19,8 +19,10 @@ namespace osu.Game.Beatmaps //TODO: should be in database public int BeatmapVersion; + [JsonProperty("id")] public int? OnlineBeatmapID { get; set; } + [JsonProperty("beatmapset_id")] public int? OnlineBeatmapSetID { get; set; } [ForeignKey(typeof(BeatmapSetInfo))] diff --git a/osu.Game/Online/API/Requests/GetUserScoresRequest.cs b/osu.Game/Online/API/Requests/GetUserScoresRequest.cs index 20597aecc1..98db234196 100644 --- a/osu.Game/Online/API/Requests/GetUserScoresRequest.cs +++ b/osu.Game/Online/API/Requests/GetUserScoresRequest.cs @@ -9,14 +9,16 @@ namespace osu.Game.Online.API.Requests { private readonly long userId; private readonly ScoreType type; + private readonly int offset; - public GetUserScoresRequest(long userId, ScoreType type) + public GetUserScoresRequest(long userId, ScoreType type, int offset = 0) { this.userId = userId; this.type = type; + this.offset = offset; } - protected override string Target => $@"users/{userId}/scores/{type.ToString().ToLower()}"; + protected override string Target => $@"users/{userId}/scores/{type.ToString().ToLower()}?offset={offset}"; } public enum ScoreType diff --git a/osu.Game/Overlays/Profile/Sections/Ranks/DrawableScore.cs b/osu.Game/Overlays/Profile/Sections/Ranks/DrawableScore.cs index d92ebf6dca..27df3fd0fa 100644 --- a/osu.Game/Overlays/Profile/Sections/Ranks/DrawableScore.cs +++ b/osu.Game/Overlays/Profile/Sections/Ranks/DrawableScore.cs @@ -17,6 +17,7 @@ using osu.Framework.Localisation; using System.Globalization; using osu.Game.Rulesets.Scoring; using osu.Framework.Graphics.Cursor; +using System; namespace osu.Game.Overlays.Profile.Sections.Ranks { @@ -81,7 +82,7 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks { stats.Add(new OsuSpriteText { - Text = $"{score.PP ?? 0}pp", + Text = $"{Math.Round(score.PP ?? 0)}pp", Anchor = Anchor.TopRight, Origin = Anchor.TopRight, TextSize = 18, @@ -91,7 +92,7 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks { stats.Add(new OsuSpriteText { - Text = $"weighted: {(int)(score?.PP * weight ?? 0)}pp ({weight.ToString("0%", CultureInfo.CurrentCulture)})", + Text = $"weighted: {Math.Round(score.PP * weight ?? 0)}pp ({weight.ToString("0%", CultureInfo.CurrentCulture)})", Anchor = Anchor.TopRight, Origin = Anchor.TopRight, Colour = colour.GrayA, diff --git a/osu.Game/Overlays/Profile/Sections/RanksSection.cs b/osu.Game/Overlays/Profile/Sections/RanksSection.cs index 4f9470bd6e..b6c56f5cb1 100644 --- a/osu.Game/Overlays/Profile/Sections/RanksSection.cs +++ b/osu.Game/Overlays/Profile/Sections/RanksSection.cs @@ -15,6 +15,8 @@ using osu.Game.Online.API; using osu.Game.Online.API.Requests; using osu.Game.Rulesets; using osu.Game.Users; +using osu.Game.Graphics.UserInterface; +using OpenTK; namespace osu.Game.Overlays.Profile.Sections { @@ -24,8 +26,7 @@ namespace osu.Game.Overlays.Profile.Sections public override string Identifier => "top_ranks"; - private readonly ScoreFlowContainer best, first; - private readonly OsuSpriteText bestMissing, firstMissing; + private readonly ScoreContainer best, first; private APIAccess api; private RulesetStore rulesets; @@ -34,40 +35,8 @@ namespace osu.Game.Overlays.Profile.Sections { Children = new Drawable[] { - new OsuSpriteText - { - TextSize = 15, - Text = "Best Performance", - Font = "Exo2.0-RegularItalic", - Margin = new MarginPadding { Top = 10, Bottom = 10 }, - }, - best = new ScoreFlowContainer - { - AutoSizeAxes = Axes.Y, - RelativeSizeAxes = Axes.X, - }, - bestMissing = new OsuSpriteText - { - TextSize = 14, - Text = "No awesome performance records yet. :(", - }, - new OsuSpriteText - { - TextSize = 15, - Text = "First Place Ranks", - Font = "Exo2.0-RegularItalic", - Margin = new MarginPadding { Top = 20, Bottom = 10 }, - }, - first = new ScoreFlowContainer - { - AutoSizeAxes = Axes.Y, - RelativeSizeAxes = Axes.X, - }, - firstMissing = new OsuSpriteText - { - TextSize = 14, - Text = "No awesome performance records yet. :(", - }, + best = new ScoreContainer(ScoreType.Best, "Best Performance", true), + first = new ScoreContainer(ScoreType.Firsts, "First Place Ranks"), }; } @@ -88,119 +57,67 @@ namespace osu.Game.Overlays.Profile.Sections set { base.User = value; - - // fetch online ranks - foreach (ScoreType m in new[] { ScoreType.Best, ScoreType.Firsts }) - { - ScoreType thisType = m; - var req = new GetUserScoresRequest(User.Id, m); - req.Success += scores => - { - foreach (var s in scores) - s.ApplyRuleset(rulesets.GetRuleset(s.OnlineRulesetID)); - - switch (thisType) - { - case ScoreType.Best: - ScoresBest = scores; - break; - case ScoreType.Firsts: - ScoresFirst = scores; - break; - } - }; - - Schedule(() => { api.Queue(req); }); - } + best.User = value; + first.User = value; } } - - public IEnumerable ScoresBest + private class ScoreContainer : FillFlowContainer { - set + private readonly FillFlowContainer scoreContainer; + private readonly OsuSpriteText missing; + private readonly OsuHoverContainer showMoreButton; + private readonly LoadingAnimation showMoreLoading; + + private ScoreType type; + private int visiblePages; + private User user; + private readonly bool includeWeigth; + + private RulesetStore rulesets; + private APIAccess api; + + public User User { - best.Clear(); - if (!value.Any()) + set { - bestMissing.Show(); + user = value; + visiblePages = 0; + scoreContainer.Clear(); + showMoreButton.Hide(); + missing.Show(); + showMore(); } - else - { - bestMissing.Hide(); - int i = 0; - foreach (Score score in value) - { - best.Add(new DrawableScore(score, Math.Pow(0.95, i)) - { - RelativeSizeAxes = Axes.X, - Height = 60, - Alpha = 0, - }); - i++; - } - } - best.ShowMore(); } - } - public IEnumerable ScoresFirst - { - set + public ScoreContainer(ScoreType type, string header, bool includeWeigth = false) { - first.Clear(); - if (!value.Any()) - { - firstMissing.Show(); - } - else - { - firstMissing.Hide(); - foreach (Score score in value) - first.Add(new DrawableScore(score) - { - RelativeSizeAxes = Axes.X, - Height = 60, - Alpha = 0, - }); - } - first.ShowMore(); - } - } + this.type = type; + this.includeWeigth = includeWeigth; - public class ScoreFlowContainer : Container - { - private FillFlowContainer scores; - private OsuClickableContainer showMoreText; + RelativeSizeAxes = Axes.X; + AutoSizeAxes = Axes.Y; + Direction = FillDirection.Vertical; - protected override Container Content => scores; - - protected override void LoadComplete() - { - InternalChild = new FillFlowContainer + Children = new Drawable[] { - AutoSizeAxes = Axes.Y, - RelativeSizeAxes = Axes.X, - Direction = FillDirection.Vertical, - Children = new Drawable[] + new OsuSpriteText { - scores = new FillFlowContainer - { - AutoSizeAxes = Axes.Y, - RelativeSizeAxes = Axes.X, - Direction = FillDirection.Vertical, - }, + TextSize = 15, + Text = header, + Font = "Exo2.0-RegularItalic", + Margin = new MarginPadding { Top = 10, Bottom = 10 }, }, - }; - } - - public override void Clear(bool disposeChildren) - { - base.Clear(disposeChildren); - if (showMoreText == null) - ((FillFlowContainer)InternalChild).Add(showMoreText = new OsuHoverContainer + scoreContainer = new FillFlowContainer { - Action = ShowMore, + AutoSizeAxes = Axes.Y, + RelativeSizeAxes = Axes.X, + Direction = FillDirection.Vertical, + }, + showMoreButton = new OsuHoverContainer + { + Alpha = 0, + Action = showMore, AutoSizeAxes = Axes.Both, Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, @@ -209,12 +126,57 @@ namespace osu.Game.Overlays.Profile.Sections TextSize = 14, Text = "show more", } - }); - else - showMoreText.Show(); + }, + showMoreLoading = new LoadingAnimation + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Size = new Vector2(14), + }, + missing = new OsuSpriteText + { + TextSize = 14, + Text = "No awesome performance records yet. :(", + }, + }; } - public void ShowMore() => showMoreText.Alpha = Children.Where(d => !d.IsPresent).Where((d, i) => (d.Alpha = i < 5 ? 1 : 0) == 0).Any() ? 1 : 0; + [BackgroundDependencyLoader] + private void load(APIAccess api, RulesetStore rulesets) + { + this.api = api; + this.rulesets = rulesets; + } + + private void showMore() + { + var req = new GetUserScoresRequest(user.Id, type, visiblePages++ * 5); + + showMoreLoading.Show(); + showMoreButton.Hide(); + + req.Success += scores => + { + foreach (var s in scores) + s.ApplyRuleset(rulesets.GetRuleset(s.OnlineRulesetID)); + + showMoreButton.FadeTo(scores.Count == 5 ? 1 : 0); + showMoreLoading.Hide(); + + if (scores.Any()) + { + missing.Hide(); + foreach (Score score in scores) + scoreContainer.Add(new DrawableScore(score, includeWeigth ? Math.Pow(0.95, scoreContainer.Count) : -1) + { + RelativeSizeAxes = Axes.X, + Height = 60, + }); + } + }; + + Schedule(() => { api.Queue(req); }); + } } } } diff --git a/osu.Game/Tests/Visual/TestCaseUserRanks.cs b/osu.Game/Tests/Visual/TestCaseUserRanks.cs index 41f3a37e94..e164426a4e 100644 --- a/osu.Game/Tests/Visual/TestCaseUserRanks.cs +++ b/osu.Game/Tests/Visual/TestCaseUserRanks.cs @@ -8,28 +8,28 @@ using osu.Framework.Testing; using osu.Game.Beatmaps; using osu.Game.Graphics; using osu.Game.Overlays.Profile.Sections; +using osu.Game.Overlays.Profile.Sections.Ranks; using osu.Game.Rulesets.Mods; -using osu.Game.Rulesets.Osu.Mods; using osu.Game.Rulesets.Scoring; +using osu.Game.Users; using System; using System.Collections.Generic; -namespace osu.Desktop.Tests.Visual +namespace osu.Game.Tests.Visual { - internal class TestCaseUserRanks : TestCase + internal class TestCaseUserRanks : OsuTestCase { public override string Description => "showing your latest achievements"; - protected override void LoadComplete() - { - base.LoadComplete(); + public override IReadOnlyList RequiredTypes => new Type[] { typeof(DrawableScore), typeof(RanksSection) }; + public TestCaseUserRanks() + { RanksSection ranks; Add(new Container { - AutoSizeAxes = Axes.Y, - RelativeSizeAxes = Axes.X, + RelativeSizeAxes = Axes.Both, Children = new Drawable[] { new Box @@ -37,64 +37,15 @@ namespace osu.Desktop.Tests.Visual RelativeSizeAxes = Axes.Both, Colour = OsuColour.Gray(0.2f) }, - ranks = new RanksSection(), - } - }); - - AddStep("Add Best Performances", () => - { - List scores = new List(); - Mod[] availableMods = { new OsuModHidden(), new OsuModFlashlight(), new OsuModHardRock(), new OsuModDoubleTime(), new OsuModPerfect() }; - List selectedMods = new List(availableMods); - for (int i = 0; i <= availableMods.Length; i++) - { - scores.Add(new Score + new ScrollContainer { - Rank = (ScoreRank) Enum.GetValues(typeof(ScoreRank)).GetValue(Enum.GetValues(typeof(ScoreRank)).Length - 1 - i), - Accuracy = Math.Pow(0.99, i), - PP = Math.Pow(0.5, i) * 800, - Date = DateTimeOffset.UtcNow.AddDays(-Math.Pow(i, 2)), - Mods = selectedMods.ToArray(), - Beatmap = new BeatmapInfo - { - Metadata = new BeatmapMetadata - { - Title = "Highscore", - Artist = "Panda Eyes & Teminite" - }, - Version = "Game Over", - OnlineBeatmapID = 736215, - } - }); - if(i < availableMods.Length) - selectedMods.Remove(availableMods[i]); - } - ranks.ScoresBest = scores.ToArray(); - }); - - AddStep("Add First Place", () => ranks.ScoresFirst = new[] - { - new Score - { - Rank = ScoreRank.A, - Accuracy = 0.735, - PP = 666, - Date = DateTimeOffset.UtcNow, - Mods = new Mod[] { new ModAutoplay(), new ModDoubleTime(), new OsuModEasy() }, - Beatmap = new BeatmapInfo - { - Metadata = new BeatmapMetadata - { - Title = "FREEDOM DiVE", - Artist = "xi" - }, - Version = "FOUR DIMENSIONS", - OnlineBeatmapID = 129891, - } + RelativeSizeAxes = Axes.Both, + Child = ranks = new RanksSection(), + }, } }); - AddStep("Show More", ((RanksSection.ScoreFlowContainer)ranks.Children[1]).ShowMore); + AddStep("Show cookiezi", () => ranks.User = new User { Id = 124493 }); } } } diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 7a78ed8dd4..a20a5ee13f 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -298,7 +298,6 @@ - @@ -318,7 +317,6 @@ - From 14b8e9fd775914861f1f48c8ced7f71d63876797 Mon Sep 17 00:00:00 2001 From: Jorolf Date: Thu, 21 Sep 2017 22:15:42 +0200 Subject: [PATCH 0037/1263] remove some redundant stuff --- .../Overlays/Profile/Sections/RanksSection.cs | 17 +++-------------- osu.Game/Tests/Visual/TestCaseUserRanks.cs | 6 +----- 2 files changed, 4 insertions(+), 19 deletions(-) diff --git a/osu.Game/Overlays/Profile/Sections/RanksSection.cs b/osu.Game/Overlays/Profile/Sections/RanksSection.cs index b6c56f5cb1..d5ee379a5b 100644 --- a/osu.Game/Overlays/Profile/Sections/RanksSection.cs +++ b/osu.Game/Overlays/Profile/Sections/RanksSection.cs @@ -8,15 +8,14 @@ using osu.Game.Graphics.Sprites; using osu.Game.Overlays.Profile.Sections.Ranks; using osu.Game.Rulesets.Scoring; using System; -using System.Collections.Generic; using System.Linq; -using osu.Framework.Allocation; using osu.Game.Online.API; using osu.Game.Online.API.Requests; using osu.Game.Rulesets; using osu.Game.Users; using osu.Game.Graphics.UserInterface; using OpenTK; +using osu.Framework.Allocation; namespace osu.Game.Overlays.Profile.Sections { @@ -28,9 +27,6 @@ namespace osu.Game.Overlays.Profile.Sections private readonly ScoreContainer best, first; - private APIAccess api; - private RulesetStore rulesets; - public RanksSection() { Children = new Drawable[] @@ -40,13 +36,6 @@ namespace osu.Game.Overlays.Profile.Sections }; } - [BackgroundDependencyLoader] - private void load(APIAccess api, RulesetStore rulesets) - { - this.api = api; - this.rulesets = rulesets; - } - public override User User { get @@ -69,7 +58,7 @@ namespace osu.Game.Overlays.Profile.Sections private readonly OsuHoverContainer showMoreButton; private readonly LoadingAnimation showMoreLoading; - private ScoreType type; + private readonly ScoreType type; private int visiblePages; private User user; private readonly bool includeWeigth; @@ -166,7 +155,7 @@ namespace osu.Game.Overlays.Profile.Sections if (scores.Any()) { missing.Hide(); - foreach (Score score in scores) + foreach (OnlineScore score in scores) scoreContainer.Add(new DrawableScore(score, includeWeigth ? Math.Pow(0.95, scoreContainer.Count) : -1) { RelativeSizeAxes = Axes.X, diff --git a/osu.Game/Tests/Visual/TestCaseUserRanks.cs b/osu.Game/Tests/Visual/TestCaseUserRanks.cs index e164426a4e..9667897a7d 100644 --- a/osu.Game/Tests/Visual/TestCaseUserRanks.cs +++ b/osu.Game/Tests/Visual/TestCaseUserRanks.cs @@ -4,13 +4,9 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; -using osu.Framework.Testing; -using osu.Game.Beatmaps; using osu.Game.Graphics; using osu.Game.Overlays.Profile.Sections; using osu.Game.Overlays.Profile.Sections.Ranks; -using osu.Game.Rulesets.Mods; -using osu.Game.Rulesets.Scoring; using osu.Game.Users; using System; using System.Collections.Generic; @@ -21,7 +17,7 @@ namespace osu.Game.Tests.Visual { public override string Description => "showing your latest achievements"; - public override IReadOnlyList RequiredTypes => new Type[] { typeof(DrawableScore), typeof(RanksSection) }; + public override IReadOnlyList RequiredTypes => new[] { typeof(DrawableScore), typeof(RanksSection) }; public TestCaseUserRanks() { From 9ee824ee6661dffaf01396f47f43d270b8d8fc28 Mon Sep 17 00:00:00 2001 From: Jorolf Date: Thu, 21 Sep 2017 22:28:15 +0200 Subject: [PATCH 0038/1263] some more unused stuff --- osu.Game/Overlays/Profile/Sections/RanksSection.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Overlays/Profile/Sections/RanksSection.cs b/osu.Game/Overlays/Profile/Sections/RanksSection.cs index d5ee379a5b..d7df239003 100644 --- a/osu.Game/Overlays/Profile/Sections/RanksSection.cs +++ b/osu.Game/Overlays/Profile/Sections/RanksSection.cs @@ -6,7 +6,6 @@ using osu.Framework.Graphics.Containers; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Overlays.Profile.Sections.Ranks; -using osu.Game.Rulesets.Scoring; using System; using System.Linq; using osu.Game.Online.API; From 56bde648393fb8870d1d755d9b531d972c862a82 Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Fri, 22 Sep 2017 01:16:05 +0300 Subject: [PATCH 0039/1263] Add arrows overlay --- .../Play/BreaksOverlay/ArrowsOverlay.cs | 84 +++++++++++++++++++ .../Screens/Play/BreaksOverlay/BlurredIcon.cs | 22 +++-- .../Play/BreaksOverlay/BreakOverlay.cs | 51 ++--------- .../{GlowingIcon.cs => GlowIcon.cs} | 48 +++++------ osu.Game/osu.Game.csproj | 3 +- 5 files changed, 129 insertions(+), 79 deletions(-) create mode 100644 osu.Game/Screens/Play/BreaksOverlay/ArrowsOverlay.cs rename osu.Game/Screens/Play/BreaksOverlay/{GlowingIcon.cs => GlowIcon.cs} (65%) diff --git a/osu.Game/Screens/Play/BreaksOverlay/ArrowsOverlay.cs b/osu.Game/Screens/Play/BreaksOverlay/ArrowsOverlay.cs new file mode 100644 index 0000000000..715cc4fc0f --- /dev/null +++ b/osu.Game/Screens/Play/BreaksOverlay/ArrowsOverlay.cs @@ -0,0 +1,84 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics; +using OpenTK; + +namespace osu.Game.Screens.Play.BreaksOverlay +{ + public class ArrowsOverlay : Container + { + private const int glowing_size = 60; + private const float glowing_final_offset = 0.25f; + private const float glowing_offscreen_offset = 0.6f; + + private const int blurred_size = 130; + private const float blurred_final_offset = 0.35f; + private const float blurred_offscreen_offset = 0.7f; + + private readonly GlowIcon leftGlowIcon; + private readonly GlowIcon rightGlowIcon; + + private readonly BlurredIcon leftBlurredIcon; + private readonly BlurredIcon rightBlurredIcon; + + public ArrowsOverlay() + { + RelativeSizeAxes = Axes.Both; + Children = new Drawable[] + { + leftGlowIcon = new GlowIcon + { + Anchor = Anchor.Centre, + Origin = Anchor.CentreRight, + X = - glowing_offscreen_offset, + Icon = Graphics.FontAwesome.fa_chevron_right, + Size = new Vector2(glowing_size), + }, + rightGlowIcon = new GlowIcon + { + Anchor = Anchor.Centre, + Origin = Anchor.CentreLeft, + X = glowing_offscreen_offset, + Icon = Graphics.FontAwesome.fa_chevron_left, + Size = new Vector2(glowing_size), + }, + leftBlurredIcon = new BlurredIcon + { + Anchor = Anchor.Centre, + Origin = Anchor.CentreRight, + X = - blurred_offscreen_offset, + Icon = Graphics.FontAwesome.fa_chevron_right, + Size = new Vector2(blurred_size), + }, + rightBlurredIcon = new BlurredIcon + { + Anchor = Anchor.Centre, + Origin = Anchor.CentreLeft, + X = blurred_offscreen_offset, + Icon = Graphics.FontAwesome.fa_chevron_left, + Size = new Vector2(blurred_size), + }, + }; + } + + public void Show(double fadeDuration) + { + leftGlowIcon.MoveToX(-glowing_final_offset, fadeDuration, Easing.OutQuint); + rightGlowIcon.MoveToX(glowing_final_offset, fadeDuration, Easing.OutQuint); + + leftBlurredIcon.MoveToX(-blurred_final_offset, fadeDuration, Easing.OutQuint); + rightBlurredIcon.MoveToX(blurred_final_offset, fadeDuration, Easing.OutQuint); + } + + public void Hide(double fadeDuration) + { + leftGlowIcon.MoveToX(-glowing_offscreen_offset, fadeDuration, Easing.OutQuint); + rightGlowIcon.MoveToX(glowing_offscreen_offset, fadeDuration, Easing.OutQuint); + + leftBlurredIcon.MoveToX(-blurred_offscreen_offset, fadeDuration, Easing.OutQuint); + rightBlurredIcon.MoveToX(blurred_offscreen_offset, fadeDuration, Easing.OutQuint); + } + } +} diff --git a/osu.Game/Screens/Play/BreaksOverlay/BlurredIcon.cs b/osu.Game/Screens/Play/BreaksOverlay/BlurredIcon.cs index 582bd818bd..25e6eef1fd 100644 --- a/osu.Game/Screens/Play/BreaksOverlay/BlurredIcon.cs +++ b/osu.Game/Screens/Play/BreaksOverlay/BlurredIcon.cs @@ -10,9 +10,9 @@ namespace osu.Game.Screens.Play.BreaksOverlay { public class BlurredIcon : BufferedContainer { - private const int icon_size = 130; + private const int blur_sigma = 20; - private readonly GlowingIcon icon; + private readonly GlowIcon icon; public FontAwesome Icon { @@ -20,20 +20,26 @@ namespace osu.Game.Screens.Play.BreaksOverlay get { return icon.Icon; } } + public override Vector2 Size + { + set + { + icon.Size = value; + base.Size = value + new Vector2(blur_sigma * 2); + } + get { return icon.Size; } + } + public BlurredIcon() { - Anchor = Anchor.CentreLeft; RelativePositionAxes = Axes.X; - Size = new Vector2(icon_size * 1.7f); - Masking = true; - BlurSigma = new Vector2(20); + BlurSigma = new Vector2(blur_sigma); Alpha = 0.6f; CacheDrawnFrameBuffer = true; - Child = icon = new GlowingIcon + Child = icon = new GlowIcon { Origin = Anchor.Centre, Anchor = Anchor.Centre, - Size = new Vector2(icon_size), }; } } diff --git a/osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs b/osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs index 29b24f1f87..c0088ce816 100644 --- a/osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs +++ b/osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs @@ -15,9 +15,6 @@ namespace osu.Game.Screens.Play.BreaksOverlay private const double fade_duration = BreakPeriod.MIN_BREAK_DURATION / 2; private const float remaining_time_container_max_size = 0.35f; private const int vertical_margin = 25; - private const float glowing_x_offset = 0.13f; - private const float glowing_x_final = 0.22f; - private const float blurred_x_offset = 0.2f; public List Breaks; @@ -26,12 +23,7 @@ namespace osu.Game.Screens.Play.BreaksOverlay private readonly Container remainingTimeBox; private readonly RemainingTimeCounter remainingTimeCounter; private readonly InfoContainer info; - - private readonly GlowingIcon leftGlowingIcon; - private readonly GlowingIcon rightGlowingIcon; - - private readonly BlurredIcon leftBlurredIcon; - private readonly BlurredIcon rightBlurredIcon; + private readonly ArrowsOverlay arrowsOverlay; public BreakOverlay(bool letterboxing) { @@ -67,31 +59,10 @@ namespace osu.Game.Screens.Play.BreaksOverlay Origin = Anchor.TopCentre, Margin = new MarginPadding { Top = vertical_margin }, }, - leftGlowingIcon = new GlowingIcon + arrowsOverlay = new ArrowsOverlay { - Origin = Anchor.CentreRight, - Icon = Graphics.FontAwesome.fa_chevron_left, - Size = new Vector2(60), - X = 1 + glowing_x_offset, - }, - rightGlowingIcon = new GlowingIcon - { - Origin = Anchor.CentreLeft, - Icon = Graphics.FontAwesome.fa_chevron_right, - Size = new Vector2(60), - X = -glowing_x_offset, - }, - leftBlurredIcon = new BlurredIcon - { - Origin = Anchor.CentreRight, - Icon = Graphics.FontAwesome.fa_chevron_left, - X = 1 + blurred_x_offset, - }, - rightBlurredIcon = new BlurredIcon - { - Origin = Anchor.CentreLeft, - Icon = Graphics.FontAwesome.fa_chevron_right, - X = -blurred_x_offset, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, } }; } @@ -136,12 +107,7 @@ namespace osu.Game.Screens.Play.BreaksOverlay remainingTimeCounter.FadeIn(fade_duration); info.FadeIn(fade_duration); - - leftGlowingIcon.MoveToX(1 - glowing_x_final, fade_duration, Easing.OutQuint); - rightGlowingIcon.MoveToX(glowing_x_final, fade_duration, Easing.OutQuint); - - leftBlurredIcon.MoveToX(1, fade_duration, Easing.OutQuint); - rightBlurredIcon.MoveToX(0, fade_duration, Easing.OutQuint); + arrowsOverlay.Show(fade_duration); } private void onBreakOut() @@ -151,12 +117,7 @@ namespace osu.Game.Screens.Play.BreaksOverlay remainingTimeCounter.FadeOut(fade_duration); info.FadeOut(fade_duration); - - leftGlowingIcon.MoveToX(1 + glowing_x_offset, fade_duration, Easing.OutQuint); - rightGlowingIcon.MoveToX(-glowing_x_offset, fade_duration, Easing.OutQuint); - - leftBlurredIcon.MoveToX(1 + blurred_x_offset, fade_duration, Easing.OutQuint); - rightBlurredIcon.MoveToX(-blurred_x_offset, fade_duration, Easing.OutQuint); + arrowsOverlay.Hide(fade_duration); } } } diff --git a/osu.Game/Screens/Play/BreaksOverlay/GlowingIcon.cs b/osu.Game/Screens/Play/BreaksOverlay/GlowIcon.cs similarity index 65% rename from osu.Game/Screens/Play/BreaksOverlay/GlowingIcon.cs rename to osu.Game/Screens/Play/BreaksOverlay/GlowIcon.cs index c92b0121c9..91e794ff6b 100644 --- a/osu.Game/Screens/Play/BreaksOverlay/GlowingIcon.cs +++ b/osu.Game/Screens/Play/BreaksOverlay/GlowIcon.cs @@ -1,42 +1,40 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics; +using osu.Game.Graphics; using OpenTK; using osu.Framework.Allocation; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Game.Graphics; namespace osu.Game.Screens.Play.BreaksOverlay { - public class GlowingIcon : Container + public class GlowIcon : Container { - private readonly SpriteIcon icon; - private readonly SpriteIcon glow; - private readonly BufferedContainer glowContainer; + private const int blur_sigma = 5; - public FontAwesome Icon - { - set { icon.Icon = glow.Icon = value; } - get { return icon.Icon; } - } + private readonly SpriteIcon spriteIcon; + private readonly SpriteIcon glowIcon; + private readonly BufferedContainer glowContainer; public override Vector2 Size { set { - glow.Size = icon.Size = value; - glowContainer.Size = value * 1.5f; - } - get - { - return glow.Size; + spriteIcon.Size = glowIcon.Size = value; + glowContainer.Size = value + new Vector2(blur_sigma * 2); } + get { return spriteIcon.Size; } } - public GlowingIcon() + public FontAwesome Icon + { + set { spriteIcon.Icon = glowIcon.Icon = value; } + get { return spriteIcon.Icon; } + } + + public GlowIcon() { - Anchor = Anchor.CentreLeft; RelativePositionAxes = Axes.X; AutoSizeAxes = Axes.Both; Children = new Drawable[] @@ -45,17 +43,17 @@ namespace osu.Game.Screens.Play.BreaksOverlay { Anchor = Anchor.Centre, Origin = Anchor.Centre, - Masking = true, - BlurSigma = new Vector2(10), + BlurSigma = new Vector2(blur_sigma), CacheDrawnFrameBuffer = true, - Child = glow = new SpriteIcon + Child = glowIcon = new SpriteIcon { Anchor = Anchor.Centre, Origin = Anchor.Centre, Shadow = false, }, + }, - icon = new SpriteIcon + spriteIcon = new SpriteIcon { Anchor = Anchor.Centre, Origin = Anchor.Centre, @@ -67,7 +65,7 @@ namespace osu.Game.Screens.Play.BreaksOverlay [BackgroundDependencyLoader] private void load(OsuColour colours) { - glow.Colour = colours.Blue; + glowIcon.Colour = colours.BlueLight; } } } diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 904e7800b8..dd823f6144 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -275,9 +275,10 @@ + - + From d58e5a613015beb9ffb9e1da672ab2bcdaf5db7d Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Fri, 22 Sep 2017 20:43:51 +0300 Subject: [PATCH 0040/1263] Arrows improvements --- .../Play/BreaksOverlay/ArrowsOverlay.cs | 50 +++++++++++-------- .../Screens/Play/BreaksOverlay/BlurredIcon.cs | 22 +++++--- .../Play/BreaksOverlay/BreakOverlay.cs | 2 +- .../Screens/Play/BreaksOverlay/GlowIcon.cs | 33 ++++++------ 4 files changed, 57 insertions(+), 50 deletions(-) diff --git a/osu.Game/Screens/Play/BreaksOverlay/ArrowsOverlay.cs b/osu.Game/Screens/Play/BreaksOverlay/ArrowsOverlay.cs index 715cc4fc0f..8ba801f204 100644 --- a/osu.Game/Screens/Play/BreaksOverlay/ArrowsOverlay.cs +++ b/osu.Game/Screens/Play/BreaksOverlay/ArrowsOverlay.cs @@ -9,13 +9,15 @@ namespace osu.Game.Screens.Play.BreaksOverlay { public class ArrowsOverlay : Container { - private const int glowing_size = 60; - private const float glowing_final_offset = 0.25f; - private const float glowing_offscreen_offset = 0.6f; + private const int glow_icon_size = 65; + private const int glow_icon_blur_sigma = 8; + private const float glow_icon_final_offset = 0.2f; + private const float glow_icon_offscreen_offset = 0.6f; - private const int blurred_size = 130; - private const float blurred_final_offset = 0.35f; - private const float blurred_offscreen_offset = 0.7f; + private const int blurred_icon_blur_sigma = 20; + private const int blurred_icon_size = 130; + private const float blurred_icon_final_offset = 0.35f; + private const float blurred_icon_offscreen_offset = 0.7f; private readonly GlowIcon leftGlowIcon; private readonly GlowIcon rightGlowIcon; @@ -32,53 +34,57 @@ namespace osu.Game.Screens.Play.BreaksOverlay { Anchor = Anchor.Centre, Origin = Anchor.CentreRight, - X = - glowing_offscreen_offset, + X = - glow_icon_offscreen_offset, Icon = Graphics.FontAwesome.fa_chevron_right, - Size = new Vector2(glowing_size), + BlurSigma = new Vector2(glow_icon_blur_sigma), + Size = new Vector2(glow_icon_size), }, rightGlowIcon = new GlowIcon { Anchor = Anchor.Centre, Origin = Anchor.CentreLeft, - X = glowing_offscreen_offset, + X = glow_icon_offscreen_offset, Icon = Graphics.FontAwesome.fa_chevron_left, - Size = new Vector2(glowing_size), + BlurSigma = new Vector2(glow_icon_blur_sigma), + Size = new Vector2(glow_icon_size), }, leftBlurredIcon = new BlurredIcon { Anchor = Anchor.Centre, Origin = Anchor.CentreRight, - X = - blurred_offscreen_offset, + X = - blurred_icon_offscreen_offset, Icon = Graphics.FontAwesome.fa_chevron_right, - Size = new Vector2(blurred_size), + BlurSigma = new Vector2(blurred_icon_blur_sigma), + Size = new Vector2(blurred_icon_size), }, rightBlurredIcon = new BlurredIcon { Anchor = Anchor.Centre, Origin = Anchor.CentreLeft, - X = blurred_offscreen_offset, + X = blurred_icon_offscreen_offset, Icon = Graphics.FontAwesome.fa_chevron_left, - Size = new Vector2(blurred_size), + BlurSigma = new Vector2(blurred_icon_blur_sigma), + Size = new Vector2(blurred_icon_size), }, }; } public void Show(double fadeDuration) { - leftGlowIcon.MoveToX(-glowing_final_offset, fadeDuration, Easing.OutQuint); - rightGlowIcon.MoveToX(glowing_final_offset, fadeDuration, Easing.OutQuint); + leftGlowIcon.MoveToX(-glow_icon_final_offset, fadeDuration, Easing.OutQuint); + rightGlowIcon.MoveToX(glow_icon_final_offset, fadeDuration, Easing.OutQuint); - leftBlurredIcon.MoveToX(-blurred_final_offset, fadeDuration, Easing.OutQuint); - rightBlurredIcon.MoveToX(blurred_final_offset, fadeDuration, Easing.OutQuint); + leftBlurredIcon.MoveToX(-blurred_icon_final_offset, fadeDuration, Easing.OutQuint); + rightBlurredIcon.MoveToX(blurred_icon_final_offset, fadeDuration, Easing.OutQuint); } public void Hide(double fadeDuration) { - leftGlowIcon.MoveToX(-glowing_offscreen_offset, fadeDuration, Easing.OutQuint); - rightGlowIcon.MoveToX(glowing_offscreen_offset, fadeDuration, Easing.OutQuint); + leftGlowIcon.MoveToX(-glow_icon_offscreen_offset, fadeDuration, Easing.OutQuint); + rightGlowIcon.MoveToX(glow_icon_offscreen_offset, fadeDuration, Easing.OutQuint); - leftBlurredIcon.MoveToX(-blurred_offscreen_offset, fadeDuration, Easing.OutQuint); - rightBlurredIcon.MoveToX(blurred_offscreen_offset, fadeDuration, Easing.OutQuint); + leftBlurredIcon.MoveToX(-blurred_icon_offscreen_offset, fadeDuration, Easing.OutQuint); + rightBlurredIcon.MoveToX(blurred_icon_offscreen_offset, fadeDuration, Easing.OutQuint); } } } diff --git a/osu.Game/Screens/Play/BreaksOverlay/BlurredIcon.cs b/osu.Game/Screens/Play/BreaksOverlay/BlurredIcon.cs index 25e6eef1fd..9e69d9d076 100644 --- a/osu.Game/Screens/Play/BreaksOverlay/BlurredIcon.cs +++ b/osu.Game/Screens/Play/BreaksOverlay/BlurredIcon.cs @@ -5,14 +5,13 @@ using OpenTK; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics; using osu.Game.Graphics; +using osu.Framework.Allocation; namespace osu.Game.Screens.Play.BreaksOverlay { public class BlurredIcon : BufferedContainer { - private const int blur_sigma = 20; - - private readonly GlowIcon icon; + private readonly SpriteIcon icon; public FontAwesome Icon { @@ -25,22 +24,29 @@ namespace osu.Game.Screens.Play.BreaksOverlay set { icon.Size = value; - base.Size = value + new Vector2(blur_sigma * 2); + base.Size = value + BlurSigma * 2.5f; + ForceRedraw(); } - get { return icon.Size; } + get { return base.Size; } } public BlurredIcon() { RelativePositionAxes = Axes.X; - BlurSigma = new Vector2(blur_sigma); - Alpha = 0.6f; + Alpha = 0.7f; CacheDrawnFrameBuffer = true; - Child = icon = new GlowIcon + Child = icon = new SpriteIcon { Origin = Anchor.Centre, Anchor = Anchor.Centre, + Shadow = false, }; } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + Colour = colours.BlueLighter; + } } } diff --git a/osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs b/osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs index c0088ce816..1264feff3d 100644 --- a/osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs +++ b/osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs @@ -13,7 +13,7 @@ namespace osu.Game.Screens.Play.BreaksOverlay public class BreakOverlay : Container { private const double fade_duration = BreakPeriod.MIN_BREAK_DURATION / 2; - private const float remaining_time_container_max_size = 0.35f; + private const float remaining_time_container_max_size = 0.3f; private const int vertical_margin = 25; public List Breaks; diff --git a/osu.Game/Screens/Play/BreaksOverlay/GlowIcon.cs b/osu.Game/Screens/Play/BreaksOverlay/GlowIcon.cs index 91e794ff6b..81c2445324 100644 --- a/osu.Game/Screens/Play/BreaksOverlay/GlowIcon.cs +++ b/osu.Game/Screens/Play/BreaksOverlay/GlowIcon.cs @@ -11,25 +11,29 @@ namespace osu.Game.Screens.Play.BreaksOverlay { public class GlowIcon : Container { - private const int blur_sigma = 5; - private readonly SpriteIcon spriteIcon; - private readonly SpriteIcon glowIcon; - private readonly BufferedContainer glowContainer; + private readonly BlurredIcon blurredIcon; public override Vector2 Size { set { - spriteIcon.Size = glowIcon.Size = value; - glowContainer.Size = value + new Vector2(blur_sigma * 2); + blurredIcon.Size = value; + spriteIcon.Size = value - new Vector2(10); //Make it a bit smaller to make blur more visible + blurredIcon.ForceRedraw(); } - get { return spriteIcon.Size; } + get { return base.Size; } + } + + public Vector2 BlurSigma + { + set { blurredIcon.BlurSigma = value; } + get { return blurredIcon.BlurSigma; } } public FontAwesome Icon { - set { spriteIcon.Icon = glowIcon.Icon = value; } + set { spriteIcon.Icon = blurredIcon.Icon = value; } get { return spriteIcon.Icon; } } @@ -39,19 +43,10 @@ namespace osu.Game.Screens.Play.BreaksOverlay AutoSizeAxes = Axes.Both; Children = new Drawable[] { - glowContainer = new BufferedContainer + blurredIcon = new BlurredIcon { Anchor = Anchor.Centre, Origin = Anchor.Centre, - BlurSigma = new Vector2(blur_sigma), - CacheDrawnFrameBuffer = true, - Child = glowIcon = new SpriteIcon - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Shadow = false, - }, - }, spriteIcon = new SpriteIcon { @@ -65,7 +60,7 @@ namespace osu.Game.Screens.Play.BreaksOverlay [BackgroundDependencyLoader] private void load(OsuColour colours) { - glowIcon.Colour = colours.BlueLight; + blurredIcon.Colour = colours.Blue; } } } From 6fe2b64abdc0a7ab551e79e557932851e54cacab Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Fri, 22 Sep 2017 20:50:00 +0300 Subject: [PATCH 0041/1263] Start breakOut animation a bit earlier --- osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs b/osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs index 1264feff3d..27b7dc5408 100644 --- a/osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs +++ b/osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs @@ -87,7 +87,7 @@ namespace osu.Game.Screens.Play.BreaksOverlay { onBreakIn(b); - using (BeginDelayedSequence(b.Duration, true)) + using (BeginDelayedSequence(b.Duration - fade_duration, true)) onBreakOut(); } } From 92eb8e4fa9700640ab322a0e8d850ae37255c5a0 Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Fri, 22 Sep 2017 21:00:45 +0300 Subject: [PATCH 0042/1263] Move blurred icons to a parallax container --- .../Play/BreaksOverlay/ArrowsOverlay.cs | 42 +++++++++++-------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/osu.Game/Screens/Play/BreaksOverlay/ArrowsOverlay.cs b/osu.Game/Screens/Play/BreaksOverlay/ArrowsOverlay.cs index 8ba801f204..9178daac54 100644 --- a/osu.Game/Screens/Play/BreaksOverlay/ArrowsOverlay.cs +++ b/osu.Game/Screens/Play/BreaksOverlay/ArrowsOverlay.cs @@ -4,6 +4,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics; using OpenTK; +using osu.Game.Graphics.Containers; namespace osu.Game.Screens.Play.BreaksOverlay { @@ -48,24 +49,31 @@ namespace osu.Game.Screens.Play.BreaksOverlay BlurSigma = new Vector2(glow_icon_blur_sigma), Size = new Vector2(glow_icon_size), }, - leftBlurredIcon = new BlurredIcon + new ParallaxContainer { - Anchor = Anchor.Centre, - Origin = Anchor.CentreRight, - X = - blurred_icon_offscreen_offset, - Icon = Graphics.FontAwesome.fa_chevron_right, - BlurSigma = new Vector2(blurred_icon_blur_sigma), - Size = new Vector2(blurred_icon_size), - }, - rightBlurredIcon = new BlurredIcon - { - Anchor = Anchor.Centre, - Origin = Anchor.CentreLeft, - X = blurred_icon_offscreen_offset, - Icon = Graphics.FontAwesome.fa_chevron_left, - BlurSigma = new Vector2(blurred_icon_blur_sigma), - Size = new Vector2(blurred_icon_size), - }, + ParallaxAmount = -0.02f, + Children = new Drawable[] + { + leftBlurredIcon = new BlurredIcon + { + Anchor = Anchor.Centre, + Origin = Anchor.CentreRight, + X = - blurred_icon_offscreen_offset, + Icon = Graphics.FontAwesome.fa_chevron_right, + BlurSigma = new Vector2(blurred_icon_blur_sigma), + Size = new Vector2(blurred_icon_size), + }, + rightBlurredIcon = new BlurredIcon + { + Anchor = Anchor.Centre, + Origin = Anchor.CentreLeft, + X = blurred_icon_offscreen_offset, + Icon = Graphics.FontAwesome.fa_chevron_left, + BlurSigma = new Vector2(blurred_icon_blur_sigma), + Size = new Vector2(blurred_icon_size), + }, + } + } }; } From d73b40768e50426ed44349da7a6ad8d5f13fb143 Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Fri, 22 Sep 2017 21:12:58 +0300 Subject: [PATCH 0043/1263] More arrow adjustments to match the design --- osu.Game/Screens/Play/BreaksOverlay/ArrowsOverlay.cs | 8 +++++--- osu.Game/Screens/Play/BreaksOverlay/BlurredIcon.cs | 1 - osu.Game/Screens/Play/BreaksOverlay/GlowIcon.cs | 3 +-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/osu.Game/Screens/Play/BreaksOverlay/ArrowsOverlay.cs b/osu.Game/Screens/Play/BreaksOverlay/ArrowsOverlay.cs index 9178daac54..87dc8caf13 100644 --- a/osu.Game/Screens/Play/BreaksOverlay/ArrowsOverlay.cs +++ b/osu.Game/Screens/Play/BreaksOverlay/ArrowsOverlay.cs @@ -10,9 +10,9 @@ namespace osu.Game.Screens.Play.BreaksOverlay { public class ArrowsOverlay : Container { - private const int glow_icon_size = 65; - private const int glow_icon_blur_sigma = 8; - private const float glow_icon_final_offset = 0.2f; + private const int glow_icon_size = 60; + private const int glow_icon_blur_sigma = 10; + private const float glow_icon_final_offset = 0.22f; private const float glow_icon_offscreen_offset = 0.6f; private const int blurred_icon_blur_sigma = 20; @@ -58,6 +58,7 @@ namespace osu.Game.Screens.Play.BreaksOverlay { Anchor = Anchor.Centre, Origin = Anchor.CentreRight, + Alpha = 0.7f, X = - blurred_icon_offscreen_offset, Icon = Graphics.FontAwesome.fa_chevron_right, BlurSigma = new Vector2(blurred_icon_blur_sigma), @@ -67,6 +68,7 @@ namespace osu.Game.Screens.Play.BreaksOverlay { Anchor = Anchor.Centre, Origin = Anchor.CentreLeft, + Alpha = 0.7f, X = blurred_icon_offscreen_offset, Icon = Graphics.FontAwesome.fa_chevron_left, BlurSigma = new Vector2(blurred_icon_blur_sigma), diff --git a/osu.Game/Screens/Play/BreaksOverlay/BlurredIcon.cs b/osu.Game/Screens/Play/BreaksOverlay/BlurredIcon.cs index 9e69d9d076..f16e7c7b96 100644 --- a/osu.Game/Screens/Play/BreaksOverlay/BlurredIcon.cs +++ b/osu.Game/Screens/Play/BreaksOverlay/BlurredIcon.cs @@ -33,7 +33,6 @@ namespace osu.Game.Screens.Play.BreaksOverlay public BlurredIcon() { RelativePositionAxes = Axes.X; - Alpha = 0.7f; CacheDrawnFrameBuffer = true; Child = icon = new SpriteIcon { diff --git a/osu.Game/Screens/Play/BreaksOverlay/GlowIcon.cs b/osu.Game/Screens/Play/BreaksOverlay/GlowIcon.cs index 81c2445324..b27eef632c 100644 --- a/osu.Game/Screens/Play/BreaksOverlay/GlowIcon.cs +++ b/osu.Game/Screens/Play/BreaksOverlay/GlowIcon.cs @@ -18,8 +18,7 @@ namespace osu.Game.Screens.Play.BreaksOverlay { set { - blurredIcon.Size = value; - spriteIcon.Size = value - new Vector2(10); //Make it a bit smaller to make blur more visible + blurredIcon.Size = spriteIcon.Size = value; blurredIcon.ForceRedraw(); } get { return base.Size; } From ced620421913f255f20d271414f8c9206c3240a5 Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Fri, 22 Sep 2017 22:10:05 +0300 Subject: [PATCH 0044/1263] oops --- osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs | 2 +- osu.Game/Screens/Play/BreaksOverlay/RemainingTimeCounter.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs b/osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs index 27b7dc5408..bc0a0a2242 100644 --- a/osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs +++ b/osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs @@ -101,7 +101,7 @@ namespace osu.Game.Screens.Play.BreaksOverlay remainingTimeBox .ResizeWidthTo(remaining_time_container_max_size, fade_duration, Easing.OutQuint) .Then() - .ResizeWidthTo(0, b.Duration); + .ResizeWidthTo(0, b.Duration - fade_duration); Scheduler.AddDelayed(() => remainingTimeCounter.StartCounting(b.EndTime), b.StartTime); remainingTimeCounter.FadeIn(fade_duration); diff --git a/osu.Game/Screens/Play/BreaksOverlay/RemainingTimeCounter.cs b/osu.Game/Screens/Play/BreaksOverlay/RemainingTimeCounter.cs index fbf3e10688..ab6ee5ea5c 100644 --- a/osu.Game/Screens/Play/BreaksOverlay/RemainingTimeCounter.cs +++ b/osu.Game/Screens/Play/BreaksOverlay/RemainingTimeCounter.cs @@ -46,7 +46,7 @@ namespace osu.Game.Screens.Play.BreaksOverlay var currentTime = Clock.CurrentTime; if (currentTime < remainingTime) { - int currentSecond = (int)Math.Floor((remainingTime - Clock.CurrentTime) / 1000.0) + 1; + int currentSecond = (int)Math.Floor((remainingTime - Clock.CurrentTime) / 1000.0); if (currentSecond != previousSecond) { counter.Text = currentSecond.ToString(); From 2da3ea00b6a0bb550e2ab3a642632e6e363d6c01 Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Sat, 23 Sep 2017 16:42:18 +0300 Subject: [PATCH 0045/1263] Bind break overlay to accuracy --- .../Play/BreaksOverlay/BreakOverlay.cs | 6 ++ .../Play/BreaksOverlay/InfoContainer.cs | 56 ++---------- .../Screens/Play/BreaksOverlay/InfoLine.cs | 89 +++++++++++++++++++ osu.Game/Screens/Play/Player.cs | 5 +- osu.Game/osu.Game.csproj | 1 + 5 files changed, 109 insertions(+), 48 deletions(-) create mode 100644 osu.Game/Screens/Play/BreaksOverlay/InfoLine.cs diff --git a/osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs b/osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs index bc0a0a2242..e9dd112557 100644 --- a/osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs +++ b/osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs @@ -6,6 +6,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Game.Beatmaps.Timing; +using osu.Game.Rulesets.Scoring; using System.Collections.Generic; namespace osu.Game.Screens.Play.BreaksOverlay @@ -119,5 +120,10 @@ namespace osu.Game.Screens.Play.BreaksOverlay info.FadeOut(fade_duration); arrowsOverlay.Hide(fade_duration); } + + public void BindProcessor(ScoreProcessor processor) + { + info.AccuracyDisplay.Current.BindTo(processor.Accuracy); + } } } diff --git a/osu.Game/Screens/Play/BreaksOverlay/InfoContainer.cs b/osu.Game/Screens/Play/BreaksOverlay/InfoContainer.cs index 75fcfcba0e..dc85fabbe0 100644 --- a/osu.Game/Screens/Play/BreaksOverlay/InfoContainer.cs +++ b/osu.Game/Screens/Play/BreaksOverlay/InfoContainer.cs @@ -2,16 +2,18 @@ // 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.Game.Graphics; using osu.Game.Graphics.Sprites; namespace osu.Game.Screens.Play.BreaksOverlay { public class InfoContainer : FillFlowContainer { + public PercentageInfoLine AccuracyDisplay; + public InfoLine RankDisplay; + public InfoLine GradeDisplay; + public InfoContainer() { AutoSizeAxes = Axes.Both; @@ -28,60 +30,20 @@ namespace osu.Game.Screens.Play.BreaksOverlay TextSize = 15, Font = "Exo2.0-Black", }, - new FillFlowContainer + new FillFlowContainer { AutoSizeAxes = Axes.Both, Origin = Anchor.TopCentre, Anchor = Anchor.TopCentre, Direction = FillDirection.Vertical, - Children = new [] + Children = new Drawable[] { - new InfoLine(@"Accuracy", @"-"), - new InfoLine(@"Rank", @"-"), - new InfoLine(@"Grade", @"-"), + AccuracyDisplay = new PercentageInfoLine(@"Accuracy"), + RankDisplay = new InfoLine(@"Rank", @"#"), + GradeDisplay = new InfoLine(@"Grade"), }, } }; } - - private class InfoLine : Container - { - private const int margin = 2; - - private readonly OsuSpriteText text; - private readonly OsuSpriteText valueText; - - public InfoLine(string name, string value) - { - AutoSizeAxes = Axes.Y; - Children = new Drawable[] - { - text = new OsuSpriteText - { - Anchor = Anchor.Centre, - Origin = Anchor.CentreRight, - Text = name, - TextSize = 17, - Margin = new MarginPadding { Right = margin } - }, - valueText = new OsuSpriteText - { - Anchor = Anchor.Centre, - Origin = Anchor.CentreLeft, - Text = value, - TextSize = 17, - Font = "Exo2.0-Bold", - Margin = new MarginPadding { Left = margin } - } - }; - } - - [BackgroundDependencyLoader] - private void load(OsuColour colours) - { - text.Colour = colours.Yellow; - valueText.Colour = colours.YellowLight; - } - } } } diff --git a/osu.Game/Screens/Play/BreaksOverlay/InfoLine.cs b/osu.Game/Screens/Play/BreaksOverlay/InfoLine.cs new file mode 100644 index 0000000000..0af766b321 --- /dev/null +++ b/osu.Game/Screens/Play/BreaksOverlay/InfoLine.cs @@ -0,0 +1,89 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Allocation; +using osu.Framework.Configuration; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; + +namespace osu.Game.Screens.Play.BreaksOverlay +{ + public class InfoLine : Container + where T : struct + { + private const int margin = 2; + + public Bindable Current = new Bindable(); + + private readonly OsuSpriteText text; + private readonly OsuSpriteText valueText; + + private readonly string prefix; + + public InfoLine(string name, string prefix = @"") + { + this.prefix = prefix; + + AutoSizeAxes = Axes.Y; + Children = new Drawable[] + { + text = new OsuSpriteText + { + Anchor = Anchor.Centre, + Origin = Anchor.CentreRight, + Text = name, + TextSize = 17, + Margin = new MarginPadding { Right = margin } + }, + valueText = new OsuSpriteText + { + Anchor = Anchor.Centre, + Origin = Anchor.CentreLeft, + Text = prefix + @"-", + TextSize = 17, + Font = "Exo2.0-Bold", + Margin = new MarginPadding { Left = margin } + } + }; + + Current.ValueChanged += currentValueChanged; + } + + private void currentValueChanged(T newValue) + { + valueText.Text = prefix + Format(newValue); + } + + protected virtual string Format(T count) => count.ToString(); + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + text.Colour = colours.Yellow; + valueText.Colour = colours.YellowLight; + } + } + + public class PercentageInfoLine : InfoLine + { + public PercentageInfoLine(string name, string prefix = "") : base(name, prefix) + { + } + + protected override string Format(double count) => $@"{count:P2}"; + } + + public enum Grade + { + SSplus, + SS, + Splus, + S, + A, + B, + C, + F + } +} diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 86aa00875c..d8ddee0ac3 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -67,6 +67,7 @@ namespace osu.Game.Screens.Play #endregion + private BreakOverlay breakOverlay; private HUDOverlay hudOverlay; private FailOverlay failOverlay; @@ -173,7 +174,7 @@ namespace osu.Game.Screens.Play Anchor = Anchor.Centre, Origin = Anchor.Centre }, - new BreakOverlay(beatmap.BeatmapInfo.LetterboxInBreaks) + breakOverlay = new BreakOverlay(beatmap.BeatmapInfo.LetterboxInBreaks) { Anchor = Anchor.Centre, Origin = Anchor.Centre, @@ -211,6 +212,8 @@ namespace osu.Game.Screens.Play hudOverlay.ModDisplay.Current.BindTo(working.Mods); + breakOverlay.BindProcessor(scoreProcessor); + // Bind ScoreProcessor to ourselves scoreProcessor.AllJudged += onCompletion; scoreProcessor.Failed += onFail; diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index dd823f6144..2cbbc42061 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -280,6 +280,7 @@ + From a69bef8ec075d52e721ac3f0e89b2ee2e3ff4b11 Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Sat, 23 Sep 2017 16:51:31 +0300 Subject: [PATCH 0046/1263] Use existing enum instead of my own --- osu.Game/Screens/Play/BreaksOverlay/InfoContainer.cs | 5 +++-- osu.Game/Screens/Play/BreaksOverlay/InfoLine.cs | 12 ------------ 2 files changed, 3 insertions(+), 14 deletions(-) diff --git a/osu.Game/Screens/Play/BreaksOverlay/InfoContainer.cs b/osu.Game/Screens/Play/BreaksOverlay/InfoContainer.cs index dc85fabbe0..f6c47d757f 100644 --- a/osu.Game/Screens/Play/BreaksOverlay/InfoContainer.cs +++ b/osu.Game/Screens/Play/BreaksOverlay/InfoContainer.cs @@ -5,6 +5,7 @@ using OpenTK; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Graphics.Sprites; +using osu.Game.Rulesets.Scoring; namespace osu.Game.Screens.Play.BreaksOverlay { @@ -12,7 +13,7 @@ namespace osu.Game.Screens.Play.BreaksOverlay { public PercentageInfoLine AccuracyDisplay; public InfoLine RankDisplay; - public InfoLine GradeDisplay; + public InfoLine GradeDisplay; public InfoContainer() { @@ -40,7 +41,7 @@ namespace osu.Game.Screens.Play.BreaksOverlay { AccuracyDisplay = new PercentageInfoLine(@"Accuracy"), RankDisplay = new InfoLine(@"Rank", @"#"), - GradeDisplay = new InfoLine(@"Grade"), + GradeDisplay = new InfoLine(@"Grade"), }, } }; diff --git a/osu.Game/Screens/Play/BreaksOverlay/InfoLine.cs b/osu.Game/Screens/Play/BreaksOverlay/InfoLine.cs index 0af766b321..089dad6c38 100644 --- a/osu.Game/Screens/Play/BreaksOverlay/InfoLine.cs +++ b/osu.Game/Screens/Play/BreaksOverlay/InfoLine.cs @@ -74,16 +74,4 @@ namespace osu.Game.Screens.Play.BreaksOverlay protected override string Format(double count) => $@"{count:P2}"; } - - public enum Grade - { - SSplus, - SS, - Splus, - S, - A, - B, - C, - F - } } From 0615f375e1b206a55eb36fe0f396127cb0a10be2 Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Sat, 23 Sep 2017 19:52:44 +0300 Subject: [PATCH 0047/1263] Show current grade --- osu.Game/Rulesets/Scoring/ScoreProcessor.cs | 4 ++-- osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs | 1 + osu.Game/Screens/Play/BreaksOverlay/InfoContainer.cs | 5 ++--- osu.Game/Screens/Play/BreaksOverlay/InfoLine.cs | 10 ++++++++++ 4 files changed, 15 insertions(+), 5 deletions(-) diff --git a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs index deb87e92d8..e8dd87a6a6 100644 --- a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs +++ b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs @@ -76,7 +76,7 @@ namespace osu.Game.Rulesets.Scoring Combo.ValueChanged += delegate { HighestCombo.Value = Math.Max(HighestCombo.Value, Combo.Value); }; } - private ScoreRank rankFrom(double acc) + public static ScoreRank RankFrom(double acc) { if (acc == 1) return ScoreRank.X; @@ -142,7 +142,7 @@ namespace osu.Game.Rulesets.Scoring score.Combo = Combo; score.MaxCombo = HighestCombo; score.Accuracy = Accuracy; - score.Rank = rankFrom(Accuracy); + score.Rank = RankFrom(Accuracy); score.Date = DateTimeOffset.Now; score.Health = Health; } diff --git a/osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs b/osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs index e9dd112557..33fcebf3bb 100644 --- a/osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs +++ b/osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs @@ -124,6 +124,7 @@ namespace osu.Game.Screens.Play.BreaksOverlay public void BindProcessor(ScoreProcessor processor) { info.AccuracyDisplay.Current.BindTo(processor.Accuracy); + info.GradeDisplay.Current.BindTo(processor.Accuracy); } } } diff --git a/osu.Game/Screens/Play/BreaksOverlay/InfoContainer.cs b/osu.Game/Screens/Play/BreaksOverlay/InfoContainer.cs index f6c47d757f..4cff9372a3 100644 --- a/osu.Game/Screens/Play/BreaksOverlay/InfoContainer.cs +++ b/osu.Game/Screens/Play/BreaksOverlay/InfoContainer.cs @@ -5,7 +5,6 @@ using OpenTK; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Graphics.Sprites; -using osu.Game.Rulesets.Scoring; namespace osu.Game.Screens.Play.BreaksOverlay { @@ -13,7 +12,7 @@ namespace osu.Game.Screens.Play.BreaksOverlay { public PercentageInfoLine AccuracyDisplay; public InfoLine RankDisplay; - public InfoLine GradeDisplay; + public GradeInfoLine GradeDisplay; public InfoContainer() { @@ -41,7 +40,7 @@ namespace osu.Game.Screens.Play.BreaksOverlay { AccuracyDisplay = new PercentageInfoLine(@"Accuracy"), RankDisplay = new InfoLine(@"Rank", @"#"), - GradeDisplay = new InfoLine(@"Grade"), + GradeDisplay = new GradeInfoLine(@"Grade"), }, } }; diff --git a/osu.Game/Screens/Play/BreaksOverlay/InfoLine.cs b/osu.Game/Screens/Play/BreaksOverlay/InfoLine.cs index 089dad6c38..bf486e2480 100644 --- a/osu.Game/Screens/Play/BreaksOverlay/InfoLine.cs +++ b/osu.Game/Screens/Play/BreaksOverlay/InfoLine.cs @@ -7,6 +7,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; +using osu.Game.Rulesets.Scoring; namespace osu.Game.Screens.Play.BreaksOverlay { @@ -74,4 +75,13 @@ namespace osu.Game.Screens.Play.BreaksOverlay protected override string Format(double count) => $@"{count:P2}"; } + + public class GradeInfoLine : InfoLine + { + public GradeInfoLine(string name, string prefix = "") : base(name, prefix) + { + } + + protected override string Format(double count) => $@"{ScoreProcessor.RankFrom(count)}"; + } } From 94269e119e3838914c5ab5c9f7ec4d65594d7553 Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Sat, 23 Sep 2017 19:59:34 +0300 Subject: [PATCH 0048/1263] Reset text only if it has been changed --- osu.Game/Screens/Play/BreaksOverlay/InfoLine.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/BreaksOverlay/InfoLine.cs b/osu.Game/Screens/Play/BreaksOverlay/InfoLine.cs index bf486e2480..f74329ceb3 100644 --- a/osu.Game/Screens/Play/BreaksOverlay/InfoLine.cs +++ b/osu.Game/Screens/Play/BreaksOverlay/InfoLine.cs @@ -54,7 +54,12 @@ namespace osu.Game.Screens.Play.BreaksOverlay private void currentValueChanged(T newValue) { - valueText.Text = prefix + Format(newValue); + var newText = prefix + Format(newValue); + + if (valueText.Text == newText) + return; + + valueText.Text = newText; } protected virtual string Format(T count) => count.ToString(); From 1f2a82b7ab3b3dba01bf1a44e3fe5e4b15e31db8 Mon Sep 17 00:00:00 2001 From: Jorolf Date: Tue, 26 Sep 2017 12:21:00 +0200 Subject: [PATCH 0049/1263] make PreviewPlaying readonly instead of abstract --- osu.Game/Overlays/Direct/DirectGridPanel.cs | 1 - osu.Game/Overlays/Direct/DirectListPanel.cs | 1 - osu.Game/Overlays/Direct/DirectPanel.cs | 2 +- 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/osu.Game/Overlays/Direct/DirectGridPanel.cs b/osu.Game/Overlays/Direct/DirectGridPanel.cs index 24ccd8b7eb..3c51235fad 100644 --- a/osu.Game/Overlays/Direct/DirectGridPanel.cs +++ b/osu.Game/Overlays/Direct/DirectGridPanel.cs @@ -27,7 +27,6 @@ namespace osu.Game.Overlays.Direct private Box progressBar; protected override PlayButton PlayButton => playButton; - public override Bindable PreviewPlaying { get; } = new Bindable(); public DirectGridPanel(BeatmapSetInfo beatmap) : base(beatmap) { diff --git a/osu.Game/Overlays/Direct/DirectListPanel.cs b/osu.Game/Overlays/Direct/DirectListPanel.cs index 7112e927bd..3aa8c8a7c2 100644 --- a/osu.Game/Overlays/Direct/DirectListPanel.cs +++ b/osu.Game/Overlays/Direct/DirectListPanel.cs @@ -35,7 +35,6 @@ namespace osu.Game.Overlays.Direct private Box progressBar; protected override PlayButton PlayButton => playButton; - public override Bindable PreviewPlaying { get; } = new Bindable(); [BackgroundDependencyLoader] private void load(LocalisationEngine localisation, OsuColour colours) diff --git a/osu.Game/Overlays/Direct/DirectPanel.cs b/osu.Game/Overlays/Direct/DirectPanel.cs index 24cd8dc54e..65808c32a1 100644 --- a/osu.Game/Overlays/Direct/DirectPanel.cs +++ b/osu.Game/Overlays/Direct/DirectPanel.cs @@ -39,7 +39,7 @@ namespace osu.Game.Overlays.Direct private BeatmapManager beatmaps; private NotificationOverlay notifications; - public abstract Bindable PreviewPlaying { get; } + public readonly Bindable PreviewPlaying = new Bindable(); protected abstract PlayButton PlayButton { get; } protected override Container Content => content; From adebe166d43431671f1ccac4ced5566debdd1b4d Mon Sep 17 00:00:00 2001 From: Shawdooow Date: Tue, 26 Sep 2017 12:13:34 -0400 Subject: [PATCH 0050/1263] slider bouncers --- .../Objects/Drawables/DrawableSlider.cs | 40 +++++---- .../Drawables/DrawableSliderBouncer.cs | 84 +++++++++++++++++++ osu.Game.Rulesets.Osu/Objects/Slider.cs | 31 +++++++ .../Objects/SliderBouncer.cs | 10 +++ .../osu.Game.Rulesets.Osu.csproj | 2 + 5 files changed, 150 insertions(+), 17 deletions(-) create mode 100644 osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderBouncer.cs create mode 100644 osu.Game.Rulesets.Osu/Objects/SliderBouncer.cs diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs index c5155d1e10..61d4ec493c 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs @@ -9,6 +9,7 @@ using System.Collections.Generic; using System.Linq; using osu.Framework.Graphics.Containers; using osu.Game.Rulesets.Osu.Judgements; +using osu.Game.Rulesets.Classic.Objects.Drawables; namespace osu.Game.Rulesets.Osu.Objects.Drawables { @@ -21,15 +22,13 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables private readonly List components = new List(); private readonly Container ticks; + private readonly Container bouncers; private readonly SliderBody body; private readonly SliderBall ball; - private readonly SliderBouncer bouncer2; - public DrawableSlider(Slider s) : base(s) { - SliderBouncer bouncer1; slider = s; Children = new Drawable[] @@ -41,16 +40,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables PathWidth = s.Scale * 64, }, ticks = new Container(), - bouncer1 = new SliderBouncer(s, false) - { - Position = s.Curve.PositionAt(1), - Scale = new Vector2(s.Scale), - }, - bouncer2 = new SliderBouncer(s, true) - { - Position = s.StackedPosition, - Scale = new Vector2(s.Scale), - }, + bouncers = new Container(), ball = new SliderBall(s) { Scale = new Vector2(s.Scale), @@ -70,8 +60,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables components.Add(body); components.Add(ball); - components.Add(bouncer1); - components.Add(bouncer2); AddNested(initialCircle); @@ -92,14 +80,34 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables ticks.Add(drawableTick); AddNested(drawableTick); } + + foreach (var bouncer in s.Bouncers) + { + var repeatStartTime = s.StartTime + bouncer.RepeatIndex * repeatDuration; + var fadeInTime = repeatStartTime + (bouncer.StartTime - repeatStartTime) / 2 - (bouncer.RepeatIndex == 0 ? TIME_FADEIN : TIME_FADEIN / 2); + var fadeOutTime = repeatStartTime + repeatDuration; + + var drawableBouncer = new DrawableSliderBouncer(bouncer, this) + { + FadeInTime = fadeInTime, + FadeOutTime = fadeOutTime, + Position = bouncer.Position, + }; + + bouncers.Add(drawableBouncer); + AddNested(drawableBouncer); + } } private int currentRepeat; + public bool Tracking; protected override void Update() { base.Update(); + Tracking = ball.Tracking; + double progress = MathHelper.Clamp((Time.Current - slider.StartTime) / slider.Duration, 0, 1); int repeat = slider.RepeatAt(progress); @@ -112,8 +120,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables currentRepeat = repeat; } - bouncer2.Position = slider.Curve.PositionAt(body.SnakedEnd ?? 0); - //todo: we probably want to reconsider this before adding scoring, but it looks and feels nice. if (!initialCircle.Judgements.Any(j => j.IsHit)) initialCircle.Position = slider.Curve.PositionAt(progress); diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderBouncer.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderBouncer.cs new file mode 100644 index 0000000000..e1f668da86 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderBouncer.cs @@ -0,0 +1,84 @@ +// 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.Graphics; +using osu.Game.Rulesets.Objects.Drawables; +using OpenTK; +using OpenTK.Graphics; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Sprites; +using osu.Game.Graphics; +using osu.Game.Rulesets.Osu.Objects.Drawables; +using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Rulesets.Osu.Judgements; + +namespace osu.Game.Rulesets.Classic.Objects.Drawables +{ + public class DrawableSliderBouncer : DrawableOsuHitObject + { + private readonly SliderBouncer sliderBouncer; + private readonly DrawableSlider drawableSlider; + + public double FadeInTime; + public double FadeOutTime; + + public override bool RemoveWhenNotAlive => false; + + public DrawableSliderBouncer(SliderBouncer sliderBouncer, DrawableSlider drawableSlider) : base(sliderBouncer) + { + this.sliderBouncer = sliderBouncer; + this.drawableSlider = drawableSlider; + + AutoSizeAxes = Axes.Both; + Blending = BlendingMode.Additive; + Origin = Anchor.Centre; + + Children = new Drawable[] + { + new SpriteIcon + { + Icon = FontAwesome.fa_eercast, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Size = new Vector2(32), + } + }; + } + + protected override void CheckForJudgements(bool userTriggered, double timeOffset) + { + if (sliderBouncer.StartTime <= Time.Current) + AddJudgement(new OsuJudgement { Result = drawableSlider.Tracking ? HitResult.Great : HitResult.Miss }); + } + + protected override void UpdatePreemptState() + { + var animIn = Math.Min(150, sliderBouncer.StartTime - FadeInTime); + + this.Animate( + d => d.FadeIn(animIn), + d => d.ScaleTo(0.5f).ScaleTo(1.2f, animIn) + ).Then( + d => d.ScaleTo(1, 150, Easing.Out) + ); + } + + protected override void UpdateCurrentState(ArmedState state) + { + switch (state) + { + case ArmedState.Idle: + this.Delay(FadeOutTime - sliderBouncer.StartTime).FadeOut(); + break; + case ArmedState.Miss: + this.FadeOut(160); + break; + case ArmedState.Hit: + this.FadeOut(120, Easing.OutQuint) + .ScaleTo(Scale * 1.5f, 120, Easing.OutQuint); + break; + } + } + } +} diff --git a/osu.Game.Rulesets.Osu/Objects/Slider.cs b/osu.Game.Rulesets.Osu/Objects/Slider.cs index 056bde4005..b501e8e86a 100644 --- a/osu.Game.Rulesets.Osu/Objects/Slider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Slider.cs @@ -61,6 +61,7 @@ namespace osu.Game.Rulesets.Osu.Objects public double Velocity; public double TickDistance; + public double BouncerDistance; public override void ApplyDefaults(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) { @@ -73,6 +74,7 @@ namespace osu.Game.Rulesets.Osu.Objects Velocity = scoringDistance / timingPoint.BeatLength; TickDistance = scoringDistance / difficulty.SliderTickRate; + BouncerDistance = Distance; } public Vector2 PositionAt(double progress) => Curve.PositionAt(ProgressAt(progress)); @@ -131,5 +133,34 @@ namespace osu.Game.Rulesets.Osu.Objects } } } + public IEnumerable Bouncers + { + get + { + var length = Curve.Distance; + var bouncerDistance = Math.Min(BouncerDistance, length); + var repeatDuration = length / Velocity; + + for (var repeat = 0; repeat < RepeatCount; repeat++) + { + if (repeat > 0) + for (var d = bouncerDistance; d <= length; d += bouncerDistance) + { + var repeatStartTime = StartTime + repeat * repeatDuration; + var distanceProgress = d / length; + + yield return new SliderBouncer + { + RepeatIndex = repeat, + StartTime = repeatStartTime, + Position = Curve.PositionAt(distanceProgress), + StackHeight = StackHeight, + Scale = Scale, + ComboColour = ComboColour, + }; + } + } + } + } } } diff --git a/osu.Game.Rulesets.Osu/Objects/SliderBouncer.cs b/osu.Game.Rulesets.Osu/Objects/SliderBouncer.cs new file mode 100644 index 0000000000..da98cc8422 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Objects/SliderBouncer.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 class SliderBouncer : OsuHitObject + { + public int RepeatIndex { get; set; } + } +} diff --git a/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj b/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj index 300000754c..f12d932acb 100644 --- a/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj +++ b/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj @@ -53,6 +53,7 @@ + @@ -72,6 +73,7 @@ + From b5ad6ae73536a82c4536832ba1fc95497665287a Mon Sep 17 00:00:00 2001 From: Shawdooow Date: Tue, 26 Sep 2017 12:21:39 -0400 Subject: [PATCH 0051/1263] appveyor fixes --- .../Objects/Drawables/DrawableSlider.cs | 9 ++++----- .../Objects/Drawables/DrawableSliderBouncer.cs | 7 +------ 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs index 61d4ec493c..2833cc81bf 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs @@ -9,7 +9,6 @@ using System.Collections.Generic; using System.Linq; using osu.Framework.Graphics.Containers; using osu.Game.Rulesets.Osu.Judgements; -using osu.Game.Rulesets.Classic.Objects.Drawables; namespace osu.Game.Rulesets.Osu.Objects.Drawables { @@ -132,12 +131,12 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables { if (!userTriggered && Time.Current >= slider.EndTime) { - var ticksCount = ticks.Children.Count + 1; - var ticksHit = ticks.Children.Count(t => t.Judgements.Any(j => j.IsHit)); + var judgementsCount = ticks.Children.Count + bouncers.Children.Count + 1; + var judgementsHit = ticks.Children.Count(t => t.Judgements.Any(j => j.IsHit)) + bouncers.Children.Count(t => t.Judgements.Any(j => j.IsHit)); if (initialCircle.Judgements.Any(j => j.IsHit)) - ticksHit++; + judgementsHit++; - var hitFraction = (double)ticksHit / ticksCount; + var hitFraction = (double)judgementsHit / judgementsCount; if (hitFraction == 1 && initialCircle.Judgements.Any(j => j.Result == HitResult.Great)) AddJudgement(new OsuJudgement { Result = HitResult.Great }); else if (hitFraction >= 0.5 && initialCircle.Judgements.Any(j => j.Result >= HitResult.Good)) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderBouncer.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderBouncer.cs index e1f668da86..45be022027 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderBouncer.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderBouncer.cs @@ -5,15 +5,10 @@ using System; using osu.Framework.Graphics; using osu.Game.Rulesets.Objects.Drawables; using OpenTK; -using OpenTK.Graphics; -using osu.Framework.Graphics.Shapes; -using osu.Framework.Graphics.Sprites; using osu.Game.Graphics; -using osu.Game.Rulesets.Osu.Objects.Drawables; -using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Judgements; -namespace osu.Game.Rulesets.Classic.Objects.Drawables +namespace osu.Game.Rulesets.Osu.Objects.Drawables { public class DrawableSliderBouncer : DrawableOsuHitObject { From 801fa391457d2c4e5bd3a985206028513b0b099d Mon Sep 17 00:00:00 2001 From: Shawdooow Date: Tue, 26 Sep 2017 12:23:13 -0400 Subject: [PATCH 0052/1263] remove old `SliderBouncer` --- .../Objects/Drawables/Pieces/SliderBouncer.cs | 52 ------------------- .../osu.Game.Rulesets.Osu.csproj | 1 - 2 files changed, 53 deletions(-) delete mode 100644 osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBouncer.cs diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBouncer.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBouncer.cs deleted file mode 100644 index a06aaff7fb..0000000000 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBouncer.cs +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (c) 2007-2017 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Game.Graphics; -using OpenTK; - -namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces -{ - public class SliderBouncer : Container, ISliderProgress - { - private readonly Slider slider; - private readonly bool isEnd; - private readonly SpriteIcon icon; - - public SliderBouncer(Slider slider, bool isEnd) - { - this.slider = slider; - this.isEnd = isEnd; - - AutoSizeAxes = Axes.Both; - Blending = BlendingMode.Additive; - Origin = Anchor.Centre; - - Children = new Drawable[] - { - icon = new SpriteIcon - { - Icon = FontAwesome.fa_eercast, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Size = new Vector2(48), - } - }; - } - - protected override void LoadComplete() - { - base.LoadComplete(); - icon.Spin(1000, RotationDirection.Clockwise); - } - - public void UpdateProgress(double progress, int repeat) - { - if (Time.Current < slider.StartTime) - Alpha = 0; - - Alpha = repeat + 1 < slider.RepeatCount && repeat % 2 == (isEnd ? 0 : 1) ? 1 : 0; - } - } -} diff --git a/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj b/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj index f12d932acb..662fba49d4 100644 --- a/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj +++ b/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj @@ -67,7 +67,6 @@ - From c696f7457883c11e8c771096e6bb36a1efd11ec6 Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Wed, 27 Sep 2017 01:10:48 +0300 Subject: [PATCH 0053/1263] Fix broken testcase and apply suggested changes --- .../Screens/Play/BreaksOverlay/ArrowsOverlay.cs | 4 ++-- .../Screens/Play/BreaksOverlay/BreakOverlay.cs | 2 +- .../Screens/Play/BreaksOverlay/InfoContainer.cs | 8 ++++---- .../Play/BreaksOverlay/LetterboxOverlay.cs | 16 ++++++++-------- .../Play/BreaksOverlay/RemainingTimeCounter.cs | 10 +++++----- 5 files changed, 20 insertions(+), 20 deletions(-) diff --git a/osu.Game/Screens/Play/BreaksOverlay/ArrowsOverlay.cs b/osu.Game/Screens/Play/BreaksOverlay/ArrowsOverlay.cs index 87dc8caf13..9d729826de 100644 --- a/osu.Game/Screens/Play/BreaksOverlay/ArrowsOverlay.cs +++ b/osu.Game/Screens/Play/BreaksOverlay/ArrowsOverlay.cs @@ -35,7 +35,7 @@ namespace osu.Game.Screens.Play.BreaksOverlay { Anchor = Anchor.Centre, Origin = Anchor.CentreRight, - X = - glow_icon_offscreen_offset, + X = -glow_icon_offscreen_offset, Icon = Graphics.FontAwesome.fa_chevron_right, BlurSigma = new Vector2(glow_icon_blur_sigma), Size = new Vector2(glow_icon_size), @@ -59,7 +59,7 @@ namespace osu.Game.Screens.Play.BreaksOverlay Anchor = Anchor.Centre, Origin = Anchor.CentreRight, Alpha = 0.7f, - X = - blurred_icon_offscreen_offset, + X = -blurred_icon_offscreen_offset, Icon = Graphics.FontAwesome.fa_chevron_right, BlurSigma = new Vector2(blurred_icon_blur_sigma), Size = new Vector2(blurred_icon_size), diff --git a/osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs b/osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs index 33fcebf3bb..90321df9d6 100644 --- a/osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs +++ b/osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs @@ -104,7 +104,7 @@ namespace osu.Game.Screens.Play.BreaksOverlay .Then() .ResizeWidthTo(0, b.Duration - fade_duration); - Scheduler.AddDelayed(() => remainingTimeCounter.StartCounting(b.EndTime), b.StartTime); + Scheduler.AddDelayed(() => remainingTimeCounter.StartCounting(b.EndTime), b.StartTime - Clock.CurrentTime); remainingTimeCounter.FadeIn(fade_duration); info.FadeIn(fade_duration); diff --git a/osu.Game/Screens/Play/BreaksOverlay/InfoContainer.cs b/osu.Game/Screens/Play/BreaksOverlay/InfoContainer.cs index 4cff9372a3..8d2bec06aa 100644 --- a/osu.Game/Screens/Play/BreaksOverlay/InfoContainer.cs +++ b/osu.Game/Screens/Play/BreaksOverlay/InfoContainer.cs @@ -26,7 +26,7 @@ namespace osu.Game.Screens.Play.BreaksOverlay { Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, - Text = @"current progress".ToUpper(), + Text = "current progress".ToUpper(), TextSize = 15, Font = "Exo2.0-Black", }, @@ -38,9 +38,9 @@ namespace osu.Game.Screens.Play.BreaksOverlay Direction = FillDirection.Vertical, Children = new Drawable[] { - AccuracyDisplay = new PercentageInfoLine(@"Accuracy"), - RankDisplay = new InfoLine(@"Rank", @"#"), - GradeDisplay = new GradeInfoLine(@"Grade"), + AccuracyDisplay = new PercentageInfoLine("Accuracy"), + RankDisplay = new InfoLine("Rank", @"#"), + GradeDisplay = new GradeInfoLine("Grade"), }, } }; diff --git a/osu.Game/Screens/Play/BreaksOverlay/LetterboxOverlay.cs b/osu.Game/Screens/Play/BreaksOverlay/LetterboxOverlay.cs index c95b15ef3a..1581c45c56 100644 --- a/osu.Game/Screens/Play/BreaksOverlay/LetterboxOverlay.cs +++ b/osu.Game/Screens/Play/BreaksOverlay/LetterboxOverlay.cs @@ -11,9 +11,9 @@ namespace osu.Game.Screens.Play.BreaksOverlay { public class LetterboxOverlay : Container { - private const int letterbox_height = 350; + private const int height = 350; - private Color4 transparentBlack => new Color4(0, 0, 0, 0); + private static readonly Color4 transparent_black = new Color4(0, 0, 0, 0); public LetterboxOverlay() { @@ -26,7 +26,7 @@ namespace osu.Game.Screens.Play.BreaksOverlay Anchor = Anchor.TopLeft, Origin = Anchor.TopLeft, RelativeSizeAxes = Axes.X, - Height = letterbox_height, + Height = height, Child = new Box { RelativeSizeAxes = Axes.Both, @@ -34,8 +34,8 @@ namespace osu.Game.Screens.Play.BreaksOverlay { TopLeft = Color4.Black, TopRight = Color4.Black, - BottomLeft = transparentBlack, - BottomRight = transparentBlack, + BottomLeft = transparent_black, + BottomRight = transparent_black, } } }, @@ -44,14 +44,14 @@ namespace osu.Game.Screens.Play.BreaksOverlay Anchor = Anchor.BottomLeft, Origin = Anchor.BottomLeft, RelativeSizeAxes = Axes.X, - Height = letterbox_height, + Height = height, Child = new Box { RelativeSizeAxes = Axes.Both, Colour = new ColourInfo { - TopLeft = transparentBlack, - TopRight = transparentBlack, + TopLeft = transparent_black, + TopRight = transparent_black, BottomLeft = Color4.Black, BottomRight = Color4.Black, } diff --git a/osu.Game/Screens/Play/BreaksOverlay/RemainingTimeCounter.cs b/osu.Game/Screens/Play/BreaksOverlay/RemainingTimeCounter.cs index ab6ee5ea5c..e89c1e292c 100644 --- a/osu.Game/Screens/Play/BreaksOverlay/RemainingTimeCounter.cs +++ b/osu.Game/Screens/Play/BreaksOverlay/RemainingTimeCounter.cs @@ -14,7 +14,7 @@ namespace osu.Game.Screens.Play.BreaksOverlay private int? previousSecond; - private double remainingTime; + private double endTime; private bool isCounting; @@ -31,9 +31,9 @@ namespace osu.Game.Screens.Play.BreaksOverlay }; } - public void StartCounting(double remainingTime) + public void StartCounting(double endTime) { - this.remainingTime = remainingTime; + this.endTime = endTime; isCounting = true; } @@ -44,9 +44,9 @@ namespace osu.Game.Screens.Play.BreaksOverlay if (isCounting) { var currentTime = Clock.CurrentTime; - if (currentTime < remainingTime) + if (currentTime < endTime) { - int currentSecond = (int)Math.Floor((remainingTime - Clock.CurrentTime) / 1000.0); + int currentSecond = (int)Math.Floor((endTime - Clock.CurrentTime) / 1000.0); if (currentSecond != previousSecond) { counter.Text = currentSecond.ToString(); From 708632bca84655c894e24da82a225112a9727f14 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 27 Sep 2017 10:06:36 +0800 Subject: [PATCH 0054/1263] Remove second unnecessary colour set --- .../Edit/Components/Timelines/Summary/Parts/MarkerPart.cs | 3 --- 1 file changed, 3 deletions(-) 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 d4a1177c4f..290412d170 100644 --- a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/MarkerPart.cs +++ b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/MarkerPart.cs @@ -99,9 +99,6 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts } }; } - - [BackgroundDependencyLoader] - private void load(OsuColour colours) => Colour = colours.Red; } } } From 4e8944de04b44aa3f1b66fc0691133fbab8a89a8 Mon Sep 17 00:00:00 2001 From: Shawdooow Date: Tue, 26 Sep 2017 22:54:33 -0400 Subject: [PATCH 0055/1263] fix maps ending early --- osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs b/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs index 50239bf16c..990ff4bdef 100644 --- a/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs +++ b/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs @@ -41,6 +41,10 @@ namespace osu.Game.Rulesets.Osu.Scoring // Ticks foreach (var unused in slider.Ticks) AddJudgement(new OsuJudgement { Result = HitResult.Great }); + + //Bouncers + foreach (var unused in slider.Bouncers) + AddJudgement(new OsuJudgement { Result = HitResult.Great }); } AddJudgement(new OsuJudgement { Result = HitResult.Great }); From eae29820c069324333e37024315e7699ecc4da1a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 27 Sep 2017 11:06:33 +0800 Subject: [PATCH 0056/1263] Fix marker being cleared each beatmap change --- .../Components/Timelines/Summary/Parts/BookmarkPart.cs | 1 + .../Edit/Components/Timelines/Summary/Parts/BreakPart.cs | 1 + .../Components/Timelines/Summary/Parts/ControlPointPart.cs | 2 ++ .../Edit/Components/Timelines/Summary/Parts/MarkerPart.cs | 7 ++++++- .../Components/Timelines/Summary/Parts/TimelinePart.cs | 2 +- 5 files changed, 11 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/BookmarkPart.cs b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/BookmarkPart.cs index 8afec62a08..1793cb4334 100644 --- a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/BookmarkPart.cs +++ b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/BookmarkPart.cs @@ -15,6 +15,7 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts { protected override void LoadBeatmap(WorkingBeatmap beatmap) { + base.LoadBeatmap(beatmap); foreach (int bookmark in beatmap.BeatmapInfo.Bookmarks) Add(new BookmarkVisualisation(bookmark)); } diff --git a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/BreakPart.cs b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/BreakPart.cs index 721825270b..004491d489 100644 --- a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/BreakPart.cs +++ b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/BreakPart.cs @@ -16,6 +16,7 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts { protected override void LoadBeatmap(WorkingBeatmap beatmap) { + base.LoadBeatmap(beatmap); foreach (var breakPeriod in beatmap.Beatmap.Breaks) Add(new BreakVisualisation(breakPeriod)); } diff --git a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/ControlPointPart.cs b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/ControlPointPart.cs index e7f4f03f9b..d230578e13 100644 --- a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/ControlPointPart.cs +++ b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/ControlPointPart.cs @@ -18,6 +18,8 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts { protected override void LoadBeatmap(WorkingBeatmap beatmap) { + base.LoadBeatmap(beatmap); + ControlPointInfo cpi = beatmap.Beatmap.ControlPointInfo; cpi.TimingPoints.ForEach(addTimingPoint); 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 290412d170..228d32cee4 100644 --- a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/MarkerPart.cs +++ b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/MarkerPart.cs @@ -7,6 +7,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Input; +using osu.Game.Beatmaps; using osu.Game.Graphics; namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts @@ -61,10 +62,14 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts protected override void Update() { base.Update(); - marker.X = (float)(Beatmap.Value?.Track.CurrentTime ?? 0); } + protected override void LoadBeatmap(WorkingBeatmap beatmap) + { + // block base call so we don't clear our marker (can be reused on beatmap change). + } + private class MarkerVisualisation : CompositeDrawable { public MarkerVisualisation() diff --git a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/TimelinePart.cs b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/TimelinePart.cs index f5d4124b19..8071aa9c59 100644 --- a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/TimelinePart.cs +++ b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/TimelinePart.cs @@ -25,7 +25,6 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts Beatmap.ValueChanged += b => { - timeline.Clear(); timeline.RelativeChildSize = new Vector2((float)Math.Max(1, b.Track.Length), 1); LoadBeatmap(b); }; @@ -35,6 +34,7 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts protected virtual void LoadBeatmap(WorkingBeatmap beatmap) { + timeline.Clear(); } } } From 7ad21d9a6d09ba31c90041264b60f5e61a7ab79d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 27 Sep 2017 11:07:23 +0800 Subject: [PATCH 0057/1263] Simplify marker part construction --- .../Components/Timelines/Summary/Parts/MarkerPart.cs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) 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 228d32cee4..2e7eaf99f8 100644 --- a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/MarkerPart.cs +++ b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/MarkerPart.cs @@ -17,17 +17,15 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts /// internal class MarkerPart : TimelinePart { - private readonly Drawable marker; - - public MarkerPart() - { - Add(marker = new MarkerVisualisation()); - } + private Drawable marker; [BackgroundDependencyLoader] private void load(OsuColour colours) { - marker.Colour = colours.Red; + Add(marker = new MarkerVisualisation + { + Colour = colours.Red + }); } protected override bool OnDragStart(InputState state) => true; From d5ed218488aac139909012bb0343a69edf357421 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 27 Sep 2017 11:07:43 +0800 Subject: [PATCH 0058/1263] Fix timeline sizes being updated potentially before the track has a length --- .../Timelines/Summary/Parts/TimelinePart.cs | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/TimelinePart.cs b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/TimelinePart.cs index 8071aa9c59..75651640d5 100644 --- a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/TimelinePart.cs +++ b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/TimelinePart.cs @@ -25,11 +25,31 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts Beatmap.ValueChanged += b => { - timeline.RelativeChildSize = new Vector2((float)Math.Max(1, b.Track.Length), 1); + updateRelativeChildSize(); LoadBeatmap(b); }; } + private void updateRelativeChildSize() + { + if (!Beatmap.Value.TrackLoaded) + { + timeline.RelativeChildSize = Vector2.One; + return; + } + + var track = Beatmap.Value.Track; + + if (!track.IsLoaded) + { + // the track may not be loaded completely (only has a length once it is). + Schedule(updateRelativeChildSize); + return; + } + + timeline.RelativeChildSize = new Vector2((float)Math.Max(1, track.Length), 1); + } + protected void Add(Drawable visualisation) => timeline.Add(visualisation); protected virtual void LoadBeatmap(WorkingBeatmap beatmap) From 3018d32b13ec02cfb531ea38b9f237927105c564 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 27 Sep 2017 11:22:47 +0800 Subject: [PATCH 0059/1263] Close BeatmapSetOverlay when clicking outside of it --- osu.Game/Overlays/BeatmapSetOverlay.cs | 3 +++ osu.Game/Overlays/UserProfileOverlay.cs | 1 + 2 files changed, 4 insertions(+) diff --git a/osu.Game/Overlays/BeatmapSetOverlay.cs b/osu.Game/Overlays/BeatmapSetOverlay.cs index 8e28ad33c5..7a4c6338a1 100644 --- a/osu.Game/Overlays/BeatmapSetOverlay.cs +++ b/osu.Game/Overlays/BeatmapSetOverlay.cs @@ -23,6 +23,9 @@ namespace osu.Game.Overlays private readonly Header header; private readonly Info info; + // receive input outside our bounds so we can trigger a close event on ourselves. + public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => true; + public BeatmapSetOverlay() { FirstWaveColour = OsuColour.Gray(0.4f); diff --git a/osu.Game/Overlays/UserProfileOverlay.cs b/osu.Game/Overlays/UserProfileOverlay.cs index f03ef3f1ed..088b0a1335 100644 --- a/osu.Game/Overlays/UserProfileOverlay.cs +++ b/osu.Game/Overlays/UserProfileOverlay.cs @@ -34,6 +34,7 @@ namespace osu.Game.Overlays public const float CONTENT_X_MARGIN = 50; + // receive input outside our bounds so we can trigger a close event on ourselves. public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => true; protected override bool OnClick(InputState state) From bbc990a6fd8be9ade98a74a7ad5c5bd19866660d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 27 Sep 2017 11:26:56 +0800 Subject: [PATCH 0060/1263] Assign a name to individual import tests to avoid file contention --- osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs b/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs index be48c997ea..9277310efc 100644 --- a/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs +++ b/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs @@ -24,7 +24,7 @@ namespace osu.Game.Tests.Beatmaps.IO public void TestImportWhenClosed() { //unfortunately for the time being we need to reference osu.Framework.Desktop for a game host here. - using (HeadlessGameHost host = new HeadlessGameHost()) + using (HeadlessGameHost host = new HeadlessGameHost("TestImportWhenClosed")) { var osu = loadOsu(host); @@ -69,7 +69,7 @@ namespace osu.Game.Tests.Beatmaps.IO public void TestImportWhenFileOpen() { //unfortunately for the time being we need to reference osu.Framework.Desktop for a game host here. - using (HeadlessGameHost host = new HeadlessGameHost()) + using (HeadlessGameHost host = new HeadlessGameHost("TestImportWhenFileOpen")) { var osu = loadOsu(host); From 05c6829debe91a01c5a3b9ba0afe60b20f4a1773 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 27 Sep 2017 12:18:24 +0800 Subject: [PATCH 0061/1263] Move all APIAccess State changes to the local thread Previously changes to the state were triggering events like Logout, which could get things into a bad state. --- osu.Game/Online/API/APIAccess.cs | 55 ++++++++++---------------------- 1 file changed, 17 insertions(+), 38 deletions(-) diff --git a/osu.Game/Online/API/APIAccess.cs b/osu.Game/Online/API/APIAccess.cs index 57f5c54a18..00abeea444 100644 --- a/osu.Game/Online/API/APIAccess.cs +++ b/osu.Game/Online/API/APIAccess.cs @@ -101,18 +101,16 @@ namespace osu.Game.Online.API } break; case APIState.Offline: + case APIState.Connecting: //work to restore a connection... if (!HasLogin) { - //OsuGame.Scheduler.Add(() => { OsuGame.ShowLogin(); }); - State = APIState.Offline; - Thread.Sleep(500); + Thread.Sleep(50); continue; } - if (State < APIState.Connecting) - State = APIState.Connecting; + State = APIState.Connecting; if (!authentication.HasValidAccessToken && !authentication.AuthenticateWithLogin(Username, Password)) { @@ -125,7 +123,8 @@ namespace osu.Game.Online.API var userReq = new GetUserRequest(); - userReq.Success += u => { + userReq.Success += u => + { LocalUser.Value = u; //we're connected! State = APIState.Online; @@ -133,16 +132,14 @@ namespace osu.Game.Online.API }; if (!handleRequest(userReq)) - { - State = APIState.Failing; continue; - } break; } //hard bail if we can't get a valid access token. if (authentication.RequestAccessToken() == null) { + Logout(false); State = APIState.Offline; continue; } @@ -162,20 +159,12 @@ namespace osu.Game.Online.API } } - private void clearCredentials() - { - Username = null; - Password = null; - } - public void Login(string username, string password) { Debug.Assert(State == APIState.Offline); Username = username; Password = password; - - State = APIState.Connecting; } /// @@ -204,7 +193,7 @@ namespace osu.Game.Online.API switch (statusCode) { case HttpStatusCode.Unauthorized: - State = APIState.Offline; + Logout(false); return true; case HttpStatusCode.RequestTimeout: failureCount++; @@ -215,6 +204,7 @@ namespace osu.Game.Online.API return false; State = APIState.Failing; + flushQueue(); return true; } @@ -242,26 +232,14 @@ namespace osu.Game.Online.API state = value; - switch (state) - { - case APIState.Failing: - case APIState.Offline: - flushQueue(); - break; - } - if (oldState != newState) { - //OsuGame.Scheduler.Add(delegate + log.Add($@"We just went {newState}!"); + Scheduler.Add(delegate { - //NotificationOverlay.ShowMessage($@"We just went {newState}!", newState == APIState.Online ? Color4.YellowGreen : Color4.OrangeRed, 5000); - log.Add($@"We just went {newState}!"); - Scheduler.Add(delegate - { - components.ForEach(c => c.APIStateChanged(this, newState)); - OnStateChange?.Invoke(oldState, newState); - }); - } + components.ForEach(c => c.APIStateChanged(this, newState)); + OnStateChange?.Invoke(oldState, newState); + }); } } } @@ -292,11 +270,12 @@ namespace osu.Game.Online.API } } - public void Logout() + public void Logout(bool clearUsername = true) { - clearCredentials(); + flushQueue(); + if (clearUsername) Username = null; + Password = null; authentication.Clear(); - State = APIState.Offline; LocalUser.Value = createGuestUser(); } From ec50834e98c2ac2a3ca3010fda4227a4555d2a89 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 27 Sep 2017 12:23:48 +0800 Subject: [PATCH 0062/1263] Load osu!direct overlay to "newest maps" tab by default --- osu.Game/Overlays/Direct/Header.cs | 2 +- osu.Game/Overlays/DirectOverlay.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Direct/Header.cs b/osu.Game/Overlays/Direct/Header.cs index 2c50fb453f..77743a3a4b 100644 --- a/osu.Game/Overlays/Direct/Header.cs +++ b/osu.Game/Overlays/Direct/Header.cs @@ -21,7 +21,7 @@ namespace osu.Game.Overlays.Direct public Header() { - Tabs.Current.Value = DirectTab.Search; + Tabs.Current.Value = DirectTab.NewestMaps; Tabs.Current.TriggerChange(); } } diff --git a/osu.Game/Overlays/DirectOverlay.cs b/osu.Game/Overlays/DirectOverlay.cs index 9c07e1087f..5b5003b30f 100644 --- a/osu.Game/Overlays/DirectOverlay.cs +++ b/osu.Game/Overlays/DirectOverlay.cs @@ -251,7 +251,7 @@ namespace osu.Game.Overlays if (Header.Tabs.Current.Value == DirectTab.Search && (Filter.Search.Text == string.Empty || currentQuery == string.Empty)) return; - getSetsRequest = new GetBeatmapSetsRequest(currentQuery, + getSetsRequest = new GetBeatmapSetsRequest(currentQuery.Value ?? string.Empty, ((FilterControl)Filter).Ruleset.Value, Filter.DisplayStyleControl.Dropdown.Current.Value, Filter.Tabs.Current.Value); //todo: sort direction (?) From faad3fc7d39291f59a6feb679b585224bf9e82dd Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 27 Sep 2017 12:40:32 +0800 Subject: [PATCH 0063/1263] Arbitrarily move colour assignment --- .../Timelines/Summary/Parts/MarkerPart.cs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) 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 2e7eaf99f8..0bdd081907 100644 --- a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/MarkerPart.cs +++ b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/MarkerPart.cs @@ -17,15 +17,11 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts /// internal class MarkerPart : TimelinePart { - private Drawable marker; + private readonly Drawable marker; - [BackgroundDependencyLoader] - private void load(OsuColour colours) + public MarkerPart() { - Add(marker = new MarkerVisualisation - { - Colour = colours.Red - }); + Add(marker = new MarkerVisualisation()); } protected override bool OnDragStart(InputState state) => true; @@ -102,6 +98,9 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts } }; } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) => Colour = colours.Red; } } } From e64860ad45b44dfe27d36c1389d30af79e498e17 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 27 Sep 2017 12:46:34 +0800 Subject: [PATCH 0064/1263] Fix test case not working as expected --- .../Timelines/Summary/Parts/TimelinePart.cs | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/TimelinePart.cs b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/TimelinePart.cs index 75651640d5..378ce78c67 100644 --- a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/TimelinePart.cs +++ b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/TimelinePart.cs @@ -32,22 +32,15 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts private void updateRelativeChildSize() { - if (!Beatmap.Value.TrackLoaded) + // the track may not be loaded completely (only has a length once it is). + if (!Beatmap.Value.Track.IsLoaded) { timeline.RelativeChildSize = Vector2.One; - return; - } - - var track = Beatmap.Value.Track; - - if (!track.IsLoaded) - { - // the track may not be loaded completely (only has a length once it is). Schedule(updateRelativeChildSize); return; } - timeline.RelativeChildSize = new Vector2((float)Math.Max(1, track.Length), 1); + timeline.RelativeChildSize = new Vector2((float)Math.Max(1, Beatmap.Value.Track.Length), 1); } protected void Add(Drawable visualisation) => timeline.Add(visualisation); From 4a95d64239eb10b207604a9aaaa45a79c3024653 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 27 Sep 2017 13:06:57 +0800 Subject: [PATCH 0065/1263] Fix yellow line in login overlay not following size correctly Also allows right click context menu to correctly extrude beyond the local masking. --- osu.Game/Overlays/LoginOverlay.cs | 49 ++++++++++++++++++------------- 1 file changed, 29 insertions(+), 20 deletions(-) diff --git a/osu.Game/Overlays/LoginOverlay.cs b/osu.Game/Overlays/LoginOverlay.cs index 58b259fcbb..0a47637589 100644 --- a/osu.Game/Overlays/LoginOverlay.cs +++ b/osu.Game/Overlays/LoginOverlay.cs @@ -3,6 +3,7 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; using osu.Game.Graphics; using osu.Game.Overlays.Settings.Sections.General; using OpenTK.Graphics; @@ -28,35 +29,43 @@ namespace osu.Game.Overlays { Children = new Drawable[] { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = Color4.Black, - Alpha = 0.6f, - }, new OsuContextMenuContainer { Width = 360, AutoSizeAxes = Axes.Y, - Masking = true, - AutoSizeDuration = transition_time, - AutoSizeEasing = Easing.OutQuint, Children = new Drawable[] { - settingsSection = new LoginSettings - { - Padding = new MarginPadding(10), - RequestHide = Hide, - }, new Box { - RelativeSizeAxes = Axes.X, - Anchor = Anchor.BottomLeft, - Origin = Anchor.BottomLeft, - Height = 3, - Colour = colours.Yellow, - Alpha = 1, + RelativeSizeAxes = Axes.Both, + Colour = Color4.Black, + Alpha = 0.6f, }, + new Container + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Masking = true, + AutoSizeDuration = transition_time, + AutoSizeEasing = Easing.OutQuint, + Children = new Drawable[] + { + settingsSection = new LoginSettings + { + Padding = new MarginPadding(10), + RequestHide = Hide, + }, + new Box + { + RelativeSizeAxes = Axes.X, + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + Height = 3, + Colour = colours.Yellow, + Alpha = 1, + }, + } + } } } }; From a17cc04cdedc2455b19563977d3bf6b971de532e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 27 Sep 2017 13:16:17 +0800 Subject: [PATCH 0066/1263] Make APIAccess's state only privately settable --- osu.Game/Online/API/APIAccess.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Online/API/APIAccess.cs b/osu.Game/Online/API/APIAccess.cs index 00abeea444..bb72efb750 100644 --- a/osu.Game/Online/API/APIAccess.cs +++ b/osu.Game/Online/API/APIAccess.cs @@ -225,7 +225,7 @@ namespace osu.Game.Online.API public APIState State { get { return state; } - set + private set { APIState oldState = state; APIState newState = value; From 990ef3ca56d05cb424657545aa1770687ba63d4e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 27 Sep 2017 14:38:12 +0800 Subject: [PATCH 0067/1263] Make import tests more resilient to race condition failures Also centralises wait-or-assert logic. --- .../Beatmaps/IO/ImportBeatmapTest.cs | 35 +++++++------------ 1 file changed, 13 insertions(+), 22 deletions(-) diff --git a/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs b/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs index 9277310efc..35bebf2d4f 100644 --- a/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs +++ b/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs @@ -36,7 +36,7 @@ namespace osu.Game.Tests.Beatmaps.IO ensureLoaded(osu); - Assert.IsFalse(File.Exists(temp)); + waitForOrAssert(() => !File.Exists(temp), "Temporary file still exists after standard import", 5000); } } @@ -61,14 +61,13 @@ namespace osu.Game.Tests.Beatmaps.IO ensureLoaded(osu); - Assert.IsFalse(File.Exists(temp)); + waitForOrAssert(() => !File.Exists(temp), "Temporary still exists after IPC import", 5000); } } [Test] public void TestImportWhenFileOpen() { - //unfortunately for the time being we need to reference osu.Framework.Desktop for a game host here. using (HeadlessGameHost host = new HeadlessGameHost("TestImportWhenFileOpen")) { var osu = loadOsu(host); @@ -101,8 +100,7 @@ namespace osu.Game.Tests.Beatmaps.IO var osu = new OsuGameBase(); Task.Run(() => host.Run(osu)); - while (!osu.IsLoaded) - Thread.Sleep(1); + waitForOrAssert(() => osu.IsLoaded, @"osu! failed to start in a reasonable amount of time"); return osu; } @@ -113,30 +111,17 @@ namespace osu.Game.Tests.Beatmaps.IO var store = osu.Dependencies.Get(); - Action waitAction = () => - { - while (!(resultSets = store.QueryBeatmapSets(s => s.OnlineBeatmapSetID == 241526)).Any()) - Thread.Sleep(50); - }; - - Assert.IsTrue(waitAction.BeginInvoke(null, null).AsyncWaitHandle.WaitOne(timeout), - @"BeatmapSet did not import to the database in allocated time."); + waitForOrAssert(() => (resultSets = store.QueryBeatmapSets(s => s.OnlineBeatmapSetID == 241526)).Any(), + @"BeatmapSet did not import to the database in allocated time.", timeout); //ensure we were stored to beatmap database backing... - Assert.IsTrue(resultSets.Count() == 1, $@"Incorrect result count found ({resultSets.Count()} but should be 1)."); IEnumerable resultBeatmaps = null; //if we don't re-check here, the set will be inserted but the beatmaps won't be present yet. - waitAction = () => - { - while ((resultBeatmaps = store.QueryBeatmaps(s => s.OnlineBeatmapSetID == 241526 && s.BaseDifficultyID > 0)).Count() != 12) - Thread.Sleep(50); - }; - - Assert.IsTrue(waitAction.BeginInvoke(null, null).AsyncWaitHandle.WaitOne(timeout), - @"Beatmaps did not import to the database in allocated time"); + waitForOrAssert(() => (resultBeatmaps = store.QueryBeatmaps(s => s.OnlineBeatmapSetID == 241526 && s.BaseDifficultyID > 0)).Count() == 12, + @"Beatmaps did not import to the database in allocated time", timeout); var set = store.QueryBeatmapSets(s => s.OnlineBeatmapSetID == 241526).First(); @@ -160,5 +145,11 @@ namespace osu.Game.Tests.Beatmaps.IO beatmap = store.GetWorkingBeatmap(set.Beatmaps.First(b => b.RulesetID == 3))?.Beatmap; Assert.IsTrue(beatmap?.HitObjects.Count > 0); } + + private void waitForOrAssert(Func result, string failureMessage, int timeout = 60000) + { + Action waitAction = () => { while (!result()) Thread.Sleep(20); }; + Assert.IsTrue(waitAction.BeginInvoke(null, null).AsyncWaitHandle.WaitOne(timeout), failureMessage); + } } } From 545c375199703de17ccdecbd38b87427fb85bc71 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 27 Sep 2017 21:53:33 +0900 Subject: [PATCH 0068/1263] Update design of EditorMenuBar to match flyte's design more closely --- osu-framework | 2 +- osu.Game/Screens/Edit/Editor.cs | 7 +- osu.Game/Screens/Edit/Menus/EditorMenuBar.cs | 55 +++++++- .../Tests/Visual/TestCaseEditorMenuBar.cs | 125 ++++++++++-------- 4 files changed, 124 insertions(+), 65 deletions(-) diff --git a/osu-framework b/osu-framework index cdb031c3a8..a24fd77ad5 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit cdb031c3a8ef693cd71458c5e19c68127ab72938 +Subproject commit a24fd77ad5f69e133a84175ef79c4ab7f600316b diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 3ffd7754c1..d85026bb27 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -32,16 +32,11 @@ namespace osu.Game.Screens.Edit Height = 40, Children = new Drawable[] { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = OsuColour.FromHex("111") - }, new EditorMenuBar { Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, - X = 100, + RelativeSizeAxes = Axes.Both, Items = new[] { new EditorMenuBarItem("File") diff --git a/osu.Game/Screens/Edit/Menus/EditorMenuBar.cs b/osu.Game/Screens/Edit/Menus/EditorMenuBar.cs index bb349b1531..818eb37bfb 100644 --- a/osu.Game/Screens/Edit/Menus/EditorMenuBar.cs +++ b/osu.Game/Screens/Edit/Menus/EditorMenuBar.cs @@ -19,8 +19,20 @@ namespace osu.Game.Screens.Edit.Menus public EditorMenuBar() : base(Direction.Horizontal, true) { - ItemsContainer.Padding = new MarginPadding(0); + RelativeSizeAxes = Axes.X; + + ItemsContainer.Padding = new MarginPadding { Left = 100 }; BackgroundColour = Color4.Transparent; + + AddRangeInternal(new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = OsuColour.FromHex("111"), + Depth = float.MaxValue + }, + }); } protected override Framework.Graphics.UserInterface.Menu CreateSubMenu() => new SubMenu(); @@ -32,9 +44,32 @@ namespace osu.Game.Screens.Edit.Menus private Color4 openedForegroundColour; private Color4 openedBackgroundColour; + public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => parentSizedBox.ReceiveMouseInputAt(screenSpacePos); + + /// + /// A box with width equal to this 's width, and height equal to the parent height. + /// + private readonly Box parentSizedBox; + public DrawableEditorBarMenuItem(MenuItem item) : base(item) { + Anchor = Anchor.CentreLeft; + Origin = Anchor.CentreLeft; + + AddInternal(parentSizedBox = new Box + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.X, + BypassAutoSizeAxes = Axes.Both, + Alpha = 0, + }); + } + + public override void SetFlowDirection(Direction direction) + { + AutoSizeAxes = Axes.Both; } [BackgroundDependencyLoader] @@ -62,6 +97,13 @@ namespace osu.Game.Screens.Edit.Menus base.UpdateForegroundColour(); } + protected override void Update() + { + base.Update(); + + parentSizedBox.Height = Parent.DrawHeight; + } + protected override Drawable CreateBackground() => new Container { RelativeSizeAxes = Axes.Both, @@ -75,6 +117,17 @@ namespace osu.Game.Screens.Edit.Menus Child = new Box { RelativeSizeAxes = Axes.Both } } }; + + protected override DrawableOsuMenuItem.TextContainer CreateTextContainer() => new TextContainer(); + + private new class TextContainer : DrawableOsuMenuItem.TextContainer + { + public TextContainer() + { + NormalText.TextSize = BoldText.TextSize = 14; + NormalText.Margin = BoldText.Margin = new MarginPadding { Horizontal = 10, Vertical = MARGIN_VERTICAL }; + } + } } private class SubMenu : OsuMenu diff --git a/osu.Game/Tests/Visual/TestCaseEditorMenuBar.cs b/osu.Game/Tests/Visual/TestCaseEditorMenuBar.cs index 8b5132fe08..b0c21b6b8c 100644 --- a/osu.Game/Tests/Visual/TestCaseEditorMenuBar.cs +++ b/osu.Game/Tests/Visual/TestCaseEditorMenuBar.cs @@ -1,7 +1,10 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System; +using System.Collections.Generic; using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; using osu.Game.Graphics.UserInterface; using osu.Game.Screens.Edit.Menus; @@ -9,74 +12,82 @@ namespace osu.Game.Tests.Visual { public class TestCaseEditorMenuBar : OsuTestCase { + public override IReadOnlyList RequiredTypes => new[] { typeof(EditorMenuBar), typeof(ScreenSelectionTabControl) }; + public TestCaseEditorMenuBar() { - Add(new EditorMenuBar + Add(new Container { Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, + RelativeSizeAxes = Axes.X, + Height = 50, Y = 50, - Items = new[] + Child = new EditorMenuBar { - new EditorMenuBarItem("File") + RelativeSizeAxes = Axes.Both, + Items = new[] { - Items = new[] + new EditorMenuBarItem("File") { - new EditorMenuItem("Clear All Notes"), - new EditorMenuItem("Open Difficulty..."), - new EditorMenuItem("Save"), - new EditorMenuItem("Create a new Difficulty..."), - new EditorMenuItemSpacer(), - new EditorMenuItem("Revert to Saved"), - new EditorMenuItem("Revert to Saved (Full)"), - new EditorMenuItemSpacer(), - new EditorMenuItem("Test Beatmap"), - new EditorMenuItem("Open AiMod"), - new EditorMenuItemSpacer(), - new EditorMenuItem("Upload Beatmap..."), - new EditorMenuItem("Export Package"), - new EditorMenuItem("Export Map Package"), - new EditorMenuItem("Import from..."), - new EditorMenuItemSpacer(), - new EditorMenuItem("Open Song Folder"), - new EditorMenuItem("Open .osu in Notepad"), - new EditorMenuItem("Open .osb in Notepad"), - new EditorMenuItemSpacer(), - new EditorMenuItem("Exit"), - } - }, - new EditorMenuBarItem("Timing") - { - Items = new[] + Items = new[] + { + new EditorMenuItem("Clear All Notes"), + new EditorMenuItem("Open Difficulty..."), + new EditorMenuItem("Save"), + new EditorMenuItem("Create a new Difficulty..."), + new EditorMenuItemSpacer(), + new EditorMenuItem("Revert to Saved"), + new EditorMenuItem("Revert to Saved (Full)"), + new EditorMenuItemSpacer(), + new EditorMenuItem("Test Beatmap"), + new EditorMenuItem("Open AiMod"), + new EditorMenuItemSpacer(), + new EditorMenuItem("Upload Beatmap..."), + new EditorMenuItem("Export Package"), + new EditorMenuItem("Export Map Package"), + new EditorMenuItem("Import from..."), + new EditorMenuItemSpacer(), + new EditorMenuItem("Open Song Folder"), + new EditorMenuItem("Open .osu in Notepad"), + new EditorMenuItem("Open .osb in Notepad"), + new EditorMenuItemSpacer(), + new EditorMenuItem("Exit"), + } + }, + new EditorMenuBarItem("Timing") { - new EditorMenuItem("Time Signature"), - new EditorMenuItem("Metronome Clicks"), - new EditorMenuItemSpacer(), - new EditorMenuItem("Add Timing Section"), - new EditorMenuItem("Add Inheriting Section"), - new EditorMenuItem("Reset Current Section"), - new EditorMenuItem("Delete Timing Section"), - new EditorMenuItem("Resnap Current Section"), - new EditorMenuItemSpacer(), - new EditorMenuItem("Timing Setup"), - new EditorMenuItemSpacer(), - new EditorMenuItem("Resnap All Notes", MenuItemType.Destructive), - new EditorMenuItem("Move all notes in time...", MenuItemType.Destructive), - new EditorMenuItem("Recalculate Slider Lengths", MenuItemType.Destructive), - new EditorMenuItem("Delete All Timing Sections", MenuItemType.Destructive), - new EditorMenuItemSpacer(), - new EditorMenuItem("Set Current Position as Preview Point"), - } - }, - new EditorMenuBarItem("Testing") - { - Items = new[] + Items = new[] + { + new EditorMenuItem("Time Signature"), + new EditorMenuItem("Metronome Clicks"), + new EditorMenuItemSpacer(), + new EditorMenuItem("Add Timing Section"), + new EditorMenuItem("Add Inheriting Section"), + new EditorMenuItem("Reset Current Section"), + new EditorMenuItem("Delete Timing Section"), + new EditorMenuItem("Resnap Current Section"), + new EditorMenuItemSpacer(), + new EditorMenuItem("Timing Setup"), + new EditorMenuItemSpacer(), + new EditorMenuItem("Resnap All Notes", MenuItemType.Destructive), + new EditorMenuItem("Move all notes in time...", MenuItemType.Destructive), + new EditorMenuItem("Recalculate Slider Lengths", MenuItemType.Destructive), + new EditorMenuItem("Delete All Timing Sections", MenuItemType.Destructive), + new EditorMenuItemSpacer(), + new EditorMenuItem("Set Current Position as Preview Point"), + } + }, + new EditorMenuBarItem("Testing") { - new EditorMenuItem("Item 1"), - new EditorMenuItem("Item 2"), - new EditorMenuItem("Item 3"), - } - }, + Items = new[] + { + new EditorMenuItem("Item 1"), + new EditorMenuItem("Item 2"), + new EditorMenuItem("Item 3"), + } + }, + } } }); } From ba8bf6cbd51bb6a7a6c48a4aa1d03fb459372742 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 27 Sep 2017 22:01:53 +0900 Subject: [PATCH 0069/1263] Add ScreenSelectionTabControl to EditorMenuBar --- .../Graphics/UserInterface/OsuTabControl.cs | 8 +- osu.Game/Screens/Edit/Menus/EditorMenuBar.cs | 6 ++ .../Edit/Menus/ScreenSelectionTabControl.cs | 84 +++++++++++++++++++ osu.Game/osu.Game.csproj | 1 + 4 files changed, 95 insertions(+), 4 deletions(-) create mode 100644 osu.Game/Screens/Edit/Menus/ScreenSelectionTabControl.cs diff --git a/osu.Game/Graphics/UserInterface/OsuTabControl.cs b/osu.Game/Graphics/UserInterface/OsuTabControl.cs index 89b1f4124b..b053195030 100644 --- a/osu.Game/Graphics/UserInterface/OsuTabControl.cs +++ b/osu.Game/Graphics/UserInterface/OsuTabControl.cs @@ -59,7 +59,7 @@ namespace osu.Game.Graphics.UserInterface public class OsuTabItem : TabItem, IHasAccentColour { protected readonly SpriteText Text; - private readonly Box box; + protected readonly Box Bar; private Color4 accentColour; public Color4 AccentColour @@ -77,13 +77,13 @@ namespace osu.Game.Graphics.UserInterface private void fadeActive() { - box.FadeIn(transition_length, Easing.OutQuint); + Bar.FadeIn(transition_length, Easing.OutQuint); Text.FadeColour(Color4.White, transition_length, Easing.OutQuint); } private void fadeInactive() { - box.FadeOut(transition_length, Easing.OutQuint); + Bar.FadeOut(transition_length, Easing.OutQuint); Text.FadeColour(AccentColour, transition_length, Easing.OutQuint); } @@ -123,7 +123,7 @@ namespace osu.Game.Graphics.UserInterface TextSize = 14, Font = @"Exo2.0-Bold", // Font should only turn bold when active? }, - box = new Box + Bar = new Box { RelativeSizeAxes = Axes.X, Height = 1, diff --git a/osu.Game/Screens/Edit/Menus/EditorMenuBar.cs b/osu.Game/Screens/Edit/Menus/EditorMenuBar.cs index 818eb37bfb..a3b48d8c70 100644 --- a/osu.Game/Screens/Edit/Menus/EditorMenuBar.cs +++ b/osu.Game/Screens/Edit/Menus/EditorMenuBar.cs @@ -32,6 +32,12 @@ namespace osu.Game.Screens.Edit.Menus Colour = OsuColour.FromHex("111"), Depth = float.MaxValue }, + new ScreenSelectionTabControl + { + Anchor = Anchor.BottomRight, + Origin = Anchor.BottomRight, + X = -15 + } }); } diff --git a/osu.Game/Screens/Edit/Menus/ScreenSelectionTabControl.cs b/osu.Game/Screens/Edit/Menus/ScreenSelectionTabControl.cs new file mode 100644 index 0000000000..a455fa8d71 --- /dev/null +++ b/osu.Game/Screens/Edit/Menus/ScreenSelectionTabControl.cs @@ -0,0 +1,84 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using OpenTK.Graphics; +using osu.Framework.Allocation; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.UserInterface; +using osu.Game.Graphics; +using osu.Game.Graphics.UserInterface; +using OpenTK; + +namespace osu.Game.Screens.Edit.Menus +{ + public class ScreenSelectionTabControl : OsuTabControl + { + public ScreenSelectionTabControl() + { + AutoSizeAxes = Axes.X; + RelativeSizeAxes = Axes.Y; + + TabContainer.RelativeSizeAxes &= ~Axes.X; + TabContainer.AutoSizeAxes = Axes.X; + TabContainer.Padding = new MarginPadding(); + + Add(new Box + { + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + RelativeSizeAxes = Axes.X, + Height = 1, + Colour = Color4.White.Opacity(0.2f), + }); + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + AccentColour = colours.Yellow; + } + + protected override Dropdown CreateDropdown() => null; + + protected override TabItem CreateTabItem(EditorScreenMode value) => new TabItem(value); + + private new class TabItem : OsuTabItem + { + private const float transition_length = 250; + + public TabItem(EditorScreenMode value) + : base(value) + { + Text.Margin = new MarginPadding(); + Text.Anchor = Anchor.CentreLeft; + Text.Origin = Anchor.CentreLeft; + } + + protected override void OnActivated() + { + base.OnActivated(); + Bar.ScaleTo(new Vector2(1, 5), transition_length, Easing.OutQuint); + } + + protected override void OnDeactivated() + { + base.OnDeactivated(); + Bar.ScaleTo(Vector2.One, transition_length, Easing.OutQuint); + } + } + } + + public enum EditorScreenMode + { + [System.ComponentModel.Description("compose")] + Compose, + [System.ComponentModel.Description("design")] + Design, + [System.ComponentModel.Description("timing")] + Timing, + [System.ComponentModel.Description("song")] + SongSetup + } +} diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index a6860e4e8c..0afb0247df 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -618,6 +618,7 @@ + From 95364d0173cdc6db99b3ada2f20cdab6f4e8221c Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 27 Sep 2017 22:15:11 +0900 Subject: [PATCH 0070/1263] No more box background --- osu.Game/Screens/Edit/Menus/EditorMenuBar.cs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/osu.Game/Screens/Edit/Menus/EditorMenuBar.cs b/osu.Game/Screens/Edit/Menus/EditorMenuBar.cs index a3b48d8c70..3142e3d6bc 100644 --- a/osu.Game/Screens/Edit/Menus/EditorMenuBar.cs +++ b/osu.Game/Screens/Edit/Menus/EditorMenuBar.cs @@ -22,16 +22,10 @@ namespace osu.Game.Screens.Edit.Menus RelativeSizeAxes = Axes.X; ItemsContainer.Padding = new MarginPadding { Left = 100 }; - BackgroundColour = Color4.Transparent; + BackgroundColour = OsuColour.FromHex("111"); AddRangeInternal(new Drawable[] { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = OsuColour.FromHex("111"), - Depth = float.MaxValue - }, new ScreenSelectionTabControl { Anchor = Anchor.BottomRight, From cfb1804aa1519c26993b5c5065c7789a5096d6c6 Mon Sep 17 00:00:00 2001 From: Shawdooow Date: Wed, 27 Sep 2017 11:28:44 -0400 Subject: [PATCH 0071/1263] address review --- ...liderBouncer.cs => DrawableRepeatPoint.cs} | 14 ++++++------ .../Objects/Drawables/DrawableSlider.cs | 22 +++++++++---------- .../{SliderBouncer.cs => RepeatPoint.cs} | 2 +- osu.Game.Rulesets.Osu/Objects/Slider.cs | 10 ++++----- .../Scoring/OsuScoreProcessor.cs | 4 ++-- .../osu.Game.Rulesets.Osu.csproj | 4 ++-- 6 files changed, 27 insertions(+), 29 deletions(-) rename osu.Game.Rulesets.Osu/Objects/Drawables/{DrawableSliderBouncer.cs => DrawableRepeatPoint.cs} (78%) rename osu.Game.Rulesets.Osu/Objects/{SliderBouncer.cs => RepeatPoint.cs} (81%) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderBouncer.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableRepeatPoint.cs similarity index 78% rename from osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderBouncer.cs rename to osu.Game.Rulesets.Osu/Objects/Drawables/DrawableRepeatPoint.cs index 45be022027..bb200c9ecd 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderBouncer.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableRepeatPoint.cs @@ -10,9 +10,9 @@ using osu.Game.Rulesets.Osu.Judgements; namespace osu.Game.Rulesets.Osu.Objects.Drawables { - public class DrawableSliderBouncer : DrawableOsuHitObject + public class DrawableRepeatPoint : DrawableOsuHitObject { - private readonly SliderBouncer sliderBouncer; + private readonly RepeatPoint repeatPoint; private readonly DrawableSlider drawableSlider; public double FadeInTime; @@ -20,9 +20,9 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables public override bool RemoveWhenNotAlive => false; - public DrawableSliderBouncer(SliderBouncer sliderBouncer, DrawableSlider drawableSlider) : base(sliderBouncer) + public DrawableRepeatPoint(RepeatPoint repeatPoint, DrawableSlider drawableSlider) : base(repeatPoint) { - this.sliderBouncer = sliderBouncer; + this.repeatPoint = repeatPoint; this.drawableSlider = drawableSlider; AutoSizeAxes = Axes.Both; @@ -43,13 +43,13 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables protected override void CheckForJudgements(bool userTriggered, double timeOffset) { - if (sliderBouncer.StartTime <= Time.Current) + if (repeatPoint.StartTime <= Time.Current) AddJudgement(new OsuJudgement { Result = drawableSlider.Tracking ? HitResult.Great : HitResult.Miss }); } protected override void UpdatePreemptState() { - var animIn = Math.Min(150, sliderBouncer.StartTime - FadeInTime); + var animIn = Math.Min(150, repeatPoint.StartTime - FadeInTime); this.Animate( d => d.FadeIn(animIn), @@ -64,7 +64,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables switch (state) { case ArmedState.Idle: - this.Delay(FadeOutTime - sliderBouncer.StartTime).FadeOut(); + this.Delay(FadeOutTime - repeatPoint.StartTime).FadeOut(); break; case ArmedState.Miss: this.FadeOut(160); diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs index 2833cc81bf..2e6e82ce0c 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs @@ -21,7 +21,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables private readonly List components = new List(); private readonly Container ticks; - private readonly Container bouncers; + private readonly Container repeatPoints; private readonly SliderBody body; private readonly SliderBall ball; @@ -39,7 +39,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables PathWidth = s.Scale * 64, }, ticks = new Container(), - bouncers = new Container(), + repeatPoints = new Container(), ball = new SliderBall(s) { Scale = new Vector2(s.Scale), @@ -80,21 +80,21 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables AddNested(drawableTick); } - foreach (var bouncer in s.Bouncers) + foreach (var repeatPoint in s.RepeatPoints) { - var repeatStartTime = s.StartTime + bouncer.RepeatIndex * repeatDuration; - var fadeInTime = repeatStartTime + (bouncer.StartTime - repeatStartTime) / 2 - (bouncer.RepeatIndex == 0 ? TIME_FADEIN : TIME_FADEIN / 2); + var repeatStartTime = s.StartTime + repeatPoint.RepeatIndex * repeatDuration; + var fadeInTime = repeatStartTime + (repeatPoint.StartTime - repeatStartTime) / 2 - (repeatPoint.RepeatIndex == 0 ? TIME_FADEIN : TIME_FADEIN / 2); var fadeOutTime = repeatStartTime + repeatDuration; - var drawableBouncer = new DrawableSliderBouncer(bouncer, this) + var drawableRepeatPoint = new DrawableRepeatPoint(repeatPoint, this) { FadeInTime = fadeInTime, FadeOutTime = fadeOutTime, - Position = bouncer.Position, + Position = repeatPoint.Position, }; - bouncers.Add(drawableBouncer); - AddNested(drawableBouncer); + repeatPoints.Add(drawableRepeatPoint); + AddNested(drawableRepeatPoint); } } @@ -131,8 +131,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables { if (!userTriggered && Time.Current >= slider.EndTime) { - var judgementsCount = ticks.Children.Count + bouncers.Children.Count + 1; - var judgementsHit = ticks.Children.Count(t => t.Judgements.Any(j => j.IsHit)) + bouncers.Children.Count(t => t.Judgements.Any(j => j.IsHit)); + var judgementsCount = ticks.Children.Count + repeatPoints.Children.Count + 1; + var judgementsHit = ticks.Children.Count(t => t.Judgements.Any(j => j.IsHit)) + repeatPoints.Children.Count(t => t.Judgements.Any(j => j.IsHit)); if (initialCircle.Judgements.Any(j => j.IsHit)) judgementsHit++; diff --git a/osu.Game.Rulesets.Osu/Objects/SliderBouncer.cs b/osu.Game.Rulesets.Osu/Objects/RepeatPoint.cs similarity index 81% rename from osu.Game.Rulesets.Osu/Objects/SliderBouncer.cs rename to osu.Game.Rulesets.Osu/Objects/RepeatPoint.cs index da98cc8422..c113b7cd7a 100644 --- a/osu.Game.Rulesets.Osu/Objects/SliderBouncer.cs +++ b/osu.Game.Rulesets.Osu/Objects/RepeatPoint.cs @@ -3,7 +3,7 @@ namespace osu.Game.Rulesets.Osu.Objects { - public class SliderBouncer : OsuHitObject + public class RepeatPoint : OsuHitObject { public int RepeatIndex { get; set; } } diff --git a/osu.Game.Rulesets.Osu/Objects/Slider.cs b/osu.Game.Rulesets.Osu/Objects/Slider.cs index b501e8e86a..7522a449c6 100644 --- a/osu.Game.Rulesets.Osu/Objects/Slider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Slider.cs @@ -61,7 +61,6 @@ namespace osu.Game.Rulesets.Osu.Objects public double Velocity; public double TickDistance; - public double BouncerDistance; public override void ApplyDefaults(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) { @@ -74,7 +73,6 @@ namespace osu.Game.Rulesets.Osu.Objects Velocity = scoringDistance / timingPoint.BeatLength; TickDistance = scoringDistance / difficulty.SliderTickRate; - BouncerDistance = Distance; } public Vector2 PositionAt(double progress) => Curve.PositionAt(ProgressAt(progress)); @@ -133,23 +131,23 @@ namespace osu.Game.Rulesets.Osu.Objects } } } - public IEnumerable Bouncers + public IEnumerable RepeatPoints { get { var length = Curve.Distance; - var bouncerDistance = Math.Min(BouncerDistance, length); + var repeatPointDistance = Math.Min(Distance, length); var repeatDuration = length / Velocity; for (var repeat = 0; repeat < RepeatCount; repeat++) { if (repeat > 0) - for (var d = bouncerDistance; d <= length; d += bouncerDistance) + for (var d = repeatPointDistance; d <= length; d += repeatPointDistance) { var repeatStartTime = StartTime + repeat * repeatDuration; var distanceProgress = d / length; - yield return new SliderBouncer + yield return new RepeatPoint { RepeatIndex = repeat, StartTime = repeatStartTime, diff --git a/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs b/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs index 990ff4bdef..9252b3b7b8 100644 --- a/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs +++ b/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs @@ -42,8 +42,8 @@ namespace osu.Game.Rulesets.Osu.Scoring foreach (var unused in slider.Ticks) AddJudgement(new OsuJudgement { Result = HitResult.Great }); - //Bouncers - foreach (var unused in slider.Bouncers) + //Repeats + foreach (var unused in slider.RepeatPoints) AddJudgement(new OsuJudgement { Result = HitResult.Great }); } diff --git a/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj b/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj index 662fba49d4..d950742589 100644 --- a/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj +++ b/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj @@ -53,7 +53,7 @@ - + @@ -72,7 +72,7 @@ - + From 8688d63a9e23117dec10cf3bc19c06e51b56b42f Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 28 Sep 2017 00:48:21 +0900 Subject: [PATCH 0072/1263] Update framework --- osu-framework | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu-framework b/osu-framework index a24fd77ad5..9d142a8e00 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit a24fd77ad5f69e133a84175ef79c4ab7f600316b +Subproject commit 9d142a8e009794dfee828392e36025d08577131d From 4eaf6b4b94ac2850a15f1b9a775dba8201d7ebae Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 28 Sep 2017 00:08:42 +0800 Subject: [PATCH 0073/1263] Remove single usage of dynamic and stop referencing Microsoft.CSharp.dll --- osu.Game/Online/API/Requests/GetScoresRequest.cs | 2 +- osu.Game/Rulesets/Scoring/Score.cs | 2 +- osu.Game/Screens/Ranking/ResultsPageScore.cs | 4 ++-- osu.Game/osu.Game.csproj | 1 - 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/osu.Game/Online/API/Requests/GetScoresRequest.cs b/osu.Game/Online/API/Requests/GetScoresRequest.cs index 13bd8d288d..537fce2548 100644 --- a/osu.Game/Online/API/Requests/GetScoresRequest.cs +++ b/osu.Game/Online/API/Requests/GetScoresRequest.cs @@ -80,7 +80,7 @@ namespace osu.Game.Online.API.Requests } [JsonProperty(@"statistics")] - private Dictionary jsonStats + private Dictionary jsonStats { set { diff --git a/osu.Game/Rulesets/Scoring/Score.cs b/osu.Game/Rulesets/Scoring/Score.cs index 7f053ec1c5..c4ffa4e93c 100644 --- a/osu.Game/Rulesets/Scoring/Score.cs +++ b/osu.Game/Rulesets/Scoring/Score.cs @@ -38,6 +38,6 @@ namespace osu.Game.Rulesets.Scoring public DateTimeOffset Date; - public Dictionary Statistics = new Dictionary(); + public Dictionary Statistics = new Dictionary(); } } diff --git a/osu.Game/Screens/Ranking/ResultsPageScore.cs b/osu.Game/Screens/Ranking/ResultsPageScore.cs index bf406ff912..b01410cff5 100644 --- a/osu.Game/Screens/Ranking/ResultsPageScore.cs +++ b/osu.Game/Screens/Ranking/ResultsPageScore.cs @@ -186,9 +186,9 @@ namespace osu.Game.Screens.Ranking private class DrawableScoreStatistic : Container { - private readonly KeyValuePair statistic; + private readonly KeyValuePair statistic; - public DrawableScoreStatistic(KeyValuePair statistic) + public DrawableScoreStatistic(KeyValuePair statistic) { this.statistic = statistic; diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index a6860e4e8c..bdca48ccdf 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -124,7 +124,6 @@ $(SolutionDir)\packages\DotNetZip.1.10.1\lib\net20\DotNetZip.dll True - $(SolutionDir)\packages\Mono.Cecil.0.9.6.4\lib\net45\Mono.Cecil.dll True From 75cd6eeb1c1b740cc62e713066e6d805f899bbe9 Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Thu, 28 Sep 2017 14:20:19 +0300 Subject: [PATCH 0074/1263] Clean up Wave in WaveOverlayContainer --- osu.Game/Overlays/WaveOverlayContainer.cs | 37 +++-------------------- 1 file changed, 4 insertions(+), 33 deletions(-) diff --git a/osu.Game/Overlays/WaveOverlayContainer.cs b/osu.Game/Overlays/WaveOverlayContainer.cs index 4f9783a762..77c532350b 100644 --- a/osu.Game/Overlays/WaveOverlayContainer.cs +++ b/osu.Game/Overlays/WaveOverlayContainer.cs @@ -1,7 +1,6 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using osu.Framework; using OpenTK.Graphics; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics.Containers; @@ -165,10 +164,8 @@ namespace osu.Game.Overlays wavesContainer.Height = Math.Max(0, DrawHeight - (contentContainer.DrawHeight - contentContainer.Y)); } - private class Wave : Container, IStateful + private class Wave : VisibilityContainer { - public event Action StateChanged; - public float FinalPosition; public Wave() @@ -183,13 +180,7 @@ namespace osu.Game.Overlays Radius = 20f, }; - Children = new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - }, - }; + Child = new Box { RelativeSizeAxes = Axes.Both }; } protected override void Update() @@ -201,28 +192,8 @@ namespace osu.Game.Overlays Height = Parent.Parent.DrawSize.Y * 1.5f; } - private Visibility state; - - public Visibility State - { - get { return state; } - set - { - state = value; - - switch (value) - { - case Visibility.Hidden: - this.MoveToY(Parent.Parent.DrawSize.Y, DISAPPEAR_DURATION, easing_hide); - break; - case Visibility.Visible: - this.MoveToY(FinalPosition, APPEAR_DURATION, easing_show); - break; - } - - StateChanged?.Invoke(State); - } - } + protected override void PopIn() => this.MoveToY(FinalPosition, APPEAR_DURATION, easing_show); + protected override void PopOut() => this.MoveToY(Parent.Parent.DrawSize.Y, DISAPPEAR_DURATION, easing_hide); } } } From ca1f96208a00864209a8fa760a978fe75a217e0d Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Thu, 28 Sep 2017 14:31:02 +0300 Subject: [PATCH 0075/1263] Fix TestCaseContextMenu not being updated inline with previous changes --- osu.Game/Tests/Visual/TestCaseContextMenu.cs | 43 ++++++++++---------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/osu.Game/Tests/Visual/TestCaseContextMenu.cs b/osu.Game/Tests/Visual/TestCaseContextMenu.cs index 28aae1f5b9..91a766f8c7 100644 --- a/osu.Game/Tests/Visual/TestCaseContextMenu.cs +++ b/osu.Game/Tests/Visual/TestCaseContextMenu.cs @@ -9,6 +9,7 @@ using osu.Framework.Graphics.UserInterface; using osu.Game.Graphics.UserInterface; using OpenTK; using OpenTK.Graphics; +using osu.Game.Graphics.Cursor; namespace osu.Game.Tests.Visual { @@ -23,32 +24,32 @@ namespace osu.Game.Tests.Visual public TestCaseContextMenu() { - Add(container = new MyContextMenuContainer + Add(new OsuContextMenuContainer { - Size = new Vector2(200), - Anchor = Anchor.Centre, - Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, Children = new Drawable[] { - new Box + container = new MyContextMenuContainer { - RelativeSizeAxes = Axes.Both, - Colour = Color4.Green, - } - } - }); - - Add(new AnotherContextMenuContainer - { - Size = new Vector2(200), - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Children = new Drawable[] - { - new Box + Size = new Vector2(200), + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Child = new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Green, + } + }, + new AnotherContextMenuContainer { - RelativeSizeAxes = Axes.Both, - Colour = Color4.Red, + Size = new Vector2(200), + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Child = new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Red, + } } } }); From 6bb5210c7cf6c97ec96f2094e62af0f41aa74efd Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 29 Sep 2017 15:09:28 +0900 Subject: [PATCH 0076/1263] Remove the parentSizedBox --- osu.Game/Screens/Edit/Menus/EditorMenuBar.cs | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/osu.Game/Screens/Edit/Menus/EditorMenuBar.cs b/osu.Game/Screens/Edit/Menus/EditorMenuBar.cs index 3142e3d6bc..329471fd0a 100644 --- a/osu.Game/Screens/Edit/Menus/EditorMenuBar.cs +++ b/osu.Game/Screens/Edit/Menus/EditorMenuBar.cs @@ -44,27 +44,12 @@ namespace osu.Game.Screens.Edit.Menus private Color4 openedForegroundColour; private Color4 openedBackgroundColour; - public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => parentSizedBox.ReceiveMouseInputAt(screenSpacePos); - - /// - /// A box with width equal to this 's width, and height equal to the parent height. - /// - private readonly Box parentSizedBox; public DrawableEditorBarMenuItem(MenuItem item) : base(item) { Anchor = Anchor.CentreLeft; Origin = Anchor.CentreLeft; - - AddInternal(parentSizedBox = new Box - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.X, - BypassAutoSizeAxes = Axes.Both, - Alpha = 0, - }); } public override void SetFlowDirection(Direction direction) @@ -100,8 +85,6 @@ namespace osu.Game.Screens.Edit.Menus protected override void Update() { base.Update(); - - parentSizedBox.Height = Parent.DrawHeight; } protected override Drawable CreateBackground() => new Container From b2eab1f4351ad2b84a19706c35835ae9f98aad71 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 29 Sep 2017 15:09:56 +0900 Subject: [PATCH 0077/1263] Set the hover background colour as dictated by flyte --- osu.Game/Screens/Edit/Menus/EditorMenuBar.cs | 25 +++++++++----------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/osu.Game/Screens/Edit/Menus/EditorMenuBar.cs b/osu.Game/Screens/Edit/Menus/EditorMenuBar.cs index 329471fd0a..488ba220a2 100644 --- a/osu.Game/Screens/Edit/Menus/EditorMenuBar.cs +++ b/osu.Game/Screens/Edit/Menus/EditorMenuBar.cs @@ -41,9 +41,6 @@ namespace osu.Game.Screens.Edit.Menus private class DrawableEditorBarMenuItem : DrawableOsuMenuItem { - private Color4 openedForegroundColour; - private Color4 openedBackgroundColour; - public DrawableEditorBarMenuItem(MenuItem item) : base(item) @@ -52,24 +49,24 @@ namespace osu.Game.Screens.Edit.Menus Origin = Anchor.CentreLeft; } + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + ForegroundColour = colours.BlueLight; + BackgroundColour = Color4.Transparent; + ForegroundColourHover = Color4.White; + BackgroundColourHover = colours.Gray3; + } + public override void SetFlowDirection(Direction direction) { AutoSizeAxes = Axes.Both; } - [BackgroundDependencyLoader] - private void load(OsuColour colours) - { - ForegroundColour = ForegroundColourHover = colours.BlueLight; - BackgroundColour = BackgroundColourHover = Color4.Transparent; - openedForegroundColour = Color4.White; - openedBackgroundColour = colours.Gray3; - } - protected override void UpdateBackgroundColour() { if (State == MenuItemState.Selected) - Background.FadeColour(openedBackgroundColour); + Background.FadeColour(BackgroundColourHover); else base.UpdateBackgroundColour(); } @@ -77,7 +74,7 @@ namespace osu.Game.Screens.Edit.Menus protected override void UpdateForegroundColour() { if (State == MenuItemState.Selected) - Foreground.FadeColour(openedForegroundColour); + Foreground.FadeColour(ForegroundColourHover); else base.UpdateForegroundColour(); } From 775e8bada5e742a0ac62423fa1d61b6f3aa44047 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 29 Sep 2017 15:10:24 +0900 Subject: [PATCH 0078/1263] Make the background bottom corners look nice with the new hover functionality --- osu.Game/Screens/Edit/Menus/EditorMenuBar.cs | 53 ++++++++++++++------ 1 file changed, 37 insertions(+), 16 deletions(-) diff --git a/osu.Game/Screens/Edit/Menus/EditorMenuBar.cs b/osu.Game/Screens/Edit/Menus/EditorMenuBar.cs index 488ba220a2..616cabbab2 100644 --- a/osu.Game/Screens/Edit/Menus/EditorMenuBar.cs +++ b/osu.Game/Screens/Edit/Menus/EditorMenuBar.cs @@ -41,12 +41,15 @@ namespace osu.Game.Screens.Edit.Menus private class DrawableEditorBarMenuItem : DrawableOsuMenuItem { + private BackgroundBox background; public DrawableEditorBarMenuItem(MenuItem item) : base(item) { Anchor = Anchor.CentreLeft; Origin = Anchor.CentreLeft; + + StateChanged += stateChanged; } [BackgroundDependencyLoader] @@ -79,25 +82,15 @@ namespace osu.Game.Screens.Edit.Menus base.UpdateForegroundColour(); } - protected override void Update() + private void stateChanged(MenuItemState newState) { - base.Update(); + if (newState == MenuItemState.Selected) + background.Expand(); + else + background.Contract(); } - protected override Drawable CreateBackground() => new Container - { - RelativeSizeAxes = Axes.Both, - Masking = true, - Child = new Container - { - RelativeSizeAxes = Axes.Both, - Height = 2, - Masking = true, - CornerRadius = 4, - Child = new Box { RelativeSizeAxes = Axes.Both } - } - }; - + protected override Drawable CreateBackground() => background = new BackgroundBox(); protected override DrawableOsuMenuItem.TextContainer CreateTextContainer() => new TextContainer(); private new class TextContainer : DrawableOsuMenuItem.TextContainer @@ -108,6 +101,34 @@ namespace osu.Game.Screens.Edit.Menus NormalText.Margin = BoldText.Margin = new MarginPadding { Horizontal = 10, Vertical = MARGIN_VERTICAL }; } } + + private class BackgroundBox : CompositeDrawable + { + private readonly Container innerBackground; + + public BackgroundBox() + { + RelativeSizeAxes = Axes.Both; + Masking = true; + InternalChild = innerBackground = new Container + { + RelativeSizeAxes = Axes.Both, + Masking = true, + CornerRadius = 4, + Child = new Box { RelativeSizeAxes = Axes.Both } + }; + } + + /// + /// Expands the background such that it doesn't show the bottom corners. + /// + public void Expand() => innerBackground.Height = 2; + + /// + /// Contracts the background such that it shows the bottom corners. + /// + public void Contract() => innerBackground.Height = 1; + } } private class SubMenu : OsuMenu From 7b4348254c47d60aeb76a7ff7b8c695f36da4564 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 29 Sep 2017 20:02:55 +0900 Subject: [PATCH 0079/1263] Don't use new --- osu.Game/Screens/Edit/Menus/ScreenSelectionTabControl.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Menus/ScreenSelectionTabControl.cs b/osu.Game/Screens/Edit/Menus/ScreenSelectionTabControl.cs index a455fa8d71..516b954e44 100644 --- a/osu.Game/Screens/Edit/Menus/ScreenSelectionTabControl.cs +++ b/osu.Game/Screens/Edit/Menus/ScreenSelectionTabControl.cs @@ -44,7 +44,7 @@ namespace osu.Game.Screens.Edit.Menus protected override TabItem CreateTabItem(EditorScreenMode value) => new TabItem(value); - private new class TabItem : OsuTabItem + private class TabItem : OsuTabItem { private const float transition_length = 250; From 21c6a63fa1bc50e4ec5caf11618fd892cefda8ea Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 29 Sep 2017 20:03:09 +0900 Subject: [PATCH 0080/1263] Use using for Description --- osu.Game/Screens/Edit/Menus/ScreenSelectionTabControl.cs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Edit/Menus/ScreenSelectionTabControl.cs b/osu.Game/Screens/Edit/Menus/ScreenSelectionTabControl.cs index 516b954e44..652ef1d61f 100644 --- a/osu.Game/Screens/Edit/Menus/ScreenSelectionTabControl.cs +++ b/osu.Game/Screens/Edit/Menus/ScreenSelectionTabControl.cs @@ -10,6 +10,7 @@ using osu.Framework.Graphics.UserInterface; using osu.Game.Graphics; using osu.Game.Graphics.UserInterface; using OpenTK; +using System.ComponentModel; namespace osu.Game.Screens.Edit.Menus { @@ -72,13 +73,13 @@ namespace osu.Game.Screens.Edit.Menus public enum EditorScreenMode { - [System.ComponentModel.Description("compose")] + [Description("compose")] Compose, - [System.ComponentModel.Description("design")] + [Description("design")] Design, - [System.ComponentModel.Description("timing")] + [Description("timing")] Timing, - [System.ComponentModel.Description("song")] + [Description("song")] SongSetup } } From 40a27c810a7dabba9082475ed36aa0aa71872029 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Fri, 29 Sep 2017 19:24:14 +0800 Subject: [PATCH 0081/1263] Calculate SPM in spinner disc. --- osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerDisc.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerDisc.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerDisc.cs index 6577c7fd50..518fe188fb 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerDisc.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerDisc.cs @@ -76,7 +76,9 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces private float lastAngle; private float currentRotation; + private double lastTime; public float RotationAbsolute; + public double SpinsPerMinute; private int completeTick; @@ -107,9 +109,11 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces currentRotation += thisAngle - lastAngle; RotationAbsolute += Math.Abs(thisAngle - lastAngle); + SpinsPerMinute = (thisAngle - lastAngle) / (Time.Current - lastTime) * 1000 * 60 / 360; } lastAngle = thisAngle; + lastTime = Time.Current; if (Complete && updateCompleteTick()) { From e2e26c91af5856851ab414186258683ce07d9b85 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Fri, 29 Sep 2017 22:30:41 +0800 Subject: [PATCH 0082/1263] Show SPM value basically. --- .../Objects/Drawables/DrawableSpinner.cs | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs index 98dd40b0e6..c7e0353985 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs @@ -13,6 +13,7 @@ using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Allocation; using osu.Game.Rulesets.Osu.Judgements; using osu.Game.Screens.Ranking; +using osu.Game.Graphics.Sprites; namespace osu.Game.Rulesets.Osu.Objects.Drawables { @@ -29,6 +30,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables private readonly Container circleContainer; private readonly CirclePiece circle; private readonly GlowPiece glow; + private readonly OsuSpriteText spmText; private readonly SpriteIcon symbol; @@ -96,6 +98,24 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables Origin = Anchor.Centre, }, circleContainer.CreateProxy(), + spmText = new OsuSpriteText + { + Anchor = Anchor.Centre, + Origin = Anchor.BottomCentre, + Text = @"0", + Font = @"Venera", + TextSize = 24, + Y = 120 + }, + new OsuSpriteText + { + Anchor = Anchor.Centre, + Origin = Anchor.TopCentre, + Text = @"SPINS PER MINUTE", + Font = @"Venera", + TextSize = 12, + Y = 125 + }, ticks = new SpinnerTicks { Anchor = Anchor.Centre, @@ -167,6 +187,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables circle.Rotation = disc.Rotation; ticks.Rotation = disc.Rotation; + spmText.Text = disc.SpinsPerMinute.ToString(@"#0"); float relativeCircleScale = spinner.Scale * circle.DrawHeight / mainContainer.DrawHeight; disc.ScaleTo(relativeCircleScale + (1 - relativeCircleScale) * Progress, 200, Easing.OutQuint); From 647304c14bd1b247c6ac1df2dce51bcb3339e0ca Mon Sep 17 00:00:00 2001 From: Jorolf Date: Fri, 29 Sep 2017 23:08:30 +0200 Subject: [PATCH 0083/1263] move logic to DirectPanel and reuse stuff for the PreviewButton --- osu.Game/Audio/AudioLoadWrapper.cs | 35 +++++ osu.Game/Overlays/BeatmapSet/PreviewButton.cs | 128 +++++------------- osu.Game/Overlays/Direct/DirectGridPanel.cs | 13 +- osu.Game/Overlays/Direct/DirectListPanel.cs | 14 +- osu.Game/Overlays/Direct/DirectPanel.cs | 53 ++++++++ osu.Game/Overlays/Direct/PlayButton.cs | 91 ++++++------- osu.Game/osu.Game.csproj | 1 + 7 files changed, 166 insertions(+), 169 deletions(-) create mode 100644 osu.Game/Audio/AudioLoadWrapper.cs diff --git a/osu.Game/Audio/AudioLoadWrapper.cs b/osu.Game/Audio/AudioLoadWrapper.cs new file mode 100644 index 0000000000..8c013cf70f --- /dev/null +++ b/osu.Game/Audio/AudioLoadWrapper.cs @@ -0,0 +1,35 @@ +using osu.Framework.Allocation; +using osu.Framework.Audio; +using osu.Framework.Audio.Track; +using osu.Framework.Graphics; +using osu.Game.Beatmaps; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace osu.Game.Audio +{ + public class AudioLoadWrapper : Drawable + { + private readonly string preview; + + public Track Preview; + + public AudioLoadWrapper(string preview) + { + this.preview = preview; + } + + [BackgroundDependencyLoader] + private void load(AudioManager audio) + { + if (!string.IsNullOrEmpty(preview)) + { + Preview = audio.Track.Get(preview); + Preview.Volume.Value = 0.5; + } + } + } +} diff --git a/osu.Game/Overlays/BeatmapSet/PreviewButton.cs b/osu.Game/Overlays/BeatmapSet/PreviewButton.cs index bdb06106f0..9bb8b9a1a5 100644 --- a/osu.Game/Overlays/BeatmapSet/PreviewButton.cs +++ b/osu.Game/Overlays/BeatmapSet/PreviewButton.cs @@ -15,6 +15,9 @@ using osu.Game.Graphics.Containers; using osu.Game.Graphics.UserInterface; using OpenTK; using OpenTK.Graphics; +using osu.Game.Audio; +using osu.Game.Overlays.Direct; +using osu.Framework.Configuration; namespace osu.Game.Overlays.BeatmapSet { @@ -24,27 +27,10 @@ namespace osu.Game.Overlays.BeatmapSet private readonly Container audioWrapper; private readonly Box bg, progress; - private readonly SpriteIcon icon; - private readonly LoadingAnimation loadingAnimation; + private readonly PlayButton playButton; private Track preview; - - private bool loading - { - set - { - if (value) - { - loadingAnimation.Show(); - icon.FadeOut(transition_duration * 5, Easing.OutQuint); - } - else - { - loadingAnimation.Hide(); - icon.FadeIn(transition_duration, Easing.OutQuint); - } - } - } + private readonly Bindable playing = new Bindable(); private BeatmapSetInfo beatmapSet; public BeatmapSetInfo BeatmapSet @@ -55,42 +41,11 @@ namespace osu.Game.Overlays.BeatmapSet if (value == beatmapSet) return; beatmapSet = value; - Playing = false; + playing.Value = false; preview = null; } } - private bool playing; - public bool Playing - { - get { return playing; } - set - { - if (value == playing) return; - playing = value; - - if (preview == null) - { - loading = true; - audioWrapper.Child = new AsyncLoadWrapper(new AudioLoadWrapper(BeatmapSet) - { - OnLoadComplete = d => - { - loading = false; - - preview = (d as AudioLoadWrapper)?.Preview; - Playing = Playing; - updatePlayingState(); - }, - }); - - return; - } - - updatePlayingState(); - } - } - public PreviewButton() { Height = 42; @@ -116,22 +71,16 @@ namespace osu.Game.Overlays.BeatmapSet Alpha = 0f, }, }, - icon = new SpriteIcon + playButton = new PlayButton(playing) { Anchor = Anchor.Centre, Origin = Anchor.Centre, - Icon = FontAwesome.fa_play, Size = new Vector2(18), - Shadow = false, - }, - loadingAnimation = new LoadingAnimation - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, }, }; - Action = () => Playing = !Playing; + Action = () => playing.Value = !playing.Value; + playing.ValueChanged += updatePlayingState; } [BackgroundDependencyLoader] @@ -144,12 +93,12 @@ namespace osu.Game.Overlays.BeatmapSet { base.Update(); - if (Playing && preview != null) + if (playing.Value && preview != null) { progress.Width = (float)(preview.CurrentTime / preview.Length); if (preview.HasCompleted) { - Playing = false; + playing.Value = false; preview = null; } } @@ -157,7 +106,7 @@ namespace osu.Game.Overlays.BeatmapSet protected override void Dispose(bool isDisposing) { - Playing = false; + playing.Value = false; base.Dispose(isDisposing); } @@ -173,44 +122,35 @@ namespace osu.Game.Overlays.BeatmapSet base.OnHoverLost(state); } - private void updatePlayingState() + private void updatePlayingState(bool newValue) { - if (preview == null) return; - - if (Playing) + if (preview == null) { - icon.Icon = FontAwesome.fa_stop; - progress.FadeIn(100); + playButton.Loading = true; + audioWrapper.Child = new AsyncLoadWrapper(new AudioLoadWrapper(BeatmapSet.OnlineInfo.Preview) + { + OnLoadComplete = d => + { + playButton.Loading = false; - preview.Seek(0); - preview.Start(); + preview = (d as AudioLoadWrapper)?.Preview; + playing.TriggerChange(); + }, + }); } else { - icon.Icon = FontAwesome.fa_play; - progress.FadeOut(100); - preview.Stop(); - } - } - - private class AudioLoadWrapper : Drawable - { - private readonly string preview; - - public Track Preview; - - public AudioLoadWrapper(BeatmapSetInfo set) - { - preview = set.OnlineInfo.Preview; - } - - [BackgroundDependencyLoader] - private void load(AudioManager audio) - { - if (!string.IsNullOrEmpty(preview)) + if (newValue) { - Preview = audio.Track.Get(preview); - Preview.Volume.Value = 0.5; + progress.FadeIn(100); + + preview.Seek(0); + preview.Start(); + } + else + { + progress.FadeOut(100); + preview.Stop(); } } } diff --git a/osu.Game/Overlays/Direct/DirectGridPanel.cs b/osu.Game/Overlays/Direct/DirectGridPanel.cs index 8a26ae906d..3b8cd20200 100644 --- a/osu.Game/Overlays/Direct/DirectGridPanel.cs +++ b/osu.Game/Overlays/Direct/DirectGridPanel.cs @@ -26,6 +26,7 @@ namespace osu.Game.Overlays.Direct private Box progressBar; protected override PlayButton PlayButton => playButton; + protected override Box PreviewBar => progressBar; public DirectGridPanel(BeatmapSetInfo beatmap) : base(beatmap) { @@ -197,20 +198,8 @@ namespace osu.Game.Overlays.Direct Margin = new MarginPadding { Top = 5, Left = 10 }, Size = new Vector2(30), Alpha = 0, - TrackUrl = "https://b.ppy.sh/preview/" + SetInfo.OnlineBeatmapSetID + ".mp3", }, }); - - PreviewPlaying.ValueChanged += newValue => playButton.FadeTo(newValue || IsHovered ? 1 : 0, 120, Easing.InOutQuint); - PreviewPlaying.ValueChanged += newValue => progressBar.FadeTo(newValue ? 1 : 0, 120, Easing.InOutQuint); - } - - protected override void Update() - { - base.Update(); - - if (PreviewPlaying && playButton.Track != null) - progressBar.Width = (float)(playButton.Track.CurrentTime / playButton.Track.Length); } } } diff --git a/osu.Game/Overlays/Direct/DirectListPanel.cs b/osu.Game/Overlays/Direct/DirectListPanel.cs index a9d7993f7a..6a73c15ee6 100644 --- a/osu.Game/Overlays/Direct/DirectListPanel.cs +++ b/osu.Game/Overlays/Direct/DirectListPanel.cs @@ -14,6 +14,7 @@ using osu.Framework.Localisation; using osu.Framework.Graphics.Shapes; using osu.Game.Beatmaps; using osu.Framework.Configuration; +using System; namespace osu.Game.Overlays.Direct { @@ -33,6 +34,7 @@ namespace osu.Game.Overlays.Direct private Box progressBar; protected override PlayButton PlayButton => playButton; + protected override Box PreviewBar => progressBar; [BackgroundDependencyLoader] private void load(LocalisationEngine localisation, OsuColour colours) @@ -70,7 +72,6 @@ namespace osu.Game.Overlays.Direct Size = new Vector2(height / 2), FillMode = FillMode.Fit, Alpha = 0, - TrackUrl = "https://b.ppy.sh/preview/" + SetInfo.OnlineBeatmapSetID + ".mp3", }, new FillFlowContainer { @@ -165,17 +166,6 @@ namespace osu.Game.Overlays.Direct Colour = colours.Yellow, }, }); - - PreviewPlaying.ValueChanged += newValue => playButton.FadeTo(newValue || IsHovered ? 1 : 0, 120, Easing.InOutQuint); - PreviewPlaying.ValueChanged += newValue => progressBar.FadeTo(newValue ? 1 : 0, 120, Easing.InOutQuint); - } - - protected override void Update() - { - base.Update(); - - if (PreviewPlaying && playButton.Track != null) - progressBar.Width = (float)(playButton.Track.CurrentTime / playButton.Track.Length); } } } diff --git a/osu.Game/Overlays/Direct/DirectPanel.cs b/osu.Game/Overlays/Direct/DirectPanel.cs index c4c20da297..6b1e06fd3a 100644 --- a/osu.Game/Overlays/Direct/DirectPanel.cs +++ b/osu.Game/Overlays/Direct/DirectPanel.cs @@ -21,6 +21,8 @@ using osu.Framework.Logging; using osu.Game.Overlays.Notifications; using osu.Game.Online.API.Requests; using osu.Framework.Configuration; +using osu.Framework.Audio.Track; +using osu.Game.Audio; namespace osu.Game.Overlays.Direct { @@ -39,9 +41,12 @@ namespace osu.Game.Overlays.Direct private BeatmapManager beatmaps; private NotificationOverlay notifications; private BeatmapSetOverlay beatmapSetOverlay; + private Container audioWrapper; + protected Track Preview; public readonly Bindable PreviewPlaying = new Bindable(); protected abstract PlayButton PlayButton { get; } + protected abstract Box PreviewBar { get; } protected override Container Content => content; @@ -82,6 +87,7 @@ namespace osu.Game.Overlays.Direct EdgeEffect = edgeEffectNormal, Children = new[] { + audioWrapper = new Container(), // temporary blackness until the actual background loads. BlackBackground = new Box { @@ -106,6 +112,53 @@ namespace osu.Game.Overlays.Direct if (downloadRequest != null) attachDownload(downloadRequest); + + PreviewPlaying.ValueChanged += newValue => PlayButton.FadeTo(newValue || IsHovered ? 1 : 0, 120, Easing.InOutQuint); + PreviewPlaying.ValueChanged += newValue => PreviewBar.FadeTo(newValue ? 1 : 0, 120, Easing.InOutQuint); + PreviewPlaying.ValueChanged += setPlaying; + } + + private void setPlaying(bool newValue) + { + if (newValue) + { + if(Preview == null) + { + PlayButton.Loading = true; + audioWrapper.Child = new AsyncLoadWrapper(new AudioLoadWrapper("https://b.ppy.sh/preview/" + SetInfo.OnlineBeatmapSetID + ".mp3") + { + OnLoadComplete = d => + { + PlayButton.Loading = false; + Preview = (d as AudioLoadWrapper)?.Preview; + Preview.Start(); + }, + }); + } + else + { + Preview.Start(); + } + } + else + { + Preview?.Stop(); + } + } + + protected override void Update() + { + base.Update(); + + if (PreviewPlaying && Preview != null) + { + PreviewBar.Width = (float)(Preview.CurrentTime / Preview.Length); + if (Preview.HasCompleted) + { + PreviewPlaying.Value = false; + Preview = null; + } + } } protected override bool OnHover(InputState state) diff --git a/osu.Game/Overlays/Direct/PlayButton.cs b/osu.Game/Overlays/Direct/PlayButton.cs index b0d011a81c..34b0ace1c5 100644 --- a/osu.Game/Overlays/Direct/PlayButton.cs +++ b/osu.Game/Overlays/Direct/PlayButton.cs @@ -11,81 +11,70 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Input; using osu.Game.Beatmaps; using osu.Game.Graphics; +using osu.Game.Graphics.UserInterface; using System.Threading.Tasks; namespace osu.Game.Overlays.Direct { public class PlayButton : Container { - public string TrackUrl; - - public Bindable Playing; - - public Track Track; - private Bindable gameBeatmap; - private AudioManager audio; + private readonly Bindable playing; private Color4 hoverColour; private readonly SpriteIcon icon; + private readonly LoadingAnimation loadingAnimation; + private const float transition_duration = 500; + + private bool loading; + public bool Loading + { + get { return loading; } + set + { + loading = value; + if (value) + { + loadingAnimation.Show(); + icon.FadeOut(transition_duration * 5, Easing.OutQuint); + } + else + { + loadingAnimation.Hide(); + icon.FadeIn(transition_duration, Easing.OutQuint); + } + } + } public PlayButton(Bindable playing) { - Playing = playing; - Add(icon = new SpriteIcon + this.playing = playing; + AddRange(new Drawable[] { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - FillMode = FillMode.Fit, - RelativeSizeAxes = Axes.Both, - Icon = FontAwesome.fa_play, + icon = new SpriteIcon + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + FillMode = FillMode.Fit, + RelativeSizeAxes = Axes.Both, + Icon = FontAwesome.fa_play, + }, + loadingAnimation = new LoadingAnimation(), }); - Playing.ValueChanged += newValue => icon.Icon = newValue ? (Track == null ? FontAwesome.fa_spinner : FontAwesome.fa_pause) : FontAwesome.fa_play; + playing.ValueChanged += newValue => icon.Icon = newValue ? FontAwesome.fa_pause : FontAwesome.fa_play; - Playing.ValueChanged += newValue => - { - if (newValue) - Track?.Start(); - else - Track?.Stop(); - }; - - Playing.ValueChanged += newValue => icon.FadeColour(newValue || IsHovered ? hoverColour : Color4.White, 120, Easing.InOutQuint); + playing.ValueChanged += newValue => icon.FadeColour(newValue || IsHovered ? hoverColour : Color4.White, 120, Easing.InOutQuint); } [BackgroundDependencyLoader] - private void load(OsuColour colour, OsuGameBase game, AudioManager audio) + private void load(OsuColour colour) { hoverColour = colour.Yellow; - gameBeatmap = game.Beatmap; - this.audio = audio; } - private Task loadTask; - protected override bool OnClick(InputState state) { - gameBeatmap.Value.Track.Stop(); - - Playing.Value = !Playing.Value; - - if (loadTask == null) - { - icon.Spin(2000, RotationDirection.Clockwise); - - loadTask = Task.Run(() => - { - Track = audio.Track.Get(TrackUrl); - Track.Looping = true; - if (Playing) - Track.Start(); - - icon.ClearTransforms(); - icon.Rotation = 0; - Playing.TriggerChange(); - }); - } - + playing.Value = !playing.Value; return true; } @@ -97,7 +86,7 @@ namespace osu.Game.Overlays.Direct protected override void OnHoverLost(InputState state) { - if(!Playing) + if(!playing.Value) icon.FadeColour(Color4.White, 120, Easing.InOutQuint); base.OnHoverLost(state); } diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 95a15c06ba..3d81c5a539 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -239,6 +239,7 @@ + From 26e7a3f157ced6e6fb0ab01f05b9ec2abe2ab862 Mon Sep 17 00:00:00 2001 From: Jorolf Date: Fri, 29 Sep 2017 23:12:12 +0200 Subject: [PATCH 0084/1263] add license header --- osu.Game/Audio/AudioLoadWrapper.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/osu.Game/Audio/AudioLoadWrapper.cs b/osu.Game/Audio/AudioLoadWrapper.cs index 8c013cf70f..69bf9d8147 100644 --- a/osu.Game/Audio/AudioLoadWrapper.cs +++ b/osu.Game/Audio/AudioLoadWrapper.cs @@ -1,4 +1,7 @@ -using osu.Framework.Allocation; +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Audio.Track; using osu.Framework.Graphics; From 2457df8e18b88006b3ecae32dd1ab0ac970a79e1 Mon Sep 17 00:00:00 2001 From: Jorolf Date: Fri, 29 Sep 2017 23:26:16 +0200 Subject: [PATCH 0085/1263] remove unused usings and reset the track to the start when playing again --- osu.Game/Audio/AudioLoadWrapper.cs | 5 ----- osu.Game/Overlays/BeatmapSet/PreviewButton.cs | 2 -- osu.Game/Overlays/Direct/DirectGridPanel.cs | 1 - osu.Game/Overlays/Direct/DirectListPanel.cs | 2 -- osu.Game/Overlays/Direct/DirectPanel.cs | 3 ++- osu.Game/Overlays/Direct/PlayButton.cs | 4 ---- 6 files changed, 2 insertions(+), 15 deletions(-) diff --git a/osu.Game/Audio/AudioLoadWrapper.cs b/osu.Game/Audio/AudioLoadWrapper.cs index 69bf9d8147..efdde48564 100644 --- a/osu.Game/Audio/AudioLoadWrapper.cs +++ b/osu.Game/Audio/AudioLoadWrapper.cs @@ -6,11 +6,6 @@ using osu.Framework.Audio; using osu.Framework.Audio.Track; using osu.Framework.Graphics; using osu.Game.Beatmaps; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace osu.Game.Audio { diff --git a/osu.Game/Overlays/BeatmapSet/PreviewButton.cs b/osu.Game/Overlays/BeatmapSet/PreviewButton.cs index 9bb8b9a1a5..ea49963f67 100644 --- a/osu.Game/Overlays/BeatmapSet/PreviewButton.cs +++ b/osu.Game/Overlays/BeatmapSet/PreviewButton.cs @@ -2,7 +2,6 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using osu.Framework.Allocation; -using osu.Framework.Audio; using osu.Framework.Audio.Track; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; @@ -12,7 +11,6 @@ using osu.Framework.Input; using osu.Game.Beatmaps; using osu.Game.Graphics; using osu.Game.Graphics.Containers; -using osu.Game.Graphics.UserInterface; using OpenTK; using OpenTK.Graphics; using osu.Game.Audio; diff --git a/osu.Game/Overlays/Direct/DirectGridPanel.cs b/osu.Game/Overlays/Direct/DirectGridPanel.cs index 3b8cd20200..10611cd5be 100644 --- a/osu.Game/Overlays/Direct/DirectGridPanel.cs +++ b/osu.Game/Overlays/Direct/DirectGridPanel.cs @@ -12,7 +12,6 @@ using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Framework.Graphics.Shapes; using osu.Game.Beatmaps; -using osu.Framework.Configuration; namespace osu.Game.Overlays.Direct { diff --git a/osu.Game/Overlays/Direct/DirectListPanel.cs b/osu.Game/Overlays/Direct/DirectListPanel.cs index 6a73c15ee6..7f5fa3e3f0 100644 --- a/osu.Game/Overlays/Direct/DirectListPanel.cs +++ b/osu.Game/Overlays/Direct/DirectListPanel.cs @@ -13,8 +13,6 @@ using osu.Framework.Allocation; using osu.Framework.Localisation; using osu.Framework.Graphics.Shapes; using osu.Game.Beatmaps; -using osu.Framework.Configuration; -using System; namespace osu.Game.Overlays.Direct { diff --git a/osu.Game/Overlays/Direct/DirectPanel.cs b/osu.Game/Overlays/Direct/DirectPanel.cs index 6b1e06fd3a..2195fc9ce7 100644 --- a/osu.Game/Overlays/Direct/DirectPanel.cs +++ b/osu.Game/Overlays/Direct/DirectPanel.cs @@ -131,12 +131,13 @@ namespace osu.Game.Overlays.Direct { PlayButton.Loading = false; Preview = (d as AudioLoadWrapper)?.Preview; - Preview.Start(); + PreviewPlaying.TriggerChange(); }, }); } else { + Preview.Seek(0); Preview.Start(); } } diff --git a/osu.Game/Overlays/Direct/PlayButton.cs b/osu.Game/Overlays/Direct/PlayButton.cs index 34b0ace1c5..0405049c6a 100644 --- a/osu.Game/Overlays/Direct/PlayButton.cs +++ b/osu.Game/Overlays/Direct/PlayButton.cs @@ -3,16 +3,12 @@ using OpenTK.Graphics; using osu.Framework.Allocation; -using osu.Framework.Audio; -using osu.Framework.Audio.Track; using osu.Framework.Configuration; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Input; -using osu.Game.Beatmaps; using osu.Game.Graphics; using osu.Game.Graphics.UserInterface; -using System.Threading.Tasks; namespace osu.Game.Overlays.Direct { From 59247bcf1eeef982a1ab442afcef0c3afa055561 Mon Sep 17 00:00:00 2001 From: Jorolf Date: Fri, 29 Sep 2017 23:31:42 +0200 Subject: [PATCH 0086/1263] another unused using --- osu.Game/Audio/AudioLoadWrapper.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Audio/AudioLoadWrapper.cs b/osu.Game/Audio/AudioLoadWrapper.cs index efdde48564..67836d1690 100644 --- a/osu.Game/Audio/AudioLoadWrapper.cs +++ b/osu.Game/Audio/AudioLoadWrapper.cs @@ -5,7 +5,6 @@ using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Audio.Track; using osu.Framework.Graphics; -using osu.Game.Beatmaps; namespace osu.Game.Audio { From 92c3d722b4140020088fa8a471b6e24a2b8ad0b0 Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Sat, 30 Sep 2017 05:41:32 +0300 Subject: [PATCH 0087/1263] Show mapper's profile when clicking on avatar in BeatmapSetOverlay --- osu.Game/OsuGame.cs | 6 ++--- osu.Game/Overlays/BeatmapSet/AuthorInfo.cs | 28 ++++++++++++++++++++-- 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index c137b8f6f5..75a1d61371 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -188,11 +188,11 @@ namespace osu.Game GetToolbarHeight = () => ToolbarOffset, Depth = -1 }, overlayContent.Add); - LoadComponentAsync(userProfile = new UserProfileOverlay { Depth = -2 }, mainContent.Add); LoadComponentAsync(beatmapSetOverlay = new BeatmapSetOverlay { Depth = -2 }, mainContent.Add); + LoadComponentAsync(userProfile = new UserProfileOverlay { Depth = -3 }, mainContent.Add); LoadComponentAsync(musicController = new MusicController { - Depth = -3, + Depth = -4, Position = new Vector2(0, Toolbar.HEIGHT), Anchor = Anchor.TopRight, Origin = Anchor.TopRight, @@ -200,7 +200,7 @@ namespace osu.Game LoadComponentAsync(notificationOverlay = new NotificationOverlay { - Depth = -3, + Depth = -4, Anchor = Anchor.TopRight, Origin = Anchor.TopRight, }, overlayContent.Add); diff --git a/osu.Game/Overlays/BeatmapSet/AuthorInfo.cs b/osu.Game/Overlays/BeatmapSet/AuthorInfo.cs index b0e4e49e31..fc9fd1e614 100644 --- a/osu.Game/Overlays/BeatmapSet/AuthorInfo.cs +++ b/osu.Game/Overlays/BeatmapSet/AuthorInfo.cs @@ -9,6 +9,9 @@ using osu.Game.Graphics.Sprites; using osu.Game.Users; using OpenTK; using OpenTK.Graphics; +using osu.Framework.Allocation; +using osu.Game.Graphics.Containers; +using osu.Framework.Graphics.Cursor; namespace osu.Game.Overlays.BeatmapSet { @@ -17,8 +20,11 @@ namespace osu.Game.Overlays.BeatmapSet private const float height = 50; private readonly UpdateableAvatar avatar; + private readonly ClickableArea clickableArea; private readonly FillFlowContainer fields; + private UserProfileOverlay profile; + private BeatmapSetInfo beatmapSet; public BeatmapSetInfo BeatmapSet { @@ -31,6 +37,8 @@ namespace osu.Game.Overlays.BeatmapSet var i = BeatmapSet.OnlineInfo; avatar.User = i.Author; + clickableArea.Action = () => profile?.ShowUser(avatar.User); + fields.Children = new Drawable[] { new Field("made by", i.Author.Username, @"Exo2.0-RegularItalic"), @@ -58,11 +66,15 @@ namespace osu.Game.Overlays.BeatmapSet Children = new Drawable[] { - avatar = new UpdateableAvatar + clickableArea = new ClickableArea { - Size = new Vector2(height), + AutoSizeAxes = Axes.Both, CornerRadius = 3, Masking = true, + Child = avatar = new UpdateableAvatar + { + Size = new Vector2(height), + }, EdgeEffect = new EdgeEffectParameters { Colour = Color4.Black.Opacity(0.25f), @@ -80,6 +92,13 @@ namespace osu.Game.Overlays.BeatmapSet }; } + [BackgroundDependencyLoader(true)] + private void load(UserProfileOverlay profile) + { + this.profile = profile; + clickableArea.Action = () => profile?.ShowUser(avatar.User); + } + private class Field : FillFlowContainer { public Field(string first, string second, string secondFont) @@ -103,5 +122,10 @@ namespace osu.Game.Overlays.BeatmapSet }; } } + + private class ClickableArea : OsuClickableContainer, IHasTooltip + { + public string TooltipText => @"View Profile"; + } } } From 3de42ee4050f8b08d7c0db3796e4d6913097dc9a Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Sat, 30 Sep 2017 15:23:10 +0800 Subject: [PATCH 0088/1263] Smooth spm values into a time range. --- .../Objects/Drawables/DrawableSpinner.cs | 3 ++- .../Objects/Drawables/Pieces/SpinnerDisc.cs | 20 ++++++++++++++++--- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs index c7e0353985..6b9e91d4f4 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.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.Linq; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -187,7 +188,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables circle.Rotation = disc.Rotation; ticks.Rotation = disc.Rotation; - spmText.Text = disc.SpinsPerMinute.ToString(@"#0"); + spmText.Text = Math.Truncate(disc.SpinsPerMinute).ToString(@"#0"); float relativeCircleScale = spinner.Scale * circle.DrawHeight / mainContainer.DrawHeight; disc.ScaleTo(relativeCircleScale + (1 - relativeCircleScale) * Progress, 200, Easing.OutQuint); diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerDisc.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerDisc.cs index 518fe188fb..04bbd8b871 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerDisc.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerDisc.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 osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Input; @@ -76,9 +77,11 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces private float lastAngle; private float currentRotation; - private double lastTime; public float RotationAbsolute; public double SpinsPerMinute; + private readonly Queue rotations = new Queue(); + private readonly Queue times = new Queue(); + private const double spm_count_duration = 595; // not using hundreds to avoid frame rounding issues private int completeTick; @@ -109,11 +112,22 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces currentRotation += thisAngle - lastAngle; RotationAbsolute += Math.Abs(thisAngle - lastAngle); - SpinsPerMinute = (thisAngle - lastAngle) / (Time.Current - lastTime) * 1000 * 60 / 360; + if (rotations.Count > 0) + { + float rotationFrom = rotations.Peek(); + double timeFrom = times.Peek(); + while (Time.Current - times.Peek() > spm_count_duration) + { + rotationFrom = rotations.Dequeue(); + timeFrom = times.Dequeue(); + } + SpinsPerMinute = (currentRotation - rotationFrom) / (Time.Current - timeFrom) * 1000 * 60 / 360; + } } lastAngle = thisAngle; - lastTime = Time.Current; + rotations.Enqueue(currentRotation); + times.Enqueue(Time.Current); if (Complete && updateCompleteTick()) { From 5e751ea0ec38aabdf24bb80be772ee88eaf5274e Mon Sep 17 00:00:00 2001 From: "Franc[e]sco" Date: Sun, 1 Oct 2017 00:15:23 +0200 Subject: [PATCH 0089/1263] Only convert chords into strong hits for mania -> taiko --- .../Beatmaps/TaikoBeatmapConverter.cs | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs b/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs index 4f2707ff88..ceaecbb555 100644 --- a/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs +++ b/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs @@ -55,14 +55,17 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps Beatmap converted = base.ConvertBeatmap(original); - // Post processing step to transform hit objects with the same start time into strong hits - converted.HitObjects = converted.HitObjects.GroupBy(t => t.StartTime).Select(x => + if (original.BeatmapInfo.RulesetID == 3) { - TaikoHitObject first = x.First(); - if (x.Skip(1).Any()) - first.IsStrong = true; - return first; - }).ToList(); + // Post processing step to transform mania hit objects with the same start time into strong hits + converted.HitObjects = converted.HitObjects.GroupBy(t => t.StartTime).Select(x => + { + TaikoHitObject first = x.First(); + if (x.Skip(1).Any()) + first.IsStrong = true; + return first; + }).ToList(); + } return converted; } From b62f2437acc92d24d2b7f334cf53a3d9201fc84a Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Sun, 1 Oct 2017 23:38:11 +0300 Subject: [PATCH 0090/1263] Don't allow counter became 0 --- osu.Game/Screens/Play/BreaksOverlay/RemainingTimeCounter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/BreaksOverlay/RemainingTimeCounter.cs b/osu.Game/Screens/Play/BreaksOverlay/RemainingTimeCounter.cs index e89c1e292c..c8b8b6a072 100644 --- a/osu.Game/Screens/Play/BreaksOverlay/RemainingTimeCounter.cs +++ b/osu.Game/Screens/Play/BreaksOverlay/RemainingTimeCounter.cs @@ -46,7 +46,7 @@ namespace osu.Game.Screens.Play.BreaksOverlay var currentTime = Clock.CurrentTime; if (currentTime < endTime) { - int currentSecond = (int)Math.Floor((endTime - Clock.CurrentTime) / 1000.0); + int currentSecond = (int)Math.Ceiling((endTime - Clock.CurrentTime) / 1000.0); if (currentSecond != previousSecond) { counter.Text = currentSecond.ToString(); From ac6c323f93ef73786845e3384675c91a664e1fb0 Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Mon, 2 Oct 2017 00:44:57 +0300 Subject: [PATCH 0091/1263] Clear all tasks and transforms when resetting Breaks --- .../Play/BreaksOverlay/BreakOverlay.cs | 36 +++++++++++++++---- osu.Game/Tests/Visual/TestCaseBreakOverlay.cs | 4 --- 2 files changed, 30 insertions(+), 10 deletions(-) diff --git a/osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs b/osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs index 90321df9d6..fe4d5ea424 100644 --- a/osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs +++ b/osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs @@ -5,9 +5,11 @@ using OpenTK; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; +using osu.Framework.Threading; using osu.Game.Beatmaps.Timing; using osu.Game.Rulesets.Scoring; using System.Collections.Generic; +using System.Linq; namespace osu.Game.Screens.Play.BreaksOverlay { @@ -17,7 +19,21 @@ namespace osu.Game.Screens.Play.BreaksOverlay private const float remaining_time_container_max_size = 0.3f; private const int vertical_margin = 25; - public List Breaks; + private List breaks; + public List Breaks + { + set + { + breaks = value; + initializeBreaks(); + } + get + { + return breaks; + } + } + + private readonly List tasks = new List(); private readonly bool letterboxing; private readonly LetterboxOverlay letterboxOverlay; @@ -71,15 +87,21 @@ namespace osu.Game.Screens.Play.BreaksOverlay protected override void LoadComplete() { base.LoadComplete(); - InitializeBreaks(); + initializeBreaks(); } - public void InitializeBreaks() + private void initializeBreaks() { - if (Breaks == null) + FinishTransforms(true); + + foreach (var t in tasks) + t.Cancel(); + tasks.Clear(); + + if (breaks == null) return; - foreach (var b in Breaks) + foreach (var b in breaks) { if (!b.HasEffect) continue; @@ -104,7 +126,9 @@ namespace osu.Game.Screens.Play.BreaksOverlay .Then() .ResizeWidthTo(0, b.Duration - fade_duration); - Scheduler.AddDelayed(() => remainingTimeCounter.StartCounting(b.EndTime), b.StartTime - Clock.CurrentTime); + tasks.Add(new ScheduledDelegate(() => remainingTimeCounter.StartCounting(b.EndTime), b.StartTime)); + Scheduler.Add(tasks.Last()); + remainingTimeCounter.FadeIn(fade_duration); info.FadeIn(fade_duration); diff --git a/osu.Game/Tests/Visual/TestCaseBreakOverlay.cs b/osu.Game/Tests/Visual/TestCaseBreakOverlay.cs index 055a2bc5c4..074aa16934 100644 --- a/osu.Game/Tests/Visual/TestCaseBreakOverlay.cs +++ b/osu.Game/Tests/Visual/TestCaseBreakOverlay.cs @@ -37,8 +37,6 @@ namespace osu.Game.Tests.Visual EndTime = Clock.CurrentTime + duration, } }; - - breakOverlay.InitializeBreaks(); } private void startMultipleBreaks() @@ -58,8 +56,6 @@ namespace osu.Game.Tests.Visual EndTime = currentTime + 6000, } }; - - breakOverlay.InitializeBreaks(); } } } \ No newline at end of file From 2a9edcbb4f0754563d484f3e8acd2f0d9ea38c37 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 2 Oct 2017 08:10:16 +0900 Subject: [PATCH 0092/1263] Add test case for the editor --- osu.Game/Tests/Visual/TestCaseEditor.cs | 47 +++++++++++++++++++++++++ osu.Game/osu.Game.csproj | 1 + 2 files changed, 48 insertions(+) create mode 100644 osu.Game/Tests/Visual/TestCaseEditor.cs diff --git a/osu.Game/Tests/Visual/TestCaseEditor.cs b/osu.Game/Tests/Visual/TestCaseEditor.cs new file mode 100644 index 0000000000..6114d1eb2e --- /dev/null +++ b/osu.Game/Tests/Visual/TestCaseEditor.cs @@ -0,0 +1,47 @@ +// 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.Allocation; +using osu.Framework.MathUtils; +using osu.Game.Beatmaps; +using osu.Game.Screens.Edit; + +namespace osu.Game.Tests.Visual +{ + public class TestCaseEditor : OsuTestCase + { + public override IReadOnlyList RequiredTypes => new[] { typeof(Editor) }; + + private readonly Random rng; + + private BeatmapManager beatmaps; + private OsuGameBase osuGame; + + public TestCaseEditor() + { + rng = new Random(1337); + + Add(new Editor()); + AddStep("Next beatmap", nextBeatmap); + } + + [BackgroundDependencyLoader] + private void load(OsuGameBase osuGame, BeatmapManager beatmaps) + { + this.osuGame = osuGame; + this.beatmaps = beatmaps; + } + + private void nextBeatmap() + { + var sets = beatmaps.GetAllUsableBeatmapSets(); + if (sets.Count == 0) + return; + + BeatmapInfo info = sets[rng.Next(0, sets.Count)].Beatmaps[0]; + osuGame.Beatmap.Value = beatmaps.GetWorkingBeatmap(info); + } + } +} diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index c8e42a3ad3..9dfc2401ae 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -742,6 +742,7 @@ + From 8ed23a60e97601226c80a00f7a5fa36e1cdaa683 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 2 Oct 2017 09:10:40 +0900 Subject: [PATCH 0093/1263] Remove items from the editor menu bar --- osu.Game/Screens/Edit/Editor.cs | 146 +------------------------------- 1 file changed, 1 insertion(+), 145 deletions(-) diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index d85026bb27..6395e6c3b1 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -36,151 +36,7 @@ namespace osu.Game.Screens.Edit { Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, - RelativeSizeAxes = Axes.Both, - Items = new[] - { - new EditorMenuBarItem("File") - { - Items = new[] - { - new EditorMenuItem("Clear all notes"), - new EditorMenuItem("Open difficulty..."), - new EditorMenuItem("Save"), - new EditorMenuItem("Create new difficulty..."), - new EditorMenuItemSpacer(), - new EditorMenuItem("Revert to saved"), - new EditorMenuItem("Revert to saved (full"), - new EditorMenuItemSpacer(), - new EditorMenuItem("Test beatmap"), - new EditorMenuItem("Open AiMod"), - new EditorMenuItemSpacer(), - new EditorMenuItem("Upload Beatmap..."), - new EditorMenuItem("Export package"), - new EditorMenuItem("Export map package"), - new EditorMenuItem("Import from..."), - new EditorMenuItemSpacer(), - new EditorMenuItem("Open song folder"), - new EditorMenuItem("Open .osu in Notepad"), - new EditorMenuItem("Open .osb in Notepad"), - new EditorMenuItemSpacer(), - new EditorMenuItem("Exit", MenuItemType.Standard, Exit) - } - }, - new EditorMenuBarItem("Edit") - { - Items = new[] - { - new EditorMenuItem("Undo"), - new EditorMenuItem("Redo"), - new EditorMenuItemSpacer(), - new EditorMenuItem("Cut"), - new EditorMenuItem("Copy"), - new EditorMenuItem("Paste"), - new EditorMenuItem("Delete"), - new EditorMenuItemSpacer(), - new EditorMenuItem("Select all"), - new EditorMenuItem("Clone"), - new EditorMenuItemSpacer(), - new EditorMenuItem("Reverse selection"), - new EditorMenuItem("Flip horizontally"), - new EditorMenuItem("Flip vertically"), - new EditorMenuItem("Rotate 90deg clockwise"), - new EditorMenuItem("Rotate 90deg anticlockwise"), - new EditorMenuItem("Rotate by..."), - new EditorMenuItem("Scale by..."), - new EditorMenuItemSpacer(), - new EditorMenuItem("Reset selected objects' samples"), - new EditorMenuItem("Reset all samples", MenuItemType.Destructive), - new EditorMenuItem("Reset combo colours", MenuItemType.Destructive), - new EditorMenuItem("Reset breaks", MenuItemType.Destructive), - new EditorMenuItemSpacer(), - new EditorMenuItem("Nudge backward"), - new EditorMenuItem("Nudge forward") - } - }, - new EditorMenuBarItem("View") - { - Items = new[] - { - new EditorMenuItem("Compose"), - new EditorMenuItem("Design"), - new EditorMenuItem("Timing"), - new EditorMenuItemSpacer(), - new EditorMenuItem("Song setup..."), - new EditorMenuItem("Timing setup..."), - new EditorMenuItemSpacer(), - new EditorMenuItem("Volume"), - new EditorMenuItem("Grid level"), - new EditorMenuItem("Show video"), - new EditorMenuItem("Show sample name"), - new EditorMenuItem("Snaking sliders"), - new EditorMenuItem("Hit animations"), - new EditorMenuItem("Follow points"), - new EditorMenuItem("Stacking") - } - }, - new EditorMenuBarItem("Compose") - { - Items = new[] - { - new EditorMenuItem("Snap divisor"), - new EditorMenuItem("Audio rate"), - new EditorMenuItem("Grid snapping"), - new EditorMenuItemSpacer(), - new EditorMenuItem("Create polygon cricles..."), - new EditorMenuItem("Convert slider to stream"), - new EditorMenuItem("Enable live mapping mode"), - new EditorMenuItem("Sample import") - } - }, - new EditorMenuBarItem("Design") - { - Items = new[] - { - new EditorMenuItem("Move all elements in time...") - } - }, - new EditorMenuBarItem("Timing") - { - Items = new[] - { - new EditorMenuItem("Time signature"), - new EditorMenuItem("Metronome clicks"), - new EditorMenuItemSpacer(), - new EditorMenuItem("Add timing section"), - new EditorMenuItem("Add inheriting section"), - new EditorMenuItem("Reset current section"), - new EditorMenuItem("Delete timing section"), - new EditorMenuItem("Resnap current section"), - new EditorMenuItemSpacer(), - new EditorMenuItem("Timing setup..."), - new EditorMenuItemSpacer(), - new EditorMenuItem("Resnap all notes", MenuItemType.Destructive), - new EditorMenuItem("Move all notes in time...", MenuItemType.Destructive), - new EditorMenuItem("Recalculate slider lengths", MenuItemType.Destructive), - new EditorMenuItem("Delete all timing sections", MenuItemType.Destructive), - new EditorMenuItemSpacer(), - new EditorMenuItem("Set current position as preview point") - } - }, - new EditorMenuBarItem("Web") - { - Items = new[] - { - new EditorMenuItem("This Beatmap's information page"), - new EditorMenuItem("This Beatmap's thread"), - new EditorMenuItem("Quick reply") - } - }, - new EditorMenuBarItem("Help") - { - Items = new[] - { - new EditorMenuItem("Show in-game help"), - new EditorMenuItem("View FAQ") - } - } - } + RelativeSizeAxes = Axes.Both } } }); From 7b1ef53f36fc60877bfacbe729ef72e71942a316 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 2 Oct 2017 09:24:25 +0900 Subject: [PATCH 0094/1263] Expose a mode change event from EditorMenuBar --- osu.Game/Screens/Edit/Menus/EditorMenuBar.cs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Menus/EditorMenuBar.cs b/osu.Game/Screens/Edit/Menus/EditorMenuBar.cs index 616cabbab2..4c9b3c84b3 100644 --- a/osu.Game/Screens/Edit/Menus/EditorMenuBar.cs +++ b/osu.Game/Screens/Edit/Menus/EditorMenuBar.cs @@ -11,11 +11,19 @@ using osu.Game.Graphics; using osu.Game.Graphics.UserInterface; using OpenTK; using OpenTK.Graphics; +using System; namespace osu.Game.Screens.Edit.Menus { public class EditorMenuBar : OsuMenu { + /// + /// Invaoked when the selected mode has changed. + /// + public event Action ModeChanged; + + private readonly ScreenSelectionTabControl tabControl; + public EditorMenuBar() : base(Direction.Horizontal, true) { @@ -26,13 +34,21 @@ namespace osu.Game.Screens.Edit.Menus AddRangeInternal(new Drawable[] { - new ScreenSelectionTabControl + tabControl = new ScreenSelectionTabControl { Anchor = Anchor.BottomRight, Origin = Anchor.BottomRight, X = -15 } }); + + tabControl.Current.ValueChanged += v => ModeChanged?.Invoke(v); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + tabControl.Current.TriggerChange(); } protected override Framework.Graphics.UserInterface.Menu CreateSubMenu() => new SubMenu(); From 221902f4fefe2c94e0d546b0ecab4065bc198f33 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 2 Oct 2017 09:26:16 +0900 Subject: [PATCH 0095/1263] Restructure Editor construction --- osu.Game/Screens/Edit/Editor.cs | 68 +++++++++++++++++---------------- 1 file changed, 36 insertions(+), 32 deletions(-) diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 6395e6c3b1..8b6c0f0bf5 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -26,57 +26,61 @@ namespace osu.Game.Screens.Edit public Editor() { - Add(new Container + EditorMenuBar menuBar; + SummaryTimeline timeline; + + Children = new[] { - RelativeSizeAxes = Axes.X, - Height = 40, - Children = new Drawable[] + new Container { - new EditorMenuBar + Name = "Top bar", + RelativeSizeAxes = Axes.X, + Height = 40, + Child = menuBar = new EditorMenuBar { Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, RelativeSizeAxes = Axes.Both } - } - }); - - SummaryTimeline summaryTimeline; - Add(new Container - { - Anchor = Anchor.BottomLeft, - Origin = Anchor.BottomLeft, - RelativeSizeAxes = Axes.X, - Height = 60, - Children = new Drawable[] + }, + new Container { - bottomBackground = new Box { RelativeSizeAxes = Axes.Both }, - new Container + Name = "Bottom bar", + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + RelativeSizeAxes = Axes.X, + Height = 60, + Children = new Drawable[] { - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding { Top = 5, Bottom = 5, Left = 10, Right = 10 }, - Child = new FillFlowContainer + bottomBackground = new Box { RelativeSizeAxes = Axes.Both }, + new Container { - Name = "Bottom bar", RelativeSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - Spacing = new Vector2(10, 0), - Children = new[] + Padding = new MarginPadding { Top = 5, Bottom = 5, Left = 10, Right = 10 }, + Child = new FillFlowContainer { - summaryTimeline = new SummaryTimeline + Name = "Bottom bar", + RelativeSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(10, 0), + Children = new[] { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Both, - Width = 0.65f + timeline = new SummaryTimeline + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Width = 0.65f + } } } } } + }, } - }); + }; - summaryTimeline.Beatmap.BindTo(Beatmap); + timeline.Beatmap.BindTo(Beatmap); } [BackgroundDependencyLoader] From c2d63eb0bd9f239084f12de5c51aabab9e7477d8 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 2 Oct 2017 09:26:41 +0900 Subject: [PATCH 0096/1263] Add EditorScreen + screen changing functionality --- osu.Game/Screens/Edit/Editor.cs | 24 +++++++++++ osu.Game/Screens/Edit/Screens/EditorScreen.cs | 40 +++++++++++++++++++ osu.Game/Tests/Visual/TestCaseEditor.cs | 3 +- osu.Game/osu.Game.csproj | 1 + 4 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 osu.Game/Screens/Edit/Screens/EditorScreen.cs diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 8b6c0f0bf5..7f5ad0aa0a 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -13,6 +13,7 @@ using osu.Game.Screens.Edit.Menus; using osu.Game.Screens.Edit.Components.Timelines.Summary; using OpenTK; using osu.Framework.Allocation; +using osu.Game.Screens.Edit.Screens; namespace osu.Game.Screens.Edit { @@ -23,6 +24,9 @@ namespace osu.Game.Screens.Edit internal override bool ShowOverlays => false; private readonly Box bottomBackground; + private readonly Container modeContainer; + + private EditorScreen currentScreen; public Editor() { @@ -77,10 +81,16 @@ namespace osu.Game.Screens.Edit } } }, + modeContainer = new Container + { + Name = "Screen container", + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding { Top = 40, Bottom = 60 } } }; timeline.Beatmap.BindTo(Beatmap); + menuBar.ModeChanged += onModeChanged; } [BackgroundDependencyLoader] @@ -89,6 +99,20 @@ namespace osu.Game.Screens.Edit bottomBackground.Colour = colours.Gray2; } + private void onModeChanged(EditorScreenMode mode) + { + currentScreen?.Exit(); + + switch (mode) + { + default: + currentScreen = new EditorScreen(); + break; + } + + modeContainer.Add(currentScreen); + } + protected override void OnResuming(Screen last) { Beatmap.Value.Track?.Stop(); diff --git a/osu.Game/Screens/Edit/Screens/EditorScreen.cs b/osu.Game/Screens/Edit/Screens/EditorScreen.cs new file mode 100644 index 0000000000..49921a0025 --- /dev/null +++ b/osu.Game/Screens/Edit/Screens/EditorScreen.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 OpenTK; +using OpenTK.Graphics; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.MathUtils; + +namespace osu.Game.Screens.Edit.Screens +{ + public class EditorScreen : CompositeDrawable + { + private readonly Container content; + + public EditorScreen() + { + Anchor = Anchor.Centre; + Origin = Anchor.Centre; + RelativeSizeAxes = Axes.Both; + + InternalChild = content = new Container { RelativeSizeAxes = Axes.Both }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + this.ScaleTo(0.5f).FadeTo(0) + .Then() + .ScaleTo(1f, 500, Easing.OutQuint).FadeTo(1f, 500, Easing.OutQuint); + } + + public void Exit() + { + this.ScaleTo(1.5f, 500).FadeOut(500f).Expire(); + } + } +} diff --git a/osu.Game/Tests/Visual/TestCaseEditor.cs b/osu.Game/Tests/Visual/TestCaseEditor.cs index 6114d1eb2e..6f7d05d299 100644 --- a/osu.Game/Tests/Visual/TestCaseEditor.cs +++ b/osu.Game/Tests/Visual/TestCaseEditor.cs @@ -7,12 +7,13 @@ using osu.Framework.Allocation; using osu.Framework.MathUtils; using osu.Game.Beatmaps; using osu.Game.Screens.Edit; +using osu.Game.Screens.Edit.Screens; namespace osu.Game.Tests.Visual { public class TestCaseEditor : OsuTestCase { - public override IReadOnlyList RequiredTypes => new[] { typeof(Editor) }; + public override IReadOnlyList RequiredTypes => new[] { typeof(Editor), typeof(EditorScreen) }; private readonly Random rng; diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 9dfc2401ae..94bd4862af 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -618,6 +618,7 @@ + From 2a310f02bcf0326f81d996ec72cd3076b1488436 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 2 Oct 2017 09:27:27 +0900 Subject: [PATCH 0097/1263] modeContainer -> screenContainer --- osu.Game/Screens/Edit/Editor.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 7f5ad0aa0a..33b1f04cba 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -24,7 +24,7 @@ namespace osu.Game.Screens.Edit internal override bool ShowOverlays => false; private readonly Box bottomBackground; - private readonly Container modeContainer; + private readonly Container screenContainer; private EditorScreen currentScreen; @@ -81,7 +81,7 @@ namespace osu.Game.Screens.Edit } } }, - modeContainer = new Container + screenContainer = new Container { Name = "Screen container", RelativeSizeAxes = Axes.Both, @@ -110,7 +110,7 @@ namespace osu.Game.Screens.Edit break; } - modeContainer.Add(currentScreen); + screenContainer.Add(currentScreen); } protected override void OnResuming(Screen last) From 6018b4e5e4b606e0c7fd65720153f7e6bfbaa34c Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 2 Oct 2017 09:34:51 +0900 Subject: [PATCH 0098/1263] Make EditorScreen a Container --- osu.Game/Screens/Edit/Screens/EditorScreen.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Screens/EditorScreen.cs b/osu.Game/Screens/Edit/Screens/EditorScreen.cs index 49921a0025..ecc7ee1e7c 100644 --- a/osu.Game/Screens/Edit/Screens/EditorScreen.cs +++ b/osu.Game/Screens/Edit/Screens/EditorScreen.cs @@ -10,8 +10,9 @@ using osu.Framework.MathUtils; namespace osu.Game.Screens.Edit.Screens { - public class EditorScreen : CompositeDrawable + public class EditorScreen : Container { + protected override Container Content => content; private readonly Container content; public EditorScreen() From 91cede79c28e763110e0657f1108494f4144b953 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 2 Oct 2017 10:07:34 +0900 Subject: [PATCH 0099/1263] Mask the editor screens --- osu.Game/Screens/Edit/Editor.cs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 33b1f04cba..05443420ef 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -81,11 +81,16 @@ namespace osu.Game.Screens.Edit } } }, - screenContainer = new Container + new Container { Name = "Screen container", RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding { Top = 40, Bottom = 60 } + Padding = new MarginPadding { Top = 40, Bottom = 60 }, + Child = screenContainer = new Container + { + RelativeSizeAxes = Axes.Both, + Masking = true + } } }; From af4c6276e46b82b7a6779d2424b2dcad4284323e Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 2 Oct 2017 10:09:10 +0900 Subject: [PATCH 0100/1263] Adjust transforms of EditorScreen --- osu.Game/Screens/Edit/Screens/EditorScreen.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Edit/Screens/EditorScreen.cs b/osu.Game/Screens/Edit/Screens/EditorScreen.cs index ecc7ee1e7c..8c4f6e7dbe 100644 --- a/osu.Game/Screens/Edit/Screens/EditorScreen.cs +++ b/osu.Game/Screens/Edit/Screens/EditorScreen.cs @@ -30,12 +30,12 @@ namespace osu.Game.Screens.Edit.Screens this.ScaleTo(0.5f).FadeTo(0) .Then() - .ScaleTo(1f, 500, Easing.OutQuint).FadeTo(1f, 500, Easing.OutQuint); + .ScaleTo(1f, 500, Easing.OutQuint).FadeTo(1f, 250, Easing.OutQuint); } public void Exit() { - this.ScaleTo(1.5f, 500).FadeOut(500f).Expire(); + this.ScaleTo(1.5f, 500).FadeOut(250).Expire(); } } } From 69b61a62a53ac1a23c1f5dafc1264fce51294a99 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 2 Oct 2017 10:09:21 +0900 Subject: [PATCH 0101/1263] Implement base Compose screen --- osu.Game/Screens/Edit/Editor.cs | 4 ++ .../Screens/Edit/Screens/Compose/Compose.cs | 42 +++++++++++++++++++ osu.Game/osu.Game.csproj | 1 + 3 files changed, 47 insertions(+) create mode 100644 osu.Game/Screens/Edit/Screens/Compose/Compose.cs diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 05443420ef..06b2a6de64 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -14,6 +14,7 @@ using osu.Game.Screens.Edit.Components.Timelines.Summary; using OpenTK; using osu.Framework.Allocation; using osu.Game.Screens.Edit.Screens; +using osu.Game.Screens.Edit.Screens.Compose; namespace osu.Game.Screens.Edit { @@ -110,6 +111,9 @@ namespace osu.Game.Screens.Edit switch (mode) { + case EditorScreenMode.Compose: + currentScreen = new Compose(); + break; default: currentScreen = new EditorScreen(); break; diff --git a/osu.Game/Screens/Edit/Screens/Compose/Compose.cs b/osu.Game/Screens/Edit/Screens/Compose/Compose.cs new file mode 100644 index 0000000000..6da7fc900d --- /dev/null +++ b/osu.Game/Screens/Edit/Screens/Compose/Compose.cs @@ -0,0 +1,42 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using OpenTK.Graphics; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Game.Graphics; + +namespace osu.Game.Screens.Edit.Screens.Compose +{ + public class Compose : EditorScreen + { + public Compose() + { + Children = new[] + { + new Container + { + Name = "Timeline", + RelativeSizeAxes = Axes.X, + Height = 110, + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Black.Opacity(0.5f) + }, + new Container + { + Name = "Content", + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding { Horizontal = 17, Vertical = 10 } + } + } + } + }; + } + } +} diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 94bd4862af..9a8536bbc2 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -619,6 +619,7 @@ + From 7211dd201546ae7293971431bd9c8a067137d56b Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 2 Oct 2017 10:11:43 +0900 Subject: [PATCH 0102/1263] Remove unnecessary usings --- osu.Game/Screens/Edit/Editor.cs | 1 - osu.Game/Screens/Edit/Screens/Compose/Compose.cs | 1 - osu.Game/Screens/Edit/Screens/EditorScreen.cs | 4 ---- osu.Game/Tests/Visual/TestCaseEditor.cs | 1 - 4 files changed, 7 deletions(-) diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 06b2a6de64..8a11a50fd6 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -8,7 +8,6 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Game.Graphics; -using osu.Game.Graphics.UserInterface; using osu.Game.Screens.Edit.Menus; using osu.Game.Screens.Edit.Components.Timelines.Summary; using OpenTK; diff --git a/osu.Game/Screens/Edit/Screens/Compose/Compose.cs b/osu.Game/Screens/Edit/Screens/Compose/Compose.cs index 6da7fc900d..2fe40dd010 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Compose.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Compose.cs @@ -6,7 +6,6 @@ using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; -using osu.Game.Graphics; namespace osu.Game.Screens.Edit.Screens.Compose { diff --git a/osu.Game/Screens/Edit/Screens/EditorScreen.cs b/osu.Game/Screens/Edit/Screens/EditorScreen.cs index 8c4f6e7dbe..c456ad6a51 100644 --- a/osu.Game/Screens/Edit/Screens/EditorScreen.cs +++ b/osu.Game/Screens/Edit/Screens/EditorScreen.cs @@ -1,12 +1,8 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using OpenTK; -using OpenTK.Graphics; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; -using osu.Framework.MathUtils; namespace osu.Game.Screens.Edit.Screens { diff --git a/osu.Game/Tests/Visual/TestCaseEditor.cs b/osu.Game/Tests/Visual/TestCaseEditor.cs index 6f7d05d299..6da5e514b2 100644 --- a/osu.Game/Tests/Visual/TestCaseEditor.cs +++ b/osu.Game/Tests/Visual/TestCaseEditor.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; using osu.Framework.Allocation; -using osu.Framework.MathUtils; using osu.Game.Beatmaps; using osu.Game.Screens.Edit; using osu.Game.Screens.Edit.Screens; From 6d97da8b19151fdf9cee4cd46b1ae6733caa9c02 Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Mon, 2 Oct 2017 04:42:38 +0300 Subject: [PATCH 0103/1263] Add replay speed adjustment --- osu.Game/Screens/Play/HUDOverlay.cs | 18 +++++++++------- osu.Game/Screens/Play/Player.cs | 2 ++ .../Play/ReplaySettings/PlaybackSettings.cs | 21 ++++++++++++------- .../Screens/Play/ReplaySettingsOverlay.cs | 8 ++++--- 4 files changed, 32 insertions(+), 17 deletions(-) diff --git a/osu.Game/Screens/Play/HUDOverlay.cs b/osu.Game/Screens/Play/HUDOverlay.cs index ddcf031bd4..c632b7d893 100644 --- a/osu.Game/Screens/Play/HUDOverlay.cs +++ b/osu.Game/Screens/Play/HUDOverlay.cs @@ -32,6 +32,7 @@ namespace osu.Game.Screens.Play public readonly HealthDisplay HealthDisplay; public readonly SongProgress Progress; public readonly ModDisplay ModDisplay; + public readonly ReplaySettingsOverlay ReplaySettingsOverlay; private Bindable showHud; private bool replayLoaded; @@ -55,7 +56,7 @@ namespace osu.Game.Screens.Play HealthDisplay = CreateHealthDisplay(), Progress = CreateProgress(), ModDisplay = CreateModsContainer(), - //ReplaySettingsOverlay = CreateReplaySettingsOverlay(), + ReplaySettingsOverlay = CreateReplaySettingsOverlay(), } }); } @@ -98,7 +99,10 @@ namespace osu.Game.Screens.Play // in the case a replay isn't loaded, we want some elements to only appear briefly. if (!replayLoaded) + { + ReplaySettingsOverlay.Hide(); ModDisplay.Delay(2000).FadeOut(200); + } } protected override bool OnKeyDown(InputState state, KeyDownEventArgs args) @@ -176,12 +180,12 @@ namespace osu.Game.Screens.Play Margin = new MarginPadding { Top = 20, Right = 10 }, }; - //protected virtual ReplaySettingsOverlay CreateReplaySettingsOverlay() => new ReplaySettingsOverlay - //{ - // Anchor = Anchor.TopRight, - // Origin = Anchor.TopRight, - // Margin = new MarginPadding { Top = 100, Right = 10 }, - //}; + protected virtual ReplaySettingsOverlay CreateReplaySettingsOverlay() => new ReplaySettingsOverlay + { + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + Margin = new MarginPadding { Top = 100, Right = 10 }, + }; public virtual void BindProcessor(ScoreProcessor processor) { diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index e120c7f193..9d983fd0a9 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -222,6 +222,8 @@ namespace osu.Game.Screens.Play hudOverlay.ModDisplay.Current.BindTo(working.Mods); + hudOverlay.ReplaySettingsOverlay.PlaybackSettings.BindClock(adjustableSourceClock); + // Bind ScoreProcessor to ourselves scoreProcessor.AllJudged += onCompletion; scoreProcessor.Failed += onFail; diff --git a/osu.Game/Screens/Play/ReplaySettings/PlaybackSettings.cs b/osu.Game/Screens/Play/ReplaySettings/PlaybackSettings.cs index ea958d05f9..49b5ce4474 100644 --- a/osu.Game/Screens/Play/ReplaySettings/PlaybackSettings.cs +++ b/osu.Game/Screens/Play/ReplaySettings/PlaybackSettings.cs @@ -3,7 +3,7 @@ using osu.Framework.Allocation; using osu.Game.Configuration; -using osu.Framework.Graphics; +using osu.Framework.Timing; namespace osu.Game.Screens.Play.ReplaySettings { @@ -11,17 +11,24 @@ namespace osu.Game.Screens.Play.ReplaySettings { protected override string Title => @"playback"; + private ReplaySliderBar sliderbar; + [BackgroundDependencyLoader] private void load(OsuConfigManager config) { - Children = new Drawable[] + Child = sliderbar = new ReplaySliderBar { - new ReplaySliderBar - { - LabelText = "Playback speed", - Bindable = config.GetBindable(OsuSetting.PlaybackSpeed) - } + LabelText = "Playback speed", + Bindable = config.GetBindable(OsuSetting.PlaybackSpeed), }; } + + public void BindClock(IAdjustableClock clock) + { + var clockRate = clock.Rate; + sliderbar.Bindable.ValueChanged += (rateMultiplier) => clock.Rate = clockRate * rateMultiplier; + + sliderbar.Bindable.Value = 1; + } } } diff --git a/osu.Game/Screens/Play/ReplaySettingsOverlay.cs b/osu.Game/Screens/Play/ReplaySettingsOverlay.cs index 415f70005d..0edf4634ba 100644 --- a/osu.Game/Screens/Play/ReplaySettingsOverlay.cs +++ b/osu.Game/Screens/Play/ReplaySettingsOverlay.cs @@ -10,15 +10,17 @@ namespace osu.Game.Screens.Play { public class ReplaySettingsOverlay : FillFlowContainer { + public readonly PlaybackSettings PlaybackSettings; + public ReplaySettingsOverlay() { Direction = FillDirection.Vertical; AutoSizeAxes = Axes.Both; Spacing = new Vector2(0, 20); - Add(new CollectionSettings()); - Add(new DiscussionSettings()); - Add(new PlaybackSettings()); + //Add(new CollectionSettings()); + //Add(new DiscussionSettings()); + Add(PlaybackSettings = new PlaybackSettings()); } } } From 5ce2723719f6697c03125142a5b4c66d808008c8 Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Mon, 2 Oct 2017 05:12:56 +0300 Subject: [PATCH 0104/1263] Don't use linq query --- osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs b/osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs index fe4d5ea424..c7c5afe42c 100644 --- a/osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs +++ b/osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs @@ -9,7 +9,6 @@ using osu.Framework.Threading; using osu.Game.Beatmaps.Timing; using osu.Game.Rulesets.Scoring; using System.Collections.Generic; -using System.Linq; namespace osu.Game.Screens.Play.BreaksOverlay { @@ -127,7 +126,7 @@ namespace osu.Game.Screens.Play.BreaksOverlay .ResizeWidthTo(0, b.Duration - fade_duration); tasks.Add(new ScheduledDelegate(() => remainingTimeCounter.StartCounting(b.EndTime), b.StartTime)); - Scheduler.Add(tasks.Last()); + Scheduler.Add(tasks[tasks.Count - 1]); remainingTimeCounter.FadeIn(fade_duration); From c2f487aa3edb9012fd97b58e8d5ae1b0cc8e4013 Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Mon, 2 Oct 2017 05:56:38 +0300 Subject: [PATCH 0105/1263] Add Rank as a property to the Score Processor --- osu.Game/Rulesets/Scoring/ScoreProcessor.cs | 11 +++++++++-- osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs | 2 +- osu.Game/Screens/Play/BreaksOverlay/InfoContainer.cs | 5 +++-- osu.Game/Screens/Play/BreaksOverlay/InfoLine.cs | 10 ---------- 4 files changed, 13 insertions(+), 15 deletions(-) diff --git a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs index e8dd87a6a6..0b631a7148 100644 --- a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs +++ b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs @@ -51,6 +51,11 @@ namespace osu.Game.Rulesets.Scoring /// public readonly BindableInt Combo = new BindableInt(); + /// + /// The current rank. + /// + public readonly Bindable Rank = new Bindable(ScoreRank.X); + /// /// THe highest combo achieved by this score. /// @@ -74,9 +79,10 @@ namespace osu.Game.Rulesets.Scoring protected ScoreProcessor() { Combo.ValueChanged += delegate { HighestCombo.Value = Math.Max(HighestCombo.Value, Combo.Value); }; + Accuracy.ValueChanged += delegate { Rank.Value = rankFrom(Accuracy.Value); }; } - public static ScoreRank RankFrom(double acc) + private ScoreRank rankFrom(double acc) { if (acc == 1) return ScoreRank.X; @@ -101,6 +107,7 @@ namespace osu.Game.Rulesets.Scoring Accuracy.Value = 1; Health.Value = 1; Combo.Value = 0; + Rank.Value = ScoreRank.X; HighestCombo.Value = 0; alreadyFailed = false; @@ -142,7 +149,7 @@ namespace osu.Game.Rulesets.Scoring score.Combo = Combo; score.MaxCombo = HighestCombo; score.Accuracy = Accuracy; - score.Rank = RankFrom(Accuracy); + score.Rank = Rank; score.Date = DateTimeOffset.Now; score.Health = Health; } diff --git a/osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs b/osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs index c7c5afe42c..53a2f4919e 100644 --- a/osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs +++ b/osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs @@ -147,7 +147,7 @@ namespace osu.Game.Screens.Play.BreaksOverlay public void BindProcessor(ScoreProcessor processor) { info.AccuracyDisplay.Current.BindTo(processor.Accuracy); - info.GradeDisplay.Current.BindTo(processor.Accuracy); + info.GradeDisplay.Current.BindTo(processor.Rank); } } } diff --git a/osu.Game/Screens/Play/BreaksOverlay/InfoContainer.cs b/osu.Game/Screens/Play/BreaksOverlay/InfoContainer.cs index 8d2bec06aa..351dc66930 100644 --- a/osu.Game/Screens/Play/BreaksOverlay/InfoContainer.cs +++ b/osu.Game/Screens/Play/BreaksOverlay/InfoContainer.cs @@ -5,6 +5,7 @@ using OpenTK; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Graphics.Sprites; +using osu.Game.Rulesets.Scoring; namespace osu.Game.Screens.Play.BreaksOverlay { @@ -12,7 +13,7 @@ namespace osu.Game.Screens.Play.BreaksOverlay { public PercentageInfoLine AccuracyDisplay; public InfoLine RankDisplay; - public GradeInfoLine GradeDisplay; + public InfoLine GradeDisplay; public InfoContainer() { @@ -40,7 +41,7 @@ namespace osu.Game.Screens.Play.BreaksOverlay { AccuracyDisplay = new PercentageInfoLine("Accuracy"), RankDisplay = new InfoLine("Rank", @"#"), - GradeDisplay = new GradeInfoLine("Grade"), + GradeDisplay = new InfoLine("Grade"), }, } }; diff --git a/osu.Game/Screens/Play/BreaksOverlay/InfoLine.cs b/osu.Game/Screens/Play/BreaksOverlay/InfoLine.cs index f74329ceb3..751523d68c 100644 --- a/osu.Game/Screens/Play/BreaksOverlay/InfoLine.cs +++ b/osu.Game/Screens/Play/BreaksOverlay/InfoLine.cs @@ -7,7 +7,6 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; -using osu.Game.Rulesets.Scoring; namespace osu.Game.Screens.Play.BreaksOverlay { @@ -80,13 +79,4 @@ namespace osu.Game.Screens.Play.BreaksOverlay protected override string Format(double count) => $@"{count:P2}"; } - - public class GradeInfoLine : InfoLine - { - public GradeInfoLine(string name, string prefix = "") : base(name, prefix) - { - } - - protected override string Format(double count) => $@"{ScoreProcessor.RankFrom(count)}"; - } } From 70524628635d5a17535bc4f4277261164b85750c Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Mon, 2 Oct 2017 08:51:00 +0300 Subject: [PATCH 0106/1263] Update inline with framework --- osu-framework | 2 +- osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs | 11 ++--------- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/osu-framework b/osu-framework index 9d142a8e00..5f19dd913d 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit 9d142a8e009794dfee828392e36025d08577131d +Subproject commit 5f19dd913dfc69013a3b9cf30ccfd9c44881a321 diff --git a/osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs b/osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs index 53a2f4919e..9ffaf906c8 100644 --- a/osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs +++ b/osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs @@ -5,7 +5,6 @@ using OpenTK; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; -using osu.Framework.Threading; using osu.Game.Beatmaps.Timing; using osu.Game.Rulesets.Scoring; using System.Collections.Generic; @@ -32,8 +31,6 @@ namespace osu.Game.Screens.Play.BreaksOverlay } } - private readonly List tasks = new List(); - private readonly bool letterboxing; private readonly LetterboxOverlay letterboxOverlay; private readonly Container remainingTimeBox; @@ -92,10 +89,7 @@ namespace osu.Game.Screens.Play.BreaksOverlay private void initializeBreaks() { FinishTransforms(true); - - foreach (var t in tasks) - t.Cancel(); - tasks.Clear(); + Scheduler.CancelDelayedTasks(); if (breaks == null) return; @@ -125,8 +119,7 @@ namespace osu.Game.Screens.Play.BreaksOverlay .Then() .ResizeWidthTo(0, b.Duration - fade_duration); - tasks.Add(new ScheduledDelegate(() => remainingTimeCounter.StartCounting(b.EndTime), b.StartTime)); - Scheduler.Add(tasks[tasks.Count - 1]); + Scheduler.AddDelayed(() => remainingTimeCounter.StartCounting(b.EndTime), b.StartTime - Clock.CurrentTime); remainingTimeCounter.FadeIn(fade_duration); From b6ed977e1e383a388b57f557e707cff546ee56f0 Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Mon, 2 Oct 2017 09:04:03 +0300 Subject: [PATCH 0107/1263] Fix hard crash and fix breaks have been initialized twice --- osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs | 6 ------ osu.Game/Screens/Play/Player.cs | 4 ++-- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs b/osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs index 9ffaf906c8..3b2335a455 100644 --- a/osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs +++ b/osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs @@ -80,12 +80,6 @@ namespace osu.Game.Screens.Play.BreaksOverlay }; } - protected override void LoadComplete() - { - base.LoadComplete(); - initializeBreaks(); - } - private void initializeBreaks() { FinishTransforms(true); diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 79ace6c45a..589f4b663a 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -192,8 +192,8 @@ namespace osu.Game.Screens.Play { Anchor = Anchor.Centre, Origin = Anchor.Centre, - Breaks = beatmap.Breaks, - Clock = decoupledClock + Clock = decoupledClock, + Breaks = beatmap.Breaks }, } }, From 66afba62190f56c698678a4fb4ad03e280ed8318 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 2 Oct 2017 17:38:48 +0800 Subject: [PATCH 0108/1263] Allow TestCasePlayer to instantiate only one ruleset type --- .../Tests/TestCaseCatchPlayer.cs | 4 +++ osu.Game/Rulesets/RulesetStore.cs | 1 - osu.Game/Tests/Visual/TestCasePlayer.cs | 31 ++++++++++++------- 3 files changed, 24 insertions(+), 12 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Tests/TestCaseCatchPlayer.cs b/osu.Game.Rulesets.Catch/Tests/TestCaseCatchPlayer.cs index 8d18a712d8..45ab8ac300 100644 --- a/osu.Game.Rulesets.Catch/Tests/TestCaseCatchPlayer.cs +++ b/osu.Game.Rulesets.Catch/Tests/TestCaseCatchPlayer.cs @@ -10,6 +10,10 @@ namespace osu.Game.Rulesets.Catch.Tests [TestFixture] public class TestCaseCatchPlayer : Game.Tests.Visual.TestCasePlayer { + public TestCaseCatchPlayer() : base(typeof(CatchRuleset)) + { + + } protected override Beatmap CreateBeatmap() { var beatmap = new Beatmap(); diff --git a/osu.Game/Rulesets/RulesetStore.cs b/osu.Game/Rulesets/RulesetStore.cs index 5eef4a8470..407a5f7c3c 100644 --- a/osu.Game/Rulesets/RulesetStore.cs +++ b/osu.Game/Rulesets/RulesetStore.cs @@ -38,7 +38,6 @@ namespace osu.Game.Rulesets protected override void Prepare(bool reset = false) { - Connection.CreateTable(); if (reset) diff --git a/osu.Game/Tests/Visual/TestCasePlayer.cs b/osu.Game/Tests/Visual/TestCasePlayer.cs index 4a25a52e36..b0953ceb7e 100644 --- a/osu.Game/Tests/Visual/TestCasePlayer.cs +++ b/osu.Game/Tests/Visual/TestCasePlayer.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.IO; using System.Linq; using System.Text; @@ -18,31 +19,39 @@ namespace osu.Game.Tests.Visual { public class TestCasePlayer : OsuTestCase { + private readonly Type ruleset; + protected Player Player; - private RulesetStore rulesets; public override string Description => @"Showing everything to play the game."; + /// + /// Create a TestCase which runs through the Player screen. + /// + /// An optional ruleset type which we want to target. If not provided we'll allow all rulesets to be tested. + protected TestCasePlayer(Type ruleset) + { + this.ruleset = ruleset; + } + + public TestCasePlayer() + { + + } + [BackgroundDependencyLoader] private void load(RulesetStore rulesets) { - this.rulesets = rulesets; - } - - protected override void LoadComplete() - { - base.LoadComplete(); - Add(new Box { RelativeSizeAxes = Framework.Graphics.Axes.Both, Colour = Color4.Black, }); - foreach (var r in rulesets.Query()) - AddStep(r.Name, () => loadPlayerFor(r)); + string instantiation = ruleset?.AssemblyQualifiedName; - loadPlayerFor(rulesets.Query().First()); + foreach (var r in rulesets.Query(rs => rs.Available && (instantiation == null || rs.InstantiationInfo == instantiation))) + AddStep(r.Name, () => loadPlayerFor(r)); } protected virtual Beatmap CreateBeatmap() From 12a9cbad56b84960226b21204ee2e6453d67d9a0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 2 Oct 2017 21:54:26 +0800 Subject: [PATCH 0109/1263] Allow Beatmap to populate some metadata defaults if they aren't provided via BetamapInfo --- osu.Game/Beatmaps/Beatmap.cs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/osu.Game/Beatmaps/Beatmap.cs b/osu.Game/Beatmaps/Beatmap.cs index 458c2304f2..383a331eb4 100644 --- a/osu.Game/Beatmaps/Beatmap.cs +++ b/osu.Game/Beatmaps/Beatmap.cs @@ -58,6 +58,23 @@ namespace osu.Game.Beatmaps ComboColors = original?.ComboColors ?? ComboColors; HitObjects = original?.HitObjects ?? HitObjects; Storyboard = original?.Storyboard ?? Storyboard; + + if (original == null && Metadata == null) + { + // we may have no metadata in cases we weren't sourced from the database. + // let's fill it (and other related fields) so we don't need to null-check it in future usages. + BeatmapInfo = new BeatmapInfo + { + Metadata = new BeatmapMetadata + { + Artist = @"Unknown", + Title = @"Unknown", + Author = @"Unknown Creator", + }, + Version = @"Normal", + Difficulty = new BeatmapDifficulty() + }; + } } } From 7168629b2a28f59a121a844b45f481b138e3df0d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 2 Oct 2017 21:55:37 +0800 Subject: [PATCH 0110/1263] Remove CatcherArea abstraction Also fixes catcher size being relative to aspect ratio. --- .../Tests/TestCaseCatcher.cs | 4 +- osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs | 34 ++- osu.Game.Rulesets.Catch/UI/Catcher.cs | 193 +++++++++++++++ osu.Game.Rulesets.Catch/UI/CatcherArea.cs | 229 ------------------ .../osu.Game.Rulesets.Catch.csproj | 2 +- 5 files changed, 225 insertions(+), 237 deletions(-) create mode 100644 osu.Game.Rulesets.Catch/UI/Catcher.cs delete mode 100644 osu.Game.Rulesets.Catch/UI/CatcherArea.cs diff --git a/osu.Game.Rulesets.Catch/Tests/TestCaseCatcher.cs b/osu.Game.Rulesets.Catch/Tests/TestCaseCatcher.cs index 6a065e197d..21a9bdec51 100644 --- a/osu.Game.Rulesets.Catch/Tests/TestCaseCatcher.cs +++ b/osu.Game.Rulesets.Catch/Tests/TestCaseCatcher.cs @@ -17,7 +17,7 @@ namespace osu.Game.Rulesets.Catch.Tests { public override IReadOnlyList RequiredTypes => new[] { - typeof(CatcherArea), + typeof(Catcher), }; [BackgroundDependencyLoader] @@ -28,7 +28,7 @@ namespace osu.Game.Rulesets.Catch.Tests new CatchInputManager(rulesets.GetRuleset(2)) { RelativeSizeAxes = Axes.Both, - Child = new CatcherArea + Child = new Catcher { RelativePositionAxes = Axes.Both, RelativeSizeAxes = Axes.Both, diff --git a/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs b/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs index 2b6f9bbf5a..38f3273055 100644 --- a/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs +++ b/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs @@ -1,10 +1,12 @@ // 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.Graphics; using osu.Game.Rulesets.UI; using OpenTK; using osu.Framework.Graphics.Containers; +using osu.Game.Rulesets.Catch.Objects; using osu.Game.Rulesets.Catch.Objects.Drawable; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Objects.Drawables; @@ -15,11 +17,15 @@ namespace osu.Game.Rulesets.Catch.UI { protected override Container Content => content; private readonly Container content; - private readonly CatcherArea catcherArea; + + private readonly Container catcherContainer; + private readonly Catcher catcher; public CatchPlayfield() : base(Axes.Y) { + Container explodingFruitContainer; + Reversed.Value = true; Size = new Vector2(1); @@ -33,16 +39,34 @@ namespace osu.Game.Rulesets.Catch.UI { RelativeSizeAxes = Axes.Both, }, - catcherArea = new CatcherArea + explodingFruitContainer = new Container { RelativeSizeAxes = Axes.Both, + }, + catcherContainer = new Container { + RelativeSizeAxes = Axes.X, Anchor = Anchor.BottomLeft, Origin = Anchor.TopLeft, - Height = 0.3f + Height = 180, + Child = catcher = new Catcher + { + ExplodingFruitTarget = explodingFruitContainer, + RelativePositionAxes = Axes.Both, + Origin = Anchor.TopCentre, + X = 0.5f, + } } }; } + protected override void Update() + { + base.Update(); + catcher.Size = new Vector2(catcherContainer.DrawSize.Y); + } + + public bool CheckIfWeCanCatch(CatchBaseHit obj) => Math.Abs(catcher.Position.X - obj.X) < catcher.DrawSize.X / DrawSize.X / 2; + public override void Add(DrawableHitObject h) { h.Depth = (float)h.HitObject.StartTime; @@ -50,7 +74,7 @@ namespace osu.Game.Rulesets.Catch.UI base.Add(h); var fruit = (DrawableFruit)h; - fruit.CheckPosition = catcherArea.CheckIfWeCanCatch; + fruit.CheckPosition = CheckIfWeCanCatch; } public override void OnJudgement(DrawableHitObject judgedObject, Judgement judgement) @@ -59,7 +83,7 @@ namespace osu.Game.Rulesets.Catch.UI { Vector2 screenPosition = judgedObject.ScreenSpaceDrawQuad.Centre; Remove(judgedObject); - catcherArea.Add(judgedObject, screenPosition); + catcher.Add(judgedObject, screenPosition); } } } diff --git a/osu.Game.Rulesets.Catch/UI/Catcher.cs b/osu.Game.Rulesets.Catch/UI/Catcher.cs new file mode 100644 index 0000000000..87fe95ed2f --- /dev/null +++ b/osu.Game.Rulesets.Catch/UI/Catcher.cs @@ -0,0 +1,193 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using System.Linq; +using osu.Framework.Allocation; +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.Framework.MathUtils; +using osu.Game.Rulesets.Catch.Objects; +using osu.Game.Rulesets.Objects.Drawables; +using OpenTK; + +namespace osu.Game.Rulesets.Catch.UI +{ + public class Catcher : Container, IKeyBindingHandler + { + private Texture texture; + + private Container caughtFruit; + + public Container ExplodingFruitTarget; + + [BackgroundDependencyLoader] + private void load(TextureStore textures) + { + texture = textures.Get(@"Play/Catch/fruit-catcher-idle"); + + Children = new Drawable[] + { + createCatcherSprite(), + caughtFruit = new Container + { + Anchor = Anchor.TopCentre, + Origin = Anchor.BottomCentre, + } + }; + } + + private int currentDirection; + + private bool dashing; + + protected bool Dashing + { + get { return dashing; } + set + { + if (value == dashing) return; + + dashing = value; + + if (dashing) + Schedule(addAdditiveSprite); + } + } + + private void addAdditiveSprite() + { + if (!dashing) return; + + var additive = createCatcherSprite(); + + additive.RelativePositionAxes = Axes.Both; + additive.Blending = BlendingMode.Additive; + additive.Position = Position; + additive.Scale = Scale; + + ((Container)Parent).Add(additive); + + additive.FadeTo(0.4f).FadeOut(800, Easing.OutQuint).Expire(); + + Scheduler.AddDelayed(addAdditiveSprite, 50); + } + + private Sprite createCatcherSprite() => new Sprite + { + RelativeSizeAxes = Axes.Both, + FillMode = FillMode.Fit, + Texture = texture, + OriginPosition = new Vector2(DrawWidth / 2, 10) //temporary until the sprite is aligned correctly. + }; + + public bool OnPressed(CatchAction action) + { + switch (action) + { + case CatchAction.MoveLeft: + currentDirection--; + return true; + case CatchAction.MoveRight: + currentDirection++; + return true; + case CatchAction.Dash: + Dashing = true; + return true; + } + + return false; + } + + public bool OnReleased(CatchAction action) + { + switch (action) + { + case CatchAction.MoveLeft: + currentDirection++; + return true; + case CatchAction.MoveRight: + currentDirection--; + return true; + case CatchAction.Dash: + Dashing = false; + return true; + } + + return false; + } + + /// + /// The relative space to cover in 1 millisecond. based on 1 game pixel per millisecond as in osu-stable. + /// + private const double base_speed = 1.0 / 512; + + protected override void Update() + { + base.Update(); + + if (currentDirection == 0) return; + + double dashModifier = Dashing ? 1 : 0.5; + + Scale = new Vector2(Math.Sign(currentDirection), 1); + X = (float)MathHelper.Clamp(X + Math.Sign(currentDirection) * Clock.ElapsedFrameTime * base_speed * dashModifier, 0, 1); + } + + public void Add(DrawableHitObject fruit, Vector2 absolutePosition) + { + fruit.RelativePositionAxes = Axes.None; + fruit.Position = new Vector2(ToLocalSpace(absolutePosition).X - DrawSize.X / 2, 0); + + fruit.Anchor = Anchor.TopCentre; + fruit.Origin = Anchor.BottomCentre; + fruit.Scale *= 0.7f; + fruit.LifetimeEnd = double.MaxValue; + + float distance = fruit.DrawSize.X / 2 * fruit.Scale.X; + + while (caughtFruit.Any(f => f.LifetimeEnd == double.MaxValue && Vector2Extensions.DistanceSquared(f.Position, fruit.Position) < distance * distance)) + { + fruit.X += RNG.Next(-5, 5); + fruit.Y -= RNG.Next(0, 5); + } + + caughtFruit.Add(fruit); + + if (((CatchBaseHit)fruit.HitObject).LastInCombo) + explode(); + } + + private void explode() + { + var fruit = caughtFruit.ToArray(); + + foreach (var f in fruit) + { + var originalX = f.X * Scale.X; + + if (ExplodingFruitTarget != null) + { + f.Anchor = Anchor.TopLeft; + f.Position = caughtFruit.ToSpaceOfOtherDrawable(f.DrawPosition, ExplodingFruitTarget); + + caughtFruit.Remove(f); + + ExplodingFruitTarget.Add(f); + } + + f.MoveToY(f.Y - 50, 250, Easing.OutSine) + .Then() + .MoveToY(f.Y + 50, 500, Easing.InSine); + + f.MoveToX(f.X + originalX * 6, 1000); + f.FadeOut(750); + + f.Expire(); + } + } + } +} diff --git a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs deleted file mode 100644 index 2930dbb7cc..0000000000 --- a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs +++ /dev/null @@ -1,229 +0,0 @@ -// Copyright (c) 2007-2017 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using System; -using System.Linq; -using osu.Framework.Allocation; -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.Framework.MathUtils; -using osu.Game.Rulesets.Catch.Objects; -using osu.Game.Rulesets.Objects.Drawables; -using OpenTK; - -namespace osu.Game.Rulesets.Catch.UI -{ - public class CatcherArea : Container - { - private Catcher catcher; - private Container explodingFruitContainer; - - public void Add(DrawableHitObject fruit, Vector2 screenPosition) => catcher.AddToStack(fruit, screenPosition); - - public bool CheckIfWeCanCatch(CatchBaseHit obj) => Math.Abs(catcher.Position.X - obj.X) < catcher.DrawSize.X / DrawSize.X / 2; - - [BackgroundDependencyLoader] - private void load() - { - Children = new Drawable[] - { - explodingFruitContainer = new Container - { - RelativeSizeAxes = Axes.Both, - }, - catcher = new Catcher - { - RelativePositionAxes = Axes.Both, - ExplodingFruitTarget = explodingFruitContainer, - Origin = Anchor.TopCentre, - X = 0.5f, - } - }; - } - - protected override void Update() - { - base.Update(); - - catcher.Size = new Vector2(DrawSize.Y); - } - - private class Catcher : Container, IKeyBindingHandler - { - private Texture texture; - - private Container caughtFruit; - - [BackgroundDependencyLoader] - private void load(TextureStore textures) - { - texture = textures.Get(@"Play/Catch/fruit-catcher-idle"); - - Children = new Drawable[] - { - createCatcherSprite(), - caughtFruit = new Container - { - Anchor = Anchor.TopCentre, - Origin = Anchor.BottomCentre, - } - }; - } - - private int currentDirection; - - private bool dashing; - - public Container ExplodingFruitTarget; - - protected bool Dashing - { - get { return dashing; } - set - { - if (value == dashing) return; - - dashing = value; - - if (dashing) - Schedule(addAdditiveSprite); - } - } - - private void addAdditiveSprite() - { - if (!dashing) return; - - var additive = createCatcherSprite(); - - additive.RelativePositionAxes = Axes.Both; - additive.Blending = BlendingMode.Additive; - additive.Position = Position; - additive.Scale = Scale; - - ((CatcherArea)Parent).Add(additive); - - additive.FadeTo(0.4f).FadeOut(800, Easing.OutQuint).Expire(); - - Scheduler.AddDelayed(addAdditiveSprite, 50); - } - - private Sprite createCatcherSprite() => new Sprite - { - RelativeSizeAxes = Axes.Both, - FillMode = FillMode.Fit, - Texture = texture, - OriginPosition = new Vector2(DrawWidth / 2, 10) //temporary until the sprite is aligned correctly. - }; - - public bool OnPressed(CatchAction action) - { - switch (action) - { - case CatchAction.MoveLeft: - currentDirection--; - return true; - case CatchAction.MoveRight: - currentDirection++; - return true; - case CatchAction.Dash: - Dashing = true; - return true; - } - - return false; - } - - public bool OnReleased(CatchAction action) - { - switch (action) - { - case CatchAction.MoveLeft: - currentDirection++; - return true; - case CatchAction.MoveRight: - currentDirection--; - return true; - case CatchAction.Dash: - Dashing = false; - return true; - } - - return false; - } - - /// - /// The relative space to cover in 1 millisecond. based on 1 game pixel per millisecond as in osu-stable. - /// - private const double base_speed = 1.0 / 512; - - protected override void Update() - { - base.Update(); - - if (currentDirection == 0) return; - - double dashModifier = Dashing ? 1 : 0.5; - - Scale = new Vector2(Math.Sign(currentDirection), 1); - X = (float)MathHelper.Clamp(X + Math.Sign(currentDirection) * Clock.ElapsedFrameTime * base_speed * dashModifier, 0, 1); - } - - public void AddToStack(DrawableHitObject fruit, Vector2 absolutePosition) - { - fruit.RelativePositionAxes = Axes.None; - fruit.Position = new Vector2(ToLocalSpace(absolutePosition).X - DrawSize.X / 2, 0); - - fruit.Anchor = Anchor.TopCentre; - fruit.Origin = Anchor.BottomCentre; - fruit.Scale *= 0.7f; - fruit.LifetimeEnd = double.MaxValue; - - float distance = fruit.DrawSize.X / 2 * fruit.Scale.X; - - while (caughtFruit.Any(f => f.LifetimeEnd == double.MaxValue && Vector2Extensions.DistanceSquared(f.Position, fruit.Position) < distance * distance)) - { - fruit.X += RNG.Next(-5, 5); - fruit.Y -= RNG.Next(0, 5); - } - - caughtFruit.Add(fruit); - - if (((CatchBaseHit)fruit.HitObject).LastInCombo) - explode(); - } - - private void explode() - { - var fruit = caughtFruit.ToArray(); - - foreach (var f in fruit) - { - var originalX = f.X * Scale.X; - - if (ExplodingFruitTarget != null) - { - f.Anchor = Anchor.TopLeft; - f.Position = caughtFruit.ToSpaceOfOtherDrawable(f.DrawPosition, ExplodingFruitTarget); - - caughtFruit.Remove(f); - - ExplodingFruitTarget.Add(f); - } - - f.MoveToY(f.Y - 50, 250, Easing.OutSine) - .Then() - .MoveToY(f.Y + 50, 500, Easing.InSine); - - f.MoveToX(f.X + originalX * 6, 1000); - f.FadeOut(750); - - f.Expire(); - } - } - } - } -} diff --git a/osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj b/osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj index 787825d482..718ae32a17 100644 --- a/osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj +++ b/osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj @@ -59,7 +59,7 @@ - + From 3338024c17b6febbf5aa47acc41b021e1f25c83c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 2 Oct 2017 22:12:53 +0800 Subject: [PATCH 0111/1263] Fix incorrect whitespace --- osu.Game.Rulesets.Catch/Tests/TestCaseCatchPlayer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Catch/Tests/TestCaseCatchPlayer.cs b/osu.Game.Rulesets.Catch/Tests/TestCaseCatchPlayer.cs index 45ab8ac300..5be07e94c0 100644 --- a/osu.Game.Rulesets.Catch/Tests/TestCaseCatchPlayer.cs +++ b/osu.Game.Rulesets.Catch/Tests/TestCaseCatchPlayer.cs @@ -12,8 +12,8 @@ namespace osu.Game.Rulesets.Catch.Tests { public TestCaseCatchPlayer() : base(typeof(CatchRuleset)) { - } + protected override Beatmap CreateBeatmap() { var beatmap = new Beatmap(); From 37393ab2c946bfb236e7ae0514efcf895ffcec4a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 2 Oct 2017 22:24:22 +0800 Subject: [PATCH 0112/1263] Move brace --- osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs b/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs index 38f3273055..c4033b562d 100644 --- a/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs +++ b/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs @@ -43,7 +43,8 @@ namespace osu.Game.Rulesets.Catch.UI { RelativeSizeAxes = Axes.Both, }, - catcherContainer = new Container { + catcherContainer = new Container + { RelativeSizeAxes = Axes.X, Anchor = Anchor.BottomLeft, Origin = Anchor.TopLeft, From c34cc07fdadcc00bd4328a532a88e4a6dd53efb7 Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Mon, 2 Oct 2017 18:09:00 +0300 Subject: [PATCH 0113/1263] Remove default bindable from the config manager --- osu.Game/Configuration/OsuConfigManager.cs | 2 -- .../Play/ReplaySettings/PlaybackSettings.cs | 18 ++++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs index b000f08369..b341c4413b 100644 --- a/osu.Game/Configuration/OsuConfigManager.cs +++ b/osu.Game/Configuration/OsuConfigManager.cs @@ -69,7 +69,6 @@ namespace osu.Game.Configuration Set(OsuSetting.KeyOverlay, false); Set(OsuSetting.FloatingComments, false); - Set(OsuSetting.PlaybackSpeed, 1.0, 0.5f, 2); // Update Set(OsuSetting.ReleaseStream, ReleaseStream.Lazer); @@ -93,7 +92,6 @@ namespace osu.Game.Configuration ShowStoryboard, KeyOverlay, FloatingComments, - PlaybackSpeed, ShowInterface, MouseDisableButtons, MouseDisableWheel, diff --git a/osu.Game/Screens/Play/ReplaySettings/PlaybackSettings.cs b/osu.Game/Screens/Play/ReplaySettings/PlaybackSettings.cs index 49b5ce4474..e8f20e3087 100644 --- a/osu.Game/Screens/Play/ReplaySettings/PlaybackSettings.cs +++ b/osu.Game/Screens/Play/ReplaySettings/PlaybackSettings.cs @@ -1,9 +1,8 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using osu.Framework.Allocation; -using osu.Game.Configuration; using osu.Framework.Timing; +using osu.Framework.Configuration; namespace osu.Game.Screens.Play.ReplaySettings { @@ -11,15 +10,20 @@ namespace osu.Game.Screens.Play.ReplaySettings { protected override string Title => @"playback"; - private ReplaySliderBar sliderbar; + private readonly ReplaySliderBar sliderbar; - [BackgroundDependencyLoader] - private void load(OsuConfigManager config) + private readonly BindableNumber current; + + public PlaybackSettings() { + current = new BindableDouble(1) as BindableNumber; + current.MinValue = 0.5; + current.MaxValue = 2; + Child = sliderbar = new ReplaySliderBar { LabelText = "Playback speed", - Bindable = config.GetBindable(OsuSetting.PlaybackSpeed), + Bindable = current, }; } @@ -27,8 +31,6 @@ namespace osu.Game.Screens.Play.ReplaySettings { var clockRate = clock.Rate; sliderbar.Bindable.ValueChanged += (rateMultiplier) => clock.Rate = clockRate * rateMultiplier; - - sliderbar.Bindable.Value = 1; } } } From 4a298098c506fb3e61a680d5872a83ad321239a4 Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Mon, 2 Oct 2017 18:19:55 +0300 Subject: [PATCH 0114/1263] CI fixes --- .../Play/ReplaySettings/PlaybackSettings.cs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/osu.Game/Screens/Play/ReplaySettings/PlaybackSettings.cs b/osu.Game/Screens/Play/ReplaySettings/PlaybackSettings.cs index e8f20e3087..9129dcab94 100644 --- a/osu.Game/Screens/Play/ReplaySettings/PlaybackSettings.cs +++ b/osu.Game/Screens/Play/ReplaySettings/PlaybackSettings.cs @@ -12,25 +12,23 @@ namespace osu.Game.Screens.Play.ReplaySettings private readonly ReplaySliderBar sliderbar; - private readonly BindableNumber current; - public PlaybackSettings() { - current = new BindableDouble(1) as BindableNumber; - current.MinValue = 0.5; - current.MaxValue = 2; - Child = sliderbar = new ReplaySliderBar { LabelText = "Playback speed", - Bindable = current, + Bindable = new BindableDouble(1) + { + MinValue = 0.5, + MaxValue = 2 + }, }; } public void BindClock(IAdjustableClock clock) { var clockRate = clock.Rate; - sliderbar.Bindable.ValueChanged += (rateMultiplier) => clock.Rate = clockRate * rateMultiplier; + sliderbar.Bindable.ValueChanged += rateMultiplier => clock.Rate = clockRate * rateMultiplier; } } } From b94c78e99306c4728fcd79f6cb7c9c9b1557aacb Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Mon, 2 Oct 2017 19:33:58 +0300 Subject: [PATCH 0115/1263] Hide/Show Replay settings on pressing Ctrl+H --- .../Screens/Play/HUD/ReplaySettingsOverlay.cs | 66 +++++++++++++++++++ osu.Game/Screens/Play/HUDOverlay.cs | 7 +- .../Screens/Play/ReplaySettingsOverlay.cs | 26 -------- .../Visual/TestCaseReplaySettingsOverlay.cs | 2 +- osu.Game/osu.Game.csproj | 2 +- 5 files changed, 69 insertions(+), 34 deletions(-) create mode 100644 osu.Game/Screens/Play/HUD/ReplaySettingsOverlay.cs delete mode 100644 osu.Game/Screens/Play/ReplaySettingsOverlay.cs diff --git a/osu.Game/Screens/Play/HUD/ReplaySettingsOverlay.cs b/osu.Game/Screens/Play/HUD/ReplaySettingsOverlay.cs new file mode 100644 index 0000000000..9f55ce8ce5 --- /dev/null +++ b/osu.Game/Screens/Play/HUD/ReplaySettingsOverlay.cs @@ -0,0 +1,66 @@ +// 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.Screens.Play.ReplaySettings; +using OpenTK; +using osu.Framework.Input; +using OpenTK.Input; + +namespace osu.Game.Screens.Play.HUD +{ + public class ReplaySettingsOverlay : VisibilityContainer + { + private const int fade_duration = 200; + + public override bool HandleInput => true; + + public readonly PlaybackSettings PlaybackSettings; + //public readonly CollectionSettings CollectionSettings; + //public readonly DiscussionSettings DiscussionSettings; + + public ReplaySettingsOverlay() + { + AlwaysPresent = true; + RelativeSizeAxes = Axes.Both; + + Child = new FillFlowContainer + { + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Vertical, + Spacing = new Vector2(0, 20), + Margin = new MarginPadding { Top = 100, Right = 10 }, + Children = new [] + { + //CollectionSettings = new CollectionSettings(), + //DiscussionSettings = new DiscussionSettings(), + PlaybackSettings = new PlaybackSettings(), + } + }; + + State = Visibility.Visible; + } + + protected override void PopIn() => this.FadeIn(fade_duration); + protected override void PopOut() => this.FadeOut(fade_duration); + + protected override bool OnKeyDown(InputState state, KeyDownEventArgs args) + { + if (args.Repeat) return false; + + if (state.Keyboard.ControlPressed) + { + if (args.Key == Key.H) + { + ToggleVisibility(); + return true; + } + } + + return base.OnKeyDown(state, args); + } + } +} diff --git a/osu.Game/Screens/Play/HUDOverlay.cs b/osu.Game/Screens/Play/HUDOverlay.cs index c632b7d893..1d7e0727ba 100644 --- a/osu.Game/Screens/Play/HUDOverlay.cs +++ b/osu.Game/Screens/Play/HUDOverlay.cs @@ -180,12 +180,7 @@ namespace osu.Game.Screens.Play Margin = new MarginPadding { Top = 20, Right = 10 }, }; - protected virtual ReplaySettingsOverlay CreateReplaySettingsOverlay() => new ReplaySettingsOverlay - { - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, - Margin = new MarginPadding { Top = 100, Right = 10 }, - }; + protected virtual ReplaySettingsOverlay CreateReplaySettingsOverlay() => new ReplaySettingsOverlay(); public virtual void BindProcessor(ScoreProcessor processor) { diff --git a/osu.Game/Screens/Play/ReplaySettingsOverlay.cs b/osu.Game/Screens/Play/ReplaySettingsOverlay.cs deleted file mode 100644 index 0edf4634ba..0000000000 --- a/osu.Game/Screens/Play/ReplaySettingsOverlay.cs +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) 2007-2017 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Game.Screens.Play.ReplaySettings; -using OpenTK; - -namespace osu.Game.Screens.Play -{ - public class ReplaySettingsOverlay : FillFlowContainer - { - public readonly PlaybackSettings PlaybackSettings; - - public ReplaySettingsOverlay() - { - Direction = FillDirection.Vertical; - AutoSizeAxes = Axes.Both; - Spacing = new Vector2(0, 20); - - //Add(new CollectionSettings()); - //Add(new DiscussionSettings()); - Add(PlaybackSettings = new PlaybackSettings()); - } - } -} diff --git a/osu.Game/Tests/Visual/TestCaseReplaySettingsOverlay.cs b/osu.Game/Tests/Visual/TestCaseReplaySettingsOverlay.cs index 256c3d25c9..3105a7d588 100644 --- a/osu.Game/Tests/Visual/TestCaseReplaySettingsOverlay.cs +++ b/osu.Game/Tests/Visual/TestCaseReplaySettingsOverlay.cs @@ -3,7 +3,7 @@ using osu.Framework.Graphics; using osu.Game.Graphics.UserInterface; -using osu.Game.Screens.Play; +using osu.Game.Screens.Play.HUD; using osu.Game.Screens.Play.ReplaySettings; namespace osu.Game.Tests.Visual diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index c8e42a3ad3..f04aa4708c 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -656,7 +656,7 @@ - + From feb0b1852fe8e5e8107be177352fd81297058fb5 Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Tue, 3 Oct 2017 20:05:50 +0300 Subject: [PATCH 0116/1263] Remove the dangerous function --- osu.Game/Screens/Play/Player.cs | 2 +- .../Play/ReplaySettings/PlaybackSettings.cs | 18 +++++++++++++++--- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 9d983fd0a9..7e5ab58adb 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -222,7 +222,7 @@ namespace osu.Game.Screens.Play hudOverlay.ModDisplay.Current.BindTo(working.Mods); - hudOverlay.ReplaySettingsOverlay.PlaybackSettings.BindClock(adjustableSourceClock); + hudOverlay.ReplaySettingsOverlay.PlaybackSettings.AdjustableClock = adjustableSourceClock; // Bind ScoreProcessor to ourselves scoreProcessor.AllJudged += onCompletion; diff --git a/osu.Game/Screens/Play/ReplaySettings/PlaybackSettings.cs b/osu.Game/Screens/Play/ReplaySettings/PlaybackSettings.cs index 9129dcab94..24f128ef49 100644 --- a/osu.Game/Screens/Play/ReplaySettings/PlaybackSettings.cs +++ b/osu.Game/Screens/Play/ReplaySettings/PlaybackSettings.cs @@ -10,6 +10,13 @@ namespace osu.Game.Screens.Play.ReplaySettings { protected override string Title => @"playback"; + private IAdjustableClock adjustableClock; + public IAdjustableClock AdjustableClock + { + set { adjustableClock = value; } + get { return adjustableClock; } + } + private readonly ReplaySliderBar sliderbar; public PlaybackSettings() @@ -25,10 +32,15 @@ namespace osu.Game.Screens.Play.ReplaySettings }; } - public void BindClock(IAdjustableClock clock) + protected override void LoadComplete() { - var clockRate = clock.Rate; - sliderbar.Bindable.ValueChanged += rateMultiplier => clock.Rate = clockRate * rateMultiplier; + base.LoadComplete(); + + if (adjustableClock != null) + { + var clockRate = adjustableClock.Rate; + sliderbar.Bindable.ValueChanged += rateMultiplier => adjustableClock.Rate = clockRate * rateMultiplier; + } } } } From 1c132938dfdd57d338eed74751107e11e266b27e Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Tue, 3 Oct 2017 20:26:53 +0300 Subject: [PATCH 0117/1263] Allow visibility can be toggled only if replay is loaded --- osu.Game/Screens/Play/HUD/ReplaySettingsOverlay.cs | 4 +++- osu.Game/Screens/Play/HUDOverlay.cs | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/HUD/ReplaySettingsOverlay.cs b/osu.Game/Screens/Play/HUD/ReplaySettingsOverlay.cs index 9f55ce8ce5..e44a738d55 100644 --- a/osu.Game/Screens/Play/HUD/ReplaySettingsOverlay.cs +++ b/osu.Game/Screens/Play/HUD/ReplaySettingsOverlay.cs @@ -14,6 +14,8 @@ namespace osu.Game.Screens.Play.HUD { private const int fade_duration = 200; + public bool ReplayLoaded; + public override bool HandleInput => true; public readonly PlaybackSettings PlaybackSettings; @@ -53,7 +55,7 @@ namespace osu.Game.Screens.Play.HUD if (state.Keyboard.ControlPressed) { - if (args.Key == Key.H) + if (args.Key == Key.H && ReplayLoaded) { ToggleVisibility(); return true; diff --git a/osu.Game/Screens/Play/HUDOverlay.cs b/osu.Game/Screens/Play/HUDOverlay.cs index 1d7e0727ba..f4b5efe1e5 100644 --- a/osu.Game/Screens/Play/HUDOverlay.cs +++ b/osu.Game/Screens/Play/HUDOverlay.cs @@ -97,6 +97,8 @@ namespace osu.Game.Screens.Play replayLoaded = rulesetContainer.HasReplayLoaded; + ReplaySettingsOverlay.ReplayLoaded = replayLoaded; + // in the case a replay isn't loaded, we want some elements to only appear briefly. if (!replayLoaded) { From cf44868bcdd090d0b43313545b9e0c5646b42e5e Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 4 Oct 2017 15:02:11 +0900 Subject: [PATCH 0118/1263] Give EditorScreen a Beatmap --- osu.Game/Screens/Edit/Editor.cs | 1 + osu.Game/Screens/Edit/Screens/EditorScreen.cs | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 8a11a50fd6..ca072ed73e 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -118,6 +118,7 @@ namespace osu.Game.Screens.Edit break; } + currentScreen.Beatmap.BindTo(Beatmap); screenContainer.Add(currentScreen); } diff --git a/osu.Game/Screens/Edit/Screens/EditorScreen.cs b/osu.Game/Screens/Edit/Screens/EditorScreen.cs index c456ad6a51..509c61a530 100644 --- a/osu.Game/Screens/Edit/Screens/EditorScreen.cs +++ b/osu.Game/Screens/Edit/Screens/EditorScreen.cs @@ -1,13 +1,17 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using osu.Framework.Configuration; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Game.Beatmaps; namespace osu.Game.Screens.Edit.Screens { public class EditorScreen : Container { + public readonly Bindable Beatmap = new Bindable(); + protected override Container Content => content; private readonly Container content; From 1a7e3fa09e4d51db6a30dfe7975538fc1277b824 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 3 Oct 2017 19:21:08 +0900 Subject: [PATCH 0119/1263] Initial implementation of a test case which showcases waveforms --- osu.Game/Tests/Visual/TestCaseWaveform.cs | 149 ++++++++++++++++++++++ osu.Game/osu.Game.csproj | 1 + 2 files changed, 150 insertions(+) create mode 100644 osu.Game/Tests/Visual/TestCaseWaveform.cs diff --git a/osu.Game/Tests/Visual/TestCaseWaveform.cs b/osu.Game/Tests/Visual/TestCaseWaveform.cs new file mode 100644 index 0000000000..5f4e86fb92 --- /dev/null +++ b/osu.Game/Tests/Visual/TestCaseWaveform.cs @@ -0,0 +1,149 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using System.Collections.Generic; +using OpenTK; +using OpenTK.Graphics; +using osu.Framework.Allocation; +using osu.Framework.Audio.Track; +using osu.Framework.Configuration; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Game.Beatmaps; +using osu.Game.Graphics.Sprites; +using osu.Game.Overlays; + +namespace osu.Game.Tests.Visual +{ + internal class TestCaseWaveform : OsuTestCase + { + private readonly Bindable beatmapBacking = new Bindable(); + + private readonly List displays = new List(); + + public TestCaseWaveform() + { + MusicController mc; + FillFlowContainer flow; + Child = flow = new FillFlowContainer + { + RelativeSizeAxes = Axes.Both, + Direction = FillDirection.Vertical, + Spacing = new Vector2(0, 10), + Children = new Drawable[] + { + mc = new MusicController + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Y = 100, + State = Visibility.Visible + }, + } + }; + + for (int i = 1; i <= 16; i *= 2) + { + var newDisplay = new WaveformDisplay(i) { RelativeSizeAxes = Axes.Both }; + + displays.Add(newDisplay); + + flow.Add(new Container + { + RelativeSizeAxes = Axes.X, + Height = 100, + Children = new Drawable[] + { + newDisplay, + new Container + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + AutoSizeAxes = Axes.Both, + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Black, + Alpha = 0.75f + }, + new OsuSpriteText + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Text = $"Resolution: {(1f / i).ToString("0.00")}" + } + } + } + } + }); + } + } + + [BackgroundDependencyLoader] + private void load(OsuGameBase osuGame) + { + beatmapBacking.BindTo(osuGame.Beatmap); + beatmapBacking.ValueChanged += b => b.Track.QueryWaveform(processWaveform); + } + + private void processWaveform(Waveform waveform) => Schedule(() => displays.ForEach(d => d.Display(waveform))); + + private class WaveformDisplay : CompositeDrawable + { + private readonly int resolution; + + public WaveformDisplay(int resolution) + { + this.resolution = resolution; + } + + public void Display(Waveform waveform) + { + ClearInternal(); + + var generated = waveform.Generate((int)MathHelper.Clamp(Math.Ceiling(DrawWidth), 0, waveform.TotalPoints) / resolution); + + for (int i = 0; i < generated.Count; i++) + { + var point = generated[i]; + + // Left channel + AddInternal(new NonInputBox + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.BottomLeft, + RelativePositionAxes = Axes.X, + RelativeSizeAxes = Axes.Both, + X = 1f / generated.Count * i, + Size = new Vector2(1f / generated.Count, point.Amplitude[0] / 2), + Colour = Color4.Red + }); + + if (waveform.Channels >= 2) + { + // Right channel + AddInternal(new NonInputBox + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.TopLeft, + RelativePositionAxes = Axes.X, + RelativeSizeAxes = Axes.Both, + X = 1f / generated.Count * i, + Size = new Vector2(1f / generated.Count, point.Amplitude[1] / 2), + Colour = Color4.Green + }); + } + } + } + + private class NonInputBox : Box + { + public override bool HandleInput => false; + } + } + } +} diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 9a8536bbc2..56490b6119 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -777,6 +777,7 @@ + From 319649f4465a45bc93c615d57ceb11ac36cd8460 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 3 Oct 2017 21:19:38 +0900 Subject: [PATCH 0120/1263] Make TestCaseWaveform use a custom drawnode instead of boxes --- osu.Game/Tests/Visual/TestCaseWaveform.cs | 128 +++++++++++++++++----- 1 file changed, 101 insertions(+), 27 deletions(-) diff --git a/osu.Game/Tests/Visual/TestCaseWaveform.cs b/osu.Game/Tests/Visual/TestCaseWaveform.cs index 5f4e86fb92..3f71e74a8d 100644 --- a/osu.Game/Tests/Visual/TestCaseWaveform.cs +++ b/osu.Game/Tests/Visual/TestCaseWaveform.cs @@ -5,12 +5,19 @@ using System; using System.Collections.Generic; using OpenTK; using OpenTK.Graphics; +using OpenTK.Graphics.ES30; using osu.Framework.Allocation; using osu.Framework.Audio.Track; using osu.Framework.Configuration; using osu.Framework.Graphics; +using osu.Framework.Graphics.Batches; +using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.OpenGL.Vertices; +using osu.Framework.Graphics.Primitives; +using osu.Framework.Graphics.Shaders; using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Textures; using osu.Game.Beatmaps; using osu.Game.Graphics.Sprites; using osu.Game.Overlays; @@ -92,51 +99,118 @@ namespace osu.Game.Tests.Visual private void processWaveform(Waveform waveform) => Schedule(() => displays.ForEach(d => d.Display(waveform))); - private class WaveformDisplay : CompositeDrawable + private class WaveformDisplay : Drawable { + private List points; + private int channels; + + private Shader shader; + private readonly Texture texture; + private readonly int resolution; public WaveformDisplay(int resolution) { this.resolution = resolution; + + texture = Texture.WhitePixel; + } + + [BackgroundDependencyLoader] + private void load(ShaderManager shaders) + { + shader = shaders?.Load(VertexShaderDescriptor.TEXTURE_2, FragmentShaderDescriptor.TEXTURE_ROUNDED); } public void Display(Waveform waveform) { - ClearInternal(); + points = waveform.Generate((int)MathHelper.Clamp(Math.Ceiling(DrawWidth), 0, waveform.TotalPoints) / resolution); + channels = waveform.Channels; + Invalidate(Invalidation.DrawNode); + } - var generated = waveform.Generate((int)MathHelper.Clamp(Math.Ceiling(DrawWidth), 0, waveform.TotalPoints) / resolution); + protected override DrawNode CreateDrawNode() => new WaveformDrawNode(); - for (int i = 0; i < generated.Count; i++) + private readonly WaveformDrawNodeSharedData sharedData = new WaveformDrawNodeSharedData(); + protected override void ApplyDrawNode(DrawNode node) + { + var n = (WaveformDrawNode)node; + + n.Shader = shader; + n.Texture = texture; + n.Points = points; + n.Channels = channels; + n.Size = DrawSize; + n.Shared = sharedData; + + + base.ApplyDrawNode(node); + } + + private class WaveformDrawNodeSharedData + { + public readonly QuadBatch VertexBatch = new QuadBatch(1000, 10); + } + + private class WaveformDrawNode : DrawNode + { + public Shader Shader; + public Texture Texture; + + public WaveformDrawNodeSharedData Shared; + + public List Points; + public Vector2 Size; + public int Channels; + + public override void Draw(Action vertexAction) { - var point = generated[i]; + base.Draw(vertexAction); - // Left channel - AddInternal(new NonInputBox - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.BottomLeft, - RelativePositionAxes = Axes.X, - RelativeSizeAxes = Axes.Both, - X = 1f / generated.Count * i, - Size = new Vector2(1f / generated.Count, point.Amplitude[0] / 2), - Colour = Color4.Red - }); + if (Points == null || Points.Count == 0) + return; - if (waveform.Channels >= 2) + Shader.Bind(); + Texture.TextureGL.Bind(); + + float separation = Size.X / (Points.Count - 1); + Vector2 localInflationAmount = new Vector2(0, 1) * DrawInfo.MatrixInverse.ExtractScale().Xy; + + for (int i = 0; i < Points.Count - 1; i++) { - // Right channel - AddInternal(new NonInputBox + ColourInfo colour = DrawInfo.Colour; + Quad quadToDraw; + + switch (Channels) { - Anchor = Anchor.CentreLeft, - Origin = Anchor.TopLeft, - RelativePositionAxes = Axes.X, - RelativeSizeAxes = Axes.Both, - X = 1f / generated.Count * i, - Size = new Vector2(1f / generated.Count, point.Amplitude[1] / 2), - Colour = Color4.Green - }); + default: + case 2: + { + float height = Size.Y / 2; + quadToDraw = new Quad( + new Vector2(i * separation, height - Points[i].Amplitude[0] * height), + new Vector2((i + 1) * separation, height - Points[i + 1].Amplitude[0] * height), + new Vector2(i * separation, height + Points[i].Amplitude[1] * height), + new Vector2((i + 1) * separation, height + Points[i + 1].Amplitude[1] * height) + ); + } + break; + case 1: + { + quadToDraw = new Quad( + new Vector2(i * separation, Size.Y - Points[i].Amplitude[0] * Size.Y), + new Vector2((i + 1) * separation, Size.Y - Points[i + 1].Amplitude[0] * Size.Y), + new Vector2(i * separation, Size.Y), + new Vector2((i + 1) * separation, Size.Y) + ); + break; + } + } + + Texture.DrawQuad(quadToDraw * DrawInfo.Matrix, colour, null, Shared.VertexBatch.Add, Vector2.Divide(localInflationAmount, quadToDraw.Size)); } + + Shader.Unbind(); } } From 3eeb36cbd42f3cfa4b7b448e9c4170af4a346601 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 3 Oct 2017 23:23:20 +0900 Subject: [PATCH 0121/1263] Remove now unused class --- osu.Game/Tests/Visual/TestCaseWaveform.cs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/osu.Game/Tests/Visual/TestCaseWaveform.cs b/osu.Game/Tests/Visual/TestCaseWaveform.cs index 3f71e74a8d..2966728fb5 100644 --- a/osu.Game/Tests/Visual/TestCaseWaveform.cs +++ b/osu.Game/Tests/Visual/TestCaseWaveform.cs @@ -143,7 +143,6 @@ namespace osu.Game.Tests.Visual n.Size = DrawSize; n.Shared = sharedData; - base.ApplyDrawNode(node); } @@ -213,11 +212,6 @@ namespace osu.Game.Tests.Visual Shader.Unbind(); } } - - private class NonInputBox : Box - { - public override bool HandleInput => false; - } } } } From a37b10d51220b5f0df864cd8e503696eb669a0b6 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 4 Oct 2017 14:42:22 +0900 Subject: [PATCH 0122/1263] Make TestCaseWaveform use invalidations + remove some of the crud --- osu.Game/Tests/Visual/TestCaseWaveform.cs | 69 +++++++++++++++-------- 1 file changed, 44 insertions(+), 25 deletions(-) diff --git a/osu.Game/Tests/Visual/TestCaseWaveform.cs b/osu.Game/Tests/Visual/TestCaseWaveform.cs index 2966728fb5..4df7ffe367 100644 --- a/osu.Game/Tests/Visual/TestCaseWaveform.cs +++ b/osu.Game/Tests/Visual/TestCaseWaveform.cs @@ -28,8 +28,6 @@ namespace osu.Game.Tests.Visual { private readonly Bindable beatmapBacking = new Bindable(); - private readonly List displays = new List(); - public TestCaseWaveform() { MusicController mc; @@ -53,9 +51,13 @@ namespace osu.Game.Tests.Visual for (int i = 1; i <= 16; i *= 2) { - var newDisplay = new WaveformDisplay(i) { RelativeSizeAxes = Axes.Both }; + var newDisplay = new WaveformDisplay + { + RelativeSizeAxes = Axes.Both, + Resolution = 1f / i + }; - displays.Add(newDisplay); + newDisplay.Beatmap.BindTo(beatmapBacking); flow.Add(new Container { @@ -91,29 +93,21 @@ namespace osu.Game.Tests.Visual } [BackgroundDependencyLoader] - private void load(OsuGameBase osuGame) - { - beatmapBacking.BindTo(osuGame.Beatmap); - beatmapBacking.ValueChanged += b => b.Track.QueryWaveform(processWaveform); - } - - private void processWaveform(Waveform waveform) => Schedule(() => displays.ForEach(d => d.Display(waveform))); + private void load(OsuGameBase osuGame) => beatmapBacking.BindTo(osuGame.Beatmap); private class WaveformDisplay : Drawable { - private List points; - private int channels; + public readonly Bindable Beatmap = new Bindable(); + + private Waveform waveform; private Shader shader; private readonly Texture texture; - private readonly int resolution; - - public WaveformDisplay(int resolution) + public WaveformDisplay() { - this.resolution = resolution; - texture = Texture.WhitePixel; + Beatmap.ValueChanged += generateWaveform; } [BackgroundDependencyLoader] @@ -122,26 +116,51 @@ namespace osu.Game.Tests.Visual shader = shaders?.Load(VertexShaderDescriptor.TEXTURE_2, FragmentShaderDescriptor.TEXTURE_ROUNDED); } - public void Display(Waveform waveform) + private float resolution = 1; + public float Resolution { - points = waveform.Generate((int)MathHelper.Clamp(Math.Ceiling(DrawWidth), 0, waveform.TotalPoints) / resolution); - channels = waveform.Channels; - Invalidate(Invalidation.DrawNode); + get { return resolution; } + set + { + if (resolution == value) + return; + resolution = value; + + Invalidate(Invalidation.DrawNode); + } } - protected override DrawNode CreateDrawNode() => new WaveformDrawNode(); + private Track lastQueriedTrack; + + private void generateWaveform(WorkingBeatmap beatmap) + { + // Cancel the old query so we don't saturate the audio thread + lastQueriedTrack?.CancelWaveformQuery(); + + beatmap.Track.QueryWaveform(w => + { + if (Beatmap.Value == beatmap) + { + waveform = w; + Invalidate(Invalidation.DrawNode); + } + }); + + lastQueriedTrack = beatmap.Track; + } private readonly WaveformDrawNodeSharedData sharedData = new WaveformDrawNodeSharedData(); + protected override DrawNode CreateDrawNode() => new WaveformDrawNode(); protected override void ApplyDrawNode(DrawNode node) { var n = (WaveformDrawNode)node; n.Shader = shader; n.Texture = texture; - n.Points = points; - n.Channels = channels; n.Size = DrawSize; n.Shared = sharedData; + n.Points = waveform.Generate((int)(MathHelper.Clamp(Math.Ceiling(DrawWidth), 0, waveform.TotalPoints) * resolution)); + n.Channels = waveform.Channels; base.ApplyDrawNode(node); } From 01c839eda7dfeb6f68edf6b6a442e956f6715c60 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 4 Oct 2017 14:55:17 +0900 Subject: [PATCH 0123/1263] Move WaveformDisplay into separate class and add some commenting --- .../Edit/Screens/Compose/WaveformDisplay.cs | 168 ++++++++++++++++++ osu.Game/Tests/Visual/TestCaseWaveform.cs | 149 +--------------- osu.Game/osu.Game.csproj | 1 + 3 files changed, 170 insertions(+), 148 deletions(-) create mode 100644 osu.Game/Screens/Edit/Screens/Compose/WaveformDisplay.cs diff --git a/osu.Game/Screens/Edit/Screens/Compose/WaveformDisplay.cs b/osu.Game/Screens/Edit/Screens/Compose/WaveformDisplay.cs new file mode 100644 index 0000000000..0f0c32ea0d --- /dev/null +++ b/osu.Game/Screens/Edit/Screens/Compose/WaveformDisplay.cs @@ -0,0 +1,168 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using System.Collections.Generic; +using OpenTK; +using osu.Framework.Allocation; +using osu.Framework.Audio.Track; +using osu.Framework.Configuration; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Batches; +using osu.Framework.Graphics.Colour; +using osu.Framework.Graphics.OpenGL.Vertices; +using osu.Framework.Graphics.Primitives; +using osu.Framework.Graphics.Shaders; +using osu.Framework.Graphics.Textures; +using osu.Game.Beatmaps; + +namespace osu.Game.Screens.Edit.Screens.Compose +{ + public class WaveformDisplay : Drawable + { + /// + /// The beatmap which the audio waveform should be displayed for. + /// + /// + public readonly Bindable Beatmap = new Bindable(); + + private Shader shader; + private readonly Texture texture; + + public WaveformDisplay() + { + texture = Texture.WhitePixel; + Beatmap.ValueChanged += generateWaveform; + } + + [BackgroundDependencyLoader] + private void load(ShaderManager shaders) + { + shader = shaders?.Load(VertexShaderDescriptor.TEXTURE_2, FragmentShaderDescriptor.TEXTURE_ROUNDED); + } + + private float resolution = 1; + /// + /// Controls the amount of interpolation of the waveform into the width of this . + /// Points in the waveform are interpolated between 1 / pixels of this . + /// + /// + public float Resolution + { + get { return resolution; } + set + { + if (value < 0 || value > 1) + throw new ArgumentOutOfRangeException(nameof(value)); + + if (resolution == value) + return; + resolution = value; + + Invalidate(Invalidation.DrawNode); + } + } + + private Waveform waveform; + private Track lastQueriedTrack; + private void generateWaveform(WorkingBeatmap beatmap) + { + // Cancel the old query so we don't saturate the audio thread + lastQueriedTrack?.CancelWaveformQuery(); + + beatmap.Track.QueryWaveform(w => + { + if (Beatmap.Value == beatmap) + { + waveform = w; + Invalidate(Invalidation.DrawNode); + } + }); + + lastQueriedTrack = beatmap.Track; + } + + private readonly WaveformDrawNodeSharedData sharedData = new WaveformDrawNodeSharedData(); + protected override DrawNode CreateDrawNode() => new WaveformDrawNode(); + protected override void ApplyDrawNode(DrawNode node) + { + var n = (WaveformDrawNode)node; + + n.Shader = shader; + n.Texture = texture; + n.Size = DrawSize; + n.Shared = sharedData; + n.Points = waveform.Generate((int)(MathHelper.Clamp(Math.Ceiling(DrawWidth), 0, waveform.TotalPoints) * resolution)); + n.Channels = waveform.Channels; + + base.ApplyDrawNode(node); + } + + private class WaveformDrawNodeSharedData + { + public readonly QuadBatch VertexBatch = new QuadBatch(1000, 10); + } + + private class WaveformDrawNode : DrawNode + { + public Shader Shader; + public Texture Texture; + + public WaveformDrawNodeSharedData Shared; + + public List Points; + public Vector2 Size; + public int Channels; + + public override void Draw(Action vertexAction) + { + base.Draw(vertexAction); + + if (Points == null || Points.Count == 0) + return; + + Shader.Bind(); + Texture.TextureGL.Bind(); + + float separation = Size.X / (Points.Count - 1); + Vector2 localInflationAmount = new Vector2(0, 1) * DrawInfo.MatrixInverse.ExtractScale().Xy; + + for (int i = 0; i < Points.Count - 1; i++) + { + ColourInfo colour = DrawInfo.Colour; + Quad quadToDraw; + + switch (Channels) + { + default: + case 2: + { + float height = Size.Y / 2; + quadToDraw = new Quad( + new Vector2(i * separation, height - Points[i].Amplitude[0] * height), + new Vector2((i + 1) * separation, height - Points[i + 1].Amplitude[0] * height), + new Vector2(i * separation, height + Points[i].Amplitude[1] * height), + new Vector2((i + 1) * separation, height + Points[i + 1].Amplitude[1] * height) + ); + } + break; + case 1: + { + quadToDraw = new Quad( + new Vector2(i * separation, Size.Y - Points[i].Amplitude[0] * Size.Y), + new Vector2((i + 1) * separation, Size.Y - Points[i + 1].Amplitude[0] * Size.Y), + new Vector2(i * separation, Size.Y), + new Vector2((i + 1) * separation, Size.Y) + ); + break; + } + } + + Texture.DrawQuad(quadToDraw * DrawInfo.Matrix, colour, null, Shared.VertexBatch.Add, Vector2.Divide(localInflationAmount, quadToDraw.Size)); + } + + Shader.Unbind(); + } + } + } +} diff --git a/osu.Game/Tests/Visual/TestCaseWaveform.cs b/osu.Game/Tests/Visual/TestCaseWaveform.cs index 4df7ffe367..0430185bf7 100644 --- a/osu.Game/Tests/Visual/TestCaseWaveform.cs +++ b/osu.Game/Tests/Visual/TestCaseWaveform.cs @@ -1,26 +1,17 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using System; -using System.Collections.Generic; using OpenTK; using OpenTK.Graphics; -using OpenTK.Graphics.ES30; using osu.Framework.Allocation; -using osu.Framework.Audio.Track; using osu.Framework.Configuration; using osu.Framework.Graphics; -using osu.Framework.Graphics.Batches; -using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.OpenGL.Vertices; -using osu.Framework.Graphics.Primitives; -using osu.Framework.Graphics.Shaders; using osu.Framework.Graphics.Shapes; -using osu.Framework.Graphics.Textures; using osu.Game.Beatmaps; using osu.Game.Graphics.Sprites; using osu.Game.Overlays; +using osu.Game.Screens.Edit.Screens.Compose; namespace osu.Game.Tests.Visual { @@ -94,143 +85,5 @@ namespace osu.Game.Tests.Visual [BackgroundDependencyLoader] private void load(OsuGameBase osuGame) => beatmapBacking.BindTo(osuGame.Beatmap); - - private class WaveformDisplay : Drawable - { - public readonly Bindable Beatmap = new Bindable(); - - private Waveform waveform; - - private Shader shader; - private readonly Texture texture; - - public WaveformDisplay() - { - texture = Texture.WhitePixel; - Beatmap.ValueChanged += generateWaveform; - } - - [BackgroundDependencyLoader] - private void load(ShaderManager shaders) - { - shader = shaders?.Load(VertexShaderDescriptor.TEXTURE_2, FragmentShaderDescriptor.TEXTURE_ROUNDED); - } - - private float resolution = 1; - public float Resolution - { - get { return resolution; } - set - { - if (resolution == value) - return; - resolution = value; - - Invalidate(Invalidation.DrawNode); - } - } - - private Track lastQueriedTrack; - - private void generateWaveform(WorkingBeatmap beatmap) - { - // Cancel the old query so we don't saturate the audio thread - lastQueriedTrack?.CancelWaveformQuery(); - - beatmap.Track.QueryWaveform(w => - { - if (Beatmap.Value == beatmap) - { - waveform = w; - Invalidate(Invalidation.DrawNode); - } - }); - - lastQueriedTrack = beatmap.Track; - } - - private readonly WaveformDrawNodeSharedData sharedData = new WaveformDrawNodeSharedData(); - protected override DrawNode CreateDrawNode() => new WaveformDrawNode(); - protected override void ApplyDrawNode(DrawNode node) - { - var n = (WaveformDrawNode)node; - - n.Shader = shader; - n.Texture = texture; - n.Size = DrawSize; - n.Shared = sharedData; - n.Points = waveform.Generate((int)(MathHelper.Clamp(Math.Ceiling(DrawWidth), 0, waveform.TotalPoints) * resolution)); - n.Channels = waveform.Channels; - - base.ApplyDrawNode(node); - } - - private class WaveformDrawNodeSharedData - { - public readonly QuadBatch VertexBatch = new QuadBatch(1000, 10); - } - - private class WaveformDrawNode : DrawNode - { - public Shader Shader; - public Texture Texture; - - public WaveformDrawNodeSharedData Shared; - - public List Points; - public Vector2 Size; - public int Channels; - - public override void Draw(Action vertexAction) - { - base.Draw(vertexAction); - - if (Points == null || Points.Count == 0) - return; - - Shader.Bind(); - Texture.TextureGL.Bind(); - - float separation = Size.X / (Points.Count - 1); - Vector2 localInflationAmount = new Vector2(0, 1) * DrawInfo.MatrixInverse.ExtractScale().Xy; - - for (int i = 0; i < Points.Count - 1; i++) - { - ColourInfo colour = DrawInfo.Colour; - Quad quadToDraw; - - switch (Channels) - { - default: - case 2: - { - float height = Size.Y / 2; - quadToDraw = new Quad( - new Vector2(i * separation, height - Points[i].Amplitude[0] * height), - new Vector2((i + 1) * separation, height - Points[i + 1].Amplitude[0] * height), - new Vector2(i * separation, height + Points[i].Amplitude[1] * height), - new Vector2((i + 1) * separation, height + Points[i + 1].Amplitude[1] * height) - ); - } - break; - case 1: - { - quadToDraw = new Quad( - new Vector2(i * separation, Size.Y - Points[i].Amplitude[0] * Size.Y), - new Vector2((i + 1) * separation, Size.Y - Points[i + 1].Amplitude[0] * Size.Y), - new Vector2(i * separation, Size.Y), - new Vector2((i + 1) * separation, Size.Y) - ); - break; - } - } - - Texture.DrawQuad(quadToDraw * DrawInfo.Matrix, colour, null, Shared.VertexBatch.Add, Vector2.Divide(localInflationAmount, quadToDraw.Size)); - } - - Shader.Unbind(); - } - } - } } } diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 56490b6119..f89810dfc1 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -620,6 +620,7 @@ + From 80e984f72dea9361b6b2d53cb9bdbe42614412d2 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 4 Oct 2017 18:55:38 +0900 Subject: [PATCH 0124/1263] Update in-line with framework --- osu.Game/Screens/Edit/Screens/Compose/WaveformDisplay.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Screens/Compose/WaveformDisplay.cs b/osu.Game/Screens/Edit/Screens/Compose/WaveformDisplay.cs index 0f0c32ea0d..a781e63fd9 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/WaveformDisplay.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/WaveformDisplay.cs @@ -92,7 +92,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose n.Texture = texture; n.Size = DrawSize; n.Shared = sharedData; - n.Points = waveform.Generate((int)(MathHelper.Clamp(Math.Ceiling(DrawWidth), 0, waveform.TotalPoints) * resolution)); + n.Points = waveform.Generate((int)(MathHelper.Clamp(Math.Ceiling(DrawWidth), 0, waveform.MaximumPoints) * resolution)); n.Channels = waveform.Channels; base.ApplyDrawNode(node); From 81960c7b487d2a66b134ad9554d0a639153a2483 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 4 Oct 2017 18:55:45 +0900 Subject: [PATCH 0125/1263] CI fixes --- osu.Game/Screens/Edit/Screens/Compose/WaveformDisplay.cs | 2 -- osu.Game/Tests/Visual/TestCaseWaveform.cs | 5 ++--- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/osu.Game/Screens/Edit/Screens/Compose/WaveformDisplay.cs b/osu.Game/Screens/Edit/Screens/Compose/WaveformDisplay.cs index a781e63fd9..236f6b6d47 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/WaveformDisplay.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/WaveformDisplay.cs @@ -23,7 +23,6 @@ namespace osu.Game.Screens.Edit.Screens.Compose /// /// The beatmap which the audio waveform should be displayed for. /// - /// public readonly Bindable Beatmap = new Bindable(); private Shader shader; @@ -46,7 +45,6 @@ namespace osu.Game.Screens.Edit.Screens.Compose /// Controls the amount of interpolation of the waveform into the width of this . /// Points in the waveform are interpolated between 1 / pixels of this . /// - /// public float Resolution { get { return resolution; } diff --git a/osu.Game/Tests/Visual/TestCaseWaveform.cs b/osu.Game/Tests/Visual/TestCaseWaveform.cs index 0430185bf7..eff4f5cdad 100644 --- a/osu.Game/Tests/Visual/TestCaseWaveform.cs +++ b/osu.Game/Tests/Visual/TestCaseWaveform.cs @@ -21,7 +21,6 @@ namespace osu.Game.Tests.Visual public TestCaseWaveform() { - MusicController mc; FillFlowContainer flow; Child = flow = new FillFlowContainer { @@ -30,7 +29,7 @@ namespace osu.Game.Tests.Visual Spacing = new Vector2(0, 10), Children = new Drawable[] { - mc = new MusicController + new MusicController { Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, @@ -74,7 +73,7 @@ namespace osu.Game.Tests.Visual { Anchor = Anchor.Centre, Origin = Anchor.Centre, - Text = $"Resolution: {(1f / i).ToString("0.00")}" + Text = $"Resolution: {(1f / i):0.00}" } } } From 5ca4a2d2c81600178816afb37778e40ce480f47c Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 4 Oct 2017 19:09:39 +0900 Subject: [PATCH 0126/1263] Add some nullchecks to WaveformDisplay --- osu.Game/Screens/Edit/Screens/Compose/WaveformDisplay.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Edit/Screens/Compose/WaveformDisplay.cs b/osu.Game/Screens/Edit/Screens/Compose/WaveformDisplay.cs index 236f6b6d47..d1550117df 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/WaveformDisplay.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/WaveformDisplay.cs @@ -90,8 +90,8 @@ namespace osu.Game.Screens.Edit.Screens.Compose n.Texture = texture; n.Size = DrawSize; n.Shared = sharedData; - n.Points = waveform.Generate((int)(MathHelper.Clamp(Math.Ceiling(DrawWidth), 0, waveform.MaximumPoints) * resolution)); - n.Channels = waveform.Channels; + n.Points = waveform?.Generate((int)(MathHelper.Clamp(Math.Ceiling(DrawWidth), 0, waveform.MaximumPoints) * resolution)); + n.Channels = waveform?.Channels ?? 0; base.ApplyDrawNode(node); } From 357a4673373a3dd1e0fc1da0bc5b01e3ba998c7d Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 4 Oct 2017 19:24:19 +0900 Subject: [PATCH 0127/1263] Implement design mode --- osu.Game/Screens/Edit/Editor.cs | 4 ++ .../Screens/Edit/Screens/Design/Design.cs | 52 +++++++++++++++++++ osu.Game/osu.Game.csproj | 1 + 3 files changed, 57 insertions(+) create mode 100644 osu.Game/Screens/Edit/Screens/Design/Design.cs diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index ca072ed73e..036243e668 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -14,6 +14,7 @@ using OpenTK; using osu.Framework.Allocation; using osu.Game.Screens.Edit.Screens; using osu.Game.Screens.Edit.Screens.Compose; +using osu.Game.Screens.Edit.Screens.Design; namespace osu.Game.Screens.Edit { @@ -113,6 +114,9 @@ namespace osu.Game.Screens.Edit case EditorScreenMode.Compose: currentScreen = new Compose(); break; + case EditorScreenMode.Design: + currentScreen = new Design(); + break; default: currentScreen = new EditorScreen(); break; diff --git a/osu.Game/Screens/Edit/Screens/Design/Design.cs b/osu.Game/Screens/Edit/Screens/Design/Design.cs new file mode 100644 index 0000000000..e527d7dad9 --- /dev/null +++ b/osu.Game/Screens/Edit/Screens/Design/Design.cs @@ -0,0 +1,52 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Game.Graphics.Sprites; +using OpenTK.Graphics; + +namespace osu.Game.Screens.Edit.Screens.Design +{ + internal class Design : EditorScreen + { + public Design() + { + Add(new Container + { + RelativeSizeAxes = Axes.Both, + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Black, + Alpha = 0.35f + }, + new Container + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + AutoSizeAxes = Axes.Both, + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Black, + Alpha = 0.5f + }, + new Container + { + AutoSizeAxes = Axes.Both, + Padding = new MarginPadding(20), + Child = new OsuSpriteText { Text = "Design screen" } + } + } + } + } + }); + } + } +} diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 9a8536bbc2..39fd968763 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -618,6 +618,7 @@ + From e2824d4732c1c177619820ae231223991520ff5f Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 4 Oct 2017 19:26:26 +0900 Subject: [PATCH 0128/1263] Reduce harshness of scale for now Though I don't feel like we should worry about this much just yet until we have actual designs and can see how it looks. It's very well possible that we use different transitions here... --- osu.Game/Screens/Edit/Screens/EditorScreen.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Edit/Screens/EditorScreen.cs b/osu.Game/Screens/Edit/Screens/EditorScreen.cs index 509c61a530..152c00a48d 100644 --- a/osu.Game/Screens/Edit/Screens/EditorScreen.cs +++ b/osu.Game/Screens/Edit/Screens/EditorScreen.cs @@ -28,14 +28,14 @@ namespace osu.Game.Screens.Edit.Screens { base.LoadComplete(); - this.ScaleTo(0.5f).FadeTo(0) + this.ScaleTo(0.75f).FadeTo(0) .Then() .ScaleTo(1f, 500, Easing.OutQuint).FadeTo(1f, 250, Easing.OutQuint); } public void Exit() { - this.ScaleTo(1.5f, 500).FadeOut(250).Expire(); + this.ScaleTo(1.25f, 500).FadeOut(250).Expire(); } } } From 34eede0d04dd887e472846163027d36b52f1bbc5 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 4 Oct 2017 19:36:55 +0900 Subject: [PATCH 0129/1263] Re-namespace EditorScreenMode --- osu.Game/Screens/Edit/Menus/EditorMenuBar.cs | 2 +- .../Edit/Menus/ScreenSelectionTabControl.cs | 14 +------------- .../Screens/Edit/Screens/EditorScreenMode.cs | 19 +++++++++++++++++++ osu.Game/osu.Game.csproj | 1 + 4 files changed, 22 insertions(+), 14 deletions(-) create mode 100644 osu.Game/Screens/Edit/Screens/EditorScreenMode.cs diff --git a/osu.Game/Screens/Edit/Menus/EditorMenuBar.cs b/osu.Game/Screens/Edit/Menus/EditorMenuBar.cs index 4c9b3c84b3..34a96b0a6e 100644 --- a/osu.Game/Screens/Edit/Menus/EditorMenuBar.cs +++ b/osu.Game/Screens/Edit/Menus/EditorMenuBar.cs @@ -11,7 +11,7 @@ using osu.Game.Graphics; using osu.Game.Graphics.UserInterface; using OpenTK; using OpenTK.Graphics; -using System; +using osu.Game.Screens.Edit.Screens; namespace osu.Game.Screens.Edit.Menus { diff --git a/osu.Game/Screens/Edit/Menus/ScreenSelectionTabControl.cs b/osu.Game/Screens/Edit/Menus/ScreenSelectionTabControl.cs index 652ef1d61f..f5e47464ae 100644 --- a/osu.Game/Screens/Edit/Menus/ScreenSelectionTabControl.cs +++ b/osu.Game/Screens/Edit/Menus/ScreenSelectionTabControl.cs @@ -9,8 +9,8 @@ using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.UserInterface; using osu.Game.Graphics; using osu.Game.Graphics.UserInterface; +using osu.Game.Screens.Edit.Screens; using OpenTK; -using System.ComponentModel; namespace osu.Game.Screens.Edit.Menus { @@ -70,16 +70,4 @@ namespace osu.Game.Screens.Edit.Menus } } } - - public enum EditorScreenMode - { - [Description("compose")] - Compose, - [Description("design")] - Design, - [Description("timing")] - Timing, - [Description("song")] - SongSetup - } } diff --git a/osu.Game/Screens/Edit/Screens/EditorScreenMode.cs b/osu.Game/Screens/Edit/Screens/EditorScreenMode.cs new file mode 100644 index 0000000000..6489bb305b --- /dev/null +++ b/osu.Game/Screens/Edit/Screens/EditorScreenMode.cs @@ -0,0 +1,19 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System.ComponentModel; + +namespace osu.Game.Screens.Edit.Screens +{ + public enum EditorScreenMode + { + [Description("compose")] + Compose, + [Description("design")] + Design, + [Description("timing")] + Timing, + [Description("song")] + SongSetup + } +} diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 39fd968763..f1ba54cba3 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -613,6 +613,7 @@ + From 8a52fdc8fa5abc503c6399cb214a7c0d97a39092 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 4 Oct 2017 19:37:17 +0900 Subject: [PATCH 0130/1263] Use a bindable for the current screen in EditorMenuBar Replaces the current Action. --- osu.Game/Screens/Edit/Editor.cs | 2 +- osu.Game/Screens/Edit/Menus/EditorMenuBar.cs | 8 +++----- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 036243e668..4fca38a6c6 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -96,7 +96,7 @@ namespace osu.Game.Screens.Edit }; timeline.Beatmap.BindTo(Beatmap); - menuBar.ModeChanged += onModeChanged; + menuBar.Mode.ValueChanged += onModeChanged; } [BackgroundDependencyLoader] diff --git a/osu.Game/Screens/Edit/Menus/EditorMenuBar.cs b/osu.Game/Screens/Edit/Menus/EditorMenuBar.cs index 34a96b0a6e..a4348b4489 100644 --- a/osu.Game/Screens/Edit/Menus/EditorMenuBar.cs +++ b/osu.Game/Screens/Edit/Menus/EditorMenuBar.cs @@ -11,16 +11,14 @@ using osu.Game.Graphics; using osu.Game.Graphics.UserInterface; using OpenTK; using OpenTK.Graphics; +using osu.Framework.Configuration; using osu.Game.Screens.Edit.Screens; namespace osu.Game.Screens.Edit.Menus { public class EditorMenuBar : OsuMenu { - /// - /// Invaoked when the selected mode has changed. - /// - public event Action ModeChanged; + public readonly Bindable Mode = new Bindable(); private readonly ScreenSelectionTabControl tabControl; @@ -42,7 +40,7 @@ namespace osu.Game.Screens.Edit.Menus } }); - tabControl.Current.ValueChanged += v => ModeChanged?.Invoke(v); + tabControl.Current.BindTo(Mode); } protected override void LoadComplete() From 1377f73b460b90f7fd4037b51536cb36a7fff92f Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 4 Oct 2017 21:57:29 +0900 Subject: [PATCH 0131/1263] Multiply resolution before clamping --- osu.Game/Screens/Edit/Screens/Compose/WaveformDisplay.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Screens/Compose/WaveformDisplay.cs b/osu.Game/Screens/Edit/Screens/Compose/WaveformDisplay.cs index d1550117df..e11cd667e6 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/WaveformDisplay.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/WaveformDisplay.cs @@ -90,7 +90,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose n.Texture = texture; n.Size = DrawSize; n.Shared = sharedData; - n.Points = waveform?.Generate((int)(MathHelper.Clamp(Math.Ceiling(DrawWidth), 0, waveform.MaximumPoints) * resolution)); + n.Points = waveform?.Generate((int)(MathHelper.Clamp(Math.Ceiling(DrawWidth) * Resolution, 0, waveform.MaximumPoints))); n.Channels = waveform?.Channels ?? 0; base.ApplyDrawNode(node); From ea4545299386900ba257dadcb25f7a0960901884 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 4 Oct 2017 21:57:46 +0900 Subject: [PATCH 0132/1263] Allow resolution > 1 --- osu.Game/Screens/Edit/Screens/Compose/WaveformDisplay.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Screens/Compose/WaveformDisplay.cs b/osu.Game/Screens/Edit/Screens/Compose/WaveformDisplay.cs index e11cd667e6..3856558a32 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/WaveformDisplay.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/WaveformDisplay.cs @@ -50,7 +50,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose get { return resolution; } set { - if (value < 0 || value > 1) + if (value < 0) throw new ArgumentOutOfRangeException(nameof(value)); if (resolution == value) From 8427bb44d18759b516865d49fd648327e3d14c99 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 4 Oct 2017 21:10:01 +0900 Subject: [PATCH 0133/1263] Implement basic layout for the compose screen ScrollableTimeline --- .../Screens/Compose/ScrollableTimeline.cs | 143 ++++++++++++++++++ .../Visual/TestCaseEditorComposeTimeline.cs | 46 ++++++ osu.Game/osu.Game.csproj | 2 + 3 files changed, 191 insertions(+) create mode 100644 osu.Game/Screens/Edit/Screens/Compose/ScrollableTimeline.cs create mode 100644 osu.Game/Tests/Visual/TestCaseEditorComposeTimeline.cs diff --git a/osu.Game/Screens/Edit/Screens/Compose/ScrollableTimeline.cs b/osu.Game/Screens/Edit/Screens/Compose/ScrollableTimeline.cs new file mode 100644 index 0000000000..31d207a152 --- /dev/null +++ b/osu.Game/Screens/Edit/Screens/Compose/ScrollableTimeline.cs @@ -0,0 +1,143 @@ +// 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.Configuration; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Input; +using osu.Game.Beatmaps; +using osu.Game.Graphics; +using osu.Game.Graphics.UserInterface; + +namespace osu.Game.Screens.Edit.Screens.Compose +{ + public class ScrollableTimeline : CompositeDrawable + { + public readonly Bindable Beatmap = new Bindable(); + + private readonly Container timelineContainer; + private readonly WaveformDisplay waveform; + + public ScrollableTimeline() + { + Masking = true; + CornerRadius = 5; + + InternalChildren = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = OsuColour.FromHex("111") + }, + new FillFlowContainer + { + RelativeSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Children = new Drawable[] + { + new Container + { + AutoSizeAxes = Axes.X, + RelativeSizeAxes = Axes.Y, + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = OsuColour.FromHex("222") + }, + new FillFlowContainer + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + AutoSizeAxes = Axes.Y, + Width = 160, + Padding = new MarginPadding { Horizontal = 25 }, + Direction = FillDirection.Vertical, + Spacing = new Vector2(0, 4), + Children = new[] + { + new OsuCheckbox { LabelText = "Hit Objects" }, + new OsuCheckbox { LabelText = "Hit Sounds" }, + new OsuCheckbox { LabelText = "Waveform" } + } + } + } + }, + new Container + { + AutoSizeAxes = Axes.X, + RelativeSizeAxes = Axes.Y, + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = OsuColour.FromHex("333") + }, + new FillFlowContainer + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + AutoSizeAxes = Axes.Both, + Padding = new MarginPadding { Horizontal = 15 }, + Direction = FillDirection.Vertical, + Spacing = new Vector2(0, 30), + Children = new[] + { + new SpriteIcon + { + Size = new Vector2(18), + Icon = FontAwesome.fa_search_plus, + Colour = OsuColour.FromHex("555") + }, + new SpriteIcon + { + Size = new Vector2(18), + Icon = FontAwesome.fa_search_minus, + Colour = OsuColour.FromHex("555") + }, + } + } + } + }, + timelineContainer = new Container + { + RelativeSizeAxes = Axes.Y, + Children = new Drawable[] + { + waveform = new WaveformDisplay + { + RelativeSizeAxes = Axes.Both, + Colour = OsuColour.FromHex("081a84") + // Resolution = 0.33f, + } + } + } + } + } + }; + + waveform.Beatmap.BindTo(Beatmap); + } + + protected override bool OnWheel(InputState state) + { + if (!state.Keyboard.ControlPressed) + return false; + + waveform.ScaleTo(new Vector2(MathHelper.Clamp(waveform.Scale.X + state.Mouse.WheelDelta, 1, 30), 1), 150, Easing.OutQuint); + return true; + } + + protected override void Update() + { + base.Update(); + + timelineContainer.Size = new Vector2(DrawSize.X - timelineContainer.DrawPosition.X, 1); + } + } +} diff --git a/osu.Game/Tests/Visual/TestCaseEditorComposeTimeline.cs b/osu.Game/Tests/Visual/TestCaseEditorComposeTimeline.cs new file mode 100644 index 0000000000..714c7b5d50 --- /dev/null +++ b/osu.Game/Tests/Visual/TestCaseEditorComposeTimeline.cs @@ -0,0 +1,46 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using System.Collections.Generic; +using OpenTK; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Overlays; +using osu.Game.Screens.Edit.Screens.Compose; + +namespace osu.Game.Tests.Visual +{ + public class TestCaseEditorComposeTimeline : OsuTestCase + { + public override IReadOnlyList RequiredTypes => new[] { typeof(ScrollableTimeline), typeof(WaveformDisplay) }; + + private readonly ScrollableTimeline timeline; + + public TestCaseEditorComposeTimeline() + { + Children = new Drawable[] + { + new MusicController + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + State = Visibility.Visible + }, + timeline = new ScrollableTimeline + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Size = new Vector2(1000, 100) + } + }; + } + + [BackgroundDependencyLoader] + private void load(OsuGameBase osuGame) + { + timeline.Beatmap.BindTo(osuGame.Beatmap); + } + } +} diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index fde38848f1..d9c98e9b92 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -622,6 +622,7 @@ + @@ -748,6 +749,7 @@ + From e9bc5dbd0f5e18cb0520596303cf021acc3f6c5e Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 4 Oct 2017 23:35:20 +0900 Subject: [PATCH 0134/1263] Include framework commits --- osu-framework | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu-framework b/osu-framework index 9d142a8e00..bcd92492a9 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit 9d142a8e009794dfee828392e36025d08577131d +Subproject commit bcd92492a9f01178b83c2360cb9b87536435adde From 6a4198d0d67b77294916ebd0767a1817bf30e2d4 Mon Sep 17 00:00:00 2001 From: TocoToucan Date: Wed, 4 Oct 2017 22:52:12 +0300 Subject: [PATCH 0135/1263] Initial EF Core commit --- .../Beatmaps/ManiaBeatmapConverter.cs | 2 +- .../Legacy/DistanceObjectPatternGenerator.cs | 2 +- .../Patterns/Legacy/PatternGenerator.cs | 2 +- .../ManiaDifficultyCalculator.cs | 2 +- .../Scoring/ManiaScoreProcessor.cs | 2 +- .../UI/ManiaRulesetContainer.cs | 10 +- .../Scoring/OsuScoreProcessor.cs | 2 +- .../UI/Cursor/GameplayCursor.cs | 2 +- .../Beatmaps/TaikoBeatmapConverter.cs | 12 +-- .../Scoring/TaikoScoreProcessor.cs | 4 +- .../Tests/TestCaseTaikoPlayfield.cs | 4 +- .../UI/TaikoRulesetContainer.cs | 2 +- .../Beatmaps/Formats/OsuLegacyDecoderTest.cs | 8 +- .../Beatmaps/IO/ImportBeatmapTest.cs | 16 +-- .../Beatmaps/IO/OszArchiveReaderTest.cs | 2 +- osu.Game.Tests/app.config | 4 + osu.Game.Tests/osu.Game.Tests.csproj | 9 -- osu.Game.Tests/packages.config | 2 - osu.Game/Beatmaps/Beatmap.cs | 2 +- osu.Game/Beatmaps/BeatmapDifficulty.cs | 7 +- osu.Game/Beatmaps/BeatmapInfo.cs | 67 +++++------- osu.Game/Beatmaps/BeatmapManager.cs | 63 +++++------ osu.Game/Beatmaps/BeatmapMetadata.cs | 9 +- osu.Game/Beatmaps/BeatmapOnlineInfo.cs | 4 + osu.Game/Beatmaps/BeatmapSetFileInfo.cs | 21 ++-- osu.Game/Beatmaps/BeatmapSetInfo.cs | 23 ++-- osu.Game/Beatmaps/BeatmapSetOnlineInfo.cs | 16 ++- osu.Game/Beatmaps/BeatmapStore.cs | 102 +++++++----------- osu.Game/Beatmaps/DifficultyCalculator.cs | 2 +- osu.Game/Beatmaps/Drawables/BeatmapPanel.cs | 2 +- osu.Game/Beatmaps/Drawables/DifficultyIcon.cs | 2 +- osu.Game/Beatmaps/DummyWorkingBeatmap.cs | 8 +- osu.Game/Beatmaps/Formats/BeatmapDecoder.cs | 4 +- osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs | 24 ++--- osu.Game/Beatmaps/WorkingBeatmap.cs | 4 +- osu.Game/Database/DatabaseBackedStore.cs | 79 +------------- osu.Game/Database/DbContextBase.cs | 8 ++ osu.Game/Database/OsuDbContext.cs | 55 ++++++++++ osu.Game/Database/StoreVersion.cs | 15 --- osu.Game/IO/FileInfo.cs | 9 +- osu.Game/IO/FileStore.cs | 91 +++++----------- .../Input/Bindings/DatabasedKeyBinding.cs | 17 ++- .../DatabasedKeyBindingInputManager.cs | 2 +- osu.Game/Input/KeyBindingStore.cs | 55 ++++------ .../API/Requests/DownloadBeatmapSetRequest.cs | 2 +- .../API/Requests/GetBeatmapDetailsRequest.cs | 2 +- .../API/Requests/GetBeatmapSetsRequest.cs | 10 +- .../Online/API/Requests/GetScoresRequest.cs | 8 +- osu.Game/OsuGame.cs | 2 +- osu.Game/OsuGameBase.cs | 42 +++++--- osu.Game/Overlays/BeatmapSet/Header.cs | 4 +- osu.Game/Overlays/BeatmapSet/Info.cs | 4 +- osu.Game/Overlays/Direct/DirectGridPanel.cs | 10 +- osu.Game/Overlays/Direct/DirectListPanel.cs | 10 +- osu.Game/Overlays/Direct/FilterControl.cs | 2 +- osu.Game/Overlays/DirectOverlay.cs | 12 +-- .../KeyBinding/KeyBindingsSubsection.cs | 2 +- osu.Game/Overlays/Music/PlaylistItem.cs | 2 +- osu.Game/Overlays/Music/PlaylistList.cs | 4 +- osu.Game/Overlays/Music/PlaylistOverlay.cs | 2 +- osu.Game/Overlays/MusicController.cs | 4 +- .../Overlays/Toolbar/ToolbarModeSelector.cs | 2 +- osu.Game/Rulesets/RulesetInfo.cs | 11 +- osu.Game/Rulesets/RulesetStore.cs | 91 +++++++++------- osu.Game/Rulesets/Scoring/ScoreStore.cs | 3 +- osu.Game/Rulesets/UI/RulesetContainer.cs | 4 +- osu.Game/Screens/Menu/Intro.cs | 2 +- osu.Game/Screens/Multiplayer/DrawableRoom.cs | 6 +- osu.Game/Screens/Multiplayer/RoomInspector.cs | 8 +- osu.Game/Screens/Play/Player.cs | 6 +- osu.Game/Screens/Play/PlayerLoader.cs | 2 +- osu.Game/Screens/Ranking/ResultsPageScore.cs | 6 +- osu.Game/Screens/Select/BeatmapCarousel.cs | 12 +-- .../Screens/Select/BeatmapDeleteDialog.cs | 2 +- osu.Game/Screens/Select/BeatmapDetails.cs | 6 +- osu.Game/Screens/Select/BeatmapInfoWedge.cs | 4 +- .../Screens/Select/Details/AdvancedStats.cs | 12 +-- osu.Game/Screens/Select/FilterCriteria.cs | 10 +- .../Select/Leaderboards/Leaderboard.cs | 2 +- osu.Game/Screens/Select/SongSelect.cs | 4 +- osu.Game/Storyboards/Storyboard.cs | 2 +- osu.Game/Tests/Platform/TestStorage.cs | 17 +-- .../Tests/Visual/TestCaseBeatmapDetails.cs | 16 +-- .../Tests/Visual/TestCaseBeatmapSetOverlay.cs | 44 ++++---- osu.Game/Tests/Visual/TestCaseDirect.cs | 52 ++++----- osu.Game/Tests/Visual/TestCaseDrawableRoom.cs | 12 +-- .../Tests/Visual/TestCasePlaySongSelect.cs | 34 +++--- osu.Game/Tests/Visual/TestCasePlayer.cs | 7 +- osu.Game/Tests/Visual/TestCaseResults.cs | 2 +- .../Tests/Visual/TestCaseRoomInspector.cs | 12 +-- .../Visual/TestCaseScrollingPlayfield.cs | 4 +- osu.Game/osu.Game.csproj | 100 ++++++++++++++--- osu.Game/packages.config | 43 +++++++- 93 files changed, 730 insertions(+), 708 deletions(-) create mode 100644 osu.Game/Database/DbContextBase.cs create mode 100644 osu.Game/Database/OsuDbContext.cs delete mode 100644 osu.Game/Database/StoreVersion.cs diff --git a/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs b/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs index d7c86e1f89..713ee6bb44 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs @@ -43,7 +43,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps { beatmap = original; - BeatmapDifficulty difficulty = original.BeatmapInfo.Difficulty; + BeatmapDifficulty difficulty = original.BeatmapInfo.BeatmapDifficulty; int seed = (int)Math.Round(difficulty.DrainRate + difficulty.CircleSize) * 20 + (int)(difficulty.OverallDifficulty * 41.2) + (int)Math.Round(difficulty.ApproachRate); random = new FastRandom(seed); diff --git a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs index 20966a75f7..07a7c47f82 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs @@ -47,7 +47,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy // The true distance, accounting for any repeats double distance = (distanceData?.Distance ?? 0) * repeatCount; // The velocity of the osu! hit object - calculated as the velocity of a slider - double osuVelocity = osu_base_scoring_distance * beatmap.BeatmapInfo.Difficulty.SliderMultiplier * difficultyPoint.SpeedMultiplier / timingPoint.BeatLength; + double osuVelocity = osu_base_scoring_distance * beatmap.BeatmapInfo.BeatmapDifficulty.SliderMultiplier * difficultyPoint.SpeedMultiplier / timingPoint.BeatLength; // The duration of the osu! hit object double osuDuration = distance / osuVelocity; diff --git a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/PatternGenerator.cs b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/PatternGenerator.cs index a3173f9784..d3b743062d 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/PatternGenerator.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/PatternGenerator.cs @@ -104,7 +104,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy if (drainTime == 0) drainTime = 10000; - BeatmapDifficulty difficulty = Beatmap.BeatmapInfo.Difficulty; + BeatmapDifficulty difficulty = Beatmap.BeatmapInfo.BeatmapDifficulty; conversionDifficulty = ((difficulty.DrainRate + MathHelper.Clamp(difficulty.ApproachRate, 4, 7)) / 1.5 + Beatmap.HitObjects.Count / drainTime * 9f) / 38f * 5f / 1.15; conversionDifficulty = Math.Min(conversionDifficulty.Value, 12); diff --git a/osu.Game.Rulesets.Mania/ManiaDifficultyCalculator.cs b/osu.Game.Rulesets.Mania/ManiaDifficultyCalculator.cs index b98802db69..6a96bc0a7d 100644 --- a/osu.Game.Rulesets.Mania/ManiaDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Mania/ManiaDifficultyCalculator.cs @@ -21,6 +21,6 @@ namespace osu.Game.Rulesets.Mania return 0; } - protected override BeatmapConverter CreateBeatmapConverter() => new ManiaBeatmapConverter(true, (int)Math.Max(1, Math.Round(Beatmap.BeatmapInfo.Difficulty.CircleSize))); + protected override BeatmapConverter CreateBeatmapConverter() => new ManiaBeatmapConverter(true, (int)Math.Max(1, Math.Round(Beatmap.BeatmapInfo.BeatmapDifficulty.CircleSize))); } } diff --git a/osu.Game.Rulesets.Mania/Scoring/ManiaScoreProcessor.cs b/osu.Game.Rulesets.Mania/Scoring/ManiaScoreProcessor.cs index a200ba31e2..d6c076803d 100644 --- a/osu.Game.Rulesets.Mania/Scoring/ManiaScoreProcessor.cs +++ b/osu.Game.Rulesets.Mania/Scoring/ManiaScoreProcessor.cs @@ -100,7 +100,7 @@ namespace osu.Game.Rulesets.Mania.Scoring protected override void SimulateAutoplay(Beatmap beatmap) { - BeatmapDifficulty difficulty = beatmap.BeatmapInfo.Difficulty; + BeatmapDifficulty difficulty = beatmap.BeatmapInfo.BeatmapDifficulty; hpMultiplier = BeatmapDifficulty.DifficultyRange(difficulty.DrainRate, hp_multiplier_min, hp_multiplier_mid, hp_multiplier_max); hpMissMultiplier = BeatmapDifficulty.DifficultyRange(difficulty.DrainRate, hp_multiplier_miss_min, hp_multiplier_miss_mid, hp_multiplier_miss_max); diff --git a/osu.Game.Rulesets.Mania/UI/ManiaRulesetContainer.cs b/osu.Game.Rulesets.Mania/UI/ManiaRulesetContainer.cs index 3b49d81674..3858c60367 100644 --- a/osu.Game.Rulesets.Mania/UI/ManiaRulesetContainer.cs +++ b/osu.Game.Rulesets.Mania/UI/ManiaRulesetContainer.cs @@ -88,18 +88,18 @@ namespace osu.Game.Rulesets.Mania.UI protected override BeatmapConverter CreateBeatmapConverter() { if (IsForCurrentRuleset) - AvailableColumns = (int)Math.Max(1, Math.Round(WorkingBeatmap.BeatmapInfo.Difficulty.CircleSize)); + AvailableColumns = (int)Math.Max(1, Math.Round(WorkingBeatmap.BeatmapInfo.BeatmapDifficulty.CircleSize)); else { float percentSliderOrSpinner = (float)WorkingBeatmap.Beatmap.HitObjects.Count(h => h is IHasEndTime) / WorkingBeatmap.Beatmap.HitObjects.Count; if (percentSliderOrSpinner < 0.2) AvailableColumns = 7; - else if (percentSliderOrSpinner < 0.3 || Math.Round(WorkingBeatmap.BeatmapInfo.Difficulty.CircleSize) >= 5) - AvailableColumns = Math.Round(WorkingBeatmap.BeatmapInfo.Difficulty.OverallDifficulty) > 5 ? 7 : 6; + else if (percentSliderOrSpinner < 0.3 || Math.Round(WorkingBeatmap.BeatmapInfo.BeatmapDifficulty.CircleSize) >= 5) + AvailableColumns = Math.Round(WorkingBeatmap.BeatmapInfo.BeatmapDifficulty.OverallDifficulty) > 5 ? 7 : 6; else if (percentSliderOrSpinner > 0.6) - AvailableColumns = Math.Round(WorkingBeatmap.BeatmapInfo.Difficulty.OverallDifficulty) > 4 ? 5 : 4; + AvailableColumns = Math.Round(WorkingBeatmap.BeatmapInfo.BeatmapDifficulty.OverallDifficulty) > 4 ? 5 : 4; else - AvailableColumns = Math.Max(4, Math.Min((int)Math.Round(WorkingBeatmap.BeatmapInfo.Difficulty.OverallDifficulty) + 1, 7)); + AvailableColumns = Math.Max(4, Math.Min((int)Math.Round(WorkingBeatmap.BeatmapInfo.BeatmapDifficulty.OverallDifficulty) + 1, 7)); } return new ManiaBeatmapConverter(IsForCurrentRuleset, AvailableColumns); diff --git a/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs b/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs index 50239bf16c..b320940e67 100644 --- a/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs +++ b/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs @@ -28,7 +28,7 @@ namespace osu.Game.Rulesets.Osu.Scoring protected override void SimulateAutoplay(Beatmap beatmap) { - hpDrainRate = beatmap.BeatmapInfo.Difficulty.DrainRate; + hpDrainRate = beatmap.BeatmapInfo.BeatmapDifficulty.DrainRate; foreach (var obj in beatmap.HitObjects) { diff --git a/osu.Game.Rulesets.Osu/UI/Cursor/GameplayCursor.cs b/osu.Game.Rulesets.Osu/UI/Cursor/GameplayCursor.cs index adfc946f86..724a5f2b7a 100644 --- a/osu.Game.Rulesets.Osu/UI/Cursor/GameplayCursor.cs +++ b/osu.Game.Rulesets.Osu/UI/Cursor/GameplayCursor.cs @@ -125,7 +125,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor if (autoCursorScale && beatmap.Value != null) { // if we have a beatmap available, let's get its circle size to figure out an automatic cursor scale modifier. - scale *= (float)(1 - 0.7 * (1 + beatmap.Value.BeatmapInfo.Difficulty.CircleSize - BeatmapDifficulty.DEFAULT_DIFFICULTY) / BeatmapDifficulty.DEFAULT_DIFFICULTY); + scale *= (float)(1 - 0.7 * (1 + beatmap.Value.BeatmapInfo.BeatmapDifficulty.CircleSize - BeatmapDifficulty.DEFAULT_DIFFICULTY) / BeatmapDifficulty.DEFAULT_DIFFICULTY); } cursorContainer.Scale = new Vector2(scale); diff --git a/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs b/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs index 4f2707ff88..6a8f046800 100644 --- a/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs +++ b/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs @@ -51,7 +51,7 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps { // Rewrite the beatmap info to add the slider velocity multiplier BeatmapInfo info = original.BeatmapInfo.DeepClone(); - info.Difficulty.SliderMultiplier *= legacy_velocity_multiplier; + info.BeatmapDifficulty.SliderMultiplier *= legacy_velocity_multiplier; Beatmap converted = base.ConvertBeatmap(original); @@ -93,7 +93,7 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps double distance = distanceData.Distance * repeats * legacy_velocity_multiplier; // The velocity of the taiko hit object - calculated as the velocity of a drum roll - double taikoVelocity = taiko_base_distance * beatmap.BeatmapInfo.Difficulty.SliderMultiplier * legacy_velocity_multiplier / speedAdjustedBeatLength; + double taikoVelocity = taiko_base_distance * beatmap.BeatmapInfo.BeatmapDifficulty.SliderMultiplier * legacy_velocity_multiplier / speedAdjustedBeatLength; // The duration of the taiko hit object double taikoDuration = distance / taikoVelocity; @@ -103,12 +103,12 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps speedAdjustedBeatLength *= speedAdjustment; // The velocity of the osu! hit object - calculated as the velocity of a slider - double osuVelocity = osu_base_scoring_distance * beatmap.BeatmapInfo.Difficulty.SliderMultiplier * legacy_velocity_multiplier / speedAdjustedBeatLength; + double osuVelocity = osu_base_scoring_distance * beatmap.BeatmapInfo.BeatmapDifficulty.SliderMultiplier * legacy_velocity_multiplier / speedAdjustedBeatLength; // The duration of the osu! hit object double osuDuration = distance / osuVelocity; // If the drum roll is to be split into hit circles, assume the ticks are 1/8 spaced within the duration of one beat - double tickSpacing = Math.Min(speedAdjustedBeatLength / beatmap.BeatmapInfo.Difficulty.SliderTickRate, taikoDuration / repeats); + double tickSpacing = Math.Min(speedAdjustedBeatLength / beatmap.BeatmapInfo.BeatmapDifficulty.SliderTickRate, taikoDuration / repeats); if (!isForCurrentRuleset && tickSpacing > 0 && osuDuration < 2 * speedAdjustedBeatLength) { @@ -151,13 +151,13 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps Samples = obj.Samples, IsStrong = strong, Duration = taikoDuration, - TickRate = beatmap.BeatmapInfo.Difficulty.SliderTickRate == 3 ? 3 : 4, + TickRate = beatmap.BeatmapInfo.BeatmapDifficulty.SliderTickRate == 3 ? 3 : 4, }; } } else if (endTimeData != null) { - double hitMultiplier = BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.Difficulty.OverallDifficulty, 3, 5, 7.5) * swell_hit_multiplier; + double hitMultiplier = BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BeatmapDifficulty.OverallDifficulty, 3, 5, 7.5) * swell_hit_multiplier; yield return new Swell { diff --git a/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs b/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs index abdda9676f..9b208813dc 100644 --- a/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs +++ b/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs @@ -71,12 +71,12 @@ namespace osu.Game.Rulesets.Taiko.Scoring protected override void SimulateAutoplay(Beatmap beatmap) { - double hpMultiplierNormal = 1 / (hp_hit_great * beatmap.HitObjects.FindAll(o => o is Hit).Count * BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.Difficulty.DrainRate, 0.5, 0.75, 0.98)); + double hpMultiplierNormal = 1 / (hp_hit_great * beatmap.HitObjects.FindAll(o => o is Hit).Count * BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BeatmapDifficulty.DrainRate, 0.5, 0.75, 0.98)); hpIncreaseTick = hp_hit_tick; hpIncreaseGreat = hpMultiplierNormal * hp_hit_great; hpIncreaseGood = hpMultiplierNormal * hp_hit_good; - hpIncreaseMiss = BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.Difficulty.DrainRate, hp_miss_min, hp_miss_mid, hp_miss_max); + hpIncreaseMiss = BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BeatmapDifficulty.DrainRate, hp_miss_min, hp_miss_mid, hp_miss_max); foreach (var obj in beatmap.HitObjects) { diff --git a/osu.Game.Rulesets.Taiko/Tests/TestCaseTaikoPlayfield.cs b/osu.Game.Rulesets.Taiko/Tests/TestCaseTaikoPlayfield.cs index 79ee2945ad..8e93d52492 100644 --- a/osu.Game.Rulesets.Taiko/Tests/TestCaseTaikoPlayfield.cs +++ b/osu.Game.Rulesets.Taiko/Tests/TestCaseTaikoPlayfield.cs @@ -67,8 +67,8 @@ namespace osu.Game.Rulesets.Taiko.Tests HitObjects = new List { new CentreHit() }, BeatmapInfo = new BeatmapInfo { - Difficulty = new BeatmapDifficulty(), - Metadata = new BeatmapMetadata + BeatmapDifficulty = new BeatmapDifficulty(), + BeatmapMetadata = new BeatmapMetadata { Artist = @"Unknown", Title = @"Sample Beatmap", diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoRulesetContainer.cs b/osu.Game.Rulesets.Taiko/UI/TaikoRulesetContainer.cs index f0853aef0e..ca0a7e058f 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoRulesetContainer.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoRulesetContainer.cs @@ -63,7 +63,7 @@ namespace osu.Game.Rulesets.Taiko.UI StartTime = time, }; - barLine.ApplyDefaults(Beatmap.ControlPointInfo, Beatmap.BeatmapInfo.Difficulty); + barLine.ApplyDefaults(Beatmap.ControlPointInfo, Beatmap.BeatmapInfo.BeatmapDifficulty); bool isMajor = currentBeat % (int)currentPoint.TimeSignature == 0; Playfield.Add(isMajor ? new DrawableBarLineMajor(barLine) : new DrawableBarLine(barLine)); diff --git a/osu.Game.Tests/Beatmaps/Formats/OsuLegacyDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/OsuLegacyDecoderTest.cs index da3b448f74..4c71601eed 100644 --- a/osu.Game.Tests/Beatmaps/Formats/OsuLegacyDecoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/OsuLegacyDecoderTest.cs @@ -23,8 +23,8 @@ namespace osu.Game.Tests.Beatmaps.Formats using (var stream = Resource.OpenResource("Soleily - Renatus (Gamu) [Insane].osu")) { var beatmap = decoder.Decode(new StreamReader(stream)); - var meta = beatmap.BeatmapInfo.Metadata; - Assert.AreEqual(241526, meta.OnlineBeatmapSetID); + var meta = beatmap.BeatmapInfo.BeatmapMetadata; + Assert.AreEqual(241526, meta.BeatmapSetOnlineInfoId); Assert.AreEqual("Soleily", meta.Artist); Assert.AreEqual("Soleily", meta.ArtistUnicode); Assert.AreEqual("03. Renatus - Soleily 192kbps.mp3", meta.AudioFile); @@ -49,7 +49,7 @@ namespace osu.Game.Tests.Beatmaps.Formats Assert.AreEqual(false, beatmapInfo.Countdown); Assert.AreEqual(0.7f, beatmapInfo.StackLeniency); Assert.AreEqual(false, beatmapInfo.SpecialStyle); - Assert.IsTrue(beatmapInfo.RulesetID == 0); + Assert.IsTrue(beatmapInfo.RulesetInfoId == 0); Assert.AreEqual(false, beatmapInfo.LetterboxInBreaks); Assert.AreEqual(false, beatmapInfo.WidescreenStoryboard); } @@ -85,7 +85,7 @@ namespace osu.Game.Tests.Beatmaps.Formats using (var stream = Resource.OpenResource("Soleily - Renatus (Gamu) [Insane].osu")) { var beatmap = decoder.Decode(new StreamReader(stream)); - var difficulty = beatmap.BeatmapInfo.Difficulty; + var difficulty = beatmap.BeatmapInfo.BeatmapDifficulty; Assert.AreEqual(6.5f, difficulty.DrainRate); Assert.AreEqual(4, difficulty.CircleSize); Assert.AreEqual(8, difficulty.OverallDifficulty); diff --git a/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs b/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs index 35bebf2d4f..4b704fe242 100644 --- a/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs +++ b/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs @@ -111,7 +111,7 @@ namespace osu.Game.Tests.Beatmaps.IO var store = osu.Dependencies.Get(); - waitForOrAssert(() => (resultSets = store.QueryBeatmapSets(s => s.OnlineBeatmapSetID == 241526)).Any(), + waitForOrAssert(() => (resultSets = store.QueryBeatmapSets(s => s.BeatmapSetOnlineInfoId == 241526)).Any(), @"BeatmapSet did not import to the database in allocated time.", timeout); //ensure we were stored to beatmap database backing... @@ -120,29 +120,29 @@ namespace osu.Game.Tests.Beatmaps.IO IEnumerable resultBeatmaps = null; //if we don't re-check here, the set will be inserted but the beatmaps won't be present yet. - waitForOrAssert(() => (resultBeatmaps = store.QueryBeatmaps(s => s.OnlineBeatmapSetID == 241526 && s.BaseDifficultyID > 0)).Count() == 12, + waitForOrAssert(() => (resultBeatmaps = store.QueryBeatmaps(s => s.BeatmapSetOnlineInfoId == 241526 && s.BeatmapDifficultyId > 0)).Count() == 12, @"Beatmaps did not import to the database in allocated time", timeout); - var set = store.QueryBeatmapSets(s => s.OnlineBeatmapSetID == 241526).First(); + var set = store.QueryBeatmapSets(s => s.BeatmapSetOnlineInfoId == 241526).First(); Assert.IsTrue(set.Beatmaps.Count == resultBeatmaps.Count(), $@"Incorrect database beatmap count post-import ({resultBeatmaps.Count()} but should be {set.Beatmaps.Count})."); foreach (BeatmapInfo b in resultBeatmaps) - Assert.IsTrue(set.Beatmaps.Any(c => c.OnlineBeatmapID == b.OnlineBeatmapID)); + Assert.IsTrue(set.Beatmaps.Any(c => c.BeatmapOnlineInfoId == b.BeatmapOnlineInfoId)); Assert.IsTrue(set.Beatmaps.Count > 0); - var beatmap = store.GetWorkingBeatmap(set.Beatmaps.First(b => b.RulesetID == 0))?.Beatmap; + var beatmap = store.GetWorkingBeatmap(set.Beatmaps.First(b => b.RulesetInfoId == 0))?.Beatmap; Assert.IsTrue(beatmap?.HitObjects.Count > 0); - beatmap = store.GetWorkingBeatmap(set.Beatmaps.First(b => b.RulesetID == 1))?.Beatmap; + beatmap = store.GetWorkingBeatmap(set.Beatmaps.First(b => b.RulesetInfoId == 1))?.Beatmap; Assert.IsTrue(beatmap?.HitObjects.Count > 0); - beatmap = store.GetWorkingBeatmap(set.Beatmaps.First(b => b.RulesetID == 2))?.Beatmap; + beatmap = store.GetWorkingBeatmap(set.Beatmaps.First(b => b.RulesetInfoId == 2))?.Beatmap; Assert.IsTrue(beatmap?.HitObjects.Count > 0); - beatmap = store.GetWorkingBeatmap(set.Beatmaps.First(b => b.RulesetID == 3))?.Beatmap; + beatmap = store.GetWorkingBeatmap(set.Beatmaps.First(b => b.RulesetInfoId == 3))?.Beatmap; Assert.IsTrue(beatmap?.HitObjects.Count > 0); } diff --git a/osu.Game.Tests/Beatmaps/IO/OszArchiveReaderTest.cs b/osu.Game.Tests/Beatmaps/IO/OszArchiveReaderTest.cs index 7a7a8a58bc..9ca3089944 100644 --- a/osu.Game.Tests/Beatmaps/IO/OszArchiveReaderTest.cs +++ b/osu.Game.Tests/Beatmaps/IO/OszArchiveReaderTest.cs @@ -52,7 +52,7 @@ namespace osu.Game.Tests.Beatmaps.IO using (var stream = new StreamReader(reader.GetStream("Soleily - Renatus (Deif) [Platter].osu"))) meta = BeatmapDecoder.GetDecoder(stream).Decode(stream).Metadata; - Assert.AreEqual(241526, meta.OnlineBeatmapSetID); + Assert.AreEqual(241526, meta.BeatmapSetOnlineInfoId); Assert.AreEqual("Soleily", meta.Artist); Assert.AreEqual("Soleily", meta.ArtistUnicode); Assert.AreEqual("03. Renatus - Soleily 192kbps.mp3", meta.AudioFile); diff --git a/osu.Game.Tests/app.config b/osu.Game.Tests/app.config index faeaf001de..11af32e2cf 100644 --- a/osu.Game.Tests/app.config +++ b/osu.Game.Tests/app.config @@ -6,6 +6,10 @@ + + + + \ 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 8ebd38022e..e188c82e79 100644 --- a/osu.Game.Tests/osu.Game.Tests.csproj +++ b/osu.Game.Tests/osu.Game.Tests.csproj @@ -39,15 +39,6 @@ True - - $(SolutionDir)\packages\SQLite.Net.Core-PCL.3.1.1\lib\portable-win8+net45+wp8+wpa81+MonoAndroid1+MonoTouch1\SQLite.Net.dll - - - $(SolutionDir)\packages\SQLite.Net-PCL.3.1.1\lib\net4\SQLite.Net.Platform.Win32.dll - - - $(SolutionDir)\packages\SQLite.Net-PCL.3.1.1\lib\net40\SQLite.Net.Platform.Generic.dll - diff --git a/osu.Game.Tests/packages.config b/osu.Game.Tests/packages.config index af47f642e3..b94c0c6e2d 100644 --- a/osu.Game.Tests/packages.config +++ b/osu.Game.Tests/packages.config @@ -6,6 +6,4 @@ Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/maste - - \ No newline at end of file diff --git a/osu.Game/Beatmaps/Beatmap.cs b/osu.Game/Beatmaps/Beatmap.cs index 458c2304f2..0d6cd6f49a 100644 --- a/osu.Game/Beatmaps/Beatmap.cs +++ b/osu.Game/Beatmaps/Beatmap.cs @@ -29,7 +29,7 @@ namespace osu.Game.Beatmaps new Color4(121, 9, 13, 255) }; - public BeatmapMetadata Metadata => BeatmapInfo?.Metadata ?? BeatmapInfo?.BeatmapSet?.Metadata; + public BeatmapMetadata Metadata => BeatmapInfo?.BeatmapMetadata ?? BeatmapInfo?.BeatmapSetInfo?.BeatmapMetadata; /// /// The HitObjects this Beatmap contains. diff --git a/osu.Game/Beatmaps/BeatmapDifficulty.cs b/osu.Game/Beatmaps/BeatmapDifficulty.cs index 7c2294cae9..e354f3703e 100644 --- a/osu.Game/Beatmaps/BeatmapDifficulty.cs +++ b/osu.Game/Beatmaps/BeatmapDifficulty.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 SQLite.Net.Attributes; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; namespace osu.Game.Beatmaps { @@ -12,8 +13,8 @@ namespace osu.Game.Beatmaps /// public const float DEFAULT_DIFFICULTY = 5; - [PrimaryKey, AutoIncrement] - public int ID { get; set; } + [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public int Id { get; set; } public float DrainRate { get; set; } = DEFAULT_DIFFICULTY; public float CircleSize { get; set; } = DEFAULT_DIFFICULTY; public float OverallDifficulty { get; set; } = DEFAULT_DIFFICULTY; diff --git a/osu.Game/Beatmaps/BeatmapInfo.cs b/osu.Game/Beatmaps/BeatmapInfo.cs index 5e4e122fb5..565e1b97d6 100644 --- a/osu.Game/Beatmaps/BeatmapInfo.cs +++ b/osu.Game/Beatmaps/BeatmapInfo.cs @@ -2,49 +2,43 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; using System.Linq; using Newtonsoft.Json; using osu.Game.IO.Serialization; using osu.Game.Rulesets; -using SQLite.Net.Attributes; -using SQLiteNetExtensions.Attributes; namespace osu.Game.Beatmaps { public class BeatmapInfo : IEquatable, IJsonSerializable { - [PrimaryKey, AutoIncrement] - public int ID { get; set; } + [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public int Id { get; set; } //TODO: should be in database public int BeatmapVersion; - public int? OnlineBeatmapID { get; set; } + public int? BeatmapOnlineInfoId { get; set; } - public int? OnlineBeatmapSetID { get; set; } + public int? BeatmapSetOnlineInfoId { get; set; } - [ForeignKey(typeof(BeatmapSetInfo))] - public int BeatmapSetInfoID { get; set; } + [ForeignKey(nameof(BeatmapSetInfo))] + public int BeatmapSetInfoId { get; set; } + public BeatmapSetInfo BeatmapSetInfo { get; set; } - [ManyToOne] - public BeatmapSetInfo BeatmapSet { get; set; } + [ForeignKey(nameof(BeatmapMetadata))] + public int BeatmapMetadataId { get; set; } + public BeatmapMetadata BeatmapMetadata { get; set; } - [ForeignKey(typeof(BeatmapMetadata))] - public int BeatmapMetadataID { get; set; } + [ForeignKey(nameof(BeatmapDifficulty))] + public int BeatmapDifficultyId { get; set; } + public BeatmapDifficulty BeatmapDifficulty { get; set; } - [OneToOne(CascadeOperations = CascadeOperation.All)] - public BeatmapMetadata Metadata { get; set; } - - [ForeignKey(typeof(BeatmapDifficulty)), NotNull] - public int BaseDifficultyID { get; set; } - - [OneToOne(CascadeOperations = CascadeOperation.All)] - public BeatmapDifficulty Difficulty { get; set; } - - [Ignore] + [NotMapped] public BeatmapMetrics Metrics { get; set; } - [Ignore] + [NotMapped] public BeatmapOnlineInfo OnlineInfo { get; set; } public string Path { get; set; } @@ -57,7 +51,6 @@ namespace osu.Game.Beatmaps /// /// MD5 is kept for legacy support (matching against replays, osu-web-10 etc.). /// - [Indexed] [JsonProperty("file_md5")] public string MD5Hash { get; set; } @@ -67,11 +60,9 @@ namespace osu.Game.Beatmaps public float StackLeniency { get; set; } public bool SpecialStyle { get; set; } - [ForeignKey(typeof(RulesetInfo))] - public int RulesetID { get; set; } - - [OneToOne(CascadeOperations = CascadeOperation.CascadeRead)] - public RulesetInfo Ruleset { get; set; } + [ForeignKey(nameof(RulesetInfo))] + public int RulesetInfoId { get; set; } + public RulesetInfo RulesetInfo { get; set; } public bool LetterboxInBreaks { get; set; } public bool WidescreenStoryboard { get; set; } @@ -99,7 +90,7 @@ namespace osu.Game.Beatmaps } } - [Ignore] + [NotMapped] public int[] Bookmarks { get; set; } = new int[0]; public double DistanceSpacing { get; set; } @@ -114,20 +105,20 @@ namespace osu.Game.Beatmaps public bool Equals(BeatmapInfo other) { - if (ID == 0 || other?.ID == 0) + if (Id == 0 || other?.Id == 0) // one of the two BeatmapInfos we are comparing isn't sourced from a database. // fall back to reference equality. return ReferenceEquals(this, other); - return ID == other?.ID; + return Id == other?.Id; } - public bool AudioEquals(BeatmapInfo other) => other != null && BeatmapSet != null && other.BeatmapSet != null && - BeatmapSet.Hash == other.BeatmapSet.Hash && - (Metadata ?? BeatmapSet.Metadata).AudioFile == (other.Metadata ?? other.BeatmapSet.Metadata).AudioFile; + public bool AudioEquals(BeatmapInfo other) => other != null && BeatmapSetInfo != null && other.BeatmapSetInfo != null && + BeatmapSetInfo.Hash == other.BeatmapSetInfo.Hash && + (BeatmapMetadata ?? BeatmapSetInfo.BeatmapMetadata).AudioFile == (other.BeatmapMetadata ?? other.BeatmapSetInfo.BeatmapMetadata).AudioFile; - public bool BackgroundEquals(BeatmapInfo other) => other != null && BeatmapSet != null && other.BeatmapSet != null && - BeatmapSet.Hash == other.BeatmapSet.Hash && - (Metadata ?? BeatmapSet.Metadata).BackgroundFile == (other.Metadata ?? other.BeatmapSet.Metadata).BackgroundFile; + public bool BackgroundEquals(BeatmapInfo other) => other != null && BeatmapSetInfo != null && other.BeatmapSetInfo != null && + BeatmapSetInfo.Hash == other.BeatmapSetInfo.Hash && + (BeatmapMetadata ?? BeatmapSetInfo.BeatmapMetadata).BackgroundFile == (other.BeatmapMetadata ?? other.BeatmapSetInfo.BeatmapMetadata).BackgroundFile; } } diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index a1b678392b..3b023e34e4 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -19,9 +19,9 @@ using osu.Game.IO; using osu.Game.IPC; using osu.Game.Overlays.Notifications; using osu.Game.Rulesets; -using SQLite.Net; using osu.Game.Online.API.Requests; using System.Threading.Tasks; +using osu.Game.Database; using osu.Game.Online.API; namespace osu.Game.Beatmaps @@ -60,7 +60,7 @@ namespace osu.Game.Beatmaps private readonly FileStore files; - private readonly SQLiteConnection connection; + private readonly OsuDbContext connection; private readonly RulesetStore rulesets; @@ -83,7 +83,7 @@ namespace osu.Game.Beatmaps /// public Func GetStableStorage { private get; set; } - public BeatmapManager(Storage storage, FileStore files, SQLiteConnection connection, RulesetStore rulesets, APIAccess api, IIpcHost importHost = null) + public BeatmapManager(Storage storage, FileStore files, OsuDbContext connection, RulesetStore rulesets, APIAccess api, IIpcHost importHost = null) { beatmaps = new BeatmapStore(connection); beatmaps.BeatmapSetAdded += s => BeatmapSetAdded?.Invoke(s); @@ -168,7 +168,7 @@ namespace osu.Game.Beatmaps // let's only allow one concurrent import at a time for now. lock (importLock) - connection.RunInTransaction(() => Import(set = importToStorage(archiveReader))); + Import(set = importToStorage(archiveReader)); return set; } @@ -180,7 +180,7 @@ namespace osu.Game.Beatmaps public void Import(BeatmapSetInfo beatmapSetInfo) { // If we have an ID then we already exist in the database. - if (beatmapSetInfo.ID != 0) return; + if (beatmapSetInfo.Id != 0) return; beatmaps.Add(beatmapSetInfo); } @@ -200,7 +200,7 @@ namespace osu.Game.Beatmaps ProgressNotification downloadNotification = new ProgressNotification { - Text = $"Downloading {beatmapSetInfo.Metadata.Artist} - {beatmapSetInfo.Metadata.Title}", + Text = $"Downloading {beatmapSetInfo.BeatmapMetadata.Artist} - {beatmapSetInfo.BeatmapMetadata.Title}", }; var request = new DownloadBeatmapSetRequest(beatmapSetInfo); @@ -251,7 +251,7 @@ namespace osu.Game.Beatmaps /// /// The whose download request is wanted. /// The object if it exists, or null. - public DownloadBeatmapSetRequest GetExistingDownload(BeatmapSetInfo beatmap) => currentDownloads.Find(d => d.BeatmapSet.OnlineBeatmapSetID == beatmap.OnlineBeatmapSetID); + public DownloadBeatmapSetRequest GetExistingDownload(BeatmapSetInfo beatmap) => currentDownloads.Find(d => d.BeatmapSet.BeatmapSetOnlineInfoId == beatmap.BeatmapSetOnlineInfoId); /// /// Delete a beatmap from the manager. @@ -302,14 +302,15 @@ namespace osu.Game.Beatmaps if (beatmapInfo == null || beatmapInfo == DefaultBeatmap?.BeatmapInfo) return DefaultBeatmap; - lock (beatmaps) - beatmaps.Populate(beatmapInfo); + // TODO Include() + //lock (beatmaps) + // beatmaps.Populate(beatmapInfo); - if (beatmapInfo.BeatmapSet == null) - throw new InvalidOperationException($@"Beatmap set {beatmapInfo.BeatmapSetInfoID} is not in the local database."); + if (beatmapInfo.BeatmapSetInfo == null) + throw new InvalidOperationException($@"Beatmap set {beatmapInfo.BeatmapSetInfoId} is not in the local database."); - if (beatmapInfo.Metadata == null) - beatmapInfo.Metadata = beatmapInfo.BeatmapSet.Metadata; + if (beatmapInfo.BeatmapMetadata == null) + beatmapInfo.BeatmapMetadata = beatmapInfo.BeatmapSetInfo.BeatmapMetadata; WorkingBeatmap working = new BeatmapManagerWorkingBeatmap(files.Store, beatmapInfo); @@ -336,10 +337,11 @@ namespace osu.Game.Beatmaps { lock (beatmaps) { - BeatmapSetInfo set = beatmaps.Query().FirstOrDefault(query); + BeatmapSetInfo set = beatmaps.QueryBeatmapSet(query); - if (set != null) - beatmaps.Populate(set); + // TODO Include() + //if (set != null) + // beatmaps.Populate(set); return set; } @@ -350,7 +352,7 @@ namespace osu.Game.Beatmaps /// /// A stale instance. /// A fresh instance. - public BeatmapSetInfo Refresh(BeatmapSetInfo beatmapSet) => QueryBeatmapSet(s => s.ID == beatmapSet.ID); + public BeatmapSetInfo Refresh(BeatmapSetInfo beatmapSet) => QueryBeatmapSet(s => s.Id == beatmapSet.Id); /// /// Perform a lookup query on available s. @@ -359,7 +361,7 @@ namespace osu.Game.Beatmaps /// Results from the provided query. public List QueryBeatmapSets(Expression> query) { - return beatmaps.QueryAndPopulate(query); + return beatmaps.QueryBeatmapSets(query); } /// @@ -369,10 +371,11 @@ namespace osu.Game.Beatmaps /// The first result for the provided query, or null if no results were found. public BeatmapInfo QueryBeatmap(Func query) { - BeatmapInfo set = beatmaps.Query().FirstOrDefault(query); + BeatmapInfo set = beatmaps.QueryBeatmap(query); - if (set != null) - beatmaps.Populate(set); + // TODO Include() + //if (set != null) + // beatmaps.Populate(set); return set; } @@ -384,7 +387,7 @@ namespace osu.Game.Beatmaps /// Results from the provided query. public List QueryBeatmaps(Expression> query) { - lock (beatmaps) return beatmaps.QueryAndPopulate(query); + lock (beatmaps) return beatmaps.QueryBeatmaps(query); } /// @@ -424,7 +427,7 @@ namespace osu.Game.Beatmaps // check if this beatmap has already been imported and exit early if so. BeatmapSetInfo beatmapSet; lock (beatmaps) - beatmapSet = beatmaps.QueryAndPopulate(b => b.Hash == hash).FirstOrDefault(); + beatmapSet = beatmaps.QueryBeatmapSet(b => b.Hash == hash); if (beatmapSet != null) { @@ -459,11 +462,11 @@ namespace osu.Game.Beatmaps beatmapSet = new BeatmapSetInfo { - OnlineBeatmapSetID = metadata.OnlineBeatmapSetID, + BeatmapSetOnlineInfoId = metadata.BeatmapSetOnlineInfoId, Beatmaps = new List(), Hash = hash, Files = fileInfos, - Metadata = metadata + BeatmapMetadata = metadata }; var mapNames = reader.Filenames.Where(f => f.EndsWith(".osu")); @@ -485,11 +488,11 @@ namespace osu.Game.Beatmaps beatmap.BeatmapInfo.MD5Hash = ms.ComputeMD5Hash(); // TODO: Diff beatmap metadata with set metadata and leave it here if necessary - beatmap.BeatmapInfo.Metadata = null; + beatmap.BeatmapInfo.BeatmapMetadata = null; // TODO: this should be done in a better place once we actually need to dynamically update it. - beatmap.BeatmapInfo.Ruleset = rulesets.Query().FirstOrDefault(r => r.ID == beatmap.BeatmapInfo.RulesetID); - beatmap.BeatmapInfo.StarDifficulty = rulesets.Query().FirstOrDefault(r => r.ID == beatmap.BeatmapInfo.RulesetID)?.CreateInstance()?.CreateDifficultyCalculator(beatmap) + beatmap.BeatmapInfo.RulesetInfo = rulesets.QueryRulesetInfo(r => r.Id == beatmap.BeatmapInfo.RulesetInfoId); + beatmap.BeatmapInfo.StarDifficulty = rulesets.QueryRulesetInfo(r => r.Id == beatmap.BeatmapInfo.RulesetInfoId)?.CreateInstance()?.CreateDifficultyCalculator(beatmap) .Calculate() ?? 0; beatmapSet.Beatmaps.Add(beatmap.BeatmapInfo); @@ -509,9 +512,9 @@ namespace osu.Game.Beatmaps lock (beatmaps) { if (populate) - return beatmaps.QueryAndPopulate(b => !b.DeletePending).ToList(); + return beatmaps.QueryBeatmapSets(b => !b.DeletePending); else - return beatmaps.Query(b => !b.DeletePending).ToList(); + return beatmaps.QueryBeatmapSets(b => !b.DeletePending); } } diff --git a/osu.Game/Beatmaps/BeatmapMetadata.cs b/osu.Game/Beatmaps/BeatmapMetadata.cs index cc9a51b4e2..8266dc9161 100644 --- a/osu.Game/Beatmaps/BeatmapMetadata.cs +++ b/osu.Game/Beatmaps/BeatmapMetadata.cs @@ -1,18 +1,19 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; using System.Linq; using Newtonsoft.Json; -using SQLite.Net.Attributes; namespace osu.Game.Beatmaps { public class BeatmapMetadata { - [PrimaryKey, AutoIncrement] - public int ID { get; set; } + [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public int Id { get; set; } - public int? OnlineBeatmapSetID { get; set; } + public int? BeatmapSetOnlineInfoId { get; set; } public string Title { get; set; } public string TitleUnicode { get; set; } diff --git a/osu.Game/Beatmaps/BeatmapOnlineInfo.cs b/osu.Game/Beatmaps/BeatmapOnlineInfo.cs index 399cabda99..2264a4fc1a 100644 --- a/osu.Game/Beatmaps/BeatmapOnlineInfo.cs +++ b/osu.Game/Beatmaps/BeatmapOnlineInfo.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.ComponentModel.DataAnnotations.Schema; using Newtonsoft.Json; namespace osu.Game.Beatmaps @@ -10,6 +11,9 @@ namespace osu.Game.Beatmaps /// public class BeatmapOnlineInfo { + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public int Id { get; set; } + /// /// The length in milliseconds of this beatmap's song. /// diff --git a/osu.Game/Beatmaps/BeatmapSetFileInfo.cs b/osu.Game/Beatmaps/BeatmapSetFileInfo.cs index a05362b32d..aec87296a0 100644 --- a/osu.Game/Beatmaps/BeatmapSetFileInfo.cs +++ b/osu.Game/Beatmaps/BeatmapSetFileInfo.cs @@ -1,27 +1,26 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; using osu.Game.IO; -using SQLite.Net.Attributes; -using SQLiteNetExtensions.Attributes; namespace osu.Game.Beatmaps { public class BeatmapSetFileInfo { - [PrimaryKey, AutoIncrement] + [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int ID { get; set; } - [ForeignKey(typeof(BeatmapSetInfo)), NotNull] - public int BeatmapSetInfoID { get; set; } + [ForeignKey(nameof(BeatmapSetInfo))] + public int BeatmapSetInfoId { get; set; } + public BeatmapSetInfo BeatmapSetInfo { get; set; } - [ForeignKey(typeof(FileInfo)), NotNull] - public int FileInfoID { get; set; } - - [OneToOne(CascadeOperations = CascadeOperation.CascadeRead)] + [ForeignKey(nameof(FileInfo))] + public int FileInfoId { get; set; } public FileInfo FileInfo { get; set; } - [NotNull] + [Required] public string Filename { get; set; } } -} \ No newline at end of file +} diff --git a/osu.Game/Beatmaps/BeatmapSetInfo.cs b/osu.Game/Beatmaps/BeatmapSetInfo.cs index f47affcab8..9be00152c3 100644 --- a/osu.Game/Beatmaps/BeatmapSetInfo.cs +++ b/osu.Game/Beatmaps/BeatmapSetInfo.cs @@ -2,41 +2,36 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; using System.Linq; -using SQLite.Net.Attributes; -using SQLiteNetExtensions.Attributes; namespace osu.Game.Beatmaps { public class BeatmapSetInfo { - [PrimaryKey, AutoIncrement] - public int ID { get; set; } + [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public int Id { get; set; } - public int? OnlineBeatmapSetID { get; set; } + public int? BeatmapSetOnlineInfoId { get; set; } - [OneToOne(CascadeOperations = CascadeOperation.All)] - public BeatmapMetadata Metadata { get; set; } + [ForeignKey(nameof(BeatmapMetadata))] + public int BeatmapMetadataId { get; set; } + public BeatmapMetadata BeatmapMetadata { get; set; } - [NotNull, ForeignKey(typeof(BeatmapMetadata))] - public int BeatmapMetadataID { get; set; } - - [OneToMany(CascadeOperations = CascadeOperation.All)] public List Beatmaps { get; set; } - [Ignore] + [NotMapped] public BeatmapSetOnlineInfo OnlineInfo { get; set; } public double MaxStarDifficulty => Beatmaps.Max(b => b.StarDifficulty); - [Indexed] public bool DeletePending { get; set; } public string Hash { get; set; } public string StoryboardFile => Files.FirstOrDefault(f => f.Filename.EndsWith(".osb"))?.Filename; - [OneToMany(CascadeOperations = CascadeOperation.All)] public List Files { get; set; } public bool Protected { get; set; } diff --git a/osu.Game/Beatmaps/BeatmapSetOnlineInfo.cs b/osu.Game/Beatmaps/BeatmapSetOnlineInfo.cs index 6b59f0f298..c33ee66dac 100644 --- a/osu.Game/Beatmaps/BeatmapSetOnlineInfo.cs +++ b/osu.Game/Beatmaps/BeatmapSetOnlineInfo.cs @@ -2,6 +2,9 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; using Newtonsoft.Json; using osu.Game.Users; @@ -12,11 +15,19 @@ namespace osu.Game.Beatmaps /// public class BeatmapSetOnlineInfo { + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public int Id { get; set; } + /// /// The author of the beatmaps in this set. /// public User Author; + public int BeatmapSetInfoId { get; set; } + public BeatmapSetInfo BeatmapSetInfo { get; set; } + + public List Beatmaps { get; set; } + /// /// The date this beatmap set was submitted to the online listing. /// @@ -35,7 +46,7 @@ namespace osu.Game.Beatmaps /// /// The different sizes of cover art for this beatmap set. /// - [JsonProperty(@"covers")] + [Required, JsonProperty(@"covers")] public BeatmapSetOnlineCovers Covers { get; set; } /// @@ -64,6 +75,9 @@ namespace osu.Game.Beatmaps public class BeatmapSetOnlineCovers { + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public int Id { get; set; } + public string CoverLowRes { get; set; } [JsonProperty(@"cover@2x")] diff --git a/osu.Game/Beatmaps/BeatmapStore.cs b/osu.Game/Beatmaps/BeatmapStore.cs index 0f2d8cffa6..ece006a818 100644 --- a/osu.Game/Beatmaps/BeatmapStore.cs +++ b/osu.Game/Beatmaps/BeatmapStore.cs @@ -2,9 +2,11 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using Microsoft.EntityFrameworkCore; using osu.Game.Database; -using SQLite.Net; -using SQLiteNetExtensions.Extensions; namespace osu.Game.Beatmaps { @@ -19,13 +21,7 @@ namespace osu.Game.Beatmaps public event Action BeatmapHidden; public event Action BeatmapRestored; - /// - /// The current version of this store. Used for migrations (see ). - /// The initial version is 1. - /// - protected override int StoreVersion => 4; - - public BeatmapStore(SQLiteConnection connection) + public BeatmapStore(OsuDbContext connection) : base(connection) { } @@ -42,18 +38,13 @@ namespace osu.Game.Beatmaps { if (reset) { - Connection.DropTable(); - Connection.DropTable(); - Connection.DropTable(); - Connection.DropTable(); - Connection.DropTable(); + // https://stackoverflow.com/a/10450893 + Connection.Database.ExecuteSqlCommand("DELETE FROM BeatmapMetadata"); + Connection.Database.ExecuteSqlCommand("DELETE FROM BeatmapDifficulty"); + Connection.Database.ExecuteSqlCommand("DELETE FROM BeatmapSetInfo"); + Connection.Database.ExecuteSqlCommand("DELETE FROM BeatmapSetFileInfo"); + Connection.Database.ExecuteSqlCommand("DELETE FROM BeatmapInfo"); } - - Connection.CreateTable(); - Connection.CreateTable(); - Connection.CreateTable(); - Connection.CreateTable(); - Connection.CreateTable(); } protected override void StartupTasks() @@ -62,46 +53,14 @@ namespace osu.Game.Beatmaps cleanupPendingDeletions(); } - /// - /// Perform migrations between two store versions. - /// - /// The current store version. This will be zero on a fresh database initialisation. - /// The target version which we are migrating to (equal to the current ). - protected override void PerformMigration(int currentVersion, int targetVersion) - { - base.PerformMigration(currentVersion, targetVersion); - - while (currentVersion++ < targetVersion) - { - switch (currentVersion) - { - case 1: - case 2: - // cannot migrate; breaking underlying changes. - Reset(); - break; - case 3: - // Added MD5Hash column to BeatmapInfo - Connection.MigrateTable(); - break; - case 4: - // Added Hidden column to BeatmapInfo - Connection.MigrateTable(); - break; - } - } - } - /// /// Add a to the database. /// /// The beatmap to add. public void Add(BeatmapSetInfo beatmapSet) { - Connection.RunInTransaction(() => - { - Connection.InsertOrReplaceWithChildren(beatmapSet, true); - }); + Connection.BeatmapSetInfo.Update(beatmapSet); + Connection.SaveChanges(); BeatmapSetAdded?.Invoke(beatmapSet); } @@ -116,7 +75,8 @@ namespace osu.Game.Beatmaps if (beatmapSet.DeletePending) return false; beatmapSet.DeletePending = true; - Connection.Update(beatmapSet); + Connection.BeatmapSetInfo.Remove(beatmapSet); + Connection.SaveChanges(); BeatmapSetRemoved?.Invoke(beatmapSet); return true; @@ -132,7 +92,7 @@ namespace osu.Game.Beatmaps if (!beatmapSet.DeletePending) return false; beatmapSet.DeletePending = false; - Connection.Update(beatmapSet); + Connection.BeatmapSetInfo.Update(beatmapSet); BeatmapSetAdded?.Invoke(beatmapSet); return true; @@ -148,7 +108,7 @@ namespace osu.Game.Beatmaps if (beatmap.Hidden) return false; beatmap.Hidden = true; - Connection.Update(beatmap); + Connection.BeatmapInfo.Update(beatmap); BeatmapHidden?.Invoke(beatmap); return true; @@ -164,7 +124,7 @@ namespace osu.Game.Beatmaps if (!beatmap.Hidden) return false; beatmap.Hidden = false; - Connection.Update(beatmap); + Connection.BeatmapInfo.Update(beatmap); BeatmapRestored?.Invoke(beatmap); return true; @@ -172,11 +132,27 @@ namespace osu.Game.Beatmaps private void cleanupPendingDeletions() { - Connection.RunInTransaction(() => - { - foreach (var b in QueryAndPopulate(b => b.DeletePending && !b.Protected)) - Connection.Delete(b, true); - }); + Connection.BeatmapSetInfo.RemoveRange(Connection.BeatmapSetInfo.Where(b => b.DeletePending && !b.Protected)); + } + + public BeatmapSetInfo QueryBeatmapSet(Func query) + { + return Connection.BeatmapSetInfo.FirstOrDefault(query); + } + + public List QueryBeatmapSets(Expression> query) + { + return Connection.BeatmapSetInfo.Where(query).ToList(); + } + + public BeatmapInfo QueryBeatmap(Func query) + { + return Connection.BeatmapInfo.FirstOrDefault(query); + } + + public List QueryBeatmaps(Expression> query) + { + return Connection.BeatmapInfo.Where(query).ToList(); } } } diff --git a/osu.Game/Beatmaps/DifficultyCalculator.cs b/osu.Game/Beatmaps/DifficultyCalculator.cs index 60cbf0ac61..1cd0516b0e 100644 --- a/osu.Game/Beatmaps/DifficultyCalculator.cs +++ b/osu.Game/Beatmaps/DifficultyCalculator.cs @@ -40,7 +40,7 @@ namespace osu.Game.Beatmaps Objects = CreateBeatmapConverter().Convert(beatmap).HitObjects; foreach (var h in Objects) - h.ApplyDefaults(beatmap.ControlPointInfo, beatmap.BeatmapInfo.Difficulty); + h.ApplyDefaults(beatmap.ControlPointInfo, beatmap.BeatmapInfo.BeatmapDifficulty); PreprocessHitObjects(); } diff --git a/osu.Game/Beatmaps/Drawables/BeatmapPanel.cs b/osu.Game/Beatmaps/Drawables/BeatmapPanel.cs index e216f1b83e..dfff949fe9 100644 --- a/osu.Game/Beatmaps/Drawables/BeatmapPanel.cs +++ b/osu.Game/Beatmaps/Drawables/BeatmapPanel.cs @@ -135,7 +135,7 @@ namespace osu.Game.Beatmaps.Drawables new OsuSpriteText { Font = @"Exo2.0-MediumItalic", - Text = $"{(beatmap.Metadata ?? beatmap.BeatmapSet.Metadata).Author}", + Text = $"{(beatmap.BeatmapMetadata ?? beatmap.BeatmapSetInfo.BeatmapMetadata).Author}", TextSize = 16, Anchor = Anchor.BottomLeft, Origin = Anchor.BottomLeft diff --git a/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs b/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs index 42db025a40..2981b3b053 100644 --- a/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs +++ b/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs @@ -35,7 +35,7 @@ namespace osu.Game.Beatmaps.Drawables new ConstrainedIconContainer { RelativeSizeAxes = Axes.Both, - Icon = beatmap.Ruleset.CreateInstance().CreateIcon() + Icon = beatmap.RulesetInfo.CreateInstance().CreateIcon() } }; } diff --git a/osu.Game/Beatmaps/DummyWorkingBeatmap.cs b/osu.Game/Beatmaps/DummyWorkingBeatmap.cs index d8cd58d939..3746a1fabe 100644 --- a/osu.Game/Beatmaps/DummyWorkingBeatmap.cs +++ b/osu.Game/Beatmaps/DummyWorkingBeatmap.cs @@ -18,14 +18,14 @@ namespace osu.Game.Beatmaps public DummyWorkingBeatmap(OsuGameBase game) : base(new BeatmapInfo { - Metadata = new BeatmapMetadata + BeatmapMetadata = new BeatmapMetadata { Artist = "please load a beatmap!", Title = "no beatmaps available!", Author = "no one", }, - BeatmapSet = new BeatmapSetInfo(), - Difficulty = new BeatmapDifficulty + BeatmapSetInfo = new BeatmapSetInfo(), + BeatmapDifficulty = new BeatmapDifficulty { DrainRate = 0, CircleSize = 0, @@ -34,7 +34,7 @@ namespace osu.Game.Beatmaps SliderMultiplier = 0, SliderTickRate = 0, }, - Ruleset = new DummyRulesetInfo() + RulesetInfo = new DummyRulesetInfo() }) { this.game = game; diff --git a/osu.Game/Beatmaps/Formats/BeatmapDecoder.cs b/osu.Game/Beatmaps/Formats/BeatmapDecoder.cs index 81695c3b5a..9d97ca8602 100644 --- a/osu.Game/Beatmaps/Formats/BeatmapDecoder.cs +++ b/osu.Game/Beatmaps/Formats/BeatmapDecoder.cs @@ -48,8 +48,8 @@ namespace osu.Game.Beatmaps.Formats { BeatmapInfo = new BeatmapInfo { - Metadata = new BeatmapMetadata(), - Difficulty = new BeatmapDifficulty(), + BeatmapMetadata = new BeatmapMetadata(), + BeatmapDifficulty = new BeatmapDifficulty(), }, }; diff --git a/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs b/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs index 21fee0f465..9d6586ef26 100644 --- a/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs +++ b/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs @@ -72,7 +72,7 @@ namespace osu.Game.Beatmaps.Formats { var pair = splitKeyVal(line, ':'); - var metadata = beatmap.BeatmapInfo.Metadata; + var metadata = beatmap.BeatmapInfo.BeatmapMetadata; switch (pair.Key) { case @"AudioFilename": @@ -97,9 +97,9 @@ namespace osu.Game.Beatmaps.Formats beatmap.BeatmapInfo.StackLeniency = float.Parse(pair.Value, NumberFormatInfo.InvariantInfo); break; case @"Mode": - beatmap.BeatmapInfo.RulesetID = int.Parse(pair.Value); + beatmap.BeatmapInfo.RulesetInfoId = int.Parse(pair.Value); - switch (beatmap.BeatmapInfo.RulesetID) + switch (beatmap.BeatmapInfo.RulesetInfoId) { case 0: parser = new Rulesets.Objects.Legacy.Osu.ConvertHitObjectParser(); @@ -155,7 +155,7 @@ namespace osu.Game.Beatmaps.Formats { var pair = splitKeyVal(line, ':'); - var metadata = beatmap.BeatmapInfo.Metadata; + var metadata = beatmap.BeatmapInfo.BeatmapMetadata; switch (pair.Key) { case @"Title": @@ -177,17 +177,17 @@ namespace osu.Game.Beatmaps.Formats beatmap.BeatmapInfo.Version = pair.Value; break; case @"Source": - beatmap.BeatmapInfo.Metadata.Source = pair.Value; + beatmap.BeatmapInfo.BeatmapMetadata.Source = pair.Value; break; case @"Tags": - beatmap.BeatmapInfo.Metadata.Tags = pair.Value; + beatmap.BeatmapInfo.BeatmapMetadata.Tags = pair.Value; break; case @"BeatmapID": - beatmap.BeatmapInfo.OnlineBeatmapID = int.Parse(pair.Value); + beatmap.BeatmapInfo.BeatmapOnlineInfoId = int.Parse(pair.Value); break; case @"BeatmapSetID": - beatmap.BeatmapInfo.OnlineBeatmapSetID = int.Parse(pair.Value); - metadata.OnlineBeatmapSetID = int.Parse(pair.Value); + beatmap.BeatmapInfo.BeatmapSetOnlineInfoId = int.Parse(pair.Value); + metadata.BeatmapSetOnlineInfoId = int.Parse(pair.Value); break; } } @@ -196,7 +196,7 @@ namespace osu.Game.Beatmaps.Formats { var pair = splitKeyVal(line, ':'); - var difficulty = beatmap.BeatmapInfo.Difficulty; + var difficulty = beatmap.BeatmapInfo.BeatmapDifficulty; switch (pair.Key) { case @"HPDrainRate": @@ -270,7 +270,7 @@ namespace osu.Game.Beatmaps.Formats string filename = split[2].Trim('"'); if (type == EventType.Background) - beatmap.BeatmapInfo.Metadata.BackgroundFile = filename; + beatmap.BeatmapInfo.BeatmapMetadata.BackgroundFile = filename; break; case EventType.Break: @@ -674,7 +674,7 @@ namespace osu.Game.Beatmaps.Formats } foreach (var hitObject in beatmap.HitObjects) - hitObject.ApplyDefaults(beatmap.ControlPointInfo, beatmap.BeatmapInfo.Difficulty); + hitObject.ApplyDefaults(beatmap.ControlPointInfo, beatmap.BeatmapInfo.BeatmapDifficulty); } private KeyValuePair splitKeyVal(string line, char separator) diff --git a/osu.Game/Beatmaps/WorkingBeatmap.cs b/osu.Game/Beatmaps/WorkingBeatmap.cs index 277846ee80..4b50e50efe 100644 --- a/osu.Game/Beatmaps/WorkingBeatmap.cs +++ b/osu.Game/Beatmaps/WorkingBeatmap.cs @@ -24,8 +24,8 @@ namespace osu.Game.Beatmaps protected WorkingBeatmap(BeatmapInfo beatmapInfo) { BeatmapInfo = beatmapInfo; - BeatmapSetInfo = beatmapInfo.BeatmapSet; - Metadata = beatmapInfo.Metadata ?? BeatmapSetInfo?.Metadata ?? new BeatmapMetadata(); + BeatmapSetInfo = beatmapInfo.BeatmapSetInfo; + Metadata = beatmapInfo.BeatmapMetadata ?? BeatmapSetInfo?.BeatmapMetadata ?? new BeatmapMetadata(); Mods.ValueChanged += mods => applyRateAdjustments(); } diff --git a/osu.Game/Database/DatabaseBackedStore.cs b/osu.Game/Database/DatabaseBackedStore.cs index d8e2e35bd7..f4b6a866dc 100644 --- a/osu.Game/Database/DatabaseBackedStore.cs +++ b/osu.Game/Database/DatabaseBackedStore.cs @@ -2,27 +2,23 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; -using System.Collections.Generic; using System.Linq; -using System.Linq.Expressions; +using Microsoft.EntityFrameworkCore; using osu.Framework.Logging; using osu.Framework.Platform; -using SQLite.Net; -using SQLiteNetExtensions.Extensions; namespace osu.Game.Database { public abstract class DatabaseBackedStore { protected readonly Storage Storage; - protected readonly SQLiteConnection Connection; + protected readonly OsuDbContext Connection; - protected virtual int StoreVersion => 1; - - protected DatabaseBackedStore(SQLiteConnection connection, Storage storage = null) + protected DatabaseBackedStore(OsuDbContext connection, Storage storage = null) { Storage = storage; Connection = connection; + Connection.Database.SetCommandTimeout(new TimeSpan(TimeSpan.TicksPerSecond * 10)); try { @@ -33,36 +29,6 @@ namespace osu.Game.Database Logger.Error(e, $@"Failed to initialise the {GetType()}! Trying again with a clean database..."); Prepare(true); } - - checkMigrations(); - } - - private void checkMigrations() - { - var storeName = GetType().Name; - - var reportedVersion = Connection.Table().Where(s => s.StoreName == storeName).FirstOrDefault() ?? new StoreVersion - { - StoreName = storeName, - Version = 0 - }; - - if (reportedVersion.Version != StoreVersion) - PerformMigration(reportedVersion.Version, reportedVersion.Version = StoreVersion); - - Connection.InsertOrReplace(reportedVersion); - - StartupTasks(); - } - - /// - /// Called when the database version of this store doesn't match the local version. - /// Any manual migration operations should be performed in this. - /// - /// The current store version. This will be zero on a fresh database initialisation. - /// The target version which we are migrating to (equal to the current ). - protected virtual void PerformMigration(int currentVersion, int targetVersion) - { } /// @@ -83,43 +49,6 @@ namespace osu.Game.Database /// public void Reset() => Prepare(true); - - public TableQuery Query(Expression> filter = null) where T : class - { - checkType(typeof(T)); - - var query = Connection.Table(); - - if (filter != null) - query = query.Where(filter); - - return query; - } - - /// - /// Query and populate results. - /// - /// An filter to refine results. - /// - public List QueryAndPopulate(Expression> filter) - where T : class - { - checkType(typeof(T)); - - return Connection.GetAllWithChildren(filter, true); - } - - /// - /// Populate a database-backed item. - /// - /// - /// Whether population should recurse beyond a single level. - public void Populate(T item, bool recursive = true) - { - checkType(item.GetType()); - Connection.GetChildren(item, recursive); - } - private void checkType(Type type) { if (!ValidTypes.Contains(type)) diff --git a/osu.Game/Database/DbContextBase.cs b/osu.Game/Database/DbContextBase.cs new file mode 100644 index 0000000000..93f4ac4c23 --- /dev/null +++ b/osu.Game/Database/DbContextBase.cs @@ -0,0 +1,8 @@ +using Microsoft.EntityFrameworkCore; + +namespace osu.Game.Database +{ + public abstract class DbContextBase:DbContext + { + } +} diff --git a/osu.Game/Database/OsuDbContext.cs b/osu.Game/Database/OsuDbContext.cs new file mode 100644 index 0000000000..41ae0711f4 --- /dev/null +++ b/osu.Game/Database/OsuDbContext.cs @@ -0,0 +1,55 @@ +using Microsoft.EntityFrameworkCore; +using osu.Game.Beatmaps; +using osu.Game.Input.Bindings; +using osu.Game.IO; +using osu.Game.Rulesets; + +namespace osu.Game.Database +{ + public class OsuDbContext : DbContext + { + private readonly string connectionString; + + public OsuDbContext() + { + connectionString = "DataSource=:memory:"; + } + + public OsuDbContext(string connectionString) + { + this.connectionString = connectionString; + } + + public DbSet BeatmapMetadata { get; set; } + public DbSet BeatmapDifficulty { get; set; } + public DbSet BeatmapInfo { get; set; } + public DbSet BeatmapSetInfo { get; set; } + public DbSet BeatmapSetFileInfo { get; set; } + public DbSet DatabasedKeyBinding { get; set; } + public DbSet FileInfo { get; set; } + public DbSet RulesetInfo { get; set; } + + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + { + base.OnConfiguring(optionsBuilder); + optionsBuilder.UseSqlite(connectionString); + } + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + base.OnModelCreating(modelBuilder); + modelBuilder.Entity().HasIndex(b => b.MD5Hash); + modelBuilder.Entity().HasIndex(b => b.DeletePending); + modelBuilder.Entity().HasIndex(b => b.Variant); + modelBuilder.Entity().HasIndex(b => b.IntAction); + modelBuilder.Entity().HasIndex(b => b.Hash).IsUnique(); + modelBuilder.Entity().HasIndex(b => b.ReferenceCount); + modelBuilder.Entity().HasIndex(b => b.Name).IsUnique(); + modelBuilder.Entity().HasIndex(b => b.InstantiationInfo).IsUnique(); + modelBuilder.Entity().HasIndex(b => b.Available); + //modelBuilder.Entity().HasOne(b => b.BeatmapSetOnlineInfo).WithOne(bs => bs.BeatmapMetadata).OnDelete(DeleteBehavior.SetNull); + //modelBuilder.Entity().HasOne(b => b.BeatmapSetOnlineInfo).WithOne(bs => bs.BeatmapSetInfo).OnDelete(DeleteBehavior.SetNull); + //modelBuilder.Entity().HasOne(b => b.BeatmapSetOnlineInfo).WithMany(bs => bs.Beatmaps).OnDelete(DeleteBehavior.SetNull); + } + } +} diff --git a/osu.Game/Database/StoreVersion.cs b/osu.Game/Database/StoreVersion.cs deleted file mode 100644 index 00314875a6..0000000000 --- a/osu.Game/Database/StoreVersion.cs +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright (c) 2007-2017 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using SQLite.Net.Attributes; - -namespace osu.Game.Database -{ - public class StoreVersion - { - [PrimaryKey] - public string StoreName { get; set; } - - public int Version { get; set; } - } -} diff --git a/osu.Game/IO/FileInfo.cs b/osu.Game/IO/FileInfo.cs index 367fd68f7b..7ba75eeb0c 100644 --- a/osu.Game/IO/FileInfo.cs +++ b/osu.Game/IO/FileInfo.cs @@ -1,22 +1,21 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; using System.IO; -using SQLite.Net.Attributes; namespace osu.Game.IO { public class FileInfo { - [PrimaryKey, AutoIncrement] - public int ID { get; set; } + [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public int Id { get; set; } - [Indexed(Unique = true)] public string Hash { get; set; } public string StoragePath => Path.Combine(Hash.Remove(1), Hash.Remove(2), Hash); - [Indexed] public int ReferenceCount { get; set; } } } diff --git a/osu.Game/IO/FileStore.cs b/osu.Game/IO/FileStore.cs index c3d8c1df46..416b6c2989 100644 --- a/osu.Game/IO/FileStore.cs +++ b/osu.Game/IO/FileStore.cs @@ -4,12 +4,12 @@ using System; using System.IO; using System.Linq; +using Microsoft.EntityFrameworkCore; using osu.Framework.Extensions; using osu.Framework.IO.Stores; using osu.Framework.Logging; using osu.Framework.Platform; using osu.Game.Database; -using SQLite.Net; namespace osu.Game.IO { @@ -22,9 +22,7 @@ namespace osu.Game.IO public readonly ResourceStore Store; - protected override int StoreVersion => 2; - - public FileStore(SQLiteConnection connection, Storage storage) : base(connection, storage) + public FileStore(OsuDbContext connection, Storage storage) : base(connection, storage) { Store = new NamespacedResourceStore(new StorageBackedResourceStore(storage), prefix); } @@ -44,10 +42,8 @@ namespace osu.Game.IO if (Storage.ExistsDirectory(prefix)) Storage.DeleteDirectory(prefix); - Connection.DropTable(); + Connection.Database.ExecuteSqlCommand("DELETE FROM FileInfo"); } - - Connection.CreateTable(); } protected override void StartupTasks() @@ -56,33 +52,11 @@ namespace osu.Game.IO deletePending(); } - /// - /// Perform migrations between two store versions. - /// - /// The current store version. This will be zero on a fresh database initialisation. - /// The target version which we are migrating to (equal to the current ). - protected override void PerformMigration(int currentVersion, int targetVersion) - { - base.PerformMigration(currentVersion, targetVersion); - - while (currentVersion++ < targetVersion) - { - switch (currentVersion) - { - case 1: - case 2: - // cannot migrate; breaking underlying changes. - Reset(); - break; - } - } - } - public FileInfo Add(Stream data, bool reference = true) { string hash = data.ComputeSHA2Hash(); - var existing = Connection.Table().Where(f => f.Hash == hash).FirstOrDefault(); + var existing = Connection.FileInfo.Where(f => f.Hash == hash).FirstOrDefault(); var info = existing ?? new FileInfo { Hash = hash }; @@ -100,61 +74,54 @@ namespace osu.Game.IO } if (existing == null) - Connection.Insert(info); + Connection.FileInfo.Add(info); if (reference || existing == null) Reference(info); + Connection.SaveChanges(); return info; } public void Reference(params FileInfo[] files) { - Connection.RunInTransaction(() => + var incrementedFiles = files.GroupBy(f => f.Id).Select(f => { - var incrementedFiles = files.GroupBy(f => f.ID).Select(f => - { - var accurateRefCount = Connection.Get(f.First().ID); - accurateRefCount.ReferenceCount += f.Count(); - return accurateRefCount; - }); - - Connection.UpdateAll(incrementedFiles); + var accurateRefCount = Connection.Find(f.First().Id); + accurateRefCount.ReferenceCount += f.Count(); + return accurateRefCount; }); + //Connection.FileInfo.UpdateRange(incrementedFiles); + Connection.SaveChanges(); } public void Dereference(params FileInfo[] files) { - Connection.RunInTransaction(() => + var incrementedFiles = files.GroupBy(f => f.Id).Select(f => { - var incrementedFiles = files.GroupBy(f => f.ID).Select(f => - { - var accurateRefCount = Connection.Get(f.First().ID); - accurateRefCount.ReferenceCount -= f.Count(); - return accurateRefCount; - }); - - Connection.UpdateAll(incrementedFiles); + var accurateRefCount = Connection.Find(f.First().Id); + accurateRefCount.ReferenceCount -= f.Count(); + return accurateRefCount; }); + + //Connection.FileInfo.UpdateRange(incrementedFiles); + Connection.SaveChanges(); } private void deletePending() { - Connection.RunInTransaction(() => + foreach (var f in Connection.FileInfo.Where(f => f.ReferenceCount < 1)) { - foreach (var f in Query(f => f.ReferenceCount < 1)) + try { - try - { - Storage.Delete(Path.Combine(prefix, f.StoragePath)); - Connection.Delete(f); - } - catch (Exception e) - { - Logger.Error(e, $@"Could not delete beatmap {f}"); - } + Storage.Delete(Path.Combine(prefix, f.StoragePath)); + Connection.FileInfo.Remove(f); } - }); + catch (Exception e) + { + Logger.Error(e, $@"Could not delete beatmap {f}"); + } + } } } -} \ No newline at end of file +} diff --git a/osu.Game/Input/Bindings/DatabasedKeyBinding.cs b/osu.Game/Input/Bindings/DatabasedKeyBinding.cs index cbf74d6984..73a8e117d3 100644 --- a/osu.Game/Input/Bindings/DatabasedKeyBinding.cs +++ b/osu.Game/Input/Bindings/DatabasedKeyBinding.cs @@ -1,23 +1,23 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; using osu.Framework.Input.Bindings; using osu.Game.Rulesets; -using SQLite.Net.Attributes; -using SQLiteNetExtensions.Attributes; namespace osu.Game.Input.Bindings { [Table("KeyBinding")] public class DatabasedKeyBinding : KeyBinding { - [PrimaryKey, AutoIncrement] - public int ID { get; set; } + [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public int Id { get; set; } - [ForeignKey(typeof(RulesetInfo))] - public int? RulesetID { get; set; } + [ForeignKey(nameof(RulesetInfo))] + public int? RulesetInfoId { get; set; } + public RulesetInfo RulesetInfo; - [Indexed] public int? Variant { get; set; } [Column("Keys")] @@ -27,7 +27,6 @@ namespace osu.Game.Input.Bindings private set { KeyCombination = value; } } - [Indexed] [Column("Action")] public int IntAction { @@ -35,4 +34,4 @@ namespace osu.Game.Input.Bindings set { Action = value; } } } -} \ No newline at end of file +} diff --git a/osu.Game/Input/Bindings/DatabasedKeyBindingInputManager.cs b/osu.Game/Input/Bindings/DatabasedKeyBindingInputManager.cs index 0a4fcf4389..41a2f54277 100644 --- a/osu.Game/Input/Bindings/DatabasedKeyBindingInputManager.cs +++ b/osu.Game/Input/Bindings/DatabasedKeyBindingInputManager.cs @@ -48,7 +48,7 @@ namespace osu.Game.Input.Bindings protected override void ReloadMappings() { - KeyBindings = store.Query(ruleset?.ID, variant); + KeyBindings = store.Query(ruleset?.Id, variant); } } } \ No newline at end of file diff --git a/osu.Game/Input/KeyBindingStore.cs b/osu.Game/Input/KeyBindingStore.cs index c5ba1683dd..3157bee6a7 100644 --- a/osu.Game/Input/KeyBindingStore.cs +++ b/osu.Game/Input/KeyBindingStore.cs @@ -4,78 +4,54 @@ using System; using System.Collections.Generic; using System.Linq; +using Microsoft.EntityFrameworkCore; using osu.Framework.Input.Bindings; using osu.Framework.Platform; using osu.Game.Database; using osu.Game.Input.Bindings; using osu.Game.Rulesets; -using SQLite.Net; namespace osu.Game.Input { public class KeyBindingStore : DatabaseBackedStore { - public KeyBindingStore(SQLiteConnection connection, RulesetStore rulesets, Storage storage = null) + public KeyBindingStore(OsuDbContext connection, RulesetStore rulesets, Storage storage = null) : base(connection, storage) { foreach (var info in rulesets.AllRulesets) { var ruleset = info.CreateInstance(); foreach (var variant in ruleset.AvailableVariants) - insertDefaults(ruleset.GetDefaultKeyBindings(variant), info.ID, variant); + insertDefaults(ruleset.GetDefaultKeyBindings(variant), info.Id, variant); } } public void Register(KeyBindingInputManager manager) => insertDefaults(manager.DefaultKeyBindings); - protected override int StoreVersion => 3; - - protected override void PerformMigration(int currentVersion, int targetVersion) - { - base.PerformMigration(currentVersion, targetVersion); - - while (currentVersion++ < targetVersion) - { - switch (currentVersion) - { - case 1: - case 2: - case 3: - // cannot migrate; breaking underlying changes. - Reset(); - break; - } - } - } - protected override void Prepare(bool reset = false) { - if (reset) - Connection.DropTable(); - - Connection.CreateTable(); + Connection.Database.ExecuteSqlCommand("DELETE FROM KeyBinding"); } private void insertDefaults(IEnumerable defaults, int? rulesetId = null, int? variant = null) { - var query = Query(rulesetId, variant); - // compare counts in database vs defaults foreach (var group in defaults.GroupBy(k => k.Action)) { int count; - while (group.Count() > (count = query.Count(k => (int)k.Action == (int)group.Key))) + while (group.Count() > (count = Query(rulesetId, variant).Count(k => (int)k.Action == (int)group.Key))) { var insertable = group.Skip(count).First(); // insert any defaults which are missing. - Connection.Insert(new DatabasedKeyBinding + Connection.DatabasedKeyBinding.Add(new DatabasedKeyBinding { KeyCombination = insertable.KeyCombination, Action = insertable.Action, - RulesetID = rulesetId, + RulesetInfoId = rulesetId, Variant = variant }); + Connection.SaveChanges(); } } } @@ -85,9 +61,18 @@ namespace osu.Game.Input typeof(DatabasedKeyBinding) }; - public IEnumerable Query(int? rulesetId = null, int? variant = null) => - Query(b => b.RulesetID == rulesetId && b.Variant == variant); + public List Query(int? rulesetId = null, int? variant = null) => + new List(Connection.DatabasedKeyBinding.Where(b => b.RulesetInfoId == rulesetId && b.Variant == variant)); - public void Update(KeyBinding keyBinding) => Connection.Update(keyBinding); + public void Update(KeyBinding keyBinding) + { + var dbKeyBinding = Connection.DatabasedKeyBinding.FirstOrDefault(kb => kb.ToString() == keyBinding.ToString()); + if (dbKeyBinding!=null) + { + dbKeyBinding.KeyCombination = keyBinding.KeyCombination; + dbKeyBinding.Action = keyBinding.Action; + } + Connection.SaveChanges(); + } } } diff --git a/osu.Game/Online/API/Requests/DownloadBeatmapSetRequest.cs b/osu.Game/Online/API/Requests/DownloadBeatmapSetRequest.cs index 5a9f609bca..f8e20d1e9f 100644 --- a/osu.Game/Online/API/Requests/DownloadBeatmapSetRequest.cs +++ b/osu.Game/Online/API/Requests/DownloadBeatmapSetRequest.cs @@ -19,6 +19,6 @@ namespace osu.Game.Online.API.Requests Progress += (current, total) => DownloadProgressed?.Invoke((float) current / total); } - protected override string Target => $@"beatmapsets/{BeatmapSet.OnlineBeatmapSetID}/download"; + protected override string Target => $@"beatmapsets/{BeatmapSet.BeatmapSetOnlineInfoId}/download"; } } diff --git a/osu.Game/Online/API/Requests/GetBeatmapDetailsRequest.cs b/osu.Game/Online/API/Requests/GetBeatmapDetailsRequest.cs index 934ef7ffa2..233e16beb1 100644 --- a/osu.Game/Online/API/Requests/GetBeatmapDetailsRequest.cs +++ b/osu.Game/Online/API/Requests/GetBeatmapDetailsRequest.cs @@ -10,7 +10,7 @@ namespace osu.Game.Online.API.Requests { private readonly BeatmapInfo beatmap; - private string lookupString => beatmap.OnlineBeatmapID > 0 ? beatmap.OnlineBeatmapID.ToString() : $@"lookup?checksum={beatmap.Hash}&filename={System.Uri.EscapeUriString(beatmap.Path)}"; + private string lookupString => beatmap.BeatmapOnlineInfoId > 0 ? beatmap.BeatmapOnlineInfoId.ToString() : $@"lookup?checksum={beatmap.Hash}&filename={System.Uri.EscapeUriString(beatmap.Path)}"; public GetBeatmapDetailsRequest(BeatmapInfo beatmap) { diff --git a/osu.Game/Online/API/Requests/GetBeatmapSetsRequest.cs b/osu.Game/Online/API/Requests/GetBeatmapSetsRequest.cs index 470e13ea7b..37d7a5e2d6 100644 --- a/osu.Game/Online/API/Requests/GetBeatmapSetsRequest.cs +++ b/osu.Game/Online/API/Requests/GetBeatmapSetsRequest.cs @@ -30,7 +30,7 @@ namespace osu.Game.Online.API.Requests this.direction = direction; } - protected override string Target => $@"beatmapsets/search?q={query}&m={ruleset.ID ?? 0}&s={(int)rankStatus}&sort={sortCriteria.ToString().ToLower()}_{directionString}"; + protected override string Target => $@"beatmapsets/search?q={query}&m={ruleset.Id ?? 0}&s={(int)rankStatus}&sort={sortCriteria.ToString().ToLower()}_{directionString}"; } public class GetBeatmapSetsResponse : BeatmapMetadata @@ -63,8 +63,8 @@ namespace osu.Game.Online.API.Requests { return new BeatmapSetInfo { - OnlineBeatmapSetID = onlineId, - Metadata = this, + BeatmapSetOnlineInfoId = onlineId, + BeatmapMetadata = this, OnlineInfo = new BeatmapSetOnlineInfo { Author = new User @@ -99,8 +99,8 @@ namespace osu.Game.Online.API.Requests { return new BeatmapInfo { - Metadata = this, - Ruleset = rulesets.GetRuleset(ruleset), + BeatmapMetadata = this, + RulesetInfo = rulesets.GetRuleset(ruleset), StarDifficulty = starDifficulty, OnlineInfo = new BeatmapOnlineInfo { diff --git a/osu.Game/Online/API/Requests/GetScoresRequest.cs b/osu.Game/Online/API/Requests/GetScoresRequest.cs index 537fce2548..6bb654f403 100644 --- a/osu.Game/Online/API/Requests/GetScoresRequest.cs +++ b/osu.Game/Online/API/Requests/GetScoresRequest.cs @@ -18,8 +18,8 @@ namespace osu.Game.Online.API.Requests public GetScoresRequest(BeatmapInfo beatmap) { - if (!beatmap.OnlineBeatmapID.HasValue) - throw new InvalidOperationException($"Cannot lookup a beatmap's scores without having a populated {nameof(BeatmapInfo.OnlineBeatmapID)}."); + if (!beatmap.BeatmapOnlineInfoId.HasValue) + throw new InvalidOperationException($"Cannot lookup a beatmap's scores without having a populated {nameof(BeatmapInfo.BeatmapOnlineInfoId)}."); this.beatmap = beatmap; @@ -32,7 +32,7 @@ namespace osu.Game.Online.API.Requests score.ApplyBeatmap(beatmap); } - protected override string Target => $@"beatmaps/{beatmap.OnlineBeatmapID}/scores"; + protected override string Target => $@"beatmaps/{beatmap.BeatmapOnlineInfoId}/scores"; } public class GetScoresResponse @@ -116,7 +116,7 @@ namespace osu.Game.Online.API.Requests public void ApplyBeatmap(BeatmapInfo beatmap) { Beatmap = beatmap; - Ruleset = beatmap.Ruleset; + Ruleset = beatmap.RulesetInfo; // Evaluate the mod string Mods = Ruleset.CreateInstance().GetAllMods().Where(mod => modStrings.Contains(mod.ShortenedName)).ToArray(); diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index c137b8f6f5..6dacef6e8d 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -110,7 +110,7 @@ namespace osu.Game configRuleset = LocalConfig.GetBindable(OsuSetting.Ruleset); Ruleset.Value = RulesetStore.GetRuleset(configRuleset.Value); - Ruleset.ValueChanged += r => configRuleset.Value = r.ID ?? 0; + Ruleset.ValueChanged += r => configRuleset.Value = r.Id ?? 0; } private ScheduledDelegate scoreLoad; diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 8e7bfa8a76..f2ee6effb9 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -3,7 +3,9 @@ using System; using System.Diagnostics; +using System.Linq; using System.Reflection; +using Microsoft.EntityFrameworkCore; using osu.Framework.Allocation; using osu.Framework.Configuration; using osu.Framework.Development; @@ -17,7 +19,6 @@ using osu.Game.Graphics; using osu.Game.Graphics.Cursor; using osu.Game.Graphics.Processing; using osu.Game.Online.API; -using SQLite.Net; using osu.Framework.Graphics.Performance; using osu.Game.Database; using osu.Game.Input; @@ -82,14 +83,21 @@ namespace osu.Game protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent) => dependencies = new DependencyContainer(base.CreateLocalDependencies(parent)); - private SQLiteConnection createConnection() - { - var conn = Host.Storage.GetDatabase(@"client"); - conn.BusyTimeout = new TimeSpan(TimeSpan.TicksPerSecond * 10); - return conn; - } + //private OsuDbContext dbContext; - private SQLiteConnection connection; + private OsuDbContext createDbContext() + { + var connectionString = Host.Storage.GetDatabaseConnectionString(@"client"); + var context = new OsuDbContext(connectionString); + var connection = context.Database.GetDbConnection(); + connection.Open(); + using (var command = connection.CreateCommand()) + { + command.CommandText = "PRAGMA journal_mode=WAL;"; + command.ExecuteNonQuery(); + } + return context; + } [BackgroundDependencyLoader] private void load() @@ -97,8 +105,10 @@ namespace osu.Game dependencies.Cache(this); dependencies.Cache(LocalConfig); - connection = createConnection(); - connection.CreateTable(); + + using (var dbContext = createDbContext()) + if (dbContext.Database.GetPendingMigrations().Any()) + dbContext.Database.Migrate(); dependencies.Cache(API = new APIAccess { @@ -106,11 +116,11 @@ namespace osu.Game Token = LocalConfig.Get(OsuSetting.Token) }); - dependencies.Cache(RulesetStore = new RulesetStore(connection)); - dependencies.Cache(FileStore = new FileStore(connection, Host.Storage)); - dependencies.Cache(BeatmapManager = new BeatmapManager(Host.Storage, FileStore, connection, RulesetStore, API, Host)); - dependencies.Cache(ScoreStore = new ScoreStore(Host.Storage, connection, Host, BeatmapManager, RulesetStore)); - dependencies.Cache(KeyBindingStore = new KeyBindingStore(connection, RulesetStore)); + dependencies.Cache(RulesetStore = new RulesetStore(createDbContext())); + dependencies.Cache(FileStore = new FileStore(createDbContext(), Host.Storage)); + dependencies.Cache(BeatmapManager = new BeatmapManager(Host.Storage, FileStore, createDbContext(), RulesetStore, API, Host)); + dependencies.Cache(ScoreStore = new ScoreStore(Host.Storage, createDbContext(), Host, BeatmapManager, RulesetStore)); + dependencies.Cache(KeyBindingStore = new KeyBindingStore(createDbContext(), RulesetStore)); dependencies.Cache(new OsuColour()); //this completely overrides the framework default. will need to change once we make a proper FontStore. @@ -237,7 +247,7 @@ namespace osu.Game LocalConfig.Save(); } - connection?.Dispose(); + //dbContext?.Dispose(); base.Dispose(isDisposing); } diff --git a/osu.Game/Overlays/BeatmapSet/Header.cs b/osu.Game/Overlays/BeatmapSet/Header.cs index a93ccbf704..25e598ffb9 100644 --- a/osu.Game/Overlays/BeatmapSet/Header.cs +++ b/osu.Game/Overlays/BeatmapSet/Header.cs @@ -43,8 +43,8 @@ namespace osu.Game.Overlays.BeatmapSet beatmapSet = value; Picker.BeatmapSet = author.BeatmapSet = details.BeatmapSet = BeatmapSet; - title.Text = BeatmapSet.Metadata.Title; - artist.Text = BeatmapSet.Metadata.Artist; + title.Text = BeatmapSet.BeatmapMetadata.Title; + artist.Text = BeatmapSet.BeatmapMetadata.Artist; cover?.FadeOut(400, Easing.Out); coverContainer.Add(cover = new DelayedLoadWrapper(new BeatmapSetCover(BeatmapSet) diff --git a/osu.Game/Overlays/BeatmapSet/Info.cs b/osu.Game/Overlays/BeatmapSet/Info.cs index 4a59591a72..16cb19dbd7 100644 --- a/osu.Game/Overlays/BeatmapSet/Info.cs +++ b/osu.Game/Overlays/BeatmapSet/Info.cs @@ -33,8 +33,8 @@ namespace osu.Game.Overlays.BeatmapSet if (value == beatmapSet) return; beatmapSet = value; - source.Text = BeatmapSet.Metadata.Source; - tags.Text = BeatmapSet.Metadata.Tags; + source.Text = BeatmapSet.BeatmapMetadata.Source; + tags.Text = BeatmapSet.BeatmapMetadata.Tags; } } diff --git a/osu.Game/Overlays/Direct/DirectGridPanel.cs b/osu.Game/Overlays/Direct/DirectGridPanel.cs index 1675a2f663..8d3d91fcd2 100644 --- a/osu.Game/Overlays/Direct/DirectGridPanel.cs +++ b/osu.Game/Overlays/Direct/DirectGridPanel.cs @@ -66,13 +66,13 @@ namespace osu.Game.Overlays.Direct { new OsuSpriteText { - Text = localisation.GetUnicodePreference(SetInfo.Metadata.TitleUnicode, SetInfo.Metadata.Title), + Text = localisation.GetUnicodePreference(SetInfo.BeatmapMetadata.TitleUnicode, SetInfo.BeatmapMetadata.Title), TextSize = 18, Font = @"Exo2.0-BoldItalic", }, new OsuSpriteText { - Text = localisation.GetUnicodePreference(SetInfo.Metadata.ArtistUnicode, SetInfo.Metadata.Artist), + Text = localisation.GetUnicodePreference(SetInfo.BeatmapMetadata.ArtistUnicode, SetInfo.BeatmapMetadata.Artist), Font = @"Exo2.0-BoldItalic", }, }, @@ -116,7 +116,7 @@ namespace osu.Game.Overlays.Direct }, new OsuSpriteText { - Text = SetInfo.Metadata.Author, + Text = SetInfo.BeatmapMetadata.Author, TextSize = 14, Font = @"Exo2.0-SemiBoldItalic", Shadow = false, @@ -132,11 +132,11 @@ namespace osu.Game.Overlays.Direct { new OsuSpriteText { - Text = $"from {SetInfo.Metadata.Source}", + Text = $"from {SetInfo.BeatmapMetadata.Source}", TextSize = 14, Shadow = false, Colour = colours.Gray5, - Alpha = string.IsNullOrEmpty(SetInfo.Metadata.Source) ? 0f : 1f, + Alpha = string.IsNullOrEmpty(SetInfo.BeatmapMetadata.Source) ? 0f : 1f, }, }, }, diff --git a/osu.Game/Overlays/Direct/DirectListPanel.cs b/osu.Game/Overlays/Direct/DirectListPanel.cs index 6702b7394c..b46ce78654 100644 --- a/osu.Game/Overlays/Direct/DirectListPanel.cs +++ b/osu.Game/Overlays/Direct/DirectListPanel.cs @@ -54,13 +54,13 @@ namespace osu.Game.Overlays.Direct { new OsuSpriteText { - Current = localisation.GetUnicodePreference(SetInfo.Metadata.TitleUnicode, SetInfo.Metadata.Title), + Current = localisation.GetUnicodePreference(SetInfo.BeatmapMetadata.TitleUnicode, SetInfo.BeatmapMetadata.Title), TextSize = 18, Font = @"Exo2.0-BoldItalic", }, new OsuSpriteText { - Current = localisation.GetUnicodePreference(SetInfo.Metadata.ArtistUnicode, SetInfo.Metadata.Artist), + Current = localisation.GetUnicodePreference(SetInfo.BeatmapMetadata.ArtistUnicode, SetInfo.BeatmapMetadata.Artist), Font = @"Exo2.0-BoldItalic", }, new FillFlowContainer @@ -101,7 +101,7 @@ namespace osu.Game.Overlays.Direct }, new OsuSpriteText { - Text = SetInfo.Metadata.Author, + Text = SetInfo.BeatmapMetadata.Author, TextSize = 14, Font = @"Exo2.0-SemiBoldItalic", }, @@ -109,11 +109,11 @@ namespace osu.Game.Overlays.Direct }, new OsuSpriteText { - Text = $"from {SetInfo.Metadata.Source}", + Text = $"from {SetInfo.BeatmapMetadata.Source}", Anchor = Anchor.TopRight, Origin = Anchor.TopRight, TextSize = 14, - Alpha = string.IsNullOrEmpty(SetInfo.Metadata.Source) ? 0f : 1f, + Alpha = string.IsNullOrEmpty(SetInfo.BeatmapMetadata.Source) ? 0f : 1f, }, }, }, diff --git a/osu.Game/Overlays/Direct/FilterControl.cs b/osu.Game/Overlays/Direct/FilterControl.cs index 28d26d0641..1500723680 100644 --- a/osu.Game/Overlays/Direct/FilterControl.cs +++ b/osu.Game/Overlays/Direct/FilterControl.cs @@ -70,7 +70,7 @@ namespace osu.Game.Overlays.Direct private void Bindable_ValueChanged(RulesetInfo obj) { - iconContainer.FadeTo(Ruleset.ID == obj?.ID ? 1f : 0.5f, 100); + iconContainer.FadeTo(Ruleset.Id == obj?.Id ? 1f : 0.5f, 100); } public RulesetToggleButton(Bindable bindable, RulesetInfo ruleset) diff --git a/osu.Game/Overlays/DirectOverlay.cs b/osu.Game/Overlays/DirectOverlay.cs index 5b5003b30f..df08400ee9 100644 --- a/osu.Game/Overlays/DirectOverlay.cs +++ b/osu.Game/Overlays/DirectOverlay.cs @@ -57,9 +57,9 @@ namespace osu.Game.Overlays var tags = new List(); foreach (var s in beatmapSets) { - artists.Add(s.Metadata.Artist); - songs.Add(s.Metadata.Title); - tags.AddRange(s.Metadata.Tags.Split(' ')); + artists.Add(s.BeatmapMetadata.Artist); + songs.Add(s.BeatmapMetadata.Title); + tags.AddRange(s.BeatmapMetadata.Tags.Split(' ')); } ResultAmounts = new ResultCounts(distinctCount(artists), distinctCount(songs), distinctCount(tags)); @@ -175,8 +175,8 @@ namespace osu.Game.Overlays private void setAdded(BeatmapSetInfo set) { // if a new map was imported, we should remove it from search results (download completed etc.) - panels?.FirstOrDefault(p => p.SetInfo.OnlineBeatmapSetID == set.OnlineBeatmapSetID)?.FadeOut(400).Expire(); - BeatmapSets = BeatmapSets?.Where(b => b.OnlineBeatmapSetID != set.OnlineBeatmapSetID); + panels?.FirstOrDefault(p => p.SetInfo.BeatmapSetOnlineInfoId == set.BeatmapSetOnlineInfoId)?.FadeOut(400).Expire(); + BeatmapSets = BeatmapSets?.Where(b => b.BeatmapSetOnlineInfoId != set.BeatmapSetOnlineInfoId); } private void updateResultCounts() @@ -260,7 +260,7 @@ namespace osu.Game.Overlays { BeatmapSets = r?. Select(response => response.ToBeatmapSet(rulesets)). - Where(b => beatmaps.QueryBeatmapSet(q => q.OnlineBeatmapSetID == b.OnlineBeatmapSetID) == null); + Where(b => beatmaps.QueryBeatmapSet(q => q.BeatmapSetOnlineInfoId == b.BeatmapSetOnlineInfoId) == null); recreatePanels(Filter.DisplayStyleControl.DisplayStyle.Value); }; diff --git a/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs b/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs index bd69403831..8442203f14 100644 --- a/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs +++ b/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs @@ -33,7 +33,7 @@ namespace osu.Game.Overlays.KeyBinding [BackgroundDependencyLoader] private void load(KeyBindingStore store) { - var bindings = store.Query(Ruleset?.ID, variant); + var bindings = store.Query(Ruleset?.Id, variant); foreach (var defaultGroup in Defaults.GroupBy(d => d.Action)) { diff --git a/osu.Game/Overlays/Music/PlaylistItem.cs b/osu.Game/Overlays/Music/PlaylistItem.cs index 723b3f4e96..6a8476dddd 100644 --- a/osu.Game/Overlays/Music/PlaylistItem.cs +++ b/osu.Game/Overlays/Music/PlaylistItem.cs @@ -66,7 +66,7 @@ namespace osu.Game.Overlays.Music hoverColour = colours.Yellow; artistColour = colours.Gray9; - var metadata = BeatmapSetInfo.Metadata; + var metadata = BeatmapSetInfo.BeatmapMetadata; FilterTerms = metadata.SearchableTerms; Children = new Drawable[] diff --git a/osu.Game/Overlays/Music/PlaylistList.cs b/osu.Game/Overlays/Music/PlaylistList.cs index 6f1eaded7f..b989b1cb1c 100644 --- a/osu.Game/Overlays/Music/PlaylistList.cs +++ b/osu.Game/Overlays/Music/PlaylistList.cs @@ -105,7 +105,7 @@ namespace osu.Game.Overlays.Music public bool RemoveBeatmapSet(BeatmapSetInfo beatmapSet) { - var itemToRemove = items.FirstOrDefault(i => i.BeatmapSetInfo.ID == beatmapSet.ID); + var itemToRemove = items.FirstOrDefault(i => i.BeatmapSetInfo.Id == beatmapSet.Id); if (itemToRemove == null) return false; return items.Remove(itemToRemove); @@ -117,7 +117,7 @@ namespace osu.Game.Overlays.Music set { foreach (PlaylistItem s in items.Children) - s.Selected = s.BeatmapSetInfo.ID == value?.ID; + s.Selected = s.BeatmapSetInfo.Id == value?.Id; } } diff --git a/osu.Game/Overlays/Music/PlaylistOverlay.cs b/osu.Game/Overlays/Music/PlaylistOverlay.cs index d05ad85726..e78e3d44be 100644 --- a/osu.Game/Overlays/Music/PlaylistOverlay.cs +++ b/osu.Game/Overlays/Music/PlaylistOverlay.cs @@ -115,7 +115,7 @@ namespace osu.Game.Overlays.Music private void itemSelected(BeatmapSetInfo set) { - if (set.ID == (beatmapBacking.Value?.BeatmapSetInfo?.ID ?? -1)) + if (set.Id == (beatmapBacking.Value?.BeatmapSetInfo?.Id ?? -1)) { beatmapBacking.Value?.Track?.Seek(0); return; diff --git a/osu.Game/Overlays/MusicController.cs b/osu.Game/Overlays/MusicController.cs index 64d0d628f0..4efd395212 100644 --- a/osu.Game/Overlays/MusicController.cs +++ b/osu.Game/Overlays/MusicController.cs @@ -302,8 +302,8 @@ namespace osu.Game.Overlays else { //figure out the best direction based on order in playlist. - var last = playlist.BeatmapSets.TakeWhile(b => b.ID != current.BeatmapSetInfo?.ID).Count(); - var next = beatmap == null ? -1 : playlist.BeatmapSets.TakeWhile(b => b.ID != beatmap.BeatmapSetInfo?.ID).Count(); + var last = playlist.BeatmapSets.TakeWhile(b => b.Id != current.BeatmapSetInfo?.Id).Count(); + var next = beatmap == null ? -1 : playlist.BeatmapSets.TakeWhile(b => b.Id != beatmap.BeatmapSetInfo?.Id).Count(); direction = last > next ? TransformDirection.Prev : TransformDirection.Next; } diff --git a/osu.Game/Overlays/Toolbar/ToolbarModeSelector.cs b/osu.Game/Overlays/Toolbar/ToolbarModeSelector.cs index 60c1261190..cd18980e32 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarModeSelector.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarModeSelector.cs @@ -98,7 +98,7 @@ namespace osu.Game.Overlays.Toolbar { foreach (ToolbarModeButton m in modeButtons.Children.Cast()) { - bool isActive = m.Ruleset.ID == ruleset.ID; + bool isActive = m.Ruleset.Id == ruleset.Id; m.Active = isActive; if (isActive) activeButton = m; diff --git a/osu.Game/Rulesets/RulesetInfo.cs b/osu.Game/Rulesets/RulesetInfo.cs index 740369b1b6..9c51e1e66a 100644 --- a/osu.Game/Rulesets/RulesetInfo.cs +++ b/osu.Game/Rulesets/RulesetInfo.cs @@ -2,26 +2,23 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; -using SQLite.Net.Attributes; +using System.ComponentModel.DataAnnotations; namespace osu.Game.Rulesets { public class RulesetInfo : IEquatable { - [PrimaryKey, AutoIncrement] - public int? ID { get; set; } + [Key] + public int? Id { get; set; } - [Indexed(Unique = true)] public string Name { get; set; } - [Indexed(Unique = true)] public string InstantiationInfo { get; set; } - [Indexed] public bool Available { get; set; } public virtual Ruleset CreateInstance() => (Ruleset)Activator.CreateInstance(Type.GetType(InstantiationInfo), this); - public bool Equals(RulesetInfo other) => other != null && ID == other.ID && Available == other.Available && Name == other.Name && InstantiationInfo == other.InstantiationInfo; + public bool Equals(RulesetInfo other) => other != null && Id == other.Id && Available == other.Available && Name == other.Name && InstantiationInfo == other.InstantiationInfo; } } diff --git a/osu.Game/Rulesets/RulesetStore.cs b/osu.Game/Rulesets/RulesetStore.cs index 5eef4a8470..f29929a6aa 100644 --- a/osu.Game/Rulesets/RulesetStore.cs +++ b/osu.Game/Rulesets/RulesetStore.cs @@ -6,8 +6,8 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; +using Microsoft.EntityFrameworkCore; using osu.Game.Database; -using SQLite.Net; namespace osu.Game.Rulesets { @@ -18,9 +18,9 @@ namespace osu.Game.Rulesets { private static readonly Dictionary loaded_assemblies = new Dictionary(); - public IEnumerable AllRulesets => Query().Where(r => r.Available); + public IEnumerable AllRulesets => Connection.RulesetInfo.Where(r => r.Available); - public RulesetStore(SQLiteConnection connection) : base(connection) + public RulesetStore(OsuDbContext connection) : base(connection) { } @@ -38,54 +38,50 @@ namespace osu.Game.Rulesets protected override void Prepare(bool reset = false) { - - Connection.CreateTable(); - if (reset) { - Connection.DeleteAll(); + Connection.Database.ExecuteSqlCommand("DELETE FROM RulesetInfo"); } - + var instances = loaded_assemblies.Values.Select(r => (Ruleset)Activator.CreateInstance(r, new RulesetInfo())); - Connection.RunInTransaction(() => + //add all legacy modes in correct order + foreach (var r in instances.Where(r => r.LegacyID >= 0).OrderBy(r => r.LegacyID)) { - //add all legacy modes in correct order - foreach (var r in instances.Where(r => r.LegacyID >= 0).OrderBy(r => r.LegacyID)) + var rulesetInfo = createRulesetInfo(r); + if (Connection.RulesetInfo.SingleOrDefault(rsi=>rsi.Id==rulesetInfo.Id)==null) { - Connection.InsertOrReplace(createRulesetInfo(r)); + Connection.RulesetInfo.Add(rulesetInfo); } + } - //add any other modes - foreach (var r in instances.Where(r => r.LegacyID < 0)) - { - var us = createRulesetInfo(r); - - var existing = Query().Where(ri => ri.InstantiationInfo == us.InstantiationInfo).FirstOrDefault(); - - if (existing == null) - Connection.Insert(us); - } - }); - - Connection.RunInTransaction(() => + //add any other modes + foreach (var r in instances.Where(r => r.LegacyID < 0)) { - //perform a consistency check - foreach (var r in Query()) - { - try - { - r.CreateInstance(); - r.Available = true; - } - catch - { - r.Available = false; - } + var us = createRulesetInfo(r); - Connection.Update(r); + var existing = Connection.RulesetInfo.Where(ri => ri.InstantiationInfo == us.InstantiationInfo).FirstOrDefault(); + + if (existing == null) + Connection.RulesetInfo.Add(us); + } + + //perform a consistency check + foreach (var r in Connection.RulesetInfo) + { + try + { + r.CreateInstance(); + r.Available = true; } - }); + catch + { + r.Available = false; + } + + //Connection.RulesetInfo.Update(r); + } + Connection.SaveChanges(); } private static void loadRulesetFromFile(string file) @@ -107,11 +103,24 @@ namespace osu.Game.Rulesets { Name = ruleset.Description, InstantiationInfo = ruleset.GetType().AssemblyQualifiedName, - ID = ruleset.LegacyID + Id = ruleset.LegacyID }; protected override Type[] ValidTypes => new[] { typeof(RulesetInfo) }; - public RulesetInfo GetRuleset(int id) => Query().First(r => r.ID == id); + public RulesetInfo GetRuleset(int id) => Connection.RulesetInfo.First(r => r.Id == id); + + public RulesetInfo QueryRulesetInfo(Func query) + { + return Connection.RulesetInfo.FirstOrDefault(query); + } + + public List QueryRulesets(Func query = null) + { + var rulesets = Connection.RulesetInfo; + if (query != null) + return rulesets.Where(query).ToList(); + return rulesets.ToList(); + } } } diff --git a/osu.Game/Rulesets/Scoring/ScoreStore.cs b/osu.Game/Rulesets/Scoring/ScoreStore.cs index c06d31e38f..1604e8cb1c 100644 --- a/osu.Game/Rulesets/Scoring/ScoreStore.cs +++ b/osu.Game/Rulesets/Scoring/ScoreStore.cs @@ -11,7 +11,6 @@ using osu.Game.IO.Legacy; using osu.Game.IPC; using osu.Game.Rulesets.Replays; using SharpCompress.Compressors.LZMA; -using SQLite.Net; namespace osu.Game.Rulesets.Scoring { @@ -27,7 +26,7 @@ namespace osu.Game.Rulesets.Scoring // ReSharper disable once NotAccessedField.Local (we should keep a reference to this so it is not finalised) private ScoreIPCChannel ipc; - public ScoreStore(Storage storage, SQLiteConnection connection, IIpcHost importHost = null, BeatmapManager beatmaps = null, RulesetStore rulesets = null) : base(connection) + public ScoreStore(Storage storage, OsuDbContext connection, IIpcHost importHost = null, BeatmapManager beatmaps = null, RulesetStore rulesets = null) : base(connection) { this.storage = storage; this.beatmaps = beatmaps; diff --git a/osu.Game/Rulesets/UI/RulesetContainer.cs b/osu.Game/Rulesets/UI/RulesetContainer.cs index 729df02ffd..0e784c06af 100644 --- a/osu.Game/Rulesets/UI/RulesetContainer.cs +++ b/osu.Game/Rulesets/UI/RulesetContainer.cs @@ -172,11 +172,11 @@ namespace osu.Game.Rulesets.UI // Apply difficulty adjustments from mods before using Difficulty. foreach (var mod in Mods.OfType()) - mod.ApplyToDifficulty(Beatmap.BeatmapInfo.Difficulty); + mod.ApplyToDifficulty(Beatmap.BeatmapInfo.BeatmapDifficulty); // Apply defaults foreach (var h in Beatmap.HitObjects) - h.ApplyDefaults(Beatmap.ControlPointInfo, Beatmap.BeatmapInfo.Difficulty); + h.ApplyDefaults(Beatmap.ControlPointInfo, Beatmap.BeatmapInfo.BeatmapDifficulty); // Post-process the beatmap processor.PostProcess(Beatmap); diff --git a/osu.Game/Screens/Menu/Intro.cs b/osu.Game/Screens/Menu/Intro.cs index 3aeef4bbc9..66e6da3af9 100644 --- a/osu.Game/Screens/Menu/Intro.cs +++ b/osu.Game/Screens/Menu/Intro.cs @@ -78,7 +78,7 @@ namespace osu.Game.Screens.Menu { var sets = beatmaps.GetAllUsableBeatmapSets(false); if (sets.Count > 0) - setInfo = beatmaps.QueryBeatmapSet(s => s.ID == sets[RNG.Next(0, sets.Count - 1)].ID); + setInfo = beatmaps.QueryBeatmapSet(s => s.Id == sets[RNG.Next(0, sets.Count - 1)].Id); } if (setInfo == null) diff --git a/osu.Game/Screens/Multiplayer/DrawableRoom.cs b/osu.Game/Screens/Multiplayer/DrawableRoom.cs index d2f88224c2..f3d648e07b 100644 --- a/osu.Game/Screens/Multiplayer/DrawableRoom.cs +++ b/osu.Game/Screens/Multiplayer/DrawableRoom.cs @@ -230,7 +230,7 @@ namespace osu.Game.Screens.Multiplayer coverContainer.FadeIn(transition_duration); coverContainer.Children = new[] { - new AsyncLoadWrapper(new BeatmapSetCover(value.BeatmapSet) + new AsyncLoadWrapper(new BeatmapSetCover(value.BeatmapSetInfo) { Anchor = Anchor.Centre, Origin = Anchor.Centre, @@ -239,9 +239,9 @@ namespace osu.Game.Screens.Multiplayer }) { RelativeSizeAxes = Axes.Both }, }; - beatmapTitle.Current = localisation.GetUnicodePreference(value.Metadata.TitleUnicode, value.Metadata.Title); + beatmapTitle.Current = localisation.GetUnicodePreference(value.BeatmapMetadata.TitleUnicode, value.BeatmapMetadata.Title); beatmapDash.Text = @" - "; - beatmapArtist.Current = localisation.GetUnicodePreference(value.Metadata.ArtistUnicode, value.Metadata.Artist); + beatmapArtist.Current = localisation.GetUnicodePreference(value.BeatmapMetadata.ArtistUnicode, value.BeatmapMetadata.Artist); } else { diff --git a/osu.Game/Screens/Multiplayer/RoomInspector.cs b/osu.Game/Screens/Multiplayer/RoomInspector.cs index 66ce51b428..aabbd2be5f 100644 --- a/osu.Game/Screens/Multiplayer/RoomInspector.cs +++ b/osu.Game/Screens/Multiplayer/RoomInspector.cs @@ -331,7 +331,7 @@ namespace osu.Game.Screens.Multiplayer coverContainer.FadeIn(transition_duration); coverContainer.Children = new[] { - new AsyncLoadWrapper(new BeatmapSetCover(value.BeatmapSet) + new AsyncLoadWrapper(new BeatmapSetCover(value.BeatmapSetInfo) { RelativeSizeAxes = Axes.Both, Anchor = Anchor.Centre, @@ -341,10 +341,10 @@ namespace osu.Game.Screens.Multiplayer }) { RelativeSizeAxes = Axes.Both }, }; - beatmapTitle.Current = localisation.GetUnicodePreference(value.Metadata.TitleUnicode, value.Metadata.Title); + beatmapTitle.Current = localisation.GetUnicodePreference(value.BeatmapMetadata.TitleUnicode, value.BeatmapMetadata.Title); beatmapDash.Text = @" - "; - beatmapArtist.Current = localisation.GetUnicodePreference(value.Metadata.ArtistUnicode, value.Metadata.Artist); - beatmapAuthor.Text = $"mapped by {value.Metadata.Author}"; + beatmapArtist.Current = localisation.GetUnicodePreference(value.BeatmapMetadata.ArtistUnicode, value.BeatmapMetadata.Artist); + beatmapAuthor.Text = $"mapped by {value.BeatmapMetadata.Author}"; } else { diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index e120c7f193..9b0172a1b2 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -99,18 +99,18 @@ namespace osu.Game.Screens.Play if (beatmap == null) throw new InvalidOperationException("Beatmap was not loaded"); - ruleset = Ruleset.Value ?? beatmap.BeatmapInfo.Ruleset; + ruleset = Ruleset.Value ?? beatmap.BeatmapInfo.RulesetInfo; var rulesetInstance = ruleset.CreateInstance(); try { - RulesetContainer = rulesetInstance.CreateRulesetContainerWith(working, ruleset.ID == beatmap.BeatmapInfo.Ruleset.ID); + RulesetContainer = rulesetInstance.CreateRulesetContainerWith(working, ruleset.Id == beatmap.BeatmapInfo.RulesetInfo.Id); } catch (BeatmapInvalidForRulesetException) { // we may fail to create a RulesetContainer if the beatmap cannot be loaded with the user's preferred ruleset // let's try again forcing the beatmap's ruleset. - ruleset = beatmap.BeatmapInfo.Ruleset; + ruleset = beatmap.BeatmapInfo.RulesetInfo; rulesetInstance = ruleset.CreateInstance(); RulesetContainer = rulesetInstance.CreateRulesetContainerWith(Beatmap, true); } diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index 9366797f47..92369c4f29 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -177,7 +177,7 @@ namespace osu.Game.Screens.Play [BackgroundDependencyLoader] private void load(LocalisationEngine localisation) { - var metadata = beatmap?.BeatmapInfo?.Metadata ?? new BeatmapMetadata(); + var metadata = beatmap?.BeatmapInfo?.BeatmapMetadata ?? new BeatmapMetadata(); AutoSizeAxes = Axes.Both; Children = new Drawable[] diff --git a/osu.Game/Screens/Ranking/ResultsPageScore.cs b/osu.Game/Screens/Ranking/ResultsPageScore.cs index b01410cff5..694391a5ff 100644 --- a/osu.Game/Screens/Ranking/ResultsPageScore.cs +++ b/osu.Game/Screens/Ranking/ResultsPageScore.cs @@ -324,9 +324,9 @@ namespace osu.Game.Screens.Ranking title.Colour = artist.Colour = colours.BlueDarker; versionMapper.Colour = colours.Gray8; - versionMapper.Text = $"{beatmap.Version} - mapped by {beatmap.Metadata.Author}"; - title.Current = localisation.GetUnicodePreference(beatmap.Metadata.TitleUnicode, beatmap.Metadata.Title); - artist.Current = localisation.GetUnicodePreference(beatmap.Metadata.ArtistUnicode, beatmap.Metadata.Artist); + versionMapper.Text = $"{beatmap.Version} - mapped by {beatmap.BeatmapMetadata.Author}"; + title.Current = localisation.GetUnicodePreference(beatmap.BeatmapMetadata.TitleUnicode, beatmap.BeatmapMetadata.Title); + artist.Current = localisation.GetUnicodePreference(beatmap.BeatmapMetadata.ArtistUnicode, beatmap.BeatmapMetadata.Artist); } } diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index abd288baf2..0c31f51c2b 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -113,15 +113,15 @@ namespace osu.Game.Screens.Select }); } - public void RemoveBeatmap(BeatmapSetInfo beatmapSet) => removeGroup(groups.Find(b => b.BeatmapSet.ID == beatmapSet.ID)); + public void RemoveBeatmap(BeatmapSetInfo beatmapSet) => removeGroup(groups.Find(b => b.BeatmapSet.Id == beatmapSet.Id)); internal void UpdateBeatmap(BeatmapInfo beatmap) { // todo: this method should not run more than once for the same BeatmapSetInfo. - var set = manager.Refresh(beatmap.BeatmapSet); + var set = manager.Refresh(beatmap.BeatmapSetInfo); // todo: this method should be smarter as to not recreate panels that haven't changed, etc. - var group = groups.Find(b => b.BeatmapSet.ID == set.ID); + var group = groups.Find(b => b.BeatmapSet.Id == set.Id); if (group == null) return; @@ -141,7 +141,7 @@ namespace osu.Game.Screens.Select if (selectedGroup == group && newGroup.BeatmapPanels.Count > 0) { var newSelection = - newGroup.BeatmapPanels.Find(p => p.Beatmap.ID == selectedPanel?.Beatmap.ID) ?? + newGroup.BeatmapPanels.Find(p => p.Beatmap.Id == selectedPanel?.Beatmap.Id) ?? newGroup.BeatmapPanels[Math.Min(newGroup.BeatmapPanels.Count - 1, group.BeatmapPanels.IndexOf(selectedPanel))]; selectGroup(newGroup, newSelection); @@ -337,8 +337,8 @@ namespace osu.Game.Screens.Select { foreach (var b in beatmapSet.Beatmaps) { - if (b.Metadata == null) - b.Metadata = beatmapSet.Metadata; + if (b.BeatmapMetadata == null) + b.BeatmapMetadata = beatmapSet.BeatmapMetadata; } return new BeatmapGroup(beatmapSet, manager) diff --git a/osu.Game/Screens/Select/BeatmapDeleteDialog.cs b/osu.Game/Screens/Select/BeatmapDeleteDialog.cs index aa37705cdf..7bd50e1fea 100644 --- a/osu.Game/Screens/Select/BeatmapDeleteDialog.cs +++ b/osu.Game/Screens/Select/BeatmapDeleteDialog.cs @@ -20,7 +20,7 @@ namespace osu.Game.Screens.Select public BeatmapDeleteDialog(BeatmapSetInfo beatmap) { - BodyText = $@"{beatmap.Metadata?.Artist} - {beatmap.Metadata?.Title}"; + BodyText = $@"{beatmap.BeatmapMetadata?.Artist} - {beatmap.BeatmapMetadata?.Title}"; Icon = FontAwesome.fa_trash_o; HeaderText = @"Confirm deletion of"; diff --git a/osu.Game/Screens/Select/BeatmapDetails.cs b/osu.Game/Screens/Select/BeatmapDetails.cs index a98362e89c..9d8c76c1fe 100644 --- a/osu.Game/Screens/Select/BeatmapDetails.cs +++ b/osu.Game/Screens/Select/BeatmapDetails.cs @@ -188,8 +188,8 @@ namespace osu.Game.Screens.Select ratingsContainer.FadeIn(transition_duration); advanced.Beatmap = Beatmap; description.Text = Beatmap.Version; - source.Text = Beatmap.Metadata.Source; - tags.Text = Beatmap.Metadata.Tags; + source.Text = Beatmap.BeatmapMetadata.Source; + tags.Text = Beatmap.BeatmapMetadata.Tags; var requestedBeatmap = Beatmap; if (requestedBeatmap.Metrics == null) @@ -264,7 +264,7 @@ namespace osu.Game.Screens.Select advanced.Beatmap = new BeatmapInfo { StarDifficulty = 0, - Difficulty = new BeatmapDifficulty + BeatmapDifficulty = new BeatmapDifficulty { CircleSize = 0, DrainRate = 0, diff --git a/osu.Game/Screens/Select/BeatmapInfoWedge.cs b/osu.Game/Screens/Select/BeatmapInfoWedge.cs index 76c384b84c..a940c49b07 100644 --- a/osu.Game/Screens/Select/BeatmapInfoWedge.cs +++ b/osu.Game/Screens/Select/BeatmapInfoWedge.cs @@ -90,7 +90,7 @@ namespace osu.Game.Screens.Select public BufferedWedgeInfo(WorkingBeatmap beatmap) { BeatmapInfo beatmapInfo = beatmap.BeatmapInfo; - BeatmapMetadata metadata = beatmapInfo.Metadata ?? beatmap.BeatmapSetInfo?.Metadata ?? new BeatmapMetadata(); + BeatmapMetadata metadata = beatmapInfo.BeatmapMetadata ?? beatmap.BeatmapSetInfo?.BeatmapMetadata ?? new BeatmapMetadata(); List labels = new List(); @@ -114,7 +114,7 @@ namespace osu.Game.Screens.Select })); //get statistics from the current ruleset. - labels.AddRange(beatmapInfo.Ruleset.CreateInstance().GetBeatmapStatistics(beatmap).Select(s => new InfoLabel(s))); + labels.AddRange(beatmapInfo.RulesetInfo.CreateInstance().GetBeatmapStatistics(beatmap).Select(s => new InfoLabel(s))); } PixelSnapping = true; diff --git a/osu.Game/Screens/Select/Details/AdvancedStats.cs b/osu.Game/Screens/Select/Details/AdvancedStats.cs index f1215ab33d..551f67c51b 100644 --- a/osu.Game/Screens/Select/Details/AdvancedStats.cs +++ b/osu.Game/Screens/Select/Details/AdvancedStats.cs @@ -29,20 +29,20 @@ namespace osu.Game.Screens.Select.Details beatmap = value; //mania specific - if ((Beatmap?.Ruleset?.ID ?? 0) == 3) + if ((Beatmap?.RulesetInfo?.Id ?? 0) == 3) { firstValue.Title = "Key Amount"; - firstValue.Value = (int)Math.Round(Beatmap?.Difficulty?.CircleSize ?? 0); + firstValue.Value = (int)Math.Round(Beatmap?.BeatmapDifficulty?.CircleSize ?? 0); } else { firstValue.Title = "Circle Size"; - firstValue.Value = Beatmap?.Difficulty?.CircleSize ?? 0; + firstValue.Value = Beatmap?.BeatmapDifficulty?.CircleSize ?? 0; } - hpDrain.Value = beatmap.Difficulty?.DrainRate ?? 0; - accuracy.Value = beatmap.Difficulty?.OverallDifficulty ?? 0; - approachRate.Value = beatmap.Difficulty?.ApproachRate ?? 0; + hpDrain.Value = beatmap.BeatmapDifficulty?.DrainRate ?? 0; + accuracy.Value = beatmap.BeatmapDifficulty?.OverallDifficulty ?? 0; + approachRate.Value = beatmap.BeatmapDifficulty?.ApproachRate ?? 0; starDifficulty.Value = (float)beatmap.StarDifficulty; } } diff --git a/osu.Game/Screens/Select/FilterCriteria.cs b/osu.Game/Screens/Select/FilterCriteria.cs index a1fea4a41d..f0bf6c94e7 100644 --- a/osu.Game/Screens/Select/FilterCriteria.cs +++ b/osu.Game/Screens/Select/FilterCriteria.cs @@ -23,12 +23,12 @@ namespace osu.Game.Screens.Select { var set = g.BeatmapSet; - bool hasCurrentMode = set.Beatmaps.Any(bm => bm.RulesetID == (Ruleset?.ID ?? 0)); + bool hasCurrentMode = set.Beatmaps.Any(bm => bm.RulesetInfoId == (Ruleset?.Id ?? 0)); bool match = hasCurrentMode; if (!string.IsNullOrEmpty(SearchText)) - match &= set.Metadata.SearchableTerms.Any(term => term.IndexOf(SearchText, StringComparison.InvariantCultureIgnoreCase) >= 0); + match &= set.BeatmapMetadata.SearchableTerms.Any(term => term.IndexOf(SearchText, StringComparison.InvariantCultureIgnoreCase) >= 0); switch (g.State) { @@ -45,13 +45,13 @@ namespace osu.Game.Screens.Select { default: case SortMode.Artist: - groups.Sort((x, y) => string.Compare(x.BeatmapSet.Metadata.Artist, y.BeatmapSet.Metadata.Artist, StringComparison.InvariantCultureIgnoreCase)); + groups.Sort((x, y) => string.Compare(x.BeatmapSet.BeatmapMetadata.Artist, y.BeatmapSet.BeatmapMetadata.Artist, StringComparison.InvariantCultureIgnoreCase)); break; case SortMode.Title: - groups.Sort((x, y) => string.Compare(x.BeatmapSet.Metadata.Title, y.BeatmapSet.Metadata.Title, StringComparison.InvariantCultureIgnoreCase)); + groups.Sort((x, y) => string.Compare(x.BeatmapSet.BeatmapMetadata.Title, y.BeatmapSet.BeatmapMetadata.Title, StringComparison.InvariantCultureIgnoreCase)); break; case SortMode.Author: - groups.Sort((x, y) => string.Compare(x.BeatmapSet.Metadata.Author, y.BeatmapSet.Metadata.Author, StringComparison.InvariantCultureIgnoreCase)); + groups.Sort((x, y) => string.Compare(x.BeatmapSet.BeatmapMetadata.Author, y.BeatmapSet.BeatmapMetadata.Author, StringComparison.InvariantCultureIgnoreCase)); break; case SortMode.Difficulty: groups.Sort((x, y) => x.BeatmapSet.MaxStarDifficulty.CompareTo(y.BeatmapSet.MaxStarDifficulty)); diff --git a/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs b/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs index 7d65b8b648..df08d4e6f6 100644 --- a/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs +++ b/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs @@ -130,7 +130,7 @@ namespace osu.Game.Screens.Select.Leaderboards Scores = null; getScoresRequest?.Cancel(); - if (api == null || Beatmap?.OnlineBeatmapID == null) return; + if (api == null || Beatmap?.BeatmapOnlineInfoId == null) return; loading.Show(); diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 836ed465c3..6b0d9f1eb7 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -238,7 +238,7 @@ namespace osu.Game.Screens.Select // In these cases, the other component has already loaded the beatmap, so we don't need to do so again. if (beatmap?.Equals(Beatmap.Value.BeatmapInfo) != true) { - bool preview = beatmap?.BeatmapSetInfoID != Beatmap.Value.BeatmapInfo.BeatmapSetInfoID; + bool preview = beatmap?.BeatmapSetInfoId != Beatmap.Value.BeatmapInfo.BeatmapSetInfoId; Beatmap.Value = manager.GetWorkingBeatmap(beatmap, Beatmap); ensurePlayingSelected(preview); @@ -261,7 +261,7 @@ namespace osu.Game.Screens.Select } else { - if (beatmap.BeatmapSetInfoID == beatmapNoDebounce?.BeatmapSetInfoID) + if (beatmap.BeatmapSetInfoId == beatmapNoDebounce?.BeatmapSetInfoId) sampleChangeDifficulty.Play(); else sampleChangeBeatmap.Play(); diff --git a/osu.Game/Storyboards/Storyboard.cs b/osu.Game/Storyboards/Storyboard.cs index 59cbe74650..bad31ee55a 100644 --- a/osu.Game/Storyboards/Storyboard.cs +++ b/osu.Game/Storyboards/Storyboard.cs @@ -37,7 +37,7 @@ namespace osu.Game.Storyboards /// public bool ReplacesBackground(BeatmapInfo beatmapInfo) { - var backgroundPath = beatmapInfo.BeatmapSet?.Metadata?.BackgroundFile?.ToLowerInvariant(); + var backgroundPath = beatmapInfo.BeatmapSetInfo?.BeatmapMetadata?.BackgroundFile?.ToLowerInvariant(); if (backgroundPath == null) return false; diff --git a/osu.Game/Tests/Platform/TestStorage.cs b/osu.Game/Tests/Platform/TestStorage.cs index 9f76df2a58..be893f7e9c 100644 --- a/osu.Game/Tests/Platform/TestStorage.cs +++ b/osu.Game/Tests/Platform/TestStorage.cs @@ -1,12 +1,8 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using osu.Framework; +using Microsoft.Data.Sqlite; using osu.Framework.Platform; -using SQLite.Net; -using SQLite.Net.Interop; -using SQLite.Net.Platform.Generic; -using SQLite.Net.Platform.Win32; namespace osu.Game.Tests.Platform { @@ -16,14 +12,9 @@ namespace osu.Game.Tests.Platform { } - public override SQLiteConnection GetDatabase(string name) + public override string GetDatabaseConnectionString(string name) { - ISQLitePlatform platform; - if (RuntimeInfo.IsWindows) - platform = new SQLitePlatformWin32(); - else - platform = new SQLitePlatformGeneric(); - return new SQLiteConnection(platform, @":memory:"); + return "DataSource=:memory:"; } } -} \ No newline at end of file +} diff --git a/osu.Game/Tests/Visual/TestCaseBeatmapDetails.cs b/osu.Game/Tests/Visual/TestCaseBeatmapDetails.cs index cd4d97425b..e126980edf 100644 --- a/osu.Game/Tests/Visual/TestCaseBeatmapDetails.cs +++ b/osu.Game/Tests/Visual/TestCaseBeatmapDetails.cs @@ -24,12 +24,12 @@ namespace osu.Game.Tests.Visual AddStep("beatmap all metrics", () => details.Beatmap = new BeatmapInfo { Version = "All Metrics", - Metadata = new BeatmapMetadata + BeatmapMetadata = new BeatmapMetadata { Source = "osu!lazer", Tags = "this beatmap has all the metrics", }, - Difficulty = new BeatmapDifficulty + BeatmapDifficulty = new BeatmapDifficulty { CircleSize = 7, DrainRate = 1, @@ -48,12 +48,12 @@ namespace osu.Game.Tests.Visual AddStep("beatmap ratings", () => details.Beatmap = new BeatmapInfo { Version = "Only Ratings", - Metadata = new BeatmapMetadata + BeatmapMetadata = new BeatmapMetadata { Source = "osu!lazer", Tags = "this beatmap has ratings metrics but not retries or fails", }, - Difficulty = new BeatmapDifficulty + BeatmapDifficulty = new BeatmapDifficulty { CircleSize = 6, DrainRate = 9, @@ -70,12 +70,12 @@ namespace osu.Game.Tests.Visual AddStep("beatmap fails retries", () => details.Beatmap = new BeatmapInfo { Version = "Only Retries and Fails", - Metadata = new BeatmapMetadata + BeatmapMetadata = new BeatmapMetadata { Source = "osu!lazer", Tags = "this beatmap has retries and fails but no ratings", }, - Difficulty = new BeatmapDifficulty + BeatmapDifficulty = new BeatmapDifficulty { CircleSize = 3.7f, DrainRate = 6, @@ -93,12 +93,12 @@ namespace osu.Game.Tests.Visual AddStep("beatmap no metrics", () => details.Beatmap = new BeatmapInfo { Version = "No Metrics", - Metadata = new BeatmapMetadata + BeatmapMetadata = new BeatmapMetadata { Source = "osu!lazer", Tags = "this beatmap has no metrics", }, - Difficulty = new BeatmapDifficulty + BeatmapDifficulty = new BeatmapDifficulty { CircleSize = 5, DrainRate = 5, diff --git a/osu.Game/Tests/Visual/TestCaseBeatmapSetOverlay.cs b/osu.Game/Tests/Visual/TestCaseBeatmapSetOverlay.cs index 76ed9979ca..e8027978b4 100644 --- a/osu.Game/Tests/Visual/TestCaseBeatmapSetOverlay.cs +++ b/osu.Game/Tests/Visual/TestCaseBeatmapSetOverlay.cs @@ -33,7 +33,7 @@ namespace osu.Game.Tests.Visual { overlay.ShowBeatmapSet(new BeatmapSetInfo { - Metadata = new BeatmapMetadata + BeatmapMetadata = new BeatmapMetadata { Title = @"Lachryma ", Artist = @"Kaneko Chiharu", @@ -64,8 +64,8 @@ namespace osu.Game.Tests.Visual { StarDifficulty = 1.36, Version = @"BASIC", - Ruleset = mania, - Difficulty = new BeatmapDifficulty + RulesetInfo = mania, + BeatmapDifficulty = new BeatmapDifficulty { CircleSize = 4, DrainRate = 6.5f, @@ -92,8 +92,8 @@ namespace osu.Game.Tests.Visual { StarDifficulty = 2.22, Version = @"NOVICE", - Ruleset = mania, - Difficulty = new BeatmapDifficulty + RulesetInfo = mania, + BeatmapDifficulty = new BeatmapDifficulty { CircleSize = 4, DrainRate = 7, @@ -120,8 +120,8 @@ namespace osu.Game.Tests.Visual { StarDifficulty = 3.49, Version = @"ADVANCED", - Ruleset = mania, - Difficulty = new BeatmapDifficulty + RulesetInfo = mania, + BeatmapDifficulty = new BeatmapDifficulty { CircleSize = 4, DrainRate = 7.5f, @@ -148,8 +148,8 @@ namespace osu.Game.Tests.Visual { StarDifficulty = 4.24, Version = @"EXHAUST", - Ruleset = mania, - Difficulty = new BeatmapDifficulty + RulesetInfo = mania, + BeatmapDifficulty = new BeatmapDifficulty { CircleSize = 4, DrainRate = 8, @@ -176,8 +176,8 @@ namespace osu.Game.Tests.Visual { StarDifficulty = 5.26, Version = @"GRAVITY", - Ruleset = mania, - Difficulty = new BeatmapDifficulty + RulesetInfo = mania, + BeatmapDifficulty = new BeatmapDifficulty { CircleSize = 4, DrainRate = 8.5f, @@ -208,7 +208,7 @@ namespace osu.Game.Tests.Visual { overlay.ShowBeatmapSet(new BeatmapSetInfo { - Metadata = new BeatmapMetadata + BeatmapMetadata = new BeatmapMetadata { Title = @"Soumatou Labyrinth", Artist = @"Yunomi with Momobako&miko", @@ -238,8 +238,8 @@ namespace osu.Game.Tests.Visual { StarDifficulty = 1.40, Version = @"yzrin's Kantan", - Ruleset = taiko, - Difficulty = new BeatmapDifficulty + RulesetInfo = taiko, + BeatmapDifficulty = new BeatmapDifficulty { CircleSize = 2, DrainRate = 7, @@ -266,8 +266,8 @@ namespace osu.Game.Tests.Visual { StarDifficulty = 2.23, Version = @"Futsuu", - Ruleset = taiko, - Difficulty = new BeatmapDifficulty + RulesetInfo = taiko, + BeatmapDifficulty = new BeatmapDifficulty { CircleSize = 2, DrainRate = 6, @@ -294,8 +294,8 @@ namespace osu.Game.Tests.Visual { StarDifficulty = 3.19, Version = @"Muzukashii", - Ruleset = taiko, - Difficulty = new BeatmapDifficulty + RulesetInfo = taiko, + BeatmapDifficulty = new BeatmapDifficulty { CircleSize = 2, DrainRate = 6, @@ -322,8 +322,8 @@ namespace osu.Game.Tests.Visual { StarDifficulty = 3.97, Version = @"Charlotte's Oni", - Ruleset = taiko, - Difficulty = new BeatmapDifficulty + RulesetInfo = taiko, + BeatmapDifficulty = new BeatmapDifficulty { CircleSize = 5, DrainRate = 6, @@ -350,8 +350,8 @@ namespace osu.Game.Tests.Visual { StarDifficulty = 5.08, Version = @"Labyrinth Oni", - Ruleset = taiko, - Difficulty = new BeatmapDifficulty + RulesetInfo = taiko, + BeatmapDifficulty = new BeatmapDifficulty { CircleSize = 5, DrainRate = 5, diff --git a/osu.Game/Tests/Visual/TestCaseDirect.cs b/osu.Game/Tests/Visual/TestCaseDirect.cs index 1fb9dbea8f..cb34d28578 100644 --- a/osu.Game/Tests/Visual/TestCaseDirect.cs +++ b/osu.Game/Tests/Visual/TestCaseDirect.cs @@ -41,8 +41,8 @@ namespace osu.Game.Tests.Visual { new BeatmapSetInfo { - OnlineBeatmapSetID = 578332, - Metadata = new BeatmapMetadata + BeatmapSetOnlineInfoId = 578332, + BeatmapMetadata = new BeatmapMetadata { Title = @"OrVid", Artist = @"An", @@ -65,16 +65,16 @@ namespace osu.Game.Tests.Visual { new BeatmapInfo { - Ruleset = ruleset, + RulesetInfo = ruleset, StarDifficulty = 5.35f, - Metadata = new BeatmapMetadata(), + BeatmapMetadata = new BeatmapMetadata(), }, }, }, new BeatmapSetInfo { - OnlineBeatmapSetID = 599627, - Metadata = new BeatmapMetadata + BeatmapSetOnlineInfoId = 599627, + BeatmapMetadata = new BeatmapMetadata { Title = @"tiny lamp", Artist = @"fhana", @@ -97,16 +97,16 @@ namespace osu.Game.Tests.Visual { new BeatmapInfo { - Ruleset = ruleset, + RulesetInfo = ruleset, StarDifficulty = 5.81f, - Metadata = new BeatmapMetadata(), + BeatmapMetadata = new BeatmapMetadata(), }, }, }, new BeatmapSetInfo { - OnlineBeatmapSetID = 513268, - Metadata = new BeatmapMetadata + BeatmapSetOnlineInfoId = 513268, + BeatmapMetadata = new BeatmapMetadata { Title = @"At Gwanghwamun", Artist = @"KYUHYUN", @@ -129,31 +129,31 @@ namespace osu.Game.Tests.Visual { new BeatmapInfo { - Ruleset = ruleset, + RulesetInfo = ruleset, StarDifficulty = 0.9f, - Metadata = new BeatmapMetadata(), + BeatmapMetadata = new BeatmapMetadata(), }, new BeatmapInfo { - Ruleset = ruleset, + RulesetInfo = ruleset, StarDifficulty = 1.1f, }, new BeatmapInfo { - Ruleset = ruleset, + RulesetInfo = ruleset, StarDifficulty = 2.02f, }, new BeatmapInfo { - Ruleset = ruleset, + RulesetInfo = ruleset, StarDifficulty = 3.49f, }, }, }, new BeatmapSetInfo { - OnlineBeatmapSetID = 586841, - Metadata = new BeatmapMetadata + BeatmapSetOnlineInfoId = 586841, + BeatmapMetadata = new BeatmapMetadata { Title = @"RHAPSODY OF BLUE SKY", Artist = @"fhana", @@ -176,43 +176,43 @@ namespace osu.Game.Tests.Visual { new BeatmapInfo { - Ruleset = ruleset, + RulesetInfo = ruleset, StarDifficulty = 1.26f, - Metadata = new BeatmapMetadata(), + BeatmapMetadata = new BeatmapMetadata(), }, new BeatmapInfo { - Ruleset = ruleset, + RulesetInfo = ruleset, StarDifficulty = 2.01f, }, new BeatmapInfo { - Ruleset = ruleset, + RulesetInfo = ruleset, StarDifficulty = 2.87f, }, new BeatmapInfo { - Ruleset = ruleset, + RulesetInfo = ruleset, StarDifficulty = 3.76f, }, new BeatmapInfo { - Ruleset = ruleset, + RulesetInfo = ruleset, StarDifficulty = 3.93f, }, new BeatmapInfo { - Ruleset = ruleset, + RulesetInfo = ruleset, StarDifficulty = 4.37f, }, new BeatmapInfo { - Ruleset = ruleset, + RulesetInfo = ruleset, StarDifficulty = 5.13f, }, new BeatmapInfo { - Ruleset = ruleset, + RulesetInfo = ruleset, StarDifficulty = 5.42f, }, }, diff --git a/osu.Game/Tests/Visual/TestCaseDrawableRoom.cs b/osu.Game/Tests/Visual/TestCaseDrawableRoom.cs index 7113bcbff5..a57bf64c9a 100644 --- a/osu.Game/Tests/Visual/TestCaseDrawableRoom.cs +++ b/osu.Game/Tests/Visual/TestCaseDrawableRoom.cs @@ -43,13 +43,13 @@ namespace osu.Game.Tests.Visual Value = new BeatmapInfo { StarDifficulty = 4.65, - Ruleset = rulesets.GetRuleset(3), - Metadata = new BeatmapMetadata + RulesetInfo = rulesets.GetRuleset(3), + BeatmapMetadata = new BeatmapMetadata { Title = @"Critical Crystal", Artist = @"Seiryu", }, - BeatmapSet = new BeatmapSetInfo + BeatmapSetInfo = new BeatmapSetInfo { OnlineInfo = new BeatmapSetOnlineInfo { @@ -81,13 +81,13 @@ namespace osu.Game.Tests.Visual Value = new BeatmapInfo { StarDifficulty = 1.96, - Ruleset = rulesets.GetRuleset(0), - Metadata = new BeatmapMetadata + RulesetInfo = rulesets.GetRuleset(0), + BeatmapMetadata = new BeatmapMetadata { Title = @"Serendipity", Artist = @"ZAQ", }, - BeatmapSet = new BeatmapSetInfo + BeatmapSetInfo = new BeatmapSetInfo { OnlineInfo = new BeatmapSetOnlineInfo { diff --git a/osu.Game/Tests/Visual/TestCasePlaySongSelect.cs b/osu.Game/Tests/Visual/TestCasePlaySongSelect.cs index feff7497d8..12ac7240d6 100644 --- a/osu.Game/Tests/Visual/TestCasePlaySongSelect.cs +++ b/osu.Game/Tests/Visual/TestCasePlaySongSelect.cs @@ -2,6 +2,7 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System.Collections.Generic; +using System.Linq; using osu.Framework.Allocation; using osu.Framework.MathUtils; using osu.Game.Beatmaps; @@ -37,12 +38,11 @@ namespace osu.Game.Tests.Visual { var storage = new TestStorage(@"TestCasePlaySongSelect"); - var backingDatabase = storage.GetDatabase(@"client"); - backingDatabase.CreateTable(); + var dbConnectionString = storage.GetDatabaseConnectionString(@"client"); - dependencies.Cache(rulesets = new RulesetStore(backingDatabase)); - dependencies.Cache(files = new FileStore(backingDatabase, storage)); - dependencies.Cache(manager = new BeatmapManager(storage, files, backingDatabase, rulesets, null)); + dependencies.Cache(rulesets = new RulesetStore(new OsuDbContext(dbConnectionString))); + dependencies.Cache(files = new FileStore(new OsuDbContext(dbConnectionString), storage)); + dependencies.Cache(manager = new BeatmapManager(storage, files, new OsuDbContext(dbConnectionString), rulesets, null)); for (int i = 0; i < 100; i += 10) manager.Import(createTestBeatmapSet(i)); @@ -60,11 +60,11 @@ namespace osu.Game.Tests.Visual { return new BeatmapSetInfo { - OnlineBeatmapSetID = 1234 + i, + BeatmapSetOnlineInfoId = 1234 + i, Hash = "d8e8fca2dc0f896fd7cb4cb0031ba249", - Metadata = new BeatmapMetadata + BeatmapMetadata = new BeatmapMetadata { - OnlineBeatmapSetID = 1234 + i, + BeatmapSetOnlineInfoId = 1234 + i, // Create random metadata, then we can check if sorting works based on these Artist = "MONACA " + RNG.Next(0, 9), Title = "Black Song " + RNG.Next(0, 9), @@ -74,33 +74,33 @@ namespace osu.Game.Tests.Visual { new BeatmapInfo { - OnlineBeatmapID = 1234 + i, - Ruleset = rulesets.Query().First(), + BeatmapOnlineInfoId = 1234 + i, + RulesetInfo = rulesets.QueryRulesets().First(), Path = "normal.osu", Version = "Normal", - Difficulty = new BeatmapDifficulty + BeatmapDifficulty = new BeatmapDifficulty { OverallDifficulty = 3.5f, } }, new BeatmapInfo { - OnlineBeatmapID = 1235 + i, - Ruleset = rulesets.Query().First(), + BeatmapOnlineInfoId = 1235 + i, + RulesetInfo = rulesets.QueryRulesets().First(), Path = "hard.osu", Version = "Hard", - Difficulty = new BeatmapDifficulty + BeatmapDifficulty = new BeatmapDifficulty { OverallDifficulty = 5, } }, new BeatmapInfo { - OnlineBeatmapID = 1236 + i, - Ruleset = rulesets.Query().First(), + BeatmapOnlineInfoId = 1236 + i, + RulesetInfo = rulesets.QueryRulesets().First(), Path = "insane.osu", Version = "Insane", - Difficulty = new BeatmapDifficulty + BeatmapDifficulty = new BeatmapDifficulty { OverallDifficulty = 7, } diff --git a/osu.Game/Tests/Visual/TestCasePlayer.cs b/osu.Game/Tests/Visual/TestCasePlayer.cs index 4a25a52e36..98c573f62c 100644 --- a/osu.Game/Tests/Visual/TestCasePlayer.cs +++ b/osu.Game/Tests/Visual/TestCasePlayer.cs @@ -39,10 +39,11 @@ namespace osu.Game.Tests.Visual Colour = Color4.Black, }); - foreach (var r in rulesets.Query()) + var queryRulesets = rulesets.QueryRulesets(r=>true); + foreach (var r in queryRulesets) AddStep(r.Name, () => loadPlayerFor(r)); - loadPlayerFor(rulesets.Query().First()); + loadPlayerFor(queryRulesets.First()); } protected virtual Beatmap CreateBeatmap() @@ -60,7 +61,7 @@ namespace osu.Game.Tests.Visual { var beatmap = CreateBeatmap(); - beatmap.BeatmapInfo.Ruleset = r; + beatmap.BeatmapInfo.RulesetInfo = r; var instance = r.CreateInstance(); diff --git a/osu.Game/Tests/Visual/TestCaseResults.cs b/osu.Game/Tests/Visual/TestCaseResults.cs index 62154a535a..a0146de7d0 100644 --- a/osu.Game/Tests/Visual/TestCaseResults.cs +++ b/osu.Game/Tests/Visual/TestCaseResults.cs @@ -31,7 +31,7 @@ namespace osu.Game.Tests.Visual if (beatmap == null) { - var beatmapInfo = beatmaps.QueryBeatmap(b => b.RulesetID == 0); + var beatmapInfo = beatmaps.QueryBeatmap(b => b.RulesetInfoId == 0); if (beatmapInfo != null) beatmap = beatmaps.GetWorkingBeatmap(beatmapInfo); } diff --git a/osu.Game/Tests/Visual/TestCaseRoomInspector.cs b/osu.Game/Tests/Visual/TestCaseRoomInspector.cs index dd773b361a..41b722841c 100644 --- a/osu.Game/Tests/Visual/TestCaseRoomInspector.cs +++ b/osu.Game/Tests/Visual/TestCaseRoomInspector.cs @@ -32,14 +32,14 @@ namespace osu.Game.Tests.Visual Value = new BeatmapInfo { StarDifficulty = 3.7, - Ruleset = rulesets.GetRuleset(3), - Metadata = new BeatmapMetadata + RulesetInfo = rulesets.GetRuleset(3), + BeatmapMetadata = new BeatmapMetadata { Title = @"Platina", Artist = @"Maaya Sakamoto", Author = @"uwutm8", }, - BeatmapSet = new BeatmapSetInfo + BeatmapSetInfo = new BeatmapSetInfo { OnlineInfo = new BeatmapSetOnlineInfo { @@ -99,14 +99,14 @@ namespace osu.Game.Tests.Visual Value = new BeatmapInfo { StarDifficulty = 7.07, - Ruleset = rulesets.GetRuleset(0), - Metadata = new BeatmapMetadata + RulesetInfo = rulesets.GetRuleset(0), + BeatmapMetadata = new BeatmapMetadata { Title = @"FREEDOM DIVE", Artist = @"xi", Author = @"Nakagawa-Kanon", }, - BeatmapSet = new BeatmapSetInfo + BeatmapSetInfo = new BeatmapSetInfo { OnlineInfo = new BeatmapSetOnlineInfo { diff --git a/osu.Game/Tests/Visual/TestCaseScrollingPlayfield.cs b/osu.Game/Tests/Visual/TestCaseScrollingPlayfield.cs index d0761e5841..29623fb05f 100644 --- a/osu.Game/Tests/Visual/TestCaseScrollingPlayfield.cs +++ b/osu.Game/Tests/Visual/TestCaseScrollingPlayfield.cs @@ -48,8 +48,8 @@ namespace osu.Game.Tests.Visual HitObjects = objects, BeatmapInfo = new BeatmapInfo { - Difficulty = new BeatmapDifficulty(), - Metadata = new BeatmapMetadata() + BeatmapDifficulty = new BeatmapDifficulty(), + BeatmapMetadata = new BeatmapMetadata() } }; diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index bdca48ccdf..afccbe9dc1 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -124,6 +124,49 @@ $(SolutionDir)\packages\DotNetZip.1.10.1\lib\net20\DotNetZip.dll True + + + ..\packages\Microsoft.Data.Sqlite.Core.2.0.0\lib\netstandard2.0\Microsoft.Data.Sqlite.dll + + + ..\packages\Microsoft.EntityFrameworkCore.2.0.0\lib\netstandard2.0\Microsoft.EntityFrameworkCore.dll + + + ..\packages\Microsoft.EntityFrameworkCore.Design.2.0.0\lib\net461\Microsoft.EntityFrameworkCore.Design.dll + + + ..\packages\Microsoft.EntityFrameworkCore.Relational.2.0.0\lib\netstandard2.0\Microsoft.EntityFrameworkCore.Relational.dll + + + ..\packages\Microsoft.EntityFrameworkCore.Sqlite.Core.2.0.0\lib\netstandard2.0\Microsoft.EntityFrameworkCore.Sqlite.dll + + + ..\packages\Microsoft.Extensions.Caching.Abstractions.2.0.0\lib\netstandard2.0\Microsoft.Extensions.Caching.Abstractions.dll + + + ..\packages\Microsoft.Extensions.Caching.Memory.2.0.0\lib\netstandard2.0\Microsoft.Extensions.Caching.Memory.dll + + + ..\packages\Microsoft.Extensions.Configuration.Abstractions.2.0.0\lib\netstandard2.0\Microsoft.Extensions.Configuration.Abstractions.dll + + + ..\packages\Microsoft.Extensions.DependencyInjection.2.0.0\lib\netstandard2.0\Microsoft.Extensions.DependencyInjection.dll + + + ..\packages\Microsoft.Extensions.DependencyInjection.Abstractions.2.0.0\lib\netstandard2.0\Microsoft.Extensions.DependencyInjection.Abstractions.dll + + + ..\packages\Microsoft.Extensions.Logging.2.0.0\lib\netstandard2.0\Microsoft.Extensions.Logging.dll + + + ..\packages\Microsoft.Extensions.Logging.Abstractions.2.0.0\lib\netstandard2.0\Microsoft.Extensions.Logging.Abstractions.dll + + + ..\packages\Microsoft.Extensions.Options.2.0.0\lib\netstandard2.0\Microsoft.Extensions.Options.dll + + + ..\packages\Microsoft.Extensions.Primitives.2.0.0\lib\netstandard2.0\Microsoft.Extensions.Primitives.dll + $(SolutionDir)\packages\Mono.Cecil.0.9.6.4\lib\net45\Mono.Cecil.dll True @@ -157,6 +200,9 @@ $(SolutionDir)\packages\OpenTK.3.0.0-git00009\lib\net20\OpenTK.dll True + + ..\packages\Remotion.Linq.2.1.2\lib\net45\Remotion.Linq.dll + $(SolutionDir)\packages\SharpCompress.0.18.1\lib\net45\SharpCompress.dll True @@ -165,29 +211,43 @@ $(SolutionDir)\packages\Splat.2.0.0\lib\Net45\Splat.dll True - - $(SolutionDir)\packages\SQLite.Net.Core-PCL.3.1.1\lib\portable-win8+net45+wp8+wpa81+MonoAndroid1+MonoTouch1\SQLite.Net.dll - True + + ..\packages\SQLitePCLRaw.bundle_green.1.1.8\lib\net45\SQLitePCLRaw.batteries_green.dll - - $(SolutionDir)\packages\SQLite.Net-PCL.3.1.1\lib\net40\SQLite.Net.Platform.Generic.dll - True + + ..\packages\SQLitePCLRaw.bundle_green.1.1.8\lib\net45\SQLitePCLRaw.batteries_v2.dll - - $(SolutionDir)\packages\SQLite.Net-PCL.3.1.1\lib\net4\SQLite.Net.Platform.Win32.dll - True + + ..\packages\SQLitePCLRaw.core.1.1.8\lib\net45\SQLitePCLRaw.core.dll - - $(SolutionDir)\packages\SQLiteNetExtensions.1.3.0\lib\portable-net45+netcore45+wpa81+wp8+MonoAndroid1+MonoTouch1\SQLiteNetExtensions.dll - True + + ..\packages\SQLitePCLRaw.provider.e_sqlite3.net45.1.1.8\lib\net45\SQLitePCLRaw.provider.e_sqlite3.dll $(SolutionDir)\packages\squirrel.windows.1.7.8\lib\Net45\Squirrel.dll True + + ..\packages\System.Collections.Immutable.1.4.0\lib\netstandard2.0\System.Collections.Immutable.dll + + + ..\packages\System.ComponentModel.Annotations.4.4.0\lib\net461\System.ComponentModel.Annotations.dll + + + + + + ..\packages\System.Diagnostics.DiagnosticSource.4.4.1\lib\net46\System.Diagnostics.DiagnosticSource.dll + + + ..\packages\System.Interactive.Async.3.1.1\lib\net46\System.Interactive.Async.dll + + + ..\packages\System.Runtime.CompilerServices.Unsafe.4.4.0\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll + @@ -287,7 +347,7 @@ - + @@ -800,6 +860,9 @@ + + + + + + + + + + diff --git a/osu.Game/OsuGameDesktop.cs b/osu.Desktop/OsuGameDesktop.cs similarity index 95% rename from osu.Game/OsuGameDesktop.cs rename to osu.Desktop/OsuGameDesktop.cs index 47e64a0d5b..f4fb10a496 100644 --- a/osu.Game/OsuGameDesktop.cs +++ b/osu.Desktop/OsuGameDesktop.cs @@ -9,12 +9,13 @@ using System.Reflection; using System.Threading.Tasks; using System.Windows.Forms; using Microsoft.Win32; +using osu.Desktop.Overlays; using osu.Framework.Graphics.Containers; using osu.Framework.Platform; -using osu.Game.Overlays; +using osu.Game; using osu.Game.Screens.Menu; -namespace osu.Game +namespace osu.Desktop { internal class OsuGameDesktop : OsuGame { diff --git a/osu.Game/OsuTestBrowser.cs b/osu.Desktop/OsuTestBrowser.cs similarity index 92% rename from osu.Game/OsuTestBrowser.cs rename to osu.Desktop/OsuTestBrowser.cs index b0864e441f..23617de1c0 100644 --- a/osu.Game/OsuTestBrowser.cs +++ b/osu.Desktop/OsuTestBrowser.cs @@ -3,9 +3,10 @@ using osu.Framework.Platform; using osu.Framework.Testing; +using osu.Game; using osu.Game.Screens.Backgrounds; -namespace osu.Game +namespace osu.Desktop { internal class OsuTestBrowser : OsuGameBase { diff --git a/osu.Game/Overlays/VersionManager.cs b/osu.Desktop/Overlays/VersionManager.cs similarity index 96% rename from osu.Game/Overlays/VersionManager.cs rename to osu.Desktop/Overlays/VersionManager.cs index 7b0b3520cb..e7c3370354 100644 --- a/osu.Game/Overlays/VersionManager.cs +++ b/osu.Desktop/Overlays/VersionManager.cs @@ -13,15 +13,17 @@ using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; using osu.Framework.Logging; +using osu.Game; using osu.Game.Configuration; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; +using osu.Game.Overlays; using osu.Game.Overlays.Notifications; using OpenTK; using OpenTK.Graphics; using Squirrel; -namespace osu.Game.Overlays +namespace osu.Desktop.Overlays { public class VersionManager : OverlayContainer { diff --git a/osu.Game/Program.cs b/osu.Desktop/Program.cs similarity index 95% rename from osu.Game/Program.cs rename to osu.Desktop/Program.cs index 8044e9fa87..720b38144c 100644 --- a/osu.Game/Program.cs +++ b/osu.Desktop/Program.cs @@ -8,7 +8,7 @@ using osu.Framework; using osu.Framework.Platform; using osu.Game.IPC; -namespace osu.Game +namespace osu.Desktop { public static class Program { diff --git a/osu.Desktop/Properties/AssemblyInfo.cs b/osu.Desktop/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..fe7ad20124 --- /dev/null +++ b/osu.Desktop/Properties/AssemblyInfo.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.Reflection; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("osu!lazer")] +[assembly: AssemblyDescription("click the circles. to the beat.")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("ppy Pty Ltd")] +[assembly: AssemblyProduct("osu!lazer")] +[assembly: AssemblyCopyright("ppy Pty Ltd 2007-2017")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("55e28cb2-7b6c-4595-8dcc-9871d8aad7e9")] + +[assembly: AssemblyVersion("0.0.0")] +[assembly: AssemblyFileVersion("0.0.0")] diff --git a/osu.Desktop/Properties/app.manifest b/osu.Desktop/Properties/app.manifest new file mode 100644 index 0000000000..555db8513d --- /dev/null +++ b/osu.Desktop/Properties/app.manifest @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + + + + + + + + diff --git a/osu.Desktop/app.config b/osu.Desktop/app.config new file mode 100644 index 0000000000..824430b24a --- /dev/null +++ b/osu.Desktop/app.config @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/osu.Game/lazer.ico b/osu.Desktop/lazer.ico similarity index 100% rename from osu.Game/lazer.ico rename to osu.Desktop/lazer.ico diff --git a/osu.Desktop/osu!.res b/osu.Desktop/osu!.res new file mode 100644 index 0000000000000000000000000000000000000000..7c70e30401fc50ef59dc7b34bb4c834175a957a9 GIT binary patch literal 156596 zcmeFZbzD`=_dhyxAG!ntL=g$;mJkpDkrHeH0TGK50qKyEE-C4dkOl>%QIIZ`&O_Is z8_t~rkI(abKfmwqck6Xu_x^Dg%$~hx)_birv1iYFZxH|h*kD4VPZB)+FEWe$ryd9D zU>(;9Q2e991y9*vl7|Tk;KCySZV>ZF{-uhkIsOH1ZkRKe;18w<9%^c8Ue^;Qf%bLwvA2)5w?9!J-*L8c_JKcv zCkjxz*S^=M&(1d*qX4U6y>B4Y==Fsb(7tx|eZKG~5av)}r?AE!HbK0P4^%&{$2fuYfzCb{{EjbdBgFgK+d+32bsy*nUiUd;6fyEwec(wv zKE6Jf7Vq>qV=TgWVI;@#+XdPmx6k>weQ4jlK6{@Nh%am}Ic$F~Mxz&of$33nV4$xv zY&|9{%n-l`V11x{@1G8b7GS-P4+ed#u;Ux(>>TL(_lTXe4Ku=j$$yOJpJGgo8ENzw z!SQrB0>JeE0J$9iSYagOV*n7;0D$u+xxuOUe6N6kzUylL`Kx_W=d0$LRdI4{G4~AHmf9BW`fg!z(!Nk283Lr~gOqgTFcq28HQ& zLQKa%a4?(*!8`EMH`uoiy+XJHvz=f!I6vSSX5It_?*wD=9jJLck9L9sgVE&h=(~en zAxH1@?O=u`cn6LUZ22F%VCTdSrs>e#fgAuUW{y2y=oB;2Qk>LHKaS-=#61+E>1PLb7An^$jBt9PliDr`^@zE?u zGMxcQ&yXPL#TZC>ItfzDCqbG8EHj-2DQ0sZ?dd#7e=!g9MUe4)8Dv^4gH+22koIx{ zq}#w`ISn#wra`7HOpfCq%YF*vxJ-duS6FT}3$k9#fh;Q&$ay^nK03^SJm-0kYrhQg zT^B*2D+*+quYhdJHSp1T9pt`RhxrD`v)KX#POG5MVG9&FZ-4^Z9Z+Py3rZaKL5afw z_~dj1a@@wjM~`uk=LM6;6v+3Q1o`fBpy16kDD*{w;@}BTI zH84G}31)^j!R*K;nEJH?X8L!)?7%LV8{Pp6BL`r9d=o59ZG*+}U9da_6Y>D8%x!~} z>3y&=bp+3M!P?RuSe-op8_S1aZEX!~ZEb>6n!SE-`=~ zAb=L21(tvb;@Kgd6XJOxUX~IKZVRG;l{Oj#SV3E%Xi!~<1_NFH;7=BW|EtITfw8d( zC}U#-{r|f*`o|`aDAdIG`1r&G3Z9JpFCha^dA#dumZOcixs82vQO76>IWh1*bJ9P7 zM0O^>lo1y@78(TN)UAvjBx>Tn_c4G(_C#|cSWmRYSP=*W4HL6aOb-(I-?NjfQ zKL8V`E@wFyF%)u9F*X_s3K|3j6BEm^GiKF}{{W1kI#fj2j@1zeCNVK)3UYFCCMaw$ zI8kD3?he$yLmET%-b9d-BS?s#5F^;c*myh`C}?PDnV>T<8d#|M`(JGsK#sp=BE?uI z!p6qJC7}_eG3+?UM1vs3BViIdar&A%-}Hb zCwGPt>VLXkn;%x19$f5Jrm0cW{D=V#A*+}u>yw|DF_=IVF*C6;AM4YQsuX^IaPOmU zduMlBePDq`SWE0F7(N9vGaD`|H@(0HOhk(*jp zVk{~uifJn|GX;_Iu|6{X@@33u9SgILu2=QPUvLdVO?)pccx3$o-Y>`M%rxW%$MK-D z<)uVfPSk1X?pA-kpP$~-H~i~+dT?}8y4FRp6Z5R1Y;ni^iK>)?vkhZ|iCV3sBSN(# zvaFz}qBuV+{jFAcN07jYc{Wk@&nVblc&E#ViHnNCyPVnQSCKGFYNTIrVO(WqWSxG| zBX-Bu7Cj6Anio2`>ye|DCrcDF(=Gec%uIY*E%p_!Yh#k)iUs&sMWx^CVD#BUMJ-36 zc{l*5jAQ*jZDzUNQ<+UW7=f}b(CMTDP2?wL!BZ65qj>mw4g4UqZOkCQs zN!pY(rsc5|+p#(;o2ZmU?}WI~F7||02stoJ=&#{4`MX zJ2`1Zr7k^{l#)AZwwf#$-i4`uLP;P$arC^qnlwuRRte~K9SwTK({BQHe z5viX5SVdW(HVlECg_(j46TK|dSCDu5{g3%$4{gerKxJjc*qA6NFh=FYpaa+mqL}lS zo&QB06H=QxEfbTZlqef31r4*Df`S|~Et@E&H>DIV+x@3H2Jq`X1FIyQy==@B6ru_W zq7=;VoE1(4nRov+7#I%}ByuEFTTVS*3Pt-9np-{+? z#$2yER}_`h4ZJ?KjX>LfM)lvO|2~J+m|JmtXlVR+5&BWsn^y8m?{nO8X^?N4azj-V!#@heDW7%MtJWPM{*b_Baa$IqCnL<48NQQ z)$#L?V=jVH?-fw$z6HtySHTy5$SM7Iz}HX=pIimi@76$7=oY9B*#$KT^Pnbn8KzZG z7rzR*=l&*k|!VS>*X%%#T+63L@t0(-i4D!b>kUv&#fS%GF&{wq!dg~xx zY+QkSaRUrCK+f0%d1A}@F;^UE*#x6)+hDMEAB=XbLY}w<#@coOvUd$k{KW7>$O#7_ zCxpCkqI2h%7fy8_9P`5YVaN^p55VFmOi0KJCt;d^yl`?4EKfi_I0Jd%%mG-P-v#T- zdthzu=pR0~e!>NJwhm6X;NAh`f(PIba=`*123eduTtid=n({6{3t9rSwl_dqy$9&f zB7iRZ0nlBefAc_o_(n(zVl06=WPwHyZx8W75T6F|#SmWw@r@AQ1@S`=KLznCf8%)} zkGuvgJb@N`poMg3;TyCt4lS%uqQROV8f<8z!Il*oY=@%3ZXp`%cm2a7nIN7I;^iRz z|HC}Cu(+h4Ag`dfxbW|lxQ$rz-ckr5LUP{AnhSksIC3hfRR zF|>}w^pt=|+JlNr!h{IpjZnGZSfM!b3^f%IAt5e-w$mN3~mt; zbMpvilmJljhMJq2ii%v>&%nUgFDTH@!dcDQj+qbvxj`7LFTPC$tEs4nnGG#1V~dNj z-#&MdBO)ZGrlzC52LmX$jH!ieg~izHT}gFyb(ZC0LsCKnrt~rlAWsT&cHY9`nc0g} zSY2HdZuRW(qsJJrh7HWS&Ok#&#eVtnWrHWNnEHZX%ZE2^=v>vgs&EV93m%9tU@TB^ z7(EZnt*$PKv9`Oz!%Yo^SQ^$BJMm-Ury^JMG_?pyPm8vG=52R@9#+#Z+=cO#gz@q) zGBU7RdCQoX`uqEPcsO5v9ijy585q5*VSTay98MbA%d}Kn-VUx_u5P!_GG3RVrl#i+ zN`&nP1-d*ujL-vu%E;lmuDhm8fG`gg2F~wzJU%56d^|MN)KrM`A%fhRUfdUb9C(hc z^TlD{prqg)1FWW|;*fzo;!Vw?p?47qKmW@D=pLhxE(YzvUt(h7^Qs8?i#*&Sa6ftT z!!aDA5XDJF&CSa|M$E&{&qKw-Kz&hER6F5MHAX>@&tVz_wRiSynynb@8c<885>N0 z_A&DRdIt{+|CYQLXixyx*diPF-tRRUzMDpaGB-4+@`vy40??o)5WWk9>+i@nG?;8h zpS+(O+=cHZ_rb#O0a%*ef$t#Ub7pB5Y@lF1e*iYu_Q2N0F4$Uy&zr41`0nul?CtJ> z{hg!Z^}lQ3pLHDY@&j;93ji}q0K7v0NG|}Oz5{^q6+nqX1Hn}^&|Zh{6gSZzbQ=u{ zchR70|6h21b^x@*0kBjDAjB9>{nr3=1jEg62B1Wj06}yW&_@3NR_GoOiXH-m=qb2k}-A?*sAi5MKoGO%VUja}XPbj|;=c zhv5^#@QGpgBrtr$3haM06_7y-f_rFf@EY2QMu&n@bRqbOhR?*m-lx(){247cewF~p zgaDvk0KgrHf4l;KJ(?1{h4}Xnp9k?Z5Z?{)lmEhVLcF{d0Cz0`un7Smr~rU0h_71# zFiuL)2k|2ikA(O+h(|&E*1z!loUr+qVe{|7=G(yL2f^lN!RFV)t#&shK=%m(^sqKS zPg()=d?-M#6aw^C*WdB;(?C4zI!ghFmxcK25D#swJc0PvlmPu!5TN6=0Xp9bpld^+ z%|d{l>iP!{`GFSPV_V`wJQ2jh??xS@5D$k1%|->#vVs78UmKtutN=PH6rev90`$+W zfAGg|qv_!;fF154c;GJL|KG>_pL-uqPeV=r_i_Lz5wuKd@bG&HA9PXF(I7d@W> z?{R4AFdq3PAF*s?ud$`+-Gg z0=M^%V$c>2{Db!#G*wji)3mVJiDXo0NeGyed{gWatQ{K14P-VVZfH|#X(&DEPUAdF zL8YU@7O|oKXm#8%gd7_&8I*vbK`DUm1Hn0&r+#-f zPX{;hMzvg5OYf#4#QnHomT^_sxj_lFFxOR+_(Aci&zIi03Y)Uom7Z}zd`}IBk_$9% zHKbe#WKb*nhb%Vj8hd<9l{0Bq#a$Cldn(G%b3~j91T_L|Mq+p@4xb0(uae$Yzlv8W z;~lhWqf3GFu5*-Rw%iZF!E)*iV?6nljY}Jns@rkxv^={wgr3-}r==Ec`et?cHVW~j zp3X{K0XI}pdOhn6@7}%Js;g7L_pQ7)N{(xj-@tKpjautW{mmoHA`4tWz z@J;EUUS~k9@wU-U%(q37*-*`G-D)qy?{!y73vK|MB$sYt~y2{;?} z-a)nw%dGQOE(uR?0e(y$`&EK#D}^?#>BbjW)@LhMzmbySHYdNEzf)oRn5cVWt9=RQsR+oQ*pJC-CfGeM6=}^ee-kSW~mCvJ0`fKMOQgM$mO@+1|=88{1ft%8})3|Q|mWgN3Lb*aH%uD zkWk_m?=DP8Kz(Rzrxa#?DN@8GEMKDa>vZtrio3a{-qjvKuWcp+RrXr7zQy#ZH8$ED zcm@TEeEu-Eg4pcymJS5+Z@+a{RaOowl!WNJxCi;qGAR1%i2gL*=cR6w-Y1oqF{Ebc z=()#gsKlcZqYT(oCl;kY^xVnonY-Dw&SW;um-3m9gZpSq=bO?P>GucLY2Ohx;67mjmNc2{(3_E1moj5>GYphbY6* z1cFG%%8@L!^fmvI%-g>bRf3z7Pv1JIU9-X_<`8@iY0{oz;jD+yPBS- zo*mO3qZ&RfJPfjvNDem&XMP$|zqoexo!Pd>42C4imzp1W^y^8HMVz8FA;pyvjlk!N z;AGLIlll3Y(`@a!);+R~gwx!qbk=(x-&aME@Vw0nRP_FEn|m1XcCO;SfP;9wov;fp__4QQ(sydsHf>#4$T3Na`&-#gDR3jCz}+GA zW4O+a;kZHEwY=OR`Zr>-C(aTFn8;it1 z36iTR_zYO!a)~^z&3!dZR7xXWiOSC>iMnSBotIw}*WVcqXipWjeE*T2l(nRso!s)F z8#A}0u;Vs+uz>UJ<`!Jfy}k^Tk>MR>b6(->yQ#`{Qi@zs1`{#hqpx>OD~f!lUcSbS zVxyiuZHDv|aX04=_0EVp58rFyuSXCwDAR{tczBlV;flb!hJ|Ef@&~;ZbM~G=L6`Se znbSK&fhBfu$IQJnEw1I{?**|4<1N>Sl2^g><~lPmz2iyN z5h&*Qn(n0ZDC(6e%A9k1uYz!=IJLisE=lK{#tTCU!UFs{w8A(C#oI0fA!&uX0NVp)c> zTX17>JXDhEuG?L*?zek~q|ZRIVaJN2(k+S%FW~FjGB@E5xBs=f;VG8`m>6KI9x+ip5Km2AMfI!thJ<0|oJYgSqIa z>(X*cI{m}l7ow|{kkpp(&*gtCyT6UF3)I02RJcNAa3QVgetWyrt{dqn^5Ekh^|~;j zNjMENt=9L?!(KRoY<%0w42X|dq2m;!-e*o-R+47xslAG7Q9m`?5XI&?q7?msnt>)( zN%zb>npN_}WF$Qq8JWeq$VkZ|sTfJ+L?$psDyy(};cQ#gb^d(+pCgaQeL!^&*-17<5b{**A2s1E#h?jxKi3{#!rIZkg=vA`)1CiuDrwolv%FlvI^14 z{EtmJJ~pntGKeFK-{?$B3u@G?` z;Je@ElNYe`b}=v`urbHSWyN8_a+e-UuMbYTi&)w*qTx-zUg$?AH;MZ@d8ywx`@AeT zZ*B(H7M=9$6{2|(!S0-a#b&hdGIGSu49nGTq{!qz{NQrg!eHl77g3+AES{_Jc?EM; zk+gwlsuRVEn(S%Ld+My$KJM)wdd3abnF49N)QF&s;Hz~_O##Hu997gJ}P#51c zeEJNwTRpNsb`3}7XSFPH1|l*J`JH$N_gmCZCuGV z_%tT>p>I1CO{bwWB6%bEqR`{#??dyHSi3FIA$hLrkJHO$g|Wcm6#s<_yFxODSi{lU zF;e-X(+c|uNV7o)LbD>pe64!2Jhz3iNq*w6rXwHV7A#l$M^u6*T?P$0h$M>oZ+V>*&2} z;|qe+(W_+&b$1xt{MB*4_WIq7V#!|h;(8#>`i{|9=%$^#@fe+nYr)`BwLo0kbx$$& zJ4p{oKqv*P-R!R5a6rzSO0}C$bjzLIx3S`KZ=5?+Z_`Re|CAaZyK!alV1&AXv_4FD zaCJxB>o7o>BY@MG_53;M{zWlqGwsI15yPyb$_vEUm#SCu5^D^YhkGgW?oO^e{Ltc_ z5p>hO)cUq6HP=`Bi#F-6882uC(a=?@V9&~Zyt$zI?VS#SNvWJaRQ3ftm%Bj0}mG9%tDarY{5es^i zMbs>C!Trte-?z&>D{}XC>pPbh`uY*Phs8@fElO2#n$*Jn`iXs~ZKdL87Z=qp^8R4- zxD)4|5LDf_FfL&FGqj&|clNX(p@gK3ici#ztVI`1#K#zd7kBmsYj0c2< zbbNhifzqYJC~C!{_nZz!Us^k89okT=%9}hW4&6~APaTp<9loE3X1jdC>X$Oc_uE?& zm!4OsPwfk*79cIy2u?p^YI=hgvzJ5t19x*~2kBU!+&XfNEjw%DsES`FXfeuXY}`8S z3=Z+F4);gPxLw-&u#R_#bBGJ`8?8T+jAh zmCVaeAAF=cm!y}um$_fpq!d>CdEGxI>=&BX;AKOd3-kJ8?@)!-15#`qS8@G#`3$av z4NWD#HJY-=$!~RC+qp_!Kd`)jEx;S=o1*tJ>7qco%*`N*&iYCb?`ra>(>V3mz>NLr z><;nu`QRsov>#qx)R>)<(Df2_btNC64iw-PscZTWl(yW!fru+iRi&feGS-tE4626n z^0wzgity$n(o4_rS47p)M_ysaBxUY~^9q`6|5n) z0Mt(k{pcpO>W*eIdvFl)doJ9@L|h~StNArZBKj4ETNck5Uc67-ElDrEH~)EAaX9B| z^5RNOWsX>%{e6k z-b=kwlXloJGd@~gvl~(JLYmZBi=El|e&PAj+dlN-p7OeT!p6##6a6Zn zS*b6$k+aUF;ipu*l}gA0ZdzEx)Vibwx4*D=WDDu&J2Yzt+y+s!obEWXvrT8Y z^rh*!pE(SVn>m+siyqw4)6>)NlyAodIfo@+Iq6E|>2>N-tv@Ar>b3_21= zYFc2;OFh(?Q<^&6JJaHDl#sSA$Z=)qzDs~Za?Bm!M^q+4i;eoO@0{i+u1ZNB)6Te0_MKwWVR_Ome;a0(A@i@Rl{lHN9}?(_CH|PD)<2R6sxmoCCM?VPTvPcR z&$Z{jv4zHIT21IUW6}+fke~e;V-Xlbt)Zl#;2UN-TL)>haxZ^<=)Q2 z(Uk8M8!Z=FnHX@PMt^gJh>N$hCzs#{bSiw*9r;arLa^|H0K>ytbyZi+(>OTtMVzWy zJ9rYhvu_j`-FEBla8(#)^d0f)rIhDnh+1#+r+x$s!TLfPo zhU>_XTcql3c59SW6_b01P$?U^gf{Yz>!iDZYhvy43w+}#Pip6QN8o)XVbWyWYIxzJ zCB77MxBn=W7oKqrh4F<4jRwJ^Y#HK|>mP_c7U{>d*gf6I^cmh=zq}e-uEn4;N)elf zVqmd5*lCm-u|^+m&nPt*<^i{WwAM>T*>Y6t9jcpWD^yLVUf$~}JR}UTCL_K7jbqVy zZWZP3o9^mrD=O@oji^DCuA46YQU^Q3tM)5;ha=UYSwqCXJB?n7 z>#%Q;yjjN^nk6kuejuSgNs`%`6-j@!$D3%wOp3gU<}y&z`9z z{d;^eNnj}>m%M3VrhPyBsb1pOESwJsP6W%E+z)R)MLO)I>$v*I#rQKmWAo7|kyH^1 zyL2N+?p+yt#{4Sq%nvLDS;kAbcpDm>l#ay8196XeRwu{O6WDB=U=H{y239SO{#j-Dj;_Q^}WsiU5vrgclSzkw1{s!&S|^#i3|3yw$aLB$A#$D z`(#Q@-iJEuzi}CG2b^)S(}*JUzluD1=_XA=N$6yO8mV->TVQzEHco9r{ITL{>QI{x z-O=~OjccMqjfmzJb-xQFrcx(mH(G^Bm7|DvQp3~@y< zlpPBg1{g<}yV$l-)+^#gi~Nh?W7{0xFZnUw z!%U*3Rk_>W+G~ymd^R~vTa_67VhEFk%2t?7zCL;#Q8pOTGo#G(1UuFXsWe|u7g8}z zX+`WJpR}ik?OyLGw8L=924v>tUF3qhSw6v^ud+&(r_Uxf(|<~K?s18p8rRXk;w|O2 z%~>U0I9KiGE7yCkuFwQ!q5YV9k^aF>|I;5`tgEjC2}#o`S9Wgik&DRU*V$yVrk)%0 zRCP%vD(hOdyZqUS_$_~YqRu(?&+xSu7XB2l8ptEBeo7kq8Y4-pW=8_bV`n!2hcKSmaAiV+IE@*-3;XW&op^N4(`n4mBqU?Ho}>ms-M1C5v#Gx7Xn-M4)Hjls3~ zu|%_4&dLY$^jjk4!#)EaKG)8M`&*Bw4;&CR@a-0p0v)<>L-Pfh2$7Jb(Kwy!X+}+n z=3O_kzi~Xe?k0>cJ>@d_K$P|Oxf?p%Y$*$Q9H+~@qn7@y2<8#QdEjTIBpS3H$Z;%$ZaZlmNwW3k_!lSFb9G01< zO-uEke~W30x1+xAlh)z)hCWir-1TzdL$CABjRtu)N{obl>E6$Jc-hn`tLcvCWm4?> zSNfK%*d#8nri;hN=>&n?VB1*FuPTlXoP#eKie+EM$H(_HDLZ;cqZdu8TTY{eH7(qo z7arb@s9^kX*P0|>{f3Zw%e+~IrEW%@%M)t5rWkGfN2&&w=*C-cN(n`5Go1F^>s)X` zBMQb0eGb#8JS$pISK@k!Hp5oAs;sruLb1BtWM4@zi$}LjfAq#LZodA0J}xm4&6f53 zGbhuU@dtyR>B>x3TY`Ygk0h$)u8qq!8LQQ^M`slnaB^`))$aXzB=ElH^Ssm~dCF9w z-T2{-x?1eJp9Q1xB3idCx$0bW{Psz$O_F3Ly?58jf7}zq5qfR?vS|}r$yLgF@<(;+ zd&wJj>#h(-h=Q@bBUkjcYxO&dJ@Rh{zfGzwq;~z}%h%dQQ`IPvO%ZfeD<60|O1=Z?|}d)4ZBodV7ZavKz$|tTH?oUE(|O zJtS)`sb`sCmD6ldw{zcpKh1yf@{w2Z-hs^QYU*=woj&HRqs(^6o_y9 z+drW@-O{8c*fyAYq>D4cdGk`H4j1zoioRd)4@Qme-09DH4*!J+s3DRwZVWo)4?9Au zQ3+ho)apbkw!Iu2A8{eQ8Hshu{4^!$RKQ+qM1*2UL&qoAyf=sTlOt~A4GVNBmTg0_ zu8*s)E#;56Eh=5p0X4nNPhV%eSR09qET`BCSJVDr7}tw6HL=R2|Cwv<#g8-E?uiyd zWvf@C?pv!iNRvFq0VZ%_@%)f=j5XJ>b|4qL+0xEo=HMXBds%dY`&E><%wuLV6%7)@ zX4>iCFrTyGt0e2%_Hz}ouGEJ#tWGRzH*!_6h$~9l0u2G%Y{a6ui+mG+?S;HisGLw#>Pg7XS*J8(}>20VX@r^sy^a6 zMb}yiH`zw6;5?D!x*k{g6tR@?GZ;5`~Kqjw3Ks?(#jVG zwKi8A%;GK?;RGv%osYUSuYTz6W-_O#p2S1g@w*Vn>_~ju9d~oX zPji1@G4n97H|e>Jn%WnmuX1{E_isLbvzIMNnDCq~)*y4ZA5|(0R-6!~T%upLjXAjn zbONqp-Acx%wfpGtNksAn{Ok2=y{@Ph{_2AT^(DR#L16auX>2T9WzJk52uQp5_L@`T zFg|JvS&%uAb0l+~igAfO>f(3fHTP(_FPW2cEG7QuDb_W;iu!O-F?1!e2MC21?H^6e zh=7EhkXn_EIV)HZvrAca)%VH%CBp`k>Rqw~RDA{X%cptG+7r)+)EGV>aFW(!FRP|w zzv|@HF^N#u;nF9sx8XYFKDQ#7EN#cloo9e3=avlj&O3A)Hm@EqDr9c^7A;iNp5VAF zxfyv&f0s2a#aXVuz@TxY$IRYIxYeb7t4AeFsysrkG2*$o+x-u8@sCPpG~BJ9vzs)p zoIyGf?B^ub>~B&2D6)TXzy6|u2%VRKJ|ZS%276o7Hf8P>Q_}JZX9ay1#pC9CZjo`x zUw4^*tbZ-uRj2|UA5@t7T&Ubr14W{%*blscWFx@Vy z6%&>dm-I}otEP=5aq&w^7=H@;Qmsz7yeM8jb)X~!!ls#%eA?Uii z9IiI<`l1wWs(k0D$HV=>WYUz$-y|X8t~x`~6lSk#w)$=+WpMByO#q=fzw#;zy=@HZ z17yzA%Popb$*;WjD!pyej6z&AE6v4z`ZqLI+8X4rlm@@>_|(Au`-*E)*P2_X~f#RT>@$&8@hz=PG_-PVeKbGL`55YQ%yqn;{J>;!ev@A$8BkYQsU8HL>(dyrC0&k^^=?gk z%_k3PN>T*C#=OCdX__5+5)#5^Q zyKF#~mKd|geV&@!?}5)uQ#P8vJC_u`86|&)CFgjs+KA?1F_6CtwC>%Lu1rgtd=wjf z0rudX{x<`om3XNfgz;(|Pi97reCa*-izWO^G+QFK(*fnNB@;yCW{! zH|Mdm`hqb2dDD&rBRHU5*FMnt;d z2+drXI6`OK%t2{3th25WXzjP!?tDt5h;+#&71?U_(iyxx$9fJ?_}%zS)vCf_ai%~} z2|%V5mCe|=s(e}zW>uJOTP)pGOv4H}dvR~i%Nf+XDx+Hpe(o*Ch7#VgiFSK^N34|a zOB|j5Wa7xTn50tIe(e4#soSOaU0Zx~TF5R-auVV*E8E;ZhVBZ{dEMeW8?G)T*ZFFn z2%wSG=>2L}E6CYDn2@KFg7caQ%+jW<(NRC>-p93WGfXXbIp|PC>V5 zQMmP$3E}9WdU&IQ)!*uKo`=Hdt#b&e$^yAU7I#H5#x@ee{T{jB9(7-5?Ow^mbiK~R zX9=z#c~L+QI&Y+(A)CwBmVb%F&NRKbamdkjZ-3d?%-P}m+T@qKSCr(s`>n>_wzOdi zF}8%wN@QLLee6lZE3o?+t|EOYlhdLMLpN^S`fUC)Q(NysAbTXgRXf_QdVlzyjTFoF zZurold%Eke@Zi{}6)|Vz#Z;L?pCS#mE`{qR#Fkl^50(|@ZnZ0puQ6K5)FvE?S{^+* zZ?fDfS%C`z#8Ow7oZTA>w@IbY8>dT>6Sl-Z9B|(V-0hL;|7bmHew#vkW9~(1@^olm z=dW_Z-}8>xXhg)Pg1tYu)J#Ty?@3yEHQ7lj`2A+8N-# zP&LrB{GrIU`t#zBTwZ(M^HtPdb0F83eIu>_8Gn1`#P{Ay=ue8&VcXc?wbM&)MjJNc zcwLwJTTu$4xhPwT#ho0-UFWh9*?=>ZjPnvPNp;^yw&WV`b6>hm>8}0+i}cJ;cR(+G z2kSPa2_G9O@#fiFyv{wxg_ZGoakzC7o_pY>Q%-ybzDRjm+<#yrlv{OsuUGCfPSuO& z`_I1XyToK96Otg#CVzXgnS=L6rgo7+BtO>g?X#%HVZ8>sk65-wYB4gxy$xWD?|16X zy`1D(TK~@|S*-nV>EzH0__$_OTkZ_O`P#+y6=s(?{d-93Z9mdQRy$LBUFK_*avs7y z%m2jIJc{Q$bESHWC80IhmFEj0wykTQkjdYTwJm>nq@BSYl4>+f%%%DL)u&q1_m4Qt4P<&9+h zCszwh(CmC+S=%U05<{x2WE0{QmvtoSKF*`}Keb%-c%HjDkr#>G8bD5W>uM&Px-zOy z@<_j<{Y(5k^7`GyWh`Og*9ipJ0~F2=zB&oD_VUe#Ths(qXDs=2?o8f{nExnXRzl<& z9Fut2uB2*SmDI zgS6|xJ0QRAHkmU+Tpa83TXA%rw)Cifq|XzJZLs@Hq$#T(v&Z{WPs4Y$Y?i2K@?!_L zr^DkH>|gL#pqMo@NXFJT)GnCj*26y;*;x{G#xiVSmq^@C;s-0QcUB0}ues(ReoOPa zIouy*u`XL(XfmiKHufjq#V<~iqM(n#Dv#KWc}qtzESy~Zs^+d+Tef_yoB`0Q+DMT4 zh}(H^u+SzxdhoRxeTWLv8%vW2jdy)H)9xJ9`7C`S6f5^0B58ehSb#@}dYjevHlOC> zoF`e;p~UB`35za_@%{800*BF6K}qt8k0q{@30_VP(Lt17#(5n|^j2`U&S_;?qARtF z5XY_Yqr&*-i{9CNL&yadrtR9pwe!yJt(xZ^)xCRs{hMP3N4S9*BjU{ys09ob{3 z|2awXi{QRzw!sk5Oal&==!_yq*IAQ5&r-MhS!k8t>_4^>^w3J$xCWiUwuvOMJf`&( zHflP|YU{;MwwH%{`5%1IEfN-B1R?NW=Eq0Dt?i`;zLOE@ZuOqAaus;LvTSG1z1uhS zkT@INR$wSK7M7_|vux*IIo;?qcOa`Og+oi+L`>S58*_od!2FkDhIXC7F#cdYN`dZ% zF+ZqDBgK)=A9j}#TlAXwRjJj;WxqJntM4MVk<(6vpG9z$X;l72twIxE=Az(H&wOKx4c zVaij&8RwVBPVLNdRto1_#{oz1rIfwqTUBdlkyCAU;r&yMwnm+)s8J^X*R5A!j9CM#%0|o(>VV6`;hg4#ual3__6jtjWOW!MW3yY%V$r&o8Z%| zAQ)ZlaV9P=>nHfkEc`(1L$J8?*v8nTG1D7l{+qOF?k3UN?eJ2!;2~up|u|(HIsdo#9Y#FMMPhO%L0W=IMJWoXNjG?Xx>Q zCD6t+dT6C{D4j4AG?p-bQI!YCpI59M&Pif?(1{#+f$qZ@&8U9>*am3siWH1EvquO{ zdjyBuopxfGSH8u%|KO$(Rd;pAi09(Ype+R%Wn-dt&b21iZ?P=kOCb%i3(V+dmj(q#dq^hVx&eUAy1RJj(XMnMm~W53(fa8PPb9_iOTZ^ z&(00m;geO5a&5f`_yrU;zV5X=t}k)8+4qD&aXBNX0GZ$KgB>n9Wu~=JB{ZcbYIeql z&G8`oNjzOU)n-Z$m*UY9y}TZm^Huil5UCepgPS*VUg4aL#tKumfnTSyFpGqoJfW?o zP$Bx$HX>!coZRr;v#|NCaMe?!K86jAyv!c@_PpEyyL+b?&Ts4B%;{Wm)TrNWC3xVa z;PmSBQ9BnkcU3uEb2O=3$N1g8(~jh72KET0J>Hmiyy>OX#uMusvUa8jbGd#zz#ACR za=y-bDaG77qvKa~2}yhJ_SWjc51x+&MH~FHbG39q)%3PCpB}QlCA}GnO60zhdZBfv zT#JB;<%Vm9n^}BDg#KFltqJnIt~tAU%Qo!WQJUeG5bZ=sn@3{?M{7}z=@CTNPTf#C zL=$A8NzxE+KJR27A_uijKc(_F;Sztz5Kv&4;pgwgj76@y-e9=MN59$BKXY^7Q}v?! zn4xp;^+{Bp9#+Iq<*7ZQ;eaKJPszy77K$VDbcwVNuTo9_9sv|*!4A_Cy07iNPcN-L zxI_45fv%?Dx%GDAkpBDKHYP3R7t6{0UNk}sRRXLHBpKVQ4{T27HN=coVx>}d=I9uZ zAKa_F_hv@Tu}u9pk&@__u>hlhFV1=fK9<-u{byTp(_T3L@d-@I)Y^Sznpi@lnna?S zSPVt637$`@!kbtO5(Ofr02d35z3UQaOMBukhvV!|?}GoMsxHaSMJ2%*B`ClBqVA0- z>3(#+{1JTb9Hn~^0RR~T!1>TmkMZmWf@uD~Es%XuE0~l&=PxoK@9vABjA825?T66% z#CtHxy7z7jspK$Tzlb!2Ua@O-{B7Nj`X}FmnLe*gviD=3dqI*vp2IC}HK;-k6@ile zq8aR|L+6t_5VB{tbU2e*0N;N$15E4Yqi~h<=R&CiXBDybkxft?Yt2~Af4Y>iL(rgx_11Hto>T(QfoeE59Du*FWx$dx+!kb~xWX4EN3x!W*ASlChVa zQ*C3i>%zGKK2a=GLAIb}R?lLg-i1OUgcS0MvQo?Z?k?@V>Q;38ZZnh)Ul#zFZe9js zY{<~-N8@AfKyj!^0D#x;gL=(buwFj5OZxaa9H=DqUtQ;fCSux!)C!otbPjY2C-hiR zL3aE-za6#>dtp&Vdp|}#AeTWksaRwa2I{3XKV{}mBwa;&xKIG9DW%X~e3sDMVzUta zbscDXWHUnbof*Avy(yFJ!x+%*q8JU#jw6sy8ic?~!^qH|&S^cw1ta<7$`zAPazl4GFlcw9?f36M zUL9sO4*`JjD@$Qq&|TBTj@zb(--hCNi%{)7AwSHwtbk$OxUSFG57(gXH|t>tD4>+d z!_t378S+S*koR&_b{?t{8Gl9>BKti?)&fh(X=O0qv_xbSc0RWofy&l|)+#ep!c98p zoU(ia6idfLvuHfz#yA;woMlIIYbU^z`LmlKmZ|n(0?^3}FkinI`RAV{`Fp&LSZ8PF z9eH_qf8m!2rmcUv@4oxA_uhN&LxjAyNseKXL~8l#HiSN@fkv*(3H86%#7J@ohDdT4 z*`s~_^gi+IC<93lY>YdHJYJUm{W6qB3FXXksLv;LpTRmo6`jb8 ze0(eXhX!U+RE;EjF}2@-B33J|QWkOcWo3nX)@jodB;v?p~93+j)?i66bC+WBE=s zlQysq-a~c$7RU5QiZTn#H!gvCN=cWR&A`(6%r1C8sp|4Iuq0qpz+0%rn7h{YDHaMe zbinp#ct;^oUaShD|p|+qh*v8vgnoEKv6d6|z>v zDXwY`KgO&+e@z=Yxc^~g-#V6lr9UycywofhUpcD+G6^9E=OauV3)2C0LGkWyse-QFYHa?vDtKjto+EXlno!{-Er_=WCk@APLHAy+3;>P4c?+^LZ8SF_sLmOWf|&gSc^BvEU%U!k zXF!DiLV6V}x1QUhMnHV7A?)~5*E@P_`XaOH3G5a_bM~m79&NfGc5X)c*Bwx{x_Y)E z>&NjYGpM1QHwJ1lb>xM{fj#7W&s%M1-hK$K?Z=>N_d%6~u2en7m?14dm;nUY1-G3K zQxba#()w={DDna=_ zcZUPnf!Y4h+mN?7!vJvgJXltC+m!*E3-u4a33+X&04L*h3t^7=J9qAF{?ofKKqc&X z^`ddGeraisR$s#L_uMwvXb!p^e-P0W(-#&%w`76{$#pN85IPQ2qWUkJp=%+~5}AeF zfA16aBQR2o&4+sBR47PmlA;p(>@GBacog+-eJuPXCNf`4YW<*;rf0$-$aBPiu30r5 z#p@O&6Atv+Y__iv5C0kc_yPJo)7^L9t@+u{e)emvR(reD^k23i+sMAsRoX~J4Eqcd zZQ;~gJsNB+pue!7@VpZPF$l2pO*JYXWvk|*Xz^62O!|S(?ef9>@fniH2jH*m5WpCZ z{6TIC>Vlor^|EW1qV$5bv|bb zMiPa%t5faYw!-`Fk?=0gWExrSI1if1JsW*?9IQkoJO13V?oD6lT!u@|hW^6oJv!b- zng8_vZGy7N3A08oA`4yS0<90Vsyn16vk;&x8BdzY1QF&Nhyt7dwf{6~H|&AqNG&u0 zIcX#s;gIC$)L><&rt1(CY2Lhn$i#e9eEniFx1{;w*$?1$yZ=CZe9!&&-yc`n^*aNb zH*YRnzI^$MH24)#2kIj`wByk&BKt3juKjJ^z|7zK2JnTl?KxN=kf@0$g8;|i83?#K z&!Y%JH>DgEYvvD8K3tykjVzsIh_eDK-_bq3}yGMg{D+`zd#bcTi<>6-K$rvS`~MT zss3g`cJScAv!+g+`Z^7M3?!0kUlrU>eE^eO-9wFI0Eq49#*@)sX(T)62D9x`BC|u( z*oVSQ%3C;bc+IDg!7^_m$}gS|^Muj?d$_aI6}|o6+7I8Ez6nG^6X8Z6tZk4cPYcH+_1bWYT%;t zIG)&nppWeMH8YTR`MmDAZ?U2Nmv2DP?1J*FG8EmpvWsaQC+boAt2bcqkX@T^g!PUK zpdR0|lCW{}J~TY_9xO6VxTP2^eC{G-x@Mv1QWSg5v67#+hUd@678MD{pIRmCd)11` zP|Y6`cSoTfb4l~$s%u5#mVM|Tb470RLLH(p$drQd6>|BIMWxc!0z?b>kPrE{o(t35 z@zTE+2%I^2^5i8`rcB{pfqf)vf3qR4udlzXsHo^E8ngjYh|^8q+zZ*36X9YH^vu=n z?CccG9j%S-4-t8BaIJSPlz4WHiT?5C4Z{8=Tg(~oAZXU2aM^T}t(*g0X@24cjsqkR zMWwpk>lQl)my(^=2Lu8^ICmU}{iQt!IlN+%Q8rH$vqxd%oPzwT7k1f{Uee$M0JOVBB2C^Gy8qVn)+Zuf&xKw3mD6Fqx@W5| zb`YNU^{db{IKz%VlK!e$|5##QfX!wTlQ2+Q zBnFCHYWox=)&>}fInFNHHjyo^D6ydA!r3TUIsM;u zVDCL^0?GhN*0Clqk3b+sZRV`M&4=K4?Nd?U!*;ww5kS$6OHp|4Sv?j7YaJa=Y!l-w zzUyKbCWrSQ3_3h$d-xsUSX5mwMKqk~0)YB<0RVEl7uK6sz_>VUIr@bwxeFIf`Qb14Xr^oL;2jFm1;pYM+0XSqm1i3RMJce z623vZ-TqzT9JYpbV8=Bj9F)GtYp`AcCX3cyQ%$WqGK5^$4mcGvI$Kcv}q(_BX9}u`I z0s^tNGZz58u~+yO0$!gm1$?CjjJ<0uv@y0Jf3EYXooL^E9EPjrqHy(`@cX36bUeKa zZqg={ODCY<#&d+K&g8CcK?4B*H|i+-*6OZiA)cmARQ=)=XxhE7tep)rrv}H^;T`+W zpz`7MFuLWU_Cr~oClY;B<9eD1oyTg3`8N^s+u}-o&fe2384vw=)1Vk2w8suU&NOV; z_zB#{>YxoONaBa>e3e2WOwg_(&LP}2DwfjK0@x?zD$oeWuF5J+F=rx;`j6lH-uJ%o z&_fUPNeGHJ64{F{zLy@fyL%Awt0;*OEC z
M;zWr$UbMIZbG-27T%o(X~~T;tjug4DeSSQJa! zCOl-23AhFaah+Fn}T;BA_UelSCB(MI}d(oO6x>iX@4WbIy54wN=AA z%JK8O@7Zs6|NVEatLUbur@QVaKTlOxpMNcJf|qRix~M}*WrWm)3WCC+xR^TYL?R_q zQ>@6^$|5kgw9Hi_a6h{0&j1c}q&{exJAAj)LQ?;ADos!Gz9_A1wjC8eGU=&yUFCsZ zOZvXU_tSD$y7a3%NMFQNG8^x`qkWAdk2q|U*4D*K_)>s#%kps^4xS)thf0CkLI)X5 z1$U`IX6ax@fvx8*^6jzuHe)2l!6QlIA~PReB{i6;UsLdI(fXtB&bKdP`o#K{Uy7r=!BnhlzvC`}~ z*G`4c&$b_oXi?<0<~$>{Zlf^$o~l45z{z^ju*>*`mLq&x%GW^e)=6-n$iO7qv99bFFZVVD2d!u@T7cWzUd*`)OwSjz&NUb*+K=dWNkl_$#O>_}vNiYBXa@O~jf!=3Wnb3FYL%QqQs zuz0xl*RvlW?vGll=PF-iI7Y^;QlCV8lcB&cmVo<$vU_Oh^F=pfYs_l9)^;x!7mbig zxs>fh&RN`2%MU}xxukv5KJL$>F`Zn+^q3K8v=q6wGzIfxdgr=Xd5i2znH{B4{rqI; zRy7PIM#Smec{)u8{Y_C!#g#IIsb|nL=Hut#;n5nb^0z*xpkU?xP*p%Gckzf|oEX)O z5W-#0X0Nbqqbj<|(-m2{&r||g-$rNPzDw=BY(-8nRWQT6We+apJhO1A9zF)iAjc_{)k z9qM8}_{2YA?%iX~2VV}lKQrRH5 zuWeGNWPZ%XC4HWgclj}k&ccl}?A455`Z)KoL3PXPc{V#qqmP3{%bG=I^w%C%iyanU*-IQ4Hb%IEg2ki9f?AhEo< z(!KYy>&I;>1ra=#K7S1z5#uY+=?1esm5;JYSNO8f-Xh5KkV{Qd>R>yo8+m@ahsT}s zW~XGYetUGMi=UOC?S!(C*?wov2dAD4)excS3>dK@>(`@+r{brot=Ekf#n*-vZ!@N9 zV_JPB2Nj4sg#ALp>Wi5b?4uP5uBCFs7VLV%%yuo~%8(yJ&H22>2No}0iw`fcI%hxd z^xYW|9r66YWDH5|Q??)VyP{l!>YN9b6emWP*cF%#6%q$Agt?vxYG>UOq)JFLs%f*Z zmU>Uk=Iw21X3XyP({GJ}>T({v{>bvJD|+oQKa<<7u#yT3#S1A8-*~houDpJbFZ_hO zF@!e6n23D`YV*-5THEGKd< z(Lp&{bbcaxvg35UH7mhDdO*Oq?ksYZMoUxO*DhVY%yEy6x?>J!3{rAl7Dg;(cx zy}8*I_Jb?@Ky)yTg!lG{e7hqyI>D|4Cw9=&Kh2$y-t}WPu9X>6!_97#Zc=Wd`{|se z_+Im1Q>V~My5oF76!yi*oDZh2IJH+|!ihs^i&PBTXN^Kg=?GkOS;V!1TSx;dD6bn8 zo68Jy)b5vJ(tY*DW@Gs7t%d7;^br#>MlepqarK$&1i2oN9)*}M4Yz^S4tQIg43 z@*dLNd^9~R=VUW)GII3~GZz@~D(aswBjFXtl59Pd_?*DY+01*U>^i5jLEKQWuw9g5 zn(h4RF}ZiU7}5@@Vur1ANMycLw%7%KB-IsPBFWJ8b$_&U-d?NRS$i% zG3;j=BgF3x~;G9+J^Mt8v6@qdW zPtu$0egpDc#;nrksYd8dc}^xB^H?&l&$Ji{dMh7B&%t_!EB^A6GEO?Tk?nL2Q4J%a z)#6~)GSFh?%>Je6^`qo{XLK&rz?IMf#~{>meGZAQ Y67-Oxvlp}X1soSQ}Ql{ox zN88Ye8e=`?9!-{i%DO@7Fd0u4Svt~FbA<8)9hlncPCL=Fbm;7SG>1O%XyjwHcu8}@ zmnW~wUckti(2mWM1wJIJa5)mid-Q=r=Hiy~!vxGaKFIVj$!jKkt3%GlE_MHXN=M~2`fF}+JIl-Qd;7dc;B)6 zTANtJNi^D6lpIiwVM5RS#oJ41kdE%=lM!t*BRJp6pRGyiNNMXxQhZYJ5JLjPFrRNr zSz~|r>G>V+$#z)fk@(Q`)maea-MmzH?}ALo-bGFh$tR3o>Kg-NEUxe-7pv7Tcg-&cF5W9qqrDt`n4_GqJESX4kg`**9PB74~wu!=ynM{ z16;q-V z@D1{~YooBJXuCu&+8$ur$V$go@FexU7x%b1Q~1%39PERKOm%zu;H_8+R*=$zt!8zQTGn>yJ&oF|-=b zx~$%EP2xaF5w)th0+Wq6A7}Hhn62FcW0xVUV<$>YP1JI7wARHk&{tT_inoxLGVT$) z*O=+gbRmXbrO=C)?BWM*=aGOdFXp(F0{I=54QT8* zdy=d;;8e?#5^USf;BA-4FZalvk+`f%?TT$GP`N_g^O)K>HZI`lUhAS3QGzV7!xito zG{-+bjCH)aViRhR@1r6Rl(&b!WzVuO!`nAGx(tG`x|(~*KP}Sin{$fHC!=9CFrNCWo4*wo_10A7dd=`&RlB+6w!4G} z!ACI>N|Q_1NR^TYIES9ydaQvFQagqArqu0UMSh8$QT^i zD3O9O`k+!?N*coc^~pTRRi)=QKl=OFtnMrz$7rjY@t?Jhr#4JvurLvx(w?J`UuKjI z6^AB*vPAH9@D<*~8Gg=pyiBAL{W7`YVh<-452#P!+sE-J;%sh#Xq?OpWt|2o35$^l%=7k-zF3|kE>$DA*&so-J+)hZ`v9F4Gw-L^2>kC|bfc>DzWNO84*`buX1i7S@5 zv>_*UMHxHo6bz*b64$^eRvA(rZ8Q)g8JTo*avLagn(sd3USl??BlJ2XK22FlP*(ip zhUKyMD{&-}4nD%|MHihlr9`X@Nk592C9@DIO`M{QGN5sAB@j@>IMQc_YrlHxJyOZhkaE4&M?>7YY1(t<>jih|)w`LTy0!ge zk`*RRY<4Y^ZZ(f@OL{poFx#lh>==6GBFc9~p+Al?Xn9$^nF&KUOD-U6yY5=wDr=_K zzxLoM`SSNI^j@VR10)Fs8w_BIrgY2XO(V+VFN^x&|{oonHHzUbke)?>{VSJS(|OSa(_r zuSFY^XPrv6A$v3{C;iPcFD6S-cnf%T;_iy|p$6J|PMC0=!x z(!j4zn$1o@l$eMhjxWz?;eG!Z68j&0TEQ=u!)kXO2#{i^!K%tzU-7oH>N3pH(13=K zF) zN1ac3N$aZ-ttZJ`(8nsDXKn{2EO4J)mh~iI@SZtkZ7LG5mlpH(XGlu2HNmBCJgwjcV-+fuKMV!;yWl-RQr>DgU_^^PG z^gFoHUeS~uG#yjLv}ACW@sd%ZN}H(r^F-opPFF{Yn6~SUCIpHH&0Rh}LjCBO>q7Hb ztyE**$k&HK9gpZki0^#JSvABkI()2Kk^J6Ps~;7<+;=r%MNhk#$tIau*4NR?N8*u@ zczM=?5MQD z!&>u+^;5P@`*&V?f8Kz-rIzsPxiF=r4zrfs;>{iNc{V@nzIzjKVi!Z(m}~|t_Sajb zu-OkxJrO^0@~N7Zs?+^#r-l~V^xU=0*^fKC^?V@yqpF3=`8!AUoWONs+2>rlVtb`Y zLiuKn_Hbgq+&?tltitZro40-#PRYLqUp~pSNSk@gIKz0mEBR_azx5YW__lhnw-x=* z359oNE(8;{+~KWP5jfh;^Id&($w=gN%n7a4J>QszJyz--cUB*lX1q?Dvi9RFkQlo? z_qD=+gX&DOT*lf3qhPA24-ZKay;&Z6$MGC}b)WME(Y54>%J~xoL~lQjD05)OU!RLP zzHfVzvwzRn70Mc2wR;@ITZG?EcO(We)g9$5co;{1$=iv?srPz7j`Jq^8{s|&Ml9spI zC5*&me~_j<{%m{f%bt}BMl*e1cI>_2Gv}%rD|_|i!R}bYBbXMUDOk4qViCxB=+ML` ziDeSbSKH=mrY74Z2T4(c9+Q6HF$n__MW46!hP~uLhifSbX>W1vOh3!+zL(*eR_oLVoFbdi}=& zGmw>)RjGJty5wl|wfIA%;&oPpk{N1=LG+(g()Djnz&Y~oDIALWY+lPYjLQdCZml8t zl$WX%>LyWSrN2m#*1hf9z5{PnZ zUvs-vjt?#f-F$TH3LPnDz0XZYb<(+4R!RKcq#?SA+mhG=B~LJMd_B%iu&36FnDl^u zuEYT*(>$I--D|-Ez2od26v6vz4rPg-A*M60W^#8O+nz9@n3DAsJxVDC7x`xE3v8Y^ zphvq^pVVfMk$R`#J}jD$Y<>Ou^+iSs2Bov!4eEpqi)A`r1c=?~z6TUr=~t6~vsYsr z`X*cRHc;6+w%=3cZrJQv^I2=pRVf~da;-X+7%k_U5=;e}&q!;osGeggFr$ljbmJKR zK0ccZ3wzQ=lzqvQU+j>6D=ViheoW zOD?Bz6?vC4VMPM>xB4q^RTE~%wW>gIH_?W}x7d&G-{GRAmtoWoXY+S1^IcEsyX$?v zQM`uH>p??J!X19EnfT;oD|6ZvQ&EmI_mEcwgnM5*Fo>otm3rPj&QH3B^Q^T3CB@K# zy1FAbAID~#X5`e;d)?YOzwN2gbR%gOqn!+4A4vpB!m;A1AKt^FUi+PQH=I6L7PUJe zKEVES%KkaBi%#k+#x|vi`qQ)u3o66Iv?U$lx$qHNxmzaP4n~l)XO6|t#K}LsyA|qW zJ6uV)jefW6s;l0W#@-U9A^w|0{U26T9PC;y=UEE`S$2(A3a_0JBhBLuioc-9jHy1G zO>^4Kc(O@5Lf2*{y^$zC?#soJqPssbjw;E1n`4qt_h4+jqV3yDTgh(xJ%z8>uFZtG zq+Oi8L40Jzn>Jkq|D6B$Y|wQGtrYLv5N#(DR-6c zZKOLYk-LylUBl@=QTG}S>)cAfINe=(Yr{lcL%+8xZTQRL1$+G-b}#aa#ci#|EK%>2 z7WQgjQiaJRLjr9tTnladnyeU?3{W#4>1$9wPhj-?ebon{TM>r6) zti#Xn!$+C|SacHU2t~+)#S3mIPcF5)GAvM<6t1SwQa(AcN0`Xll)~iT-cTmz9`}?! zE%$+sS(cqK`n#yQs)+ZLg6gJ>&|_&GK4+3N54o8X@2Z@CP=_uO>)LfVM6ttGA$avSBU)X zN?p%Y zK|4g=%Dt7_`@!i}phO1`SCaDy;`=U(H$x>4r)d{Vl4}SsMLnBn!&<}l_DmjU*!$UJ zZFd${^}#-tI7d|c|MH+Q#xw>#kLLFF!qx;Xr?6t5@j=Pdb#6YEdz9R)p6t9K>#2h- z1$hO>r^EI{lr*vUG1%Dx0OFikaPU3uAr&XEXAPdBYyiz zE_rgXkxy21BIYUur^U#runqO~dN-0ZzXZD293)f=yB*!fpT3}?e8WEiE)i`|{+w29 ziN-W?&F+Vc4xylhIdRI$jET2Hewj7e#Z>phQJ!CG)%@;~(YirAA{PLdRo6EPee1fZs0zY%jp>`h8Ub{yF7Vm8 zo6Y&wV9;5U^3)lhf*bL{Zw-7EZp`b%@9Hk28=lNL(*NLK%Nv5B8i|w2jFVv79(&S`@qWb@(iAu<9DbGQ?3-lacza|*#ZP@ zr%rf$zT8Y6w#$bwmaT(w>-o?Mb*bAr1NIg5i7h;B8SS@;i|tGlEGFdTSl!R)){hhj zN=dE0;kwD$J&`E6ZHY4>_ZnQ7D+;Z1oeW=Gvqk50b|>@0&loyEarN4e(>KwJ1FkVJ zFnl7r!LLqskMIG_4=_&dW>EU-{lOfj&2g+l)?X z%9d{J__H}vaHYWfsjla=?7Q-dGy|2NE@z5fQ@aW0^bef2pX$w99*N!$nQ!502)?N+ zYBdZMCWT{8$elaf`+4wL>jM>mOB(q~-4`e^@PUvM+{Xim!mJ-~?>tGw%(I0^@j)3q zg$@VsQggy6Zok3BV3*_DQ|T*||D@^WvxhvdFrw?RZ^n8l$88BXb!wIL^z>HKJFUzs z;M|;bRy`AUDFeca?mGz+e8jH((;VuV|O`_9k7dzG8FFoZZl~L)t3C`!K&mQ>kSy>r3_OMT2CR;npMs zeZI>^+CV79*&*+=wrbl*0V^+Od^|GTDrz>zw+owp;LxE` zLk|5k>!h!bV4d}J;Q~%t~-~8AJGXt+bX~O(Uev5>-LhA2yysa zb@uE)rP|xTz}wVmc~;|gOZ4Ne1e`U#+{Hz~XbfI5-)fD0a29Jzt@w=e_=kuqw(}n< zFxX@4jE+ica#d~$g=xe`JL5#{*H*dOGzuGyS51i)&IxGA)+UahNayl;bBolT>p*p& zc>WWpd(jF3r(8(H#$UkOco1;9QoI{uA}x*=mF? zpe@s=V*8;ROMy`SuGqRRwch-enR^6d|C}OdZ%w*EXPMLyGCER56$J*;gm5~EVg1>= zvR+ZHMRvBwvos|r4pSM6_ezt0)DB30x<&9HQ=$ccPjkJyRJ4Ptk}Bhw^*Oqpc%Bka zo4eSt(g3G|U7QKk{jpBEO=?98V`7kE&*WV&(_aAu)C+9Fr5;o5s^K?GrHK)V!+6$b zdlAbM4^cX&@Z|1sSJw%xIG$!*eDdtehyD_34r@LJHbgmxraAo@$(DY&%ykAAs0-9H z_<}W*4~g*f$bIRwDmt&AQ%z+<&_JA&oXqI5SHQf)nO@Op>#mgImLQ^0u@DNsT{|T& zCu=!gqARwGz0Si)5nOxkge|Y=-V*!XA3q#PYA0x&dilM~2hKWh?)0E8IwNY!!eW+B zuF0Xn+Q_Lel5Ee1hleR-7`?=-R+k3J8Oy1z>oQfU z=PFSs3sS_jh7dt-LHyZ6MbTdvVRg+!z9l^w(X9=@XWtFL9B2Nnb!F6x`#BFhrrbpvA5h#&6L-{0#s(<0;3^;{*o%63e8QDx-XX^_+wwGJf?19 zU!c^czmP#!bx}3;hZvPhXIC)Yi)gy%7Ehiz`?Sy!f2rjRd+pjaFarmVbHVax z{B7?1OLlzez>&+U#I+nlS592>V7n+BoA`F^w&lESOiYY8aqIPRYA@LvDwIAC2PI6G zdD*VB>nFejOj)2ce2YUdSF`GPF`ZY#m%hh__NV9;$Ea%S$ZRsM>BGXW#8%bqlioTx|devaJE)l+knYv(-mFUHOONrw-2d1_L z@0k|}(sC?RGKE55EjnL+xs&ab2_2(_m)SbY>m_=jBSh*G99ONc!&N|7H3%8uQ@~j= zhdwOQeCp4T>$=i4B3m<7K{Q@yAv{Syvs*F{wIeuGKyZsieD5VpA!LdiKk~3e( zp&~9$k`T^fA!i6J3YpkVKCK4VS;UUFrdv;yFe;86I&eT*o8xU)oqn-})rXi^1J3i+ zHjXKt5%q`Tb7sy?I#BKqd++Y<&hl-F-k^XT8$qJ8c!RWkdY6FEklh{PaXwhij%D9Y zMLMMI>|vv$v{%0D37J(mTo9S(1}Bx$?aP;ED_(3nAht^vIBc)VV|fpel^)V0(nyAAdgR)*xcJr~s z6*yPr)XRv@!qi9e1cKD(n|4Y(i*fcL-Fr~MG21*ZD3FKoh3i$>N+=r*iRPVt1XQ_)STB`MjI`aw0>HX^W!WP30J`L8-IwiL1kR zN}Nkjg>s;~*olAF`CvH}1}9ZJdF!$BZBOD}$f7wJUB5#jkxRoJGF1&N zh`PMM4aRq?%9ITE-S{%?Px?!o+Q+!$JzcQp73U?9_wtrk;R=BR?+#qE!XlmiK043T zT6Txsb2)$KyZk*?<5V`LvZa#FEfPhy!E)1n8I}y%Vu$Vp>JvnjL{uz3Gx5*oFKzQW zH&WQryfw|ju2EK{*e-z8PA1AIl$&$t4JO3uKIfPR;f*_^a#EGr65m)Z-@V&QvTHuy z1g_U*>>jvp{&0?yU);@WGY&-gB%}oe*IAs+#uCetIINbsGvUBPIxI1kxW9a{ib%m z(e`O3*V0jFNk-S_%OR_4m_TOIbS+hu$M=!E!{NsD4+ z=yum?^APY$Dp>LBykk2f$aLYth01kkflV6@#OFM=6CfC?b-Tn-XKFovsgpVX7-<1~ zuwmzZP7YIjef=3q{u}|*a(AxTF)hi_uwn0S>KBjMhFv1j(j?#WR6VzYe0x33`SG`0 z>T$X6AF9xeu92KlbuU(Q`BZXf#D{pbUPV}g=LQz5XG3zztMVCqOsN5m2$#N&RZG89 z2HE+_2?%k``%kOg!+cBbow)mr@UtBW<#(6s0!MjxwBf4w6AWj7jhwmx;dAB~8I}aP zz3Q@+HeOrakI0UQB-|O?)$%s~;f~kd5`D_nZr}ZzM^%j6N?f@_BxPB#+%`d%siy9H zOtUhN^&_)AZ0WCX4NY-bE90=vx!?cwU6@R}oQvCt*yWNsn(Ghyrq#4CRDS;UmmH+% z=f54Tev&&|C1Ozd^{WqDfv0X4!*NZbXuj_9sAJ7uQm#HnNLN)xQ;&ZNI(q4o#_S%I z-TAI3(?GIeOwdt=77y}>UYat^Q2RkfsX<1TfE@=&;?7gCip5tNGds>xkxKt)h`weG zbA|Zh2i4LJ-VVET*m&JQp?%SwhO~x?`*Dk*y~Rg=;ioUGMk2$_+Fr{N7}N1_Sk$iaKQR(Kl`1V47EnBIwJ>cPqha zJfrADM(=BHs2i7E?z<~6Nv@3c6k?=bL9Xpe^!0P*@FvxzkZo1rUpD8Vk#J%2wy}9Y znXRGAS4=#`<97Ezf{O&9LNj~&ox}8XA3eKvNG*x~py1eJb*>0pIA^Jy(wY7v&G0Vq z^z`%#Id)TSbNIf$%h^vyjTtqF+f7d0T8STCqqd>TyA@j7w`2Qu{k8R#Noy`+D~*Q_ z`9epIPOs7wE!xnKcCqj=6D*VWJ?k*l9)Y4(3YRa^-iduCUPQjtqiXk%%>jYe2FHC_ z-kt6L0pGrCus+~xu;8I+diU;b21~N;WSO#0_sAUSPxv|P@{kvX<5Wv9-KJ%NQ}yaU ze*EYm6`a8Mq2giwKw&&4Vt|Fp@x^FUJjdSVtUI4y)WJ9K#OygP9)(@f@H1z#uO?)p z;xrU^g?a0;@2I?@;s^d483Ln?Y6fiWa9aAA$C)`h0;}D&s9g)`JdwcS_C@nj)Rm}n zBqSsvLJwO~0_m&{C(e5_iCGDl#}{Yr;1p((nCg-;GCO>PkfL@Ax6A=&_%PP3>WiVW zuH*HQb^9W(w2&O75;<>Qpnh%om}+cVL{83Xmn{+5LhP;FZDs7q>jJ>TZza-Mrc!kEs-1}qXxMKsdsZ`hV;=XD$hClp$7Y* zmo6`?$4Xon$(mx-p1~)MsgISU$%PmsS^I@S$~i&e)7|3KxEp74^eA0fS=qTy=e-#e znWPpapOaGW^(j;;;!JY!rjzrs?MjbgZRTNNaWT6ct{hDX<7DI2`pC;=6orEZoq4(M zF<}DtYu`Lg0v*d~nOOea-*cB?IHS93-k-uB z`$gWg^wT8gva%Ezk&cMKgK8bJSCbfV!a-V%Ep~o>tUtO6pWlUV|Dq4{_xJbn^sIMT z6}x)q0}p-jt^kWWOBQ*a0;K!9DWuHz?9O*6uI0~9_^_nvzwRn?zvzYVOeg8g<(D0% zdfun&=T+}yUu$S;`oOr7`$m2-YISwh2hL624_`(6k*lPNE`7F)xRRmchk2*u+(RfA zHF*U(WL2t!oyAV;0d%6`$Btcf4}i~re*5P6#_izY!xt62p6?PCR^@v8r4O#OBKwVk zS%ZclL^NoiV7K^bW9lLTJ@@AeLJYzlJ;EVrqvR=lp^Z9%`!ZP$=cZ+4?Hug6UoNMn zs@ihp)-45^;>R*%8b?doXY%=KxVl@}px&%FCcp0*JE!hNG}|q__GI0_j7no`mH6;U zwby%%bg>Wj09WD{VJTFF!i@Z(QNI3S@3)J4-^B=%=iLl_PSEDnbz)5q+r5kxWf71W zJ(y^@7ANhRFIiiNvGVU)!V0OWtgU7f37vptaiy_;OER~1(`T0 zbvw*HDGY`a9sqy{HZt@bMt}~t!Ts3>|4P7S0~-PEOt=Go^MC0>0Pjo0&CN{)msX;2 zaB$cGSN3BI3=HH%4eh^t`Eon@4xNL}g$@1Y|J4ubJF$t034LN>;-QKPxJp=8m&MS~ zP|)P$WY+BL?AQ7E`TB*0g=W;yK01cJLsij^jt+~;%F4^=x9A$^TCn}UKo3IH-~9ai zQxJnC#FLH1Vtb%QFRZPtt%HB~LFc01EG;edplcx7p= zgSyOF(DQu}ObxAol_hwA-)MsF0q<1`@2Lf+U@}1h{9lm=EiJ7r)z#JKkbM4*dl~k7 ztZM}{W@B+UQ*35I?9&+#^$0e@KetGOX%KjC5cp{H0{?q`;M3y)koIa6d{3JLqn*ne zwAe&kbWa%FW>r;Hoke~5|4c3im<^TxR9s&{YS~;GRpyTTzSc3P!f7aKb{;aGF4-5=Ahlhu= zK^puYwUKa=8BuX@@d-qCq>}i4EHAF(a3?v9;CP2H_-gclum|J+2!DkB6!5=0@E7cU zcltn(*3e&C=!0R9{&F0&eVGT?gf`?jS%5M|($LVLxVX630O^j? zO7wTCZyl8Q&x1hi{=f7e(I7x`5Fok!o!7trAEGn*hu;qT1v{P=NG5zWyFuogVKCBx z1?&GJ1L_m>rEplgUIF#>e@kDgE*%D7CWK=!h*2kd5-WPJGZ$Zo}z|i9_bDG z4$tr3>4(1#ejEFA8kBvS0t?f~fo^;tp9bLU0oDIiIY7Du{fxq9zR!-Wg7Oe7NV8l6 z3C2sfe&c!lciUiXWD7U!KH@*ZhR2NGA{juxM_W90{1)*a|NGy!NO!z$cY+M453^${ zcoG042e9uK{uk^40rYRjk-p7sz9U#?p=r1&YeXoc9@z{UIFXZIpu)w%H18?gV zX4XK?yK&%qXT!FK-XFusHXbAD$KN${PT;+vpBRt~1Zxk2AiZwz(YPH1==9*|h-iVw zym^cC0nq?YKl~P*gRtWpq5+Zvye^==!&oUDPJ!L|KVu7EOh-O8Hs*x)aVQQe4~KHA z4dWAtfOa2f%%A<~8xfZF_V&~NL=Rw|wH3)dUguHl8Dl#7 zQ!f9~zu#oxcNvJW?*Oe86Cm1pqyGpKq9L;LXulv}6f7@7{4N``Mc<)@WCML4W7h-P zt0zH%^M-yPx**$u?9NXb{niH@-QcnCCj+?n0LMcZsKD4DEjv4#@ju7_AsmXjgOBG? zT$k@P`4c<7f4|3S_jh;7*#dl=2=!nd&QG}g?_>bRk2|2vEWz`>9<3W)8 zvL7tWu7KvEIox&dzxk(I)W47iL!k595*`kK^@Ji=>)ie~GC%<9GpdkIxEvPc85yr8 zaCRE$-R8DgM*q|wqz6bA(04JGLtuJ%1+;#h0)ATXIJ8f`+HJt+ZWk_wou66-33d?w zeHiaQ?1FR{1i=sbL0iQ%?sqX3L;sQ2zxM(00L7%qrYoS-cNJjgH%NfwdT?-1FH>Ikfnfb!94!(Y z`$4A12$-FKvSBj}GCYPs>z8Q|W;h7a-3M_pQyM-FZRf9R{rO%S{s{GDgGVDcUyJa^ z8qI?wvn9||{VOhl7~|p8ddlBr0NTf6kUm2QKk|1az6-eDqif(Bq6PB9c>Kr~qI@06 zwU;{dbHB+qzP}+4`$2!>BIx=)1A+~@KzHo|D2p7!#ZuFw%ODoYNL32VZ!4g_8TNzD znpx1_vWn|Y6?0rH3bI$fYJ4BBS%HXI%BeL{5cyWa+U?{$DQ z*9~50edq^YVkSUq*(}I#8v&DpP|j?IKv&HiC=HtgS?>nH9F&R7H>1E$ryT@8hPtvz z2D~&nK&)dssLF&oY4}&0iu#0n<7VuLXBp3z!DR17Aqj>=s}Spx%{l;IIztKL2S42npY4CI2Yk<&0AG`aAul^Y zeGcSn^BfN2z>fuh?B94F79_h2fuXiVNTVUp(=Z2GKQDkVqdriVhjM)=b9w_fyAf#6 z3ce(vdo6?c$yMC>zi7P?V{VR-P@hq}kz~3IS_^*VN6^NnZq|X`-rhYhM(9HLQSB<@ z^*9bE%Ds>bpoa2IJm%lGArA&Yw&xfaXj%eT=+C?Ara-JyJMg{>WAc|HV6=M)ltd1I zNb_DW)`JBViK9@y=VAOa3P!t@K(6-)=&fG>#bLu>vVR#QISqoUv{9TKraHrXQMU)A zcyxh*wpnP))^K`~jA|{K|B92Kokenp_=Eb4mjQ$wA2*i=z** zeA(1lyw68<$Eat&_>Aa@uJb$Q-~UH34bt=Cpb0S6y$t3imqA4ejOiY=LH-Vcq4q_P z7t{x1(=jmIxd6KBXFy}gI2h|&1mE+pZp442`=~#7ABFT3@gDIEPm>IXMKC+Mfgi;J5VJfUKdc=+!RI-s z_8JQPCLSO9{brkoKmPj`AG0BQ_{nGhRK!k!DX80n9djVfvkN4@>V>ioc^)wUMtc@u zT(SyQSJq*Sx(>H%kX~3Y*1G^I(}r=fkmTGCas&Es$0qt#VE!=!eZ!x9A-XpnJHEe& z2AhvXJ)Q(Z%^NxZv97_q=n=w?@?#hmc;N&C{;A8F{fYf|jQ{EXpZ@S}C-Aw~1|m#* z!S~D=Sj)zOhT<`Zy&uesV{y3g_uIT(Szd$kuz^IziL z-+8|o^X7fT!=}7n<#~wtJCqk{_@f)m>66HO+`~sX8J(9OBX1O8Gtrr8hlHH zb%T3aJ{VoriF4>|Pvv{3gyqduU%<$l<(eSe4Xug5plv0&U5 z2%8_YL(vw4pgeLC`nY+3?0j$2EG`e4pZQrb-VFJ_?2q*?K%F0fzF-CnwJzf7-WAca zAlYFYV*QmrA$bde|NlG8o4?EbF!q!F&<2*kx*iRz<8Oudt5GMAeav|MUvrVaV*X_t z!j1btvRfBOeANm0)CuAoJ3;jG4iIkH3c}1bT9jQoNPW`{YO+TER_=c%0CsT|+C*6M z_l5j-?go*Togm!oR|_*~2O&>e0NQRo{_plbnRb9o?{0u}41FNxs^;eAtx*1%;C?+i zw!E|kQeXUY`~`mFxcnXE@TkvA^Q*WxcW!DKr{`0{OJHJPal?i|nMStmpM21H$j2j_ z_@_1tkK@~)zW>uP-1$?#`T#N4LD}B{bDkalUHoxYqoDNTG$;w028Di8xLi3Gj?-j$ zOh7u0fOv;~ko2MtWO?_3x`Kbsf5fBihAB{!Jp#VQkKugDx40Ql88`diY8A0FFbA0c zbvctbUxRpn@WWha`(NZAj>G1^oB2!5gJOw);{P`5NC?bv5?*wI(l{8)*G_?fmU++u zbDNp5e+A+HK?sn4?5v)Jwgdj|>jWqc?}s&zZt&^RAZ|sP?!zzQh#oBc~{zd6SF6K-@2 z#RmAAOsaeTPx}Wk7sI+BHS&LOKNSQrVorqipA7C2LSOJ6cM$$*DZ+vj^Hp5!0H5mpk%`S1*`CJ_Dz#`gajQ$~9EpJX3>k7$J2r-u`uAr}r@{p$lUd!qOU z#egstdW4UE2b-2bn$-$Oe1`p*|NfKsANl?Ooo5&vL6Mp&wFsZ ztW2B+Ut(eW-@XL(dk$9{8|zuZ<-!g5Q#hV~ju^r9v$GoJu@=1``^^LxYJvG4%rBdY zCqbg)AP6@c!{y?edHnl6vRNnw#^aB8G!EnHMI3q*|3b_L2s`?~d{7P^!&Ql9Mpi+V z(*|~=UnuuO*TCDG&0D-~pt0X5Ynb0c8;@#sNLN1x!&;915Qv2}+`+avP@gpi^SS{r z(Z2*L<7dD?^CE6cVXPaAiJrR(*KmHd zGIb0dhczzkzsCKWX@L5M$Bwpf7UM7u--y2;);Y+3R1e2}rlzKL!($zYIH>kh=rsp@ zz{YqTsvjUa{HfvbC)&fj73ww8-RU=DkK7(^IMf?RiK3+p!K z#ULM%RHtrCuEI1j^x~A&~Wc2=Wiv@EPzeehPF|!Ccm35@#P!opq=M z3vxb;K)IQMI=>9ZLyY_@wLx_@sUKRxY(`9I79YO(OT zP!H=CKy~6g#1FB;G1WBZNzhid2xSG%4R|t)qeWNkEQl}~{)q$88`(T0b0Kj2^^@TU zZX9+qZnTfLd5A~&+Es$ZG#KgJsDmSn5bICf$I}4TzXYHR3?lhJJ~;3F-{VKL-Hd(n zKHk@$E$+AutOX>Ffkilen&%1UL770TrAr{kV+Q2Do!Y2lxlDqxkXg`}2gljqctfG@ z6j+*D1*PE=ApYq*Zk#>-=_1Ys{f_td|M9#>dYfjk4$>{xL0Qn^PoE1h4nVAj@VN2Y zf9XIB!jC@fU*|xS(SN1EhTr*B1Kx}s?W1@DwGI4((3bVXdge0d__7304Fb_F>M@-E zVK@nC4CgJ(tb&Y}8^;-b z-v~~ZnhO@8J^eL@2amtVZyM(_kR3qB5O%!ICYnK8|9u4)N94WRs6*pzF8*Gdx4-*4 zbUh?T?G2`@atf%1_Qv(LLpzFFWb!P&HH%l zXp7_$@e%Fgas6qF>e&f4BRJY_{vPQ8UIt=~=6?D;bR5aRzr&tvj)gUnnV)$+!T_7a zw{PG6r{+Y$S6y#|GLr;{hjjH% z4Sk2sL-rGWk7$6lNS^StM%Vs3{K@9axV!`TRP;f8ho1zvyY-*)e)D-SPT+$ysKs3j z{+S+ywE;Ic*76$-5TB84M!Z2|?)aPu?4(Xx`!PG(dbW@}I_yr{ntz`(6X_AKZ-Te^B=pa8+ep*!V?JvAZ1sTgMu83=HgU zozbxaJFt@y1-liyK|~Bt1QBTi6;V-CL_!+r<`U<8&vPzEuZ%PA_Rlxc8#GxUq+xo`NY=LgPVfc~t*kJP#3w@6R< z$T;K`CDVZNU9XGaaTcrWnb`hp7tYbN@t5l^U)g`t=B|A?-47F zRr2UE&gxgzM{Zl04y2V_f8NW_Nh|fVyjS%B74N{jq`eT|nq8tHVgxS>PhCa&_ z?;lPTudnCW|0;Kq>A*HDxgN^zWSX#ktY=A(Xt5OY;F4&`<{{J{b^s_-{v$4^J8^1D z982Q;Z~sOa)R~!}Jc&n=@!+26A%9c;>_G=*lxst7BXN?L|tu`Lbd^!8Qb~t+DOQZBasJe zA&?jK!s>r$?`)LIHt+qTyv=`G=kKKhPE~=!9{^9lH*}yZjkKT+F#Kh@_~LFN){PkP z_5tWhw}*+>wuVaJ0Nv@`qtT*|b)57~*o!nVITkh&NL$kXjb#8l0Fznv_i*}u@eKIX z0E`FN1ITZG+hE0w$C*=-`72?Ui24zzKc((n)=j9lGw+#Kah}YZW&GtH_WwoQ)yo8K zAlWk3x;?PB14WxnG#f0xI<{SM`s z5h+p3Qz*1~jZi4c@oENdN?Zh%Xo^A0t3Dk5c&#dZCVl9|-=(F`r3CzmEwq#j38iF6 zC|^+u|ForSkdb_ikRB__$yYCh^jEs%)lBtV<3C+hpZ$CP|EKc2R7L#>-w4(7awV=` z>MhelzRGlx=_g-BRX$(o?8OJ5djzj&FewA=uk9oyK>LYa(q~e`q1mJcHRV-|U^8E7 zu2AS82UQ#im5WTtI1(N4eilHEBVmR#|D!(*eSLk+g9i^*!GSQ^Po6yKh_jIT1O^5U zA|NJ0A3ozde#37iwEjoP{L^d^x1tKh4Z ze1>=LAzyLlx9~OkooSiJKP~TH`c4Be3#z<*`*sj)Ku!Xu58xwnF%LP%# zKNte<)#DWKTc*LDAQ*X^U>lu2eY!I6`=8EXd-v`w4`1Ygkk?-WO;dmemB8=0Kk)v{GRgO(z~-4cSC2zk*xNw|vg-T#X39fk-yix_SR2AuVh?oV zu32Ilbna{$=83!$P{uxQZ*Sdyt1VzFp-H;HH|!z!6YyiAr00JOT3&{))hXCNbMM0a z?_UAmtJ|xyF5LHASV$X}MDeM82J*~D9VA^%AnIVg^fG?w`|e3eRCr0X}|h2%KmxZ!=Ew-b-yp#n@hN3?=H(`DCfVjJ{G=r*sq{3vMiKI zTl1;J;Yac2_e=*Hy?N{}9GKZD@K3NWLOhAgKiLA4wv-{r_;WwWJvD(i(q5GI!UXO+ zi9h$&>{kTVkzl_XI(F-9F(XkWPh)?Aot(js)`9JYbW>&AQ=(uOa-sk-52aMTdS8(5 zX-7}F0P8^f<^8d|Zzk?+2jWg(eTlnVXZcE*p~JRVjB%BiqPPxIP=|ji7t#n15AVl5 zL%JtL=8HGCzzzfc?w6OUd{1SZOJ0eWj1%$WUiUQiyre(tM_*tWe_q)JGTywh{*oWv zv@p@$B<4#U*q89v7v17N&aapswPEA)fPF9{5wg;q7<=gJG7iL zuh&guMc>QNYc66;2g)r}I!;-Bq26Z1pU@UeW*qeP4-#vu9+fe26CVx-gINEQ}jz;b`r1?#YXz~3c=vh{NjW@!!DOm=8 zGp5WN_YB|<77>1Kh?%1QJ^bklg*LK7Jq4~QH;lfub7B7}nZNA!Yr9s}S07x4f3up; zmh)cNw1fbE=(}Y6FD#A`Klr6fu}oxt7S;Upbv{-vhkccED{ae&8*sE$_hFLj0-Ija zKACGFZRShr4%jzKwy!)6*v{T(VVed29Gf+0gSnsJ+ZHZ5?TVND@#vd)aXIxrSa< zsAL)ELDw+g>Pz4{|=_8btirN16Be<JTWKiYk!;_ zA=+*Zhac@%e{=QN8yw%)R>K#=3+tL{9K6N)^kpuB?td)ioLr7`#@XRoNF5~ga5C-X z{!2M#fKv*5wjlS1ee)@UaPhQ3r1;1Vey6ba47imhzPgtzzVl8OAKJhU;%T<{^m>Zu zcQr)}d!C6oEk*P?7cbHW?(|&v?tu=E?BgU^p~opzd;qpB=K$hC+zIRtk50mN7N(rQ zH76w{Weod1ZCNoUc1dd${LgGxscd5SJ=4p0t6%LmCcrK(1N}Hp(&gA}2p3&JWBMM` z_l7>1Z@p6`o7@n;45{w~+)0MLYL@7IApw4Puunk$r(ZAq+2TIrN%JK8AaR%480{_d zg~Wq>>5f^Bm=>erkAU+I;H-gmsDSm&mH1P4Po9vta{Xc7Q^#Ar=UC>t%5|B3;xQkx zB;P5w6LI2OpH%n`z`qc7l9azP&O|~)w$xt!w-aHD2|e<@Sjbyd_P9^&VdH@HL47=t z_A+lL%jWspc6o~U$zR1A0cRJ;pDQ44Uw!obx9nF>>{KycWIX@wNIPMSB|ETw%U(n-g3F4=~OetR4O>@ZB4awJiojW;~%DD4N8h-f= z-st%a*afM^z#HsC>tX-a2K_0v2=>_SR$qO*{|AAl8+lHdK6&7VYP_y;_?`Wbf2$Abs67-J7{a-3Y=5G>->s3^ud&xLI2j< zmfx#Y6ZQzp-!@FlK`zE2x^7t$%>8T9%amC{-*^A4nkI!L&~ zhQ@J+Djr5+xKez0F*k!=!asuVvwfX{;|>=WQO&OZIfIt_ddcpg9a@p@&7{?{`Rhb2ey zYhk^j-{wfMPd-2f$FXQ@m@LxXH!-Y0;=Q?FD2YG&u}u4G8{lJ)I0B$KefcekJ9!}7 zkHWJY@^5YjzVb|RzvPwmAT3D$yO5nRzK?p08~Q6aY-K!#Joq!DgYG#Z?Q|nw<%&

*Ms8svxmdMrR5vLsfTgMz(tVONf|0DcAcVP_u`1e^Oq=@M^6zfJDP z$b(*6l_~MJGF_zoQVDx2mdW>=4{vQ!!jBxxC&npo4Z^(HNQJ#Z!My;U9YPxjl;b&? zs^mB_{aJsuYf1cN*$!jh+&h{erbOq9F5A-~he|_?!*r=F1) z4{e%X-U3euyCa~V2wZ#0w3n}V&Uwg&^-GOKdzq{3*O^Djyyf3)587+rJCr2(o;aF) zYiI3#Bu$c)U)!LuAiJg=!d~}l<_TjmGCFOh;^8;J6IRFO?ah!adMOr?W1~5Tv!L%*t=M$_NiQJ znjRWoVWSW<}qED3p{+56O&P85lu$E)KEQvRN%VUA{Bd+pT zP`}bAJrprt>Ho{;q%qeOxg9tkb9}1XM9Q|2ygF?z5TDv+W6!9PUjcs$;#d-I_1_rR z4e^~9>&rR*)(+bJ{<#jsMV^~k2X(wzKk5Avteb|EL#z5Xzah@VpW{L9GaR4lc&qLU zr5MWelL9^Y=K=Uf@eJ{u9v~ETmHcXNZsnfnYaNI$%cMOm=|`N{9&#N@(vdOcP0h#iHdQ@cofDHr@zCwiJy8ld%0oy5&6%ej%lJ{ee)M~kL;Eh);~*di@FlpJdl$s!&MwPWp(!z~|Zug=7x~t5*3M!ROGl$yYD_2Bqbz8GoY| zC9iz^zx*>}=HDsTi_g{Yi{NiH{N;Md^_8zO9b~$IL=v4;=3BUpD5fJ4XyYXf>?Asi zUN8bvC>CO-(qR(mJRsE&Drv{n3h&1PWIL|D|KjY%IBKxVst#FrE7&ykMQou7IJadw zf%k|--k0xeY;3CkU&JH__W%5kIuRcqpV}WkejJW?cl)4g@CDz_^JvmBPv!x*MiKJ( z40cSBSYLc03*U=0!=U4>jne+LwMz|ijRy}NG=RQrG0J;@vNNzA3zR)(CL#vR$3ijc zWxg2xL9*bb-Qy+Q%D`VNt&aOQ4*W-y7>B4wDi~$|w3VDbX z_>(Q*H`ikiyPEr06>wilnL5`~=iQ0oE5xizipZDFxM3coJ7i4bn70}Ye)tx)fAyg6 z+Jm~MP*1@ai5@4go-YS43I0izGpJw5n~~>|^$KUO_n<8Sc zQs(RUErGZZh&SsX)0%q%()P;6XvEZ#VxSe0j<8p(`*(DNJWC65_1!=%pD{fdr{M%OOgrKA3b9InuO&m#U$&Ll~KEyE*wjL}Kwun24 z!(ZUYc-3P$78nbbF8s~S+ekmV z6lq*TzUp1Foyqq==QbZS&f~nwI4g4BDM>@t`6$}u!qO=5(@Vtcg>HdyjT!6t){c0| zeuZ);){Sv`KRm{HB(|`tP}9Y#<0juzKmYk7Y&L-d`j~+_4KY{Nz;sl@ zn(>fbp_8-zEC#xziC(9ZU@HlGT-Zb~mg0v;)XB%8K5|^=NGXpqh^r-~N4+m&TuE~d z^fW9xHALM{lv6P-KHD$!IqJGM3VN*s z=-HvSx|%5Ih^XUw=bH|FRw{IHurskugpEeJ)Gz(6Bc^gtw)oH*@{!{9=G>*48yV9W zdJmNO;G`-Z9rz+o@Mx9MwoQRw1bL0C8&rA{?)kZ9s^iCdY5s-opXU>NKs@i~cRq^` zF2^I*Cu1CEOED}N`=7QKtOLib&qc<0hYrgLx|sEH{PeH3BE*m7$ub?Dag>=<#JMIM zxHZ9A!M$x7*KO-%f5z!s998qpHM1!AtVf}(6D0dO;#ShGA{TMXLY}5dv~)k2Ajzm` zCnb*!)|I%Ggv*AXp-WM69H(Kv?m>MH$8;F8fIR`?@P#}{6W{tGb|zwx2f8OAhJ8Bfss)m|$OPhxf|5TCoKR)M^r1)!|$I?X=AYKgOF{y+5 z(Gp-c=0#aE&3PJ7LE3pv}xlSmi}4Aze_S4$faTsi}ba7ium3)Lkzr^Ch;58&vEYJ z+N6#b@7ZR=nQ_X<*8#s&;MN^`fhM>Q=RU`62Y4zq9e{cs#O(rP#Eb*Ub0LCZ-*xYB z0@e+*AL2kqyv&x?W5$gSL5%$1hnQcWdwzI1Q92Kdu?}fdbi)X|4&vvj=goW4gglyq zNeb#Jt;1o!jlLO`F@8N62jAy-&Q~51ZNPRQP;N_Icfg$#iJ$a63m*vB=00~!h5abk zu}m@WE^V_^F&=4m`}$sn=w}aK4P1Gykelk9O+Q=E%_keN88aoj zy>QqV+(yiKyVWZBG~3tnSenQf{Ob6z{-gurVbO1exBw^Wlq5b7yi0%lPUn8$=H{<_ zxZGFN`=L5dOg<$#2zu*Xu%Wr0C3;%HKKK#N1vra!7yK>b+PratzIUB`Cc&R|g6wlr zyF%XXYM~U9BPAUG0)LBr$sh0!_tn_Oj5EyG#WD@$_+H=Ohw;I=|04FcjDz&b2{tK+ z#mM+=_x7d31~ON)UqhP;#O5^Reo_g%>BEy*Jnq!m7W+B5U8%S6hyGML`?aXZgK?)+ z*h%;?4%Zyun8&e0y*Ft`x~sQ?d`}uW?f5L6zd)Tk%OKp_pN80Ph&_h5axCxqnrz80 zD(q<<_VC~8u9%lRCP+WVDWr`6=M~^G3%Gs5~KG5B@hXN5Q5<>USm9NNJ7% ze%6QudefBi_}6`q%icts^$I&)oFBomsSCP=cqVRpzUpLeu7zz$G01uphYh*ni(6R| ze-9iy(4OCo?}L6w*=$l4;!e7NH&)mE$+RPW+)MH*@iS;^`RcIcGsZOJ2gUm%_Ib`% zq$TnFD}AN!$sEMDEhJAs+5RxOT}xi^t{lJuprqWNeirID%6*yTvOF0t;>tGSzLv5V z#wO!4(w{WsJJyeVfHq)Xb*hD;`~Dp0!s%lr#mv|S+WoCx5^0NX?ErbOyWpfs6&_aj=bkHzUTbJy2$h=kF3%+s&J#71j_>LuHgEg&g+s$itn@m zPE1ESI_<`O5j+<0V_T6P1pek&A&#Vtvk`3U0lcU07T@zb{+9g)c+WG0d`@IbHUumK zz*wn`OSb3V{YDz%NIEJR-}I4PBGz|Rj7}LpUfG7kk9bnAOOV@^_)&jFpuUjp?r5AY zK6gl$;wdw4z?C1xO~$*pt=S)wcqRvJpdMX7N;L|6aLXcuxEx0K`|mQa{Cd$n}!zDc74ckiZMU2Y4^jshDn8z{TkB zxul0u9ZOzP55@O=0kR&->+o`5So;zmhS0 z$8Y%U4`%=kt#9ricXg={_ z?B@u`DRu-02RHfAal$xDkU5XWKJz*3+6sAIoeR#3;eMgy+4fxLW&cI`zuKO zEB!}h-bP*@xj&crA+FuTPXMm}9kwkvD~a~Lko!DC zSvu+)wHO2%d&q;d9beClFQ^Ul|>kualF~-l#hm09@cC>&UI%Fs;k8Q#8 zg&$qPdCkznkndEl1N9;Ik1manIg*LVmmBt52VdzkKC+4vce*vcfQ*v}XBi3&=V* z0Iwq76FCwe%f6%H4~yldbH4gHUN?!CWa{@%B#1s2lE4$f4j=vvo~IHa$A*p(azd#* z_~pv?YzMX%+vMTtJlcm+cejpZ1CJ_{33J|HOh4{>*ne1m0(HIguj3gNlwE&_;yB|BGVxG<*ylrr&-<4ysql-y z*$FsfkaF^;*C49_?i?@d8?3*IuZ3Tuw$Mb3!+m2@$mi)^H9Vip#IhfR`Jh_o5 z`dvq?58zW0C|_ipKa7J_a`|^G(O#IZIDgCd+88E?&O0IZg$pQ(&F+e%s2N^aqb7=l5d5~73XU` zv4?yZa@u!@fAY?oGElVpJ?>9o!wa9xXIHW%pJCTSs=1V9v;VVf?qzv~2+E8G{aWG5 z7-{aG!w`34qq>Y!b@m3&W2fw&zB`neTr*0Lbcysedf}KQ$zEUF&JYP+r!dE@=GqAR z>}{#yo$X)cXygev|J~dKAB`|ck8>a8OM3{k!&eWGRQ4ilEA>2B{B1p%2)PB>av|Izv>vAF=w$~Q0~q$?`#2IiWvTs^-w+~ z0q$9E%Jv@N><^ZKvdmE?wD0%D`yfQC4WQ^tW~lJX_?U$z6wm--UM zE5|JFNgrNGYo;SEvOMno?mXCa<#WFui~NVMtS=Q;yTNm|g8{xvjsy;j;~>fNQNA2+ zn*D<1vm7~pxlGoZbYS_ki{^R29tUzIn=-7i$;f*y%TO!wPq%nqmN)=nlcI2zEzVYO z*u*}q>T{$4>q2*!)78lg~>^McrdU@B%_+vN9zn zE9a@_FpC%9(<^<0Gvx)?E}$;4sB5(JJ=0(xDrBb= zBqPtk%pYTt=RaTh;FAX$r${tq8h*<w5X%Pm#(c>a zdm5=Mwnym0d;xjdvJTu!!3HQA=Y0v_BPE)$?GP_RaM}YpECNouV}<9pl7$y{QibP^ zX@FD#ad8C5Cj@(wXu8F;-$8; zF^m^HPbUe`vj`7t69oAC3$Wu5U>_&Ef0!mbyO}J&e;tqvT;e1e!QNKtWAM`z5JwVO zD}P5lOu<_Tu;uxZH~R+baBe}gfU~ZJ0GC7|E;LKPTnjxoVmE!x6W(~H2#@WO1iOu- zWfa;wP5_?@NI*Rj1jxZiBV(*(hu?Z+NjNiKg6*n!0eca_^Gt#On4R2fu0> z{i;xaU$_9?;u{)4_96Hpf9y*H?8yb3`6(a{gMjmJ1=w*20gmZ{)3!8e?2#@Keb5G% zmV6cvTZlI9#(+s|3&bOk<^Z-a)^q`UnBeb_B6yun5gu443$QB`z-J5CcL;CX)2052 zy}R)0PL_c4Xa(3qNVI2KwlCrW(g^1_RJt|$k~{h*=P#TYCgl&FR=~NdNEau7Zx8|; zG9`dbq43x?O~9F^0{CX(+PYK$e$5i@9LMaRo=39SKO>QUD~>O;fo-sNj$pqE^CRXN z)|LGfdNaYsFb;N#8Nw~oG|Xe^f}c&M0C|fLa5G!Dzb^}YT9r4`uD1<)BXFs!% z=Lpnc5YARib~}(RjbBwiQ}tKuPtkUqV-f`L=)$8*n9G)>2zM>B1^4~gsB?ydGq2#! z1^2_5LQYy?64vd3^8CX(po~MDo8VuqYA5z%^e5Jt^BKp()wPM}SIJWSm>=s3I|uyQy1-G5~Lc+%a`W_x+o^t-YBL7CmhQPG zfajHf&)s$^1?*uEF|g<^@@lA_w|tN1Em;Qk#RV>Vl7wq(h$H4P^a;pP1eOP%1_^)8 z%k0mWmnR7xph-eVKA0&f?-p`?-@CFNfJ1B#*wzTJTM_Knp$!*dzL*~?tuZ(kLa=9_?X%arVc z=zEv({lJp+E}7@|eixTR-iT#DoLm^Mjf9aSjJchpJ(FMfn zyP7V1^vlZUyX?&D-TanmzK0{8mx3;0Fy_(#oR3_1%?Pqs`0i4!#C<0Bfs}7kK6=X> z`el3rIplMs8N{^ed9n=Vm7bss^ShWUoL{K&YoMJl_ly{GQtVRxrac7ryH{7jChSDA zkeZ+j1<%TU^#xDl)eL0?c%DqboS^a3;q*dlBcdGKrZ3dghQ2Li}FN*m}(icz`P8llW@OeQl4PHlz*KlVqY`hU0@!TTF z%b~|1Eg0hnF>ybFXKo7KU@BrV=~9f7P5`Vj8Tu^xy~FY?J}{DHmOuBYe+nCI1GeAr8)j+B?uo|f`t+EYiof^9zR zL@7r*P2CFjyl5Zdh`4Tu|6H^qKd<1TEW0Ld;D@Ah2Ei*xcCw5gCRrJPIE=Lwct06> z1K1_PKEh>xf_QiTX9-?7r^24L;Cz05!NteutLzudkM@raX83*=WVsHBIHN^%-X7)! z>70Ak-S=Fo=&~bCyp4D`x3^($3^^ffAfXdI53jpjZ=4D^=Sq09-n0XALAg(Fz}^@# zO~yQBT%!-LZKn+X0nU`Zw(hG8iu-!R;vpZh1AM}iPtTP~%;}O$g7l^A`u-7Ix6+O) zjr~D<!S*IO| z;se+udLGSyEF%-LauceCLr<$aqJruhiC% zT~ap6I6{mkKzmE}3)+xfU#mK2nd6%Ap5J*wIE=PsUd3aiNltp9KVs98zme!jc?V@f z?B7?{B#SqVRI+nf?kvf_j0#16Tcv($puNX(^+^n4R0{^$}S%uDs>vN^J{*(t%9!1(? zot5g3c)5kSnG#;i>znyX&X;8XnvkBr^&?_yDxX|U6?lHM$B9J9p|J)&$x>z{=7$s& zi967ir2jW~$$6FoR`94o04Qta1tZyB$wpEir ze)pfQ^7l;3Jeb!)l%j)#s&$Pa^&x9evyd0p%KUCi*ozxapx*8)8(F-Bfv z|H8j4+y~&K}_-4ZQ^5Ap47nm~og(!L>a+9->DBfBlik^E^ z&-jktl*|La>)?4h--kUAMW>CTc-M@-RQETQsjhs-KYq(JG9IX#IiE)dsJ`R9?;%wl za`}A5eEALkNFzBt=<|}#y!PUpLzG2)`Nup6@;z~4z4(VTujKT=M>@#Wah0kJmMN#> zw=yogm+OTznI+TH9#j6NWP0XF{2f-RzCn7WoLxOXP@F9zu~ts z?&?=Q$0uphhu`^+IQ~^yIUgjG$4?->&m)k&#Wecc@gwK)BUi=-NP|IFL^;@^LF#LU zS@7?G-|$s@)!3Bm5R$lI?R-n702NH3v^Jg z(o+3!`^_A?bL{9Ll`Ax$5nE;Ag{v7si~9%PKC_?UQg+UWAp>C%hkxhYZ4cu~`4vO| zSdHsY2?jq|(nq1F<1lPszlj?@B%fKfXIjw4$EI-}&kHssXKyMp*R5wh%HVK|3$3fP z8&-bt;ab+0D~~&HV0{0BSBK83c_4p_;j+V3bv0XFk96)oaFo6CBI^Ukt}d?L`nP6{ zY`VUDkocf{m9l&O*t+*!Sm;LAo3`2kXF`Ls13s=^5EtODSKulFRz;i24T^$(5Msa>Jp z-5d66&sZtu*mN)+sxh!;&6-nF?j_#nY3LebRdwI~{f7N_M!wT%Qfa{Y#fv}tV`mk; z`bF>c@oArYUre$OI+2%J_E|-1eT$l#a%`KM+2roiZht>Bpr`)E2(K-VotKAhdZ^QQ z)%z70(NAXf&VDl?T$%sQQ>c3Q@Zlj*`%leS)m_(Sq*3pzmjj+ZD>JKy;?N1_V@nTQA8wo*+OXU5kKN;as`iA?{L#4$ zkvm&9HqLrA%=fx@K z=K3_MYqGM!>@_AHV+S8e?p51XtHFdoo%Bm%?az-lUv^UKxyjXmGd3-&=RL4Y*Gc1l zpRk!(o0t_9-<`akvo+_NAF~=?KBC}pMAYVpx$lGX`mETV!@Jj z#^$lUIcN4S@6~rwHM0&)2d^%({N#=&``0`fv##J}e~)eZ-i8nN_&t0;>C1``%hU&@ z@-FqBGP9vm%lO@qu}{|TN_uW)RK8Z(VJ1r)Gaa>l-`O($S=C>kcrJ?6%g~G7{hNXE zSuInGCh>{YetE53y{}Hw!DmW!8#T?=Pimv)+%|q-&lK%(RhcPpFCQM-dd$QtD$C?@wlX_{tY@xk)%WiFp<333nW@;R_+%osWws9}hr_>J_9b~AOwJTt7 zvu%B!HvhD@Q~#_c7nkf9bYQ1q@T%qxyURxpxP7Z4TW77uM6Cu}o=wayb>aT|^uVEm zYh7zJbwtB@D|a=RaBQ(&o_RNyyK8O?(OuCx>*9FJiJHM9HHVe&)MQ`d*H=!hyV14l zT-_C=k6lfzp<8}lLEL_8>sdXPwqEAdWlxz&=f|1b7;l^Ze&UOc+nU6OjGWc!!$c>u z!4Uy&8KZYtTQBS}ZCu!nMaLbrdVcJwe7AYOZcT5mcb9th*ZSyn>2tRl%kK784%qQ~ z^>q?y7=8KM&DewD802xUw0)FCLSI`79yRZC&!F4%Gr}TGnf0WWSKKh;l)V&D(bMA9kc#4Tl9U&L(cDFt+)i z&JHaUH5RvN9ki?O<{@LP-a9RNy`j%J?L}Q0jM7**d+13sU5jdd3u|BdSz$SQvgPde z)>#9Vlv-GB_SlNk!t{Fo8h>b^ZkWRdMjZJ?FPAfOPN%EoF zEzD|P94371(WIuiUBzh|2Ai6g9B7^zI|7+l%pO~{!Tmn#+wW^qN9%EHlD__sqBz@f z)9)>9yzyljzbd5$bpGRF-$7+2xi`4^{H*W({?=V=%th8a_@_sYV=+0W;Hc&rQgveqD{i|@oz0$QcSgHjhnx3 z#_wkpzR^hA=u{sYtKEyn>~9jjRM#_8=-;~e?HQHzD+IN_=rL(p*Z7+XtEF#}raudB zCa!H^J7#u;0lpcd+Km3CwsJE%g;Hl52Rji_WLZqgYM<(wRtvkb-{>(j*45&!XqAJB{u45 zI($hp$Jm@>L)MKltG2BZrt}2{O539$V{~Q?-x<25VBw+E8DYykYuDeX=vS?b|Gmb# zp$4(>D^65{WnittaWj2u%@0Wq89%&PjmJ){Cc7HAXb)@hV!_+%pH9`N?$Xnkvk(azxs4Ynu=Sqy zBZp1xsp}F~A+NCW3Xcyh7NmVXSEa#*k>_{Kcw;|QW3tc4p>^6l`J-!Xw|d%3>rUNR zuU~-q&u_imTFiR!``!5?lb))7mv-Z56`-h+Fx}%B~KD?>3RjXxczmjGy5S8kqsNmob~auTzavOj z(amdP>d{)M`R)9Z6U$9M`K*F(2QwX?k9x!Bg)duN&&BfWoV+4i?K!Do&Vx+`*V}Nt z#e#Cjc5Hd^xI^fQrc?Wj>EG>LPSvfo%@iF*hOG;FZRFnilch%G^;N3d?p`vumPMx~ z!~MoL(HK!rOV`QDs(G7V&&)e+{A^;Umkw!zPb)SZul{7{!MYZUPX;?YIn}kU`;^Dl zK{bx%w=k@`P;BeugA9w>>Ho%UQYjvd6Z#wk6%V*Cxz7Nb8GXfdCrRto(sQcb*NCY z($i#@i~6PFpJqh;)YHA0XjFNhr_E5)glqX?$MFg8+m;@;rhTyay!uve>o^1r?UU8I z?X-6p6PCRTeAuw_ilj=7&Wu;)%#Yk-?QGZIz2nhSRYLC0+WTgWWi|UlM)3nCZ_s=8 zZcj++HXZXxwzWS!4)C(8xOn~b>g6`XZZ7b%56U>@H(Js9W1njW3Qtz`+!c~}&a?c2 z`Q8=Z48O4K@{|^DN43!%wnTa8*7SO9GIV_%(oTk-pRd`V^ZEYSx6U-lR92oktlAvq z*({6v$ehAyzqzgqnfRb?QgkEJ>z-R0d`>u9eO85jPu}XzoTasO*YvRidLJ5GHZri! zcHO8KoA&$r_>@^ZrE~g+y!catBicYO3VR*}ksiJLLZLh9%K4dC~Yj#L0 zA9ZU@`>n(K_x4=i(DaSQVGIJ@8h-m%SGjv(jQ6UA%?t+C?f+8CIPBWYX-SSRD~Q$_Fr?O~zr6B2$oQmSL5yTy~}^`CN1MUQZL6tz4e@s3h!pGWA_j543! z99}#6U^|=2C*EXx4e+t@89GmSa{0{R*4l>-w>Wyb@)pezPD|_TePdW=`ujgDm+SA? zerogMbz@g;Ix%9U#(?GuFww4A6)+P`(DbHogE8rorx=5vuA6|ItE7^=0ucQxbAA;9VM3hHv`?8#+A9N(PY86 zy!hoAo^B(SHCeR%Ow@|Zo)L#rEh|2G{H|ZGc^@k)*L6~w)cWP*&$rgkX*tMN@tb?6 zwOhAToHcv2`;JAEe^FjHP98BK!v40!^lk3`0}m*sX|E31)W$SN*MG_5?220Q+$b7cp%DeWJN7rh3Cg8-nXD7BbSZ+GUc2z-r+pG2OD*FEPzE!nt<5nbS z&)eZ>pf_n$s`H6v6`Jg+Ja4d2*tA~M&+ltDy0o^GZTSIOqXSNV8d=n&VMcSk`E7Rg zZ?o>K`Gm0{K|QnMZ1h~SVxPauwlJz!N<-`XXSbnN>sJS6x6*8X>_bdOVpd>9KZKt+ zdmy~b3E;cdav3i>3}V32e5%+Q4zOUUZpXtJJ%)rE?W#pEnLk z&+mJ>e5FgzJFO_^*WK)OlFbcwi@iTreC0N7$fwIEKP}PKKT>`4xz_bhD+)IhE*rXS zuI|$w0|Uk<4y~-+-HnW&fEAxHBS@l1>a}A|2>~?ME>r=;#3)L=cl={Bm#HaJF4?TNyvT*+8OpPw3?#^%eF}?lKlkH{%PXFv+ z5i_gKPyW|0b>Ftx7*+EF=9hT+s>ZdM{QVMr&7Op)`tQzCh00)j;Wef z;I?Vq&&ji@c>A0d-|VSS{n+@u9Y+o*T3>H}*1Vy$eyz5#=b-Il4s|>8+lW3{0~9p| z`3zr`-EPa=DU(lz+^KW+&18?(jytysC24Ne`C)W+t$)4|TmcKtr%=R+-bHNoce!k!unTIILfH&PSq>~A+K^bei!)_Bzm z_ko|THqO#m+-KzI?5=y=j+}bM8uiBjP4vp4c8PsNU zK}$2?TA6yK>JRca$u9TCGq= z7T-@fZts(EyQ%)El-V7x+}@(lBCgakFTV~+g*&Yc&KzDabwAJDLpl7#7yeD_5`AmA?6n zk9rwQHEHH{WJP_ito}!vU94Wpdspha@vXb`-`~T~J7eDS#CkOyYk=D=c)It!X?{op z+tuY8)xTAF%gdn;yND86ZXOHRSnoQ9c z>eYKq{L9_a^G6js++X3JTeRDH>6t*S^F1alF^*~&p11tct9mJi8=E{|0ePKa;KNmO zrf6(4>%KDbL3Gpoy)uIO>1Q>lRi$ySJi`}#3X*PL8Ex#-;=#kAA({it%I)Z2s(fae z>(_LD;oj5&_ePpGb(?$S+_`C-C={fM6_2dklQ{bp@; z)jW5k$P5CytWv)o`H<1K-k^i}-MY1$?7q6EeVI{JN*z(0?6Chxvi_QGHQy&y>Kg8z z*Qd^|!r2uzdp3GitFNE=v#RmtMlWl5b!zYa$BxTdMs-?d{!z1E*8}ZRuQ!?&nX~rP z>~BFVfTSAE4e9fTAYYb+unWr~*)jV7jojU%~rQI(b+jZqD3lF~>M-Lb$bZnq@V4`R z3rt_Vdi7ofII2vUD-`ABzyuVbRrtFka4<3qCTpmt}|!b2G%-i!uf074YS`%$WCLww9JwZ#g|wR!WCCs`H%i zO!Tru?4yl{n`DV|mY|=vn}ir$qtiu)+3-DCmR(Sw6w@kHsPH8{)2OHS-6g3T`B;3o zTPeM>`yH`@DDSb+%N|nAz z@4F-C3l6M1fq$2VA)eJx_sj&Yxl{6$+fphPLa!E(0YD`lurK7ZDSVjg3r=a z__;007Q8KU^YbzalVticy)vsX=h5~Y@y^0b(P@6R_-LDIY#d~Y= zie6nR$jd_dGG)qqX@B&GBL7pl!p-S8i)j+uKUZ{x|B&CIe9?VtKGG>gudRjR{Z0Ae z>nmt}gw$8>KTLmhGUEP>gT2T^#AluY->T_2+r}_YbVKYNpY4U>^D~0@@)FKgvjb}Q zUPD8pC+?*F&nG^hza#q4&6)5uM*8bW?>H}4^xRS)zBq@N{e@qu#G^>QNzd}1SRvNj z{2cKX^0>7Cv{;raIxSa-z-d)l{}U`)DwJamI=3(7i!M0x-W9%4x8@@T9?E-l zu|V|1n7BR#XKodzXD-EKRZ6R#p6{eTNyCdf`C9y#my&7C@Zg6*18Jy7g^tt;o(4L| zL#01dDMi(7H2$nVL}F+oCH>*FRafTY*FV!Awz?_n4>un8>9KLRe(!fZb9{`qp4U2L zrej{Kb?Y~uCU1*B^vC$NJFl*4)MNC)i*sI&c5Kz-!t`IB4Lf1A?BSsaj`I%3Y^^cj z;M^&Dnoeq~cVq04^UrD+>^w5iysp*(9Yv(h=sD}de;pFH|3t9y<~jRQa%a3qth(6Y z{r1p}y)$DAl4s8JtTTRi+d3mmBklCYU3wL zcL$Fv84WCY=YMu+Ykt!t+y3bq`?jU3^^Yj%GrL~<{7H55PTF`nT!?Peecz>|X-_LD z#@C$ezkf`DUdWQSTD$h1&PmNlEz^0F*Gcm^M;dsQT2wbT%XG;5s;)Dun?18mYd&F= zj@US<^Tj=*8+xtrj&mHT<*+d`wq3W6D}2{NK>xwfq$q!sS$J|ogI9xlb?v$?2P<&P z8JiMpCRO=KFDv8Kr6Ds%9kM=AVo%fFcYYCi9E>(a;D7k*40paVta)UefY zXVwdmXM1lpS!`fnFv`VnmrdrI#dqFS{Yh`lif|9(0_aF@8YNE+&wuN2xaF9}FNBb$ zzi!)hVpJK2!47LCX18eEYr_E@t@)dG=X?ljem!V};@C_RWz5X{z+;WA>OAWbfUF}A z4r#1>R@F4mSNqEE_5*@%N0-vD)4dzqIcWW*^3W0db~$8p{l0E_&lIT}Uu-tX$V-pf z?pAdEk4@)Fm#fmNsG(%Xi{<*0 z>)h^coS)?wUKAQ$G$!%w^{MB2&(ttpsM)4+-%zv2ksk(hZrStVvJmI#N=bE5u58&_ zqvqYps<`CswO}J?K82i`V|t~B&QuWVTb~@q{h?*M9M?PMwaZi^exKsQ64TTuZ87gmsK=}k zj`bQho{=4~wW^T&!YH=$xl)lyG55!KHSli!a<=03ouU}j@aDaQ%csIZlPfycI=nf> zHBP?|^ueZ0w)w?r`ga|tY%Zocd!B`P_a>Yn zWAX^o6(P%9iX!9mMdgctIi=oeUA|ynRY%mDU26PrH;2c8zbyAG$_XBcIyJagr!<1( zzL=9x&n4WXphKyTDop$(g}>x9QXwG2}$k8h)9ToL;XV{IY!Mv2RoKglz5Av3AF-8(wMc+-!QKJH`gR zf4jNo!;6^*{I+d+Gk!zB{f~zZB}Vm3$r#hM=;Qbr&om8nFUFJQAwtFm^@N`LmsV^Ibiym*?pUMqxffSNxQ>v)fS1;Ui36ceIR~d3c&@*)|?s zn>s$cGtv6;~eRg-w!}&w!yfIF3%{w)4Ufpt& zf=@I*w5wsq_(`>_y0z;(bg-}9C`}J-v(yeB6?KkPTGwLdwim`@B6=L^J!yED`%h)F z2iD5$QtooM^7%em`8U@0sVm;GcUk#x*Qf)n{0Fr8u-K&j&y`IxPR_K?i(1io$_$g) znqxB}vhGIQG;MY_^_RSW*~?0up1Z@L!-7gVM>R(7Fb(Q@qh7GqFw}mu&d@{C3d{HZ zwEE32>FW!Ea~oaBU*X&$?{%t{(r^DnlfDy5k#7r+&HL5VIwks|du+EZNvRJPOjFd>PS1VO zV@;T5e*eOk<;r$!o^>?+9j6J7oawjHb zbGl1i*U~N6`JT@!Ws%aT?KO>&%Q6io>c3fVI&Z?B8m6O9m5)!Vd3~h$AhiS&Gdy7h0JncG7tMu_dGUHD9UDc^+>g@2iZF<9xv7T8m!F@E!)H75Z zb}u@XP~G!QJ0Ygs(v#QyE$W&U*sOEuF{`lJg;!-euC+WDnc(i4Hz4#^{R+=cpSADs z;N0teHS<2k^~oJFD6wY8w~EWo%2C&p$=y9W>2+C_cS*Y_zQd@_8d0Z84{l(lS)+CE z^{IuA*5ujDOB#{x5^i3_zn=fdh^iLVl$-0hoB4GwJ#>k%E!4jKT(`yPFD3^q*p=6O zZc$qyXX>l^HSeyriZxpqS+3&&Bjys{rLlh_WXS7JvwPrCYYzg9~Kjc-DeC3N`gsLp+j@-G+`-JTqcz0hI zmpX?{p6nO%C_QpkUu-xk$Gy3!QQD!Ha-rzua$|2sbG*_F*D34UD-@rE3w&Rm@O~YQ z+dZZvwfXo3ic{OXHqValVZ|yn$gmwzD*2$oY8Rz_oAF{nfwgG%?auD{1b>SC3p&SF zj5XR#n4<@|K0k}=3VR#(mPYOn-8RRrh(tXyd72|z@+|joyb&hWz8wguNqoKAoI!S1 z4E}{Y!wB^ehCEB9tF2}RM-N+F3gN9yG?BGtkY&{)RB4Q>nXg!}0g4Ye-E2hqt&_hIxY-SA`XssQA{;oVI5uzEbAlgHFfMqG)B7#?;leC!V;W zt-ku6=^{lDM;_iTymEx{X)5Zz)`@eU-`edsyhM9*@p01Ht>lxBumy{>EW=?FjCzEQ zSNn3@(PuwNF;ptuRU0m-{I-HGBz`R%Wa#{IMF+=;lP?-c(sNSo63H0pd3qvEq%_9s z^$Bkc&y^1BQh{sLgkZ8Vdm73C6;&JPY51(Ke#pbYsPm0?h+Ny8%9a!OVeT!PHy5;+ zehs8GAdlW6LOlOz|D{%$gvF4W)AP}|*9p=?^KsbaxFykTlphaKO8bd>Jp(yveXC~j zR3GHRmsEqyfLD}j)oify^TflRvM<7d49TMzcypm&e> zl$8DXqu`8dn`B5g#i@FE%=25t zH=3N!S*}#VFF3s#N{m%@5{9#f>l* zSSn1U8`78^M`35WZ4w&io)7PHzR@gBy_pMtFf6C8GQr0e9v6*j7(Joy|{Y@Exg`VV__!`Z{ngWdAk^{BTa%MmA?Tz{*#D4g#+ZXZ6ghTfqb{ck5(AR)RHow0>w8zYjOLln` z?>1vQ?YZh~Uv)v6k_3s$Ql)puAQXQ!{(|h(v(b?V5AL!4G>up3OosfQEhev+%U&Hk zxlgh-X3w*)9!$FrzL;R|xQzL*cjfid2rujBLh5VF`p-Zx%ZGI`#R{7TXQ)(+^mv86 zO(fqa%s)fZ2s{*}rRCCbI$41q>+LWShfVl5S~no0r#D5N-p zJ|fS(=6ahC>xXAxFDO-z@0#Os<*ld9%d2&CW_@Z)(UW;>fm11|=B?fiUY<*5n(iFH zU6#B=oy6XBFvEMhKSpL0m{@i^XiHFAeuQE-arlaHl`S zDXhX2gE#WKc>C>sBLCBnw9L9u&mf!X*en#4hDzAXY!XBwtwC3*cB*QV&+C?kIK2& zNY9F3_#4d1Me~YF80NG zexF?FBe2a0d7;yDS6Wz*%eO|hTnV7bP6hu>?lXeeav z&eT---koXus6!2&@!;aYOWB2f6`lN%rZqSko`J(%YO@ougSj`Huneo4f-I=aoq9b# z*XAC(rRUgt0DXE+5@}fB5WClLSpQs&@Az$Jy|L}hlN>gvtuGC7Pu)5E@$BqV4ZkwZ z7R7YW9g?1V8CG|kR^E(NRIwCd!iAbOTs65q5+xh|=E9L}!JPi$cPOO0M@_1!K2+9c zy`V`tacch6yTfY{R@X#IrVqYC8D3UYlYeag0Mo&K8 zEmI;VjEgx3OVKXQ_0MkZBA@fcd#f(rsuU{R=`DlocMA$8yLex|&^#O+?a$v{MIE`? zG9EDR%ScZdkr5!H-X6P?R>7wC*=84KACv9o&07~yPiMt?J;|zNUih-q{Ar-?gY@0UWG<`w&#?uGqZABgB$3j^W83{o zVlg_xM7ahJo{L<555$Zw?tgRu*S_6=T+~Z7(DU^of$Hhah(TWIHs!Vhjx^?c-6;2X zsh+v=^6|T@rQ`c<1&Dj?v{h+MYI?Hx+^dV+accScmnF7lzGA93X*3jdrrQp%y}6iS zvADwPX4RdDy}&>pU6hrQ5e2S02yA8AMPF(2Ja9|g>Gnl}_&JZkqSoE}s)EJ6OnKDX zmlwD8KcG|4cW$h75}7n~?we!FHz5B^wbg%AcRu7!r7h$1*98ja!9c77^Xu3er>HmW zyTNr9ZN55+R1PM$r`z?0r{DW~uIUkS?P8pri?0FQ<*2fN*u4jrZ)a2C`+7#qDr1H# z^4**b9Qx)W3#=GqsW0EY*dWQz`rIULrm#=`Qmbu$v)=VeYqn;f)MYDrT|6aO$NEUd zbzerg^NVxvslf(LFO}GXgN>~8Yj>AMoJ`+NwHxe>s?WTtb&@Y-@}S#Ns~&;Ps)#C? z=H0zLNc~y2sKRe9T6-fYL3T{FOcc)Vx~D7+_6F5*deI3CS4xVo3iK8k9Q7AR?P@wK zg>A6paA85kHCn!-Ie4SxZX^BVd+moW7jLs~aX`rmSmiP7O)%`0eZm>q!mg=e{DDWg zBR2Qsh}8be5BEe~i1mIpLg{9VF?^8 z3l6I8TI0cdK26?KFXPlu7@<6?uRSZm(ylvuz_TOb%X|<%Wr#jGe@x%=f_IUEH}3H4 zCg1H*VnKM;Lm!v!<5QC8&E*LUpTs>AEBcsRZg~o09&{1*uhe4Bj4Z93CcHV2;H6Vv zs7I8?h3YrB9uIu4^ITJ~!A!hxY&xw7n=o=3rE`>U*ng<4-mH{*_q~A4@u`b4*wfc$ z%2bI@71dd>%Hp0$f!u*R(bl7cqkbzsUKZG+&(5D_;&84>d0dKd^O?=M9~$qLU|s56 zezop7R?x=C8AxRRe;AR$FeM(R)kyM+dR^0SYNcX2JwU~G%iCJp30htbI$=rm9bgo( zClPJW>iNFXF&>{rVJfv{RRc#1yEISMX?VW%TcxJypw%!<$~9MW5#npDz2tB95_!Yw z%{F~_6H^-L`Hdx>!&i@@Agp_y72CHfo)z4r%|-s%3-3`~j@;a_*?MZ3JnKV?TSZ#Y z`0bv`RM6*4A8QarwK@_L*^rl7Zi_6yd%^VRCU#CQHHB3iWlMCtb;Hn(770{v?uvWK z*!^8x=N;O(rII!e30-J&B^M!nvl#4XSI1t%ch!};wDrxsI3WLcsc&vmO(3>1+5r{o zKr9GC78SR0TNRat&D8ST zLMeT<^o?tbF&VSpxfZ4!8iuw<+o3pn=EieZjtUYLGp)X_YGgXD=)bNrION#oG2qyy z8e{WaDB_aO`(6A2;kw5bM%wK73}z2-f#I^|{n&fV4hFp)DY4jX8D*!A#agLiIeGYy=0I~srtI8Z8H_%c>kWEQkmk>y=b99dHRN+vD_gitt&ULoX?TUSBO`9er;B~JN$0; z>3tbXX_G5l&)ov8M#pFNzhzOW^+y*+x(dn!TQw0jrO})7O-0sy3@h}TZb-hqkY8FexZiRQts~g8@$1Rs1;7$>@vb7GRH1ywjQAnI?{lx<>R3k&8HIIH_{W^)Ta}01=qXtlwky#! zDh!NBWQ@6%6qzOA@7})PlC-KoFlR77mp-zz?R)cAZmyKaW3Kmdmovg+FJJ%^()%C+`D}VEu|@9z1NO>KS=D*7WKWYE!-O ztiy%533*8Ysz4bP%fY8t4oT}do^>}Jh_*UwQh#w)U)*OcHahx)o!(uu{ltViBUwS) z{t0?8z?aR%&t1ltjJS$CWnwHB4BGd;`-!R`w;nH!^}H!r)~304Wv^$#9D$6i$NDDZ zKFM6&&mn**q7psuzJXha4IAF1cTdE^&78(Hoz8*Ee9e62`bo-1a(Y2DTve!}) zzwutWz@mP?&Yr(juQP|mT0T^%w40zHcXnC$ML?`)m!8trjPY+Q-Ka6#p4rp1C9J$u zDioF7hb|2q=}*{h-XTgK!RA`PYGAAiywFDeV8e{`XRT-MRQ<5;~9H}$Ld1M)PX>J z4JVF%zMG)AX?tf_cS*wmhkfy73iQuCB|gQur1!byW=_^fKgp3fU~Pf@wpm7msA|EG z9IWn-WfNz5Eq2O`IpE@{aL?}-9?5v}zkYPV)%m^loA-T%c4w2)-5@AtCE8v3NqFX% zH~w{>x(ES2du)f<2h~53_gr7{+sCxqVQ#{tJ=Y~$gRJ=8yQ;4x@&Vj=Xlo^vf)|%W z-$WLcENM%>)C&(p>{?iWm=q0I{ty!-SkEmIeRO-XkAWb*)<(0AWy(Ns(pW1mRt5~& z)f_S&PB06;ZP#|R!;bKemjws-WU9X0uD?a7%F06{(5$G)IzQx+_8?oHDIhi1 z3MqIgV0>{MyqGhz$5wR-Z`#hFl!ZSV$aC<8ab$7wP^o;;T4YKLbJ{cz_+WwUr5m%< zp!|{A&b`N|KRkPNcZ==Esij@d-KaJvdW-a2TYY^drFiLvPv5rL34=D7jJm?biHV0VpWgBY|MjX*8`o*w_Nn*RgUntOG_38#eBMoN-*7&^ z>O9Bb^KAt~^nH5rLQ|%d*6eZ9e5Zt;^0W3k=F$!p@9+Xy7;5ZHSx8W5#vHNhBuvTE z8M}RBA#^d%I9JHx2dryAK#jer()c7es%3t*^G{U&4N+8O+nx#iTvb} z^OO-wQ?D}v_Xkrt_MDylAVS@4+l;MFxw_3G^X&@JqLDbi{ruL4xUSw0S?3E+@MfRZ zBWPYDw^uAGA>*!~A}+gBr99?04-n~NE7Lb?xLa67Q&_#3``OL{gZu?Hbs@X_lWWeN zN^8goU&UwD-P6V69}#>8<0aUZuM^O_R4n=`NjX-koOsjG+SpCI;cSWzOgB4`!B`@5x*Z z$2Un?=ljz12P9(N2w|jO51n_{=T((^_@u#;NM%!&TwuB1h%hB-SzX+;~GkM;Gh|Y_s!i$o6Cyy zvoxb>IR;C2x)e;fD34jcGQIVPy+pR6`0j*S^*dkp*ssztR#nwJeJlcfjOib}NBL8u zzZ{A$y^g27pQ26qA`m+Y-Y`N@Fwj4x-4dYa;!=1*&X%TGCgKUOF^L(sKTq#@<*6QM zgDOZXlej7MQ5@0KJYrW^O@AxwX34H9J%UM^L6A2WI%ClI$OI3^BE$RaLkdCoPwDs_ zm5JC~77;T4UH9$+8Ib31>*L?bbmH@)<(jzYL5DuVKw}Y&Y>TIW*g$guyVRol`w1sp zn9v)3jMCkeQz~cU13uNsztd{2#WdF*6ehE8+-GRP@Lb9dZ+&mB>JB|2$YkK%i2I3Z z&w83!{$0BcDAn09oMA=ZyW5(PVU|?cr2CvlJjz^lfuV-kR=kf5*Z>%J9SnZz>pzZ1 zQ%kySoi;k4?Y`7Cu>YIDfp|Y|?&&W9%2VklGRD2PgheYgHp^)Fg=;RTyxXi$!Sy5> z&fcI(&g>amO}-U1i(T0{cy92IyswTkd`7+Rqso^lHNiRCRsyz5bQpUns9X)n6*iGgJtML>0 zwbcYJ-|3y|>>uKHs*ZQEyQ$_liSlCF0?k+(#J#w986&(@J`NvuVXVH+@ubju;z$Oq z!ja8)%6%d=`Ob66oSr8rQ!OT)t z_eTPKta}t~Wo|R_;DnZygoLDb8r{`ne(KGNJq7w~+K%J9h0@XK;+|kKU@x)eC9`#l zn8_})2HS>0Zk-11moy1ix1QB`dIJ?Ej%=-$8M={C?`k4K+-#nX_f3xQxmVU=cu#i^ zc{C%|teppQKcCzo4=--@2wx{@S$bB#qA7=&C6hKZ5UcjCM{CaG;*L^rtdklW(xAr> z+UP@+^7TgvI$%UFItR}Y(((<sFwP&N>Q&|>t^uc0grEku8HB2$~}0c)AHad#6; z*;IKYZ{lYT3fUxVo|kcXv<0_XvjsClZ{EF^HYj5g{QUi{tfCR+qfK2@JXvefGGN`L zC2sKHFtX|Bfkw-NJA`ZqpMXQKkyl%KV(B*TZ|XQ&X8%eSJgvbz!zqQxZZ;eB;>_dBf>0&w)m03JQhR4cC=?md40`E>Ovk;Ome(GJH4Uf;C5 z1S+FB%&%RW?;mg-S~ELboz-BucMI^0sT(4UNgzx#(Vb^JbPT1A#-XN8tG&yYT&3QE)*gi`Q?Kv(-RBsv4(EihYTCGtgN6idx!^f@N;#~mIghLz8$Xpvq^2h z*G9dk;oRQiAIk!PxhTAIpWsBPWR6# z*c*L)gD!nZYwwbdU-?i=DXsISon1hAtIT4r)zGu$u{h6VIN4eCBo_NJ9jyl5!IPdU zK67{T4$GbblTyQd(eX7Ot?#NHE%*}Vaw+`%W^~g&qbCLlMh|o9x6fp-pqNL+rOm5?OpJBUyEK#?Rj8cWR7tp z4DPx$ILFU^bM@_m8SbNDOnb0i){#AP79stp{>i2tVlsQ#bk1)X>PuQ$#1y+IM4!RG zSCcJAE0r8Mp~GOl!kE&Wj+S(!ZaIu{poug+^?LSJyGy-VFs2XN<|&8_$Sb0z1V!Wc zkG=~Aj$9s7&L^D@KG^198GQlulIw2#;_Ca)y4r7Cn7wjNg>IK^=~Pz`!KgAtJ36+^ z-yl8?UU0R>=Z2m0&MH5z*w^Ee<4An=p4d&lH&fI|$Gn>SD9}FD4QJlnL$R@a2UCO5 zx8ujlo?Tc8(QyAVR*kxXE-aJSPGRy?j;&cNX5!hDo1@J3SM)r}4;PhXgXH$lAbI$G zf_&`DE4u=$u6qazAM#?@eq_e?z)f#~b64KWh+GP?K^tEUu9%vgH1-I}04~27w1Jwr zxlV(?!|^w7@PFz)F23$Qu5TDL_PYoEsr&dZ4+v5pG6WC&MfY*iIx#%pxpluyCUEqR z{^LC0oGeIi?HJMq+&h2fKMvhWL0mBuKR-VpE*lE?1OJaC_-;NvKGc;fSAO+qmq-8%VFk|gG8hsiy#BF2-05zV$alpb)mrVzf9nsfm$Lm2=D#zesKJ* zY84sl22T56D=#l^{#p59{&8_}kKsK{X^TjlCLT%EN01O@5Ti>I#4iHJ872slX}Z3L z$3G@`J{kDTCmAjxS>QPHm+SC+k`4jEg)PBXBPAszFaBNrFEi(nDBTI9A&LOvq0ECg z;$V%!2n2a#1Cs5}Q?4C?q+2Z^aV8*Mf+g_(2LCq_#Pc$Nl>MK}KLz-0hyLdOzWyXw zV=Ej%vdj@A$9lc&@HpKB#9lQcB6%RcOzUM*-WdQ#mh~!<27K<*fG>FlxaY6r-n-Gy#e}VpQ^VaDL>6~J`h$QMRBZCb@5PN3{3D*EI_#S*m z<|m0H1Z%77v?=zSMPdym5Fd?31OvWEj4}Fzwy0Z|83--3wSNX z9K?D%w}gCnfgtdF!nrvl2IP}w2V%8?*z`}_5#-x2f;_$rV%C`~A@Qc4k!vUOk$bxB zr22q$;h~5{O70Jk0Q}YbQ!T!e@b}lRAa5T5JZC|B0^f1O8G_h==Rh1JGXnB$2mx{E z2_SzEXZt(?+Q4Vzp?)8dWCqrC1#RJ`A`bY=y!zAmx8<%Oae6c0d9bdi1&9-EyoU7S zh{*g`1nDY4kmr7Yu6ApHuRxwgE6Bva8iET1ZNYQ}$+lS|(H*vdY#RcS1O6u)Eg=oD z>+R{!l)oL&In`(tNi>@x@l)ct1*ETfz5X_S=RO132+mapuOgGft4NhU5%Av*|`OEbW_MMKCtyKivQ;KE{ApF~$p|{2|R?yH7No0&Q@C zBs2d?``_TdJQDw{*MC#`!tcIc`6HH!J3uyB5Py-68~b(shcfuDav{}sk_UqCO5pUdXIn*STXe<^^kvaMH0GAzXc#GC>+ z9_kJw_s+aSqV&g+$Jarbz&ACcEeJC8fq)cUUqP}g*AUod|JX7kv@SPLvS74c88;dgrau(D%lzIPc{*e9|KxRVzh5g9J zI}1n{CJ;}xYS6~PdcVKq2kR-#9PmD9C$OwP_RH`%MHfLDqt>hH&$K_te~|y7?98zt z{*I=Q4zNBTPb8R50{JkHB$F~vBkl; z@1NFlo$N=Dk!HY`t?LP{r8?XQu8*%@FDNLe)zsAdss6X2e{JLs^Mv&eCx;0n05E^3mq84qyg{D@x52@|AwfYwQd}LV z>w{CjOF!zrFb-ZC=<{GXvw#drHV1KAe@W?9pp9AMNpwgypC-wtEP!F7{PjRbgf#zW zdBbtoxpU`!mp8=nWB$caZxK($7sw-PAjg5un`#c^ixFsV#vo>)kwlYe zB*_HyaaPE$`D4MFuuwmo`>ou=8|7Xf1pf2<R7F6Okfk zpz~f>LQ?IfNGbQ?3h7*d6A{S<=ixfGGauoT;M+`~m(Koj3~2rjdH=KW8yOj)l9H0j z;5$IfN(97PLcV`nLh#@d+GX%LD@;q^cq46`gL^zkfBaVR$NJtV_s0Hb^oQr<<>d`P zZ0PC5rG-`e^5W_eesOgX1Rz_)&;ODZz&ZH;$8+n~78d4LK|G?>@$vC*si~*QtSAcb=B|quFG~K0NkU&=pZCCl1EhCJNJyZ5mcY3B$NZ6D zusH4iaM}Xi&kd3cNS+{pJkiJuiW-4y;qst1>=;|Y(LdTTz~Z|obC7HU0lX_4;D3A#=roJJlK(%V|6|M|l5R7H%ulWT_M#t-W8Z%@<%#C z8yYMZ#E}E^#*Oh4+(XP8V+**4V~zE3#WL70lXPE5e;DK7zr|nS4Rm7H9{~U15SS1_ zOy6Y^R!BRDInxZ-Ae|7T?8f>SCeawIp91V%8?=S?O^A78JOaxE#|dy;2I~as?0*;j zN?*`UjS=K^CeSy3l}hV{fU*JFAs<}>_A=8&Ql1d=@CyW41jABzeR&Ry2isSWa=&>b z(|mnw0r>}xp?@6X!?M9~J!}_$H~x)r5sVq}JQ%Et5(U=exif<_Wz3Tb@(9GxhPKU2 zux1M6r=M*E5Pl->I#`DW*qWey8``*_oe|pkHpZr~4D0r{znA_HKjdx5(@91PNR0kB zBvNAvsfk|r4Zl8!5p6w%EYAEU@BUbh@&I7JI5$hOA4D2{K%$L4l2V2hi0=)sZ?qq1 zPk#jR`aAd^^3MkTjkX8vqfmCfN?Jz<<0HkMn;^;AGT&KbVi1gJe<;TCdNm<1{!onm z6v+m0OSKYlIaNeT0ottqJFtO)GQe^qf${0XvjfNzAlrVl*Zn8*|9ALF^*aaZ9oV0N zovQg4{AFOy0=7{&2M`150rK|aTT4i7D1yNDU;ALaoKO5`k!bx1lHCH@w>^}fB3Bf1 z5r3^_!1G|;B+#azohb>}Ua!a(An|sC2;sNooc<&E`7``*ZX`~B8fi*gm#J{h1xyGH7$aUIAnUMa{(An||9y8Qnc{-2#Iy9?}jMqs`Y>Yq?oAeCXB^j=64_n`g6VXXT{p! zf5_h?K8L*i3%~#I|KH6&P+q`1AkUKc-we#7g1J?PWbKPg7EHDNd)J->J z&%fILUHCWV*C2LicZc}ne$jJDJPYRM;tYWPrU&|D>qVr>Z{0@#wq4kUf81*C1Nrm6 zjQ{B!FpmNHAjqE^_VZLrIIjVHB!C_X`pjV6P9)@PHxjJV3Fi7fkjBN3f1wP8j3(cj1Tp1IHauuEDVd9N+zzH*AZr z4-M7p0k;1H7AScZ_Z zU4Z`2Kpz492Yx66Y&#(3fc`bn1jPO{T_0~|fjQiNmNI~T4(C7q+wt#){s}Rz>n31c z7hwKleZzAQBOI4NURy82FS-Wc7gF0X12W$RtWSAs6{)xl=4<{%dg{3zvk|N}`s?;z z>z_Zt{bM=cd?@_C(MQ8QtTQ;C4bkpJ;_ds9&;0<<4`Z8O!TpJY{}%s`Sbug*;&Y%s z{tiFjC3tVV!7S2M{RacUpTPX%Ex>;Gm+fyG{PQ!se?0fk@WXlQ95BB5+WQ+C0<=wl z;RDoJf0p32jdAD3Q^0;J`B&|S{|-OIywRRF@I%|eZ|NIpya;vJ&)pkH*5@0c-K+TO z&l7xScj<5UgSg}qVBJ}ce>H#ci~ad`_S+xvZ{UOD7${F6U&Apk9B;t3yHOvI-oGUR zNoGO(Uw*(3?MZ3BjM<>9hY9w1FhL)@8qin&D0>nT64K!0#J`%q_;>grK1dfRzt`I) z@NqI60rUI)K)(N022!2CdqINFz&4y>viLjvZQ1Mg>y0vR?4hj;j`tydZEPUc`aGD6 z7Wq5yZZwk@R@c#@uh;P0E{5EtUcDVgj z`a^weL;v5v1nCO-1@;HfUlHPm>7jl}h8@IbT>(BX zdh5v7fBzbOU?2AaF~ouFAkiJ*hM3_P2I>cCK#zku0koSydk$<5>A;o-$7vh)Ks_%5 z=p3-m9q;~4@c)SaXV@X#|A_rRp?}!LS|n2M69RpxHp)PKnNU$A1JrvdlOpxxd zjF7irKMehSpf41p!H@E11OLyk|BUV%b@12dk01{naL5(eLg0rp{#zLU#vjMRPzFJI z|JrWBb*L{vzJcW<$)Z2VPl!KB`ybmX#IB>GqrZXokNdxhKiCS3*dNY8oR8%r54A@~ zzH_8GDxhB_om(W?v7n!2lrFT%&64bj8*^CD|1?$)_}Ul&pHl+_8SmVXCMT%jNkbW5MjwZQ7AmzgK!!%|Ns6sI&l9&kBz;|FaH6(NOVHh_vl~t zu$8iKwHsS~vg>vb~j3eXm zEw3u(&wlMT*=Ho7S`r#ulZZPKHA~N|X5NUV*mPj;c14c6J7h&Sof0II!PRY^D=Mzp zU%ZKf%Ksd7UKCoda?;(UW~Uhr&qr_YX%vMVBZb_xoq1ghMR_JZ+jMiczsV`R^QM=~Q}F1PvX*J4 zSo?_KUOrDjh0l9C<7ILwiB8psAZI!&nbq9QV1!EsM02N(k>k_~C{(U_d=leSUFbs< zyYEqYuhj!`FT&^3GO<+?1(i>n-j&!)KLM-UdnA^ttHfxjl%*#4oC{~<3)c<_4hb=p zy#BTG3veJTH@&sc^}rc37sm`Dile`_H5%8Un&?a4?zL#0nzEYB^_Z@bKwg4%aToKA z$}xFZEaK90U4o9cM4qPls|J6btV)0=J-LvLvWnD+g9m5bpBWSD-aWSSbp6=$fSnse z0q+2d=_^v|pZ1?yi!q>VJ?!;S6{QKH7BwZprF1s|rz7sgV}*rX5_jy6s|ZoZX+F{w zb`A~>KE4Lx>>ghMtLn?lfpA4rx2IPxyYDG3+Quk?D@C_VElcsuKF&&X|5^pYeIu?_ zRaMS*_xNsFVr~v4CC0|Cbog#!#}FqUw-MX!P;W_;^dvs7?>Z&>7AI`)hZgX-wHc*x zV)^3^i9xqfiOR}K*C#7fj4q6R7Mgq6?g!tyN5Fr{N+LSLz~?VT=|{1G{06&fhdp*v z6BMT!V07~d=gO%kNN-xb=2)%#A_XihU*b zJM7STs-721jw27nj)q8gCmg;06{{k|Dt8!^tl`0f2T35#!sl+|{ZW*ml%YAtow@Wi z_?hR-g~^o02*tETcfm)=YcP!R&}A-=qk3;JW9>c`Iu8lwLBb%6s1SDg{?1!dA76&e z_Tr42XxMN*=$3?Wc2xYW)kW45OV8SFou7JNCQ-JM8gLEAp&%G`?y+ra>{8Y0z_d%a zwx=5i>vXGy?N~77-rLIL{vMua*_*RLX8mi`OI6d(hho&6a}UHSvCGpGmX|L@g73=5 zw^cztCB$x!N;*5s-#`N5u!&W)!_r&@-$hMm8(+#dFx#ZeC^e? z<57pvVs|J-9Z~88_hE19Z~a9Ubx9rZG8S~NpLGlj+!_U6KYy2FJSMYyN3yQ@PPJ_) zjpxRwZ{sq^@)m~8o3)7=9J`KqPZVOShgXRpV%CiOMKWvDTyh_3Y(L?$<{_`uZ}lSqV0JH=T0TdACvG(1vN!-Jp^SfdnmluwaeRrBKW=4@3$kI)QtunIx@cKgZ7Dj^cFl~vD4ABEP++;t zO4J5*%AH)0Bf738q0#*WB`znx)1&R^rPkKq`e}Z1x;MtXP0ai0)b%P)rEBk@I&stI zlF#GkE+Qy-1uy;0UY;w=cf#q)>4o}B7z}zc*0#mIplH+-QNOb}m@HP$MKx#fX;v!} z_F1CLw7XxuncS|tf)O)^3-`itF|>XP2M*nwI6wTdhgH~na8tuxX8fz;OZ^>pSIn;) z7xGDkM7YP=pd2qBa%A_cStu=kc5rsW2OWR%eCsn>zoh3hTu1q|9$lE0vSh}8kHQin zz*+)X>;WogKl99zvjw9M2d<5@UGNm{J59JcOi#m7S9o_@`a^u&n(XT?_hnjUloxjO zwQKdEkd-`x7wP0XEKpB^WQLSS?gxkvk7MG=MK6#o4SC9hYtQ0%6b?)CXi41ejFtV$ zVEzQ(nVosZiz|K}|GFUn{~}eHFy9 zBu9TxLM>cFefE0i-MO>+^7YQ4!`Z)4cIogXX{iRSX z5V67;of2^21l&xP~8jEwC(;{?k-FR{5 z+Z@wTJ;K4qnKUuAL&igUnf;5e1im>+t`z8by3JjcnxI5D6&_2Ak)TEZAo%Cj^MwVoTL|j-WF-hdjYr465B6rNTRknoulUI~njXTM^wegrh?- z2dVB$m+h-^7tuZ~PIxt=uoiJOFZ0F(#kU(kV&OO*AAyf}rF@h7=>F=|qY+&)?guYF z=ap`c*v@X8EW8k)iyk(ovG&(grWxq+KBo)T+4kEbt9&VYaXXpwpq^!J2ik$&%R8m7 z^+KV~CRF^vk6c@%936u(qY*`cs-Ki~YiS+Hv``e|94(8Gsd2kDEMk7OgJlI7t6laIr_O{k{S36jz{sZ_FC1I zT_>|uGk?uuQSzMQO>G&#o$FQ4omR?z(2@4?(HVndC+&~y2-U`nt_~rXD=x`4IVc9Q z0>-VLTdCSE^G1(V(d0j4kri&-DgFA=XB(R<<{%u~G}71Sj6HsT51qfpF7+qr=R?tX zsIADwE9z8IyTklAcq~Ddz1g(J9#dsYwsYjvhF#~Rg)n?L61Ea)6@k8gHD zras*3GPasp(ejI*Lc`E2}YmJ%VoJIC8Of zrpF9f=@|-GF+eGVHIg-<#=!ErbbuT3KpeJZ62mCcT8Ia<*D%#qUfcHBw5tDgp+wpP=pR@~tn zlGuOjYsKw)EMtI)kAE(MU4owz`*^%#|I^t6G7C8xAWVtO%3GS$*XL5Jt==@fmJ>rM zvU;EK?-ZB~kgcE=X7#!~%Byg{aYP`Crt+BYmPxs^)5n(<7r!kJQ_Hv|+oH&{2D~J< zik2w*Yome=zE#jE#FBA%X_DP%Am4pzJDa^=*q6a_=bQL1eyxx-|3ID>!> z0i&{I#fNrnv-&(e?Ky7ZI?#20nVPID4h?Uiv%{(K<6ep|oJOy$tx3ZG6#28#b(dIV zsbotN&)wo8=g?ina@d;2lk2ehv9~GCRWtDTd>+7hBG$S~^MX2nOJ+2~QNfu7Vs2KO4)s`BDbJ%OYiw6v93MLlmH*a>&-ZW&;Dl3M% zZGR|STVBZKCLJRWIS;2dx+^&l*JHLXtK)%oyNh{h)vS&G+-O?fHJj8l>TmRK!(&m0 zH_7JFnfXbYan+TY$$y(P$c+m-dTn~vfF=;-&pO)7IIe0Hy;<0cOrD`iXfMf7%t{#{=7*r@faOz)2YEk zd$cvGzC_7y?P{f9<2FH05Bi2EbuE@;T26AF_kPbTkh7wG=8x+4AOB8IcpN+(v^$o1 z8>)CuHT~rjNzb+T>R+`jPxg_A>9{6?Cy-n~O+um{~g7do+#&eoWp%AD&SF3=JhEaD=+@Mcb)yS zR6G&#$@11ukC*dl(v1gMHC@UQ)Vy`+b?67OHBI{PE7AI#k zA9x2bogv4|n{4I*IlYwhBelM{&h4^LSEQ%14MzKDy4|v*;BOG=?I@=;w$iWLrZD)D zugYjA}oe1}FAdZc0{LbPa1&5Mz) z@P5*Z8NAfTlcy$l1>+C0^v9dd_RQ1?XWkKGA?Iy`I8Ye%8AGkeud2xlEI z`qyWZPVU(i-RKv`>gfgW#5<<&(|gs+#8u!I?xR=5aMvR0oj2tqQS!{T`PE|hlppb< z92#WgMs~+4TwuUmn7#i1A21gBiUp@Pi2Fyv?_Swq>47qFDp!9-< z40@d}l_u3YAJ0)nUu4C;i%-g2@o!M}MfVC5B`$K!@Xuz^O)%hWXX7@lp2yuc*r|6P z;!+^T)TL`Czv?)f(Y*v21l ztshfsA9CjSoK@2cTB+RAID92!plW+cp|&;4qU$p$w^VO4GpoC(rnPne=h`$!-TPiT&i*TVdgjLVDX|vmTG!AR3<7 zl7Z4!ysKyYnCht$WA6zRJsYaf`!tRfC;f!%t_C?qNzk0v8WmYInNuy9MD3MFo;N|} zk{9g0;?Rv+yMcQfE$=uA}a5ORuBaoO3_TNq3XoF$w-Or+8Xk zLoKd$n?lV?zBI+oK99MNbGM!~(bHH)fCsj#c#HVS3kIp_pWw9a6Q`NvMER|FecQXQ zZda)s)tk)%-*3FtmnFVmXqp`8CEQH>EZKxIloLy8qw%kClI)`%o_t5+I)2oD;dpo( z^BM2N5?dyXE^qHoT>jUOUveq9Q|ZcIzbH5J(cR;={Z?y~U;z84OJ1zU{LkFFRM>}F zs#sv`>%Q%3S2pdy;~ybQWlolZqME5b7M~)nWsmhZUO#rC=%(NI8>x;wHM->*Hi0F63Ww$l?ndJ%qFLiyO{-Nj2?`0zOG7R zc`_7je@DfJ8Pr8GgRuLV-qSDI$o8PTA2MJyvQoq4rLtwIB6jif)JTSFhsL%(L=WFn z5FVJOza;8bOR4c?BtPT`iZYoCpG~nCFV^X_XOC{J@NFEm5e~(Ix_k9$$X!c=lRV_2 z!9fDYKFEtEv*0-kMG9UHXXp`Rsk2bUcvZPwmya?Q8?uG@*GW~xa~TWbP*WoZo}LqJ zTu3Va>^7rVp?}#W9o@nvW3jac+_CrnYwt_oq3Zts@1RXYRMKY9Lc&-gB2+4stfkE| zX2!l{##WM2qD?*R6v|VQN}KkgLOm_CNy}5DLPb#$n#}+6xih2T(f0K8e81n{>wmqD zyUe-gocHH^&gU%m-uGv~0iNB;yf?*5v)&l~;ZwZjmR3}%xC0@#=$-6{J~=J^g~>s7 zL5JgATy1zo9`joY*G}-9%UXS^apCpygf*`wvk#oG-x)JSdPV7VpHiRm#)GSEZt1A! z`qjPKXy!Q}q9n#`AbYez{)xtcayeSYDq=K^mf7!J2By~^Q=ObYuKa3q-TcBpTW(@; zX-0V$<6L5D1y?WR$_diA6i=Un(xG9G1!@+#O1P>+Cj{tC#kvxr$RKu5J*$JHFIoI3>v2*tq;- z_R8F(v|O*A^o%%aZQA0H^9pmz@#B6ZOvVc`$lPNS^%7C0+ z@h$r`a>Et7vK%wl>P5d}RdS`II+ci5Haj`|)_9%q#No`S!7WCUI!&D(efw!{t!3Fg z%d%<-nsY{q+O>OoU-hLG{ef-BO zjl6lh@>HiI4h!$Enf2_*0DJbZYnpEljps&noxA2;Q}^6>yRzV(wK0>budSKisbb>C zhmB$P#O&u8t}1$WJgu?!⩔Ax-Xw3I7>`(j-TH`T~{>6ap$Vt&51Tiro|fRX?fbc zX*J@W1*+$jPIuilFd;Znx+zj4KJU%C#-yo9CigSbRD)Y=C#2O6lW*cSS*1Fzp77pt ze4y4D!?V|RXhrp_2{gFdFFK;Ga;*+6>+A@wY+p^WVOru@1x;Li+iqzmo3=)tGcr2+ zhs}lxXRE$$nN6e=s;?N`b>5@?nq<|);*=>xaMtT-`mxcHt}%5Zw` zsa5-V1;n#$QUeN)S#i`wO& zC;g3GIwzauBBkt&rxsOv2DCVvsbxI;mYU|zAy~BzGXy(9b`L0 z!*=#N_t-0|8nt~(k}h_V3^=ChW3rnknG~n~^tcN*aY4(9edU)|HTIv9Q6cw%yPX;p zEoI*SKv1rCKV&asE3s^xP`uM(Gu8RKH-Y)}t$TRf9pRd?qVE<|dWVJc_k)`|3tp2Az!2QWcL%ycnfu8ouvgjNZ{cO{Pgt{FDfTdg9TbwLPae zDM~UqGplBH8)e#Oqk8{yUFU8)VA*x|!LyZF@ul{ci9Wg88s9Jbv^TU*^u0e5u8lsX z%zoM@PV7Mn!C6~Ix4E(%bk*kG~ zU+rM$PUco|(x$bK7YsaOcDhfb|K`VOITGS`D;8%zJo-4scyLQ-w3J(qp7bgVU z`upvOvyU#j%)Q^^*=rNx(8(;zn9$X3p?iz&M711^SArFQW$Ja}(T;MkZngDhLvd=a znFSUNFP+Z&%IhEH);5WkpzOJc8XUh~|* z`ltOO?JRZ_X{4^zIh1KbhXwgldMEE727;Khi#E`)-+Y;&W9!vUmPt=Pa_&HFh7<9o zP~~IGS+|o78l(36@a9Mr_B}kU^Frd3zLKOIGzX_A>cqy>6e!tQ#+#b7G8;#zKdBzD^n^!h)A0%7`$FAqVn@Hfax!ttoU={}b*cVV3+AnFSR$3% zxo-@+hPuVmHFuLqrcD^(?~@z2sWB-ueYUt_v^1^r-6Y=-jTtxn*b_O1Bt1=6gpHpKw z`;L^k87b^5vvk#)b~I+%@IBO}!@Jm8D(!tXZewP)X~U!eHTz3?d-Q&1OH6Z#H>enJ z@6OB7PC3igvl@%G$Gu)w)~jL8q)J6||5xCSVCEd+Sp9|jw^kkqiKxx)RGU0^a8$C| zHs#)qeaH6BT+6V$++DuwG*^r8a=9f(7`E~(^Oq0x7EB+a6bl4?#X4?t%x?4$Uov?I zw|<`E@}l*Pn!DLj<`a^<4xa3C?>Ob&=^poPb>S?K?QzN8_f=n_{uvdT)dGWD2g$vT zmf-;diZ>Uf&gV$@Wte`r>URF+*=>|87m1bwF8K%zN#b>McE)QFVDM;Nk&4HnEddkAT*o6a*{yiT7sKJB&AsXYYt$U}s57-U?Ovxp56Pckb*=g%v1vf(gIZZTj?diGIIAWx zIZFHltsD2fOWCOqJDr4~vMyW3H#udczSYjM*tmCaORu#q;%g=EogUP9`C+v0-J_>Q zt~|VR+~}D#JQo;5D0T^WAo=HfY1*BVAPHUV$rfv-T{Mf7dp>N9a-^@mPi$Gi?&hgA zmBZ>>t&OG4hnE#t=MH;3NV+~-Cv(iv7(KTKU6LaQHeOV8D>5#Nwa#6WeUnO8wOj0H zJ4EUH3ynQ3FZ8(zHp(V?eI7X#dL^4#{$51-)5C$&5; z#rPJBkTkzb8FR49%#z}lcSo$aJ8pFO+eh{k)%Ce2yOrH{xOuj!Zf9Jow!-wTg{Pxc zcc$!@uG;JesXE*?5#Z)eqvPjT4YpfH?*#3$|))H;cl1AH+(#&6E(`qZn0tl0G4U{eEk$jhe9gPl8<)v9#~n9^%N!8$$84v)6ns`f<7D^Qb1 zFRuRhA^X(H5by$aX1>Ln`wKhkD7S3cE7|k1?bUemI>jlohKX-x*Q85@h~1SI(+a7V z5R1RXGg|V}w{p&-J8?(kbG2RL3x-xTO&y@J^Xb{>ZR;%_*G=MP<{696Y+lj#S-#a& z-c!Affw5ew@kHA}A@0~WYYHu=n|j5lKzU(w4N*JQyq zGuvQS$df6eOoY}hZC+jyGo3+bEYVx4D!-*=c_}r#X~dbFd)+;~u1}vbH(RB55M467 zS)%r#d@gfYULYZtGv<~rLF6hr?ppCS=S=L&DV{e&uJ#yZ7$|v{ zPj2Tn{h?+t1co(vS(`ci3E7RWMIR zu|m1|%5_P~#hrsTHZE>{96?P?939fBrB+{SV*%y-d1p$6k=p_Bf>}(WSoVqxHIpJc zNlpEUk)l+e=5_3cZ%({EYEf=D(MOt^teQNer70?|xZxbTPjODBg!!&xDdt0>dfbeP z$X7HexfmO%6ntUa#fdBBSB@<=oHAV6?Q!y=CSG4XjnE1%qf@SYkN6y`dulD_le_NP z=goe3m!dzo#d1r}MQid(rTls=8X{#YHGGDtVumj9w7lqpYUSESYerh*Ct5DYHrBCu zO`LD%3?1TK`I~XmnC9h%D_56iU5hh&oXnKTpus%X_@Es(s&DE{`9)_Q-5E#D+w94vp-bdV-Qlco#&s=Qk1wo`%a9q{Ii1;U+;AZ z-o4gtbiUm6(%vXtTe*!so#wL6EBKz=P}YCG;t?;WJ(itwsVzP-wUwuj=7gLpF1f2r zBMb^Nx~g$BkGQ%mS^T_atHH5LM0C}OSNoi;hgN$YdOF=deO63#FDLo&{cjzeMXX=$*upnM-L>#Tzx8 zT#^zKR}>i;CQ5EuLzEXBnW(g|KJWR}%?XMvCQA+`2A_<49zQHOe8;R5&tNHPlojz3 z-h>%sHov}#*ZrdH(?4n@)@gy;?GIe=JP=dj!&CRwX4pjsh)*)8A1>e6a6IQzW_Jax z0Xp-PCFrB`-RD)8s{F=owQd5?11F#Q0tI zbbRZ_*YFWX{^3#Y+b);pRo^$VkWK7%krw%MwPA8NJVfJt(vGTIsTU`a(reM5ANwnc z(*{!VTs?P5Fc^%tH$hwx;GSBcB+GS?wLwx%+O7-Z(?RZ+WR%8mZ)-1nF{KpV3vB`Q(eL$uIreO_lsJ}FRxR58kgsiarU=z86BQmYM-g0r~j}pU+nd2-tLCC za@y&cnO8sFSU%?H`@+$0&ddYf4IfXPK5h6s_~f8_GY_w#R^;||DE7%7rK2;C&SXAo z1i3Yot0tJ}M!tRaht>GArxQ*!YGm_z*cwuNrKwTft{G4i)-^K51^Fy0axMv39vd6% zTXNuiU&a7pgZ&02S%aNE8T%8HlMldSpQK$G85z1SclMBd-_WwnsrUQGW?Ol4SVY~& zqSX>}$1e%9GmL3mFs!Z0`Jd~v8FleEOI@jUd&e*^I<{V zho?zBCsM>h#N!+YUE;z7_nQT0;pxDkT!wsC+MGsq<)_s(_{LD3cf4LEMZPp4UukFZ zpuBRM2^1Zs*i!3j&SwojY_&O8(Z5z)YNe7_@}7!9$-$Od6-|i)%)C5CcN;sbyXH!n zN_d6N#PxEDr1+$$yOArG{$@JnQgLTQLDdclW^M4L!%F?HO{e1GzP)UF;^=*OmqREIil5sNlm&_LaMHT#sN#7){R`)(80*bW@9 zg!*6=Pevwy6RXkepiF$1=Kuq~=Kznx>lU=R;ftOF1UD$WQNIK?{FvtewXvdnd%fWP zw(n`G!MQnvXb7!*dvM`PegokBPx3un;3XqmTwMN7hU?d_w|UoCh*@->ot+I5Yu&`) zs0##12;Kk30+t!eju^-d-oyVU{u3uo2%{rEpcDipDJdx<85x-||4TtyTG|-Oj!jn@ zLMI4B`*+Pn>s@#(z>hCAcT-kY9=Cu0{+wseo>c>%Xzl+}c>er(4d`-#hK7bUU_o6F z`vLr7Aiu%I#l??7F8|Y8d3pH@@K>VsgZT0L2>3eg|Hj5*vBCiVkLW+)<>fX1{|0*S z+pu84${)oK{%e5w?em6yD$cKK;a!ApVOzs*z$LW?c(LGG9vrt`7mf2bk1@^MwcPJZ z7xKoqCs)4Zorr(Sd-JRPc>LeMAO0CV_{J#z1iVkRpeilEF@SSKHa7t9&|26nY zu6}3a354&0!50p4bnFdz&C6W$gqN|fjF%n+d};8#JJ$U-%lZvDA^udzhyPvs>+g~Q z-h=s9KZHsb+5XA;-v-?67%rtY@@mV0`a(q1$anq%I2rPQyB_%gusnZP4#N5;@eBA9 zguDd8Z=2ifA+KMJAL|3TiEbZl6p?PnhnJH;2GAzI8$al-Xk5gCylU76Fkdpj_vrX7 zH*zEHg>Se;1IGWA_|Y!}a`?j|Cz1oSW7MCoRu%Jk08=pqn`x90wpsip zU1(DiKN|>lOlHMIQ$z7V`a=TulWox{V-H4)F2KenWDR3T1$KVcp}m{jGWq*YFr+f_w%1 zwt@ab&_)8^#V^K>d1Kun58m@4kU&cZQV?8weuoPj6~ILReuMBnvfou*I<&e44%D9R~kpxC!wmgMXVX)2m6I^Dn?|bNR#y;4*}97VjnezYMzYc_YH_Y5$YfD zC(W+mWzDbq3x8c3;DVErE5R=ta{mJV#fDjrN&joeB}ekfIo>AuRj_@C$^dO8@+9uZ z_W6tYf3$y?XM6mJ8+8xs1>1NIa9H40RouecJ{!j`I9_@Uwg7kuW8d*!{wXqG;729L z5NHE%L;Q)r35>k0scx@`+pn*?3xYu3;D%8y{duKf5eypdX2oq z$jgH=Ks{JyQy}OUKHEgZzrwzd^z{=uKAZRSF5dKjiXY0<+V-Ga$d5$UKZ(DZcQl4?|Eq4pZ@~M7oRQ?X1Y{u8 z1EIV~8Nm1e=dMEhxQ2k|C>z92+8opa$P4|ot*|d5?TKg_XoFGz(bp4uY!>hFoqrxb z^2npVF7y$$(+&7OAqY94_OO7T7RKes?R*COSK`+2n#a4glh65yHW~Fi9qa-6*g{@# z(U9i+k%#`(a6|m$I1w;o98%VBjQuUz1LQhGyqI5W8gPt!RVdG-In}%u_doIz6a4?D z>L0nl(MO)JzOfF_z6-~wqV``{0OV|a1@qC{z<_f)hF_oQ&U}nyUjmp=-^;G?+YO1| zl|TN+HbahUpp6LoTkPktZ$Npp>LL7&eILpP)BI)jAJP}vGqPVpdnRnlpvN8I7s^4n zNB?5?Pr`cDD!yOZbikTu|BhFBr7eEMhc=ME{=w(6L%fI|<&QGJxsXslTE}F+y8nlA zVZOq)jB6r%89+Y|z6^5Wg-E}>e_zexmFB@3;;Ik4XSet|du|Q*zl8RW`1#|1>|Y#ierimKyX&-}o9@qqhX^FE;< z{-^On8zB1wz>l_It0SxxfRo%f`#v&vh1ZeAhQj`si6_;Gw8(0j7qh4VDw{0D4+ za7>E(RIp3r`UQ*^x6c84H5+{Jz*rc4XkFSW@Tml2#P-{THT`$1lK%a}tyR>On{Nv5f6yfb}0UEx&b4+o22~eO&LsbpKoNlXEsGC&~cJiCoC7 z^(dkP?PY-LH>m&oHEom~f8L1eAFcPpF`o0E@9^~>&rz1&6Hs4}cl?*l|FA4Dza(`K zj>)+=%*R{H-wwa146t5TI24h3gMB21zsLa6#Ca^Pnc!S11N>%_xFJu>_gev<&*8n* z58C!B|J3{+akk<|ta#o5W>P*P*D(%%?uI(UA1e!Gfb9sMWo@4Gl+WGn@PwBc{*w3j z5|{V76yCci`|%*^V+|$o%kYa}Y>)Xb=UA`sOhY(VXvGimzl%668vU^|!2i?lzjV0%`=j{5=Sqk8p-;j7Vw+Pf@6MT@n?H6WnTUvp|9bq`may%L z`c&u$%ip;M_?Q3e`#)c;e<(X?14Z}kbpw7&hx!+eorL2DJWod-M2H{O%iBL&$8+RH z$7dzq3fI%x`p6K<3f|}T`6c+F%(w=EYq5KwZDYXamKezP55KqC0mKK_aoqyfF@yon zvHgDu|D8jy4(155gEiByh23*uecXY^yLViOn!o=Do2sfRx}N``_aEW?KX@wjdF!zL z1^96tPPAQPoo;h}LH6aOUbNQ*(Q`-x=MbdaK>yplF0s>zwZMw$82i+%7sOw@^oLyo2LCd|vpX-Mb~< z!Y{;*deYHmWMl+iO7OQIc>kIBuKE{ZYLx+B4^S7-_eTOew@#c}`E?n1yfbVm4J>XwE<37lsNayk1xVX4gqS*ft{Ln{ZzJF5U_{jFd?UwgveaScTnpWMSaK1W5LL>0F`39Fvmx3B-di~VQuS3IsI{TibTaE>Ch zUBdYq`kwjRr`M2cU-%o2>&Rzwf;t!aYQp-)__!zge~5?UpRd{fpTYjK_^V3a!8*nP z-g4Wk(661h0i_|Yd3_U~V6@8B}vo7hnV4H@8=v}N#)4?Y9HfbaXHxWIe6Oumm#(YUylwjI_Jce{fROSl)Gdsf|P z)BJhGhryo0xb92X!Pb2j_P>EYLbN1U{}Gdp^1>z_;f2E<*Yx7-ukrSJa@($dLOcGQ z@g8g+>OZdIfgIo%$GK!%fZtpD060#E^^E$MFgzFR;TXS{XdAe^+UG6&cp`Dhd+|O&Xuo#x z8ExC6AI1Ko_}$&zgWBf!-*X1-{V!u1#P_Z3N7}!dnwk!m%Wc~k|A$3@bGgXK$f$4O z{L=3~f*;fH@$vC*fbBmFn+N{CYWM8flVMg6oJ;>jYQ^E@v0%Tf$+oTS65>zUmZ(Cl)NFKNgnAC2Jo9PfqB{p z;$zKWo0gOPVcYvplpI@>=~$C%D$ zv;5utBB=iK0B;W#n=_-$osd=l8*U2@FlIBnSpIajroT5MIFKFa!O>&{`osPHTA?~B zR5Bu-h3foRblq=8*A=E7&h|D{@#1iTjJ37H!osw|^t1wlJ+*adG#%}k)>9qG0&02( zusQSq21|GsmPzlMndqs2OsG_l3SS;pOjZELn-kGSl3FyBW&quvWvUX$4pCO2YV+^n z1c$IWRskM?d^vnGH(h>ikRO}H2nmLK$aJW%nFO=ug+M*9n6|;*q27KhPZs+-Qx#yq zR3IH?O-<@_i*ZzILB&#Sf;gZOY=rrFv+|%u1cp$<=m8umCy>hUq6c`gs2ndA)yX@6 z85qWSSADzLE-Zt4*5SHNp5c8c%-VqSU zWKqMsIbPJj02VdSgUrbz(9bV04D?e=TJm!;p9Rq_4SwdPDs;A0Kxm*ZD_DgZ;td64 zu|ZQk=zeUddVam|VSY0qEUb4h%Yy0e9pKI81k*WzKb@wRx2G4>qD3g(+mG(<2Sw_z zjGy6RS=&_x$j#4tK8rd5w17$vU{dW_o>;yJ>J0B-P6!=-q@!r59)ZDBcRIs2j2_IS zwoMY+Xb?nlhm=5>p_cjRTET(P)#&7Th&ukLEF^}sT1E@EhgHnd4JaP z)?7^JK|y}r3=*9^zdcw(-S~(2w?=`2Fj*e-5I>HEpvej%QiE8*{@!dfe-12;J^Nwnf&T4u!&WphmEi~N-&DmR0@|OymV=;eYPE@^B4QF$sM7<2p_+re8PH%& zRlp8FONe5QXbWU1 zD(qJAlIBBb0%m~L(WxR@V8RXw3JMGc%r*{GD*(QLrAyP%(I083sWVdFKvQ3jF;bI0 z(u1W*qm5z$)r=lf&x5wG4Scju!VC<*p19sf9lcTRMs&@QOe09#!=0%)ilxicr0eSI z({y!5dKl@^znu7}uP3fg*Y(gH#nRIpspoE_sjsiEqv=jJVrViAjF|d#eYyclZ`4;3 z*V6fV@;V*{h6W5n1I2y`GOSUWAg7U<`lCFUBWZM8LC-80Cup^f6SN=)Z3k;B?5Ia-3#wdrvrq}KIR|-LfCXcX!B%9V z-FnKmLs0aNG8cg8xWr%~f>;62lQV?8glc z=Z^)fg+n4O0XnU5f&Tu10h)sDlHKN>*0GrZjwfJ5A(~)Na3FSMfx#BR3@@-43{FTe zq!4$oj#F3>j?n$VAkSbVsFZ=ej=nyF;i1FyXcO5Fdh`&wXS+m%9VEzEAfvVt T`Fx#}9bfvNhl?OJ7=!*lN4_$= literal 0 HcmV?d00001 diff --git a/osu.Desktop/osu.Desktop.csproj b/osu.Desktop/osu.Desktop.csproj new file mode 100644 index 0000000000..fad297fa0a --- /dev/null +++ b/osu.Desktop/osu.Desktop.csproj @@ -0,0 +1,260 @@ + + + + {419659FD-72EA-4678-9EB8-B22A746CED70} + Debug + AnyCPU + WinExe + Properties + osu.Desktop + osu! + 3CF060CD28877D0E3112948951A64B2A7CEEC909 + codesigning.pfx + false + false + false + + + 3.5 + + + osu.Desktop.Program + OnOutputUpdated + false + LocalIntranet + v4.6.1 + true + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 2 + 1.0.0.%2a + false + true + 12.0.0 + 2.0 + + + + + + + true + full + false + bin\Debug\ + DEBUG + prompt + 0 + true + false + AnyCPU + true + AllRules.ruleset + false + false + false + + + 6 + + + none + true + bin\Release\ + CuttingEdge NoUpdate + prompt + 4 + true + false + AnyCPU + true + AllRules.ruleset + false + false + + + + + + + lazer.ico + + + Properties\app.manifest + + + true + bin\Debug\ + DEBUG + true + 0 + true + full + AnyCPU + false + 6 + prompt + AllRules.ruleset + --tests + + + + $(SolutionDir)\packages\DeltaCompressionDotNet.1.1.0\lib\net20\DeltaCompressionDotNet.dll + True + + + $(SolutionDir)\packages\DeltaCompressionDotNet.1.1.0\lib\net20\DeltaCompressionDotNet.MsDelta.dll + True + + + $(SolutionDir)\packages\DeltaCompressionDotNet.1.1.0\lib\net20\DeltaCompressionDotNet.PatchApi.dll + True + + + $(SolutionDir)\packages\Mono.Cecil.0.9.6.4\lib\net45\Mono.Cecil.dll + True + + + $(SolutionDir)\packages\Mono.Cecil.0.9.6.4\lib\net45\Mono.Cecil.Mdb.dll + True + + + $(SolutionDir)\packages\Mono.Cecil.0.9.6.4\lib\net45\Mono.Cecil.Pdb.dll + True + + + $(SolutionDir)\packages\Mono.Cecil.0.9.6.4\lib\net45\Mono.Cecil.Rocks.dll + True + + + + ..\packages\squirrel.windows.1.7.8\lib\Net45\NuGet.Squirrel.dll + True + + + ..\packages\OpenTK.3.0.0-git00009\lib\net20\OpenTK.dll + True + + + ..\packages\SharpCompress.0.18.1\lib\net45\SharpCompress.dll + True + + + $(SolutionDir)\packages\Splat.2.0.0\lib\Net45\Splat.dll + True + + + ..\packages\squirrel.windows.1.7.8\lib\Net45\Squirrel.dll + True + + + + + + + + + osu.licenseheader + + + + + + + + + + False + .NET Framework 3.5 SP1 Client Profile + false + + + False + .NET Framework 2.0 %28x86%29 + true + + + False + .NET Framework 3.0 %28x86%29 + false + + + False + .NET Framework 3.5 + false + + + False + .NET Framework 3.5 SP1 + false + + + + + + + + + + + + + + + {c76bf5b3-985e-4d39-95fe-97c9c879b83a} + osu.Framework + + + {d9a367c9-4c1a-489f-9b05-a0cea2b53b58} + osu.Game.Resources + + + {58f6c80c-1253-4a0e-a465-b8c85ebeadf3} + osu.Game.Rulesets.Catch + + + {48f4582b-7687-4621-9cbe-5c24197cb536} + osu.Game.Rulesets.Mania + + + {c92a607b-1fdd-4954-9f92-03ff547d9080} + osu.Game.Rulesets.Osu + + + {f167e17a-7de6-4af5-b920-a5112296c695} + osu.Game.Rulesets.Taiko + + + {2a66dd92-adb1-4994-89e2-c94e04acda0d} + osu.Game + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/osu.Desktop/osu.nuspec b/osu.Desktop/osu.nuspec new file mode 100644 index 0000000000..4c529f57e5 --- /dev/null +++ b/osu.Desktop/osu.nuspec @@ -0,0 +1,26 @@ + + + + osulazer + 0.0.0 + osulazer + ppy Pty Ltd + Dean Herbert + https://osu.ppy.sh/ + https://puu.sh/tYyXZ/9a01a5d1b0.ico + false + click the circles. to the beat. +

click the circles. + testing + Copyright ppy Pty Ltd 2007-2017 + en-AU + + + + + + + + + + diff --git a/osu.Desktop/packages.config b/osu.Desktop/packages.config new file mode 100644 index 0000000000..0ec2cc196d --- /dev/null +++ b/osu.Desktop/packages.config @@ -0,0 +1,14 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj b/osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj index ba2c7a5f2e..83b16997a7 100644 --- a/osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj +++ b/osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj @@ -16,7 +16,7 @@ true full false - ..\osu.Game\bin\Debug\ + bin\Debug\ DEBUG;TRACE prompt 4 @@ -26,7 +26,7 @@ pdbonly true - ..\osu.Game\bin\Release\ + bin\Release\ TRACE prompt 4 diff --git a/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj b/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj index 967f23bfd3..bacb4185b2 100644 --- a/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj +++ b/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj @@ -16,7 +16,7 @@ true full false - ..\osu.Game\bin\Debug\ + bin\Debug\ DEBUG;TRACE prompt 4 @@ -26,7 +26,7 @@ pdbonly true - ..\osu.Game\bin\Release\ + bin\Release\ TRACE prompt 4 diff --git a/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj b/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj index 6bad45b8ca..f812132dc0 100644 --- a/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj +++ b/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj @@ -17,7 +17,7 @@ true full false - ..\osu.Game\bin\Debug\ + bin\Debug\ DEBUG;TRACE prompt 4 @@ -27,7 +27,7 @@ pdbonly true - ..\osu.Game\bin\Release\ + bin\Release\ TRACE prompt 4 diff --git a/osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj b/osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj index 2c49be287b..d38b24f933 100644 --- a/osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj +++ b/osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj @@ -16,7 +16,7 @@ true full false - ..\osu.Game\bin\Debug\ + bin\Debug\ DEBUG;TRACE prompt 4 @@ -26,7 +26,7 @@ pdbonly true - ..\osu.Game\bin\Release\ + bin\Release\ TRACE prompt 4 diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index ebedf32da0..a84970b4ee 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -4,10 +4,10 @@ {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D} Debug AnyCPU - WinExe + Library Properties osu.Game - osu! + osu.Game 3CF060CD28877D0E3112948951A64B2A7CEEC909 codesigning.pfx false @@ -18,7 +18,6 @@ 3.5 - osu.Game.Program OnOutputUpdated false LocalIntranet @@ -83,9 +82,6 @@ - - lazer.ico - Properties\app.manifest @@ -105,47 +101,15 @@ false - - $(SolutionDir)\packages\DeltaCompressionDotNet.1.1.0\lib\net20\DeltaCompressionDotNet.dll - True - - - $(SolutionDir)\packages\DeltaCompressionDotNet.1.1.0\lib\net20\DeltaCompressionDotNet.MsDelta.dll - True - - - $(SolutionDir)\packages\DeltaCompressionDotNet.1.1.0\lib\net20\DeltaCompressionDotNet.PatchApi.dll - True - $(SolutionDir)\packages\DotNetZip.1.10.1\lib\net20\DotNetZip.dll True - - $(SolutionDir)\packages\Mono.Cecil.0.9.6.4\lib\net45\Mono.Cecil.dll - True - - - $(SolutionDir)\packages\Mono.Cecil.0.9.6.4\lib\net45\Mono.Cecil.Mdb.dll - True - - - $(SolutionDir)\packages\Mono.Cecil.0.9.6.4\lib\net45\Mono.Cecil.Pdb.dll - True - - - $(SolutionDir)\packages\Mono.Cecil.0.9.6.4\lib\net45\Mono.Cecil.Rocks.dll - True - $(SolutionDir)\packages\Newtonsoft.Json.10.0.3\lib\net45\Newtonsoft.Json.dll True - - $(SolutionDir)\packages\squirrel.windows.1.7.8\lib\Net45\NuGet.Squirrel.dll - True - $(SolutionDir)\packages\NUnit.3.8.1\lib\net45\nunit.framework.dll True @@ -158,10 +122,6 @@ $(SolutionDir)\packages\SharpCompress.0.18.1\lib\net45\SharpCompress.dll True - - $(SolutionDir)\packages\Splat.2.0.0\lib\Net45\Splat.dll - True - $(SolutionDir)\packages\SQLite.Net.Core-PCL.3.1.1\lib\portable-win8+net45+wp8+wpa81+MonoAndroid1+MonoTouch1\SQLite.Net.dll True @@ -178,14 +138,7 @@ $(SolutionDir)\packages\SQLiteNetExtensions.1.3.0\lib\portable-net45+netcore45+wpa81+wp8+MonoAndroid1+MonoTouch1\SQLiteNetExtensions.dll True - - $(SolutionDir)\packages\squirrel.windows.1.7.8\lib\Net45\Squirrel.dll - True - - - - @@ -389,8 +342,6 @@ - - @@ -518,9 +469,7 @@ - - @@ -821,9 +770,6 @@ - - - - - - - \ No newline at end of file diff --git a/osu.sln b/osu.sln index 2b1a0aa0e5..b1341051f9 100644 --- a/osu.sln +++ b/osu.sln @@ -21,6 +21,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "osu.Desktop.Deploy", "osu.D EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "osu.Game.Tests", "osu.Game.Tests\osu.Game.Tests.csproj", "{54377672-20B1-40AF-8087-5CF73BF3953A}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "osu.Desktop", "osu.Desktop\osu.Desktop.csproj", "{419659FD-72EA-4678-9EB8-B22A746CED70}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -79,6 +81,12 @@ Global {54377672-20B1-40AF-8087-5CF73BF3953A}.Release|Any CPU.Build.0 = Release|Any CPU {54377672-20B1-40AF-8087-5CF73BF3953A}.VisualTests|Any CPU.ActiveCfg = Release|Any CPU {54377672-20B1-40AF-8087-5CF73BF3953A}.VisualTests|Any CPU.Build.0 = Release|Any CPU + {419659FD-72EA-4678-9EB8-B22A746CED70}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {419659FD-72EA-4678-9EB8-B22A746CED70}.Debug|Any CPU.Build.0 = Debug|Any CPU + {419659FD-72EA-4678-9EB8-B22A746CED70}.Release|Any CPU.ActiveCfg = Release|Any CPU + {419659FD-72EA-4678-9EB8-B22A746CED70}.Release|Any CPU.Build.0 = Release|Any CPU + {419659FD-72EA-4678-9EB8-B22A746CED70}.VisualTests|Any CPU.ActiveCfg = Debug|Any CPU + {419659FD-72EA-4678-9EB8-B22A746CED70}.VisualTests|Any CPU.Build.0 = Debug|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/osu.sln.DotSettings b/osu.sln.DotSettings index 4011e3991f..c236ce82b0 100644 --- a/osu.sln.DotSettings +++ b/osu.sln.DotSettings @@ -645,6 +645,7 @@ 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" /> <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> + True True True True From 179542daf10453e0199c375e817e2cc81984f711 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 14 Oct 2017 15:02:20 +0900 Subject: [PATCH 0272/1263] Standardise AssemblyInfos --- osu.Desktop/Properties/AssemblyInfo.cs | 2 +- .../Properties/AssemblyInfo.cs | 16 +----- .../Properties/AssemblyInfo.cs | 16 +----- .../Properties/AssemblyInfo.cs | 16 +----- .../Properties/AssemblyInfo.cs | 16 +----- osu.Game/Properties/AssemblyInfo.cs | 8 +-- osu.Game/Properties/app.manifest | 57 ------------------- osu.Game/osu.Game.csproj | 5 +- 8 files changed, 18 insertions(+), 118 deletions(-) delete mode 100644 osu.Game/Properties/app.manifest diff --git a/osu.Desktop/Properties/AssemblyInfo.cs b/osu.Desktop/Properties/AssemblyInfo.cs index fe7ad20124..2ed304ebd7 100644 --- a/osu.Desktop/Properties/AssemblyInfo.cs +++ b/osu.Desktop/Properties/AssemblyInfo.cs @@ -22,7 +22,7 @@ using System.Runtime.InteropServices; [assembly: ComVisible(false)] // The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("55e28cb2-7b6c-4595-8dcc-9871d8aad7e9")] +[assembly: Guid("b0cb1d48-e4c2-4612-a347-beea7b1a71e7")] [assembly: AssemblyVersion("0.0.0")] [assembly: AssemblyFileVersion("0.0.0")] diff --git a/osu.Game.Rulesets.Catch/Properties/AssemblyInfo.cs b/osu.Game.Rulesets.Catch/Properties/AssemblyInfo.cs index 42fbc7e082..dd2006c60c 100644 --- a/osu.Game.Rulesets.Catch/Properties/AssemblyInfo.cs +++ b/osu.Game.Rulesets.Catch/Properties/AssemblyInfo.cs @@ -8,11 +8,11 @@ using System.Runtime.InteropServices; // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyTitle("osu.Game.Rulesets.Catch")] -[assembly: AssemblyDescription("")] +[assembly: AssemblyDescription("catch the fruit. to the beat.")] [assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] +[assembly: AssemblyCompany("ppy Pty Ltd")] [assembly: AssemblyProduct("osu.Game.Rulesets.Catch")] -[assembly: AssemblyCopyright("Copyright © 2016")] +[assembly: AssemblyCopyright("ppy Pty Ltd 2007-2017")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] @@ -24,15 +24,5 @@ using System.Runtime.InteropServices; // The following GUID is for the ID of the typelib if this project is exposed to COM [assembly: Guid("58f6c80c-1253-4a0e-a465-b8c85ebeadf3")] -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/osu.Game.Rulesets.Mania/Properties/AssemblyInfo.cs b/osu.Game.Rulesets.Mania/Properties/AssemblyInfo.cs index 790002acd7..85a8f95b14 100644 --- a/osu.Game.Rulesets.Mania/Properties/AssemblyInfo.cs +++ b/osu.Game.Rulesets.Mania/Properties/AssemblyInfo.cs @@ -8,11 +8,11 @@ using System.Runtime.InteropServices; // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyTitle("osu.Game.Rulesets.Mania")] -[assembly: AssemblyDescription("")] +[assembly: AssemblyDescription("smash the keys. to the beat.")] [assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] +[assembly: AssemblyCompany("ppy Pty Ltd")] [assembly: AssemblyProduct("osu.Game.Rulesets.Mania")] -[assembly: AssemblyCopyright("Copyright © 2016")] +[assembly: AssemblyCopyright("ppy Pty Ltd 2007-2017")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] @@ -24,15 +24,5 @@ using System.Runtime.InteropServices; // The following GUID is for the ID of the typelib if this project is exposed to COM [assembly: Guid("48f4582b-7687-4621-9cbe-5c24197cb536")] -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/osu.Game.Rulesets.Osu/Properties/AssemblyInfo.cs b/osu.Game.Rulesets.Osu/Properties/AssemblyInfo.cs index 791c9b594d..b6cf47071a 100644 --- a/osu.Game.Rulesets.Osu/Properties/AssemblyInfo.cs +++ b/osu.Game.Rulesets.Osu/Properties/AssemblyInfo.cs @@ -8,11 +8,11 @@ using System.Runtime.InteropServices; // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyTitle("osu.Game.Mode.Osu")] -[assembly: AssemblyDescription("")] +[assembly: AssemblyDescription("click the circles. to the beat.")] [assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] +[assembly: AssemblyCompany("ppy Pty Ltd")] [assembly: AssemblyProduct("osu.Game.Mode.Osu")] -[assembly: AssemblyCopyright("Copyright © 2016")] +[assembly: AssemblyCopyright("ppy Pty Ltd 2007-2017")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] @@ -24,15 +24,5 @@ using System.Runtime.InteropServices; // The following GUID is for the ID of the typelib if this project is exposed to COM [assembly: Guid("c92a607b-1fdd-4954-9f92-03ff547d9080")] -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/osu.Game.Rulesets.Taiko/Properties/AssemblyInfo.cs b/osu.Game.Rulesets.Taiko/Properties/AssemblyInfo.cs index 89c07517ca..f6a9c8f101 100644 --- a/osu.Game.Rulesets.Taiko/Properties/AssemblyInfo.cs +++ b/osu.Game.Rulesets.Taiko/Properties/AssemblyInfo.cs @@ -8,11 +8,11 @@ using System.Runtime.InteropServices; // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyTitle("osu.Game.Rulesets.Taiko")] -[assembly: AssemblyDescription("")] +[assembly: AssemblyDescription("bash the drum. to the beat.")] [assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] +[assembly: AssemblyCompany("ppy Pty Ltd")] [assembly: AssemblyProduct("osu.Game.Rulesets.Taiko")] -[assembly: AssemblyCopyright("Copyright © 2016")] +[assembly: AssemblyCopyright("ppy Pty Ltd 2007-2017")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] @@ -24,15 +24,5 @@ using System.Runtime.InteropServices; // The following GUID is for the ID of the typelib if this project is exposed to COM [assembly: Guid("f167e17a-7de6-4af5-b920-a5112296c695")] -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/osu.Game/Properties/AssemblyInfo.cs b/osu.Game/Properties/AssemblyInfo.cs index fe7ad20124..e28f8a3873 100644 --- a/osu.Game/Properties/AssemblyInfo.cs +++ b/osu.Game/Properties/AssemblyInfo.cs @@ -7,11 +7,11 @@ using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. -[assembly: AssemblyTitle("osu!lazer")] +[assembly: AssemblyTitle("osu.Game")] [assembly: AssemblyDescription("click the circles. to the beat.")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("ppy Pty Ltd")] -[assembly: AssemblyProduct("osu!lazer")] +[assembly: AssemblyProduct("osu.Game")] [assembly: AssemblyCopyright("ppy Pty Ltd 2007-2017")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] @@ -24,5 +24,5 @@ using System.Runtime.InteropServices; // The following GUID is for the ID of the typelib if this project is exposed to COM [assembly: Guid("55e28cb2-7b6c-4595-8dcc-9871d8aad7e9")] -[assembly: AssemblyVersion("0.0.0")] -[assembly: AssemblyFileVersion("0.0.0")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/osu.Game/Properties/app.manifest b/osu.Game/Properties/app.manifest deleted file mode 100644 index 555db8513d..0000000000 --- a/osu.Game/Properties/app.manifest +++ /dev/null @@ -1,57 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - true - - - - - - - - diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index a84970b4ee..4b9297b963 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -82,9 +82,7 @@ - - Properties\app.manifest - + true bin\Debug\ @@ -148,7 +146,6 @@ - From 7ecf4b2154ff7977523f44a1ea70c5feb8f01e7d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 14 Oct 2017 15:05:03 +0900 Subject: [PATCH 0273/1263] Update framework --- osu-framework | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu-framework b/osu-framework index 3760443ea9..0bc71f95b4 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit 3760443ea9bf682a1bbf6cfa6aa00ea9541c12aa +Subproject commit 0bc71f95b455d3829b2abf662b5fe25989e6c43c From 97b14f7d81549d90c9ad94992e0fb8fa9b33c12d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 14 Oct 2017 15:06:43 +0900 Subject: [PATCH 0274/1263] Update vscode launch configuration --- .vscode/launch.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index d17dc33669..506915f462 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -7,7 +7,7 @@ }, "type": "mono", "request": "launch", - "program": "${workspaceRoot}/osu.Game/bin/Debug/osu!.exe", + "program": "${workspaceRoot}/osu.Desktop/bin/Debug/osu!.exe", "args": [ "--tests" ], @@ -24,7 +24,7 @@ }, "type": "mono", "request": "launch", - "program": "${workspaceRoot}/osu.Game/bin/Release/osu!.exe", + "program": "${workspaceRoot}/osu.Desktop/bin/Release/osu!.exe", "args": [ "--tests" ], @@ -41,7 +41,7 @@ }, "type": "mono", "request": "launch", - "program": "${workspaceRoot}/osu.Game/bin/Debug/osu!.exe", + "program": "${workspaceRoot}/osu.Desktop/bin/Debug/osu!.exe", "cwd": "${workspaceRoot}", "preLaunchTask": "Build (Debug)", "runtimeExecutable": null, @@ -55,7 +55,7 @@ }, "type": "mono", "request": "launch", - "program": "${workspaceRoot}/osu.Game/bin/Release/osu!.exe", + "program": "${workspaceRoot}/osu.Desktop/bin/Release/osu!.exe", "cwd": "${workspaceRoot}", "preLaunchTask": "Build (Release)", "runtimeExecutable": null, From 167eefa39781a12e4421a5b5d40cbce32764fd3d Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Sat, 14 Oct 2017 15:16:08 +0900 Subject: [PATCH 0275/1263] Add logging --- osu.Game/Database/OsuDbContext.cs | 37 ++++++++++++++++++- osu.Game/Migrations/20171014052545_Init.cs | 2 - .../Migrations/OsuDbContextModelSnapshot.cs | 4 -- 3 files changed, 36 insertions(+), 7 deletions(-) diff --git a/osu.Game/Database/OsuDbContext.cs b/osu.Game/Database/OsuDbContext.cs index cd4a780979..9d5111d5d8 100644 --- a/osu.Game/Database/OsuDbContext.cs +++ b/osu.Game/Database/OsuDbContext.cs @@ -1,8 +1,12 @@ -using Microsoft.EntityFrameworkCore; +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Logging; +using osu.Framework.Logging; using osu.Game.Beatmaps; using osu.Game.Input.Bindings; using osu.Game.IO; using osu.Game.Rulesets; +using LogLevel = Microsoft.Extensions.Logging.LogLevel; namespace osu.Game.Database { @@ -30,6 +34,7 @@ namespace osu.Game.Database { base.OnConfiguring(optionsBuilder); optionsBuilder.UseSqlite(connectionString); + optionsBuilder.UseLoggerFactory(new OsuDbLoggerFactory()); } protected override void OnModelCreating(ModelBuilder modelBuilder) @@ -45,5 +50,35 @@ namespace osu.Game.Database modelBuilder.Entity().HasIndex(b => b.InstantiationInfo).IsUnique(); modelBuilder.Entity().HasIndex(b => b.Available); } + + private class OsuDbLoggerFactory : ILoggerFactory + { + public void Dispose() + { + } + + public ILogger CreateLogger(string categoryName) => new OsuDbLogger(); + + public void AddProvider(ILoggerProvider provider) => new OsuDbLoggerProvider(); + + private class OsuDbLoggerProvider : ILoggerProvider + { + public void Dispose() + { + } + + public ILogger CreateLogger(string categoryName) => new OsuDbLogger(); + } + + private class OsuDbLogger : ILogger + { + public void Log(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func formatter) + => Logger.Log(formatter(state, exception), LoggingTarget.Database, Framework.Logging.LogLevel.Debug); + + public bool IsEnabled(LogLevel logLevel) => true; + + public IDisposable BeginScope(TState state) => null; + } + } } } diff --git a/osu.Game/Migrations/20171014052545_Init.cs b/osu.Game/Migrations/20171014052545_Init.cs index 3b098ed2a6..6792f79e3d 100644 --- a/osu.Game/Migrations/20171014052545_Init.cs +++ b/osu.Game/Migrations/20171014052545_Init.cs @@ -2,8 +2,6 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using Microsoft.EntityFrameworkCore.Migrations; -using System; -using System.Collections.Generic; namespace osu.Game.Migrations { diff --git a/osu.Game/Migrations/OsuDbContextModelSnapshot.cs b/osu.Game/Migrations/OsuDbContextModelSnapshot.cs index bfcd09e309..f3a6c5a520 100644 --- a/osu.Game/Migrations/OsuDbContextModelSnapshot.cs +++ b/osu.Game/Migrations/OsuDbContextModelSnapshot.cs @@ -4,11 +4,7 @@ // using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Metadata; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage; using osu.Game.Database; -using System; namespace osu.Game.Migrations { From 9226456f3cf2c4c717238f0615d23ac6df1be5a2 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Sat, 14 Oct 2017 16:36:43 +0900 Subject: [PATCH 0276/1263] Update framework --- osu-framework | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu-framework b/osu-framework index 244775160f..27d78a17d6 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit 244775160fd3d9cbb97c70e9213c2e732d65bb0e +Subproject commit 27d78a17d606ccbbd67f679f52133aaf5ae4df63 From 89c17ed13e13f0e02d9ab752104ea91db4f7c699 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 14 Oct 2017 21:40:26 +0900 Subject: [PATCH 0277/1263] Initialise batteries Note that this is in the wrong place. But so is the rest of this code. --- osu.Game/OsuGameBase.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 7d9d3517bd..590007494b 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -83,6 +83,7 @@ namespace osu.Game private OsuDbContext createDbContext() { + SQLitePCL.Batteries.Init(); var connectionString = Host.Storage.GetDatabaseConnectionString(@"client"); var context = new OsuDbContext(connectionString); var connection = context.Database.GetDbConnection(); From 5f083f10a7bf5f21999f8af7ac8bc822a3985e84 Mon Sep 17 00:00:00 2001 From: TocoToucan Date: Sat, 14 Oct 2017 16:19:03 +0300 Subject: [PATCH 0278/1263] Add System.ValueTuple NuGet package --- osu.Desktop/osu.Desktop.csproj | 3 +++ osu.Desktop/packages.config | 1 + 2 files changed, 4 insertions(+) diff --git a/osu.Desktop/osu.Desktop.csproj b/osu.Desktop/osu.Desktop.csproj index fad297fa0a..859ff42dad 100644 --- a/osu.Desktop/osu.Desktop.csproj +++ b/osu.Desktop/osu.Desktop.csproj @@ -158,6 +158,9 @@ + + ..\packages\System.ValueTuple.4.4.0\lib\net461\System.ValueTuple.dll + diff --git a/osu.Desktop/packages.config b/osu.Desktop/packages.config index 0ec2cc196d..7c4e9632e0 100644 --- a/osu.Desktop/packages.config +++ b/osu.Desktop/packages.config @@ -11,4 +11,5 @@ Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/maste + \ No newline at end of file From 7cf5d63cd32bde05ee0bcbc262e5dac7595036f4 Mon Sep 17 00:00:00 2001 From: TocoToucan Date: Sun, 15 Oct 2017 00:40:41 +0300 Subject: [PATCH 0279/1263] Return back DatabaseBackedStore's query and populate functions --- osu.Game/Beatmaps/BeatmapInfo.cs | 9 +++- osu.Game/Beatmaps/BeatmapManager.cs | 46 ++++++++++++------- osu.Game/Beatmaps/BeatmapSetInfo.cs | 24 +++++++++- osu.Game/Beatmaps/BeatmapStore.cs | 42 ----------------- osu.Game/Database/DatabaseBackedStore.cs | 41 +++++++++++++++++ osu.Game/Database/IPopulate.cs | 7 +++ osu.Game/Rulesets/RulesetStore.cs | 19 ++------ .../Tests/Visual/TestCasePlaySongSelect.cs | 6 +-- osu.Game/Tests/Visual/TestCasePlayer.cs | 2 +- osu.Game/osu.Game.csproj | 1 + 10 files changed, 117 insertions(+), 80 deletions(-) create mode 100644 osu.Game/Database/IPopulate.cs diff --git a/osu.Game/Beatmaps/BeatmapInfo.cs b/osu.Game/Beatmaps/BeatmapInfo.cs index c1516f17c9..621bc59786 100644 --- a/osu.Game/Beatmaps/BeatmapInfo.cs +++ b/osu.Game/Beatmaps/BeatmapInfo.cs @@ -6,12 +6,13 @@ using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; using System.Linq; using Newtonsoft.Json; +using osu.Game.Database; using osu.Game.IO.Serialization; using osu.Game.Rulesets; namespace osu.Game.Beatmaps { - public class BeatmapInfo : IEquatable, IJsonSerializable + public class BeatmapInfo : IEquatable, IJsonSerializable, IPopulate { [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int ID { get; set; } @@ -124,5 +125,11 @@ namespace osu.Game.Beatmaps public bool BackgroundEquals(BeatmapInfo other) => other != null && BeatmapSet != null && other.BeatmapSet != null && BeatmapSet.Hash == other.BeatmapSet.Hash && (Metadata ?? BeatmapSet.Metadata).BackgroundFile == (other.Metadata ?? other.BeatmapSet.Metadata).BackgroundFile; + + public void Populate(OsuDbContext connection) + { + var entry = connection.Entry(this); + entry.Reference(nameof(Difficulty)); + } } } diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 955c6f4b17..d364a8fbe4 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -5,7 +5,6 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; -using System.Linq.Expressions; using System.Threading.Tasks; using Ionic.Zip; using osu.Framework.Audio.Track; @@ -260,10 +259,13 @@ namespace osu.Game.Beatmaps /// The beatmap set to delete. public void Delete(BeatmapSetInfo beatmapSet) { - if (!beatmaps.Delete(beatmapSet)) return; + lock (beatmaps) + { + if (!beatmaps.Delete(beatmapSet)) return; - if (!beatmapSet.Protected) - files.Dereference(beatmapSet.Files.Select(f => f.FileInfo).ToArray()); + if (!beatmapSet.Protected) + files.Dereference(beatmapSet.Files.Select(f => f.FileInfo).ToArray()); + } } /// @@ -302,6 +304,9 @@ namespace osu.Game.Beatmaps if (beatmapInfo == null || beatmapInfo == DefaultBeatmap?.BeatmapInfo) return DefaultBeatmap; + lock (beatmaps) + beatmaps.Populate(beatmapInfo); + if (beatmapInfo.BeatmapSet == null) throw new InvalidOperationException($@"Beatmap set {beatmapInfo.BeatmapSetInfoID} is not in the local database."); @@ -333,7 +338,10 @@ namespace osu.Game.Beatmaps { lock (beatmaps) { - BeatmapSetInfo set = beatmaps.QueryBeatmapSet(query); + BeatmapSetInfo set = beatmaps.Query(query).FirstOrDefault(); + + if (set != null) + beatmaps.Populate(set); return set; } @@ -351,9 +359,9 @@ namespace osu.Game.Beatmaps /// /// The query. /// Results from the provided query. - public List QueryBeatmapSets(Expression> query) + public List QueryBeatmapSets(Func query) { - return beatmaps.QueryBeatmapSets(query); + return beatmaps.QueryAndPopulate(query); } /// @@ -363,9 +371,15 @@ namespace osu.Game.Beatmaps /// The first result for the provided query, or null if no results were found. public BeatmapInfo QueryBeatmap(Func query) { - BeatmapInfo set = beatmaps.QueryBeatmap(query); + lock (beatmaps) + { + BeatmapInfo set = beatmaps.Query(query).FirstOrDefault(); - return set; + if (set != null) + beatmaps.Populate(set); + + return set; + } } /// @@ -373,9 +387,9 @@ namespace osu.Game.Beatmaps /// /// The query. /// Results from the provided query. - public List QueryBeatmaps(Expression> query) + public List QueryBeatmaps(Func query) { - lock (beatmaps) return beatmaps.QueryBeatmaps(query); + lock (beatmaps) return beatmaps.Query(query); } /// @@ -414,7 +428,7 @@ namespace osu.Game.Beatmaps // check if this beatmap has already been imported and exit early if so. BeatmapSetInfo beatmapSet; lock (beatmaps) - beatmapSet = beatmaps.QueryBeatmapSet(b => b.Hash == hash); + beatmapSet = beatmaps.QueryAndPopulate(b => b.Hash == hash).FirstOrDefault(); if (beatmapSet != null) { @@ -478,8 +492,8 @@ namespace osu.Game.Beatmaps beatmap.BeatmapInfo.Metadata = null; // TODO: this should be done in a better place once we actually need to dynamically update it. - beatmap.BeatmapInfo.Ruleset = rulesets.QueryRulesetInfo(r => r.ID == beatmap.BeatmapInfo.RulesetID); - beatmap.BeatmapInfo.StarDifficulty = rulesets.QueryRulesetInfo(r => r.ID == beatmap.BeatmapInfo.RulesetID)?.CreateInstance()?.CreateDifficultyCalculator(beatmap) + beatmap.BeatmapInfo.Ruleset = rulesets.Query(r => r.ID == beatmap.BeatmapInfo.RulesetID).FirstOrDefault(); + beatmap.BeatmapInfo.StarDifficulty = rulesets.Query(r => r.ID == beatmap.BeatmapInfo.RulesetID).FirstOrDefault()?.CreateInstance()?.CreateDifficultyCalculator(beatmap) .Calculate() ?? 0; beatmapSet.Beatmaps.Add(beatmap.BeatmapInfo); @@ -493,11 +507,11 @@ namespace osu.Game.Beatmaps /// Returns a list of all usable s. /// /// A list of available . - public List GetAllUsableBeatmapSets() + public List GetAllUsableBeatmapSets(bool populate = true) { lock (beatmaps) { - return beatmaps.QueryBeatmapSets(b => !b.DeletePending); + return populate ? beatmaps.QueryAndPopulate(b => !b.DeletePending) : beatmaps.Query(b => !b.DeletePending); } } diff --git a/osu.Game/Beatmaps/BeatmapSetInfo.cs b/osu.Game/Beatmaps/BeatmapSetInfo.cs index 404add2fa5..ddbc5d0dfb 100644 --- a/osu.Game/Beatmaps/BeatmapSetInfo.cs +++ b/osu.Game/Beatmaps/BeatmapSetInfo.cs @@ -4,10 +4,12 @@ using System.Collections.Generic; using System.ComponentModel.DataAnnotations.Schema; using System.Linq; +using osu.Game.Database; +using osu.Game.IO; namespace osu.Game.Beatmaps { - public class BeatmapSetInfo + public class BeatmapSetInfo : IPopulate { [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int ID { get; set; } @@ -34,5 +36,25 @@ namespace osu.Game.Beatmaps public List Files { get; set; } public bool Protected { get; set; } + + public void Populate(OsuDbContext connection) + { + var entry = connection.Entry(this); + entry.Collection(nameof(Beatmaps)).Load(); + entry.Reference(nameof(Metadata)).Load(); + entry.Collection(nameof(Files)).Load(); + + foreach (var beatmap in Beatmaps) + { + var beatmapEntry = connection.Entry(beatmap); + beatmapEntry.Reference(nameof(beatmap.Difficulty)).Load(); + } + + foreach (var file in Files) + { + var fileEntry = connection.Entry(file); + fileEntry.Reference(nameof(file.FileInfo)).Load(); + } + } } } diff --git a/osu.Game/Beatmaps/BeatmapStore.cs b/osu.Game/Beatmaps/BeatmapStore.cs index 9c5a1a9dfc..0be502132f 100644 --- a/osu.Game/Beatmaps/BeatmapStore.cs +++ b/osu.Game/Beatmaps/BeatmapStore.cs @@ -2,9 +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 System.Linq.Expressions; using Microsoft.EntityFrameworkCore; using osu.Game.Database; @@ -134,45 +132,5 @@ namespace osu.Game.Beatmaps { Connection.BeatmapSetInfo.RemoveRange(Connection.BeatmapSetInfo.Where(b => b.DeletePending && !b.Protected)); } - - public BeatmapSetInfo QueryBeatmapSet(Func query) - { - return Connection.BeatmapSetInfo - .Include(b => b.Metadata) - .Include(b => b.Beatmaps).ThenInclude(b => b.Ruleset) - .Include(b => b.Beatmaps).ThenInclude(b => b.Difficulty) - .Include(b => b.Files).ThenInclude(f => f.FileInfo) - .FirstOrDefault(query); - } - - public List QueryBeatmapSets(Expression> query) - { - return Connection.BeatmapSetInfo - .Include(b => b.Metadata) - .Include(b => b.Beatmaps).ThenInclude(b => b.Ruleset) - .Include(b => b.Beatmaps).ThenInclude(b => b.Difficulty) - .Include(b => b.Files).ThenInclude(f => f.FileInfo) - .Where(query).ToList(); - } - - public BeatmapInfo QueryBeatmap(Func query) - { - return Connection.BeatmapInfo - .Include(b => b.BeatmapSet) - .Include(b => b.Metadata) - .Include(b => b.Ruleset) - .Include(b => b.Difficulty) - .FirstOrDefault(query); - } - - public List QueryBeatmaps(Expression> query) - { - return Connection.BeatmapInfo - .Include(b => b.BeatmapSet) - .Include(b => b.Metadata) - .Include(b => b.Ruleset) - .Include(b => b.Difficulty) - .Where(query).ToList(); - } } } diff --git a/osu.Game/Database/DatabaseBackedStore.cs b/osu.Game/Database/DatabaseBackedStore.cs index f4b6a866dc..fd891ca825 100644 --- a/osu.Game/Database/DatabaseBackedStore.cs +++ b/osu.Game/Database/DatabaseBackedStore.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 Microsoft.EntityFrameworkCore; using osu.Framework.Logging; @@ -49,6 +50,46 @@ namespace osu.Game.Database /// public void Reset() => Prepare(true); + public List Query(Func filter = null) where T : class + { + checkType(typeof(T)); + + var dbSet = Connection.GetType().GetProperties().Single(property => property.PropertyType == typeof(DbSet)).GetValue(Connection) as DbSet; + var query = dbSet.ToList(); + + if (filter != null) + query = query.Where(filter).ToList(); + + return query; + } + + /// + /// Query and populate results. + /// + /// An filter to refine results. + /// + public List QueryAndPopulate(Func filter) + where T : class, IPopulate + { + checkType(typeof(T)); + + var query = Query(filter); + foreach (var item in query) + Populate(item); + return query; + } + + /// + /// Populate a database-backed item. + /// + /// + public void Populate(IPopulate item) + { + checkType(item.GetType()); + + item.Populate(Connection); + } + private void checkType(Type type) { if (!ValidTypes.Contains(type)) diff --git a/osu.Game/Database/IPopulate.cs b/osu.Game/Database/IPopulate.cs new file mode 100644 index 0000000000..24cabf6d5a --- /dev/null +++ b/osu.Game/Database/IPopulate.cs @@ -0,0 +1,7 @@ +namespace osu.Game.Database +{ + public interface IPopulate + { + void Populate(OsuDbContext connection); + } +} diff --git a/osu.Game/Rulesets/RulesetStore.cs b/osu.Game/Rulesets/RulesetStore.cs index 5a4b33df0b..8a8bbd9244 100644 --- a/osu.Game/Rulesets/RulesetStore.cs +++ b/osu.Game/Rulesets/RulesetStore.cs @@ -42,14 +42,14 @@ namespace osu.Game.Rulesets { Connection.Database.ExecuteSqlCommand("DELETE FROM RulesetInfo"); } - + var instances = loaded_assemblies.Values.Select(r => (Ruleset)Activator.CreateInstance(r, new RulesetInfo())); //add all legacy modes in correct order foreach (var r in instances.Where(r => r.LegacyID >= 0).OrderBy(r => r.LegacyID)) { var rulesetInfo = createRulesetInfo(r); - if (Connection.RulesetInfo.SingleOrDefault(rsi=>rsi.ID==rulesetInfo.ID)==null) + if (Connection.RulesetInfo.SingleOrDefault(rsi => rsi.ID == rulesetInfo.ID) == null) { Connection.RulesetInfo.Add(rulesetInfo); } @@ -108,19 +108,6 @@ namespace osu.Game.Rulesets protected override Type[] ValidTypes => new[] { typeof(RulesetInfo) }; - public RulesetInfo GetRuleset(int id) => Connection.RulesetInfo.First(r => r.ID == id); - - public RulesetInfo QueryRulesetInfo(Func query) - { - return Connection.RulesetInfo.FirstOrDefault(query); - } - - public List QueryRulesets(Func query = null) - { - var rulesets = Connection.RulesetInfo; - if (query != null) - return rulesets.Where(query).ToList(); - return rulesets.ToList(); - } + public RulesetInfo GetRuleset(int id) => Query().First(r => r.ID == id); } } diff --git a/osu.Game/Tests/Visual/TestCasePlaySongSelect.cs b/osu.Game/Tests/Visual/TestCasePlaySongSelect.cs index 1b7f2def4d..f4c0d0b1b6 100644 --- a/osu.Game/Tests/Visual/TestCasePlaySongSelect.cs +++ b/osu.Game/Tests/Visual/TestCasePlaySongSelect.cs @@ -75,7 +75,7 @@ namespace osu.Game.Tests.Visual new BeatmapInfo { OnlineBeatmapID = 1234 + i, - Ruleset = rulesets.QueryRulesets().First(), + Ruleset = rulesets.Query().First(), Path = "normal.osu", Version = "Normal", Difficulty = new BeatmapDifficulty @@ -86,7 +86,7 @@ namespace osu.Game.Tests.Visual new BeatmapInfo { OnlineBeatmapID = 1235 + i, - Ruleset = rulesets.QueryRulesets().First(), + Ruleset = rulesets.Query().First(), Path = "hard.osu", Version = "Hard", Difficulty = new BeatmapDifficulty @@ -97,7 +97,7 @@ namespace osu.Game.Tests.Visual new BeatmapInfo { OnlineBeatmapID = 1236 + i, - Ruleset = rulesets.QueryRulesets().First(), + Ruleset = rulesets.Query().First(), Path = "insane.osu", Version = "Insane", Difficulty = new BeatmapDifficulty diff --git a/osu.Game/Tests/Visual/TestCasePlayer.cs b/osu.Game/Tests/Visual/TestCasePlayer.cs index 811e240cee..b0953ceb7e 100644 --- a/osu.Game/Tests/Visual/TestCasePlayer.cs +++ b/osu.Game/Tests/Visual/TestCasePlayer.cs @@ -50,7 +50,7 @@ namespace osu.Game.Tests.Visual string instantiation = ruleset?.AssemblyQualifiedName; - foreach (var r in rulesets.QueryRulesets(rs => rs.Available && (instantiation == null || rs.InstantiationInfo == instantiation))) + foreach (var r in rulesets.Query(rs => rs.Available && (instantiation == null || rs.InstantiationInfo == instantiation))) AddStep(r.Name, () => loadPlayerFor(r)); } diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 8773119f26..b9154f7e77 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -273,6 +273,7 @@ + 20171014052545_Init.cs From bed5a64ee2182e3d2c99b87fa57dd3d53512c926 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Sun, 15 Oct 2017 16:15:35 +0800 Subject: [PATCH 0280/1263] Construct DwarableScore using null weight. --- osu.Game/Overlays/Profile/Sections/RanksSection.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Profile/Sections/RanksSection.cs b/osu.Game/Overlays/Profile/Sections/RanksSection.cs index d7df239003..3b2c9d83ed 100644 --- a/osu.Game/Overlays/Profile/Sections/RanksSection.cs +++ b/osu.Game/Overlays/Profile/Sections/RanksSection.cs @@ -155,7 +155,7 @@ namespace osu.Game.Overlays.Profile.Sections { missing.Hide(); foreach (OnlineScore score in scores) - scoreContainer.Add(new DrawableScore(score, includeWeigth ? Math.Pow(0.95, scoreContainer.Count) : -1) + scoreContainer.Add(new DrawableScore(score, includeWeigth ? Math.Pow(0.95, scoreContainer.Count) : (double?)null) { RelativeSizeAxes = Axes.X, Height = 60, From 192ebe776f3d12e73606ad7b0255babdc8e257ae Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Sun, 15 Oct 2017 16:30:52 +0800 Subject: [PATCH 0281/1263] Use localisation engine instead of asking current culture directly. --- osu.Game/Overlays/Profile/ProfileHeader.cs | 2 +- osu.Game/Overlays/Profile/Sections/Ranks/DrawableScore.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Profile/ProfileHeader.cs b/osu.Game/Overlays/Profile/ProfileHeader.cs index 973769a114..b033503141 100644 --- a/osu.Game/Overlays/Profile/ProfileHeader.cs +++ b/osu.Game/Overlays/Profile/ProfileHeader.cs @@ -402,7 +402,7 @@ namespace osu.Game.Overlays.Profile scoreText.Add(createScoreText("Ranked Score")); scoreNumberText.Add(createScoreNumberText(user.Statistics.RankedScore.ToString(@"#,0"))); scoreText.Add(createScoreText("Accuracy")); - scoreNumberText.Add(createScoreNumberText($"{user.Statistics.Accuracy.ToString("0.##", CultureInfo.CurrentCulture)}%")); + scoreNumberText.Add(createScoreNumberText($"{user.Statistics.Accuracy.ToString("0.##")}%")); scoreText.Add(createScoreText("Play Count")); scoreNumberText.Add(createScoreNumberText(user.Statistics.PlayCount.ToString(@"#,0"))); scoreText.Add(createScoreText("Total Score")); diff --git a/osu.Game/Overlays/Profile/Sections/Ranks/DrawableScore.cs b/osu.Game/Overlays/Profile/Sections/Ranks/DrawableScore.cs index 52b68e7b30..b2961aad59 100644 --- a/osu.Game/Overlays/Profile/Sections/Ranks/DrawableScore.cs +++ b/osu.Game/Overlays/Profile/Sections/Ranks/DrawableScore.cs @@ -92,7 +92,7 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks { stats.Add(new OsuSpriteText { - Text = $"weighted: {Math.Round(score.PP * weight ?? 0)}pp ({weight.Value.ToString("0%", CultureInfo.CurrentCulture)})", + Current = locale.Format($"weighted: {score.PP * weight ?? 0:0}pp ({weight:0%})"), Anchor = Anchor.TopRight, Origin = Anchor.TopRight, Colour = colour.GrayA, From 9b3676c5623970c8a9a99b34647339c7ea6c5e4e Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Sun, 15 Oct 2017 16:44:15 +0800 Subject: [PATCH 0282/1263] Use format string for double instead of Math.Round. --- osu.Game/Overlays/BeatmapSet/SuccessRate.cs | 2 +- osu.Game/Overlays/Profile/Sections/Ranks/DrawableScore.cs | 7 ++++--- osu.Game/Screens/Select/BeatmapInfoWedge.cs | 4 ++-- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/osu.Game/Overlays/BeatmapSet/SuccessRate.cs b/osu.Game/Overlays/BeatmapSet/SuccessRate.cs index 26335aac9b..c2e1a7b660 100644 --- a/osu.Game/Overlays/BeatmapSet/SuccessRate.cs +++ b/osu.Game/Overlays/BeatmapSet/SuccessRate.cs @@ -31,7 +31,7 @@ namespace osu.Game.Overlays.BeatmapSet beatmap = value; var rate = (float)beatmap.OnlineInfo.PassCount / beatmap.OnlineInfo.PlayCount; - successPercent.Text = $"{Math.Round(rate * 100)}%"; + successPercent.Text = rate.ToString("P0"); successRate.Length = rate; percentContainer.ResizeWidthTo(successRate.Length, 250, Easing.InOutCubic); diff --git a/osu.Game/Overlays/Profile/Sections/Ranks/DrawableScore.cs b/osu.Game/Overlays/Profile/Sections/Ranks/DrawableScore.cs index b2961aad59..5162c350e8 100644 --- a/osu.Game/Overlays/Profile/Sections/Ranks/DrawableScore.cs +++ b/osu.Game/Overlays/Profile/Sections/Ranks/DrawableScore.cs @@ -79,9 +79,10 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks [BackgroundDependencyLoader] private void load(OsuColour colour, LocalisationEngine locale, BeatmapSetOverlay beatmapSetOverlay) { + double pp = score.PP ?? 0; stats.Add(new OsuSpriteText { - Text = $"{Math.Round(score.PP ?? 0)}pp", + Text = $"{pp:0}pp", Anchor = Anchor.TopRight, Origin = Anchor.TopRight, TextSize = 18, @@ -92,7 +93,7 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks { stats.Add(new OsuSpriteText { - Current = locale.Format($"weighted: {score.PP * weight ?? 0:0}pp ({weight:0%})"), + Text = $"weighted: {pp * weight:0}pp ({weight:P0})", Anchor = Anchor.TopRight, Origin = Anchor.TopRight, Colour = colour.GrayA, @@ -103,7 +104,7 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks stats.Add(new OsuSpriteText { - Text = "accuracy: " + score.Accuracy.ToString("0.00%"), + Text = $"accuracy: {score.Accuracy:P2}", Anchor = Anchor.TopRight, Origin = Anchor.TopRight, Colour = colour.GrayA, diff --git a/osu.Game/Screens/Select/BeatmapInfoWedge.cs b/osu.Game/Screens/Select/BeatmapInfoWedge.cs index 3b26f7bffc..dc3b012328 100644 --- a/osu.Game/Screens/Select/BeatmapInfoWedge.cs +++ b/osu.Game/Screens/Select/BeatmapInfoWedge.cs @@ -232,9 +232,9 @@ namespace osu.Game.Screens.Select double bpmMax = beatmap.ControlPointInfo.BPMMaximum; double bpmMin = beatmap.ControlPointInfo.BPMMinimum; - if (Precision.AlmostEquals(bpmMin, bpmMax)) return Math.Round(bpmMin) + "bpm"; + if (Precision.AlmostEquals(bpmMin, bpmMax)) return $"{bpmMin:0}bpm"; - return Math.Round(bpmMin) + "-" + Math.Round(bpmMax) + "bpm (mostly " + Math.Round(beatmap.ControlPointInfo.BPMMode) + "bpm)"; + return $"{bpmMin:0}-{bpmMax:0}bpm (mostly {beatmap.ControlPointInfo.BPMMode:0}bpm)"; } public class InfoLabel : Container From 06fe8745945ce602666a1947c4638928debfaab8 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Sun, 15 Oct 2017 16:53:30 +0800 Subject: [PATCH 0283/1263] CI fixes. --- osu.Game/Overlays/BeatmapSet/SuccessRate.cs | 1 - osu.Game/Overlays/Profile/ProfileHeader.cs | 3 +-- osu.Game/Overlays/Profile/Sections/Ranks/DrawableScore.cs | 2 -- 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/osu.Game/Overlays/BeatmapSet/SuccessRate.cs b/osu.Game/Overlays/BeatmapSet/SuccessRate.cs index c2e1a7b660..9402ed82f4 100644 --- a/osu.Game/Overlays/BeatmapSet/SuccessRate.cs +++ b/osu.Game/Overlays/BeatmapSet/SuccessRate.cs @@ -1,7 +1,6 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using System; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; diff --git a/osu.Game/Overlays/Profile/ProfileHeader.cs b/osu.Game/Overlays/Profile/ProfileHeader.cs index b033503141..22e34be34c 100644 --- a/osu.Game/Overlays/Profile/ProfileHeader.cs +++ b/osu.Game/Overlays/Profile/ProfileHeader.cs @@ -17,7 +17,6 @@ using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Users; using System.Diagnostics; -using System.Globalization; using System.Collections.Generic; using osu.Framework.Graphics.Cursor; @@ -402,7 +401,7 @@ namespace osu.Game.Overlays.Profile scoreText.Add(createScoreText("Ranked Score")); scoreNumberText.Add(createScoreNumberText(user.Statistics.RankedScore.ToString(@"#,0"))); scoreText.Add(createScoreText("Accuracy")); - scoreNumberText.Add(createScoreNumberText($"{user.Statistics.Accuracy.ToString("0.##")}%")); + scoreNumberText.Add(createScoreNumberText($"{user.Statistics.Accuracy:0.##}%")); scoreText.Add(createScoreText("Play Count")); scoreNumberText.Add(createScoreNumberText(user.Statistics.PlayCount.ToString(@"#,0"))); scoreText.Add(createScoreText("Total Score")); diff --git a/osu.Game/Overlays/Profile/Sections/Ranks/DrawableScore.cs b/osu.Game/Overlays/Profile/Sections/Ranks/DrawableScore.cs index 5162c350e8..af336c2529 100644 --- a/osu.Game/Overlays/Profile/Sections/Ranks/DrawableScore.cs +++ b/osu.Game/Overlays/Profile/Sections/Ranks/DrawableScore.cs @@ -13,9 +13,7 @@ using osu.Game.Rulesets.Mods; using osu.Game.Screens.Select.Leaderboards; using System.Linq; using osu.Framework.Localisation; -using System.Globalization; using osu.Game.Rulesets.Scoring; -using System; using osu.Game.Rulesets.UI; namespace osu.Game.Overlays.Profile.Sections.Ranks From db2750592d0e946de8f07a4269c2adf14abaf1d7 Mon Sep 17 00:00:00 2001 From: TocoToucan Date: Sun, 15 Oct 2017 14:01:35 +0300 Subject: [PATCH 0284/1263] Fix removal of FileInfo, BeatmapMetadata, BeatmapDifficulty objects --- osu.Game/Beatmaps/BeatmapDifficulty.cs | 1 + osu.Game/Beatmaps/BeatmapMetadata.cs | 1 + osu.Game/Beatmaps/BeatmapStore.cs | 5 + ...ner.cs => 20171015101238_Init.Designer.cs} | 56 +++-- ...4052545_Init.cs => 20171015101238_Init.cs} | 235 +++++++++--------- .../Migrations/OsuDbContextModelSnapshot.cs | 54 ++-- osu.Game/osu.Game.csproj | 11 +- osu.Game/packages.config | 1 + 8 files changed, 192 insertions(+), 172 deletions(-) rename osu.Game/Migrations/{20171014052545_Init.designer.cs => 20171015101238_Init.Designer.cs} (85%) rename osu.Game/Migrations/{20171014052545_Init.cs => 20171015101238_Init.cs} (90%) diff --git a/osu.Game/Beatmaps/BeatmapDifficulty.cs b/osu.Game/Beatmaps/BeatmapDifficulty.cs index 25e212f3c5..0c2299e5e6 100644 --- a/osu.Game/Beatmaps/BeatmapDifficulty.cs +++ b/osu.Game/Beatmaps/BeatmapDifficulty.cs @@ -14,6 +14,7 @@ namespace osu.Game.Beatmaps [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int ID { get; set; } + public int BeatmapInfoId { get; set; } public float DrainRate { get; set; } = DEFAULT_DIFFICULTY; public float CircleSize { get; set; } = DEFAULT_DIFFICULTY; public float OverallDifficulty { get; set; } = DEFAULT_DIFFICULTY; diff --git a/osu.Game/Beatmaps/BeatmapMetadata.cs b/osu.Game/Beatmaps/BeatmapMetadata.cs index 5e47d6c13d..5e1a77a5bf 100644 --- a/osu.Game/Beatmaps/BeatmapMetadata.cs +++ b/osu.Game/Beatmaps/BeatmapMetadata.cs @@ -15,6 +15,7 @@ namespace osu.Game.Beatmaps [NotMapped] public int? OnlineBeatmapSetID { get; set; } + public int BeatmapSetInfoId { get; set; } public string Title { get; set; } public string TitleUnicode { get; set; } diff --git a/osu.Game/Beatmaps/BeatmapStore.cs b/osu.Game/Beatmaps/BeatmapStore.cs index 0be502132f..19e30a23ce 100644 --- a/osu.Game/Beatmaps/BeatmapStore.cs +++ b/osu.Game/Beatmaps/BeatmapStore.cs @@ -73,6 +73,11 @@ namespace osu.Game.Beatmaps if (beatmapSet.DeletePending) return false; beatmapSet.DeletePending = true; + + // We can't use one to one relationship with its cascade delete because FileInfo can be used not only inside of BeatmapSetFileInfo + var files = beatmapSet.Files.Select(beatmapSetFileInfo => beatmapSetFileInfo.FileInfo); + Connection.FileInfo.RemoveRange(files); + Connection.BeatmapSetInfo.Remove(beatmapSet); Connection.SaveChanges(); diff --git a/osu.Game/Migrations/20171014052545_Init.designer.cs b/osu.Game/Migrations/20171015101238_Init.Designer.cs similarity index 85% rename from osu.Game/Migrations/20171014052545_Init.designer.cs rename to osu.Game/Migrations/20171015101238_Init.Designer.cs index f151131882..2d37d1d07f 100644 --- a/osu.Game/Migrations/20171014052545_Init.designer.cs +++ b/osu.Game/Migrations/20171015101238_Init.Designer.cs @@ -1,7 +1,4 @@ -// Copyright (c) 2007-2017 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -// +// using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata; @@ -13,7 +10,7 @@ using System; namespace osu.Game.Migrations { [DbContext(typeof(OsuDbContext))] - [Migration("20171014052545_Init")] + [Migration("20171015101238_Init")] partial class Init { protected override void BuildTargetModel(ModelBuilder modelBuilder) @@ -29,6 +26,8 @@ namespace osu.Game.Migrations b.Property("ApproachRate"); + b.Property("BeatmapInfoId"); + b.Property("CircleSize"); b.Property("DrainRate"); @@ -41,6 +40,9 @@ namespace osu.Game.Migrations b.HasKey("ID"); + b.HasIndex("BeatmapInfoId") + .IsUnique(); + b.ToTable("BeatmapDifficulty"); }); @@ -59,8 +61,6 @@ namespace osu.Game.Migrations b.Property("Countdown"); - b.Property("DifficultyID"); - b.Property("DistanceSpacing"); b.Property("GridSize"); @@ -97,8 +97,6 @@ namespace osu.Game.Migrations b.HasIndex("BeatmapSetInfoID"); - b.HasIndex("DifficultyID"); - b.HasIndex("MD5Hash"); b.HasIndex("MetadataID"); @@ -119,10 +117,13 @@ namespace osu.Game.Migrations b.Property("AudioFile"); - b.Property("Author"); + b.Property("AuthorString") + .HasColumnName("Author"); b.Property("BackgroundFile"); + b.Property("BeatmapSetInfoId"); + b.Property("PreviewTime"); b.Property("Source"); @@ -135,6 +136,9 @@ namespace osu.Game.Migrations b.HasKey("ID"); + b.HasIndex("BeatmapSetInfoId") + .IsUnique(); + b.ToTable("BeatmapMetadata"); }); @@ -168,16 +172,12 @@ namespace osu.Game.Migrations b.Property("Hash"); - b.Property("MetadataID"); - b.Property("Protected"); b.HasKey("ID"); b.HasIndex("DeletePending"); - b.HasIndex("MetadataID"); - b.ToTable("BeatmapSetInfo"); }); @@ -248,6 +248,14 @@ namespace osu.Game.Migrations b.ToTable("RulesetInfo"); }); + modelBuilder.Entity("osu.Game.Beatmaps.BeatmapDifficulty", b => + { + b.HasOne("osu.Game.Beatmaps.BeatmapInfo") + .WithOne("Difficulty") + .HasForeignKey("osu.Game.Beatmaps.BeatmapDifficulty", "BeatmapInfoId") + .OnDelete(DeleteBehavior.Cascade); + }); + modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b => { b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo", "BeatmapSet") @@ -255,11 +263,6 @@ namespace osu.Game.Migrations .HasForeignKey("BeatmapSetInfoID") .OnDelete(DeleteBehavior.Cascade); - b.HasOne("osu.Game.Beatmaps.BeatmapDifficulty", "Difficulty") - .WithMany() - .HasForeignKey("DifficultyID") - .OnDelete(DeleteBehavior.Cascade); - b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata") .WithMany() .HasForeignKey("MetadataID"); @@ -270,6 +273,14 @@ namespace osu.Game.Migrations .OnDelete(DeleteBehavior.Cascade); }); + modelBuilder.Entity("osu.Game.Beatmaps.BeatmapMetadata", b => + { + b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo") + .WithOne("Metadata") + .HasForeignKey("osu.Game.Beatmaps.BeatmapMetadata", "BeatmapSetInfoId") + .OnDelete(DeleteBehavior.Cascade); + }); + modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b => { b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo") @@ -282,13 +293,6 @@ namespace osu.Game.Migrations .HasForeignKey("FileInfoID") .OnDelete(DeleteBehavior.Cascade); }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata") - .WithMany() - .HasForeignKey("MetadataID"); - }); #pragma warning restore 612, 618 } } diff --git a/osu.Game/Migrations/20171014052545_Init.cs b/osu.Game/Migrations/20171015101238_Init.cs similarity index 90% rename from osu.Game/Migrations/20171014052545_Init.cs rename to osu.Game/Migrations/20171015101238_Init.cs index 6792f79e3d..afa83a7fff 100644 --- a/osu.Game/Migrations/20171014052545_Init.cs +++ b/osu.Game/Migrations/20171015101238_Init.cs @@ -1,7 +1,4 @@ -// Copyright (c) 2007-2017 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Migrations; namespace osu.Game.Migrations { @@ -10,43 +7,18 @@ namespace osu.Game.Migrations protected override void Up(MigrationBuilder migrationBuilder) { migrationBuilder.CreateTable( - name: "BeatmapDifficulty", + name: "BeatmapSetInfo", columns: table => new { ID = table.Column(type: "INTEGER", nullable: false) .Annotation("Sqlite:Autoincrement", true), - ApproachRate = table.Column(type: "REAL", nullable: false), - CircleSize = table.Column(type: "REAL", nullable: false), - DrainRate = table.Column(type: "REAL", nullable: false), - OverallDifficulty = table.Column(type: "REAL", nullable: false), - SliderMultiplier = table.Column(type: "REAL", nullable: false), - SliderTickRate = table.Column(type: "REAL", nullable: false) + DeletePending = table.Column(type: "INTEGER", nullable: false), + Hash = table.Column(type: "TEXT", nullable: true), + Protected = table.Column(type: "INTEGER", nullable: false) }, constraints: table => { - table.PrimaryKey("PK_BeatmapDifficulty", x => x.ID); - }); - - migrationBuilder.CreateTable( - name: "BeatmapMetadata", - columns: table => new - { - ID = table.Column(type: "INTEGER", nullable: false) - .Annotation("Sqlite:Autoincrement", true), - Artist = table.Column(type: "TEXT", nullable: true), - ArtistUnicode = table.Column(type: "TEXT", nullable: true), - AudioFile = table.Column(type: "TEXT", nullable: true), - Author = table.Column(type: "TEXT", nullable: true), - BackgroundFile = table.Column(type: "TEXT", nullable: true), - PreviewTime = table.Column(type: "INTEGER", nullable: false), - Source = table.Column(type: "TEXT", nullable: true), - Tags = table.Column(type: "TEXT", nullable: true), - Title = table.Column(type: "TEXT", nullable: true), - TitleUnicode = table.Column(type: "TEXT", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_BeatmapMetadata", x => x.ID); + table.PrimaryKey("PK_BeatmapSetInfo", x => x.ID); }); migrationBuilder.CreateTable( @@ -95,83 +67,32 @@ namespace osu.Game.Migrations }); migrationBuilder.CreateTable( - name: "BeatmapSetInfo", + name: "BeatmapMetadata", columns: table => new { ID = table.Column(type: "INTEGER", nullable: false) .Annotation("Sqlite:Autoincrement", true), - DeletePending = table.Column(type: "INTEGER", nullable: false), - Hash = table.Column(type: "TEXT", nullable: true), - MetadataID = table.Column(type: "INTEGER", nullable: true), - Protected = table.Column(type: "INTEGER", nullable: false) + Artist = table.Column(type: "TEXT", nullable: true), + ArtistUnicode = table.Column(type: "TEXT", nullable: true), + AudioFile = table.Column(type: "TEXT", nullable: true), + Author = table.Column(type: "TEXT", nullable: true), + BackgroundFile = table.Column(type: "TEXT", nullable: true), + BeatmapSetInfoId = table.Column(type: "INTEGER", nullable: false), + PreviewTime = table.Column(type: "INTEGER", nullable: false), + Source = table.Column(type: "TEXT", nullable: true), + Tags = table.Column(type: "TEXT", nullable: true), + Title = table.Column(type: "TEXT", nullable: true), + TitleUnicode = table.Column(type: "TEXT", nullable: true) }, constraints: table => { - table.PrimaryKey("PK_BeatmapSetInfo", x => x.ID); + table.PrimaryKey("PK_BeatmapMetadata", x => x.ID); table.ForeignKey( - name: "FK_BeatmapSetInfo_BeatmapMetadata_MetadataID", - column: x => x.MetadataID, - principalTable: "BeatmapMetadata", - principalColumn: "ID", - onDelete: ReferentialAction.Restrict); - }); - - migrationBuilder.CreateTable( - name: "BeatmapInfo", - columns: table => new - { - ID = table.Column(type: "INTEGER", nullable: false) - .Annotation("Sqlite:Autoincrement", true), - AudioLeadIn = table.Column(type: "INTEGER", nullable: false), - BaseDifficultyID = table.Column(type: "INTEGER", nullable: false), - BeatDivisor = table.Column(type: "INTEGER", nullable: false), - BeatmapSetInfoID = table.Column(type: "INTEGER", nullable: false), - Countdown = table.Column(type: "INTEGER", nullable: false), - DifficultyID = table.Column(type: "INTEGER", nullable: false), - DistanceSpacing = table.Column(type: "REAL", nullable: false), - GridSize = table.Column(type: "INTEGER", nullable: false), - Hash = table.Column(type: "TEXT", nullable: true), - Hidden = table.Column(type: "INTEGER", nullable: false), - LetterboxInBreaks = table.Column(type: "INTEGER", nullable: false), - MD5Hash = table.Column(type: "TEXT", nullable: true), - MetadataID = table.Column(type: "INTEGER", nullable: true), - Path = table.Column(type: "TEXT", nullable: true), - RulesetID = table.Column(type: "INTEGER", nullable: false), - SpecialStyle = table.Column(type: "INTEGER", nullable: false), - StackLeniency = table.Column(type: "REAL", nullable: false), - StarDifficulty = table.Column(type: "REAL", nullable: false), - StoredBookmarks = table.Column(type: "TEXT", nullable: true), - TimelineZoom = table.Column(type: "REAL", nullable: false), - Version = table.Column(type: "TEXT", nullable: true), - WidescreenStoryboard = table.Column(type: "INTEGER", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_BeatmapInfo", x => x.ID); - table.ForeignKey( - name: "FK_BeatmapInfo_BeatmapSetInfo_BeatmapSetInfoID", - column: x => x.BeatmapSetInfoID, + name: "FK_BeatmapMetadata_BeatmapSetInfo_BeatmapSetInfoId", + column: x => x.BeatmapSetInfoId, principalTable: "BeatmapSetInfo", principalColumn: "ID", onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "FK_BeatmapInfo_BeatmapDifficulty_DifficultyID", - column: x => x.DifficultyID, - principalTable: "BeatmapDifficulty", - principalColumn: "ID", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "FK_BeatmapInfo_BeatmapMetadata_MetadataID", - column: x => x.MetadataID, - principalTable: "BeatmapMetadata", - principalColumn: "ID", - onDelete: ReferentialAction.Restrict); - table.ForeignKey( - name: "FK_BeatmapInfo_RulesetInfo_RulesetID", - column: x => x.RulesetID, - principalTable: "RulesetInfo", - principalColumn: "ID", - onDelete: ReferentialAction.Cascade); }); migrationBuilder.CreateTable( @@ -201,16 +122,93 @@ namespace osu.Game.Migrations onDelete: ReferentialAction.Cascade); }); + migrationBuilder.CreateTable( + name: "BeatmapInfo", + columns: table => new + { + ID = table.Column(type: "INTEGER", nullable: false) + .Annotation("Sqlite:Autoincrement", true), + AudioLeadIn = table.Column(type: "INTEGER", nullable: false), + BaseDifficultyID = table.Column(type: "INTEGER", nullable: false), + BeatDivisor = table.Column(type: "INTEGER", nullable: false), + BeatmapSetInfoID = table.Column(type: "INTEGER", nullable: false), + Countdown = table.Column(type: "INTEGER", nullable: false), + DistanceSpacing = table.Column(type: "REAL", nullable: false), + GridSize = table.Column(type: "INTEGER", nullable: false), + Hash = table.Column(type: "TEXT", nullable: true), + Hidden = table.Column(type: "INTEGER", nullable: false), + LetterboxInBreaks = table.Column(type: "INTEGER", nullable: false), + MD5Hash = table.Column(type: "TEXT", nullable: true), + MetadataID = table.Column(type: "INTEGER", nullable: true), + Path = table.Column(type: "TEXT", nullable: true), + RulesetID = table.Column(type: "INTEGER", nullable: false), + SpecialStyle = table.Column(type: "INTEGER", nullable: false), + StackLeniency = table.Column(type: "REAL", nullable: false), + StarDifficulty = table.Column(type: "REAL", nullable: false), + StoredBookmarks = table.Column(type: "TEXT", nullable: true), + TimelineZoom = table.Column(type: "REAL", nullable: false), + Version = table.Column(type: "TEXT", nullable: true), + WidescreenStoryboard = table.Column(type: "INTEGER", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_BeatmapInfo", x => x.ID); + table.ForeignKey( + name: "FK_BeatmapInfo_BeatmapSetInfo_BeatmapSetInfoID", + column: x => x.BeatmapSetInfoID, + principalTable: "BeatmapSetInfo", + principalColumn: "ID", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_BeatmapInfo_BeatmapMetadata_MetadataID", + column: x => x.MetadataID, + principalTable: "BeatmapMetadata", + principalColumn: "ID", + onDelete: ReferentialAction.Restrict); + table.ForeignKey( + name: "FK_BeatmapInfo_RulesetInfo_RulesetID", + column: x => x.RulesetID, + principalTable: "RulesetInfo", + principalColumn: "ID", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "BeatmapDifficulty", + columns: table => new + { + ID = table.Column(type: "INTEGER", nullable: false) + .Annotation("Sqlite:Autoincrement", true), + ApproachRate = table.Column(type: "REAL", nullable: false), + BeatmapInfoId = table.Column(type: "INTEGER", nullable: false), + CircleSize = table.Column(type: "REAL", nullable: false), + DrainRate = table.Column(type: "REAL", nullable: false), + OverallDifficulty = table.Column(type: "REAL", nullable: false), + SliderMultiplier = table.Column(type: "REAL", nullable: false), + SliderTickRate = table.Column(type: "REAL", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_BeatmapDifficulty", x => x.ID); + table.ForeignKey( + name: "FK_BeatmapDifficulty_BeatmapInfo_BeatmapInfoId", + column: x => x.BeatmapInfoId, + principalTable: "BeatmapInfo", + principalColumn: "ID", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_BeatmapDifficulty_BeatmapInfoId", + table: "BeatmapDifficulty", + column: "BeatmapInfoId", + unique: true); + migrationBuilder.CreateIndex( name: "IX_BeatmapInfo_BeatmapSetInfoID", table: "BeatmapInfo", column: "BeatmapSetInfoID"); - migrationBuilder.CreateIndex( - name: "IX_BeatmapInfo_DifficultyID", - table: "BeatmapInfo", - column: "DifficultyID"); - migrationBuilder.CreateIndex( name: "IX_BeatmapInfo_MD5Hash", table: "BeatmapInfo", @@ -226,6 +224,12 @@ namespace osu.Game.Migrations table: "BeatmapInfo", column: "RulesetID"); + migrationBuilder.CreateIndex( + name: "IX_BeatmapMetadata_BeatmapSetInfoId", + table: "BeatmapMetadata", + column: "BeatmapSetInfoId", + unique: true); + migrationBuilder.CreateIndex( name: "IX_BeatmapSetFileInfo_BeatmapSetInfoID", table: "BeatmapSetFileInfo", @@ -241,11 +245,6 @@ namespace osu.Game.Migrations table: "BeatmapSetInfo", column: "DeletePending"); - migrationBuilder.CreateIndex( - name: "IX_BeatmapSetInfo_MetadataID", - table: "BeatmapSetInfo", - column: "MetadataID"); - migrationBuilder.CreateIndex( name: "IX_FileInfo_Hash", table: "FileInfo", @@ -288,7 +287,7 @@ namespace osu.Game.Migrations protected override void Down(MigrationBuilder migrationBuilder) { migrationBuilder.DropTable( - name: "BeatmapInfo"); + name: "BeatmapDifficulty"); migrationBuilder.DropTable( name: "BeatmapSetFileInfo"); @@ -297,19 +296,19 @@ namespace osu.Game.Migrations name: "KeyBinding"); migrationBuilder.DropTable( - name: "BeatmapDifficulty"); - - migrationBuilder.DropTable( - name: "RulesetInfo"); - - migrationBuilder.DropTable( - name: "BeatmapSetInfo"); + name: "BeatmapInfo"); migrationBuilder.DropTable( name: "FileInfo"); migrationBuilder.DropTable( name: "BeatmapMetadata"); + + migrationBuilder.DropTable( + name: "RulesetInfo"); + + migrationBuilder.DropTable( + name: "BeatmapSetInfo"); } } } diff --git a/osu.Game/Migrations/OsuDbContextModelSnapshot.cs b/osu.Game/Migrations/OsuDbContextModelSnapshot.cs index f3a6c5a520..162119408b 100644 --- a/osu.Game/Migrations/OsuDbContextModelSnapshot.cs +++ b/osu.Game/Migrations/OsuDbContextModelSnapshot.cs @@ -1,7 +1,4 @@ -// Copyright (c) 2007-2017 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -// +// using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using osu.Game.Database; @@ -24,6 +21,8 @@ namespace osu.Game.Migrations b.Property("ApproachRate"); + b.Property("BeatmapInfoId"); + b.Property("CircleSize"); b.Property("DrainRate"); @@ -36,6 +35,9 @@ namespace osu.Game.Migrations b.HasKey("ID"); + b.HasIndex("BeatmapInfoId") + .IsUnique(); + b.ToTable("BeatmapDifficulty"); }); @@ -54,8 +56,6 @@ namespace osu.Game.Migrations b.Property("Countdown"); - b.Property("DifficultyID"); - b.Property("DistanceSpacing"); b.Property("GridSize"); @@ -92,8 +92,6 @@ namespace osu.Game.Migrations b.HasIndex("BeatmapSetInfoID"); - b.HasIndex("DifficultyID"); - b.HasIndex("MD5Hash"); b.HasIndex("MetadataID"); @@ -114,10 +112,13 @@ namespace osu.Game.Migrations b.Property("AudioFile"); - b.Property("Author"); + b.Property("AuthorString") + .HasColumnName("Author"); b.Property("BackgroundFile"); + b.Property("BeatmapSetInfoId"); + b.Property("PreviewTime"); b.Property("Source"); @@ -130,6 +131,9 @@ namespace osu.Game.Migrations b.HasKey("ID"); + b.HasIndex("BeatmapSetInfoId") + .IsUnique(); + b.ToTable("BeatmapMetadata"); }); @@ -163,16 +167,12 @@ namespace osu.Game.Migrations b.Property("Hash"); - b.Property("MetadataID"); - b.Property("Protected"); b.HasKey("ID"); b.HasIndex("DeletePending"); - b.HasIndex("MetadataID"); - b.ToTable("BeatmapSetInfo"); }); @@ -243,6 +243,14 @@ namespace osu.Game.Migrations b.ToTable("RulesetInfo"); }); + modelBuilder.Entity("osu.Game.Beatmaps.BeatmapDifficulty", b => + { + b.HasOne("osu.Game.Beatmaps.BeatmapInfo") + .WithOne("Difficulty") + .HasForeignKey("osu.Game.Beatmaps.BeatmapDifficulty", "BeatmapInfoId") + .OnDelete(DeleteBehavior.Cascade); + }); + modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b => { b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo", "BeatmapSet") @@ -250,11 +258,6 @@ namespace osu.Game.Migrations .HasForeignKey("BeatmapSetInfoID") .OnDelete(DeleteBehavior.Cascade); - b.HasOne("osu.Game.Beatmaps.BeatmapDifficulty", "Difficulty") - .WithMany() - .HasForeignKey("DifficultyID") - .OnDelete(DeleteBehavior.Cascade); - b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata") .WithMany() .HasForeignKey("MetadataID"); @@ -265,6 +268,14 @@ namespace osu.Game.Migrations .OnDelete(DeleteBehavior.Cascade); }); + modelBuilder.Entity("osu.Game.Beatmaps.BeatmapMetadata", b => + { + b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo") + .WithOne("Metadata") + .HasForeignKey("osu.Game.Beatmaps.BeatmapMetadata", "BeatmapSetInfoId") + .OnDelete(DeleteBehavior.Cascade); + }); + modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b => { b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo") @@ -277,13 +288,6 @@ namespace osu.Game.Migrations .HasForeignKey("FileInfoID") .OnDelete(DeleteBehavior.Cascade); }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata") - .WithMany() - .HasForeignKey("MetadataID"); - }); #pragma warning restore 612, 618 } } diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index b9154f7e77..404576e832 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -23,6 +23,7 @@ LocalIntranet v4.6.1 true + true publish\ true Disk @@ -197,6 +198,10 @@ ..\packages\System.Runtime.CompilerServices.Unsafe.4.4.0\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll + + ..\packages\System.ValueTuple.4.4.0\lib\net461\System.ValueTuple.dll + True + @@ -274,9 +279,9 @@ - - - 20171014052545_Init.cs + + + 20171015101238_Init.cs diff --git a/osu.Game/packages.config b/osu.Game/packages.config index 8691e7062a..ae7b74ef16 100644 --- a/osu.Game/packages.config +++ b/osu.Game/packages.config @@ -49,4 +49,5 @@ Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/maste + \ No newline at end of file From 298349ba77c22b8dff7226eda23811b4c1445369 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 16 Oct 2017 00:16:15 +0900 Subject: [PATCH 0285/1263] Update framework --- osu-framework | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu-framework b/osu-framework index 27d78a17d6..4489791c8f 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit 27d78a17d606ccbbd67f679f52133aaf5ae4df63 +Subproject commit 4489791c8f1299ee4cc045454f76bfd34940aabf From a232033469bf7a8e59bfaece9ea511753ff80111 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 16 Oct 2017 00:53:59 +0900 Subject: [PATCH 0286/1263] Fix some file headers and unused files --- osu.Game/Database/DbContextBase.cs | 8 -------- osu.Game/Database/IPopulate.cs | 5 ++++- osu.Game/Database/OsuDbContext.cs | 24 +++++++++++++++++------- 3 files changed, 21 insertions(+), 16 deletions(-) delete mode 100644 osu.Game/Database/DbContextBase.cs diff --git a/osu.Game/Database/DbContextBase.cs b/osu.Game/Database/DbContextBase.cs deleted file mode 100644 index 93f4ac4c23..0000000000 --- a/osu.Game/Database/DbContextBase.cs +++ /dev/null @@ -1,8 +0,0 @@ -using Microsoft.EntityFrameworkCore; - -namespace osu.Game.Database -{ - public abstract class DbContextBase:DbContext - { - } -} diff --git a/osu.Game/Database/IPopulate.cs b/osu.Game/Database/IPopulate.cs index 24cabf6d5a..b07312f81c 100644 --- a/osu.Game/Database/IPopulate.cs +++ b/osu.Game/Database/IPopulate.cs @@ -1,4 +1,7 @@ -namespace osu.Game.Database +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +namespace osu.Game.Database { public interface IPopulate { diff --git a/osu.Game/Database/OsuDbContext.cs b/osu.Game/Database/OsuDbContext.cs index 9d5111d5d8..3f019a07fa 100644 --- a/osu.Game/Database/OsuDbContext.cs +++ b/osu.Game/Database/OsuDbContext.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; using osu.Framework.Logging; @@ -12,6 +15,11 @@ namespace osu.Game.Database { public class OsuDbContext : DbContext { + public DbSet BeatmapInfo { get; set; } + public DbSet BeatmapSetInfo { get; set; } + public DbSet DatabasedKeyBinding { get; set; } + public DbSet FileInfo { get; set; } + public DbSet RulesetInfo { get; set; } private readonly string connectionString; public OsuDbContext() @@ -24,12 +32,6 @@ namespace osu.Game.Database this.connectionString = connectionString; } - public DbSet BeatmapInfo { get; set; } - public DbSet BeatmapSetInfo { get; set; } - public DbSet DatabasedKeyBinding { get; set; } - public DbSet FileInfo { get; set; } - public DbSet RulesetInfo { get; set; } - protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { base.OnConfiguring(optionsBuilder); @@ -53,20 +55,28 @@ namespace osu.Game.Database private class OsuDbLoggerFactory : ILoggerFactory { + #region Disposal + public void Dispose() { } + #endregion + public ILogger CreateLogger(string categoryName) => new OsuDbLogger(); public void AddProvider(ILoggerProvider provider) => new OsuDbLoggerProvider(); private class OsuDbLoggerProvider : ILoggerProvider { + #region Disposal + public void Dispose() { } + #endregion + public ILogger CreateLogger(string categoryName) => new OsuDbLogger(); } From 0a8b3ad61933b7bb5fdf7f655773c652a866765f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 16 Oct 2017 00:58:56 +0900 Subject: [PATCH 0287/1263] Add one more licence header --- osu.Game/Migrations/20171015101238_Init.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/osu.Game/Migrations/20171015101238_Init.cs b/osu.Game/Migrations/20171015101238_Init.cs index afa83a7fff..61ad66fd25 100644 --- a/osu.Game/Migrations/20171015101238_Init.cs +++ b/osu.Game/Migrations/20171015101238_Init.cs @@ -1,4 +1,7 @@ -using Microsoft.EntityFrameworkCore.Migrations; +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using Microsoft.EntityFrameworkCore.Migrations; namespace osu.Game.Migrations { From 76ee6ed8faec069383f4f598f4d2a3b1eb0579d5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 16 Oct 2017 01:21:17 +0900 Subject: [PATCH 0288/1263] Update CodeFileSanity to ignore migrations folder --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 21c15724e6..7d41a6deb4 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -11,7 +11,7 @@ install: - cmd: git submodule update --init --recursive - cmd: choco install resharper-clt -y - cmd: choco install nvika -y - - cmd: appveyor DownloadFile https://github.com/peppy/CodeFileSanity/releases/download/v0.2.2/CodeFileSanity.exe + - cmd: appveyor DownloadFile https://github.com/peppy/CodeFileSanity/releases/download/v0.2.3/CodeFileSanity.exe before_build: - cmd: CodeFileSanity.exe - cmd: nuget restore From ba4cfd6a2f8c187721c9d6c76b8aaa6c428eec07 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 16 Oct 2017 01:25:58 +0900 Subject: [PATCH 0289/1263] Update appveyor worker image to vs2017 --- appveyor.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/appveyor.yml b/appveyor.yml index 7d41a6deb4..9048428590 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,6 +1,7 @@ # 2017-09-14 clone_depth: 1 version: '{branch}-{build}' +image: Visual Studio 2017 configuration: Debug cache: - C:\ProgramData\chocolatey\bin -> appveyor.yml From e7c7ebdd9d8e4397efeadab5b1e7c077b6fffd42 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 16 Oct 2017 02:15:05 +0900 Subject: [PATCH 0290/1263] Ignore migrations directory for inspections --- osu.sln.DotSettings | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.sln.DotSettings b/osu.sln.DotSettings index c236ce82b0..4eeaa23a32 100644 --- a/osu.sln.DotSettings +++ b/osu.sln.DotSettings @@ -3,6 +3,7 @@ True True True + ExplicitlyExcluded ExplicitlyExcluded SOLUTION HINT From 4a064da30f6349a7d2f327aa2b2769635fe02037 Mon Sep 17 00:00:00 2001 From: TocoToucan Date: Sun, 15 Oct 2017 21:56:33 +0300 Subject: [PATCH 0291/1263] Fix inconsistent lock usage in BeatmapManager --- .../Beatmaps/IO/ImportBeatmapTest.cs | 3 ++- osu.Game/Beatmaps/BeatmapManager.cs | 26 ++++++++++++------- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs b/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs index f2ab00bead..cd9e765e7f 100644 --- a/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs +++ b/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs @@ -138,8 +138,9 @@ namespace osu.Game.Tests.Beatmaps.IO var set = queryBeatmapSets().First(); foreach (BeatmapInfo b in set.Beatmaps) + Assert.IsTrue(set.Beatmaps.Any(c => c.OnlineBeatmapID == b.OnlineBeatmapID)); - Assert.IsTrue(set.Beatmaps.Count > 0); + Assert.IsTrue(set.Beatmaps.Count > 0); var beatmap = store.GetWorkingBeatmap(set.Beatmaps.First(b => b.RulesetID == 0))?.Beatmap; Assert.IsTrue(beatmap?.HitObjects.Count > 0); diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index d364a8fbe4..30da9ceae9 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -59,8 +59,6 @@ namespace osu.Game.Beatmaps private readonly FileStore files; - private readonly OsuDbContext connection; - private readonly RulesetStore rulesets; private readonly BeatmapStore beatmaps; @@ -92,7 +90,6 @@ namespace osu.Game.Beatmaps this.storage = storage; this.files = files; - this.connection = connection; this.rulesets = rulesets; this.api = api; @@ -163,7 +160,7 @@ namespace osu.Game.Beatmaps /// The beatmap to be imported. public BeatmapSetInfo Import(ArchiveReader archiveReader) { - BeatmapSetInfo set = null; + BeatmapSetInfo set; // let's only allow one concurrent import at a time for now. lock (importLock) @@ -181,7 +178,8 @@ namespace osu.Game.Beatmaps // If we have an ID then we already exist in the database. if (beatmapSetInfo.ID != 0) return; - beatmaps.Add(beatmapSetInfo); + lock (beatmaps) + beatmaps.Add(beatmapSetInfo); } /// @@ -272,13 +270,21 @@ namespace osu.Game.Beatmaps /// Delete a beatmap difficulty. /// /// The beatmap difficulty to hide. - public void Hide(BeatmapInfo beatmap) => beatmaps.Hide(beatmap); + public void Hide(BeatmapInfo beatmap) + { + lock (beatmaps) + beatmaps.Hide(beatmap); + } /// /// Restore a beatmap difficulty. /// /// The beatmap difficulty to restore. - public void Restore(BeatmapInfo beatmap) => beatmaps.Restore(beatmap); + public void Restore(BeatmapInfo beatmap) + { + lock (beatmaps) + beatmaps.Restore(beatmap); + } /// /// Returns a to a usable state if it has previously been deleted but not yet purged. @@ -287,7 +293,8 @@ namespace osu.Game.Beatmaps /// The beatmap to restore. public void Undelete(BeatmapSetInfo beatmapSet) { - if (!beatmaps.Undelete(beatmapSet)) return; + lock (beatmaps) + if (!beatmaps.Undelete(beatmapSet)) return; if (!beatmapSet.Protected) files.Reference(beatmapSet.Files.Select(f => f.FileInfo).ToArray()); @@ -361,7 +368,8 @@ namespace osu.Game.Beatmaps /// Results from the provided query. public List QueryBeatmapSets(Func query) { - return beatmaps.QueryAndPopulate(query); + lock (beatmaps) + return beatmaps.QueryAndPopulate(query); } /// From 90592b075768b9d0ad38463b2568e6131ed0e8f8 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Sun, 15 Oct 2017 16:15:35 +0800 Subject: [PATCH 0292/1263] Construct DwarableScore using null weight. --- osu.Game/Overlays/Profile/Sections/RanksSection.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Profile/Sections/RanksSection.cs b/osu.Game/Overlays/Profile/Sections/RanksSection.cs index d7df239003..3b2c9d83ed 100644 --- a/osu.Game/Overlays/Profile/Sections/RanksSection.cs +++ b/osu.Game/Overlays/Profile/Sections/RanksSection.cs @@ -155,7 +155,7 @@ namespace osu.Game.Overlays.Profile.Sections { missing.Hide(); foreach (OnlineScore score in scores) - scoreContainer.Add(new DrawableScore(score, includeWeigth ? Math.Pow(0.95, scoreContainer.Count) : -1) + scoreContainer.Add(new DrawableScore(score, includeWeigth ? Math.Pow(0.95, scoreContainer.Count) : (double?)null) { RelativeSizeAxes = Axes.X, Height = 60, From f837117495ae7263d9040592b49d6ecdca2fcc06 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Sun, 15 Oct 2017 16:30:52 +0800 Subject: [PATCH 0293/1263] Use localisation engine instead of asking current culture directly. --- osu.Game/Overlays/Profile/ProfileHeader.cs | 2 +- osu.Game/Overlays/Profile/Sections/Ranks/DrawableScore.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Profile/ProfileHeader.cs b/osu.Game/Overlays/Profile/ProfileHeader.cs index 973769a114..b033503141 100644 --- a/osu.Game/Overlays/Profile/ProfileHeader.cs +++ b/osu.Game/Overlays/Profile/ProfileHeader.cs @@ -402,7 +402,7 @@ namespace osu.Game.Overlays.Profile scoreText.Add(createScoreText("Ranked Score")); scoreNumberText.Add(createScoreNumberText(user.Statistics.RankedScore.ToString(@"#,0"))); scoreText.Add(createScoreText("Accuracy")); - scoreNumberText.Add(createScoreNumberText($"{user.Statistics.Accuracy.ToString("0.##", CultureInfo.CurrentCulture)}%")); + scoreNumberText.Add(createScoreNumberText($"{user.Statistics.Accuracy.ToString("0.##")}%")); scoreText.Add(createScoreText("Play Count")); scoreNumberText.Add(createScoreNumberText(user.Statistics.PlayCount.ToString(@"#,0"))); scoreText.Add(createScoreText("Total Score")); diff --git a/osu.Game/Overlays/Profile/Sections/Ranks/DrawableScore.cs b/osu.Game/Overlays/Profile/Sections/Ranks/DrawableScore.cs index 52b68e7b30..b2961aad59 100644 --- a/osu.Game/Overlays/Profile/Sections/Ranks/DrawableScore.cs +++ b/osu.Game/Overlays/Profile/Sections/Ranks/DrawableScore.cs @@ -92,7 +92,7 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks { stats.Add(new OsuSpriteText { - Text = $"weighted: {Math.Round(score.PP * weight ?? 0)}pp ({weight.Value.ToString("0%", CultureInfo.CurrentCulture)})", + Current = locale.Format($"weighted: {score.PP * weight ?? 0:0}pp ({weight:0%})"), Anchor = Anchor.TopRight, Origin = Anchor.TopRight, Colour = colour.GrayA, From c2836a8393894212f95e49c8a63b3cdba8e1bc18 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Sun, 15 Oct 2017 16:44:15 +0800 Subject: [PATCH 0294/1263] Use format string for double instead of Math.Round. --- osu.Game/Overlays/BeatmapSet/SuccessRate.cs | 2 +- osu.Game/Overlays/Profile/Sections/Ranks/DrawableScore.cs | 7 ++++--- osu.Game/Screens/Select/BeatmapInfoWedge.cs | 4 ++-- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/osu.Game/Overlays/BeatmapSet/SuccessRate.cs b/osu.Game/Overlays/BeatmapSet/SuccessRate.cs index 26335aac9b..c2e1a7b660 100644 --- a/osu.Game/Overlays/BeatmapSet/SuccessRate.cs +++ b/osu.Game/Overlays/BeatmapSet/SuccessRate.cs @@ -31,7 +31,7 @@ namespace osu.Game.Overlays.BeatmapSet beatmap = value; var rate = (float)beatmap.OnlineInfo.PassCount / beatmap.OnlineInfo.PlayCount; - successPercent.Text = $"{Math.Round(rate * 100)}%"; + successPercent.Text = rate.ToString("P0"); successRate.Length = rate; percentContainer.ResizeWidthTo(successRate.Length, 250, Easing.InOutCubic); diff --git a/osu.Game/Overlays/Profile/Sections/Ranks/DrawableScore.cs b/osu.Game/Overlays/Profile/Sections/Ranks/DrawableScore.cs index b2961aad59..5162c350e8 100644 --- a/osu.Game/Overlays/Profile/Sections/Ranks/DrawableScore.cs +++ b/osu.Game/Overlays/Profile/Sections/Ranks/DrawableScore.cs @@ -79,9 +79,10 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks [BackgroundDependencyLoader] private void load(OsuColour colour, LocalisationEngine locale, BeatmapSetOverlay beatmapSetOverlay) { + double pp = score.PP ?? 0; stats.Add(new OsuSpriteText { - Text = $"{Math.Round(score.PP ?? 0)}pp", + Text = $"{pp:0}pp", Anchor = Anchor.TopRight, Origin = Anchor.TopRight, TextSize = 18, @@ -92,7 +93,7 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks { stats.Add(new OsuSpriteText { - Current = locale.Format($"weighted: {score.PP * weight ?? 0:0}pp ({weight:0%})"), + Text = $"weighted: {pp * weight:0}pp ({weight:P0})", Anchor = Anchor.TopRight, Origin = Anchor.TopRight, Colour = colour.GrayA, @@ -103,7 +104,7 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks stats.Add(new OsuSpriteText { - Text = "accuracy: " + score.Accuracy.ToString("0.00%"), + Text = $"accuracy: {score.Accuracy:P2}", Anchor = Anchor.TopRight, Origin = Anchor.TopRight, Colour = colour.GrayA, diff --git a/osu.Game/Screens/Select/BeatmapInfoWedge.cs b/osu.Game/Screens/Select/BeatmapInfoWedge.cs index 3b26f7bffc..dc3b012328 100644 --- a/osu.Game/Screens/Select/BeatmapInfoWedge.cs +++ b/osu.Game/Screens/Select/BeatmapInfoWedge.cs @@ -232,9 +232,9 @@ namespace osu.Game.Screens.Select double bpmMax = beatmap.ControlPointInfo.BPMMaximum; double bpmMin = beatmap.ControlPointInfo.BPMMinimum; - if (Precision.AlmostEquals(bpmMin, bpmMax)) return Math.Round(bpmMin) + "bpm"; + if (Precision.AlmostEquals(bpmMin, bpmMax)) return $"{bpmMin:0}bpm"; - return Math.Round(bpmMin) + "-" + Math.Round(bpmMax) + "bpm (mostly " + Math.Round(beatmap.ControlPointInfo.BPMMode) + "bpm)"; + return $"{bpmMin:0}-{bpmMax:0}bpm (mostly {beatmap.ControlPointInfo.BPMMode:0}bpm)"; } public class InfoLabel : Container From 5a684f926f6c05c3fb900f9e3c841cbfae5c368f Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Sun, 15 Oct 2017 16:53:30 +0800 Subject: [PATCH 0295/1263] CI fixes. --- osu.Game/Overlays/BeatmapSet/SuccessRate.cs | 1 - osu.Game/Overlays/Profile/ProfileHeader.cs | 3 +-- osu.Game/Overlays/Profile/Sections/Ranks/DrawableScore.cs | 2 -- 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/osu.Game/Overlays/BeatmapSet/SuccessRate.cs b/osu.Game/Overlays/BeatmapSet/SuccessRate.cs index c2e1a7b660..9402ed82f4 100644 --- a/osu.Game/Overlays/BeatmapSet/SuccessRate.cs +++ b/osu.Game/Overlays/BeatmapSet/SuccessRate.cs @@ -1,7 +1,6 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using System; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; diff --git a/osu.Game/Overlays/Profile/ProfileHeader.cs b/osu.Game/Overlays/Profile/ProfileHeader.cs index b033503141..22e34be34c 100644 --- a/osu.Game/Overlays/Profile/ProfileHeader.cs +++ b/osu.Game/Overlays/Profile/ProfileHeader.cs @@ -17,7 +17,6 @@ using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Users; using System.Diagnostics; -using System.Globalization; using System.Collections.Generic; using osu.Framework.Graphics.Cursor; @@ -402,7 +401,7 @@ namespace osu.Game.Overlays.Profile scoreText.Add(createScoreText("Ranked Score")); scoreNumberText.Add(createScoreNumberText(user.Statistics.RankedScore.ToString(@"#,0"))); scoreText.Add(createScoreText("Accuracy")); - scoreNumberText.Add(createScoreNumberText($"{user.Statistics.Accuracy.ToString("0.##")}%")); + scoreNumberText.Add(createScoreNumberText($"{user.Statistics.Accuracy:0.##}%")); scoreText.Add(createScoreText("Play Count")); scoreNumberText.Add(createScoreNumberText(user.Statistics.PlayCount.ToString(@"#,0"))); scoreText.Add(createScoreText("Total Score")); diff --git a/osu.Game/Overlays/Profile/Sections/Ranks/DrawableScore.cs b/osu.Game/Overlays/Profile/Sections/Ranks/DrawableScore.cs index 5162c350e8..af336c2529 100644 --- a/osu.Game/Overlays/Profile/Sections/Ranks/DrawableScore.cs +++ b/osu.Game/Overlays/Profile/Sections/Ranks/DrawableScore.cs @@ -13,9 +13,7 @@ using osu.Game.Rulesets.Mods; using osu.Game.Screens.Select.Leaderboards; using System.Linq; using osu.Framework.Localisation; -using System.Globalization; using osu.Game.Rulesets.Scoring; -using System; using osu.Game.Rulesets.UI; namespace osu.Game.Overlays.Profile.Sections.Ranks From 129cca07043e8874c0990ff90c461f9c4a70a38e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 16 Oct 2017 11:06:19 +0900 Subject: [PATCH 0296/1263] Tidy up context creation --- osu.Game/Database/OsuDbContext.cs | 21 ++++++++++++++++++--- osu.Game/OsuGameBase.cs | 16 +--------------- 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/osu.Game/Database/OsuDbContext.cs b/osu.Game/Database/OsuDbContext.cs index 3f019a07fa..51fabb56fe 100644 --- a/osu.Game/Database/OsuDbContext.cs +++ b/osu.Game/Database/OsuDbContext.cs @@ -22,14 +22,29 @@ namespace osu.Game.Database public DbSet RulesetInfo { get; set; } private readonly string connectionString; - public OsuDbContext() + static OsuDbContext() { - connectionString = "DataSource=:memory:"; + // required to initialise native SQLite libraries on some platforms. + SQLitePCL.Batteries_V2.Init(); } - public OsuDbContext(string connectionString) + /// + /// Create a new OsuDbContext instance. + /// + /// A valid SQLite connection string. If not provided, an in-memory instance will be created. + public OsuDbContext(string connectionString = "DataSource=:memory:") { this.connectionString = connectionString; + + Database.SetCommandTimeout(new TimeSpan(TimeSpan.TicksPerSecond * 10)); + + var connection = Database.GetDbConnection(); + connection.Open(); + using (var cmd = connection.CreateCommand()) + { + cmd.CommandText = "PRAGMA journal_mode=WAL;"; + cmd.ExecuteNonQuery(); + } } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 590007494b..d1e684499c 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -81,21 +81,7 @@ namespace osu.Game protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent) => dependencies = new DependencyContainer(base.CreateLocalDependencies(parent)); - private OsuDbContext createDbContext() - { - SQLitePCL.Batteries.Init(); - var connectionString = Host.Storage.GetDatabaseConnectionString(@"client"); - var context = new OsuDbContext(connectionString); - var connection = context.Database.GetDbConnection(); - connection.Open(); - using (var command = connection.CreateCommand()) - { - command.CommandText = "PRAGMA journal_mode=WAL;"; - command.ExecuteNonQuery(); - } - context.Database.SetCommandTimeout(new TimeSpan(TimeSpan.TicksPerSecond * 10)); - return context; - } + private OsuDbContext createDbContext() => new OsuDbContext(Host.Storage.GetDatabaseConnectionString(@"client")); [BackgroundDependencyLoader] private void load() From 845c5ef39a5bdc86ecd6fff8518043aa021a190f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 16 Oct 2017 11:15:54 +0900 Subject: [PATCH 0297/1263] Update framework --- osu-framework | 2 +- osu.sln.DotSettings | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/osu-framework b/osu-framework index 4489791c8f..f7aab38362 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit 4489791c8f1299ee4cc045454f76bfd34940aabf +Subproject commit f7aab38362a8f510b32340d45d35f8015c3a76b5 diff --git a/osu.sln.DotSettings b/osu.sln.DotSettings index 4eeaa23a32..fdfbf25144 100644 --- a/osu.sln.DotSettings +++ b/osu.sln.DotSettings @@ -194,6 +194,8 @@ IPC LTRB MD5 + NS + OS RGB RNG SHA From e3d31bdd10c2c64a7b6bf122ac39943ee23e7144 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 16 Oct 2017 12:51:46 +0900 Subject: [PATCH 0298/1263] Not implemented instead of incorrect --- osu.Game/Database/OsuDbContext.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/osu.Game/Database/OsuDbContext.cs b/osu.Game/Database/OsuDbContext.cs index 51fabb56fe..5f4e42ed6b 100644 --- a/osu.Game/Database/OsuDbContext.cs +++ b/osu.Game/Database/OsuDbContext.cs @@ -80,7 +80,10 @@ namespace osu.Game.Database public ILogger CreateLogger(string categoryName) => new OsuDbLogger(); - public void AddProvider(ILoggerProvider provider) => new OsuDbLoggerProvider(); + public void AddProvider(ILoggerProvider provider) + { + throw new NotImplementedException(); + } private class OsuDbLoggerProvider : ILoggerProvider { From 56e8c7303ce402400f87b6b42c66f9477b02272c Mon Sep 17 00:00:00 2001 From: TocoToucan Date: Sun, 15 Oct 2017 21:56:33 +0300 Subject: [PATCH 0299/1263] Revert "Fix inconsistent lock usage in BeatmapManager" This reverts commit 4a064da30f6349a7d2f327aa2b2769635fe02037. --- .../Beatmaps/IO/ImportBeatmapTest.cs | 3 +-- osu.Game/Beatmaps/BeatmapManager.cs | 26 +++++++------------ 2 files changed, 10 insertions(+), 19 deletions(-) diff --git a/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs b/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs index cd9e765e7f..f2ab00bead 100644 --- a/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs +++ b/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs @@ -138,9 +138,8 @@ namespace osu.Game.Tests.Beatmaps.IO var set = queryBeatmapSets().First(); foreach (BeatmapInfo b in set.Beatmaps) - Assert.IsTrue(set.Beatmaps.Any(c => c.OnlineBeatmapID == b.OnlineBeatmapID)); - Assert.IsTrue(set.Beatmaps.Count > 0); + Assert.IsTrue(set.Beatmaps.Count > 0); var beatmap = store.GetWorkingBeatmap(set.Beatmaps.First(b => b.RulesetID == 0))?.Beatmap; Assert.IsTrue(beatmap?.HitObjects.Count > 0); diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 30da9ceae9..d364a8fbe4 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -59,6 +59,8 @@ namespace osu.Game.Beatmaps private readonly FileStore files; + private readonly OsuDbContext connection; + private readonly RulesetStore rulesets; private readonly BeatmapStore beatmaps; @@ -90,6 +92,7 @@ namespace osu.Game.Beatmaps this.storage = storage; this.files = files; + this.connection = connection; this.rulesets = rulesets; this.api = api; @@ -160,7 +163,7 @@ namespace osu.Game.Beatmaps /// The beatmap to be imported. public BeatmapSetInfo Import(ArchiveReader archiveReader) { - BeatmapSetInfo set; + BeatmapSetInfo set = null; // let's only allow one concurrent import at a time for now. lock (importLock) @@ -178,8 +181,7 @@ namespace osu.Game.Beatmaps // If we have an ID then we already exist in the database. if (beatmapSetInfo.ID != 0) return; - lock (beatmaps) - beatmaps.Add(beatmapSetInfo); + beatmaps.Add(beatmapSetInfo); } /// @@ -270,21 +272,13 @@ namespace osu.Game.Beatmaps /// Delete a beatmap difficulty. /// /// The beatmap difficulty to hide. - public void Hide(BeatmapInfo beatmap) - { - lock (beatmaps) - beatmaps.Hide(beatmap); - } + public void Hide(BeatmapInfo beatmap) => beatmaps.Hide(beatmap); /// /// Restore a beatmap difficulty. /// /// The beatmap difficulty to restore. - public void Restore(BeatmapInfo beatmap) - { - lock (beatmaps) - beatmaps.Restore(beatmap); - } + public void Restore(BeatmapInfo beatmap) => beatmaps.Restore(beatmap); /// /// Returns a to a usable state if it has previously been deleted but not yet purged. @@ -293,8 +287,7 @@ namespace osu.Game.Beatmaps /// The beatmap to restore. public void Undelete(BeatmapSetInfo beatmapSet) { - lock (beatmaps) - if (!beatmaps.Undelete(beatmapSet)) return; + if (!beatmaps.Undelete(beatmapSet)) return; if (!beatmapSet.Protected) files.Reference(beatmapSet.Files.Select(f => f.FileInfo).ToArray()); @@ -368,8 +361,7 @@ namespace osu.Game.Beatmaps /// Results from the provided query. public List QueryBeatmapSets(Func query) { - lock (beatmaps) - return beatmaps.QueryAndPopulate(query); + return beatmaps.QueryAndPopulate(query); } /// From 04e5f764a34e807db1a25de355bd79709f3aac74 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 16 Oct 2017 12:55:36 +0900 Subject: [PATCH 0300/1263] Revert "Fix removal of FileInfo, BeatmapMetadata, BeatmapDifficulty objects" --- osu.Game/Beatmaps/BeatmapDifficulty.cs | 1 - osu.Game/Beatmaps/BeatmapMetadata.cs | 1 - osu.Game/Beatmaps/BeatmapStore.cs | 5 - ...5101238_Init.cs => 20171014052545_Init.cs} | 230 +++++++++--------- ...ner.cs => 20171014052545_Init.designer.cs} | 56 ++--- .../Migrations/OsuDbContextModelSnapshot.cs | 54 ++-- osu.Game/osu.Game.csproj | 7 +- 7 files changed, 168 insertions(+), 186 deletions(-) rename osu.Game/Migrations/{20171015101238_Init.cs => 20171014052545_Init.cs} (91%) rename osu.Game/Migrations/{20171015101238_Init.Designer.cs => 20171014052545_Init.designer.cs} (85%) diff --git a/osu.Game/Beatmaps/BeatmapDifficulty.cs b/osu.Game/Beatmaps/BeatmapDifficulty.cs index 0c2299e5e6..25e212f3c5 100644 --- a/osu.Game/Beatmaps/BeatmapDifficulty.cs +++ b/osu.Game/Beatmaps/BeatmapDifficulty.cs @@ -14,7 +14,6 @@ namespace osu.Game.Beatmaps [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int ID { get; set; } - public int BeatmapInfoId { get; set; } public float DrainRate { get; set; } = DEFAULT_DIFFICULTY; public float CircleSize { get; set; } = DEFAULT_DIFFICULTY; public float OverallDifficulty { get; set; } = DEFAULT_DIFFICULTY; diff --git a/osu.Game/Beatmaps/BeatmapMetadata.cs b/osu.Game/Beatmaps/BeatmapMetadata.cs index 5e1a77a5bf..5e47d6c13d 100644 --- a/osu.Game/Beatmaps/BeatmapMetadata.cs +++ b/osu.Game/Beatmaps/BeatmapMetadata.cs @@ -15,7 +15,6 @@ namespace osu.Game.Beatmaps [NotMapped] public int? OnlineBeatmapSetID { get; set; } - public int BeatmapSetInfoId { get; set; } public string Title { get; set; } public string TitleUnicode { get; set; } diff --git a/osu.Game/Beatmaps/BeatmapStore.cs b/osu.Game/Beatmaps/BeatmapStore.cs index 19e30a23ce..0be502132f 100644 --- a/osu.Game/Beatmaps/BeatmapStore.cs +++ b/osu.Game/Beatmaps/BeatmapStore.cs @@ -73,11 +73,6 @@ namespace osu.Game.Beatmaps if (beatmapSet.DeletePending) return false; beatmapSet.DeletePending = true; - - // We can't use one to one relationship with its cascade delete because FileInfo can be used not only inside of BeatmapSetFileInfo - var files = beatmapSet.Files.Select(beatmapSetFileInfo => beatmapSetFileInfo.FileInfo); - Connection.FileInfo.RemoveRange(files); - Connection.BeatmapSetInfo.Remove(beatmapSet); Connection.SaveChanges(); diff --git a/osu.Game/Migrations/20171015101238_Init.cs b/osu.Game/Migrations/20171014052545_Init.cs similarity index 91% rename from osu.Game/Migrations/20171015101238_Init.cs rename to osu.Game/Migrations/20171014052545_Init.cs index 61ad66fd25..6792f79e3d 100644 --- a/osu.Game/Migrations/20171015101238_Init.cs +++ b/osu.Game/Migrations/20171014052545_Init.cs @@ -10,18 +10,43 @@ namespace osu.Game.Migrations protected override void Up(MigrationBuilder migrationBuilder) { migrationBuilder.CreateTable( - name: "BeatmapSetInfo", + name: "BeatmapDifficulty", columns: table => new { ID = table.Column(type: "INTEGER", nullable: false) .Annotation("Sqlite:Autoincrement", true), - DeletePending = table.Column(type: "INTEGER", nullable: false), - Hash = table.Column(type: "TEXT", nullable: true), - Protected = table.Column(type: "INTEGER", nullable: false) + ApproachRate = table.Column(type: "REAL", nullable: false), + CircleSize = table.Column(type: "REAL", nullable: false), + DrainRate = table.Column(type: "REAL", nullable: false), + OverallDifficulty = table.Column(type: "REAL", nullable: false), + SliderMultiplier = table.Column(type: "REAL", nullable: false), + SliderTickRate = table.Column(type: "REAL", nullable: false) }, constraints: table => { - table.PrimaryKey("PK_BeatmapSetInfo", x => x.ID); + table.PrimaryKey("PK_BeatmapDifficulty", x => x.ID); + }); + + migrationBuilder.CreateTable( + name: "BeatmapMetadata", + columns: table => new + { + ID = table.Column(type: "INTEGER", nullable: false) + .Annotation("Sqlite:Autoincrement", true), + Artist = table.Column(type: "TEXT", nullable: true), + ArtistUnicode = table.Column(type: "TEXT", nullable: true), + AudioFile = table.Column(type: "TEXT", nullable: true), + Author = table.Column(type: "TEXT", nullable: true), + BackgroundFile = table.Column(type: "TEXT", nullable: true), + PreviewTime = table.Column(type: "INTEGER", nullable: false), + Source = table.Column(type: "TEXT", nullable: true), + Tags = table.Column(type: "TEXT", nullable: true), + Title = table.Column(type: "TEXT", nullable: true), + TitleUnicode = table.Column(type: "TEXT", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_BeatmapMetadata", x => x.ID); }); migrationBuilder.CreateTable( @@ -70,32 +95,83 @@ namespace osu.Game.Migrations }); migrationBuilder.CreateTable( - name: "BeatmapMetadata", + name: "BeatmapSetInfo", columns: table => new { ID = table.Column(type: "INTEGER", nullable: false) .Annotation("Sqlite:Autoincrement", true), - Artist = table.Column(type: "TEXT", nullable: true), - ArtistUnicode = table.Column(type: "TEXT", nullable: true), - AudioFile = table.Column(type: "TEXT", nullable: true), - Author = table.Column(type: "TEXT", nullable: true), - BackgroundFile = table.Column(type: "TEXT", nullable: true), - BeatmapSetInfoId = table.Column(type: "INTEGER", nullable: false), - PreviewTime = table.Column(type: "INTEGER", nullable: false), - Source = table.Column(type: "TEXT", nullable: true), - Tags = table.Column(type: "TEXT", nullable: true), - Title = table.Column(type: "TEXT", nullable: true), - TitleUnicode = table.Column(type: "TEXT", nullable: true) + DeletePending = table.Column(type: "INTEGER", nullable: false), + Hash = table.Column(type: "TEXT", nullable: true), + MetadataID = table.Column(type: "INTEGER", nullable: true), + Protected = table.Column(type: "INTEGER", nullable: false) }, constraints: table => { - table.PrimaryKey("PK_BeatmapMetadata", x => x.ID); + table.PrimaryKey("PK_BeatmapSetInfo", x => x.ID); table.ForeignKey( - name: "FK_BeatmapMetadata_BeatmapSetInfo_BeatmapSetInfoId", - column: x => x.BeatmapSetInfoId, + name: "FK_BeatmapSetInfo_BeatmapMetadata_MetadataID", + column: x => x.MetadataID, + principalTable: "BeatmapMetadata", + principalColumn: "ID", + onDelete: ReferentialAction.Restrict); + }); + + migrationBuilder.CreateTable( + name: "BeatmapInfo", + columns: table => new + { + ID = table.Column(type: "INTEGER", nullable: false) + .Annotation("Sqlite:Autoincrement", true), + AudioLeadIn = table.Column(type: "INTEGER", nullable: false), + BaseDifficultyID = table.Column(type: "INTEGER", nullable: false), + BeatDivisor = table.Column(type: "INTEGER", nullable: false), + BeatmapSetInfoID = table.Column(type: "INTEGER", nullable: false), + Countdown = table.Column(type: "INTEGER", nullable: false), + DifficultyID = table.Column(type: "INTEGER", nullable: false), + DistanceSpacing = table.Column(type: "REAL", nullable: false), + GridSize = table.Column(type: "INTEGER", nullable: false), + Hash = table.Column(type: "TEXT", nullable: true), + Hidden = table.Column(type: "INTEGER", nullable: false), + LetterboxInBreaks = table.Column(type: "INTEGER", nullable: false), + MD5Hash = table.Column(type: "TEXT", nullable: true), + MetadataID = table.Column(type: "INTEGER", nullable: true), + Path = table.Column(type: "TEXT", nullable: true), + RulesetID = table.Column(type: "INTEGER", nullable: false), + SpecialStyle = table.Column(type: "INTEGER", nullable: false), + StackLeniency = table.Column(type: "REAL", nullable: false), + StarDifficulty = table.Column(type: "REAL", nullable: false), + StoredBookmarks = table.Column(type: "TEXT", nullable: true), + TimelineZoom = table.Column(type: "REAL", nullable: false), + Version = table.Column(type: "TEXT", nullable: true), + WidescreenStoryboard = table.Column(type: "INTEGER", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_BeatmapInfo", x => x.ID); + table.ForeignKey( + name: "FK_BeatmapInfo_BeatmapSetInfo_BeatmapSetInfoID", + column: x => x.BeatmapSetInfoID, principalTable: "BeatmapSetInfo", principalColumn: "ID", onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_BeatmapInfo_BeatmapDifficulty_DifficultyID", + column: x => x.DifficultyID, + principalTable: "BeatmapDifficulty", + principalColumn: "ID", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_BeatmapInfo_BeatmapMetadata_MetadataID", + column: x => x.MetadataID, + principalTable: "BeatmapMetadata", + principalColumn: "ID", + onDelete: ReferentialAction.Restrict); + table.ForeignKey( + name: "FK_BeatmapInfo_RulesetInfo_RulesetID", + column: x => x.RulesetID, + principalTable: "RulesetInfo", + principalColumn: "ID", + onDelete: ReferentialAction.Cascade); }); migrationBuilder.CreateTable( @@ -125,93 +201,16 @@ namespace osu.Game.Migrations onDelete: ReferentialAction.Cascade); }); - migrationBuilder.CreateTable( - name: "BeatmapInfo", - columns: table => new - { - ID = table.Column(type: "INTEGER", nullable: false) - .Annotation("Sqlite:Autoincrement", true), - AudioLeadIn = table.Column(type: "INTEGER", nullable: false), - BaseDifficultyID = table.Column(type: "INTEGER", nullable: false), - BeatDivisor = table.Column(type: "INTEGER", nullable: false), - BeatmapSetInfoID = table.Column(type: "INTEGER", nullable: false), - Countdown = table.Column(type: "INTEGER", nullable: false), - DistanceSpacing = table.Column(type: "REAL", nullable: false), - GridSize = table.Column(type: "INTEGER", nullable: false), - Hash = table.Column(type: "TEXT", nullable: true), - Hidden = table.Column(type: "INTEGER", nullable: false), - LetterboxInBreaks = table.Column(type: "INTEGER", nullable: false), - MD5Hash = table.Column(type: "TEXT", nullable: true), - MetadataID = table.Column(type: "INTEGER", nullable: true), - Path = table.Column(type: "TEXT", nullable: true), - RulesetID = table.Column(type: "INTEGER", nullable: false), - SpecialStyle = table.Column(type: "INTEGER", nullable: false), - StackLeniency = table.Column(type: "REAL", nullable: false), - StarDifficulty = table.Column(type: "REAL", nullable: false), - StoredBookmarks = table.Column(type: "TEXT", nullable: true), - TimelineZoom = table.Column(type: "REAL", nullable: false), - Version = table.Column(type: "TEXT", nullable: true), - WidescreenStoryboard = table.Column(type: "INTEGER", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_BeatmapInfo", x => x.ID); - table.ForeignKey( - name: "FK_BeatmapInfo_BeatmapSetInfo_BeatmapSetInfoID", - column: x => x.BeatmapSetInfoID, - principalTable: "BeatmapSetInfo", - principalColumn: "ID", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "FK_BeatmapInfo_BeatmapMetadata_MetadataID", - column: x => x.MetadataID, - principalTable: "BeatmapMetadata", - principalColumn: "ID", - onDelete: ReferentialAction.Restrict); - table.ForeignKey( - name: "FK_BeatmapInfo_RulesetInfo_RulesetID", - column: x => x.RulesetID, - principalTable: "RulesetInfo", - principalColumn: "ID", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "BeatmapDifficulty", - columns: table => new - { - ID = table.Column(type: "INTEGER", nullable: false) - .Annotation("Sqlite:Autoincrement", true), - ApproachRate = table.Column(type: "REAL", nullable: false), - BeatmapInfoId = table.Column(type: "INTEGER", nullable: false), - CircleSize = table.Column(type: "REAL", nullable: false), - DrainRate = table.Column(type: "REAL", nullable: false), - OverallDifficulty = table.Column(type: "REAL", nullable: false), - SliderMultiplier = table.Column(type: "REAL", nullable: false), - SliderTickRate = table.Column(type: "REAL", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_BeatmapDifficulty", x => x.ID); - table.ForeignKey( - name: "FK_BeatmapDifficulty_BeatmapInfo_BeatmapInfoId", - column: x => x.BeatmapInfoId, - principalTable: "BeatmapInfo", - principalColumn: "ID", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateIndex( - name: "IX_BeatmapDifficulty_BeatmapInfoId", - table: "BeatmapDifficulty", - column: "BeatmapInfoId", - unique: true); - migrationBuilder.CreateIndex( name: "IX_BeatmapInfo_BeatmapSetInfoID", table: "BeatmapInfo", column: "BeatmapSetInfoID"); + migrationBuilder.CreateIndex( + name: "IX_BeatmapInfo_DifficultyID", + table: "BeatmapInfo", + column: "DifficultyID"); + migrationBuilder.CreateIndex( name: "IX_BeatmapInfo_MD5Hash", table: "BeatmapInfo", @@ -227,12 +226,6 @@ namespace osu.Game.Migrations table: "BeatmapInfo", column: "RulesetID"); - migrationBuilder.CreateIndex( - name: "IX_BeatmapMetadata_BeatmapSetInfoId", - table: "BeatmapMetadata", - column: "BeatmapSetInfoId", - unique: true); - migrationBuilder.CreateIndex( name: "IX_BeatmapSetFileInfo_BeatmapSetInfoID", table: "BeatmapSetFileInfo", @@ -248,6 +241,11 @@ namespace osu.Game.Migrations table: "BeatmapSetInfo", column: "DeletePending"); + migrationBuilder.CreateIndex( + name: "IX_BeatmapSetInfo_MetadataID", + table: "BeatmapSetInfo", + column: "MetadataID"); + migrationBuilder.CreateIndex( name: "IX_FileInfo_Hash", table: "FileInfo", @@ -290,7 +288,7 @@ namespace osu.Game.Migrations protected override void Down(MigrationBuilder migrationBuilder) { migrationBuilder.DropTable( - name: "BeatmapDifficulty"); + name: "BeatmapInfo"); migrationBuilder.DropTable( name: "BeatmapSetFileInfo"); @@ -299,19 +297,19 @@ namespace osu.Game.Migrations name: "KeyBinding"); migrationBuilder.DropTable( - name: "BeatmapInfo"); - - migrationBuilder.DropTable( - name: "FileInfo"); - - migrationBuilder.DropTable( - name: "BeatmapMetadata"); + name: "BeatmapDifficulty"); migrationBuilder.DropTable( name: "RulesetInfo"); migrationBuilder.DropTable( name: "BeatmapSetInfo"); + + migrationBuilder.DropTable( + name: "FileInfo"); + + migrationBuilder.DropTable( + name: "BeatmapMetadata"); } } } diff --git a/osu.Game/Migrations/20171015101238_Init.Designer.cs b/osu.Game/Migrations/20171014052545_Init.designer.cs similarity index 85% rename from osu.Game/Migrations/20171015101238_Init.Designer.cs rename to osu.Game/Migrations/20171014052545_Init.designer.cs index 2d37d1d07f..f151131882 100644 --- a/osu.Game/Migrations/20171015101238_Init.Designer.cs +++ b/osu.Game/Migrations/20171014052545_Init.designer.cs @@ -1,4 +1,7 @@ -// +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +// using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata; @@ -10,7 +13,7 @@ using System; namespace osu.Game.Migrations { [DbContext(typeof(OsuDbContext))] - [Migration("20171015101238_Init")] + [Migration("20171014052545_Init")] partial class Init { protected override void BuildTargetModel(ModelBuilder modelBuilder) @@ -26,8 +29,6 @@ namespace osu.Game.Migrations b.Property("ApproachRate"); - b.Property("BeatmapInfoId"); - b.Property("CircleSize"); b.Property("DrainRate"); @@ -40,9 +41,6 @@ namespace osu.Game.Migrations b.HasKey("ID"); - b.HasIndex("BeatmapInfoId") - .IsUnique(); - b.ToTable("BeatmapDifficulty"); }); @@ -61,6 +59,8 @@ namespace osu.Game.Migrations b.Property("Countdown"); + b.Property("DifficultyID"); + b.Property("DistanceSpacing"); b.Property("GridSize"); @@ -97,6 +97,8 @@ namespace osu.Game.Migrations b.HasIndex("BeatmapSetInfoID"); + b.HasIndex("DifficultyID"); + b.HasIndex("MD5Hash"); b.HasIndex("MetadataID"); @@ -117,13 +119,10 @@ namespace osu.Game.Migrations b.Property("AudioFile"); - b.Property("AuthorString") - .HasColumnName("Author"); + b.Property("Author"); b.Property("BackgroundFile"); - b.Property("BeatmapSetInfoId"); - b.Property("PreviewTime"); b.Property("Source"); @@ -136,9 +135,6 @@ namespace osu.Game.Migrations b.HasKey("ID"); - b.HasIndex("BeatmapSetInfoId") - .IsUnique(); - b.ToTable("BeatmapMetadata"); }); @@ -172,12 +168,16 @@ namespace osu.Game.Migrations b.Property("Hash"); + b.Property("MetadataID"); + b.Property("Protected"); b.HasKey("ID"); b.HasIndex("DeletePending"); + b.HasIndex("MetadataID"); + b.ToTable("BeatmapSetInfo"); }); @@ -248,14 +248,6 @@ namespace osu.Game.Migrations b.ToTable("RulesetInfo"); }); - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapDifficulty", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapInfo") - .WithOne("Difficulty") - .HasForeignKey("osu.Game.Beatmaps.BeatmapDifficulty", "BeatmapInfoId") - .OnDelete(DeleteBehavior.Cascade); - }); - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b => { b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo", "BeatmapSet") @@ -263,6 +255,11 @@ namespace osu.Game.Migrations .HasForeignKey("BeatmapSetInfoID") .OnDelete(DeleteBehavior.Cascade); + b.HasOne("osu.Game.Beatmaps.BeatmapDifficulty", "Difficulty") + .WithMany() + .HasForeignKey("DifficultyID") + .OnDelete(DeleteBehavior.Cascade); + b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata") .WithMany() .HasForeignKey("MetadataID"); @@ -273,14 +270,6 @@ namespace osu.Game.Migrations .OnDelete(DeleteBehavior.Cascade); }); - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapMetadata", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo") - .WithOne("Metadata") - .HasForeignKey("osu.Game.Beatmaps.BeatmapMetadata", "BeatmapSetInfoId") - .OnDelete(DeleteBehavior.Cascade); - }); - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b => { b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo") @@ -293,6 +282,13 @@ namespace osu.Game.Migrations .HasForeignKey("FileInfoID") .OnDelete(DeleteBehavior.Cascade); }); + + modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b => + { + b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata") + .WithMany() + .HasForeignKey("MetadataID"); + }); #pragma warning restore 612, 618 } } diff --git a/osu.Game/Migrations/OsuDbContextModelSnapshot.cs b/osu.Game/Migrations/OsuDbContextModelSnapshot.cs index 162119408b..f3a6c5a520 100644 --- a/osu.Game/Migrations/OsuDbContextModelSnapshot.cs +++ b/osu.Game/Migrations/OsuDbContextModelSnapshot.cs @@ -1,4 +1,7 @@ -// +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +// using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using osu.Game.Database; @@ -21,8 +24,6 @@ namespace osu.Game.Migrations b.Property("ApproachRate"); - b.Property("BeatmapInfoId"); - b.Property("CircleSize"); b.Property("DrainRate"); @@ -35,9 +36,6 @@ namespace osu.Game.Migrations b.HasKey("ID"); - b.HasIndex("BeatmapInfoId") - .IsUnique(); - b.ToTable("BeatmapDifficulty"); }); @@ -56,6 +54,8 @@ namespace osu.Game.Migrations b.Property("Countdown"); + b.Property("DifficultyID"); + b.Property("DistanceSpacing"); b.Property("GridSize"); @@ -92,6 +92,8 @@ namespace osu.Game.Migrations b.HasIndex("BeatmapSetInfoID"); + b.HasIndex("DifficultyID"); + b.HasIndex("MD5Hash"); b.HasIndex("MetadataID"); @@ -112,13 +114,10 @@ namespace osu.Game.Migrations b.Property("AudioFile"); - b.Property("AuthorString") - .HasColumnName("Author"); + b.Property("Author"); b.Property("BackgroundFile"); - b.Property("BeatmapSetInfoId"); - b.Property("PreviewTime"); b.Property("Source"); @@ -131,9 +130,6 @@ namespace osu.Game.Migrations b.HasKey("ID"); - b.HasIndex("BeatmapSetInfoId") - .IsUnique(); - b.ToTable("BeatmapMetadata"); }); @@ -167,12 +163,16 @@ namespace osu.Game.Migrations b.Property("Hash"); + b.Property("MetadataID"); + b.Property("Protected"); b.HasKey("ID"); b.HasIndex("DeletePending"); + b.HasIndex("MetadataID"); + b.ToTable("BeatmapSetInfo"); }); @@ -243,14 +243,6 @@ namespace osu.Game.Migrations b.ToTable("RulesetInfo"); }); - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapDifficulty", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapInfo") - .WithOne("Difficulty") - .HasForeignKey("osu.Game.Beatmaps.BeatmapDifficulty", "BeatmapInfoId") - .OnDelete(DeleteBehavior.Cascade); - }); - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b => { b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo", "BeatmapSet") @@ -258,6 +250,11 @@ namespace osu.Game.Migrations .HasForeignKey("BeatmapSetInfoID") .OnDelete(DeleteBehavior.Cascade); + b.HasOne("osu.Game.Beatmaps.BeatmapDifficulty", "Difficulty") + .WithMany() + .HasForeignKey("DifficultyID") + .OnDelete(DeleteBehavior.Cascade); + b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata") .WithMany() .HasForeignKey("MetadataID"); @@ -268,14 +265,6 @@ namespace osu.Game.Migrations .OnDelete(DeleteBehavior.Cascade); }); - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapMetadata", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo") - .WithOne("Metadata") - .HasForeignKey("osu.Game.Beatmaps.BeatmapMetadata", "BeatmapSetInfoId") - .OnDelete(DeleteBehavior.Cascade); - }); - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b => { b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo") @@ -288,6 +277,13 @@ namespace osu.Game.Migrations .HasForeignKey("FileInfoID") .OnDelete(DeleteBehavior.Cascade); }); + + modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b => + { + b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata") + .WithMany() + .HasForeignKey("MetadataID"); + }); #pragma warning restore 612, 618 } } diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 404576e832..03ca32539c 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -23,7 +23,6 @@ LocalIntranet v4.6.1 true - true publish\ true Disk @@ -279,9 +278,9 @@ - - - 20171015101238_Init.cs + + + 20171014052545_Init.cs From 8a0b184dd6c5321789d8428f00f2fd7b0a1cddea Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 16 Oct 2017 12:56:58 +0900 Subject: [PATCH 0301/1263] Revert "Return back DatabaseBackedStore's query and populate functions" This reverts commit 7cf5d63cd32bde05ee0bcbc262e5dac7595036f4. --- osu.Game/Beatmaps/BeatmapInfo.cs | 9 +--- osu.Game/Beatmaps/BeatmapManager.cs | 46 +++++++------------ osu.Game/Beatmaps/BeatmapSetInfo.cs | 24 +--------- osu.Game/Beatmaps/BeatmapStore.cs | 42 +++++++++++++++++ osu.Game/Database/DatabaseBackedStore.cs | 41 ----------------- osu.Game/Database/IPopulate.cs | 10 ---- osu.Game/Rulesets/RulesetStore.cs | 19 ++++++-- .../Tests/Visual/TestCasePlaySongSelect.cs | 6 +-- osu.Game/Tests/Visual/TestCasePlayer.cs | 2 +- osu.Game/osu.Game.csproj | 1 - 10 files changed, 80 insertions(+), 120 deletions(-) delete mode 100644 osu.Game/Database/IPopulate.cs diff --git a/osu.Game/Beatmaps/BeatmapInfo.cs b/osu.Game/Beatmaps/BeatmapInfo.cs index 621bc59786..c1516f17c9 100644 --- a/osu.Game/Beatmaps/BeatmapInfo.cs +++ b/osu.Game/Beatmaps/BeatmapInfo.cs @@ -6,13 +6,12 @@ using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; using System.Linq; using Newtonsoft.Json; -using osu.Game.Database; using osu.Game.IO.Serialization; using osu.Game.Rulesets; namespace osu.Game.Beatmaps { - public class BeatmapInfo : IEquatable, IJsonSerializable, IPopulate + public class BeatmapInfo : IEquatable, IJsonSerializable { [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int ID { get; set; } @@ -125,11 +124,5 @@ namespace osu.Game.Beatmaps public bool BackgroundEquals(BeatmapInfo other) => other != null && BeatmapSet != null && other.BeatmapSet != null && BeatmapSet.Hash == other.BeatmapSet.Hash && (Metadata ?? BeatmapSet.Metadata).BackgroundFile == (other.Metadata ?? other.BeatmapSet.Metadata).BackgroundFile; - - public void Populate(OsuDbContext connection) - { - var entry = connection.Entry(this); - entry.Reference(nameof(Difficulty)); - } } } diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index d364a8fbe4..955c6f4b17 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; +using System.Linq.Expressions; using System.Threading.Tasks; using Ionic.Zip; using osu.Framework.Audio.Track; @@ -259,13 +260,10 @@ namespace osu.Game.Beatmaps /// The beatmap set to delete. public void Delete(BeatmapSetInfo beatmapSet) { - lock (beatmaps) - { - if (!beatmaps.Delete(beatmapSet)) return; + if (!beatmaps.Delete(beatmapSet)) return; - if (!beatmapSet.Protected) - files.Dereference(beatmapSet.Files.Select(f => f.FileInfo).ToArray()); - } + if (!beatmapSet.Protected) + files.Dereference(beatmapSet.Files.Select(f => f.FileInfo).ToArray()); } /// @@ -304,9 +302,6 @@ namespace osu.Game.Beatmaps if (beatmapInfo == null || beatmapInfo == DefaultBeatmap?.BeatmapInfo) return DefaultBeatmap; - lock (beatmaps) - beatmaps.Populate(beatmapInfo); - if (beatmapInfo.BeatmapSet == null) throw new InvalidOperationException($@"Beatmap set {beatmapInfo.BeatmapSetInfoID} is not in the local database."); @@ -338,10 +333,7 @@ namespace osu.Game.Beatmaps { lock (beatmaps) { - BeatmapSetInfo set = beatmaps.Query(query).FirstOrDefault(); - - if (set != null) - beatmaps.Populate(set); + BeatmapSetInfo set = beatmaps.QueryBeatmapSet(query); return set; } @@ -359,9 +351,9 @@ namespace osu.Game.Beatmaps /// /// The query. /// Results from the provided query. - public List QueryBeatmapSets(Func query) + public List QueryBeatmapSets(Expression> query) { - return beatmaps.QueryAndPopulate(query); + return beatmaps.QueryBeatmapSets(query); } /// @@ -371,15 +363,9 @@ namespace osu.Game.Beatmaps /// The first result for the provided query, or null if no results were found. public BeatmapInfo QueryBeatmap(Func query) { - lock (beatmaps) - { - BeatmapInfo set = beatmaps.Query(query).FirstOrDefault(); + BeatmapInfo set = beatmaps.QueryBeatmap(query); - if (set != null) - beatmaps.Populate(set); - - return set; - } + return set; } /// @@ -387,9 +373,9 @@ namespace osu.Game.Beatmaps /// /// The query. /// Results from the provided query. - public List QueryBeatmaps(Func query) + public List QueryBeatmaps(Expression> query) { - lock (beatmaps) return beatmaps.Query(query); + lock (beatmaps) return beatmaps.QueryBeatmaps(query); } /// @@ -428,7 +414,7 @@ namespace osu.Game.Beatmaps // check if this beatmap has already been imported and exit early if so. BeatmapSetInfo beatmapSet; lock (beatmaps) - beatmapSet = beatmaps.QueryAndPopulate(b => b.Hash == hash).FirstOrDefault(); + beatmapSet = beatmaps.QueryBeatmapSet(b => b.Hash == hash); if (beatmapSet != null) { @@ -492,8 +478,8 @@ namespace osu.Game.Beatmaps beatmap.BeatmapInfo.Metadata = null; // TODO: this should be done in a better place once we actually need to dynamically update it. - beatmap.BeatmapInfo.Ruleset = rulesets.Query(r => r.ID == beatmap.BeatmapInfo.RulesetID).FirstOrDefault(); - beatmap.BeatmapInfo.StarDifficulty = rulesets.Query(r => r.ID == beatmap.BeatmapInfo.RulesetID).FirstOrDefault()?.CreateInstance()?.CreateDifficultyCalculator(beatmap) + beatmap.BeatmapInfo.Ruleset = rulesets.QueryRulesetInfo(r => r.ID == beatmap.BeatmapInfo.RulesetID); + beatmap.BeatmapInfo.StarDifficulty = rulesets.QueryRulesetInfo(r => r.ID == beatmap.BeatmapInfo.RulesetID)?.CreateInstance()?.CreateDifficultyCalculator(beatmap) .Calculate() ?? 0; beatmapSet.Beatmaps.Add(beatmap.BeatmapInfo); @@ -507,11 +493,11 @@ namespace osu.Game.Beatmaps /// Returns a list of all usable s. /// /// A list of available . - public List GetAllUsableBeatmapSets(bool populate = true) + public List GetAllUsableBeatmapSets() { lock (beatmaps) { - return populate ? beatmaps.QueryAndPopulate(b => !b.DeletePending) : beatmaps.Query(b => !b.DeletePending); + return beatmaps.QueryBeatmapSets(b => !b.DeletePending); } } diff --git a/osu.Game/Beatmaps/BeatmapSetInfo.cs b/osu.Game/Beatmaps/BeatmapSetInfo.cs index ddbc5d0dfb..404add2fa5 100644 --- a/osu.Game/Beatmaps/BeatmapSetInfo.cs +++ b/osu.Game/Beatmaps/BeatmapSetInfo.cs @@ -4,12 +4,10 @@ using System.Collections.Generic; using System.ComponentModel.DataAnnotations.Schema; using System.Linq; -using osu.Game.Database; -using osu.Game.IO; namespace osu.Game.Beatmaps { - public class BeatmapSetInfo : IPopulate + public class BeatmapSetInfo { [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int ID { get; set; } @@ -36,25 +34,5 @@ namespace osu.Game.Beatmaps public List Files { get; set; } public bool Protected { get; set; } - - public void Populate(OsuDbContext connection) - { - var entry = connection.Entry(this); - entry.Collection(nameof(Beatmaps)).Load(); - entry.Reference(nameof(Metadata)).Load(); - entry.Collection(nameof(Files)).Load(); - - foreach (var beatmap in Beatmaps) - { - var beatmapEntry = connection.Entry(beatmap); - beatmapEntry.Reference(nameof(beatmap.Difficulty)).Load(); - } - - foreach (var file in Files) - { - var fileEntry = connection.Entry(file); - fileEntry.Reference(nameof(file.FileInfo)).Load(); - } - } } } diff --git a/osu.Game/Beatmaps/BeatmapStore.cs b/osu.Game/Beatmaps/BeatmapStore.cs index 0be502132f..9c5a1a9dfc 100644 --- a/osu.Game/Beatmaps/BeatmapStore.cs +++ b/osu.Game/Beatmaps/BeatmapStore.cs @@ -2,7 +2,9 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; +using System.Collections.Generic; using System.Linq; +using System.Linq.Expressions; using Microsoft.EntityFrameworkCore; using osu.Game.Database; @@ -132,5 +134,45 @@ namespace osu.Game.Beatmaps { Connection.BeatmapSetInfo.RemoveRange(Connection.BeatmapSetInfo.Where(b => b.DeletePending && !b.Protected)); } + + public BeatmapSetInfo QueryBeatmapSet(Func query) + { + return Connection.BeatmapSetInfo + .Include(b => b.Metadata) + .Include(b => b.Beatmaps).ThenInclude(b => b.Ruleset) + .Include(b => b.Beatmaps).ThenInclude(b => b.Difficulty) + .Include(b => b.Files).ThenInclude(f => f.FileInfo) + .FirstOrDefault(query); + } + + public List QueryBeatmapSets(Expression> query) + { + return Connection.BeatmapSetInfo + .Include(b => b.Metadata) + .Include(b => b.Beatmaps).ThenInclude(b => b.Ruleset) + .Include(b => b.Beatmaps).ThenInclude(b => b.Difficulty) + .Include(b => b.Files).ThenInclude(f => f.FileInfo) + .Where(query).ToList(); + } + + public BeatmapInfo QueryBeatmap(Func query) + { + return Connection.BeatmapInfo + .Include(b => b.BeatmapSet) + .Include(b => b.Metadata) + .Include(b => b.Ruleset) + .Include(b => b.Difficulty) + .FirstOrDefault(query); + } + + public List QueryBeatmaps(Expression> query) + { + return Connection.BeatmapInfo + .Include(b => b.BeatmapSet) + .Include(b => b.Metadata) + .Include(b => b.Ruleset) + .Include(b => b.Difficulty) + .Where(query).ToList(); + } } } diff --git a/osu.Game/Database/DatabaseBackedStore.cs b/osu.Game/Database/DatabaseBackedStore.cs index fd891ca825..f4b6a866dc 100644 --- a/osu.Game/Database/DatabaseBackedStore.cs +++ b/osu.Game/Database/DatabaseBackedStore.cs @@ -2,7 +2,6 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; -using System.Collections.Generic; using System.Linq; using Microsoft.EntityFrameworkCore; using osu.Framework.Logging; @@ -50,46 +49,6 @@ namespace osu.Game.Database /// public void Reset() => Prepare(true); - public List Query(Func filter = null) where T : class - { - checkType(typeof(T)); - - var dbSet = Connection.GetType().GetProperties().Single(property => property.PropertyType == typeof(DbSet)).GetValue(Connection) as DbSet; - var query = dbSet.ToList(); - - if (filter != null) - query = query.Where(filter).ToList(); - - return query; - } - - /// - /// Query and populate results. - /// - /// An filter to refine results. - /// - public List QueryAndPopulate(Func filter) - where T : class, IPopulate - { - checkType(typeof(T)); - - var query = Query(filter); - foreach (var item in query) - Populate(item); - return query; - } - - /// - /// Populate a database-backed item. - /// - /// - public void Populate(IPopulate item) - { - checkType(item.GetType()); - - item.Populate(Connection); - } - private void checkType(Type type) { if (!ValidTypes.Contains(type)) diff --git a/osu.Game/Database/IPopulate.cs b/osu.Game/Database/IPopulate.cs deleted file mode 100644 index b07312f81c..0000000000 --- a/osu.Game/Database/IPopulate.cs +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright (c) 2007-2017 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -namespace osu.Game.Database -{ - public interface IPopulate - { - void Populate(OsuDbContext connection); - } -} diff --git a/osu.Game/Rulesets/RulesetStore.cs b/osu.Game/Rulesets/RulesetStore.cs index 8a8bbd9244..5a4b33df0b 100644 --- a/osu.Game/Rulesets/RulesetStore.cs +++ b/osu.Game/Rulesets/RulesetStore.cs @@ -42,14 +42,14 @@ namespace osu.Game.Rulesets { Connection.Database.ExecuteSqlCommand("DELETE FROM RulesetInfo"); } - + var instances = loaded_assemblies.Values.Select(r => (Ruleset)Activator.CreateInstance(r, new RulesetInfo())); //add all legacy modes in correct order foreach (var r in instances.Where(r => r.LegacyID >= 0).OrderBy(r => r.LegacyID)) { var rulesetInfo = createRulesetInfo(r); - if (Connection.RulesetInfo.SingleOrDefault(rsi => rsi.ID == rulesetInfo.ID) == null) + if (Connection.RulesetInfo.SingleOrDefault(rsi=>rsi.ID==rulesetInfo.ID)==null) { Connection.RulesetInfo.Add(rulesetInfo); } @@ -108,6 +108,19 @@ namespace osu.Game.Rulesets protected override Type[] ValidTypes => new[] { typeof(RulesetInfo) }; - public RulesetInfo GetRuleset(int id) => Query().First(r => r.ID == id); + public RulesetInfo GetRuleset(int id) => Connection.RulesetInfo.First(r => r.ID == id); + + public RulesetInfo QueryRulesetInfo(Func query) + { + return Connection.RulesetInfo.FirstOrDefault(query); + } + + public List QueryRulesets(Func query = null) + { + var rulesets = Connection.RulesetInfo; + if (query != null) + return rulesets.Where(query).ToList(); + return rulesets.ToList(); + } } } diff --git a/osu.Game/Tests/Visual/TestCasePlaySongSelect.cs b/osu.Game/Tests/Visual/TestCasePlaySongSelect.cs index f4c0d0b1b6..1b7f2def4d 100644 --- a/osu.Game/Tests/Visual/TestCasePlaySongSelect.cs +++ b/osu.Game/Tests/Visual/TestCasePlaySongSelect.cs @@ -75,7 +75,7 @@ namespace osu.Game.Tests.Visual new BeatmapInfo { OnlineBeatmapID = 1234 + i, - Ruleset = rulesets.Query().First(), + Ruleset = rulesets.QueryRulesets().First(), Path = "normal.osu", Version = "Normal", Difficulty = new BeatmapDifficulty @@ -86,7 +86,7 @@ namespace osu.Game.Tests.Visual new BeatmapInfo { OnlineBeatmapID = 1235 + i, - Ruleset = rulesets.Query().First(), + Ruleset = rulesets.QueryRulesets().First(), Path = "hard.osu", Version = "Hard", Difficulty = new BeatmapDifficulty @@ -97,7 +97,7 @@ namespace osu.Game.Tests.Visual new BeatmapInfo { OnlineBeatmapID = 1236 + i, - Ruleset = rulesets.Query().First(), + Ruleset = rulesets.QueryRulesets().First(), Path = "insane.osu", Version = "Insane", Difficulty = new BeatmapDifficulty diff --git a/osu.Game/Tests/Visual/TestCasePlayer.cs b/osu.Game/Tests/Visual/TestCasePlayer.cs index b0953ceb7e..811e240cee 100644 --- a/osu.Game/Tests/Visual/TestCasePlayer.cs +++ b/osu.Game/Tests/Visual/TestCasePlayer.cs @@ -50,7 +50,7 @@ namespace osu.Game.Tests.Visual string instantiation = ruleset?.AssemblyQualifiedName; - foreach (var r in rulesets.Query(rs => rs.Available && (instantiation == null || rs.InstantiationInfo == instantiation))) + foreach (var r in rulesets.QueryRulesets(rs => rs.Available && (instantiation == null || rs.InstantiationInfo == instantiation))) AddStep(r.Name, () => loadPlayerFor(r)); } diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 03ca32539c..6fbd169e2a 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -277,7 +277,6 @@ - 20171014052545_Init.cs From d73c0c0c98c9af6a4561ecc72e62854f7753eee5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 16 Oct 2017 13:09:01 +0900 Subject: [PATCH 0302/1263] Fix test regression --- osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs b/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs index f2ab00bead..cd9e765e7f 100644 --- a/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs +++ b/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs @@ -138,8 +138,9 @@ namespace osu.Game.Tests.Beatmaps.IO var set = queryBeatmapSets().First(); foreach (BeatmapInfo b in set.Beatmaps) + Assert.IsTrue(set.Beatmaps.Any(c => c.OnlineBeatmapID == b.OnlineBeatmapID)); - Assert.IsTrue(set.Beatmaps.Count > 0); + Assert.IsTrue(set.Beatmaps.Count > 0); var beatmap = store.GetWorkingBeatmap(set.Beatmaps.First(b => b.RulesetID == 0))?.Beatmap; Assert.IsTrue(beatmap?.HitObjects.Count > 0); From 0a6dcdd405d1bf27bc457dcea64bfb2802fbea3c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 16 Oct 2017 13:09:10 +0900 Subject: [PATCH 0303/1263] Fix remaining warnings --- osu.Game/Beatmaps/BeatmapManager.cs | 5 +---- osu.Game/IO/FileStore.cs | 15 +++++++-------- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 955c6f4b17..e4c53cec94 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -60,8 +60,6 @@ namespace osu.Game.Beatmaps private readonly FileStore files; - private readonly OsuDbContext connection; - private readonly RulesetStore rulesets; private readonly BeatmapStore beatmaps; @@ -93,7 +91,6 @@ namespace osu.Game.Beatmaps this.storage = storage; this.files = files; - this.connection = connection; this.rulesets = rulesets; this.api = api; @@ -164,7 +161,7 @@ namespace osu.Game.Beatmaps /// The beatmap to be imported. public BeatmapSetInfo Import(ArchiveReader archiveReader) { - BeatmapSetInfo set = null; + BeatmapSetInfo set; // let's only allow one concurrent import at a time for now. lock (importLock) diff --git a/osu.Game/IO/FileStore.cs b/osu.Game/IO/FileStore.cs index 680ecedf52..c15ebd264e 100644 --- a/osu.Game/IO/FileStore.cs +++ b/osu.Game/IO/FileStore.cs @@ -85,23 +85,22 @@ namespace osu.Game.IO public void Reference(params FileInfo[] files) { - var incrementedFiles = files.GroupBy(f => f.ID).Select(f => + foreach (var f in files.GroupBy(f => f.ID)) { - var accurateRefCount = Connection.Find(f.First().ID); - accurateRefCount.ReferenceCount += f.Count(); - return accurateRefCount; - }); + var refetch = Connection.Find(f.First().ID); + refetch.ReferenceCount += f.Count(); + } + Connection.SaveChanges(); } public void Dereference(params FileInfo[] files) { - var incrementedFiles = files.GroupBy(f => f.ID).Select(f => + foreach (var f in files.GroupBy(f => f.ID)) { var accurateRefCount = Connection.Find(f.First().ID); accurateRefCount.ReferenceCount -= f.Count(); - return accurateRefCount; - }); + } Connection.SaveChanges(); } From 4981630131a3343aed2004cb3549c97669a33d4a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 16 Oct 2017 13:11:35 +0900 Subject: [PATCH 0304/1263] Fix formatting regressions --- osu.Game/Database/DatabaseBackedStore.cs | 1 - osu.Game/Input/KeyBindingStore.cs | 2 +- osu.Game/Rulesets/RulesetStore.cs | 11 +++++++---- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/osu.Game/Database/DatabaseBackedStore.cs b/osu.Game/Database/DatabaseBackedStore.cs index f4b6a866dc..6b3fe232b2 100644 --- a/osu.Game/Database/DatabaseBackedStore.cs +++ b/osu.Game/Database/DatabaseBackedStore.cs @@ -36,7 +36,6 @@ namespace osu.Game.Database /// protected virtual void StartupTasks() { - } /// diff --git a/osu.Game/Input/KeyBindingStore.cs b/osu.Game/Input/KeyBindingStore.cs index 41bdc40a88..e2b6c1dc87 100644 --- a/osu.Game/Input/KeyBindingStore.cs +++ b/osu.Game/Input/KeyBindingStore.cs @@ -67,7 +67,7 @@ namespace osu.Game.Input public void Update(KeyBinding keyBinding) { var dbKeyBinding = Connection.DatabasedKeyBinding.FirstOrDefault(kb => kb.ToString() == keyBinding.ToString()); - if (dbKeyBinding!=null) + if (dbKeyBinding != null) { dbKeyBinding.KeyCombination = keyBinding.KeyCombination; dbKeyBinding.Action = keyBinding.Action; diff --git a/osu.Game/Rulesets/RulesetStore.cs b/osu.Game/Rulesets/RulesetStore.cs index 5a4b33df0b..068997e732 100644 --- a/osu.Game/Rulesets/RulesetStore.cs +++ b/osu.Game/Rulesets/RulesetStore.cs @@ -20,7 +20,8 @@ namespace osu.Game.Rulesets public IEnumerable AllRulesets => Connection.RulesetInfo.Where(r => r.Available); - public RulesetStore(OsuDbContext connection) : base(connection) + public RulesetStore(OsuDbContext connection) + : base(connection) { } @@ -42,14 +43,14 @@ namespace osu.Game.Rulesets { Connection.Database.ExecuteSqlCommand("DELETE FROM RulesetInfo"); } - + var instances = loaded_assemblies.Values.Select(r => (Ruleset)Activator.CreateInstance(r, new RulesetInfo())); //add all legacy modes in correct order foreach (var r in instances.Where(r => r.LegacyID >= 0).OrderBy(r => r.LegacyID)) { var rulesetInfo = createRulesetInfo(r); - if (Connection.RulesetInfo.SingleOrDefault(rsi=>rsi.ID==rulesetInfo.ID)==null) + if (Connection.RulesetInfo.SingleOrDefault(rsi => rsi.ID == rulesetInfo.ID) == null) { Connection.RulesetInfo.Add(rulesetInfo); } @@ -96,7 +97,9 @@ namespace osu.Game.Rulesets var assembly = Assembly.LoadFrom(file); loaded_assemblies[assembly] = assembly.GetTypes().First(t => t.IsSubclassOf(typeof(Ruleset))); } - catch (Exception) { } + catch (Exception) + { + } } private RulesetInfo createRulesetInfo(Ruleset ruleset) => new RulesetInfo From 29b46a5c5e22a2f0ec9e81344a1bac9cada1c6f1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 16 Oct 2017 13:23:41 +0900 Subject: [PATCH 0305/1263] Add missing reference to System.ValueTuple --- osu.Game/osu.Game.csproj | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 6fbd169e2a..4923c399c5 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -201,6 +201,9 @@ ..\packages\System.ValueTuple.4.4.0\lib\net461\System.ValueTuple.dll True + + ..\packages\System.ValueTuple.4.4.0\lib\net461\System.ValueTuple.dll + From a5ccf12e4a91c40046a72956d142b002c3e61e8f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 16 Oct 2017 14:04:04 +0900 Subject: [PATCH 0306/1263] Fix ValueTuple mess --- osu.Desktop/osu.Desktop.csproj | 3 --- osu.Desktop/packages.config | 27 +++++++++++++-------------- osu.Game/osu.Game.csproj | 3 ++- 3 files changed, 15 insertions(+), 18 deletions(-) diff --git a/osu.Desktop/osu.Desktop.csproj b/osu.Desktop/osu.Desktop.csproj index 859ff42dad..fad297fa0a 100644 --- a/osu.Desktop/osu.Desktop.csproj +++ b/osu.Desktop/osu.Desktop.csproj @@ -158,9 +158,6 @@ - - ..\packages\System.ValueTuple.4.4.0\lib\net461\System.ValueTuple.dll - diff --git a/osu.Desktop/packages.config b/osu.Desktop/packages.config index 7c4e9632e0..9cb31a6e25 100644 --- a/osu.Desktop/packages.config +++ b/osu.Desktop/packages.config @@ -1,15 +1,14 @@ - - - - - - - - - - - + + + + + + + + + + \ No newline at end of file diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 4923c399c5..2dd159188f 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -202,7 +202,8 @@ True - ..\packages\System.ValueTuple.4.4.0\lib\net461\System.ValueTuple.dll + ../packages/System.ValueTuple.4.4.0/lib/net461/System.ValueTuple.dll + True From 5b6c331434faf50fea6663f58ff36ad272f2e67c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 16 Oct 2017 14:12:08 +0900 Subject: [PATCH 0307/1263] Fix all keybindings being reset every startup --- osu.Game/Input/KeyBindingStore.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Input/KeyBindingStore.cs b/osu.Game/Input/KeyBindingStore.cs index e2b6c1dc87..f9578d150b 100644 --- a/osu.Game/Input/KeyBindingStore.cs +++ b/osu.Game/Input/KeyBindingStore.cs @@ -30,7 +30,8 @@ namespace osu.Game.Input protected override void Prepare(bool reset = false) { - Connection.Database.ExecuteSqlCommand("DELETE FROM KeyBinding"); + if (reset) + Connection.Database.ExecuteSqlCommand("DELETE FROM KeyBinding"); } private void insertDefaults(IEnumerable defaults, int? rulesetId = null, int? variant = null) From 1a16784db9f8857ef69f20a0a82333ac7411147d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 16 Oct 2017 14:18:01 +0900 Subject: [PATCH 0308/1263] Add BindingRedirects rule to fix dependency when running via nunit See https://github.com/ErikEJ/EntityFramework.SqlServerCompact/issues/463 --- osu.Game/osu.Game.csproj | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 2dd159188f..6c447f560e 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -23,6 +23,7 @@ LocalIntranet v4.6.1 true + true publish\ true Disk From 7049a73490cf17a75c7938cbecd55fe4925f39bd Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 16 Oct 2017 14:47:33 +0900 Subject: [PATCH 0309/1263] Remove ValidTypes from databased stored; explicitly expose query methods instead --- osu.Game/Beatmaps/BeatmapStore.cs | 8 -------- osu.Game/Database/DatabaseBackedStore.cs | 9 --------- osu.Game/IO/FileStore.cs | 4 ---- osu.Game/Input/KeyBindingStore.cs | 6 ------ osu.Game/Rulesets/RulesetStore.cs | 2 -- osu.Game/Rulesets/Scoring/ScoreStore.cs | 3 --- 6 files changed, 32 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapStore.cs b/osu.Game/Beatmaps/BeatmapStore.cs index 9c5a1a9dfc..817b46041f 100644 --- a/osu.Game/Beatmaps/BeatmapStore.cs +++ b/osu.Game/Beatmaps/BeatmapStore.cs @@ -26,14 +26,6 @@ namespace osu.Game.Beatmaps { } - protected override Type[] ValidTypes => new[] - { - typeof(BeatmapSetInfo), - typeof(BeatmapInfo), - typeof(BeatmapMetadata), - typeof(BeatmapDifficulty), - }; - protected override void Prepare(bool reset = false) { if (reset) diff --git a/osu.Game/Database/DatabaseBackedStore.cs b/osu.Game/Database/DatabaseBackedStore.cs index 6b3fe232b2..46fc596584 100644 --- a/osu.Game/Database/DatabaseBackedStore.cs +++ b/osu.Game/Database/DatabaseBackedStore.cs @@ -2,7 +2,6 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; -using System.Linq; using Microsoft.EntityFrameworkCore; using osu.Framework.Logging; using osu.Framework.Platform; @@ -47,13 +46,5 @@ namespace osu.Game.Database /// Reset this database to a default state. Undo all changes to database and storage backings. /// public void Reset() => Prepare(true); - - private void checkType(Type type) - { - if (!ValidTypes.Contains(type)) - throw new InvalidOperationException($"The requested operation specified a type of {type}, which is invalid for this {nameof(DatabaseBackedStore)}."); - } - - protected abstract Type[] ValidTypes { get; } } } diff --git a/osu.Game/IO/FileStore.cs b/osu.Game/IO/FileStore.cs index c15ebd264e..55b00b51d9 100644 --- a/osu.Game/IO/FileStore.cs +++ b/osu.Game/IO/FileStore.cs @@ -27,10 +27,6 @@ namespace osu.Game.IO Store = new NamespacedResourceStore(new StorageBackedResourceStore(storage), prefix); } - protected override Type[] ValidTypes => new[] { - typeof(FileInfo), - }; - protected override void Prepare(bool reset = false) { if (reset) diff --git a/osu.Game/Input/KeyBindingStore.cs b/osu.Game/Input/KeyBindingStore.cs index f9578d150b..088e3bd75b 100644 --- a/osu.Game/Input/KeyBindingStore.cs +++ b/osu.Game/Input/KeyBindingStore.cs @@ -1,7 +1,6 @@ // 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 Microsoft.EntityFrameworkCore; @@ -57,11 +56,6 @@ namespace osu.Game.Input } } - protected override Type[] ValidTypes => new[] - { - typeof(DatabasedKeyBinding) - }; - public List Query(int? rulesetId = null, int? variant = null) => new List(Connection.DatabasedKeyBinding.Where(b => b.RulesetID == rulesetId && b.Variant == variant)); diff --git a/osu.Game/Rulesets/RulesetStore.cs b/osu.Game/Rulesets/RulesetStore.cs index 068997e732..fe9dfd7a11 100644 --- a/osu.Game/Rulesets/RulesetStore.cs +++ b/osu.Game/Rulesets/RulesetStore.cs @@ -109,8 +109,6 @@ namespace osu.Game.Rulesets ID = ruleset.LegacyID }; - protected override Type[] ValidTypes => new[] { typeof(RulesetInfo) }; - public RulesetInfo GetRuleset(int id) => Connection.RulesetInfo.First(r => r.ID == id); public RulesetInfo QueryRulesetInfo(Func query) diff --git a/osu.Game/Rulesets/Scoring/ScoreStore.cs b/osu.Game/Rulesets/Scoring/ScoreStore.cs index 1604e8cb1c..66fcfb5d67 100644 --- a/osu.Game/Rulesets/Scoring/ScoreStore.cs +++ b/osu.Game/Rulesets/Scoring/ScoreStore.cs @@ -1,7 +1,6 @@ // 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.IO; using osu.Framework.Platform; @@ -147,7 +146,5 @@ namespace osu.Game.Rulesets.Scoring protected override void Prepare(bool reset = false) { } - - protected override Type[] ValidTypes => new[] { typeof(Score) }; } } From 1f4a943f74dfeb8340296e0187c4ca865866ecd1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 16 Oct 2017 15:09:43 +0900 Subject: [PATCH 0310/1263] Fix test case runs not being correctly isolated on mono --- osu.Game/Tests/Visual/OsuTestCase.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/osu.Game/Tests/Visual/OsuTestCase.cs b/osu.Game/Tests/Visual/OsuTestCase.cs index d722f7d711..90c6e427c4 100644 --- a/osu.Game/Tests/Visual/OsuTestCase.cs +++ b/osu.Game/Tests/Visual/OsuTestCase.cs @@ -11,8 +11,15 @@ namespace osu.Game.Tests.Visual { public override void RunTest() { - using (var host = new HeadlessGameHost(AppDomain.CurrentDomain.FriendlyName.Replace(' ', '-'), realtime: false)) + Storage storage; + using (var host = new HeadlessGameHost($"test-{Guid.NewGuid()}", realtime: false)) + { + storage = host.Storage; host.Run(new OsuTestCaseTestRunner(this)); + } + + // clean up after each run + storage.DeleteDirectory(string.Empty); } public class OsuTestCaseTestRunner : OsuGameBase From ec51314e37a52d7880d2353df55eae151940bdf8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 16 Oct 2017 16:11:34 +0900 Subject: [PATCH 0311/1263] Remove duplicate command --- osu.Game/Database/DatabaseBackedStore.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game/Database/DatabaseBackedStore.cs b/osu.Game/Database/DatabaseBackedStore.cs index 46fc596584..adddad6122 100644 --- a/osu.Game/Database/DatabaseBackedStore.cs +++ b/osu.Game/Database/DatabaseBackedStore.cs @@ -2,7 +2,6 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; -using Microsoft.EntityFrameworkCore; using osu.Framework.Logging; using osu.Framework.Platform; @@ -17,7 +16,6 @@ namespace osu.Game.Database { Storage = storage; Connection = connection; - Connection.Database.SetCommandTimeout(new TimeSpan(TimeSpan.TicksPerSecond * 10)); try { From 767775988eaf2779805f12f2f337ca0d02386241 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 16 Oct 2017 16:54:14 +0900 Subject: [PATCH 0312/1263] Add NS and OS as abbreviations Satisfies Jetbrains Rider --- osu-framework | 2 +- osu.sln.DotSettings | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/osu-framework b/osu-framework index 0bc71f95b4..48ea66774c 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit 0bc71f95b455d3829b2abf662b5fe25989e6c43c +Subproject commit 48ea66774c76427b871b71c6c5f4e01ebecf1af2 diff --git a/osu.sln.DotSettings b/osu.sln.DotSettings index c236ce82b0..7808ed200b 100644 --- a/osu.sln.DotSettings +++ b/osu.sln.DotSettings @@ -193,6 +193,8 @@ IPC LTRB MD5 + NS + OS RGB RNG SHA From acc299c7b97b24dc234e27fae049a421c609ab1b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 16 Oct 2017 17:02:31 +0900 Subject: [PATCH 0313/1263] Correct and simplify RulesetStore --- osu.Game/Beatmaps/BeatmapManager.cs | 7 +-- osu.Game/Input/KeyBindingStore.cs | 2 +- osu.Game/Overlays/Direct/FilterControl.cs | 2 +- osu.Game/Overlays/KeyBindingOverlay.cs | 2 +- osu.Game/Overlays/Mods/ModSelectOverlay.cs | 2 +- .../Settings/Sections/GameplaySection.cs | 2 +- osu.Game/Overlays/Settings/SettingsFooter.cs | 2 +- .../Overlays/Toolbar/ToolbarModeSelector.cs | 2 +- osu.Game/Rulesets/RulesetStore.cs | 44 +++++++++---------- osu.Game/Tests/Visual/TestCaseMods.cs | 2 +- .../Tests/Visual/TestCasePlaySongSelect.cs | 6 +-- osu.Game/Tests/Visual/TestCasePlayer.cs | 2 +- 12 files changed, 37 insertions(+), 38 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index e4c53cec94..985d2c7a15 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -474,10 +474,11 @@ namespace osu.Game.Beatmaps // TODO: Diff beatmap metadata with set metadata and leave it here if necessary beatmap.BeatmapInfo.Metadata = null; + RulesetInfo ruleset = rulesets.GetRuleset(beatmap.BeatmapInfo.RulesetID); + // TODO: this should be done in a better place once we actually need to dynamically update it. - beatmap.BeatmapInfo.Ruleset = rulesets.QueryRulesetInfo(r => r.ID == beatmap.BeatmapInfo.RulesetID); - beatmap.BeatmapInfo.StarDifficulty = rulesets.QueryRulesetInfo(r => r.ID == beatmap.BeatmapInfo.RulesetID)?.CreateInstance()?.CreateDifficultyCalculator(beatmap) - .Calculate() ?? 0; + beatmap.BeatmapInfo.Ruleset = ruleset; + beatmap.BeatmapInfo.StarDifficulty = ruleset?.CreateInstance()?.CreateDifficultyCalculator(beatmap).Calculate() ?? 0; beatmapSet.Beatmaps.Add(beatmap.BeatmapInfo); } diff --git a/osu.Game/Input/KeyBindingStore.cs b/osu.Game/Input/KeyBindingStore.cs index 088e3bd75b..5cc018ff2c 100644 --- a/osu.Game/Input/KeyBindingStore.cs +++ b/osu.Game/Input/KeyBindingStore.cs @@ -17,7 +17,7 @@ namespace osu.Game.Input public KeyBindingStore(OsuDbContext connection, RulesetStore rulesets, Storage storage = null) : base(connection, storage) { - foreach (var info in rulesets.AllRulesets) + foreach (var info in rulesets.AvailableRulesets) { var ruleset = info.CreateInstance(); foreach (var variant in ruleset.AvailableVariants) diff --git a/osu.Game/Overlays/Direct/FilterControl.cs b/osu.Game/Overlays/Direct/FilterControl.cs index 28d26d0641..9b52cfd367 100644 --- a/osu.Game/Overlays/Direct/FilterControl.cs +++ b/osu.Game/Overlays/Direct/FilterControl.cs @@ -39,7 +39,7 @@ namespace osu.Game.Overlays.Direct DisplayStyleControl.Dropdown.AccentColour = colours.BlueDark; Ruleset.BindTo(game?.Ruleset ?? new Bindable { Value = rulesets.GetRuleset(0) }); - foreach (var r in rulesets.AllRulesets) + foreach (var r in rulesets.AvailableRulesets) { modeButtons.Add(new RulesetToggleButton(Ruleset, r)); } diff --git a/osu.Game/Overlays/KeyBindingOverlay.cs b/osu.Game/Overlays/KeyBindingOverlay.cs index 72c653030c..4394d0fec0 100644 --- a/osu.Game/Overlays/KeyBindingOverlay.cs +++ b/osu.Game/Overlays/KeyBindingOverlay.cs @@ -19,7 +19,7 @@ namespace osu.Game.Overlays { AddSection(new GlobalKeyBindingsSection(global)); - foreach (var ruleset in rulesets.AllRulesets) + foreach (var ruleset in rulesets.AvailableRulesets) AddSection(new RulesetBindingsSection(ruleset)); } diff --git a/osu.Game/Overlays/Mods/ModSelectOverlay.cs b/osu.Game/Overlays/Mods/ModSelectOverlay.cs index eb643f390f..9ff21dfdd4 100644 --- a/osu.Game/Overlays/Mods/ModSelectOverlay.cs +++ b/osu.Game/Overlays/Mods/ModSelectOverlay.cs @@ -56,7 +56,7 @@ namespace osu.Game.Overlays.Mods if (osu != null) Ruleset.BindTo(osu.Ruleset); else - Ruleset.Value = rulesets.AllRulesets.First(); + Ruleset.Value = rulesets.AvailableRulesets.First(); Ruleset.ValueChanged += rulesetChanged; Ruleset.TriggerChange(); diff --git a/osu.Game/Overlays/Settings/Sections/GameplaySection.cs b/osu.Game/Overlays/Settings/Sections/GameplaySection.cs index 326cb582e2..035a3c7a13 100644 --- a/osu.Game/Overlays/Settings/Sections/GameplaySection.cs +++ b/osu.Game/Overlays/Settings/Sections/GameplaySection.cs @@ -27,7 +27,7 @@ namespace osu.Game.Overlays.Settings.Sections [BackgroundDependencyLoader] private void load(RulesetStore rulesets) { - foreach(Ruleset ruleset in rulesets.AllRulesets.Select(info => info.CreateInstance())) + foreach(Ruleset ruleset in rulesets.AvailableRulesets.Select(info => info.CreateInstance())) { SettingsSubsection section = ruleset.CreateSettings(); if (section != null) diff --git a/osu.Game/Overlays/Settings/SettingsFooter.cs b/osu.Game/Overlays/Settings/SettingsFooter.cs index cb1c861ee7..bf417a2fac 100644 --- a/osu.Game/Overlays/Settings/SettingsFooter.cs +++ b/osu.Game/Overlays/Settings/SettingsFooter.cs @@ -27,7 +27,7 @@ namespace osu.Game.Overlays.Settings var modes = new List(); - foreach (var ruleset in rulesets.AllRulesets) + foreach (var ruleset in rulesets.AvailableRulesets) { var icon = new ConstrainedIconContainer { diff --git a/osu.Game/Overlays/Toolbar/ToolbarModeSelector.cs b/osu.Game/Overlays/Toolbar/ToolbarModeSelector.cs index 60c1261190..da72ae0347 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarModeSelector.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarModeSelector.cs @@ -67,7 +67,7 @@ namespace osu.Game.Overlays.Toolbar [BackgroundDependencyLoader] private void load(RulesetStore rulesets, OsuGame game) { - foreach (var r in rulesets.AllRulesets) + foreach (var r in rulesets.AvailableRulesets) { modeButtons.Add(new ToolbarModeButton { diff --git a/osu.Game/Rulesets/RulesetStore.cs b/osu.Game/Rulesets/RulesetStore.cs index fe9dfd7a11..c39312205c 100644 --- a/osu.Game/Rulesets/RulesetStore.cs +++ b/osu.Game/Rulesets/RulesetStore.cs @@ -18,13 +18,6 @@ namespace osu.Game.Rulesets { private static readonly Dictionary loaded_assemblies = new Dictionary(); - public IEnumerable AllRulesets => Connection.RulesetInfo.Where(r => r.Available); - - public RulesetStore(OsuDbContext connection) - : base(connection) - { - } - static RulesetStore() { AppDomain.CurrentDomain.AssemblyResolve += currentDomain_AssemblyResolve; @@ -33,6 +26,23 @@ namespace osu.Game.Rulesets loadRulesetFromFile(file); } + public RulesetStore(OsuDbContext connection) + : base(connection) + { + } + + /// + /// Retrieve a ruleset using a known ID. + /// + /// The ruleset's internal ID. + /// A ruleset, if available, else null. + public RulesetInfo GetRuleset(int id) => AvailableRulesets.FirstOrDefault(r => r.ID == id); + + /// + /// All available rulesets. + /// + public IEnumerable AvailableRulesets => Connection.RulesetInfo.Where(r => r.Available); + private static Assembly currentDomain_AssemblyResolve(object sender, ResolveEventArgs args) => loaded_assemblies.Keys.FirstOrDefault(a => a.FullName == args.Name); private const string ruleset_library_prefix = "osu.Game.Rulesets"; @@ -44,7 +54,7 @@ namespace osu.Game.Rulesets Connection.Database.ExecuteSqlCommand("DELETE FROM RulesetInfo"); } - var instances = loaded_assemblies.Values.Select(r => (Ruleset)Activator.CreateInstance(r, new RulesetInfo())); + var instances = loaded_assemblies.Values.Select(r => (Ruleset)Activator.CreateInstance(r, new RulesetInfo())).ToList(); //add all legacy modes in correct order foreach (var r in instances.Where(r => r.LegacyID >= 0).OrderBy(r => r.LegacyID)) @@ -55,6 +65,7 @@ namespace osu.Game.Rulesets Connection.RulesetInfo.Add(rulesetInfo); } } + Connection.SaveChanges(); //add any other modes @@ -67,6 +78,7 @@ namespace osu.Game.Rulesets if (existing == null) Connection.RulesetInfo.Add(us); } + Connection.SaveChanges(); //perform a consistency check @@ -82,6 +94,7 @@ namespace osu.Game.Rulesets r.Available = false; } } + Connection.SaveChanges(); } @@ -108,20 +121,5 @@ namespace osu.Game.Rulesets InstantiationInfo = ruleset.GetType().AssemblyQualifiedName, ID = ruleset.LegacyID }; - - public RulesetInfo GetRuleset(int id) => Connection.RulesetInfo.First(r => r.ID == id); - - public RulesetInfo QueryRulesetInfo(Func query) - { - return Connection.RulesetInfo.FirstOrDefault(query); - } - - public List QueryRulesets(Func query = null) - { - var rulesets = Connection.RulesetInfo; - if (query != null) - return rulesets.Where(query).ToList(); - return rulesets.ToList(); - } } } diff --git a/osu.Game/Tests/Visual/TestCaseMods.cs b/osu.Game/Tests/Visual/TestCaseMods.cs index ef250edcc3..0447d6582d 100644 --- a/osu.Game/Tests/Visual/TestCaseMods.cs +++ b/osu.Game/Tests/Visual/TestCaseMods.cs @@ -49,7 +49,7 @@ namespace osu.Game.Tests.Visual AddStep("Toggle", modSelect.ToggleVisibility); - foreach (var ruleset in rulesets.AllRulesets) + foreach (var ruleset in rulesets.AvailableRulesets) AddStep(ruleset.CreateInstance().Description, () => modSelect.Ruleset.Value = ruleset); } } diff --git a/osu.Game/Tests/Visual/TestCasePlaySongSelect.cs b/osu.Game/Tests/Visual/TestCasePlaySongSelect.cs index 1b7f2def4d..a8a00e9a0d 100644 --- a/osu.Game/Tests/Visual/TestCasePlaySongSelect.cs +++ b/osu.Game/Tests/Visual/TestCasePlaySongSelect.cs @@ -75,7 +75,7 @@ namespace osu.Game.Tests.Visual new BeatmapInfo { OnlineBeatmapID = 1234 + i, - Ruleset = rulesets.QueryRulesets().First(), + Ruleset = rulesets.AvailableRulesets.First(), Path = "normal.osu", Version = "Normal", Difficulty = new BeatmapDifficulty @@ -86,7 +86,7 @@ namespace osu.Game.Tests.Visual new BeatmapInfo { OnlineBeatmapID = 1235 + i, - Ruleset = rulesets.QueryRulesets().First(), + Ruleset = rulesets.AvailableRulesets.First(), Path = "hard.osu", Version = "Hard", Difficulty = new BeatmapDifficulty @@ -97,7 +97,7 @@ namespace osu.Game.Tests.Visual new BeatmapInfo { OnlineBeatmapID = 1236 + i, - Ruleset = rulesets.QueryRulesets().First(), + Ruleset = rulesets.AvailableRulesets.First(), Path = "insane.osu", Version = "Insane", Difficulty = new BeatmapDifficulty diff --git a/osu.Game/Tests/Visual/TestCasePlayer.cs b/osu.Game/Tests/Visual/TestCasePlayer.cs index 811e240cee..dfbdaf1d9d 100644 --- a/osu.Game/Tests/Visual/TestCasePlayer.cs +++ b/osu.Game/Tests/Visual/TestCasePlayer.cs @@ -50,7 +50,7 @@ namespace osu.Game.Tests.Visual string instantiation = ruleset?.AssemblyQualifiedName; - foreach (var r in rulesets.QueryRulesets(rs => rs.Available && (instantiation == null || rs.InstantiationInfo == instantiation))) + foreach (var r in rulesets.AvailableRulesets.Where(rs => instantiation == null || rs.InstantiationInfo == instantiation)) AddStep(r.Name, () => loadPlayerFor(r)); } From f9aba6fa27f10eefb6e431c62e7f4d52fed5c22b Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 16 Oct 2017 17:11:54 +0900 Subject: [PATCH 0314/1263] Update framework once more --- osu-framework | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu-framework b/osu-framework index 48ea66774c..b1f36efca5 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit 48ea66774c76427b871b71c6c5f4e01ebecf1af2 +Subproject commit b1f36efca59840da65df788a52107b1674a904c6 From 9ee6d1e3f9d9274cf7d37ab6f17b9eea8c93438c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 16 Oct 2017 17:58:17 +0900 Subject: [PATCH 0315/1263] Correct and simplify KeyBindingStore --- osu.Game/Input/KeyBindingStore.cs | 30 ++++++++++--------- .../KeyBinding/KeyBindingsSubsection.cs | 4 ++- 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/osu.Game/Input/KeyBindingStore.cs b/osu.Game/Input/KeyBindingStore.cs index 5cc018ff2c..9edab896b3 100644 --- a/osu.Game/Input/KeyBindingStore.cs +++ b/osu.Game/Input/KeyBindingStore.cs @@ -38,11 +38,13 @@ namespace osu.Game.Input // compare counts in database vs defaults foreach (var group in defaults.GroupBy(k => k.Action)) { - int count; - while (group.Count() > (count = Query(rulesetId, variant).Count(k => (int)k.Action == (int)group.Key))) - { - var insertable = group.Skip(count).First(); + int count = Query(rulesetId, variant).Count(k => (int)k.Action == (int)group.Key); + int aimCount = group.Count(); + if (aimCount <= count) + continue; + + foreach (var insertable in group.Skip(count).Take(aimCount - count)) // insert any defaults which are missing. Connection.DatabasedKeyBinding.Add(new DatabasedKeyBinding { @@ -51,22 +53,22 @@ namespace osu.Game.Input RulesetID = rulesetId, Variant = variant }); - Connection.SaveChanges(); - } } + + Connection.SaveChanges(); } - public List Query(int? rulesetId = null, int? variant = null) => - new List(Connection.DatabasedKeyBinding.Where(b => b.RulesetID == rulesetId && b.Variant == variant)); + /// + /// Retrieve s for a specified ruleset/variant content. + /// + /// The ruleset's internal ID. + /// An optional variant. + /// + public IEnumerable Query(int? rulesetId = null, int? variant = null) => Connection.DatabasedKeyBinding.Where(b => b.RulesetID == rulesetId && b.Variant == variant); public void Update(KeyBinding keyBinding) { - var dbKeyBinding = Connection.DatabasedKeyBinding.FirstOrDefault(kb => kb.ToString() == keyBinding.ToString()); - if (dbKeyBinding != null) - { - dbKeyBinding.KeyCombination = keyBinding.KeyCombination; - dbKeyBinding.Action = keyBinding.Action; - } + Connection.Update(keyBinding); Connection.SaveChanges(); } } diff --git a/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs b/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs index bd69403831..128b5e2f09 100644 --- a/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs +++ b/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs @@ -37,8 +37,10 @@ namespace osu.Game.Overlays.KeyBinding foreach (var defaultGroup in Defaults.GroupBy(d => d.Action)) { + int intKey = (int)defaultGroup.Key; + // one row per valid action. - Add(new KeyBindingRow(defaultGroup.Key, bindings.Where(b => b.Action.Equals((int)defaultGroup.Key))) + Add(new KeyBindingRow(defaultGroup.Key, bindings.Where(b => ((int)b.Action).Equals(intKey))) { AllowMainMouseButtons = Ruleset != null, Defaults = defaultGroup.Select(d => d.KeyCombination) From e378d0685db0847a33d4de796a26f6ba8879b7df Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 16 Oct 2017 20:28:49 +0900 Subject: [PATCH 0316/1263] Remove weird additions --- osu.Game.Tests/app.config | 4 ---- osu.Game/Beatmaps/BeatmapSetOnlineInfo.cs | 3 +-- osu.Game/osu.Game.csproj | 13 ------------- 3 files changed, 1 insertion(+), 19 deletions(-) diff --git a/osu.Game.Tests/app.config b/osu.Game.Tests/app.config index 11af32e2cf..faeaf001de 100644 --- a/osu.Game.Tests/app.config +++ b/osu.Game.Tests/app.config @@ -6,10 +6,6 @@ - - - - \ No newline at end of file diff --git a/osu.Game/Beatmaps/BeatmapSetOnlineInfo.cs b/osu.Game/Beatmaps/BeatmapSetOnlineInfo.cs index 2568af6ce1..27d1f057ca 100644 --- a/osu.Game/Beatmaps/BeatmapSetOnlineInfo.cs +++ b/osu.Game/Beatmaps/BeatmapSetOnlineInfo.cs @@ -2,7 +2,6 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; -using System.ComponentModel.DataAnnotations; using Newtonsoft.Json; namespace osu.Game.Beatmaps @@ -30,7 +29,7 @@ namespace osu.Game.Beatmaps /// /// The different sizes of cover art for this beatmap set. /// - [Required, JsonProperty(@"covers")] + [JsonProperty(@"covers")] public BeatmapSetOnlineCovers Covers { get; set; } /// diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 6c447f560e..ced7ca7318 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -23,7 +23,6 @@ LocalIntranet v4.6.1 true - true publish\ true Disk @@ -202,10 +201,6 @@ ..\packages\System.ValueTuple.4.4.0\lib\net461\System.ValueTuple.dll True - - ../packages/System.ValueTuple.4.4.0/lib/net461/System.ValueTuple.dll - True - @@ -862,14 +857,6 @@ - - - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - - From eff1c20e38cd9fd8583bc6637bea61c53e5476d8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 16 Oct 2017 20:50:34 +0900 Subject: [PATCH 0317/1263] CI fixing --- osu.Desktop/app.config | 4 ++++ osu.Desktop/osu.Desktop.csproj | 4 ++++ osu.Desktop/packages.config | 1 + osu.Game.Tests/osu.Game.Tests.csproj | 4 ++++ osu.Game.Tests/packages.config | 17 +++++++++-------- osu.Game/app.config | 4 ++++ osu.Game/osu.Game.csproj | 8 ++++++++ 7 files changed, 34 insertions(+), 8 deletions(-) diff --git a/osu.Desktop/app.config b/osu.Desktop/app.config index 824430b24a..0841541f3d 100644 --- a/osu.Desktop/app.config +++ b/osu.Desktop/app.config @@ -11,6 +11,10 @@ + + + + diff --git a/osu.Desktop/osu.Desktop.csproj b/osu.Desktop/osu.Desktop.csproj index fad297fa0a..7b2ec3b24c 100644 --- a/osu.Desktop/osu.Desktop.csproj +++ b/osu.Desktop/osu.Desktop.csproj @@ -158,6 +158,10 @@ + + ../packages/System.ValueTuple.4.4.0/lib/net461/System.ValueTuple.dll + True + diff --git a/osu.Desktop/packages.config b/osu.Desktop/packages.config index 9cb31a6e25..f47fe8ac62 100644 --- a/osu.Desktop/packages.config +++ b/osu.Desktop/packages.config @@ -11,4 +11,5 @@ Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/maste + \ 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 e188c82e79..7a3bbab176 100644 --- a/osu.Game.Tests/osu.Game.Tests.csproj +++ b/osu.Game.Tests/osu.Game.Tests.csproj @@ -39,6 +39,10 @@ True + + ../packages/System.ValueTuple.4.4.0/lib/net461/System.ValueTuple.dll + True + diff --git a/osu.Game.Tests/packages.config b/osu.Game.Tests/packages.config index b94c0c6e2d..ecc44f0c70 100644 --- a/osu.Game.Tests/packages.config +++ b/osu.Game.Tests/packages.config @@ -1,9 +1,10 @@ - - - - - + + + + + + \ No newline at end of file diff --git a/osu.Game/app.config b/osu.Game/app.config index a704cc3750..7f2ad68041 100644 --- a/osu.Game/app.config +++ b/osu.Game/app.config @@ -10,6 +10,10 @@ + + + + \ No newline at end of file diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index ced7ca7318..a442d1cef6 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -201,6 +201,10 @@ ..\packages\System.ValueTuple.4.4.0\lib\net461\System.ValueTuple.dll True + + ../packages/System.ValueTuple.4.4.0/lib/net461/System.ValueTuple.dll + True + @@ -857,6 +861,10 @@ + + true + true + From 81476ebe7543a921b962c70f8e7b065596a9e629 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 16 Oct 2017 22:04:22 +0900 Subject: [PATCH 0318/1263] Correct and simplify BeatmapStore and BeatmapManager --- osu.Game/Beatmaps/BeatmapManager.cs | 64 ++++++++++++++++++----------- osu.Game/Beatmaps/BeatmapStore.cs | 59 ++++++++------------------ 2 files changed, 57 insertions(+), 66 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 985d2c7a15..af88f22e40 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -5,7 +5,6 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; -using System.Linq.Expressions; using System.Threading.Tasks; using Ionic.Zip; using osu.Framework.Audio.Track; @@ -179,7 +178,8 @@ namespace osu.Game.Beatmaps // If we have an ID then we already exist in the database. if (beatmapSetInfo.ID != 0) return; - beatmaps.Add(beatmapSetInfo); + lock (beatmaps) + beatmaps.Add(beatmapSetInfo); } /// @@ -257,7 +257,8 @@ namespace osu.Game.Beatmaps /// The beatmap set to delete. public void Delete(BeatmapSetInfo beatmapSet) { - if (!beatmaps.Delete(beatmapSet)) return; + lock (beatmaps) + if (!beatmaps.Delete(beatmapSet)) return; if (!beatmapSet.Protected) files.Dereference(beatmapSet.Files.Select(f => f.FileInfo).ToArray()); @@ -267,13 +268,21 @@ namespace osu.Game.Beatmaps /// Delete a beatmap difficulty. /// /// The beatmap difficulty to hide. - public void Hide(BeatmapInfo beatmap) => beatmaps.Hide(beatmap); + public void Hide(BeatmapInfo beatmap) + { + lock (beatmaps) + beatmaps.Hide(beatmap); + } /// /// Restore a beatmap difficulty. /// /// The beatmap difficulty to restore. - public void Restore(BeatmapInfo beatmap) => beatmaps.Restore(beatmap); + public void Restore(BeatmapInfo beatmap) + { + lock (beatmaps) + beatmaps.Restore(beatmap); + } /// /// Returns a to a usable state if it has previously been deleted but not yet purged. @@ -282,7 +291,8 @@ namespace osu.Game.Beatmaps /// The beatmap to restore. public void Undelete(BeatmapSetInfo beatmapSet) { - if (!beatmaps.Undelete(beatmapSet)) return; + lock (beatmaps) + if (!beatmaps.Undelete(beatmapSet)) return; if (!beatmapSet.Protected) files.Reference(beatmapSet.Files.Select(f => f.FileInfo).ToArray()); @@ -329,11 +339,7 @@ namespace osu.Game.Beatmaps public BeatmapSetInfo QueryBeatmapSet(Func query) { lock (beatmaps) - { - BeatmapSetInfo set = beatmaps.QueryBeatmapSet(query); - - return set; - } + return beatmaps.BeatmapSets.FirstOrDefault(query); } /// @@ -348,9 +354,10 @@ namespace osu.Game.Beatmaps /// /// The query. /// Results from the provided query. - public List QueryBeatmapSets(Expression> query) + public List QueryBeatmapSets(Func query) { - return beatmaps.QueryBeatmapSets(query); + lock (beatmaps) + return beatmaps.BeatmapSets.Where(query).ToList(); } /// @@ -360,9 +367,8 @@ namespace osu.Game.Beatmaps /// The first result for the provided query, or null if no results were found. public BeatmapInfo QueryBeatmap(Func query) { - BeatmapInfo set = beatmaps.QueryBeatmap(query); - - return set; + lock (beatmaps) + return beatmaps.Beatmaps.FirstOrDefault(query); } /// @@ -370,9 +376,10 @@ namespace osu.Game.Beatmaps /// /// The query. /// Results from the provided query. - public List QueryBeatmaps(Expression> query) + public List QueryBeatmaps(Func query) { - lock (beatmaps) return beatmaps.QueryBeatmaps(query); + lock (beatmaps) + return beatmaps.Beatmaps.Where(query).ToList(); } /// @@ -411,7 +418,7 @@ namespace osu.Game.Beatmaps // check if this beatmap has already been imported and exit early if so. BeatmapSetInfo beatmapSet; lock (beatmaps) - beatmapSet = beatmaps.QueryBeatmapSet(b => b.Hash == hash); + beatmapSet = beatmaps.BeatmapSets.FirstOrDefault(b => b.Hash == hash); if (beatmapSet != null) { @@ -494,9 +501,7 @@ namespace osu.Game.Beatmaps public List GetAllUsableBeatmapSets() { lock (beatmaps) - { - return beatmaps.QueryBeatmapSets(b => !b.DeletePending); - } + return beatmaps.BeatmapSets.ToList(); } protected class BeatmapManagerWorkingBeatmap : WorkingBeatmap @@ -531,7 +536,10 @@ namespace osu.Game.Beatmaps return beatmap; } - catch { return null; } + catch + { + return null; + } } private string getPathForFile(string filename) => BeatmapSetInfo.Files.First(f => string.Equals(f.Filename, filename, StringComparison.InvariantCultureIgnoreCase)).FileInfo.StoragePath; @@ -545,7 +553,10 @@ namespace osu.Game.Beatmaps { return new TextureStore(new RawTextureLoaderStore(store), false).Get(getPathForFile(Metadata.BackgroundFile)); } - catch { return null; } + catch + { + return null; + } } protected override Track GetTrack() @@ -555,7 +566,10 @@ namespace osu.Game.Beatmaps var trackData = store.GetStream(getPathForFile(Metadata.AudioFile)); return trackData == null ? null : new TrackBass(trackData); } - catch { return new TrackVirtual(); } + catch + { + return new TrackVirtual(); + } } protected override Waveform GetWaveform() => new Waveform(store.GetStream(getPathForFile(Metadata.AudioFile))); diff --git a/osu.Game/Beatmaps/BeatmapStore.cs b/osu.Game/Beatmaps/BeatmapStore.cs index 817b46041f..6464db86d4 100644 --- a/osu.Game/Beatmaps/BeatmapStore.cs +++ b/osu.Game/Beatmaps/BeatmapStore.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Linq.Expressions; using Microsoft.EntityFrameworkCore; using osu.Game.Database; @@ -51,7 +50,7 @@ namespace osu.Game.Beatmaps /// The beatmap to add. public void Add(BeatmapSetInfo beatmapSet) { - Connection.BeatmapSetInfo.Update(beatmapSet); + Connection.BeatmapSetInfo.Add(beatmapSet); Connection.SaveChanges(); BeatmapSetAdded?.Invoke(beatmapSet); @@ -67,7 +66,7 @@ namespace osu.Game.Beatmaps if (beatmapSet.DeletePending) return false; beatmapSet.DeletePending = true; - Connection.BeatmapSetInfo.Remove(beatmapSet); + Connection.BeatmapSetInfo.Update(beatmapSet); Connection.SaveChanges(); BeatmapSetRemoved?.Invoke(beatmapSet); @@ -85,6 +84,7 @@ namespace osu.Game.Beatmaps beatmapSet.DeletePending = false; Connection.BeatmapSetInfo.Update(beatmapSet); + Connection.SaveChanges(); BeatmapSetAdded?.Invoke(beatmapSet); return true; @@ -101,6 +101,7 @@ namespace osu.Game.Beatmaps beatmap.Hidden = true; Connection.BeatmapInfo.Update(beatmap); + Connection.SaveChanges(); BeatmapHidden?.Invoke(beatmap); return true; @@ -117,6 +118,7 @@ namespace osu.Game.Beatmaps beatmap.Hidden = false; Connection.BeatmapInfo.Update(beatmap); + Connection.SaveChanges(); BeatmapRestored?.Invoke(beatmap); return true; @@ -125,46 +127,21 @@ namespace osu.Game.Beatmaps private void cleanupPendingDeletions() { Connection.BeatmapSetInfo.RemoveRange(Connection.BeatmapSetInfo.Where(b => b.DeletePending && !b.Protected)); + Connection.SaveChanges(); } - public BeatmapSetInfo QueryBeatmapSet(Func query) - { - return Connection.BeatmapSetInfo - .Include(b => b.Metadata) - .Include(b => b.Beatmaps).ThenInclude(b => b.Ruleset) - .Include(b => b.Beatmaps).ThenInclude(b => b.Difficulty) - .Include(b => b.Files).ThenInclude(f => f.FileInfo) - .FirstOrDefault(query); - } + public IEnumerable BeatmapSets => Connection.BeatmapSetInfo + .Include(s => s.Metadata) + .Include(s => s.Beatmaps).ThenInclude(s => s.Ruleset) + .Include(s => s.Beatmaps).ThenInclude(b => b.Difficulty) + .Include(s => s.Beatmaps).ThenInclude(b => b.Metadata) + .Include(s => s.Files).ThenInclude(f => f.FileInfo) + .Where(s => !s.DeletePending); - public List QueryBeatmapSets(Expression> query) - { - return Connection.BeatmapSetInfo - .Include(b => b.Metadata) - .Include(b => b.Beatmaps).ThenInclude(b => b.Ruleset) - .Include(b => b.Beatmaps).ThenInclude(b => b.Difficulty) - .Include(b => b.Files).ThenInclude(f => f.FileInfo) - .Where(query).ToList(); - } - - public BeatmapInfo QueryBeatmap(Func query) - { - return Connection.BeatmapInfo - .Include(b => b.BeatmapSet) - .Include(b => b.Metadata) - .Include(b => b.Ruleset) - .Include(b => b.Difficulty) - .FirstOrDefault(query); - } - - public List QueryBeatmaps(Expression> query) - { - return Connection.BeatmapInfo - .Include(b => b.BeatmapSet) - .Include(b => b.Metadata) - .Include(b => b.Ruleset) - .Include(b => b.Difficulty) - .Where(query).ToList(); - } + public IEnumerable Beatmaps => Connection.BeatmapInfo + .Include(b => b.BeatmapSet).ThenInclude(s => s.Metadata) + .Include(b => b.Metadata) + .Include(b => b.Ruleset) + .Include(b => b.Difficulty); } } From 799f51021700d394d5e19a5f329816ca018bd9a9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Oct 2017 10:25:18 +0900 Subject: [PATCH 0319/1263] FileStore logic fixes --- osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs | 2 -- osu.Game/IO/FileStore.cs | 16 +++++++++------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs b/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs index cd9e765e7f..087fb54b5f 100644 --- a/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs +++ b/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs @@ -95,8 +95,6 @@ namespace osu.Game.Tests.Beatmaps.IO private OsuGameBase loadOsu(GameHost host) { - host.Storage.DeleteDatabase(@"client"); - var osu = new OsuGameBase(); Task.Run(() => host.Run(osu)); diff --git a/osu.Game/IO/FileStore.cs b/osu.Game/IO/FileStore.cs index 55b00b51d9..ae0cfb30c8 100644 --- a/osu.Game/IO/FileStore.cs +++ b/osu.Game/IO/FileStore.cs @@ -31,10 +31,6 @@ namespace osu.Game.IO { if (reset) { - // in earlier versions we stored beatmaps as solid archives, but not any more. - if (Storage.ExistsDirectory("beatmaps")) - Storage.DeleteDirectory("beatmaps"); - if (Storage.ExistsDirectory(prefix)) Storage.DeleteDirectory(prefix); @@ -70,12 +66,14 @@ namespace osu.Game.IO } if (existing == null) + { Connection.FileInfo.Add(info); + Connection.SaveChanges(); + } if (reference || existing == null) Reference(info); - Connection.SaveChanges(); return info; } @@ -85,6 +83,7 @@ namespace osu.Game.IO { var refetch = Connection.Find(f.First().ID); refetch.ReferenceCount += f.Count(); + Connection.Update(refetch); } Connection.SaveChanges(); @@ -94,8 +93,9 @@ namespace osu.Game.IO { foreach (var f in files.GroupBy(f => f.ID)) { - var accurateRefCount = Connection.Find(f.First().ID); - accurateRefCount.ReferenceCount -= f.Count(); + var refetch = Connection.Find(f.First().ID); + refetch.ReferenceCount -= f.Count(); + Connection.Update(refetch); } Connection.SaveChanges(); @@ -115,6 +115,8 @@ namespace osu.Game.IO Logger.Error(e, $@"Could not delete beatmap {f}"); } } + + Connection.SaveChanges(); } } } From ef10bb73db05785a42def26ca2820e1d567a1b68 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Oct 2017 10:25:25 +0900 Subject: [PATCH 0320/1263] osu.Game csproj fixes --- osu.Game/osu.Game.csproj | 62 +++++++++++++++++++++------------------- 1 file changed, 33 insertions(+), 29 deletions(-) diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index a442d1cef6..731e065a48 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -105,46 +105,46 @@ - ..\packages\Microsoft.Data.Sqlite.Core.2.0.0\lib\netstandard2.0\Microsoft.Data.Sqlite.dll + $(SolutionDir)\packages\Microsoft.Data.Sqlite.Core.2.0.0\lib\netstandard2.0\Microsoft.Data.Sqlite.dll - ..\packages\Microsoft.EntityFrameworkCore.2.0.0\lib\netstandard2.0\Microsoft.EntityFrameworkCore.dll + $(SolutionDir)\packages\Microsoft.EntityFrameworkCore.2.0.0\lib\netstandard2.0\Microsoft.EntityFrameworkCore.dll - ..\packages\Microsoft.EntityFrameworkCore.Design.2.0.0\lib\net461\Microsoft.EntityFrameworkCore.Design.dll + $(SolutionDir)\packages\Microsoft.EntityFrameworkCore.Design.2.0.0\lib\net461\Microsoft.EntityFrameworkCore.Design.dll - ..\packages\Microsoft.EntityFrameworkCore.Relational.2.0.0\lib\netstandard2.0\Microsoft.EntityFrameworkCore.Relational.dll + $(SolutionDir)\packages\Microsoft.EntityFrameworkCore.Relational.2.0.0\lib\netstandard2.0\Microsoft.EntityFrameworkCore.Relational.dll - ..\packages\Microsoft.EntityFrameworkCore.Sqlite.Core.2.0.0\lib\netstandard2.0\Microsoft.EntityFrameworkCore.Sqlite.dll + $(SolutionDir)\packages\Microsoft.EntityFrameworkCore.Sqlite.Core.2.0.0\lib\netstandard2.0\Microsoft.EntityFrameworkCore.Sqlite.dll - ..\packages\Microsoft.Extensions.Caching.Abstractions.2.0.0\lib\netstandard2.0\Microsoft.Extensions.Caching.Abstractions.dll + $(SolutionDir)\packages\Microsoft.Extensions.Caching.Abstractions.2.0.0\lib\netstandard2.0\Microsoft.Extensions.Caching.Abstractions.dll - ..\packages\Microsoft.Extensions.Caching.Memory.2.0.0\lib\netstandard2.0\Microsoft.Extensions.Caching.Memory.dll + $(SolutionDir)\packages\Microsoft.Extensions.Caching.Memory.2.0.0\lib\netstandard2.0\Microsoft.Extensions.Caching.Memory.dll - ..\packages\Microsoft.Extensions.Configuration.Abstractions.2.0.0\lib\netstandard2.0\Microsoft.Extensions.Configuration.Abstractions.dll + $(SolutionDir)\packages\Microsoft.Extensions.Configuration.Abstractions.2.0.0\lib\netstandard2.0\Microsoft.Extensions.Configuration.Abstractions.dll - ..\packages\Microsoft.Extensions.DependencyInjection.2.0.0\lib\netstandard2.0\Microsoft.Extensions.DependencyInjection.dll + $(SolutionDir)\packages\Microsoft.Extensions.DependencyInjection.2.0.0\lib\netstandard2.0\Microsoft.Extensions.DependencyInjection.dll - ..\packages\Microsoft.Extensions.DependencyInjection.Abstractions.2.0.0\lib\netstandard2.0\Microsoft.Extensions.DependencyInjection.Abstractions.dll + $(SolutionDir)\packages\Microsoft.Extensions.DependencyInjection.Abstractions.2.0.0\lib\netstandard2.0\Microsoft.Extensions.DependencyInjection.Abstractions.dll - ..\packages\Microsoft.Extensions.Logging.2.0.0\lib\netstandard2.0\Microsoft.Extensions.Logging.dll + $(SolutionDir)\packages\Microsoft.Extensions.Logging.2.0.0\lib\netstandard2.0\Microsoft.Extensions.Logging.dll - ..\packages\Microsoft.Extensions.Logging.Abstractions.2.0.0\lib\netstandard2.0\Microsoft.Extensions.Logging.Abstractions.dll + $(SolutionDir)\packages\Microsoft.Extensions.Logging.Abstractions.2.0.0\lib\netstandard2.0\Microsoft.Extensions.Logging.Abstractions.dll - ..\packages\Microsoft.Extensions.Options.2.0.0\lib\netstandard2.0\Microsoft.Extensions.Options.dll + $(SolutionDir)\packages\Microsoft.Extensions.Options.2.0.0\lib\netstandard2.0\Microsoft.Extensions.Options.dll - ..\packages\Microsoft.Extensions.Primitives.2.0.0\lib\netstandard2.0\Microsoft.Extensions.Primitives.dll + $(SolutionDir)\packages\Microsoft.Extensions.Primitives.2.0.0\lib\netstandard2.0\Microsoft.Extensions.Primitives.dll @@ -160,49 +160,53 @@ True - ..\packages\Remotion.Linq.2.1.2\lib\net45\Remotion.Linq.dll + $(SolutionDir)\packages\Remotion.Linq.2.1.2\lib\net45\Remotion.Linq.dll $(SolutionDir)\packages\SharpCompress.0.18.1\lib\net45\SharpCompress.dll True - ..\packages\SQLitePCLRaw.bundle_green.1.1.8\lib\net45\SQLitePCLRaw.batteries_green.dll + $(SolutionDir)\packages\SQLitePCLRaw.bundle_green.1.1.8\lib\net45\SQLitePCLRaw.batteries_green.dll + True - ..\packages\SQLitePCLRaw.bundle_green.1.1.8\lib\net45\SQLitePCLRaw.batteries_v2.dll + $(SolutionDir)\packages\SQLitePCLRaw.bundle_green.1.1.8\lib\net45\SQLitePCLRaw.batteries_v2.dll + True - ..\packages\SQLitePCLRaw.core.1.1.8\lib\net45\SQLitePCLRaw.core.dll + $(SolutionDir)\packages\SQLitePCLRaw.core.1.1.8\lib\net45\SQLitePCLRaw.core.dll + True - ..\packages\SQLitePCLRaw.provider.e_sqlite3.net45.1.1.8\lib\net45\SQLitePCLRaw.provider.e_sqlite3.dll + $(SolutionDir)\packages\SQLitePCLRaw.provider.e_sqlite3.net45.1.1.8\lib\net45\SQLitePCLRaw.provider.e_sqlite3.dll + True - ..\packages\System.Collections.Immutable.1.4.0\lib\netstandard2.0\System.Collections.Immutable.dll + $(SolutionDir)\packages\System.Collections.Immutable.1.4.0\lib\netstandard2.0\System.Collections.Immutable.dll - ..\packages\System.ComponentModel.Annotations.4.4.0\lib\net461\System.ComponentModel.Annotations.dll + $(SolutionDir)\packages\System.ComponentModel.Annotations.4.4.0\lib\net461\System.ComponentModel.Annotations.dll - ..\packages\System.Diagnostics.DiagnosticSource.4.4.1\lib\net46\System.Diagnostics.DiagnosticSource.dll + $(SolutionDir)\packages\System.Diagnostics.DiagnosticSource.4.4.1\lib\net46\System.Diagnostics.DiagnosticSource.dll - ..\packages\System.Interactive.Async.3.1.1\lib\net46\System.Interactive.Async.dll + $(SolutionDir)\packages\System.Interactive.Async.3.1.1\lib\net46\System.Interactive.Async.dll - ..\packages\System.Runtime.CompilerServices.Unsafe.4.4.0\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll + $(SolutionDir)\packages\System.Runtime.CompilerServices.Unsafe.4.4.0\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll - ..\packages\System.ValueTuple.4.4.0\lib\net461\System.ValueTuple.dll + $(SolutionDir)\packages\System.ValueTuple.4.4.0\lib\net461\System.ValueTuple.dll True - ../packages/System.ValueTuple.4.4.0/lib/net461/System.ValueTuple.dll + $(SolutionDir)\packages\System.ValueTuple.4.4.0\lib\net461\System.ValueTuple.dll True @@ -865,7 +869,7 @@ true true - - - + + + \ No newline at end of file From 31dc5c97f2e0399795767332bddab53a5959c24f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Oct 2017 11:10:55 +0900 Subject: [PATCH 0321/1263] Fix intro and duplicate inserts --- osu.Game/Beatmaps/BeatmapManager.cs | 2 +- osu.Game/Beatmaps/BeatmapStore.cs | 5 ++-- osu.Game/IO/FileStore.cs | 4 +--- osu.Game/Screens/Menu/Intro.cs | 1 - osu.Game/Screens/Select/SongSelect.cs | 34 +++++++++++++-------------- 5 files changed, 21 insertions(+), 25 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index af88f22e40..f546172bfe 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -501,7 +501,7 @@ namespace osu.Game.Beatmaps public List GetAllUsableBeatmapSets() { lock (beatmaps) - return beatmaps.BeatmapSets.ToList(); + return beatmaps.BeatmapSets.Where(s => !s.DeletePending).ToList(); } protected class BeatmapManagerWorkingBeatmap : WorkingBeatmap diff --git a/osu.Game/Beatmaps/BeatmapStore.cs b/osu.Game/Beatmaps/BeatmapStore.cs index 6464db86d4..ea5c5f7155 100644 --- a/osu.Game/Beatmaps/BeatmapStore.cs +++ b/osu.Game/Beatmaps/BeatmapStore.cs @@ -50,7 +50,7 @@ namespace osu.Game.Beatmaps /// The beatmap to add. public void Add(BeatmapSetInfo beatmapSet) { - Connection.BeatmapSetInfo.Add(beatmapSet); + Connection.BeatmapSetInfo.Attach(beatmapSet); Connection.SaveChanges(); BeatmapSetAdded?.Invoke(beatmapSet); @@ -135,8 +135,7 @@ namespace osu.Game.Beatmaps .Include(s => s.Beatmaps).ThenInclude(s => s.Ruleset) .Include(s => s.Beatmaps).ThenInclude(b => b.Difficulty) .Include(s => s.Beatmaps).ThenInclude(b => b.Metadata) - .Include(s => s.Files).ThenInclude(f => f.FileInfo) - .Where(s => !s.DeletePending); + .Include(s => s.Files).ThenInclude(f => f.FileInfo); public IEnumerable Beatmaps => Connection.BeatmapInfo .Include(b => b.BeatmapSet).ThenInclude(s => s.Metadata) diff --git a/osu.Game/IO/FileStore.cs b/osu.Game/IO/FileStore.cs index ae0cfb30c8..19237c6063 100644 --- a/osu.Game/IO/FileStore.cs +++ b/osu.Game/IO/FileStore.cs @@ -66,10 +66,8 @@ namespace osu.Game.IO } if (existing == null) - { + // SaveChanges is performed in Reference. Connection.FileInfo.Add(info); - Connection.SaveChanges(); - } if (reference || existing == null) Reference(info); diff --git a/osu.Game/Screens/Menu/Intro.cs b/osu.Game/Screens/Menu/Intro.cs index b597fc11e4..ee84cf2d30 100644 --- a/osu.Game/Screens/Menu/Intro.cs +++ b/osu.Game/Screens/Menu/Intro.cs @@ -89,7 +89,6 @@ namespace osu.Game.Screens.Menu { // we need to import the default menu background beatmap setInfo = beatmaps.Import(new OszArchiveReader(game.Resources.GetStream(@"Tracks/circles.osz"))); - setInfo.Protected = true; } } diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index b11613634a..e11eed7040 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -26,7 +26,7 @@ namespace osu.Game.Screens.Select { public abstract class SongSelect : OsuScreen { - private BeatmapManager manager; + private BeatmapManager beatmaps; protected override BackgroundScreen CreateBackground() => new BackgroundScreenBeatmap(); private readonly BeatmapCarousel carousel; @@ -108,9 +108,9 @@ namespace osu.Game.Screens.Select SelectionChanged = carouselSelectionChanged, BeatmapsChanged = carouselBeatmapsLoaded, DeleteRequested = promptDelete, - RestoreRequested = s => { foreach (var b in s.Beatmaps) manager.Restore(b); }, + RestoreRequested = s => { foreach (var b in s.Beatmaps) beatmaps.Restore(b); }, EditRequested = editRequested, - HideDifficultyRequested = b => manager.Hide(b), + HideDifficultyRequested = b => beatmaps.Hide(b), StartRequested = () => carouselRaisedStart(), }); Add(FilterControl = new FilterControl @@ -171,16 +171,16 @@ namespace osu.Game.Screens.Select BeatmapOptions.AddButton(@"Delete", @"Beatmap", FontAwesome.fa_trash, colours.Pink, () => promptDelete(Beatmap.Value.BeatmapSetInfo), Key.Number4, float.MaxValue); } - if (manager == null) - manager = beatmaps; + if (this.beatmaps == null) + this.beatmaps = beatmaps; if (osu != null) Ruleset.BindTo(osu.Ruleset); - manager.BeatmapSetAdded += onBeatmapSetAdded; - manager.BeatmapSetRemoved += onBeatmapSetRemoved; - manager.BeatmapHidden += onBeatmapHidden; - manager.BeatmapRestored += onBeatmapRestored; + this.beatmaps.BeatmapSetAdded += onBeatmapSetAdded; + this.beatmaps.BeatmapSetRemoved += onBeatmapSetRemoved; + this.beatmaps.BeatmapHidden += onBeatmapHidden; + this.beatmaps.BeatmapRestored += onBeatmapRestored; dialogOverlay = dialog; @@ -189,7 +189,7 @@ namespace osu.Game.Screens.Select initialAddSetsTask = new CancellationTokenSource(); - carousel.Beatmaps = manager.GetAllUsableBeatmapSets(); + carousel.Beatmaps = this.beatmaps.GetAllUsableBeatmapSets(); Beatmap.ValueChanged += beatmap_ValueChanged; @@ -199,7 +199,7 @@ namespace osu.Game.Screens.Select private void editRequested(BeatmapInfo beatmap) { - Beatmap.Value = manager.GetWorkingBeatmap(beatmap, Beatmap); + Beatmap.Value = beatmaps.GetWorkingBeatmap(beatmap, Beatmap); Push(new Editor()); } @@ -248,7 +248,7 @@ namespace osu.Game.Screens.Select { bool preview = beatmap?.BeatmapSetInfoID != Beatmap.Value.BeatmapInfo.BeatmapSetInfoID; - Beatmap.Value = manager.GetWorkingBeatmap(beatmap, Beatmap); + Beatmap.Value = beatmaps.GetWorkingBeatmap(beatmap, Beatmap); ensurePlayingSelected(preview); } @@ -357,12 +357,12 @@ namespace osu.Game.Screens.Select { base.Dispose(isDisposing); - if (manager != null) + if (beatmaps != null) { - manager.BeatmapSetAdded -= onBeatmapSetAdded; - manager.BeatmapSetRemoved -= onBeatmapSetRemoved; - manager.BeatmapHidden -= onBeatmapHidden; - manager.BeatmapRestored -= onBeatmapRestored; + beatmaps.BeatmapSetAdded -= onBeatmapSetAdded; + beatmaps.BeatmapSetRemoved -= onBeatmapSetRemoved; + beatmaps.BeatmapHidden -= onBeatmapHidden; + beatmaps.BeatmapRestored -= onBeatmapRestored; } initialAddSetsTask?.Cancel(); From 0df474accb7a10ec10aa9c2fa17b71c1e1bdd4f0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Oct 2017 11:22:50 +0900 Subject: [PATCH 0322/1263] Simplify file storing --- osu.Game/IO/FileStore.cs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/osu.Game/IO/FileStore.cs b/osu.Game/IO/FileStore.cs index 19237c6063..ede85ad42f 100644 --- a/osu.Game/IO/FileStore.cs +++ b/osu.Game/IO/FileStore.cs @@ -65,10 +65,6 @@ namespace osu.Game.IO data.Seek(0, SeekOrigin.Begin); } - if (existing == null) - // SaveChanges is performed in Reference. - Connection.FileInfo.Add(info); - if (reference || existing == null) Reference(info); @@ -79,9 +75,9 @@ namespace osu.Game.IO { foreach (var f in files.GroupBy(f => f.ID)) { - var refetch = Connection.Find(f.First().ID); + var refetch = Connection.Find(f.First().ID) ?? f.First(); refetch.ReferenceCount += f.Count(); - Connection.Update(refetch); + Connection.FileInfo.Update(refetch); } Connection.SaveChanges(); From c92e0e2dc19f56fe770ddfbf75e658f67feac35f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Oct 2017 11:24:59 +0900 Subject: [PATCH 0323/1263] Fix username display on beatmap panels --- osu.Game/Beatmaps/Drawables/BeatmapPanel.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Beatmaps/Drawables/BeatmapPanel.cs b/osu.Game/Beatmaps/Drawables/BeatmapPanel.cs index e216f1b83e..c0705d8f61 100644 --- a/osu.Game/Beatmaps/Drawables/BeatmapPanel.cs +++ b/osu.Game/Beatmaps/Drawables/BeatmapPanel.cs @@ -135,7 +135,7 @@ namespace osu.Game.Beatmaps.Drawables new OsuSpriteText { Font = @"Exo2.0-MediumItalic", - Text = $"{(beatmap.Metadata ?? beatmap.BeatmapSet.Metadata).Author}", + Text = $"{(beatmap.Metadata ?? beatmap.BeatmapSet.Metadata).Author.Username}", TextSize = 16, Anchor = Anchor.BottomLeft, Origin = Anchor.BottomLeft From 66894d11ea1c1b8358fbe81dc01752a6fea67361 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Oct 2017 11:39:47 +0900 Subject: [PATCH 0324/1263] Connection -> context --- osu.Game/Beatmaps/BeatmapManager.cs | 4 +-- osu.Game/Beatmaps/BeatmapStore.cs | 42 ++++++++++++------------ osu.Game/Database/DatabaseBackedStore.cs | 6 ++-- osu.Game/IO/FileStore.cs | 24 +++++++------- osu.Game/Input/KeyBindingStore.cs | 16 ++++----- osu.Game/Rulesets/RulesetStore.cs | 24 +++++++------- osu.Game/Rulesets/Scoring/ScoreStore.cs | 2 +- 7 files changed, 59 insertions(+), 59 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index f546172bfe..7d174e6a28 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -80,9 +80,9 @@ namespace osu.Game.Beatmaps /// public Func GetStableStorage { private get; set; } - public BeatmapManager(Storage storage, FileStore files, OsuDbContext connection, RulesetStore rulesets, APIAccess api, IIpcHost importHost = null) + public BeatmapManager(Storage storage, FileStore files, OsuDbContext context, RulesetStore rulesets, APIAccess api, IIpcHost importHost = null) { - beatmaps = new BeatmapStore(connection); + beatmaps = new BeatmapStore(context); beatmaps.BeatmapSetAdded += s => BeatmapSetAdded?.Invoke(s); beatmaps.BeatmapSetRemoved += s => BeatmapSetRemoved?.Invoke(s); beatmaps.BeatmapHidden += b => BeatmapHidden?.Invoke(b); diff --git a/osu.Game/Beatmaps/BeatmapStore.cs b/osu.Game/Beatmaps/BeatmapStore.cs index ea5c5f7155..134059fd07 100644 --- a/osu.Game/Beatmaps/BeatmapStore.cs +++ b/osu.Game/Beatmaps/BeatmapStore.cs @@ -20,8 +20,8 @@ namespace osu.Game.Beatmaps public event Action BeatmapHidden; public event Action BeatmapRestored; - public BeatmapStore(OsuDbContext connection) - : base(connection) + public BeatmapStore(OsuDbContext context) + : base(context) { } @@ -30,11 +30,11 @@ namespace osu.Game.Beatmaps if (reset) { // https://stackoverflow.com/a/10450893 - Connection.Database.ExecuteSqlCommand("DELETE FROM BeatmapMetadata"); - Connection.Database.ExecuteSqlCommand("DELETE FROM BeatmapDifficulty"); - Connection.Database.ExecuteSqlCommand("DELETE FROM BeatmapSetInfo"); - Connection.Database.ExecuteSqlCommand("DELETE FROM BeatmapSetFileInfo"); - Connection.Database.ExecuteSqlCommand("DELETE FROM BeatmapInfo"); + Context.Database.ExecuteSqlCommand("DELETE FROM BeatmapMetadata"); + Context.Database.ExecuteSqlCommand("DELETE FROM BeatmapDifficulty"); + Context.Database.ExecuteSqlCommand("DELETE FROM BeatmapSetInfo"); + Context.Database.ExecuteSqlCommand("DELETE FROM BeatmapSetFileInfo"); + Context.Database.ExecuteSqlCommand("DELETE FROM BeatmapInfo"); } } @@ -50,8 +50,8 @@ namespace osu.Game.Beatmaps /// The beatmap to add. public void Add(BeatmapSetInfo beatmapSet) { - Connection.BeatmapSetInfo.Attach(beatmapSet); - Connection.SaveChanges(); + Context.BeatmapSetInfo.Attach(beatmapSet); + Context.SaveChanges(); BeatmapSetAdded?.Invoke(beatmapSet); } @@ -66,8 +66,8 @@ namespace osu.Game.Beatmaps if (beatmapSet.DeletePending) return false; beatmapSet.DeletePending = true; - Connection.BeatmapSetInfo.Update(beatmapSet); - Connection.SaveChanges(); + Context.BeatmapSetInfo.Update(beatmapSet); + Context.SaveChanges(); BeatmapSetRemoved?.Invoke(beatmapSet); return true; @@ -83,8 +83,8 @@ namespace osu.Game.Beatmaps if (!beatmapSet.DeletePending) return false; beatmapSet.DeletePending = false; - Connection.BeatmapSetInfo.Update(beatmapSet); - Connection.SaveChanges(); + Context.BeatmapSetInfo.Update(beatmapSet); + Context.SaveChanges(); BeatmapSetAdded?.Invoke(beatmapSet); return true; @@ -100,8 +100,8 @@ namespace osu.Game.Beatmaps if (beatmap.Hidden) return false; beatmap.Hidden = true; - Connection.BeatmapInfo.Update(beatmap); - Connection.SaveChanges(); + Context.BeatmapInfo.Update(beatmap); + Context.SaveChanges(); BeatmapHidden?.Invoke(beatmap); return true; @@ -117,8 +117,8 @@ namespace osu.Game.Beatmaps if (!beatmap.Hidden) return false; beatmap.Hidden = false; - Connection.BeatmapInfo.Update(beatmap); - Connection.SaveChanges(); + Context.BeatmapInfo.Update(beatmap); + Context.SaveChanges(); BeatmapRestored?.Invoke(beatmap); return true; @@ -126,18 +126,18 @@ namespace osu.Game.Beatmaps private void cleanupPendingDeletions() { - Connection.BeatmapSetInfo.RemoveRange(Connection.BeatmapSetInfo.Where(b => b.DeletePending && !b.Protected)); - Connection.SaveChanges(); + Context.BeatmapSetInfo.RemoveRange(Context.BeatmapSetInfo.Where(b => b.DeletePending && !b.Protected)); + Context.SaveChanges(); } - public IEnumerable BeatmapSets => Connection.BeatmapSetInfo + public IEnumerable BeatmapSets => Context.BeatmapSetInfo .Include(s => s.Metadata) .Include(s => s.Beatmaps).ThenInclude(s => s.Ruleset) .Include(s => s.Beatmaps).ThenInclude(b => b.Difficulty) .Include(s => s.Beatmaps).ThenInclude(b => b.Metadata) .Include(s => s.Files).ThenInclude(f => f.FileInfo); - public IEnumerable Beatmaps => Connection.BeatmapInfo + public IEnumerable Beatmaps => Context.BeatmapInfo .Include(b => b.BeatmapSet).ThenInclude(s => s.Metadata) .Include(b => b.Metadata) .Include(b => b.Ruleset) diff --git a/osu.Game/Database/DatabaseBackedStore.cs b/osu.Game/Database/DatabaseBackedStore.cs index adddad6122..0cfe2adb44 100644 --- a/osu.Game/Database/DatabaseBackedStore.cs +++ b/osu.Game/Database/DatabaseBackedStore.cs @@ -10,12 +10,12 @@ namespace osu.Game.Database public abstract class DatabaseBackedStore { protected readonly Storage Storage; - protected readonly OsuDbContext Connection; + protected readonly OsuDbContext Context; - protected DatabaseBackedStore(OsuDbContext connection, Storage storage = null) + protected DatabaseBackedStore(OsuDbContext context, Storage storage = null) { Storage = storage; - Connection = connection; + Context = context; try { diff --git a/osu.Game/IO/FileStore.cs b/osu.Game/IO/FileStore.cs index ede85ad42f..ed295c76b2 100644 --- a/osu.Game/IO/FileStore.cs +++ b/osu.Game/IO/FileStore.cs @@ -22,7 +22,7 @@ namespace osu.Game.IO public readonly ResourceStore Store; - public FileStore(OsuDbContext connection, Storage storage) : base(connection, storage) + public FileStore(OsuDbContext context, Storage storage) : base(context, storage) { Store = new NamespacedResourceStore(new StorageBackedResourceStore(storage), prefix); } @@ -34,7 +34,7 @@ namespace osu.Game.IO if (Storage.ExistsDirectory(prefix)) Storage.DeleteDirectory(prefix); - Connection.Database.ExecuteSqlCommand("DELETE FROM FileInfo"); + Context.Database.ExecuteSqlCommand("DELETE FROM FileInfo"); } } @@ -48,7 +48,7 @@ namespace osu.Game.IO { string hash = data.ComputeSHA2Hash(); - var existing = Connection.FileInfo.FirstOrDefault(f => f.Hash == hash); + var existing = Context.FileInfo.FirstOrDefault(f => f.Hash == hash); var info = existing ?? new FileInfo { Hash = hash }; @@ -75,34 +75,34 @@ namespace osu.Game.IO { foreach (var f in files.GroupBy(f => f.ID)) { - var refetch = Connection.Find(f.First().ID) ?? f.First(); + var refetch = Context.Find(f.First().ID) ?? f.First(); refetch.ReferenceCount += f.Count(); - Connection.FileInfo.Update(refetch); + Context.FileInfo.Update(refetch); } - Connection.SaveChanges(); + Context.SaveChanges(); } public void Dereference(params FileInfo[] files) { foreach (var f in files.GroupBy(f => f.ID)) { - var refetch = Connection.Find(f.First().ID); + var refetch = Context.Find(f.First().ID); refetch.ReferenceCount -= f.Count(); - Connection.Update(refetch); + Context.Update(refetch); } - Connection.SaveChanges(); + Context.SaveChanges(); } private void deletePending() { - foreach (var f in Connection.FileInfo.Where(f => f.ReferenceCount < 1)) + foreach (var f in Context.FileInfo.Where(f => f.ReferenceCount < 1)) { try { Storage.Delete(Path.Combine(prefix, f.StoragePath)); - Connection.FileInfo.Remove(f); + Context.FileInfo.Remove(f); } catch (Exception e) { @@ -110,7 +110,7 @@ namespace osu.Game.IO } } - Connection.SaveChanges(); + Context.SaveChanges(); } } } diff --git a/osu.Game/Input/KeyBindingStore.cs b/osu.Game/Input/KeyBindingStore.cs index 9edab896b3..2d0aabdd7f 100644 --- a/osu.Game/Input/KeyBindingStore.cs +++ b/osu.Game/Input/KeyBindingStore.cs @@ -14,8 +14,8 @@ namespace osu.Game.Input { public class KeyBindingStore : DatabaseBackedStore { - public KeyBindingStore(OsuDbContext connection, RulesetStore rulesets, Storage storage = null) - : base(connection, storage) + public KeyBindingStore(OsuDbContext context, RulesetStore rulesets, Storage storage = null) + : base(context, storage) { foreach (var info in rulesets.AvailableRulesets) { @@ -30,7 +30,7 @@ namespace osu.Game.Input protected override void Prepare(bool reset = false) { if (reset) - Connection.Database.ExecuteSqlCommand("DELETE FROM KeyBinding"); + Context.Database.ExecuteSqlCommand("DELETE FROM KeyBinding"); } private void insertDefaults(IEnumerable defaults, int? rulesetId = null, int? variant = null) @@ -46,7 +46,7 @@ namespace osu.Game.Input foreach (var insertable in group.Skip(count).Take(aimCount - count)) // insert any defaults which are missing. - Connection.DatabasedKeyBinding.Add(new DatabasedKeyBinding + Context.DatabasedKeyBinding.Add(new DatabasedKeyBinding { KeyCombination = insertable.KeyCombination, Action = insertable.Action, @@ -55,7 +55,7 @@ namespace osu.Game.Input }); } - Connection.SaveChanges(); + Context.SaveChanges(); } /// @@ -64,12 +64,12 @@ namespace osu.Game.Input /// The ruleset's internal ID. /// An optional variant. /// - public IEnumerable Query(int? rulesetId = null, int? variant = null) => Connection.DatabasedKeyBinding.Where(b => b.RulesetID == rulesetId && b.Variant == variant); + public IEnumerable Query(int? rulesetId = null, int? variant = null) => Context.DatabasedKeyBinding.Where(b => b.RulesetID == rulesetId && b.Variant == variant); public void Update(KeyBinding keyBinding) { - Connection.Update(keyBinding); - Connection.SaveChanges(); + Context.Update(keyBinding); + Context.SaveChanges(); } } } diff --git a/osu.Game/Rulesets/RulesetStore.cs b/osu.Game/Rulesets/RulesetStore.cs index c39312205c..82252b76fa 100644 --- a/osu.Game/Rulesets/RulesetStore.cs +++ b/osu.Game/Rulesets/RulesetStore.cs @@ -26,8 +26,8 @@ namespace osu.Game.Rulesets loadRulesetFromFile(file); } - public RulesetStore(OsuDbContext connection) - : base(connection) + public RulesetStore(OsuDbContext context) + : base(context) { } @@ -41,7 +41,7 @@ namespace osu.Game.Rulesets /// /// All available rulesets. /// - public IEnumerable AvailableRulesets => Connection.RulesetInfo.Where(r => r.Available); + public IEnumerable AvailableRulesets => Context.RulesetInfo.Where(r => r.Available); private static Assembly currentDomain_AssemblyResolve(object sender, ResolveEventArgs args) => loaded_assemblies.Keys.FirstOrDefault(a => a.FullName == args.Name); @@ -51,7 +51,7 @@ namespace osu.Game.Rulesets { if (reset) { - Connection.Database.ExecuteSqlCommand("DELETE FROM RulesetInfo"); + Context.Database.ExecuteSqlCommand("DELETE FROM RulesetInfo"); } var instances = loaded_assemblies.Values.Select(r => (Ruleset)Activator.CreateInstance(r, new RulesetInfo())).ToList(); @@ -60,29 +60,29 @@ namespace osu.Game.Rulesets foreach (var r in instances.Where(r => r.LegacyID >= 0).OrderBy(r => r.LegacyID)) { var rulesetInfo = createRulesetInfo(r); - if (Connection.RulesetInfo.SingleOrDefault(rsi => rsi.ID == rulesetInfo.ID) == null) + if (Context.RulesetInfo.SingleOrDefault(rsi => rsi.ID == rulesetInfo.ID) == null) { - Connection.RulesetInfo.Add(rulesetInfo); + Context.RulesetInfo.Add(rulesetInfo); } } - Connection.SaveChanges(); + Context.SaveChanges(); //add any other modes foreach (var r in instances.Where(r => r.LegacyID < 0)) { var us = createRulesetInfo(r); - var existing = Connection.RulesetInfo.FirstOrDefault(ri => ri.InstantiationInfo == us.InstantiationInfo); + var existing = Context.RulesetInfo.FirstOrDefault(ri => ri.InstantiationInfo == us.InstantiationInfo); if (existing == null) - Connection.RulesetInfo.Add(us); + Context.RulesetInfo.Add(us); } - Connection.SaveChanges(); + Context.SaveChanges(); //perform a consistency check - foreach (var r in Connection.RulesetInfo) + foreach (var r in Context.RulesetInfo) { try { @@ -95,7 +95,7 @@ namespace osu.Game.Rulesets } } - Connection.SaveChanges(); + Context.SaveChanges(); } private static void loadRulesetFromFile(string file) diff --git a/osu.Game/Rulesets/Scoring/ScoreStore.cs b/osu.Game/Rulesets/Scoring/ScoreStore.cs index 66fcfb5d67..02dd5c40ac 100644 --- a/osu.Game/Rulesets/Scoring/ScoreStore.cs +++ b/osu.Game/Rulesets/Scoring/ScoreStore.cs @@ -25,7 +25,7 @@ namespace osu.Game.Rulesets.Scoring // ReSharper disable once NotAccessedField.Local (we should keep a reference to this so it is not finalised) private ScoreIPCChannel ipc; - public ScoreStore(Storage storage, OsuDbContext connection, IIpcHost importHost = null, BeatmapManager beatmaps = null, RulesetStore rulesets = null) : base(connection) + public ScoreStore(Storage storage, OsuDbContext context, IIpcHost importHost = null, BeatmapManager beatmaps = null, RulesetStore rulesets = null) : base(context) { this.storage = storage; this.beatmaps = beatmaps; From fe44a28d48ead86d187ee2ee83aaf3b43ba1d4fc Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Oct 2017 12:46:38 +0900 Subject: [PATCH 0325/1263] Add back startup tasks runner --- osu.Game/Database/DatabaseBackedStore.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Database/DatabaseBackedStore.cs b/osu.Game/Database/DatabaseBackedStore.cs index 0cfe2adb44..cba334d58a 100644 --- a/osu.Game/Database/DatabaseBackedStore.cs +++ b/osu.Game/Database/DatabaseBackedStore.cs @@ -26,6 +26,8 @@ namespace osu.Game.Database Logger.Error(e, $@"Failed to initialise the {GetType()}! Trying again with a clean database..."); Prepare(true); } + + StartupTasks(); } /// From cd41862e3bcfd579b40eea94c84cb00c8d1d62ff Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Oct 2017 15:00:27 +0900 Subject: [PATCH 0326/1263] Add back transaction support for beatmap importing --- osu.Game/Beatmaps/BeatmapManager.cs | 56 +++++++++++-------- osu.Game/Beatmaps/BeatmapStore.cs | 4 +- osu.Game/Database/DatabaseBackedStore.cs | 9 ++- osu.Game/Database/DatabaseContextFactory.cs | 19 +++++++ osu.Game/IO/FileStore.cs | 2 +- osu.Game/Input/KeyBindingStore.cs | 5 +- osu.Game/OsuGameBase.cs | 18 +++--- osu.Game/Rulesets/RulesetStore.cs | 4 +- osu.Game/Rulesets/Scoring/ScoreStore.cs | 3 +- .../Tests/Visual/TestCasePlaySongSelect.cs | 11 ++-- osu.Game/osu.Game.csproj | 1 + 11 files changed, 84 insertions(+), 48 deletions(-) create mode 100644 osu.Game/Database/DatabaseContextFactory.cs diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 7d174e6a28..1423e9138f 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -57,6 +57,18 @@ namespace osu.Game.Beatmaps private readonly Storage storage; + private BeatmapStore createBeatmapStore(Func context) + { + var store = new BeatmapStore(context); + store.BeatmapSetAdded += s => BeatmapSetAdded?.Invoke(s); + store.BeatmapSetRemoved += s => BeatmapSetRemoved?.Invoke(s); + store.BeatmapHidden += b => BeatmapHidden?.Invoke(b); + store.BeatmapRestored += b => BeatmapRestored?.Invoke(b); + return store; + } + + private readonly Func createContext; + private readonly FileStore files; private readonly RulesetStore rulesets; @@ -80,16 +92,13 @@ namespace osu.Game.Beatmaps /// public Func GetStableStorage { private get; set; } - public BeatmapManager(Storage storage, FileStore files, OsuDbContext context, RulesetStore rulesets, APIAccess api, IIpcHost importHost = null) + public BeatmapManager(Storage storage, Func context, RulesetStore rulesets, APIAccess api, IIpcHost importHost = null) { - beatmaps = new BeatmapStore(context); - beatmaps.BeatmapSetAdded += s => BeatmapSetAdded?.Invoke(s); - beatmaps.BeatmapSetRemoved += s => BeatmapSetRemoved?.Invoke(s); - beatmaps.BeatmapHidden += b => BeatmapHidden?.Invoke(b); - beatmaps.BeatmapRestored += b => BeatmapRestored?.Invoke(b); + createContext = context; + beatmaps = createBeatmapStore(context); + files = new FileStore(context, storage); this.storage = storage; - this.files = files; this.rulesets = rulesets; this.api = api; @@ -160,13 +169,24 @@ namespace osu.Game.Beatmaps /// The beatmap to be imported. public BeatmapSetInfo Import(ArchiveReader archiveReader) { - BeatmapSetInfo set; - // let's only allow one concurrent import at a time for now. lock (importLock) - Import(set = importToStorage(archiveReader)); + { + var context = createContext(); - return set; + using (var transaction = context.Database.BeginTransaction()) + { + // create local stores so we can isolate and thread safely, and share a context/transaction. + var filesForImport = new FileStore(() => context, storage); + var beatmapsForImport = createBeatmapStore(() => context); + + BeatmapSetInfo set = importToStorage(filesForImport, archiveReader); + beatmapsForImport.Add(set); + context.SaveChanges(); + transaction.Commit(); + return set; + } + } } /// @@ -178,8 +198,7 @@ namespace osu.Game.Beatmaps // If we have an ID then we already exist in the database. if (beatmapSetInfo.ID != 0) return; - lock (beatmaps) - beatmaps.Add(beatmapSetInfo); + createBeatmapStore(createContext).Add(beatmapSetInfo); } /// @@ -322,15 +341,6 @@ namespace osu.Game.Beatmaps return working; } - /// - /// Reset the manager to an empty state. - /// - public void Reset() - { - lock (beatmaps) - beatmaps.Reset(); - } - /// /// Perform a lookup query on available s. /// @@ -400,7 +410,7 @@ namespace osu.Game.Beatmaps /// /// The beatmap archive to be read. /// The imported beatmap, or an existing instance if it is already present. - private BeatmapSetInfo importToStorage(ArchiveReader reader) + private BeatmapSetInfo importToStorage(FileStore files, ArchiveReader reader) { // let's make sure there are actually .osu files to import. string mapName = reader.Filenames.FirstOrDefault(f => f.EndsWith(".osu")); diff --git a/osu.Game/Beatmaps/BeatmapStore.cs b/osu.Game/Beatmaps/BeatmapStore.cs index 134059fd07..f3d3caeb0f 100644 --- a/osu.Game/Beatmaps/BeatmapStore.cs +++ b/osu.Game/Beatmaps/BeatmapStore.cs @@ -20,8 +20,8 @@ namespace osu.Game.Beatmaps public event Action BeatmapHidden; public event Action BeatmapRestored; - public BeatmapStore(OsuDbContext context) - : base(context) + public BeatmapStore(Func factory) + : base(factory) { } diff --git a/osu.Game/Database/DatabaseBackedStore.cs b/osu.Game/Database/DatabaseBackedStore.cs index cba334d58a..9d3d020250 100644 --- a/osu.Game/Database/DatabaseBackedStore.cs +++ b/osu.Game/Database/DatabaseBackedStore.cs @@ -10,12 +10,15 @@ namespace osu.Game.Database public abstract class DatabaseBackedStore { protected readonly Storage Storage; - protected readonly OsuDbContext Context; - protected DatabaseBackedStore(OsuDbContext context, Storage storage = null) + private readonly Func contextSource; + + protected OsuDbContext Context => contextSource(); + + protected DatabaseBackedStore(Func contextSource, Storage storage = null) { Storage = storage; - Context = context; + this.contextSource = contextSource; try { diff --git a/osu.Game/Database/DatabaseContextFactory.cs b/osu.Game/Database/DatabaseContextFactory.cs new file mode 100644 index 0000000000..3fc5141880 --- /dev/null +++ b/osu.Game/Database/DatabaseContextFactory.cs @@ -0,0 +1,19 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE + +using osu.Framework.Platform; + +namespace osu.Game.Database +{ + public class DatabaseContextFactory + { + private readonly GameHost host; + + public DatabaseContextFactory(GameHost host) + { + this.host = host; + } + + public OsuDbContext GetContext() => new OsuDbContext(host.Storage.GetDatabaseConnectionString(@"client")); + } +} diff --git a/osu.Game/IO/FileStore.cs b/osu.Game/IO/FileStore.cs index ed295c76b2..d715ccd0a7 100644 --- a/osu.Game/IO/FileStore.cs +++ b/osu.Game/IO/FileStore.cs @@ -22,7 +22,7 @@ namespace osu.Game.IO public readonly ResourceStore Store; - public FileStore(OsuDbContext context, Storage storage) : base(context, storage) + public FileStore(Func contextSource, Storage storage) : base(contextSource, storage) { Store = new NamespacedResourceStore(new StorageBackedResourceStore(storage), prefix); } diff --git a/osu.Game/Input/KeyBindingStore.cs b/osu.Game/Input/KeyBindingStore.cs index 2d0aabdd7f..5c41179418 100644 --- a/osu.Game/Input/KeyBindingStore.cs +++ b/osu.Game/Input/KeyBindingStore.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 Microsoft.EntityFrameworkCore; @@ -14,8 +15,8 @@ namespace osu.Game.Input { public class KeyBindingStore : DatabaseBackedStore { - public KeyBindingStore(OsuDbContext context, RulesetStore rulesets, Storage storage = null) - : base(context, storage) + public KeyBindingStore(Func contextSource, RulesetStore rulesets, Storage storage = null) + : base(contextSource, storage) { foreach (var info in rulesets.AvailableRulesets) { diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index d1e684499c..5ecc7279da 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -81,16 +81,18 @@ namespace osu.Game protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent) => dependencies = new DependencyContainer(base.CreateLocalDependencies(parent)); - private OsuDbContext createDbContext() => new OsuDbContext(Host.Storage.GetDatabaseConnectionString(@"client")); + private DatabaseContextFactory contextFactory; [BackgroundDependencyLoader] private void load() { + dependencies.Cache(contextFactory = new DatabaseContextFactory(Host)); + dependencies.Cache(this); dependencies.Cache(LocalConfig); - using (var dbContext = createDbContext()) - dbContext.Database.Migrate(); + using (var context = contextFactory.GetContext()) + context.Database.Migrate(); dependencies.Cache(API = new APIAccess { @@ -98,11 +100,11 @@ namespace osu.Game Token = LocalConfig.Get(OsuSetting.Token) }); - dependencies.Cache(RulesetStore = new RulesetStore(createDbContext())); - dependencies.Cache(FileStore = new FileStore(createDbContext(), Host.Storage)); - dependencies.Cache(BeatmapManager = new BeatmapManager(Host.Storage, FileStore, createDbContext(), RulesetStore, API, Host)); - dependencies.Cache(ScoreStore = new ScoreStore(Host.Storage, createDbContext(), Host, BeatmapManager, RulesetStore)); - dependencies.Cache(KeyBindingStore = new KeyBindingStore(createDbContext(), RulesetStore)); + dependencies.Cache(RulesetStore = new RulesetStore(contextFactory.GetContext)); + dependencies.Cache(FileStore = new FileStore(contextFactory.GetContext, Host.Storage)); + dependencies.Cache(BeatmapManager = new BeatmapManager(Host.Storage, contextFactory.GetContext, RulesetStore, API, Host)); + dependencies.Cache(ScoreStore = new ScoreStore(Host.Storage, contextFactory.GetContext, Host, BeatmapManager, RulesetStore)); + dependencies.Cache(KeyBindingStore = new KeyBindingStore(contextFactory.GetContext, RulesetStore)); dependencies.Cache(new OsuColour()); //this completely overrides the framework default. will need to change once we make a proper FontStore. diff --git a/osu.Game/Rulesets/RulesetStore.cs b/osu.Game/Rulesets/RulesetStore.cs index 82252b76fa..bd3c22fc42 100644 --- a/osu.Game/Rulesets/RulesetStore.cs +++ b/osu.Game/Rulesets/RulesetStore.cs @@ -26,8 +26,8 @@ namespace osu.Game.Rulesets loadRulesetFromFile(file); } - public RulesetStore(OsuDbContext context) - : base(context) + public RulesetStore(Func factory) + : base(factory) { } diff --git a/osu.Game/Rulesets/Scoring/ScoreStore.cs b/osu.Game/Rulesets/Scoring/ScoreStore.cs index 02dd5c40ac..67a8e5372e 100644 --- a/osu.Game/Rulesets/Scoring/ScoreStore.cs +++ b/osu.Game/Rulesets/Scoring/ScoreStore.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.IO; using osu.Framework.Platform; @@ -25,7 +26,7 @@ namespace osu.Game.Rulesets.Scoring // ReSharper disable once NotAccessedField.Local (we should keep a reference to this so it is not finalised) private ScoreIPCChannel ipc; - public ScoreStore(Storage storage, OsuDbContext context, IIpcHost importHost = null, BeatmapManager beatmaps = null, RulesetStore rulesets = null) : base(context) + public ScoreStore(Storage storage, Func factory, IIpcHost importHost = null, BeatmapManager beatmaps = null, RulesetStore rulesets = null) : base(factory) { this.storage = storage; this.beatmaps = beatmaps; diff --git a/osu.Game/Tests/Visual/TestCasePlaySongSelect.cs b/osu.Game/Tests/Visual/TestCasePlaySongSelect.cs index a8a00e9a0d..9ca6aa2fb5 100644 --- a/osu.Game/Tests/Visual/TestCasePlaySongSelect.cs +++ b/osu.Game/Tests/Visual/TestCasePlaySongSelect.cs @@ -1,13 +1,13 @@ // 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.Allocation; using osu.Framework.MathUtils; using osu.Game.Beatmaps; using osu.Game.Database; -using osu.Game.IO; using osu.Game.Rulesets; using osu.Game.Screens.Select; using osu.Game.Screens.Select.Filter; @@ -25,8 +25,6 @@ namespace osu.Game.Tests.Visual private DependencyContainer dependencies; - private FileStore files; - protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent) => dependencies = new DependencyContainer(parent); [BackgroundDependencyLoader] @@ -40,9 +38,10 @@ namespace osu.Game.Tests.Visual var dbConnectionString = storage.GetDatabaseConnectionString(@"client"); - dependencies.Cache(rulesets = new RulesetStore(new OsuDbContext(dbConnectionString))); - dependencies.Cache(files = new FileStore(new OsuDbContext(dbConnectionString), storage)); - dependencies.Cache(manager = new BeatmapManager(storage, files, new OsuDbContext(dbConnectionString), rulesets, null)); + Func contextFactory = () => new OsuDbContext(dbConnectionString); + + dependencies.Cache(rulesets = new RulesetStore(contextFactory)); + dependencies.Cache(manager = new BeatmapManager(storage, contextFactory, rulesets, null)); for (int i = 0; i < 100; i += 10) manager.Import(createTestBeatmapSet(i)); diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 731e065a48..d3ac2d6189 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -285,6 +285,7 @@ + 20171014052545_Init.cs From e487b6f82a18543592c4f209f5d428881a774d72 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Oct 2017 15:50:42 +0900 Subject: [PATCH 0327/1263] Standardise context retrieval --- osu.Game/Beatmaps/BeatmapStore.cs | 70 ++++++++++++++---------- osu.Game/Database/DatabaseBackedStore.cs | 8 +-- osu.Game/IO/FileStore.cs | 36 +++++++----- osu.Game/Input/KeyBindingStore.cs | 31 ++++++++--- osu.Game/Rulesets/RulesetStore.cs | 22 ++++---- 5 files changed, 101 insertions(+), 66 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapStore.cs b/osu.Game/Beatmaps/BeatmapStore.cs index f3d3caeb0f..69aadb470e 100644 --- a/osu.Game/Beatmaps/BeatmapStore.cs +++ b/osu.Game/Beatmaps/BeatmapStore.cs @@ -29,12 +29,14 @@ namespace osu.Game.Beatmaps { if (reset) { + var context = GetContext(); + // https://stackoverflow.com/a/10450893 - Context.Database.ExecuteSqlCommand("DELETE FROM BeatmapMetadata"); - Context.Database.ExecuteSqlCommand("DELETE FROM BeatmapDifficulty"); - Context.Database.ExecuteSqlCommand("DELETE FROM BeatmapSetInfo"); - Context.Database.ExecuteSqlCommand("DELETE FROM BeatmapSetFileInfo"); - Context.Database.ExecuteSqlCommand("DELETE FROM BeatmapInfo"); + context.Database.ExecuteSqlCommand("DELETE FROM BeatmapMetadata"); + context.Database.ExecuteSqlCommand("DELETE FROM BeatmapDifficulty"); + context.Database.ExecuteSqlCommand("DELETE FROM BeatmapSetInfo"); + context.Database.ExecuteSqlCommand("DELETE FROM BeatmapSetFileInfo"); + context.Database.ExecuteSqlCommand("DELETE FROM BeatmapInfo"); } } @@ -50,8 +52,10 @@ namespace osu.Game.Beatmaps /// The beatmap to add. public void Add(BeatmapSetInfo beatmapSet) { - Context.BeatmapSetInfo.Attach(beatmapSet); - Context.SaveChanges(); + var context = GetContext(); + + context.BeatmapSetInfo.Attach(beatmapSet); + context.SaveChanges(); BeatmapSetAdded?.Invoke(beatmapSet); } @@ -63,11 +67,13 @@ namespace osu.Game.Beatmaps /// Whether the beatmap's was changed. public bool Delete(BeatmapSetInfo beatmapSet) { + var context = GetContext(); + if (beatmapSet.DeletePending) return false; beatmapSet.DeletePending = true; - Context.BeatmapSetInfo.Update(beatmapSet); - Context.SaveChanges(); + context.BeatmapSetInfo.Update(beatmapSet); + context.SaveChanges(); BeatmapSetRemoved?.Invoke(beatmapSet); return true; @@ -80,11 +86,13 @@ namespace osu.Game.Beatmaps /// Whether the beatmap's was changed. public bool Undelete(BeatmapSetInfo beatmapSet) { + var context = GetContext(); + if (!beatmapSet.DeletePending) return false; beatmapSet.DeletePending = false; - Context.BeatmapSetInfo.Update(beatmapSet); - Context.SaveChanges(); + context.BeatmapSetInfo.Update(beatmapSet); + context.SaveChanges(); BeatmapSetAdded?.Invoke(beatmapSet); return true; @@ -97,11 +105,13 @@ namespace osu.Game.Beatmaps /// Whether the beatmap's was changed. public bool Hide(BeatmapInfo beatmap) { + var context = GetContext(); + if (beatmap.Hidden) return false; beatmap.Hidden = true; - Context.BeatmapInfo.Update(beatmap); - Context.SaveChanges(); + context.BeatmapInfo.Update(beatmap); + context.SaveChanges(); BeatmapHidden?.Invoke(beatmap); return true; @@ -114,11 +124,13 @@ namespace osu.Game.Beatmaps /// Whether the beatmap's was changed. public bool Restore(BeatmapInfo beatmap) { + var context = GetContext(); + if (!beatmap.Hidden) return false; beatmap.Hidden = false; - Context.BeatmapInfo.Update(beatmap); - Context.SaveChanges(); + context.BeatmapInfo.Update(beatmap); + context.SaveChanges(); BeatmapRestored?.Invoke(beatmap); return true; @@ -126,21 +138,23 @@ namespace osu.Game.Beatmaps private void cleanupPendingDeletions() { - Context.BeatmapSetInfo.RemoveRange(Context.BeatmapSetInfo.Where(b => b.DeletePending && !b.Protected)); - Context.SaveChanges(); + var context = GetContext(); + + context.BeatmapSetInfo.RemoveRange(context.BeatmapSetInfo.Where(b => b.DeletePending && !b.Protected)); + context.SaveChanges(); } - public IEnumerable BeatmapSets => Context.BeatmapSetInfo - .Include(s => s.Metadata) - .Include(s => s.Beatmaps).ThenInclude(s => s.Ruleset) - .Include(s => s.Beatmaps).ThenInclude(b => b.Difficulty) - .Include(s => s.Beatmaps).ThenInclude(b => b.Metadata) - .Include(s => s.Files).ThenInclude(f => f.FileInfo); + public IEnumerable BeatmapSets => GetContext().BeatmapSetInfo + .Include(s => s.Metadata) + .Include(s => s.Beatmaps).ThenInclude(s => s.Ruleset) + .Include(s => s.Beatmaps).ThenInclude(b => b.Difficulty) + .Include(s => s.Beatmaps).ThenInclude(b => b.Metadata) + .Include(s => s.Files).ThenInclude(f => f.FileInfo); - public IEnumerable Beatmaps => Context.BeatmapInfo - .Include(b => b.BeatmapSet).ThenInclude(s => s.Metadata) - .Include(b => b.Metadata) - .Include(b => b.Ruleset) - .Include(b => b.Difficulty); + public IEnumerable Beatmaps => GetContext().BeatmapInfo + .Include(b => b.BeatmapSet).ThenInclude(s => s.Metadata) + .Include(b => b.Metadata) + .Include(b => b.Ruleset) + .Include(b => b.Difficulty); } } diff --git a/osu.Game/Database/DatabaseBackedStore.cs b/osu.Game/Database/DatabaseBackedStore.cs index 9d3d020250..79aea7863a 100644 --- a/osu.Game/Database/DatabaseBackedStore.cs +++ b/osu.Game/Database/DatabaseBackedStore.cs @@ -11,14 +11,12 @@ namespace osu.Game.Database { protected readonly Storage Storage; - private readonly Func contextSource; + protected readonly Func GetContext; - protected OsuDbContext Context => contextSource(); - - protected DatabaseBackedStore(Func contextSource, Storage storage = null) + protected DatabaseBackedStore(Func getContext, Storage storage = null) { Storage = storage; - this.contextSource = contextSource; + GetContext = getContext; try { diff --git a/osu.Game/IO/FileStore.cs b/osu.Game/IO/FileStore.cs index d715ccd0a7..b60d82d61c 100644 --- a/osu.Game/IO/FileStore.cs +++ b/osu.Game/IO/FileStore.cs @@ -22,7 +22,7 @@ namespace osu.Game.IO public readonly ResourceStore Store; - public FileStore(Func contextSource, Storage storage) : base(contextSource, storage) + public FileStore(Func getContext, Storage storage) : base(getContext, storage) { Store = new NamespacedResourceStore(new StorageBackedResourceStore(storage), prefix); } @@ -34,7 +34,7 @@ namespace osu.Game.IO if (Storage.ExistsDirectory(prefix)) Storage.DeleteDirectory(prefix); - Context.Database.ExecuteSqlCommand("DELETE FROM FileInfo"); + GetContext().Database.ExecuteSqlCommand("DELETE FROM FileInfo"); } } @@ -46,9 +46,11 @@ namespace osu.Game.IO public FileInfo Add(Stream data, bool reference = true) { + var context = GetContext(); + string hash = data.ComputeSHA2Hash(); - var existing = Context.FileInfo.FirstOrDefault(f => f.Hash == hash); + var existing = context.FileInfo.FirstOrDefault(f => f.Hash == hash); var info = existing ?? new FileInfo { Hash = hash }; @@ -71,38 +73,44 @@ namespace osu.Game.IO return info; } - public void Reference(params FileInfo[] files) + public void Reference(params FileInfo[] files) => reference(GetContext(), files); + + private void reference(OsuDbContext context, FileInfo[] files) { foreach (var f in files.GroupBy(f => f.ID)) { - var refetch = Context.Find(f.First().ID) ?? f.First(); + var refetch = context.Find(f.First().ID) ?? f.First(); refetch.ReferenceCount += f.Count(); - Context.FileInfo.Update(refetch); + context.FileInfo.Update(refetch); } - Context.SaveChanges(); + context.SaveChanges(); } - public void Dereference(params FileInfo[] files) + public void Dereference(params FileInfo[] files) => dereference(GetContext(), files); + + private void dereference(OsuDbContext context, FileInfo[] files) { foreach (var f in files.GroupBy(f => f.ID)) { - var refetch = Context.Find(f.First().ID); + var refetch = context.Find(f.First().ID); refetch.ReferenceCount -= f.Count(); - Context.Update(refetch); + context.Update(refetch); } - Context.SaveChanges(); + context.SaveChanges(); } private void deletePending() { - foreach (var f in Context.FileInfo.Where(f => f.ReferenceCount < 1)) + var context = GetContext(); + + foreach (var f in context.FileInfo.Where(f => f.ReferenceCount < 1)) { try { Storage.Delete(Path.Combine(prefix, f.StoragePath)); - Context.FileInfo.Remove(f); + context.FileInfo.Remove(f); } catch (Exception e) { @@ -110,7 +118,7 @@ namespace osu.Game.IO } } - Context.SaveChanges(); + context.SaveChanges(); } } } diff --git a/osu.Game/Input/KeyBindingStore.cs b/osu.Game/Input/KeyBindingStore.cs index 5c41179418..1e9a2aa22f 100644 --- a/osu.Game/Input/KeyBindingStore.cs +++ b/osu.Game/Input/KeyBindingStore.cs @@ -15,9 +15,16 @@ namespace osu.Game.Input { public class KeyBindingStore : DatabaseBackedStore { - public KeyBindingStore(Func contextSource, RulesetStore rulesets, Storage storage = null) - : base(contextSource, storage) + /// + /// As we do a lot of lookups, let's share a context between them to hopefully improve performance. + /// + private readonly OsuDbContext queryContext; + + public KeyBindingStore(Func getContext, RulesetStore rulesets, Storage storage = null) + : base(getContext, storage) { + queryContext = GetContext(); + foreach (var info in rulesets.AvailableRulesets) { var ruleset = info.CreateInstance(); @@ -31,15 +38,17 @@ namespace osu.Game.Input protected override void Prepare(bool reset = false) { if (reset) - Context.Database.ExecuteSqlCommand("DELETE FROM KeyBinding"); + GetContext().Database.ExecuteSqlCommand("DELETE FROM KeyBinding"); } private void insertDefaults(IEnumerable defaults, int? rulesetId = null, int? variant = null) { + var context = GetContext(); + // compare counts in database vs defaults foreach (var group in defaults.GroupBy(k => k.Action)) { - int count = Query(rulesetId, variant).Count(k => (int)k.Action == (int)group.Key); + int count = query(context, rulesetId, variant).Count(k => (int)k.Action == (int)group.Key); int aimCount = group.Count(); if (aimCount <= count) @@ -47,7 +56,7 @@ namespace osu.Game.Input foreach (var insertable in group.Skip(count).Take(aimCount - count)) // insert any defaults which are missing. - Context.DatabasedKeyBinding.Add(new DatabasedKeyBinding + context.DatabasedKeyBinding.Add(new DatabasedKeyBinding { KeyCombination = insertable.KeyCombination, Action = insertable.Action, @@ -56,7 +65,7 @@ namespace osu.Game.Input }); } - Context.SaveChanges(); + context.SaveChanges(); } /// @@ -65,12 +74,16 @@ namespace osu.Game.Input /// The ruleset's internal ID. /// An optional variant. /// - public IEnumerable Query(int? rulesetId = null, int? variant = null) => Context.DatabasedKeyBinding.Where(b => b.RulesetID == rulesetId && b.Variant == variant); + public IEnumerable Query(int? rulesetId = null, int? variant = null) => query(queryContext, rulesetId, variant); + + private IEnumerable query(OsuDbContext context, int? rulesetId = null, int? variant = null) => + context.DatabasedKeyBinding.Where(b => b.RulesetID == rulesetId && b.Variant == variant); public void Update(KeyBinding keyBinding) { - Context.Update(keyBinding); - Context.SaveChanges(); + var context = GetContext(); + context.Update(keyBinding); + context.SaveChanges(); } } } diff --git a/osu.Game/Rulesets/RulesetStore.cs b/osu.Game/Rulesets/RulesetStore.cs index bd3c22fc42..7d982eb39e 100644 --- a/osu.Game/Rulesets/RulesetStore.cs +++ b/osu.Game/Rulesets/RulesetStore.cs @@ -41,7 +41,7 @@ namespace osu.Game.Rulesets /// /// All available rulesets. /// - public IEnumerable AvailableRulesets => Context.RulesetInfo.Where(r => r.Available); + public IEnumerable AvailableRulesets => GetContext().RulesetInfo.Where(r => r.Available); private static Assembly currentDomain_AssemblyResolve(object sender, ResolveEventArgs args) => loaded_assemblies.Keys.FirstOrDefault(a => a.FullName == args.Name); @@ -49,9 +49,11 @@ namespace osu.Game.Rulesets protected override void Prepare(bool reset = false) { + var context = GetContext(); + if (reset) { - Context.Database.ExecuteSqlCommand("DELETE FROM RulesetInfo"); + context.Database.ExecuteSqlCommand("DELETE FROM RulesetInfo"); } var instances = loaded_assemblies.Values.Select(r => (Ruleset)Activator.CreateInstance(r, new RulesetInfo())).ToList(); @@ -60,29 +62,29 @@ namespace osu.Game.Rulesets foreach (var r in instances.Where(r => r.LegacyID >= 0).OrderBy(r => r.LegacyID)) { var rulesetInfo = createRulesetInfo(r); - if (Context.RulesetInfo.SingleOrDefault(rsi => rsi.ID == rulesetInfo.ID) == null) + if (context.RulesetInfo.SingleOrDefault(rsi => rsi.ID == rulesetInfo.ID) == null) { - Context.RulesetInfo.Add(rulesetInfo); + context.RulesetInfo.Add(rulesetInfo); } } - Context.SaveChanges(); + context.SaveChanges(); //add any other modes foreach (var r in instances.Where(r => r.LegacyID < 0)) { var us = createRulesetInfo(r); - var existing = Context.RulesetInfo.FirstOrDefault(ri => ri.InstantiationInfo == us.InstantiationInfo); + var existing = context.RulesetInfo.FirstOrDefault(ri => ri.InstantiationInfo == us.InstantiationInfo); if (existing == null) - Context.RulesetInfo.Add(us); + context.RulesetInfo.Add(us); } - Context.SaveChanges(); + context.SaveChanges(); //perform a consistency check - foreach (var r in Context.RulesetInfo) + foreach (var r in context.RulesetInfo) { try { @@ -95,7 +97,7 @@ namespace osu.Game.Rulesets } } - Context.SaveChanges(); + context.SaveChanges(); } private static void loadRulesetFromFile(string file) From cf3881b18c4848e16188d5b96dd7b65e87ce996b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Oct 2017 15:50:52 +0900 Subject: [PATCH 0328/1263] Fix not being able to restore hidden beatmaps via context menu --- osu.Game/Beatmaps/Drawables/BeatmapGroup.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game/Beatmaps/Drawables/BeatmapGroup.cs b/osu.Game/Beatmaps/Drawables/BeatmapGroup.cs index d1682a392d..6e5af29799 100644 --- a/osu.Game/Beatmaps/Drawables/BeatmapGroup.cs +++ b/osu.Game/Beatmaps/Drawables/BeatmapGroup.cs @@ -83,8 +83,7 @@ namespace osu.Game.Beatmaps.Drawables RelativeSizeAxes = Axes.X, }; - BeatmapSet.Beatmaps = BeatmapSet.Beatmaps.Where(b => !b.Hidden).OrderBy(b => b.StarDifficulty).ToList(); - BeatmapPanels = BeatmapSet.Beatmaps.Select(b => new BeatmapPanel(b) + BeatmapPanels = BeatmapSet.Beatmaps.Where(b => !b.Hidden).OrderBy(b => b.StarDifficulty).Select(b => new BeatmapPanel(b) { Alpha = 0, GainedSelection = panelGainedSelection, From ad54ca92688be0e4f7ebf8ccc4f548b6d360d2be Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Oct 2017 16:02:13 +0900 Subject: [PATCH 0329/1263] Fix TestCasePlaySongSelect --- osu.Game/Database/DatabaseContextFactory.cs | 2 +- osu.Game/Tests/Visual/TestCasePlaySongSelect.cs | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/osu.Game/Database/DatabaseContextFactory.cs b/osu.Game/Database/DatabaseContextFactory.cs index 3fc5141880..359188b4e2 100644 --- a/osu.Game/Database/DatabaseContextFactory.cs +++ b/osu.Game/Database/DatabaseContextFactory.cs @@ -1,5 +1,5 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using osu.Framework.Platform; diff --git a/osu.Game/Tests/Visual/TestCasePlaySongSelect.cs b/osu.Game/Tests/Visual/TestCasePlaySongSelect.cs index 9ca6aa2fb5..a46542760b 100644 --- a/osu.Game/Tests/Visual/TestCasePlaySongSelect.cs +++ b/osu.Game/Tests/Visual/TestCasePlaySongSelect.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Linq; +using Microsoft.EntityFrameworkCore; using osu.Framework.Allocation; using osu.Framework.MathUtils; using osu.Game.Beatmaps; @@ -36,9 +37,11 @@ namespace osu.Game.Tests.Visual { var storage = new TestStorage(@"TestCasePlaySongSelect"); - var dbConnectionString = storage.GetDatabaseConnectionString(@"client"); + // this is by no means clean. should be replacing inside of OsuGameBase somehow. + var context = new OsuDbContext(storage.GetDatabaseConnectionString(@"client")); + context.Database.Migrate(); - Func contextFactory = () => new OsuDbContext(dbConnectionString); + Func contextFactory = () => context; dependencies.Cache(rulesets = new RulesetStore(contextFactory)); dependencies.Cache(manager = new BeatmapManager(storage, contextFactory, rulesets, null)); From e02640637a1c52df860876f1f9ab94998d412c43 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Oct 2017 17:08:01 +0900 Subject: [PATCH 0330/1263] Fix KeyBindingStore regression --- osu.Game/Input/KeyBindingStore.cs | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/osu.Game/Input/KeyBindingStore.cs b/osu.Game/Input/KeyBindingStore.cs index 1e9a2aa22f..54cf48bc2a 100644 --- a/osu.Game/Input/KeyBindingStore.cs +++ b/osu.Game/Input/KeyBindingStore.cs @@ -15,16 +15,9 @@ namespace osu.Game.Input { public class KeyBindingStore : DatabaseBackedStore { - /// - /// As we do a lot of lookups, let's share a context between them to hopefully improve performance. - /// - private readonly OsuDbContext queryContext; - public KeyBindingStore(Func getContext, RulesetStore rulesets, Storage storage = null) : base(getContext, storage) { - queryContext = GetContext(); - foreach (var info in rulesets.AvailableRulesets) { var ruleset = info.CreateInstance(); @@ -74,7 +67,7 @@ namespace osu.Game.Input /// The ruleset's internal ID. /// An optional variant. /// - public IEnumerable Query(int? rulesetId = null, int? variant = null) => query(queryContext, rulesetId, variant); + public IEnumerable Query(int? rulesetId = null, int? variant = null) => query(GetContext(), rulesetId, variant); private IEnumerable query(OsuDbContext context, int? rulesetId = null, int? variant = null) => context.DatabasedKeyBinding.Where(b => b.RulesetID == rulesetId && b.Variant == variant); From 64dfce258ff1b561120bc0e6c23f5e2872e93db3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Oct 2017 17:08:19 +0900 Subject: [PATCH 0331/1263] Fix file prefix not being read when calling storage.Exists --- osu.Game/IO/FileStore.cs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/osu.Game/IO/FileStore.cs b/osu.Game/IO/FileStore.cs index b60d82d61c..db4f5fd2a2 100644 --- a/osu.Game/IO/FileStore.cs +++ b/osu.Game/IO/FileStore.cs @@ -18,21 +18,21 @@ namespace osu.Game.IO /// public class FileStore : DatabaseBackedStore { - private const string prefix = "files"; + public readonly IResourceStore Store; - public readonly ResourceStore Store; + public Storage Storage => base.Storage; - public FileStore(Func getContext, Storage storage) : base(getContext, storage) + public FileStore(Func getContext, Storage storage) : base(getContext, storage.GetStorageForDirectory(@"files")) { - Store = new NamespacedResourceStore(new StorageBackedResourceStore(storage), prefix); + Store = new StorageBackedResourceStore(Storage); } protected override void Prepare(bool reset = false) { if (reset) { - if (Storage.ExistsDirectory(prefix)) - Storage.DeleteDirectory(prefix); + if (Storage.ExistsDirectory(string.Empty)) + Storage.DeleteDirectory(string.Empty); GetContext().Database.ExecuteSqlCommand("DELETE FROM FileInfo"); } @@ -54,7 +54,7 @@ namespace osu.Game.IO var info = existing ?? new FileInfo { Hash = hash }; - string path = Path.Combine(prefix, info.StoragePath); + string path = info.StoragePath; // we may be re-adding a file to fix missing store entries. if (!Storage.Exists(path)) @@ -109,7 +109,7 @@ namespace osu.Game.IO { try { - Storage.Delete(Path.Combine(prefix, f.StoragePath)); + Storage.Delete(f.StoragePath); context.FileInfo.Remove(f); } catch (Exception e) From 7a18d373ec9a4b96151280c5d475ce7d1a64e474 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Oct 2017 17:08:42 +0900 Subject: [PATCH 0332/1263] Improve performance of beatmap imports (still needs revision) --- osu.Game/Beatmaps/BeatmapManager.cs | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 1423e9138f..bf71033f36 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -98,7 +98,7 @@ namespace osu.Game.Beatmaps beatmaps = createBeatmapStore(context); files = new FileStore(context, storage); - this.storage = storage; + this.storage = files.Storage; this.rulesets = rulesets; this.api = api; @@ -174,16 +174,23 @@ namespace osu.Game.Beatmaps { var context = createContext(); + context.Database.AutoTransactionsEnabled = false; + using (var transaction = context.Database.BeginTransaction()) { // create local stores so we can isolate and thread safely, and share a context/transaction. - var filesForImport = new FileStore(() => context, storage); - var beatmapsForImport = createBeatmapStore(() => context); + var iFiles = new FileStore(() => context, storage); + var iBeatmaps = createBeatmapStore(() => context); + + BeatmapSetInfo set = importToStorage(iFiles, iBeatmaps, archiveReader); + + if (set.ID == 0) + { + iBeatmaps.Add(set); + context.SaveChanges(); + transaction.Commit(); + } - BeatmapSetInfo set = importToStorage(filesForImport, archiveReader); - beatmapsForImport.Add(set); - context.SaveChanges(); - transaction.Commit(); return set; } } @@ -308,7 +315,7 @@ namespace osu.Game.Beatmaps /// Is a no-op for already usable beatmaps. /// /// The beatmap to restore. - public void Undelete(BeatmapSetInfo beatmapSet) + private void undelete(BeatmapStore beatmaps, FileStore files, BeatmapSetInfo beatmapSet) { lock (beatmaps) if (!beatmaps.Undelete(beatmapSet)) return; @@ -410,7 +417,7 @@ namespace osu.Game.Beatmaps /// /// The beatmap archive to be read. /// The imported beatmap, or an existing instance if it is already present. - private BeatmapSetInfo importToStorage(FileStore files, ArchiveReader reader) + private BeatmapSetInfo importToStorage(FileStore files, BeatmapStore beatmaps, ArchiveReader reader) { // let's make sure there are actually .osu files to import. string mapName = reader.Filenames.FirstOrDefault(f => f.EndsWith(".osu")); @@ -432,7 +439,7 @@ namespace osu.Game.Beatmaps if (beatmapSet != null) { - Undelete(beatmapSet); + undelete(beatmaps, files, beatmapSet); // ensure all files are present and accessible foreach (var f in beatmapSet.Files) @@ -442,6 +449,8 @@ namespace osu.Game.Beatmaps files.Add(s, false); } + // todo: delete any files which shouldn't exist any more. + return beatmapSet; } From 0177fcbe5f9ec6c849a084ca3559311437bc4d27 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Oct 2017 17:08:47 +0900 Subject: [PATCH 0333/1263] Fix xmldoc --- osu.Game/Database/DatabaseBackedStore.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Database/DatabaseBackedStore.cs b/osu.Game/Database/DatabaseBackedStore.cs index 79aea7863a..90a43a47c5 100644 --- a/osu.Game/Database/DatabaseBackedStore.cs +++ b/osu.Game/Database/DatabaseBackedStore.cs @@ -32,7 +32,7 @@ namespace osu.Game.Database } /// - /// Perform any common startup tasks. Runs after and . + /// Perform any common startup tasks. Runs after . /// protected virtual void StartupTasks() { From 3e415e326908ba50ecb42c78dc1c70d7fc4433f7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Oct 2017 17:52:02 +0900 Subject: [PATCH 0334/1263] Fix tooling failures --- osu.Game/Database/OsuDbContext.cs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/osu.Game/Database/OsuDbContext.cs b/osu.Game/Database/OsuDbContext.cs index 5f4e42ed6b..bd288621e0 100644 --- a/osu.Game/Database/OsuDbContext.cs +++ b/osu.Game/Database/OsuDbContext.cs @@ -28,11 +28,19 @@ namespace osu.Game.Database SQLitePCL.Batteries_V2.Init(); } + /// + /// Create a new in-memory OsuDbContext instance. + /// + public OsuDbContext() : this("DataSource=:memory:") + { + // required for tooling (see https://wildermuth.com/2017/07/06/Program-cs-in-ASP-NET-Core-2-0). + } + /// /// Create a new OsuDbContext instance. /// - /// A valid SQLite connection string. If not provided, an in-memory instance will be created. - public OsuDbContext(string connectionString = "DataSource=:memory:") + /// A valid SQLite connection string. + public OsuDbContext(string connectionString) { this.connectionString = connectionString; @@ -82,7 +90,7 @@ namespace osu.Game.Database public void AddProvider(ILoggerProvider provider) { - throw new NotImplementedException(); + // no-op. called by tooling. } private class OsuDbLoggerProvider : ILoggerProvider From 12639c68191d65e8e703a0d313caf640aa6325b4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Oct 2017 17:52:20 +0900 Subject: [PATCH 0335/1263] Use a different database name for now to avoid conflicts when switching versions --- osu.Game/Database/DatabaseContextFactory.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Database/DatabaseContextFactory.cs b/osu.Game/Database/DatabaseContextFactory.cs index 359188b4e2..e22301adfe 100644 --- a/osu.Game/Database/DatabaseContextFactory.cs +++ b/osu.Game/Database/DatabaseContextFactory.cs @@ -14,6 +14,6 @@ namespace osu.Game.Database this.host = host; } - public OsuDbContext GetContext() => new OsuDbContext(host.Storage.GetDatabaseConnectionString(@"client")); + public OsuDbContext GetContext() => new OsuDbContext(host.Storage.GetDatabaseConnectionString(@"client-ef")); } } From b9d0fb96ed0fd636a18fd385887f334b7cb10a3b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Oct 2017 18:26:28 +0900 Subject: [PATCH 0336/1263] Fix cascade deletions --- osu.Game/Beatmaps/BeatmapDifficulty.cs | 3 + osu.Game/Beatmaps/BeatmapInfo.cs | 1 + osu.Game/Beatmaps/BeatmapMetadata.cs | 8 + osu.Game/Database/OsuDbContext.cs | 3 + ... 20171017092037_InitialCreate.Designer.cs} | 76 ++--- ...nit.cs => 20171017092037_InitialCreate.cs} | 280 +++++++++--------- .../Migrations/OsuDbContextModelSnapshot.cs | 76 ++--- osu.Game/osu.Game.csproj | 6 +- 8 files changed, 243 insertions(+), 210 deletions(-) rename osu.Game/Migrations/{20171014052545_Init.designer.cs => 20171017092037_InitialCreate.Designer.cs} (80%) rename osu.Game/Migrations/{20171014052545_Init.cs => 20171017092037_InitialCreate.cs} (86%) diff --git a/osu.Game/Beatmaps/BeatmapDifficulty.cs b/osu.Game/Beatmaps/BeatmapDifficulty.cs index 25e212f3c5..e310c4a646 100644 --- a/osu.Game/Beatmaps/BeatmapDifficulty.cs +++ b/osu.Game/Beatmaps/BeatmapDifficulty.cs @@ -14,6 +14,9 @@ namespace osu.Game.Beatmaps [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int ID { get; set; } + + public int BeatmapInfoID { get; set; } + public float DrainRate { get; set; } = DEFAULT_DIFFICULTY; public float CircleSize { get; set; } = DEFAULT_DIFFICULTY; public float OverallDifficulty { get; set; } = DEFAULT_DIFFICULTY; diff --git a/osu.Game/Beatmaps/BeatmapInfo.cs b/osu.Game/Beatmaps/BeatmapInfo.cs index c1516f17c9..d2ed5d692c 100644 --- a/osu.Game/Beatmaps/BeatmapInfo.cs +++ b/osu.Game/Beatmaps/BeatmapInfo.cs @@ -31,6 +31,7 @@ namespace osu.Game.Beatmaps [Required] public BeatmapSetInfo BeatmapSet { get; set; } + public BeatmapMetadata Metadata { get; set; } public int BaseDifficultyID { get; set; } diff --git a/osu.Game/Beatmaps/BeatmapMetadata.cs b/osu.Game/Beatmaps/BeatmapMetadata.cs index 5e47d6c13d..ca8702d222 100644 --- a/osu.Game/Beatmaps/BeatmapMetadata.cs +++ b/osu.Game/Beatmaps/BeatmapMetadata.cs @@ -16,6 +16,14 @@ namespace osu.Game.Beatmaps [NotMapped] public int? OnlineBeatmapSetID { get; set; } + public int? BeatmapSetInfoID { get; set; } + + public BeatmapSetInfo BeatmapSetInfo { get; set; } + + public int? BeatmapInfoID { get; set; } + + public BeatmapInfo BeatmapInfo { get; set; } + public string Title { get; set; } public string TitleUnicode { get; set; } public string Artist { get; set; } diff --git a/osu.Game/Database/OsuDbContext.cs b/osu.Game/Database/OsuDbContext.cs index bd288621e0..e360f11ba3 100644 --- a/osu.Game/Database/OsuDbContext.cs +++ b/osu.Game/Database/OsuDbContext.cs @@ -74,6 +74,9 @@ namespace osu.Game.Database modelBuilder.Entity().HasIndex(b => b.Name).IsUnique(); modelBuilder.Entity().HasIndex(b => b.InstantiationInfo).IsUnique(); modelBuilder.Entity().HasIndex(b => b.Available); + + modelBuilder.Entity().HasOne(m => m.BeatmapSetInfo).WithOne(s => s.Metadata).OnDelete(DeleteBehavior.Cascade); + modelBuilder.Entity().HasOne(m => m.BeatmapInfo).WithOne(b => b.Metadata).OnDelete(DeleteBehavior.Cascade); } private class OsuDbLoggerFactory : ILoggerFactory diff --git a/osu.Game/Migrations/20171014052545_Init.designer.cs b/osu.Game/Migrations/20171017092037_InitialCreate.Designer.cs similarity index 80% rename from osu.Game/Migrations/20171014052545_Init.designer.cs rename to osu.Game/Migrations/20171017092037_InitialCreate.Designer.cs index f151131882..422c1612d2 100644 --- a/osu.Game/Migrations/20171014052545_Init.designer.cs +++ b/osu.Game/Migrations/20171017092037_InitialCreate.Designer.cs @@ -1,7 +1,4 @@ -// Copyright (c) 2007-2017 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -// +// using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata; @@ -13,8 +10,8 @@ using System; namespace osu.Game.Migrations { [DbContext(typeof(OsuDbContext))] - [Migration("20171014052545_Init")] - partial class Init + [Migration("20171017092037_InitialCreate")] + partial class InitialCreate { protected override void BuildTargetModel(ModelBuilder modelBuilder) { @@ -29,6 +26,8 @@ namespace osu.Game.Migrations b.Property("ApproachRate"); + b.Property("BeatmapInfoID"); + b.Property("CircleSize"); b.Property("DrainRate"); @@ -41,6 +40,9 @@ namespace osu.Game.Migrations b.HasKey("ID"); + b.HasIndex("BeatmapInfoID") + .IsUnique(); + b.ToTable("BeatmapDifficulty"); }); @@ -59,8 +61,6 @@ namespace osu.Game.Migrations b.Property("Countdown"); - b.Property("DifficultyID"); - b.Property("DistanceSpacing"); b.Property("GridSize"); @@ -73,8 +73,6 @@ namespace osu.Game.Migrations b.Property("MD5Hash"); - b.Property("MetadataID"); - b.Property("Path"); b.Property("RulesetID"); @@ -97,12 +95,8 @@ namespace osu.Game.Migrations b.HasIndex("BeatmapSetInfoID"); - b.HasIndex("DifficultyID"); - b.HasIndex("MD5Hash"); - b.HasIndex("MetadataID"); - b.HasIndex("RulesetID"); b.ToTable("BeatmapInfo"); @@ -119,10 +113,15 @@ namespace osu.Game.Migrations b.Property("AudioFile"); - b.Property("Author"); + b.Property("AuthorString") + .HasColumnName("Author"); b.Property("BackgroundFile"); + b.Property("BeatmapInfoID"); + + b.Property("BeatmapSetInfoID"); + b.Property("PreviewTime"); b.Property("Source"); @@ -135,6 +134,12 @@ namespace osu.Game.Migrations b.HasKey("ID"); + b.HasIndex("BeatmapInfoID") + .IsUnique(); + + b.HasIndex("BeatmapSetInfoID") + .IsUnique(); + b.ToTable("BeatmapMetadata"); }); @@ -168,16 +173,12 @@ namespace osu.Game.Migrations b.Property("Hash"); - b.Property("MetadataID"); - b.Property("Protected"); b.HasKey("ID"); b.HasIndex("DeletePending"); - b.HasIndex("MetadataID"); - b.ToTable("BeatmapSetInfo"); }); @@ -248,6 +249,14 @@ namespace osu.Game.Migrations b.ToTable("RulesetInfo"); }); + modelBuilder.Entity("osu.Game.Beatmaps.BeatmapDifficulty", b => + { + b.HasOne("osu.Game.Beatmaps.BeatmapInfo") + .WithOne("Difficulty") + .HasForeignKey("osu.Game.Beatmaps.BeatmapDifficulty", "BeatmapInfoID") + .OnDelete(DeleteBehavior.Cascade); + }); + modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b => { b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo", "BeatmapSet") @@ -255,21 +264,25 @@ namespace osu.Game.Migrations .HasForeignKey("BeatmapSetInfoID") .OnDelete(DeleteBehavior.Cascade); - b.HasOne("osu.Game.Beatmaps.BeatmapDifficulty", "Difficulty") - .WithMany() - .HasForeignKey("DifficultyID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata") - .WithMany() - .HasForeignKey("MetadataID"); - b.HasOne("osu.Game.Rulesets.RulesetInfo", "Ruleset") .WithMany() .HasForeignKey("RulesetID") .OnDelete(DeleteBehavior.Cascade); }); + modelBuilder.Entity("osu.Game.Beatmaps.BeatmapMetadata", b => + { + b.HasOne("osu.Game.Beatmaps.BeatmapInfo", "BeatmapInfo") + .WithOne("Metadata") + .HasForeignKey("osu.Game.Beatmaps.BeatmapMetadata", "BeatmapInfoID") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo", "BeatmapSetInfo") + .WithOne("Metadata") + .HasForeignKey("osu.Game.Beatmaps.BeatmapMetadata", "BeatmapSetInfoID") + .OnDelete(DeleteBehavior.Cascade); + }); + modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b => { b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo") @@ -282,13 +295,6 @@ namespace osu.Game.Migrations .HasForeignKey("FileInfoID") .OnDelete(DeleteBehavior.Cascade); }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata") - .WithMany() - .HasForeignKey("MetadataID"); - }); #pragma warning restore 612, 618 } } diff --git a/osu.Game/Migrations/20171014052545_Init.cs b/osu.Game/Migrations/20171017092037_InitialCreate.cs similarity index 86% rename from osu.Game/Migrations/20171014052545_Init.cs rename to osu.Game/Migrations/20171017092037_InitialCreate.cs index 6792f79e3d..2626e2ea74 100644 --- a/osu.Game/Migrations/20171014052545_Init.cs +++ b/osu.Game/Migrations/20171017092037_InitialCreate.cs @@ -1,52 +1,26 @@ -// Copyright (c) 2007-2017 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Migrations; +using System; +using System.Collections.Generic; namespace osu.Game.Migrations { - public partial class Init : Migration + public partial class InitialCreate : Migration { protected override void Up(MigrationBuilder migrationBuilder) { migrationBuilder.CreateTable( - name: "BeatmapDifficulty", + name: "BeatmapSetInfo", columns: table => new { ID = table.Column(type: "INTEGER", nullable: false) .Annotation("Sqlite:Autoincrement", true), - ApproachRate = table.Column(type: "REAL", nullable: false), - CircleSize = table.Column(type: "REAL", nullable: false), - DrainRate = table.Column(type: "REAL", nullable: false), - OverallDifficulty = table.Column(type: "REAL", nullable: false), - SliderMultiplier = table.Column(type: "REAL", nullable: false), - SliderTickRate = table.Column(type: "REAL", nullable: false) + DeletePending = table.Column(type: "INTEGER", nullable: false), + Hash = table.Column(type: "TEXT", nullable: true), + Protected = table.Column(type: "INTEGER", nullable: false) }, constraints: table => { - table.PrimaryKey("PK_BeatmapDifficulty", x => x.ID); - }); - - migrationBuilder.CreateTable( - name: "BeatmapMetadata", - columns: table => new - { - ID = table.Column(type: "INTEGER", nullable: false) - .Annotation("Sqlite:Autoincrement", true), - Artist = table.Column(type: "TEXT", nullable: true), - ArtistUnicode = table.Column(type: "TEXT", nullable: true), - AudioFile = table.Column(type: "TEXT", nullable: true), - Author = table.Column(type: "TEXT", nullable: true), - BackgroundFile = table.Column(type: "TEXT", nullable: true), - PreviewTime = table.Column(type: "INTEGER", nullable: false), - Source = table.Column(type: "TEXT", nullable: true), - Tags = table.Column(type: "TEXT", nullable: true), - Title = table.Column(type: "TEXT", nullable: true), - TitleUnicode = table.Column(type: "TEXT", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_BeatmapMetadata", x => x.ID); + table.PrimaryKey("PK_BeatmapSetInfo", x => x.ID); }); migrationBuilder.CreateTable( @@ -94,86 +68,6 @@ namespace osu.Game.Migrations table.PrimaryKey("PK_RulesetInfo", x => x.ID); }); - migrationBuilder.CreateTable( - name: "BeatmapSetInfo", - columns: table => new - { - ID = table.Column(type: "INTEGER", nullable: false) - .Annotation("Sqlite:Autoincrement", true), - DeletePending = table.Column(type: "INTEGER", nullable: false), - Hash = table.Column(type: "TEXT", nullable: true), - MetadataID = table.Column(type: "INTEGER", nullable: true), - Protected = table.Column(type: "INTEGER", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_BeatmapSetInfo", x => x.ID); - table.ForeignKey( - name: "FK_BeatmapSetInfo_BeatmapMetadata_MetadataID", - column: x => x.MetadataID, - principalTable: "BeatmapMetadata", - principalColumn: "ID", - onDelete: ReferentialAction.Restrict); - }); - - migrationBuilder.CreateTable( - name: "BeatmapInfo", - columns: table => new - { - ID = table.Column(type: "INTEGER", nullable: false) - .Annotation("Sqlite:Autoincrement", true), - AudioLeadIn = table.Column(type: "INTEGER", nullable: false), - BaseDifficultyID = table.Column(type: "INTEGER", nullable: false), - BeatDivisor = table.Column(type: "INTEGER", nullable: false), - BeatmapSetInfoID = table.Column(type: "INTEGER", nullable: false), - Countdown = table.Column(type: "INTEGER", nullable: false), - DifficultyID = table.Column(type: "INTEGER", nullable: false), - DistanceSpacing = table.Column(type: "REAL", nullable: false), - GridSize = table.Column(type: "INTEGER", nullable: false), - Hash = table.Column(type: "TEXT", nullable: true), - Hidden = table.Column(type: "INTEGER", nullable: false), - LetterboxInBreaks = table.Column(type: "INTEGER", nullable: false), - MD5Hash = table.Column(type: "TEXT", nullable: true), - MetadataID = table.Column(type: "INTEGER", nullable: true), - Path = table.Column(type: "TEXT", nullable: true), - RulesetID = table.Column(type: "INTEGER", nullable: false), - SpecialStyle = table.Column(type: "INTEGER", nullable: false), - StackLeniency = table.Column(type: "REAL", nullable: false), - StarDifficulty = table.Column(type: "REAL", nullable: false), - StoredBookmarks = table.Column(type: "TEXT", nullable: true), - TimelineZoom = table.Column(type: "REAL", nullable: false), - Version = table.Column(type: "TEXT", nullable: true), - WidescreenStoryboard = table.Column(type: "INTEGER", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_BeatmapInfo", x => x.ID); - table.ForeignKey( - name: "FK_BeatmapInfo_BeatmapSetInfo_BeatmapSetInfoID", - column: x => x.BeatmapSetInfoID, - principalTable: "BeatmapSetInfo", - principalColumn: "ID", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "FK_BeatmapInfo_BeatmapDifficulty_DifficultyID", - column: x => x.DifficultyID, - principalTable: "BeatmapDifficulty", - principalColumn: "ID", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "FK_BeatmapInfo_BeatmapMetadata_MetadataID", - column: x => x.MetadataID, - principalTable: "BeatmapMetadata", - principalColumn: "ID", - onDelete: ReferentialAction.Restrict); - table.ForeignKey( - name: "FK_BeatmapInfo_RulesetInfo_RulesetID", - column: x => x.RulesetID, - principalTable: "RulesetInfo", - principalColumn: "ID", - onDelete: ReferentialAction.Cascade); - }); - migrationBuilder.CreateTable( name: "BeatmapSetFileInfo", columns: table => new @@ -201,31 +95,144 @@ namespace osu.Game.Migrations onDelete: ReferentialAction.Cascade); }); + migrationBuilder.CreateTable( + name: "BeatmapInfo", + columns: table => new + { + ID = table.Column(type: "INTEGER", nullable: false) + .Annotation("Sqlite:Autoincrement", true), + AudioLeadIn = table.Column(type: "INTEGER", nullable: false), + BaseDifficultyID = table.Column(type: "INTEGER", nullable: false), + BeatDivisor = table.Column(type: "INTEGER", nullable: false), + BeatmapSetInfoID = table.Column(type: "INTEGER", nullable: false), + Countdown = table.Column(type: "INTEGER", nullable: false), + DistanceSpacing = table.Column(type: "REAL", nullable: false), + GridSize = table.Column(type: "INTEGER", nullable: false), + Hash = table.Column(type: "TEXT", nullable: true), + Hidden = table.Column(type: "INTEGER", nullable: false), + LetterboxInBreaks = table.Column(type: "INTEGER", nullable: false), + MD5Hash = table.Column(type: "TEXT", nullable: true), + Path = table.Column(type: "TEXT", nullable: true), + RulesetID = table.Column(type: "INTEGER", nullable: false), + SpecialStyle = table.Column(type: "INTEGER", nullable: false), + StackLeniency = table.Column(type: "REAL", nullable: false), + StarDifficulty = table.Column(type: "REAL", nullable: false), + StoredBookmarks = table.Column(type: "TEXT", nullable: true), + TimelineZoom = table.Column(type: "REAL", nullable: false), + Version = table.Column(type: "TEXT", nullable: true), + WidescreenStoryboard = table.Column(type: "INTEGER", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_BeatmapInfo", x => x.ID); + table.ForeignKey( + name: "FK_BeatmapInfo_BeatmapSetInfo_BeatmapSetInfoID", + column: x => x.BeatmapSetInfoID, + principalTable: "BeatmapSetInfo", + principalColumn: "ID", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_BeatmapInfo_RulesetInfo_RulesetID", + column: x => x.RulesetID, + principalTable: "RulesetInfo", + principalColumn: "ID", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "BeatmapDifficulty", + columns: table => new + { + ID = table.Column(type: "INTEGER", nullable: false) + .Annotation("Sqlite:Autoincrement", true), + ApproachRate = table.Column(type: "REAL", nullable: false), + BeatmapInfoID = table.Column(type: "INTEGER", nullable: false), + CircleSize = table.Column(type: "REAL", nullable: false), + DrainRate = table.Column(type: "REAL", nullable: false), + OverallDifficulty = table.Column(type: "REAL", nullable: false), + SliderMultiplier = table.Column(type: "REAL", nullable: false), + SliderTickRate = table.Column(type: "REAL", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_BeatmapDifficulty", x => x.ID); + table.ForeignKey( + name: "FK_BeatmapDifficulty_BeatmapInfo_BeatmapInfoID", + column: x => x.BeatmapInfoID, + principalTable: "BeatmapInfo", + principalColumn: "ID", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "BeatmapMetadata", + columns: table => new + { + ID = table.Column(type: "INTEGER", nullable: false) + .Annotation("Sqlite:Autoincrement", true), + Artist = table.Column(type: "TEXT", nullable: true), + ArtistUnicode = table.Column(type: "TEXT", nullable: true), + AudioFile = table.Column(type: "TEXT", nullable: true), + Author = table.Column(type: "TEXT", nullable: true), + BackgroundFile = table.Column(type: "TEXT", nullable: true), + BeatmapInfoID = table.Column(type: "INTEGER", nullable: true), + BeatmapSetInfoID = table.Column(type: "INTEGER", nullable: true), + PreviewTime = table.Column(type: "INTEGER", nullable: false), + Source = table.Column(type: "TEXT", nullable: true), + Tags = table.Column(type: "TEXT", nullable: true), + Title = table.Column(type: "TEXT", nullable: true), + TitleUnicode = table.Column(type: "TEXT", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_BeatmapMetadata", x => x.ID); + table.ForeignKey( + name: "FK_BeatmapMetadata_BeatmapInfo_BeatmapInfoID", + column: x => x.BeatmapInfoID, + principalTable: "BeatmapInfo", + principalColumn: "ID", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_BeatmapMetadata_BeatmapSetInfo_BeatmapSetInfoID", + column: x => x.BeatmapSetInfoID, + principalTable: "BeatmapSetInfo", + principalColumn: "ID", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_BeatmapDifficulty_BeatmapInfoID", + table: "BeatmapDifficulty", + column: "BeatmapInfoID", + unique: true); + migrationBuilder.CreateIndex( name: "IX_BeatmapInfo_BeatmapSetInfoID", table: "BeatmapInfo", column: "BeatmapSetInfoID"); - migrationBuilder.CreateIndex( - name: "IX_BeatmapInfo_DifficultyID", - table: "BeatmapInfo", - column: "DifficultyID"); - migrationBuilder.CreateIndex( name: "IX_BeatmapInfo_MD5Hash", table: "BeatmapInfo", column: "MD5Hash"); - migrationBuilder.CreateIndex( - name: "IX_BeatmapInfo_MetadataID", - table: "BeatmapInfo", - column: "MetadataID"); - migrationBuilder.CreateIndex( name: "IX_BeatmapInfo_RulesetID", table: "BeatmapInfo", column: "RulesetID"); + migrationBuilder.CreateIndex( + name: "IX_BeatmapMetadata_BeatmapInfoID", + table: "BeatmapMetadata", + column: "BeatmapInfoID", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_BeatmapMetadata_BeatmapSetInfoID", + table: "BeatmapMetadata", + column: "BeatmapSetInfoID", + unique: true); + migrationBuilder.CreateIndex( name: "IX_BeatmapSetFileInfo_BeatmapSetInfoID", table: "BeatmapSetFileInfo", @@ -241,11 +248,6 @@ namespace osu.Game.Migrations table: "BeatmapSetInfo", column: "DeletePending"); - migrationBuilder.CreateIndex( - name: "IX_BeatmapSetInfo_MetadataID", - table: "BeatmapSetInfo", - column: "MetadataID"); - migrationBuilder.CreateIndex( name: "IX_FileInfo_Hash", table: "FileInfo", @@ -288,7 +290,10 @@ namespace osu.Game.Migrations protected override void Down(MigrationBuilder migrationBuilder) { migrationBuilder.DropTable( - name: "BeatmapInfo"); + name: "BeatmapDifficulty"); + + migrationBuilder.DropTable( + name: "BeatmapMetadata"); migrationBuilder.DropTable( name: "BeatmapSetFileInfo"); @@ -297,19 +302,16 @@ namespace osu.Game.Migrations name: "KeyBinding"); migrationBuilder.DropTable( - name: "BeatmapDifficulty"); - - migrationBuilder.DropTable( - name: "RulesetInfo"); - - migrationBuilder.DropTable( - name: "BeatmapSetInfo"); + name: "BeatmapInfo"); migrationBuilder.DropTable( name: "FileInfo"); migrationBuilder.DropTable( - name: "BeatmapMetadata"); + name: "BeatmapSetInfo"); + + migrationBuilder.DropTable( + name: "RulesetInfo"); } } } diff --git a/osu.Game/Migrations/OsuDbContextModelSnapshot.cs b/osu.Game/Migrations/OsuDbContextModelSnapshot.cs index f3a6c5a520..69cc206b7e 100644 --- a/osu.Game/Migrations/OsuDbContextModelSnapshot.cs +++ b/osu.Game/Migrations/OsuDbContextModelSnapshot.cs @@ -1,10 +1,11 @@ -// Copyright (c) 2007-2017 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -// +// using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage; using osu.Game.Database; +using System; namespace osu.Game.Migrations { @@ -24,6 +25,8 @@ namespace osu.Game.Migrations b.Property("ApproachRate"); + b.Property("BeatmapInfoID"); + b.Property("CircleSize"); b.Property("DrainRate"); @@ -36,6 +39,9 @@ namespace osu.Game.Migrations b.HasKey("ID"); + b.HasIndex("BeatmapInfoID") + .IsUnique(); + b.ToTable("BeatmapDifficulty"); }); @@ -54,8 +60,6 @@ namespace osu.Game.Migrations b.Property("Countdown"); - b.Property("DifficultyID"); - b.Property("DistanceSpacing"); b.Property("GridSize"); @@ -68,8 +72,6 @@ namespace osu.Game.Migrations b.Property("MD5Hash"); - b.Property("MetadataID"); - b.Property("Path"); b.Property("RulesetID"); @@ -92,12 +94,8 @@ namespace osu.Game.Migrations b.HasIndex("BeatmapSetInfoID"); - b.HasIndex("DifficultyID"); - b.HasIndex("MD5Hash"); - b.HasIndex("MetadataID"); - b.HasIndex("RulesetID"); b.ToTable("BeatmapInfo"); @@ -114,10 +112,15 @@ namespace osu.Game.Migrations b.Property("AudioFile"); - b.Property("Author"); + b.Property("AuthorString") + .HasColumnName("Author"); b.Property("BackgroundFile"); + b.Property("BeatmapInfoID"); + + b.Property("BeatmapSetInfoID"); + b.Property("PreviewTime"); b.Property("Source"); @@ -130,6 +133,12 @@ namespace osu.Game.Migrations b.HasKey("ID"); + b.HasIndex("BeatmapInfoID") + .IsUnique(); + + b.HasIndex("BeatmapSetInfoID") + .IsUnique(); + b.ToTable("BeatmapMetadata"); }); @@ -163,16 +172,12 @@ namespace osu.Game.Migrations b.Property("Hash"); - b.Property("MetadataID"); - b.Property("Protected"); b.HasKey("ID"); b.HasIndex("DeletePending"); - b.HasIndex("MetadataID"); - b.ToTable("BeatmapSetInfo"); }); @@ -243,6 +248,14 @@ namespace osu.Game.Migrations b.ToTable("RulesetInfo"); }); + modelBuilder.Entity("osu.Game.Beatmaps.BeatmapDifficulty", b => + { + b.HasOne("osu.Game.Beatmaps.BeatmapInfo") + .WithOne("Difficulty") + .HasForeignKey("osu.Game.Beatmaps.BeatmapDifficulty", "BeatmapInfoID") + .OnDelete(DeleteBehavior.Cascade); + }); + modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b => { b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo", "BeatmapSet") @@ -250,21 +263,25 @@ namespace osu.Game.Migrations .HasForeignKey("BeatmapSetInfoID") .OnDelete(DeleteBehavior.Cascade); - b.HasOne("osu.Game.Beatmaps.BeatmapDifficulty", "Difficulty") - .WithMany() - .HasForeignKey("DifficultyID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata") - .WithMany() - .HasForeignKey("MetadataID"); - b.HasOne("osu.Game.Rulesets.RulesetInfo", "Ruleset") .WithMany() .HasForeignKey("RulesetID") .OnDelete(DeleteBehavior.Cascade); }); + modelBuilder.Entity("osu.Game.Beatmaps.BeatmapMetadata", b => + { + b.HasOne("osu.Game.Beatmaps.BeatmapInfo", "BeatmapInfo") + .WithOne("Metadata") + .HasForeignKey("osu.Game.Beatmaps.BeatmapMetadata", "BeatmapInfoID") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo", "BeatmapSetInfo") + .WithOne("Metadata") + .HasForeignKey("osu.Game.Beatmaps.BeatmapMetadata", "BeatmapSetInfoID") + .OnDelete(DeleteBehavior.Cascade); + }); + modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b => { b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo") @@ -277,13 +294,6 @@ namespace osu.Game.Migrations .HasForeignKey("FileInfoID") .OnDelete(DeleteBehavior.Cascade); }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata") - .WithMany() - .HasForeignKey("MetadataID"); - }); #pragma warning restore 612, 618 } } diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index d3ac2d6189..9c6e03249e 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -286,9 +286,9 @@ - - - 20171014052545_Init.cs + + + 20171017092037_InitialCreate.cs From e4a066dc5fcb76926a34e75c2c333961d187becc Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Oct 2017 19:58:33 +0900 Subject: [PATCH 0337/1263] Run cleanup tasks only on startup via manual calls --- osu.Game/Beatmaps/BeatmapManager.cs | 2 ++ osu.Game/Beatmaps/BeatmapStore.cs | 8 +------- osu.Game/Database/DatabaseBackedStore.cs | 6 ++---- osu.Game/IO/FileStore.cs | 8 +------- osu.Game/OsuGameBase.cs | 2 ++ 5 files changed, 8 insertions(+), 18 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index bf71033f36..a25f454218 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -104,6 +104,8 @@ namespace osu.Game.Beatmaps if (importHost != null) ipc = new BeatmapIPCChannel(importHost, this); + + beatmaps.Cleanup(); } /// diff --git a/osu.Game/Beatmaps/BeatmapStore.cs b/osu.Game/Beatmaps/BeatmapStore.cs index 69aadb470e..4892d4f3db 100644 --- a/osu.Game/Beatmaps/BeatmapStore.cs +++ b/osu.Game/Beatmaps/BeatmapStore.cs @@ -40,12 +40,6 @@ namespace osu.Game.Beatmaps } } - protected override void StartupTasks() - { - base.StartupTasks(); - cleanupPendingDeletions(); - } - /// /// Add a to the database. /// @@ -136,7 +130,7 @@ namespace osu.Game.Beatmaps return true; } - private void cleanupPendingDeletions() + public override void Cleanup() { var context = GetContext(); diff --git a/osu.Game/Database/DatabaseBackedStore.cs b/osu.Game/Database/DatabaseBackedStore.cs index 90a43a47c5..be86d35335 100644 --- a/osu.Game/Database/DatabaseBackedStore.cs +++ b/osu.Game/Database/DatabaseBackedStore.cs @@ -27,14 +27,12 @@ namespace osu.Game.Database Logger.Error(e, $@"Failed to initialise the {GetType()}! Trying again with a clean database..."); Prepare(true); } - - StartupTasks(); } /// - /// Perform any common startup tasks. Runs after . + /// Perform any common clean-up tasks. Should be run when idle, or whenever necessary. /// - protected virtual void StartupTasks() + public virtual void Cleanup() { } diff --git a/osu.Game/IO/FileStore.cs b/osu.Game/IO/FileStore.cs index db4f5fd2a2..5f1b21ddb6 100644 --- a/osu.Game/IO/FileStore.cs +++ b/osu.Game/IO/FileStore.cs @@ -38,12 +38,6 @@ namespace osu.Game.IO } } - protected override void StartupTasks() - { - base.StartupTasks(); - deletePending(); - } - public FileInfo Add(Stream data, bool reference = true) { var context = GetContext(); @@ -101,7 +95,7 @@ namespace osu.Game.IO context.SaveChanges(); } - private void deletePending() + public override void Cleanup() { var context = GetContext(); diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 5ecc7279da..22eb75fcea 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -160,6 +160,8 @@ namespace osu.Game }; API.Register(this); + + FileStore.Cleanup(); } private WorkingBeatmap lastBeatmap; From 4e8019b31373860c4dab4921f75b19d986f60a5d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Oct 2017 19:59:22 +0900 Subject: [PATCH 0338/1263] Add some more missing indices --- osu.Game/Database/OsuDbContext.cs | 2 ++ ...ner.cs => 20171017103309_InitialCreate.Designer.cs} | 6 +++++- ...nitialCreate.cs => 20171017103309_InitialCreate.cs} | 10 ++++++++++ osu.Game/Migrations/OsuDbContextModelSnapshot.cs | 4 ++++ osu.Game/osu.Game.csproj | 6 +++--- 5 files changed, 24 insertions(+), 4 deletions(-) rename osu.Game/Migrations/{20171017092037_InitialCreate.Designer.cs => 20171017103309_InitialCreate.Designer.cs} (95%) rename osu.Game/Migrations/{20171017092037_InitialCreate.cs => 20171017103309_InitialCreate.cs} (95%) diff --git a/osu.Game/Database/OsuDbContext.cs b/osu.Game/Database/OsuDbContext.cs index e360f11ba3..cfc5f056ad 100644 --- a/osu.Game/Database/OsuDbContext.cs +++ b/osu.Game/Database/OsuDbContext.cs @@ -66,7 +66,9 @@ namespace osu.Game.Database { base.OnModelCreating(modelBuilder); modelBuilder.Entity().HasIndex(b => b.MD5Hash); + modelBuilder.Entity().HasIndex(b => b.Hash); modelBuilder.Entity().HasIndex(b => b.DeletePending); + modelBuilder.Entity().HasIndex(b => b.Hash); modelBuilder.Entity().HasIndex(b => b.Variant); modelBuilder.Entity().HasIndex(b => b.IntAction); modelBuilder.Entity().HasIndex(b => b.Hash).IsUnique(); diff --git a/osu.Game/Migrations/20171017092037_InitialCreate.Designer.cs b/osu.Game/Migrations/20171017103309_InitialCreate.Designer.cs similarity index 95% rename from osu.Game/Migrations/20171017092037_InitialCreate.Designer.cs rename to osu.Game/Migrations/20171017103309_InitialCreate.Designer.cs index 422c1612d2..4d394fcd90 100644 --- a/osu.Game/Migrations/20171017092037_InitialCreate.Designer.cs +++ b/osu.Game/Migrations/20171017103309_InitialCreate.Designer.cs @@ -10,7 +10,7 @@ using System; namespace osu.Game.Migrations { [DbContext(typeof(OsuDbContext))] - [Migration("20171017092037_InitialCreate")] + [Migration("20171017103309_InitialCreate")] partial class InitialCreate { protected override void BuildTargetModel(ModelBuilder modelBuilder) @@ -95,6 +95,8 @@ namespace osu.Game.Migrations b.HasIndex("BeatmapSetInfoID"); + b.HasIndex("Hash"); + b.HasIndex("MD5Hash"); b.HasIndex("RulesetID"); @@ -179,6 +181,8 @@ namespace osu.Game.Migrations b.HasIndex("DeletePending"); + b.HasIndex("Hash"); + b.ToTable("BeatmapSetInfo"); }); diff --git a/osu.Game/Migrations/20171017092037_InitialCreate.cs b/osu.Game/Migrations/20171017103309_InitialCreate.cs similarity index 95% rename from osu.Game/Migrations/20171017092037_InitialCreate.cs rename to osu.Game/Migrations/20171017103309_InitialCreate.cs index 2626e2ea74..759e8bb664 100644 --- a/osu.Game/Migrations/20171017092037_InitialCreate.cs +++ b/osu.Game/Migrations/20171017103309_InitialCreate.cs @@ -211,6 +211,11 @@ namespace osu.Game.Migrations table: "BeatmapInfo", column: "BeatmapSetInfoID"); + migrationBuilder.CreateIndex( + name: "IX_BeatmapInfo_Hash", + table: "BeatmapInfo", + column: "Hash"); + migrationBuilder.CreateIndex( name: "IX_BeatmapInfo_MD5Hash", table: "BeatmapInfo", @@ -248,6 +253,11 @@ namespace osu.Game.Migrations table: "BeatmapSetInfo", column: "DeletePending"); + migrationBuilder.CreateIndex( + name: "IX_BeatmapSetInfo_Hash", + table: "BeatmapSetInfo", + column: "Hash"); + migrationBuilder.CreateIndex( name: "IX_FileInfo_Hash", table: "FileInfo", diff --git a/osu.Game/Migrations/OsuDbContextModelSnapshot.cs b/osu.Game/Migrations/OsuDbContextModelSnapshot.cs index 69cc206b7e..ef2c801a6c 100644 --- a/osu.Game/Migrations/OsuDbContextModelSnapshot.cs +++ b/osu.Game/Migrations/OsuDbContextModelSnapshot.cs @@ -94,6 +94,8 @@ namespace osu.Game.Migrations b.HasIndex("BeatmapSetInfoID"); + b.HasIndex("Hash"); + b.HasIndex("MD5Hash"); b.HasIndex("RulesetID"); @@ -178,6 +180,8 @@ namespace osu.Game.Migrations b.HasIndex("DeletePending"); + b.HasIndex("Hash"); + b.ToTable("BeatmapSetInfo"); }); diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 9c6e03249e..9941792ec5 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -286,9 +286,9 @@ - - - 20171017092037_InitialCreate.cs + + + 20171017103309_InitialCreate.cs From 4193004fbfe35805b0306b168055d539d05c86cb Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Oct 2017 20:29:47 +0900 Subject: [PATCH 0339/1263] Improve performance of imports by keeping a context hot --- osu.Game/Beatmaps/BeatmapManager.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index a25f454218..e7929ff882 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -165,6 +165,8 @@ namespace osu.Game.Beatmaps private readonly object importLock = new object(); + private OsuDbContext importContext; + /// /// Import a beatmap from an . /// @@ -174,7 +176,7 @@ namespace osu.Game.Beatmaps // let's only allow one concurrent import at a time for now. lock (importLock) { - var context = createContext(); + var context = importContext ?? (importContext = createContext()); context.Database.AutoTransactionsEnabled = false; @@ -190,9 +192,9 @@ namespace osu.Game.Beatmaps { iBeatmaps.Add(set); context.SaveChanges(); - transaction.Commit(); } + transaction.Commit(); return set; } } From 518e5a2245b60e0429f86229382015fafb5a58d4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 18 Oct 2017 10:07:20 +0900 Subject: [PATCH 0340/1263] Make ProgressNotification's status and progress thread-safe Quite regularly a task will hold a reference to a progress notification and udpate it as progress is made. Therefore these operations should be thread-safe. --- .../Notifications/ProgressNotification.cs | 72 +++++++++---------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/osu.Game/Overlays/Notifications/ProgressNotification.cs b/osu.Game/Overlays/Notifications/ProgressNotification.cs index a31291e1b8..58aff16de0 100644 --- a/osu.Game/Overlays/Notifications/ProgressNotification.cs +++ b/osu.Game/Overlays/Notifications/ProgressNotification.cs @@ -25,10 +25,7 @@ namespace osu.Game.Overlays.Notifications public float Progress { get { return progressBar.Progress; } - set - { - progressBar.Progress = value; - } + set { Schedule(() => progressBar.Progress = value); } } protected override void LoadComplete() @@ -44,41 +41,44 @@ namespace osu.Game.Overlays.Notifications get { return state; } set { - bool stateChanged = state != value; - state = value; - - if (IsLoaded) + Schedule(() => { - switch (state) - { - case ProgressNotificationState.Queued: - Light.Colour = colourQueued; - Light.Pulsate = false; - progressBar.Active = false; - break; - case ProgressNotificationState.Active: - Light.Colour = colourActive; - Light.Pulsate = true; - progressBar.Active = true; - break; - case ProgressNotificationState.Cancelled: - Light.Colour = colourCancelled; - Light.Pulsate = false; - progressBar.Active = false; - break; - } - } + bool stateChanged = state != value; + state = value; - if (stateChanged) - { - switch (state) + if (IsLoaded) { - case ProgressNotificationState.Completed: - NotificationContent.MoveToY(-DrawSize.Y / 2, 200, Easing.OutQuint); - this.FadeOut(200).Finally(d => Completed()); - break; + switch (state) + { + case ProgressNotificationState.Queued: + Light.Colour = colourQueued; + Light.Pulsate = false; + progressBar.Active = false; + break; + case ProgressNotificationState.Active: + Light.Colour = colourActive; + Light.Pulsate = true; + progressBar.Active = true; + break; + case ProgressNotificationState.Cancelled: + Light.Colour = colourCancelled; + Light.Pulsate = false; + progressBar.Active = false; + break; + } } - } + + if (stateChanged) + { + switch (state) + { + case ProgressNotificationState.Completed: + NotificationContent.MoveToY(-DrawSize.Y / 2, 200, Easing.OutQuint); + this.FadeOut(200).Finally(d => Completed()); + break; + } + } + }); } } @@ -232,4 +232,4 @@ namespace osu.Game.Overlays.Notifications Completed, Cancelled } -} \ No newline at end of file +} From bae91d7de703b98441f758e64b6b6c58e0d5c45b Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Wed, 18 Oct 2017 05:06:17 +0300 Subject: [PATCH 0341/1263] Simplify gradient usage in Letterbox Overlay --- .../Play/BreaksOverlay/LetterboxOverlay.cs | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/osu.Game/Screens/Play/BreaksOverlay/LetterboxOverlay.cs b/osu.Game/Screens/Play/BreaksOverlay/LetterboxOverlay.cs index 9d5bc986e9..4733a5482b 100644 --- a/osu.Game/Screens/Play/BreaksOverlay/LetterboxOverlay.cs +++ b/osu.Game/Screens/Play/BreaksOverlay/LetterboxOverlay.cs @@ -31,13 +31,7 @@ namespace osu.Game.Screens.Play.BreaksOverlay Child = new Box { RelativeSizeAxes = Axes.Both, - Colour = new ColourInfo - { - TopLeft = Color4.Black, - TopRight = Color4.Black, - BottomLeft = transparent_black, - BottomRight = transparent_black, - } + Colour = ColourInfo.GradientVertical(Color4.Black, transparent_black), } }, new Container @@ -49,13 +43,7 @@ namespace osu.Game.Screens.Play.BreaksOverlay Child = new Box { RelativeSizeAxes = Axes.Both, - Colour = new ColourInfo - { - TopLeft = transparent_black, - TopRight = transparent_black, - BottomLeft = Color4.Black, - BottomRight = Color4.Black, - } + Colour = ColourInfo.GradientVertical(transparent_black, Color4.Black), } } }; From 9e3d54e80bd21b69225ed9ea7f62eef72961a6f4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 18 Oct 2017 11:42:55 +0900 Subject: [PATCH 0342/1263] Update framework --- osu-framework | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu-framework b/osu-framework index 2a53abda4b..dbcfa5c244 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit 2a53abda4b2ac5b559f95d934572fb99eba42a10 +Subproject commit dbcfa5c244555e7901dac7d94eab53b3b04d17e6 From cf5290fead50c908485f3572b69fd0cdda40aaa5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 18 Oct 2017 13:48:15 +0900 Subject: [PATCH 0343/1263] Remove unnecessary locking; operations are now thread-safe --- osu.Game/Beatmaps/BeatmapManager.cs | 49 ++++++----------------------- 1 file changed, 10 insertions(+), 39 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index e7929ff882..5f182c1dca 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -287,8 +287,7 @@ namespace osu.Game.Beatmaps /// The beatmap set to delete. public void Delete(BeatmapSetInfo beatmapSet) { - lock (beatmaps) - if (!beatmaps.Delete(beatmapSet)) return; + if (!beatmaps.Delete(beatmapSet)) return; if (!beatmapSet.Protected) files.Dereference(beatmapSet.Files.Select(f => f.FileInfo).ToArray()); @@ -298,21 +297,13 @@ namespace osu.Game.Beatmaps /// Delete a beatmap difficulty. /// /// The beatmap difficulty to hide. - public void Hide(BeatmapInfo beatmap) - { - lock (beatmaps) - beatmaps.Hide(beatmap); - } + public void Hide(BeatmapInfo beatmap) => beatmaps.Hide(beatmap); /// /// Restore a beatmap difficulty. /// /// The beatmap difficulty to restore. - public void Restore(BeatmapInfo beatmap) - { - lock (beatmaps) - beatmaps.Restore(beatmap); - } + public void Restore(BeatmapInfo beatmap) => beatmaps.Restore(beatmap); /// /// Returns a to a usable state if it has previously been deleted but not yet purged. @@ -321,8 +312,7 @@ namespace osu.Game.Beatmaps /// The beatmap to restore. private void undelete(BeatmapStore beatmaps, FileStore files, BeatmapSetInfo beatmapSet) { - lock (beatmaps) - if (!beatmaps.Undelete(beatmapSet)) return; + if (!beatmaps.Undelete(beatmapSet)) return; if (!beatmapSet.Protected) files.Reference(beatmapSet.Files.Select(f => f.FileInfo).ToArray()); @@ -357,11 +347,7 @@ namespace osu.Game.Beatmaps /// /// The query. /// The first result for the provided query, or null if no results were found. - public BeatmapSetInfo QueryBeatmapSet(Func query) - { - lock (beatmaps) - return beatmaps.BeatmapSets.FirstOrDefault(query); - } + public BeatmapSetInfo QueryBeatmapSet(Func query) => beatmaps.BeatmapSets.FirstOrDefault(query); /// /// Refresh an existing instance of a from the store. @@ -375,33 +361,21 @@ namespace osu.Game.Beatmaps /// /// The query. /// Results from the provided query. - public List QueryBeatmapSets(Func query) - { - lock (beatmaps) - return beatmaps.BeatmapSets.Where(query).ToList(); - } + public List QueryBeatmapSets(Func query) => beatmaps.BeatmapSets.Where(query).ToList(); /// /// Perform a lookup query on available s. /// /// The query. /// The first result for the provided query, or null if no results were found. - public BeatmapInfo QueryBeatmap(Func query) - { - lock (beatmaps) - return beatmaps.Beatmaps.FirstOrDefault(query); - } + public BeatmapInfo QueryBeatmap(Func query) => beatmaps.Beatmaps.FirstOrDefault(query); /// /// Perform a lookup query on available s. /// /// The query. /// Results from the provided query. - public List QueryBeatmaps(Func query) - { - lock (beatmaps) - return beatmaps.Beatmaps.Where(query).ToList(); - } + public List QueryBeatmaps(Func query) => beatmaps.Beatmaps.Where(query).ToList(); /// /// Creates an from a valid storage path. @@ -437,9 +411,7 @@ namespace osu.Game.Beatmaps var hash = hashable.ComputeSHA2Hash(); // check if this beatmap has already been imported and exit early if so. - BeatmapSetInfo beatmapSet; - lock (beatmaps) - beatmapSet = beatmaps.BeatmapSets.FirstOrDefault(b => b.Hash == hash); + var beatmapSet = beatmaps.BeatmapSets.FirstOrDefault(b => b.Hash == hash); if (beatmapSet != null) { @@ -523,8 +495,7 @@ namespace osu.Game.Beatmaps /// A list of available . public List GetAllUsableBeatmapSets() { - lock (beatmaps) - return beatmaps.BeatmapSets.Where(s => !s.DeletePending).ToList(); + return beatmaps.BeatmapSets.Where(s => !s.DeletePending).ToList(); } protected class BeatmapManagerWorkingBeatmap : WorkingBeatmap From 4841d4a937bb42a212fdced63568220750d42b9a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 18 Oct 2017 18:27:17 +0900 Subject: [PATCH 0344/1263] Fix deletion and use single context for imports and deletions for now --- osu.Game/Beatmaps/BeatmapManager.cs | 53 ++++++++++++++++++++++------- osu.Game/IO/FileStore.cs | 4 +-- 2 files changed, 43 insertions(+), 14 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 5f182c1dca..6b6b5cf0bc 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -7,6 +7,7 @@ using System.IO; using System.Linq; using System.Threading.Tasks; using Ionic.Zip; +using Microsoft.EntityFrameworkCore; using osu.Framework.Audio.Track; using osu.Framework.Extensions; using osu.Framework.Graphics.Textures; @@ -95,6 +96,13 @@ namespace osu.Game.Beatmaps public BeatmapManager(Storage storage, Func context, RulesetStore rulesets, APIAccess api, IIpcHost importHost = null) { createContext = context; + importContext = new Lazy(() => + { + var c = createContext(); + c.Database.AutoTransactionsEnabled = false; + return c; + }); + beatmaps = createBeatmapStore(context); files = new FileStore(context, storage); @@ -163,9 +171,7 @@ namespace osu.Game.Beatmaps notification.State = ProgressNotificationState.Completed; } - private readonly object importLock = new object(); - - private OsuDbContext importContext; + private readonly Lazy importContext; /// /// Import a beatmap from an . @@ -174,9 +180,9 @@ namespace osu.Game.Beatmaps public BeatmapSetInfo Import(ArchiveReader archiveReader) { // let's only allow one concurrent import at a time for now. - lock (importLock) + lock (importContext) { - var context = importContext ?? (importContext = createContext()); + var context = importContext.Value; context.Database.AutoTransactionsEnabled = false; @@ -287,10 +293,33 @@ namespace osu.Game.Beatmaps /// The beatmap set to delete. public void Delete(BeatmapSetInfo beatmapSet) { - if (!beatmaps.Delete(beatmapSet)) return; + lock (importContext) + { + var context = importContext.Value; - if (!beatmapSet.Protected) - files.Dereference(beatmapSet.Files.Select(f => f.FileInfo).ToArray()); + using (var transaction = context.Database.BeginTransaction()) + { + context.ChangeTracker.AutoDetectChangesEnabled = false; + + // re-fetch the beatmap set on the import context. + beatmapSet = context.BeatmapSetInfo.Include(s => s.Files).ThenInclude(f => f.FileInfo).First(s => s.ID == beatmapSet.ID); + + // create local stores so we can isolate and thread safely, and share a context/transaction. + var iFiles = new FileStore(() => context, storage); + var iBeatmaps = createBeatmapStore(() => context); + + if (iBeatmaps.Delete(beatmapSet)) + { + if (!beatmapSet.Protected) + iFiles.Dereference(beatmapSet.Files.Select(f => f.FileInfo).ToArray()); + } + + context.ChangeTracker.AutoDetectChangesEnabled = true; + context.SaveChanges(); + + transaction.Commit(); + } + } } /// @@ -587,9 +616,9 @@ namespace osu.Game.Beatmaps public void DeleteAll() { - var maps = GetAllUsableBeatmapSets().ToArray(); + var maps = GetAllUsableBeatmapSets(); - if (maps.Length == 0) return; + if (maps.Count == 0) return; var notification = new ProgressNotification { @@ -607,8 +636,8 @@ namespace osu.Game.Beatmaps // user requested abort return; - notification.Text = $"Deleting ({i} of {maps.Length})"; - notification.Progress = (float)++i / maps.Length; + notification.Text = $"Deleting ({i} of {maps.Count})"; + notification.Progress = (float)++i / maps.Count; Delete(b); } diff --git a/osu.Game/IO/FileStore.cs b/osu.Game/IO/FileStore.cs index 5f1b21ddb6..6654fa7cb1 100644 --- a/osu.Game/IO/FileStore.cs +++ b/osu.Game/IO/FileStore.cs @@ -87,9 +87,9 @@ namespace osu.Game.IO { foreach (var f in files.GroupBy(f => f.ID)) { - var refetch = context.Find(f.First().ID); + var refetch = context.FileInfo.Find(f.Key); refetch.ReferenceCount -= f.Count(); - context.Update(refetch); + context.FileInfo.Update(refetch); } context.SaveChanges(); From 668f68dd63ddd270c8ab8e6acfe4b19dc70c4e22 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 18 Oct 2017 18:27:57 +0900 Subject: [PATCH 0345/1263] Remove some unnecessary update calls --- osu.Game/Beatmaps/BeatmapStore.cs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapStore.cs b/osu.Game/Beatmaps/BeatmapStore.cs index 4892d4f3db..21a0b3ef6c 100644 --- a/osu.Game/Beatmaps/BeatmapStore.cs +++ b/osu.Game/Beatmaps/BeatmapStore.cs @@ -66,7 +66,6 @@ namespace osu.Game.Beatmaps if (beatmapSet.DeletePending) return false; beatmapSet.DeletePending = true; - context.BeatmapSetInfo.Update(beatmapSet); context.SaveChanges(); BeatmapSetRemoved?.Invoke(beatmapSet); @@ -85,7 +84,6 @@ namespace osu.Game.Beatmaps if (!beatmapSet.DeletePending) return false; beatmapSet.DeletePending = false; - context.BeatmapSetInfo.Update(beatmapSet); context.SaveChanges(); BeatmapSetAdded?.Invoke(beatmapSet); @@ -104,7 +102,6 @@ namespace osu.Game.Beatmaps if (beatmap.Hidden) return false; beatmap.Hidden = true; - context.BeatmapInfo.Update(beatmap); context.SaveChanges(); BeatmapHidden?.Invoke(beatmap); @@ -123,7 +120,6 @@ namespace osu.Game.Beatmaps if (!beatmap.Hidden) return false; beatmap.Hidden = false; - context.BeatmapInfo.Update(beatmap); context.SaveChanges(); BeatmapRestored?.Invoke(beatmap); From a85de09c0f8b76ff5a715e36c47051ab684b2e8c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 18 Oct 2017 18:36:35 +0900 Subject: [PATCH 0346/1263] Fix beatmap carousel interactions with deletion when not yet displayed --- osu.Game/Screens/Select/BeatmapCarousel.cs | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index c72f599955..b8cc9782ca 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -33,10 +33,7 @@ namespace osu.Game.Screens.Select public IEnumerable Beatmaps { - get - { - return groups.Select(g => g.BeatmapSet); - } + get { return groups.Select(g => g.BeatmapSet); } set { @@ -100,12 +97,10 @@ namespace osu.Game.Screens.Select public void AddBeatmap(BeatmapSetInfo beatmapSet) { - var group = createGroup(beatmapSet); - - //for the time being, let's completely load the difficulty panels in the background. - //this likely won't scale so well, but allows us to completely async the loading flow. - Schedule(delegate + Schedule(() => { + var group = createGroup(beatmapSet); + addGroup(group); computeYPositions(); if (selectedGroup == null) @@ -113,7 +108,10 @@ namespace osu.Game.Screens.Select }); } - public void RemoveBeatmap(BeatmapSetInfo beatmapSet) => removeGroup(groups.Find(b => b.BeatmapSet.ID == beatmapSet.ID)); + public void RemoveBeatmap(BeatmapSetInfo beatmapSet) + { + Schedule(() => removeGroup(groups.Find(b => b.BeatmapSet.ID == beatmapSet.ID))); + } internal void UpdateBeatmap(BeatmapInfo beatmap) { @@ -519,7 +517,7 @@ namespace osu.Game.Screens.Select float drawHeight = DrawHeight; // Remove all panels that should no longer be on-screen - scrollableContent.RemoveAll(delegate (Panel p) + scrollableContent.RemoveAll(delegate(Panel p) { float panelPosY = p.Position.Y; bool remove = panelPosY < Current - p.DrawHeight || panelPosY > Current + drawHeight || !p.IsPresent; From b73b4755ebdbe53100086dab741c2c8bcc6cd0d3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 18 Oct 2017 18:41:04 +0900 Subject: [PATCH 0347/1263] Ignore r# locked context inspection here --- osu.Game/Beatmaps/BeatmapManager.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 6b6b5cf0bc..8a2997987b 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -414,6 +414,7 @@ namespace osu.Game.Beatmaps private ArchiveReader getReaderFrom(string path) { if (ZipFile.IsZipFile(path)) + // ReSharper disable once InconsistentlySynchronizedField return new OszArchiveReader(storage.GetStream(path)); return new LegacyFilesystemReader(path); } From 0dac770e38d899303147e6195a2fd9030a17c782 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 18 Oct 2017 19:39:48 +0900 Subject: [PATCH 0348/1263] Remove TestCase cleanup temporarily until context disposal is sorted --- osu.Game/Tests/Visual/OsuTestCase.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/osu.Game/Tests/Visual/OsuTestCase.cs b/osu.Game/Tests/Visual/OsuTestCase.cs index 90c6e427c4..ca0aaebb5e 100644 --- a/osu.Game/Tests/Visual/OsuTestCase.cs +++ b/osu.Game/Tests/Visual/OsuTestCase.cs @@ -11,15 +11,13 @@ namespace osu.Game.Tests.Visual { public override void RunTest() { - Storage storage; using (var host = new HeadlessGameHost($"test-{Guid.NewGuid()}", realtime: false)) { - storage = host.Storage; host.Run(new OsuTestCaseTestRunner(this)); } // clean up after each run - storage.DeleteDirectory(string.Empty); + //storage.DeleteDirectory(string.Empty); } public class OsuTestCaseTestRunner : OsuGameBase From ac4b2797dc245ac34434f8c6e6b7ad0a0faaa618 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 18 Oct 2017 20:07:25 +0900 Subject: [PATCH 0349/1263] valuetuple nightmare --- osu.Game.Tests/app.config | 4 ++++ osu.Game/osu.Game.csproj | 5 ----- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/osu.Game.Tests/app.config b/osu.Game.Tests/app.config index faeaf001de..2f5b13a89d 100644 --- a/osu.Game.Tests/app.config +++ b/osu.Game.Tests/app.config @@ -6,6 +6,10 @@ + + + + \ No newline at end of file diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 9941792ec5..4488ea8333 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -103,7 +103,6 @@ $(SolutionDir)\packages\DotNetZip.1.10.1\lib\net20\DotNetZip.dll True - $(SolutionDir)\packages\Microsoft.Data.Sqlite.Core.2.0.0\lib\netstandard2.0\Microsoft.Data.Sqlite.dll @@ -201,10 +200,6 @@ $(SolutionDir)\packages\System.Runtime.CompilerServices.Unsafe.4.4.0\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll - - $(SolutionDir)\packages\System.ValueTuple.4.4.0\lib\net461\System.ValueTuple.dll - True - $(SolutionDir)\packages\System.ValueTuple.4.4.0\lib\net461\System.ValueTuple.dll True From 00be98dba732a642665042a909d38b0904d7352e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 18 Oct 2017 20:37:53 +0900 Subject: [PATCH 0350/1263] Query test assert conditions less often --- osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs b/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs index 087fb54b5f..337800cd30 100644 --- a/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs +++ b/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs @@ -155,7 +155,7 @@ namespace osu.Game.Tests.Beatmaps.IO private void waitForOrAssert(Func result, string failureMessage, int timeout = 60000) { - Action waitAction = () => { while (!result()) Thread.Sleep(20); }; + Action waitAction = () => { while (!result()) Thread.Sleep(200); }; Assert.IsTrue(waitAction.BeginInvoke(null, null).AsyncWaitHandle.WaitOne(timeout), failureMessage); } } From 71d614b813abee9720a6f5c2276e3684ad463abb Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 18 Oct 2017 21:57:54 +0900 Subject: [PATCH 0351/1263] FIx missing columns yet again --- osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs | 2 +- osu.Game/Beatmaps/BeatmapSetInfo.cs | 1 - ...Designer.cs => 20171018125509_InitialCreate.Designer.cs} | 4 +++- ...309_InitialCreate.cs => 20171018125509_InitialCreate.cs} | 1 + osu.Game/Migrations/OsuDbContextModelSnapshot.cs | 2 ++ osu.Game/osu.Game.csproj | 6 +++--- 6 files changed, 10 insertions(+), 6 deletions(-) rename osu.Game/Migrations/{20171017103309_InitialCreate.Designer.cs => 20171018125509_InitialCreate.Designer.cs} (95%) rename osu.Game/Migrations/{20171017103309_InitialCreate.cs => 20171018125509_InitialCreate.cs} (97%) diff --git a/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs b/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs index 337800cd30..e5b8c7fe57 100644 --- a/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs +++ b/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs @@ -115,7 +115,7 @@ namespace osu.Game.Tests.Beatmaps.IO //ensure we were stored to beatmap database backing... Assert.IsTrue(resultSets.Count() == 1, $@"Incorrect result count found ({resultSets.Count()} but should be 1)."); - Func> queryBeatmaps = () => store.QueryBeatmaps(s => s.OnlineBeatmapSetID == 241526 && s.BaseDifficultyID > 0); + Func> queryBeatmaps = () => store.QueryBeatmaps(s => s.BeatmapSet.OnlineBeatmapSetID == 241526 && s.BaseDifficultyID > 0); Func> queryBeatmapSets = () => store.QueryBeatmapSets(s => s.OnlineBeatmapSetID == 241526); //if we don't re-check here, the set will be inserted but the beatmaps won't be present yet. diff --git a/osu.Game/Beatmaps/BeatmapSetInfo.cs b/osu.Game/Beatmaps/BeatmapSetInfo.cs index 404add2fa5..2dfc4d0fe0 100644 --- a/osu.Game/Beatmaps/BeatmapSetInfo.cs +++ b/osu.Game/Beatmaps/BeatmapSetInfo.cs @@ -12,7 +12,6 @@ namespace osu.Game.Beatmaps [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int ID { get; set; } - [NotMapped] public int? OnlineBeatmapSetID { get; set; } public BeatmapMetadata Metadata { get; set; } diff --git a/osu.Game/Migrations/20171017103309_InitialCreate.Designer.cs b/osu.Game/Migrations/20171018125509_InitialCreate.Designer.cs similarity index 95% rename from osu.Game/Migrations/20171017103309_InitialCreate.Designer.cs rename to osu.Game/Migrations/20171018125509_InitialCreate.Designer.cs index 4d394fcd90..28e7e20743 100644 --- a/osu.Game/Migrations/20171017103309_InitialCreate.Designer.cs +++ b/osu.Game/Migrations/20171018125509_InitialCreate.Designer.cs @@ -10,7 +10,7 @@ using System; namespace osu.Game.Migrations { [DbContext(typeof(OsuDbContext))] - [Migration("20171017103309_InitialCreate")] + [Migration("20171018125509_InitialCreate")] partial class InitialCreate { protected override void BuildTargetModel(ModelBuilder modelBuilder) @@ -175,6 +175,8 @@ namespace osu.Game.Migrations b.Property("Hash"); + b.Property("OnlineBeatmapSetID"); + b.Property("Protected"); b.HasKey("ID"); diff --git a/osu.Game/Migrations/20171017103309_InitialCreate.cs b/osu.Game/Migrations/20171018125509_InitialCreate.cs similarity index 97% rename from osu.Game/Migrations/20171017103309_InitialCreate.cs rename to osu.Game/Migrations/20171018125509_InitialCreate.cs index 759e8bb664..512ffa2790 100644 --- a/osu.Game/Migrations/20171017103309_InitialCreate.cs +++ b/osu.Game/Migrations/20171018125509_InitialCreate.cs @@ -16,6 +16,7 @@ namespace osu.Game.Migrations .Annotation("Sqlite:Autoincrement", true), DeletePending = table.Column(type: "INTEGER", nullable: false), Hash = table.Column(type: "TEXT", nullable: true), + OnlineBeatmapSetID = table.Column(type: "INTEGER", nullable: true), Protected = table.Column(type: "INTEGER", nullable: false) }, constraints: table => diff --git a/osu.Game/Migrations/OsuDbContextModelSnapshot.cs b/osu.Game/Migrations/OsuDbContextModelSnapshot.cs index ef2c801a6c..8d0d8f20fe 100644 --- a/osu.Game/Migrations/OsuDbContextModelSnapshot.cs +++ b/osu.Game/Migrations/OsuDbContextModelSnapshot.cs @@ -174,6 +174,8 @@ namespace osu.Game.Migrations b.Property("Hash"); + b.Property("OnlineBeatmapSetID"); + b.Property("Protected"); b.HasKey("ID"); diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 4488ea8333..0e16c70277 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -281,9 +281,9 @@ - - - 20171017103309_InitialCreate.cs + + + 20171018125509_InitialCreate.cs From 5d5ea5fb2ef803260b1cf05bf426384c49c88471 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 19 Oct 2017 14:05:11 +0900 Subject: [PATCH 0352/1263] Fix all remaining db structure issues --- .../Beatmaps/ManiaBeatmapConverter.cs | 2 +- .../Legacy/DistanceObjectPatternGenerator.cs | 2 +- .../Patterns/Legacy/PatternGenerator.cs | 2 +- .../ManiaDifficultyCalculator.cs | 2 +- .../Scoring/ManiaScoreProcessor.cs | 2 +- .../UI/ManiaRulesetContainer.cs | 10 +- .../Scoring/OsuScoreProcessor.cs | 2 +- .../UI/Cursor/GameplayCursor.cs | 2 +- .../Beatmaps/TaikoBeatmapConverter.cs | 12 +- .../Scoring/TaikoScoreProcessor.cs | 4 +- .../Tests/TestCaseTaikoPlayfield.cs | 2 +- .../UI/TaikoRulesetContainer.cs | 2 +- .../Beatmaps/Formats/OsuLegacyDecoderTest.cs | 2 +- osu.Game/Beatmaps/Beatmap.cs | 2 +- osu.Game/Beatmaps/BeatmapDifficulty.cs | 2 - osu.Game/Beatmaps/BeatmapInfo.cs | 5 +- osu.Game/Beatmaps/BeatmapMetadata.cs | 12 +- osu.Game/Beatmaps/BeatmapStore.cs | 4 +- osu.Game/Beatmaps/DifficultyCalculator.cs | 2 +- osu.Game/Beatmaps/DummyWorkingBeatmap.cs | 2 +- osu.Game/Beatmaps/Formats/BeatmapDecoder.cs | 2 +- osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs | 4 +- osu.Game/Database/OsuDbContext.cs | 10 +- ... 20171019041408_InitialCreate.Designer.cs} | 72 ++--- ...ate.cs => 20171019041408_InitialCreate.cs} | 277 +++++++++--------- .../Migrations/OsuDbContextModelSnapshot.cs | 70 ++--- osu.Game/Rulesets/UI/RulesetContainer.cs | 4 +- osu.Game/Screens/Select/BeatmapDetails.cs | 2 +- .../Screens/Select/Details/AdvancedStats.cs | 10 +- .../Tests/Visual/TestCaseBeatmapDetails.cs | 8 +- .../Tests/Visual/TestCaseBeatmapSetOverlay.cs | 20 +- .../Tests/Visual/TestCasePlaySongSelect.cs | 6 +- .../Visual/TestCaseScrollingPlayfield.cs | 2 +- osu.Game/osu.Game.csproj | 6 +- 34 files changed, 259 insertions(+), 309 deletions(-) rename osu.Game/Migrations/{20171018125509_InitialCreate.Designer.cs => 20171019041408_InitialCreate.Designer.cs} (80%) rename osu.Game/Migrations/{20171018125509_InitialCreate.cs => 20171019041408_InitialCreate.cs} (85%) diff --git a/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs b/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs index d7c86e1f89..f6d30ad3fa 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs @@ -43,7 +43,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps { beatmap = original; - BeatmapDifficulty difficulty = original.BeatmapInfo.Difficulty; + BeatmapDifficulty difficulty = original.BeatmapInfo.BaseDifficulty; int seed = (int)Math.Round(difficulty.DrainRate + difficulty.CircleSize) * 20 + (int)(difficulty.OverallDifficulty * 41.2) + (int)Math.Round(difficulty.ApproachRate); random = new FastRandom(seed); diff --git a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs index 20966a75f7..270c264e0c 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs @@ -47,7 +47,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy // The true distance, accounting for any repeats double distance = (distanceData?.Distance ?? 0) * repeatCount; // The velocity of the osu! hit object - calculated as the velocity of a slider - double osuVelocity = osu_base_scoring_distance * beatmap.BeatmapInfo.Difficulty.SliderMultiplier * difficultyPoint.SpeedMultiplier / timingPoint.BeatLength; + double osuVelocity = osu_base_scoring_distance * beatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier * difficultyPoint.SpeedMultiplier / timingPoint.BeatLength; // The duration of the osu! hit object double osuDuration = distance / osuVelocity; diff --git a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/PatternGenerator.cs b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/PatternGenerator.cs index a3173f9784..c38680c3a5 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/PatternGenerator.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/PatternGenerator.cs @@ -104,7 +104,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy if (drainTime == 0) drainTime = 10000; - BeatmapDifficulty difficulty = Beatmap.BeatmapInfo.Difficulty; + BeatmapDifficulty difficulty = Beatmap.BeatmapInfo.BaseDifficulty; conversionDifficulty = ((difficulty.DrainRate + MathHelper.Clamp(difficulty.ApproachRate, 4, 7)) / 1.5 + Beatmap.HitObjects.Count / drainTime * 9f) / 38f * 5f / 1.15; conversionDifficulty = Math.Min(conversionDifficulty.Value, 12); diff --git a/osu.Game.Rulesets.Mania/ManiaDifficultyCalculator.cs b/osu.Game.Rulesets.Mania/ManiaDifficultyCalculator.cs index b98802db69..784df1f293 100644 --- a/osu.Game.Rulesets.Mania/ManiaDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Mania/ManiaDifficultyCalculator.cs @@ -21,6 +21,6 @@ namespace osu.Game.Rulesets.Mania return 0; } - protected override BeatmapConverter CreateBeatmapConverter() => new ManiaBeatmapConverter(true, (int)Math.Max(1, Math.Round(Beatmap.BeatmapInfo.Difficulty.CircleSize))); + protected override BeatmapConverter CreateBeatmapConverter() => new ManiaBeatmapConverter(true, (int)Math.Max(1, Math.Round(Beatmap.BeatmapInfo.BaseDifficulty.CircleSize))); } } diff --git a/osu.Game.Rulesets.Mania/Scoring/ManiaScoreProcessor.cs b/osu.Game.Rulesets.Mania/Scoring/ManiaScoreProcessor.cs index a200ba31e2..9b8ebe0070 100644 --- a/osu.Game.Rulesets.Mania/Scoring/ManiaScoreProcessor.cs +++ b/osu.Game.Rulesets.Mania/Scoring/ManiaScoreProcessor.cs @@ -100,7 +100,7 @@ namespace osu.Game.Rulesets.Mania.Scoring protected override void SimulateAutoplay(Beatmap beatmap) { - BeatmapDifficulty difficulty = beatmap.BeatmapInfo.Difficulty; + BeatmapDifficulty difficulty = beatmap.BeatmapInfo.BaseDifficulty; hpMultiplier = BeatmapDifficulty.DifficultyRange(difficulty.DrainRate, hp_multiplier_min, hp_multiplier_mid, hp_multiplier_max); hpMissMultiplier = BeatmapDifficulty.DifficultyRange(difficulty.DrainRate, hp_multiplier_miss_min, hp_multiplier_miss_mid, hp_multiplier_miss_max); diff --git a/osu.Game.Rulesets.Mania/UI/ManiaRulesetContainer.cs b/osu.Game.Rulesets.Mania/UI/ManiaRulesetContainer.cs index 3b49d81674..08acd46c57 100644 --- a/osu.Game.Rulesets.Mania/UI/ManiaRulesetContainer.cs +++ b/osu.Game.Rulesets.Mania/UI/ManiaRulesetContainer.cs @@ -88,18 +88,18 @@ namespace osu.Game.Rulesets.Mania.UI protected override BeatmapConverter CreateBeatmapConverter() { if (IsForCurrentRuleset) - AvailableColumns = (int)Math.Max(1, Math.Round(WorkingBeatmap.BeatmapInfo.Difficulty.CircleSize)); + AvailableColumns = (int)Math.Max(1, Math.Round(WorkingBeatmap.BeatmapInfo.BaseDifficulty.CircleSize)); else { float percentSliderOrSpinner = (float)WorkingBeatmap.Beatmap.HitObjects.Count(h => h is IHasEndTime) / WorkingBeatmap.Beatmap.HitObjects.Count; if (percentSliderOrSpinner < 0.2) AvailableColumns = 7; - else if (percentSliderOrSpinner < 0.3 || Math.Round(WorkingBeatmap.BeatmapInfo.Difficulty.CircleSize) >= 5) - AvailableColumns = Math.Round(WorkingBeatmap.BeatmapInfo.Difficulty.OverallDifficulty) > 5 ? 7 : 6; + else if (percentSliderOrSpinner < 0.3 || Math.Round(WorkingBeatmap.BeatmapInfo.BaseDifficulty.CircleSize) >= 5) + AvailableColumns = Math.Round(WorkingBeatmap.BeatmapInfo.BaseDifficulty.OverallDifficulty) > 5 ? 7 : 6; else if (percentSliderOrSpinner > 0.6) - AvailableColumns = Math.Round(WorkingBeatmap.BeatmapInfo.Difficulty.OverallDifficulty) > 4 ? 5 : 4; + AvailableColumns = Math.Round(WorkingBeatmap.BeatmapInfo.BaseDifficulty.OverallDifficulty) > 4 ? 5 : 4; else - AvailableColumns = Math.Max(4, Math.Min((int)Math.Round(WorkingBeatmap.BeatmapInfo.Difficulty.OverallDifficulty) + 1, 7)); + AvailableColumns = Math.Max(4, Math.Min((int)Math.Round(WorkingBeatmap.BeatmapInfo.BaseDifficulty.OverallDifficulty) + 1, 7)); } return new ManiaBeatmapConverter(IsForCurrentRuleset, AvailableColumns); diff --git a/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs b/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs index 50239bf16c..e4960c5ca2 100644 --- a/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs +++ b/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs @@ -28,7 +28,7 @@ namespace osu.Game.Rulesets.Osu.Scoring protected override void SimulateAutoplay(Beatmap beatmap) { - hpDrainRate = beatmap.BeatmapInfo.Difficulty.DrainRate; + hpDrainRate = beatmap.BeatmapInfo.BaseDifficulty.DrainRate; foreach (var obj in beatmap.HitObjects) { diff --git a/osu.Game.Rulesets.Osu/UI/Cursor/GameplayCursor.cs b/osu.Game.Rulesets.Osu/UI/Cursor/GameplayCursor.cs index adfc946f86..d8dd6c7323 100644 --- a/osu.Game.Rulesets.Osu/UI/Cursor/GameplayCursor.cs +++ b/osu.Game.Rulesets.Osu/UI/Cursor/GameplayCursor.cs @@ -125,7 +125,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor if (autoCursorScale && beatmap.Value != null) { // if we have a beatmap available, let's get its circle size to figure out an automatic cursor scale modifier. - scale *= (float)(1 - 0.7 * (1 + beatmap.Value.BeatmapInfo.Difficulty.CircleSize - BeatmapDifficulty.DEFAULT_DIFFICULTY) / BeatmapDifficulty.DEFAULT_DIFFICULTY); + scale *= (float)(1 - 0.7 * (1 + beatmap.Value.BeatmapInfo.BaseDifficulty.CircleSize - BeatmapDifficulty.DEFAULT_DIFFICULTY) / BeatmapDifficulty.DEFAULT_DIFFICULTY); } cursorContainer.Scale = new Vector2(scale); diff --git a/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs b/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs index ceaecbb555..9b4a6c47a9 100644 --- a/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs +++ b/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs @@ -51,7 +51,7 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps { // Rewrite the beatmap info to add the slider velocity multiplier BeatmapInfo info = original.BeatmapInfo.DeepClone(); - info.Difficulty.SliderMultiplier *= legacy_velocity_multiplier; + info.BaseDifficulty.SliderMultiplier *= legacy_velocity_multiplier; Beatmap converted = base.ConvertBeatmap(original); @@ -96,7 +96,7 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps double distance = distanceData.Distance * repeats * legacy_velocity_multiplier; // The velocity of the taiko hit object - calculated as the velocity of a drum roll - double taikoVelocity = taiko_base_distance * beatmap.BeatmapInfo.Difficulty.SliderMultiplier * legacy_velocity_multiplier / speedAdjustedBeatLength; + double taikoVelocity = taiko_base_distance * beatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier * legacy_velocity_multiplier / speedAdjustedBeatLength; // The duration of the taiko hit object double taikoDuration = distance / taikoVelocity; @@ -106,12 +106,12 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps speedAdjustedBeatLength *= speedAdjustment; // The velocity of the osu! hit object - calculated as the velocity of a slider - double osuVelocity = osu_base_scoring_distance * beatmap.BeatmapInfo.Difficulty.SliderMultiplier * legacy_velocity_multiplier / speedAdjustedBeatLength; + double osuVelocity = osu_base_scoring_distance * beatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier * legacy_velocity_multiplier / speedAdjustedBeatLength; // The duration of the osu! hit object double osuDuration = distance / osuVelocity; // If the drum roll is to be split into hit circles, assume the ticks are 1/8 spaced within the duration of one beat - double tickSpacing = Math.Min(speedAdjustedBeatLength / beatmap.BeatmapInfo.Difficulty.SliderTickRate, taikoDuration / repeats); + double tickSpacing = Math.Min(speedAdjustedBeatLength / beatmap.BeatmapInfo.BaseDifficulty.SliderTickRate, taikoDuration / repeats); if (!isForCurrentRuleset && tickSpacing > 0 && osuDuration < 2 * speedAdjustedBeatLength) { @@ -154,13 +154,13 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps Samples = obj.Samples, IsStrong = strong, Duration = taikoDuration, - TickRate = beatmap.BeatmapInfo.Difficulty.SliderTickRate == 3 ? 3 : 4, + TickRate = beatmap.BeatmapInfo.BaseDifficulty.SliderTickRate == 3 ? 3 : 4, }; } } else if (endTimeData != null) { - double hitMultiplier = BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.Difficulty.OverallDifficulty, 3, 5, 7.5) * swell_hit_multiplier; + double hitMultiplier = BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.OverallDifficulty, 3, 5, 7.5) * swell_hit_multiplier; yield return new Swell { diff --git a/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs b/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs index abdda9676f..752e3bee26 100644 --- a/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs +++ b/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs @@ -71,12 +71,12 @@ namespace osu.Game.Rulesets.Taiko.Scoring protected override void SimulateAutoplay(Beatmap beatmap) { - double hpMultiplierNormal = 1 / (hp_hit_great * beatmap.HitObjects.FindAll(o => o is Hit).Count * BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.Difficulty.DrainRate, 0.5, 0.75, 0.98)); + double hpMultiplierNormal = 1 / (hp_hit_great * beatmap.HitObjects.FindAll(o => o is Hit).Count * BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.DrainRate, 0.5, 0.75, 0.98)); hpIncreaseTick = hp_hit_tick; hpIncreaseGreat = hpMultiplierNormal * hp_hit_great; hpIncreaseGood = hpMultiplierNormal * hp_hit_good; - hpIncreaseMiss = BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.Difficulty.DrainRate, hp_miss_min, hp_miss_mid, hp_miss_max); + hpIncreaseMiss = BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.DrainRate, hp_miss_min, hp_miss_mid, hp_miss_max); foreach (var obj in beatmap.HitObjects) { diff --git a/osu.Game.Rulesets.Taiko/Tests/TestCaseTaikoPlayfield.cs b/osu.Game.Rulesets.Taiko/Tests/TestCaseTaikoPlayfield.cs index 2136d0d86a..14c27bc332 100644 --- a/osu.Game.Rulesets.Taiko/Tests/TestCaseTaikoPlayfield.cs +++ b/osu.Game.Rulesets.Taiko/Tests/TestCaseTaikoPlayfield.cs @@ -67,7 +67,7 @@ namespace osu.Game.Rulesets.Taiko.Tests HitObjects = new List { new CentreHit() }, BeatmapInfo = new BeatmapInfo { - Difficulty = new BeatmapDifficulty(), + BaseDifficulty = new BeatmapDifficulty(), Metadata = new BeatmapMetadata { Artist = @"Unknown", diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoRulesetContainer.cs b/osu.Game.Rulesets.Taiko/UI/TaikoRulesetContainer.cs index f0853aef0e..48ee0a5b42 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoRulesetContainer.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoRulesetContainer.cs @@ -63,7 +63,7 @@ namespace osu.Game.Rulesets.Taiko.UI StartTime = time, }; - barLine.ApplyDefaults(Beatmap.ControlPointInfo, Beatmap.BeatmapInfo.Difficulty); + barLine.ApplyDefaults(Beatmap.ControlPointInfo, Beatmap.BeatmapInfo.BaseDifficulty); bool isMajor = currentBeat % (int)currentPoint.TimeSignature == 0; Playfield.Add(isMajor ? new DrawableBarLineMajor(barLine) : new DrawableBarLine(barLine)); diff --git a/osu.Game.Tests/Beatmaps/Formats/OsuLegacyDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/OsuLegacyDecoderTest.cs index 6bccd47b5c..95b691e07f 100644 --- a/osu.Game.Tests/Beatmaps/Formats/OsuLegacyDecoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/OsuLegacyDecoderTest.cs @@ -85,7 +85,7 @@ namespace osu.Game.Tests.Beatmaps.Formats using (var stream = Resource.OpenResource("Soleily - Renatus (Gamu) [Insane].osu")) { var beatmap = decoder.Decode(new StreamReader(stream)); - var difficulty = beatmap.BeatmapInfo.Difficulty; + var difficulty = beatmap.BeatmapInfo.BaseDifficulty; Assert.AreEqual(6.5f, difficulty.DrainRate); Assert.AreEqual(4, difficulty.CircleSize); Assert.AreEqual(8, difficulty.OverallDifficulty); diff --git a/osu.Game/Beatmaps/Beatmap.cs b/osu.Game/Beatmaps/Beatmap.cs index 56bb48965f..35b6cc2b02 100644 --- a/osu.Game/Beatmaps/Beatmap.cs +++ b/osu.Game/Beatmaps/Beatmap.cs @@ -72,7 +72,7 @@ namespace osu.Game.Beatmaps AuthorString = @"Unknown Creator", }, Version = @"Normal", - Difficulty = new BeatmapDifficulty() + BaseDifficulty = new BeatmapDifficulty() }; } } diff --git a/osu.Game/Beatmaps/BeatmapDifficulty.cs b/osu.Game/Beatmaps/BeatmapDifficulty.cs index e310c4a646..0b0fca8292 100644 --- a/osu.Game/Beatmaps/BeatmapDifficulty.cs +++ b/osu.Game/Beatmaps/BeatmapDifficulty.cs @@ -15,8 +15,6 @@ namespace osu.Game.Beatmaps [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int ID { get; set; } - public int BeatmapInfoID { get; set; } - public float DrainRate { get; set; } = DEFAULT_DIFFICULTY; public float CircleSize { get; set; } = DEFAULT_DIFFICULTY; public float OverallDifficulty { get; set; } = DEFAULT_DIFFICULTY; diff --git a/osu.Game/Beatmaps/BeatmapInfo.cs b/osu.Game/Beatmaps/BeatmapInfo.cs index d2ed5d692c..08cef3f934 100644 --- a/osu.Game/Beatmaps/BeatmapInfo.cs +++ b/osu.Game/Beatmaps/BeatmapInfo.cs @@ -20,7 +20,6 @@ namespace osu.Game.Beatmaps public int BeatmapVersion; [JsonProperty("id")] - [NotMapped] public int? OnlineBeatmapID { get; set; } [JsonProperty("beatmapset_id")] @@ -36,8 +35,7 @@ namespace osu.Game.Beatmaps public int BaseDifficultyID { get; set; } - [Required] - public BeatmapDifficulty Difficulty { get; set; } + public BeatmapDifficulty BaseDifficulty { get; set; } [NotMapped] public BeatmapMetrics Metrics { get; set; } @@ -55,7 +53,6 @@ namespace osu.Game.Beatmaps /// /// MD5 is kept for legacy support (matching against replays, osu-web-10 etc.). /// - [NotMapped] [JsonProperty("file_md5")] public string MD5Hash { get; set; } diff --git a/osu.Game/Beatmaps/BeatmapMetadata.cs b/osu.Game/Beatmaps/BeatmapMetadata.cs index ca8702d222..85bcfecfb8 100644 --- a/osu.Game/Beatmaps/BeatmapMetadata.cs +++ b/osu.Game/Beatmaps/BeatmapMetadata.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 System.ComponentModel.DataAnnotations.Schema; using System.Linq; using Newtonsoft.Json; @@ -16,19 +17,14 @@ namespace osu.Game.Beatmaps [NotMapped] public int? OnlineBeatmapSetID { get; set; } - public int? BeatmapSetInfoID { get; set; } - - public BeatmapSetInfo BeatmapSetInfo { get; set; } - - public int? BeatmapInfoID { get; set; } - - public BeatmapInfo BeatmapInfo { get; set; } - public string Title { get; set; } public string TitleUnicode { get; set; } public string Artist { get; set; } public string ArtistUnicode { get; set; } + public List Beatmaps { get; set; } + public List BeatmapSets { get; set; } + /// /// Helper property to deserialize a username to . /// diff --git a/osu.Game/Beatmaps/BeatmapStore.cs b/osu.Game/Beatmaps/BeatmapStore.cs index 21a0b3ef6c..c2ec8c7b05 100644 --- a/osu.Game/Beatmaps/BeatmapStore.cs +++ b/osu.Game/Beatmaps/BeatmapStore.cs @@ -137,7 +137,7 @@ namespace osu.Game.Beatmaps public IEnumerable BeatmapSets => GetContext().BeatmapSetInfo .Include(s => s.Metadata) .Include(s => s.Beatmaps).ThenInclude(s => s.Ruleset) - .Include(s => s.Beatmaps).ThenInclude(b => b.Difficulty) + .Include(s => s.Beatmaps).ThenInclude(b => b.BaseDifficulty) .Include(s => s.Beatmaps).ThenInclude(b => b.Metadata) .Include(s => s.Files).ThenInclude(f => f.FileInfo); @@ -145,6 +145,6 @@ namespace osu.Game.Beatmaps .Include(b => b.BeatmapSet).ThenInclude(s => s.Metadata) .Include(b => b.Metadata) .Include(b => b.Ruleset) - .Include(b => b.Difficulty); + .Include(b => b.BaseDifficulty); } } diff --git a/osu.Game/Beatmaps/DifficultyCalculator.cs b/osu.Game/Beatmaps/DifficultyCalculator.cs index 60cbf0ac61..bb6a292d9d 100644 --- a/osu.Game/Beatmaps/DifficultyCalculator.cs +++ b/osu.Game/Beatmaps/DifficultyCalculator.cs @@ -40,7 +40,7 @@ namespace osu.Game.Beatmaps Objects = CreateBeatmapConverter().Convert(beatmap).HitObjects; foreach (var h in Objects) - h.ApplyDefaults(beatmap.ControlPointInfo, beatmap.BeatmapInfo.Difficulty); + h.ApplyDefaults(beatmap.ControlPointInfo, beatmap.BeatmapInfo.BaseDifficulty); PreprocessHitObjects(); } diff --git a/osu.Game/Beatmaps/DummyWorkingBeatmap.cs b/osu.Game/Beatmaps/DummyWorkingBeatmap.cs index 9a61762fa6..b9376849c1 100644 --- a/osu.Game/Beatmaps/DummyWorkingBeatmap.cs +++ b/osu.Game/Beatmaps/DummyWorkingBeatmap.cs @@ -25,7 +25,7 @@ namespace osu.Game.Beatmaps AuthorString = "no one", }, BeatmapSet = new BeatmapSetInfo(), - Difficulty = new BeatmapDifficulty + BaseDifficulty = new BeatmapDifficulty { DrainRate = 0, CircleSize = 0, diff --git a/osu.Game/Beatmaps/Formats/BeatmapDecoder.cs b/osu.Game/Beatmaps/Formats/BeatmapDecoder.cs index 81695c3b5a..962c6ad49a 100644 --- a/osu.Game/Beatmaps/Formats/BeatmapDecoder.cs +++ b/osu.Game/Beatmaps/Formats/BeatmapDecoder.cs @@ -49,7 +49,7 @@ namespace osu.Game.Beatmaps.Formats BeatmapInfo = new BeatmapInfo { Metadata = new BeatmapMetadata(), - Difficulty = new BeatmapDifficulty(), + BaseDifficulty = new BeatmapDifficulty(), }, }; diff --git a/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs b/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs index 3c06180532..d775ab409b 100644 --- a/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs +++ b/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs @@ -196,7 +196,7 @@ namespace osu.Game.Beatmaps.Formats { var pair = splitKeyVal(line, ':'); - var difficulty = beatmap.BeatmapInfo.Difficulty; + var difficulty = beatmap.BeatmapInfo.BaseDifficulty; switch (pair.Key) { case @"HPDrainRate": @@ -674,7 +674,7 @@ namespace osu.Game.Beatmaps.Formats } foreach (var hitObject in beatmap.HitObjects) - hitObject.ApplyDefaults(beatmap.ControlPointInfo, beatmap.BeatmapInfo.Difficulty); + hitObject.ApplyDefaults(beatmap.ControlPointInfo, beatmap.BeatmapInfo.BaseDifficulty); } private KeyValuePair splitKeyVal(string line, char separator) diff --git a/osu.Game/Database/OsuDbContext.cs b/osu.Game/Database/OsuDbContext.cs index cfc5f056ad..37d5bb21c8 100644 --- a/osu.Game/Database/OsuDbContext.cs +++ b/osu.Game/Database/OsuDbContext.cs @@ -65,20 +65,22 @@ namespace osu.Game.Database protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); + modelBuilder.Entity().HasIndex(b => b.MD5Hash); modelBuilder.Entity().HasIndex(b => b.Hash); + modelBuilder.Entity().HasIndex(b => b.DeletePending); modelBuilder.Entity().HasIndex(b => b.Hash); + modelBuilder.Entity().HasIndex(b => b.Variant); modelBuilder.Entity().HasIndex(b => b.IntAction); + modelBuilder.Entity().HasIndex(b => b.Hash).IsUnique(); modelBuilder.Entity().HasIndex(b => b.ReferenceCount); - modelBuilder.Entity().HasIndex(b => b.Name).IsUnique(); - modelBuilder.Entity().HasIndex(b => b.InstantiationInfo).IsUnique(); + modelBuilder.Entity().HasIndex(b => b.Available); - modelBuilder.Entity().HasOne(m => m.BeatmapSetInfo).WithOne(s => s.Metadata).OnDelete(DeleteBehavior.Cascade); - modelBuilder.Entity().HasOne(m => m.BeatmapInfo).WithOne(b => b.Metadata).OnDelete(DeleteBehavior.Cascade); + modelBuilder.Entity().HasOne(b => b.BaseDifficulty); } private class OsuDbLoggerFactory : ILoggerFactory diff --git a/osu.Game/Migrations/20171018125509_InitialCreate.Designer.cs b/osu.Game/Migrations/20171019041408_InitialCreate.Designer.cs similarity index 80% rename from osu.Game/Migrations/20171018125509_InitialCreate.Designer.cs rename to osu.Game/Migrations/20171019041408_InitialCreate.Designer.cs index 28e7e20743..0820041643 100644 --- a/osu.Game/Migrations/20171018125509_InitialCreate.Designer.cs +++ b/osu.Game/Migrations/20171019041408_InitialCreate.Designer.cs @@ -10,7 +10,7 @@ using System; namespace osu.Game.Migrations { [DbContext(typeof(OsuDbContext))] - [Migration("20171018125509_InitialCreate")] + [Migration("20171019041408_InitialCreate")] partial class InitialCreate { protected override void BuildTargetModel(ModelBuilder modelBuilder) @@ -26,8 +26,6 @@ namespace osu.Game.Migrations b.Property("ApproachRate"); - b.Property("BeatmapInfoID"); - b.Property("CircleSize"); b.Property("DrainRate"); @@ -40,9 +38,6 @@ namespace osu.Game.Migrations b.HasKey("ID"); - b.HasIndex("BeatmapInfoID") - .IsUnique(); - b.ToTable("BeatmapDifficulty"); }); @@ -73,6 +68,10 @@ namespace osu.Game.Migrations b.Property("MD5Hash"); + b.Property("MetadataID"); + + b.Property("OnlineBeatmapID"); + b.Property("Path"); b.Property("RulesetID"); @@ -93,12 +92,16 @@ namespace osu.Game.Migrations b.HasKey("ID"); + b.HasIndex("BaseDifficultyID"); + b.HasIndex("BeatmapSetInfoID"); b.HasIndex("Hash"); b.HasIndex("MD5Hash"); + b.HasIndex("MetadataID"); + b.HasIndex("RulesetID"); b.ToTable("BeatmapInfo"); @@ -120,10 +123,6 @@ namespace osu.Game.Migrations b.Property("BackgroundFile"); - b.Property("BeatmapInfoID"); - - b.Property("BeatmapSetInfoID"); - b.Property("PreviewTime"); b.Property("Source"); @@ -136,12 +135,6 @@ namespace osu.Game.Migrations b.HasKey("ID"); - b.HasIndex("BeatmapInfoID") - .IsUnique(); - - b.HasIndex("BeatmapSetInfoID") - .IsUnique(); - b.ToTable("BeatmapMetadata"); }); @@ -175,6 +168,8 @@ namespace osu.Game.Migrations b.Property("Hash"); + b.Property("MetadataID"); + b.Property("OnlineBeatmapSetID"); b.Property("Protected"); @@ -185,6 +180,8 @@ namespace osu.Game.Migrations b.HasIndex("Hash"); + b.HasIndex("MetadataID"); + b.ToTable("BeatmapSetInfo"); }); @@ -246,49 +243,31 @@ namespace osu.Game.Migrations b.HasIndex("Available"); - b.HasIndex("InstantiationInfo") - .IsUnique(); - - b.HasIndex("Name") - .IsUnique(); - b.ToTable("RulesetInfo"); }); - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapDifficulty", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapInfo") - .WithOne("Difficulty") - .HasForeignKey("osu.Game.Beatmaps.BeatmapDifficulty", "BeatmapInfoID") - .OnDelete(DeleteBehavior.Cascade); - }); - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b => { + b.HasOne("osu.Game.Beatmaps.BeatmapDifficulty", "BaseDifficulty") + .WithMany() + .HasForeignKey("BaseDifficultyID") + .OnDelete(DeleteBehavior.Cascade); + b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo", "BeatmapSet") .WithMany("Beatmaps") .HasForeignKey("BeatmapSetInfoID") .OnDelete(DeleteBehavior.Cascade); + b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata") + .WithMany("Beatmaps") + .HasForeignKey("MetadataID"); + b.HasOne("osu.Game.Rulesets.RulesetInfo", "Ruleset") .WithMany() .HasForeignKey("RulesetID") .OnDelete(DeleteBehavior.Cascade); }); - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapMetadata", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapInfo", "BeatmapInfo") - .WithOne("Metadata") - .HasForeignKey("osu.Game.Beatmaps.BeatmapMetadata", "BeatmapInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo", "BeatmapSetInfo") - .WithOne("Metadata") - .HasForeignKey("osu.Game.Beatmaps.BeatmapMetadata", "BeatmapSetInfoID") - .OnDelete(DeleteBehavior.Cascade); - }); - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b => { b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo") @@ -301,6 +280,13 @@ namespace osu.Game.Migrations .HasForeignKey("FileInfoID") .OnDelete(DeleteBehavior.Cascade); }); + + modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b => + { + b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata") + .WithMany("BeatmapSets") + .HasForeignKey("MetadataID"); + }); #pragma warning restore 612, 618 } } diff --git a/osu.Game/Migrations/20171018125509_InitialCreate.cs b/osu.Game/Migrations/20171019041408_InitialCreate.cs similarity index 85% rename from osu.Game/Migrations/20171018125509_InitialCreate.cs rename to osu.Game/Migrations/20171019041408_InitialCreate.cs index 512ffa2790..23e5b6f8bb 100644 --- a/osu.Game/Migrations/20171018125509_InitialCreate.cs +++ b/osu.Game/Migrations/20171019041408_InitialCreate.cs @@ -9,19 +9,43 @@ namespace osu.Game.Migrations protected override void Up(MigrationBuilder migrationBuilder) { migrationBuilder.CreateTable( - name: "BeatmapSetInfo", + name: "BeatmapDifficulty", columns: table => new { ID = table.Column(type: "INTEGER", nullable: false) .Annotation("Sqlite:Autoincrement", true), - DeletePending = table.Column(type: "INTEGER", nullable: false), - Hash = table.Column(type: "TEXT", nullable: true), - OnlineBeatmapSetID = table.Column(type: "INTEGER", nullable: true), - Protected = table.Column(type: "INTEGER", nullable: false) + ApproachRate = table.Column(type: "REAL", nullable: false), + CircleSize = table.Column(type: "REAL", nullable: false), + DrainRate = table.Column(type: "REAL", nullable: false), + OverallDifficulty = table.Column(type: "REAL", nullable: false), + SliderMultiplier = table.Column(type: "REAL", nullable: false), + SliderTickRate = table.Column(type: "REAL", nullable: false) }, constraints: table => { - table.PrimaryKey("PK_BeatmapSetInfo", x => x.ID); + table.PrimaryKey("PK_BeatmapDifficulty", x => x.ID); + }); + + migrationBuilder.CreateTable( + name: "BeatmapMetadata", + columns: table => new + { + ID = table.Column(type: "INTEGER", nullable: false) + .Annotation("Sqlite:Autoincrement", true), + Artist = table.Column(type: "TEXT", nullable: true), + ArtistUnicode = table.Column(type: "TEXT", nullable: true), + AudioFile = table.Column(type: "TEXT", nullable: true), + Author = table.Column(type: "TEXT", nullable: true), + BackgroundFile = table.Column(type: "TEXT", nullable: true), + PreviewTime = table.Column(type: "INTEGER", nullable: false), + Source = table.Column(type: "TEXT", nullable: true), + Tags = table.Column(type: "TEXT", nullable: true), + Title = table.Column(type: "TEXT", nullable: true), + TitleUnicode = table.Column(type: "TEXT", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_BeatmapMetadata", x => x.ID); }); migrationBuilder.CreateTable( @@ -69,6 +93,87 @@ namespace osu.Game.Migrations table.PrimaryKey("PK_RulesetInfo", x => x.ID); }); + migrationBuilder.CreateTable( + name: "BeatmapSetInfo", + columns: table => new + { + ID = table.Column(type: "INTEGER", nullable: false) + .Annotation("Sqlite:Autoincrement", true), + DeletePending = table.Column(type: "INTEGER", nullable: false), + Hash = table.Column(type: "TEXT", nullable: true), + MetadataID = table.Column(type: "INTEGER", nullable: true), + OnlineBeatmapSetID = table.Column(type: "INTEGER", nullable: true), + Protected = table.Column(type: "INTEGER", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_BeatmapSetInfo", x => x.ID); + table.ForeignKey( + name: "FK_BeatmapSetInfo_BeatmapMetadata_MetadataID", + column: x => x.MetadataID, + principalTable: "BeatmapMetadata", + principalColumn: "ID", + onDelete: ReferentialAction.Restrict); + }); + + migrationBuilder.CreateTable( + name: "BeatmapInfo", + columns: table => new + { + ID = table.Column(type: "INTEGER", nullable: false) + .Annotation("Sqlite:Autoincrement", true), + AudioLeadIn = table.Column(type: "INTEGER", nullable: false), + BaseDifficultyID = table.Column(type: "INTEGER", nullable: false), + BeatDivisor = table.Column(type: "INTEGER", nullable: false), + BeatmapSetInfoID = table.Column(type: "INTEGER", nullable: false), + Countdown = table.Column(type: "INTEGER", nullable: false), + DistanceSpacing = table.Column(type: "REAL", nullable: false), + GridSize = table.Column(type: "INTEGER", nullable: false), + Hash = table.Column(type: "TEXT", nullable: true), + Hidden = table.Column(type: "INTEGER", nullable: false), + LetterboxInBreaks = table.Column(type: "INTEGER", nullable: false), + MD5Hash = table.Column(type: "TEXT", nullable: true), + MetadataID = table.Column(type: "INTEGER", nullable: true), + OnlineBeatmapID = table.Column(type: "INTEGER", nullable: true), + Path = table.Column(type: "TEXT", nullable: true), + RulesetID = table.Column(type: "INTEGER", nullable: false), + SpecialStyle = table.Column(type: "INTEGER", nullable: false), + StackLeniency = table.Column(type: "REAL", nullable: false), + StarDifficulty = table.Column(type: "REAL", nullable: false), + StoredBookmarks = table.Column(type: "TEXT", nullable: true), + TimelineZoom = table.Column(type: "REAL", nullable: false), + Version = table.Column(type: "TEXT", nullable: true), + WidescreenStoryboard = table.Column(type: "INTEGER", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_BeatmapInfo", x => x.ID); + table.ForeignKey( + name: "FK_BeatmapInfo_BeatmapDifficulty_BaseDifficultyID", + column: x => x.BaseDifficultyID, + principalTable: "BeatmapDifficulty", + principalColumn: "ID", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_BeatmapInfo_BeatmapSetInfo_BeatmapSetInfoID", + column: x => x.BeatmapSetInfoID, + principalTable: "BeatmapSetInfo", + principalColumn: "ID", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_BeatmapInfo_BeatmapMetadata_MetadataID", + column: x => x.MetadataID, + principalTable: "BeatmapMetadata", + principalColumn: "ID", + onDelete: ReferentialAction.Restrict); + table.ForeignKey( + name: "FK_BeatmapInfo_RulesetInfo_RulesetID", + column: x => x.RulesetID, + principalTable: "RulesetInfo", + principalColumn: "ID", + onDelete: ReferentialAction.Cascade); + }); + migrationBuilder.CreateTable( name: "BeatmapSetFileInfo", columns: table => new @@ -96,116 +201,10 @@ namespace osu.Game.Migrations onDelete: ReferentialAction.Cascade); }); - migrationBuilder.CreateTable( - name: "BeatmapInfo", - columns: table => new - { - ID = table.Column(type: "INTEGER", nullable: false) - .Annotation("Sqlite:Autoincrement", true), - AudioLeadIn = table.Column(type: "INTEGER", nullable: false), - BaseDifficultyID = table.Column(type: "INTEGER", nullable: false), - BeatDivisor = table.Column(type: "INTEGER", nullable: false), - BeatmapSetInfoID = table.Column(type: "INTEGER", nullable: false), - Countdown = table.Column(type: "INTEGER", nullable: false), - DistanceSpacing = table.Column(type: "REAL", nullable: false), - GridSize = table.Column(type: "INTEGER", nullable: false), - Hash = table.Column(type: "TEXT", nullable: true), - Hidden = table.Column(type: "INTEGER", nullable: false), - LetterboxInBreaks = table.Column(type: "INTEGER", nullable: false), - MD5Hash = table.Column(type: "TEXT", nullable: true), - Path = table.Column(type: "TEXT", nullable: true), - RulesetID = table.Column(type: "INTEGER", nullable: false), - SpecialStyle = table.Column(type: "INTEGER", nullable: false), - StackLeniency = table.Column(type: "REAL", nullable: false), - StarDifficulty = table.Column(type: "REAL", nullable: false), - StoredBookmarks = table.Column(type: "TEXT", nullable: true), - TimelineZoom = table.Column(type: "REAL", nullable: false), - Version = table.Column(type: "TEXT", nullable: true), - WidescreenStoryboard = table.Column(type: "INTEGER", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_BeatmapInfo", x => x.ID); - table.ForeignKey( - name: "FK_BeatmapInfo_BeatmapSetInfo_BeatmapSetInfoID", - column: x => x.BeatmapSetInfoID, - principalTable: "BeatmapSetInfo", - principalColumn: "ID", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "FK_BeatmapInfo_RulesetInfo_RulesetID", - column: x => x.RulesetID, - principalTable: "RulesetInfo", - principalColumn: "ID", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "BeatmapDifficulty", - columns: table => new - { - ID = table.Column(type: "INTEGER", nullable: false) - .Annotation("Sqlite:Autoincrement", true), - ApproachRate = table.Column(type: "REAL", nullable: false), - BeatmapInfoID = table.Column(type: "INTEGER", nullable: false), - CircleSize = table.Column(type: "REAL", nullable: false), - DrainRate = table.Column(type: "REAL", nullable: false), - OverallDifficulty = table.Column(type: "REAL", nullable: false), - SliderMultiplier = table.Column(type: "REAL", nullable: false), - SliderTickRate = table.Column(type: "REAL", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_BeatmapDifficulty", x => x.ID); - table.ForeignKey( - name: "FK_BeatmapDifficulty_BeatmapInfo_BeatmapInfoID", - column: x => x.BeatmapInfoID, - principalTable: "BeatmapInfo", - principalColumn: "ID", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "BeatmapMetadata", - columns: table => new - { - ID = table.Column(type: "INTEGER", nullable: false) - .Annotation("Sqlite:Autoincrement", true), - Artist = table.Column(type: "TEXT", nullable: true), - ArtistUnicode = table.Column(type: "TEXT", nullable: true), - AudioFile = table.Column(type: "TEXT", nullable: true), - Author = table.Column(type: "TEXT", nullable: true), - BackgroundFile = table.Column(type: "TEXT", nullable: true), - BeatmapInfoID = table.Column(type: "INTEGER", nullable: true), - BeatmapSetInfoID = table.Column(type: "INTEGER", nullable: true), - PreviewTime = table.Column(type: "INTEGER", nullable: false), - Source = table.Column(type: "TEXT", nullable: true), - Tags = table.Column(type: "TEXT", nullable: true), - Title = table.Column(type: "TEXT", nullable: true), - TitleUnicode = table.Column(type: "TEXT", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_BeatmapMetadata", x => x.ID); - table.ForeignKey( - name: "FK_BeatmapMetadata_BeatmapInfo_BeatmapInfoID", - column: x => x.BeatmapInfoID, - principalTable: "BeatmapInfo", - principalColumn: "ID", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "FK_BeatmapMetadata_BeatmapSetInfo_BeatmapSetInfoID", - column: x => x.BeatmapSetInfoID, - principalTable: "BeatmapSetInfo", - principalColumn: "ID", - onDelete: ReferentialAction.Cascade); - }); - migrationBuilder.CreateIndex( - name: "IX_BeatmapDifficulty_BeatmapInfoID", - table: "BeatmapDifficulty", - column: "BeatmapInfoID", - unique: true); + name: "IX_BeatmapInfo_BaseDifficultyID", + table: "BeatmapInfo", + column: "BaseDifficultyID"); migrationBuilder.CreateIndex( name: "IX_BeatmapInfo_BeatmapSetInfoID", @@ -222,23 +221,16 @@ namespace osu.Game.Migrations table: "BeatmapInfo", column: "MD5Hash"); + migrationBuilder.CreateIndex( + name: "IX_BeatmapInfo_MetadataID", + table: "BeatmapInfo", + column: "MetadataID"); + migrationBuilder.CreateIndex( name: "IX_BeatmapInfo_RulesetID", table: "BeatmapInfo", column: "RulesetID"); - migrationBuilder.CreateIndex( - name: "IX_BeatmapMetadata_BeatmapInfoID", - table: "BeatmapMetadata", - column: "BeatmapInfoID", - unique: true); - - migrationBuilder.CreateIndex( - name: "IX_BeatmapMetadata_BeatmapSetInfoID", - table: "BeatmapMetadata", - column: "BeatmapSetInfoID", - unique: true); - migrationBuilder.CreateIndex( name: "IX_BeatmapSetFileInfo_BeatmapSetInfoID", table: "BeatmapSetFileInfo", @@ -259,6 +251,11 @@ namespace osu.Game.Migrations table: "BeatmapSetInfo", column: "Hash"); + migrationBuilder.CreateIndex( + name: "IX_BeatmapSetInfo_MetadataID", + table: "BeatmapSetInfo", + column: "MetadataID"); + migrationBuilder.CreateIndex( name: "IX_FileInfo_Hash", table: "FileInfo", @@ -284,27 +281,12 @@ namespace osu.Game.Migrations name: "IX_RulesetInfo_Available", table: "RulesetInfo", column: "Available"); - - migrationBuilder.CreateIndex( - name: "IX_RulesetInfo_InstantiationInfo", - table: "RulesetInfo", - column: "InstantiationInfo", - unique: true); - - migrationBuilder.CreateIndex( - name: "IX_RulesetInfo_Name", - table: "RulesetInfo", - column: "Name", - unique: true); } protected override void Down(MigrationBuilder migrationBuilder) { migrationBuilder.DropTable( - name: "BeatmapDifficulty"); - - migrationBuilder.DropTable( - name: "BeatmapMetadata"); + name: "BeatmapInfo"); migrationBuilder.DropTable( name: "BeatmapSetFileInfo"); @@ -313,16 +295,19 @@ namespace osu.Game.Migrations name: "KeyBinding"); migrationBuilder.DropTable( - name: "BeatmapInfo"); + name: "BeatmapDifficulty"); migrationBuilder.DropTable( - name: "FileInfo"); + name: "RulesetInfo"); migrationBuilder.DropTable( name: "BeatmapSetInfo"); migrationBuilder.DropTable( - name: "RulesetInfo"); + name: "FileInfo"); + + migrationBuilder.DropTable( + name: "BeatmapMetadata"); } } } diff --git a/osu.Game/Migrations/OsuDbContextModelSnapshot.cs b/osu.Game/Migrations/OsuDbContextModelSnapshot.cs index 8d0d8f20fe..0576242648 100644 --- a/osu.Game/Migrations/OsuDbContextModelSnapshot.cs +++ b/osu.Game/Migrations/OsuDbContextModelSnapshot.cs @@ -25,8 +25,6 @@ namespace osu.Game.Migrations b.Property("ApproachRate"); - b.Property("BeatmapInfoID"); - b.Property("CircleSize"); b.Property("DrainRate"); @@ -39,9 +37,6 @@ namespace osu.Game.Migrations b.HasKey("ID"); - b.HasIndex("BeatmapInfoID") - .IsUnique(); - b.ToTable("BeatmapDifficulty"); }); @@ -72,6 +67,10 @@ namespace osu.Game.Migrations b.Property("MD5Hash"); + b.Property("MetadataID"); + + b.Property("OnlineBeatmapID"); + b.Property("Path"); b.Property("RulesetID"); @@ -92,12 +91,16 @@ namespace osu.Game.Migrations b.HasKey("ID"); + b.HasIndex("BaseDifficultyID"); + b.HasIndex("BeatmapSetInfoID"); b.HasIndex("Hash"); b.HasIndex("MD5Hash"); + b.HasIndex("MetadataID"); + b.HasIndex("RulesetID"); b.ToTable("BeatmapInfo"); @@ -119,10 +122,6 @@ namespace osu.Game.Migrations b.Property("BackgroundFile"); - b.Property("BeatmapInfoID"); - - b.Property("BeatmapSetInfoID"); - b.Property("PreviewTime"); b.Property("Source"); @@ -135,12 +134,6 @@ namespace osu.Game.Migrations b.HasKey("ID"); - b.HasIndex("BeatmapInfoID") - .IsUnique(); - - b.HasIndex("BeatmapSetInfoID") - .IsUnique(); - b.ToTable("BeatmapMetadata"); }); @@ -174,6 +167,8 @@ namespace osu.Game.Migrations b.Property("Hash"); + b.Property("MetadataID"); + b.Property("OnlineBeatmapSetID"); b.Property("Protected"); @@ -184,6 +179,8 @@ namespace osu.Game.Migrations b.HasIndex("Hash"); + b.HasIndex("MetadataID"); + b.ToTable("BeatmapSetInfo"); }); @@ -245,49 +242,31 @@ namespace osu.Game.Migrations b.HasIndex("Available"); - b.HasIndex("InstantiationInfo") - .IsUnique(); - - b.HasIndex("Name") - .IsUnique(); - b.ToTable("RulesetInfo"); }); - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapDifficulty", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapInfo") - .WithOne("Difficulty") - .HasForeignKey("osu.Game.Beatmaps.BeatmapDifficulty", "BeatmapInfoID") - .OnDelete(DeleteBehavior.Cascade); - }); - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b => { + b.HasOne("osu.Game.Beatmaps.BeatmapDifficulty", "BaseDifficulty") + .WithMany() + .HasForeignKey("BaseDifficultyID") + .OnDelete(DeleteBehavior.Cascade); + b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo", "BeatmapSet") .WithMany("Beatmaps") .HasForeignKey("BeatmapSetInfoID") .OnDelete(DeleteBehavior.Cascade); + b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata") + .WithMany("Beatmaps") + .HasForeignKey("MetadataID"); + b.HasOne("osu.Game.Rulesets.RulesetInfo", "Ruleset") .WithMany() .HasForeignKey("RulesetID") .OnDelete(DeleteBehavior.Cascade); }); - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapMetadata", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapInfo", "BeatmapInfo") - .WithOne("Metadata") - .HasForeignKey("osu.Game.Beatmaps.BeatmapMetadata", "BeatmapInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo", "BeatmapSetInfo") - .WithOne("Metadata") - .HasForeignKey("osu.Game.Beatmaps.BeatmapMetadata", "BeatmapSetInfoID") - .OnDelete(DeleteBehavior.Cascade); - }); - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b => { b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo") @@ -300,6 +279,13 @@ namespace osu.Game.Migrations .HasForeignKey("FileInfoID") .OnDelete(DeleteBehavior.Cascade); }); + + modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b => + { + b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata") + .WithMany("BeatmapSets") + .HasForeignKey("MetadataID"); + }); #pragma warning restore 612, 618 } } diff --git a/osu.Game/Rulesets/UI/RulesetContainer.cs b/osu.Game/Rulesets/UI/RulesetContainer.cs index 729df02ffd..6f53b76031 100644 --- a/osu.Game/Rulesets/UI/RulesetContainer.cs +++ b/osu.Game/Rulesets/UI/RulesetContainer.cs @@ -172,11 +172,11 @@ namespace osu.Game.Rulesets.UI // Apply difficulty adjustments from mods before using Difficulty. foreach (var mod in Mods.OfType()) - mod.ApplyToDifficulty(Beatmap.BeatmapInfo.Difficulty); + mod.ApplyToDifficulty(Beatmap.BeatmapInfo.BaseDifficulty); // Apply defaults foreach (var h in Beatmap.HitObjects) - h.ApplyDefaults(Beatmap.ControlPointInfo, Beatmap.BeatmapInfo.Difficulty); + h.ApplyDefaults(Beatmap.ControlPointInfo, Beatmap.BeatmapInfo.BaseDifficulty); // Post-process the beatmap processor.PostProcess(Beatmap); diff --git a/osu.Game/Screens/Select/BeatmapDetails.cs b/osu.Game/Screens/Select/BeatmapDetails.cs index a98362e89c..d7c509d979 100644 --- a/osu.Game/Screens/Select/BeatmapDetails.cs +++ b/osu.Game/Screens/Select/BeatmapDetails.cs @@ -264,7 +264,7 @@ namespace osu.Game.Screens.Select advanced.Beatmap = new BeatmapInfo { StarDifficulty = 0, - Difficulty = new BeatmapDifficulty + BaseDifficulty = new BeatmapDifficulty { CircleSize = 0, DrainRate = 0, diff --git a/osu.Game/Screens/Select/Details/AdvancedStats.cs b/osu.Game/Screens/Select/Details/AdvancedStats.cs index f1215ab33d..3c9cffadfb 100644 --- a/osu.Game/Screens/Select/Details/AdvancedStats.cs +++ b/osu.Game/Screens/Select/Details/AdvancedStats.cs @@ -32,17 +32,17 @@ namespace osu.Game.Screens.Select.Details if ((Beatmap?.Ruleset?.ID ?? 0) == 3) { firstValue.Title = "Key Amount"; - firstValue.Value = (int)Math.Round(Beatmap?.Difficulty?.CircleSize ?? 0); + firstValue.Value = (int)Math.Round(Beatmap?.BaseDifficulty?.CircleSize ?? 0); } else { firstValue.Title = "Circle Size"; - firstValue.Value = Beatmap?.Difficulty?.CircleSize ?? 0; + firstValue.Value = Beatmap?.BaseDifficulty?.CircleSize ?? 0; } - hpDrain.Value = beatmap.Difficulty?.DrainRate ?? 0; - accuracy.Value = beatmap.Difficulty?.OverallDifficulty ?? 0; - approachRate.Value = beatmap.Difficulty?.ApproachRate ?? 0; + hpDrain.Value = beatmap.BaseDifficulty?.DrainRate ?? 0; + accuracy.Value = beatmap.BaseDifficulty?.OverallDifficulty ?? 0; + approachRate.Value = beatmap.BaseDifficulty?.ApproachRate ?? 0; starDifficulty.Value = (float)beatmap.StarDifficulty; } } diff --git a/osu.Game/Tests/Visual/TestCaseBeatmapDetails.cs b/osu.Game/Tests/Visual/TestCaseBeatmapDetails.cs index cd4d97425b..5306121a92 100644 --- a/osu.Game/Tests/Visual/TestCaseBeatmapDetails.cs +++ b/osu.Game/Tests/Visual/TestCaseBeatmapDetails.cs @@ -29,7 +29,7 @@ namespace osu.Game.Tests.Visual Source = "osu!lazer", Tags = "this beatmap has all the metrics", }, - Difficulty = new BeatmapDifficulty + BaseDifficulty = new BeatmapDifficulty { CircleSize = 7, DrainRate = 1, @@ -53,7 +53,7 @@ namespace osu.Game.Tests.Visual Source = "osu!lazer", Tags = "this beatmap has ratings metrics but not retries or fails", }, - Difficulty = new BeatmapDifficulty + BaseDifficulty = new BeatmapDifficulty { CircleSize = 6, DrainRate = 9, @@ -75,7 +75,7 @@ namespace osu.Game.Tests.Visual Source = "osu!lazer", Tags = "this beatmap has retries and fails but no ratings", }, - Difficulty = new BeatmapDifficulty + BaseDifficulty = new BeatmapDifficulty { CircleSize = 3.7f, DrainRate = 6, @@ -98,7 +98,7 @@ namespace osu.Game.Tests.Visual Source = "osu!lazer", Tags = "this beatmap has no metrics", }, - Difficulty = new BeatmapDifficulty + BaseDifficulty = new BeatmapDifficulty { CircleSize = 5, DrainRate = 5, diff --git a/osu.Game/Tests/Visual/TestCaseBeatmapSetOverlay.cs b/osu.Game/Tests/Visual/TestCaseBeatmapSetOverlay.cs index 72d97f905c..1ade0be626 100644 --- a/osu.Game/Tests/Visual/TestCaseBeatmapSetOverlay.cs +++ b/osu.Game/Tests/Visual/TestCaseBeatmapSetOverlay.cs @@ -65,7 +65,7 @@ namespace osu.Game.Tests.Visual StarDifficulty = 1.36, Version = @"BASIC", Ruleset = mania, - Difficulty = new BeatmapDifficulty + BaseDifficulty = new BeatmapDifficulty { CircleSize = 4, DrainRate = 6.5f, @@ -93,7 +93,7 @@ namespace osu.Game.Tests.Visual StarDifficulty = 2.22, Version = @"NOVICE", Ruleset = mania, - Difficulty = new BeatmapDifficulty + BaseDifficulty = new BeatmapDifficulty { CircleSize = 4, DrainRate = 7, @@ -121,7 +121,7 @@ namespace osu.Game.Tests.Visual StarDifficulty = 3.49, Version = @"ADVANCED", Ruleset = mania, - Difficulty = new BeatmapDifficulty + BaseDifficulty = new BeatmapDifficulty { CircleSize = 4, DrainRate = 7.5f, @@ -149,7 +149,7 @@ namespace osu.Game.Tests.Visual StarDifficulty = 4.24, Version = @"EXHAUST", Ruleset = mania, - Difficulty = new BeatmapDifficulty + BaseDifficulty = new BeatmapDifficulty { CircleSize = 4, DrainRate = 8, @@ -177,7 +177,7 @@ namespace osu.Game.Tests.Visual StarDifficulty = 5.26, Version = @"GRAVITY", Ruleset = mania, - Difficulty = new BeatmapDifficulty + BaseDifficulty = new BeatmapDifficulty { CircleSize = 4, DrainRate = 8.5f, @@ -239,7 +239,7 @@ namespace osu.Game.Tests.Visual StarDifficulty = 1.40, Version = @"yzrin's Kantan", Ruleset = taiko, - Difficulty = new BeatmapDifficulty + BaseDifficulty = new BeatmapDifficulty { CircleSize = 2, DrainRate = 7, @@ -267,7 +267,7 @@ namespace osu.Game.Tests.Visual StarDifficulty = 2.23, Version = @"Futsuu", Ruleset = taiko, - Difficulty = new BeatmapDifficulty + BaseDifficulty = new BeatmapDifficulty { CircleSize = 2, DrainRate = 6, @@ -295,7 +295,7 @@ namespace osu.Game.Tests.Visual StarDifficulty = 3.19, Version = @"Muzukashii", Ruleset = taiko, - Difficulty = new BeatmapDifficulty + BaseDifficulty = new BeatmapDifficulty { CircleSize = 2, DrainRate = 6, @@ -323,7 +323,7 @@ namespace osu.Game.Tests.Visual StarDifficulty = 3.97, Version = @"Charlotte's Oni", Ruleset = taiko, - Difficulty = new BeatmapDifficulty + BaseDifficulty = new BeatmapDifficulty { CircleSize = 5, DrainRate = 6, @@ -351,7 +351,7 @@ namespace osu.Game.Tests.Visual StarDifficulty = 5.08, Version = @"Labyrinth Oni", Ruleset = taiko, - Difficulty = new BeatmapDifficulty + BaseDifficulty = new BeatmapDifficulty { CircleSize = 5, DrainRate = 5, diff --git a/osu.Game/Tests/Visual/TestCasePlaySongSelect.cs b/osu.Game/Tests/Visual/TestCasePlaySongSelect.cs index a46542760b..965308c32c 100644 --- a/osu.Game/Tests/Visual/TestCasePlaySongSelect.cs +++ b/osu.Game/Tests/Visual/TestCasePlaySongSelect.cs @@ -80,7 +80,7 @@ namespace osu.Game.Tests.Visual Ruleset = rulesets.AvailableRulesets.First(), Path = "normal.osu", Version = "Normal", - Difficulty = new BeatmapDifficulty + BaseDifficulty = new BeatmapDifficulty { OverallDifficulty = 3.5f, } @@ -91,7 +91,7 @@ namespace osu.Game.Tests.Visual Ruleset = rulesets.AvailableRulesets.First(), Path = "hard.osu", Version = "Hard", - Difficulty = new BeatmapDifficulty + BaseDifficulty = new BeatmapDifficulty { OverallDifficulty = 5, } @@ -102,7 +102,7 @@ namespace osu.Game.Tests.Visual Ruleset = rulesets.AvailableRulesets.First(), Path = "insane.osu", Version = "Insane", - Difficulty = new BeatmapDifficulty + BaseDifficulty = new BeatmapDifficulty { OverallDifficulty = 7, } diff --git a/osu.Game/Tests/Visual/TestCaseScrollingPlayfield.cs b/osu.Game/Tests/Visual/TestCaseScrollingPlayfield.cs index d0761e5841..40fb22af1e 100644 --- a/osu.Game/Tests/Visual/TestCaseScrollingPlayfield.cs +++ b/osu.Game/Tests/Visual/TestCaseScrollingPlayfield.cs @@ -48,7 +48,7 @@ namespace osu.Game.Tests.Visual HitObjects = objects, BeatmapInfo = new BeatmapInfo { - Difficulty = new BeatmapDifficulty(), + BaseDifficulty = new BeatmapDifficulty(), Metadata = new BeatmapMetadata() } }; diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 0e16c70277..85b08afecd 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -281,9 +281,9 @@ - - - 20171018125509_InitialCreate.cs + + + 20171019041408_InitialCreate.cs From 908c6d827fc466e719101037d94bca27ef00b97f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 19 Oct 2017 14:49:23 +0900 Subject: [PATCH 0353/1263] ValueTuple please --- osu.Game.Tests/osu.Game.Tests.csproj | 2 +- osu.Game/osu.Game.csproj | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/osu.Game.Tests/osu.Game.Tests.csproj b/osu.Game.Tests/osu.Game.Tests.csproj index 7a3bbab176..51c1b03373 100644 --- a/osu.Game.Tests/osu.Game.Tests.csproj +++ b/osu.Game.Tests/osu.Game.Tests.csproj @@ -40,7 +40,7 @@ - ../packages/System.ValueTuple.4.4.0/lib/net461/System.ValueTuple.dll + $(SolutionDir)\packages\System.ValueTuple.4.4.0\lib\net461\System.ValueTuple.dll True diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 85b08afecd..601c99e19f 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -861,10 +861,6 @@ - - true - true - From 36af0dc809418ac61b1d1a72f547736ec68af9ef Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 19 Oct 2017 14:59:11 +0900 Subject: [PATCH 0354/1263] Update app config for rulesets --- osu.Game.Rulesets.Catch/app.config | 4 ++++ osu.Game.Rulesets.Mania/app.config | 4 ++++ osu.Game.Rulesets.Osu/app.config | 4 ++++ osu.Game.Rulesets.Taiko/app.config | 4 ++++ 4 files changed, 16 insertions(+) diff --git a/osu.Game.Rulesets.Catch/app.config b/osu.Game.Rulesets.Catch/app.config index 11af32e2cf..c9d4e44b1a 100644 --- a/osu.Game.Rulesets.Catch/app.config +++ b/osu.Game.Rulesets.Catch/app.config @@ -10,6 +10,10 @@ + + + + \ No newline at end of file diff --git a/osu.Game.Rulesets.Mania/app.config b/osu.Game.Rulesets.Mania/app.config index 11af32e2cf..c9d4e44b1a 100644 --- a/osu.Game.Rulesets.Mania/app.config +++ b/osu.Game.Rulesets.Mania/app.config @@ -10,6 +10,10 @@ + + + + \ No newline at end of file diff --git a/osu.Game.Rulesets.Osu/app.config b/osu.Game.Rulesets.Osu/app.config index 11af32e2cf..c9d4e44b1a 100644 --- a/osu.Game.Rulesets.Osu/app.config +++ b/osu.Game.Rulesets.Osu/app.config @@ -10,6 +10,10 @@ + + + + \ No newline at end of file diff --git a/osu.Game.Rulesets.Taiko/app.config b/osu.Game.Rulesets.Taiko/app.config index 11af32e2cf..c9d4e44b1a 100644 --- a/osu.Game.Rulesets.Taiko/app.config +++ b/osu.Game.Rulesets.Taiko/app.config @@ -10,6 +10,10 @@ + + + + \ No newline at end of file From 12900a8b1503869a2a5a10a7ce29ac20b6383790 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 19 Oct 2017 15:53:11 +0900 Subject: [PATCH 0355/1263] Remove unnecessary second call to AutoTransactionsEnabled --- osu.Game/Beatmaps/BeatmapManager.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 8a2997987b..47dbc72837 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -184,8 +184,6 @@ namespace osu.Game.Beatmaps { var context = importContext.Value; - context.Database.AutoTransactionsEnabled = false; - using (var transaction = context.Database.BeginTransaction()) { // create local stores so we can isolate and thread safely, and share a context/transaction. From 36c00577af65638ed56f56dedaca01d0210005ce Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 19 Oct 2017 16:35:06 +0900 Subject: [PATCH 0356/1263] Reduce database log output Also hard-disables it for uninteresting log levels, providing a further performance boost. --- osu.Game/Database/OsuDbContext.cs | 35 ++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/osu.Game/Database/OsuDbContext.cs b/osu.Game/Database/OsuDbContext.cs index 37d5bb21c8..e3605181a4 100644 --- a/osu.Game/Database/OsuDbContext.cs +++ b/osu.Game/Database/OsuDbContext.cs @@ -31,7 +31,8 @@ namespace osu.Game.Database /// /// Create a new in-memory OsuDbContext instance. /// - public OsuDbContext() : this("DataSource=:memory:") + public OsuDbContext() + : this("DataSource=:memory:") { // required for tooling (see https://wildermuth.com/2017/07/06/Program-cs-in-ASP-NET-Core-2-0). } @@ -116,9 +117,37 @@ namespace osu.Game.Database private class OsuDbLogger : ILogger { public void Log(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func formatter) - => Logger.Log(formatter(state, exception), LoggingTarget.Database, Framework.Logging.LogLevel.Debug); + { + if (logLevel < LogLevel.Information) + return; - public bool IsEnabled(LogLevel logLevel) => true; + Framework.Logging.LogLevel frameworkLogLevel; + + switch (logLevel) + { + default: + frameworkLogLevel = Framework.Logging.LogLevel.Debug; + break; + case LogLevel.Warning: + frameworkLogLevel = Framework.Logging.LogLevel.Important; + break; + case LogLevel.Error: + case LogLevel.Critical: + frameworkLogLevel = Framework.Logging.LogLevel.Error; + break; + } + + Logger.Log(formatter(state, exception), LoggingTarget.Database, frameworkLogLevel); + } + + public bool IsEnabled(LogLevel logLevel) + { +#if DEBUG + return logLevel > LogLevel.Debug; +#else + return logLevel > LogLevel.Information; +#endif + } public IDisposable BeginScope(TState state) => null; } From b02dd196f678d67f95fa80dee534a903bc2d6abb Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 19 Oct 2017 17:29:39 +0900 Subject: [PATCH 0357/1263] Don't make one factory each context A factory is supposed to be re-used. --- osu.Game/Database/OsuDbContext.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game/Database/OsuDbContext.cs b/osu.Game/Database/OsuDbContext.cs index e3605181a4..98a5cc8b67 100644 --- a/osu.Game/Database/OsuDbContext.cs +++ b/osu.Game/Database/OsuDbContext.cs @@ -22,6 +22,8 @@ namespace osu.Game.Database public DbSet RulesetInfo { get; set; } private readonly string connectionString; + private static readonly Lazy logger = new Lazy(() => new OsuDbLoggerFactory()); + static OsuDbContext() { // required to initialise native SQLite libraries on some platforms. @@ -60,7 +62,7 @@ namespace osu.Game.Database { base.OnConfiguring(optionsBuilder); optionsBuilder.UseSqlite(connectionString); - optionsBuilder.UseLoggerFactory(new OsuDbLoggerFactory()); + optionsBuilder.UseLoggerFactory(logger.Value); } protected override void OnModelCreating(ModelBuilder modelBuilder) From f7d0df174327b0edf4ead40825a793dfad4300f0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 19 Oct 2017 17:50:46 +0900 Subject: [PATCH 0358/1263] Fix beatmap difficulty and metadata deletion --- osu.Game/Beatmaps/BeatmapStore.cs | 15 ++++++++++++++- osu.Game/Database/OsuDbContext.cs | 2 ++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/osu.Game/Beatmaps/BeatmapStore.cs b/osu.Game/Beatmaps/BeatmapStore.cs index c2ec8c7b05..8eac35a667 100644 --- a/osu.Game/Beatmaps/BeatmapStore.cs +++ b/osu.Game/Beatmaps/BeatmapStore.cs @@ -130,7 +130,20 @@ namespace osu.Game.Beatmaps { var context = GetContext(); - context.BeatmapSetInfo.RemoveRange(context.BeatmapSetInfo.Where(b => b.DeletePending && !b.Protected)); + var purgeable = context.BeatmapSetInfo.Where(s => s.DeletePending && !s.Protected) + .Include(s => s.Beatmaps).ThenInclude(b => b.Metadata) + .Include(s => s.Beatmaps).ThenInclude(b => b.BaseDifficulty) + .Include(s => s.Metadata); + + // metadata is M-N so we can't rely on cascades + context.BeatmapMetadata.RemoveRange(purgeable.Select(s => s.Metadata)); + context.BeatmapMetadata.RemoveRange(purgeable.SelectMany(s => s.Beatmaps.Select(b => b.Metadata))); + + // todo: we can probably make cascades work here with a FK in BeatmapDifficulty. just make to make it work correctly. + context.BeatmapDifficulty.RemoveRange(purgeable.SelectMany(s => s.Beatmaps.Select(b => b.BaseDifficulty))); + + // cascades down to beatmaps. + context.BeatmapSetInfo.RemoveRange(purgeable); context.SaveChanges(); } diff --git a/osu.Game/Database/OsuDbContext.cs b/osu.Game/Database/OsuDbContext.cs index 98a5cc8b67..2938a8e7be 100644 --- a/osu.Game/Database/OsuDbContext.cs +++ b/osu.Game/Database/OsuDbContext.cs @@ -16,6 +16,8 @@ namespace osu.Game.Database public class OsuDbContext : DbContext { public DbSet BeatmapInfo { get; set; } + public DbSet BeatmapDifficulty { get; set; } + public DbSet BeatmapMetadata { get; set; } public DbSet BeatmapSetInfo { get; set; } public DbSet DatabasedKeyBinding { get; set; } public DbSet FileInfo { get; set; } From 1fbbee14e4c000931a8b404bac13b4ce376ab5a8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 19 Oct 2017 19:41:16 +0900 Subject: [PATCH 0359/1263] Allow migration from sqlite-net to EF Bonus stage --- osu.Game/Database/DatabaseContextFactory.cs | 2 +- osu.Game/Database/OsuDbContext.cs | 69 +++++++++++++++++++++ osu.Game/OsuGameBase.cs | 3 +- 3 files changed, 71 insertions(+), 3 deletions(-) diff --git a/osu.Game/Database/DatabaseContextFactory.cs b/osu.Game/Database/DatabaseContextFactory.cs index e22301adfe..359188b4e2 100644 --- a/osu.Game/Database/DatabaseContextFactory.cs +++ b/osu.Game/Database/DatabaseContextFactory.cs @@ -14,6 +14,6 @@ namespace osu.Game.Database this.host = host; } - public OsuDbContext GetContext() => new OsuDbContext(host.Storage.GetDatabaseConnectionString(@"client-ef")); + public OsuDbContext GetContext() => new OsuDbContext(host.Storage.GetDatabaseConnectionString(@"client")); } } diff --git a/osu.Game/Database/OsuDbContext.cs b/osu.Game/Database/OsuDbContext.cs index 2938a8e7be..3f51ac1910 100644 --- a/osu.Game/Database/OsuDbContext.cs +++ b/osu.Game/Database/OsuDbContext.cs @@ -156,5 +156,74 @@ namespace osu.Game.Database public IDisposable BeginScope(TState state) => null; } } + + public void Migrate() + { + migrateFromSqliteNet(); + Database.Migrate(); + } + + private void migrateFromSqliteNet() + { + try + { + // will fail if EF hasn't touched the database yet. + Database.ExecuteSqlCommand("SELECT * FROM __EFMigrationsHistory LIMIT 1"); + } + catch + { + try + { + // will fail (intentionally) if we don't have sqlite-net data present. + Database.ExecuteSqlCommand("SELECT OnlineBeatmapSetId FROM BeatmapMetadata LIMIT 1"); + + // we are good to perform messy migration of data!. + Database.ExecuteSqlCommand("ALTER TABLE BeatmapDifficulty RENAME TO BeatmapDifficulty_Old"); + Database.ExecuteSqlCommand("ALTER TABLE BeatmapMetadata RENAME TO BeatmapMetadata_Old"); + Database.ExecuteSqlCommand("ALTER TABLE FileInfo RENAME TO FileInfo_Old"); + Database.ExecuteSqlCommand("ALTER TABLE KeyBinding RENAME TO KeyBinding_Old"); + Database.ExecuteSqlCommand("ALTER TABLE BeatmapSetInfo RENAME TO BeatmapSetInfo_Old"); + Database.ExecuteSqlCommand("ALTER TABLE BeatmapInfo RENAME TO BeatmapInfo_Old"); + Database.ExecuteSqlCommand("ALTER TABLE BeatmapSetFileInfo RENAME TO BeatmapSetFileInfo_Old"); + Database.ExecuteSqlCommand("ALTER TABLE RulesetInfo RENAME TO RulesetInfo_Old"); + + Database.ExecuteSqlCommand("DROP TABLE StoreVersion"); + + // perform EF migrations to create sane table structure. + Database.Migrate(); + + // copy data table by table to new structure, dropping old tables as we go. + Database.ExecuteSqlCommand("INSERT INTO FileInfo SELECT * FROM FileInfo_Old"); + Database.ExecuteSqlCommand("DROP TABLE FileInfo_Old"); + + Database.ExecuteSqlCommand("INSERT INTO KeyBinding SELECT ID, [Action], Keys, RulesetID, Variant FROM KeyBinding_Old"); + Database.ExecuteSqlCommand("DROP TABLE KeyBinding_Old"); + + Database.ExecuteSqlCommand( + "INSERT INTO BeatmapMetadata SELECT ID, Artist, ArtistUnicode, AudioFile, Author, BackgroundFile, PreviewTime, Source, Tags, Title, TitleUnicode FROM BeatmapMetadata_Old"); + Database.ExecuteSqlCommand("DROP TABLE BeatmapMetadata_Old"); + + Database.ExecuteSqlCommand( + "INSERT INTO BeatmapDifficulty SELECT `ID`, `ApproachRate`, `CircleSize`, `DrainRate`, `OverallDifficulty`, `SliderMultiplier`, `SliderTickRate` FROM BeatmapDifficulty_Old"); + Database.ExecuteSqlCommand("DROP TABLE BeatmapDifficulty_Old"); + + Database.ExecuteSqlCommand("INSERT INTO BeatmapSetInfo SELECT ID, DeletePending, Hash, BeatmapMetadataID, OnlineBeatmapSetID, Protected FROM BeatmapSetInfo_Old"); + Database.ExecuteSqlCommand("DROP TABLE BeatmapSetInfo_Old"); + + Database.ExecuteSqlCommand("INSERT INTO BeatmapSetFileInfo SELECT ID, BeatmapSetInfoID, FileInfoID, Filename FROM BeatmapSetFileInfo_Old"); + Database.ExecuteSqlCommand("DROP TABLE BeatmapSetFileInfo_Old"); + + Database.ExecuteSqlCommand("INSERT INTO RulesetInfo SELECT ID, Available, InstantiationInfo, Name FROM RulesetInfo_Old"); + Database.ExecuteSqlCommand("DROP TABLE RulesetInfo_Old"); + + Database.ExecuteSqlCommand( + "INSERT INTO BeatmapInfo SELECT ID, AudioLeadIn, BaseDifficultyID, BeatDivisor, BeatmapSetInfoID, Countdown, DistanceSpacing, GridSize, Hash, Hidden, LetterboxInBreaks, MD5Hash, NULLIF(BeatmapMetadataID, 0), OnlineBeatmapID, Path, RulesetID, SpecialStyle, StackLeniency, StarDifficulty, StoredBookmarks, TimelineZoom, Version, WidescreenStoryboard FROM BeatmapInfo_Old"); + Database.ExecuteSqlCommand("DROP TABLE BeatmapInfo_Old"); + } + catch + { + } + } + } } } diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 22eb75fcea..be12f3ddbc 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -4,7 +4,6 @@ using System; using System.Diagnostics; using System.Reflection; -using Microsoft.EntityFrameworkCore; using osu.Framework.Allocation; using osu.Framework.Configuration; using osu.Framework.Development; @@ -92,7 +91,7 @@ namespace osu.Game dependencies.Cache(LocalConfig); using (var context = contextFactory.GetContext()) - context.Database.Migrate(); + context.Migrate(); dependencies.Cache(API = new APIAccess { From a724a20b020732e32bd9df7ffc471716c26d5a44 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 19 Oct 2017 20:07:25 +0900 Subject: [PATCH 0360/1263] Remove duplicate reference to opentk package --- osu.Desktop/packages.config | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Desktop/packages.config b/osu.Desktop/packages.config index 0ec2cc196d..58f9102aa1 100644 --- a/osu.Desktop/packages.config +++ b/osu.Desktop/packages.config @@ -7,7 +7,6 @@ Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/maste - From 365e2343a1af18031795136e20041692bcfa06cc Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 19 Oct 2017 21:09:29 +0900 Subject: [PATCH 0361/1263] Remove AllRuleset references --- osu.Desktop/osu.Desktop.csproj | 3 --- 1 file changed, 3 deletions(-) diff --git a/osu.Desktop/osu.Desktop.csproj b/osu.Desktop/osu.Desktop.csproj index 7b2ec3b24c..fb1ca7eb10 100644 --- a/osu.Desktop/osu.Desktop.csproj +++ b/osu.Desktop/osu.Desktop.csproj @@ -57,7 +57,6 @@ false AnyCPU true - AllRules.ruleset false false false @@ -76,7 +75,6 @@ false AnyCPU true - AllRules.ruleset false false @@ -102,7 +100,6 @@ false 6 prompt - AllRules.ruleset --tests From 1672e0d6b660c7379d4da163f3b92c3e7a70933b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 19 Oct 2017 21:11:43 +0900 Subject: [PATCH 0362/1263] Add fallback logic in case migration fails Nuke it all. --- osu.Game/Database/OsuDbContext.cs | 74 ++++++++++++++++++------------- 1 file changed, 42 insertions(+), 32 deletions(-) diff --git a/osu.Game/Database/OsuDbContext.cs b/osu.Game/Database/OsuDbContext.cs index 3f51ac1910..0ebea94683 100644 --- a/osu.Game/Database/OsuDbContext.cs +++ b/osu.Game/Database/OsuDbContext.cs @@ -177,48 +177,58 @@ namespace osu.Game.Database // will fail (intentionally) if we don't have sqlite-net data present. Database.ExecuteSqlCommand("SELECT OnlineBeatmapSetId FROM BeatmapMetadata LIMIT 1"); - // we are good to perform messy migration of data!. - Database.ExecuteSqlCommand("ALTER TABLE BeatmapDifficulty RENAME TO BeatmapDifficulty_Old"); - Database.ExecuteSqlCommand("ALTER TABLE BeatmapMetadata RENAME TO BeatmapMetadata_Old"); - Database.ExecuteSqlCommand("ALTER TABLE FileInfo RENAME TO FileInfo_Old"); - Database.ExecuteSqlCommand("ALTER TABLE KeyBinding RENAME TO KeyBinding_Old"); - Database.ExecuteSqlCommand("ALTER TABLE BeatmapSetInfo RENAME TO BeatmapSetInfo_Old"); - Database.ExecuteSqlCommand("ALTER TABLE BeatmapInfo RENAME TO BeatmapInfo_Old"); - Database.ExecuteSqlCommand("ALTER TABLE BeatmapSetFileInfo RENAME TO BeatmapSetFileInfo_Old"); - Database.ExecuteSqlCommand("ALTER TABLE RulesetInfo RENAME TO RulesetInfo_Old"); + try + { + // we are good to perform messy migration of data!. + Database.ExecuteSqlCommand("ALTER TABLE BeatmapDifficulty RENAME TO BeatmapDifficulty_Old"); + Database.ExecuteSqlCommand("ALTER TABLE BeatmapMetadata RENAME TO BeatmapMetadata_Old"); + Database.ExecuteSqlCommand("ALTER TABLE FileInfo RENAME TO FileInfo_Old"); + Database.ExecuteSqlCommand("ALTER TABLE KeyBinding RENAME TO KeyBinding_Old"); + Database.ExecuteSqlCommand("ALTER TABLE BeatmapSetInfo RENAME TO BeatmapSetInfo_Old"); + Database.ExecuteSqlCommand("ALTER TABLE BeatmapInfo RENAME TO BeatmapInfo_Old"); + Database.ExecuteSqlCommand("ALTER TABLE BeatmapSetFileInfo RENAME TO BeatmapSetFileInfo_Old"); + Database.ExecuteSqlCommand("ALTER TABLE RulesetInfo RENAME TO RulesetInfo_Old"); - Database.ExecuteSqlCommand("DROP TABLE StoreVersion"); + Database.ExecuteSqlCommand("DROP TABLE StoreVersion"); - // perform EF migrations to create sane table structure. - Database.Migrate(); + // perform EF migrations to create sane table structure. + Database.Migrate(); - // copy data table by table to new structure, dropping old tables as we go. - Database.ExecuteSqlCommand("INSERT INTO FileInfo SELECT * FROM FileInfo_Old"); - Database.ExecuteSqlCommand("DROP TABLE FileInfo_Old"); + // copy data table by table to new structure, dropping old tables as we go. + Database.ExecuteSqlCommand("INSERT INTO FileInfo SELECT * FROM FileInfo_Old"); + Database.ExecuteSqlCommand("DROP TABLE FileInfo_Old"); - Database.ExecuteSqlCommand("INSERT INTO KeyBinding SELECT ID, [Action], Keys, RulesetID, Variant FROM KeyBinding_Old"); - Database.ExecuteSqlCommand("DROP TABLE KeyBinding_Old"); + Database.ExecuteSqlCommand("INSERT INTO KeyBinding SELECT ID, [Action], Keys, RulesetID, Variant FROM KeyBinding_Old"); + Database.ExecuteSqlCommand("DROP TABLE KeyBinding_Old"); - Database.ExecuteSqlCommand( - "INSERT INTO BeatmapMetadata SELECT ID, Artist, ArtistUnicode, AudioFile, Author, BackgroundFile, PreviewTime, Source, Tags, Title, TitleUnicode FROM BeatmapMetadata_Old"); - Database.ExecuteSqlCommand("DROP TABLE BeatmapMetadata_Old"); + Database.ExecuteSqlCommand( + "INSERT INTO BeatmapMetadata SELECT ID, Artist, ArtistUnicode, AudioFile, Author, BackgroundFile, PreviewTime, Source, Tags, Title, TitleUnicode FROM BeatmapMetadata_Old"); + Database.ExecuteSqlCommand("DROP TABLE BeatmapMetadata_Old"); - Database.ExecuteSqlCommand( - "INSERT INTO BeatmapDifficulty SELECT `ID`, `ApproachRate`, `CircleSize`, `DrainRate`, `OverallDifficulty`, `SliderMultiplier`, `SliderTickRate` FROM BeatmapDifficulty_Old"); - Database.ExecuteSqlCommand("DROP TABLE BeatmapDifficulty_Old"); + Database.ExecuteSqlCommand( + "INSERT INTO BeatmapDifficulty SELECT `ID`, `ApproachRate`, `CircleSize`, `DrainRate`, `OverallDifficulty`, `SliderMultiplier`, `SliderTickRate` FROM BeatmapDifficulty_Old"); + Database.ExecuteSqlCommand("DROP TABLE BeatmapDifficulty_Old"); - Database.ExecuteSqlCommand("INSERT INTO BeatmapSetInfo SELECT ID, DeletePending, Hash, BeatmapMetadataID, OnlineBeatmapSetID, Protected FROM BeatmapSetInfo_Old"); - Database.ExecuteSqlCommand("DROP TABLE BeatmapSetInfo_Old"); + Database.ExecuteSqlCommand("INSERT INTO BeatmapSetInfo SELECT ID, DeletePending, Hash, BeatmapMetadataID, OnlineBeatmapSetID, Protected FROM BeatmapSetInfo_Old"); + Database.ExecuteSqlCommand("DROP TABLE BeatmapSetInfo_Old"); - Database.ExecuteSqlCommand("INSERT INTO BeatmapSetFileInfo SELECT ID, BeatmapSetInfoID, FileInfoID, Filename FROM BeatmapSetFileInfo_Old"); - Database.ExecuteSqlCommand("DROP TABLE BeatmapSetFileInfo_Old"); + Database.ExecuteSqlCommand("INSERT INTO BeatmapSetFileInfo SELECT ID, BeatmapSetInfoID, FileInfoID, Filename FROM BeatmapSetFileInfo_Old"); + Database.ExecuteSqlCommand("DROP TABLE BeatmapSetFileInfo_Old"); - Database.ExecuteSqlCommand("INSERT INTO RulesetInfo SELECT ID, Available, InstantiationInfo, Name FROM RulesetInfo_Old"); - Database.ExecuteSqlCommand("DROP TABLE RulesetInfo_Old"); + Database.ExecuteSqlCommand("INSERT INTO RulesetInfo SELECT ID, Available, InstantiationInfo, Name FROM RulesetInfo_Old"); + Database.ExecuteSqlCommand("DROP TABLE RulesetInfo_Old"); - Database.ExecuteSqlCommand( - "INSERT INTO BeatmapInfo SELECT ID, AudioLeadIn, BaseDifficultyID, BeatDivisor, BeatmapSetInfoID, Countdown, DistanceSpacing, GridSize, Hash, Hidden, LetterboxInBreaks, MD5Hash, NULLIF(BeatmapMetadataID, 0), OnlineBeatmapID, Path, RulesetID, SpecialStyle, StackLeniency, StarDifficulty, StoredBookmarks, TimelineZoom, Version, WidescreenStoryboard FROM BeatmapInfo_Old"); - Database.ExecuteSqlCommand("DROP TABLE BeatmapInfo_Old"); + Database.ExecuteSqlCommand( + "INSERT INTO BeatmapInfo SELECT ID, AudioLeadIn, BaseDifficultyID, BeatDivisor, BeatmapSetInfoID, Countdown, DistanceSpacing, GridSize, Hash, Hidden, LetterboxInBreaks, MD5Hash, NULLIF(BeatmapMetadataID, 0), OnlineBeatmapID, Path, RulesetID, SpecialStyle, StackLeniency, StarDifficulty, StoredBookmarks, TimelineZoom, Version, WidescreenStoryboard FROM BeatmapInfo_Old"); + Database.ExecuteSqlCommand("DROP TABLE BeatmapInfo_Old"); + + throw new Exception(); + } + catch + { + // if anything went wrong during migration just nuke the database. + Database.EnsureDeleted(); + } } catch { From 8aea6068ba4d2a3f0f923070b983ee7ebf0c9941 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 19 Oct 2017 21:37:09 +0900 Subject: [PATCH 0363/1263] Add fallback logic for the case where previous database can't be migrated --- osu.Game/Database/OsuDbContext.cs | 12 +++++++++--- osu.Game/OsuGameBase.cs | 19 +++++++++++++------ 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/osu.Game/Database/OsuDbContext.cs b/osu.Game/Database/OsuDbContext.cs index 0ebea94683..93d23cc1bc 100644 --- a/osu.Game/Database/OsuDbContext.cs +++ b/osu.Game/Database/OsuDbContext.cs @@ -221,19 +221,25 @@ namespace osu.Game.Database Database.ExecuteSqlCommand( "INSERT INTO BeatmapInfo SELECT ID, AudioLeadIn, BaseDifficultyID, BeatDivisor, BeatmapSetInfoID, Countdown, DistanceSpacing, GridSize, Hash, Hidden, LetterboxInBreaks, MD5Hash, NULLIF(BeatmapMetadataID, 0), OnlineBeatmapID, Path, RulesetID, SpecialStyle, StackLeniency, StarDifficulty, StoredBookmarks, TimelineZoom, Version, WidescreenStoryboard FROM BeatmapInfo_Old"); Database.ExecuteSqlCommand("DROP TABLE BeatmapInfo_Old"); - - throw new Exception(); } catch { // if anything went wrong during migration just nuke the database. - Database.EnsureDeleted(); + throw new MigrationFailedException(); } } + catch (MigrationFailedException e) + { + throw; + } catch { } } } } + + public class MigrationFailedException : Exception + { + } } diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index be12f3ddbc..e7ad77d099 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -90,8 +90,18 @@ namespace osu.Game dependencies.Cache(this); dependencies.Cache(LocalConfig); - using (var context = contextFactory.GetContext()) - context.Migrate(); + try + { + using (var context = contextFactory.GetContext()) + context.Migrate(); + } + catch (MigrationFailedException) + { + using (var context = contextFactory.GetContext()) + context.Database.EnsureDeleted(); + using (var context = contextFactory.GetContext()) + context.Migrate(); + } dependencies.Cache(API = new APIAccess { @@ -203,10 +213,7 @@ namespace osu.Game // TODO: This is temporary until we reimplement the local FPS display. // It's just to allow end-users to access the framework FPS display without knowing the shortcut key. fpsDisplayVisible = LocalConfig.GetBindable(OsuSetting.ShowFpsDisplay); - fpsDisplayVisible.ValueChanged += val => - { - FrameStatisticsMode = val ? FrameStatisticsMode.Minimal : FrameStatisticsMode.None; - }; + fpsDisplayVisible.ValueChanged += val => { FrameStatisticsMode = val ? FrameStatisticsMode.Minimal : FrameStatisticsMode.None; }; fpsDisplayVisible.TriggerChange(); } From d9fd05a5afe96a1b70b833a555bd10c06509407a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 19 Oct 2017 23:19:30 +0900 Subject: [PATCH 0364/1263] Hidden cannot be null --- osu.Game/Database/OsuDbContext.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Database/OsuDbContext.cs b/osu.Game/Database/OsuDbContext.cs index 93d23cc1bc..4e663159ff 100644 --- a/osu.Game/Database/OsuDbContext.cs +++ b/osu.Game/Database/OsuDbContext.cs @@ -219,7 +219,7 @@ namespace osu.Game.Database Database.ExecuteSqlCommand("DROP TABLE RulesetInfo_Old"); Database.ExecuteSqlCommand( - "INSERT INTO BeatmapInfo SELECT ID, AudioLeadIn, BaseDifficultyID, BeatDivisor, BeatmapSetInfoID, Countdown, DistanceSpacing, GridSize, Hash, Hidden, LetterboxInBreaks, MD5Hash, NULLIF(BeatmapMetadataID, 0), OnlineBeatmapID, Path, RulesetID, SpecialStyle, StackLeniency, StarDifficulty, StoredBookmarks, TimelineZoom, Version, WidescreenStoryboard FROM BeatmapInfo_Old"); + "INSERT INTO BeatmapInfo SELECT ID, AudioLeadIn, BaseDifficultyID, BeatDivisor, BeatmapSetInfoID, Countdown, DistanceSpacing, GridSize, Hash, IFNULL(Hidden, 0), LetterboxInBreaks, MD5Hash, NULLIF(BeatmapMetadataID, 0), OnlineBeatmapID, Path, RulesetID, SpecialStyle, StackLeniency, StarDifficulty, StoredBookmarks, TimelineZoom, Version, WidescreenStoryboard FROM BeatmapInfo_Old"); Database.ExecuteSqlCommand("DROP TABLE BeatmapInfo_Old"); } catch From 9b1ed5b3aaca927ef41ec637a07405a47e60b115 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 19 Oct 2017 23:33:27 +0900 Subject: [PATCH 0365/1263] Keep trying until delete succeeds Turns out it can fail if file handles are still open. --- osu.Game/OsuGameBase.cs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index e7ad77d099..4a80a0fa06 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -97,8 +97,18 @@ namespace osu.Game } catch (MigrationFailedException) { - using (var context = contextFactory.GetContext()) - context.Database.EnsureDeleted(); + while (true) + { + try + { + using (var context = contextFactory.GetContext()) + { + context.Database.EnsureDeleted(); + break; + } + } + catch { } + } using (var context = contextFactory.GetContext()) context.Migrate(); } From efaf98c5cf235d4c439e8ab147f1640b48533963 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 20 Oct 2017 00:48:27 +0900 Subject: [PATCH 0366/1263] Allow recovery from a very broken database --- osu.Game/Database/OsuDbContext.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/osu.Game/Database/OsuDbContext.cs b/osu.Game/Database/OsuDbContext.cs index 4e663159ff..1e3d76789d 100644 --- a/osu.Game/Database/OsuDbContext.cs +++ b/osu.Game/Database/OsuDbContext.cs @@ -160,7 +160,14 @@ namespace osu.Game.Database public void Migrate() { migrateFromSqliteNet(); - Database.Migrate(); + try + { + Database.Migrate(); + } + catch + { + throw new MigrationFailedException(); + } } private void migrateFromSqliteNet() From 0e1328a30eb0ef949abec7f90a8422073607d36b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 20 Oct 2017 08:01:38 +0900 Subject: [PATCH 0367/1263] Add maximum try count before bailing --- osu.Game/OsuGameBase.cs | 55 ++++++++++++++++++++++++----------------- 1 file changed, 33 insertions(+), 22 deletions(-) diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 4a80a0fa06..de9ed70ac9 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -90,28 +90,7 @@ namespace osu.Game dependencies.Cache(this); dependencies.Cache(LocalConfig); - try - { - using (var context = contextFactory.GetContext()) - context.Migrate(); - } - catch (MigrationFailedException) - { - while (true) - { - try - { - using (var context = contextFactory.GetContext()) - { - context.Database.EnsureDeleted(); - break; - } - } - catch { } - } - using (var context = contextFactory.GetContext()) - context.Migrate(); - } + runMigrations(); dependencies.Cache(API = new APIAccess { @@ -183,6 +162,38 @@ namespace osu.Game FileStore.Cleanup(); } + private void runMigrations() + { + try + { + using (var context = contextFactory.GetContext()) + context.Migrate(); + } + catch (MigrationFailedException) + { + // 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. + int retries = 20; + while (retries-- > 0) + { + try + { + using (var context = contextFactory.GetContext()) + { + context.Database.EnsureDeleted(); + break; + } + } + catch + { + } + } + + using (var context = contextFactory.GetContext()) + context.Migrate(); + } + } + private WorkingBeatmap lastBeatmap; public void APIStateChanged(APIAccess api, APIState state) From ca780784361ccc695c05a8c53ab505f043cdc51d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 20 Oct 2017 08:01:45 +0900 Subject: [PATCH 0368/1263] Add more logging output --- osu.Game/Database/OsuDbContext.cs | 18 +++++++++++++----- osu.Game/OsuGameBase.cs | 7 ++++++- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/osu.Game/Database/OsuDbContext.cs b/osu.Game/Database/OsuDbContext.cs index 1e3d76789d..bfa3c0a81b 100644 --- a/osu.Game/Database/OsuDbContext.cs +++ b/osu.Game/Database/OsuDbContext.cs @@ -160,13 +160,14 @@ namespace osu.Game.Database public void Migrate() { migrateFromSqliteNet(); + try { Database.Migrate(); } - catch + catch (Exception e) { - throw new MigrationFailedException(); + throw new MigrationFailedException(e); } } @@ -186,6 +187,8 @@ namespace osu.Game.Database try { + Logger.Log("Performing migration from sqlite-net to EF...", LoggingTarget.Database, Framework.Logging.LogLevel.Important); + // we are good to perform messy migration of data!. Database.ExecuteSqlCommand("ALTER TABLE BeatmapDifficulty RENAME TO BeatmapDifficulty_Old"); Database.ExecuteSqlCommand("ALTER TABLE BeatmapMetadata RENAME TO BeatmapMetadata_Old"); @@ -228,11 +231,12 @@ namespace osu.Game.Database Database.ExecuteSqlCommand( "INSERT INTO BeatmapInfo SELECT ID, AudioLeadIn, BaseDifficultyID, BeatDivisor, BeatmapSetInfoID, Countdown, DistanceSpacing, GridSize, Hash, IFNULL(Hidden, 0), LetterboxInBreaks, MD5Hash, NULLIF(BeatmapMetadataID, 0), OnlineBeatmapID, Path, RulesetID, SpecialStyle, StackLeniency, StarDifficulty, StoredBookmarks, TimelineZoom, Version, WidescreenStoryboard FROM BeatmapInfo_Old"); Database.ExecuteSqlCommand("DROP TABLE BeatmapInfo_Old"); + + Logger.Log("Migration complete!", LoggingTarget.Database, Framework.Logging.LogLevel.Important); } - catch + catch (Exception e) { - // if anything went wrong during migration just nuke the database. - throw new MigrationFailedException(); + throw new MigrationFailedException(e); } } catch (MigrationFailedException e) @@ -248,5 +252,9 @@ namespace osu.Game.Database public class MigrationFailedException : Exception { + public MigrationFailedException(Exception exception) + : base("sqlite-net migration failed", exception) + { + } } } diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index de9ed70ac9..0d575c52d0 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -17,6 +17,7 @@ using osu.Game.Graphics; using osu.Game.Graphics.Cursor; using osu.Game.Online.API; using osu.Framework.Graphics.Performance; +using osu.Framework.Logging; using osu.Game.Database; using osu.Game.Input; using osu.Game.Input.Bindings; @@ -169,8 +170,11 @@ namespace osu.Game using (var context = contextFactory.GetContext()) context.Migrate(); } - catch (MigrationFailedException) + catch (MigrationFailedException e) { + Logger.Log(e.ToString(), LoggingTarget.Database, LogLevel.Error); + Logger.Log("Migration failed! We'll be starting with a fresh database.", LoggingTarget.Database, LogLevel.Error); + // 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. int retries = 20; @@ -181,6 +185,7 @@ namespace osu.Game using (var context = contextFactory.GetContext()) { context.Database.EnsureDeleted(); + Logger.Log("Database purged successfully.", LoggingTarget.Database, LogLevel.Important); break; } } From d32059a7bac9da500ab120408e5ca1875302e8bd Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 20 Oct 2017 09:25:54 +0900 Subject: [PATCH 0369/1263] Ignore include-ignore warnings for now --- osu.Game/Database/OsuDbContext.cs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/osu.Game/Database/OsuDbContext.cs b/osu.Game/Database/OsuDbContext.cs index bfa3c0a81b..20d36f3ebe 100644 --- a/osu.Game/Database/OsuDbContext.cs +++ b/osu.Game/Database/OsuDbContext.cs @@ -3,6 +3,7 @@ using System; using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Diagnostics; using Microsoft.Extensions.Logging; using osu.Framework.Logging; using osu.Game.Beatmaps; @@ -63,8 +64,12 @@ namespace osu.Game.Database protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { base.OnConfiguring(optionsBuilder); - optionsBuilder.UseSqlite(connectionString); - optionsBuilder.UseLoggerFactory(logger.Value); + optionsBuilder + // this is required for the time being due to the way we are querying in places like BeatmapStore. + // if we ever move to having consumers file their own .Includes, or get eager loading support, this could be re-enabled. + .ConfigureWarnings(warnings => warnings.Ignore(CoreEventId.IncludeIgnoredWarning)) + .UseSqlite(connectionString) + .UseLoggerFactory(logger.Value); } protected override void OnModelCreating(ModelBuilder modelBuilder) From 7f83cf6780b5fb84e0da6ea6690894438d89d4d9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 20 Oct 2017 10:05:54 +0900 Subject: [PATCH 0370/1263] Fix hiding not always working Because we are not sharing a single context, we need to use Update to attach the entity to the local context. --- osu.Game/Beatmaps/BeatmapStore.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Beatmaps/BeatmapStore.cs b/osu.Game/Beatmaps/BeatmapStore.cs index 8eac35a667..ad4c657619 100644 --- a/osu.Game/Beatmaps/BeatmapStore.cs +++ b/osu.Game/Beatmaps/BeatmapStore.cs @@ -102,6 +102,7 @@ namespace osu.Game.Beatmaps if (beatmap.Hidden) return false; beatmap.Hidden = true; + context.Update(beatmap); context.SaveChanges(); BeatmapHidden?.Invoke(beatmap); @@ -120,6 +121,7 @@ namespace osu.Game.Beatmaps if (!beatmap.Hidden) return false; beatmap.Hidden = false; + context.Update(beatmap); context.SaveChanges(); BeatmapRestored?.Invoke(beatmap); From f69fa0cf1f9ef4a70f8525be5ec05103262df683 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 20 Oct 2017 10:50:00 +0900 Subject: [PATCH 0371/1263] Fix selection after hiding all difficulties in a set --- osu.Game/Screens/Select/BeatmapCarousel.cs | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index b8cc9782ca..582eeebd48 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -52,7 +52,7 @@ namespace osu.Game.Screens.Select Schedule(() => { foreach (var g in newGroups) - addGroup(g); + if (g != null) addGroup(g); computeYPositions(); BeatmapsChanged?.Invoke(); @@ -101,6 +101,9 @@ namespace osu.Game.Screens.Select { var group = createGroup(beatmapSet); + if (group == null) + return; + addGroup(group); computeYPositions(); if (selectedGroup == null) @@ -124,19 +127,23 @@ namespace osu.Game.Screens.Select if (group == null) return; - var newGroup = createGroup(set); - int i = groups.IndexOf(group); groups.RemoveAt(i); - groups.Insert(i, newGroup); - if (selectedGroup == group && newGroup.BeatmapPanels.Count == 0) + var newGroup = createGroup(set); + + if (newGroup != null) + groups.Insert(i, newGroup); + + bool hadSelection = selectedGroup == group; + + if (hadSelection && newGroup == null) selectedGroup = null; Filter(null, false); //check if we can/need to maintain our current selection. - if (selectedGroup == group && newGroup.BeatmapPanels.Count > 0) + if (hadSelection && newGroup != null) { var newSelection = newGroup.BeatmapPanels.Find(p => p.Beatmap.ID == selectedPanel?.Beatmap.ID) ?? @@ -335,6 +342,9 @@ namespace osu.Game.Screens.Select private BeatmapGroup createGroup(BeatmapSetInfo beatmapSet) { + if (beatmapSet.Beatmaps.All(b => b.Hidden)) + return null; + foreach (var b in beatmapSet.Beatmaps) { if (b.Metadata == null) From 93b2fc6dc51ff9ed665e0a4a2ad09a9421b47e0d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 20 Oct 2017 11:14:45 +0900 Subject: [PATCH 0372/1263] Fix issues with deletion Main fix is avoiding nullrefs being thrown when metadata isn't present on a beatmap (quite a common scenario). --- osu.Game/Beatmaps/BeatmapStore.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game/Beatmaps/BeatmapStore.cs b/osu.Game/Beatmaps/BeatmapStore.cs index 8eac35a667..6451862824 100644 --- a/osu.Game/Beatmaps/BeatmapStore.cs +++ b/osu.Game/Beatmaps/BeatmapStore.cs @@ -66,6 +66,7 @@ namespace osu.Game.Beatmaps if (beatmapSet.DeletePending) return false; beatmapSet.DeletePending = true; + context.Update(beatmapSet); context.SaveChanges(); BeatmapSetRemoved?.Invoke(beatmapSet); @@ -84,6 +85,7 @@ namespace osu.Game.Beatmaps if (!beatmapSet.DeletePending) return false; beatmapSet.DeletePending = false; + context.Update(beatmapSet); context.SaveChanges(); BeatmapSetAdded?.Invoke(beatmapSet); @@ -137,7 +139,7 @@ namespace osu.Game.Beatmaps // metadata is M-N so we can't rely on cascades context.BeatmapMetadata.RemoveRange(purgeable.Select(s => s.Metadata)); - context.BeatmapMetadata.RemoveRange(purgeable.SelectMany(s => s.Beatmaps.Select(b => b.Metadata))); + context.BeatmapMetadata.RemoveRange(purgeable.SelectMany(s => s.Beatmaps.Select(b => b.Metadata).Where(m => m != null))); // todo: we can probably make cascades work here with a FK in BeatmapDifficulty. just make to make it work correctly. context.BeatmapDifficulty.RemoveRange(purgeable.SelectMany(s => s.Beatmaps.Select(b => b.BaseDifficulty))); From f9d5eadd05857d5c5587d93a6924fb219d23803c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 20 Oct 2017 12:21:18 +0900 Subject: [PATCH 0373/1263] Fix TestCase failing in an infinite loop --- osu.Game/Tests/Visual/TestCaseNotificationOverlay.cs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/osu.Game/Tests/Visual/TestCaseNotificationOverlay.cs b/osu.Game/Tests/Visual/TestCaseNotificationOverlay.cs index fead5c8b24..ed331076b2 100644 --- a/osu.Game/Tests/Visual/TestCaseNotificationOverlay.cs +++ b/osu.Game/Tests/Visual/TestCaseNotificationOverlay.cs @@ -66,13 +66,11 @@ namespace osu.Game.Tests.Visual progressingNotifications.RemoveAll(n => n.State == ProgressNotificationState.Completed); - while (progressingNotifications.Count(n => n.State == ProgressNotificationState.Active) < 3) + if (progressingNotifications.Count(n => n.State == ProgressNotificationState.Active) < 3) { var p = progressingNotifications.FirstOrDefault(n => n.IsAlive && n.State == ProgressNotificationState.Queued); - if (p == null) - break; - - p.State = ProgressNotificationState.Active; + if (p != null) + p.State = ProgressNotificationState.Active; } foreach (var n in progressingNotifications.FindAll(n => n.State == ProgressNotificationState.Active)) From b805174143f8313d247fd2f4d28d9f75f6c1b536 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 20 Oct 2017 14:33:35 +0900 Subject: [PATCH 0374/1263] Output the inner exception to the log when possible --- osu.Game/OsuGameBase.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 0d575c52d0..520627ad4a 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -172,7 +172,7 @@ namespace osu.Game } catch (MigrationFailedException e) { - Logger.Log(e.ToString(), LoggingTarget.Database, LogLevel.Error); + 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); // if we failed, let's delete the database and start fresh. From 47213d2498e81440f6e2d24bd15d6c37933a4eee Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 21 Oct 2017 00:15:02 +0900 Subject: [PATCH 0375/1263] Rely on storage.DeleteDatabase for guaranteed database deletion Relies on https://github.com/ppy/osu-framework/pull/1100 being merged for most effectiveness. --- osu.Game/Database/DatabaseContextFactory.cs | 10 +++++++++- osu.Game/OsuGameBase.cs | 18 ++---------------- 2 files changed, 11 insertions(+), 17 deletions(-) diff --git a/osu.Game/Database/DatabaseContextFactory.cs b/osu.Game/Database/DatabaseContextFactory.cs index 359188b4e2..6154016083 100644 --- a/osu.Game/Database/DatabaseContextFactory.cs +++ b/osu.Game/Database/DatabaseContextFactory.cs @@ -9,11 +9,19 @@ namespace osu.Game.Database { private readonly GameHost host; + private const string database_name = @"client"; + public DatabaseContextFactory(GameHost host) { this.host = host; } - public OsuDbContext GetContext() => new OsuDbContext(host.Storage.GetDatabaseConnectionString(@"client")); + public OsuDbContext GetContext() => new OsuDbContext(host.Storage.GetDatabaseConnectionString(database_name)); + + public void ResetDatabase() + { + // todo: we probably want to make sure there are no active contexts before performing this operation. + host.Storage.DeleteDatabase(database_name); + } } } diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 520627ad4a..50639e3427 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -177,22 +177,8 @@ namespace osu.Game // 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. - int retries = 20; - while (retries-- > 0) - { - try - { - using (var context = contextFactory.GetContext()) - { - context.Database.EnsureDeleted(); - Logger.Log("Database purged successfully.", LoggingTarget.Database, LogLevel.Important); - break; - } - } - catch - { - } - } + contextFactory.ResetDatabase(); + Logger.Log("Database purged successfully.", LoggingTarget.Database, LogLevel.Important); using (var context = contextFactory.GetContext()) context.Migrate(); From 2c7343e9659b73c37d4d7e4f77c9275fb04722b0 Mon Sep 17 00:00:00 2001 From: Shane Woolcock Date: Sat, 21 Oct 2017 12:42:11 +1030 Subject: [PATCH 0376/1263] Add revert-to-default glow for settings items --- osu.Game/Overlays/Settings/SettingsItem.cs | 89 ++++++++++++++++++- osu.Game/Overlays/Settings/SettingsSection.cs | 5 +- .../Overlays/Settings/SettingsSubsection.cs | 2 +- 3 files changed, 89 insertions(+), 7 deletions(-) diff --git a/osu.Game/Overlays/Settings/SettingsItem.cs b/osu.Game/Overlays/Settings/SettingsItem.cs index f2044f178b..c98b2f1ee9 100644 --- a/osu.Game/Overlays/Settings/SettingsItem.cs +++ b/osu.Game/Overlays/Settings/SettingsItem.cs @@ -2,17 +2,23 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System.Collections.Generic; +using osu.Framework.Allocation; using OpenTK.Graphics; using osu.Framework.Configuration; +using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; +using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.UserInterface; +using osu.Framework.Input; +using osu.Game.Graphics; using osu.Game.Graphics.Sprites; namespace osu.Game.Overlays.Settings { - public abstract class SettingsItem : FillFlowContainer, IFilterable + public abstract class SettingsItem : Container, IFilterable { protected abstract Drawable CreateControl(); @@ -20,8 +26,16 @@ namespace osu.Game.Overlays.Settings private IHasCurrentValue controlWithCurrent => Control as IHasCurrentValue; + protected override Container Content => FlowContent; + + protected readonly FillFlowContainer FlowContent; + private SpriteText text; + private readonly SettingsItemDefaultIndicator defaultIndicator = new SettingsItemDefaultIndicator(); + + public bool ShowsDefaultIndicator = true; + public virtual string LabelText { get { return text?.Text ?? string.Empty; } @@ -51,6 +65,11 @@ namespace osu.Game.Overlays.Settings { bindable = value; controlWithCurrent?.Current.BindTo(bindable); + if (ShowsDefaultIndicator) + { + defaultIndicator.Bindable.BindTo(bindable); + defaultIndicator.Bindable.TriggerChange(); + } } } @@ -69,14 +88,78 @@ namespace osu.Game.Overlays.Settings { RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; - Padding = new MarginPadding { Right = 5 }; + Padding = new MarginPadding { Right = SettingsOverlay.CONTENT_MARGINS }; + + FlowContent = new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Padding = new MarginPadding { Left = SettingsOverlay.CONTENT_MARGINS, Right = 5 }, + }; if ((Control = CreateControl()) != null) { if (controlWithCurrent != null) controlWithCurrent.Current.DisabledChanged += disabled => { Colour = disabled ? Color4.Gray : Color4.White; }; - Add(Control); + FlowContent.Add(Control); } } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + AddInternal(FlowContent); + + if (defaultIndicator != null) + { + defaultIndicator.Colour = ColourInfo.GradientHorizontal(colours.Yellow.Opacity(0.8f), colours.Yellow.Opacity(0)); + defaultIndicator.Alpha = 0f; + AddInternal(defaultIndicator); + } + } + + private class SettingsItemDefaultIndicator : Box + { + internal readonly Bindable Bindable = new Bindable(); + + private bool hovering; + + public SettingsItemDefaultIndicator() + { + Bindable.ValueChanged += value => updateAlpha(); + + RelativeSizeAxes = Axes.Y; + Width = SettingsOverlay.CONTENT_MARGINS; + Alpha = 0f; + } + + public override bool HandleInput => true; + + protected override bool OnMouseDown(InputState state, MouseDownEventArgs args) => true; + + protected override bool OnMouseUp(InputState state, MouseUpEventArgs args) => true; + + protected override bool OnClick(InputState state) + { + Bindable.SetDefault(); + return true; + } + + protected override bool OnHover(InputState state) + { + hovering = true; + updateAlpha(); + return true; + } + + protected override void OnHoverLost(InputState state) + { + hovering = false; + updateAlpha(); + } + + private void updateAlpha() => + Alpha = Bindable.IsDefault ? 0f : hovering ? 1f : 0.5f; + } } } diff --git a/osu.Game/Overlays/Settings/SettingsSection.cs b/osu.Game/Overlays/Settings/SettingsSection.cs index eb6e398477..a107878fb8 100644 --- a/osu.Game/Overlays/Settings/SettingsSection.cs +++ b/osu.Game/Overlays/Settings/SettingsSection.cs @@ -69,8 +69,6 @@ namespace osu.Game.Overlays.Settings Padding = new MarginPadding { Top = 20 + border_size, - Left = SettingsOverlay.CONTENT_MARGINS, - Right = SettingsOverlay.CONTENT_MARGINS, Bottom = 10, }, RelativeSizeAxes = Axes.X, @@ -81,7 +79,8 @@ namespace osu.Game.Overlays.Settings { TextSize = header_size, Text = Header, - Colour = colours.Yellow + Colour = colours.Yellow, + Margin = new MarginPadding { Left = SettingsOverlay.CONTENT_MARGINS, Right = SettingsOverlay.CONTENT_MARGINS } }, FlowContent } diff --git a/osu.Game/Overlays/Settings/SettingsSubsection.cs b/osu.Game/Overlays/Settings/SettingsSubsection.cs index 4164ceee21..79a644b2cb 100644 --- a/osu.Game/Overlays/Settings/SettingsSubsection.cs +++ b/osu.Game/Overlays/Settings/SettingsSubsection.cs @@ -52,7 +52,7 @@ namespace osu.Game.Overlays.Settings new OsuSpriteText { Text = Header.ToUpper(), - Margin = new MarginPadding { Bottom = 10 }, + Margin = new MarginPadding { Bottom = 10, Left = SettingsOverlay.CONTENT_MARGINS, Right = SettingsOverlay.CONTENT_MARGINS }, Font = @"Exo2.0-Black", }, FlowContent From 98044a17d3de8bc29e240a10c920ce95b3766a45 Mon Sep 17 00:00:00 2001 From: Shane Woolcock Date: Sat, 21 Oct 2017 13:16:06 +1030 Subject: [PATCH 0377/1263] Fix misaligned settings buttons --- .../KeyBinding/KeyBindingsSubsection.cs | 1 + .../Settings/Sections/Audio/OffsetSettings.cs | 3 +-- .../Settings/Sections/Debug/GCSettings.cs | 3 +-- .../Settings/Sections/General/LoginSettings.cs | 6 ++---- .../Settings/Sections/General/UpdateSettings.cs | 3 +-- .../Settings/Sections/Input/KeyboardSettings.cs | 3 +-- .../Sections/Maintenance/GeneralSettings.cs | 9 +++------ osu.Game/Overlays/Settings/SettingsButton.cs | 17 +++++++++++++++++ osu.Game/osu.Game.csproj | 1 + 9 files changed, 28 insertions(+), 18 deletions(-) create mode 100644 osu.Game/Overlays/Settings/SettingsButton.cs diff --git a/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs b/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs index 128b5e2f09..2ff5d7b81f 100644 --- a/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs +++ b/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs @@ -28,6 +28,7 @@ namespace osu.Game.Overlays.KeyBinding this.variant = variant; FlowContent.Spacing = new Vector2(0, 1); + FlowContent.Padding = new MarginPadding { Left = SettingsOverlay.CONTENT_MARGINS, Right = SettingsOverlay.CONTENT_MARGINS }; } [BackgroundDependencyLoader] diff --git a/osu.Game/Overlays/Settings/Sections/Audio/OffsetSettings.cs b/osu.Game/Overlays/Settings/Sections/Audio/OffsetSettings.cs index bc09a2145a..8d3f4ee672 100644 --- a/osu.Game/Overlays/Settings/Sections/Audio/OffsetSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Audio/OffsetSettings.cs @@ -22,9 +22,8 @@ namespace osu.Game.Overlays.Settings.Sections.Audio LabelText = "Audio Offset", Bindable = config.GetBindable(OsuSetting.AudioOffset) }, - new OsuButton + new SettingsButton { - RelativeSizeAxes = Axes.X, Text = "Offset wizard" } }; diff --git a/osu.Game/Overlays/Settings/Sections/Debug/GCSettings.cs b/osu.Game/Overlays/Settings/Sections/Debug/GCSettings.cs index 495a2543d1..50768fb646 100644 --- a/osu.Game/Overlays/Settings/Sections/Debug/GCSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Debug/GCSettings.cs @@ -24,9 +24,8 @@ namespace osu.Game.Overlays.Settings.Sections.Debug LabelText = "Active mode", Bindable = config.GetBindable(DebugSetting.ActiveGCMode) }, - new OsuButton + new SettingsButton { - RelativeSizeAxes = Axes.X, Text = "Force garbage collection", Action = GC.Collect }, diff --git a/osu.Game/Overlays/Settings/Sections/General/LoginSettings.cs b/osu.Game/Overlays/Settings/Sections/General/LoginSettings.cs index 8b7d7b0d69..56b9a55398 100644 --- a/osu.Game/Overlays/Settings/Sections/General/LoginSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/General/LoginSettings.cs @@ -230,15 +230,13 @@ namespace osu.Game.Overlays.Settings.Sections.General LabelText = "Stay logged in", Bindable = config.GetBindable(OsuSetting.SavePassword), }, - new OsuButton + new SettingsButton { - RelativeSizeAxes = Axes.X, Text = "Sign in", Action = performLogin }, - new OsuButton + new SettingsButton { - RelativeSizeAxes = Axes.X, Text = "Register new account", //Action = registerLink } diff --git a/osu.Game/Overlays/Settings/Sections/General/UpdateSettings.cs b/osu.Game/Overlays/Settings/Sections/General/UpdateSettings.cs index 833a5ff966..6ccb16f538 100644 --- a/osu.Game/Overlays/Settings/Sections/General/UpdateSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/General/UpdateSettings.cs @@ -23,9 +23,8 @@ namespace osu.Game.Overlays.Settings.Sections.General LabelText = "Release stream", Bindable = config.GetBindable(OsuSetting.ReleaseStream), }, - new OsuButton + new SettingsButton { - RelativeSizeAxes = Axes.X, Text = "Open osu! folder", Action = storage.OpenInNativeExplorer, } diff --git a/osu.Game/Overlays/Settings/Sections/Input/KeyboardSettings.cs b/osu.Game/Overlays/Settings/Sections/Input/KeyboardSettings.cs index b68fd4bc04..4bc16cd0e1 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/KeyboardSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/KeyboardSettings.cs @@ -14,9 +14,8 @@ namespace osu.Game.Overlays.Settings.Sections.Input { Children = new Drawable[] { - new OsuButton + new SettingsButton { - RelativeSizeAxes = Axes.X, Text = "Key Configuration", Action = keyConfig.ToggleVisibility }, diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs index 233ca7be60..e14094cf3a 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs @@ -22,9 +22,8 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance { Children = new Drawable[] { - importButton = new OsuButton + importButton = new SettingsButton { - RelativeSizeAxes = Axes.X, Text = "Import beatmaps from stable", Action = () => { @@ -32,9 +31,8 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance Task.Run(() => beatmaps.ImportFromStable()).ContinueWith(t => Schedule(() => importButton.Enabled.Value = true)); } }, - deleteButton = new OsuButton + deleteButton = new SettingsButton { - RelativeSizeAxes = Axes.X, Text = "Delete ALL beatmaps", Action = () => { @@ -42,9 +40,8 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance Task.Run(() => beatmaps.DeleteAll()).ContinueWith(t => Schedule(() => deleteButton.Enabled.Value = true)); } }, - restoreButton = new OsuButton + restoreButton = new SettingsButton { - RelativeSizeAxes = Axes.X, Text = "Restore all hidden difficulties", Action = () => { diff --git a/osu.Game/Overlays/Settings/SettingsButton.cs b/osu.Game/Overlays/Settings/SettingsButton.cs new file mode 100644 index 0000000000..252ef30629 --- /dev/null +++ b/osu.Game/Overlays/Settings/SettingsButton.cs @@ -0,0 +1,17 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE + +using osu.Framework.Graphics; +using osu.Game.Graphics.UserInterface; + +namespace osu.Game.Overlays.Settings.Sections +{ + public class SettingsButton : OsuButton + { + public SettingsButton() + { + RelativeSizeAxes = Axes.X; + Padding = new MarginPadding { Left = SettingsOverlay.CONTENT_MARGINS, Right = SettingsOverlay.CONTENT_MARGINS }; + } + } +} diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 601c99e19f..16589c72ff 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -288,6 +288,7 @@ + From 290fac89909bd6c4accc8e2c9ca417cb3c57eaef Mon Sep 17 00:00:00 2001 From: Shane Woolcock Date: Sat, 21 Oct 2017 13:17:03 +1030 Subject: [PATCH 0378/1263] Temporarily disable revert functionality for audio device, since it crashes --- .../Overlays/Settings/Sections/Audio/AudioDevicesSettings.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Settings/Sections/Audio/AudioDevicesSettings.cs b/osu.Game/Overlays/Settings/Sections/Audio/AudioDevicesSettings.cs index a2f3ad545b..1e1dd86808 100644 --- a/osu.Game/Overlays/Settings/Sections/Audio/AudioDevicesSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Audio/AudioDevicesSettings.cs @@ -59,7 +59,7 @@ namespace osu.Game.Overlays.Settings.Sections.Audio Children = new Drawable[] { - dropdown = new SettingsDropdown() + dropdown = new SettingsDropdown { ShowsDefaultIndicator = false } }; updateItems(); From b4d575fbcd4fab7fb30ffa568d0564d2678993d2 Mon Sep 17 00:00:00 2001 From: Shane Woolcock Date: Sat, 21 Oct 2017 13:22:21 +1030 Subject: [PATCH 0379/1263] Fix namespace and unnecessary using --- osu.Game/Overlays/Settings/Sections/Debug/GCSettings.cs | 1 - osu.Game/Overlays/Settings/Sections/General/UpdateSettings.cs | 1 - osu.Game/Overlays/Settings/Sections/Input/KeyboardSettings.cs | 1 - osu.Game/Overlays/Settings/SettingsButton.cs | 2 +- 4 files changed, 1 insertion(+), 4 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/Debug/GCSettings.cs b/osu.Game/Overlays/Settings/Sections/Debug/GCSettings.cs index 50768fb646..23e7433732 100644 --- a/osu.Game/Overlays/Settings/Sections/Debug/GCSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Debug/GCSettings.cs @@ -6,7 +6,6 @@ using System.Runtime; using osu.Framework.Allocation; using osu.Framework.Configuration; using osu.Framework.Graphics; -using osu.Game.Graphics.UserInterface; namespace osu.Game.Overlays.Settings.Sections.Debug { diff --git a/osu.Game/Overlays/Settings/Sections/General/UpdateSettings.cs b/osu.Game/Overlays/Settings/Sections/General/UpdateSettings.cs index 6ccb16f538..3bca0af3af 100644 --- a/osu.Game/Overlays/Settings/Sections/General/UpdateSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/General/UpdateSettings.cs @@ -5,7 +5,6 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Platform; using osu.Game.Configuration; -using osu.Game.Graphics.UserInterface; namespace osu.Game.Overlays.Settings.Sections.General { diff --git a/osu.Game/Overlays/Settings/Sections/Input/KeyboardSettings.cs b/osu.Game/Overlays/Settings/Sections/Input/KeyboardSettings.cs index 4bc16cd0e1..00a1c093fd 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/KeyboardSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/KeyboardSettings.cs @@ -2,7 +2,6 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using osu.Framework.Graphics; -using osu.Game.Graphics.UserInterface; namespace osu.Game.Overlays.Settings.Sections.Input { diff --git a/osu.Game/Overlays/Settings/SettingsButton.cs b/osu.Game/Overlays/Settings/SettingsButton.cs index 252ef30629..6ac8aa9f46 100644 --- a/osu.Game/Overlays/Settings/SettingsButton.cs +++ b/osu.Game/Overlays/Settings/SettingsButton.cs @@ -4,7 +4,7 @@ using osu.Framework.Graphics; using osu.Game.Graphics.UserInterface; -namespace osu.Game.Overlays.Settings.Sections +namespace osu.Game.Overlays.Settings { public class SettingsButton : OsuButton { From 840ba9f48efa82f31018e2042a72f2608561cf8a Mon Sep 17 00:00:00 2001 From: Shane Woolcock Date: Sat, 21 Oct 2017 16:05:37 +1030 Subject: [PATCH 0380/1263] Allow the default indicator colour to be specified, and fix bug where disabled bindables could be reset --- osu.Game/Overlays/Settings/SettingsItem.cs | 43 ++++++++++++++++++---- 1 file changed, 35 insertions(+), 8 deletions(-) diff --git a/osu.Game/Overlays/Settings/SettingsItem.cs b/osu.Game/Overlays/Settings/SettingsItem.cs index c98b2f1ee9..01b76605e0 100644 --- a/osu.Game/Overlays/Settings/SettingsItem.cs +++ b/osu.Game/Overlays/Settings/SettingsItem.cs @@ -36,6 +36,18 @@ namespace osu.Game.Overlays.Settings public bool ShowsDefaultIndicator = true; + private Color4? defaultIndicatorColour; + + public Color4 DefaultIndicatorColour + { + get { return defaultIndicatorColour ?? Color4.White; } + set + { + defaultIndicatorColour = value; + defaultIndicator?.SetIndicatorColour(DefaultIndicatorColour); + } + } + public virtual string LabelText { get { return text?.Text ?? string.Empty; } @@ -112,8 +124,9 @@ namespace osu.Game.Overlays.Settings if (defaultIndicator != null) { - defaultIndicator.Colour = ColourInfo.GradientHorizontal(colours.Yellow.Opacity(0.8f), colours.Yellow.Opacity(0)); - defaultIndicator.Alpha = 0f; + if (!defaultIndicatorColour.HasValue) + defaultIndicatorColour = colours.Yellow; + defaultIndicator.SetIndicatorColour(DefaultIndicatorColour); AddInternal(defaultIndicator); } } @@ -122,11 +135,14 @@ namespace osu.Game.Overlays.Settings { internal readonly Bindable Bindable = new Bindable(); + private Color4 indicatorColour; + private bool hovering; public SettingsItemDefaultIndicator() { - Bindable.ValueChanged += value => updateAlpha(); + Bindable.ValueChanged += value => UpdateState(); + Bindable.DisabledChanged += disabled => UpdateState(); RelativeSizeAxes = Axes.Y; Width = SettingsOverlay.CONTENT_MARGINS; @@ -141,25 +157,36 @@ namespace osu.Game.Overlays.Settings protected override bool OnClick(InputState state) { - Bindable.SetDefault(); + if (!Bindable.Disabled) + Bindable.SetDefault(); return true; } protected override bool OnHover(InputState state) { hovering = true; - updateAlpha(); + UpdateState(); return true; } protected override void OnHoverLost(InputState state) { hovering = false; - updateAlpha(); + UpdateState(); } - private void updateAlpha() => - Alpha = Bindable.IsDefault ? 0f : hovering ? 1f : 0.5f; + internal void SetIndicatorColour(Color4 indicatorColour) + { + this.indicatorColour = indicatorColour; + UpdateState(); + } + + internal void UpdateState() + { + var colour = Bindable.Disabled ? Color4.Gray : indicatorColour; + Alpha = Bindable.IsDefault ? 0f : (hovering && !Bindable.Disabled) ? 1f : 0.5f; + Colour = ColourInfo.GradientHorizontal(colour.Opacity(0.8f), colour.Opacity(0)); + } } } } From f5946c0e07b7aa39dd7fb14e62a29c7cc77f3f71 Mon Sep 17 00:00:00 2001 From: Shane Woolcock Date: Sat, 21 Oct 2017 16:28:03 +1030 Subject: [PATCH 0381/1263] Fix wrong license header --- osu.Game/Overlays/Settings/SettingsButton.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Settings/SettingsButton.cs b/osu.Game/Overlays/Settings/SettingsButton.cs index 6ac8aa9f46..5320cef850 100644 --- a/osu.Game/Overlays/Settings/SettingsButton.cs +++ b/osu.Game/Overlays/Settings/SettingsButton.cs @@ -1,5 +1,5 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using osu.Framework.Graphics; using osu.Game.Graphics.UserInterface; From 59b10981dc24659bec8a10be7aa9131ffbd193bb Mon Sep 17 00:00:00 2001 From: Shane Woolcock Date: Sat, 21 Oct 2017 17:06:28 +1030 Subject: [PATCH 0382/1263] CI fixes --- osu.Game/Overlays/Settings/SettingsItem.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Settings/SettingsItem.cs b/osu.Game/Overlays/Settings/SettingsItem.cs index 01b76605e0..d77552bb47 100644 --- a/osu.Game/Overlays/Settings/SettingsItem.cs +++ b/osu.Game/Overlays/Settings/SettingsItem.cs @@ -184,7 +184,7 @@ namespace osu.Game.Overlays.Settings internal void UpdateState() { var colour = Bindable.Disabled ? Color4.Gray : indicatorColour; - Alpha = Bindable.IsDefault ? 0f : (hovering && !Bindable.Disabled) ? 1f : 0.5f; + Alpha = Bindable.IsDefault ? 0f : hovering && !Bindable.Disabled ? 1f : 0.5f; Colour = ColourInfo.GradientHorizontal(colour.Opacity(0.8f), colour.Opacity(0)); } } From a9657d2142d3537ed0d38f315fa11c6852b91603 Mon Sep 17 00:00:00 2001 From: Shane Woolcock Date: Sun, 22 Oct 2017 00:55:32 +1030 Subject: [PATCH 0383/1263] Change beatmap import to use OpenTK's FileDrop event --- osu.Desktop/OsuGameDesktop.cs | 22 ++++------------------ 1 file changed, 4 insertions(+), 18 deletions(-) diff --git a/osu.Desktop/OsuGameDesktop.cs b/osu.Desktop/OsuGameDesktop.cs index f4fb10a496..1e4bf3119d 100644 --- a/osu.Desktop/OsuGameDesktop.cs +++ b/osu.Desktop/OsuGameDesktop.cs @@ -7,13 +7,13 @@ using System.IO; using System.Linq; using System.Reflection; using System.Threading.Tasks; -using System.Windows.Forms; using Microsoft.Win32; using osu.Desktop.Overlays; using osu.Framework.Graphics.Containers; using osu.Framework.Platform; using osu.Game; using osu.Game.Screens.Menu; +using OpenTK.Input; namespace osu.Desktop { @@ -105,16 +105,13 @@ namespace osu.Desktop desktopWindow.Icon = new Icon(Assembly.GetExecutingAssembly().GetManifestResourceStream(GetType(), "lazer.ico")); desktopWindow.Title = Name; - desktopWindow.DragEnter += dragEnter; - desktopWindow.DragDrop += dragDrop; + desktopWindow.FileDrop += fileDrop; } } - private void dragDrop(DragEventArgs e) + private void fileDrop(object sender, FileDropEventArgs e) { - // this method will only be executed if e.Effect in dragEnter gets set to something other that None. - var dropData = (object[])e.Data.GetData(DataFormats.FileDrop); - var filePaths = dropData.Select(f => f.ToString()).ToArray(); + var filePaths = new [] { e.FileName }; if (filePaths.All(f => Path.GetExtension(f) == @".osz")) Task.Run(() => BeatmapManager.Import(filePaths)); @@ -127,16 +124,5 @@ namespace osu.Desktop } private static readonly string[] allowed_extensions = { @".osz", @".osr" }; - - private void dragEnter(DragEventArgs e) - { - // dragDrop will only be executed if e.Effect gets set to something other that None in this method. - bool isFile = e.Data.GetDataPresent(DataFormats.FileDrop); - if (isFile) - { - var paths = ((object[])e.Data.GetData(DataFormats.FileDrop)).Select(f => f.ToString()).ToArray(); - e.Effect = allowed_extensions.Any(ext => paths.All(p => p.EndsWith(ext))) ? DragDropEffects.Copy : DragDropEffects.None; - } - } } } From 4f392a867a0fe4af30fa4fdf78e3f5faedac9971 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 20 Oct 2017 16:53:51 +0900 Subject: [PATCH 0384/1263] Use a transaction for key binding population --- osu.Game/Input/KeyBindingStore.cs | 40 ++++++++++++++++--------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/osu.Game/Input/KeyBindingStore.cs b/osu.Game/Input/KeyBindingStore.cs index 54cf48bc2a..bebbb471ac 100644 --- a/osu.Game/Input/KeyBindingStore.cs +++ b/osu.Game/Input/KeyBindingStore.cs @@ -36,29 +36,31 @@ namespace osu.Game.Input private void insertDefaults(IEnumerable defaults, int? rulesetId = null, int? variant = null) { - var context = GetContext(); - - // compare counts in database vs defaults - foreach (var group in defaults.GroupBy(k => k.Action)) + using (var context = GetContext()) + using (var transaction = context.Database.BeginTransaction()) { - int count = query(context, rulesetId, variant).Count(k => (int)k.Action == (int)group.Key); - int aimCount = group.Count(); + // compare counts in database vs defaults + foreach (var group in defaults.GroupBy(k => k.Action)) + { + int count = query(context, rulesetId, variant).Count(k => (int)k.Action == (int)group.Key); + int aimCount = group.Count(); - if (aimCount <= count) - continue; + if (aimCount <= count) + continue; - foreach (var insertable in group.Skip(count).Take(aimCount - count)) - // insert any defaults which are missing. - context.DatabasedKeyBinding.Add(new DatabasedKeyBinding - { - KeyCombination = insertable.KeyCombination, - Action = insertable.Action, - RulesetID = rulesetId, - Variant = variant - }); + foreach (var insertable in group.Skip(count).Take(aimCount - count)) + // insert any defaults which are missing. + context.DatabasedKeyBinding.Add(new DatabasedKeyBinding + { + KeyCombination = insertable.KeyCombination, + Action = insertable.Action, + RulesetID = rulesetId, + Variant = variant + }); + } + + context.SaveChanges(transaction); } - - context.SaveChanges(); } /// From 1a7e23b5c1d422941a749902e42c25b837978480 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 21 Oct 2017 23:39:31 +0900 Subject: [PATCH 0385/1263] Don't query database on keypress --- .../Input/Bindings/DatabasedKeyBindingInputManager.cs | 9 +++++++-- osu.Game/Input/KeyBindingStore.cs | 7 ++++++- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/osu.Game/Input/Bindings/DatabasedKeyBindingInputManager.cs b/osu.Game/Input/Bindings/DatabasedKeyBindingInputManager.cs index 8a3c65a35e..6dedf7385b 100644 --- a/osu.Game/Input/Bindings/DatabasedKeyBindingInputManager.cs +++ b/osu.Game/Input/Bindings/DatabasedKeyBindingInputManager.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using osu.Framework.Allocation; using osu.Framework.Input.Bindings; using osu.Game.Rulesets; +using System.Linq; namespace osu.Game.Input.Bindings { @@ -44,11 +45,15 @@ namespace osu.Game.Input.Bindings private void load(KeyBindingStore keyBindings) { store = keyBindings; + store.KeyBindingChanged += ReloadMappings; } - protected override void ReloadMappings() + protected override void Dispose(bool isDisposing) { - KeyBindings = store.Query(ruleset?.ID, variant); + base.Dispose(isDisposing); + store.KeyBindingChanged -= ReloadMappings; } + + protected override void ReloadMappings() => KeyBindings = store.Query(ruleset?.ID, variant).ToList(); } } diff --git a/osu.Game/Input/KeyBindingStore.cs b/osu.Game/Input/KeyBindingStore.cs index bebbb471ac..07c0319f2f 100644 --- a/osu.Game/Input/KeyBindingStore.cs +++ b/osu.Game/Input/KeyBindingStore.cs @@ -15,6 +15,8 @@ namespace osu.Game.Input { public class KeyBindingStore : DatabaseBackedStore { + public event Action KeyBindingChanged; + public KeyBindingStore(Func getContext, RulesetStore rulesets, Storage storage = null) : base(getContext, storage) { @@ -59,7 +61,8 @@ namespace osu.Game.Input }); } - context.SaveChanges(transaction); + context.SaveChanges(); + transaction.Commit(); } } @@ -79,6 +82,8 @@ namespace osu.Game.Input var context = GetContext(); context.Update(keyBinding); context.SaveChanges(); + + KeyBindingChanged?.Invoke(); } } } From 30307de498c56632b8881914f0f8ac18183f66f2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 22 Oct 2017 11:58:40 +0900 Subject: [PATCH 0386/1263] Update framework --- osu-framework | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu-framework b/osu-framework index dbcfa5c244..383a8da7bc 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit dbcfa5c244555e7901dac7d94eab53b3b04d17e6 +Subproject commit 383a8da7bc45af498288b4b72c72a048a0996e74 From 5785af9f6a74727ceb2f01e134d6376c715341e4 Mon Sep 17 00:00:00 2001 From: Shane Woolcock Date: Sun, 22 Oct 2017 14:22:57 +1030 Subject: [PATCH 0387/1263] Reenable revert indicator on audio device since the potential crash was addressed in #1101 --- .../Overlays/Settings/Sections/Audio/AudioDevicesSettings.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Settings/Sections/Audio/AudioDevicesSettings.cs b/osu.Game/Overlays/Settings/Sections/Audio/AudioDevicesSettings.cs index 1e1dd86808..a2f3ad545b 100644 --- a/osu.Game/Overlays/Settings/Sections/Audio/AudioDevicesSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Audio/AudioDevicesSettings.cs @@ -59,7 +59,7 @@ namespace osu.Game.Overlays.Settings.Sections.Audio Children = new Drawable[] { - dropdown = new SettingsDropdown { ShowsDefaultIndicator = false } + dropdown = new SettingsDropdown() }; updateItems(); From 448ff3bf384a3116a0bde63ca8d41dfb43b2526b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 22 Oct 2017 13:28:17 +0900 Subject: [PATCH 0388/1263] Update framework --- osu-framework | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu-framework b/osu-framework index 383a8da7bc..88e7c85a9b 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit 383a8da7bc45af498288b4b72c72a048a0996e74 +Subproject commit 88e7c85a9bb20ad5806528d8682ca61baf3d5237 From 2e6a68d358aa47f32bd5da2cccade93f08645319 Mon Sep 17 00:00:00 2001 From: Shane Woolcock Date: Sun, 22 Oct 2017 16:10:41 +1030 Subject: [PATCH 0389/1263] Rename indicator class, add colour/fade easing, and add tooltip --- osu.Game/Overlays/Settings/SettingsItem.cs | 45 ++++++++++++---------- 1 file changed, 24 insertions(+), 21 deletions(-) diff --git a/osu.Game/Overlays/Settings/SettingsItem.cs b/osu.Game/Overlays/Settings/SettingsItem.cs index d77552bb47..5a0f25f7e0 100644 --- a/osu.Game/Overlays/Settings/SettingsItem.cs +++ b/osu.Game/Overlays/Settings/SettingsItem.cs @@ -9,6 +9,7 @@ using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.UserInterface; @@ -32,19 +33,19 @@ namespace osu.Game.Overlays.Settings private SpriteText text; - private readonly SettingsItemDefaultIndicator defaultIndicator = new SettingsItemDefaultIndicator(); + private readonly RestoreDefaultValueButton restoreDefaultValueButton = new RestoreDefaultValueButton(); public bool ShowsDefaultIndicator = true; - private Color4? defaultIndicatorColour; + private Color4? restoreDefaultValueColour; - public Color4 DefaultIndicatorColour + public Color4 RestoreDefaultValueColour { - get { return defaultIndicatorColour ?? Color4.White; } + get { return restoreDefaultValueColour ?? Color4.White; } set { - defaultIndicatorColour = value; - defaultIndicator?.SetIndicatorColour(DefaultIndicatorColour); + restoreDefaultValueColour = value; + restoreDefaultValueButton?.SetButtonColour(RestoreDefaultValueColour); } } @@ -79,8 +80,8 @@ namespace osu.Game.Overlays.Settings controlWithCurrent?.Current.BindTo(bindable); if (ShowsDefaultIndicator) { - defaultIndicator.Bindable.BindTo(bindable); - defaultIndicator.Bindable.TriggerChange(); + restoreDefaultValueButton.Bindable.BindTo(bindable); + restoreDefaultValueButton.Bindable.TriggerChange(); } } } @@ -122,24 +123,24 @@ namespace osu.Game.Overlays.Settings { AddInternal(FlowContent); - if (defaultIndicator != null) + if (restoreDefaultValueButton != null) { - if (!defaultIndicatorColour.HasValue) - defaultIndicatorColour = colours.Yellow; - defaultIndicator.SetIndicatorColour(DefaultIndicatorColour); - AddInternal(defaultIndicator); + if (!restoreDefaultValueColour.HasValue) + restoreDefaultValueColour = colours.Yellow; + restoreDefaultValueButton.SetButtonColour(RestoreDefaultValueColour); + AddInternal(restoreDefaultValueButton); } } - private class SettingsItemDefaultIndicator : Box + private class RestoreDefaultValueButton : Box, IHasTooltip { internal readonly Bindable Bindable = new Bindable(); - private Color4 indicatorColour; + private Color4 buttonColour; private bool hovering; - public SettingsItemDefaultIndicator() + public RestoreDefaultValueButton() { Bindable.ValueChanged += value => UpdateState(); Bindable.DisabledChanged += disabled => UpdateState(); @@ -149,6 +150,8 @@ namespace osu.Game.Overlays.Settings Alpha = 0f; } + public string TooltipText => "Revert to default"; + public override bool HandleInput => true; protected override bool OnMouseDown(InputState state, MouseDownEventArgs args) => true; @@ -175,17 +178,17 @@ namespace osu.Game.Overlays.Settings UpdateState(); } - internal void SetIndicatorColour(Color4 indicatorColour) + internal void SetButtonColour(Color4 buttonColour) { - this.indicatorColour = indicatorColour; + this.buttonColour = buttonColour; UpdateState(); } internal void UpdateState() { - var colour = Bindable.Disabled ? Color4.Gray : indicatorColour; - Alpha = Bindable.IsDefault ? 0f : hovering && !Bindable.Disabled ? 1f : 0.5f; - Colour = ColourInfo.GradientHorizontal(colour.Opacity(0.8f), colour.Opacity(0)); + var colour = Bindable.Disabled ? Color4.Gray : buttonColour; + this.FadeTo(Bindable.IsDefault ? 0f : hovering && !Bindable.Disabled ? 1f : 0.5f, 200, Easing.OutQuint); + this.FadeColour(ColourInfo.GradientHorizontal(colour.Opacity(0.8f), colour.Opacity(0)), 200, Easing.OutQuint); } } } From 6818ebdaffd09c696c904506c09e0e29e4a136a1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 22 Oct 2017 15:27:16 +0900 Subject: [PATCH 0390/1263] Change the way migrations are checked for This method allows switching between sqlite-net and EF builds without completely breaking. Note that DB migration still only happens in a forward direction, but this will allow switching back and forth without eventually being unable to start the game. --- osu.Game/Database/OsuDbContext.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/osu.Game/Database/OsuDbContext.cs b/osu.Game/Database/OsuDbContext.cs index 20d36f3ebe..d68c612bd5 100644 --- a/osu.Game/Database/OsuDbContext.cs +++ b/osu.Game/Database/OsuDbContext.cs @@ -180,13 +180,15 @@ namespace osu.Game.Database { try { - // will fail if EF hasn't touched the database yet. - Database.ExecuteSqlCommand("SELECT * FROM __EFMigrationsHistory LIMIT 1"); + // will fail if the database isn't in a sane EF-migradted state. + Database.ExecuteSqlCommand("SELECT MetadataID FROM BeatmapSetInfo LIMIT 1"); } catch { try { + Database.ExecuteSqlCommand("DROP TABLE IF EXISTS __EFMigrationsHistory"); + // will fail (intentionally) if we don't have sqlite-net data present. Database.ExecuteSqlCommand("SELECT OnlineBeatmapSetId FROM BeatmapMetadata LIMIT 1"); From 39b356880e22515bdf9b071922c6b10cf5510719 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 22 Oct 2017 15:32:47 +0900 Subject: [PATCH 0391/1263] Fix typo --- osu.Game/Database/OsuDbContext.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Database/OsuDbContext.cs b/osu.Game/Database/OsuDbContext.cs index d68c612bd5..c509093cf9 100644 --- a/osu.Game/Database/OsuDbContext.cs +++ b/osu.Game/Database/OsuDbContext.cs @@ -180,7 +180,7 @@ namespace osu.Game.Database { try { - // will fail if the database isn't in a sane EF-migradted state. + // will fail if the database isn't in a sane EF-migrated state. Database.ExecuteSqlCommand("SELECT MetadataID FROM BeatmapSetInfo LIMIT 1"); } catch From 29fcd210aa0f2168613088f6d2a44cda060822dc Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 22 Oct 2017 16:17:40 +0900 Subject: [PATCH 0392/1263] Centralise transaction committing --- osu.Game/Beatmaps/BeatmapManager.cs | 6 ++---- osu.Game/Database/OsuDbContext.cs | 7 +++++++ 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 47dbc72837..b81e239015 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -198,7 +198,7 @@ namespace osu.Game.Beatmaps context.SaveChanges(); } - transaction.Commit(); + context.SaveChanges(transaction); return set; } } @@ -313,9 +313,7 @@ namespace osu.Game.Beatmaps } context.ChangeTracker.AutoDetectChangesEnabled = true; - context.SaveChanges(); - - transaction.Commit(); + context.SaveChanges(transaction); } } } diff --git a/osu.Game/Database/OsuDbContext.cs b/osu.Game/Database/OsuDbContext.cs index c509093cf9..99e5fa9741 100644 --- a/osu.Game/Database/OsuDbContext.cs +++ b/osu.Game/Database/OsuDbContext.cs @@ -93,6 +93,13 @@ namespace osu.Game.Database modelBuilder.Entity().HasOne(b => b.BaseDifficulty); } + public new int SaveChanges(IDbContextTransaction transaction = null) + { + var ret = base.SaveChanges(); + transaction?.Commit(); + return ret; + } + private class OsuDbLoggerFactory : ILoggerFactory { #region Disposal From 9aa46bfb0dd98ed35f337bd6bcd47f605bc95412 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 22 Oct 2017 16:17:55 +0900 Subject: [PATCH 0393/1263] Add transaction usage for key binding defaults --- osu.Game/Input/KeyBindingStore.cs | 40 ++++++++++++++++--------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/osu.Game/Input/KeyBindingStore.cs b/osu.Game/Input/KeyBindingStore.cs index 54cf48bc2a..bebbb471ac 100644 --- a/osu.Game/Input/KeyBindingStore.cs +++ b/osu.Game/Input/KeyBindingStore.cs @@ -36,29 +36,31 @@ namespace osu.Game.Input private void insertDefaults(IEnumerable defaults, int? rulesetId = null, int? variant = null) { - var context = GetContext(); - - // compare counts in database vs defaults - foreach (var group in defaults.GroupBy(k => k.Action)) + using (var context = GetContext()) + using (var transaction = context.Database.BeginTransaction()) { - int count = query(context, rulesetId, variant).Count(k => (int)k.Action == (int)group.Key); - int aimCount = group.Count(); + // compare counts in database vs defaults + foreach (var group in defaults.GroupBy(k => k.Action)) + { + int count = query(context, rulesetId, variant).Count(k => (int)k.Action == (int)group.Key); + int aimCount = group.Count(); - if (aimCount <= count) - continue; + if (aimCount <= count) + continue; - foreach (var insertable in group.Skip(count).Take(aimCount - count)) - // insert any defaults which are missing. - context.DatabasedKeyBinding.Add(new DatabasedKeyBinding - { - KeyCombination = insertable.KeyCombination, - Action = insertable.Action, - RulesetID = rulesetId, - Variant = variant - }); + foreach (var insertable in group.Skip(count).Take(aimCount - count)) + // insert any defaults which are missing. + context.DatabasedKeyBinding.Add(new DatabasedKeyBinding + { + KeyCombination = insertable.KeyCombination, + Action = insertable.Action, + RulesetID = rulesetId, + Variant = variant + }); + } + + context.SaveChanges(transaction); } - - context.SaveChanges(); } /// From 1514d8451e896a41298a99ba99279e46647d95a5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 22 Oct 2017 16:18:19 +0900 Subject: [PATCH 0394/1263] Use a more elegant method of setting the connection timeout --- osu.Game/Database/OsuDbContext.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/osu.Game/Database/OsuDbContext.cs b/osu.Game/Database/OsuDbContext.cs index 99e5fa9741..271fde719b 100644 --- a/osu.Game/Database/OsuDbContext.cs +++ b/osu.Game/Database/OsuDbContext.cs @@ -3,6 +3,7 @@ using System; using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Storage; using Microsoft.EntityFrameworkCore.Diagnostics; using Microsoft.Extensions.Logging; using osu.Framework.Logging; @@ -50,8 +51,6 @@ namespace osu.Game.Database { this.connectionString = connectionString; - Database.SetCommandTimeout(new TimeSpan(TimeSpan.TicksPerSecond * 10)); - var connection = Database.GetDbConnection(); connection.Open(); using (var cmd = connection.CreateCommand()) @@ -68,7 +67,7 @@ namespace osu.Game.Database // this is required for the time being due to the way we are querying in places like BeatmapStore. // if we ever move to having consumers file their own .Includes, or get eager loading support, this could be re-enabled. .ConfigureWarnings(warnings => warnings.Ignore(CoreEventId.IncludeIgnoredWarning)) - .UseSqlite(connectionString) + .UseSqlite(connectionString, sqliteOptions => sqliteOptions.CommandTimeout(10)) .UseLoggerFactory(logger.Value); } From 5b2219a692761b1d1e4413f61ac210cb54cdeb7e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 22 Oct 2017 16:18:39 +0900 Subject: [PATCH 0395/1263] Add back test cleanup before run --- osu.Game/Tests/Visual/OsuTestCase.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/osu.Game/Tests/Visual/OsuTestCase.cs b/osu.Game/Tests/Visual/OsuTestCase.cs index ca0aaebb5e..b2c8be47bd 100644 --- a/osu.Game/Tests/Visual/OsuTestCase.cs +++ b/osu.Game/Tests/Visual/OsuTestCase.cs @@ -13,11 +13,9 @@ namespace osu.Game.Tests.Visual { using (var host = new HeadlessGameHost($"test-{Guid.NewGuid()}", realtime: false)) { + host.Storage.DeleteDirectory(string.Empty); host.Run(new OsuTestCaseTestRunner(this)); } - - // clean up after each run - //storage.DeleteDirectory(string.Empty); } public class OsuTestCaseTestRunner : OsuGameBase From aff30db89d42ee0889145a3b8974d959eaeb02e2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 22 Oct 2017 16:21:41 +0900 Subject: [PATCH 0396/1263] Add thread sleep as a temporary workaround for failing tests --- osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs b/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs index e5b8c7fe57..0f9ee60ac7 100644 --- a/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs +++ b/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs @@ -100,6 +100,10 @@ namespace osu.Game.Tests.Beatmaps.IO waitForOrAssert(() => osu.IsLoaded, @"osu! failed to start in a reasonable amount of time"); + // this is a temporary workaround for database transaction clashes. + // see https://github.com/aspnet/EntityFrameworkCore/issues/9994 for more information. + Thread.Sleep(1000); + return osu; } From 61c1dd36366c17d740a2f8be3eda04f0a61a030d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 22 Oct 2017 19:46:08 +0900 Subject: [PATCH 0397/1263] Don't output database logs unless DEBUG_DATABASE is specified compile-time --- osu.Game/Database/OsuDbContext.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Database/OsuDbContext.cs b/osu.Game/Database/OsuDbContext.cs index 271fde719b..cf97a8f216 100644 --- a/osu.Game/Database/OsuDbContext.cs +++ b/osu.Game/Database/OsuDbContext.cs @@ -157,7 +157,7 @@ namespace osu.Game.Database public bool IsEnabled(LogLevel logLevel) { -#if DEBUG +#if DEBUG_DATABASE return logLevel > LogLevel.Debug; #else return logLevel > LogLevel.Information; From cf468d6708ccb3f1f19dd8e69873173d12cee486 Mon Sep 17 00:00:00 2001 From: DerpyCrabs Date: Sun, 22 Oct 2017 20:14:38 +0700 Subject: [PATCH 0398/1263] Fix linux build Build is failing on linux because of case sensitive file system. This change fixes it. --- osu.Game/osu.Game.csproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 601c99e19f..2c1df83c68 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -282,7 +282,7 @@ - + 20171019041408_InitialCreate.cs @@ -864,4 +864,4 @@ - \ No newline at end of file + From b1d5fc523fd86a38c843bf69ed5031575dd8ac20 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 23 Oct 2017 00:29:52 +0900 Subject: [PATCH 0399/1263] Add sqlite raw packages to osu.Desktop to ensure sqlite is copied locally --- osu.Desktop/app.config | 28 ++++++++++++++++++++++++++-- osu.Desktop/osu.Desktop.csproj | 33 ++++++++++++++++++++++++++++----- osu.Desktop/packages.config | 32 +++++++++++++++++++------------- 3 files changed, 73 insertions(+), 20 deletions(-) diff --git a/osu.Desktop/app.config b/osu.Desktop/app.config index 0841541f3d..ea1576b3d8 100644 --- a/osu.Desktop/app.config +++ b/osu.Desktop/app.config @@ -12,8 +12,32 @@ - - + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/osu.Desktop/osu.Desktop.csproj b/osu.Desktop/osu.Desktop.csproj index fb1ca7eb10..7db35c27cb 100644 --- a/osu.Desktop/osu.Desktop.csproj +++ b/osu.Desktop/osu.Desktop.csproj @@ -133,30 +133,42 @@ - ..\packages\squirrel.windows.1.7.8\lib\Net45\NuGet.Squirrel.dll + $(SolutionDir)\packages\squirrel.windows.1.7.8\lib\Net45\NuGet.Squirrel.dll True - ..\packages\OpenTK.3.0.0-git00009\lib\net20\OpenTK.dll + $(SolutionDir)\packages\OpenTK.3.0.0-git00009\lib\net20\OpenTK.dll True - ..\packages\SharpCompress.0.18.1\lib\net45\SharpCompress.dll + $(SolutionDir)\packages\SharpCompress.0.18.1\lib\net45\SharpCompress.dll True $(SolutionDir)\packages\Splat.2.0.0\lib\Net45\Splat.dll True + + $(SolutionDir)\packages\SQLitePCLRaw.bundle_green.1.1.8\lib\net45\SQLitePCLRaw.batteries_green.dll + + + $(SolutionDir)\packages\SQLitePCLRaw.bundle_green.1.1.8\lib\net45\SQLitePCLRaw.batteries_v2.dll + + + $(SolutionDir)\packages\SQLitePCLRaw.core.1.1.8\lib\net45\SQLitePCLRaw.core.dll + + + $(SolutionDir)\packages\SQLitePCLRaw.provider.e_sqlite3.net45.1.1.8\lib\net45\SQLitePCLRaw.provider.e_sqlite3.dll + - ..\packages\squirrel.windows.1.7.8\lib\Net45\Squirrel.dll + $(SolutionDir)\packages\squirrel.windows.1.7.8\lib\Net45\Squirrel.dll True - ../packages/System.ValueTuple.4.4.0/lib/net461/System.ValueTuple.dll + $(SolutionDir)\packages\System.ValueTuple.4.4.0\lib\net461\System.ValueTuple.dll True @@ -258,4 +270,15 @@ + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + + + \ No newline at end of file diff --git a/osu.Desktop/packages.config b/osu.Desktop/packages.config index 80eb533644..6b6361b578 100644 --- a/osu.Desktop/packages.config +++ b/osu.Desktop/packages.config @@ -1,14 +1,20 @@ - - - - - - - - - - + + + + + + + + + + + + + + + + \ No newline at end of file From 9b54e834d9225d3b601f63ccf2de6e2d9beedc9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20Odg=C3=A5rd=20T=C3=B8rring?= Date: Sun, 22 Oct 2017 20:32:59 +0200 Subject: [PATCH 0400/1263] Implements virtual Failcondition in scoreprocessor and enforces nofail in UpdateFailed --- osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs | 2 +- osu.Game/Rulesets/Scoring/ScoreProcessor.cs | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs b/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs index 752e3bee26..0e5df329d8 100644 --- a/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs +++ b/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs @@ -53,7 +53,7 @@ namespace osu.Game.Rulesets.Taiko.Scoring /// /// Taiko fails at the end of the map if the player has not half-filled their HP bar. /// - public override bool HasFailed => Hits == MaxHits && Health.Value <= 0.5; + protected override bool FailCondition => Hits == MaxHits && Health.Value <= 0.5; private double hpIncreaseTick; private double hpIncreaseGreat; diff --git a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs index 0b631a7148..934b19b511 100644 --- a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs +++ b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs @@ -69,7 +69,12 @@ namespace osu.Game.Rulesets.Scoring /// /// Whether the score is in a failed state. /// - public virtual bool HasFailed => Health.Value == Health.MinValue; + public virtual bool HasFailed => alreadyFailed; + + /// + /// The conditions for failing + /// + protected virtual bool FailCondition => Health.Value == Health.MinValue; /// /// Whether this ScoreProcessor has already triggered the failed state. @@ -121,7 +126,7 @@ namespace osu.Game.Rulesets.Scoring /// protected void UpdateFailed() { - if (alreadyFailed || !HasFailed) + if (alreadyFailed || !FailCondition) return; if (Failed?.Invoke() != false) From 5af6fb41f5873ef98e6a52cdad4d1c71c3e2f584 Mon Sep 17 00:00:00 2001 From: Nabile Rahmani Date: Mon, 23 Oct 2017 02:03:46 +0200 Subject: [PATCH 0401/1263] Fixed .NET Standard build on Linux. --- osu.Game/osu.Game.csproj | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 2c1df83c68..f02664c3d2 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -146,6 +146,7 @@ $(SolutionDir)\packages\Microsoft.Extensions.Primitives.2.0.0\lib\netstandard2.0\Microsoft.Extensions.Primitives.dll + $(SolutionDir)\packages\Newtonsoft.Json.10.0.3\lib\net45\Newtonsoft.Json.dll True From ea2934d92c69f437e5550bcb5ed40de6f33847c7 Mon Sep 17 00:00:00 2001 From: Shane Woolcock Date: Mon, 23 Oct 2017 16:06:08 +1030 Subject: [PATCH 0402/1263] Add KeyboardStep values for configuration options --- .../Settings/Sections/Audio/OffsetSettings.cs | 3 ++- .../Settings/Sections/Audio/VolumeSettings.cs | 6 +++--- .../Settings/Sections/Gameplay/GeneralSettings.cs | 3 ++- .../Settings/Sections/Gameplay/SongSelectSettings.cs | 6 ++++-- .../Settings/Sections/Graphics/LayoutSettings.cs | 6 ++++-- osu.Game/Overlays/Settings/Sections/SkinSection.cs | 6 ++++-- osu.Game/Overlays/Settings/SettingsSlider.cs | 11 +++++++++++ .../Screens/Play/ReplaySettings/PlaybackSettings.cs | 3 ++- 8 files changed, 32 insertions(+), 12 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/Audio/OffsetSettings.cs b/osu.Game/Overlays/Settings/Sections/Audio/OffsetSettings.cs index bc09a2145a..984fe28ec5 100644 --- a/osu.Game/Overlays/Settings/Sections/Audio/OffsetSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Audio/OffsetSettings.cs @@ -20,7 +20,8 @@ namespace osu.Game.Overlays.Settings.Sections.Audio new SettingsSlider { LabelText = "Audio Offset", - Bindable = config.GetBindable(OsuSetting.AudioOffset) + Bindable = config.GetBindable(OsuSetting.AudioOffset), + KeyboardStep = 100f }, new OsuButton { diff --git a/osu.Game/Overlays/Settings/Sections/Audio/VolumeSettings.cs b/osu.Game/Overlays/Settings/Sections/Audio/VolumeSettings.cs index ea442cdfc2..d197f8c466 100644 --- a/osu.Game/Overlays/Settings/Sections/Audio/VolumeSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Audio/VolumeSettings.cs @@ -16,9 +16,9 @@ namespace osu.Game.Overlays.Settings.Sections.Audio { Children = new Drawable[] { - new SettingsSlider { LabelText = "Master", Bindable = audio.Volume }, - new SettingsSlider { LabelText = "Effect", Bindable = audio.VolumeSample }, - new SettingsSlider { LabelText = "Music", Bindable = audio.VolumeTrack }, + new SettingsSlider { LabelText = "Master", Bindable = audio.Volume, KeyboardStep = 0.1f }, + new SettingsSlider { LabelText = "Effect", Bindable = audio.VolumeSample, KeyboardStep = 0.1f }, + new SettingsSlider { LabelText = "Music", Bindable = audio.VolumeTrack, KeyboardStep = 0.1f }, }; } } diff --git a/osu.Game/Overlays/Settings/Sections/Gameplay/GeneralSettings.cs b/osu.Game/Overlays/Settings/Sections/Gameplay/GeneralSettings.cs index a8ec04514a..8ec6af5cd0 100644 --- a/osu.Game/Overlays/Settings/Sections/Gameplay/GeneralSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Gameplay/GeneralSettings.cs @@ -19,7 +19,8 @@ namespace osu.Game.Overlays.Settings.Sections.Gameplay new SettingsSlider { LabelText = "Background dim", - Bindable = config.GetBindable(OsuSetting.DimLevel) + Bindable = config.GetBindable(OsuSetting.DimLevel), + KeyboardStep = 0.1f }, new SettingsCheckbox { diff --git a/osu.Game/Overlays/Settings/Sections/Gameplay/SongSelectSettings.cs b/osu.Game/Overlays/Settings/Sections/Gameplay/SongSelectSettings.cs index 08dba011df..07a8e7464a 100644 --- a/osu.Game/Overlays/Settings/Sections/Gameplay/SongSelectSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Gameplay/SongSelectSettings.cs @@ -20,12 +20,14 @@ namespace osu.Game.Overlays.Settings.Sections.Gameplay new SettingsSlider { LabelText = "Display beatmaps from", - Bindable = config.GetBindable(OsuSetting.DisplayStarsMinimum) + Bindable = config.GetBindable(OsuSetting.DisplayStarsMinimum), + KeyboardStep = 1f }, new SettingsSlider { LabelText = "up to", - Bindable = config.GetBindable(OsuSetting.DisplayStarsMaximum) + Bindable = config.GetBindable(OsuSetting.DisplayStarsMaximum), + KeyboardStep = 1f }, new SettingsEnumDropdown { diff --git a/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs b/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs index c4ce742153..3d09d6b901 100644 --- a/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs @@ -49,12 +49,14 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics new SettingsSlider { LabelText = "Horizontal position", - Bindable = config.GetBindable(FrameworkSetting.LetterboxPositionX) + Bindable = config.GetBindable(FrameworkSetting.LetterboxPositionX), + KeyboardStep = 0.1f }, new SettingsSlider { LabelText = "Vertical position", - Bindable = config.GetBindable(FrameworkSetting.LetterboxPositionY) + Bindable = config.GetBindable(FrameworkSetting.LetterboxPositionY), + KeyboardStep = 0.1f }, } }, diff --git a/osu.Game/Overlays/Settings/Sections/SkinSection.cs b/osu.Game/Overlays/Settings/Sections/SkinSection.cs index 4b4426aca8..b4475aebb1 100644 --- a/osu.Game/Overlays/Settings/Sections/SkinSection.cs +++ b/osu.Game/Overlays/Settings/Sections/SkinSection.cs @@ -24,12 +24,14 @@ namespace osu.Game.Overlays.Settings.Sections new SettingsSlider { LabelText = "Menu cursor size", - Bindable = config.GetBindable(OsuSetting.MenuCursorSize) + Bindable = config.GetBindable(OsuSetting.MenuCursorSize), + KeyboardStep = 0.1f }, new SettingsSlider { LabelText = "Gameplay cursor size", - Bindable = config.GetBindable(OsuSetting.GameplayCursorSize) + Bindable = config.GetBindable(OsuSetting.GameplayCursorSize), + KeyboardStep = 0.1f }, new SettingsCheckbox { diff --git a/osu.Game/Overlays/Settings/SettingsSlider.cs b/osu.Game/Overlays/Settings/SettingsSlider.cs index 2881d02302..49d73f77ec 100644 --- a/osu.Game/Overlays/Settings/SettingsSlider.cs +++ b/osu.Game/Overlays/Settings/SettingsSlider.cs @@ -2,6 +2,7 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; +using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.UserInterface; using osu.Game.Graphics.UserInterface; @@ -22,5 +23,15 @@ namespace osu.Game.Overlays.Settings Margin = new MarginPadding { Top = 5, Bottom = 5 }, RelativeSizeAxes = Axes.X }; + + public float KeyboardStep; + + [BackgroundDependencyLoader] + private void load() + { + var slider = Control as U; + if (slider != null) + slider.KeyboardStep = KeyboardStep; + } } } diff --git a/osu.Game/Screens/Play/ReplaySettings/PlaybackSettings.cs b/osu.Game/Screens/Play/ReplaySettings/PlaybackSettings.cs index ea958d05f9..16868e5843 100644 --- a/osu.Game/Screens/Play/ReplaySettings/PlaybackSettings.cs +++ b/osu.Game/Screens/Play/ReplaySettings/PlaybackSettings.cs @@ -19,7 +19,8 @@ namespace osu.Game.Screens.Play.ReplaySettings new ReplaySliderBar { LabelText = "Playback speed", - Bindable = config.GetBindable(OsuSetting.PlaybackSpeed) + Bindable = config.GetBindable(OsuSetting.PlaybackSpeed), + KeyboardStep = 0.5f } }; } From 8fab6abf908b2c53d5428d7fca294f5f66879b5a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 23 Oct 2017 14:46:17 +0900 Subject: [PATCH 0403/1263] Update WebRequest usage in line with framework changes --- osu-framework | 2 +- osu.Desktop.Deploy/Program.cs | 12 +++--------- osu.Game/Online/API/APIRequest.cs | 2 +- osu.Game/Online/API/OAuth.cs | 4 ++-- 4 files changed, 7 insertions(+), 13 deletions(-) diff --git a/osu-framework b/osu-framework index 383a8da7bc..26f3091dca 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit 383a8da7bc45af498288b4b72c72a048a0996e74 +Subproject commit 26f3091dcaf47e3b355b7f7ad83b292621d7d6b5 diff --git a/osu.Desktop.Deploy/Program.cs b/osu.Desktop.Deploy/Program.cs index 785f915a3e..385bc444d1 100644 --- a/osu.Desktop.Deploy/Program.cs +++ b/osu.Desktop.Deploy/Program.cs @@ -7,7 +7,6 @@ using System.Configuration; using System.Diagnostics; using System.IO; using System.Linq; -using System.Net; using Newtonsoft.Json; using osu.Framework.IO.Network; using FileWebRequest = osu.Framework.IO.Network.FileWebRequest; @@ -391,8 +390,8 @@ namespace osu.Desktop.Deploy public static void AuthenticatedBlockingPerform(this WebRequest r) { - r.AddHeader("Authorization", $"token {GitHubAccessToken}"); - r.BlockingPerform(); + r.Headers.Add("Authorization", $"token {GitHubAccessToken}"); + r.Perform(); } } @@ -402,12 +401,7 @@ namespace osu.Desktop.Deploy { } - protected override HttpWebRequest CreateWebRequest(string requestString = null) - { - var req = base.CreateWebRequest(requestString); - req.Accept = "application/octet-stream"; - return req; - } + protected override string Accept => "application/octet-stream"; } internal class ReleaseLine diff --git a/osu.Game/Online/API/APIRequest.cs b/osu.Game/Online/API/APIRequest.cs index 37903f924f..9a8180778d 100644 --- a/osu.Game/Online/API/APIRequest.cs +++ b/osu.Game/Online/API/APIRequest.cs @@ -106,7 +106,7 @@ namespace osu.Game.Online.API return; if (!WebRequest.Aborted) //could have been aborted by a Cancel() call - WebRequest.BlockingPerform(); + WebRequest.Perform(); if (checkAndProcessFailure()) return; diff --git a/osu.Game/Online/API/OAuth.cs b/osu.Game/Online/API/OAuth.cs index 5410bcc55d..445688f2ce 100644 --- a/osu.Game/Online/API/OAuth.cs +++ b/osu.Game/Online/API/OAuth.cs @@ -37,7 +37,7 @@ namespace osu.Game.Online.API { try { - req.BlockingPerform(); + req.Perform(); } catch { @@ -61,7 +61,7 @@ namespace osu.Game.Online.API ClientSecret = clientSecret }) { - req.BlockingPerform(); + req.Perform(); Token = req.ResponseObject; return true; From 4a68dd88cb2fc731c070d8641a0c27f164121161 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 23 Oct 2017 14:53:13 +0900 Subject: [PATCH 0404/1263] Centralise BeginTransaction and disable transaction use for now --- osu.Game/Beatmaps/BeatmapManager.cs | 4 ++-- osu.Game/Database/OsuDbContext.cs | 6 ++++++ osu.Game/Input/KeyBindingStore.cs | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index b81e239015..55c3e192e3 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -184,7 +184,7 @@ namespace osu.Game.Beatmaps { var context = importContext.Value; - using (var transaction = context.Database.BeginTransaction()) + using (var transaction = context.BeginTransaction()) { // create local stores so we can isolate and thread safely, and share a context/transaction. var iFiles = new FileStore(() => context, storage); @@ -295,7 +295,7 @@ namespace osu.Game.Beatmaps { var context = importContext.Value; - using (var transaction = context.Database.BeginTransaction()) + using (var transaction = context.BeginTransaction()) { context.ChangeTracker.AutoDetectChangesEnabled = false; diff --git a/osu.Game/Database/OsuDbContext.cs b/osu.Game/Database/OsuDbContext.cs index cf97a8f216..6c267811a1 100644 --- a/osu.Game/Database/OsuDbContext.cs +++ b/osu.Game/Database/OsuDbContext.cs @@ -92,6 +92,12 @@ namespace osu.Game.Database modelBuilder.Entity().HasOne(b => b.BaseDifficulty); } + public IDbContextTransaction BeginTransaction() + { + // return Database.BeginTransaction(); + return null; + } + public new int SaveChanges(IDbContextTransaction transaction = null) { var ret = base.SaveChanges(); diff --git a/osu.Game/Input/KeyBindingStore.cs b/osu.Game/Input/KeyBindingStore.cs index b434ce4eb7..0a0cd3dd6f 100644 --- a/osu.Game/Input/KeyBindingStore.cs +++ b/osu.Game/Input/KeyBindingStore.cs @@ -39,7 +39,7 @@ namespace osu.Game.Input private void insertDefaults(IEnumerable defaults, int? rulesetId = null, int? variant = null) { using (var context = GetContext()) - using (var transaction = context.Database.BeginTransaction()) + using (var transaction = context.BeginTransaction()) { // compare counts in database vs defaults foreach (var group in defaults.GroupBy(k => k.Action)) From df20845fbb170528ad5c8c0d96c8a4d4c73ac991 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 23 Oct 2017 16:35:35 +0900 Subject: [PATCH 0405/1263] Share one context per file store for performance reasons There is now a CreateContext method for retrieving a stand-alone context for threaded use. We may want to add safety against this context being disposed (or just return a fresh one if it is). --- osu.Game/Database/DatabaseBackedStore.cs | 18 +++++++++++++++--- osu.Game/Database/OsuDbContext.cs | 1 + osu.Game/IO/FileStore.cs | 2 +- osu.Game/Input/KeyBindingStore.cs | 15 +++++++-------- .../Sections/Maintenance/GeneralSettings.cs | 3 ++- 5 files changed, 26 insertions(+), 13 deletions(-) diff --git a/osu.Game/Database/DatabaseBackedStore.cs b/osu.Game/Database/DatabaseBackedStore.cs index be86d35335..35700e90fc 100644 --- a/osu.Game/Database/DatabaseBackedStore.cs +++ b/osu.Game/Database/DatabaseBackedStore.cs @@ -11,12 +11,24 @@ namespace osu.Game.Database { protected readonly Storage Storage; - protected readonly Func GetContext; + /// + /// Create a new instance (separate from the shared context via for performing isolated operations. + /// + protected readonly Func CreateContext; - protected DatabaseBackedStore(Func getContext, Storage storage = null) + private readonly Lazy queryContext; + + /// + /// Retrieve a shared context for performing lookups (or write operations on the update thread, for now). + /// + protected OsuDbContext GetContext() => queryContext.Value; + + protected DatabaseBackedStore(Func createContext, Storage storage = null) { + CreateContext = createContext; + queryContext = new Lazy(CreateContext); + Storage = storage; - GetContext = getContext; try { diff --git a/osu.Game/Database/OsuDbContext.cs b/osu.Game/Database/OsuDbContext.cs index 6c267811a1..0904a5151d 100644 --- a/osu.Game/Database/OsuDbContext.cs +++ b/osu.Game/Database/OsuDbContext.cs @@ -24,6 +24,7 @@ namespace osu.Game.Database public DbSet DatabasedKeyBinding { get; set; } public DbSet FileInfo { get; set; } public DbSet RulesetInfo { get; set; } + private readonly string connectionString; private static readonly Lazy logger = new Lazy(() => new OsuDbLoggerFactory()); diff --git a/osu.Game/IO/FileStore.cs b/osu.Game/IO/FileStore.cs index 6654fa7cb1..b69916e565 100644 --- a/osu.Game/IO/FileStore.cs +++ b/osu.Game/IO/FileStore.cs @@ -22,7 +22,7 @@ namespace osu.Game.IO public Storage Storage => base.Storage; - public FileStore(Func getContext, Storage storage) : base(getContext, storage.GetStorageForDirectory(@"files")) + public FileStore(Func createContext, Storage storage) : base(createContext, storage.GetStorageForDirectory(@"files")) { Store = new StorageBackedResourceStore(Storage); } diff --git a/osu.Game/Input/KeyBindingStore.cs b/osu.Game/Input/KeyBindingStore.cs index 0a0cd3dd6f..1e1b1d74d4 100644 --- a/osu.Game/Input/KeyBindingStore.cs +++ b/osu.Game/Input/KeyBindingStore.cs @@ -17,8 +17,8 @@ namespace osu.Game.Input { public event Action KeyBindingChanged; - public KeyBindingStore(Func getContext, RulesetStore rulesets, Storage storage = null) - : base(getContext, storage) + public KeyBindingStore(Func createContext, RulesetStore rulesets, Storage storage = null) + : base(createContext, storage) { foreach (var info in rulesets.AvailableRulesets) { @@ -38,13 +38,14 @@ namespace osu.Game.Input private void insertDefaults(IEnumerable defaults, int? rulesetId = null, int? variant = null) { - using (var context = GetContext()) + var context = GetContext(); + using (var transaction = context.BeginTransaction()) { // compare counts in database vs defaults foreach (var group in defaults.GroupBy(k => k.Action)) { - int count = query(context, rulesetId, variant).Count(k => (int)k.Action == (int)group.Key); + int count = Query(rulesetId, variant).Count(k => (int)k.Action == (int)group.Key); int aimCount = group.Count(); if (aimCount <= count) @@ -71,10 +72,8 @@ namespace osu.Game.Input /// The ruleset's internal ID. /// An optional variant. /// - public IEnumerable Query(int? rulesetId = null, int? variant = null) => query(GetContext(), rulesetId, variant); - - private IEnumerable query(OsuDbContext context, int? rulesetId = null, int? variant = null) => - context.DatabasedKeyBinding.Where(b => b.RulesetID == rulesetId && b.Variant == variant); + public IEnumerable Query(int? rulesetId = null, int? variant = null) => + GetContext().DatabasedKeyBinding.Where(b => b.RulesetID == rulesetId && b.Variant == variant); public void Update(KeyBinding keyBinding) { diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs index 233ca7be60..cea070102d 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.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.Linq; using System.Threading.Tasks; using osu.Framework.Allocation; using osu.Framework.Graphics; @@ -51,7 +52,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance restoreButton.Enabled.Value = false; Task.Run(() => { - foreach (var b in beatmaps.QueryBeatmaps(b => b.Hidden)) + foreach (var b in beatmaps.QueryBeatmaps(b => b.Hidden).ToList()) beatmaps.Restore(b); }).ContinueWith(t => Schedule(() => restoreButton.Enabled.Value = true)); } From e7931ef4c79302434d5468cdbf3acadb0b771ff8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 23 Oct 2017 16:56:29 +0900 Subject: [PATCH 0406/1263] Add a default icon when a ruleset isn't present --- osu.Game/Beatmaps/Drawables/DifficultyIcon.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs b/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs index 42db025a40..1aff764ede 100644 --- a/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs +++ b/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs @@ -35,7 +35,8 @@ namespace osu.Game.Beatmaps.Drawables new ConstrainedIconContainer { RelativeSizeAxes = Axes.Both, - Icon = beatmap.Ruleset.CreateInstance().CreateIcon() + // the null coalesce here is only present to make unit tests work (ruleset dlls aren't copied correctly for testing at the moment) + Icon = beatmap.Ruleset?.CreateInstance().CreateIcon() ?? new SpriteIcon { Icon = FontAwesome.fa_question_circle_o } } }; } From 1a3debc91dc814fad0854a7899bc9860cc5748f1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 23 Oct 2017 17:56:04 +0900 Subject: [PATCH 0407/1263] Ensure thread safety on shared contexts Let's call this one temporary. --- osu.Game/Database/DatabaseBackedStore.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/osu.Game/Database/DatabaseBackedStore.cs b/osu.Game/Database/DatabaseBackedStore.cs index 35700e90fc..68f412eee6 100644 --- a/osu.Game/Database/DatabaseBackedStore.cs +++ b/osu.Game/Database/DatabaseBackedStore.cs @@ -2,6 +2,7 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; +using System.Threading; using osu.Framework.Logging; using osu.Framework.Platform; @@ -16,7 +17,7 @@ namespace osu.Game.Database /// protected readonly Func CreateContext; - private readonly Lazy queryContext; + private readonly ThreadLocal queryContext; /// /// Retrieve a shared context for performing lookups (or write operations on the update thread, for now). @@ -26,7 +27,9 @@ namespace osu.Game.Database protected DatabaseBackedStore(Func createContext, Storage storage = null) { CreateContext = createContext; - queryContext = new Lazy(CreateContext); + + // todo: while this seems to work quite well, we need to consider that contexts could enter a state where they are never cleaned up. + queryContext = new ThreadLocal(CreateContext); Storage = storage; From dc9c47403314a9a1cca203f8d93e0d78139e730e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 23 Oct 2017 19:29:47 +0900 Subject: [PATCH 0408/1263] Move all TestCases to Testing project This allows tests to successfully retrieve rulesets, as they are referenced. --- osu.Desktop/osu.Desktop.csproj | 4 ++ osu.Game.Tests/Visual/TestCaseAllPlayers.cs | 10 ++++ .../Visual/TestCaseBeatSyncedContainer.cs | 0 .../Visual/TestCaseBeatmapDetailArea.cs | 0 .../Visual/TestCaseBeatmapDetails.cs | 0 .../Visual/TestCaseBeatmapOptionsOverlay.cs | 0 .../Visual/TestCaseBeatmapSetOverlay.cs | 0 .../Visual/TestCaseBreadcrumbs.cs | 0 .../Visual/TestCaseBreakOverlay.cs | 0 .../Visual/TestCaseChatDisplay.cs | 0 .../Visual/TestCaseContextMenu.cs | 0 .../Visual/TestCaseDialogOverlay.cs | 0 .../Visual/TestCaseDirect.cs | 0 .../Visual/TestCaseDrawableRoom.cs | 0 .../Visual/TestCaseDrawings.cs | 0 .../Visual/TestCaseEditor.cs | 0 .../Visual/TestCaseEditorComposeTimeline.cs | 0 .../Visual/TestCaseEditorMenuBar.cs | 0 .../Visual/TestCaseEditorSummaryTimeline.cs | 0 .../Visual/TestCaseGamefield.cs | 0 .../Visual/TestCaseGraph.cs | 0 .../Visual/TestCaseIconButton.cs | 0 .../Visual/TestCaseKeyConfiguration.cs | 0 .../Visual/TestCaseKeyCounter.cs | 0 .../Visual/TestCaseLeaderboard.cs | 0 .../Visual/TestCaseMedalOverlay.cs | 0 .../Visual/TestCaseMenuButtonSystem.cs | 0 .../Visual/TestCaseMenuOverlays.cs | 0 .../Visual/TestCaseMods.cs | 0 .../Visual/TestCaseMusicController.cs | 0 .../Visual/TestCaseNotificationOverlay.cs | 0 .../Visual/TestCaseOnScreenDisplay.cs | 0 .../Visual/TestCasePlaySongSelect.cs | 4 +- .../Visual/TestCaseReplay.cs | 0 .../Visual/TestCaseReplaySettingsOverlay.cs | 0 .../Visual/TestCaseResults.cs | 0 .../Visual/TestCaseRoomInspector.cs | 0 .../Visual/TestCaseScoreCounter.cs | 0 .../Visual/TestCaseScrollingPlayfield.cs | 0 .../Visual/TestCaseSettings.cs | 0 .../Visual/TestCaseSkipButton.cs | 0 .../Visual/TestCaseSocial.cs | 0 .../Visual/TestCaseSongProgress.cs | 0 .../Visual/TestCaseStoryboard.cs | 0 .../Visual/TestCaseTabControl.cs | 0 .../Visual/TestCaseTextAwesome.cs | 0 .../Visual/TestCaseTwoLayerButton.cs | 0 .../Visual/TestCaseUserPanel.cs | 0 .../Visual/TestCaseUserProfile.cs | 0 .../Visual/TestCaseUserRanks.cs | 0 .../Visual/TestCaseWaveform.cs | 0 osu.Game.Tests/osu.Game.Tests.csproj | 50 ++++++++++++++++++ osu.Game/Database/OsuDbContext.cs | 2 + osu.Game/Screens/Edit/Editor.cs | 2 +- .../Timeline/ScrollingTimelineContainer.cs | 2 +- osu.Game/Tests/Visual/TestCasePlayer.cs | 4 +- osu.Game/osu.Game.csproj | 52 +------------------ 57 files changed, 72 insertions(+), 58 deletions(-) create mode 100644 osu.Game.Tests/Visual/TestCaseAllPlayers.cs rename {osu.Game/Tests => osu.Game.Tests}/Visual/TestCaseBeatSyncedContainer.cs (100%) rename {osu.Game/Tests => osu.Game.Tests}/Visual/TestCaseBeatmapDetailArea.cs (100%) rename {osu.Game/Tests => osu.Game.Tests}/Visual/TestCaseBeatmapDetails.cs (100%) rename {osu.Game/Tests => osu.Game.Tests}/Visual/TestCaseBeatmapOptionsOverlay.cs (100%) rename {osu.Game/Tests => osu.Game.Tests}/Visual/TestCaseBeatmapSetOverlay.cs (100%) rename {osu.Game/Tests => osu.Game.Tests}/Visual/TestCaseBreadcrumbs.cs (100%) rename {osu.Game/Tests => osu.Game.Tests}/Visual/TestCaseBreakOverlay.cs (100%) rename {osu.Game/Tests => osu.Game.Tests}/Visual/TestCaseChatDisplay.cs (100%) rename {osu.Game/Tests => osu.Game.Tests}/Visual/TestCaseContextMenu.cs (100%) rename {osu.Game/Tests => osu.Game.Tests}/Visual/TestCaseDialogOverlay.cs (100%) rename {osu.Game/Tests => osu.Game.Tests}/Visual/TestCaseDirect.cs (100%) rename {osu.Game/Tests => osu.Game.Tests}/Visual/TestCaseDrawableRoom.cs (100%) rename {osu.Game/Tests => osu.Game.Tests}/Visual/TestCaseDrawings.cs (100%) rename {osu.Game/Tests => osu.Game.Tests}/Visual/TestCaseEditor.cs (100%) rename {osu.Game/Tests => osu.Game.Tests}/Visual/TestCaseEditorComposeTimeline.cs (100%) rename {osu.Game/Tests => osu.Game.Tests}/Visual/TestCaseEditorMenuBar.cs (100%) rename {osu.Game/Tests => osu.Game.Tests}/Visual/TestCaseEditorSummaryTimeline.cs (100%) rename {osu.Game/Tests => osu.Game.Tests}/Visual/TestCaseGamefield.cs (100%) rename {osu.Game/Tests => osu.Game.Tests}/Visual/TestCaseGraph.cs (100%) rename {osu.Game/Tests => osu.Game.Tests}/Visual/TestCaseIconButton.cs (100%) rename {osu.Game/Tests => osu.Game.Tests}/Visual/TestCaseKeyConfiguration.cs (100%) rename {osu.Game/Tests => osu.Game.Tests}/Visual/TestCaseKeyCounter.cs (100%) rename {osu.Game/Tests => osu.Game.Tests}/Visual/TestCaseLeaderboard.cs (100%) rename {osu.Game/Tests => osu.Game.Tests}/Visual/TestCaseMedalOverlay.cs (100%) rename {osu.Game/Tests => osu.Game.Tests}/Visual/TestCaseMenuButtonSystem.cs (100%) rename {osu.Game/Tests => osu.Game.Tests}/Visual/TestCaseMenuOverlays.cs (100%) rename {osu.Game/Tests => osu.Game.Tests}/Visual/TestCaseMods.cs (100%) rename {osu.Game/Tests => osu.Game.Tests}/Visual/TestCaseMusicController.cs (100%) rename {osu.Game/Tests => osu.Game.Tests}/Visual/TestCaseNotificationOverlay.cs (100%) rename {osu.Game/Tests => osu.Game.Tests}/Visual/TestCaseOnScreenDisplay.cs (100%) rename {osu.Game/Tests => osu.Game.Tests}/Visual/TestCasePlaySongSelect.cs (93%) rename {osu.Game/Tests => osu.Game.Tests}/Visual/TestCaseReplay.cs (100%) rename {osu.Game/Tests => osu.Game.Tests}/Visual/TestCaseReplaySettingsOverlay.cs (100%) rename {osu.Game/Tests => osu.Game.Tests}/Visual/TestCaseResults.cs (100%) rename {osu.Game/Tests => osu.Game.Tests}/Visual/TestCaseRoomInspector.cs (100%) rename {osu.Game/Tests => osu.Game.Tests}/Visual/TestCaseScoreCounter.cs (100%) rename {osu.Game/Tests => osu.Game.Tests}/Visual/TestCaseScrollingPlayfield.cs (100%) rename {osu.Game/Tests => osu.Game.Tests}/Visual/TestCaseSettings.cs (100%) rename {osu.Game/Tests => osu.Game.Tests}/Visual/TestCaseSkipButton.cs (100%) rename {osu.Game/Tests => osu.Game.Tests}/Visual/TestCaseSocial.cs (100%) rename {osu.Game/Tests => osu.Game.Tests}/Visual/TestCaseSongProgress.cs (100%) rename {osu.Game/Tests => osu.Game.Tests}/Visual/TestCaseStoryboard.cs (100%) rename {osu.Game/Tests => osu.Game.Tests}/Visual/TestCaseTabControl.cs (100%) rename {osu.Game/Tests => osu.Game.Tests}/Visual/TestCaseTextAwesome.cs (100%) rename {osu.Game/Tests => osu.Game.Tests}/Visual/TestCaseTwoLayerButton.cs (100%) rename {osu.Game/Tests => osu.Game.Tests}/Visual/TestCaseUserPanel.cs (100%) rename {osu.Game/Tests => osu.Game.Tests}/Visual/TestCaseUserProfile.cs (100%) rename {osu.Game/Tests => osu.Game.Tests}/Visual/TestCaseUserRanks.cs (100%) rename {osu.Game/Tests => osu.Game.Tests}/Visual/TestCaseWaveform.cs (100%) diff --git a/osu.Desktop/osu.Desktop.csproj b/osu.Desktop/osu.Desktop.csproj index fb1ca7eb10..ab64fa7ede 100644 --- a/osu.Desktop/osu.Desktop.csproj +++ b/osu.Desktop/osu.Desktop.csproj @@ -233,6 +233,10 @@ {f167e17a-7de6-4af5-b920-a5112296c695} osu.Game.Rulesets.Taiko + + {54377672-20b1-40af-8087-5cf73bf3953a} + osu.Game.Tests + {2a66dd92-adb1-4994-89e2-c94e04acda0d} osu.Game diff --git a/osu.Game.Tests/Visual/TestCaseAllPlayers.cs b/osu.Game.Tests/Visual/TestCaseAllPlayers.cs new file mode 100644 index 0000000000..8c63e1a274 --- /dev/null +++ b/osu.Game.Tests/Visual/TestCaseAllPlayers.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.Tests.Visual +{ + public class TestCaseAllPlayers : TestCasePlayer + { + public override string Description => @"Showing everything to play the game."; + } +} diff --git a/osu.Game/Tests/Visual/TestCaseBeatSyncedContainer.cs b/osu.Game.Tests/Visual/TestCaseBeatSyncedContainer.cs similarity index 100% rename from osu.Game/Tests/Visual/TestCaseBeatSyncedContainer.cs rename to osu.Game.Tests/Visual/TestCaseBeatSyncedContainer.cs diff --git a/osu.Game/Tests/Visual/TestCaseBeatmapDetailArea.cs b/osu.Game.Tests/Visual/TestCaseBeatmapDetailArea.cs similarity index 100% rename from osu.Game/Tests/Visual/TestCaseBeatmapDetailArea.cs rename to osu.Game.Tests/Visual/TestCaseBeatmapDetailArea.cs diff --git a/osu.Game/Tests/Visual/TestCaseBeatmapDetails.cs b/osu.Game.Tests/Visual/TestCaseBeatmapDetails.cs similarity index 100% rename from osu.Game/Tests/Visual/TestCaseBeatmapDetails.cs rename to osu.Game.Tests/Visual/TestCaseBeatmapDetails.cs diff --git a/osu.Game/Tests/Visual/TestCaseBeatmapOptionsOverlay.cs b/osu.Game.Tests/Visual/TestCaseBeatmapOptionsOverlay.cs similarity index 100% rename from osu.Game/Tests/Visual/TestCaseBeatmapOptionsOverlay.cs rename to osu.Game.Tests/Visual/TestCaseBeatmapOptionsOverlay.cs diff --git a/osu.Game/Tests/Visual/TestCaseBeatmapSetOverlay.cs b/osu.Game.Tests/Visual/TestCaseBeatmapSetOverlay.cs similarity index 100% rename from osu.Game/Tests/Visual/TestCaseBeatmapSetOverlay.cs rename to osu.Game.Tests/Visual/TestCaseBeatmapSetOverlay.cs diff --git a/osu.Game/Tests/Visual/TestCaseBreadcrumbs.cs b/osu.Game.Tests/Visual/TestCaseBreadcrumbs.cs similarity index 100% rename from osu.Game/Tests/Visual/TestCaseBreadcrumbs.cs rename to osu.Game.Tests/Visual/TestCaseBreadcrumbs.cs diff --git a/osu.Game/Tests/Visual/TestCaseBreakOverlay.cs b/osu.Game.Tests/Visual/TestCaseBreakOverlay.cs similarity index 100% rename from osu.Game/Tests/Visual/TestCaseBreakOverlay.cs rename to osu.Game.Tests/Visual/TestCaseBreakOverlay.cs diff --git a/osu.Game/Tests/Visual/TestCaseChatDisplay.cs b/osu.Game.Tests/Visual/TestCaseChatDisplay.cs similarity index 100% rename from osu.Game/Tests/Visual/TestCaseChatDisplay.cs rename to osu.Game.Tests/Visual/TestCaseChatDisplay.cs diff --git a/osu.Game/Tests/Visual/TestCaseContextMenu.cs b/osu.Game.Tests/Visual/TestCaseContextMenu.cs similarity index 100% rename from osu.Game/Tests/Visual/TestCaseContextMenu.cs rename to osu.Game.Tests/Visual/TestCaseContextMenu.cs diff --git a/osu.Game/Tests/Visual/TestCaseDialogOverlay.cs b/osu.Game.Tests/Visual/TestCaseDialogOverlay.cs similarity index 100% rename from osu.Game/Tests/Visual/TestCaseDialogOverlay.cs rename to osu.Game.Tests/Visual/TestCaseDialogOverlay.cs diff --git a/osu.Game/Tests/Visual/TestCaseDirect.cs b/osu.Game.Tests/Visual/TestCaseDirect.cs similarity index 100% rename from osu.Game/Tests/Visual/TestCaseDirect.cs rename to osu.Game.Tests/Visual/TestCaseDirect.cs diff --git a/osu.Game/Tests/Visual/TestCaseDrawableRoom.cs b/osu.Game.Tests/Visual/TestCaseDrawableRoom.cs similarity index 100% rename from osu.Game/Tests/Visual/TestCaseDrawableRoom.cs rename to osu.Game.Tests/Visual/TestCaseDrawableRoom.cs diff --git a/osu.Game/Tests/Visual/TestCaseDrawings.cs b/osu.Game.Tests/Visual/TestCaseDrawings.cs similarity index 100% rename from osu.Game/Tests/Visual/TestCaseDrawings.cs rename to osu.Game.Tests/Visual/TestCaseDrawings.cs diff --git a/osu.Game/Tests/Visual/TestCaseEditor.cs b/osu.Game.Tests/Visual/TestCaseEditor.cs similarity index 100% rename from osu.Game/Tests/Visual/TestCaseEditor.cs rename to osu.Game.Tests/Visual/TestCaseEditor.cs diff --git a/osu.Game/Tests/Visual/TestCaseEditorComposeTimeline.cs b/osu.Game.Tests/Visual/TestCaseEditorComposeTimeline.cs similarity index 100% rename from osu.Game/Tests/Visual/TestCaseEditorComposeTimeline.cs rename to osu.Game.Tests/Visual/TestCaseEditorComposeTimeline.cs diff --git a/osu.Game/Tests/Visual/TestCaseEditorMenuBar.cs b/osu.Game.Tests/Visual/TestCaseEditorMenuBar.cs similarity index 100% rename from osu.Game/Tests/Visual/TestCaseEditorMenuBar.cs rename to osu.Game.Tests/Visual/TestCaseEditorMenuBar.cs diff --git a/osu.Game/Tests/Visual/TestCaseEditorSummaryTimeline.cs b/osu.Game.Tests/Visual/TestCaseEditorSummaryTimeline.cs similarity index 100% rename from osu.Game/Tests/Visual/TestCaseEditorSummaryTimeline.cs rename to osu.Game.Tests/Visual/TestCaseEditorSummaryTimeline.cs diff --git a/osu.Game/Tests/Visual/TestCaseGamefield.cs b/osu.Game.Tests/Visual/TestCaseGamefield.cs similarity index 100% rename from osu.Game/Tests/Visual/TestCaseGamefield.cs rename to osu.Game.Tests/Visual/TestCaseGamefield.cs diff --git a/osu.Game/Tests/Visual/TestCaseGraph.cs b/osu.Game.Tests/Visual/TestCaseGraph.cs similarity index 100% rename from osu.Game/Tests/Visual/TestCaseGraph.cs rename to osu.Game.Tests/Visual/TestCaseGraph.cs diff --git a/osu.Game/Tests/Visual/TestCaseIconButton.cs b/osu.Game.Tests/Visual/TestCaseIconButton.cs similarity index 100% rename from osu.Game/Tests/Visual/TestCaseIconButton.cs rename to osu.Game.Tests/Visual/TestCaseIconButton.cs diff --git a/osu.Game/Tests/Visual/TestCaseKeyConfiguration.cs b/osu.Game.Tests/Visual/TestCaseKeyConfiguration.cs similarity index 100% rename from osu.Game/Tests/Visual/TestCaseKeyConfiguration.cs rename to osu.Game.Tests/Visual/TestCaseKeyConfiguration.cs diff --git a/osu.Game/Tests/Visual/TestCaseKeyCounter.cs b/osu.Game.Tests/Visual/TestCaseKeyCounter.cs similarity index 100% rename from osu.Game/Tests/Visual/TestCaseKeyCounter.cs rename to osu.Game.Tests/Visual/TestCaseKeyCounter.cs diff --git a/osu.Game/Tests/Visual/TestCaseLeaderboard.cs b/osu.Game.Tests/Visual/TestCaseLeaderboard.cs similarity index 100% rename from osu.Game/Tests/Visual/TestCaseLeaderboard.cs rename to osu.Game.Tests/Visual/TestCaseLeaderboard.cs diff --git a/osu.Game/Tests/Visual/TestCaseMedalOverlay.cs b/osu.Game.Tests/Visual/TestCaseMedalOverlay.cs similarity index 100% rename from osu.Game/Tests/Visual/TestCaseMedalOverlay.cs rename to osu.Game.Tests/Visual/TestCaseMedalOverlay.cs diff --git a/osu.Game/Tests/Visual/TestCaseMenuButtonSystem.cs b/osu.Game.Tests/Visual/TestCaseMenuButtonSystem.cs similarity index 100% rename from osu.Game/Tests/Visual/TestCaseMenuButtonSystem.cs rename to osu.Game.Tests/Visual/TestCaseMenuButtonSystem.cs diff --git a/osu.Game/Tests/Visual/TestCaseMenuOverlays.cs b/osu.Game.Tests/Visual/TestCaseMenuOverlays.cs similarity index 100% rename from osu.Game/Tests/Visual/TestCaseMenuOverlays.cs rename to osu.Game.Tests/Visual/TestCaseMenuOverlays.cs diff --git a/osu.Game/Tests/Visual/TestCaseMods.cs b/osu.Game.Tests/Visual/TestCaseMods.cs similarity index 100% rename from osu.Game/Tests/Visual/TestCaseMods.cs rename to osu.Game.Tests/Visual/TestCaseMods.cs diff --git a/osu.Game/Tests/Visual/TestCaseMusicController.cs b/osu.Game.Tests/Visual/TestCaseMusicController.cs similarity index 100% rename from osu.Game/Tests/Visual/TestCaseMusicController.cs rename to osu.Game.Tests/Visual/TestCaseMusicController.cs diff --git a/osu.Game/Tests/Visual/TestCaseNotificationOverlay.cs b/osu.Game.Tests/Visual/TestCaseNotificationOverlay.cs similarity index 100% rename from osu.Game/Tests/Visual/TestCaseNotificationOverlay.cs rename to osu.Game.Tests/Visual/TestCaseNotificationOverlay.cs diff --git a/osu.Game/Tests/Visual/TestCaseOnScreenDisplay.cs b/osu.Game.Tests/Visual/TestCaseOnScreenDisplay.cs similarity index 100% rename from osu.Game/Tests/Visual/TestCaseOnScreenDisplay.cs rename to osu.Game.Tests/Visual/TestCaseOnScreenDisplay.cs diff --git a/osu.Game/Tests/Visual/TestCasePlaySongSelect.cs b/osu.Game.Tests/Visual/TestCasePlaySongSelect.cs similarity index 93% rename from osu.Game/Tests/Visual/TestCasePlaySongSelect.cs rename to osu.Game.Tests/Visual/TestCasePlaySongSelect.cs index 965308c32c..a722974c07 100644 --- a/osu.Game/Tests/Visual/TestCasePlaySongSelect.cs +++ b/osu.Game.Tests/Visual/TestCasePlaySongSelect.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; using System.Linq; -using Microsoft.EntityFrameworkCore; using osu.Framework.Allocation; using osu.Framework.MathUtils; using osu.Game.Beatmaps; @@ -38,8 +37,7 @@ namespace osu.Game.Tests.Visual var storage = new TestStorage(@"TestCasePlaySongSelect"); // this is by no means clean. should be replacing inside of OsuGameBase somehow. - var context = new OsuDbContext(storage.GetDatabaseConnectionString(@"client")); - context.Database.Migrate(); + var context = new OsuDbContext(); Func contextFactory = () => context; diff --git a/osu.Game/Tests/Visual/TestCaseReplay.cs b/osu.Game.Tests/Visual/TestCaseReplay.cs similarity index 100% rename from osu.Game/Tests/Visual/TestCaseReplay.cs rename to osu.Game.Tests/Visual/TestCaseReplay.cs diff --git a/osu.Game/Tests/Visual/TestCaseReplaySettingsOverlay.cs b/osu.Game.Tests/Visual/TestCaseReplaySettingsOverlay.cs similarity index 100% rename from osu.Game/Tests/Visual/TestCaseReplaySettingsOverlay.cs rename to osu.Game.Tests/Visual/TestCaseReplaySettingsOverlay.cs diff --git a/osu.Game/Tests/Visual/TestCaseResults.cs b/osu.Game.Tests/Visual/TestCaseResults.cs similarity index 100% rename from osu.Game/Tests/Visual/TestCaseResults.cs rename to osu.Game.Tests/Visual/TestCaseResults.cs diff --git a/osu.Game/Tests/Visual/TestCaseRoomInspector.cs b/osu.Game.Tests/Visual/TestCaseRoomInspector.cs similarity index 100% rename from osu.Game/Tests/Visual/TestCaseRoomInspector.cs rename to osu.Game.Tests/Visual/TestCaseRoomInspector.cs diff --git a/osu.Game/Tests/Visual/TestCaseScoreCounter.cs b/osu.Game.Tests/Visual/TestCaseScoreCounter.cs similarity index 100% rename from osu.Game/Tests/Visual/TestCaseScoreCounter.cs rename to osu.Game.Tests/Visual/TestCaseScoreCounter.cs diff --git a/osu.Game/Tests/Visual/TestCaseScrollingPlayfield.cs b/osu.Game.Tests/Visual/TestCaseScrollingPlayfield.cs similarity index 100% rename from osu.Game/Tests/Visual/TestCaseScrollingPlayfield.cs rename to osu.Game.Tests/Visual/TestCaseScrollingPlayfield.cs diff --git a/osu.Game/Tests/Visual/TestCaseSettings.cs b/osu.Game.Tests/Visual/TestCaseSettings.cs similarity index 100% rename from osu.Game/Tests/Visual/TestCaseSettings.cs rename to osu.Game.Tests/Visual/TestCaseSettings.cs diff --git a/osu.Game/Tests/Visual/TestCaseSkipButton.cs b/osu.Game.Tests/Visual/TestCaseSkipButton.cs similarity index 100% rename from osu.Game/Tests/Visual/TestCaseSkipButton.cs rename to osu.Game.Tests/Visual/TestCaseSkipButton.cs diff --git a/osu.Game/Tests/Visual/TestCaseSocial.cs b/osu.Game.Tests/Visual/TestCaseSocial.cs similarity index 100% rename from osu.Game/Tests/Visual/TestCaseSocial.cs rename to osu.Game.Tests/Visual/TestCaseSocial.cs diff --git a/osu.Game/Tests/Visual/TestCaseSongProgress.cs b/osu.Game.Tests/Visual/TestCaseSongProgress.cs similarity index 100% rename from osu.Game/Tests/Visual/TestCaseSongProgress.cs rename to osu.Game.Tests/Visual/TestCaseSongProgress.cs diff --git a/osu.Game/Tests/Visual/TestCaseStoryboard.cs b/osu.Game.Tests/Visual/TestCaseStoryboard.cs similarity index 100% rename from osu.Game/Tests/Visual/TestCaseStoryboard.cs rename to osu.Game.Tests/Visual/TestCaseStoryboard.cs diff --git a/osu.Game/Tests/Visual/TestCaseTabControl.cs b/osu.Game.Tests/Visual/TestCaseTabControl.cs similarity index 100% rename from osu.Game/Tests/Visual/TestCaseTabControl.cs rename to osu.Game.Tests/Visual/TestCaseTabControl.cs diff --git a/osu.Game/Tests/Visual/TestCaseTextAwesome.cs b/osu.Game.Tests/Visual/TestCaseTextAwesome.cs similarity index 100% rename from osu.Game/Tests/Visual/TestCaseTextAwesome.cs rename to osu.Game.Tests/Visual/TestCaseTextAwesome.cs diff --git a/osu.Game/Tests/Visual/TestCaseTwoLayerButton.cs b/osu.Game.Tests/Visual/TestCaseTwoLayerButton.cs similarity index 100% rename from osu.Game/Tests/Visual/TestCaseTwoLayerButton.cs rename to osu.Game.Tests/Visual/TestCaseTwoLayerButton.cs diff --git a/osu.Game/Tests/Visual/TestCaseUserPanel.cs b/osu.Game.Tests/Visual/TestCaseUserPanel.cs similarity index 100% rename from osu.Game/Tests/Visual/TestCaseUserPanel.cs rename to osu.Game.Tests/Visual/TestCaseUserPanel.cs diff --git a/osu.Game/Tests/Visual/TestCaseUserProfile.cs b/osu.Game.Tests/Visual/TestCaseUserProfile.cs similarity index 100% rename from osu.Game/Tests/Visual/TestCaseUserProfile.cs rename to osu.Game.Tests/Visual/TestCaseUserProfile.cs diff --git a/osu.Game/Tests/Visual/TestCaseUserRanks.cs b/osu.Game.Tests/Visual/TestCaseUserRanks.cs similarity index 100% rename from osu.Game/Tests/Visual/TestCaseUserRanks.cs rename to osu.Game.Tests/Visual/TestCaseUserRanks.cs diff --git a/osu.Game/Tests/Visual/TestCaseWaveform.cs b/osu.Game.Tests/Visual/TestCaseWaveform.cs similarity index 100% rename from osu.Game/Tests/Visual/TestCaseWaveform.cs rename to osu.Game.Tests/Visual/TestCaseWaveform.cs diff --git a/osu.Game.Tests/osu.Game.Tests.csproj b/osu.Game.Tests/osu.Game.Tests.csproj index 51c1b03373..92bae9d789 100644 --- a/osu.Game.Tests/osu.Game.Tests.csproj +++ b/osu.Game.Tests/osu.Game.Tests.csproj @@ -90,6 +90,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/osu.Game/Database/OsuDbContext.cs b/osu.Game/Database/OsuDbContext.cs index c509093cf9..7824cf9712 100644 --- a/osu.Game/Database/OsuDbContext.cs +++ b/osu.Game/Database/OsuDbContext.cs @@ -40,6 +40,8 @@ namespace osu.Game.Database : this("DataSource=:memory:") { // required for tooling (see https://wildermuth.com/2017/07/06/Program-cs-in-ASP-NET-Core-2-0). + + Migrate(); } /// diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index b47a3263b7..c610a24e22 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -20,7 +20,7 @@ using osu.Game.Screens.Edit.Screens.Design; namespace osu.Game.Screens.Edit { - internal class Editor : OsuScreen + public class Editor : OsuScreen { protected override BackgroundScreen CreateBackground() => new BackgroundScreenCustom(@"Backgrounds/bg4"); diff --git a/osu.Game/Screens/Edit/Screens/Compose/Timeline/ScrollingTimelineContainer.cs b/osu.Game/Screens/Edit/Screens/Compose/Timeline/ScrollingTimelineContainer.cs index 47a77090b2..587853be59 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Timeline/ScrollingTimelineContainer.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Timeline/ScrollingTimelineContainer.cs @@ -12,7 +12,7 @@ using osu.Game.Graphics; namespace osu.Game.Screens.Edit.Screens.Compose.Timeline { - internal class ScrollingTimelineContainer : ScrollContainer + public class ScrollingTimelineContainer : ScrollContainer { public readonly Bindable HitObjectsVisible = new Bindable(); public readonly Bindable HitSoundsVisible = new Bindable(); diff --git a/osu.Game/Tests/Visual/TestCasePlayer.cs b/osu.Game/Tests/Visual/TestCasePlayer.cs index dfbdaf1d9d..5965be9717 100644 --- a/osu.Game/Tests/Visual/TestCasePlayer.cs +++ b/osu.Game/Tests/Visual/TestCasePlayer.cs @@ -17,7 +17,7 @@ using OpenTK.Graphics; namespace osu.Game.Tests.Visual { - public class TestCasePlayer : OsuTestCase + public abstract class TestCasePlayer : OsuTestCase { private readonly Type ruleset; @@ -34,7 +34,7 @@ namespace osu.Game.Tests.Visual this.ruleset = ruleset; } - public TestCasePlayer() + protected TestCasePlayer() { } diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index f02664c3d2..7b65aa8d66 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -768,55 +768,7 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -839,9 +791,7 @@ - - - - - - - - - - - - - - - - - \ No newline at end of file From 40f3cb5db7fd0d2e6e7fdbb78627247226874eb5 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 30 Oct 2017 22:39:25 +0900 Subject: [PATCH 0482/1263] Update framework --- osu-framework | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu-framework b/osu-framework index b45d4d1db1..ef10edfc75 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit b45d4d1db105b5955eff0e707128e10e209a40fe +Subproject commit ef10edfc750b39258edbff46019f1d10700548c2 From 98deb1f21543ac99a6d0247183f46446efc36e8d Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 30 Oct 2017 22:53:27 +0900 Subject: [PATCH 0483/1263] Fix up VisualTests build config --- osu.sln | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.sln b/osu.sln index b1341051f9..9898f05ba4 100644 --- a/osu.sln +++ b/osu.sln @@ -34,8 +34,8 @@ Global {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.Debug|Any CPU.Build.0 = Debug|Any CPU {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.Release|Any CPU.ActiveCfg = Release|Any CPU {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.Release|Any CPU.Build.0 = Release|Any CPU - {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.VisualTests|Any CPU.ActiveCfg = VisualTests|Any CPU - {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.VisualTests|Any CPU.Build.0 = VisualTests|Any CPU + {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.VisualTests|Any CPU.ActiveCfg = Debug|Any CPU + {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.VisualTests|Any CPU.Build.0 = Debug|Any CPU {C76BF5B3-985E-4D39-95FE-97C9C879B83A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {C76BF5B3-985E-4D39-95FE-97C9C879B83A}.Debug|Any CPU.Build.0 = Debug|Any CPU {C76BF5B3-985E-4D39-95FE-97C9C879B83A}.Release|Any CPU.ActiveCfg = Release|Any CPU From 9b1ec83eb4e49328017e401689b1efea41ee8517 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 31 Oct 2017 16:55:44 +0900 Subject: [PATCH 0484/1263] Propagate sqlite build assets to parent projects --- osu.Game/osu.Game.csproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 6967f140e8..635bd70bc2 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -38,8 +38,8 @@ - - + + \ No newline at end of file From 3462fdcad911fc3cbe42f3b700a2b834a359a933 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 31 Oct 2017 16:57:01 +0900 Subject: [PATCH 0485/1263] Remove some apparently unneeded references from osu.Game --- osu.Game/osu.Game.csproj | 4 ---- 1 file changed, 4 deletions(-) diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 635bd70bc2..bb9d3b0afd 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -16,10 +16,6 @@ - - - - osu.licenseheader From 8138796ee3f863ce1052cb1c8ccfd448981ccd2a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 1 Nov 2017 14:53:33 +0900 Subject: [PATCH 0486/1263] Fix VisualTests configuration being completely wrong --- osu.Game/osu.Game.csproj | 15 --------------- osu.sln | 17 ++++++++++------- 2 files changed, 10 insertions(+), 22 deletions(-) diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index a99e97eabb..db27c77188 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -83,21 +83,6 @@ - - true - bin\Debug\ - TRACE;DEBUG - true - 0 - true - full - AnyCPU - false - 6 - prompt - --tests - false - $(SolutionDir)\packages\DotNetZip.1.10.1\lib\net20\DotNetZip.dll diff --git a/osu.sln b/osu.sln index b1341051f9..e86dd70d0b 100644 --- a/osu.sln +++ b/osu.sln @@ -1,11 +1,11 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 14 -VisualStudioVersion = 14.0.25420.1 +# Visual Studio 15 +VisualStudioVersion = 15.0.27004.2006 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "osu.Game", "osu.Game\osu.Game.csproj", "{2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "osu.Framework", "osu-framework\osu.Framework\osu.Framework.csproj", "{C76BF5B3-985E-4D39-95FE-97C9C879B83A}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "osu.Framework", "osu-framework\osu.Framework\osu.Framework.csproj", "{C76BF5B3-985E-4D39-95FE-97C9C879B83A}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "osu.Game.Resources", "osu-resources\osu.Game.Resources\osu.Game.Resources.csproj", "{D9A367C9-4C1A-489F-9B05-A0CEA2B53B58}" EndProject @@ -34,8 +34,8 @@ Global {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.Debug|Any CPU.Build.0 = Debug|Any CPU {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.Release|Any CPU.ActiveCfg = Release|Any CPU {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.Release|Any CPU.Build.0 = Release|Any CPU - {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.VisualTests|Any CPU.ActiveCfg = VisualTests|Any CPU - {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.VisualTests|Any CPU.Build.0 = VisualTests|Any CPU + {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.VisualTests|Any CPU.ActiveCfg = Debug|Any CPU + {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.VisualTests|Any CPU.Build.0 = Debug|Any CPU {C76BF5B3-985E-4D39-95FE-97C9C879B83A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {C76BF5B3-985E-4D39-95FE-97C9C879B83A}.Debug|Any CPU.Build.0 = Debug|Any CPU {C76BF5B3-985E-4D39-95FE-97C9C879B83A}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -85,12 +85,15 @@ Global {419659FD-72EA-4678-9EB8-B22A746CED70}.Debug|Any CPU.Build.0 = Debug|Any CPU {419659FD-72EA-4678-9EB8-B22A746CED70}.Release|Any CPU.ActiveCfg = Release|Any CPU {419659FD-72EA-4678-9EB8-B22A746CED70}.Release|Any CPU.Build.0 = Release|Any CPU - {419659FD-72EA-4678-9EB8-B22A746CED70}.VisualTests|Any CPU.ActiveCfg = Debug|Any CPU - {419659FD-72EA-4678-9EB8-B22A746CED70}.VisualTests|Any CPU.Build.0 = Debug|Any CPU + {419659FD-72EA-4678-9EB8-B22A746CED70}.VisualTests|Any CPU.ActiveCfg = VisualTests|Any CPU + {419659FD-72EA-4678-9EB8-B22A746CED70}.VisualTests|Any CPU.Build.0 = VisualTests|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {671B0BEC-2403-45B0-9357-2C97CC517668} + EndGlobalSection GlobalSection(MonoDevelopProperties) = preSolution Policies = $0 $0.TextStylePolicy = $1 From cbf543de73f808c9e5c636a463cdab4fa6357b96 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 1 Nov 2017 15:31:38 +0900 Subject: [PATCH 0487/1263] Apply framework project format revert --- osu-framework | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu-framework b/osu-framework index ef10edfc75..715a8328a8 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit ef10edfc750b39258edbff46019f1d10700548c2 +Subproject commit 715a8328a80af072c31dbc807b3119b3c58df8c6 From bcc30fd9470b6dfc9151929dab0184c7fb4660ca Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 1 Nov 2017 16:03:46 +0900 Subject: [PATCH 0488/1263] Revert osu-resources --- osu-resources | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu-resources b/osu-resources index a4418111f8..1750ab8f67 160000 --- a/osu-resources +++ b/osu-resources @@ -1 +1 @@ -Subproject commit a4418111f8ed2350a6fd46fe69258884f0757745 +Subproject commit 1750ab8f6761ab35592fd46da71fbe0c141bfd93 From 15197b9a7650723180606a317a0f93649ae5a6d6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 1 Nov 2017 16:57:59 +0900 Subject: [PATCH 0489/1263] Use internal less Allows for more dynamic compilation to succeed. No reason for using internal here anyways. --- osu.Game/Screens/Edit/Editor.cs | 2 +- osu.Game/Screens/Loader.cs | 2 +- osu.Game/Screens/Menu/Disclaimer.cs | 6 +++--- osu.Game/Screens/Menu/Intro.cs | 4 ++-- osu.Game/Screens/Menu/MainMenu.cs | 2 +- osu.Game/Screens/OsuScreen.cs | 8 ++++---- osu.Game/Screens/Play/Player.cs | 6 +++--- osu.Game/Screens/Play/PlayerLoader.cs | 4 ++-- osu.Game/Screens/Ranking/Results.cs | 2 +- osu.Game/Screens/Tournament/Drawings.cs | 2 +- 10 files changed, 19 insertions(+), 19 deletions(-) diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index c610a24e22..74e55e58ad 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -24,7 +24,7 @@ namespace osu.Game.Screens.Edit { protected override BackgroundScreen CreateBackground() => new BackgroundScreenCustom(@"Backgrounds/bg4"); - internal override bool ShowOverlays => false; + public override bool ShowOverlays => false; private readonly Box bottomBackground; private readonly Container screenContainer; diff --git a/osu.Game/Screens/Loader.cs b/osu.Game/Screens/Loader.cs index af084e740b..295b3603be 100644 --- a/osu.Game/Screens/Loader.cs +++ b/osu.Game/Screens/Loader.cs @@ -8,7 +8,7 @@ namespace osu.Game.Screens { internal class Loader : OsuScreen { - internal override bool ShowOverlays => false; + public override bool ShowOverlays => false; public Loader() { diff --git a/osu.Game/Screens/Menu/Disclaimer.cs b/osu.Game/Screens/Menu/Disclaimer.cs index 1ac5823ec4..532ee71b72 100644 --- a/osu.Game/Screens/Menu/Disclaimer.cs +++ b/osu.Game/Screens/Menu/Disclaimer.cs @@ -12,15 +12,15 @@ using OpenTK.Graphics; namespace osu.Game.Screens.Menu { - internal class Disclaimer : OsuScreen + public class Disclaimer : OsuScreen { private Intro intro; private readonly SpriteIcon icon; private Color4 iconColour; - internal override bool ShowOverlays => false; + public override bool ShowOverlays => false; - internal override bool HasLocalCursorDisplayed => true; + public override bool HasLocalCursorDisplayed => true; public Disclaimer() { diff --git a/osu.Game/Screens/Menu/Intro.cs b/osu.Game/Screens/Menu/Intro.cs index 066391b11f..09958472e2 100644 --- a/osu.Game/Screens/Menu/Intro.cs +++ b/osu.Game/Screens/Menu/Intro.cs @@ -32,9 +32,9 @@ namespace osu.Game.Screens.Menu private SampleChannel welcome; private SampleChannel seeya; - internal override bool HasLocalCursorDisplayed => true; + public override bool HasLocalCursorDisplayed => true; - internal override bool ShowOverlays => false; + public override bool ShowOverlays => false; protected override BackgroundScreen CreateBackground() => new BackgroundScreenEmpty(); diff --git a/osu.Game/Screens/Menu/MainMenu.cs b/osu.Game/Screens/Menu/MainMenu.cs index 1c82d15f50..ff902bf28b 100644 --- a/osu.Game/Screens/Menu/MainMenu.cs +++ b/osu.Game/Screens/Menu/MainMenu.cs @@ -23,7 +23,7 @@ namespace osu.Game.Screens.Menu { private readonly ButtonSystem buttons; - internal override bool ShowOverlays => buttons.State != MenuState.Initial; + public override bool ShowOverlays => buttons.State != MenuState.Initial; private readonly BackgroundScreenDefault background; private Screen songSelect; diff --git a/osu.Game/Screens/OsuScreen.cs b/osu.Game/Screens/OsuScreen.cs index ae10d8828b..2a3cba0d49 100644 --- a/osu.Game/Screens/OsuScreen.cs +++ b/osu.Game/Screens/OsuScreen.cs @@ -16,7 +16,7 @@ namespace osu.Game.Screens { public abstract class OsuScreen : Screen { - internal BackgroundScreen Background { get; private set; } + public BackgroundScreen Background { get; private set; } /// /// Override to create a BackgroundMode for the current screen. @@ -24,17 +24,17 @@ namespace osu.Game.Screens /// protected virtual BackgroundScreen CreateBackground() => null; - internal virtual bool ShowOverlays => true; + public virtual bool ShowOverlays => true; protected new OsuGameBase Game => base.Game as OsuGameBase; - internal virtual bool HasLocalCursorDisplayed => false; + public virtual bool HasLocalCursorDisplayed => false; /// /// Whether the beatmap or ruleset should be allowed to be changed by the user or game. /// Used to mark exclusive areas where this is strongly prohibited, like gameplay. /// - internal virtual bool AllowBeatmapRulesetChange => true; + public virtual bool AllowBeatmapRulesetChange => true; protected readonly Bindable Beatmap = new Bindable(); diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 589f4b663a..3775b9c933 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -34,13 +34,13 @@ namespace osu.Game.Screens.Play { protected override BackgroundScreen CreateBackground() => new BackgroundScreenBeatmap(Beatmap); - internal override bool ShowOverlays => false; + public override bool ShowOverlays => false; - internal override bool HasLocalCursorDisplayed => !pauseContainer.IsPaused && !HasFailed && RulesetContainer.ProvidingUserCursor; + public override bool HasLocalCursorDisplayed => !pauseContainer.IsPaused && !HasFailed && RulesetContainer.ProvidingUserCursor; public Action RestartRequested; - internal override bool AllowBeatmapRulesetChange => false; + public override bool AllowBeatmapRulesetChange => false; public bool HasFailed { get; private set; } diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index a5248acbe4..71c2ec9a6d 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -24,9 +24,9 @@ namespace osu.Game.Screens.Play private BeatmapMetadataDisplay info; private bool showOverlays = true; - internal override bool ShowOverlays => showOverlays; + public override bool ShowOverlays => showOverlays; - internal override bool AllowBeatmapRulesetChange => false; + public override bool AllowBeatmapRulesetChange => false; protected override BackgroundScreen CreateBackground() => new BackgroundScreenBeatmap(Beatmap); diff --git a/osu.Game/Screens/Ranking/Results.cs b/osu.Game/Screens/Ranking/Results.cs index 60ad484673..8e27cb235c 100644 --- a/osu.Game/Screens/Ranking/Results.cs +++ b/osu.Game/Screens/Ranking/Results.cs @@ -31,7 +31,7 @@ namespace osu.Game.Screens.Ranking private ResultModeTabControl modeChangeButtons; - internal override bool AllowBeatmapRulesetChange => false; + public override bool AllowBeatmapRulesetChange => false; private Container currentPage; diff --git a/osu.Game/Screens/Tournament/Drawings.cs b/osu.Game/Screens/Tournament/Drawings.cs index 3d27552212..e540782fc1 100644 --- a/osu.Game/Screens/Tournament/Drawings.cs +++ b/osu.Game/Screens/Tournament/Drawings.cs @@ -29,7 +29,7 @@ namespace osu.Game.Screens.Tournament { private const string results_filename = "drawings_results.txt"; - internal override bool ShowOverlays => false; + public override bool ShowOverlays => false; protected override BackgroundScreen CreateBackground() => new BackgroundScreenDefault(); From 09e0bd7a7853ff4663896e5b66cbfb45e781da8c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 1 Nov 2017 16:58:12 +0900 Subject: [PATCH 0490/1263] Remove unused class file --- osu.Game/Tests/Visual/TestCaseIntro.cs | 42 -------------------------- 1 file changed, 42 deletions(-) delete mode 100644 osu.Game/Tests/Visual/TestCaseIntro.cs diff --git a/osu.Game/Tests/Visual/TestCaseIntro.cs b/osu.Game/Tests/Visual/TestCaseIntro.cs deleted file mode 100644 index d803caf2b0..0000000000 --- a/osu.Game/Tests/Visual/TestCaseIntro.cs +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) 2007-2017 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using OpenTK.Graphics; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; -using osu.Framework.Timing; -using osu.Game.Screens.Menu; - -namespace osu.Game.Tests.Visual -{ - internal class TestCaseIntro : OsuTestCase - { - public TestCaseIntro() - { - IntroSequence intro; - - var rateAdjustClock = new StopwatchClock(true); - var framedClock = new FramedClock(rateAdjustClock); - framedClock.ProcessFrame(); - - Add(new Container - { - RelativeSizeAxes = Axes.Both, - Clock = framedClock, - Children = new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = Color4.Black, - }, - intro = new IntroSequence(), - } - }); - - AddStep(@"Restart", intro.Restart); - AddSliderStep("Playback speed", 0.0, 2.0, 1, v => rateAdjustClock.Rate = v); - } - } -} From fd5bc6fe58e086f09cd4814664d624420361806d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 1 Nov 2017 17:06:55 +0900 Subject: [PATCH 0491/1263] Make ParallaxContainer public --- osu.Game/Graphics/Containers/ParallaxContainer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Graphics/Containers/ParallaxContainer.cs b/osu.Game/Graphics/Containers/ParallaxContainer.cs index 3e0ed4b059..362563507b 100644 --- a/osu.Game/Graphics/Containers/ParallaxContainer.cs +++ b/osu.Game/Graphics/Containers/ParallaxContainer.cs @@ -11,7 +11,7 @@ using osu.Framework.Configuration; namespace osu.Game.Graphics.Containers { - internal class ParallaxContainer : Container, IRequireHighFrequencyMousePosition + public class ParallaxContainer : Container, IRequireHighFrequencyMousePosition { public float ParallaxAmount = 0.02f; From 27156aeb9304cafb86534e01b10294724f671844 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 1 Nov 2017 17:07:03 +0900 Subject: [PATCH 0492/1263] Fix the shit --- osu.Game.Tests/Visual/TestCaseIntro.cs | 7 ++ osu.Game/Screens/Menu/IntroSequence.cs | 138 ++++++++++++------------- 2 files changed, 72 insertions(+), 73 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCaseIntro.cs b/osu.Game.Tests/Visual/TestCaseIntro.cs index 6d03705bf3..a2375a592e 100644 --- a/osu.Game.Tests/Visual/TestCaseIntro.cs +++ b/osu.Game.Tests/Visual/TestCaseIntro.cs @@ -1,6 +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 OpenTK.Graphics; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -12,6 +14,11 @@ namespace osu.Game.Tests.Visual { public class TestCaseIntro : OsuTestCase { + public override IReadOnlyList RequiredTypes => new[] + { + typeof(IntroSequence) + }; + public TestCaseIntro() { IntroSequence intro; diff --git a/osu.Game/Screens/Menu/IntroSequence.cs b/osu.Game/Screens/Menu/IntroSequence.cs index 963f069312..37c891a13a 100644 --- a/osu.Game/Screens/Menu/IntroSequence.cs +++ b/osu.Game/Screens/Menu/IntroSequence.cs @@ -15,53 +15,7 @@ namespace osu.Game.Screens.Menu public class IntroSequence : Container { //Size - private const int logo_size = 460; - - private const int small_ring_size = 40; - private const int medium_ring_size = 130; - private const int big_ring_size = 400; - - private static readonly Vector2 medium_ring_thickness = new Vector2(0.3f); - private static readonly Vector2 small_ring_thickness = new Vector2(0.6f); - private static readonly Vector2 big_ring_thickness = new Vector2(0.85f); - - private static readonly Vector2 bar_size = new Vector2(105, 1.5f); - - private const int colored_circle_size = 416; - - //Time - private const int full_animation_duration = 2950; - - private const int medium_ring_resize_duration = 360; - private const int medium_ring_fade_duration = 420; - - private const int small_ring_resize_duration = 250; - private const int small_ring_fade_duration = 650; - - private const int text_fade_duration = 700; - private const int text_spacing_transform_duration = 1500; - - private const int bar_animation_duration = 700; - private const int bar_resize_delay = 150; - - private const int big_ring_animation_start_delay = 2000; - private const int big_ring_resize_duration = 500; - private const int big_ring_foreground_resize_delay = 250; - private const int big_ring_fade_duration = 450; - - private const int background_animation_start_time = 2250; - private const int foreground_animation_start_time = 2300; - - private const int colored_circle_rotation_delay = 110; - private const int colored_circles_appear_delay = 80; - private const int purple_circle_animation_start_time = 2250; - - private const int logo_fade_duration = 300; - - //Position - private const int bar_start_offset = 80; - private const int bar_end_offset = 120; - private const int colored_circle_offset = 250; + private const int logo_size = 460; //todo: this should probably be 480 private readonly OsuSpriteText welcomeText; @@ -246,18 +200,51 @@ namespace osu.Game.Screens.Menu public void Start() { - mediumRing.ResizeTo(medium_ring_size, medium_ring_resize_duration, Easing.InExpo); + const int circle_size = 416; + + //Time + const int full_animation_duration = 2950; + + const int medium_ring_resize_duration = 360; + const int medium_ring_fade_duration = 420; + + const int small_ring_resize_duration = 250; + const int small_ring_fade_duration = 650; + + const int text_fade_duration = 700; + const int text_spacing_transform_duration = 1500; + + const int bar_animation_duration = 700; + const int bar_resize_delay = 150; + + const int big_ring_animation_start_delay = 2000; + const int big_ring_resize_duration = 500; + const int big_ring_foreground_resize_delay = 250; + const int big_ring_fade_duration = 450; + + const int background_animation_start_time = 2250; + const int foreground_animation_start_time = 2300; + + const int colored_circle_rotation_delay = 110; + const int colored_circles_appear_delay = 80; + const int purple_circle_animation_start_time = 2250; + + const int logo_fade_duration = 300; + + //Position + const int bar_end_offset = 120; + + mediumRing.ResizeTo(130, medium_ring_resize_duration, Easing.InExpo); using (BeginDelayedSequence(200, true)) { welcomeText.FadeIn(text_fade_duration); welcomeText.TransformSpacingTo(new Vector2(20, 0), text_spacing_transform_duration, Easing.Out); - smallRing.ResizeTo(small_ring_size, small_ring_resize_duration, Easing.InExpo); + smallRing.ResizeTo(40, small_ring_resize_duration, Easing.InExpo); smallRing.Foreground.Delay(small_ring_resize_duration).ResizeTo(1, small_ring_fade_duration, Easing.OutQuad); } - int duration = bar_animation_duration - bar_resize_delay; using (BeginDelayedSequence(medium_ring_resize_duration, true)) { mediumRing.Foreground.ResizeTo(1, medium_ring_fade_duration, Easing.OutQuad); @@ -265,7 +252,7 @@ namespace osu.Game.Screens.Menu foreach (var bar in barsContainer) { bar.FadeIn(); - bar.Delay(bar_resize_delay).ResizeWidthTo(0, duration, Easing.OutQuint); + bar.Delay(bar_resize_delay).ResizeWidthTo(0, bar_animation_duration - bar_resize_delay, Easing.OutQuint); } barTopLeft.MoveTo(new Vector2(-bar_end_offset, -bar_end_offset), bar_animation_duration, Easing.OutQuint); @@ -276,11 +263,11 @@ namespace osu.Game.Screens.Menu using (bigRing.BeginDelayedSequence(big_ring_animation_start_delay, true)) { - bigRing.ResizeTo(big_ring_size, big_ring_resize_duration, Easing.InOutQuint); + bigRing.ResizeTo(400, big_ring_resize_duration, Easing.InOutQuint); bigRing.Foreground.Delay(big_ring_foreground_resize_delay).ResizeTo(1, big_ring_fade_duration, Easing.OutExpo); } - duration = full_animation_duration - background_animation_start_time; + int duration = full_animation_duration - background_animation_start_time; using (backgroundFill.BeginDelayedSequence(background_animation_start_time)) { backgroundFill.ResizeHeightTo(1, duration, Easing.InOutQuart); @@ -297,30 +284,30 @@ namespace osu.Game.Screens.Menu duration = full_animation_duration - purple_circle_animation_start_time; using (BeginDelayedSequence(purple_circle_animation_start_time, true)) { - purpleCircle.MoveToY((colored_circle_size - 2) / 2.0f, duration, Easing.InOutQuad); + purpleCircle.MoveToY((circle_size - 2) / 2.0f, duration, Easing.InOutQuad); purpleCircle.Delay(colored_circle_rotation_delay).RotateTo(-180, duration - colored_circle_rotation_delay, Easing.OutQuad); - purpleCircle.ResizeTo(colored_circle_size - 2, duration, Easing.InOutQuad); + purpleCircle.ResizeTo(circle_size - 2, duration, Easing.InOutQuad); duration -= colored_circles_appear_delay; using (BeginDelayedSequence(colored_circles_appear_delay, true)) { - yellowCircle.MoveToY(-(colored_circle_size - 2) / 2.0f, duration, Easing.InOutQuad); + yellowCircle.MoveToY(-(circle_size - 2) / 2.0f, duration, Easing.InOutQuad); yellowCircle.Delay(colored_circle_rotation_delay).RotateTo(-180, duration - colored_circle_rotation_delay, Easing.OutQuad); - yellowCircle.ResizeTo(colored_circle_size - 2, duration, Easing.InOutQuad); + yellowCircle.ResizeTo(circle_size - 2, duration, Easing.InOutQuad); duration -= colored_circles_appear_delay; using (BeginDelayedSequence(colored_circles_appear_delay, true)) { - blueCircle.MoveToX(-(colored_circle_size - 2) / 2.0f, duration, Easing.InOutQuad); + blueCircle.MoveToX(-(circle_size - 2) / 2.0f, duration, Easing.InOutQuad); blueCircle.Delay(colored_circle_rotation_delay).RotateTo(-180, duration - colored_circle_rotation_delay, Easing.OutQuad); - blueCircle.ResizeTo(colored_circle_size - 2, duration, Easing.InOutQuad); + blueCircle.ResizeTo(circle_size - 2, duration, Easing.InOutQuad); duration -= colored_circles_appear_delay; using (BeginDelayedSequence(colored_circles_appear_delay, true)) { - pinkCircle.MoveToX(colored_circle_size / 2.0f, duration, Easing.InOutQuad); + pinkCircle.MoveToX(circle_size / 2.0f, duration, Easing.InOutQuad); pinkCircle.Delay(colored_circle_rotation_delay).RotateTo(-180, duration - colored_circle_rotation_delay, Easing.OutQuad); - pinkCircle.ResizeTo(colored_circle_size, duration, Easing.InOutQuad); + pinkCircle.ResizeTo(circle_size, duration, Easing.InOutQuad); } } } @@ -340,16 +327,19 @@ namespace osu.Game.Screens.Menu welcomeText.Alpha = 0; smallRing.Size = mediumRing.Size = bigRing.Size = Vector2.Zero; - mediumRing.Foreground.Size = Vector2.One - medium_ring_thickness; - smallRing.Foreground.Size = Vector2.One - small_ring_thickness; - bigRing.Foreground.Size = Vector2.One - big_ring_thickness; - barTopLeft.Size = barTopRight.Size = barBottomLeft.Size = barBottomRight.Size = bar_size; + mediumRing.Foreground.Size = Vector2.One - new Vector2(0.7f); + smallRing.Foreground.Size = Vector2.One - new Vector2(0.4f); + bigRing.Foreground.Size = Vector2.One - new Vector2(0.15f); + + barTopLeft.Size = barTopRight.Size = barBottomLeft.Size = barBottomRight.Size = new Vector2(105, 1.5f); barTopLeft.Alpha = barTopRight.Alpha = barBottomLeft.Alpha = barBottomRight.Alpha = 0; - barTopLeft.Position = new Vector2(-bar_start_offset, -bar_start_offset); - barTopRight.Position = new Vector2(bar_start_offset, -bar_start_offset); - barBottomLeft.Position = new Vector2(-bar_start_offset, bar_start_offset); - barBottomRight.Position = new Vector2(bar_start_offset, bar_start_offset); + + const int bar_offset = 80; + barTopLeft.Position = new Vector2(-bar_offset, -bar_offset); + barTopRight.Position = new Vector2(bar_offset, -bar_offset); + barBottomLeft.Position = new Vector2(-bar_offset, bar_offset); + barBottomRight.Position = new Vector2(bar_offset, bar_offset); backgroundFill.Rotation = foregroundFill.Rotation = 0; backgroundFill.Alpha = foregroundFill.Alpha = 1; @@ -357,10 +347,12 @@ namespace osu.Game.Screens.Menu yellowCircle.Size = purpleCircle.Size = blueCircle.Size = pinkCircle.Size = Vector2.Zero; yellowCircle.Rotation = purpleCircle.Rotation = blueCircle.Rotation = pinkCircle.Rotation = 0; - yellowCircle.Position = new Vector2(0, -colored_circle_offset); - purpleCircle.Position = new Vector2(0, colored_circle_offset); - blueCircle.Position = new Vector2(-colored_circle_offset, 0); - pinkCircle.Position = new Vector2(colored_circle_offset, 0); + + const int circle_offset = 250; + yellowCircle.Position = new Vector2(0, -circle_offset); + purpleCircle.Position = new Vector2(0, circle_offset); + blueCircle.Position = new Vector2(-circle_offset, 0); + pinkCircle.Position = new Vector2(circle_offset, 0); } public void Restart() From 6fa02ce9bbd0ec580cc98f029dab46d9683ef66a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 1 Nov 2017 16:57:59 +0900 Subject: [PATCH 0493/1263] Use internal less Allows for more dynamic compilation to succeed. No reason for using internal here anyways. --- osu.Game/Screens/Edit/Editor.cs | 2 +- osu.Game/Screens/Loader.cs | 2 +- osu.Game/Screens/Menu/Disclaimer.cs | 6 +++--- osu.Game/Screens/Menu/Intro.cs | 4 ++-- osu.Game/Screens/Menu/MainMenu.cs | 2 +- osu.Game/Screens/OsuScreen.cs | 8 ++++---- osu.Game/Screens/Play/Player.cs | 6 +++--- osu.Game/Screens/Play/PlayerLoader.cs | 4 ++-- osu.Game/Screens/Ranking/Results.cs | 2 +- osu.Game/Screens/Tournament/Drawings.cs | 2 +- 10 files changed, 19 insertions(+), 19 deletions(-) diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index c610a24e22..74e55e58ad 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -24,7 +24,7 @@ namespace osu.Game.Screens.Edit { protected override BackgroundScreen CreateBackground() => new BackgroundScreenCustom(@"Backgrounds/bg4"); - internal override bool ShowOverlays => false; + public override bool ShowOverlays => false; private readonly Box bottomBackground; private readonly Container screenContainer; diff --git a/osu.Game/Screens/Loader.cs b/osu.Game/Screens/Loader.cs index af084e740b..295b3603be 100644 --- a/osu.Game/Screens/Loader.cs +++ b/osu.Game/Screens/Loader.cs @@ -8,7 +8,7 @@ namespace osu.Game.Screens { internal class Loader : OsuScreen { - internal override bool ShowOverlays => false; + public override bool ShowOverlays => false; public Loader() { diff --git a/osu.Game/Screens/Menu/Disclaimer.cs b/osu.Game/Screens/Menu/Disclaimer.cs index 1ac5823ec4..532ee71b72 100644 --- a/osu.Game/Screens/Menu/Disclaimer.cs +++ b/osu.Game/Screens/Menu/Disclaimer.cs @@ -12,15 +12,15 @@ using OpenTK.Graphics; namespace osu.Game.Screens.Menu { - internal class Disclaimer : OsuScreen + public class Disclaimer : OsuScreen { private Intro intro; private readonly SpriteIcon icon; private Color4 iconColour; - internal override bool ShowOverlays => false; + public override bool ShowOverlays => false; - internal override bool HasLocalCursorDisplayed => true; + public override bool HasLocalCursorDisplayed => true; public Disclaimer() { diff --git a/osu.Game/Screens/Menu/Intro.cs b/osu.Game/Screens/Menu/Intro.cs index ee84cf2d30..fb06edb0b0 100644 --- a/osu.Game/Screens/Menu/Intro.cs +++ b/osu.Game/Screens/Menu/Intro.cs @@ -33,9 +33,9 @@ namespace osu.Game.Screens.Menu private SampleChannel welcome; private SampleChannel seeya; - internal override bool HasLocalCursorDisplayed => true; + public override bool HasLocalCursorDisplayed => true; - internal override bool ShowOverlays => false; + public override bool ShowOverlays => false; protected override BackgroundScreen CreateBackground() => new BackgroundScreenEmpty(); diff --git a/osu.Game/Screens/Menu/MainMenu.cs b/osu.Game/Screens/Menu/MainMenu.cs index 1c82d15f50..ff902bf28b 100644 --- a/osu.Game/Screens/Menu/MainMenu.cs +++ b/osu.Game/Screens/Menu/MainMenu.cs @@ -23,7 +23,7 @@ namespace osu.Game.Screens.Menu { private readonly ButtonSystem buttons; - internal override bool ShowOverlays => buttons.State != MenuState.Initial; + public override bool ShowOverlays => buttons.State != MenuState.Initial; private readonly BackgroundScreenDefault background; private Screen songSelect; diff --git a/osu.Game/Screens/OsuScreen.cs b/osu.Game/Screens/OsuScreen.cs index ae10d8828b..2a3cba0d49 100644 --- a/osu.Game/Screens/OsuScreen.cs +++ b/osu.Game/Screens/OsuScreen.cs @@ -16,7 +16,7 @@ namespace osu.Game.Screens { public abstract class OsuScreen : Screen { - internal BackgroundScreen Background { get; private set; } + public BackgroundScreen Background { get; private set; } /// /// Override to create a BackgroundMode for the current screen. @@ -24,17 +24,17 @@ namespace osu.Game.Screens /// protected virtual BackgroundScreen CreateBackground() => null; - internal virtual bool ShowOverlays => true; + public virtual bool ShowOverlays => true; protected new OsuGameBase Game => base.Game as OsuGameBase; - internal virtual bool HasLocalCursorDisplayed => false; + public virtual bool HasLocalCursorDisplayed => false; /// /// Whether the beatmap or ruleset should be allowed to be changed by the user or game. /// Used to mark exclusive areas where this is strongly prohibited, like gameplay. /// - internal virtual bool AllowBeatmapRulesetChange => true; + public virtual bool AllowBeatmapRulesetChange => true; protected readonly Bindable Beatmap = new Bindable(); diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 589f4b663a..3775b9c933 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -34,13 +34,13 @@ namespace osu.Game.Screens.Play { protected override BackgroundScreen CreateBackground() => new BackgroundScreenBeatmap(Beatmap); - internal override bool ShowOverlays => false; + public override bool ShowOverlays => false; - internal override bool HasLocalCursorDisplayed => !pauseContainer.IsPaused && !HasFailed && RulesetContainer.ProvidingUserCursor; + public override bool HasLocalCursorDisplayed => !pauseContainer.IsPaused && !HasFailed && RulesetContainer.ProvidingUserCursor; public Action RestartRequested; - internal override bool AllowBeatmapRulesetChange => false; + public override bool AllowBeatmapRulesetChange => false; public bool HasFailed { get; private set; } diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index a5248acbe4..71c2ec9a6d 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -24,9 +24,9 @@ namespace osu.Game.Screens.Play private BeatmapMetadataDisplay info; private bool showOverlays = true; - internal override bool ShowOverlays => showOverlays; + public override bool ShowOverlays => showOverlays; - internal override bool AllowBeatmapRulesetChange => false; + public override bool AllowBeatmapRulesetChange => false; protected override BackgroundScreen CreateBackground() => new BackgroundScreenBeatmap(Beatmap); diff --git a/osu.Game/Screens/Ranking/Results.cs b/osu.Game/Screens/Ranking/Results.cs index 60ad484673..8e27cb235c 100644 --- a/osu.Game/Screens/Ranking/Results.cs +++ b/osu.Game/Screens/Ranking/Results.cs @@ -31,7 +31,7 @@ namespace osu.Game.Screens.Ranking private ResultModeTabControl modeChangeButtons; - internal override bool AllowBeatmapRulesetChange => false; + public override bool AllowBeatmapRulesetChange => false; private Container currentPage; diff --git a/osu.Game/Screens/Tournament/Drawings.cs b/osu.Game/Screens/Tournament/Drawings.cs index 3d27552212..e540782fc1 100644 --- a/osu.Game/Screens/Tournament/Drawings.cs +++ b/osu.Game/Screens/Tournament/Drawings.cs @@ -29,7 +29,7 @@ namespace osu.Game.Screens.Tournament { private const string results_filename = "drawings_results.txt"; - internal override bool ShowOverlays => false; + public override bool ShowOverlays => false; protected override BackgroundScreen CreateBackground() => new BackgroundScreenDefault(); From ed89f039002d97f34522c868c7fac1b596d5d67b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 1 Nov 2017 17:06:55 +0900 Subject: [PATCH 0494/1263] Make ParallaxContainer public --- osu.Game/Graphics/Containers/ParallaxContainer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Graphics/Containers/ParallaxContainer.cs b/osu.Game/Graphics/Containers/ParallaxContainer.cs index 3e0ed4b059..362563507b 100644 --- a/osu.Game/Graphics/Containers/ParallaxContainer.cs +++ b/osu.Game/Graphics/Containers/ParallaxContainer.cs @@ -11,7 +11,7 @@ using osu.Framework.Configuration; namespace osu.Game.Graphics.Containers { - internal class ParallaxContainer : Container, IRequireHighFrequencyMousePosition + public class ParallaxContainer : Container, IRequireHighFrequencyMousePosition { public float ParallaxAmount = 0.02f; From f0c0e8c34c8039cfa4658ca77d125fb0400d7697 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 1 Nov 2017 17:34:36 +0900 Subject: [PATCH 0495/1263] Update framework --- osu-framework | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu-framework b/osu-framework index 715a8328a8..3c074a0981 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit 715a8328a80af072c31dbc807b3119b3c58df8c6 +Subproject commit 3c074a0981844fbaa9f2ecbf879c542f07e2b94d From beb9d621c428abbc5d2cfef498f49671139ef46e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 1 Nov 2017 23:36:52 +0900 Subject: [PATCH 0496/1263] Revert incorrectly changed GUID --- osu.sln | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.sln b/osu.sln index e86dd70d0b..356ec4cc7b 100644 --- a/osu.sln +++ b/osu.sln @@ -5,7 +5,7 @@ VisualStudioVersion = 15.0.27004.2006 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "osu.Game", "osu.Game\osu.Game.csproj", "{2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "osu.Framework", "osu-framework\osu.Framework\osu.Framework.csproj", "{C76BF5B3-985E-4D39-95FE-97C9C879B83A}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "osu.Framework", "osu-framework\osu.Framework\osu.Framework.csproj", "{C76BF5B3-985E-4D39-95FE-97C9C879B83A}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "osu.Game.Resources", "osu-resources\osu.Game.Resources\osu.Game.Resources.csproj", "{D9A367C9-4C1A-489F-9B05-A0CEA2B53B58}" EndProject From f219b7f9fb8fa980c2556245b59781a1eb64abc4 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 2 Nov 2017 19:31:30 +0900 Subject: [PATCH 0497/1263] Fix bonusScore being stored locally instead of incrementally changing --- osu.Game/Rulesets/Scoring/ScoreProcessor.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs index 5a54c679dd..ec5d47c7c7 100644 --- a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs +++ b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs @@ -174,6 +174,7 @@ namespace osu.Game.Rulesets.Scoring private double maxBaseScore; private double rollingMaxBaseScore; private double baseScore; + private double bonusScore; protected ScoreProcessor() { @@ -219,7 +220,6 @@ namespace osu.Game.Rulesets.Scoring protected virtual void OnNewJudgement(Judgement judgement) { - double bonusScore = 0; if (judgement.AffectsCombo) { @@ -271,6 +271,7 @@ namespace osu.Game.Rulesets.Scoring Hits = 0; baseScore = 0; rollingMaxBaseScore = 0; + bonusScore = 0; } } From 6883b3742ff1cc3eb4427194da84c4924829c47d Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 2 Nov 2017 20:23:28 +0900 Subject: [PATCH 0498/1263] Make initial DrawableOsuHitObject initial states not use transforms --- .../Objects/Drawables/DrawableHitCircle.cs | 20 +++++++++++-------- .../Objects/Drawables/DrawableOsuHitObject.cs | 5 +++-- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs index 3184b83202..ed0578d3a4 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs @@ -86,15 +86,19 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables { base.UpdateInitialState(); - // sane defaults - ring.Show(); - circle.Show(); - number.Show(); - glow.Show(); + // Hide() cannot be used here, because when rewinding, we need these to be the final values - ApproachCircle.Hide(); - ApproachCircle.ScaleTo(new Vector2(4)); - explode.Hide(); + ring.Alpha = 1; + circle.Alpha = 1; + number.Alpha = 1; + glow.Alpha = 1; + + ApproachCircle.Alpha = 0; + ApproachCircle.Scale = new Vector2(4); + explode.Alpha = 0; + flash.Alpha = 0; + + Scale = new Vector2(HitObject.Scale); } protected override void UpdatePreemptState() diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs index 9205f43a6d..7429f084c3 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs @@ -23,7 +23,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables protected sealed override void UpdateState(ArmedState state) { - FinishTransforms(); + ClearTransforms(true); using (BeginAbsoluteSequence(HitObject.StartTime - TIME_PREEMPT, true)) { @@ -38,7 +38,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables protected virtual void UpdateInitialState() { - Hide(); + // Hide() cannot be used here, because when rewinding, we need these to be the final values + Alpha = 0; } protected virtual void UpdatePreemptState() From b0785b2f09924b5ef6dd23c83b0f675034929cf1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 2 Nov 2017 19:41:11 +0900 Subject: [PATCH 0499/1263] Fix a possible horrendous endless auth loop --- osu.Game/Online/API/APIAccess.cs | 1 + osu.Game/Online/API/OAuth.cs | 3 +++ 2 files changed, 4 insertions(+) diff --git a/osu.Game/Online/API/APIAccess.cs b/osu.Game/Online/API/APIAccess.cs index 4e26b1b850..daf56657d2 100644 --- a/osu.Game/Online/API/APIAccess.cs +++ b/osu.Game/Online/API/APIAccess.cs @@ -118,6 +118,7 @@ namespace osu.Game.Online.API //NotificationOverlay.ShowMessage("Login failed!"); log.Add(@"Login failed!"); Password = null; + authentication.Clear(); continue; } diff --git a/osu.Game/Online/API/OAuth.cs b/osu.Game/Online/API/OAuth.cs index 2e00fe6f1b..ca38f72904 100644 --- a/osu.Game/Online/API/OAuth.cs +++ b/osu.Game/Online/API/OAuth.cs @@ -27,6 +27,9 @@ namespace osu.Game.Online.API internal bool AuthenticateWithLogin(string username, string password) { + if (string.IsNullOrEmpty(username)) return false; + if (string.IsNullOrEmpty(password)) return false; + using (var req = new AccessTokenRequestPassword(username, password) { Url = $@"{endpoint}/oauth/token", From b8b05fe8d277fafe6da7c0f5af55105553846716 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 1 Nov 2017 20:54:58 +0900 Subject: [PATCH 0500/1263] Make the osu! logo shared game-wide There should only ever be one osu! logo. It is now passed around between screens in a superfluous manner. --- osu.Game/Screens/Loader.cs | 14 ++++ osu.Game/Screens/Menu/ButtonSystem.cs | 116 ++++++++++++++++---------- osu.Game/Screens/Menu/Intro.cs | 75 ++++++++++------- osu.Game/Screens/Menu/MainMenu.cs | 26 +++++- osu.Game/Screens/Menu/OsuLogo.cs | 42 ++++++++-- osu.Game/Screens/OsuScreen.cs | 47 +++++++++++ osu.Game/Screens/Play/PlayerLoader.cs | 27 +++--- osu.Game/Screens/Select/Footer.cs | 13 --- osu.Game/Screens/Select/SongSelect.cs | 38 ++++++++- 9 files changed, 289 insertions(+), 109 deletions(-) diff --git a/osu.Game/Screens/Loader.cs b/osu.Game/Screens/Loader.cs index 295b3603be..6de53aeeb0 100644 --- a/osu.Game/Screens/Loader.cs +++ b/osu.Game/Screens/Loader.cs @@ -2,7 +2,9 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using osu.Framework.Allocation; +using osu.Framework.Graphics; using osu.Game.Screens.Menu; +using OpenTK; namespace osu.Game.Screens { @@ -15,6 +17,18 @@ namespace osu.Game.Screens ValidForResume = false; } + protected override void LogoSetup(OsuLogo logo, bool resuming) + { + base.LogoSetup(logo, resuming); + + logo.RelativePositionAxes = Axes.Both; + logo.Triangles = false; + logo.Position = new Vector2(0.9f); + logo.Scale = new Vector2(0.2f); + + logo.FadeInFromZero(5000, Easing.OutQuint); + } + [BackgroundDependencyLoader] private void load(OsuGame game) { diff --git a/osu.Game/Screens/Menu/ButtonSystem.cs b/osu.Game/Screens/Menu/ButtonSystem.cs index e4dbe00a80..9cd92f054f 100644 --- a/osu.Game/Screens/Menu/ButtonSystem.cs +++ b/osu.Game/Screens/Menu/ButtonSystem.cs @@ -39,12 +39,25 @@ namespace osu.Game.Screens.Menu //todo: make these non-internal somehow. internal const float BUTTON_AREA_HEIGHT = 100; + internal const float BUTTON_WIDTH = 140f; internal const float WEDGE_WIDTH = 20; - public const int EXIT_DELAY = 3000; + private OsuLogo logo; + + public void SetOsuLogo(OsuLogo logo) + { + this.logo = logo; + + if (this.logo != null) + { + this.logo.Action = onOsuLogo; + + // osuLogo.SizeForFlow relies on loading to be complete. + buttonFlow.Position = new Vector2(WEDGE_WIDTH * 2 - (BUTTON_WIDTH + this.logo.SizeForFlow / 4), 0); + } + } - private readonly OsuLogo osuLogo; private readonly Drawable iconFacade; private readonly Container buttonArea; private readonly Box buttonAreaBackground; @@ -99,12 +112,6 @@ namespace osu.Game.Screens.Menu } } }, - osuLogo = new OsuLogo - { - Action = onOsuLogo, - Origin = Anchor.Centre, - Anchor = Anchor.Centre, - } }; buttonsPlay.Add(new Button(@"solo", @"select-6", FontAwesome.fa_user, new Color4(102, 68, 204, 255), () => OnSolo?.Invoke(), WEDGE_WIDTH, Key.P)); @@ -127,14 +134,6 @@ namespace osu.Game.Screens.Menu sampleBack = audio.Sample.Get(@"Menu/select-4"); } - protected override void LoadComplete() - { - base.LoadComplete(); - - // osuLogo.SizeForFlow relies on loading to be complete. - buttonFlow.Position = new Vector2(WEDGE_WIDTH * 2 - (BUTTON_WIDTH + osuLogo.SizeForFlow / 4), 0); - } - protected override bool OnKeyDown(InputState state, KeyDownEventArgs args) { if (args.Repeat) return false; @@ -142,7 +141,7 @@ namespace osu.Game.Screens.Menu switch (args.Key) { case Key.Space: - osuLogo.TriggerOnClick(state); + logo.TriggerOnClick(state); return true; case Key.Escape: switch (State) @@ -215,24 +214,31 @@ namespace osu.Game.Screens.Menu backButton.ContractStyle = 0; settingsButton.ContractStyle = 0; - bool fromInitial = lastState == MenuState.Initial; - if (state == MenuState.TopLevel) buttonArea.FinishTransforms(true); - using (buttonArea.BeginDelayedSequence(fromInitial ? 150 : 0, true)) + using (buttonArea.BeginDelayedSequence(lastState == MenuState.Initial ? 150 : 0, true)) { switch (state) { case MenuState.Exit: case MenuState.Initial: + trackingPosition = false; + buttonAreaBackground.ScaleTo(Vector2.One, 500, Easing.Out); buttonArea.FadeOut(300); - osuLogo.Delay(150) - .Schedule(() => toolbar?.Hide()) - .ScaleTo(1, 800, Easing.OutExpo) - .MoveTo(Vector2.Zero, 800, Easing.OutExpo); + logo?.Delay(150) + .Schedule(() => + { + toolbar?.Hide(); + + logo.ClearTransforms(targetMember: nameof(Position)); + logo.RelativePositionAxes = Axes.Both; + + logo.MoveTo(new Vector2(0.5f), 800, Easing.OutExpo); + logo.ScaleTo(1, 800, Easing.OutExpo); + }); foreach (Button b in buttonsTopLevel) b.State = ButtonState.Contracted; @@ -240,27 +246,40 @@ namespace osu.Game.Screens.Menu foreach (Button b in buttonsPlay) b.State = ButtonState.Contracted; - if (state == MenuState.Exit) - { - osuLogo.RotateTo(20, EXIT_DELAY * 1.5f); - osuLogo.FadeOut(EXIT_DELAY); - } - else if (lastState == MenuState.TopLevel) + if (state != MenuState.Exit && lastState == MenuState.TopLevel) sampleBack?.Play(); break; case MenuState.TopLevel: buttonAreaBackground.ScaleTo(Vector2.One, 200, Easing.Out); - var sequence = osuLogo - .ScaleTo(0.5f, 200, Easing.In) - .MoveTo(buttonFlow.DrawPosition, 200, Easing.In); + logo.ClearTransforms(targetMember: nameof(Position)); + logo.RelativePositionAxes = Axes.None; - if (fromInitial && osuLogo.Scale.X > 0.5f) - sequence.OnComplete(o => - { - o.Impact(); - toolbar?.Show(); - }); + trackingPosition = true; + + switch (lastState) + { + case MenuState.Initial: + logo.ScaleTo(0.5f, 200, Easing.In); + + trackingPosition = false; + logo + .MoveTo(iconTrackingPosition, lastState == MenuState.EnteringMode ? 0 : 200, Easing.In) + .OnComplete(o => + { + trackingPosition = true; + + if (logo.Scale.X > 0.5f) + { + o.Impact(); + toolbar?.Show(); + } + }); + break; + default: + logo.ScaleTo(0.5f, 200, Easing.OutQuint); + break; + } buttonArea.FadeIn(300); @@ -280,6 +299,8 @@ namespace osu.Game.Screens.Menu case MenuState.EnteringMode: buttonAreaBackground.ScaleTo(new Vector2(2, 0), 300, Easing.InSine); + trackingPosition = true; + buttonsTopLevel.ForEach(b => b.ContractStyle = 1); buttonsPlay.ForEach(b => b.ContractStyle = 1); backButton.ContractStyle = 1; @@ -301,15 +322,26 @@ namespace osu.Game.Screens.Menu } } + private Vector2 iconTrackingPosition => logo.Parent.ToLocalSpace(iconFacade.ScreenSpaceDrawQuad.Centre); + + private bool trackingPosition; + + public void SetLogoTracking(bool value) => trackingPosition = value; + protected override void Update() { //if (OsuGame.IdleTime > 6000 && State != MenuState.Exit) // State = MenuState.Initial; - osuLogo.Interactive = Alpha > 0.2f; - - iconFacade.Width = osuLogo.SizeForFlow * 0.5f; base.Update(); + + if (logo != null) + { + if (trackingPosition) + logo.Position = iconTrackingPosition; + + iconFacade.Width = logo.SizeForFlow * 0.5f; + } } } diff --git a/osu.Game/Screens/Menu/Intro.cs b/osu.Game/Screens/Menu/Intro.cs index fb06edb0b0..8553f68b9a 100644 --- a/osu.Game/Screens/Menu/Intro.cs +++ b/osu.Game/Screens/Menu/Intro.cs @@ -14,14 +14,13 @@ using osu.Game.Beatmaps.IO; using osu.Game.Configuration; using osu.Game.Graphics.Containers; using osu.Game.Screens.Backgrounds; +using OpenTK; using OpenTK.Graphics; namespace osu.Game.Screens.Menu { public class Intro : OsuScreen { - private readonly OsuLogo logo; - private const string menu_music_beatmap_hash = "3c8b1fcc9434dbb29e2fb613d3b9eada9d7bb6c125ceb32396c3b53437280c83"; /// @@ -39,32 +38,10 @@ namespace osu.Game.Screens.Menu protected override BackgroundScreen CreateBackground() => new BackgroundScreenEmpty(); - public Intro() - { - Children = new Drawable[] - { - new ParallaxContainer - { - ParallaxAmount = 0.01f, - Children = new Drawable[] - { - logo = new OsuLogo - { - Alpha = 0, - Triangles = false, - Blending = BlendingMode.Additive, - Interactive = false, - Colour = Color4.DarkGray, - Ripple = false - } - } - } - }; - } - private Bindable menuVoice; private Bindable menuMusic; private Track track; + private readonly ParallaxContainer parallax; [BackgroundDependencyLoader] private void load(AudioManager audio, OsuConfigManager config, BeatmapManager beatmaps, Framework.Game game) @@ -121,14 +98,48 @@ namespace osu.Game.Screens.Menu { DidLoadMenu = true; Push(mainMenu); - }, 2300); - }, 600); + }, delay_step_one); + }, delay_step_two); + } - logo.ScaleTo(0.4f); - logo.FadeOut(); + private const double delay_step_one = 2300; + private const double delay_step_two = 600; - logo.ScaleTo(1, 4400, Easing.OutQuint); - logo.FadeIn(20000, Easing.OutQuint); + public const int EXIT_DELAY = 3000; + + protected override void LogoSetup(OsuLogo logo, bool resuming) + { + base.LogoSetup(logo, resuming); + + logo.RelativePositionAxes = Axes.Both; + + logo.Triangles = false; + logo.Colour = Color4.DarkGray; + logo.Ripple = false; + + const int quick_appear = 150; + + int initialMovementTime = logo.Alpha > 0.2f ? quick_appear : 0; + + logo.MoveTo(new Vector2(0.5f), initialMovementTime, Easing.OutQuint); + + if (!resuming) + { + logo.ScaleTo(0.4f); + logo.FadeOut(); + + logo.ScaleTo(1, delay_step_one + delay_step_two, Easing.OutQuint); + logo.FadeIn(delay_step_one + delay_step_two, Easing.OutQuint); + } + else + { + logo + .ScaleTo(1, initialMovementTime, Easing.OutQuint) + .FadeIn(quick_appear, Easing.OutQuint) + .Then() + .RotateTo(20, EXIT_DELAY * 1.5f) + .FadeOut(EXIT_DELAY); + } } protected override void OnSuspending(Screen next) @@ -148,7 +159,7 @@ namespace osu.Game.Screens.Menu if (!(last is MainMenu)) Content.FadeIn(300); - double fadeOutTime = 2000; + double fadeOutTime = EXIT_DELAY; //we also handle the exit transition. if (menuVoice) seeya.Play(); diff --git a/osu.Game/Screens/Menu/MainMenu.cs b/osu.Game/Screens/Menu/MainMenu.cs index ff902bf28b..77e45c4575 100644 --- a/osu.Game/Screens/Menu/MainMenu.cs +++ b/osu.Game/Screens/Menu/MainMenu.cs @@ -2,6 +2,7 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using OpenTK; +using OpenTK.Graphics; using OpenTK.Input; using osu.Framework.Allocation; using osu.Framework.Graphics; @@ -102,6 +103,29 @@ namespace osu.Game.Screens.Menu Beatmap.ValueChanged += beatmap_ValueChanged; } + protected override void LogoSetup(OsuLogo logo, bool resuming) + { + base.LogoSetup(logo, resuming); + + buttons.SetOsuLogo(logo); + + logo.Triangles = true; + logo.Ripple = false; + + logo.FadeColour(Color4.White, 100, Easing.OutQuint); + logo.FadeIn(100, Easing.OutQuint); + + if (resuming) + buttons.State = MenuState.TopLevel; + } + + protected override void LogoOnSuspending(OsuLogo logo) + { + logo.FadeOut(300, Easing.InSine) + .ScaleTo(0.2f, 300, Easing.InSine) + .OnComplete(l => buttons.SetOsuLogo(null)); + } + private void beatmap_ValueChanged(WorkingBeatmap newValue) { if (!IsCurrentScreen) @@ -135,8 +159,6 @@ namespace osu.Game.Screens.Menu const float length = 300; - buttons.State = MenuState.TopLevel; - Content.FadeIn(length, Easing.OutQuint); Content.MoveTo(new Vector2(0, 0), length, Easing.OutQuint); diff --git a/osu.Game/Screens/Menu/OsuLogo.cs b/osu.Game/Screens/Menu/OsuLogo.cs index 6f4a46b10b..297076a78b 100644 --- a/osu.Game/Screens/Menu/OsuLogo.cs +++ b/osu.Game/Screens/Menu/OsuLogo.cs @@ -29,6 +29,8 @@ namespace osu.Game.Screens.Menu { public readonly Color4 OsuPink = OsuColour.FromHex(@"e967a1"); + private const double transition_length = 300; + private readonly Sprite logo; private readonly CircularContainer logoContainer; private readonly Container logoBounceContainer; @@ -54,7 +56,7 @@ namespace osu.Game.Screens.Menu public bool Triangles { - set { colourAndTriangles.Alpha = value ? 1 : 0; } + set { colourAndTriangles.FadeTo(value ? 1 : 0, transition_length, Easing.OutQuint); } } public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => logoContainer.ReceiveMouseInputAt(screenSpacePos); @@ -62,10 +64,9 @@ namespace osu.Game.Screens.Menu public bool Ripple { get { return rippleContainer.Alpha > 0; } - set { rippleContainer.Alpha = value ? 1 : 0; } + set { rippleContainer.FadeTo(value ? 1 : 0, transition_length, Easing.OutQuint); } } - public bool Interactive = true; private readonly Box flashLayer; private readonly Container impactContainer; @@ -76,11 +77,12 @@ namespace osu.Game.Screens.Menu public OsuLogo() { + AlwaysPresent = true; + EarlyActivationMilliseconds = early_activation; Size = new Vector2(default_size); - Anchor = Anchor.Centre; Origin = Anchor.Centre; AutoSizeAxes = Axes.Both; @@ -222,6 +224,27 @@ namespace osu.Game.Screens.Menu ripple.Texture = textures.Get(@"Menu/logo"); } + private double? reservationEndTime; + private Action reservationCallback; + + private bool canFulfillReservation => !reservationEndTime.HasValue || reservationEndTime <= Time.Current; + + public void RequestUsage(Action callback) + { + reservationCallback = callback; + } + + private void fulfillReservation() + { + reservationCallback(this); + reservationCallback = null; + } + + public void ReserveFor(float duration) + { + reservationEndTime = Time.Current + duration; + } + private int lastBeatIndex; protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, TrackAmplitudes amplitudes) @@ -288,11 +311,16 @@ namespace osu.Game.Screens.Menu { triangles.Velocity = paused_velocity; } + + if (reservationCallback != null && canFulfillReservation) + fulfillReservation(); } + private bool interactive => Action != null && Alpha > 0.2f; + protected override bool OnMouseDown(InputState state, MouseDownEventArgs args) { - if (!Interactive) return false; + if (!interactive) return false; logoBounceContainer.ScaleTo(0.9f, 1000, Easing.Out); return true; @@ -306,7 +334,7 @@ namespace osu.Game.Screens.Menu protected override bool OnClick(InputState state) { - if (!Interactive) return false; + if (!interactive) return false; sampleClick.Play(); @@ -320,7 +348,7 @@ namespace osu.Game.Screens.Menu protected override bool OnHover(InputState state) { - if (!Interactive) return false; + if (!interactive) return false; logoHoverContainer.ScaleTo(1.1f, 500, Easing.OutElastic); return true; diff --git a/osu.Game/Screens/OsuScreen.cs b/osu.Game/Screens/OsuScreen.cs index 2a3cba0d49..412fe02d30 100644 --- a/osu.Game/Screens/OsuScreen.cs +++ b/osu.Game/Screens/OsuScreen.cs @@ -10,7 +10,9 @@ using osu.Game.Graphics.Containers; using OpenTK; using osu.Framework.Audio.Sample; using osu.Framework.Audio; +using osu.Framework.Graphics; using osu.Game.Rulesets; +using osu.Game.Screens.Menu; namespace osu.Game.Screens { @@ -30,6 +32,8 @@ namespace osu.Game.Screens public virtual bool HasLocalCursorDisplayed => false; + private OsuLogo logo; + /// /// Whether the beatmap or ruleset should be allowed to be changed by the user or game. /// Used to mark exclusive areas where this is strongly prohibited, like gameplay. @@ -72,9 +76,16 @@ namespace osu.Game.Screens protected override void OnResuming(Screen last) { base.OnResuming(last); + logo.WaitForTransforms().Schedule(() => logoSetup(true)); sampleExit?.Play(); } + protected override void OnSuspending(Screen next) + { + base.OnSuspending(next); + logoOnSuspending(); + } + protected override void OnEntering(Screen last) { OsuScreen lastOsu = last as OsuScreen; @@ -106,11 +117,19 @@ namespace osu.Game.Screens }); } + if ((logo = lastOsu?.logo) == null) + AddInternal(logo = new OsuLogo()); + base.OnEntering(last); + + logo.WaitForTransforms().Schedule(() => logoSetup(false)); } protected override bool OnExiting(Screen next) { + if (ValidForResume && logo != null) + logoOnExiting(); + OsuScreen nextOsu = next as OsuScreen; if (Background != null && !Background.Equals(nextOsu?.Background)) @@ -128,5 +147,33 @@ namespace osu.Game.Screens Beatmap.UnbindAll(); return false; } + + private void logoSetup(bool resuming) => LogoSetup(logo, resuming); + + protected virtual void LogoSetup(OsuLogo logo, bool resuming) + { + logo.Action = null; + logo.FadeOut(300, Easing.OutQuint); + } + + private void logoOnExiting() + { + logo.ClearTransforms(); + LogoOnExiting(logo); + } + + protected virtual void LogoOnExiting(OsuLogo logo) + { + } + + private void logoOnSuspending() + { + logo.ClearTransforms(); + LogoOnSuspending(logo); + } + + protected virtual void LogoOnSuspending(OsuLogo logo) + { + } } } diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index 71c2ec9a6d..054b4c0a0f 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -10,9 +10,9 @@ using osu.Game.Beatmaps; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Screens.Backgrounds; -using osu.Game.Screens.Menu; using OpenTK; using osu.Framework.Localisation; +using osu.Game.Screens.Menu; namespace osu.Game.Screens.Play { @@ -20,7 +20,6 @@ namespace osu.Game.Screens.Play { private Player player; - private readonly OsuLogo logo; private BeatmapMetadataDisplay info; private bool showOverlays = true; @@ -39,15 +38,6 @@ namespace osu.Game.Screens.Play showOverlays = false; ValidForResume = true; }; - - Children = new Drawable[] - { - logo = new OsuLogo - { - Scale = new Vector2(0.15f), - Interactive = false, - }, - }; } [BackgroundDependencyLoader] @@ -101,11 +91,24 @@ namespace osu.Game.Screens.Play contentIn(); - logo.Delay(500).MoveToOffset(new Vector2(0, -180), 500, Easing.InOutExpo); info.Delay(750).FadeIn(500); this.Delay(2150).Schedule(pushWhenLoaded); } + protected override void LogoSetup(OsuLogo logo, bool resuming) + { + base.LogoSetup(logo, resuming); + + logo.ClearTransforms(targetMember: nameof(Position)); + logo.RelativePositionAxes = Axes.Both; + + logo.ScaleTo(new Vector2(0.15f), 300, Easing.In); + logo.MoveTo(new Vector2(0.5f), 300, Easing.In); + logo.FadeIn(); + + logo.Delay(500).MoveToOffset(new Vector2(0, -0.24f), 500, Easing.InOutExpo); + } + private void pushWhenLoaded() { if (player.LoadState != LoadState.Ready) diff --git a/osu.Game/Screens/Select/Footer.cs b/osu.Game/Screens/Select/Footer.cs index 00f311e522..40c3cf0fd4 100644 --- a/osu.Game/Screens/Select/Footer.cs +++ b/osu.Game/Screens/Select/Footer.cs @@ -13,7 +13,6 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Input; using osu.Game.Graphics.UserInterface; -using osu.Game.Screens.Menu; namespace osu.Game.Screens.Select { @@ -31,12 +30,9 @@ namespace osu.Game.Screens.Select private const float padding = 80; public Action OnBack; - public Action OnStart; private readonly FillFlowContainer buttons; - public OsuLogo StartButton; - /// Text on the button. /// Colour of the button. /// Hotkey of the button. @@ -106,13 +102,6 @@ namespace osu.Game.Screens.Select Height = 3, Position = new Vector2(0, -3), }, - StartButton = new OsuLogo - { - Anchor = Anchor.BottomRight, - Scale = new Vector2(0.4f), - Position = new Vector2(-70, -25), - Action = () => OnStart?.Invoke() - }, new BackButton { Anchor = Anchor.BottomLeft, @@ -143,8 +132,6 @@ namespace osu.Game.Screens.Select updateModeLight(); } - public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => base.ReceiveMouseInputAt(screenSpacePos) || StartButton.ReceiveMouseInputAt(screenSpacePos); - protected override bool OnMouseDown(InputState state, MouseDownEventArgs args) => true; protected override bool OnClick(InputState state) => true; diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index e11eed7040..f9e3b0902d 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -20,6 +20,7 @@ using osu.Game.Graphics.Containers; using osu.Game.Overlays; using osu.Game.Screens.Backgrounds; using osu.Game.Screens.Edit; +using osu.Game.Screens.Menu; using osu.Game.Screens.Select.Options; namespace osu.Game.Screens.Select @@ -153,7 +154,6 @@ namespace osu.Game.Screens.Select Add(Footer = new Footer { OnBack = Exit, - OnStart = () => carouselRaisedStart(), }); FooterPanels.Add(BeatmapOptions = new BeatmapOptionsOverlay()); @@ -309,6 +309,41 @@ namespace osu.Game.Screens.Select FilterControl.Activate(); } + private const double logo_transition = 250; + + protected override void LogoSetup(OsuLogo logo, bool resuming) + { + base.LogoSetup(logo, resuming); + + logo.ClearTransforms(); + logo.RelativePositionAxes = Axes.Both; + + Vector2 position = new Vector2(0.95f, 0.96f); + + if (logo.Alpha > 0.8f) + { + logo.MoveTo(position, 500, Easing.OutQuint); + } + else + { + logo.Hide(); + logo.ScaleTo(0.2f); + logo.MoveTo(position); + } + + logo.FadeIn(logo_transition, Easing.OutQuint); + logo.ScaleTo(0.4f, logo_transition, Easing.OutQuint); + + logo.Action = () => carouselRaisedStart(); + } + + protected override void LogoOnExiting(OsuLogo logo) + { + base.LogoOnExiting(logo); + logo.ScaleTo(0.2f, logo_transition, Easing.OutQuint); + logo.FadeOut(logo_transition, Easing.OutQuint); + } + private void beatmap_ValueChanged(WorkingBeatmap beatmap) { if (!IsCurrentScreen) return; @@ -350,6 +385,7 @@ namespace osu.Game.Screens.Select Content.FadeOut(100); FilterControl.Deactivate(); + return base.OnExiting(next); } From fe00ac7e4136d125c97e99ce3c17a128a7c57d47 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 2 Nov 2017 21:21:07 +0900 Subject: [PATCH 0501/1263] Make DrawableHitObject/ScoreProcessor support rewinding --- .../Objects/Drawables/DrawableHoldNoteTick.cs | 2 +- .../Tests/TestCaseHitObjects.cs | 2 +- .../Objects/Drawables/DrawableHit.cs | 2 +- .../Rulesets/Judgements/DrawableJudgement.cs | 2 +- osu.Game/Rulesets/Judgements/Judgement.cs | 13 +++ .../Objects/Drawables/DrawableHitObject.cs | 87 +++++++++++-------- osu.Game/Rulesets/Scoring/ScoreProcessor.cs | 39 ++++++++- osu.Game/Rulesets/UI/RulesetContainer.cs | 3 + 8 files changed, 107 insertions(+), 43 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNoteTick.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNoteTick.cs index 324f4e4e99..557fbf6ea8 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNoteTick.cs +++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNoteTick.cs @@ -94,7 +94,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables protected override void UpdateState(ArmedState state) { - switch (State) + switch (State.Value) { case ArmedState.Hit: AccentColour = Color4.Green; diff --git a/osu.Game.Rulesets.Osu/Tests/TestCaseHitObjects.cs b/osu.Game.Rulesets.Osu/Tests/TestCaseHitObjects.cs index 2ac15c55a7..99526b64ee 100644 --- a/osu.Game.Rulesets.Osu/Tests/TestCaseHitObjects.cs +++ b/osu.Game.Rulesets.Osu/Tests/TestCaseHitObjects.cs @@ -111,7 +111,7 @@ namespace osu.Game.Rulesets.Osu.Tests h.Depth = depth++; if (auto) - h.State = ArmedState.Hit; + h.State.Value = ArmedState.Hit; playfieldContainer.Add(h); var proxyable = h as IDrawableHitObjectWithProxiedApproach; diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs index 55eaa8dbb8..6c14a71a4c 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs @@ -72,7 +72,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables var offset = !AllJudged ? 0 : Time.Current - HitObject.StartTime; using (BeginDelayedSequence(HitObject.StartTime - Time.Current + offset, true)) { - switch (State) + switch (State.Value) { case ArmedState.Idle: this.Delay(HitObject.HitWindowMiss).Expire(); diff --git a/osu.Game/Rulesets/Judgements/DrawableJudgement.cs b/osu.Game/Rulesets/Judgements/DrawableJudgement.cs index 12edfd802a..5ab4b7636b 100644 --- a/osu.Game/Rulesets/Judgements/DrawableJudgement.cs +++ b/osu.Game/Rulesets/Judgements/DrawableJudgement.cs @@ -83,7 +83,7 @@ namespace osu.Game.Rulesets.Judgements break; } - Expire(); + Expire(true); } } } diff --git a/osu.Game/Rulesets/Judgements/Judgement.cs b/osu.Game/Rulesets/Judgements/Judgement.cs index 0ae33272a7..a1920097d3 100644 --- a/osu.Game/Rulesets/Judgements/Judgement.cs +++ b/osu.Game/Rulesets/Judgements/Judgement.cs @@ -17,6 +17,19 @@ namespace osu.Game.Rulesets.Judgements /// public virtual HitResult MaxResult => HitResult.Perfect; + /// + /// The combo prior to this judgement occurring. + /// + internal int ComboAtJudgement { get; set; } + + /// + /// The highest combo achieved prior to this judgement occurring. + /// + internal int HighestComboAtJudgement { get; set; } + + /// + /// Whether a successful hit occurred. + /// public bool IsHit => Result > HitResult.Miss; /// diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index bcd6734af6..9b4f7e7fc7 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -13,6 +13,7 @@ using OpenTK.Graphics; using osu.Game.Audio; using System.Linq; using osu.Game.Graphics; +using osu.Framework.Configuration; namespace osu.Game.Rulesets.Objects.Drawables { @@ -30,6 +31,9 @@ namespace osu.Game.Rulesets.Objects.Drawables /// public virtual bool DisplayJudgement => true; + public override bool RemoveCompletedTransforms => false; + public override bool RemoveWhenNotAlive => false; + protected DrawableHitObject(HitObject hitObject) { HitObject = hitObject; @@ -40,6 +44,7 @@ namespace osu.Game.Rulesets.Objects.Drawables where TObject : HitObject { public event Action OnJudgement; + public event Action OnJudgementRemoved; public new readonly TObject HitObject; @@ -56,31 +61,42 @@ namespace osu.Game.Rulesets.Objects.Drawables protected List Samples = new List(); + public readonly Bindable State = new Bindable(); + protected DrawableHitObject(TObject hitObject) : base(hitObject) { HitObject = hitObject; } - private ArmedState state; - public ArmedState State + [BackgroundDependencyLoader] + private void load(AudioManager audio) { - get { return state; } - - set + foreach (SampleInfo sample in HitObject.Samples) { - if (state == value) - return; - state = value; + SampleChannel channel = audio.Sample.Get($@"Gameplay/{sample.Bank}-{sample.Name}"); - if (!IsLoaded) - return; + if (channel == null) + continue; + channel.Volume.Value = sample.Volume; + Samples.Add(channel); + } + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + State.ValueChanged += state => + { UpdateState(state); if (State == ArmedState.Hit) PlaySamples(); - } + }; + + State.TriggerChange(); } protected void PlaySamples() @@ -88,16 +104,8 @@ namespace osu.Game.Rulesets.Objects.Drawables Samples.ForEach(s => s?.Play()); } - protected override void LoadComplete() - { - base.LoadComplete(); - - //force application of the state that was set before we loaded. - UpdateState(State); - } - - private bool hasJudgementResult; private bool judgementOccurred; + private bool hasJudgementResult => Judgements.LastOrDefault()?.Result >= HitResult.Miss; /// /// Whether this and all of its nested s have been judged. @@ -110,7 +118,6 @@ namespace osu.Game.Rulesets.Objects.Drawables /// The . protected void AddJudgement(Judgement judgement) { - hasJudgementResult = judgement.Result >= HitResult.Miss; judgementOccurred = true; // Ensure that the judgement is given a valid time offset, because this may not get set by the caller @@ -124,10 +131,10 @@ namespace osu.Game.Rulesets.Objects.Drawables case HitResult.None: break; case HitResult.Miss: - State = ArmedState.Miss; + State.Value = ArmedState.Miss; break; default: - State = ArmedState.Hit; + State.Value = ArmedState.Hit; break; } @@ -170,6 +177,25 @@ namespace osu.Game.Rulesets.Objects.Drawables /// implies that this check occurred after the end time of . protected virtual void CheckForJudgements(bool userTriggered, double timeOffset) { } + protected override void Update() + { + base.Update(); + + var endTime = (HitObject as IHasEndTime)?.EndTime ?? HitObject.StartTime; + + while (judgements.Count > 0) + { + var lastJudgement = judgements[judgements.Count - 1]; + if (lastJudgement.TimeOffset + endTime <= Time.Current) + break; + + judgements.RemoveAt(judgements.Count - 1); + State.Value = ArmedState.Idle; + + OnJudgementRemoved?.Invoke(this, lastJudgement); + } + } + protected override void UpdateAfterChildren() { base.UpdateAfterChildren(); @@ -177,21 +203,6 @@ namespace osu.Game.Rulesets.Objects.Drawables UpdateJudgement(false); } - [BackgroundDependencyLoader] - private void load(AudioManager audio) - { - foreach (SampleInfo sample in HitObject.Samples) - { - SampleChannel channel = audio.Sample.Get($@"Gameplay/{sample.Bank}-{sample.Name}"); - - if (channel == null) - continue; - - channel.Volume.Value = sample.Volume; - Samples.Add(channel); - } - } - private List> nestedHitObjects; protected IEnumerable> NestedHitObjects => nestedHitObjects; diff --git a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs index ec5d47c7c7..4dd88600b2 100644 --- a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs +++ b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs @@ -185,6 +185,7 @@ namespace osu.Game.Rulesets.Scoring Debug.Assert(base_portion + combo_portion == 1.0); rulesetContainer.OnJudgement += AddJudgement; + rulesetContainer.OnJudgementRemoved += RemoveJudgement; SimulateAutoplay(rulesetContainer.Beatmap); Reset(true); @@ -213,13 +214,26 @@ namespace osu.Game.Rulesets.Scoring protected void AddJudgement(Judgement judgement) { OnNewJudgement(judgement); - NotifyNewJudgement(judgement); + updateScore(); + NotifyNewJudgement(judgement); UpdateFailed(); } + protected void RemoveJudgement(Judgement judgement) + { + OnJudgementRemoved(judgement); + updateScore(); + } + + /// + /// Applies a judgement. + /// + /// The judgement to apply/ protected virtual void OnNewJudgement(Judgement judgement) { + judgement.ComboAtJudgement = Combo; + judgement.HighestComboAtJudgement = HighestCombo; if (judgement.AffectsCombo) { @@ -242,7 +256,30 @@ namespace osu.Game.Rulesets.Scoring } else if (judgement.IsHit) bonusScore += judgement.NumericResult; + } + /// + /// Removes a judgement. This should reverse everything in . + /// + /// The judgement to remove. + protected virtual void OnJudgementRemoved(Judgement judgement) + { + Combo.Value = judgement.ComboAtJudgement; + HighestCombo.Value = judgement.HighestComboAtJudgement; + + if (judgement.AffectsCombo) + { + baseScore -= judgement.NumericResult; + rollingMaxBaseScore -= judgement.MaxNumericResult; + + Hits--; + } + else if (judgement.IsHit) + bonusScore -= judgement.NumericResult; + } + + private void updateScore() + { if (rollingMaxBaseScore != 0) Accuracy.Value = baseScore / rollingMaxBaseScore; diff --git a/osu.Game/Rulesets/UI/RulesetContainer.cs b/osu.Game/Rulesets/UI/RulesetContainer.cs index 6f53b76031..36dce7218d 100644 --- a/osu.Game/Rulesets/UI/RulesetContainer.cs +++ b/osu.Game/Rulesets/UI/RulesetContainer.cs @@ -104,6 +104,7 @@ namespace osu.Game.Rulesets.UI where TObject : HitObject { public event Action OnJudgement; + public event Action OnJudgementRemoved; /// /// The Beatmap @@ -241,6 +242,8 @@ namespace osu.Game.Rulesets.UI OnJudgement?.Invoke(j); }; + drawableObject.OnJudgementRemoved += (d, j) => { OnJudgementRemoved?.Invoke(j); }; + Playfield.Add(drawableObject); } From 8ee13ef0aea5c09b22ece39ba0e439048a8ce148 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 2 Nov 2017 21:33:31 +0900 Subject: [PATCH 0502/1263] Properties are unnecessary --- osu.Game/Rulesets/Judgements/Judgement.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Rulesets/Judgements/Judgement.cs b/osu.Game/Rulesets/Judgements/Judgement.cs index a1920097d3..684ee0b403 100644 --- a/osu.Game/Rulesets/Judgements/Judgement.cs +++ b/osu.Game/Rulesets/Judgements/Judgement.cs @@ -20,12 +20,12 @@ namespace osu.Game.Rulesets.Judgements /// /// The combo prior to this judgement occurring. /// - internal int ComboAtJudgement { get; set; } + internal int ComboAtJudgement; /// /// The highest combo achieved prior to this judgement occurring. /// - internal int HighestComboAtJudgement { get; set; } + internal int HighestComboAtJudgement; /// /// Whether a successful hit occurred. From 9b2d41f4eb19a5cb729d45e28d7b9d20b932bca4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 2 Nov 2017 21:52:01 +0900 Subject: [PATCH 0503/1263] Fix quick retry looking bad --- osu.Game/Screens/Play/PlayerLoader.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index 054b4c0a0f..e53026fb8d 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -104,9 +104,9 @@ namespace osu.Game.Screens.Play logo.ScaleTo(new Vector2(0.15f), 300, Easing.In); logo.MoveTo(new Vector2(0.5f), 300, Easing.In); - logo.FadeIn(); + logo.FadeIn(350); - logo.Delay(500).MoveToOffset(new Vector2(0, -0.24f), 500, Easing.InOutExpo); + logo.Delay(resuming ? 0 : 500).MoveToOffset(new Vector2(0, -0.24f), 500, Easing.InOutExpo); } private void pushWhenLoaded() From c99ffb4aa39dbea7b0789a1b97d9bb78d47e17ef Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 2 Nov 2017 21:52:12 +0900 Subject: [PATCH 0504/1263] Fix potential nullref --- osu.Game/Screens/Menu/ButtonSystem.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Menu/ButtonSystem.cs b/osu.Game/Screens/Menu/ButtonSystem.cs index 9cd92f054f..6f9b77e18e 100644 --- a/osu.Game/Screens/Menu/ButtonSystem.cs +++ b/osu.Game/Screens/Menu/ButtonSystem.cs @@ -141,7 +141,7 @@ namespace osu.Game.Screens.Menu switch (args.Key) { case Key.Space: - logo.TriggerOnClick(state); + logo?.TriggerOnClick(state); return true; case Key.Escape: switch (State) From 8f78d84ad6617ba4365cd7dd86c3f4875c9b404b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 2 Nov 2017 21:52:23 +0900 Subject: [PATCH 0505/1263] Make intro resume slower --- osu.Game/Screens/Menu/Intro.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Menu/Intro.cs b/osu.Game/Screens/Menu/Intro.cs index 8553f68b9a..dcf4a00a9a 100644 --- a/osu.Game/Screens/Menu/Intro.cs +++ b/osu.Game/Screens/Menu/Intro.cs @@ -117,7 +117,7 @@ namespace osu.Game.Screens.Menu logo.Colour = Color4.DarkGray; logo.Ripple = false; - const int quick_appear = 150; + const int quick_appear = 350; int initialMovementTime = logo.Alpha > 0.2f ? quick_appear : 0; From 326891f51c3f7e0a58bb6b62863a1b20d0b1b92c Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 2 Nov 2017 21:54:28 +0900 Subject: [PATCH 0506/1263] Add "Final" to better determine when to stop processing the hitobject --- osu.Game/Rulesets/Judgements/Judgement.cs | 5 +++++ osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs | 6 +++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/osu.Game/Rulesets/Judgements/Judgement.cs b/osu.Game/Rulesets/Judgements/Judgement.cs index 684ee0b403..2b5c4aae95 100644 --- a/osu.Game/Rulesets/Judgements/Judgement.cs +++ b/osu.Game/Rulesets/Judgements/Judgement.cs @@ -32,6 +32,11 @@ namespace osu.Game.Rulesets.Judgements /// public bool IsHit => Result > HitResult.Miss; + /// + /// Whether this judgement is the final judgement for the hit object. + /// + public bool Final = true; + /// /// The offset from a perfect hit at which this judgement occurred. /// Populated when added via . diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index 9b4f7e7fc7..19bddd05e0 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -105,12 +105,12 @@ namespace osu.Game.Rulesets.Objects.Drawables } private bool judgementOccurred; - private bool hasJudgementResult => Judgements.LastOrDefault()?.Result >= HitResult.Miss; + private bool judgementFinalized => judgements.LastOrDefault()?.Final == true; /// /// Whether this and all of its nested s have been judged. /// - public virtual bool AllJudged => (!ProvidesJudgement || hasJudgementResult) && (NestedHitObjects?.All(h => h.AllJudged) ?? true); + public virtual bool AllJudged => (!ProvidesJudgement || judgementFinalized) && (NestedHitObjects?.All(h => h.AllJudged) ?? true); /// /// Notifies that a new judgement has occurred for this . @@ -159,7 +159,7 @@ namespace osu.Game.Rulesets.Objects.Drawables judgementOccurred |= d.UpdateJudgement(userTriggered); } - if (!ProvidesJudgement || hasJudgementResult || judgementOccurred) + if (!ProvidesJudgement || judgementFinalized || judgementOccurred) return judgementOccurred; var endTime = (HitObject as IHasEndTime)?.EndTime ?? HitObject.StartTime; From e2b6003f9864ff412df4d3ebe842f1b13ecc9f17 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 2 Nov 2017 21:55:50 +0900 Subject: [PATCH 0507/1263] Make taiko use the new "Final" field Ensures that the first hit on HitStrongs is _always_ non-final unless it was a miss. The second hit is always final. --- .../Judgements/TaikoStrongHitJudgement.cs | 4 +--- .../Objects/Drawables/DrawableHit.cs | 15 +++++++++++- .../Objects/Drawables/DrawableHitStrong.cs | 24 +++++++++---------- 3 files changed, 26 insertions(+), 17 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Judgements/TaikoStrongHitJudgement.cs b/osu.Game.Rulesets.Taiko/Judgements/TaikoStrongHitJudgement.cs index f0b57e5c09..07c499b56c 100644 --- a/osu.Game.Rulesets.Taiko/Judgements/TaikoStrongHitJudgement.cs +++ b/osu.Game.Rulesets.Taiko/Judgements/TaikoStrongHitJudgement.cs @@ -11,9 +11,7 @@ namespace osu.Game.Rulesets.Taiko.Judgements public TaikoStrongHitJudgement() { - base.Result = HitResult.Perfect; + Final = true; } - - public new HitResult Result => base.Result; } } diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs index 6c14a71a4c..abb4c7770e 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs @@ -17,6 +17,11 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables /// protected abstract TaikoAction[] HitActions { get; } + /// + /// Whether a second hit is allowed to be processed. + /// + protected bool SecondHitAllowed { get; private set; } + /// /// Whether the last key pressed is a valid hit key. /// @@ -45,7 +50,15 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables if (!validKeyPressed) AddJudgement(new TaikoJudgement { Result = HitResult.Miss }); else if (hitOffset < HitObject.HitWindowGood) - AddJudgement(new TaikoJudgement { Result = hitOffset < HitObject.HitWindowGreat ? HitResult.Great : HitResult.Good }); + { + AddJudgement(new TaikoJudgement + { + Result = hitOffset < HitObject.HitWindowGreat ? HitResult.Great : HitResult.Good, + Final = !HitObject.IsStrong + }); + + SecondHitAllowed = true; + } else AddJudgement(new TaikoJudgement { Result = HitResult.Miss }); } diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHitStrong.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHitStrong.cs index 48812093c4..c07eaf4d8b 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHitStrong.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHitStrong.cs @@ -3,6 +3,7 @@ using System; using System.Linq; +using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Taiko.Judgements; namespace osu.Game.Rulesets.Taiko.Objects.Drawables @@ -24,27 +25,25 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables { } - private bool processedSecondHit; - public override bool AllJudged => processedSecondHit && base.AllJudged; - protected override void CheckForJudgements(bool userTriggered, double timeOffset) { - if (!base.AllJudged) + if (!SecondHitAllowed) { base.CheckForJudgements(userTriggered, timeOffset); return; } if (!userTriggered) + { + if (timeOffset > second_hit_window) + AddJudgement(new TaikoStrongHitJudgement { Result = HitResult.Miss }); return; + } // If we get here, we're assured that the key pressed is the correct secondary key if (Math.Abs(firstHitTime - Time.Current) < second_hit_window) - { - AddJudgement(new TaikoStrongHitJudgement()); - processedSecondHit = true; - } + AddJudgement(new TaikoStrongHitJudgement { Result = HitResult.Great }); } public override bool OnReleased(TaikoAction action) @@ -56,8 +55,11 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables public override bool OnPressed(TaikoAction action) { + if (AllJudged) + return false; + // Check if we've handled the first key - if (!base.AllJudged) + if (!SecondHitAllowed) { // First key hasn't been handled yet, attempt to handle it bool handled = base.OnPressed(action); @@ -72,10 +74,6 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables return handled; } - // If we've already hit the second key, don't handle this object any further - if (processedSecondHit) - return false; - // Don't handle represses of the first key if (firstHitAction == action) return false; From 0620d0bd7a2e21034d7a96e10acc556c958b79b6 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 2 Nov 2017 21:56:09 +0900 Subject: [PATCH 0508/1263] AllJudged does not need to be virtual anymore --- 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 19bddd05e0..091af04106 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -110,7 +110,7 @@ namespace osu.Game.Rulesets.Objects.Drawables /// /// Whether this and all of its nested s have been judged. /// - public virtual bool AllJudged => (!ProvidesJudgement || judgementFinalized) && (NestedHitObjects?.All(h => h.AllJudged) ?? true); + public bool AllJudged => (!ProvidesJudgement || judgementFinalized) && (NestedHitObjects?.All(h => h.AllJudged) ?? true); /// /// Notifies that a new judgement has occurred for this . From 240997e4fbbd95617e4cd02af875ad413e4b13cf Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 2 Nov 2017 21:56:18 +0900 Subject: [PATCH 0509/1263] Remove duplicate property --- osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTick.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTick.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTick.cs index 8a96640b1e..7199691ae6 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTick.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTick.cs @@ -20,8 +20,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables public bool Tracking; - public override bool RemoveWhenNotAlive => false; - public override bool DisplayJudgement => false; public DrawableSliderTick(SliderTick sliderTick) : base(sliderTick) From 5c2b1d4be2941166b6e7c48c80bf44026375d8c9 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 2 Nov 2017 21:58:29 +0900 Subject: [PATCH 0510/1263] Update xmldoc --- osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs index abb4c7770e..489eacf386 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs @@ -18,7 +18,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables protected abstract TaikoAction[] HitActions { get; } /// - /// Whether a second hit is allowed to be processed. + /// Whether a second hit is allowed to be processed. This occurs once this hit object has been hit successfully. /// protected bool SecondHitAllowed { get; private set; } From f7540e28baf59f8c063a1abd11b39d5db550f1e6 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 2 Nov 2017 22:22:53 +0900 Subject: [PATCH 0511/1263] Update framework --- osu-framework | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu-framework b/osu-framework index ef10edfc75..c8222d1dc9 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit ef10edfc750b39258edbff46019f1d10700548c2 +Subproject commit c8222d1dc932aafe17ec42bfbe6cbec81851f55d From 3f20caa543897e87b93f2a2da3aeda86b1f004a0 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 2 Nov 2017 23:31:50 +0900 Subject: [PATCH 0512/1263] Make taiko stop crashing for now --- osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs index 136da8a532..ac3796f5b8 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs @@ -244,7 +244,12 @@ namespace osu.Game.Rulesets.Taiko.UI if (judgedObject.X >= -0.05f && judgedObject is DrawableHit) { // If we're far enough away from the left stage, we should bring outselves in front of it - topLevelHitContainer.Add(judgedObject.CreateProxy()); + // Todo: The following try-catch is temporary for replay rewinding support + try + { + topLevelHitContainer.Add(judgedObject.CreateProxy()); + } + catch { } } hitExplosionContainer.Add(new HitExplosion(judgedObject, isRim)); From 6a206c616baff0070ab852f6136a032864f40093 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 3 Nov 2017 14:34:12 +0900 Subject: [PATCH 0513/1263] Update in line with framework changes --- osu.Game/Screens/OsuScreen.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/OsuScreen.cs b/osu.Game/Screens/OsuScreen.cs index 412fe02d30..5ecfcd8e8d 100644 --- a/osu.Game/Screens/OsuScreen.cs +++ b/osu.Game/Screens/OsuScreen.cs @@ -76,7 +76,7 @@ namespace osu.Game.Screens protected override void OnResuming(Screen last) { base.OnResuming(last); - logo.WaitForTransforms().Schedule(() => logoSetup(true)); + logo.DelayUntilTransformsFinished().Schedule(() => logoSetup(true)); sampleExit?.Play(); } @@ -122,7 +122,7 @@ namespace osu.Game.Screens base.OnEntering(last); - logo.WaitForTransforms().Schedule(() => logoSetup(false)); + logo.DelayUntilTransformsFinished().Schedule(() => logoSetup(false)); } protected override bool OnExiting(Screen next) From 70ea3e50253210f52b72d8ae7aff00b6d4c19ff1 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 3 Nov 2017 15:29:16 +0900 Subject: [PATCH 0514/1263] Fix up initial scale of DrawableRepeatPoint --- .../Objects/Drawables/DrawableRepeatPoint.cs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableRepeatPoint.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableRepeatPoint.cs index bb200c9ecd..235a646ac8 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableRepeatPoint.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableRepeatPoint.cs @@ -47,16 +47,20 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables AddJudgement(new OsuJudgement { Result = drawableSlider.Tracking ? HitResult.Great : HitResult.Miss }); } + protected override void UpdateInitialState() + { + base.UpdateInitialState(); + + Scale = new Vector2(0.5f); + } + protected override void UpdatePreemptState() { var animIn = Math.Min(150, repeatPoint.StartTime - FadeInTime); - this.Animate( - d => d.FadeIn(animIn), - d => d.ScaleTo(0.5f).ScaleTo(1.2f, animIn) - ).Then( - d => d.ScaleTo(1, 150, Easing.Out) - ); + this.FadeIn(animIn).ScaleTo(1.2f, animIn) + .Then() + .ScaleTo(1, 150, Easing.Out); } protected override void UpdateCurrentState(ArmedState state) From 06a62edeb635602211eba9e1f7ab83acb0faa6d1 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 3 Nov 2017 15:30:46 +0900 Subject: [PATCH 0515/1263] Make DrawableRepeatPoints show up when replayed Fixes #1458 --- .../Objects/Drawables/DrawableRepeatPoint.cs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableRepeatPoint.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableRepeatPoint.cs index 235a646ac8..200c697a0f 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableRepeatPoint.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableRepeatPoint.cs @@ -18,13 +18,16 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables public double FadeInTime; public double FadeOutTime; - public override bool RemoveWhenNotAlive => false; - - public DrawableRepeatPoint(RepeatPoint repeatPoint, DrawableSlider drawableSlider) : base(repeatPoint) + public DrawableRepeatPoint(RepeatPoint repeatPoint, DrawableSlider drawableSlider) + : base(repeatPoint) { this.repeatPoint = repeatPoint; this.drawableSlider = drawableSlider; + // The containing DrawableSlider is updated before us and clears our transforms, so we need to be + // present to get updated and have UpdateState correctly called when rewinding. + AlwaysPresent = true; + AutoSizeAxes = Axes.Both; Blending = BlendingMode.Additive; Origin = Anchor.Centre; From 60048e6cd1f65d74a0b947e66f8c106c4cccd0ab Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 3 Nov 2017 15:33:24 +0900 Subject: [PATCH 0516/1263] Fix slider ticks not showing up again once replayed Fixes #1456 --- osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTick.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTick.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTick.cs index 7199691ae6..9fe475f4aa 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTick.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTick.cs @@ -28,6 +28,10 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables Size = new Vector2(16) * sliderTick.Scale; + // The containing DrawableSlider is updated before us and clears our transforms, so we need to be + // present to get updated and have UpdateState correctly called when rewinding. + AlwaysPresent = true; + Masking = true; CornerRadius = Size.X / 2; From 5fd311514239d795cefbf272fe806f063c32b5b5 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 3 Nov 2017 15:58:12 +0900 Subject: [PATCH 0517/1263] Fix slider ball not animating fade/scale after rewinding Fixes #1455 --- .../Objects/Drawables/Pieces/SliderBall.cs | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBall.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBall.cs index 1986b1431b..2068ad9205 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBall.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBall.cs @@ -101,14 +101,21 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces // If the current time is between the start and end of the slider, we should track mouse input regardless of the cursor position. public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => canCurrentlyTrack || base.ReceiveMouseInputAt(screenSpacePos); + public override void ClearTransforms(bool propagateChildren = false, string targetMember = null) + { + // Consider the case of rewinding - children's transforms are handled internally, so propagating down + // any further will cause weirdness with the Tracking bool below. Let's not propagate further at this point. + base.ClearTransforms(false, targetMember); + } + private bool tracking; public bool Tracking { get { return tracking; } private set { - if (value == tracking) return; - + if (value == tracking) + return; tracking = value; follow.ScaleTo(tracking ? 2.8f : 1, 300, Easing.OutQuint); @@ -123,8 +130,10 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces base.Update(); // Make sure to use the base version of ReceiveMouseInputAt so that we correctly check the position. - if (Time.Current < slider.EndTime) - Tracking = canCurrentlyTrack && lastState != null && base.ReceiveMouseInputAt(lastState.Mouse.NativeState.Position) && ((Parent as DrawableSlider)?.OsuActionInputManager?.PressedActions.Any(x => x == OsuAction.LeftButton || x == OsuAction.RightButton) ?? false); + Tracking = canCurrentlyTrack + && lastState != null + && base.ReceiveMouseInputAt(lastState.Mouse.NativeState.Position) + && ((Parent as DrawableSlider)?.OsuActionInputManager?.PressedActions.Any(x => x == OsuAction.LeftButton || x == OsuAction.RightButton) ?? false); } public void UpdateProgress(double progress, int repeat) From 3adcfa8c385c74a9a3785a246f39126c31335773 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 3 Nov 2017 17:54:35 +0900 Subject: [PATCH 0518/1263] Many fixes --- ...tCaseIntro.cs => TestCaseIntroSequence.cs} | 15 +- osu.Game.Tests/osu.Game.Tests.csproj | 2 +- osu.Game/Screens/Menu/IntroSequence.cs | 191 ++++++------------ osu.Game/Screens/Menu/LogoVisualisation.cs | 2 +- osu.Game/Screens/Menu/OsuLogo.cs | 17 ++ 5 files changed, 95 insertions(+), 132 deletions(-) rename osu.Game.Tests/Visual/{TestCaseIntro.cs => TestCaseIntroSequence.cs} (75%) diff --git a/osu.Game.Tests/Visual/TestCaseIntro.cs b/osu.Game.Tests/Visual/TestCaseIntroSequence.cs similarity index 75% rename from osu.Game.Tests/Visual/TestCaseIntro.cs rename to osu.Game.Tests/Visual/TestCaseIntroSequence.cs index a2375a592e..ba5cf8ef46 100644 --- a/osu.Game.Tests/Visual/TestCaseIntro.cs +++ b/osu.Game.Tests/Visual/TestCaseIntroSequence.cs @@ -12,16 +12,16 @@ using osu.Game.Screens.Menu; namespace osu.Game.Tests.Visual { - public class TestCaseIntro : OsuTestCase + public class TestCaseIntroSequence : OsuTestCase { public override IReadOnlyList RequiredTypes => new[] { - typeof(IntroSequence) + typeof(OsuLogo), }; - public TestCaseIntro() + public TestCaseIntroSequence() { - IntroSequence intro; + OsuLogo logo; var rateAdjustClock = new StopwatchClock(true); var framedClock = new FramedClock(rateAdjustClock); @@ -38,11 +38,14 @@ namespace osu.Game.Tests.Visual RelativeSizeAxes = Axes.Both, Colour = Color4.Black, }, - intro = new IntroSequence(), + logo = new OsuLogo + { + Anchor = Anchor.Centre, + } } }); - AddStep(@"Restart", intro.Restart); + AddStep(@"Restart", logo.PlayIntro); AddSliderStep("Playback speed", 0.0, 2.0, 1, v => rateAdjustClock.Rate = v); } } diff --git a/osu.Game.Tests/osu.Game.Tests.csproj b/osu.Game.Tests/osu.Game.Tests.csproj index 31d48097f9..4cc06df609 100644 --- a/osu.Game.Tests/osu.Game.Tests.csproj +++ b/osu.Game.Tests/osu.Game.Tests.csproj @@ -110,7 +110,7 @@ - + diff --git a/osu.Game/Screens/Menu/IntroSequence.cs b/osu.Game/Screens/Menu/IntroSequence.cs index 37c891a13a..8ca2bbaf14 100644 --- a/osu.Game/Screens/Menu/IntroSequence.cs +++ b/osu.Game/Screens/Menu/IntroSequence.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 OpenTK; using OpenTK.Graphics; using osu.Framework.Extensions.Color4Extensions; @@ -15,12 +16,10 @@ namespace osu.Game.Screens.Menu public class IntroSequence : Container { //Size - private const int logo_size = 460; //todo: this should probably be 480 + private const float logo_size = 460; //todo: this should probably be 480 private readonly OsuSpriteText welcomeText; - private readonly OsuLogo logo; - private readonly Container barsContainer; private readonly Container barTopLeft; @@ -185,144 +184,95 @@ namespace osu.Game.Screens.Menu Colour = OsuColour.FromHex(@"e967a1"), } }, - logo = new OsuLogo - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Ripple = false, - Interactive = false, - Blending = BlendingMode.Additive, - }, }; - - setDefaults(); } - public void Start() + public void Start(double length) { - const int circle_size = 416; + FinishTransforms(true); + setDefaults(); - //Time - const int full_animation_duration = 2950; + mediumRing.ResizeTo(130, 360, Easing.InExpo).OnComplete(r => r.Foreground.ResizeTo(1, 420, Easing.OutQuad)); - const int medium_ring_resize_duration = 360; - const int medium_ring_fade_duration = 420; - - const int small_ring_resize_duration = 250; - const int small_ring_fade_duration = 650; - - const int text_fade_duration = 700; - const int text_spacing_transform_duration = 1500; - - const int bar_animation_duration = 700; - const int bar_resize_delay = 150; - - const int big_ring_animation_start_delay = 2000; - const int big_ring_resize_duration = 500; - const int big_ring_foreground_resize_delay = 250; - const int big_ring_fade_duration = 450; - - const int background_animation_start_time = 2250; - const int foreground_animation_start_time = 2300; - - const int colored_circle_rotation_delay = 110; - const int colored_circles_appear_delay = 80; - const int purple_circle_animation_start_time = 2250; - - const int logo_fade_duration = 300; - - //Position - const int bar_end_offset = 120; - - mediumRing.ResizeTo(130, medium_ring_resize_duration, Easing.InExpo); + Func remainingTime = () => length - TransformDelay; using (BeginDelayedSequence(200, true)) { - welcomeText.FadeIn(text_fade_duration); - welcomeText.TransformSpacingTo(new Vector2(20, 0), text_spacing_transform_duration, Easing.Out); + welcomeText.FadeIn(700); + welcomeText.TransformSpacingTo(new Vector2(20, 0), 1500, Easing.Out); - smallRing.ResizeTo(40, small_ring_resize_duration, Easing.InExpo); - smallRing.Foreground.Delay(small_ring_resize_duration).ResizeTo(1, small_ring_fade_duration, Easing.OutQuad); - } + smallRing.ResizeTo(logo_size * 0.086f, 250, Easing.InExpo).OnComplete(r => r.Foreground.ResizeTo(1, 650, Easing.OutQuad)); - using (BeginDelayedSequence(medium_ring_resize_duration, true)) - { - mediumRing.Foreground.ResizeTo(1, medium_ring_fade_duration, Easing.OutQuad); - - foreach (var bar in barsContainer) + using (BeginDelayedSequence(160, true)) { - bar.FadeIn(); - bar.Delay(bar_resize_delay).ResizeWidthTo(0, bar_animation_duration - bar_resize_delay, Easing.OutQuint); - } + const int bar_duration = 700; + const int bar_resize = 150; - barTopLeft.MoveTo(new Vector2(-bar_end_offset, -bar_end_offset), bar_animation_duration, Easing.OutQuint); - barTopRight.MoveTo(new Vector2(bar_end_offset, -bar_end_offset), bar_animation_duration, Easing.OutQuint); - barBottomLeft.MoveTo(new Vector2(-bar_end_offset, bar_end_offset), bar_animation_duration, Easing.OutQuint); - barBottomRight.MoveTo(new Vector2(bar_end_offset, bar_end_offset), bar_animation_duration, Easing.OutQuint); - } - - using (bigRing.BeginDelayedSequence(big_ring_animation_start_delay, true)) - { - bigRing.ResizeTo(400, big_ring_resize_duration, Easing.InOutQuint); - bigRing.Foreground.Delay(big_ring_foreground_resize_delay).ResizeTo(1, big_ring_fade_duration, Easing.OutExpo); - } - - int duration = full_animation_duration - background_animation_start_time; - using (backgroundFill.BeginDelayedSequence(background_animation_start_time)) - { - backgroundFill.ResizeHeightTo(1, duration, Easing.InOutQuart); - backgroundFill.RotateTo(-90, duration, Easing.InOutQuart); - } - - duration = full_animation_duration - foreground_animation_start_time; - using (foregroundFill.BeginDelayedSequence(foreground_animation_start_time)) - { - foregroundFill.ResizeWidthTo(1, duration, Easing.InOutQuart); - foregroundFill.RotateTo(-90, duration, Easing.InOutQuart); - } - - duration = full_animation_duration - purple_circle_animation_start_time; - using (BeginDelayedSequence(purple_circle_animation_start_time, true)) - { - purpleCircle.MoveToY((circle_size - 2) / 2.0f, duration, Easing.InOutQuad); - purpleCircle.Delay(colored_circle_rotation_delay).RotateTo(-180, duration - colored_circle_rotation_delay, Easing.OutQuad); - purpleCircle.ResizeTo(circle_size - 2, duration, Easing.InOutQuad); - - duration -= colored_circles_appear_delay; - using (BeginDelayedSequence(colored_circles_appear_delay, true)) - { - yellowCircle.MoveToY(-(circle_size - 2) / 2.0f, duration, Easing.InOutQuad); - yellowCircle.Delay(colored_circle_rotation_delay).RotateTo(-180, duration - colored_circle_rotation_delay, Easing.OutQuad); - yellowCircle.ResizeTo(circle_size - 2, duration, Easing.InOutQuad); - - duration -= colored_circles_appear_delay; - using (BeginDelayedSequence(colored_circles_appear_delay, true)) + foreach (var bar in barsContainer) { - blueCircle.MoveToX(-(circle_size - 2) / 2.0f, duration, Easing.InOutQuad); - blueCircle.Delay(colored_circle_rotation_delay).RotateTo(-180, duration - colored_circle_rotation_delay, Easing.OutQuad); - blueCircle.ResizeTo(circle_size - 2, duration, Easing.InOutQuad); + bar.FadeIn(); + bar.Delay(bar_resize).ResizeWidthTo(0, bar_duration - bar_resize, Easing.OutQuint); + } - duration -= colored_circles_appear_delay; - using (BeginDelayedSequence(colored_circles_appear_delay, true)) + const int bar_end_offset = 120; + barTopLeft.MoveTo(new Vector2(-bar_end_offset, -bar_end_offset), bar_duration, Easing.OutQuint); + barTopRight.MoveTo(new Vector2(bar_end_offset, -bar_end_offset), bar_duration, Easing.OutQuint); + barBottomLeft.MoveTo(new Vector2(-bar_end_offset, bar_end_offset), bar_duration, Easing.OutQuint); + barBottomRight.MoveTo(new Vector2(bar_end_offset, bar_end_offset), bar_duration, Easing.OutQuint); + + using (BeginDelayedSequence(1640, true)) // 2000 + { + bigRing.ResizeTo(logo_size * 0.86f, 500, Easing.InOutQuint); + bigRing.Foreground.Delay(250).ResizeTo(1, 450, Easing.OutExpo); + + using (BeginDelayedSequence(250, true)) // 2250 { - pinkCircle.MoveToX(circle_size / 2.0f, duration, Easing.InOutQuad); - pinkCircle.Delay(colored_circle_rotation_delay).RotateTo(-180, duration - colored_circle_rotation_delay, Easing.OutQuad); - pinkCircle.ResizeTo(circle_size, duration, Easing.InOutQuad); + backgroundFill.ResizeHeightTo(1, remainingTime(), Easing.InOutQuart); + backgroundFill.RotateTo(-90, remainingTime(), Easing.InOutQuart); + + using (BeginDelayedSequence(50, true)) + { + foregroundFill.ResizeWidthTo(1, remainingTime(), Easing.InOutQuart); + foregroundFill.RotateTo(-90, remainingTime(), Easing.InOutQuart); + } + + const float circle_size = logo_size * 0.9f; + + const int rotation_delay = 110; + const int appear_delay = 80; + + purpleCircle.MoveToY(circle_size / 2, remainingTime(), Easing.InOutQuad); + purpleCircle.Delay(rotation_delay).RotateTo(-180, remainingTime() - rotation_delay, Easing.OutQuad); + purpleCircle.ResizeTo(circle_size, remainingTime(), Easing.InOutQuad); + + using (BeginDelayedSequence(appear_delay, true)) + { + yellowCircle.MoveToY(-circle_size / 2, remainingTime(), Easing.InOutQuad); + yellowCircle.Delay(rotation_delay).RotateTo(-180, remainingTime() - rotation_delay, Easing.OutQuad); + yellowCircle.ResizeTo(circle_size, remainingTime(), Easing.InOutQuad); + + using (BeginDelayedSequence(appear_delay, true)) + { + blueCircle.MoveToX(-circle_size / 2, remainingTime(), Easing.InOutQuad); + blueCircle.Delay(rotation_delay).RotateTo(-180, remainingTime() - rotation_delay, Easing.OutQuad); + blueCircle.ResizeTo(circle_size, remainingTime(), Easing.InOutQuad); + + using (BeginDelayedSequence(appear_delay, true)) + { + pinkCircle.MoveToX(circle_size / 2, remainingTime(), Easing.InOutQuad); + pinkCircle.Delay(rotation_delay).RotateTo(-180, remainingTime() - rotation_delay, Easing.OutQuad); + pinkCircle.ResizeTo(circle_size, remainingTime(), Easing.InOutQuad); + } + } + } } } } } - - logo.Delay(full_animation_duration).FadeIn(logo_fade_duration); - - backgroundFill.Delay(full_animation_duration + logo_fade_duration).FadeOut(); - foregroundFill.Delay(full_animation_duration + logo_fade_duration).FadeOut(); } private void setDefaults() { - logo.Alpha = 0; - welcomeText.Spacing = new Vector2(5); welcomeText.Alpha = 0; @@ -355,13 +305,6 @@ namespace osu.Game.Screens.Menu pinkCircle.Position = new Vector2(circle_offset, 0); } - public void Restart() - { - FinishTransforms(true); - setDefaults(); - Start(); - } - private class Ring : Container { public readonly CircularContainer Foreground; diff --git a/osu.Game/Screens/Menu/LogoVisualisation.cs b/osu.Game/Screens/Menu/LogoVisualisation.cs index 4b8942349d..3e7662a441 100644 --- a/osu.Game/Screens/Menu/LogoVisualisation.cs +++ b/osu.Game/Screens/Menu/LogoVisualisation.cs @@ -19,7 +19,7 @@ using osu.Framework.Allocation; namespace osu.Game.Screens.Menu { - internal class LogoVisualisation : Drawable, IHasAccentColour + public class LogoVisualisation : Drawable, IHasAccentColour { private readonly Bindable beatmap = new Bindable(); diff --git a/osu.Game/Screens/Menu/OsuLogo.cs b/osu.Game/Screens/Menu/OsuLogo.cs index 297076a78b..6215cb5660 100644 --- a/osu.Game/Screens/Menu/OsuLogo.cs +++ b/osu.Game/Screens/Menu/OsuLogo.cs @@ -39,6 +39,8 @@ namespace osu.Game.Screens.Menu private readonly Container logoHoverContainer; private readonly LogoVisualisation visualizer; + private readonly IntroSequence intro; + private SampleChannel sampleClick; private SampleChannel sampleBeat; @@ -89,6 +91,10 @@ namespace osu.Game.Screens.Menu Children = new Drawable[] { + intro = new IntroSequence + { + RelativeSizeAxes = Axes.Both, + }, logoHoverContainer = new Container { AutoSizeAxes = Axes.Both, @@ -289,6 +295,17 @@ namespace osu.Game.Screens.Menu } } + public void PlayIntro() + { + const double length = 2950; + const double fade = 300; + + logoHoverContainer.FadeOut().Delay(length).FadeIn(fade); + intro.Show(); + intro.Start(length); + intro.Delay(length + fade).FadeOut(); + } + protected override void Update() { base.Update(); From 3b189c1ffed02f8e758efaaf2cce8c4e789636ca Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 3 Nov 2017 21:20:36 +0900 Subject: [PATCH 0519/1263] Fix BreakOverlay not properly working with rewinding In various ways: * It wouldn't show up if rewound after the break was complete. * The time would increase backwards if rewind happened during a break. * Etc. * Basically the fix is to use transformations everywhere. BreakOverlay could be refactored further, but this is enough to make it work for now. --- .../Play/BreaksOverlay/BreakOverlay.cs | 37 +++++++++------- .../BreaksOverlay/RemainingTimeCounter.cs | 44 +++++++------------ 2 files changed, 36 insertions(+), 45 deletions(-) diff --git a/osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs b/osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs index f5062aa40f..b3d08c0c82 100644 --- a/osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs +++ b/osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs @@ -30,6 +30,8 @@ namespace osu.Game.Screens.Play.BreaksOverlay } } + public override bool RemoveCompletedTransforms => false; + private readonly bool letterboxing; private readonly LetterboxOverlay letterboxOverlay; private readonly Container remainingTimeAdjustmentBox; @@ -101,38 +103,41 @@ namespace osu.Game.Screens.Play.BreaksOverlay if (!b.HasEffect) continue; + using (BeginAbsoluteSequence(b.StartTime, true)) + { + remainingTimeAdjustmentBox + .ResizeWidthTo(remaining_time_container_max_size, fade_duration, Easing.OutQuint) + .Delay(b.Duration - fade_duration) + .ResizeWidthTo(0); + + remainingTimeBox + .ResizeWidthTo(0, b.Duration - fade_duration) + .Then() + .ResizeWidthTo(1); + + remainingTimeCounter.CountTo(b.Duration); + } + using (BeginAbsoluteSequence(b.StartTime)) { - Schedule(() => onBreakIn(b)); + Schedule(() => showBreak(b)); using (BeginDelayedSequence(b.Duration - fade_duration)) - Schedule(onBreakOut); + Schedule(hideBreak); } } } - private void onBreakIn(BreakPeriod b) + private void showBreak(BreakPeriod b) { if (letterboxing) letterboxOverlay.Show(); - remainingTimeAdjustmentBox - .ResizeWidthTo(remaining_time_container_max_size, fade_duration, Easing.OutQuint) - .Delay(b.Duration - fade_duration) - .ResizeWidthTo(0); - - remainingTimeBox - .ResizeWidthTo(0, b.Duration - fade_duration) - .Then() - .ResizeWidthTo(1); - - remainingTimeCounter.StartCounting(b.EndTime); - remainingTimeCounter.Show(); info.Show(); arrowsOverlay.Show(); } - private void onBreakOut() + private void hideBreak() { if (letterboxing) letterboxOverlay.Hide(); diff --git a/osu.Game/Screens/Play/BreaksOverlay/RemainingTimeCounter.cs b/osu.Game/Screens/Play/BreaksOverlay/RemainingTimeCounter.cs index b5d77d0d02..e144ac25da 100644 --- a/osu.Game/Screens/Play/BreaksOverlay/RemainingTimeCounter.cs +++ b/osu.Game/Screens/Play/BreaksOverlay/RemainingTimeCounter.cs @@ -9,18 +9,12 @@ using osu.Game.Beatmaps.Timing; namespace osu.Game.Screens.Play.BreaksOverlay { - public class RemainingTimeCounter : VisibilityContainer + public class RemainingTimeCounter : Container { private const double fade_duration = BreakPeriod.MIN_BREAK_DURATION / 2; private readonly OsuSpriteText counter; - private int? previousSecond; - - private double endTime; - - private bool isCounting; - public RemainingTimeCounter() { AutoSizeAxes = Axes.Both; @@ -31,35 +25,27 @@ namespace osu.Game.Screens.Play.BreaksOverlay TextSize = 33, Font = "Venera", }; + + Alpha = 0; } - public void StartCounting(double endTime) + public void CountTo(double duration) { - this.endTime = endTime; - isCounting = true; - } + double offset = 0; - protected override void Update() - { - base.Update(); - - if (isCounting) + while (duration > 0) { - var currentTime = Clock.CurrentTime; - if (currentTime < endTime) - { - int currentSecond = (int)Math.Ceiling((endTime - Clock.CurrentTime) / 1000.0); - if (currentSecond != previousSecond) - { - counter.Text = currentSecond.ToString(); - previousSecond = currentSecond; - } - } - else isCounting = false; + int seconds = (int)Math.Ceiling(duration / 1000); + counter.Delay(offset).TransformTextTo(seconds.ToString()); + + double localOffset = duration - (seconds - 1) * 1000 + 1; // +1 because we want the duration to be the next second when ceiled + + offset += localOffset; + duration -= localOffset; } } - protected override void PopIn() => this.FadeIn(fade_duration); - protected override void PopOut() => this.FadeOut(fade_duration); + public override void Show() => this.FadeIn(fade_duration); + public override void Hide() => this.FadeOut(fade_duration); } } From edd0d166b1c774cf102cc83208c52c56d6ab8df4 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Sat, 4 Nov 2017 00:42:36 +0900 Subject: [PATCH 0520/1263] Add text transforms to OsuSpriteText --- osu.Game/Graphics/Sprites/OsuSpriteText.cs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/osu.Game/Graphics/Sprites/OsuSpriteText.cs b/osu.Game/Graphics/Sprites/OsuSpriteText.cs index f5749846be..cbd9d9582d 100644 --- a/osu.Game/Graphics/Sprites/OsuSpriteText.cs +++ b/osu.Game/Graphics/Sprites/OsuSpriteText.cs @@ -6,6 +6,7 @@ using osu.Framework.Graphics.Sprites; using osu.Framework.MathUtils; using OpenTK; using OpenTK.Graphics; +using osu.Framework.Graphics.Transforms; namespace osu.Game.Graphics.Sprites { @@ -40,4 +41,23 @@ namespace osu.Game.Graphics.Sprites return base.CreateFallbackCharacterDrawable(); } } + + public static class OsuSpriteTextTransformExtensions + { + /// + /// Sets to a new value after a duration. + /// + /// A to which further transforms can be added. + public static TransformSequence TransformTextTo(this T spriteText, string newText, double duration = 0, Easing easing = Easing.None) + where T : OsuSpriteText + => spriteText.TransformTo(nameof(OsuSpriteText.Text), newText, duration, easing); + + /// + /// Sets to a new value after a duration. + /// + /// A to which further transforms can be added. + public static TransformSequence TransformTextTo(this TransformSequence t, string newText, double duration = 0, Easing easing = Easing.None) + where T : OsuSpriteText + => t.Append(o => o.TransformTextTo(newText, duration, easing)); + } } From 15f69dff813f5ff46e7c31d1208627d12b2fcb6e Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Sat, 4 Nov 2017 00:57:10 +0900 Subject: [PATCH 0521/1263] Make mania hit explosions not stick around when rewinding Fixes #1461. --- osu.Game.Rulesets.Mania/UI/HitExplosion.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Mania/UI/HitExplosion.cs b/osu.Game.Rulesets.Mania/UI/HitExplosion.cs index 8164adcebd..433c518929 100644 --- a/osu.Game.Rulesets.Mania/UI/HitExplosion.cs +++ b/osu.Game.Rulesets.Mania/UI/HitExplosion.cs @@ -57,8 +57,10 @@ namespace osu.Game.Rulesets.Mania.UI { base.LoadComplete(); - this.ScaleTo(2f, 600, Easing.OutQuint).FadeOut(500).Expire(); + this.ScaleTo(2f, 600, Easing.OutQuint).FadeOut(500); inner.FadeOut(250); + + Expire(true); } } } From 4854302aaa9065d62aeebc298596e5c4ddaf5414 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Sat, 4 Nov 2017 01:02:33 +0900 Subject: [PATCH 0522/1263] Fix follow points not showing up again after rewinding Fixes #1463. --- .../Objects/Drawables/Connections/FollowPoint.cs | 2 ++ .../Objects/Drawables/Connections/FollowPointRenderer.cs | 3 +++ 2 files changed, 5 insertions(+) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPoint.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPoint.cs index dbf5c6c541..ee0b5e6c50 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPoint.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPoint.cs @@ -14,6 +14,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections { private const float width = 8; + public override bool RemoveWhenNotAlive => false; + public FollowPoint() { Origin = Anchor.Centre; diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPointRenderer.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPointRenderer.cs index 2396e5d129..fca9187047 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPointRenderer.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPointRenderer.cs @@ -52,9 +52,12 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections } } + public override bool RemoveCompletedTransforms => false; + private void update() { Clear(); + if (hitObjects == null) return; From 761d885167d1ea94db18c5798fe7746a954d0b55 Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Fri, 3 Nov 2017 20:25:21 +0300 Subject: [PATCH 0523/1263] Add Favourite Beatmaps section in UserProfileOverlay --- .../API/Requests/GetUserBeatmapsRequest.cs | 30 +++++ .../Beatmaps/PaginatedBeatmapContainer.cs | 70 +++++++++++ .../Profile/Sections/BeatmapsSection.cs | 11 ++ .../Profile/Sections/HistoricalSection.cs | 2 +- .../Profile/Sections/PaginatedContainer.cs | 109 +++++++++++++++++ .../Sections/Ranks/PaginatedScoreContainer.cs | 111 +++--------------- .../Overlays/Profile/Sections/RanksSection.cs | 4 +- osu.Game/Overlays/UserProfileOverlay.cs | 2 +- osu.Game/osu.Game.csproj | 3 + 9 files changed, 242 insertions(+), 100 deletions(-) create mode 100644 osu.Game/Online/API/Requests/GetUserBeatmapsRequest.cs create mode 100644 osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs create mode 100644 osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs diff --git a/osu.Game/Online/API/Requests/GetUserBeatmapsRequest.cs b/osu.Game/Online/API/Requests/GetUserBeatmapsRequest.cs new file mode 100644 index 0000000000..8c243f899b --- /dev/null +++ b/osu.Game/Online/API/Requests/GetUserBeatmapsRequest.cs @@ -0,0 +1,30 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System.Collections.Generic; + +namespace osu.Game.Online.API.Requests +{ + public class GetUserBeatmapsRequest : APIRequest> + { + private readonly long userId; + private readonly BeatmapSetType type; + private readonly int offset; + + public GetUserBeatmapsRequest(long userId, BeatmapSetType type, int offset = 0) + { + this.userId = userId; + this.type = type; + this.offset = offset; + } + + protected override string Target => $@"users/{userId}/beatmapsets/{type.ToString().ToLower()}?offset={offset}"; + } + + public enum BeatmapSetType + { + Most_Played, + Favourite, + Ranked_And_Approved + } +} diff --git a/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs b/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs new file mode 100644 index 0000000000..1a1442979f --- /dev/null +++ b/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs @@ -0,0 +1,70 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using OpenTK; +using osu.Framework.Configuration; +using osu.Framework.Graphics; +using osu.Game.Online.API.Requests; +using osu.Game.Overlays.Direct; +using osu.Game.Users; +using System.Linq; + +namespace osu.Game.Overlays.Profile.Sections.Beatmaps +{ + public class PaginatedBeatmapContainer : PaginatedContainer + { + private const float panel_padding = 10f; + + private readonly BeatmapSetType type; + private string header; + + private DirectPanel playing; + + public PaginatedBeatmapContainer(BeatmapSetType type, Bindable user, string header, string missing) + : base(user, header, missing) + { + this.type = type; + this.header = header; + + ItemsPerPage = 6; + + ItemsContainer.Spacing = new Vector2(panel_padding); + ItemsContainer.Margin = new MarginPadding { Bottom = panel_padding }; + } + + protected override void ShowMore() + { + base.ShowMore(); + + var req = new GetUserBeatmapsRequest(User.Value.Id, type, VisiblePages++ * ItemsPerPage); + + req.Success += sets => + { + ShowMoreButton.FadeTo(sets.Count == ItemsPerPage ? 1 : 0); + ShowMoreLoading.Hide(); + + if (!sets.Any()) return; + + MissingText.Hide(); + + foreach (var s in sets) + { + var panel = new DirectGridPanel(s.ToBeatmapSet(Rulesets)) { Width = 400 }; + ItemsContainer.Add(panel); + + panel.PreviewPlaying.ValueChanged += newValue => + { + if (newValue) + { + if (playing != null && playing != panel) + playing.PreviewPlaying.Value = false; + playing = panel; + } + }; + } + }; + + Api.Queue(req); + } + } +} diff --git a/osu.Game/Overlays/Profile/Sections/BeatmapsSection.cs b/osu.Game/Overlays/Profile/Sections/BeatmapsSection.cs index 1c39223e6f..48c8c69922 100644 --- a/osu.Game/Overlays/Profile/Sections/BeatmapsSection.cs +++ b/osu.Game/Overlays/Profile/Sections/BeatmapsSection.cs @@ -1,6 +1,9 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using osu.Game.Online.API.Requests; +using osu.Game.Overlays.Profile.Sections.Beatmaps; + namespace osu.Game.Overlays.Profile.Sections { public class BeatmapsSection : ProfileSection @@ -8,5 +11,13 @@ namespace osu.Game.Overlays.Profile.Sections public override string Title => "Beatmaps"; public override string Identifier => "beatmaps"; + + public BeatmapsSection() + { + Children = new[] + { + new PaginatedBeatmapContainer(BeatmapSetType.Favourite, User, "Favourite Beatmaps", "None... yet."), + }; + } } } diff --git a/osu.Game/Overlays/Profile/Sections/HistoricalSection.cs b/osu.Game/Overlays/Profile/Sections/HistoricalSection.cs index d25407f4a3..a4d043d20a 100644 --- a/osu.Game/Overlays/Profile/Sections/HistoricalSection.cs +++ b/osu.Game/Overlays/Profile/Sections/HistoricalSection.cs @@ -14,7 +14,7 @@ namespace osu.Game.Overlays.Profile.Sections public HistoricalSection() { - Child = new PaginatedScoreContainer(ScoreType.Recent, User, "Recent Plays (24h)"); + Child = new PaginatedScoreContainer(ScoreType.Recent, User, "Recent Plays (24h)", "No performance records. :("); } } } diff --git a/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs b/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs new file mode 100644 index 0000000000..d0ccf6af41 --- /dev/null +++ b/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs @@ -0,0 +1,109 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using OpenTK; +using osu.Framework.Allocation; +using osu.Framework.Configuration; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Graphics.Containers; +using osu.Game.Graphics.Sprites; +using osu.Game.Graphics.UserInterface; +using osu.Game.Online.API; +using osu.Game.Rulesets; +using osu.Game.Users; + +namespace osu.Game.Overlays.Profile.Sections +{ + public class PaginatedContainer : FillFlowContainer + { + protected readonly FillFlowContainer ItemsContainer; + protected readonly OsuHoverContainer ShowMoreButton; + protected readonly LoadingAnimation ShowMoreLoading; + protected readonly OsuSpriteText MissingText; + + protected int VisiblePages; + protected int ItemsPerPage; + + protected readonly Bindable User = new Bindable(); + + protected APIAccess Api; + protected RulesetStore Rulesets; + + public PaginatedContainer(Bindable user, string header, string missing) + { + User.BindTo(user); + + RelativeSizeAxes = Axes.X; + AutoSizeAxes = Axes.Y; + Direction = FillDirection.Vertical; + + Children = new Drawable[] + { + new OsuSpriteText + { + TextSize = 15, + Text = header, + Font = "Exo2.0-RegularItalic", + Margin = new MarginPadding { Top = 10, Bottom = 10 }, + }, + ItemsContainer = new FillFlowContainer + { + AutoSizeAxes = Axes.Y, + RelativeSizeAxes = Axes.X, + }, + ShowMoreButton = new OsuHoverContainer + { + Alpha = 0, + Action = ShowMore, + AutoSizeAxes = Axes.Both, + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Child = new OsuSpriteText + { + TextSize = 14, + Text = "show more", + } + }, + ShowMoreLoading = new LoadingAnimation + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Size = new Vector2(14), + }, + MissingText = new OsuSpriteText + { + TextSize = 14, + Text = missing + }, + }; + } + + [BackgroundDependencyLoader] + private void load(APIAccess api, RulesetStore rulesets) + { + Api = api; + Rulesets = rulesets; + + User.ValueChanged += onUserChanged; + User.TriggerChange(); + } + + private void onUserChanged(User newUser) + { + VisiblePages = 0; + ItemsContainer.Clear(); + ShowMoreButton.Hide(); + MissingText.Show(); + + if (newUser != null) + ShowMore(); + } + + protected virtual void ShowMore() + { + ShowMoreLoading.Show(); + ShowMoreButton.Hide(); + } + } +} diff --git a/osu.Game/Overlays/Profile/Sections/Ranks/PaginatedScoreContainer.cs b/osu.Game/Overlays/Profile/Sections/Ranks/PaginatedScoreContainer.cs index 060bb03014..4c2bea4554 100644 --- a/osu.Game/Overlays/Profile/Sections/Ranks/PaginatedScoreContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/Ranks/PaginatedScoreContainer.cs @@ -1,130 +1,49 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using OpenTK; -using osu.Framework.Allocation; using osu.Framework.Configuration; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Game.Graphics.Containers; -using osu.Game.Graphics.Sprites; -using osu.Game.Graphics.UserInterface; -using osu.Game.Online.API; using osu.Game.Online.API.Requests; -using osu.Game.Rulesets; using osu.Game.Users; using System; using System.Linq; namespace osu.Game.Overlays.Profile.Sections.Ranks { - public class PaginatedScoreContainer : FillFlowContainer + public class PaginatedScoreContainer : PaginatedContainer { - private readonly FillFlowContainer scoreContainer; - private readonly OsuSpriteText missing; - private readonly OsuHoverContainer showMoreButton; - private readonly LoadingAnimation showMoreLoading; - private readonly bool includeWeight; private readonly ScoreType type; - private int visiblePages; - private readonly Bindable user = new Bindable(); - - private RulesetStore rulesets; - private APIAccess api; - - public PaginatedScoreContainer(ScoreType type, Bindable user, string header, bool includeWeight = false) + public PaginatedScoreContainer(ScoreType type, Bindable user, string header, string missing, bool includeWeight = false) + : base(user, header, missing) { this.type = type; this.includeWeight = includeWeight; - this.user.BindTo(user); - RelativeSizeAxes = Axes.X; - AutoSizeAxes = Axes.Y; - Direction = FillDirection.Vertical; + ItemsPerPage = 5; - Children = new Drawable[] - { - new OsuSpriteText - { - TextSize = 15, - Text = header, - Font = "Exo2.0-RegularItalic", - Margin = new MarginPadding { Top = 10, Bottom = 10 }, - }, - scoreContainer = new FillFlowContainer - { - AutoSizeAxes = Axes.Y, - RelativeSizeAxes = Axes.X, - Direction = FillDirection.Vertical, - }, - showMoreButton = new OsuHoverContainer - { - Alpha = 0, - Action = showMore, - AutoSizeAxes = Axes.Both, - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - Child = new OsuSpriteText - { - TextSize = 14, - Text = "show more", - } - }, - showMoreLoading = new LoadingAnimation - { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - Size = new Vector2(14), - }, - missing = new OsuSpriteText - { - TextSize = 14, - Text = type == ScoreType.Recent ? "No performance records. :(" : "No awesome performance records yet. :(", - }, - }; + ItemsContainer.Direction = FillDirection.Vertical; } - [BackgroundDependencyLoader] - private void load(APIAccess api, RulesetStore rulesets) + protected override void ShowMore() { - this.api = api; - this.rulesets = rulesets; + base.ShowMore(); - user.ValueChanged += user_ValueChanged; - user.TriggerChange(); - } - - private void user_ValueChanged(User newUser) - { - visiblePages = 0; - scoreContainer.Clear(); - showMoreButton.Hide(); - missing.Show(); - - if (newUser != null) - showMore(); - } - - private void showMore() - { - var req = new GetUserScoresRequest(user.Value.Id, type, visiblePages++ * 5); - - showMoreLoading.Show(); - showMoreButton.Hide(); + var req = new GetUserScoresRequest(User.Value.Id, type, VisiblePages++ * ItemsPerPage); req.Success += scores => { foreach (var s in scores) - s.ApplyRuleset(rulesets.GetRuleset(s.OnlineRulesetID)); + s.ApplyRuleset(Rulesets.GetRuleset(s.OnlineRulesetID)); - showMoreButton.FadeTo(scores.Count == 5 ? 1 : 0); - showMoreLoading.Hide(); + ShowMoreButton.FadeTo(scores.Count == ItemsPerPage ? 1 : 0); + ShowMoreLoading.Hide(); if (!scores.Any()) return; - missing.Hide(); + MissingText.Hide(); foreach (OnlineScore score in scores) { @@ -133,7 +52,7 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks switch (type) { default: - drawableScore = new DrawablePerformanceScore(score, includeWeight ? Math.Pow(0.95, scoreContainer.Count) : (double?)null); + drawableScore = new DrawablePerformanceScore(score, includeWeight ? Math.Pow(0.95, ItemsContainer.Count) : (double?)null); break; case ScoreType.Recent: drawableScore = new DrawableTotalScore(score); @@ -143,11 +62,11 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks drawableScore.RelativeSizeAxes = Axes.X; drawableScore.Height = 60; - scoreContainer.Add(drawableScore); + ItemsContainer.Add(drawableScore); } }; - api.Queue(req); + Api.Queue(req); } } } diff --git a/osu.Game/Overlays/Profile/Sections/RanksSection.cs b/osu.Game/Overlays/Profile/Sections/RanksSection.cs index 553691ef77..7691100d7a 100644 --- a/osu.Game/Overlays/Profile/Sections/RanksSection.cs +++ b/osu.Game/Overlays/Profile/Sections/RanksSection.cs @@ -16,8 +16,8 @@ namespace osu.Game.Overlays.Profile.Sections { Children = new[] { - new PaginatedScoreContainer(ScoreType.Best, User, "Best Performance", true), - new PaginatedScoreContainer(ScoreType.Firsts, User, "First Place Ranks"), + new PaginatedScoreContainer(ScoreType.Best, User, "Best Performance", "No performance records. :(", true), + new PaginatedScoreContainer(ScoreType.Firsts, User, "First Place Ranks", "No awesome performance records yet. :("), }; } } diff --git a/osu.Game/Overlays/UserProfileOverlay.cs b/osu.Game/Overlays/UserProfileOverlay.cs index 5032f2d55b..66d8071dd0 100644 --- a/osu.Game/Overlays/UserProfileOverlay.cs +++ b/osu.Game/Overlays/UserProfileOverlay.cs @@ -96,7 +96,7 @@ namespace osu.Game.Overlays new RanksSection(), //new MedalsSection(), new HistoricalSection(), - //new BeatmapsSection(), + new BeatmapsSection(), //new KudosuSection() }; tabs = new ProfileTabControl diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index db27c77188..2388ec4cc2 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -279,6 +279,9 @@ + + + From 48c39b1d19ec9ffb2362641e48dd03f155b49268 Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Sat, 4 Nov 2017 00:53:58 +0300 Subject: [PATCH 0524/1263] Add "Ranked & Approved Beatmaps" section --- osu.Game/Overlays/Profile/Sections/BeatmapsSection.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Overlays/Profile/Sections/BeatmapsSection.cs b/osu.Game/Overlays/Profile/Sections/BeatmapsSection.cs index 48c8c69922..708487b8e2 100644 --- a/osu.Game/Overlays/Profile/Sections/BeatmapsSection.cs +++ b/osu.Game/Overlays/Profile/Sections/BeatmapsSection.cs @@ -17,6 +17,7 @@ namespace osu.Game.Overlays.Profile.Sections Children = new[] { new PaginatedBeatmapContainer(BeatmapSetType.Favourite, User, "Favourite Beatmaps", "None... yet."), + new PaginatedBeatmapContainer(BeatmapSetType.Ranked_And_Approved, User, "Ranked & Approved Beatmaps", "None... yet."), }; } } From 729777a7e0d38e815291d51cb19fa405cc55bacd Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Sat, 4 Nov 2017 18:38:02 +0300 Subject: [PATCH 0525/1263] Remove useless variable --- .../Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs b/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs index 1a1442979f..f15798864f 100644 --- a/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs @@ -16,7 +16,6 @@ namespace osu.Game.Overlays.Profile.Sections.Beatmaps private const float panel_padding = 10f; private readonly BeatmapSetType type; - private string header; private DirectPanel playing; @@ -24,7 +23,6 @@ namespace osu.Game.Overlays.Profile.Sections.Beatmaps : base(user, header, missing) { this.type = type; - this.header = header; ItemsPerPage = 6; From 1afe2c18be781e28c3566317f4c5aa7083f0b5da Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Sat, 4 Nov 2017 19:42:28 +0300 Subject: [PATCH 0526/1263] Fix osu! deleting beatmaps on startup if MenuMusic is disabled --- osu.Game/Screens/Menu/Intro.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Menu/Intro.cs b/osu.Game/Screens/Menu/Intro.cs index fb06edb0b0..d767d4eb12 100644 --- a/osu.Game/Screens/Menu/Intro.cs +++ b/osu.Game/Screens/Menu/Intro.cs @@ -99,7 +99,9 @@ namespace osu.Game.Screens.Menu welcome = audio.Sample.Get(@"welcome"); seeya = audio.Sample.Get(@"seeya"); - beatmaps.Delete(setInfo); + + if (setInfo.Protected) + beatmaps.Delete(setInfo); } protected override void OnEntering(Screen last) From 2fbd49062690c2bc4dd2402552a1291425abcde3 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 6 Nov 2017 14:58:05 +0900 Subject: [PATCH 0527/1263] Make RemainingTimeCounter into a Counter --- .../Play/BreaksOverlay/BreakOverlay.cs | 3 ++- .../BreaksOverlay/RemainingTimeCounter.cs | 21 ++++--------------- 2 files changed, 6 insertions(+), 18 deletions(-) diff --git a/osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs b/osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs index b3d08c0c82..6128a8f3d7 100644 --- a/osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs +++ b/osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs @@ -7,6 +7,7 @@ using osu.Framework.Graphics.Shapes; using osu.Game.Beatmaps.Timing; using osu.Game.Rulesets.Scoring; using System.Collections.Generic; +using osu.Framework.Graphics.UserInterface; namespace osu.Game.Screens.Play.BreaksOverlay { @@ -115,7 +116,7 @@ namespace osu.Game.Screens.Play.BreaksOverlay .Then() .ResizeWidthTo(1); - remainingTimeCounter.CountTo(b.Duration); + remainingTimeCounter.CountTo(b.Duration).CountTo(0, b.Duration); } using (BeginAbsoluteSequence(b.StartTime)) diff --git a/osu.Game/Screens/Play/BreaksOverlay/RemainingTimeCounter.cs b/osu.Game/Screens/Play/BreaksOverlay/RemainingTimeCounter.cs index e144ac25da..9b043a6e90 100644 --- a/osu.Game/Screens/Play/BreaksOverlay/RemainingTimeCounter.cs +++ b/osu.Game/Screens/Play/BreaksOverlay/RemainingTimeCounter.cs @@ -6,10 +6,11 @@ using osu.Game.Graphics.Sprites; using osu.Framework.Graphics; using System; using osu.Game.Beatmaps.Timing; +using osu.Framework.Graphics.UserInterface; namespace osu.Game.Screens.Play.BreaksOverlay { - public class RemainingTimeCounter : Container + public class RemainingTimeCounter : Counter { private const double fade_duration = BreakPeriod.MIN_BREAK_DURATION / 2; @@ -18,7 +19,7 @@ namespace osu.Game.Screens.Play.BreaksOverlay public RemainingTimeCounter() { AutoSizeAxes = Axes.Both; - Child = counter = new OsuSpriteText + InternalChild = counter = new OsuSpriteText { Anchor = Anchor.Centre, Origin = Anchor.Centre, @@ -29,21 +30,7 @@ namespace osu.Game.Screens.Play.BreaksOverlay Alpha = 0; } - public void CountTo(double duration) - { - double offset = 0; - - while (duration > 0) - { - int seconds = (int)Math.Ceiling(duration / 1000); - counter.Delay(offset).TransformTextTo(seconds.ToString()); - - double localOffset = duration - (seconds - 1) * 1000 + 1; // +1 because we want the duration to be the next second when ceiled - - offset += localOffset; - duration -= localOffset; - } - } + protected override void OnCountChanged(double count) => counter.Text = ((int)Math.Ceiling(count / 1000)).ToString(); public override void Show() => this.FadeIn(fade_duration); public override void Hide() => this.FadeOut(fade_duration); From 8d610cfd434c573f3ff1389cf1050937280bdf5e Mon Sep 17 00:00:00 2001 From: Shane Woolcock Date: Mon, 6 Nov 2017 16:57:51 +1030 Subject: [PATCH 0528/1263] Update framework --- osu-framework | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu-framework b/osu-framework index 3c074a0981..2de91c4f0c 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit 3c074a0981844fbaa9f2ecbf879c542f07e2b94d +Subproject commit 2de91c4f0cce97a4a18229d4d63685111ec06c61 From a7c7f7d690b0c17f009d91c737280883b9baaa0c Mon Sep 17 00:00:00 2001 From: Shane Woolcock Date: Mon, 6 Nov 2017 16:58:17 +1030 Subject: [PATCH 0529/1263] Add precision values to some of the config bindables --- osu.Game/Configuration/OsuConfigManager.cs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs index b000f08369..9598372d2d 100644 --- a/osu.Game/Configuration/OsuConfigManager.cs +++ b/osu.Game/Configuration/OsuConfigManager.cs @@ -16,12 +16,12 @@ namespace osu.Game.Configuration Set(OsuSetting.Ruleset, 0, 0, int.MaxValue); Set(OsuSetting.BeatmapDetailTab, BeatmapDetailTab.Details); - Set(OsuSetting.DisplayStarsMinimum, 0.0, 0, 10); - Set(OsuSetting.DisplayStarsMaximum, 10.0, 0, 10); + Set(OsuSetting.DisplayStarsMinimum, 0.0, 0, 10, 0.1); + Set(OsuSetting.DisplayStarsMaximum, 10.0, 0, 10, 0.1); Set(OsuSetting.SelectionRandomType, SelectionRandomType.RandomPermutation); - Set(OsuSetting.ChatDisplayHeight, ChatOverlay.DEFAULT_HEIGHT, 0.2, 1); + Set(OsuSetting.ChatDisplayHeight, ChatOverlay.DEFAULT_HEIGHT, 0.2, 1, 0.01); // Online settings Set(OsuSetting.Username, string.Empty); @@ -41,11 +41,11 @@ namespace osu.Game.Configuration Set(OsuSetting.MenuVoice, true); Set(OsuSetting.MenuMusic, true); - Set(OsuSetting.AudioOffset, 0, -500.0, 500.0); + Set(OsuSetting.AudioOffset, 0, -500.0, 500.0, 1); // Input - Set(OsuSetting.MenuCursorSize, 1.0, 0.5f, 2); - Set(OsuSetting.GameplayCursorSize, 1.0, 0.5f, 2); + Set(OsuSetting.MenuCursorSize, 1.0, 0.5f, 2, 0.01); + Set(OsuSetting.GameplayCursorSize, 1.0, 0.5f, 2, 0.01); Set(OsuSetting.AutoCursorSize, false); Set(OsuSetting.MouseDisableButtons, false); @@ -63,13 +63,13 @@ namespace osu.Game.Configuration Set(OsuSetting.SnakingOutSliders, true); // Gameplay - Set(OsuSetting.DimLevel, 0.3, 0, 1); + Set(OsuSetting.DimLevel, 0.3, 0, 1, 0.01); Set(OsuSetting.ShowInterface, true); Set(OsuSetting.KeyOverlay, false); Set(OsuSetting.FloatingComments, false); - Set(OsuSetting.PlaybackSpeed, 1.0, 0.5f, 2); + Set(OsuSetting.PlaybackSpeed, 1.0, 0.5f, 2, 0.01); // Update Set(OsuSetting.ReleaseStream, ReleaseStream.Lazer); From c7426ebed80d6187b65e1efca94877f48d99a498 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 6 Nov 2017 17:22:22 +0900 Subject: [PATCH 0530/1263] Fix spinners showing very weird numbers after rewinding Fixes #1462 --- .../Objects/Drawables/Pieces/SpinnerSpmCounter.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerSpmCounter.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerSpmCounter.cs index ebe978f659..774511313a 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerSpmCounter.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerSpmCounter.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Linq; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Graphics.Sprites; @@ -61,6 +62,10 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces public void SetRotation(float currentRotation) { + // If we've gone back in time, it's fine to work with a fresh set of records for now + if (records.Count > 0 && Time.Current < records.Last().Time) + records.Clear(); + if (records.Count > 0) { var record = records.Peek(); From ebaef864324c2f630443124c20fa8748ebf486ca Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Mon, 6 Nov 2017 21:28:01 +0300 Subject: [PATCH 0531/1263] Fix hard crash when opening beatmap with zero playcount in beatmap overlay --- osu.Game/Overlays/BeatmapSet/SuccessRate.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/BeatmapSet/SuccessRate.cs b/osu.Game/Overlays/BeatmapSet/SuccessRate.cs index 9402ed82f4..e22ec3c70c 100644 --- a/osu.Game/Overlays/BeatmapSet/SuccessRate.cs +++ b/osu.Game/Overlays/BeatmapSet/SuccessRate.cs @@ -29,7 +29,10 @@ namespace osu.Game.Overlays.BeatmapSet if (value == beatmap) return; beatmap = value; - var rate = (float)beatmap.OnlineInfo.PassCount / beatmap.OnlineInfo.PlayCount; + int passCount = beatmap.OnlineInfo.PassCount; + int playCount = beatmap.OnlineInfo.PlayCount; + + var rate = (playCount != 0) ? (float)passCount / playCount : 0; successPercent.Text = rate.ToString("P0"); successRate.Length = rate; percentContainer.ResizeWidthTo(successRate.Length, 250, Easing.InOutCubic); From b8b5c67cd2502bbe25a3b90f8f5b501d4274aa5c Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Mon, 6 Nov 2017 21:46:28 +0300 Subject: [PATCH 0532/1263] Apply suggestion concerning the BeatmapSetType enum --- .../API/Requests/GetUserBeatmapsRequest.cs | 22 ++++++++++++++----- osu.Game/Overlays/BeatmapSet/SuccessRate.cs | 2 +- .../Profile/Sections/BeatmapsSection.cs | 2 +- 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/osu.Game/Online/API/Requests/GetUserBeatmapsRequest.cs b/osu.Game/Online/API/Requests/GetUserBeatmapsRequest.cs index 8c243f899b..7ad3c32bed 100644 --- a/osu.Game/Online/API/Requests/GetUserBeatmapsRequest.cs +++ b/osu.Game/Online/API/Requests/GetUserBeatmapsRequest.cs @@ -8,23 +8,35 @@ namespace osu.Game.Online.API.Requests public class GetUserBeatmapsRequest : APIRequest> { private readonly long userId; - private readonly BeatmapSetType type; private readonly int offset; + private readonly string type; public GetUserBeatmapsRequest(long userId, BeatmapSetType type, int offset = 0) { this.userId = userId; - this.type = type; this.offset = offset; + + switch (type) + { + case BeatmapSetType.Favourite: + this.type = type.ToString().ToLower(); + break; + case BeatmapSetType.MostPlayed: + this.type = "most_played"; + break; + case BeatmapSetType.RankedAndApproved: + this.type = "ranked_and_approved"; + break; + } } - protected override string Target => $@"users/{userId}/beatmapsets/{type.ToString().ToLower()}?offset={offset}"; + protected override string Target => $@"users/{userId}/beatmapsets/{type}?offset={offset}"; } public enum BeatmapSetType { - Most_Played, + MostPlayed, Favourite, - Ranked_And_Approved + RankedAndApproved } } diff --git a/osu.Game/Overlays/BeatmapSet/SuccessRate.cs b/osu.Game/Overlays/BeatmapSet/SuccessRate.cs index e22ec3c70c..6df31b9f85 100644 --- a/osu.Game/Overlays/BeatmapSet/SuccessRate.cs +++ b/osu.Game/Overlays/BeatmapSet/SuccessRate.cs @@ -32,7 +32,7 @@ namespace osu.Game.Overlays.BeatmapSet int passCount = beatmap.OnlineInfo.PassCount; int playCount = beatmap.OnlineInfo.PlayCount; - var rate = (playCount != 0) ? (float)passCount / playCount : 0; + var rate = playCount != 0 ? (float)passCount / playCount : 0; successPercent.Text = rate.ToString("P0"); successRate.Length = rate; percentContainer.ResizeWidthTo(successRate.Length, 250, Easing.InOutCubic); diff --git a/osu.Game/Overlays/Profile/Sections/BeatmapsSection.cs b/osu.Game/Overlays/Profile/Sections/BeatmapsSection.cs index 708487b8e2..f55de9b83f 100644 --- a/osu.Game/Overlays/Profile/Sections/BeatmapsSection.cs +++ b/osu.Game/Overlays/Profile/Sections/BeatmapsSection.cs @@ -17,7 +17,7 @@ namespace osu.Game.Overlays.Profile.Sections Children = new[] { new PaginatedBeatmapContainer(BeatmapSetType.Favourite, User, "Favourite Beatmaps", "None... yet."), - new PaginatedBeatmapContainer(BeatmapSetType.Ranked_And_Approved, User, "Ranked & Approved Beatmaps", "None... yet."), + new PaginatedBeatmapContainer(BeatmapSetType.RankedAndApproved, User, "Ranked & Approved Beatmaps", "None... yet."), }; } } From 5d846bff7baf34c03dec78c1305775fa3e760563 Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Mon, 6 Nov 2017 22:05:04 +0300 Subject: [PATCH 0533/1263] Add (temporarily?) subrequest for each item to provide correct beatmap information --- .../Beatmaps/PaginatedBeatmapContainer.cs | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs b/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs index f15798864f..9b623a3db9 100644 --- a/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs @@ -47,18 +47,24 @@ namespace osu.Game.Overlays.Profile.Sections.Beatmaps foreach (var s in sets) { - var panel = new DirectGridPanel(s.ToBeatmapSet(Rulesets)) { Width = 400 }; - ItemsContainer.Add(panel); - - panel.PreviewPlaying.ValueChanged += newValue => + var subReq = new GetBeatmapSetRequest(s.OnlineBeatmapSetID.Value); + subReq.Success += b => { - if (newValue) + var panel = new DirectGridPanel(b.ToBeatmapSet(Rulesets)) { Width = 400 }; + ItemsContainer.Add(panel); + + panel.PreviewPlaying.ValueChanged += newValue => { - if (playing != null && playing != panel) - playing.PreviewPlaying.Value = false; - playing = panel; - } + if (newValue) + { + if (playing != null && playing != panel) + playing.PreviewPlaying.Value = false; + playing = panel; + } + }; }; + + Api.Queue(subReq); } }; From a12052ac51b11cb623a3362fcbfb4e4db1e7f908 Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Mon, 6 Nov 2017 22:18:37 +0300 Subject: [PATCH 0534/1263] CI fix --- .../Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs b/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs index 9b623a3db9..2ac7a29177 100644 --- a/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs @@ -47,6 +47,9 @@ namespace osu.Game.Overlays.Profile.Sections.Beatmaps foreach (var s in sets) { + if (!s.OnlineBeatmapSetID.HasValue) + continue; + var subReq = new GetBeatmapSetRequest(s.OnlineBeatmapSetID.Value); subReq.Success += b => { From d10dcd82bc572c3914b5989f0b3307e45351eee4 Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Tue, 7 Nov 2017 02:39:48 +0300 Subject: [PATCH 0535/1263] Rank Line Graph improvements --- osu.Game/Overlays/Profile/RankChart.cs | 122 +++++++++++++++---------- 1 file changed, 75 insertions(+), 47 deletions(-) diff --git a/osu.Game/Overlays/Profile/RankChart.cs b/osu.Game/Overlays/Profile/RankChart.cs index 2e2286098a..b8690efa2a 100644 --- a/osu.Game/Overlays/Profile/RankChart.cs +++ b/osu.Game/Overlays/Profile/RankChart.cs @@ -24,6 +24,7 @@ namespace osu.Game.Overlays.Profile private readonly RankChartLineGraph graph; private readonly int[] ranks; + private readonly int rankedDays; private const float primary_textsize = 25, secondary_textsize = 13, padding = 10; @@ -33,6 +34,10 @@ namespace osu.Game.Overlays.Profile { this.user = user; + int[] userRanks = user.RankHistory?.Data ?? new[] { user.Statistics.Rank }; + ranks = userRanks.SkipWhile(x => x == 0).ToArray(); + rankedDays = ranks.Length; + Padding = new MarginPadding { Vertical = padding }; Children = new Drawable[] { @@ -64,13 +69,12 @@ namespace osu.Game.Overlays.Profile Origin = Anchor.BottomCentre, RelativeSizeAxes = Axes.X, Y = -secondary_textsize, - DefaultValueCount = 90, - BallRelease = updateRankTexts, - BallMove = showHistoryRankTexts + DefaultValueCount = rankedDays, } }; - ranks = user.RankHistory?.Data ?? new[] { user.Statistics.Rank }; + graph.OnBallMove += showHistoryRankTexts; + graph.OnReset += updateRankTexts; } private void updateRankTexts() @@ -82,8 +86,8 @@ namespace osu.Game.Overlays.Profile private void showHistoryRankTexts(int dayIndex) { - rankText.Text = ranks[dayIndex] > 0 ? $"#{ranks[dayIndex]:#,0}" : "no rank"; - relativeText.Text = dayIndex == ranks.Length ? "Now" : $"{ranks.Length - dayIndex} days ago"; + rankText.Text = $"#{ranks[dayIndex]:#,0}"; + relativeText.Text = dayIndex == rankedDays ? "Now" : $"{rankedDays - dayIndex} days ago"; //plural should be handled in a general way } @@ -96,7 +100,8 @@ namespace osu.Game.Overlays.Profile { // use logarithmic coordinates graph.Values = ranks.Select(x => -(float)Math.Log(x)); - graph.ResetBall(); + graph.SetStaticBallPosition(); + updateRankTexts(); } } @@ -110,67 +115,90 @@ namespace osu.Game.Overlays.Profile return base.Invalidate(invalidation, source, shallPropagate); } + protected override bool OnHover(InputState state) + { + graph.ShowBall(ToLocalSpace(state.Mouse.NativeState.Position).X); + return base.OnHover(state); + } + + protected override bool OnMouseMove(InputState state) + { + graph.MoveBall(ToLocalSpace(state.Mouse.NativeState.Position).X); + return base.OnMouseMove(state); + } + + protected override void OnHoverLost(InputState state) + { + graph.HideBall(); + updateRankTexts(); + base.OnHoverLost(state); + } + private class RankChartLineGraph : LineGraph { - private readonly CircularContainer ball; - private bool ballShown; + private const double fade_duration = 300; + private const double move_duration = 100; - private const double transform_duration = 100; + private readonly CircularContainer staticBall; + private readonly CircularContainer movingBall; - public Action BallMove; - public Action BallRelease; + public Action OnBallMove; + public Action OnReset; public RankChartLineGraph() { - Add(ball = new CircularContainer + Add(staticBall = new CircularContainer { + Origin = Anchor.Centre, Size = new Vector2(8), Masking = true, - Origin = Anchor.Centre, - Alpha = 0, RelativePositionAxes = Axes.Both, - Children = new Drawable[] - { - new Box { RelativeSizeAxes = Axes.Both } - } + Child = new Box { RelativeSizeAxes = Axes.Both } + }); + Add(movingBall = new CircularContainer + { + Origin = Anchor.Centre, + Size = new Vector2(8), + Alpha = 0, + Masking = true, + RelativePositionAxes = Axes.Both, + Child = new Box { RelativeSizeAxes = Axes.Both } }); } - public void ResetBall() + public void SetStaticBallPosition() { - ball.MoveTo(new Vector2(1, GetYPosition(Values.Last())), ballShown ? transform_duration : 0, Easing.OutQuint); - ball.Show(); - BallRelease(); - ballShown = true; + staticBall.Position = new Vector2(1, GetYPosition(Values.Last())); + OnReset.Invoke(); } - protected override bool OnMouseMove(InputState state) + public void ShowBall(float mouseXPosition) { - if (ballShown) - { - var values = (IList)Values; - var position = ToLocalSpace(state.Mouse.NativeState.Position); - int count = Math.Max(values.Count, DefaultValueCount); - int index = (int)Math.Round(position.X / DrawWidth * (count - 1)); - if (index >= count - values.Count) - { - int i = index + values.Count - count; - float y = GetYPosition(values[i]); - if (Math.Abs(y * DrawHeight - position.Y) <= 8f) - { - ball.MoveTo(new Vector2(index / (float)(count - 1), y), transform_duration, Easing.OutQuint); - BallMove(i); - } - } - } - return base.OnMouseMove(state); + int index = calculateIndex(mouseXPosition); + movingBall.Position = calculateBallPosition(mouseXPosition, index); + movingBall.FadeIn(fade_duration); + OnBallMove.Invoke(index); } - protected override void OnHoverLost(InputState state) + public void MoveBall(float mouseXPosition) { - if (ballShown) - ResetBall(); - base.OnHoverLost(state); + int index = calculateIndex(mouseXPosition); + movingBall.MoveTo(calculateBallPosition(mouseXPosition, index), move_duration, Easing.OutQuint); + OnBallMove.Invoke(index); + } + + public void HideBall() + { + movingBall.FadeOut(fade_duration); + OnReset.Invoke(); + } + + private int calculateIndex(float mouseXPosition) => (int)Math.Round(mouseXPosition / DrawWidth * (DefaultValueCount - 1)); + + private Vector2 calculateBallPosition(float mouseXPosition, int index) + { + float y = GetYPosition(Values.ElementAt(index)); + return new Vector2(index / (float)(DefaultValueCount - 1), y); } } } From 28167388d69e9a5fd0f70b6aa52fec69ba0623ca Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Tue, 7 Nov 2017 02:53:07 +0300 Subject: [PATCH 0536/1263] Remove useless calls --- osu.Game/Overlays/Profile/RankChart.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game/Overlays/Profile/RankChart.cs b/osu.Game/Overlays/Profile/RankChart.cs index b8690efa2a..1caa171c88 100644 --- a/osu.Game/Overlays/Profile/RankChart.cs +++ b/osu.Game/Overlays/Profile/RankChart.cs @@ -101,7 +101,6 @@ namespace osu.Game.Overlays.Profile // use logarithmic coordinates graph.Values = ranks.Select(x => -(float)Math.Log(x)); graph.SetStaticBallPosition(); - updateRankTexts(); } } @@ -130,7 +129,6 @@ namespace osu.Game.Overlays.Profile protected override void OnHoverLost(InputState state) { graph.HideBall(); - updateRankTexts(); base.OnHoverLost(state); } From 461baf3b9729af2607e3ed781c047a45b0b0c662 Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Tue, 7 Nov 2017 03:05:12 +0300 Subject: [PATCH 0537/1263] CI fixes --- osu.Game/Overlays/Profile/RankChart.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/osu.Game/Overlays/Profile/RankChart.cs b/osu.Game/Overlays/Profile/RankChart.cs index 1caa171c88..67f1e4b951 100644 --- a/osu.Game/Overlays/Profile/RankChart.cs +++ b/osu.Game/Overlays/Profile/RankChart.cs @@ -2,7 +2,6 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; -using System.Collections.Generic; using System.Linq; using OpenTK; using osu.Framework.Allocation; @@ -173,7 +172,7 @@ namespace osu.Game.Overlays.Profile public void ShowBall(float mouseXPosition) { int index = calculateIndex(mouseXPosition); - movingBall.Position = calculateBallPosition(mouseXPosition, index); + movingBall.Position = calculateBallPosition(index); movingBall.FadeIn(fade_duration); OnBallMove.Invoke(index); } @@ -181,7 +180,7 @@ namespace osu.Game.Overlays.Profile public void MoveBall(float mouseXPosition) { int index = calculateIndex(mouseXPosition); - movingBall.MoveTo(calculateBallPosition(mouseXPosition, index), move_duration, Easing.OutQuint); + movingBall.MoveTo(calculateBallPosition(index), move_duration, Easing.OutQuint); OnBallMove.Invoke(index); } @@ -193,7 +192,7 @@ namespace osu.Game.Overlays.Profile private int calculateIndex(float mouseXPosition) => (int)Math.Round(mouseXPosition / DrawWidth * (DefaultValueCount - 1)); - private Vector2 calculateBallPosition(float mouseXPosition, int index) + private Vector2 calculateBallPosition(int index) { float y = GetYPosition(Values.ElementAt(index)); return new Vector2(index / (float)(DefaultValueCount - 1), y); From 1063e18566ae1635dfbcdf468c5c5b1f85e9a152 Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Tue, 7 Nov 2017 03:16:27 +0300 Subject: [PATCH 0538/1263] Don't show graph at all if there's no data to use --- osu.Game/Overlays/Profile/RankChart.cs | 46 ++++++++++++++------------ 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/osu.Game/Overlays/Profile/RankChart.cs b/osu.Game/Overlays/Profile/RankChart.cs index 67f1e4b951..88cbd1ec74 100644 --- a/osu.Game/Overlays/Profile/RankChart.cs +++ b/osu.Game/Overlays/Profile/RankChart.cs @@ -62,25 +62,28 @@ namespace osu.Game.Overlays.Profile Font = @"Exo2.0-RegularItalic", TextSize = secondary_textsize }, - graph = new RankChartLineGraph + }; + + if (rankedDays > 0) + { + Add(graph = new RankChartLineGraph { Anchor = Anchor.BottomCentre, Origin = Anchor.BottomCentre, RelativeSizeAxes = Axes.X, Y = -secondary_textsize, DefaultValueCount = rankedDays, - } - }; + }); - graph.OnBallMove += showHistoryRankTexts; - graph.OnReset += updateRankTexts; + graph.OnBallMove += showHistoryRankTexts; + } } private void updateRankTexts() { - rankText.Text = user.Statistics.Rank > 0 ? $"#{user.Statistics.Rank:#,0}" : "no rank"; - performanceText.Text = user.Statistics.PP != null ? $"{user.Statistics.PP:#,0}pp" : string.Empty; - relativeText.Text = $"{user.Country?.FullName} #{user.CountryRank:#,0}"; + rankText.Text = rankedDays > 0 ? $"#{user.Statistics.Rank:#,0}" : "no rank"; + performanceText.Text = rankedDays > 0 ? $"{user.Statistics.PP:#,0}pp" : string.Empty; + relativeText.Text = rankedDays > 0 ? $"{user.Country?.FullName} #{user.CountryRank:#,0}" : string.Empty; } private void showHistoryRankTexts(int dayIndex) @@ -93,14 +96,15 @@ namespace osu.Game.Overlays.Profile [BackgroundDependencyLoader] private void load(OsuColour colours) { - graph.Colour = colours.Yellow; - - if (user.Statistics.Rank > 0) + if (graph != null) { + graph.Colour = colours.Yellow; // use logarithmic coordinates graph.Values = ranks.Select(x => -(float)Math.Log(x)); graph.SetStaticBallPosition(); } + + updateRankTexts(); } public override bool Invalidate(Invalidation invalidation = Invalidation.All, Drawable source = null, bool shallPropagate = true) @@ -115,19 +119,25 @@ namespace osu.Game.Overlays.Profile protected override bool OnHover(InputState state) { - graph.ShowBall(ToLocalSpace(state.Mouse.NativeState.Position).X); + if (graph != null) + graph.ShowBall(ToLocalSpace(state.Mouse.NativeState.Position).X); return base.OnHover(state); } protected override bool OnMouseMove(InputState state) { - graph.MoveBall(ToLocalSpace(state.Mouse.NativeState.Position).X); + if (graph != null) + graph.MoveBall(ToLocalSpace(state.Mouse.NativeState.Position).X); return base.OnMouseMove(state); } protected override void OnHoverLost(InputState state) { - graph.HideBall(); + if (graph != null) + { + graph.HideBall(); + updateRankTexts(); + } base.OnHoverLost(state); } @@ -140,7 +150,6 @@ namespace osu.Game.Overlays.Profile private readonly CircularContainer movingBall; public Action OnBallMove; - public Action OnReset; public RankChartLineGraph() { @@ -163,11 +172,7 @@ namespace osu.Game.Overlays.Profile }); } - public void SetStaticBallPosition() - { - staticBall.Position = new Vector2(1, GetYPosition(Values.Last())); - OnReset.Invoke(); - } + public void SetStaticBallPosition() => staticBall.Position = new Vector2(1, GetYPosition(Values.Last())); public void ShowBall(float mouseXPosition) { @@ -187,7 +192,6 @@ namespace osu.Game.Overlays.Profile public void HideBall() { movingBall.FadeOut(fade_duration); - OnReset.Invoke(); } private int calculateIndex(float mouseXPosition) => (int)Math.Round(mouseXPosition / DrawWidth * (DefaultValueCount - 1)); From 60e6177b7f2e26de652029551d673ded7d0bbfd7 Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Tue, 7 Nov 2017 03:26:47 +0300 Subject: [PATCH 0539/1263] Use null propagation --- osu.Game/Overlays/Profile/RankChart.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/osu.Game/Overlays/Profile/RankChart.cs b/osu.Game/Overlays/Profile/RankChart.cs index 88cbd1ec74..873fcaa78a 100644 --- a/osu.Game/Overlays/Profile/RankChart.cs +++ b/osu.Game/Overlays/Profile/RankChart.cs @@ -119,15 +119,13 @@ namespace osu.Game.Overlays.Profile protected override bool OnHover(InputState state) { - if (graph != null) - graph.ShowBall(ToLocalSpace(state.Mouse.NativeState.Position).X); + graph?.ShowBall(ToLocalSpace(state.Mouse.NativeState.Position).X); return base.OnHover(state); } protected override bool OnMouseMove(InputState state) { - if (graph != null) - graph.MoveBall(ToLocalSpace(state.Mouse.NativeState.Position).X); + graph?.MoveBall(ToLocalSpace(state.Mouse.NativeState.Position).X); return base.OnMouseMove(state); } From 1b0e7e71452d77e569de0e79d78b890be046ebc6 Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Tue, 7 Nov 2017 03:44:21 +0300 Subject: [PATCH 0540/1263] Undo some useless changes --- osu.Game/Overlays/Profile/RankChart.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/Profile/RankChart.cs b/osu.Game/Overlays/Profile/RankChart.cs index 873fcaa78a..0171988967 100644 --- a/osu.Game/Overlays/Profile/RankChart.cs +++ b/osu.Game/Overlays/Profile/RankChart.cs @@ -81,9 +81,9 @@ namespace osu.Game.Overlays.Profile private void updateRankTexts() { - rankText.Text = rankedDays > 0 ? $"#{user.Statistics.Rank:#,0}" : "no rank"; - performanceText.Text = rankedDays > 0 ? $"{user.Statistics.PP:#,0}pp" : string.Empty; - relativeText.Text = rankedDays > 0 ? $"{user.Country?.FullName} #{user.CountryRank:#,0}" : string.Empty; + rankText.Text = user.Statistics.Rank > 0 ? $"#{user.Statistics.Rank:#,0}" : "no rank"; + performanceText.Text = user.Statistics.PP != null ? $"{user.Statistics.PP:#,0}pp" : string.Empty; + relativeText.Text = $"{user.Country?.FullName} #{user.CountryRank:#,0}"; } private void showHistoryRankTexts(int dayIndex) From 5946585a6f6013ed8ee9af3fc0bc03930d09a13f Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Tue, 7 Nov 2017 12:19:23 +0300 Subject: [PATCH 0541/1263] Apply suggested changes --- osu.Game/Overlays/Profile/RankChart.cs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/osu.Game/Overlays/Profile/RankChart.cs b/osu.Game/Overlays/Profile/RankChart.cs index 0171988967..dc2c9e92ca 100644 --- a/osu.Game/Overlays/Profile/RankChart.cs +++ b/osu.Game/Overlays/Profile/RankChart.cs @@ -23,7 +23,6 @@ namespace osu.Game.Overlays.Profile private readonly RankChartLineGraph graph; private readonly int[] ranks; - private readonly int rankedDays; private const float primary_textsize = 25, secondary_textsize = 13, padding = 10; @@ -35,7 +34,6 @@ namespace osu.Game.Overlays.Profile int[] userRanks = user.RankHistory?.Data ?? new[] { user.Statistics.Rank }; ranks = userRanks.SkipWhile(x => x == 0).ToArray(); - rankedDays = ranks.Length; Padding = new MarginPadding { Vertical = padding }; Children = new Drawable[] @@ -64,7 +62,7 @@ namespace osu.Game.Overlays.Profile }, }; - if (rankedDays > 0) + if (ranks.Length > 0) { Add(graph = new RankChartLineGraph { @@ -72,7 +70,7 @@ namespace osu.Game.Overlays.Profile Origin = Anchor.BottomCentre, RelativeSizeAxes = Axes.X, Y = -secondary_textsize, - DefaultValueCount = rankedDays, + DefaultValueCount = ranks.Length, }); graph.OnBallMove += showHistoryRankTexts; @@ -89,7 +87,7 @@ namespace osu.Game.Overlays.Profile private void showHistoryRankTexts(int dayIndex) { rankText.Text = $"#{ranks[dayIndex]:#,0}"; - relativeText.Text = dayIndex == rankedDays ? "Now" : $"{rankedDays - dayIndex} days ago"; + relativeText.Text = dayIndex == ranks.Length ? "Now" : $"{ranks.Length - dayIndex} days ago"; //plural should be handled in a general way } @@ -119,13 +117,13 @@ namespace osu.Game.Overlays.Profile protected override bool OnHover(InputState state) { - graph?.ShowBall(ToLocalSpace(state.Mouse.NativeState.Position).X); + graph?.ShowBall(state.Mouse.Position.X); return base.OnHover(state); } protected override bool OnMouseMove(InputState state) { - graph?.MoveBall(ToLocalSpace(state.Mouse.NativeState.Position).X); + graph?.MoveBall(state.Mouse.Position.X); return base.OnMouseMove(state); } From a46dbee5325e0c98f5e2aa8d43dc9964c562db6d Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Tue, 7 Nov 2017 12:38:10 +0300 Subject: [PATCH 0542/1263] Add Humanizer package --- .../API/Requests/GetUserBeatmapsRequest.cs | 19 ++------- osu.Game/osu.Game.csproj | 3 ++ osu.Game/packages.config | 42 +++++++++++++++++++ 3 files changed, 49 insertions(+), 15 deletions(-) diff --git a/osu.Game/Online/API/Requests/GetUserBeatmapsRequest.cs b/osu.Game/Online/API/Requests/GetUserBeatmapsRequest.cs index 7ad3c32bed..66b2cae892 100644 --- a/osu.Game/Online/API/Requests/GetUserBeatmapsRequest.cs +++ b/osu.Game/Online/API/Requests/GetUserBeatmapsRequest.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 Humanizer; using System.Collections.Generic; namespace osu.Game.Online.API.Requests @@ -9,28 +10,16 @@ namespace osu.Game.Online.API.Requests { private readonly long userId; private readonly int offset; - private readonly string type; + private readonly BeatmapSetType type; public GetUserBeatmapsRequest(long userId, BeatmapSetType type, int offset = 0) { this.userId = userId; this.offset = offset; - - switch (type) - { - case BeatmapSetType.Favourite: - this.type = type.ToString().ToLower(); - break; - case BeatmapSetType.MostPlayed: - this.type = "most_played"; - break; - case BeatmapSetType.RankedAndApproved: - this.type = "ranked_and_approved"; - break; - } + this.type = type; } - protected override string Target => $@"users/{userId}/beatmapsets/{type}?offset={offset}"; + protected override string Target => $@"users/{userId}/beatmapsets/{type.ToString().Underscore()}?offset={offset}"; } public enum BeatmapSetType diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 2388ec4cc2..ef2e573443 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -88,6 +88,9 @@ $(SolutionDir)\packages\DotNetZip.1.10.1\lib\net20\DotNetZip.dll True + + ..\packages\Humanizer.Core.2.2.0\lib\netstandard1.0\Humanizer.dll + $(SolutionDir)\packages\Microsoft.Data.Sqlite.Core.2.0.0\lib\netstandard2.0\Microsoft.Data.Sqlite.dll diff --git a/osu.Game/packages.config b/osu.Game/packages.config index ae7b74ef16..02ace918de 100644 --- a/osu.Game/packages.config +++ b/osu.Game/packages.config @@ -5,6 +5,48 @@ Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/maste --> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 8e806cd11c2a8820ecd7fa896a77ea2a8133859a Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Tue, 7 Nov 2017 13:43:02 +0300 Subject: [PATCH 0543/1263] Simplify moving ball behaviour --- osu.Game/Overlays/Profile/RankChart.cs | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/osu.Game/Overlays/Profile/RankChart.cs b/osu.Game/Overlays/Profile/RankChart.cs index dc2c9e92ca..393575ff60 100644 --- a/osu.Game/Overlays/Profile/RankChart.cs +++ b/osu.Game/Overlays/Profile/RankChart.cs @@ -117,13 +117,14 @@ namespace osu.Game.Overlays.Profile protected override bool OnHover(InputState state) { - graph?.ShowBall(state.Mouse.Position.X); + graph?.UpdateBallPosition(state.Mouse.Position.X); + graph?.ShowBall(); return base.OnHover(state); } protected override bool OnMouseMove(InputState state) { - graph?.MoveBall(state.Mouse.Position.X); + graph?.UpdateBallPosition(state.Mouse.Position.X); return base.OnMouseMove(state); } @@ -139,8 +140,7 @@ namespace osu.Game.Overlays.Profile private class RankChartLineGraph : LineGraph { - private const double fade_duration = 300; - private const double move_duration = 100; + private const double fade_duration = 200; private readonly CircularContainer staticBall; private readonly CircularContainer movingBall; @@ -170,25 +170,16 @@ namespace osu.Game.Overlays.Profile public void SetStaticBallPosition() => staticBall.Position = new Vector2(1, GetYPosition(Values.Last())); - public void ShowBall(float mouseXPosition) + public void UpdateBallPosition(float mouseXPosition) { int index = calculateIndex(mouseXPosition); movingBall.Position = calculateBallPosition(index); - movingBall.FadeIn(fade_duration); OnBallMove.Invoke(index); } - public void MoveBall(float mouseXPosition) - { - int index = calculateIndex(mouseXPosition); - movingBall.MoveTo(calculateBallPosition(index), move_duration, Easing.OutQuint); - OnBallMove.Invoke(index); - } + public void ShowBall() => movingBall.FadeIn(fade_duration); - public void HideBall() - { - movingBall.FadeOut(fade_duration); - } + public void HideBall() => movingBall.FadeOut(fade_duration); private int calculateIndex(float mouseXPosition) => (int)Math.Round(mouseXPosition / DrawWidth * (DefaultValueCount - 1)); From 13cc1fcc92e8af93e33b987f6266e61a3c6a7dd5 Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Tue, 7 Nov 2017 14:30:44 +0300 Subject: [PATCH 0544/1263] Fix wrong index offset --- osu.Game/Overlays/Profile/RankChart.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Overlays/Profile/RankChart.cs b/osu.Game/Overlays/Profile/RankChart.cs index 393575ff60..5bd6d30b42 100644 --- a/osu.Game/Overlays/Profile/RankChart.cs +++ b/osu.Game/Overlays/Profile/RankChart.cs @@ -87,6 +87,7 @@ namespace osu.Game.Overlays.Profile private void showHistoryRankTexts(int dayIndex) { rankText.Text = $"#{ranks[dayIndex]:#,0}"; + dayIndex++; relativeText.Text = dayIndex == ranks.Length ? "Now" : $"{ranks.Length - dayIndex} days ago"; //plural should be handled in a general way } From e417eceb98de1f432b3780e770ff254bfe1ec152 Mon Sep 17 00:00:00 2001 From: Miterosan Date: Tue, 7 Nov 2017 22:49:32 +0100 Subject: [PATCH 0545/1263] Texture in Avatar.cs can not be null. --- osu.Game/Users/Avatar.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game/Users/Avatar.cs b/osu.Game/Users/Avatar.cs index 111c901ca0..7ced0305fd 100644 --- a/osu.Game/Users/Avatar.cs +++ b/osu.Game/Users/Avatar.cs @@ -1,6 +1,7 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -25,6 +26,9 @@ namespace osu.Game.Users [BackgroundDependencyLoader] private void load(TextureStore textures) { + if (textures == null) + throw new ArgumentNullException(nameof(textures)); + Texture texture = null; if (user != null && user.Id > 1) texture = textures.Get($@"https://a.ppy.sh/{user.Id}"); if (texture == null) texture = textures.Get(@"Online/avatar-guest"); From d5b275fa5368607db4b735587b8d53e9e7585094 Mon Sep 17 00:00:00 2001 From: Miterosan Date: Tue, 7 Nov 2017 22:50:00 +0100 Subject: [PATCH 0546/1263] The TextureStore in Country.cs can noit be null. --- osu.Game/Users/Country.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game/Users/Country.cs b/osu.Game/Users/Country.cs index bf06d9f8bc..0c0d12c1cc 100644 --- a/osu.Game/Users/Country.cs +++ b/osu.Game/Users/Country.cs @@ -1,6 +1,7 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System; using Newtonsoft.Json; using osu.Framework.Allocation; using osu.Framework.Graphics; @@ -45,6 +46,9 @@ namespace osu.Game.Users [BackgroundDependencyLoader] private void load(TextureStore ts) { + if (ts == null) + throw new ArgumentNullException(nameof(ts)); + textures = ts; sprite.Texture = textures.Get($@"Flags/{flagName}"); } From 2518b5e9a0a52674a529604776258e5beb7a8653 Mon Sep 17 00:00:00 2001 From: Miterosan Date: Tue, 7 Nov 2017 22:50:45 +0100 Subject: [PATCH 0547/1263] Textures in UserCoverBackground.cs can not be null --- osu.Game/Users/UserCoverBackground.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game/Users/UserCoverBackground.cs b/osu.Game/Users/UserCoverBackground.cs index c0f0d09d9d..68c97fc8fd 100644 --- a/osu.Game/Users/UserCoverBackground.cs +++ b/osu.Game/Users/UserCoverBackground.cs @@ -1,6 +1,7 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System; using osu.Framework.Allocation; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; @@ -19,6 +20,9 @@ namespace osu.Game.Users [BackgroundDependencyLoader] private void load(TextureStore textures) { + if (textures == null) + throw new ArgumentNullException(nameof(textures)); + if (!string.IsNullOrEmpty(user.CoverUrl)) Texture = textures.Get(user.CoverUrl); } From e430256b092c1cc3bfdfbaae75d3a6ec788d24d2 Mon Sep 17 00:00:00 2001 From: Miterosan Date: Tue, 7 Nov 2017 22:51:06 +0100 Subject: [PATCH 0548/1263] User and colors can not be null in UserPanel.cs --- osu.Game/Users/UserPanel.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/osu.Game/Users/UserPanel.cs b/osu.Game/Users/UserPanel.cs index e5518b5845..706ad86bfc 100644 --- a/osu.Game/Users/UserPanel.cs +++ b/osu.Game/Users/UserPanel.cs @@ -38,6 +38,9 @@ namespace osu.Game.Users public UserPanel(User user) { + if (user == null) + throw new ArgumentNullException(nameof(user)); + this.user = user; Height = height - status_height; @@ -173,6 +176,9 @@ namespace osu.Game.Users [BackgroundDependencyLoader(permitNulls: true)] private void load(OsuColour colours, UserProfileOverlay profile) { + if (colours == null) + throw new ArgumentNullException(nameof(colours)); + Status.ValueChanged += displayStatus; Status.ValueChanged += status => statusBg.FadeColour(status?.GetAppropriateColour(colours) ?? colours.Gray5, 500, Easing.OutQuint); From 840946d160483f351808c5f8a1712d04f889c040 Mon Sep 17 00:00:00 2001 From: Miterosan Date: Tue, 7 Nov 2017 23:08:24 +0100 Subject: [PATCH 0549/1263] list can not be null in ControlPointInfo.cs --- osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs b/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs index e7035880dd..e46eb8e20a 100644 --- a/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs +++ b/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs @@ -1,6 +1,7 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System; using System.Collections.Generic; using System.Linq; using osu.Framework.Lists; @@ -85,6 +86,9 @@ namespace osu.Game.Beatmaps.ControlPoints private T binarySearch(SortedList list, double time, T prePoint = null) where T : ControlPoint, new() { + if (list == null) + throw new ArgumentNullException(nameof(list)); + if (list.Count == 0) return new T(); From 1f620886cbe283bb9816bf7fd3ad95de53c76a0d Mon Sep 17 00:00:00 2001 From: Miterosan Date: Tue, 7 Nov 2017 23:09:16 +0100 Subject: [PATCH 0550/1263] beatmap and line can not be null in OsuLegacyDecoder.cs --- osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs b/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs index d775ab409b..3cf3b3a168 100644 --- a/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs +++ b/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs @@ -70,6 +70,11 @@ namespace osu.Game.Beatmaps.Formats private void handleGeneral(Beatmap beatmap, string line) { + if (beatmap == null) + throw new ArgumentNullException(nameof(beatmap)); + if (line == null) + throw new ArgumentNullException(nameof(line)); + var pair = splitKeyVal(line, ':'); var metadata = beatmap.BeatmapInfo.Metadata; From 080c3fabba909854939d156427523e92d455c7af Mon Sep 17 00:00:00 2001 From: Miterosan Date: Tue, 7 Nov 2017 23:10:06 +0100 Subject: [PATCH 0551/1263] BeatmapSet and manager can not be null in BeatmapGroup.cs --- osu.Game/Beatmaps/Drawables/BeatmapGroup.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/osu.Game/Beatmaps/Drawables/BeatmapGroup.cs b/osu.Game/Beatmaps/Drawables/BeatmapGroup.cs index 6e5af29799..163dd7fbe9 100644 --- a/osu.Game/Beatmaps/Drawables/BeatmapGroup.cs +++ b/osu.Game/Beatmaps/Drawables/BeatmapGroup.cs @@ -72,6 +72,11 @@ namespace osu.Game.Beatmaps.Drawables public BeatmapGroup(BeatmapSetInfo beatmapSet, BeatmapManager manager) { + if (beatmapSet == null) + throw new ArgumentNullException(nameof(beatmapSet)); + if (manager == null) + throw new ArgumentNullException(nameof(manager)); + BeatmapSet = beatmapSet; WorkingBeatmap beatmap = manager.GetWorkingBeatmap(BeatmapSet.Beatmaps.FirstOrDefault()); From 2f47b336e2780945fb493d118ef1439d11cc4039 Mon Sep 17 00:00:00 2001 From: Miterosan Date: Tue, 7 Nov 2017 23:10:30 +0100 Subject: [PATCH 0552/1263] beatmap and line can not be null in OsuLegacyDecoder.cs --- osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs b/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs index 3cf3b3a168..e73e056cb4 100644 --- a/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs +++ b/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs @@ -134,6 +134,11 @@ namespace osu.Game.Beatmaps.Formats private void handleEditor(Beatmap beatmap, string line) { + if (beatmap == null) + throw new ArgumentNullException(nameof(beatmap)); + if (line == null) + throw new ArgumentNullException(nameof(line)); + var pair = splitKeyVal(line, ':'); switch (pair.Key) From cf296d4bb22ca57d81519c52326e20527fbf6b95 Mon Sep 17 00:00:00 2001 From: Miterosan Date: Tue, 7 Nov 2017 23:10:41 +0100 Subject: [PATCH 0553/1263] beatmap and line can not be null in OsuLegacyDecoder.cs --- osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs b/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs index e73e056cb4..f231342234 100644 --- a/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs +++ b/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs @@ -163,6 +163,11 @@ namespace osu.Game.Beatmaps.Formats private void handleMetadata(Beatmap beatmap, string line) { + if (beatmap == null) + throw new ArgumentNullException(nameof(beatmap)); + if (line == null) + throw new ArgumentNullException(nameof(line)); + var pair = splitKeyVal(line, ':'); var metadata = beatmap.BeatmapInfo.Metadata; From 0287d3d7a05a98a26a9faee9f310fc364c19be46 Mon Sep 17 00:00:00 2001 From: Miterosan Date: Tue, 7 Nov 2017 23:10:54 +0100 Subject: [PATCH 0554/1263] beatmap and line can not be null in OsuLegacyDecoder.cs --- osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs b/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs index f231342234..d240b7669c 100644 --- a/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs +++ b/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs @@ -209,6 +209,11 @@ namespace osu.Game.Beatmaps.Formats private void handleDifficulty(Beatmap beatmap, string line) { + if (beatmap == null) + throw new ArgumentNullException(nameof(beatmap)); + if (line == null) + throw new ArgumentNullException(nameof(line)); + var pair = splitKeyVal(line, ':'); var difficulty = beatmap.BeatmapInfo.BaseDifficulty; From 34083baa4dc596ea1816af9d254eb816e8fe0a14 Mon Sep 17 00:00:00 2001 From: Miterosan Date: Tue, 7 Nov 2017 23:11:04 +0100 Subject: [PATCH 0555/1263] beatmap and line can not be null in OsuLegacyDecoder.cs --- osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs b/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs index d240b7669c..0d9d875f86 100644 --- a/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs +++ b/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs @@ -264,6 +264,11 @@ namespace osu.Game.Beatmaps.Formats private void handleEvents(Beatmap beatmap, string line, ref StoryboardSprite storyboardSprite, ref CommandTimelineGroup timelineGroup) { + if (line == null) + throw new ArgumentNullException(nameof(line)); + if (beatmap == null) + throw new ArgumentNullException(nameof(beatmap)); + var depth = 0; while (line.StartsWith(" ") || line.StartsWith("_")) { From d27dced3af926ab0aed4591ba7fb8ac5bf7cb94c Mon Sep 17 00:00:00 2001 From: Miterosan Date: Tue, 7 Nov 2017 23:11:16 +0100 Subject: [PATCH 0556/1263] beatmap and line can not be null in OsuLegacyDecoder.cs --- osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs b/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs index 0d9d875f86..5277044550 100644 --- a/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs +++ b/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs @@ -494,6 +494,11 @@ namespace osu.Game.Beatmaps.Formats private void handleTimingPoints(Beatmap beatmap, string line) { + if (beatmap == null) + throw new ArgumentNullException(nameof(beatmap)); + if (line == null) + throw new ArgumentNullException(nameof(line)); + string[] split = line.Split(','); double time = double.Parse(split[0].Trim(), NumberFormatInfo.InvariantInfo); From 8dc24a52a7fdbe4fcb461a32fe897b1abd72156d Mon Sep 17 00:00:00 2001 From: Miterosan Date: Tue, 7 Nov 2017 23:11:33 +0100 Subject: [PATCH 0557/1263] beatmap and line can not be null in OsuLegacyDecoder.cs --- osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs b/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs index 5277044550..1c7a08d17a 100644 --- a/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs +++ b/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs @@ -585,6 +585,11 @@ namespace osu.Game.Beatmaps.Formats private void handleColours(Beatmap beatmap, string line, ref bool hasCustomColours) { + if (beatmap == null) + throw new ArgumentNullException(nameof(beatmap)); + if (line == null) + throw new ArgumentNullException(nameof(line)); + var pair = splitKeyVal(line, ':'); string[] split = pair.Value.Split(','); From a8acea9cdbfeae752ae8cbd7011c6d89b4056e6d Mon Sep 17 00:00:00 2001 From: Miterosan Date: Tue, 7 Nov 2017 23:12:30 +0100 Subject: [PATCH 0558/1263] stream can not be null in BeatmapDecoder.cs --- osu.Game/Beatmaps/Formats/BeatmapDecoder.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Beatmaps/Formats/BeatmapDecoder.cs b/osu.Game/Beatmaps/Formats/BeatmapDecoder.cs index 962c6ad49a..7e1a87085c 100644 --- a/osu.Game/Beatmaps/Formats/BeatmapDecoder.cs +++ b/osu.Game/Beatmaps/Formats/BeatmapDecoder.cs @@ -18,6 +18,9 @@ namespace osu.Game.Beatmaps.Formats public static BeatmapDecoder GetDecoder(StreamReader stream) { + if (stream == null) + throw new ArgumentNullException(nameof(stream)); + string line; do { line = stream.ReadLine()?.Trim(); } while (line != null && line.Length == 0); From 289a1346fc00c850f5045a298d2602133a328752 Mon Sep 17 00:00:00 2001 From: Miterosan Date: Tue, 7 Nov 2017 23:13:09 +0100 Subject: [PATCH 0559/1263] beatmap can not be null in DifficultyIcon.cs --- osu.Game/Beatmaps/Drawables/DifficultyIcon.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs b/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs index 1aff764ede..8259da9492 100644 --- a/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs +++ b/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs @@ -1,6 +1,7 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Game.Graphics; @@ -15,6 +16,9 @@ namespace osu.Game.Beatmaps.Drawables public DifficultyIcon(BeatmapInfo beatmap) : base(beatmap) { + if (beatmap == null) + throw new ArgumentNullException(nameof(beatmap)); + this.beatmap = beatmap; Size = new Vector2(20); } From dd3874daa8a6ca865eda007ff49e3c9093bee993 Mon Sep 17 00:00:00 2001 From: Miterosan Date: Tue, 7 Nov 2017 23:13:32 +0100 Subject: [PATCH 0560/1263] beatmap can not be null in BeatmapPanel.cs --- osu.Game/Beatmaps/Drawables/BeatmapPanel.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Beatmaps/Drawables/BeatmapPanel.cs b/osu.Game/Beatmaps/Drawables/BeatmapPanel.cs index c0705d8f61..e6bf08eb9f 100644 --- a/osu.Game/Beatmaps/Drawables/BeatmapPanel.cs +++ b/osu.Game/Beatmaps/Drawables/BeatmapPanel.cs @@ -73,6 +73,9 @@ namespace osu.Game.Beatmaps.Drawables public BeatmapPanel(BeatmapInfo beatmap) { + if (beatmap == null) + throw new ArgumentNullException(nameof(beatmap)); + Beatmap = beatmap; Height *= 0.60f; From d7dee57886e98696247ceddf2a030bed46fe4e03 Mon Sep 17 00:00:00 2001 From: Miterosan Date: Tue, 7 Nov 2017 23:13:56 +0100 Subject: [PATCH 0561/1263] set can not be null in BeatmapSetCover.cs --- osu.Game/Beatmaps/Drawables/BeatmapSetCover.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game/Beatmaps/Drawables/BeatmapSetCover.cs b/osu.Game/Beatmaps/Drawables/BeatmapSetCover.cs index df7e0905d0..614ebc236b 100644 --- a/osu.Game/Beatmaps/Drawables/BeatmapSetCover.cs +++ b/osu.Game/Beatmaps/Drawables/BeatmapSetCover.cs @@ -1,6 +1,7 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System; using osu.Framework.Allocation; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; @@ -12,6 +13,9 @@ namespace osu.Game.Beatmaps.Drawables private readonly BeatmapSetInfo set; public BeatmapSetCover(BeatmapSetInfo set) { + if (set == null) + throw new ArgumentNullException(nameof(set)); + this.set = set; } From bc941790329421cec6aee6afc6c69362c0af8030 Mon Sep 17 00:00:00 2001 From: Miterosan Date: Tue, 7 Nov 2017 23:14:22 +0100 Subject: [PATCH 0562/1263] workingbeatmap can not be null in BeatmapBackgroundSprite.cs --- osu.Game/Beatmaps/Drawables/BeatmapBackgroundSprite.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game/Beatmaps/Drawables/BeatmapBackgroundSprite.cs b/osu.Game/Beatmaps/Drawables/BeatmapBackgroundSprite.cs index 9b897b4912..0ac8d12591 100644 --- a/osu.Game/Beatmaps/Drawables/BeatmapBackgroundSprite.cs +++ b/osu.Game/Beatmaps/Drawables/BeatmapBackgroundSprite.cs @@ -1,6 +1,7 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System; using osu.Framework.Allocation; using osu.Framework.Graphics.Sprites; @@ -12,6 +13,9 @@ namespace osu.Game.Beatmaps.Drawables public BeatmapBackgroundSprite(WorkingBeatmap working) { + if (working == null) + throw new ArgumentNullException(nameof(working)); + this.working = working; } From dc317139c90576f1c2d30b9ff885d1818c604610 Mon Sep 17 00:00:00 2001 From: Miterosan Date: Tue, 7 Nov 2017 23:15:02 +0100 Subject: [PATCH 0563/1263] beatmap can not be null in BeatmapSetHeader.cs --- osu.Game/Beatmaps/Drawables/BeatmapSetHeader.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Beatmaps/Drawables/BeatmapSetHeader.cs b/osu.Game/Beatmaps/Drawables/BeatmapSetHeader.cs index ee75b77747..f1dc933a3f 100644 --- a/osu.Game/Beatmaps/Drawables/BeatmapSetHeader.cs +++ b/osu.Game/Beatmaps/Drawables/BeatmapSetHeader.cs @@ -36,6 +36,9 @@ namespace osu.Game.Beatmaps.Drawables public BeatmapSetHeader(WorkingBeatmap beatmap) { + if (beatmap == null) + throw new ArgumentNullException(nameof(beatmap)); + this.beatmap = beatmap; Children = new Drawable[] From 0f539d24f0926d2bdbcff6631ff5d46153c26876 Mon Sep 17 00:00:00 2001 From: Miterosan Date: Tue, 7 Nov 2017 23:15:21 +0100 Subject: [PATCH 0564/1263] Localisation can not be null in BeatmapSetHeader.cs --- osu.Game/Beatmaps/Drawables/BeatmapSetHeader.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Beatmaps/Drawables/BeatmapSetHeader.cs b/osu.Game/Beatmaps/Drawables/BeatmapSetHeader.cs index f1dc933a3f..6593ea6de2 100644 --- a/osu.Game/Beatmaps/Drawables/BeatmapSetHeader.cs +++ b/osu.Game/Beatmaps/Drawables/BeatmapSetHeader.cs @@ -91,6 +91,9 @@ namespace osu.Game.Beatmaps.Drawables [BackgroundDependencyLoader] private void load(LocalisationEngine localisation) { + if (localisation == null) + throw new ArgumentNullException(nameof(localisation)); + title.Current = localisation.GetUnicodePreference(beatmap.Metadata.TitleUnicode, beatmap.Metadata.Title); artist.Current = localisation.GetUnicodePreference(beatmap.Metadata.ArtistUnicode, beatmap.Metadata.Artist); } From 36ce287b886cde96d9a636c8581d62c4f172bf82 Mon Sep 17 00:00:00 2001 From: Miterosan Date: Tue, 7 Nov 2017 23:15:51 +0100 Subject: [PATCH 0565/1263] panels can not be null in BeatmapSetHeader.cs --- osu.Game/Beatmaps/Drawables/BeatmapSetHeader.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Beatmaps/Drawables/BeatmapSetHeader.cs b/osu.Game/Beatmaps/Drawables/BeatmapSetHeader.cs index 6593ea6de2..8a589ccd30 100644 --- a/osu.Game/Beatmaps/Drawables/BeatmapSetHeader.cs +++ b/osu.Game/Beatmaps/Drawables/BeatmapSetHeader.cs @@ -160,6 +160,9 @@ namespace osu.Game.Beatmaps.Drawables public void AddDifficultyIcons(IEnumerable panels) { + if (panels == null) + throw new ArgumentNullException(nameof(panels)); + foreach (var p in panels) difficultyIcons.Add(new DifficultyIcon(p.Beatmap)); } From a15ab785f28078eb30b821922146c91b27207ee3 Mon Sep 17 00:00:00 2001 From: Miterosan Date: Tue, 7 Nov 2017 23:16:19 +0100 Subject: [PATCH 0566/1263] palette can not be null in DifficultyColouredContainer.cs --- osu.Game/Beatmaps/Drawables/DifficultyColouredContainer.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game/Beatmaps/Drawables/DifficultyColouredContainer.cs b/osu.Game/Beatmaps/Drawables/DifficultyColouredContainer.cs index 41b77f6584..f2bb9c62d7 100644 --- a/osu.Game/Beatmaps/Drawables/DifficultyColouredContainer.cs +++ b/osu.Game/Beatmaps/Drawables/DifficultyColouredContainer.cs @@ -1,6 +1,7 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System; using osu.Framework.Allocation; using osu.Framework.Graphics.Containers; using osu.Game.Graphics; @@ -23,6 +24,9 @@ namespace osu.Game.Beatmaps.Drawables [BackgroundDependencyLoader] private void load(OsuColour palette) { + if (palette == null) + throw new ArgumentNullException(nameof(palette)); + this.palette = palette; AccentColour = getColour(beatmap); } From 1e6f1d07d237cd7bcf484b508b96cd91940724dc Mon Sep 17 00:00:00 2001 From: Miterosan Date: Tue, 7 Nov 2017 23:16:42 +0100 Subject: [PATCH 0567/1263] line can not be null in OsuLegacyDecoder.cs --- osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs b/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs index 1c7a08d17a..2fb14c65f7 100644 --- a/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs +++ b/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs @@ -246,6 +246,9 @@ namespace osu.Game.Beatmaps.Formats /// The line which may contains variables. private void decodeVariables(ref string line) { + if (line == null) + throw new ArgumentNullException(nameof(line)); + while (line.IndexOf('$') >= 0) { string origLine = line; @@ -622,6 +625,9 @@ namespace osu.Game.Beatmaps.Formats private void handleVariables(string line) { + if (line == null) + throw new ArgumentNullException(nameof(line)); + var pair = splitKeyVal(line, '='); variables[pair.Key] = pair.Value; } From 13e75780d71383e7738bdc918efa35b8a60258a1 Mon Sep 17 00:00:00 2001 From: Miterosan Date: Tue, 7 Nov 2017 23:17:07 +0100 Subject: [PATCH 0568/1263] beatmap and stream can not be null in OsuLegacyDecoder.cs --- osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs b/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs index 2fb14c65f7..34ae2ede54 100644 --- a/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs +++ b/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs @@ -644,6 +644,11 @@ namespace osu.Game.Beatmaps.Formats protected override void ParseFile(StreamReader stream, Beatmap beatmap) { + if (beatmap == null) + throw new ArgumentNullException(nameof(beatmap)); + if (stream == null) + throw new ArgumentNullException(nameof(stream)); + beatmap.BeatmapInfo.BeatmapVersion = beatmapVersion; Section section = Section.None; From b2e49c1e7144e78a09ed4553ff613ed198750f0e Mon Sep 17 00:00:00 2001 From: Miterosan Date: Tue, 7 Nov 2017 23:17:26 +0100 Subject: [PATCH 0569/1263] line can not be null in OsuLegacyDecoder.cs --- osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs b/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs index 34ae2ede54..11631e9447 100644 --- a/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs +++ b/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs @@ -725,6 +725,9 @@ namespace osu.Game.Beatmaps.Formats private KeyValuePair splitKeyVal(string line, char separator) { + if (line == null) + throw new ArgumentNullException(nameof(line)); + var split = line.Trim().Split(new[] { separator }, 2); return new KeyValuePair From 567cd6316c7803ea0ccffe818dbd6628101126f8 Mon Sep 17 00:00:00 2001 From: Miterosan Date: Tue, 7 Nov 2017 23:17:45 +0100 Subject: [PATCH 0570/1263] beatmap can not be null in DifficultyColouredContainer.cs --- osu.Game/Beatmaps/Drawables/DifficultyColouredContainer.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Beatmaps/Drawables/DifficultyColouredContainer.cs b/osu.Game/Beatmaps/Drawables/DifficultyColouredContainer.cs index f2bb9c62d7..57a5abc4c7 100644 --- a/osu.Game/Beatmaps/Drawables/DifficultyColouredContainer.cs +++ b/osu.Game/Beatmaps/Drawables/DifficultyColouredContainer.cs @@ -43,6 +43,9 @@ namespace osu.Game.Beatmaps.Drawables private DifficultyRating getDifficultyRating(BeatmapInfo beatmap) { + if (beatmap == null) + throw new ArgumentNullException(nameof(beatmap)); + var rating = beatmap.StarDifficulty; if (rating < 1.5) return DifficultyRating.Easy; From 97b238d0847d7c86da8bffb66de3e2af533eacce Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 8 Nov 2017 11:20:21 +0900 Subject: [PATCH 0571/1263] Simplify intro sequence a bit more --- osu.Game/Screens/Menu/IntroSequence.cs | 92 ++++++++++++-------------- 1 file changed, 44 insertions(+), 48 deletions(-) diff --git a/osu.Game/Screens/Menu/IntroSequence.cs b/osu.Game/Screens/Menu/IntroSequence.cs index 8ca2bbaf14..54e6d74189 100644 --- a/osu.Game/Screens/Menu/IntroSequence.cs +++ b/osu.Game/Screens/Menu/IntroSequence.cs @@ -193,76 +193,72 @@ namespace osu.Game.Screens.Menu setDefaults(); mediumRing.ResizeTo(130, 360, Easing.InExpo).OnComplete(r => r.Foreground.ResizeTo(1, 420, Easing.OutQuad)); + smallRing.ResizeTo(logo_size * 0.086f, 250, Easing.InExpo).OnComplete(r => r.Foreground.ResizeTo(1, 650, Easing.OutQuad)); Func remainingTime = () => length - TransformDelay; - using (BeginDelayedSequence(200, true)) + using (BeginDelayedSequence(360, true)) { welcomeText.FadeIn(700); - welcomeText.TransformSpacingTo(new Vector2(20, 0), 1500, Easing.Out); + welcomeText.TransformSpacingTo(new Vector2(20, 0), remainingTime(), Easing.Out); - smallRing.ResizeTo(logo_size * 0.086f, 250, Easing.InExpo).OnComplete(r => r.Foreground.ResizeTo(1, 650, Easing.OutQuad)); + const int bar_duration = 700; + const int bar_resize = 150; - using (BeginDelayedSequence(160, true)) + foreach (var bar in barsContainer) { - const int bar_duration = 700; - const int bar_resize = 150; + bar.FadeIn(); + bar.Delay(bar_resize).ResizeWidthTo(0, bar_duration - bar_resize, Easing.OutQuint); + } - foreach (var bar in barsContainer) + const int bar_end_offset = 120; + barTopLeft.MoveTo(new Vector2(-bar_end_offset, -bar_end_offset), bar_duration, Easing.OutQuint); + barTopRight.MoveTo(new Vector2(bar_end_offset, -bar_end_offset), bar_duration, Easing.OutQuint); + barBottomLeft.MoveTo(new Vector2(-bar_end_offset, bar_end_offset), bar_duration, Easing.OutQuint); + barBottomRight.MoveTo(new Vector2(bar_end_offset, bar_end_offset), bar_duration, Easing.OutQuint); + + using (BeginDelayedSequence(1640, true)) // 2000 + { + bigRing.ResizeTo(logo_size * 0.86f, 500, Easing.InOutQuint); + bigRing.Foreground.Delay(250).ResizeTo(1, 450, Easing.OutExpo); + + using (BeginDelayedSequence(250, true)) // 2250 { - bar.FadeIn(); - bar.Delay(bar_resize).ResizeWidthTo(0, bar_duration - bar_resize, Easing.OutQuint); - } + backgroundFill.ResizeHeightTo(1, remainingTime(), Easing.InOutQuart); + backgroundFill.RotateTo(-90, remainingTime(), Easing.InOutQuart); - const int bar_end_offset = 120; - barTopLeft.MoveTo(new Vector2(-bar_end_offset, -bar_end_offset), bar_duration, Easing.OutQuint); - barTopRight.MoveTo(new Vector2(bar_end_offset, -bar_end_offset), bar_duration, Easing.OutQuint); - barBottomLeft.MoveTo(new Vector2(-bar_end_offset, bar_end_offset), bar_duration, Easing.OutQuint); - barBottomRight.MoveTo(new Vector2(bar_end_offset, bar_end_offset), bar_duration, Easing.OutQuint); - - using (BeginDelayedSequence(1640, true)) // 2000 - { - bigRing.ResizeTo(logo_size * 0.86f, 500, Easing.InOutQuint); - bigRing.Foreground.Delay(250).ResizeTo(1, 450, Easing.OutExpo); - - using (BeginDelayedSequence(250, true)) // 2250 + using (BeginDelayedSequence(50, true)) { - backgroundFill.ResizeHeightTo(1, remainingTime(), Easing.InOutQuart); - backgroundFill.RotateTo(-90, remainingTime(), Easing.InOutQuart); + foregroundFill.ResizeWidthTo(1, remainingTime(), Easing.InOutQuart); + foregroundFill.RotateTo(-90, remainingTime(), Easing.InOutQuart); + } - using (BeginDelayedSequence(50, true)) - { - foregroundFill.ResizeWidthTo(1, remainingTime(), Easing.InOutQuart); - foregroundFill.RotateTo(-90, remainingTime(), Easing.InOutQuart); - } + const float circle_size = logo_size * 0.9f; - const float circle_size = logo_size * 0.9f; + const int rotation_delay = 110; + const int appear_delay = 80; - const int rotation_delay = 110; - const int appear_delay = 80; + purpleCircle.MoveToY(circle_size / 2, remainingTime(), Easing.InOutQuad); + purpleCircle.Delay(rotation_delay).RotateTo(-180, remainingTime() - rotation_delay, Easing.OutQuad); + purpleCircle.ResizeTo(circle_size, remainingTime(), Easing.InOutQuad); - purpleCircle.MoveToY(circle_size / 2, remainingTime(), Easing.InOutQuad); - purpleCircle.Delay(rotation_delay).RotateTo(-180, remainingTime() - rotation_delay, Easing.OutQuad); - purpleCircle.ResizeTo(circle_size, remainingTime(), Easing.InOutQuad); + using (BeginDelayedSequence(appear_delay, true)) + { + yellowCircle.MoveToY(-circle_size / 2, remainingTime(), Easing.InOutQuad); + yellowCircle.Delay(rotation_delay).RotateTo(-180, remainingTime() - rotation_delay, Easing.OutQuad); + yellowCircle.ResizeTo(circle_size, remainingTime(), Easing.InOutQuad); using (BeginDelayedSequence(appear_delay, true)) { - yellowCircle.MoveToY(-circle_size / 2, remainingTime(), Easing.InOutQuad); - yellowCircle.Delay(rotation_delay).RotateTo(-180, remainingTime() - rotation_delay, Easing.OutQuad); - yellowCircle.ResizeTo(circle_size, remainingTime(), Easing.InOutQuad); + blueCircle.MoveToX(-circle_size / 2, remainingTime(), Easing.InOutQuad); + blueCircle.Delay(rotation_delay).RotateTo(-180, remainingTime() - rotation_delay, Easing.OutQuad); + blueCircle.ResizeTo(circle_size, remainingTime(), Easing.InOutQuad); using (BeginDelayedSequence(appear_delay, true)) { - blueCircle.MoveToX(-circle_size / 2, remainingTime(), Easing.InOutQuad); - blueCircle.Delay(rotation_delay).RotateTo(-180, remainingTime() - rotation_delay, Easing.OutQuad); - blueCircle.ResizeTo(circle_size, remainingTime(), Easing.InOutQuad); - - using (BeginDelayedSequence(appear_delay, true)) - { - pinkCircle.MoveToX(circle_size / 2, remainingTime(), Easing.InOutQuad); - pinkCircle.Delay(rotation_delay).RotateTo(-180, remainingTime() - rotation_delay, Easing.OutQuad); - pinkCircle.ResizeTo(circle_size, remainingTime(), Easing.InOutQuad); - } + pinkCircle.MoveToX(circle_size / 2, remainingTime(), Easing.InOutQuad); + pinkCircle.Delay(rotation_delay).RotateTo(-180, remainingTime() - rotation_delay, Easing.OutQuad); + pinkCircle.ResizeTo(circle_size, remainingTime(), Easing.InOutQuad); } } } From a72e798b8556812e3f2c6b2c42b372891592fa60 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 8 Nov 2017 11:21:50 +0900 Subject: [PATCH 0572/1263] bar -> line --- osu.Game/Screens/Menu/IntroSequence.cs | 54 +++++++++++++------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/osu.Game/Screens/Menu/IntroSequence.cs b/osu.Game/Screens/Menu/IntroSequence.cs index 54e6d74189..c3a45e74a9 100644 --- a/osu.Game/Screens/Menu/IntroSequence.cs +++ b/osu.Game/Screens/Menu/IntroSequence.cs @@ -20,12 +20,12 @@ namespace osu.Game.Screens.Menu private readonly OsuSpriteText welcomeText; - private readonly Container barsContainer; + private readonly Container linesContainer; - private readonly Container barTopLeft; - private readonly Container barBottomLeft; - private readonly Container barTopRight; - private readonly Container barBottomRight; + private readonly Container lineTopLeft; + private readonly Container lineBottomLeft; + private readonly Container lineTopRight; + private readonly Container lineBottomRight; private readonly Ring smallRing; private readonly Ring mediumRing; @@ -45,14 +45,14 @@ namespace osu.Game.Screens.Menu Children = new Drawable[] { mediumRing = new Ring(Color4.White.Opacity(130)), - barsContainer = new Container + linesContainer = new Container { Anchor = Anchor.Centre, Origin = Anchor.Centre, AutoSizeAxes = Axes.Both, Children = new Drawable[] { - barTopLeft = new Container + lineTopLeft = new Container { Origin = Anchor.CentreLeft, Anchor = Anchor.Centre, @@ -63,7 +63,7 @@ namespace osu.Game.Screens.Menu Colour = Color4.White.Opacity(180), } }, - barTopRight = new Container + lineTopRight = new Container { Origin = Anchor.CentreRight, Anchor = Anchor.Centre, @@ -74,7 +74,7 @@ namespace osu.Game.Screens.Menu Colour = Color4.White.Opacity(80), } }, - barBottomLeft = new Container + lineBottomLeft = new Container { Origin = Anchor.CentreLeft, Anchor = Anchor.Centre, @@ -85,7 +85,7 @@ namespace osu.Game.Screens.Menu Colour = Color4.White.Opacity(230), } }, - barBottomRight = new Container + lineBottomRight = new Container { Origin = Anchor.CentreRight, Anchor = Anchor.Centre, @@ -202,20 +202,20 @@ namespace osu.Game.Screens.Menu welcomeText.FadeIn(700); welcomeText.TransformSpacingTo(new Vector2(20, 0), remainingTime(), Easing.Out); - const int bar_duration = 700; - const int bar_resize = 150; + const int line_duration = 700; + const int line_resize = 150; - foreach (var bar in barsContainer) + foreach (var line in linesContainer) { - bar.FadeIn(); - bar.Delay(bar_resize).ResizeWidthTo(0, bar_duration - bar_resize, Easing.OutQuint); + line.FadeIn(); + line.Delay(line_resize).ResizeWidthTo(0, line_duration - line_resize, Easing.OutQuint); } - const int bar_end_offset = 120; - barTopLeft.MoveTo(new Vector2(-bar_end_offset, -bar_end_offset), bar_duration, Easing.OutQuint); - barTopRight.MoveTo(new Vector2(bar_end_offset, -bar_end_offset), bar_duration, Easing.OutQuint); - barBottomLeft.MoveTo(new Vector2(-bar_end_offset, bar_end_offset), bar_duration, Easing.OutQuint); - barBottomRight.MoveTo(new Vector2(bar_end_offset, bar_end_offset), bar_duration, Easing.OutQuint); + const int line_end_offset = 120; + lineTopLeft.MoveTo(new Vector2(-line_end_offset, -line_end_offset), line_duration, Easing.OutQuint); + lineTopRight.MoveTo(new Vector2(line_end_offset, -line_end_offset), line_duration, Easing.OutQuint); + lineBottomLeft.MoveTo(new Vector2(-line_end_offset, line_end_offset), line_duration, Easing.OutQuint); + lineBottomRight.MoveTo(new Vector2(line_end_offset, line_end_offset), line_duration, Easing.OutQuint); using (BeginDelayedSequence(1640, true)) // 2000 { @@ -278,14 +278,14 @@ namespace osu.Game.Screens.Menu smallRing.Foreground.Size = Vector2.One - new Vector2(0.4f); bigRing.Foreground.Size = Vector2.One - new Vector2(0.15f); - barTopLeft.Size = barTopRight.Size = barBottomLeft.Size = barBottomRight.Size = new Vector2(105, 1.5f); - barTopLeft.Alpha = barTopRight.Alpha = barBottomLeft.Alpha = barBottomRight.Alpha = 0; + lineTopLeft.Size = lineTopRight.Size = lineBottomLeft.Size = lineBottomRight.Size = new Vector2(105, 1.5f); + lineTopLeft.Alpha = lineTopRight.Alpha = lineBottomLeft.Alpha = lineBottomRight.Alpha = 0; - const int bar_offset = 80; - barTopLeft.Position = new Vector2(-bar_offset, -bar_offset); - barTopRight.Position = new Vector2(bar_offset, -bar_offset); - barBottomLeft.Position = new Vector2(-bar_offset, bar_offset); - barBottomRight.Position = new Vector2(bar_offset, bar_offset); + const int line_offset = 80; + lineTopLeft.Position = new Vector2(-line_offset, -line_offset); + lineTopRight.Position = new Vector2(line_offset, -line_offset); + lineBottomLeft.Position = new Vector2(-line_offset, line_offset); + lineBottomRight.Position = new Vector2(line_offset, line_offset); backgroundFill.Rotation = foregroundFill.Rotation = 0; backgroundFill.Alpha = foregroundFill.Alpha = 1; From 7dcdf78608973eea91cabb1a5417f67ea343a702 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 8 Nov 2017 12:06:22 +0900 Subject: [PATCH 0573/1263] Make bars and circles better --- osu.Game/Screens/Menu/IntroSequence.cs | 86 ++++++++++++++------------ 1 file changed, 47 insertions(+), 39 deletions(-) diff --git a/osu.Game/Screens/Menu/IntroSequence.cs b/osu.Game/Screens/Menu/IntroSequence.cs index c3a45e74a9..5373270d08 100644 --- a/osu.Game/Screens/Menu/IntroSequence.cs +++ b/osu.Game/Screens/Menu/IntroSequence.cs @@ -187,17 +187,56 @@ namespace osu.Game.Screens.Menu }; } + private void setDefaults() + { + welcomeText.Spacing = new Vector2(5); + welcomeText.Alpha = 0; + + smallRing.Size = mediumRing.Size = bigRing.Size = Vector2.Zero; + + bigRing.Foreground.Size = new Vector2(0.85f); + mediumRing.Foreground.Size = new Vector2(0.7f); + smallRing.Foreground.Size = new Vector2(0.6f); + + foreach (var line in linesContainer) + { + line.Size = new Vector2(105, 1.5f); + line.Alpha = 0; + } + + const int line_offset = 80; + lineTopLeft.Position = new Vector2(-line_offset, -line_offset); + lineTopRight.Position = new Vector2(line_offset, -line_offset); + lineBottomLeft.Position = new Vector2(-line_offset, line_offset); + lineBottomRight.Position = new Vector2(line_offset, line_offset); + + backgroundFill.Rotation = foregroundFill.Rotation = 0; + backgroundFill.Alpha = foregroundFill.Alpha = 1; + backgroundFill.Height = foregroundFill.Width = 0; + + yellowCircle.Size = purpleCircle.Size = blueCircle.Size = pinkCircle.Size = Vector2.Zero; + yellowCircle.Rotation = purpleCircle.Rotation = blueCircle.Rotation = pinkCircle.Rotation = 0; + + const int circle_offset = 250; + yellowCircle.Position = new Vector2(0, -circle_offset); + purpleCircle.Position = new Vector2(0, circle_offset); + blueCircle.Position = new Vector2(-circle_offset, 0); + pinkCircle.Position = new Vector2(circle_offset, 0); + } + public void Start(double length) { FinishTransforms(true); setDefaults(); - mediumRing.ResizeTo(130, 360, Easing.InExpo).OnComplete(r => r.Foreground.ResizeTo(1, 420, Easing.OutQuad)); - smallRing.ResizeTo(logo_size * 0.086f, 250, Easing.InExpo).OnComplete(r => r.Foreground.ResizeTo(1, 650, Easing.OutQuad)); + smallRing.ResizeTo(logo_size * 0.086f, 400, Easing.InOutQuint); + + mediumRing.ResizeTo(130, 340, Easing.OutQuad); + mediumRing.Foreground.ResizeTo(1, 880, Easing.Out); Func remainingTime = () => length - TransformDelay; - using (BeginDelayedSequence(360, true)) + using (BeginDelayedSequence(250, true)) { welcomeText.FadeIn(700); welcomeText.TransformSpacingTo(new Vector2(20, 0), remainingTime(), Easing.Out); @@ -207,11 +246,13 @@ namespace osu.Game.Screens.Menu foreach (var line in linesContainer) { - line.FadeIn(); - line.Delay(line_resize).ResizeWidthTo(0, line_duration - line_resize, Easing.OutQuint); + line.FadeIn(40).ResizeWidthTo(0, line_duration - line_resize, Easing.OutQuint); } const int line_end_offset = 120; + + smallRing.Foreground.ResizeTo(1, line_duration, Easing.OutQuint); + lineTopLeft.MoveTo(new Vector2(-line_end_offset, -line_end_offset), line_duration, Easing.OutQuint); lineTopRight.MoveTo(new Vector2(line_end_offset, -line_end_offset), line_duration, Easing.OutQuint); lineBottomLeft.MoveTo(new Vector2(-line_end_offset, line_end_offset), line_duration, Easing.OutQuint); @@ -267,40 +308,6 @@ namespace osu.Game.Screens.Menu } } - private void setDefaults() - { - welcomeText.Spacing = new Vector2(5); - welcomeText.Alpha = 0; - - smallRing.Size = mediumRing.Size = bigRing.Size = Vector2.Zero; - - mediumRing.Foreground.Size = Vector2.One - new Vector2(0.7f); - smallRing.Foreground.Size = Vector2.One - new Vector2(0.4f); - bigRing.Foreground.Size = Vector2.One - new Vector2(0.15f); - - lineTopLeft.Size = lineTopRight.Size = lineBottomLeft.Size = lineBottomRight.Size = new Vector2(105, 1.5f); - lineTopLeft.Alpha = lineTopRight.Alpha = lineBottomLeft.Alpha = lineBottomRight.Alpha = 0; - - const int line_offset = 80; - lineTopLeft.Position = new Vector2(-line_offset, -line_offset); - lineTopRight.Position = new Vector2(line_offset, -line_offset); - lineBottomLeft.Position = new Vector2(-line_offset, line_offset); - lineBottomRight.Position = new Vector2(line_offset, line_offset); - - backgroundFill.Rotation = foregroundFill.Rotation = 0; - backgroundFill.Alpha = foregroundFill.Alpha = 1; - backgroundFill.Height = foregroundFill.Width = 0; - - yellowCircle.Size = purpleCircle.Size = blueCircle.Size = pinkCircle.Size = Vector2.Zero; - yellowCircle.Rotation = purpleCircle.Rotation = blueCircle.Rotation = pinkCircle.Rotation = 0; - - const int circle_offset = 250; - yellowCircle.Position = new Vector2(0, -circle_offset); - purpleCircle.Position = new Vector2(0, circle_offset); - blueCircle.Position = new Vector2(-circle_offset, 0); - pinkCircle.Position = new Vector2(circle_offset, 0); - } - private class Ring : Container { public readonly CircularContainer Foreground; @@ -317,6 +324,7 @@ namespace osu.Game.Screens.Menu Origin = Anchor.Centre, RelativeSizeAxes = Axes.Both, Masking = true, + Scale = new Vector2(0.98f), Child = new Box { RelativeSizeAxes = Axes.Both, From 89426e1c11c7c04c11327f3840482af038542840 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 8 Nov 2017 12:07:52 +0900 Subject: [PATCH 0574/1263] Simplify lines --- osu.Game/Screens/Menu/IntroSequence.cs | 50 +++++++++----------------- 1 file changed, 17 insertions(+), 33 deletions(-) diff --git a/osu.Game/Screens/Menu/IntroSequence.cs b/osu.Game/Screens/Menu/IntroSequence.cs index 5373270d08..c238f77168 100644 --- a/osu.Game/Screens/Menu/IntroSequence.cs +++ b/osu.Game/Screens/Menu/IntroSequence.cs @@ -20,12 +20,12 @@ namespace osu.Game.Screens.Menu private readonly OsuSpriteText welcomeText; - private readonly Container linesContainer; + private readonly Container lines; - private readonly Container lineTopLeft; - private readonly Container lineBottomLeft; - private readonly Container lineTopRight; - private readonly Container lineBottomRight; + private readonly Box lineTopLeft; + private readonly Box lineBottomLeft; + private readonly Box lineTopRight; + private readonly Box lineBottomRight; private readonly Ring smallRing; private readonly Ring mediumRing; @@ -45,56 +45,40 @@ namespace osu.Game.Screens.Menu Children = new Drawable[] { mediumRing = new Ring(Color4.White.Opacity(130)), - linesContainer = new Container + lines = new Container { Anchor = Anchor.Centre, Origin = Anchor.Centre, AutoSizeAxes = Axes.Both, - Children = new Drawable[] + Children = new [] { - lineTopLeft = new Container + lineTopLeft = new Box { Origin = Anchor.CentreLeft, Anchor = Anchor.Centre, Rotation = 45, - Child = new Box - { - RelativeSizeAxes = Axes.Both, - Colour = Color4.White.Opacity(180), - } + Colour = Color4.White.Opacity(180), }, - lineTopRight = new Container + lineTopRight = new Box { Origin = Anchor.CentreRight, Anchor = Anchor.Centre, Rotation = -45, - Child = new Box - { - RelativeSizeAxes = Axes.Both, - Colour = Color4.White.Opacity(80), - } + Colour = Color4.White.Opacity(80), }, - lineBottomLeft = new Container + lineBottomLeft = new Box { Origin = Anchor.CentreLeft, Anchor = Anchor.Centre, Rotation = -45, - Child = new Box - { - RelativeSizeAxes = Axes.Both, - Colour = Color4.White.Opacity(230), - } + Colour = Color4.White.Opacity(230), }, - lineBottomRight = new Container + lineBottomRight = new Box { Origin = Anchor.CentreRight, Anchor = Anchor.Centre, Rotation = 45, - Child = new Box - { - RelativeSizeAxes = Axes.Both, - Colour = Color4.White.Opacity(130), - } + Colour = Color4.White.Opacity(130), }, } }, @@ -198,7 +182,7 @@ namespace osu.Game.Screens.Menu mediumRing.Foreground.Size = new Vector2(0.7f); smallRing.Foreground.Size = new Vector2(0.6f); - foreach (var line in linesContainer) + foreach (var line in lines) { line.Size = new Vector2(105, 1.5f); line.Alpha = 0; @@ -244,7 +228,7 @@ namespace osu.Game.Screens.Menu const int line_duration = 700; const int line_resize = 150; - foreach (var line in linesContainer) + foreach (var line in lines) { line.FadeIn(40).ResizeWidthTo(0, line_duration - line_resize, Easing.OutQuint); } From f83c095269449e81464070d6480bd8e55f0b4f2a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 8 Nov 2017 12:10:32 +0900 Subject: [PATCH 0575/1263] Simplify more --- osu.Game/Screens/Menu/IntroSequence.cs | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/osu.Game/Screens/Menu/IntroSequence.cs b/osu.Game/Screens/Menu/IntroSequence.cs index c238f77168..70d4bb4016 100644 --- a/osu.Game/Screens/Menu/IntroSequence.cs +++ b/osu.Game/Screens/Menu/IntroSequence.cs @@ -31,8 +31,8 @@ namespace osu.Game.Screens.Menu private readonly Ring mediumRing; private readonly Ring bigRing; - private readonly Container backgroundFill; - private readonly Container foregroundFill; + private readonly Box backgroundFill; + private readonly Box foregroundFill; private readonly CircularContainer pinkCircle; private readonly CircularContainer blueCircle; @@ -44,7 +44,6 @@ namespace osu.Game.Screens.Menu RelativeSizeAxes = Axes.Both; Children = new Drawable[] { - mediumRing = new Ring(Color4.White.Opacity(130)), lines = new Container { Anchor = Anchor.Centre, @@ -82,8 +81,9 @@ namespace osu.Game.Screens.Menu }, } }, - smallRing = new Ring(Color4.White), bigRing = new Ring(OsuColour.FromHex(@"B6C5E9")), + mediumRing = new Ring(Color4.White.Opacity(130)), + smallRing = new Ring(Color4.White), new CircularContainer { Anchor = Anchor.Centre, @@ -92,16 +92,12 @@ namespace osu.Game.Screens.Menu Masking = true, Children = new Drawable[] { - backgroundFill = new Container + backgroundFill = new Box { Anchor = Anchor.Centre, Origin = Anchor.Centre, RelativeSizeAxes = Axes.Both, - Child = new Box - { - RelativeSizeAxes = Axes.Both, - Colour = OsuColour.FromHex(@"C6D8FF").Opacity(160), - } + Colour = OsuColour.FromHex(@"C6D8FF").Opacity(160), }, welcomeText = new OsuSpriteText { @@ -111,16 +107,12 @@ namespace osu.Game.Screens.Menu Font = @"Exo2.0-Light", TextSize = 42, }, - foregroundFill = new Container + foregroundFill = new Box { Anchor = Anchor.Centre, Origin = Anchor.Centre, RelativeSizeAxes = Axes.Both, - Child = new Box - { - RelativeSizeAxes = Axes.Both, - Colour = Color4.White, - } + Colour = Color4.White, }, } }, From 419f041291fb42d8cb49104d54abdc952cda360a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 8 Nov 2017 12:12:27 +0900 Subject: [PATCH 0576/1263] Fix text alignment --- osu.Game/Screens/Menu/IntroSequence.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Screens/Menu/IntroSequence.cs b/osu.Game/Screens/Menu/IntroSequence.cs index 70d4bb4016..a207af629a 100644 --- a/osu.Game/Screens/Menu/IntroSequence.cs +++ b/osu.Game/Screens/Menu/IntroSequence.cs @@ -104,6 +104,7 @@ namespace osu.Game.Screens.Menu Anchor = Anchor.Centre, Origin = Anchor.Centre, Text = "welcome", + Padding = new MarginPadding { Bottom = 10 }, Font = @"Exo2.0-Light", TextSize = 42, }, From 1771e003f7908340f5358084d597ab0ed0993cd0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 8 Nov 2017 12:13:30 +0900 Subject: [PATCH 0577/1263] Simplify more --- osu.Game/Screens/Menu/IntroSequence.cs | 32 +++++++------------------- 1 file changed, 8 insertions(+), 24 deletions(-) diff --git a/osu.Game/Screens/Menu/IntroSequence.cs b/osu.Game/Screens/Menu/IntroSequence.cs index a207af629a..9ac075df92 100644 --- a/osu.Game/Screens/Menu/IntroSequence.cs +++ b/osu.Game/Screens/Menu/IntroSequence.cs @@ -117,49 +117,33 @@ namespace osu.Game.Screens.Menu }, } }, - purpleCircle = new CircularContainer + purpleCircle = new Circle { Anchor = Anchor.Centre, Origin = Anchor.TopCentre, Masking = true, - Child = new Box - { - RelativeSizeAxes = Axes.Both, - Colour = OsuColour.FromHex(@"AA92FF"), - } + Colour = OsuColour.FromHex(@"AA92FF"), }, - yellowCircle = new CircularContainer + yellowCircle = new Circle { Anchor = Anchor.Centre, Origin = Anchor.BottomCentre, Masking = true, - Child = new Box - { - RelativeSizeAxes = Axes.Both, - Colour = OsuColour.FromHex(@"FFD64C"), - } + Colour = OsuColour.FromHex(@"FFD64C"), }, - blueCircle = new CircularContainer + blueCircle = new Circle { Anchor = Anchor.Centre, Origin = Anchor.CentreRight, Masking = true, - Child = new Box - { - RelativeSizeAxes = Axes.Both, - Colour = OsuColour.FromHex(@"8FE5FE"), - } + Colour = OsuColour.FromHex(@"8FE5FE"), }, - pinkCircle = new CircularContainer + pinkCircle = new Circle { Anchor = Anchor.Centre, Origin = Anchor.CentreLeft, Masking = true, - Child = new Box - { - RelativeSizeAxes = Axes.Both, - Colour = OsuColour.FromHex(@"e967a1"), - } + Colour = OsuColour.FromHex(@"e967a1"), }, }; } From 713d730d1093b005e54a233231c660d9d2d7692c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 8 Nov 2017 13:21:26 +0900 Subject: [PATCH 0578/1263] Simplify restart process and defaults initialisation --- osu.Game/Screens/Menu/IntroSequence.cs | 170 +++++++++++-------------- 1 file changed, 76 insertions(+), 94 deletions(-) diff --git a/osu.Game/Screens/Menu/IntroSequence.cs b/osu.Game/Screens/Menu/IntroSequence.cs index 9ac075df92..0c68410c92 100644 --- a/osu.Game/Screens/Menu/IntroSequence.cs +++ b/osu.Game/Screens/Menu/IntroSequence.cs @@ -2,8 +2,10 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; +using System.Linq; using OpenTK; using OpenTK.Graphics; +using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -15,33 +17,40 @@ namespace osu.Game.Screens.Menu { public class IntroSequence : Container { - //Size private const float logo_size = 460; //todo: this should probably be 480 - private readonly OsuSpriteText welcomeText; + private OsuSpriteText welcomeText; - private readonly Container lines; + private Container lines; - private readonly Box lineTopLeft; - private readonly Box lineBottomLeft; - private readonly Box lineTopRight; - private readonly Box lineBottomRight; + private Box lineTopLeft; + private Box lineBottomLeft; + private Box lineTopRight; + private Box lineBottomRight; - private readonly Ring smallRing; - private readonly Ring mediumRing; - private readonly Ring bigRing; + private Ring smallRing; + private Ring mediumRing; + private Ring bigRing; - private readonly Box backgroundFill; - private readonly Box foregroundFill; + private Box backgroundFill; + private Box foregroundFill; - private readonly CircularContainer pinkCircle; - private readonly CircularContainer blueCircle; - private readonly CircularContainer yellowCircle; - private readonly CircularContainer purpleCircle; + private CircularContainer pinkCircle; + private CircularContainer blueCircle; + private CircularContainer yellowCircle; + private CircularContainer purpleCircle; public IntroSequence() { RelativeSizeAxes = Axes.Both; + } + + [BackgroundDependencyLoader] + private void load() + { + const int line_offset = 80; + const int circle_offset = 250; + Children = new Drawable[] { lines = new Container @@ -55,6 +64,7 @@ namespace osu.Game.Screens.Menu { Origin = Anchor.CentreLeft, Anchor = Anchor.Centre, + Position = new Vector2(-line_offset, -line_offset), Rotation = 45, Colour = Color4.White.Opacity(180), }, @@ -62,6 +72,7 @@ namespace osu.Game.Screens.Menu { Origin = Anchor.CentreRight, Anchor = Anchor.Centre, + Position = new Vector2(line_offset, -line_offset), Rotation = -45, Colour = Color4.White.Opacity(80), }, @@ -69,6 +80,7 @@ namespace osu.Game.Screens.Menu { Origin = Anchor.CentreLeft, Anchor = Anchor.Centre, + Position = new Vector2(-line_offset, line_offset), Rotation = -45, Colour = Color4.White.Opacity(230), }, @@ -76,14 +88,26 @@ namespace osu.Game.Screens.Menu { Origin = Anchor.CentreRight, Anchor = Anchor.Centre, + Position = new Vector2(line_offset, line_offset), Rotation = 45, Colour = Color4.White.Opacity(130), }, } }, - bigRing = new Ring(OsuColour.FromHex(@"B6C5E9")), - mediumRing = new Ring(Color4.White.Opacity(130)), - smallRing = new Ring(Color4.White), + bigRing = new Ring(OsuColour.FromHex(@"B6C5E9"), 0.85f), + mediumRing = new Ring(Color4.White.Opacity(130), 0.7f), + smallRing = new Ring(Color4.White, 0.6f), + welcomeText = new OsuSpriteText + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Text = "welcome", + Padding = new MarginPadding { Bottom = 10 }, + Font = @"Exo2.0-Light", + Alpha = 0, + TextSize = 42, + Spacing = new Vector2(5), + }, new CircularContainer { Anchor = Anchor.Centre, @@ -97,98 +121,65 @@ namespace osu.Game.Screens.Menu Anchor = Anchor.Centre, Origin = Anchor.Centre, RelativeSizeAxes = Axes.Both, + Height = 0, Colour = OsuColour.FromHex(@"C6D8FF").Opacity(160), }, - welcomeText = new OsuSpriteText - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Text = "welcome", - Padding = new MarginPadding { Bottom = 10 }, - Font = @"Exo2.0-Light", - TextSize = 42, - }, foregroundFill = new Box { Anchor = Anchor.Centre, Origin = Anchor.Centre, + Size = Vector2.Zero, RelativeSizeAxes = Axes.Both, + Width = 0, Colour = Color4.White, }, } }, - purpleCircle = new Circle - { - Anchor = Anchor.Centre, - Origin = Anchor.TopCentre, - Masking = true, - Colour = OsuColour.FromHex(@"AA92FF"), - }, yellowCircle = new Circle { Anchor = Anchor.Centre, Origin = Anchor.BottomCentre, - Masking = true, + Position = new Vector2(0, -circle_offset), Colour = OsuColour.FromHex(@"FFD64C"), }, - blueCircle = new Circle - { - Anchor = Anchor.Centre, - Origin = Anchor.CentreRight, - Masking = true, - Colour = OsuColour.FromHex(@"8FE5FE"), - }, pinkCircle = new Circle { Anchor = Anchor.Centre, Origin = Anchor.CentreLeft, - Masking = true, + Position = new Vector2(circle_offset, 0), Colour = OsuColour.FromHex(@"e967a1"), }, + purpleCircle = new Circle + { + Anchor = Anchor.Centre, + Origin = Anchor.TopCentre, + Position = new Vector2(0, circle_offset), + Colour = OsuColour.FromHex(@"AA92FF"), + }, + blueCircle = new Circle + { + Anchor = Anchor.Centre, + Origin = Anchor.CentreRight, + Position = new Vector2(-circle_offset, 0), + Colour = OsuColour.FromHex(@"8FE5FE"), + }, }; - } - - private void setDefaults() - { - welcomeText.Spacing = new Vector2(5); - welcomeText.Alpha = 0; - - smallRing.Size = mediumRing.Size = bigRing.Size = Vector2.Zero; - - bigRing.Foreground.Size = new Vector2(0.85f); - mediumRing.Foreground.Size = new Vector2(0.7f); - smallRing.Foreground.Size = new Vector2(0.6f); foreach (var line in lines) { line.Size = new Vector2(105, 1.5f); line.Alpha = 0; } - - const int line_offset = 80; - lineTopLeft.Position = new Vector2(-line_offset, -line_offset); - lineTopRight.Position = new Vector2(line_offset, -line_offset); - lineBottomLeft.Position = new Vector2(-line_offset, line_offset); - lineBottomRight.Position = new Vector2(line_offset, line_offset); - - backgroundFill.Rotation = foregroundFill.Rotation = 0; - backgroundFill.Alpha = foregroundFill.Alpha = 1; - backgroundFill.Height = foregroundFill.Width = 0; - - yellowCircle.Size = purpleCircle.Size = blueCircle.Size = pinkCircle.Size = Vector2.Zero; - yellowCircle.Rotation = purpleCircle.Rotation = blueCircle.Rotation = pinkCircle.Rotation = 0; - - const int circle_offset = 250; - yellowCircle.Position = new Vector2(0, -circle_offset); - purpleCircle.Position = new Vector2(0, circle_offset); - blueCircle.Position = new Vector2(-circle_offset, 0); - pinkCircle.Position = new Vector2(circle_offset, 0); } public void Start(double length) { - FinishTransforms(true); - setDefaults(); + if (Children.Any()) + { + // restart if we were already run previously. + FinishTransforms(true); + load(); + } smallRing.ResizeTo(logo_size * 0.086f, 400, Easing.InOutQuint); @@ -269,40 +260,31 @@ namespace osu.Game.Screens.Menu } } - private class Ring : Container + private class Ring : Container { - public readonly CircularContainer Foreground; + public readonly Circle Foreground; - public Ring(Color4 ringColour) + public Ring(Color4 ringColour, float foregroundSize) { Anchor = Anchor.Centre; Origin = Anchor.Centre; Children = new[] { - new CircularContainer + new Circle { Anchor = Anchor.Centre, Origin = Anchor.Centre, RelativeSizeAxes = Axes.Both, - Masking = true, Scale = new Vector2(0.98f), - Child = new Box - { - RelativeSizeAxes = Axes.Both, - Colour = ringColour, - } + Colour = ringColour, }, - Foreground = new CircularContainer + Foreground = new Circle { + Size = new Vector2(foregroundSize), Anchor = Anchor.Centre, Origin = Anchor.Centre, RelativeSizeAxes = Axes.Both, - Masking = true, - Child = new Box - { - RelativeSizeAxes = Axes.Both, - Colour = Color4.Black, - } + Colour = Color4.Black, } }; } From d8d7165164db8353541839e36889c44cda7b1e8d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 8 Nov 2017 13:52:44 +0900 Subject: [PATCH 0579/1263] Add a test case which starts the game --- osu.Game.Tests/Visual/TestCaseOsuGame.cs | 39 ++++++++++++++++++++++++ osu.Game.Tests/osu.Game.Tests.csproj | 1 + osu.Game/Screens/Loader.cs | 4 +-- osu.Game/Screens/Menu/MainMenu.cs | 11 ++++--- 4 files changed, 49 insertions(+), 6 deletions(-) create mode 100644 osu.Game.Tests/Visual/TestCaseOsuGame.cs diff --git a/osu.Game.Tests/Visual/TestCaseOsuGame.cs b/osu.Game.Tests/Visual/TestCaseOsuGame.cs new file mode 100644 index 0000000000..3f869e7378 --- /dev/null +++ b/osu.Game.Tests/Visual/TestCaseOsuGame.cs @@ -0,0 +1,39 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using System.Collections.Generic; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Timing; +using osu.Game.Screens; +using osu.Game.Screens.Menu; +using OpenTK.Graphics; + +namespace osu.Game.Tests.Visual +{ + public class TestCaseOsuGame : OsuTestCase + { + public override IReadOnlyList RequiredTypes => new[] + { + typeof(OsuLogo), + }; + + public TestCaseOsuGame() + { + var rateAdjustClock = new StopwatchClock(true); + var framedClock = new FramedClock(rateAdjustClock); + framedClock.ProcessFrame(); + + Add(new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Black, + }); + + Add(new Loader()); + + AddSliderStep("Playback speed", 0.0, 2.0, 1, v => rateAdjustClock.Rate = v); + } + } +} diff --git a/osu.Game.Tests/osu.Game.Tests.csproj b/osu.Game.Tests/osu.Game.Tests.csproj index 4cc06df609..b1081890c8 100644 --- a/osu.Game.Tests/osu.Game.Tests.csproj +++ b/osu.Game.Tests/osu.Game.Tests.csproj @@ -122,6 +122,7 @@ + diff --git a/osu.Game/Screens/Loader.cs b/osu.Game/Screens/Loader.cs index 6de53aeeb0..6680864368 100644 --- a/osu.Game/Screens/Loader.cs +++ b/osu.Game/Screens/Loader.cs @@ -8,7 +8,7 @@ using OpenTK; namespace osu.Game.Screens { - internal class Loader : OsuScreen + public class Loader : OsuScreen { public override bool ShowOverlays => false; @@ -30,7 +30,7 @@ namespace osu.Game.Screens } [BackgroundDependencyLoader] - private void load(OsuGame game) + private void load(OsuGameBase game) { if (game.IsDeployedBuild) LoadComponentAsync(new Disclaimer(), d => Push(d)); diff --git a/osu.Game/Screens/Menu/MainMenu.cs b/osu.Game/Screens/Menu/MainMenu.cs index 77e45c4575..7729211c4c 100644 --- a/osu.Game/Screens/Menu/MainMenu.cs +++ b/osu.Game/Screens/Menu/MainMenu.cs @@ -59,13 +59,16 @@ namespace osu.Game.Screens.Menu }; } - [BackgroundDependencyLoader] - private void load(OsuGame game) + [BackgroundDependencyLoader(true)] + private void load(OsuGame game = null) { LoadComponentAsync(background); - buttons.OnSettings = game.ToggleSettings; - buttons.OnDirect = game.ToggleDirect; + if (game != null) + { + buttons.OnSettings = game.ToggleSettings; + buttons.OnDirect = game.ToggleDirect; + } preloadSongSelect(); } From 41fcecf759a4a0c287d3ea28861963d3b68c8b22 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 8 Nov 2017 14:31:11 +0900 Subject: [PATCH 0580/1263] Add intro in to actual game --- osu.Game/Screens/Menu/Intro.cs | 12 +++++------- osu.Game/Screens/Menu/IntroSequence.cs | 4 ++-- osu.Game/Screens/Menu/OsuLogo.cs | 4 ++-- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/osu.Game/Screens/Menu/Intro.cs b/osu.Game/Screens/Menu/Intro.cs index 490b2b3346..311e453a65 100644 --- a/osu.Game/Screens/Menu/Intro.cs +++ b/osu.Game/Screens/Menu/Intro.cs @@ -117,8 +117,8 @@ namespace osu.Game.Screens.Menu logo.RelativePositionAxes = Axes.Both; - logo.Triangles = false; - logo.Colour = Color4.DarkGray; + logo.Triangles = true; + logo.Colour = Color4.White; logo.Ripple = false; const int quick_appear = 350; @@ -129,11 +129,9 @@ namespace osu.Game.Screens.Menu if (!resuming) { - logo.ScaleTo(0.4f); - logo.FadeOut(); - - logo.ScaleTo(1, delay_step_one + delay_step_two, Easing.OutQuint); - logo.FadeIn(delay_step_one + delay_step_two, Easing.OutQuint); + logo.ScaleTo(1); + logo.FadeIn(); + logo.PlayIntro(); } else { diff --git a/osu.Game/Screens/Menu/IntroSequence.cs b/osu.Game/Screens/Menu/IntroSequence.cs index 0c68410c92..25265eed76 100644 --- a/osu.Game/Screens/Menu/IntroSequence.cs +++ b/osu.Game/Screens/Menu/IntroSequence.cs @@ -210,12 +210,12 @@ namespace osu.Game.Screens.Menu lineBottomLeft.MoveTo(new Vector2(-line_end_offset, line_end_offset), line_duration, Easing.OutQuint); lineBottomRight.MoveTo(new Vector2(line_end_offset, line_end_offset), line_duration, Easing.OutQuint); - using (BeginDelayedSequence(1640, true)) // 2000 + using (BeginDelayedSequence(length * 0.56, true)) { bigRing.ResizeTo(logo_size * 0.86f, 500, Easing.InOutQuint); bigRing.Foreground.Delay(250).ResizeTo(1, 450, Easing.OutExpo); - using (BeginDelayedSequence(250, true)) // 2250 + using (BeginDelayedSequence(250, true)) { backgroundFill.ResizeHeightTo(1, remainingTime(), Easing.InOutQuart); backgroundFill.RotateTo(-90, remainingTime(), Easing.InOutQuart); diff --git a/osu.Game/Screens/Menu/OsuLogo.cs b/osu.Game/Screens/Menu/OsuLogo.cs index 6215cb5660..f7c485cf19 100644 --- a/osu.Game/Screens/Menu/OsuLogo.cs +++ b/osu.Game/Screens/Menu/OsuLogo.cs @@ -297,8 +297,8 @@ namespace osu.Game.Screens.Menu public void PlayIntro() { - const double length = 2950; - const double fade = 300; + const double length = 3150; + const double fade = 200; logoHoverContainer.FadeOut().Delay(length).FadeIn(fade); intro.Show(); From fafca093e8ca56bfab9395f7c571dd956443eb83 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 8 Nov 2017 14:43:15 +0900 Subject: [PATCH 0581/1263] Update framework --- osu-framework | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu-framework b/osu-framework index 3c074a0981..ded020da31 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit 3c074a0981844fbaa9f2ecbf879c542f07e2b94d +Subproject commit ded020da31505c124fa0414e85816e6201f235ed From 7ad498cb2921fca0db5eb906d76019a5beaea750 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 8 Nov 2017 14:45:01 +0900 Subject: [PATCH 0582/1263] Remove unused puzzle pieces --- osu.Game/Screens/Menu/ButtonSystem.cs | 2 -- osu.Game/Screens/Menu/OsuLogo.cs | 24 ------------------------ 2 files changed, 26 deletions(-) diff --git a/osu.Game/Screens/Menu/ButtonSystem.cs b/osu.Game/Screens/Menu/ButtonSystem.cs index 6f9b77e18e..33d118d12e 100644 --- a/osu.Game/Screens/Menu/ButtonSystem.cs +++ b/osu.Game/Screens/Menu/ButtonSystem.cs @@ -326,8 +326,6 @@ namespace osu.Game.Screens.Menu private bool trackingPosition; - public void SetLogoTracking(bool value) => trackingPosition = value; - protected override void Update() { //if (OsuGame.IdleTime > 6000 && State != MenuState.Exit) diff --git a/osu.Game/Screens/Menu/OsuLogo.cs b/osu.Game/Screens/Menu/OsuLogo.cs index 297076a78b..5a5b90b3fb 100644 --- a/osu.Game/Screens/Menu/OsuLogo.cs +++ b/osu.Game/Screens/Menu/OsuLogo.cs @@ -224,27 +224,6 @@ namespace osu.Game.Screens.Menu ripple.Texture = textures.Get(@"Menu/logo"); } - private double? reservationEndTime; - private Action reservationCallback; - - private bool canFulfillReservation => !reservationEndTime.HasValue || reservationEndTime <= Time.Current; - - public void RequestUsage(Action callback) - { - reservationCallback = callback; - } - - private void fulfillReservation() - { - reservationCallback(this); - reservationCallback = null; - } - - public void ReserveFor(float duration) - { - reservationEndTime = Time.Current + duration; - } - private int lastBeatIndex; protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, TrackAmplitudes amplitudes) @@ -311,9 +290,6 @@ namespace osu.Game.Screens.Menu { triangles.Velocity = paused_velocity; } - - if (reservationCallback != null && canFulfillReservation) - fulfillReservation(); } private bool interactive => Action != null && Alpha > 0.2f; From a8bacd1ed48604583bfa94f17bf2e6cd838e2dde Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 8 Nov 2017 14:46:47 +0900 Subject: [PATCH 0583/1263] Remove unnecessary private method /shrug --- osu.Game/Screens/OsuScreen.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/OsuScreen.cs b/osu.Game/Screens/OsuScreen.cs index 5ecfcd8e8d..a7e1dd0f25 100644 --- a/osu.Game/Screens/OsuScreen.cs +++ b/osu.Game/Screens/OsuScreen.cs @@ -76,7 +76,7 @@ namespace osu.Game.Screens protected override void OnResuming(Screen last) { base.OnResuming(last); - logo.DelayUntilTransformsFinished().Schedule(() => logoSetup(true)); + logo.DelayUntilTransformsFinished().Schedule(() => LogoSetup(logo, true)); sampleExit?.Play(); } @@ -122,7 +122,7 @@ namespace osu.Game.Screens base.OnEntering(last); - logo.DelayUntilTransformsFinished().Schedule(() => logoSetup(false)); + logo.DelayUntilTransformsFinished().Schedule(() => LogoSetup(logo, false)); } protected override bool OnExiting(Screen next) @@ -148,8 +148,6 @@ namespace osu.Game.Screens return false; } - private void logoSetup(bool resuming) => LogoSetup(logo, resuming); - protected virtual void LogoSetup(OsuLogo logo, bool resuming) { logo.Action = null; From c2d4a213b125b77a8418caa3c1187c42cd8e272e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 8 Nov 2017 16:34:03 +0900 Subject: [PATCH 0584/1263] Rename logo-related methods --- osu.Game/Screens/Loader.cs | 4 ++-- osu.Game/Screens/Menu/Intro.cs | 4 ++-- osu.Game/Screens/Menu/MainMenu.cs | 6 +++--- osu.Game/Screens/OsuScreen.cs | 31 +++++++++++++++++---------- osu.Game/Screens/Play/PlayerLoader.cs | 4 ++-- osu.Game/Screens/Select/SongSelect.cs | 8 +++---- 6 files changed, 33 insertions(+), 24 deletions(-) diff --git a/osu.Game/Screens/Loader.cs b/osu.Game/Screens/Loader.cs index 6de53aeeb0..8c70e2421b 100644 --- a/osu.Game/Screens/Loader.cs +++ b/osu.Game/Screens/Loader.cs @@ -17,9 +17,9 @@ namespace osu.Game.Screens ValidForResume = false; } - protected override void LogoSetup(OsuLogo logo, bool resuming) + protected override void OnArrivedLogo(OsuLogo logo, bool resuming) { - base.LogoSetup(logo, resuming); + base.OnArrivedLogo(logo, resuming); logo.RelativePositionAxes = Axes.Both; logo.Triangles = false; diff --git a/osu.Game/Screens/Menu/Intro.cs b/osu.Game/Screens/Menu/Intro.cs index 9efe7455f7..2cd51f05db 100644 --- a/osu.Game/Screens/Menu/Intro.cs +++ b/osu.Game/Screens/Menu/Intro.cs @@ -109,9 +109,9 @@ namespace osu.Game.Screens.Menu public const int EXIT_DELAY = 3000; - protected override void LogoSetup(OsuLogo logo, bool resuming) + protected override void OnArrivedLogo(OsuLogo logo, bool resuming) { - base.LogoSetup(logo, resuming); + base.OnArrivedLogo(logo, resuming); logo.RelativePositionAxes = Axes.Both; diff --git a/osu.Game/Screens/Menu/MainMenu.cs b/osu.Game/Screens/Menu/MainMenu.cs index 77e45c4575..6f01199a60 100644 --- a/osu.Game/Screens/Menu/MainMenu.cs +++ b/osu.Game/Screens/Menu/MainMenu.cs @@ -103,9 +103,9 @@ namespace osu.Game.Screens.Menu Beatmap.ValueChanged += beatmap_ValueChanged; } - protected override void LogoSetup(OsuLogo logo, bool resuming) + protected override void OnArrivedLogo(OsuLogo logo, bool resuming) { - base.LogoSetup(logo, resuming); + base.OnArrivedLogo(logo, resuming); buttons.SetOsuLogo(logo); @@ -119,7 +119,7 @@ namespace osu.Game.Screens.Menu buttons.State = MenuState.TopLevel; } - protected override void LogoOnSuspending(OsuLogo logo) + protected override void OnSuspendingLogo(OsuLogo logo) { logo.FadeOut(300, Easing.InSine) .ScaleTo(0.2f, 300, Easing.InSine) diff --git a/osu.Game/Screens/OsuScreen.cs b/osu.Game/Screens/OsuScreen.cs index a7e1dd0f25..2693ad97fa 100644 --- a/osu.Game/Screens/OsuScreen.cs +++ b/osu.Game/Screens/OsuScreen.cs @@ -76,14 +76,14 @@ namespace osu.Game.Screens protected override void OnResuming(Screen last) { base.OnResuming(last); - logo.DelayUntilTransformsFinished().Schedule(() => LogoSetup(logo, true)); + logo.DelayUntilTransformsFinished().Schedule(() => OnArrivedLogo(logo, true)); sampleExit?.Play(); } protected override void OnSuspending(Screen next) { base.OnSuspending(next); - logoOnSuspending(); + onSuspendingLogo(); } protected override void OnEntering(Screen last) @@ -122,13 +122,13 @@ namespace osu.Game.Screens base.OnEntering(last); - logo.DelayUntilTransformsFinished().Schedule(() => LogoSetup(logo, false)); + logo.DelayUntilTransformsFinished().Schedule(() => OnArrivedLogo(logo, false)); } protected override bool OnExiting(Screen next) { if (ValidForResume && logo != null) - logoOnExiting(); + onExitingLogo(); OsuScreen nextOsu = next as OsuScreen; @@ -148,29 +148,38 @@ namespace osu.Game.Screens return false; } - protected virtual void LogoSetup(OsuLogo logo, bool resuming) + /// + /// Fired when this screen was entered or resumed and the logo state is required to be adjusted. + /// + protected virtual void OnArrivedLogo(OsuLogo logo, bool resuming) { logo.Action = null; logo.FadeOut(300, Easing.OutQuint); } - private void logoOnExiting() + private void onExitingLogo() { logo.ClearTransforms(); - LogoOnExiting(logo); + OnExitingLogo(logo); } - protected virtual void LogoOnExiting(OsuLogo logo) + /// + /// Fired when this screen was exited to add any outwards transition to the logo. + /// + protected virtual void OnExitingLogo(OsuLogo logo) { } - private void logoOnSuspending() + private void onSuspendingLogo() { logo.ClearTransforms(); - LogoOnSuspending(logo); + OnSuspendingLogo(logo); } - protected virtual void LogoOnSuspending(OsuLogo logo) + /// + /// Fired when this screen was suspended to add any outwards transition to the logo. + /// + protected virtual void OnSuspendingLogo(OsuLogo logo) { } } diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index e53026fb8d..6e96fb8b71 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -95,9 +95,9 @@ namespace osu.Game.Screens.Play this.Delay(2150).Schedule(pushWhenLoaded); } - protected override void LogoSetup(OsuLogo logo, bool resuming) + protected override void OnArrivedLogo(OsuLogo logo, bool resuming) { - base.LogoSetup(logo, resuming); + base.OnArrivedLogo(logo, resuming); logo.ClearTransforms(targetMember: nameof(Position)); logo.RelativePositionAxes = Axes.Both; diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index f9e3b0902d..11e7d452fa 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -311,9 +311,9 @@ namespace osu.Game.Screens.Select private const double logo_transition = 250; - protected override void LogoSetup(OsuLogo logo, bool resuming) + protected override void OnArrivedLogo(OsuLogo logo, bool resuming) { - base.LogoSetup(logo, resuming); + base.OnArrivedLogo(logo, resuming); logo.ClearTransforms(); logo.RelativePositionAxes = Axes.Both; @@ -337,9 +337,9 @@ namespace osu.Game.Screens.Select logo.Action = () => carouselRaisedStart(); } - protected override void LogoOnExiting(OsuLogo logo) + protected override void OnExitingLogo(OsuLogo logo) { - base.LogoOnExiting(logo); + base.OnExitingLogo(logo); logo.ScaleTo(0.2f, logo_transition, Easing.OutQuint); logo.FadeOut(logo_transition, Easing.OutQuint); } From df6c808d28dfe7bfa216646e4fac4de6a030c55d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 8 Nov 2017 17:04:36 +0900 Subject: [PATCH 0585/1263] Adjust animation to designer-san's liking --- osu.Game/Screens/Menu/IntroSequence.cs | 56 ++++++++++++++------------ 1 file changed, 30 insertions(+), 26 deletions(-) diff --git a/osu.Game/Screens/Menu/IntroSequence.cs b/osu.Game/Screens/Menu/IntroSequence.cs index 25265eed76..f8886f8dc1 100644 --- a/osu.Game/Screens/Menu/IntroSequence.cs +++ b/osu.Game/Screens/Menu/IntroSequence.cs @@ -135,20 +135,6 @@ namespace osu.Game.Screens.Menu }, } }, - yellowCircle = new Circle - { - Anchor = Anchor.Centre, - Origin = Anchor.BottomCentre, - Position = new Vector2(0, -circle_offset), - Colour = OsuColour.FromHex(@"FFD64C"), - }, - pinkCircle = new Circle - { - Anchor = Anchor.Centre, - Origin = Anchor.CentreLeft, - Position = new Vector2(circle_offset, 0), - Colour = OsuColour.FromHex(@"e967a1"), - }, purpleCircle = new Circle { Anchor = Anchor.Centre, @@ -163,6 +149,20 @@ namespace osu.Game.Screens.Menu Position = new Vector2(-circle_offset, 0), Colour = OsuColour.FromHex(@"8FE5FE"), }, + yellowCircle = new Circle + { + Anchor = Anchor.Centre, + Origin = Anchor.BottomCentre, + Position = new Vector2(0, -circle_offset), + Colour = OsuColour.FromHex(@"FFD64C"), + }, + pinkCircle = new Circle + { + Anchor = Anchor.Centre, + Origin = Anchor.CentreLeft, + Position = new Vector2(circle_offset, 0), + Colour = OsuColour.FromHex(@"e967a1"), + }, }; foreach (var line in lines) @@ -170,6 +170,8 @@ namespace osu.Game.Screens.Menu line.Size = new Vector2(105, 1.5f); line.Alpha = 0; } + + Scale = new Vector2(0.5f); } public void Start(double length) @@ -226,32 +228,34 @@ namespace osu.Game.Screens.Menu foregroundFill.RotateTo(-90, remainingTime(), Easing.InOutQuart); } + this.ScaleTo(1, remainingTime(), Easing.InOutCubic); + const float circle_size = logo_size * 0.9f; const int rotation_delay = 110; const int appear_delay = 80; - purpleCircle.MoveToY(circle_size / 2, remainingTime(), Easing.InOutQuad); - purpleCircle.Delay(rotation_delay).RotateTo(-180, remainingTime() - rotation_delay, Easing.OutQuad); - purpleCircle.ResizeTo(circle_size, remainingTime(), Easing.InOutQuad); + purpleCircle.MoveToY(circle_size / 2, remainingTime(), Easing.InOutQuart); + purpleCircle.Delay(rotation_delay).RotateTo(-180, remainingTime() - rotation_delay, Easing.InOutQuart); + purpleCircle.ResizeTo(circle_size, remainingTime(), Easing.InOutQuart); using (BeginDelayedSequence(appear_delay, true)) { - yellowCircle.MoveToY(-circle_size / 2, remainingTime(), Easing.InOutQuad); - yellowCircle.Delay(rotation_delay).RotateTo(-180, remainingTime() - rotation_delay, Easing.OutQuad); - yellowCircle.ResizeTo(circle_size, remainingTime(), Easing.InOutQuad); + yellowCircle.MoveToY(-circle_size / 2, remainingTime(), Easing.InOutQuart); + yellowCircle.Delay(rotation_delay).RotateTo(-180, remainingTime() - rotation_delay, Easing.InOutQuart); + yellowCircle.ResizeTo(circle_size, remainingTime(), Easing.InOutQuart); using (BeginDelayedSequence(appear_delay, true)) { - blueCircle.MoveToX(-circle_size / 2, remainingTime(), Easing.InOutQuad); - blueCircle.Delay(rotation_delay).RotateTo(-180, remainingTime() - rotation_delay, Easing.OutQuad); - blueCircle.ResizeTo(circle_size, remainingTime(), Easing.InOutQuad); + blueCircle.MoveToX(-circle_size / 2, remainingTime(), Easing.InOutQuart); + blueCircle.Delay(rotation_delay).RotateTo(-180, remainingTime() - rotation_delay, Easing.InOutQuart); + blueCircle.ResizeTo(circle_size, remainingTime(), Easing.InOutQuart); using (BeginDelayedSequence(appear_delay, true)) { - pinkCircle.MoveToX(circle_size / 2, remainingTime(), Easing.InOutQuad); - pinkCircle.Delay(rotation_delay).RotateTo(-180, remainingTime() - rotation_delay, Easing.OutQuad); - pinkCircle.ResizeTo(circle_size, remainingTime(), Easing.InOutQuad); + pinkCircle.MoveToX(circle_size / 2, remainingTime(), Easing.InOutQuart); + pinkCircle.Delay(rotation_delay).RotateTo(-180, remainingTime() - rotation_delay, Easing.InOutQuart); + pinkCircle.ResizeTo(circle_size, remainingTime(), Easing.InOutQuart); } } } From e2005c44316754c2884e01e2dad2bdcc8d4f2761 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 8 Nov 2017 20:36:18 +0900 Subject: [PATCH 0586/1263] Add comment explaining necessity of AlwaysPresent for now --- osu.Game/Screens/Menu/OsuLogo.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Screens/Menu/OsuLogo.cs b/osu.Game/Screens/Menu/OsuLogo.cs index 5a5b90b3fb..3b79749341 100644 --- a/osu.Game/Screens/Menu/OsuLogo.cs +++ b/osu.Game/Screens/Menu/OsuLogo.cs @@ -77,6 +77,7 @@ namespace osu.Game.Screens.Menu public OsuLogo() { + // Required to make Schedule calls run in OsuScreen even when we are not visible. AlwaysPresent = true; EarlyActivationMilliseconds = early_activation; From edeeefea3b85808bc48e41456e226d213a46eb48 Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Wed, 8 Nov 2017 20:42:24 +0300 Subject: [PATCH 0587/1263] Fix missing text has been shown before api request has been completed --- .../Sections/Beatmaps/PaginatedBeatmapContainer.cs | 8 +++++--- osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs | 4 ++-- .../Profile/Sections/Ranks/PaginatedScoreContainer.cs | 6 +++++- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs b/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs index 2ac7a29177..2607585573 100644 --- a/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs @@ -41,9 +41,11 @@ namespace osu.Game.Overlays.Profile.Sections.Beatmaps ShowMoreButton.FadeTo(sets.Count == ItemsPerPage ? 1 : 0); ShowMoreLoading.Hide(); - if (!sets.Any()) return; - - MissingText.Hide(); + if (!sets.Any()) + { + MissingText.Show(); + return; + } foreach (var s in sets) { diff --git a/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs b/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs index d0ccf6af41..b75d1bc4d6 100644 --- a/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs @@ -74,7 +74,8 @@ namespace osu.Game.Overlays.Profile.Sections MissingText = new OsuSpriteText { TextSize = 14, - Text = missing + Text = missing, + Alpha = 0, }, }; } @@ -94,7 +95,6 @@ namespace osu.Game.Overlays.Profile.Sections VisiblePages = 0; ItemsContainer.Clear(); ShowMoreButton.Hide(); - MissingText.Show(); if (newUser != null) ShowMore(); diff --git a/osu.Game/Overlays/Profile/Sections/Ranks/PaginatedScoreContainer.cs b/osu.Game/Overlays/Profile/Sections/Ranks/PaginatedScoreContainer.cs index 4c2bea4554..eab708f978 100644 --- a/osu.Game/Overlays/Profile/Sections/Ranks/PaginatedScoreContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/Ranks/PaginatedScoreContainer.cs @@ -41,7 +41,11 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks ShowMoreButton.FadeTo(scores.Count == ItemsPerPage ? 1 : 0); ShowMoreLoading.Hide(); - if (!scores.Any()) return; + if (!scores.Any()) + { + MissingText.Show(); + return; + } MissingText.Hide(); From 348083f589e0faff13d33878fd71ed3e6dac94d0 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 9 Nov 2017 14:04:59 +0900 Subject: [PATCH 0588/1263] Update with framework state transformation Removes explicit initial state setting in DrawableOsuHitObjects. --- osu-framework | 2 +- .../Objects/Drawables/DrawableHitCircle.cs | 21 ++----------------- .../Objects/Drawables/DrawableOsuHitObject.cs | 15 +++++-------- .../Objects/Drawables/DrawableRepeatPoint.cs | 12 +---------- .../Objects/Drawables/DrawableSlider.cs | 14 +++---------- .../Objects/Drawables/DrawableSliderTick.cs | 4 ---- .../Objects/Drawables/DrawableHitObject.cs | 3 +++ 7 files changed, 15 insertions(+), 56 deletions(-) diff --git a/osu-framework b/osu-framework index c8222d1dc9..b70ca3de9e 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit c8222d1dc932aafe17ec42bfbe6cbec81851f55d +Subproject commit b70ca3de9ec1a8eb7fb73fcfd169ff38d00b07cd diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs index ed0578d3a4..a973d2b580 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs @@ -58,6 +58,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables }, ApproachCircle = new ApproachCircle { + Alpha = 0, + Scale = new Vector2(4), Colour = AccentColour, } }; @@ -82,25 +84,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables }); } - protected override void UpdateInitialState() - { - base.UpdateInitialState(); - - // Hide() cannot be used here, because when rewinding, we need these to be the final values - - ring.Alpha = 1; - circle.Alpha = 1; - number.Alpha = 1; - glow.Alpha = 1; - - ApproachCircle.Alpha = 0; - ApproachCircle.Scale = new Vector2(4); - explode.Alpha = 0; - flash.Alpha = 0; - - Scale = new Vector2(HitObject.Scale); - } - protected override void UpdatePreemptState() { base.UpdatePreemptState(); diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs index 7429f084c3..e968e5b9df 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs @@ -23,12 +23,13 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables protected sealed override void UpdateState(ArmedState state) { - ClearTransforms(true); + double transformTime = HitObject.StartTime - TIME_PREEMPT; - using (BeginAbsoluteSequence(HitObject.StartTime - TIME_PREEMPT, true)) + TransformStateTo(transformTime, true); + ClearTransformsAfter(transformTime, true); + + using (BeginAbsoluteSequence(transformTime, true)) { - UpdateInitialState(); - UpdatePreemptState(); using (BeginDelayedSequence(TIME_PREEMPT + (Judgements.FirstOrDefault()?.TimeOffset ?? 0), true)) @@ -36,12 +37,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables } } - protected virtual void UpdateInitialState() - { - // Hide() cannot be used here, because when rewinding, we need these to be the final values - Alpha = 0; - } - protected virtual void UpdatePreemptState() { this.FadeIn(TIME_FADEIN); diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableRepeatPoint.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableRepeatPoint.cs index 200c697a0f..a9b63ea642 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableRepeatPoint.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableRepeatPoint.cs @@ -24,13 +24,10 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables this.repeatPoint = repeatPoint; this.drawableSlider = drawableSlider; - // The containing DrawableSlider is updated before us and clears our transforms, so we need to be - // present to get updated and have UpdateState correctly called when rewinding. - AlwaysPresent = true; - AutoSizeAxes = Axes.Both; Blending = BlendingMode.Additive; Origin = Anchor.Centre; + Scale = new Vector2(0.5f); Children = new Drawable[] { @@ -50,13 +47,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables AddJudgement(new OsuJudgement { Result = drawableSlider.Tracking ? HitResult.Great : HitResult.Miss }); } - protected override void UpdateInitialState() - { - base.UpdateInitialState(); - - Scale = new Vector2(0.5f); - } - protected override void UpdatePreemptState() { var animIn = Math.Min(150, repeatPoint.StartTime - FadeInTime); diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs index 2e6e82ce0c..74454ca555 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs @@ -43,7 +43,9 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables ball = new SliderBall(s) { Scale = new Vector2(s.Scale), - AccentColour = AccentColour + AccentColour = AccentColour, + AlwaysPresent = true, + Alpha = 0 }, initialCircle = new DrawableHitCircle(new HitCircle { @@ -148,16 +150,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables } } - protected override void UpdateInitialState() - { - base.UpdateInitialState(); - body.Alpha = 1; - - //we need to be present to handle input events. note that we still don't get enough events (we don't get a position if the mouse hasn't moved since the slider appeared). - ball.AlwaysPresent = true; - ball.Alpha = 0; - } - protected override void UpdateCurrentState(ArmedState state) { ball.FadeIn(); diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTick.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTick.cs index 9fe475f4aa..7199691ae6 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTick.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTick.cs @@ -28,10 +28,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables Size = new Vector2(16) * sliderTick.Scale; - // The containing DrawableSlider is updated before us and clears our transforms, so we need to be - // present to get updated and have UpdateState correctly called when rewinding. - AlwaysPresent = true; - Masking = true; CornerRadius = Size.X / 2; diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index 091af04106..99b62f265d 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -215,6 +215,9 @@ namespace osu.Game.Rulesets.Objects.Drawables nestedHitObjects.Add(h); } + protected override bool AllowStateTransformByParent => false; + protected override bool AllowTransformClearByParent => false; + protected abstract void UpdateState(ArmedState state); } } From 66ee9d163188908c7084bc77635222ec214f8847 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 9 Nov 2017 17:04:04 +0900 Subject: [PATCH 0589/1263] Update in-line with framework changes --- osu-framework | 2 +- .../Objects/Drawables/DrawableOsuHitObject.cs | 9 +++++++-- osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs | 3 --- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/osu-framework b/osu-framework index b70ca3de9e..ff1e04024d 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit b70ca3de9ec1a8eb7fb73fcfd169ff38d00b07cd +Subproject commit ff1e04024d16c0a6cabec7792573b0d019bd1bba diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs index e968e5b9df..3e0c23a1ab 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs @@ -25,8 +25,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables { double transformTime = HitObject.StartTime - TIME_PREEMPT; - TransformStateTo(transformTime, true); - ClearTransformsAfter(transformTime, true); + base.ApplyTransformsAt(transformTime, true); + base.ClearTransformsAfter(transformTime, true); using (BeginAbsoluteSequence(transformTime, true)) { @@ -46,6 +46,11 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables { } + // Todo: At some point we need to move these to DrawableHitObject after ensuring that all other Rulesets apply + // transforms in the same way and don't rely on them not being cleared + public override void ClearTransformsAfter(double time, bool propagateChildren = false, string targetMember = null) { } + public override void ApplyTransformsAt(double time, bool propagateChildren = false) { } + private OsuInputManager osuActionInputManager; internal OsuInputManager OsuActionInputManager => osuActionInputManager ?? (osuActionInputManager = GetContainingInputManager() as OsuInputManager); } diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index 99b62f265d..091af04106 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -215,9 +215,6 @@ namespace osu.Game.Rulesets.Objects.Drawables nestedHitObjects.Add(h); } - protected override bool AllowStateTransformByParent => false; - protected override bool AllowTransformClearByParent => false; - protected abstract void UpdateState(ArmedState state); } } From 4874371dbffa6e568ddaf9aeda94c07c2e40ccac Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 9 Nov 2017 17:38:20 +0900 Subject: [PATCH 0590/1263] Rename methods back --- osu.Game/Screens/Loader.cs | 4 ++-- osu.Game/Screens/Menu/Intro.cs | 4 ++-- osu.Game/Screens/Menu/MainMenu.cs | 6 +++--- osu.Game/Screens/OsuScreen.cs | 14 +++++++------- osu.Game/Screens/Play/PlayerLoader.cs | 4 ++-- osu.Game/Screens/Select/SongSelect.cs | 8 ++++---- 6 files changed, 20 insertions(+), 20 deletions(-) diff --git a/osu.Game/Screens/Loader.cs b/osu.Game/Screens/Loader.cs index 8c70e2421b..8fe6b2c5a2 100644 --- a/osu.Game/Screens/Loader.cs +++ b/osu.Game/Screens/Loader.cs @@ -17,9 +17,9 @@ namespace osu.Game.Screens ValidForResume = false; } - protected override void OnArrivedLogo(OsuLogo logo, bool resuming) + protected override void LogoArriving(OsuLogo logo, bool resuming) { - base.OnArrivedLogo(logo, resuming); + base.LogoArriving(logo, resuming); logo.RelativePositionAxes = Axes.Both; logo.Triangles = false; diff --git a/osu.Game/Screens/Menu/Intro.cs b/osu.Game/Screens/Menu/Intro.cs index 2cd51f05db..70c2430e10 100644 --- a/osu.Game/Screens/Menu/Intro.cs +++ b/osu.Game/Screens/Menu/Intro.cs @@ -109,9 +109,9 @@ namespace osu.Game.Screens.Menu public const int EXIT_DELAY = 3000; - protected override void OnArrivedLogo(OsuLogo logo, bool resuming) + protected override void LogoArriving(OsuLogo logo, bool resuming) { - base.OnArrivedLogo(logo, resuming); + base.LogoArriving(logo, resuming); logo.RelativePositionAxes = Axes.Both; diff --git a/osu.Game/Screens/Menu/MainMenu.cs b/osu.Game/Screens/Menu/MainMenu.cs index 6f01199a60..8b9dd38a7b 100644 --- a/osu.Game/Screens/Menu/MainMenu.cs +++ b/osu.Game/Screens/Menu/MainMenu.cs @@ -103,9 +103,9 @@ namespace osu.Game.Screens.Menu Beatmap.ValueChanged += beatmap_ValueChanged; } - protected override void OnArrivedLogo(OsuLogo logo, bool resuming) + protected override void LogoArriving(OsuLogo logo, bool resuming) { - base.OnArrivedLogo(logo, resuming); + base.LogoArriving(logo, resuming); buttons.SetOsuLogo(logo); @@ -119,7 +119,7 @@ namespace osu.Game.Screens.Menu buttons.State = MenuState.TopLevel; } - protected override void OnSuspendingLogo(OsuLogo logo) + protected override void LogoSuspending(OsuLogo logo) { logo.FadeOut(300, Easing.InSine) .ScaleTo(0.2f, 300, Easing.InSine) diff --git a/osu.Game/Screens/OsuScreen.cs b/osu.Game/Screens/OsuScreen.cs index 2693ad97fa..3dd175ca88 100644 --- a/osu.Game/Screens/OsuScreen.cs +++ b/osu.Game/Screens/OsuScreen.cs @@ -76,7 +76,7 @@ namespace osu.Game.Screens protected override void OnResuming(Screen last) { base.OnResuming(last); - logo.DelayUntilTransformsFinished().Schedule(() => OnArrivedLogo(logo, true)); + logo.DelayUntilTransformsFinished().Schedule(() => LogoArriving(logo, true)); sampleExit?.Play(); } @@ -122,7 +122,7 @@ namespace osu.Game.Screens base.OnEntering(last); - logo.DelayUntilTransformsFinished().Schedule(() => OnArrivedLogo(logo, false)); + logo.DelayUntilTransformsFinished().Schedule(() => LogoArriving(logo, false)); } protected override bool OnExiting(Screen next) @@ -151,7 +151,7 @@ namespace osu.Game.Screens /// /// Fired when this screen was entered or resumed and the logo state is required to be adjusted. /// - protected virtual void OnArrivedLogo(OsuLogo logo, bool resuming) + protected virtual void LogoArriving(OsuLogo logo, bool resuming) { logo.Action = null; logo.FadeOut(300, Easing.OutQuint); @@ -160,26 +160,26 @@ namespace osu.Game.Screens private void onExitingLogo() { logo.ClearTransforms(); - OnExitingLogo(logo); + LogoExiting(logo); } /// /// Fired when this screen was exited to add any outwards transition to the logo. /// - protected virtual void OnExitingLogo(OsuLogo logo) + protected virtual void LogoExiting(OsuLogo logo) { } private void onSuspendingLogo() { logo.ClearTransforms(); - OnSuspendingLogo(logo); + LogoSuspending(logo); } /// /// Fired when this screen was suspended to add any outwards transition to the logo. /// - protected virtual void OnSuspendingLogo(OsuLogo logo) + protected virtual void LogoSuspending(OsuLogo logo) { } } diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index 6e96fb8b71..53a2dcc41f 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -95,9 +95,9 @@ namespace osu.Game.Screens.Play this.Delay(2150).Schedule(pushWhenLoaded); } - protected override void OnArrivedLogo(OsuLogo logo, bool resuming) + protected override void LogoArriving(OsuLogo logo, bool resuming) { - base.OnArrivedLogo(logo, resuming); + base.LogoArriving(logo, resuming); logo.ClearTransforms(targetMember: nameof(Position)); logo.RelativePositionAxes = Axes.Both; diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 11e7d452fa..987fef2541 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -311,9 +311,9 @@ namespace osu.Game.Screens.Select private const double logo_transition = 250; - protected override void OnArrivedLogo(OsuLogo logo, bool resuming) + protected override void LogoArriving(OsuLogo logo, bool resuming) { - base.OnArrivedLogo(logo, resuming); + base.LogoArriving(logo, resuming); logo.ClearTransforms(); logo.RelativePositionAxes = Axes.Both; @@ -337,9 +337,9 @@ namespace osu.Game.Screens.Select logo.Action = () => carouselRaisedStart(); } - protected override void OnExitingLogo(OsuLogo logo) + protected override void LogoExiting(OsuLogo logo) { - base.OnExitingLogo(logo); + base.LogoExiting(logo); logo.ScaleTo(0.2f, logo_transition, Easing.OutQuint); logo.FadeOut(logo_transition, Easing.OutQuint); } From 6d56b3c2df8f59f21298580ea5f10ba9c56f0e53 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 9 Nov 2017 17:52:38 +0900 Subject: [PATCH 0591/1263] Hide triangles during outro --- osu.Game/Screens/Menu/Intro.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Menu/Intro.cs b/osu.Game/Screens/Menu/Intro.cs index 85dc13747f..0445733b23 100644 --- a/osu.Game/Screens/Menu/Intro.cs +++ b/osu.Game/Screens/Menu/Intro.cs @@ -116,8 +116,6 @@ namespace osu.Game.Screens.Menu base.LogoArriving(logo, resuming); logo.RelativePositionAxes = Axes.Both; - - logo.Triangles = true; logo.Colour = Color4.White; logo.Ripple = false; @@ -129,12 +127,16 @@ namespace osu.Game.Screens.Menu if (!resuming) { + logo.Triangles = true; + logo.ScaleTo(1); logo.FadeIn(); logo.PlayIntro(); } else { + logo.Triangles = false; + logo .ScaleTo(1, initialMovementTime, Easing.OutQuint) .FadeIn(quick_appear, Easing.OutQuint) From 598e1652dcdfebfa6fb9e9df0cc6ba464a649960 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 9 Nov 2017 18:12:33 +0900 Subject: [PATCH 0592/1263] Adjust timings --- osu.Game/Screens/Menu/IntroSequence.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Menu/IntroSequence.cs b/osu.Game/Screens/Menu/IntroSequence.cs index f8886f8dc1..5fca389708 100644 --- a/osu.Game/Screens/Menu/IntroSequence.cs +++ b/osu.Game/Screens/Menu/IntroSequence.cs @@ -214,8 +214,8 @@ namespace osu.Game.Screens.Menu using (BeginDelayedSequence(length * 0.56, true)) { - bigRing.ResizeTo(logo_size * 0.86f, 500, Easing.InOutQuint); - bigRing.Foreground.Delay(250).ResizeTo(1, 450, Easing.OutExpo); + bigRing.ResizeTo(logo_size, 500, Easing.InOutQuint); + bigRing.Foreground.Delay(250).ResizeTo(1, 850, Easing.OutQuint); using (BeginDelayedSequence(250, true)) { From 724540ceaa614d4b3817410c721ed16432f97055 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 9 Nov 2017 20:33:39 +0900 Subject: [PATCH 0593/1263] Fix toolbar not appearing at main menu --- osu.Game/Screens/Menu/ButtonSystem.cs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/osu.Game/Screens/Menu/ButtonSystem.cs b/osu.Game/Screens/Menu/ButtonSystem.cs index 33d118d12e..af16fbd71c 100644 --- a/osu.Game/Screens/Menu/ButtonSystem.cs +++ b/osu.Game/Screens/Menu/ButtonSystem.cs @@ -263,17 +263,15 @@ namespace osu.Game.Screens.Menu logo.ScaleTo(0.5f, 200, Easing.In); trackingPosition = false; + logo .MoveTo(iconTrackingPosition, lastState == MenuState.EnteringMode ? 0 : 200, Easing.In) .OnComplete(o => { trackingPosition = true; - if (logo.Scale.X > 0.5f) - { - o.Impact(); - toolbar?.Show(); - } + o.Impact(); + toolbar?.Show(); }); break; default: From c9353e37950ca5268d6f2ffa26495d0a3b49fc3b Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Thu, 9 Nov 2017 15:49:17 +0300 Subject: [PATCH 0594/1263] Fix humanizer package path --- osu.Game/osu.Game.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index ab8112504d..97d2879ae0 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -89,7 +89,7 @@ True - ..\packages\Humanizer.Core.2.2.0\lib\netstandard1.0\Humanizer.dll + $(SolutionDir)\packages\Humanizer.Core.2.2.0\lib\netstandard1.0\Humanizer.dll $(SolutionDir)\packages\Microsoft.Data.Sqlite.Core.2.0.0\lib\netstandard2.0\Microsoft.Data.Sqlite.dll From a9b58a2ad24d3e08b43628c691c459091e0946a5 Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Thu, 9 Nov 2017 17:12:06 +0300 Subject: [PATCH 0595/1263] Drawable score visual improvements --- .../Ranks/DrawablePerformanceScore.cs | 2 +- .../Profile/Sections/Ranks/DrawableScore.cs | 142 +++++++++++++----- .../Sections/Ranks/DrawableTotalScore.cs | 2 +- .../Sections/Ranks/PaginatedScoreContainer.cs | 3 - osu.Game/Overlays/UserProfileOverlay.cs | 2 +- 5 files changed, 110 insertions(+), 41 deletions(-) diff --git a/osu.Game/Overlays/Profile/Sections/Ranks/DrawablePerformanceScore.cs b/osu.Game/Overlays/Profile/Sections/Ranks/DrawablePerformanceScore.cs index 0380b6c4b7..e6ba5b26ac 100644 --- a/osu.Game/Overlays/Profile/Sections/Ranks/DrawablePerformanceScore.cs +++ b/osu.Game/Overlays/Profile/Sections/Ranks/DrawablePerformanceScore.cs @@ -20,7 +20,7 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks } [BackgroundDependencyLoader] - private new void load(OsuColour colour) + private void load(OsuColour colour) { double pp = Score.PP ?? 0; Stats.Add(new OsuSpriteText diff --git a/osu.Game/Overlays/Profile/Sections/Ranks/DrawableScore.cs b/osu.Game/Overlays/Profile/Sections/Ranks/DrawableScore.cs index 91f5650b92..4fc15a202b 100644 --- a/osu.Game/Overlays/Profile/Sections/Ranks/DrawableScore.cs +++ b/osu.Game/Overlays/Profile/Sections/Ranks/DrawableScore.cs @@ -7,7 +7,6 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Graphics; -using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Rulesets.Mods; using osu.Game.Screens.Select.Leaderboards; @@ -15,66 +14,113 @@ using System.Linq; using osu.Framework.Localisation; using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.UI; +using OpenTK.Graphics; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Cursor; +using osu.Framework.Input; +using osu.Framework.Extensions.Color4Extensions; +using osu.Game.Graphics.Containers; namespace osu.Game.Overlays.Profile.Sections.Ranks { public abstract class DrawableScore : Container { + private const int fade_duration = 200; + protected readonly FillFlowContainer Stats; private readonly FillFlowContainer metadata; private readonly ModContainer modContainer; protected readonly Score Score; + private readonly Box underscoreLine; + private readonly Box coloredBackground; + private readonly Container background; protected DrawableScore(Score score) { Score = score; + RelativeSizeAxes = Axes.X; + Height = 60; Children = new Drawable[] { - new DrawableRank(score.Rank) + background = new Container { - RelativeSizeAxes = Axes.Y, - Width = 60, - FillMode = FillMode.Fit, - }, - Stats = new FillFlowContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Anchor = Anchor.CentreRight, - Origin = Anchor.CentreRight, - Direction = FillDirection.Vertical, - }, - metadata = new FillFlowContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Margin = new MarginPadding { Left = 70 }, - Direction = FillDirection.Vertical, - Child = new OsuSpriteText + RelativeSizeAxes = Axes.Both, + Masking = true, + CornerRadius = 3, + Alpha = 0, + EdgeEffect = new EdgeEffectParameters { - Text = score.Date.LocalDateTime.ToShortDateString(), - TextSize = 11, - Colour = OsuColour.Gray(0xAA), - Depth = -1, + Type = EdgeEffectType.Shadow, + Offset = new Vector2(0f, 1f), + Radius = 1f, + Colour = Color4.Black.Opacity(0.2f), }, + Child = coloredBackground = new Box { RelativeSizeAxes = Axes.Both } }, - modContainer = new ModContainer + new Container { - AutoSizeAxes = Axes.Y, - Anchor = Anchor.CentreRight, - Origin = Anchor.CentreRight, - Width = 60, - Margin = new MarginPadding { Right = 150 } - } + RelativeSizeAxes = Axes.Both, + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Width = 0.97f, + Children = new Drawable[] + { + underscoreLine = new Box + { + Anchor = Anchor.BottomCentre, + Origin = Anchor.BottomCentre, + RelativeSizeAxes = Axes.X, + Height = 1, + }, + new DrawableRank(score.Rank) + { + RelativeSizeAxes = Axes.Y, + Width = 60, + FillMode = FillMode.Fit, + }, + Stats = new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + Direction = FillDirection.Vertical, + }, + metadata = new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Margin = new MarginPadding { Left = 70 }, + Direction = FillDirection.Vertical, + Child = new OsuSpriteText + { + Text = score.Date.LocalDateTime.ToShortDateString(), + TextSize = 11, + Colour = OsuColour.Gray(0xAA), + Depth = -1, + }, + }, + modContainer = new ModContainer + { + AutoSizeAxes = Axes.Y, + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + Width = 60, + Margin = new MarginPadding { Right = 160 } + } + } + }, }; } [BackgroundDependencyLoader(true)] private void load(OsuColour colour, LocalisationEngine locale, BeatmapSetOverlay beatmapSetOverlay) { + coloredBackground.Colour = underscoreLine.Colour = colour.Gray4; + Stats.Add(new OsuSpriteText { Text = $"accuracy: {Score.Accuracy:P2}", @@ -86,7 +132,7 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks Depth = -1, }); - metadata.Add(new OsuHoverContainer + metadata.Add(new MetadataContainer(Score.Beatmap.Metadata.Title, Score.Beatmap.Metadata.Artist) { AutoSizeAxes = Axes.Both, Action = () => @@ -126,6 +172,22 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks }); } + protected override bool OnClick(InputState state) => true; + + protected override bool OnHover(InputState state) + { + background.FadeIn(fade_duration, Easing.OutQuint); + underscoreLine.FadeOut(fade_duration, Easing.OutQuint); + return true; + } + + protected override void OnHoverLost(InputState state) + { + background.FadeOut(fade_duration, Easing.OutQuint); + underscoreLine.FadeIn(fade_duration, Easing.OutQuint); + base.OnHoverLost(state); + } + private class ModContainer : FlowContainer { protected override IEnumerable ComputeLayoutPositions() @@ -135,5 +197,15 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks yield return new Vector2(DrawWidth * i * (count == 1 ? 0 : 1f / (count - 1)), 0); } } + + private class MetadataContainer : OsuHoverContainer, IHasTooltip + { + public string TooltipText { get; set; } + + public MetadataContainer(string title, string artist) + { + TooltipText = $"{artist} - {title}"; + } + } } } diff --git a/osu.Game/Overlays/Profile/Sections/Ranks/DrawableTotalScore.cs b/osu.Game/Overlays/Profile/Sections/Ranks/DrawableTotalScore.cs index 7aa9d75f02..537b208b39 100644 --- a/osu.Game/Overlays/Profile/Sections/Ranks/DrawableTotalScore.cs +++ b/osu.Game/Overlays/Profile/Sections/Ranks/DrawableTotalScore.cs @@ -16,7 +16,7 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks } [BackgroundDependencyLoader] - private new void load() + private void load() { Stats.Add(new OsuSpriteText { diff --git a/osu.Game/Overlays/Profile/Sections/Ranks/PaginatedScoreContainer.cs b/osu.Game/Overlays/Profile/Sections/Ranks/PaginatedScoreContainer.cs index 060bb03014..bab78b52fd 100644 --- a/osu.Game/Overlays/Profile/Sections/Ranks/PaginatedScoreContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/Ranks/PaginatedScoreContainer.cs @@ -140,9 +140,6 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks break; } - drawableScore.RelativeSizeAxes = Axes.X; - drawableScore.Height = 60; - scoreContainer.Add(drawableScore); } }; diff --git a/osu.Game/Overlays/UserProfileOverlay.cs b/osu.Game/Overlays/UserProfileOverlay.cs index 5032f2d55b..32c8a83b02 100644 --- a/osu.Game/Overlays/UserProfileOverlay.cs +++ b/osu.Game/Overlays/UserProfileOverlay.cs @@ -91,7 +91,7 @@ namespace osu.Game.Overlays sections = new ProfileSection[] { - new AboutSection(), + //new AboutSection(), //new RecentSection(), new RanksSection(), //new MedalsSection(), From 5eb94f7e68be77e78b836f194daaa91e6e32d993 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 9 Nov 2017 23:24:14 +0900 Subject: [PATCH 0596/1263] Fix loader pushing children screens before it is displayed itself --- osu.Game/Screens/Loader.cs | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/osu.Game/Screens/Loader.cs b/osu.Game/Screens/Loader.cs index faa8b7e40a..3afaa02824 100644 --- a/osu.Game/Screens/Loader.cs +++ b/osu.Game/Screens/Loader.cs @@ -5,11 +5,14 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Game.Screens.Menu; using OpenTK; +using osu.Framework.Screens; namespace osu.Game.Screens { public class Loader : OsuScreen { + private bool showDisclaimer; + public override bool ShowOverlays => false; public Loader() @@ -21,21 +24,40 @@ namespace osu.Game.Screens { base.LogoArriving(logo, resuming); - logo.RelativePositionAxes = Axes.Both; + logo.RelativePositionAxes = Axes.None; logo.Triangles = false; - logo.Position = new Vector2(0.9f); + logo.Origin = Anchor.BottomRight; + logo.Anchor = Anchor.BottomRight; + logo.Position = new Vector2(-40); logo.Scale = new Vector2(0.2f); logo.FadeInFromZero(5000, Easing.OutQuint); } - [BackgroundDependencyLoader] - private void load(OsuGameBase game) + protected override void OnEntering(Screen last) { - if (game.IsDeployedBuild) + base.OnEntering(last); + + if (showDisclaimer) LoadComponentAsync(new Disclaimer(), d => Push(d)); else LoadComponentAsync(new Intro(), d => Push(d)); } + + protected override void LogoSuspending(OsuLogo logo) + { + base.LogoSuspending(logo); + logo.FadeOut(100).OnComplete(l => + { + l.Anchor = Anchor.TopLeft; + l.Origin = Anchor.Centre; + }); + } + + [BackgroundDependencyLoader] + private void load(OsuGameBase game) + { + showDisclaimer = game.IsDeployedBuild; + } } } From 9e82fc21acd3bf57311d5dc08a9708acf74776f2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 10 Nov 2017 01:10:40 +0900 Subject: [PATCH 0597/1263] Improve transition when exiting song select Reduces the delay before the main menu appears, but also synchronises the full main menu appearance animation with the logo's apperance. --- osu.Game/Screens/Menu/MainMenu.cs | 18 ++++++++++-------- osu.Game/Screens/Select/SongSelect.cs | 4 ++-- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/osu.Game/Screens/Menu/MainMenu.cs b/osu.Game/Screens/Menu/MainMenu.cs index 691e8eab04..b0170edfe1 100644 --- a/osu.Game/Screens/Menu/MainMenu.cs +++ b/osu.Game/Screens/Menu/MainMenu.cs @@ -119,7 +119,16 @@ namespace osu.Game.Screens.Menu logo.FadeIn(100, Easing.OutQuint); if (resuming) + { buttons.State = MenuState.TopLevel; + + const float length = 300; + + Content.FadeIn(length, Easing.OutQuint); + Content.MoveTo(new Vector2(0, 0), length, Easing.OutQuint); + + sideFlashes.Delay(length).FadeIn(64, Easing.InQuint); + } } protected override void LogoSuspending(OsuLogo logo) @@ -148,7 +157,7 @@ namespace osu.Game.Screens.Menu Content.FadeOut(length, Easing.InSine); Content.MoveTo(new Vector2(-800, 0), length, Easing.InSine); - sideFlashes.FadeOut(length / 4, Easing.OutQuint); + sideFlashes.FadeOut(64, Easing.OutQuint); } protected override void OnResuming(Screen last) @@ -159,13 +168,6 @@ namespace osu.Game.Screens.Menu //we may have consumed our preloaded instance, so let's make another. preloadSongSelect(); - - const float length = 300; - - Content.FadeIn(length, Easing.OutQuint); - Content.MoveTo(new Vector2(0, 0), length, Easing.OutQuint); - - sideFlashes.FadeIn(length / 4, Easing.InQuint); } protected override bool OnExiting(Screen next) diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 987fef2541..121a53f699 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -340,8 +340,8 @@ namespace osu.Game.Screens.Select protected override void LogoExiting(OsuLogo logo) { base.LogoExiting(logo); - logo.ScaleTo(0.2f, logo_transition, Easing.OutQuint); - logo.FadeOut(logo_transition, Easing.OutQuint); + logo.ScaleTo(0.2f, logo_transition / 2, Easing.Out); + logo.FadeOut(logo_transition / 2, Easing.Out); } private void beatmap_ValueChanged(WorkingBeatmap beatmap) From c2f39711882817a40a46942ad3c194242625dbaf Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Fri, 10 Nov 2017 03:01:11 +0300 Subject: [PATCH 0598/1263] Extend Beatmap Set Response --- .../Visual/TestCaseBeatmapSetOverlay.cs | 12 +--- osu.Game/Beatmaps/BeatmapOnlineInfo.cs | 11 ---- osu.Game/Beatmaps/BeatmapSetOnlineInfo.cs | 13 ++--- .../API/Requests/GetBeatmapSetsResponse.cs | 56 +++++++++++++++++++ osu.Game/Overlays/BeatmapSet/BasicStats.cs | 6 +- osu.Game/Overlays/BeatmapSet/Header.cs | 24 ++------ 6 files changed, 72 insertions(+), 50 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCaseBeatmapSetOverlay.cs b/osu.Game.Tests/Visual/TestCaseBeatmapSetOverlay.cs index 1ade0be626..2226dbf9e9 100644 --- a/osu.Game.Tests/Visual/TestCaseBeatmapSetOverlay.cs +++ b/osu.Game.Tests/Visual/TestCaseBeatmapSetOverlay.cs @@ -53,6 +53,7 @@ namespace osu.Game.Tests.Visual Submitted = new DateTime(2016, 2, 10), Ranked = new DateTime(2016, 6, 19), BPM = 236, + HasVideo = true, Covers = new BeatmapSetOnlineCovers { Cover = @"https://assets.ppy.sh/beatmaps/415886/covers/cover.jpg?1465651778", @@ -75,7 +76,6 @@ namespace osu.Game.Tests.Visual OnlineInfo = new BeatmapOnlineInfo { Length = 115000, - HasVideo = false, CircleCount = 265, SliderCount = 71, PlayCount = 47906, @@ -103,7 +103,6 @@ namespace osu.Game.Tests.Visual OnlineInfo = new BeatmapOnlineInfo { Length = 118000, - HasVideo = true, CircleCount = 592, SliderCount = 62, PlayCount = 162021, @@ -131,7 +130,6 @@ namespace osu.Game.Tests.Visual OnlineInfo = new BeatmapOnlineInfo { Length = 118000, - HasVideo = false, CircleCount = 1042, SliderCount = 79, PlayCount = 225178, @@ -159,7 +157,6 @@ namespace osu.Game.Tests.Visual OnlineInfo = new BeatmapOnlineInfo { Length = 118000, - HasVideo = false, CircleCount = 1352, SliderCount = 69, PlayCount = 131545, @@ -187,7 +184,6 @@ namespace osu.Game.Tests.Visual OnlineInfo = new BeatmapOnlineInfo { Length = 118000, - HasVideo = false, CircleCount = 1730, SliderCount = 115, PlayCount = 117673, @@ -227,6 +223,7 @@ namespace osu.Game.Tests.Visual Submitted = new DateTime(2016, 6, 11), Ranked = new DateTime(2016, 7, 12), BPM = 160, + HasVideo = false, Covers = new BeatmapSetOnlineCovers { Cover = @"https://assets.ppy.sh/beatmaps/625493/covers/cover.jpg?1499167472", @@ -249,7 +246,6 @@ namespace osu.Game.Tests.Visual OnlineInfo = new BeatmapOnlineInfo { Length = 193000, - HasVideo = false, CircleCount = 262, SliderCount = 0, PlayCount = 3952, @@ -277,7 +273,6 @@ namespace osu.Game.Tests.Visual OnlineInfo = new BeatmapOnlineInfo { Length = 193000, - HasVideo = false, CircleCount = 464, SliderCount = 0, PlayCount = 4833, @@ -305,7 +300,6 @@ namespace osu.Game.Tests.Visual OnlineInfo = new BeatmapOnlineInfo { Length = 193000, - HasVideo = false, CircleCount = 712, SliderCount = 0, PlayCount = 4405, @@ -333,7 +327,6 @@ namespace osu.Game.Tests.Visual OnlineInfo = new BeatmapOnlineInfo { Length = 193000, - HasVideo = false, CircleCount = 943, SliderCount = 0, PlayCount = 3950, @@ -361,7 +354,6 @@ namespace osu.Game.Tests.Visual OnlineInfo = new BeatmapOnlineInfo { Length = 193000, - HasVideo = false, CircleCount = 1068, SliderCount = 0, PlayCount = 5856, diff --git a/osu.Game/Beatmaps/BeatmapOnlineInfo.cs b/osu.Game/Beatmaps/BeatmapOnlineInfo.cs index 399cabda99..6a988036c5 100644 --- a/osu.Game/Beatmaps/BeatmapOnlineInfo.cs +++ b/osu.Game/Beatmaps/BeatmapOnlineInfo.cs @@ -1,8 +1,6 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using Newtonsoft.Json; - namespace osu.Game.Beatmaps { /// @@ -15,33 +13,24 @@ namespace osu.Game.Beatmaps /// public double Length { get; set; } - /// - /// Whether or not this beatmap has a background video. - /// - public bool HasVideo { get; set; } - /// /// The amount of circles in this beatmap. /// - [JsonProperty(@"count_circles")] public int CircleCount { get; set; } /// /// The amount of sliders in this beatmap. /// - [JsonProperty(@"count_sliders")] public int SliderCount { get; set; } /// /// The amount of plays this beatmap has. /// - [JsonProperty(@"playcount")] public int PlayCount { get; set; } /// /// The amount of passes this beatmap has. /// - [JsonProperty(@"passcount")] public int PassCount { get; set; } } } diff --git a/osu.Game/Beatmaps/BeatmapSetOnlineInfo.cs b/osu.Game/Beatmaps/BeatmapSetOnlineInfo.cs index 27d1f057ca..0518526f29 100644 --- a/osu.Game/Beatmaps/BeatmapSetOnlineInfo.cs +++ b/osu.Game/Beatmaps/BeatmapSetOnlineInfo.cs @@ -2,7 +2,6 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; -using Newtonsoft.Json; namespace osu.Game.Beatmaps { @@ -25,17 +24,20 @@ namespace osu.Game.Beatmaps /// The date this beatmap set was last updated. /// public DateTimeOffset? LastUpdated { get; set; } + + /// + /// Whether or not this beatmap set has a background video. + /// + public bool HasVideo { get; set; } /// /// The different sizes of cover art for this beatmap set. /// - [JsonProperty(@"covers")] public BeatmapSetOnlineCovers Covers { get; set; } /// /// A small sample clip of this beatmap set's song. /// - [JsonProperty(@"previewUrl")] public string Preview { get; set; } /// @@ -46,13 +48,11 @@ namespace osu.Game.Beatmaps /// /// The amount of plays this beatmap set has. /// - [JsonProperty(@"play_count")] public int PlayCount { get; set; } /// /// The amount of people who have favourited this beatmap set. /// - [JsonProperty(@"favourite_count")] public int FavouriteCount { get; set; } } @@ -60,17 +60,14 @@ namespace osu.Game.Beatmaps { public string CoverLowRes { get; set; } - [JsonProperty(@"cover@2x")] public string Cover { get; set; } public string CardLowRes { get; set; } - [JsonProperty(@"card@2x")] public string Card { get; set; } public string ListLowRes { get; set; } - [JsonProperty(@"list@2x")] public string List { get; set; } } } diff --git a/osu.Game/Online/API/Requests/GetBeatmapSetsResponse.cs b/osu.Game/Online/API/Requests/GetBeatmapSetsResponse.cs index f2ca0c1a2f..45f6d84784 100644 --- a/osu.Game/Online/API/Requests/GetBeatmapSetsResponse.cs +++ b/osu.Game/Online/API/Requests/GetBeatmapSetsResponse.cs @@ -6,6 +6,7 @@ using System.Linq; using Newtonsoft.Json; using osu.Game.Beatmaps; using osu.Game.Rulesets; +using System; namespace osu.Game.Online.API.Requests { @@ -23,6 +24,21 @@ namespace osu.Game.Online.API.Requests [JsonProperty(@"favourite_count")] private int favouriteCount { get; set; } + [JsonProperty(@"bpm")] + private double bpm { get; set; } + + [JsonProperty(@"video")] + private bool hasVideo { get; set; } + + [JsonProperty(@"submitted_date")] + private DateTimeOffset submitted { get; set; } + + [JsonProperty(@"ranked_date")] + private DateTimeOffset ranked { get; set; } + + [JsonProperty(@"last_updated")] + private DateTimeOffset lastUpdated { get; set; } + [JsonProperty(@"user_id")] private long creatorId { set { Author.Id = value; } @@ -43,6 +59,11 @@ namespace osu.Game.Online.API.Requests Preview = preview, PlayCount = playCount, FavouriteCount = favouriteCount, + BPM = bpm, + HasVideo = hasVideo, + Submitted = submitted, + Ranked = ranked, + LastUpdated = lastUpdated, }, Beatmaps = beatmaps.Select(b => b.ToBeatmap(rulesets)).ToList(), }; @@ -62,6 +83,30 @@ namespace osu.Game.Online.API.Requests [JsonProperty(@"difficulty_rating")] private double starDifficulty { get; set; } + [JsonProperty(@"drain")] + private float drainRate { get; set; } + + [JsonProperty(@"cs")] + private float circleSize { get; set; } + + [JsonProperty(@"ar")] + private float approachRate { get; set; } + + [JsonProperty(@"accuracy")] + private float overallDifficulty { get; set; } + + [JsonProperty(@"total_length")] + private double length { get; set; } + + [JsonProperty(@"count_circles")] + private int circleCount { get; set; } + + [JsonProperty(@"count_sliders")] + private int sliderCount { get; set; } + + [JsonProperty(@"version")] + private string version { get; set; } + public BeatmapInfo ToBeatmap(RulesetStore rulesets) { return new BeatmapInfo @@ -69,10 +114,21 @@ namespace osu.Game.Online.API.Requests Metadata = this, Ruleset = rulesets.GetRuleset(ruleset), StarDifficulty = starDifficulty, + Version = version, + BaseDifficulty = new BeatmapDifficulty + { + DrainRate = drainRate, + CircleSize = circleSize, + ApproachRate = approachRate, + OverallDifficulty = overallDifficulty, + }, OnlineInfo = new BeatmapOnlineInfo { PlayCount = playCount, PassCount = passCount, + Length = length, + CircleCount = circleCount, + SliderCount = sliderCount, }, }; } diff --git a/osu.Game/Overlays/BeatmapSet/BasicStats.cs b/osu.Game/Overlays/BeatmapSet/BasicStats.cs index 885f9cc219..3ecff85bee 100644 --- a/osu.Game/Overlays/BeatmapSet/BasicStats.cs +++ b/osu.Game/Overlays/BeatmapSet/BasicStats.cs @@ -39,9 +39,9 @@ namespace osu.Game.Overlays.BeatmapSet if (value == beatmap) return; beatmap = value; - length.Value = TimeSpan.FromMilliseconds(beatmap.OnlineInfo.Length).ToString(@"m\:ss"); - circleCount.Value = beatmap.OnlineInfo.CircleCount.ToString("N0"); - sliderCount.Value = beatmap.OnlineInfo.SliderCount.ToString("N0"); + length.Value = TimeSpan.FromSeconds(beatmap.OnlineInfo.Length).ToString(@"m\:ss"); + circleCount.Value = beatmap.OnlineInfo.CircleCount.ToString(); + sliderCount.Value = beatmap.OnlineInfo.SliderCount.ToString(); } } diff --git a/osu.Game/Overlays/BeatmapSet/Header.cs b/osu.Game/Overlays/BeatmapSet/Header.cs index d4514cbaed..96bb613f9f 100644 --- a/osu.Game/Overlays/BeatmapSet/Header.cs +++ b/osu.Game/Overlays/BeatmapSet/Header.cs @@ -26,6 +26,8 @@ namespace osu.Game.Overlays.BeatmapSet private readonly Box tabsBg; private readonly Container coverContainer; private readonly OsuSpriteText title, artist; + private readonly Container noVideoButtons; + private readonly FillFlowContainer videoButtons; private readonly AuthorInfo author; public Details Details; @@ -46,6 +48,9 @@ namespace osu.Game.Overlays.BeatmapSet title.Text = BeatmapSet.Metadata.Title; artist.Text = BeatmapSet.Metadata.Artist; + noVideoButtons.FadeTo(BeatmapSet.OnlineInfo.HasVideo ? 0 : 1, transition_duration); + videoButtons.FadeTo(BeatmapSet.OnlineInfo.HasVideo ? 1 : 0, transition_duration); + cover?.FadeOut(400, Easing.Out); coverContainer.Add(cover = new DelayedLoadWrapper(new BeatmapSetCover(BeatmapSet) { @@ -77,9 +82,6 @@ namespace osu.Game.Overlays.BeatmapSet Radius = 3, Offset = new Vector2(0f, 1f), }; - - Container noVideoButtons; - FillFlowContainer videoButtons; Children = new Drawable[] { new Container @@ -202,21 +204,7 @@ namespace osu.Game.Overlays.BeatmapSet }, }; - Picker.Beatmap.ValueChanged += b => - { - Details.Beatmap = b; - - if (b.OnlineInfo.HasVideo) - { - noVideoButtons.FadeOut(transition_duration); - videoButtons.FadeIn(transition_duration); - } - else - { - noVideoButtons.FadeIn(transition_duration); - videoButtons.FadeOut(transition_duration); - } - }; + Picker.Beatmap.ValueChanged += b => Details.Beatmap = b; } [BackgroundDependencyLoader] From 7280f77a02621decb74bd0c08e84cc79de2ad35e Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Fri, 10 Nov 2017 03:06:21 +0300 Subject: [PATCH 0599/1263] Trim whitespace --- osu.Game/Beatmaps/BeatmapSetOnlineInfo.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Beatmaps/BeatmapSetOnlineInfo.cs b/osu.Game/Beatmaps/BeatmapSetOnlineInfo.cs index 0518526f29..2b9418d6ae 100644 --- a/osu.Game/Beatmaps/BeatmapSetOnlineInfo.cs +++ b/osu.Game/Beatmaps/BeatmapSetOnlineInfo.cs @@ -24,7 +24,7 @@ namespace osu.Game.Beatmaps /// The date this beatmap set was last updated. /// public DateTimeOffset? LastUpdated { get; set; } - + /// /// Whether or not this beatmap set has a background video. /// From bc54d4dd4fa9e4dd7bd159c220fa4ea376aaaa0f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 10 Nov 2017 18:32:15 +0900 Subject: [PATCH 0600/1263] Ensure we wait for audio track reset before proceeding with player execution --- osu.Game/Screens/Play/Player.cs | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 3775b9c933..fe26e4a1d1 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -17,6 +17,8 @@ using osu.Game.Rulesets.UI; using osu.Game.Screens.Backgrounds; using System; using System.Linq; +using System.Threading; +using System.Threading.Tasks; using osu.Framework.Threading; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Scoring; @@ -142,14 +144,21 @@ namespace osu.Game.Screens.Play userAudioOffset.ValueChanged += v => offsetClock.Offset = v; userAudioOffset.TriggerChange(); - Schedule(() => + Task.Run(() => { adjustableSourceClock.Reset(); - foreach (var mod in working.Mods.Value.OfType()) - mod.ApplyToClock(adjustableSourceClock); + // this is temporary until we have blocking (async.Wait()) audio component methods. + // then we can call ResetAsync().Wait() or the blocking version above. + while (adjustableSourceClock.IsRunning) + Thread.Sleep(1); - decoupledClock.ChangeSource(adjustableSourceClock); + Schedule(() => + { + decoupledClock.ChangeSource(adjustableSourceClock); + foreach (var mod in working.Mods.Value.OfType()) + mod.ApplyToClock(adjustableSourceClock); + }); }); Children = new Drawable[] From 819b0b1970dec8a409850834a1c4e824528ab840 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 10 Nov 2017 18:48:46 +0900 Subject: [PATCH 0601/1263] Update framework --- osu-framework | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu-framework b/osu-framework index db625dc65f..5e26808ec7 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit db625dc65fb7ae9be154b03a0968b2f8cedb036d +Subproject commit 5e26808ec77a8fd600cb1cdca3a4b2f62fd0c653 From bd2de899183ebc28262a4466e35c3f2dc09991f9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 10 Nov 2017 19:26:25 +0900 Subject: [PATCH 0602/1263] Why weren't these fixed previously --- osu.Game.Rulesets.Taiko/Judgements/TaikoStrongHitJudgement.cs | 2 -- osu.Game/Screens/Play/BreaksOverlay/RemainingTimeCounter.cs | 1 - 2 files changed, 3 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Judgements/TaikoStrongHitJudgement.cs b/osu.Game.Rulesets.Taiko/Judgements/TaikoStrongHitJudgement.cs index 07c499b56c..e1fe19212b 100644 --- a/osu.Game.Rulesets.Taiko/Judgements/TaikoStrongHitJudgement.cs +++ b/osu.Game.Rulesets.Taiko/Judgements/TaikoStrongHitJudgement.cs @@ -1,8 +1,6 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using osu.Game.Rulesets.Objects.Drawables; - namespace osu.Game.Rulesets.Taiko.Judgements { public class TaikoStrongHitJudgement : TaikoJudgement diff --git a/osu.Game/Screens/Play/BreaksOverlay/RemainingTimeCounter.cs b/osu.Game/Screens/Play/BreaksOverlay/RemainingTimeCounter.cs index 9b043a6e90..0df7bb97e0 100644 --- a/osu.Game/Screens/Play/BreaksOverlay/RemainingTimeCounter.cs +++ b/osu.Game/Screens/Play/BreaksOverlay/RemainingTimeCounter.cs @@ -1,7 +1,6 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using osu.Framework.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Framework.Graphics; using System; From 49731f4c050ed31ab155f4c3e8502801faf7c1ab Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 10 Nov 2017 19:32:09 +0900 Subject: [PATCH 0603/1263] Remove unused parmeter --- osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs b/osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs index 6128a8f3d7..7ef1ef8d8a 100644 --- a/osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs +++ b/osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs @@ -121,14 +121,14 @@ namespace osu.Game.Screens.Play.BreaksOverlay using (BeginAbsoluteSequence(b.StartTime)) { - Schedule(() => showBreak(b)); + Schedule(showBreak); using (BeginDelayedSequence(b.Duration - fade_duration)) Schedule(hideBreak); } } } - private void showBreak(BreakPeriod b) + private void showBreak() { if (letterboxing) letterboxOverlay.Show(); From 5277c3c1647c86b33c04ee98ea35d1c54fe52aca Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 10 Nov 2017 22:11:25 +0900 Subject: [PATCH 0604/1263] Set the frame time appropriately to reverse judgements a little better --- osu.Game/Rulesets/Replays/FramedReplayInputHandler.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/osu.Game/Rulesets/Replays/FramedReplayInputHandler.cs b/osu.Game/Rulesets/Replays/FramedReplayInputHandler.cs index f0d68c0467..06f7259f78 100644 --- a/osu.Game/Rulesets/Replays/FramedReplayInputHandler.cs +++ b/osu.Game/Rulesets/Replays/FramedReplayInputHandler.cs @@ -104,7 +104,13 @@ namespace osu.Game.Rulesets.Replays { //if we changed frames, we want to execute once *exactly* on the frame's time. if (currentDirection == time.CompareTo(NextFrame.Time) && advanceFrame()) + { + // If going backwards, we need to execute once _before_ the frame time to reverse any judgements + // that would occur as a result of this frame in forward playback + if (currentDirection == -1) + return currentTime = CurrentFrame.Time - 1; return currentTime = CurrentFrame.Time; + } //if we didn't change frames, we need to ensure we are allowed to run frames in between, else return null. if (inImportantSection) From e742c07f7d3edaf3e703397493ad07f1268e2bae Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 10 Nov 2017 22:17:41 +0900 Subject: [PATCH 0605/1263] Update framework --- osu-framework | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu-framework b/osu-framework index 68e0072674..1a563d7ce0 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit 68e0072674c4bbc4e608120f51cd1d7e91e9500c +Subproject commit 1a563d7ce0834cede2ef587762f98fe580badf3c From 6def49d6a42f81bc2987fe87607a62e19fe334ca Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Sat, 11 Nov 2017 01:51:42 +0300 Subject: [PATCH 0606/1263] Allow beatmap set response get online id --- osu.Game/Online/API/Requests/GetBeatmapSetsResponse.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game/Online/API/Requests/GetBeatmapSetsResponse.cs b/osu.Game/Online/API/Requests/GetBeatmapSetsResponse.cs index f2ca0c1a2f..7a6b1132b5 100644 --- a/osu.Game/Online/API/Requests/GetBeatmapSetsResponse.cs +++ b/osu.Game/Online/API/Requests/GetBeatmapSetsResponse.cs @@ -50,6 +50,9 @@ namespace osu.Game.Online.API.Requests private class GetBeatmapSetsBeatmapResponse : BeatmapMetadata { + [JsonProperty(@"id")] + private int onlineBeatmapID { get; set; } + [JsonProperty(@"playcount")] private int playCount { get; set; } @@ -69,6 +72,7 @@ namespace osu.Game.Online.API.Requests Metadata = this, Ruleset = rulesets.GetRuleset(ruleset), StarDifficulty = starDifficulty, + OnlineBeatmapID = onlineBeatmapID, OnlineInfo = new BeatmapOnlineInfo { PlayCount = playCount, From 3261af5200e51c9ba2ec2238fbbd43318dfd0024 Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Sat, 11 Nov 2017 03:46:06 +0300 Subject: [PATCH 0607/1263] Add scores container --- .../BeatmapSet/Scores/DrawableScore.cs | 157 ++++++++++++++++++ .../BeatmapSet/Scores/ScoresContainer.cs | 73 ++++++++ osu.Game/Overlays/BeatmapSetOverlay.cs | 5 +- .../Profile/Sections/Ranks/DrawableScore.cs | 16 +- .../Sections/Ranks/ScoreModsContainer.cs | 21 +++ osu.Game/osu.Game.csproj | 3 + 6 files changed, 261 insertions(+), 14 deletions(-) create mode 100644 osu.Game/Overlays/BeatmapSet/Scores/DrawableScore.cs create mode 100644 osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs create mode 100644 osu.Game/Overlays/Profile/Sections/Ranks/ScoreModsContainer.cs diff --git a/osu.Game/Overlays/BeatmapSet/Scores/DrawableScore.cs b/osu.Game/Overlays/BeatmapSet/Scores/DrawableScore.cs new file mode 100644 index 0000000000..457454d423 --- /dev/null +++ b/osu.Game/Overlays/BeatmapSet/Scores/DrawableScore.cs @@ -0,0 +1,157 @@ +// 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.Framework.Input; +using osu.Game.Graphics; +using osu.Game.Graphics.Containers; +using osu.Game.Graphics.Sprites; +using osu.Game.Online.API.Requests; +using osu.Game.Overlays.Profile.Sections.Ranks; +using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.UI; +using osu.Game.Screens.Select.Leaderboards; +using osu.Game.Users; + +namespace osu.Game.Overlays.BeatmapSet.Scores +{ + public class DrawableScore : Container + { + private const int fade_duration = 100; + private const int height = 30; + + private readonly Box background; + private readonly ScoreModsContainer modsContainer; + + public DrawableScore(int index, OnlineScore score) + { + RelativeSizeAxes = Axes.X; + Height = height; + CornerRadius = 3; + Masking = true; + Children = new Drawable[] + { + background = new Box + { + RelativeSizeAxes = Axes.Both, + Alpha = 0, + }, + new OsuSpriteText + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Text = $"#{index + 1}", + Font = @"Exo2.0-RegularItalic", + RelativePositionAxes = Axes.X, + X = 0.02f + }, + new DrawableFlag(score.User.Country?.FlagName) + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Width = 30, + Height = 20, + RelativePositionAxes = Axes.X, + X = 0.06f + }, + new ClickableUsername(score.User.Username) + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + RelativePositionAxes = Axes.X, + X = 0.1f + }, + modsContainer = new ScoreModsContainer + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + AutoSizeAxes = Axes.Y, + Width = 60, + RelativePositionAxes = Axes.X, + X = 0.45f + }, + new DrawableRank(score.Rank) + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Width = 30, + Height = 20, + FillMode = FillMode.Fit, + RelativePositionAxes = Axes.X, + X = 0.55f + }, + new OsuSpriteText + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreRight, + Text = score.TotalScore.ToString(), + Font = @"Exo2.0-MediumItalic", + RelativePositionAxes = Axes.X, + X = 0.7f + }, + new OsuSpriteText + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreRight, + Text = $@"{score.Accuracy:P2}", + Font = @"Exo2.0-RegularItalic", + RelativePositionAxes = Axes.X, + X = 0.8f + }, + new OsuSpriteText + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreRight, + Text = $"{score.Statistics["300"]}/{score.Statistics["100"]}/{score.Statistics["50"]}", + Font = @"Exo2.0-RegularItalic", + RelativePositionAxes = Axes.X, + X = 0.98f + }, + }; + + foreach (Mod mod in score.Mods) + modsContainer.Add(new ModIcon(mod) + { + AutoSizeAxes = Axes.Both, + Scale = new Vector2(0.35f), + }); + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + background.Colour = colours.Gray4; + } + + protected override bool OnHover(InputState state) + { + background.FadeIn(fade_duration, Easing.OutQuint); + return base.OnHover(state); + } + + protected override void OnHoverLost(InputState state) + { + background.FadeOut(fade_duration, Easing.OutQuint); + base.OnHoverLost(state); + } + + protected override bool OnClick(InputState state) => true; + + private class ClickableUsername : OsuHoverContainer + { + public ClickableUsername(string username) + { + AutoSizeAxes = Axes.Both; + Child = new OsuSpriteText + { + Text = username, + Font = @"Exo2.0-BoldItalic", + }; + } + } + } +} diff --git a/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs b/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs new file mode 100644 index 0000000000..61f9d5a634 --- /dev/null +++ b/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs @@ -0,0 +1,73 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using OpenTK; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Beatmaps; +using osu.Game.Graphics.Sprites; +using osu.Game.Online.API; +using osu.Game.Online.API.Requests; +using System.Linq; + +namespace osu.Game.Overlays.BeatmapSet.Scores +{ + public class ScoresContainer : Container + { + private readonly FillFlowContainer flow; + private APIAccess api; + + private BeatmapInfo beatmap; + public BeatmapInfo Beatmap + { + set + { + if (beatmap == value) return; + beatmap = value; + + getScores(); + } + get { return beatmap; } + } + + public ScoresContainer() + { + RelativeSizeAxes = Axes.X; + AutoSizeAxes = Axes.Y; + Child = flow = new FillFlowContainer + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Width = 0.95f, + Direction = FillDirection.Vertical, + Spacing = new Vector2(0, 1), + }; + } + + [BackgroundDependencyLoader] + private void load(APIAccess api) + { + this.api = api; + } + + private void getScores() + { + flow.Clear(); + + var req = new GetScoresRequest(beatmap); + req.Success += scores => + { + int i = 0; + foreach(var s in scores.Scores) + { + flow.Add(new DrawableScore(i, s)); + i++; + } + }; + api.Queue(req); + } + } +} diff --git a/osu.Game/Overlays/BeatmapSetOverlay.cs b/osu.Game/Overlays/BeatmapSetOverlay.cs index ddd146bcb6..7ce7d86cd5 100644 --- a/osu.Game/Overlays/BeatmapSetOverlay.cs +++ b/osu.Game/Overlays/BeatmapSetOverlay.cs @@ -16,6 +16,7 @@ using osu.Game.Online.API; using osu.Game.Online.API.Requests; using osu.Game.Overlays.BeatmapSet; using osu.Game.Rulesets; +using osu.Game.Overlays.BeatmapSet.Scores; namespace osu.Game.Overlays { @@ -26,6 +27,7 @@ namespace osu.Game.Overlays private readonly Header header; private readonly Info info; + private readonly ScoresContainer scores; private APIAccess api; private RulesetStore rulesets; @@ -74,12 +76,13 @@ namespace osu.Game.Overlays { header = new Header(), info = new Info(), + scores = new ScoresContainer(), }, }, }, }; - header.Picker.Beatmap.ValueChanged += b => info.Beatmap = b; + header.Picker.Beatmap.ValueChanged += b => info.Beatmap = scores.Beatmap = b; } [BackgroundDependencyLoader] diff --git a/osu.Game/Overlays/Profile/Sections/Ranks/DrawableScore.cs b/osu.Game/Overlays/Profile/Sections/Ranks/DrawableScore.cs index 91f5650b92..2c8cb06c4a 100644 --- a/osu.Game/Overlays/Profile/Sections/Ranks/DrawableScore.cs +++ b/osu.Game/Overlays/Profile/Sections/Ranks/DrawableScore.cs @@ -22,7 +22,7 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks { protected readonly FillFlowContainer Stats; private readonly FillFlowContainer metadata; - private readonly ModContainer modContainer; + private readonly ScoreModsContainer modsContainer; protected readonly Score Score; protected DrawableScore(Score score) @@ -61,7 +61,7 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks Depth = -1, }, }, - modContainer = new ModContainer + modsContainer = new ScoreModsContainer { AutoSizeAxes = Axes.Y, Anchor = Anchor.CentreRight, @@ -119,21 +119,11 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks }); foreach (Mod mod in Score.Mods) - modContainer.Add(new ModIcon(mod) + modsContainer.Add(new ModIcon(mod) { AutoSizeAxes = Axes.Both, Scale = new Vector2(0.5f), }); } - - private class ModContainer : FlowContainer - { - protected override IEnumerable ComputeLayoutPositions() - { - int count = FlowingChildren.Count(); - for (int i = 0; i < count; i++) - yield return new Vector2(DrawWidth * i * (count == 1 ? 0 : 1f / (count - 1)), 0); - } - } } } diff --git a/osu.Game/Overlays/Profile/Sections/Ranks/ScoreModsContainer.cs b/osu.Game/Overlays/Profile/Sections/Ranks/ScoreModsContainer.cs new file mode 100644 index 0000000000..6f050750e4 --- /dev/null +++ b/osu.Game/Overlays/Profile/Sections/Ranks/ScoreModsContainer.cs @@ -0,0 +1,21 @@ +// 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.Graphics.Containers; +using osu.Game.Rulesets.UI; +using System.Collections.Generic; +using System.Linq; + +namespace osu.Game.Overlays.Profile.Sections.Ranks +{ + public class ScoreModsContainer : FlowContainer + { + protected override IEnumerable ComputeLayoutPositions() + { + int count = FlowingChildren.Count(); + for (int i = 0; i < count; i++) + yield return new Vector2(DrawWidth * i * (count == 1 ? 0 : 1f / (count - 1)), 0); + } + } +} diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 23a9a07ae7..93083134ba 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -279,9 +279,12 @@ + + + From 5bf756c3c603db0faa1291b35849d3fb5c2f853a Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Sat, 11 Nov 2017 06:54:52 +0300 Subject: [PATCH 0608/1263] Add DrawableTopScore --- .../BeatmapSet/Scores/ClickableUsername.cs | 64 +++++ .../BeatmapSet/Scores/DrawableScore.cs | 17 +- .../BeatmapSet/Scores/DrawableTopScore.cs | 254 ++++++++++++++++++ .../BeatmapSet/Scores/ScoresContainer.cs | 117 ++++++-- .../Profile/Sections/Ranks/DrawableScore.cs | 2 - .../Select/Leaderboards/DrawableRank.cs | 22 +- osu.Game/osu.Game.csproj | 2 + 7 files changed, 436 insertions(+), 42 deletions(-) create mode 100644 osu.Game/Overlays/BeatmapSet/Scores/ClickableUsername.cs create mode 100644 osu.Game/Overlays/BeatmapSet/Scores/DrawableTopScore.cs diff --git a/osu.Game/Overlays/BeatmapSet/Scores/ClickableUsername.cs b/osu.Game/Overlays/BeatmapSet/Scores/ClickableUsername.cs new file mode 100644 index 0000000000..0aa1fae12f --- /dev/null +++ b/osu.Game/Overlays/BeatmapSet/Scores/ClickableUsername.cs @@ -0,0 +1,64 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Game.Graphics.Containers; +using osu.Game.Graphics.Sprites; +using osu.Game.Users; +using System; +using osu.Framework.Input; + +namespace osu.Game.Overlays.BeatmapSet.Scores +{ + public class ClickableUsername : OsuHoverContainer + { + private readonly OsuSpriteText text; + private Action clickAction; + private UserProfileOverlay profile; + + private User user; + public User User + { + set + { + if (user == value) return; + user = value; + + text.Text = user.Username; + } + get { return user; } + } + + public float TextSize + { + set + { + if (text.TextSize == value) return; + text.TextSize = value; + } + get { return text.TextSize; } + } + + public ClickableUsername() + { + AutoSizeAxes = Axes.Both; + Child = text = new OsuSpriteText + { + Font = @"Exo2.0-BoldItalic", + }; + } + + [BackgroundDependencyLoader] + private void load(UserProfileOverlay profile) + { + this.profile = profile; + } + + protected override bool OnClick(InputState state) + { + profile.ShowUser(user); + return base.OnClick(state); + } + } +} diff --git a/osu.Game/Overlays/BeatmapSet/Scores/DrawableScore.cs b/osu.Game/Overlays/BeatmapSet/Scores/DrawableScore.cs index 457454d423..ae40b4205d 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/DrawableScore.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/DrawableScore.cs @@ -8,7 +8,6 @@ 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.Online.API.Requests; using osu.Game.Overlays.Profile.Sections.Ranks; @@ -58,10 +57,11 @@ namespace osu.Game.Overlays.BeatmapSet.Scores RelativePositionAxes = Axes.X, X = 0.06f }, - new ClickableUsername(score.User.Username) + new ClickableUsername { Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, + User = score.User, RelativePositionAxes = Axes.X, X = 0.1f }, @@ -140,18 +140,5 @@ namespace osu.Game.Overlays.BeatmapSet.Scores } protected override bool OnClick(InputState state) => true; - - private class ClickableUsername : OsuHoverContainer - { - public ClickableUsername(string username) - { - AutoSizeAxes = Axes.Both; - Child = new OsuSpriteText - { - Text = username, - Font = @"Exo2.0-BoldItalic", - }; - } - } } } diff --git a/osu.Game/Overlays/BeatmapSet/Scores/DrawableTopScore.cs b/osu.Game/Overlays/BeatmapSet/Scores/DrawableTopScore.cs new file mode 100644 index 0000000000..f9ad72bd2c --- /dev/null +++ b/osu.Game/Overlays/BeatmapSet/Scores/DrawableTopScore.cs @@ -0,0 +1,254 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using OpenTK; +using OpenTK.Graphics; +using osu.Framework.Allocation; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Input; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osu.Game.Online.API.Requests; +using osu.Game.Overlays.Profile.Sections.Ranks; +using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Scoring; +using osu.Game.Rulesets.UI; +using osu.Game.Screens.Select.Leaderboards; +using osu.Game.Users; + +namespace osu.Game.Overlays.BeatmapSet.Scores +{ + public class DrawableTopScore : Container + { + private const int fade_duration = 100; + private const int height = 200; + private const int avatar_size = 80; + private const int margin = 10; + + private readonly Box background; + private readonly Box bottomBackground; + private readonly Box middleLine; + private readonly UpdateableAvatar avatar; + private readonly DrawableFlag flag; + private readonly ClickableUsername username; + private readonly OsuSpriteText rankText; + private readonly OsuSpriteText date; + private readonly DrawableRank rank; + private readonly InfoColumn totalScore; + private readonly InfoColumn accuracy; + private readonly InfoColumn statistics; + private readonly ScoreModsContainer modsContainer; + + private OnlineScore score; + public OnlineScore Score + { + set + { + if (score == value) return; + score = value; + + setScore(); + } + get { return score; } + } + + public DrawableTopScore() + { + RelativeSizeAxes = Axes.X; + Height = height; + CornerRadius = 5; + BorderThickness = 4; + Masking = true; + Children = new Drawable[] + { + background = new Box + { + RelativeSizeAxes = Axes.Both, + Alpha = 0, + AlwaysPresent = true, //used for correct border representation + }, + avatar = new UpdateableAvatar + { + Size = new Vector2(avatar_size), + Masking = true, + CornerRadius = 5, + EdgeEffect = new EdgeEffectParameters + { + Type = EdgeEffectType.Shadow, + Colour = Color4.Black.Opacity(0.25f), + Offset = new Vector2(0, 2), + Radius = 1, + }, + Margin = new MarginPadding { Top = margin, Left = margin } + }, + flag = new DrawableFlag + { + Width = 30, + Height = 20, + Y = height / 4, + X = height / 2, + }, + username = new ClickableUsername + { + Origin = Anchor.BottomLeft, + TextSize = 30, + Y = height / 4, + X = height / 2, + Margin = new MarginPadding { Bottom = 4 }, + }, + rankText = new OsuSpriteText + { + Anchor = Anchor.TopRight, + Origin = Anchor.BottomRight, + Text = "#1", + TextSize = 40, + Font = @"Exo2.0-BoldItalic", + Y = height / 4, + Margin = new MarginPadding { Right = margin } + }, + date = new OsuSpriteText + { + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + Y = height / 4, + Margin = new MarginPadding { Right = margin } + }, + new Container + { + Anchor = Anchor.BottomCentre, + Origin = Anchor.BottomCentre, + RelativeSizeAxes = Axes.Both, + Height = 0.5f, + Children = new Drawable[] + { + bottomBackground = new Box { RelativeSizeAxes = Axes.Both }, + middleLine = new Box + { + RelativeSizeAxes = Axes.X, + Height = 1, + }, + rank = new DrawableRank(ScoreRank.F) + { + Origin = Anchor.BottomLeft, + Width = avatar_size, + Height = 40, + FillMode = FillMode.Fit, + Y = height / 4, + Margin = new MarginPadding { Left = margin } + }, + new FillFlowContainer + { + Origin = Anchor.BottomLeft, + AutoSizeAxes = Axes.Both, + X = height / 2, + Y = height / 4, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(15, 0), + Children = new[] + { + totalScore = new InfoColumn("Score"), + accuracy = new InfoColumn("Accuracy"), + statistics = new InfoColumn("300/100/50"), + }, + }, + modsContainer = new ScoreModsContainer + { + AutoSizeAxes = Axes.Y, + Width = 80, + X = height / 2, + Y = height / 4, + } + } + }, + }; + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + background.Colour = bottomBackground.Colour = colours.Gray4; + middleLine.Colour = colours.Gray2; + date.Colour = colours.Gray9; + BorderColour = rankText.Colour = colours.Yellow; + } + + private void setScore() + { + avatar.User = username.User = score.User; + flag.FlagName = score.User.Country?.FlagName; + date.Text = $"achieved {score.Date:MMM d, yyyy}"; + rank.UpdateRank(score.Rank); + + totalScore.Value = score.TotalScore.ToString(); + accuracy.Value = $@"{score.Accuracy:P2}"; + statistics.Value = $"{score.Statistics["300"]}/{score.Statistics["100"]}/{score.Statistics["50"]}"; + + modsContainer.Clear(); + foreach (Mod mod in score.Mods) + modsContainer.Add(new ModIcon(mod) + { + AutoSizeAxes = Axes.Both, + Scale = new Vector2(0.45f), + }); + } + + protected override bool OnHover(InputState state) + { + background.FadeIn(fade_duration, Easing.OutQuint); + return base.OnHover(state); + } + + protected override void OnHoverLost(InputState state) + { + background.FadeOut(fade_duration, Easing.OutQuint); + base.OnHoverLost(state); + } + + private class InfoColumn : FillFlowContainer + { + private readonly OsuSpriteText headerText; + private readonly OsuSpriteText valueText; + + public string Value + { + set + { + if (valueText.Text == value) + return; + valueText.Text = value; + } + get { return valueText.Text; } + } + + public InfoColumn(string header) + { + AutoSizeAxes = Axes.Both; + Direction = FillDirection.Vertical; + Spacing = new Vector2(0, 3); + Children = new Drawable[] + { + headerText = new OsuSpriteText + { + TextSize = 14, + Text = header, + Font = @"Exo2.0-Bold", + }, + valueText = new OsuSpriteText + { + TextSize = 25, + Font = @"Exo2.0-RegularItalic", + } + }; + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + headerText.Colour = colours.Gray9; + } + } + } +} diff --git a/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs b/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs index 61f9d5a634..0f25021cf5 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs @@ -2,11 +2,14 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using OpenTK; +using OpenTK.Graphics; using osu.Framework.Allocation; +using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; using osu.Game.Beatmaps; -using osu.Game.Graphics.Sprites; +using osu.Game.Graphics.UserInterface; using osu.Game.Online.API; using osu.Game.Online.API.Requests; using System.Linq; @@ -15,9 +18,25 @@ namespace osu.Game.Overlays.BeatmapSet.Scores { public class ScoresContainer : Container { + private const int spacing = 15; + private const int fade_duration = 200; + private readonly FillFlowContainer flow; + private readonly DrawableTopScore topScore; + private readonly LoadingAnimation loadingAnimation; + private readonly Box foreground; + private GetScoresRequest request; private APIAccess api; + private bool isLoading + { + set + { + foreground.FadeTo(value ? 1 : 0, fade_duration); + loadingAnimation.FadeTo(value ? 1 : 0, fade_duration); + } + } + private BeatmapInfo beatmap; public BeatmapInfo Beatmap { @@ -26,7 +45,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores if (beatmap == value) return; beatmap = value; - getScores(); + updateScores(); } get { return beatmap; } } @@ -35,15 +54,44 @@ namespace osu.Game.Overlays.BeatmapSet.Scores { RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; - Child = flow = new FillFlowContainer + Children = new Drawable[] { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Width = 0.95f, - Direction = FillDirection.Vertical, - Spacing = new Vector2(0, 1), + new FillFlowContainer + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Width = 0.95f, + Direction = FillDirection.Vertical, + Spacing = new Vector2(0, spacing), + Margin = new MarginPadding { Top = spacing }, + Children = new Drawable[] + { + topScore = new DrawableTopScore(), + flow = new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical, + Spacing = new Vector2(0, 1), + }, + } + }, + foreground = new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Black.Opacity(0.7f), + Alpha = 0, + }, + loadingAnimation = new LoadingAnimation + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Size = new Vector2(20), + Margin = new MarginPadding { Top = 10 }, + Alpha = 0, + }, }; } @@ -53,21 +101,52 @@ namespace osu.Game.Overlays.BeatmapSet.Scores this.api = api; } - private void getScores() + private void updateScores() { - flow.Clear(); + request?.Cancel(); - var req = new GetScoresRequest(beatmap); - req.Success += scores => + if (beatmap == null) { - int i = 0; - foreach(var s in scores.Scores) + clearAllScores(); + return; + } + + isLoading = true; + + request = new GetScoresRequest(beatmap); + request.Success += scores => + { + var scoresAmount = scores.Scores.Count(); + if (scoresAmount == 0) { - flow.Add(new DrawableScore(i, s)); - i++; + clearAllScores(); + return; } + + topScore.Score = scores.Scores.FirstOrDefault(); + topScore.Show(); + + flow.Clear(); + + if (scoresAmount < 2) + { + isLoading = false; + return; + } + + for (int i = 1; i < scoresAmount; i++) + flow.Add(new DrawableScore(i, scores.Scores.ElementAt(i))); + + isLoading = false; }; - api.Queue(req); + api.Queue(request); + } + + private void clearAllScores() + { + topScore.Hide(); + flow.Clear(); + isLoading = false; } } } diff --git a/osu.Game/Overlays/Profile/Sections/Ranks/DrawableScore.cs b/osu.Game/Overlays/Profile/Sections/Ranks/DrawableScore.cs index 2c8cb06c4a..6ce438baed 100644 --- a/osu.Game/Overlays/Profile/Sections/Ranks/DrawableScore.cs +++ b/osu.Game/Overlays/Profile/Sections/Ranks/DrawableScore.cs @@ -1,7 +1,6 @@ // 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 OpenTK; using osu.Framework.Allocation; using osu.Framework.Graphics; @@ -11,7 +10,6 @@ using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Rulesets.Mods; using osu.Game.Screens.Select.Leaderboards; -using System.Linq; using osu.Framework.Localisation; using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.UI; diff --git a/osu.Game/Screens/Select/Leaderboards/DrawableRank.cs b/osu.Game/Screens/Select/Leaderboards/DrawableRank.cs index 6329729687..5bd78d5971 100644 --- a/osu.Game/Screens/Select/Leaderboards/DrawableRank.cs +++ b/osu.Game/Screens/Select/Leaderboards/DrawableRank.cs @@ -14,15 +14,10 @@ namespace osu.Game.Screens.Select.Leaderboards public class DrawableRank : Container { private readonly Sprite rankSprite; + private TextureStore textures; public ScoreRank Rank { get; private set; } - [BackgroundDependencyLoader] - private void load(TextureStore textures) - { - rankSprite.Texture = textures.Get($@"Grades/{Rank.GetDescription()}"); - } - public DrawableRank(ScoreRank rank) { Rank = rank; @@ -38,5 +33,20 @@ namespace osu.Game.Screens.Select.Leaderboards }, }; } + + [BackgroundDependencyLoader] + private void load(TextureStore textures) + { + this.textures = textures; + updateTexture(); + } + + private void updateTexture() => rankSprite.Texture = textures.Get($@"Grades/{Rank.GetDescription()}"); + + public void UpdateRank(ScoreRank newRank) + { + Rank = newRank; + updateTexture(); + } } } diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 93083134ba..c062391af6 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -279,7 +279,9 @@ + + From 3142832693d28ccc9e7c5d355c374554656a4b58 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 11 Nov 2017 13:00:29 +0900 Subject: [PATCH 0609/1263] Add precision to playback speed --- osu.Game/Screens/Play/ReplaySettings/PlaybackSettings.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/ReplaySettings/PlaybackSettings.cs b/osu.Game/Screens/Play/ReplaySettings/PlaybackSettings.cs index 7cabe1f3ab..bf2909b8ab 100644 --- a/osu.Game/Screens/Play/ReplaySettings/PlaybackSettings.cs +++ b/osu.Game/Screens/Play/ReplaySettings/PlaybackSettings.cs @@ -23,7 +23,8 @@ namespace osu.Game.Screens.Play.ReplaySettings { Default = 1, MinValue = 0.5, - MaxValue = 2 + MaxValue = 2, + Precision = 0.01, }, }; } From 7d4e1b6f22c9ee350b2cebde7a5cc5e9d8238fbb Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 11 Nov 2017 13:00:54 +0900 Subject: [PATCH 0610/1263] Don't require a local storage variable for restoring playback speed --- osu.Game/Screens/Play/Player.cs | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 2daf8f0765..59d56a5a44 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -51,7 +51,6 @@ namespace osu.Game.Screens.Play private IAdjustableClock adjustableSourceClock; private FramedOffsetClock offsetClock; private DecoupleableInterpolatingFramedClock decoupledClock; - private double clockRate; private PauseContainer pauseContainer; @@ -157,10 +156,7 @@ namespace osu.Game.Screens.Play Schedule(() => { decoupledClock.ChangeSource(adjustableSourceClock); - foreach (var mod in working.Mods.Value.OfType()) - mod.ApplyToClock(adjustableSourceClock); - - clockRate = adjustableSourceClock.Rate; + applyRateFromMods(); }); }); @@ -249,6 +245,13 @@ namespace osu.Game.Screens.Play scoreProcessor.Failed += onFail; } + private void applyRateFromMods() + { + adjustableSourceClock.Rate = 1; + foreach (var mod in Beatmap.Value.Mods.Value.OfType()) + mod.ApplyToClock(adjustableSourceClock); + } + private void initializeStoryboard(bool asyncLoad) { var beatmap = Beatmap.Value.Beatmap; @@ -346,8 +349,9 @@ namespace osu.Game.Screens.Play { if (HasFailed || !ValidForResume || pauseContainer?.AllowExit != false || RulesetContainer?.HasReplayLoaded != false) { - // We want to make sure we restore the clock rate - adjustableSourceClock.Rate = clockRate; + // In the case of replays, we may have changed the playback rate. + applyRateFromMods(); + fadeOut(); return base.OnExiting(next); } From 944bdc1c25b17217589fa6b164b5baf986ffd934 Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Sat, 11 Nov 2017 07:07:41 +0300 Subject: [PATCH 0611/1263] CI fixes --- osu.Game/Overlays/BeatmapSet/Scores/DrawableScore.cs | 7 ++++--- .../Overlays/BeatmapSet/Scores/DrawableTopScore.cs | 12 ++++++------ osu.Game/Overlays/BeatmapSetOverlay.cs | 3 ++- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/osu.Game/Overlays/BeatmapSet/Scores/DrawableScore.cs b/osu.Game/Overlays/BeatmapSet/Scores/DrawableScore.cs index ae40b4205d..8aba88c639 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/DrawableScore.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/DrawableScore.cs @@ -21,13 +21,14 @@ namespace osu.Game.Overlays.BeatmapSet.Scores public class DrawableScore : Container { private const int fade_duration = 100; - private const int height = 30; + private const float height = 30; private readonly Box background; - private readonly ScoreModsContainer modsContainer; public DrawableScore(int index, OnlineScore score) { + ScoreModsContainer modsContainer; + RelativeSizeAxes = Axes.X; Height = height; CornerRadius = 3; @@ -88,7 +89,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores { Anchor = Anchor.CentreLeft, Origin = Anchor.CentreRight, - Text = score.TotalScore.ToString(), + Text = $@"{score.TotalScore}", Font = @"Exo2.0-MediumItalic", RelativePositionAxes = Axes.X, X = 0.7f diff --git a/osu.Game/Overlays/BeatmapSet/Scores/DrawableTopScore.cs b/osu.Game/Overlays/BeatmapSet/Scores/DrawableTopScore.cs index f9ad72bd2c..665a563e6e 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/DrawableTopScore.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/DrawableTopScore.cs @@ -23,10 +23,10 @@ namespace osu.Game.Overlays.BeatmapSet.Scores { public class DrawableTopScore : Container { - private const int fade_duration = 100; - private const int height = 200; - private const int avatar_size = 80; - private const int margin = 10; + private const float fade_duration = 100; + private const float height = 200; + private const float avatar_size = 80; + private const float margin = 10; private readonly Box background; private readonly Box bottomBackground; @@ -179,10 +179,10 @@ namespace osu.Game.Overlays.BeatmapSet.Scores { avatar.User = username.User = score.User; flag.FlagName = score.User.Country?.FlagName; - date.Text = $"achieved {score.Date:MMM d, yyyy}"; + date.Text = $@"achieved {score.Date:MMM d, yyyy}"; rank.UpdateRank(score.Rank); - totalScore.Value = score.TotalScore.ToString(); + totalScore.Value = $@"{score.TotalScore}"; accuracy.Value = $@"{score.Accuracy:P2}"; statistics.Value = $"{score.Statistics["300"]}/{score.Statistics["100"]}/{score.Statistics["50"]}"; diff --git a/osu.Game/Overlays/BeatmapSetOverlay.cs b/osu.Game/Overlays/BeatmapSetOverlay.cs index 7ce7d86cd5..db01d02c79 100644 --- a/osu.Game/Overlays/BeatmapSetOverlay.cs +++ b/osu.Game/Overlays/BeatmapSetOverlay.cs @@ -27,7 +27,6 @@ namespace osu.Game.Overlays private readonly Header header; private readonly Info info; - private readonly ScoresContainer scores; private APIAccess api; private RulesetStore rulesets; @@ -37,6 +36,8 @@ namespace osu.Game.Overlays public BeatmapSetOverlay() { + ScoresContainer scores; + FirstWaveColour = OsuColour.Gray(0.4f); SecondWaveColour = OsuColour.Gray(0.3f); ThirdWaveColour = OsuColour.Gray(0.2f); From 057ada018337fc3dceec16a872a132831b7f8301 Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Sat, 11 Nov 2017 07:50:40 +0300 Subject: [PATCH 0612/1263] Fix nulls --- osu.Game/Overlays/BeatmapSet/Scores/ClickableUsername.cs | 2 +- osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/BeatmapSet/Scores/ClickableUsername.cs b/osu.Game/Overlays/BeatmapSet/Scores/ClickableUsername.cs index 0aa1fae12f..762e3f0105 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/ClickableUsername.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/ClickableUsername.cs @@ -49,7 +49,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores }; } - [BackgroundDependencyLoader] + [BackgroundDependencyLoader(true)] private void load(UserProfileOverlay profile) { this.profile = profile; diff --git a/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs b/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs index 0f25021cf5..164823f105 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs @@ -105,7 +105,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores { request?.Cancel(); - if (beatmap == null) + if (!beatmap?.OnlineBeatmapID.HasValue ?? false) { clearAllScores(); return; From 74bcc61a67cd265e10af95bdbe6df5d3d5b714fd Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Sat, 11 Nov 2017 07:51:07 +0300 Subject: [PATCH 0613/1263] Fix possible overlapping --- osu.Game/Overlays/BeatmapSet/Scores/DrawableScore.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/BeatmapSet/Scores/DrawableScore.cs b/osu.Game/Overlays/BeatmapSet/Scores/DrawableScore.cs index 8aba88c639..6d20082383 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/DrawableScore.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/DrawableScore.cs @@ -83,7 +83,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores Height = 20, FillMode = FillMode.Fit, RelativePositionAxes = Axes.X, - X = 0.55f + X = 0.57f }, new OsuSpriteText { From 9e447fcb271fd7ea8391fd38ab31331a2adf2b9e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 11 Nov 2017 15:53:01 +0900 Subject: [PATCH 0614/1263] Update framework an resources --- osu-framework | 2 +- osu-resources | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu-framework b/osu-framework index 1a563d7ce0..36fad894f0 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit 1a563d7ce0834cede2ef587762f98fe580badf3c +Subproject commit 36fad894f0657d0fdc998ffd3f2f3fa87e45d67d diff --git a/osu-resources b/osu-resources index a4418111f8..1750ab8f67 160000 --- a/osu-resources +++ b/osu-resources @@ -1 +1 @@ -Subproject commit a4418111f8ed2350a6fd46fe69258884f0757745 +Subproject commit 1750ab8f6761ab35592fd46da71fbe0c141bfd93 From 3d6bb3befec25e93a3b47c93960a4957b8bdd794 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Sat, 11 Nov 2017 22:53:50 +0900 Subject: [PATCH 0615/1263] Add startup argument to disable the version overlay --- osu.Desktop/OsuGameDesktop.cs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/osu.Desktop/OsuGameDesktop.cs b/osu.Desktop/OsuGameDesktop.cs index 990dc789e6..3393bbf7fb 100644 --- a/osu.Desktop/OsuGameDesktop.cs +++ b/osu.Desktop/OsuGameDesktop.cs @@ -18,9 +18,12 @@ namespace osu.Desktop { internal class OsuGameDesktop : OsuGame { + private readonly bool noVersionOverlay; + public OsuGameDesktop(string[] args = null) : base(args) { + noVersionOverlay = args?.Any(a => a == "--no-version-overlay") ?? false; } public override Storage GetStorageForStableInstall() @@ -79,11 +82,14 @@ namespace osu.Desktop { base.LoadComplete(); - LoadComponentAsync(new VersionManager { Depth = int.MinValue }, v => + if (!noVersionOverlay) { - Add(v); - v.State = Visibility.Visible; - }); + LoadComponentAsync(new VersionManager { Depth = int.MinValue }, v => + { + Add(v); + v.State = Visibility.Visible; + }); + } } public override void SetHost(GameHost host) From 36ac002820c05e1729cbce47af510a85dfcdcc86 Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Sat, 11 Nov 2017 18:25:16 +0300 Subject: [PATCH 0616/1263] Fix incorrect null check --- osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs b/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs index 164823f105..1134d43f53 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs @@ -105,7 +105,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores { request?.Cancel(); - if (!beatmap?.OnlineBeatmapID.HasValue ?? false) + if (!beatmap?.OnlineBeatmapID.HasValue ?? true) { clearAllScores(); return; From 569780d37b0b664d1281ae40354cc6d5430f233f Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Sun, 12 Nov 2017 07:05:50 +0300 Subject: [PATCH 0617/1263] Move Api request outside the scores container itself --- .../BeatmapSet/Scores/ClickableUsername.cs | 3 +- .../BeatmapSet/Scores/ScoresContainer.cs | 84 ++++++++----------- osu.Game/Overlays/BeatmapSetOverlay.cs | 28 ++++++- 3 files changed, 60 insertions(+), 55 deletions(-) diff --git a/osu.Game/Overlays/BeatmapSet/Scores/ClickableUsername.cs b/osu.Game/Overlays/BeatmapSet/Scores/ClickableUsername.cs index 762e3f0105..bc5595587b 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/ClickableUsername.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/ClickableUsername.cs @@ -14,7 +14,6 @@ namespace osu.Game.Overlays.BeatmapSet.Scores public class ClickableUsername : OsuHoverContainer { private readonly OsuSpriteText text; - private Action clickAction; private UserProfileOverlay profile; private User user; @@ -57,7 +56,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores protected override bool OnClick(InputState state) { - profile.ShowUser(user); + profile?.ShowUser(user); return base.OnClick(state); } } diff --git a/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs b/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs index 1134d43f53..41773cf18d 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs @@ -3,15 +3,13 @@ using OpenTK; using OpenTK.Graphics; -using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; -using osu.Game.Beatmaps; using osu.Game.Graphics.UserInterface; -using osu.Game.Online.API; using osu.Game.Online.API.Requests; +using System.Collections.Generic; using System.Linq; namespace osu.Game.Overlays.BeatmapSet.Scores @@ -25,29 +23,36 @@ namespace osu.Game.Overlays.BeatmapSet.Scores private readonly DrawableTopScore topScore; private readonly LoadingAnimation loadingAnimation; private readonly Box foreground; - private GetScoresRequest request; - private APIAccess api; - private bool isLoading + private bool isLoading; + public bool IsLoading { set { - foreground.FadeTo(value ? 1 : 0, fade_duration); - loadingAnimation.FadeTo(value ? 1 : 0, fade_duration); + if (isLoading == value) return; + isLoading = value; + + foreground.FadeTo(isLoading ? 1 : 0, fade_duration); + loadingAnimation.FadeTo(isLoading ? 1 : 0, fade_duration); } + get { return isLoading; } } - private BeatmapInfo beatmap; - public BeatmapInfo Beatmap + private IEnumerable scores; + public IEnumerable Scores { set { - if (beatmap == value) return; - beatmap = value; + if (scores == value) + { + IsLoading = false; + return; + } + scores = value; updateScores(); } - get { return beatmap; } + get { return scores; } } public ScoresContainer() @@ -95,58 +100,37 @@ namespace osu.Game.Overlays.BeatmapSet.Scores }; } - [BackgroundDependencyLoader] - private void load(APIAccess api) - { - this.api = api; - } - private void updateScores() { - request?.Cancel(); - - if (!beatmap?.OnlineBeatmapID.HasValue ?? true) + var scoresAmount = scores.Count(); + if (scoresAmount == 0) { - clearAllScores(); + CleanAllScores(); return; } - isLoading = true; + topScore.Score = scores.FirstOrDefault(); + topScore.Show(); - request = new GetScoresRequest(beatmap); - request.Success += scores => + flow.Clear(); + + if (scoresAmount < 2) { - var scoresAmount = scores.Scores.Count(); - if (scoresAmount == 0) - { - clearAllScores(); - return; - } + IsLoading = false; + return; + } - topScore.Score = scores.Scores.FirstOrDefault(); - topScore.Show(); + for (int i = 1; i < scoresAmount; i++) + flow.Add(new DrawableScore(i, scores.ElementAt(i))); - flow.Clear(); - - if (scoresAmount < 2) - { - isLoading = false; - return; - } - - for (int i = 1; i < scoresAmount; i++) - flow.Add(new DrawableScore(i, scores.Scores.ElementAt(i))); - - isLoading = false; - }; - api.Queue(request); + IsLoading = false; } - private void clearAllScores() + public void CleanAllScores() { topScore.Hide(); flow.Clear(); - isLoading = false; + IsLoading = false; } } } diff --git a/osu.Game/Overlays/BeatmapSetOverlay.cs b/osu.Game/Overlays/BeatmapSetOverlay.cs index db01d02c79..480808ee54 100644 --- a/osu.Game/Overlays/BeatmapSetOverlay.cs +++ b/osu.Game/Overlays/BeatmapSetOverlay.cs @@ -27,17 +27,17 @@ namespace osu.Game.Overlays private readonly Header header; private readonly Info info; + private readonly ScoresContainer scores; private APIAccess api; private RulesetStore rulesets; + private GetScoresRequest getScoresRequest; // receive input outside our bounds so we can trigger a close event on ourselves. public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => true; public BeatmapSetOverlay() { - ScoresContainer scores; - FirstWaveColour = OsuColour.Gray(0.4f); SecondWaveColour = OsuColour.Gray(0.3f); ThirdWaveColour = OsuColour.Gray(0.2f); @@ -83,7 +83,29 @@ namespace osu.Game.Overlays }, }; - header.Picker.Beatmap.ValueChanged += b => info.Beatmap = scores.Beatmap = b; + header.Picker.Beatmap.ValueChanged += b => + { + info.Beatmap = b; + updateScores(b); + }; + } + + private void updateScores(BeatmapInfo beatmap) + { + scores.IsLoading = true; + + getScoresRequest?.Cancel(); + + if (!beatmap.OnlineBeatmapID.HasValue) + { + scores.CleanAllScores(); + return; + } + + getScoresRequest = new GetScoresRequest(beatmap); + getScoresRequest.Success += r => scores.Scores = r.Scores; + + api.Queue(getScoresRequest); } [BackgroundDependencyLoader] From 7c0b13f9efa4b247ded6b3128ff73523a923ef8f Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Sun, 12 Nov 2017 07:31:08 +0300 Subject: [PATCH 0618/1263] CI fixes and minor visual improvements --- .../BeatmapSet/Scores/ClickableUsername.cs | 1 - .../BeatmapSet/Scores/DrawableScore.cs | 20 +++++++++---------- .../BeatmapSet/Scores/ScoresContainer.cs | 10 ++-------- 3 files changed, 12 insertions(+), 19 deletions(-) diff --git a/osu.Game/Overlays/BeatmapSet/Scores/ClickableUsername.cs b/osu.Game/Overlays/BeatmapSet/Scores/ClickableUsername.cs index bc5595587b..ab828cf0eb 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/ClickableUsername.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/ClickableUsername.cs @@ -6,7 +6,6 @@ using osu.Framework.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Users; -using System; using osu.Framework.Input; namespace osu.Game.Overlays.BeatmapSet.Scores diff --git a/osu.Game/Overlays/BeatmapSet/Scores/DrawableScore.cs b/osu.Game/Overlays/BeatmapSet/Scores/DrawableScore.cs index 6d20082383..f7655e54a9 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/DrawableScore.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/DrawableScore.cs @@ -22,6 +22,9 @@ namespace osu.Game.Overlays.BeatmapSet.Scores { private const int fade_duration = 100; private const float height = 30; + private const float side_margin = 20; + private const float flag_margin = 60; + private const float username_margin = 100; private readonly Box background; @@ -46,8 +49,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores Origin = Anchor.CentreLeft, Text = $"#{index + 1}", Font = @"Exo2.0-RegularItalic", - RelativePositionAxes = Axes.X, - X = 0.02f + Margin = new MarginPadding { Left = side_margin } }, new DrawableFlag(score.User.Country?.FlagName) { @@ -55,23 +57,22 @@ namespace osu.Game.Overlays.BeatmapSet.Scores Origin = Anchor.CentreLeft, Width = 30, Height = 20, - RelativePositionAxes = Axes.X, - X = 0.06f + Margin = new MarginPadding { Left = flag_margin } }, new ClickableUsername { Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, User = score.User, - RelativePositionAxes = Axes.X, - X = 0.1f + Margin = new MarginPadding { Left = username_margin } }, modsContainer = new ScoreModsContainer { Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, AutoSizeAxes = Axes.Y, - Width = 60, + RelativeSizeAxes = Axes.X, + Width = 0.05f, RelativePositionAxes = Axes.X, X = 0.45f }, @@ -105,12 +106,11 @@ namespace osu.Game.Overlays.BeatmapSet.Scores }, new OsuSpriteText { - Anchor = Anchor.CentreLeft, + Anchor = Anchor.CentreRight, Origin = Anchor.CentreRight, Text = $"{score.Statistics["300"]}/{score.Statistics["100"]}/{score.Statistics["50"]}", Font = @"Exo2.0-RegularItalic", - RelativePositionAxes = Axes.X, - X = 0.98f + Margin = new MarginPadding { Right = side_margin } }, }; diff --git a/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs b/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs index 41773cf18d..5bc2d0e1c4 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs @@ -43,13 +43,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores { set { - if (scores == value) - { - IsLoading = false; - return; - } scores = value; - updateScores(); } get { return scores; } @@ -92,9 +86,9 @@ namespace osu.Game.Overlays.BeatmapSet.Scores loadingAnimation = new LoadingAnimation { Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, + Origin = Anchor.Centre, Size = new Vector2(20), - Margin = new MarginPadding { Top = 10 }, + Margin = new MarginPadding { Top = 115 }, Alpha = 0, }, }; From 1792075cf9292350670dc83878eaf78554663e32 Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Sun, 12 Nov 2017 07:50:01 +0300 Subject: [PATCH 0619/1263] Loading animation fix --- osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs b/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs index 5bc2d0e1c4..c3281985ca 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs @@ -86,9 +86,8 @@ namespace osu.Game.Overlays.BeatmapSet.Scores loadingAnimation = new LoadingAnimation { Anchor = Anchor.TopCentre, - Origin = Anchor.Centre, - Size = new Vector2(20), - Margin = new MarginPadding { Top = 115 }, + Origin = Anchor.TopCentre, + Margin = new MarginPadding { Top = 105 }, Alpha = 0, }, }; From 96e99d996b04dd5c1cc1f94efdddea8a7e68a309 Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Sun, 12 Nov 2017 09:01:13 +0300 Subject: [PATCH 0620/1263] Add TestCase --- .../Visual/TestCaseBeatmapScoresContainer.cs | 314 ++++++++++++++++++ osu.Game.Tests/osu.Game.Tests.csproj | 1 + .../BeatmapSet/Scores/DrawableScore.cs | 2 +- .../BeatmapSet/Scores/ScoresContainer.cs | 5 +- 4 files changed, 317 insertions(+), 5 deletions(-) create mode 100644 osu.Game.Tests/Visual/TestCaseBeatmapScoresContainer.cs diff --git a/osu.Game.Tests/Visual/TestCaseBeatmapScoresContainer.cs b/osu.Game.Tests/Visual/TestCaseBeatmapScoresContainer.cs new file mode 100644 index 0000000000..274cee8d3a --- /dev/null +++ b/osu.Game.Tests/Visual/TestCaseBeatmapScoresContainer.cs @@ -0,0 +1,314 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.MathUtils; +using osu.Game.Graphics; +using osu.Game.Online.API.Requests; +using osu.Game.Overlays.BeatmapSet.Scores; +using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Osu.Mods; +using osu.Game.Rulesets.Scoring; +using osu.Game.Users; +using System.Collections.Generic; + +namespace osu.Game.Tests.Visual +{ + public class TestCaseBeatmapScoresContainer : OsuTestCase + { + public override string Description => "BeatmapOverlay scores container"; + + private readonly IEnumerable scores; + private readonly IEnumerable anotherScores; + private readonly OnlineScore topScore; + private readonly Box background; + private readonly Container container; + + public TestCaseBeatmapScoresContainer() + { + ScoresContainer scoresContainer; + + Child = container = new Container + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + AutoSizeAxes = Axes.Y, + RelativeSizeAxes = Axes.X, + Width = 0.8f, + Children = new Drawable[] + { + background = new Box { RelativeSizeAxes = Axes.Both }, + scoresContainer = new ScoresContainer(), + } + }; + + AddStep("scores pack 1", () => scoresContainer.Scores = scores); + AddStep("scores pack 2", () => scoresContainer.Scores = anotherScores); + AddStep("only top score", () => scoresContainer.Scores = new OnlineScore[] { topScore }); + AddStep("remove scores", scoresContainer.CleanAllScores); + AddStep("turn on loading", () => scoresContainer.IsLoading = true); + AddStep("turn off loading", () => scoresContainer.IsLoading = false); + AddStep("resize to big", () => container.ResizeWidthTo(1, 300)); + AddStep("resize to normal", () => container.ResizeWidthTo(0.8f, 300)); + + scores = new OnlineScore[] + { + new OnlineScore + { + User = new User + { + Id = 6602580, + Username = @"waaiiru", + Country = new Country + { + FullName = @"Spain", + FlagName = @"ES", + }, + }, + Mods = new Mod[] + { + new OsuModDoubleTime(), + new OsuModHidden(), + new OsuModFlashlight(), + new OsuModHardRock(), + }, + Rank = ScoreRank.XH, + TotalScore = 1234567890, + Accuracy = 1, + }, + new OnlineScore + { + User = new User + { + Id = 4608074, + Username = @"Skycries", + Country = new Country + { + FullName = @"Brazil", + FlagName = @"BR", + }, + }, + Mods = new Mod[] + { + new OsuModDoubleTime(), + new OsuModHidden(), + new OsuModFlashlight(), + }, + Rank = ScoreRank.S, + TotalScore = 1234789, + Accuracy = 0.9997, + }, + new OnlineScore + { + User = new User + { + Id = 1014222, + Username = @"eLy", + Country = new Country + { + FullName = @"Japan", + FlagName = @"JP", + }, + }, + Mods = new Mod[] + { + new OsuModDoubleTime(), + new OsuModHidden(), + }, + Rank = ScoreRank.B, + TotalScore = 12345678, + Accuracy = 0.9854, + }, + new OnlineScore + { + User = new User + { + Id = 1541390, + Username = @"Toukai", + Country = new Country + { + FullName = @"Canada", + FlagName = @"CA", + }, + }, + Mods = new Mod[] + { + new OsuModDoubleTime(), + }, + Rank = ScoreRank.C, + TotalScore = 1234567, + Accuracy = 0.8765, + }, + new OnlineScore + { + User = new User + { + Id = 7151382, + Username = @"Mayuri Hana", + Country = new Country + { + FullName = @"Thailand", + FlagName = @"TH", + }, + }, + Rank = ScoreRank.F, + TotalScore = 123456, + Accuracy = 0.6543, + }, + }; + foreach(var s in scores) + { + s.Statistics.Add("300", RNG.Next(2000)); + s.Statistics.Add("100", RNG.Next(2000)); + s.Statistics.Add("50", RNG.Next(2000)); + } + + anotherScores = new OnlineScore[] + { + new OnlineScore + { + User = new User + { + Id = 4608074, + Username = @"Skycries", + Country = new Country + { + FullName = @"Brazil", + FlagName = @"BR", + }, + }, + Mods = new Mod[] + { + new OsuModDoubleTime(), + new OsuModHidden(), + new OsuModFlashlight(), + }, + Rank = ScoreRank.S, + TotalScore = 1234789, + Accuracy = 0.9997, + }, + new OnlineScore + { + User = new User + { + Id = 6602580, + Username = @"waaiiru", + Country = new Country + { + FullName = @"Spain", + FlagName = @"ES", + }, + }, + Mods = new Mod[] + { + new OsuModDoubleTime(), + new OsuModHidden(), + new OsuModFlashlight(), + new OsuModHardRock(), + }, + Rank = ScoreRank.XH, + TotalScore = 1234567890, + Accuracy = 1, + }, + new OnlineScore + { + User = new User + { + Id = 7151382, + Username = @"Mayuri Hana", + Country = new Country + { + FullName = @"Thailand", + FlagName = @"TH", + }, + }, + Rank = ScoreRank.F, + TotalScore = 123456, + Accuracy = 0.6543, + }, + new OnlineScore + { + User = new User + { + Id = 1014222, + Username = @"eLy", + Country = new Country + { + FullName = @"Japan", + FlagName = @"JP", + }, + }, + Mods = new Mod[] + { + new OsuModDoubleTime(), + new OsuModHidden(), + }, + Rank = ScoreRank.B, + TotalScore = 12345678, + Accuracy = 0.9854, + }, + new OnlineScore + { + User = new User + { + Id = 1541390, + Username = @"Toukai", + Country = new Country + { + FullName = @"Canada", + FlagName = @"CA", + }, + }, + Mods = new Mod[] + { + new OsuModDoubleTime(), + }, + Rank = ScoreRank.C, + TotalScore = 1234567, + Accuracy = 0.8765, + }, + }; + foreach (var s in anotherScores) + { + s.Statistics.Add("300", RNG.Next(2000)); + s.Statistics.Add("100", RNG.Next(2000)); + s.Statistics.Add("50", RNG.Next(2000)); + } + + topScore = new OnlineScore + { + User = new User + { + Id = 2705430, + Username = @"Mooha", + Country = new Country + { + FullName = @"France", + FlagName = @"FR", + }, + }, + Mods = new Mod[] + { + new OsuModDoubleTime(), + new OsuModFlashlight(), + new OsuModHardRock(), + }, + Rank = ScoreRank.B, + TotalScore = 987654321, + Accuracy = 0.8487, + }; + topScore.Statistics.Add("300", RNG.Next(2000)); + topScore.Statistics.Add("100", RNG.Next(2000)); + topScore.Statistics.Add("50", RNG.Next(2000)); + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + background.Colour = colours.Gray2; + } + } +} diff --git a/osu.Game.Tests/osu.Game.Tests.csproj b/osu.Game.Tests/osu.Game.Tests.csproj index b1081890c8..974bde9319 100644 --- a/osu.Game.Tests/osu.Game.Tests.csproj +++ b/osu.Game.Tests/osu.Game.Tests.csproj @@ -93,6 +93,7 @@ + diff --git a/osu.Game/Overlays/BeatmapSet/Scores/DrawableScore.cs b/osu.Game/Overlays/BeatmapSet/Scores/DrawableScore.cs index f7655e54a9..2b1cdf5c25 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/DrawableScore.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/DrawableScore.cs @@ -84,7 +84,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores Height = 20, FillMode = FillMode.Fit, RelativePositionAxes = Axes.X, - X = 0.57f + X = 0.55f }, new OsuSpriteText { diff --git a/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs b/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs index c3281985ca..679e36971c 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs @@ -64,7 +64,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores Width = 0.95f, Direction = FillDirection.Vertical, Spacing = new Vector2(0, spacing), - Margin = new MarginPadding { Top = spacing }, + Margin = new MarginPadding { Vertical = spacing }, Children = new Drawable[] { topScore = new DrawableTopScore(), @@ -85,9 +85,6 @@ namespace osu.Game.Overlays.BeatmapSet.Scores }, loadingAnimation = new LoadingAnimation { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - Margin = new MarginPadding { Top = 105 }, Alpha = 0, }, }; From f5e510cdf2d510fa0995f903a0af33cc0b64c73b Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Sun, 12 Nov 2017 09:09:54 +0300 Subject: [PATCH 0621/1263] CI fixes --- osu.Game.Tests/Visual/TestCaseBeatmapScoresContainer.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCaseBeatmapScoresContainer.cs b/osu.Game.Tests/Visual/TestCaseBeatmapScoresContainer.cs index 274cee8d3a..8cae3feae2 100644 --- a/osu.Game.Tests/Visual/TestCaseBeatmapScoresContainer.cs +++ b/osu.Game.Tests/Visual/TestCaseBeatmapScoresContainer.cs @@ -25,10 +25,10 @@ namespace osu.Game.Tests.Visual private readonly IEnumerable anotherScores; private readonly OnlineScore topScore; private readonly Box background; - private readonly Container container; public TestCaseBeatmapScoresContainer() { + Container container; ScoresContainer scoresContainer; Child = container = new Container @@ -47,14 +47,14 @@ namespace osu.Game.Tests.Visual AddStep("scores pack 1", () => scoresContainer.Scores = scores); AddStep("scores pack 2", () => scoresContainer.Scores = anotherScores); - AddStep("only top score", () => scoresContainer.Scores = new OnlineScore[] { topScore }); + AddStep("only top score", () => scoresContainer.Scores = new[] { topScore }); AddStep("remove scores", scoresContainer.CleanAllScores); AddStep("turn on loading", () => scoresContainer.IsLoading = true); AddStep("turn off loading", () => scoresContainer.IsLoading = false); AddStep("resize to big", () => container.ResizeWidthTo(1, 300)); AddStep("resize to normal", () => container.ResizeWidthTo(0.8f, 300)); - scores = new OnlineScore[] + scores = new[] { new OnlineScore { @@ -166,7 +166,7 @@ namespace osu.Game.Tests.Visual s.Statistics.Add("50", RNG.Next(2000)); } - anotherScores = new OnlineScore[] + anotherScores = new[] { new OnlineScore { From ae9b7518e00bc3018577327079b0eabd603ee63a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 12 Nov 2017 21:07:14 +0900 Subject: [PATCH 0622/1263] Update framework --- osu-framework | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu-framework b/osu-framework index 36fad894f0..47aabeaee5 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit 36fad894f0657d0fdc998ffd3f2f3fa87e45d67d +Subproject commit 47aabeaee5a8d85a0e6769fd601736f8dc1eb051 From 16e48ed187073b9f77799016005356a3a166e38d Mon Sep 17 00:00:00 2001 From: Unknown Date: Sun, 5 Nov 2017 16:33:58 +0530 Subject: [PATCH 0623/1263] Hook up download logic with BeatmapSetOverlay download buttons. - Add noVideo option to DownloadBeatmapSetRequest - Make Download fire an event with new download instead of returning it --- osu.Game/Beatmaps/BeatmapManager.cs | 27 +++++++++---- .../API/Requests/DownloadBeatmapSetRequest.cs | 7 +++- osu.Game/Overlays/BeatmapSet/Header.cs | 40 ++++++++++++++++--- osu.Game/Overlays/BeatmapSetOverlay.cs | 14 ++++++- osu.Game/Overlays/Direct/DirectPanel.cs | 20 +++------- 5 files changed, 78 insertions(+), 30 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index f02a9a176c..e610073300 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -18,6 +18,7 @@ using osu.Framework.Platform; using osu.Game.Beatmaps.Formats; using osu.Game.Beatmaps.IO; using osu.Game.Database; +using osu.Game.Graphics; using osu.Game.IO; using osu.Game.IPC; using osu.Game.Online.API; @@ -52,6 +53,11 @@ namespace osu.Game.Beatmaps /// public event Action BeatmapRestored; + /// + /// Fired when a beatmap download begins. + /// + public event Action BeatmapDownloadBegan; + /// /// A default representation of a WorkingBeatmap to use when no beatmap is available. /// @@ -221,21 +227,29 @@ namespace osu.Game.Beatmaps /// Downloads a beatmap. /// /// The to be downloaded. - /// A new , or an existing one if a download is already in progress. - public DownloadBeatmapSetRequest Download(BeatmapSetInfo beatmapSetInfo) + /// Whether the beatmap should be downloaded without video. Defaults to false. + public void Download(BeatmapSetInfo beatmapSetInfo, bool noVideo = false) { var existing = GetExistingDownload(beatmapSetInfo); - if (existing != null) return existing; + if (existing != null || api == null) return; - if (api == null) return null; + if (!api.LocalUser.Value.IsSupporter) + { + PostNotification?.Invoke(new SimpleNotification + { + Icon = FontAwesome.fa_superpowers, + Text = "You gotta be a supporter to download for now 'yo" + }); + return; + } ProgressNotification downloadNotification = new ProgressNotification { Text = $"Downloading {beatmapSetInfo.Metadata.Artist} - {beatmapSetInfo.Metadata.Title}", }; - var request = new DownloadBeatmapSetRequest(beatmapSetInfo); + var request = new DownloadBeatmapSetRequest(beatmapSetInfo, noVideo); request.DownloadProgressed += progress => { @@ -280,8 +294,7 @@ namespace osu.Game.Beatmaps // don't run in the main api queue as this is a long-running task. Task.Factory.StartNew(() => request.Perform(api), TaskCreationOptions.LongRunning); - - return request; + BeatmapDownloadBegan?.Invoke(request); } /// diff --git a/osu.Game/Online/API/Requests/DownloadBeatmapSetRequest.cs b/osu.Game/Online/API/Requests/DownloadBeatmapSetRequest.cs index 5a9f609bca..cdcc06a65c 100644 --- a/osu.Game/Online/API/Requests/DownloadBeatmapSetRequest.cs +++ b/osu.Game/Online/API/Requests/DownloadBeatmapSetRequest.cs @@ -12,13 +12,16 @@ namespace osu.Game.Online.API.Requests public Action DownloadProgressed; - public DownloadBeatmapSetRequest(BeatmapSetInfo set) + private readonly bool noVideo; + + public DownloadBeatmapSetRequest(BeatmapSetInfo set, bool noVideo) { + this.noVideo = noVideo; BeatmapSet = set; Progress += (current, total) => DownloadProgressed?.Invoke((float) current / total); } - protected override string Target => $@"beatmapsets/{BeatmapSet.OnlineBeatmapSetID}/download"; + protected override string Target => $@"beatmapsets/{BeatmapSet.OnlineBeatmapSetID}/download{(noVideo ? "?noVideo=1" : "")}"; } } diff --git a/osu.Game/Overlays/BeatmapSet/Header.cs b/osu.Game/Overlays/BeatmapSet/Header.cs index d4514cbaed..a9802c8155 100644 --- a/osu.Game/Overlays/BeatmapSet/Header.cs +++ b/osu.Game/Overlays/BeatmapSet/Header.cs @@ -27,12 +27,17 @@ namespace osu.Game.Overlays.BeatmapSet private readonly Container coverContainer; private readonly OsuSpriteText title, artist; private readonly AuthorInfo author; + private readonly Container downloadButtonsContainer; public Details Details; + private BeatmapManager beatmaps; + private DelayedLoadWrapper cover; public readonly BeatmapPicker Picker; + private bool isDownloading => beatmaps.GetExistingDownload(BeatmapSet) != null; + private BeatmapSetInfo beatmapSet; public BeatmapSetInfo BeatmapSet { @@ -162,7 +167,7 @@ namespace osu.Game.Overlays.BeatmapSet Children = new Drawable[] { new FavouriteButton(), - new Container + downloadButtonsContainer = new Container { RelativeSizeAxes = Axes.Both, Padding = new MarginPadding { Left = buttons_height + buttons_spacing }, @@ -172,7 +177,10 @@ namespace osu.Game.Overlays.BeatmapSet { RelativeSizeAxes = Axes.Both, Alpha = 0f, - Child = new DownloadButton("Download", @""), + Child = new DownloadButton("Download", @"") + { + Action = () => download(false), + }, }, videoButtons = new FillFlowContainer { @@ -181,8 +189,14 @@ namespace osu.Game.Overlays.BeatmapSet Alpha = 0f, Children = new[] { - new DownloadButton("Download", "with Video"), - new DownloadButton("Download", "without Video"), + new DownloadButton("Download", "with Video") + { + Action = () => download(false), + }, + new DownloadButton("Download", "without Video") + { + Action = () => download(true), + }, }, }, }, @@ -220,9 +234,25 @@ namespace osu.Game.Overlays.BeatmapSet } [BackgroundDependencyLoader] - private void load(OsuColour colours) + private void load(OsuColour colours, BeatmapManager beatmaps) { tabsBg.Colour = colours.Gray3; + this.beatmaps = beatmaps; + } + + private void download(bool video) + { + if (beatmaps.GetExistingDownload(BeatmapSet) != null) + { + downloadButtonsContainer.MoveToX(-5, 50, Easing.OutSine).Then() + .MoveToX(5, 100, Easing.InOutSine).Then() + .MoveToX(-5, 100, Easing.InOutSine).Then() + .MoveToX(0, 50, Easing.InSine).Then(); + + return; + } + + beatmaps.Download(BeatmapSet); } } } diff --git a/osu.Game/Overlays/BeatmapSetOverlay.cs b/osu.Game/Overlays/BeatmapSetOverlay.cs index ddd146bcb6..7e80f427de 100644 --- a/osu.Game/Overlays/BeatmapSetOverlay.cs +++ b/osu.Game/Overlays/BeatmapSetOverlay.cs @@ -24,11 +24,14 @@ namespace osu.Game.Overlays public const float X_PADDING = 40; public const float RIGHT_WIDTH = 275; + private BeatmapSetInfo currentBeatmap; + private readonly Header header; private readonly Info info; private APIAccess api; private RulesetStore rulesets; + private BeatmapManager manager; // receive input outside our bounds so we can trigger a close event on ourselves. public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => true; @@ -83,10 +86,17 @@ namespace osu.Game.Overlays } [BackgroundDependencyLoader] - private void load(APIAccess api, RulesetStore rulesets) + private void load(APIAccess api, RulesetStore rulesets, BeatmapManager manager) { this.api = api; this.rulesets = rulesets; + this.manager = manager; + + manager.BeatmapSetAdded += beatmap => + { + if (beatmap.OnlineBeatmapSetID == currentBeatmap.OnlineBeatmapSetID) + Hide(); + }; } protected override void PopIn() @@ -118,7 +128,7 @@ namespace osu.Game.Overlays public void ShowBeatmapSet(BeatmapSetInfo set) { - header.BeatmapSet = info.BeatmapSet = set; + currentBeatmap = header.BeatmapSet = info.BeatmapSet = set; Show(); } } diff --git a/osu.Game/Overlays/Direct/DirectPanel.cs b/osu.Game/Overlays/Direct/DirectPanel.cs index ef89c0022b..702aef7417 100644 --- a/osu.Game/Overlays/Direct/DirectPanel.cs +++ b/osu.Game/Overlays/Direct/DirectPanel.cs @@ -18,7 +18,6 @@ using osu.Framework.Input; using osu.Game.Graphics.UserInterface; using osu.Game.Online.API; using osu.Framework.Logging; -using osu.Game.Overlays.Notifications; using osu.Game.Online.API.Requests; using osu.Framework.Configuration; using osu.Framework.Audio.Track; @@ -109,6 +108,8 @@ namespace osu.Game.Overlays.Direct if (downloadRequest != null) attachDownload(downloadRequest); + + beatmaps.BeatmapDownloadBegan += attachDownload; } protected override void Update() @@ -151,16 +152,6 @@ namespace osu.Game.Overlays.Direct protected void StartDownload() { - if (!api.LocalUser.Value.IsSupporter) - { - notifications.Post(new SimpleNotification - { - Icon = FontAwesome.fa_superpowers, - Text = "You gotta be a supporter to download for now 'yo" - }); - return; - } - if (beatmaps.GetExistingDownload(SetInfo) != null) { // we already have an active download running. @@ -172,13 +163,14 @@ namespace osu.Game.Overlays.Direct return; } - var request = beatmaps.Download(SetInfo); - - attachDownload(request); + beatmaps.Download(SetInfo); } private void attachDownload(DownloadBeatmapSetRequest request) { + if (request.BeatmapSet.OnlineBeatmapSetID != SetInfo.OnlineBeatmapSetID) + return; + progressBar.FadeIn(400, Easing.OutQuint); progressBar.ResizeHeightTo(4, 400, Easing.OutQuint); From 11077546d1404ae28c51358dde32fbbbc9e43945 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 12 Nov 2017 15:59:11 +0900 Subject: [PATCH 0624/1263] Load logo async --- osu.Game/Screens/OsuScreen.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/OsuScreen.cs b/osu.Game/Screens/OsuScreen.cs index 3dd175ca88..25c159ed40 100644 --- a/osu.Game/Screens/OsuScreen.cs +++ b/osu.Game/Screens/OsuScreen.cs @@ -118,7 +118,7 @@ namespace osu.Game.Screens } if ((logo = lastOsu?.logo) == null) - AddInternal(logo = new OsuLogo()); + LoadComponentAsync(logo = new OsuLogo(), AddInternal); base.OnEntering(last); From ec758379659e83226a63b747173e2cd17fc03205 Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Mon, 13 Nov 2017 05:04:21 +0300 Subject: [PATCH 0625/1263] Replay speed setting visual improvements --- .../Play/ReplaySettings/PlaybackSettings.cs | 47 +++++++++++++++---- 1 file changed, 39 insertions(+), 8 deletions(-) diff --git a/osu.Game/Screens/Play/ReplaySettings/PlaybackSettings.cs b/osu.Game/Screens/Play/ReplaySettings/PlaybackSettings.cs index bf2909b8ab..8aaf5b5711 100644 --- a/osu.Game/Screens/Play/ReplaySettings/PlaybackSettings.cs +++ b/osu.Game/Screens/Play/ReplaySettings/PlaybackSettings.cs @@ -3,6 +3,9 @@ using osu.Framework.Timing; using osu.Framework.Configuration; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Graphics.Sprites; namespace osu.Game.Screens.Play.ReplaySettings { @@ -13,19 +16,43 @@ namespace osu.Game.Screens.Play.ReplaySettings public IAdjustableClock AdjustableClock { set; get; } private readonly ReplaySliderBar sliderbar; + private readonly OsuSpriteText multiplierText; public PlaybackSettings() { - Child = sliderbar = new ReplaySliderBar + Children = new Drawable[] { - LabelText = "Playback speed", - Bindable = new BindableDouble(1) + new Container { - Default = 1, - MinValue = 0.5, - MaxValue = 2, - Precision = 0.01, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Children = new Drawable[] + { + new OsuSpriteText + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Text = "Playback speed", + }, + multiplierText = new OsuSpriteText + { + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + Text = "1x", + Font = @"Exo2.0-Bold", + } + }, }, + sliderbar = new ReplaySliderBar + { + Bindable = new BindableDouble(1) + { + Default = 1, + MinValue = 0.5, + MaxValue = 2, + Precision = 0.01, + }, + } }; } @@ -37,7 +64,11 @@ namespace osu.Game.Screens.Play.ReplaySettings return; var clockRate = AdjustableClock.Rate; - sliderbar.Bindable.ValueChanged += rateMultiplier => AdjustableClock.Rate = clockRate * rateMultiplier; + sliderbar.Bindable.ValueChanged += rateMultiplier => + { + AdjustableClock.Rate = clockRate * rateMultiplier; + multiplierText.Text = $"{rateMultiplier}x"; + }; } } } From 89e9f847532d0a8283fada2f568d49b616574a2d Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Mon, 13 Nov 2017 05:52:05 +0300 Subject: [PATCH 0626/1263] Add padding to the text container --- .../Screens/Play/ReplaySettings/PlaybackSettings.cs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/osu.Game/Screens/Play/ReplaySettings/PlaybackSettings.cs b/osu.Game/Screens/Play/ReplaySettings/PlaybackSettings.cs index 8aaf5b5711..71526d72ef 100644 --- a/osu.Game/Screens/Play/ReplaySettings/PlaybackSettings.cs +++ b/osu.Game/Screens/Play/ReplaySettings/PlaybackSettings.cs @@ -11,6 +11,8 @@ namespace osu.Game.Screens.Play.ReplaySettings { public class PlaybackSettings : ReplayGroup { + private const int padding = 10; + protected override string Title => @"playback"; public IAdjustableClock AdjustableClock { set; get; } @@ -26,6 +28,7 @@ namespace osu.Game.Screens.Play.ReplaySettings { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, + Padding = new MarginPadding { Horizontal = padding }, Children = new Drawable[] { new OsuSpriteText @@ -54,6 +57,8 @@ namespace osu.Game.Screens.Play.ReplaySettings }, } }; + + sliderbar.Bindable.ValueChanged += rateMultiplier => multiplierText.Text = $"{rateMultiplier}x"; } protected override void LoadComplete() @@ -64,11 +69,7 @@ namespace osu.Game.Screens.Play.ReplaySettings return; var clockRate = AdjustableClock.Rate; - sliderbar.Bindable.ValueChanged += rateMultiplier => - { - AdjustableClock.Rate = clockRate * rateMultiplier; - multiplierText.Text = $"{rateMultiplier}x"; - }; + sliderbar.Bindable.ValueChanged += rateMultiplier => AdjustableClock.Rate = clockRate * rateMultiplier; } } } From 51adea2a604350e7b66f7dad4c70406a57308ae4 Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Mon, 13 Nov 2017 05:58:19 +0300 Subject: [PATCH 0627/1263] Convert text to a local variable --- osu.Game/Screens/Play/ReplaySettings/PlaybackSettings.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/ReplaySettings/PlaybackSettings.cs b/osu.Game/Screens/Play/ReplaySettings/PlaybackSettings.cs index 71526d72ef..3109552532 100644 --- a/osu.Game/Screens/Play/ReplaySettings/PlaybackSettings.cs +++ b/osu.Game/Screens/Play/ReplaySettings/PlaybackSettings.cs @@ -18,10 +18,11 @@ namespace osu.Game.Screens.Play.ReplaySettings public IAdjustableClock AdjustableClock { set; get; } private readonly ReplaySliderBar sliderbar; - private readonly OsuSpriteText multiplierText; public PlaybackSettings() { + OsuSpriteText multiplierText; + Children = new Drawable[] { new Container From e006090c5b26bfc26c9569b2eeaaaabaabf3cff5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 13 Nov 2017 13:13:43 +0900 Subject: [PATCH 0628/1263] Fix SpriteIcon loading textures on the update thread --- osu.Game/Graphics/SpriteIcon.cs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/osu.Game/Graphics/SpriteIcon.cs b/osu.Game/Graphics/SpriteIcon.cs index d4f9127d54..ca108bfa7a 100644 --- a/osu.Game/Graphics/SpriteIcon.cs +++ b/osu.Game/Graphics/SpriteIcon.cs @@ -57,11 +57,6 @@ namespace osu.Game.Graphics private void load(FontStore store) { this.store = store; - } - - protected override void LoadComplete() - { - base.LoadComplete(); updateTexture(); } From 8adf0a6db32ede8350df91963cf67d50818f0283 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 13 Nov 2017 13:58:44 +0900 Subject: [PATCH 0629/1263] Null-check in disposal of DatabasedKeyBindingInputManager --- osu.Game/Input/Bindings/DatabasedKeyBindingInputManager.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game/Input/Bindings/DatabasedKeyBindingInputManager.cs b/osu.Game/Input/Bindings/DatabasedKeyBindingInputManager.cs index 6dedf7385b..bae14fc1dc 100644 --- a/osu.Game/Input/Bindings/DatabasedKeyBindingInputManager.cs +++ b/osu.Game/Input/Bindings/DatabasedKeyBindingInputManager.cs @@ -51,7 +51,9 @@ namespace osu.Game.Input.Bindings protected override void Dispose(bool isDisposing) { base.Dispose(isDisposing); - store.KeyBindingChanged -= ReloadMappings; + + if (store != null) + store.KeyBindingChanged -= ReloadMappings; } protected override void ReloadMappings() => KeyBindings = store.Query(ruleset?.ID, variant).ToList(); From ae8407a3f370d5c7df52c90d54f2b71ff98c36cf Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 13 Nov 2017 14:00:35 +0900 Subject: [PATCH 0630/1263] Fix nested hitobject judgements not being removed --- osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs | 1 + osu.Game/Rulesets/UI/RulesetContainer.cs | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index 091af04106..941cedca3f 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -212,6 +212,7 @@ namespace osu.Game.Rulesets.Objects.Drawables nestedHitObjects = new List>(); h.OnJudgement += (d, j) => OnJudgement?.Invoke(d, j); + h.OnJudgementRemoved += (d, j) => OnJudgementRemoved?.Invoke(d, j); nestedHitObjects.Add(h); } diff --git a/osu.Game/Rulesets/UI/RulesetContainer.cs b/osu.Game/Rulesets/UI/RulesetContainer.cs index 36dce7218d..278814ea7e 100644 --- a/osu.Game/Rulesets/UI/RulesetContainer.cs +++ b/osu.Game/Rulesets/UI/RulesetContainer.cs @@ -242,7 +242,7 @@ namespace osu.Game.Rulesets.UI OnJudgement?.Invoke(j); }; - drawableObject.OnJudgementRemoved += (d, j) => { OnJudgementRemoved?.Invoke(j); }; + drawableObject.OnJudgementRemoved += (d, j) => OnJudgementRemoved?.Invoke(j); Playfield.Add(drawableObject); } From 0cec51110acbb2aa61cdd49489f0e3b5f5f50ceb Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 13 Nov 2017 17:52:16 +0900 Subject: [PATCH 0631/1263] Fix replay clock always running 1 frame behind * Fixes swells never completing. * Fixes forward playback missing notes every now and then. * Probably more stuff. --- osu.Game/Rulesets/UI/RulesetInputManager.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Rulesets/UI/RulesetInputManager.cs b/osu.Game/Rulesets/UI/RulesetInputManager.cs index 0419070b42..ddce60d819 100644 --- a/osu.Game/Rulesets/UI/RulesetInputManager.cs +++ b/osu.Game/Rulesets/UI/RulesetInputManager.cs @@ -148,6 +148,7 @@ namespace osu.Game.Rulesets.UI } clock.CurrentTime = newTime.Value; + Clock.ProcessFrame(); } requireMoreUpdateLoops = clock.CurrentTime != parentClock.CurrentTime; From 49a5af60e2fdfe15e60fa69feaf0cc5a03a1e1f5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 13 Nov 2017 18:43:05 +0900 Subject: [PATCH 0632/1263] Fix multiple order-of-execution issues with osu! logo Also sets better defaults. --- osu.Game/Screens/Loader.cs | 7 +------ osu.Game/Screens/Menu/Intro.cs | 2 -- osu.Game/Screens/Menu/MainMenu.cs | 3 --- osu.Game/Screens/Menu/OsuLogo.cs | 24 ++++++++++++++++++++++++ osu.Game/Screens/OsuScreen.cs | 19 +++++++++++-------- osu.Game/Screens/Play/PlayerLoader.cs | 1 - osu.Game/Screens/Select/SongSelect.cs | 2 -- 7 files changed, 36 insertions(+), 22 deletions(-) diff --git a/osu.Game/Screens/Loader.cs b/osu.Game/Screens/Loader.cs index 3afaa02824..ca541ea552 100644 --- a/osu.Game/Screens/Loader.cs +++ b/osu.Game/Screens/Loader.cs @@ -24,7 +24,6 @@ namespace osu.Game.Screens { base.LogoArriving(logo, resuming); - logo.RelativePositionAxes = Axes.None; logo.Triangles = false; logo.Origin = Anchor.BottomRight; logo.Anchor = Anchor.BottomRight; @@ -47,11 +46,7 @@ namespace osu.Game.Screens protected override void LogoSuspending(OsuLogo logo) { base.LogoSuspending(logo); - logo.FadeOut(100).OnComplete(l => - { - l.Anchor = Anchor.TopLeft; - l.Origin = Anchor.Centre; - }); + logo.FadeOut(100); } [BackgroundDependencyLoader] diff --git a/osu.Game/Screens/Menu/Intro.cs b/osu.Game/Screens/Menu/Intro.cs index 0445733b23..0cb343c1ac 100644 --- a/osu.Game/Screens/Menu/Intro.cs +++ b/osu.Game/Screens/Menu/Intro.cs @@ -127,8 +127,6 @@ namespace osu.Game.Screens.Menu if (!resuming) { - logo.Triangles = true; - logo.ScaleTo(1); logo.FadeIn(); logo.PlayIntro(); diff --git a/osu.Game/Screens/Menu/MainMenu.cs b/osu.Game/Screens/Menu/MainMenu.cs index b0170edfe1..90f68ba9f1 100644 --- a/osu.Game/Screens/Menu/MainMenu.cs +++ b/osu.Game/Screens/Menu/MainMenu.cs @@ -112,9 +112,6 @@ namespace osu.Game.Screens.Menu buttons.SetOsuLogo(logo); - logo.Triangles = true; - logo.Ripple = false; - logo.FadeColour(Color4.White, 100, Easing.OutQuint); logo.FadeIn(100, Easing.OutQuint); diff --git a/osu.Game/Screens/Menu/OsuLogo.cs b/osu.Game/Screens/Menu/OsuLogo.cs index dccb910d86..fb8e755b61 100644 --- a/osu.Game/Screens/Menu/OsuLogo.cs +++ b/osu.Game/Screens/Menu/OsuLogo.cs @@ -221,6 +221,30 @@ namespace osu.Game.Screens.Menu }; } + /// + /// Schedule a new extenral animation. Handled queueing and finishing previous animations in a sane way. + /// + /// The animation to be performed + /// If true, the new animation is delayed until all previous transforms finish. If false, existing transformed are cleared. + internal void AppendAnimatingAction(Action action, bool waitForPrevious) + { + Action runnableAction = () => + { + if (waitForPrevious) + this.DelayUntilTransformsFinished().Schedule(action); + else + { + ClearTransforms(); + action(); + } + }; + + if (IsLoaded) + runnableAction(); + else + Schedule(() => runnableAction()); + } + [BackgroundDependencyLoader] private void load(TextureStore textures, AudioManager audio) { diff --git a/osu.Game/Screens/OsuScreen.cs b/osu.Game/Screens/OsuScreen.cs index 25c159ed40..f5ff9ea036 100644 --- a/osu.Game/Screens/OsuScreen.cs +++ b/osu.Game/Screens/OsuScreen.cs @@ -76,7 +76,7 @@ namespace osu.Game.Screens protected override void OnResuming(Screen last) { base.OnResuming(last); - logo.DelayUntilTransformsFinished().Schedule(() => LogoArriving(logo, true)); + logo.AppendAnimatingAction(() => LogoArriving(logo, true), true); sampleExit?.Play(); } @@ -118,11 +118,11 @@ namespace osu.Game.Screens } if ((logo = lastOsu?.logo) == null) - LoadComponentAsync(logo = new OsuLogo(), AddInternal); + LoadComponentAsync(logo = new OsuLogo { Alpha = 0 }, AddInternal); + + logo.AppendAnimatingAction(() => LogoArriving(logo, false), true); base.OnEntering(last); - - logo.DelayUntilTransformsFinished().Schedule(() => LogoArriving(logo, false)); } protected override bool OnExiting(Screen next) @@ -155,12 +155,16 @@ namespace osu.Game.Screens { logo.Action = null; logo.FadeOut(300, Easing.OutQuint); + logo.Anchor = Anchor.TopLeft; + logo.Origin = Anchor.Centre; + logo.RelativePositionAxes = Axes.None; + logo.Triangles = true; + logo.Ripple = true; } private void onExitingLogo() { - logo.ClearTransforms(); - LogoExiting(logo); + logo.AppendAnimatingAction(() => { LogoExiting(logo); }, false); } /// @@ -172,8 +176,7 @@ namespace osu.Game.Screens private void onSuspendingLogo() { - logo.ClearTransforms(); - LogoSuspending(logo); + logo.AppendAnimatingAction(() => { LogoSuspending(logo); }, false); } /// diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index 53a2dcc41f..de67bef004 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -99,7 +99,6 @@ namespace osu.Game.Screens.Play { base.LogoArriving(logo, resuming); - logo.ClearTransforms(targetMember: nameof(Position)); logo.RelativePositionAxes = Axes.Both; logo.ScaleTo(new Vector2(0.15f), 300, Easing.In); diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 121a53f699..5500d06136 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -315,9 +315,7 @@ namespace osu.Game.Screens.Select { base.LogoArriving(logo, resuming); - logo.ClearTransforms(); logo.RelativePositionAxes = Axes.Both; - Vector2 position = new Vector2(0.95f, 0.96f); if (logo.Alpha > 0.8f) From 495155874cf7fa4e4d0d7cb749c09fabd2799529 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 13 Nov 2017 19:02:53 +0900 Subject: [PATCH 0633/1263] Make sure that the clock is only updated once per time value --- osu-framework | 2 +- osu.Game/Rulesets/UI/RulesetInputManager.cs | 9 ++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/osu-framework b/osu-framework index 47aabeaee5..81a3551886 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit 47aabeaee5a8d85a0e6769fd601736f8dc1eb051 +Subproject commit 81a35518860cc533c4bf55b407c4e63d47ad11ce diff --git a/osu.Game/Rulesets/UI/RulesetInputManager.cs b/osu.Game/Rulesets/UI/RulesetInputManager.cs index ddce60d819..8c4d6de1fe 100644 --- a/osu.Game/Rulesets/UI/RulesetInputManager.cs +++ b/osu.Game/Rulesets/UI/RulesetInputManager.cs @@ -76,6 +76,8 @@ namespace osu.Game.Rulesets.UI #region Clock control + protected override bool ShouldProcessClock => false; // We handle processing the clock ourselves + private ManualClock clock; private IFrameBasedClock parentClock; @@ -148,10 +150,15 @@ namespace osu.Game.Rulesets.UI } clock.CurrentTime = newTime.Value; - Clock.ProcessFrame(); } requireMoreUpdateLoops = clock.CurrentTime != parentClock.CurrentTime; + + // The manual clock time has changed in the above code. The framed clock now needs to be updated + // to ensure that the its time is valid for our children before input is processed + Clock.ProcessFrame(); + + // Process input base.Update(); } From a2cb9d4086a70f72c735d942b9756d2d4a11cb19 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 13 Nov 2017 19:43:00 +0900 Subject: [PATCH 0634/1263] Fix audio not playing during player loading Regression due to changed audio initialisation logic. --- osu.Game/Screens/Play/Player.cs | 38 ++++++++++++++++----------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 59d56a5a44..675d20fe63 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -144,22 +144,6 @@ namespace osu.Game.Screens.Play userAudioOffset.ValueChanged += v => offsetClock.Offset = v; userAudioOffset.TriggerChange(); - Task.Run(() => - { - adjustableSourceClock.Reset(); - - // this is temporary until we have blocking (async.Wait()) audio component methods. - // then we can call ResetAsync().Wait() or the blocking version above. - while (adjustableSourceClock.IsRunning) - Thread.Sleep(1); - - Schedule(() => - { - decoupledClock.ChangeSource(adjustableSourceClock); - applyRateFromMods(); - }); - }); - Children = new Drawable[] { storyboardContainer = new Container @@ -329,10 +313,26 @@ namespace osu.Game.Screens.Play .Delay(250) .FadeIn(250); - this.Delay(750).Schedule(() => + Task.Run(() => { - if (!pauseContainer.IsPaused) - decoupledClock.Start(); + adjustableSourceClock.Reset(); + + // this is temporary until we have blocking (async.Wait()) audio component methods. + // then we can call ResetAsync().Wait() or the blocking version above. + while (adjustableSourceClock.IsRunning) + Thread.Sleep(1); + + Schedule(() => + { + decoupledClock.ChangeSource(adjustableSourceClock); + applyRateFromMods(); + + this.Delay(750).Schedule(() => + { + if (!pauseContainer.IsPaused) + decoupledClock.Start(); + }); + }); }); pauseContainer.Alpha = 0; From 952530e1a8fe6cb2235263584ce38a8a026f68e1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 13 Nov 2017 20:03:58 +0900 Subject: [PATCH 0635/1263] Update framework --- osu-framework | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu-framework b/osu-framework index 81a3551886..c95b9350ed 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit 81a35518860cc533c4bf55b407c4e63d47ad11ce +Subproject commit c95b9350edb6305cfefdf08f902f6f73d336736b From fa6d3f97929d871a5f442cc1072c7909f515d552 Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Mon, 13 Nov 2017 18:49:10 +0300 Subject: [PATCH 0636/1263] Reduce isLoading calls --- .../Overlays/BeatmapSet/Scores/ScoresContainer.cs | 6 ------ osu.Game/Overlays/BeatmapSetOverlay.cs | 11 +++++++---- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs b/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs index 679e36971c..2bbfa0f56a 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs @@ -105,22 +105,16 @@ namespace osu.Game.Overlays.BeatmapSet.Scores flow.Clear(); if (scoresAmount < 2) - { - IsLoading = false; return; - } for (int i = 1; i < scoresAmount; i++) flow.Add(new DrawableScore(i, scores.ElementAt(i))); - - IsLoading = false; } public void CleanAllScores() { topScore.Hide(); flow.Clear(); - IsLoading = false; } } } diff --git a/osu.Game/Overlays/BeatmapSetOverlay.cs b/osu.Game/Overlays/BeatmapSetOverlay.cs index 480808ee54..51be30b120 100644 --- a/osu.Game/Overlays/BeatmapSetOverlay.cs +++ b/osu.Game/Overlays/BeatmapSetOverlay.cs @@ -92,8 +92,6 @@ namespace osu.Game.Overlays private void updateScores(BeatmapInfo beatmap) { - scores.IsLoading = true; - getScoresRequest?.Cancel(); if (!beatmap.OnlineBeatmapID.HasValue) @@ -102,9 +100,14 @@ namespace osu.Game.Overlays return; } - getScoresRequest = new GetScoresRequest(beatmap); - getScoresRequest.Success += r => scores.Scores = r.Scores; + scores.IsLoading = true; + getScoresRequest = new GetScoresRequest(beatmap); + getScoresRequest.Success += r => + { + scores.Scores = r.Scores; + scores.IsLoading = false; + }; api.Queue(getScoresRequest); } From f6cbde95e2374a5ab5e918d5bd3a7819c388580e Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 14 Nov 2017 13:06:40 +0900 Subject: [PATCH 0637/1263] Remove unused files --- osu.Game/Resources/Resource.cs | 20 - .../Soleily - Renatus (Gamu) [Insane].osu | 1002 ----------------- 2 files changed, 1022 deletions(-) delete mode 100644 osu.Game/Resources/Resource.cs delete mode 100644 osu.Game/Resources/Soleily - Renatus (Gamu) [Insane].osu diff --git a/osu.Game/Resources/Resource.cs b/osu.Game/Resources/Resource.cs deleted file mode 100644 index 6c66b6818b..0000000000 --- a/osu.Game/Resources/Resource.cs +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) 2007-2017 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using System; -using System.IO; -using System.Reflection; - -namespace osu.Game.Tests.Resources -{ - public static class Resource - { - public static Stream OpenResource(string name) - { - var localPath = Path.GetDirectoryName(Uri.UnescapeDataString(new UriBuilder(Assembly.GetExecutingAssembly().CodeBase).Path)); - - return Assembly.GetExecutingAssembly().GetManifestResourceStream($@"osu.Game.Tests.Resources.{name}") ?? - Assembly.LoadFrom(Path.Combine(localPath, @"osu.Game.Resources.dll")).GetManifestResourceStream($@"osu.Game.Resources.{name}"); - } - } -} \ No newline at end of file diff --git a/osu.Game/Resources/Soleily - Renatus (Gamu) [Insane].osu b/osu.Game/Resources/Soleily - Renatus (Gamu) [Insane].osu deleted file mode 100644 index 3e44dc0af8..0000000000 --- a/osu.Game/Resources/Soleily - Renatus (Gamu) [Insane].osu +++ /dev/null @@ -1,1002 +0,0 @@ -osu file format v14 - -[General] -AudioFilename: 03. Renatus - Soleily 192kbps.mp3 -AudioLeadIn: 0 -PreviewTime: 164471 -Countdown: 0 -SampleSet: Soft -StackLeniency: 0.7 -Mode: 0 -LetterboxInBreaks: 0 -WidescreenStoryboard: 0 - -[Editor] -Bookmarks: 11505,22054,32604,43153,53703,64252,74802,85351,95901,106450,116999,119637,130186,140735,151285,161834,164471,175020,185570,196119,206669,209306 -DistanceSpacing: 1.8 -BeatDivisor: 4 -GridSize: 4 -TimelineZoom: 2 - -[Metadata] -Title:Renatus -TitleUnicode:Renatus -Artist:Soleily -ArtistUnicode:Soleily -Creator:Gamu -Version:Insane -Source: -Tags:MBC7 Unisphere 地球ヤバイEP Chikyu Yabai -BeatmapID:557821 -BeatmapSetID:241526 - -[Difficulty] -HPDrainRate:6.5 -CircleSize:4 -OverallDifficulty:8 -ApproachRate:9 -SliderMultiplier:1.8 -SliderTickRate:2 - -[Events] -//Background and Video events -0,0,"machinetop_background.jpg",0,0 -//Break Periods -2,122474,140135 -//Storyboard Layer 0 (Background) -//Storyboard Layer 1 (Fail) -//Storyboard Layer 2 (Pass) -//Storyboard Layer 3 (Foreground) -//Storyboard Sound Samples - -[TimingPoints] -956,329.67032967033,4,2,0,60,1,0 -20736,-100,4,2,0,65,0,0 -22054,-100,4,2,0,70,0,0 -43153,-100,4,2,0,60,0,0 -48428,-100,4,2,0,50,0,0 -52879,-100,4,2,0,50,0,0 -53373,-100,4,2,0,60,0,0 -53703,-100,4,2,0,70,0,1 -74719,-100,4,2,0,70,0,0 -74802,-100,4,2,0,70,0,1 -95901,-100,4,2,0,70,0,0 -116999,-133.333333333333,4,2,0,50,0,0 -117164,-133.333333333333,4,2,0,30,0,0 -117329,-79.9999999999999,4,2,0,50,0,0 -117659,-100,4,2,0,50,0,0 -118977,-100,4,2,0,60,0,0 -119307,-100,4,2,0,70,0,0 -119637,659.340659340659,4,2,0,80,1,0 -119966,-100,4,2,0,70,0,0 -120296,-100,4,2,0,60,0,0 -120626,-100,4,2,0,50,0,0 -120955,-100,4,2,0,40,0,0 -121285,-100,4,2,0,30,0,0 -121615,-100,4,2,0,20,0,0 -121944,-100,4,2,0,10,0,0 -122274,-100,4,2,0,5,0,0 -140735,-100,4,2,0,50,0,0 -151285,-80,4,2,0,60,0,0 -161834,329.67032967033,4,2,0,65,1,0 -164141,-100,4,2,0,70,0,0 -164471,-100,4,2,0,70,0,1 -185487,-100,4,2,0,70,0,0 -185570,-100,4,2,0,70,0,1 -206669,659.340659340659,4,2,0,80,1,0 -206998,-100,4,2,0,70,0,0 -207328,-100,4,2,0,60,0,0 -207658,-100,4,2,0,50,0,0 -207987,-100,4,2,0,40,0,0 -208317,-100,4,2,0,30,0,0 -208647,-100,4,2,0,20,0,0 -208976,-100,4,2,0,10,0,0 -209306,-100,4,2,0,5,0,0 - - -[Colours] -Combo1 : 142,199,255 -Combo2 : 255,128,128 -Combo3 : 128,255,255 -Combo4 : 128,255,128 -Combo5 : 255,187,255 -Combo6 : 255,177,140 - -[HitObjects] -192,168,956,6,0,P|184:128|200:80,1,90,4|0,1:2|0:0,0:0:0:0: -304,56,1285,1,8,0:0:0:0: -244,236,1450,2,0,P|204:252|156:244,1,90,2|0,0:0|0:0,0:0:0:0: -276,156,1780,2,0,P|310:181|329:226,1,90,2|8,1:2|0:0,0:0:0:0: -300,328,2109,1,2,0:0:0:0: -192,332,2274,6,0,L|144:340,2,45,0|0|0,1:0|0:0|0:0,0:0:0:0: -388,300,2604,1,8,0:0:0:0: -244,236,2769,1,0,1:0:0:0: -232,208,2851,1,0,0:0:0:0: -224,176,2934,1,0,0:0:0:0: -228,144,3016,1,0,0:0:0:0: -244,116,3098,1,0,1:0:0:0: -332,52,3263,2,0,P|376:48|424:56,1,90,8|0,0:0|0:0,0:0:0:0: -488,228,3593,5,0,1:0:0:0: -460,240,3675,1,0,0:0:0:0: -428,236,3758,1,0,0:0:0:0: -292,160,3923,2,0,P|288:204|300:252,1,90,8|0,0:0|0:0,0:0:0:0: -316,276,4170,1,0,0:0:0:0: -344,292,4252,2,0,L|388:300,1,45,0|0,0:0|0:0,0:0:0:0: -288,356,4417,2,0,L|244:364,1,45,0|0,1:0|0:0,0:0:0:0: -168,328,4582,2,0,P|124:324|72:332,1,90,8|0,0:0|0:0,0:0:0:0: -24,188,4912,5,0,1:0:0:0: -56,192,4994,1,0,0:0:0:0: -88,196,5076,1,0,0:0:0:0: -148,108,5241,1,8,0:0:0:0: -188,240,5406,1,0,1:0:0:0: -188,240,5488,1,0,0:0:0:0: -188,240,5571,2,0,L|168:328,1,90,0|0,0:0|1:0,0:0:0:0: -260,216,5901,2,0,P|236:180|188:164,1,90,8|0,0:0|0:0,0:0:0:0: -248,296,6230,6,0,L|348:292,1,90,0|0,1:0|0:0,0:0:0:0: -504,232,6560,1,8,0:0:0:0: -400,204,6725,1,0,0:0:0:0: -392,176,6807,1,0,0:0:0:0: -384,144,6890,1,0,0:0:0:0: -376,116,6972,1,0,0:0:0:0: -368,88,7054,1,0,1:0:0:0: -188,48,7219,2,0,L|208:140,1,90,8|0,0:0|0:0,0:0:0:0: -248,296,7549,5,0,1:0:0:0: -207,135,7714,1,0,0:0:0:0: -156,232,7879,1,8,0:0:0:0: -316,191,8043,1,0,1:0:0:0: -316,191,8126,1,0,0:0:0:0: -316,191,8208,2,0,L|372:200,1,45,0|0,0:0|0:0,0:0:0:0: -492,200,8373,2,0,L|447:207,1,45,0|0,1:0|0:0,0:0:0:0: -408,136,8538,2,0,P|396:92|400:48,1,90,8|0,0:0|0:0,0:0:0:0: -260,32,8868,5,0,1:0:0:0: -252,64,8950,1,0,0:0:0:0: -236,92,9032,2,0,P|204:116|148:128,1,90,0|8,0:0|0:0,0:0:0:0: -28,188,9362,1,0,0:0:0:0: -60,196,9445,1,0,0:0:0:0: -88,212,9527,2,0,P|112:244|124:300,1,90,0|0,0:0|1:0,0:0:0:0: -112,128,9857,2,0,P|152:156|184:196,1,90,8|0,0:0|0:0,0:0:0:0: -216,288,10186,5,0,1:0:0:0: -216,288,10269,1,0,0:0:0:0: -216,288,10351,1,0,0:0:0:0: -268,192,10516,1,8,0:0:0:0: -356,128,10681,1,0,1:0:0:0: -388,120,10763,1,0,0:0:0:0: -420,128,10846,2,0,P|440:168|436:220,1,90,0|0,0:0|1:0,0:0:0:0: -332,328,11175,2,0,L|280:332,1,45,8|8,0:0|0:0,0:0:0:0: -216,288,11340,2,0,L|164:292,1,45,0|0,1:0|0:0,1:0:0:0: -100,248,11505,5,4,1:2:0:0: -148,116,11670,1,2,0:0:0:0: -268,192,11835,1,10,0:0:0:0: -136,328,11999,2,0,L|44:336,1,90,2|0,0:0|0:0,0:0:0:0: -216,288,12329,1,2,1:2:0:0: -148,116,12494,1,10,0:0:0:0: -100,248,12659,1,2,0:0:0:0: -268,192,12824,5,0,1:0:0:0: -268,192,12906,1,0,0:0:0:0: -268,192,12988,1,0,0:0:0:0: -340,272,13153,2,0,P|384:276|432:264,1,90,8|0,0:0|1:0,0:0:0:0: -452,244,13401,1,0,0:0:0:0: -468,216,13483,2,0,L|476:124,1,90,0|0,0:0|1:0,0:0:0:0: -368,32,13813,2,0,L|360:121,1,90,8|0,0:0|0:0,0:0:0:0: -340,272,14142,6,0,L|316:316,2,45,0|0|0,1:0|0:0|0:0,0:0:0:0: -452,244,14472,1,8,0:0:0:0: -268,192,14637,1,0,0:0:0:0: -236,188,14719,1,0,0:0:0:0: -204,192,14802,2,0,P|172:228|160:272,1,90,0|0,0:0|1:0,0:0:0:0: -128,140,15131,2,0,P|160:104|172:60,1,90,8|0,0:0|0:0,0:0:0:0: -64,52,15461,6,0,L|20:68,2,45,0|0|0,1:0|0:0|0:0,0:0:0:0: -171,64,15791,1,8,0:0:0:0: -264,8,15956,2,0,L|356:12,1,90,0|0,1:0|0:0,0:0:0:0: -452,56,16285,1,0,1:0:0:0: -296,140,16450,2,0,L|206:136,1,90,8|0,0:0|0:0,0:0:0:0: -108,184,16780,6,0,P|92:224|96:272,1,90,0|0,1:0|0:0,0:0:0:0: -200,244,17109,1,8,0:0:0:0: -108,108,17274,2,0,L|12:116,1,90,0|0,0:0|0:0,0:0:0:0: -200,244,17604,1,0,1:0:0:0: -296,140,17769,2,0,L|385:132,1,90,8|0,0:0|0:0,0:0:0:0: -480,184,18098,5,0,1:0:0:0: -488,216,18181,1,0,0:0:0:0: -496,248,18263,2,0,L|492:340,1,90,0|8,0:0|0:0,0:0:0:0: -404,224,18593,2,0,L|396:176,2,45,0|0|0,1:0|0:0|0:0,0:0:0:0: -304,264,18923,1,0,1:0:0:0: -200,244,19087,2,0,P|156:240|108:248,1,90,8|0,0:0|0:0,0:0:0:0: -296,140,19417,6,0,P|340:144|388:136,1,90,0|0,1:0|0:0,0:0:0:0: -440,44,19747,1,8,0:0:0:0: -404,224,19912,1,0,0:0:0:0: -404,224,19994,1,0,0:0:0:0: -404,224,20076,2,0,L|412:320,1,90,0|0,0:0|1:0,0:0:0:0: -200,244,20406,2,0,L|192:154,1,90,8|0,0:0|0:0,0:0:0:0: -184,44,20736,5,4,1:2:0:0: -152,40,20818,1,0,0:0:0:0: -120,48,20901,1,0,0:0:0:0: -96,68,20983,1,0,0:0:0:0: -76,92,21065,1,2,0:3:0:0: -64,120,21148,1,0,0:0:0:0: -60,152,21230,1,0,1:0:0:0: -64,184,21313,1,0,0:0:0:0: -76,212,21395,2,0,L|96:252,3,45,0|0|0|0,0:0|0:0|1:0|0:0,0:0:0:0: -144,316,21725,2,0,L|188:324,3,45,0|0|2|0,0:0|0:0|0:3|0:0,0:0:0:0: -268,340,22054,6,0,L|364:336,1,90,4|0,1:2|0:0,0:0:0:0: -452,280,22384,1,8,0:0:0:0: -512,188,22549,2,0,P|516:144|504:96,1,90,2|0,0:0|0:0,0:0:0:0: -340,24,22879,2,0,P|336:68|348:116,1,90,2|8,1:2|0:0,0:0:0:0: -420,192,23208,1,2,0:0:0:0: -328,252,23373,6,0,L|232:240,1,90,0|0,1:0|0:0,0:0:0:0: -64,256,23703,1,8,0:0:0:0: -144,184,23868,2,0,P|148:140|136:88,1,90,0|0,1:0|0:0,0:0:0:0: -40,52,24197,1,2,1:2:0:0: -139,95,24362,1,8,0:0:0:0: -216,20,24527,1,0,0:0:0:0: -315,63,24692,6,0,P|360:72|408:68,1,90,2|0,1:2|0:0,0:0:0:0: -492,132,25021,1,8,0:0:0:0: -412,204,25186,2,0,P|403:249|407:297,1,90,2|0,0:0|0:0,0:0:0:0: -268,328,25516,2,0,P|277:283|273:235,1,90,2|8,1:2|0:0,0:0:0:0: -232,140,25846,2,0,P|187:131|139:135,1,90,2|0,0:0|1:0,0:0:0:0: -64,208,26175,5,2,0:0:0:0: -44,316,26340,1,8,0:0:0:0: -148,280,26505,1,2,1:2:0:0: -456,208,26835,1,2,1:2:0:0: -476,316,26999,1,10,0:0:0:0: -372,280,27164,1,2,0:0:0:0: -356,172,27329,6,0,L|380:80,1,90,0|0,1:0|0:0,0:0:0:0: -456,208,27659,1,8,0:0:0:0: -300,236,27824,1,2,0:0:0:0: -300,236,27906,1,0,0:0:0:0: -300,236,27988,2,0,L|208:228,1,90,0|2,0:0|1:2,0:0:0:0: -140,312,28318,1,8,0:0:0:0: -372,280,28483,2,0,L|464:272,1,90,2|0,0:0|1:0,0:0:0:0: -500,136,28813,5,2,0:0:0:0: -432,56,28977,1,8,0:0:0:0: -328,24,29142,2,0,P|284:24|236:28,1,90,2|0,1:2|0:0,0:0:0:0: -80,144,29472,1,2,1:2:0:0: -116,44,29637,1,10,0:0:0:0: -184,128,29802,1,2,0:0:0:0: -20,88,29966,6,0,P|1:164|73:227,1,180,2|10,1:2|0:0,0:0:0:0: -184,128,30461,2,0,P|227:120|276:124,1,90,2|0,0:0|0:0,0:0:0:0: -392,188,30791,1,2,1:2:0:0: -272,260,30956,1,8,0:0:0:0: -396,328,31120,1,0,0:0:0:0: -256,348,31285,5,2,1:2:0:0: -224,344,31368,1,0,1:0:0:0: -192,340,31450,2,0,L|172:248,1,90,2|0,1:2|1:0,0:0:0:0: -8,136,31780,2,0,L|27:223,1,90,2|0,1:2|0:0,0:0:0:0: -56,328,32109,1,2,1:2:0:0: -108,192,32274,1,2,1:2:0:0: -100,160,32357,1,0,1:0:0:0: -92,132,32439,1,2,1:2:0:0: -84,104,32521,1,0,1:0:0:0: -76,72,32604,6,0,P|100:112|148:136,1,90,4|0,1:2|0:0,0:0:0:0: -240,168,32934,1,8,0:0:0:0: -336,124,33098,2,0,L|344:80,2,45,2|0|0,0:0|0:0|0:0,0:0:0:0: -264,248,33428,2,0,P|220:248|176:220,1,90,2|8,1:2|0:0,0:0:0:0: -260,84,33758,1,2,0:0:0:0: -344,212,33923,5,0,1:0:0:0: -344,212,34005,1,0,0:0:0:0: -344,212,34087,1,0,0:0:0:0: -440,160,34252,1,8,0:0:0:0: -312,320,34417,2,0,P|272:336|220:324,1,90,0|0,1:0|0:0,0:0:0:0: -156,176,34747,2,0,P|196:160|248:172,2,90,2|8|0,1:2|0:0|0:0,0:0:0:0: -132,280,35241,5,2,1:2:0:0: -132,280,35324,1,0,0:0:0:0: -132,280,35406,2,0,L|120:376,1,90,0|8,0:0|0:0,0:0:0:0: -312,320,35736,2,0,L|300:230,1,90,2|0,0:0|0:0,0:0:0:0: -316,124,36065,1,2,1:2:0:0: -400,192,36230,1,8,0:0:0:0: -300,230,36395,2,0,P|255:231|211:224,1,90,2|0,0:0|1:0,0:0:0:0: -24,132,36725,5,0,0:0:0:0: -132,152,36890,1,8,0:0:0:0: -60,232,37054,1,2,1:2:0:0: -60,232,37137,1,0,0:0:0:0: -60,232,37219,1,0,0:0:0:0: -92,56,37384,2,0,L|184:44,1,90,2|10,1:2|0:0,0:0:0:0: -316,124,37714,2,0,L|226:135,1,90,2|0,0:0|1:0,0:0:0:0: -60,232,38043,6,0,P|52:276|64:328,1,90,0|8,0:0|0:0,0:0:0:0: -220,152,38373,2,0,P|176:144|124:156,1,90,2|0,0:0|0:0,0:0:0:0: -176,252,38703,1,2,1:2:0:0: -323,213,38868,2,0,L|316:124,1,90,8|2,0:0|0:0,0:0:0:0: -332,320,39197,5,0,1:0:0:0: -424,260,39362,1,2,0:0:0:0: -260,272,39527,2,0,P|246:313|256:360,1,90,8|2,0:0|1:2,0:0:0:0: -408,336,39857,1,0,0:0:0:0: -176,252,40021,2,0,L|80:260,2,90,2|10|2,1:2|0:0|0:0,0:0:0:0: -324,212,40516,5,2,1:2:0:0: -324,212,40598,1,0,1:0:0:0: -324,212,40681,1,0,1:0:0:0: -200,336,40846,1,2,1:2:0:0: -236,188,41010,1,2,1:2:0:0: -236,188,41093,1,0,1:0:0:0: -236,188,41175,1,0,1:0:0:0: -281,357,41340,1,2,1:2:0:0: -176,252,41505,1,2,1:2:0:0: -176,252,41587,1,0,1:0:0:0: -176,252,41670,1,0,1:0:0:0: -344,297,41835,5,2,1:2:0:0: -432,232,41999,1,2,1:2:0:0: -444,204,42082,1,0,1:0:0:0: -448,172,42164,1,0,1:0:0:0: -444,140,42247,1,0,1:0:0:0: -432,112,42329,2,0,L|440:64,2,45,2|0|0,1:2|1:0|1:0,0:0:0:0: -236,188,42659,1,0,0:0:0:0: -340,172,42824,1,2,0:3:0:0: -272,88,42988,1,0,0:0:0:0: -132,160,43153,6,0,P|148:248|220:296,1,180,4|8,1:2|0:0,0:0:0:0: -324,320,43648,2,0,L|336:364,2,45,0|0|0,0:0|0:0|0:0,0:0:0:0: -292,216,43977,1,0,1:0:0:0: -396,240,44142,2,0,P|440:244|488:232,1,90,8|0,0:0|0:0,0:0:0:0: -328,124,44472,6,0,P|284:120|236:132,1,90,0|0,1:0|0:0,0:0:0:0: -168,212,44802,1,8,0:0:0:0: -192,316,44966,1,0,1:0:0:0: -140,220,45131,1,0,0:0:0:0: -83,310,45296,1,0,1:0:0:0: -114,205,45461,1,8,0:0:0:0: -10,229,45626,1,0,0:0:0:0: -106,176,45791,6,0,P|113:133|108:85,1,90,0|0,1:0|0:0,0:0:0:0: -204,136,46120,1,8,0:0:0:0: -256,40,46285,1,0,0:0:0:0: -256,40,46368,1,0,0:0:0:0: -256,40,46450,2,0,L|356:44,1,90,0|0,0:0|1:0,0:0:0:0: -501,124,46780,2,0,L|412:128,1,90,8|0,0:0|0:0,0:0:0:0: -324,192,47109,5,0,1:0:0:0: -356,296,47274,1,0,0:0:0:0: -284,216,47439,1,8,0:0:0:0: -269,323,47604,1,0,1:0:0:0: -237,220,47769,1,0,0:0:0:0: -178,311,47934,1,0,1:0:0:0: -191,203,48098,1,8,0:0:0:0: -99,261,48263,1,0,0:0:0:0: -156,168,48428,6,0,B|176:112|136:64|136:64|200:96,1,180,4|8,1:2|0:0,0:0:0:0: -300,124,48923,2,0,L|392:120,1,90,0|0,0:0|0:0,0:0:0:0: -468,48,49252,1,0,1:0:0:0: -390,120,49417,2,0,P|390:164|406:208,1,90,8|0,0:0|0:0,0:0:0:0: -352,344,49747,6,0,P|352:300|336:256,1,90,4|0,1:2|0:0,0:0:0:0: -240,208,50076,1,8,0:0:0:0: -163,320,50241,2,0,P|207:324|252:316,1,90,0|0,1:0|0:0,0:0:0:0: -240,208,50571,1,0,1:0:0:0: -76,296,50736,2,0,P|76:340|92:384,1,90,8|0,0:0|0:0,0:0:0:0: -312,164,51065,6,0,P|236:124|160:184,1,180,4|8,1:2|0:0,0:0:0:0: -247,297,51560,2,0,L|240:208,1,90,0|0,0:0|0:0,0:0:0:0: -224,48,51890,1,0,1:0:0:0: -332,56,52054,2,0,L|366:58,5,30,8|0|0|0|0|0,0:0|0:0|0:0|0:0|0:0|0:0,0:0:0:0: -408,64,52384,6,0,P|420:108|416:156,1,90,0|0,1:0|0:0,0:0:0:0: -360,260,52714,1,8,0:0:0:0: -247,297,52879,2,0,B|203:281|159:297|159:297|115:313|71:297,1,180,0|0,1:0|1:0,0:0:0:0: -116,196,53373,1,8,0:0:0:0: -120,164,53456,1,0,0:0:0:0: -124,132,53538,1,0,0:0:0:0: -128,100,53620,1,0,0:0:0:0: -132,68,53703,5,4,1:2:0:0: -40,136,53868,1,0,0:0:0:0: -204,160,54032,2,0,L|304:152,1,90,8|0,0:0|0:0,0:0:0:0: -408,64,54362,1,0,0:0:0:0: -408,64,54445,1,0,0:0:0:0: -408,64,54527,2,0,P|404:112|416:160,1,90,0|8,1:0|0:0,0:0:0:0: -484,236,54857,1,0,0:0:0:0: -428,328,55021,5,0,1:0:0:0: -328,296,55186,1,0,0:0:0:0: -328,296,55269,1,0,0:0:0:0: -328,296,55351,1,8,0:0:0:0: -416,300,55516,1,0,1:0:0:0: -472,208,55681,1,0,0:0:0:0: -316,268,55846,1,0,1:0:0:0: -460,180,56010,1,8,0:0:0:0: -304,240,56175,1,0,0:0:0:0: -404,272,56340,5,0,1:0:0:0: -448,152,56505,1,0,0:0:0:0: -448,152,56587,1,0,0:0:0:0: -448,152,56670,2,0,P|456:112|448:60,1,90,8|0,0:0|0:0,0:0:0:0: -268,28,56999,2,0,P|260:68|268:120,1,90,0|0,0:0|1:0,0:0:0:0: -404,272,57329,2,0,P|444:280|496:272,2,90,8|0|0,0:0|0:0|1:0,0:0:0:0: -304,240,57824,5,0,0:0:0:0: -252,336,57988,1,8,0:0:0:0: -196,244,58153,1,0,1:0:0:0: -24,256,58318,1,0,0:0:0:0: -116,200,58483,1,0,1:0:0:0: -136,60,58648,1,8,0:0:0:0: -192,152,58813,1,0,0:0:0:0: -304,240,58977,6,0,P|348:252|396:248,1,90,0|0,1:0|0:0,0:0:0:0: -456,116,59307,2,0,P|412:104|364:108,1,90,8|0,0:0|0:0,0:0:0:0: -273,161,59637,1,0,0:0:0:0: -136,60,59802,1,0,1:0:0:0: -192,152,59966,1,8,0:0:0:0: -23,177,60131,1,0,0:0:0:0: -129,203,60296,5,0,1:0:0:0: -88,304,60461,2,0,P|132:311|176:303,1,90,0|8,0:0|0:0,0:0:0:0: -304,240,60791,1,0,1:0:0:0: -304,240,60873,1,0,0:0:0:0: -304,240,60956,2,0,L|312:288,3,45,0|0|0|0,0:0|0:0|1:0|0:0,0:0:0:0: -384,256,61285,2,0,L|392:304,3,45,8|0|0|0,0:0|0:0|0:0|0:0,0:0:0:0: -464,272,61615,5,2,1:2:0:0: -488,168,61780,1,2,0:0:0:0: -428,80,61945,1,10,0:0:0:0: -332,32,62109,2,0,P|288:28|240:36,1,90,2|0,0:0|0:0,0:0:0:0: -28,216,62439,1,2,1:2:0:0: -88,304,62604,1,10,0:0:0:0: -184,352,62769,2,0,P|228:356|276:348,1,90,2|0,0:0|1:0,0:0:0:0: -384,256,63098,6,0,P|409:219|426:174,1,90,2|8,0:0|0:0,0:0:0:0: -428,80,63428,2,0,L|420:36,2,45,2|0|0,1:2|0:0|0:0,0:0:0:0: -456,288,63758,1,2,1:2:0:0: -324,200,63923,1,10,1:2:0:0: -292,204,64005,1,0,1:0:0:0: -260,208,64087,1,2,1:2:0:0: -228,212,64170,1,0,1:0:0:0: -196,216,64252,5,4,1:2:0:0: -104,160,64417,1,0,0:0:0:0: -228,296,64582,2,0,L|320:284,1,90,8|0,0:0|0:0,0:0:0:0: -344,112,64912,1,0,0:0:0:0: -344,112,64994,1,0,0:0:0:0: -344,112,65076,2,0,L|254:123,1,90,0|8,1:0|0:0,0:0:0:0: -144,284,65406,2,0,P|148:328|176:364,1,90,0|0,0:0|1:0,0:0:0:0: -196,216,65736,5,0,0:0:0:0: -196,216,65818,1,0,0:0:0:0: -196,216,65901,2,0,P|155:198|110:205,1,90,8|0,0:0|1:0,0:0:0:0: -36,284,66230,1,0,0:0:0:0: -4,180,66395,1,0,1:0:0:0: -132,24,66560,1,8,0:0:0:0: -100,128,66725,1,0,0:0:0:0: -24,48,66890,5,0,1:0:0:0: -212,108,67054,1,0,0:0:0:0: -212,108,67137,1,0,0:0:0:0: -212,108,67219,2,0,L|300:92,1,90,8|0,0:0|0:0,0:0:0:0: -472,144,67549,2,0,L|384:160,1,90,0|0,0:0|1:0,0:0:0:0: -196,216,67879,2,0,P|240:216|288:240,1,90,8|0,0:0|0:0,0:0:0:0: -324,336,68208,5,0,1:0:0:0: -144,288,68373,1,0,0:0:0:0: -58,170,68538,1,8,0:0:0:0: -196,215,68703,1,0,1:0:0:0: -58,260,68868,1,0,0:0:0:0: -144,142,69032,2,0,L|138:108,2,30,0|0|0,1:0|0:0|0:0,0:0:0:0: -144,142,69197,2,0,P|184:124|232:132,1,90,8|0,0:0|0:0,0:0:0:0: -312,248,69527,6,0,L|324:338,1,90,0|0,1:0|0:0,0:0:0:0: -436,248,69857,1,8,0:0:0:0: -432,216,69939,1,0,0:0:0:0: -428,184,70021,1,0,0:0:0:0: -328,120,70186,1,0,0:0:0:0: -324,152,70269,1,0,0:0:0:0: -320,184,70351,1,0,1:0:0:0: -316,216,70434,1,0,0:0:0:0: -312,248,70516,2,0,L|320:300,1,45,8|0,0:0|0:0,0:0:0:0: -244,340,70681,2,0,L|237:295,1,45,0|0,0:0|0:0,0:0:0:0: -216,224,70846,6,0,P|168:216|124:224,1,90,0|0,1:0|0:0,0:0:0:0: -40,288,71175,1,8,0:0:0:0: -2,95,71340,2,0,P|-4:139|4:184,1,90,0|0,1:0|0:0,0:0:0:0: -164,304,71670,1,0,1:0:0:0: -312,248,71835,1,8,0:0:0:0: -244,340,71999,1,0,0:0:0:0: -216,224,72164,6,0,L|228:132,1,90,0|0,1:0|0:0,0:0:0:0: -332,148,72494,2,0,L|344:56,1,90,8|0,0:0|0:0,0:0:0:0: -312,248,72824,1,0,0:0:0:0: -164,304,72988,1,0,1:0:0:0: -332,336,73153,1,8,0:0:0:0: -360,324,73236,1,0,0:0:0:0: -384,304,73318,1,0,0:0:0:0: -399,276,73401,1,0,0:0:0:0: -403,244,73483,6,0,L|396:200,3,45,4|0|2|0,1:2|0:0|0:0|1:0,0:0:0:0: -420,112,73813,2,0,L|427:68,3,45,2|0|2|0,1:2|0:0|1:2|0:0,0:0:0:0: -352,16,74142,2,0,L|345:60,3,45,0|0|2|0,0:0|1:0|1:2|0:0,0:0:0:0: -332,148,74472,1,2,1:2:0:0: -332,148,74554,1,0,1:0:0:0: -332,148,74637,1,2,1:2:0:0: -332,148,74719,1,0,1:0:0:0: -332,148,74802,6,0,P|360:216|320:312,1,180,4|2,1:2|0:3,0:0:0:0: -190,310,75296,2,0,P|151:231|180:148,1,180,4|0,1:2|0:0,0:0:0:0: -256,56,75791,1,0,0:0:0:0: -332,148,75956,1,2,0:3:0:0: -179,148,76120,5,4,1:2:0:0: -336,64,76285,1,4,1:2:0:0: -256,224,76450,1,2,0:3:0:0: -176,64,76615,1,4,1:2:0:0: -256,140,76780,2,0,L|256:324,1,180,2|0,0:0|0:0,0:0:0:0: -364,300,77274,1,2,0:3:0:0: -148,300,77439,6,0,P|104:316|76:356,1,90,4|0,1:2|0:0,0:0:0:0: -24,252,77769,2,0,L|16:208,3,45,8|0|0|0,0:0|0:0|0:0|0:0,0:0:0:0: -96,212,78098,2,0,L|104:168,3,45,0|0|0|0,0:0|0:0|1:0|0:0,0:0:0:0: -32,128,78428,2,0,L|24:84,3,45,8|0|0|0,0:0|0:0|0:0|0:0,0:0:0:0: -104,88,78758,5,2,1:2:0:0: -204,132,78923,1,0,0:0:0:0: -236,124,79005,1,0,0:0:0:0: -268,116,79087,2,0,L|280:68,3,45,8|0|0|0,0:0|0:0|1:0|0:0,0:0:0:0: -348,100,79417,2,0,L|360:52,3,45,0|0|0|0,0:0|0:0|1:0|0:0,0:0:0:0: -428,84,79747,1,8,1:2:0:0: -460,76,79829,1,0,1:0:0:0: -492,68,79912,1,0,1:0:0:0: -492,260,80076,6,0,P|400:248|328:296,1,180,4|2,1:2|0:3,0:0:0:0: -144,236,80571,2,0,P|236:248|308:200,1,180,4|0,1:2|0:0,0:0:0:0: -348,100,81065,2,0,P|348:56|336:8,1,90,0|2,0:0|0:3,0:0:0:0: -140,48,81395,5,4,1:2:0:0: -244,68,81560,1,4,1:2:0:0: -144,236,81725,1,2,0:3:0:0: -176,133,81890,1,4,1:2:0:0: -184,304,82054,2,0,P|100:300|68:220,1,180,2|0,0:0|0:0,0:0:0:0: -100,116,82549,1,2,0:3:0:0: -264,244,82714,6,0,L|272:340,1,90,4|0,1:2|0:0,0:0:0:0: -380,316,83043,1,8,0:0:0:0: -396,288,83126,1,0,0:0:0:0: -400,256,83208,1,0,0:0:0:0: -396,224,83291,1,0,0:0:0:0: -380,196,83373,2,0,L|336:176,3,45,0|0|0|0,0:0|0:0|1:0|0:0,0:0:0:0: -272,148,83703,1,8,0:0:0:0: -256,120,83785,1,0,0:0:0:0: -252,88,83868,1,0,0:0:0:0: -256,56,83950,1,0,0:0:0:0: -272,28,84032,6,0,L|316:8,3,45,2|0|0|0,1:2|0:0|0:0|0:0,0:0:0:0: -360,72,84362,2,0,L|408:72,3,45,8|0|0|0,0:0|0:0|1:0|0:0,0:0:0:0: -421,149,84692,2,0,L|464:169,3,45,2|0|0|0,0:0|0:0|1:0|0:0,0:0:0:0: -443,244,85021,2,0,L|473:281,3,45,8|0|0|0,1:2|1:0|0:0|0:0,0:0:0:0: -422,339,85351,6,0,L|240:348,1,180,4|2,1:2|0:3,0:0:0:0: -76,172,85846,2,0,L|255:163,1,180,4|0,1:2|0:0,0:0:0:0: -421,149,86340,2,0,P|435:107|428:56,1,90,0|2,0:0|0:3,0:0:0:0: -228,56,86670,5,4,1:2:0:0: -280,192,86835,1,4,1:2:0:0: -328,96,86999,1,2,0:3:0:0: -180,152,87164,1,4,1:2:0:0: -28,100,87330,2,0,P|16:56|20:8,1,90,2|0,0:0|0:0,0:0:0:0: -0,180,87659,1,0,0:0:0:0: -28,284,87824,1,2,0:3:0:0: -108,352,87988,6,0,P|152:360|196:356,1,90,4|0,1:2|0:0,0:0:0:0: -276,284,88318,1,8,0:0:0:0: -304,272,88401,1,0,0:0:0:0: -336,268,88483,1,0,0:0:0:0: -368,272,88565,1,0,0:0:0:0: -396,284,88648,2,0,L|432:312,1,45,0|0,0:0|0:0,0:0:0:0: -488,252,88813,2,0,L|452:224,1,45,0|0,1:0|0:0,0:0:0:0: -400,164,88977,2,0,L|396:116,3,45,8|0|0|0,0:0|0:0|0:0|0:0,0:0:0:0: -316,64,89307,6,0,L|320:160,1,90,2|0,1:2|0:0,0:0:0:0: -276,284,89637,1,8,0:0:0:0: -248,296,89719,1,0,0:0:0:0: -216,300,89802,1,0,1:0:0:0: -184,296,89884,1,0,0:0:0:0: -156,284,89966,2,0,L|120:256,1,45,0|0,0:0|0:0,0:0:0:0: -176,200,90131,2,0,L|140:172,1,45,0|0,1:0|0:0,0:0:0:0: -196,116,90296,2,0,L|160:88,3,45,8|0|0|0,1:2|1:0|1:0|0:0,0:0:0:0: -92,44,90626,6,0,P|48:44|24:160,1,180,4|2,1:2|0:3,0:0:0:0: -156,284,91120,2,0,B|200:300|244:284|244:284|288:268|332:284,1,180,4|0,1:2|0:0,0:0:0:0: -176,200,91615,2,0,P|176:156|196:116,1,90,0|2,0:0|0:3,0:0:0:0: -264,28,91945,6,0,L|353:39,1,90,4|0,1:2|1:0,0:0:0:0: -453,159,92274,2,0,L|364:148,1,90,2|4,0:3|1:2,0:0:0:0: -268,196,92604,2,0,P|260:268|328:348,1,180,2|0,0:0|0:0,0:0:0:0: -364,248,93098,1,2,0:3:0:0: -176,200,93263,5,4,1:2:0:0: -72,228,93428,1,0,1:0:0:0: -152,92,93593,1,0,1:0:0:0: -256,64,93758,1,0,1:0:0:0: -336,200,93923,5,0,1:0:0:0: -440,228,94087,1,0,1:0:0:0: -360,92,94252,1,0,1:0:0:0: -256,64,94417,1,0,1:0:0:0: -176,200,94582,5,2,1:2:0:0: -168,228,94664,1,0,1:0:0:0: -168,260,94747,1,0,1:0:0:0: -172,292,94829,1,0,1:0:0:0: -192,316,94912,1,0,1:0:0:0: -220,328,94994,1,0,1:0:0:0: -252,332,95076,1,0,1:0:0:0: -280,320,95159,1,0,1:0:0:0: -300,296,95241,2,0,L|308:248,3,45,2|0|0|0,1:2|1:0|1:0|1:0,0:0:0:0: -312,172,95571,2,0,L|304:127,3,45,0|0|0|0,1:0|1:0|1:0|1:0,0:0:0:0: -256,64,95901,6,0,P|208:56|164:60,1,90,4|0,1:2|0:0,0:0:0:0: -76,116,96230,1,8,0:0:0:0: -60,224,96395,1,0,0:0:0:0: -60,224,96477,1,0,0:0:0:0: -160,184,96642,1,0,0:0:0:0: -160,184,96725,1,0,1:0:0:0: -63,26,96890,2,0,L|76:116,1,90,8|0,0:0|0:0,0:0:0:0: -136,272,97219,5,0,1:0:0:0: -168,268,97302,1,0,0:0:0:0: -200,264,97384,1,0,0:0:0:0: -232,260,97466,1,0,0:0:0:0: -264,256,97549,1,8,0:0:0:0: -384,136,97714,1,0,1:0:0:0: -376,168,97796,1,0,0:0:0:0: -380,200,97879,1,0,0:0:0:0: -392,228,97961,1,0,0:0:0:0: -416,248,98043,2,0,P|464:260|512:260,2,90,0|8|0,1:0|0:0|0:0,0:0:0:0: -231,105,98538,6,0,L|188:116,2,45,0|0|0,1:0|0:0|0:0,0:0:0:0: -376,56,98868,2,0,L|420:64,1,45,8|0,0:0|0:0,0:0:0:0: -384,136,99032,1,0,0:0:0:0: -384,136,99115,2,0,P|340:128|304:92,1,90,0|0,0:0|0:0,0:0:0:0: -303,18,99362,2,0,L|207:26,2,90,0|8|0,1:0|0:0|0:0,0:0:0:0: -452,88,99857,5,0,1:0:0:0: -465,116,99939,1,0,0:0:0:0: -466,147,100021,1,0,0:0:0:0: -456,177,100104,1,0,0:0:0:0: -436,201,100186,2,0,P|416:213|389:216,3,45,8|0|0|0,0:0|0:0|1:0|0:0,0:0:0:0: -320,188,100516,2,0,P|300:176|273:173,3,45,0|0|0|0,0:0|1:0|1:0|0:0,0:0:0:0: -204,200,100846,2,0,P|192:220|189:247,3,45,8|0|0|0,0:0|0:0|1:0|0:0,0:0:0:0: -188,320,101175,6,0,P|143:322|100:310,1,90,0|0,1:0|0:0,0:0:0:0: -76,292,101423,1,0,0:0:0:0: -76,292,101505,1,8,0:0:0:0: -76,292,101587,2,0,L|72:248,1,45 -12,68,101835,2,0,L|6:24,2,45,0|0|0,0:0|0:0|1:0,0:0:0:0: -104,140,102164,2,0,L|171:132,3,45,8|0|0|0,0:0|0:0|0:0|0:0,0:0:0:0: -224,124,102494,6,0,P|236:164|232:216,1,90,0|0,1:0|0:0,0:0:0:0: -288,296,102824,1,8,0:0:0:0: -288,296,102906,1,0,0:0:0:0: -288,296,102988,2,0,P|328:284|380:288,1,90,0|0,1:0|0:0,0:0:0:0: -404,304,103236,1,0,0:0:0:0: -424,328,103318,1,0,1:0:0:0: -448,188,103483,2,0,L|440:140,3,45,8|0|0|0,0:0|0:0|0:0|0:0,0:0:0:0: -424,72,103813,5,0,1:0:0:0: -324,112,103977,1,0,0:0:0:0: -324,112,104060,1,0,0:0:0:0: -324,112,104142,2,0,P|280:116|232:104,1,90,8|0,0:0|0:0,0:0:0:0: -160,28,104472,1,0,0:0:0:0: -216,208,104637,1,0,1:0:0:0: -216,208,104719,1,0,0:0:0:0: -216,208,104802,1,8,0:0:0:0: -352,240,104966,1,0,0:0:0:0: -384,244,105049,1,0,0:0:0:0: -416,248,105131,6,0,L|460:240,4,45,0|0|0|0|8,1:0|0:0|0:0|0:0|0:0,0:0:0:0: -272,288,105626,1,0,1:0:0:0: -264,320,105708,1,0,0:0:0:0: -256,352,105791,2,0,L|204:356,5,30,0|0|0|0|0|0,0:0|0:0|0:0|1:0|0:0|0:0,0:0:0:0: -156,332,106120,2,0,L|104:336,5,30,8|0|0|0|0|0,0:0|0:0|0:0|1:0|0:0|0:0,0:0:0:0: -56,312,106450,5,4,1:2:0:0: -4,188,106615,1,0,0:0:0:0: -168,220,106780,2,0,P|127:232|79:228,1,90,8|0,0:0|0:0,0:0:0:0: -112,124,107109,1,0,0:0:0:0: -272,216,107274,2,0,L|264:316,1,90,0|8,1:0|0:0,0:0:0:0: -400,268,107604,1,0,0:0:0:0: -428,132,107769,5,0,1:0:0:0: -428,132,107851,1,0,0:0:0:0: -428,132,107934,1,0,0:0:0:0: -428,132,108016,1,0,0:0:0:0: -428,132,108098,1,8,0:0:0:0: -332,84,108263,2,0,P|288:80|232:88,1,90,0|0,1:0|0:0,0:0:0:0: -112,124,108593,1,0,1:0:0:0: -148,264,108758,1,8,0:0:0:0: -16,236,108923,1,0,0:0:0:0: -264,126,109087,6,0,L|272:216,1,90,0|0,1:0|0:0,0:0:0:0: -452,224,109417,2,0,L|460:320,1,90,8|0,0:0|0:0,0:0:0:0: -360,232,109747,1,0,0:0:0:0: -348,56,109912,1,0,1:0:0:0: -416,140,110076,1,8,0:0:0:0: -256,112,110241,2,0,P|212:120|160:112,1,90,0|0,0:0|1:0,0:0:0:0: -348,56,110571,6,0,L|331:150,1,90,0|8,0:0|0:0,0:0:0:0: -208,328,110901,2,0,L|191:239,1,90,0|0,1:0|0:0,0:0:0:0: -184,216,111148,1,0,1:0:0:0: -178,194,111230,1,0,1:0:0:0: -68,272,111395,1,8,0:0:0:0: -56,136,111560,1,0,1:0:0:0: -178,194,111725,6,0,P|219:203|267:199,1,90,4|0,1:2|0:0,0:0:0:0: -364,148,112054,1,8,0:0:0:0: -384,256,112219,2,0,P|406:291|443:322,1,90,0|0,0:0|0:0,0:0:0:0: -488,224,112549,1,0,1:0:0:0: -304,232,112714,2,0,L|208:224,2,90,8|0|0,0:0|0:0|1:0,0:0:0:0: -208,328,113208,6,0,L|112:320,1,90,0|8,0:0|0:0,0:0:0:0: -26,184,113538,2,0,L|116:192,1,90,0|0,1:0|0:0,0:0:0:0: -304,232,113868,1,0,1:0:0:0: -116,192,114032,1,8,0:0:0:0: -224,132,114197,1,0,0:0:0:0: -208,328,114362,6,0,B|272:360|320:312|320:312|340:368,1,180,4|8,1:2|0:0,0:0:0:0: -304,232,114857,2,0,P|300:184|308:140,1,90,0|0,0:0|0:0,0:0:0:0: -384,64,115186,1,0,1:0:0:0: -307,143,115351,1,8,0:0:0:0: -256,48,115516,1,0,0:0:0:0: -456,24,115681,6,0,B|482:101|420:136|420:136|440:184,1,180,4|8,1:2|0:0,0:0:0:0: -384,64,116175,2,0,P|340:56|296:64,1,90,0|0,1:0|0:0,0:0:0:0: -211,171,116505,1,0,1:0:0:0: -439,181,116670,2,0,L|448:84,1,90,8|0,0:0|0:0,0:0:0:0: -372,296,116999,6,2,L|304:292,1,67.5000025749208,2|0,0:1|0:0,0:0:0:0: -136,252,117329,6,2,P|196:260|212:172,1,168.75,0|0,0:0|0:0,0:0:0:0: -192,148,117659,1,2,0:3:0:0: -164,132,117741,1,2,0:3:0:0: -132,124,117824,1,2,1:3:0:0: -100,132,117906,1,2,0:3:0:0: -72,148,117988,2,0,L|52:56,1,90,2|8,0:3|0:0,0:0:0:0: -36,244,118318,5,0,1:0:0:0: -76,344,118483,1,0,1:0:0:0: -184,352,118648,1,0,1:0:0:0: -244,264,118813,1,0,1:0:0:0: -244,264,118895,1,0,1:0:0:0: -244,264,118977,2,0,L|288:260,3,45,2|0|2|0,1:2|0:0|0:0|0:0,0:0:0:0: -332,328,119307,2,0,L|376:324,3,45,2|0|2|0,1:2|0:0|0:0|0:0,0:0:0:0: -412,252,119637,5,4,1:2:0:0: -256,192,119719,12,0,122274,0:0:0:0: -256,192,140735,6,0,L|228:156,1,45,4|0,1:2|0:0,0:0:0:0: -152,132,141065,2,0,P|129:129|104:136,1,45 -48,192,141395,2,0,P|40:236|52:280,1,90,8|8,0:0|0:0,0:0:0:0: -196,352,142054,6,0,L|308:340,1,90,8|8,0:0|1:2,0:0:0:0: -336,280,142549,1,0,0:0:0:0: -404,324,142713,1,8,0:0:0:0: -404,324,142878,1,8,0:0:0:0: -292,120,143373,5,0,1:0:0:0: -212,104,143538,1,0,0:0:0:0: -140,140,143702,1,0,0:0:0:0: -120,220,143867,1,0,0:0:0:0: -144,296,144032,2,0,P|184:320|228:316,1,90,10|8,0:0|0:0,0:0:0:0: -372,212,144691,6,0,P|327:209|290:232,1,90,10|8,0:0|1:2,0:0:0:0: -348,288,145186,1,0,0:0:0:0: -452,220,145351,1,10,0:0:0:0: -452,220,145516,1,8,0:0:0:0: -328,36,146010,5,2,1:2:0:0: -264,88,146175,1,0,0:0:0:0: -184,108,146340,1,0,0:0:0:0: -104,88,146505,1,0,0:0:0:0: -44,36,146669,1,8,0:0:0:0: -44,36,146999,1,8,0:0:0:0: -44,36,147329,6,0,L|24:84,1,45,8|0,0:0|0:0,0:0:0:0: -52,156,147658,2,0,L|71:204,1,45,8|0,1:2|0:0,0:0:0:0: -144,236,147988,1,8,0:0:0:0: -144,236,148153,1,8,0:0:0:0: -316,64,148647,5,0,1:0:0:0: -380,116,148812,1,0,0:0:0:0: -408,192,148977,1,0,0:0:0:0: -380,268,149142,1,0,0:0:0:0: -316,320,149307,2,0,L|224:316,1,90,10|8,0:0|0:0,0:0:0:0: -64,248,149966,5,10,0:0:0:0: -144,236,150131,1,0,0:0:0:0: -188,168,150296,1,8,1:2:0:0: -192,88,150461,1,0,0:0:0:0: -140,24,150626,2,0,P|120:16|96:20,1,45,10|0,0:0|0:0,0:0:0:0: -260,132,150955,2,0,P|280:140|304:136,1,45,2|0,0:0|0:0,0:0:0:0: -476,48,151285,6,0,L|484:160,1,112.5,4|0,1:2|0:0,0:0:0:0: -464,236,151779,1,0,0:0:0:0: -436,308,151944,2,0,P|380:320|324:308,1,112.5,8|8,0:0|0:0,0:0:0:0: -76,308,152604,6,0,P|132:320|188:308,1,112.5,8|8,0:0|1:2,0:0:0:0: -256,88,153263,1,8,0:0:0:0: -256,168,153428,1,8,0:0:0:0: -256,168,153922,5,4,1:2:0:0: -256,248,154087,1,0,0:0:0:0: -324,128,154252,1,0,0:0:0:0: -188,128,154417,1,0,0:0:0:0: -332,212,154582,2,0,L|388:204,1,56.25,10|0,0:0|0:0,0:0:0:0: -492,152,154911,2,0,L|436:144,1,56.25,8|0,0:0|0:0,0:0:0:0: -324,128,155241,5,10,0:0:0:0: -180,212,155406,1,0,0:0:0:0: -332,212,155571,1,8,1:2:0:0: -188,128,155735,1,0,0:0:0:0: -256,248,155900,1,10,0:0:0:0: -256,248,156065,2,0,L|256:304,2,56.25,0|0|0,0:0|0:0|0:0,0:0:0:0: -180,212,156560,6,0,L|124:204,1,56.25,4|0,1:2|0:0,0:0:0:0: -20,152,156889,2,0,L|76:144,1,56.25,0|0,0:0|0:0,0:0:0:0: -188,128,157219,2,0,P|212:72|192:16,1,112.5,8|8,0:0|0:0,0:0:0:0: -132,72,157713,1,0,0:0:0:0: -180,212,157878,6,0,L|236:208,1,56.25,8|0,0:0|0:0,0:0:0:0: -360,252,158208,2,8,L|304:248,1,56.25,8|0,1:2|0:0,0:0:0:0: -168,292,158538,2,0,L|160:356,2,56.25,8|8|0,0:0|0:0|0:0,0:0:0:0: -180,212,159032,1,0,0:0:0:0: -144,140,159197,6,0,P|104:128|36:148,1,112.5,2|0,1:2|0:0,0:0:0:0: -12,220,159691,1,0,0:0:0:0: -36,296,159856,2,0,P|60:316|92:324,1,56.25,8|0,0:0|0:0,0:0:0:0: -215,264,160186,2,0,P|189:273|168:292,1,56.25,8|0,0:0|0:0,0:0:0:0: -228,344,160516,6,0,L|284:340,1,56.25,10|0,0:0|0:0,0:0:0:0: -328,276,160845,2,0,L|384:272,1,56.25,8|0,1:2|0:0,0:0:0:0: -428,208,161175,1,8,0:0:0:0: -440,128,161340,1,8,0:0:0:0: -400,60,161505,1,2,0:0:0:0: -328,28,161669,1,0,0:0:0:0: -212,76,161834,6,0,P|200:120|208:164,1,90,2|0,1:2|1:0,0:0:0:0: -300,308,162163,2,0,P|312:264|304:220,1,90,2|0,1:2|1:0,0:0:0:0: -140,236,162493,2,0,P|184:248|228:240,1,90,2|0,1:2|1:0,0:0:0:0: -372,148,162823,2,0,P|328:136|284:144,1,90,2|0,1:2|1:0,0:0:0:0: -104,316,163152,5,2,1:2:0:0: -78,297,163235,1,0,1:0:0:0: -60,270,163317,1,0,1:0:0:0: -54,239,163399,1,0,1:0:0:0: -58,207,163482,1,2,1:2:0:0: -74,180,163564,1,0,1:0:0:0: -98,159,163647,1,0,1:0:0:0: -127,149,163729,1,0,1:0:0:0: -158,150,163812,2,0,L|208:160,1,45,2|0,1:2|1:0,0:0:0:0: -344,184,163976,2,0,L|294:194,1,45,0|0,1:0|1:0,0:0:0:0: -140,236,164141,1,4,1:2:0:0: -140,236,164471,6,0,L|232:252,1,90,4|0,1:2|0:0,0:0:0:0: -344,184,164801,1,8,0:0:0:0: -380,284,164965,1,0,0:0:0:0: -368,104,165130,2,0,P|324:104|284:128,1,90,0|0,0:0|1:0,0:0:0:0: -356,360,165460,2,0,P|400:360|440:336,1,90,8|0,0:0|0:0,0:0:0:0: -432,208,165790,5,0,1:0:0:0: -292,260,165954,1,0,0:0:0:0: -344,184,166119,1,8,0:0:0:0: -204,236,166284,1,0,1:0:0:0: -204,236,166366,1,0,0:0:0:0: -204,236,166449,2,0,L|216:328,1,90,0|0,0:0|1:0,0:0:0:0: -120,208,166779,2,0,L|131:118,1,90,8|0,0:0|0:0,0:0:0:0: -204,236,167108,5,0,1:0:0:0: -32,216,167273,1,0,0:0:0:0: -130,118,167438,1,8,0:0:0:0: -110,298,167603,1,0,0:0:0:0: -110,298,167685,1,0,0:0:0:0: -110,298,167768,2,0,L|121:208,1,90,0|0,0:0|1:0,0:0:0:0: -304,40,168097,2,0,L|315:130,1,90,8|0,0:0|0:0,0:0:0:0: -328,236,168427,5,0,1:0:0:0: -184,148,168592,1,0,0:0:0:0: -314,129,168757,1,8,0:0:0:0: -197,254,168921,1,0,1:0:0:0: -197,254,169004,1,0,0:0:0:0: -197,254,169086,2,0,P|220:292|260:312,1,90,0|0,0:0|1:0,0:0:0:0: -409,210,169416,2,0,P|365:211|328:236,1,90,8|0,0:0|0:0,0:0:0:0: -488,232,169746,6,0,P|487:192|464:149,1,90,0|0,1:0|0:0,0:0:0:0: -314,129,170075,1,8,0:0:0:0: -409,210,170240,1,0,0:0:0:0: -332,40,170405,2,0,L|240:36,1,90,0|0,0:0|1:0,0:0:0:0: -68,144,170735,2,0,L|157:140,1,90,8|0,0:0|0:0,0:0:0:0: -314,129,171064,5,0,1:0:0:0: -332,40,171229,1,0,0:0:0:0: -324,216,171394,1,8,0:0:0:0: -306,305,171559,1,0,1:0:0:0: -257,178,171724,1,0,0:0:0:0: -168,160,171888,1,0,1:0:0:0: -384,164,172053,1,8,0:0:0:0: -473,182,172218,1,0,0:0:0:0: -306,305,172383,6,0,L|216:312,1,90,0|0,1:0|0:0,0:0:0:0: -60,172,172713,1,8,0:0:0:0: -120,260,172877,1,0,0:0:0:0: -168,160,173042,2,0,L|172:68,1,90,0|0,0:0|1:0,0:0:0:0: -309,216,173372,2,0,L|306:306,1,90,8|0,0:0|0:0,0:0:0:0: -120,260,173702,5,0,1:0:0:0: -152,256,173784,1,0,1:0:0:0: -184,252,173866,1,0,1:0:0:0: -309,216,174031,1,8,0:0:0:0: -103,168,174196,1,0,1:0:0:0: -135,164,174279,1,0,1:0:0:0: -167,160,174361,1,0,1:0:0:0: -292,124,174526,1,0,1:0:0:0: -87,76,174691,1,8,1:2:0:0: -119,72,174773,1,0,1:0:0:0: -151,68,174855,1,0,1:0:0:0: -276,32,175020,6,0,L|368:40,1,90,0|0,1:0|0:0,0:0:0:0: -448,108,175350,1,8,0:0:0:0: -292,124,175515,1,0,0:0:0:0: -292,124,175597,1,0,0:0:0:0: -292,124,175680,2,0,L|308:216,1,90,0|0,0:0|1:0,0:0:0:0: -328,320,176009,1,8,0:0:0:0: -408,248,176174,1,0,0:0:0:0: -220,300,176339,6,0,P|176:304|128:292,1,90,0|0,1:0|0:0,0:0:0:0: -16,120,176669,1,8,0:0:0:0: -120,152,176834,1,0,1:0:0:0: -120,152,176916,1,0,0:0:0:0: -120,152,176998,2,0,L|124:200,1,45 -212,176,177163,2,0,L|239:215,1,45,0|0,1:0|0:0,0:0:0:0: -292,124,177328,2,0,P|302:79|283:30,1,90,8|0,0:0|0:0,0:0:0:0: -344,192,177658,6,0,P|372:156|376:104,1,90,0|0,1:0|0:0,0:0:0:0: -212,88,177987,1,8,0:0:0:0: -272,228,178152,1,0,0:0:0:0: -272,228,178235,1,0,0:0:0:0: -272,228,178317,1,0,0:0:0:0: -292,124,178482,1,0,1:0:0:0: -180,180,178647,1,8,0:0:0:0: -200,284,178812,1,0,0:0:0:0: -292,124,178976,5,0,1:0:0:0: -288,92,179059,1,0,0:0:0:0: -280,60,179141,2,0,P|248:24|208:14,1,90,0|8,0:0|0:0,0:0:0:0: -22,65,179471,2,0,P|67:71|112:68,1,90,0|0,1:0|0:0,0:0:0:0: -212,88,179801,1,0,1:0:0:0: -22,65,179965,1,8,0:0:0:0: -180,180,180130,5,0,0:0:0:0: -180,180,180213,1,0,0:0:0:0: -180,180,180295,2,0,P|184:224|172:272,1,90,0|0,1:0|0:0,0:0:0:0: -76,216,180625,2,0,P|72:172|84:124,1,90,8|0,0:0|0:0,0:0:0:0: -380,240,180954,2,0,P|384:284|372:332,1,90,0|0,0:0|1:0,0:0:0:0: -276,276,181284,2,0,P|272:232|284:184,1,90,8|0,0:0|0:0,0:0:0:0: -374,129,181614,5,0,1:0:0:0: -300,352,181779,2,0,L|204:348,2,90,0|8|0,0:0|0:0|1:0,0:0:0:0: -448,180,182273,1,2,0:0:0:0: -448,180,182438,1,2,1:2:0:0: -276,276,182603,1,10,0:0:0:0: -276,276,182768,1,2,0:0:0:0: -96,200,182932,6,0,L|88:108,1,90,0|0,1:0|0:0,0:0:0:0: -96,200,183262,1,8,0:0:0:0: -12,68,183427,2,0,P|72:24|164:68,1,180,0|0,0:0|1:0,0:0:0:0: -140,272,183921,2,0,P|92:284|52:271,1,90,8|0,0:0|0:0,0:0:0:0: -176,156,184251,5,0,1:0:0:0: -208,152,184334,1,0,1:0:0:0: -240,148,184416,1,0,1:0:0:0: -308,64,184581,1,8,0:0:0:0: -296,240,184746,1,0,1:0:0:0: -312,268,184828,1,0,1:0:0:0: -336,284,184910,1,0,1:0:0:0: -368,292,184993,1,0,1:0:0:0: -400,288,185075,1,0,1:0:0:0: -464,184,185240,1,8,0:0:0:0: -468,152,185323,1,0,0:0:0:0: -472,120,185405,2,0,L|464:76,1,45,0|0,1:0|1:0,0:0:0:0: -388,96,185570,6,0,P|360:132|316:148,1,90,4|0,1:2|0:0,0:0:0:0: -224,46,185899,2,0,P|268:43|308:63,1,90,8|0,0:0|0:0,0:0:0:0: -296,240,186229,1,0,0:0:0:0: -308,64,186394,1,0,1:0:0:0: -296,240,186559,2,0,L|312:332,1,90,8|0,0:0|0:0,0:0:0:0: -464,184,186888,6,0,P|420:180|372:188,1,90,0|0,1:0|0:0,0:0:0:0: -296,240,187218,1,8,0:0:0:0: -136,292,187383,2,0,P|94:277|54:249,1,90,0|0,1:0|0:0,0:0:0:0: -21,159,187713,1,0,1:0:0:0: -104,8,187877,2,0,L|124:96,1,90,10|0,0:0|0:0,0:0:0:0: -124,96,188207,6,0,P|152:132|196:148,1,90,0|0,1:0|0:0,0:0:0:0: -287,46,188537,2,0,P|243:43|204:63,1,90,8|0,0:0|0:0,0:0:0:0: -216,240,188866,1,2,0:0:0:0: -204,64,189031,1,0,1:0:0:0: -216,240,189196,2,0,L|200:332,1,90,8|0,0:0|0:0,0:0:0:0: -40,240,189526,5,2,1:2:0:0: -128,192,189691,1,0,0:0:0:0: -216,240,189855,1,8,0:0:0:0: -304,192,190020,1,0,1:0:0:0: -392,240,190185,2,0,L|400:332,1,90,2|0,0:0|1:0,0:0:0:0: -464,168,190515,2,0,L|456:76,1,90,8|0,0:0|0:0,0:0:0:0: -392,240,190844,6,0,P|364:272|312:292,1,90,2|0,1:2|0:0,0:0:0:0: -220,140,191174,2,0,P|248:108|296:92,1,90,8|0,0:0|0:0,0:0:0:0: -324,96,191421,1,0,0:0:0:0: -356,104,191504,2,0,L|340:16,1,90,0|0,0:0|1:0,0:0:0:0: -256,276,191834,2,0,L|272:364,1,90,8|0,0:0|0:0,0:0:0:0: -392,240,192163,5,0,1:0:0:0: -356,104,192328,1,0,0:0:0:0: -220,140,192493,1,8,0:0:0:0: -256,276,192658,1,0,1:0:0:0: -305,191,192823,1,0,0:0:0:0: -212,56,192987,1,0,1:0:0:0: -200,220,193152,1,10,0:0:0:0: -200,220,193482,6,0,P|156:228|108:220,1,90,0|0,1:0|0:0,0:0:0:0: -88,116,193812,1,8,0:0:0:0: -16,192,193976,1,0,0:0:0:0: -16,192,194059,1,0,0:0:0:0: -16,192,194141,2,0,L|28:288,1,90,2|0,0:0|1:0,0:0:0:0: -188,309,194471,2,0,L|200:220,1,90,8|0,0:0|0:0,0:0:0:0: -216,112,194801,5,2,1:2:0:0: -216,112,194883,1,0,1:0:0:0: -216,112,194965,1,0,1:0:0:0: -361,25,195130,1,8,0:0:0:0: -294,180,195295,1,0,1:0:0:0: -294,180,195377,1,0,1:0:0:0: -294,180,195460,1,2,0:0:0:0: -256,16,195625,1,0,1:0:0:0: -384,127,195790,1,10,1:2:0:0: -416,132,195872,1,0,1:0:0:0: -448,140,195954,2,0,L|452:84,1,45,0|0,1:0|1:0,0:0:0:0: -416,216,196119,6,0,P|412:264|432:312,1,90,4|0,1:2|0:0,0:0:0:0: -304,268,196449,2,0,P|308:220|288:172,1,90,8|0,0:0|0:0,0:0:0:0: -216,112,196779,2,0,L|120:104,1,90,0|0,0:0|1:0,0:0:0:0: -52,248,197108,2,0,L|141:255,1,90,8|0,0:0|0:0,0:0:0:0: -304,268,197438,5,0,1:0:0:0: -416,216,197603,1,0,0:0:0:0: -408,340,197768,1,8,0:0:0:0: -332,180,197932,1,0,1:0:0:0: -332,180,198015,1,0,0:0:0:0: -332,180,198097,2,0,P|360:140|400:120,1,90,0|0,0:0|1:0,0:0:0:0: -484,284,198427,1,10,0:0:0:0: -304,268,198592,1,2,0:0:0:0: -416,216,198757,6,0,P|428:172|420:124,1,90,2|0,1:2|0:0,0:0:0:0: -344,52,199086,1,8,0:0:0:0: -332,180,199251,1,0,0:0:0:0: -164,236,199416,2,0,P|152:192|160:144,1,90,0|0,0:0|1:0,0:0:0:0: -236,72,199746,1,8,0:0:0:0: -248,200,199910,1,0,0:0:0:0: -156,328,200075,6,0,L|56:320,1,90,2|0,1:2|0:0,0:0:0:0: -164,236,200405,1,8,0:0:0:0: -256,292,200570,2,0,P|300:296|344:284,1,90,0|0,1:0|0:0,0:0:0:0: -432,220,200899,2,0,L|460:308,2,90,0|8|0,1:0|0:0|0:0,0:0:0:0: -392,120,201394,5,4,1:2:0:0: -396,32,201559,1,0,1:0:0:0: -316,72,201724,1,0,1:0:0:0: -256,6,201888,1,0,1:0:0:0: -228,91,202053,1,0,1:0:0:0: -139,87,202218,1,0,1:0:0:0: -179,166,202383,1,0,1:0:0:0: -113,226,202548,1,0,1:0:0:0: -197,253,202713,5,4,1:2:0:0: -193,342,202877,1,0,1:0:0:0: -272,302,203042,1,0,1:0:0:0: -332,367,203207,1,0,1:0:0:0: -359,283,203372,1,2,1:2:0:0: -448,287,203537,1,2,1:2:0:0: -407,208,203702,1,2,1:2:0:0: -472,147,203866,1,2,1:2:0:0: -387,121,204031,5,4,1:2:0:0: -360,100,204114,1,0,1:0:0:0: -344,72,204196,1,0,1:0:0:0: -336,40,204279,1,0,1:0:0:0: -340,8,204361,1,0,1:0:0:0: -316,28,204443,1,0,1:0:0:0: -284,32,204526,1,0,1:0:0:0: -252,28,204608,1,0,1:0:0:0: -228,8,204691,2,0,L|184:20,7,45,4|0|0|0|0|0|0|0,1:2|1:0|1:0|1:0|1:0|1:0|1:0|1:0,0:0:0:0: -112,56,205350,5,4,1:2:0:0: -100,84,205432,1,0,1:0:0:0: -96,116,205515,1,0,1:0:0:0: -100,148,205597,1,0,1:0:0:0: -112,176,205680,1,0,1:0:0:0: -124,204,205762,1,0,1:0:0:0: -128,236,205844,1,0,1:0:0:0: -124,268,205927,1,0,1:0:0:0: -112,296,206009,2,0,L|71:313,3,45,2|0|2|0,1:2|0:0|0:0|0:0,0:0:0:0: -192,312,206339,2,0,L|175:353,3,45,2|0|2|0,1:2|0:0|0:0|0:0,0:0:0:0: -256,264,206669,5,4,1:2:0:0: -256,192,206751,12,0,209306,0:0:0:0: From 08ce2705c6bc8ba9ad2bdd244b6f5b1e927bcd1a Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Tue, 14 Nov 2017 08:26:44 +0300 Subject: [PATCH 0638/1263] Add pending and graveyarded beatmapsets to profile page --- osu.Game/Online/API/Requests/GetUserBeatmapsRequest.cs | 4 +++- .../Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs | 3 +-- osu.Game/Overlays/Profile/Sections/BeatmapsSection.cs | 6 ++++-- osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs | 1 + 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/osu.Game/Online/API/Requests/GetUserBeatmapsRequest.cs b/osu.Game/Online/API/Requests/GetUserBeatmapsRequest.cs index 66b2cae892..a66799f404 100644 --- a/osu.Game/Online/API/Requests/GetUserBeatmapsRequest.cs +++ b/osu.Game/Online/API/Requests/GetUserBeatmapsRequest.cs @@ -26,6 +26,8 @@ namespace osu.Game.Online.API.Requests { MostPlayed, Favourite, - RankedAndApproved + RankedAndApproved, + Unranked, + Graveyard } } diff --git a/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs b/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs index 2607585573..0a86b15504 100644 --- a/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs @@ -19,7 +19,7 @@ namespace osu.Game.Overlays.Profile.Sections.Beatmaps private DirectPanel playing; - public PaginatedBeatmapContainer(BeatmapSetType type, Bindable user, string header, string missing) + public PaginatedBeatmapContainer(BeatmapSetType type, Bindable user, string header, string missing = "None... yet.") : base(user, header, missing) { this.type = type; @@ -27,7 +27,6 @@ namespace osu.Game.Overlays.Profile.Sections.Beatmaps ItemsPerPage = 6; ItemsContainer.Spacing = new Vector2(panel_padding); - ItemsContainer.Margin = new MarginPadding { Bottom = panel_padding }; } protected override void ShowMore() diff --git a/osu.Game/Overlays/Profile/Sections/BeatmapsSection.cs b/osu.Game/Overlays/Profile/Sections/BeatmapsSection.cs index f55de9b83f..3e88795b77 100644 --- a/osu.Game/Overlays/Profile/Sections/BeatmapsSection.cs +++ b/osu.Game/Overlays/Profile/Sections/BeatmapsSection.cs @@ -16,8 +16,10 @@ namespace osu.Game.Overlays.Profile.Sections { Children = new[] { - new PaginatedBeatmapContainer(BeatmapSetType.Favourite, User, "Favourite Beatmaps", "None... yet."), - new PaginatedBeatmapContainer(BeatmapSetType.RankedAndApproved, User, "Ranked & Approved Beatmaps", "None... yet."), + new PaginatedBeatmapContainer(BeatmapSetType.Favourite, User, "Favourite Beatmaps"), + new PaginatedBeatmapContainer(BeatmapSetType.RankedAndApproved, User, "Ranked & Approved Beatmaps"), + new PaginatedBeatmapContainer(BeatmapSetType.Unranked, User, "Pending Beatmaps"), + new PaginatedBeatmapContainer(BeatmapSetType.Graveyard, User, "Graveyarded Beatmaps"), }; } } diff --git a/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs b/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs index b75d1bc4d6..1d4045c379 100644 --- a/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs @@ -51,6 +51,7 @@ namespace osu.Game.Overlays.Profile.Sections { AutoSizeAxes = Axes.Y, RelativeSizeAxes = Axes.X, + Margin = new MarginPadding { Bottom = 10 } }, ShowMoreButton = new OsuHoverContainer { From bd7a6a90f5a4f938727effbebbf253a9f3452445 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 14 Nov 2017 17:43:19 +0900 Subject: [PATCH 0639/1263] Remove unused fields --- osu.Game/Screens/Menu/Intro.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/osu.Game/Screens/Menu/Intro.cs b/osu.Game/Screens/Menu/Intro.cs index 0cb343c1ac..d78227920d 100644 --- a/osu.Game/Screens/Menu/Intro.cs +++ b/osu.Game/Screens/Menu/Intro.cs @@ -21,8 +21,6 @@ namespace osu.Game.Screens.Menu { public class Intro : OsuScreen { - private readonly IntroSequence introSequence; - private const string menu_music_beatmap_hash = "3c8b1fcc9434dbb29e2fb613d3b9eada9d7bb6c125ceb32396c3b53437280c83"; /// @@ -43,7 +41,6 @@ namespace osu.Game.Screens.Menu private Bindable menuVoice; private Bindable menuMusic; private Track track; - private readonly ParallaxContainer parallax; [BackgroundDependencyLoader] private void load(AudioManager audio, OsuConfigManager config, BeatmapManager beatmaps, Framework.Game game) From 9344502b7114b8b39bb09013dd381a1245360472 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 14 Nov 2017 18:05:07 +0900 Subject: [PATCH 0640/1263] More warning fixes --- osu.Desktop/Overlays/VersionManager.cs | 3 ++- osu.Game/Screens/Menu/Intro.cs | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Desktop/Overlays/VersionManager.cs b/osu.Desktop/Overlays/VersionManager.cs index e7c3370354..8c17e18ed8 100644 --- a/osu.Desktop/Overlays/VersionManager.cs +++ b/osu.Desktop/Overlays/VersionManager.cs @@ -233,7 +233,8 @@ namespace osu.Desktop.Overlays Text = @"Update ready to install. Click to restart!", Activated = () => { - UpdateManager.RestartAppWhenExited(); + // Squirrel returns execution to us after the update process is started, so it's safe to use Wait() here + UpdateManager.RestartAppWhenExited().Wait(); game.GracefullyExit(); return true; } diff --git a/osu.Game/Screens/Menu/Intro.cs b/osu.Game/Screens/Menu/Intro.cs index d78227920d..987e29d6d6 100644 --- a/osu.Game/Screens/Menu/Intro.cs +++ b/osu.Game/Screens/Menu/Intro.cs @@ -12,7 +12,6 @@ using osu.Framework.MathUtils; using osu.Game.Beatmaps; using osu.Game.Beatmaps.IO; using osu.Game.Configuration; -using osu.Game.Graphics.Containers; using osu.Game.Screens.Backgrounds; using OpenTK; using OpenTK.Graphics; From 160b988735de65d71a6b5d360bb947dfee8055fe Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 14 Nov 2017 18:51:41 +0900 Subject: [PATCH 0641/1263] Reduce number of rqeuests to display beatmaps in profile Comes at the cost of losing some information which should be loaded. This will be fixed at the osu-web end. --- .../Beatmaps/PaginatedBeatmapContainer.cs | 24 +++++++------------ 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs b/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs index 2607585573..aec345e4d8 100644 --- a/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs @@ -52,24 +52,18 @@ namespace osu.Game.Overlays.Profile.Sections.Beatmaps if (!s.OnlineBeatmapSetID.HasValue) continue; - var subReq = new GetBeatmapSetRequest(s.OnlineBeatmapSetID.Value); - subReq.Success += b => + var panel = new DirectGridPanel(s.ToBeatmapSet(Rulesets)) { Width = 400 }; + ItemsContainer.Add(panel); + + panel.PreviewPlaying.ValueChanged += newValue => { - var panel = new DirectGridPanel(b.ToBeatmapSet(Rulesets)) { Width = 400 }; - ItemsContainer.Add(panel); - - panel.PreviewPlaying.ValueChanged += newValue => + if (newValue) { - if (newValue) - { - if (playing != null && playing != panel) - playing.PreviewPlaying.Value = false; - playing = panel; - } - }; + if (playing != null && playing != panel) + playing.PreviewPlaying.Value = false; + playing = panel; + } }; - - Api.Queue(subReq); } }; From f96f7e696d73f507ea87ad8b952defe5c79bf4cd Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 14 Nov 2017 18:53:09 +0900 Subject: [PATCH 0642/1263] Tidy up variables a bit --- .../Beatmaps/PaginatedBeatmapContainer.cs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs b/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs index aec345e4d8..4840341f2f 100644 --- a/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs @@ -17,7 +17,7 @@ namespace osu.Game.Overlays.Profile.Sections.Beatmaps private readonly BeatmapSetType type; - private DirectPanel playing; + private DirectPanel currentlyPlaying; public PaginatedBeatmapContainer(BeatmapSetType type, Bindable user, string header, string missing) : base(user, header, missing) @@ -55,14 +55,14 @@ namespace osu.Game.Overlays.Profile.Sections.Beatmaps var panel = new DirectGridPanel(s.ToBeatmapSet(Rulesets)) { Width = 400 }; ItemsContainer.Add(panel); - panel.PreviewPlaying.ValueChanged += newValue => + panel.PreviewPlaying.ValueChanged += isPlaying => { - if (newValue) - { - if (playing != null && playing != panel) - playing.PreviewPlaying.Value = false; - playing = panel; - } + if (!isPlaying) return; + + if (currentlyPlaying != null && currentlyPlaying != panel) + currentlyPlaying.PreviewPlaying.Value = false; + + currentlyPlaying = panel; }; } }; From 44671ad9cbfaa1d6ca0d81e83f06a9ecb8608b4d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 14 Nov 2017 19:03:50 +0900 Subject: [PATCH 0643/1263] Move common width definition to base class --- osu.Game/Overlays/Direct/DirectGridPanel.cs | 1 + osu.Game/Overlays/DirectOverlay.cs | 2 +- .../Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Direct/DirectGridPanel.cs b/osu.Game/Overlays/Direct/DirectGridPanel.cs index e863f78e3f..a40f20850e 100644 --- a/osu.Game/Overlays/Direct/DirectGridPanel.cs +++ b/osu.Game/Overlays/Direct/DirectGridPanel.cs @@ -29,6 +29,7 @@ namespace osu.Game.Overlays.Direct public DirectGridPanel(BeatmapSetInfo beatmap) : base(beatmap) { + Width = 400; Height = 140 + vertical_padding; //full height of all the elements plus vertical padding (autosize uses the image) } diff --git a/osu.Game/Overlays/DirectOverlay.cs b/osu.Game/Overlays/DirectOverlay.cs index d11f2342cd..6f7fabb910 100644 --- a/osu.Game/Overlays/DirectOverlay.cs +++ b/osu.Game/Overlays/DirectOverlay.cs @@ -222,7 +222,7 @@ namespace osu.Game.Overlays switch (displayStyle) { case PanelDisplayStyle.Grid: - return new DirectGridPanel(b) { Width = 400 }; + return new DirectGridPanel(b); default: return new DirectListPanel(b); } diff --git a/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs b/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs index 4840341f2f..983ef004d0 100644 --- a/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs @@ -52,7 +52,7 @@ namespace osu.Game.Overlays.Profile.Sections.Beatmaps if (!s.OnlineBeatmapSetID.HasValue) continue; - var panel = new DirectGridPanel(s.ToBeatmapSet(Rulesets)) { Width = 400 }; + var panel = new DirectGridPanel(s.ToBeatmapSet(Rulesets)); ItemsContainer.Add(panel); panel.PreviewPlaying.ValueChanged += isPlaying => From 6933a41b7504404785625f22be86fad35bf402f1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 15 Nov 2017 13:26:02 +0900 Subject: [PATCH 0644/1263] Add back high resolution cover regressions --- osu.Game/Beatmaps/BeatmapSetOnlineInfo.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game/Beatmaps/BeatmapSetOnlineInfo.cs b/osu.Game/Beatmaps/BeatmapSetOnlineInfo.cs index 2b9418d6ae..b38f74b3f7 100644 --- a/osu.Game/Beatmaps/BeatmapSetOnlineInfo.cs +++ b/osu.Game/Beatmaps/BeatmapSetOnlineInfo.cs @@ -2,6 +2,7 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; +using Newtonsoft.Json; namespace osu.Game.Beatmaps { @@ -60,14 +61,17 @@ namespace osu.Game.Beatmaps { public string CoverLowRes { get; set; } + [JsonProperty(@"cover@2x")] public string Cover { get; set; } public string CardLowRes { get; set; } + [JsonProperty(@"card@2x")] public string Card { get; set; } public string ListLowRes { get; set; } + [JsonProperty(@"list@2x")] public string List { get; set; } } } From a30cf27506687abc7cf8a7ad2deacbfd2f6f2cc5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 15 Nov 2017 13:15:20 +0900 Subject: [PATCH 0645/1263] Fix incorrect json mapping for preview urls --- osu.Game/Online/API/Requests/GetBeatmapSetsResponse.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Online/API/Requests/GetBeatmapSetsResponse.cs b/osu.Game/Online/API/Requests/GetBeatmapSetsResponse.cs index 45f6d84784..fa053d6418 100644 --- a/osu.Game/Online/API/Requests/GetBeatmapSetsResponse.cs +++ b/osu.Game/Online/API/Requests/GetBeatmapSetsResponse.cs @@ -15,7 +15,7 @@ namespace osu.Game.Online.API.Requests [JsonProperty(@"covers")] private BeatmapSetOnlineCovers covers { get; set; } - [JsonProperty(@"previewUrl")] + [JsonProperty(@"preview_url")] private string preview { get; set; } [JsonProperty(@"play_count")] From ea2fa5fa00d4c467a0a3d2e34ea35f765ea1a2e3 Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Wed, 15 Nov 2017 09:48:40 +0300 Subject: [PATCH 0646/1263] Fix wrong ratings calculations --- .../Visual/TestCaseBeatmapDetails.cs | 4 ++-- .../Visual/TestCaseBeatmapSetOverlay.cs | 20 +++++++++---------- .../Screens/Select/Details/UserRatings.cs | 6 +++--- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCaseBeatmapDetails.cs b/osu.Game.Tests/Visual/TestCaseBeatmapDetails.cs index 5306121a92..b31eded9a0 100644 --- a/osu.Game.Tests/Visual/TestCaseBeatmapDetails.cs +++ b/osu.Game.Tests/Visual/TestCaseBeatmapDetails.cs @@ -39,7 +39,7 @@ namespace osu.Game.Tests.Visual StarDifficulty = 5.3f, Metrics = new BeatmapMetrics { - Ratings = Enumerable.Range(0, 10), + Ratings = Enumerable.Range(0, 11), Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6), Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6), }, @@ -63,7 +63,7 @@ namespace osu.Game.Tests.Visual StarDifficulty = 4.8f, Metrics = new BeatmapMetrics { - Ratings = Enumerable.Range(0, 10), + Ratings = Enumerable.Range(0, 11), }, }); diff --git a/osu.Game.Tests/Visual/TestCaseBeatmapSetOverlay.cs b/osu.Game.Tests/Visual/TestCaseBeatmapSetOverlay.cs index 2226dbf9e9..c2de4ec05d 100644 --- a/osu.Game.Tests/Visual/TestCaseBeatmapSetOverlay.cs +++ b/osu.Game.Tests/Visual/TestCaseBeatmapSetOverlay.cs @@ -83,7 +83,7 @@ namespace osu.Game.Tests.Visual }, Metrics = new BeatmapMetrics { - Ratings = Enumerable.Range(0, 10), + Ratings = Enumerable.Range(0, 11), Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6), Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6), }, @@ -110,7 +110,7 @@ namespace osu.Game.Tests.Visual }, Metrics = new BeatmapMetrics { - Ratings = Enumerable.Range(0, 10), + Ratings = Enumerable.Range(0, 11), Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6), Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6), }, @@ -137,7 +137,7 @@ namespace osu.Game.Tests.Visual }, Metrics = new BeatmapMetrics { - Ratings = Enumerable.Range(0, 10), + Ratings = Enumerable.Range(0, 11), Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6), Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6), }, @@ -164,7 +164,7 @@ namespace osu.Game.Tests.Visual }, Metrics = new BeatmapMetrics { - Ratings = Enumerable.Range(0, 10), + Ratings = Enumerable.Range(0, 11), Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6), Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6), }, @@ -191,7 +191,7 @@ namespace osu.Game.Tests.Visual }, Metrics = new BeatmapMetrics { - Ratings = Enumerable.Range(0, 10), + Ratings = Enumerable.Range(0, 11), Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6), Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6), }, @@ -253,7 +253,7 @@ namespace osu.Game.Tests.Visual }, Metrics = new BeatmapMetrics { - Ratings = Enumerable.Range(0, 10), + Ratings = Enumerable.Range(0, 11), Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6), Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6), }, @@ -280,7 +280,7 @@ namespace osu.Game.Tests.Visual }, Metrics = new BeatmapMetrics { - Ratings = Enumerable.Range(0, 10), + Ratings = Enumerable.Range(0, 11), Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6), Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6), }, @@ -307,7 +307,7 @@ namespace osu.Game.Tests.Visual }, Metrics = new BeatmapMetrics { - Ratings = Enumerable.Range(0, 10), + Ratings = Enumerable.Range(0, 11), Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6), Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6), }, @@ -334,7 +334,7 @@ namespace osu.Game.Tests.Visual }, Metrics = new BeatmapMetrics { - Ratings = Enumerable.Range(0, 10), + Ratings = Enumerable.Range(0, 11), Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6), Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6), }, @@ -361,7 +361,7 @@ namespace osu.Game.Tests.Visual }, Metrics = new BeatmapMetrics { - Ratings = Enumerable.Range(0, 10), + Ratings = Enumerable.Range(0, 11), Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6), Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6), }, diff --git a/osu.Game/Screens/Select/Details/UserRatings.cs b/osu.Game/Screens/Select/Details/UserRatings.cs index db6d932464..2153eb150c 100644 --- a/osu.Game/Screens/Select/Details/UserRatings.cs +++ b/osu.Game/Screens/Select/Details/UserRatings.cs @@ -30,9 +30,9 @@ namespace osu.Game.Screens.Select.Details metrics = value; var ratings = Metrics.Ratings.ToList(); - negativeRatings.Text = ratings.GetRange(0, ratings.Count / 2).Sum().ToString(); - positiveRatings.Text = ratings.GetRange(ratings.Count / 2, ratings.Count / 2).Sum().ToString(); - ratingsBar.Length = (float)ratings.GetRange(0, ratings.Count / 2).Sum() / ratings.Sum(); + negativeRatings.Text = ratings.GetRange(0, ratings.Count / 2 + 1).Sum().ToString(); + positiveRatings.Text = ratings.GetRange(ratings.Count / 2 + 1, ratings.Count / 2).Sum().ToString(); + ratingsBar.Length = (float)ratings.GetRange(0, ratings.Count / 2 + 1).Sum() / ratings.Sum(); graph.Values = Metrics.Ratings.Select(r => (float)r); } } From 093ebb8b17114302ae4cd3e716557b7aac0da8f0 Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Wed, 15 Nov 2017 10:21:07 +0300 Subject: [PATCH 0647/1263] Apply suggested changes --- .../BeatmapSet/Scores/ClickableUsername.cs | 4 +- .../BeatmapSet/Scores/DrawableScore.cs | 28 ++++----- .../BeatmapSet/Scores/DrawableTopScore.cs | 58 ++++++++----------- .../BeatmapSet/Scores/ScoresContainer.cs | 43 ++++++-------- 4 files changed, 56 insertions(+), 77 deletions(-) diff --git a/osu.Game/Overlays/BeatmapSet/Scores/ClickableUsername.cs b/osu.Game/Overlays/BeatmapSet/Scores/ClickableUsername.cs index ab828cf0eb..bbb4ef767c 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/ClickableUsername.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/ClickableUsername.cs @@ -18,6 +18,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores private User user; public User User { + get { return user; } set { if (user == value) return; @@ -25,7 +26,6 @@ namespace osu.Game.Overlays.BeatmapSet.Scores text.Text = user.Username; } - get { return user; } } public float TextSize @@ -56,7 +56,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores protected override bool OnClick(InputState state) { profile?.ShowUser(user); - return base.OnClick(state); + return true; } } } diff --git a/osu.Game/Overlays/BeatmapSet/Scores/DrawableScore.cs b/osu.Game/Overlays/BeatmapSet/Scores/DrawableScore.cs index 2b1cdf5c25..5a3aba7b43 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/DrawableScore.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/DrawableScore.cs @@ -21,10 +21,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores public class DrawableScore : Container { private const int fade_duration = 100; - private const float height = 30; private const float side_margin = 20; - private const float flag_margin = 60; - private const float username_margin = 100; private readonly Box background; @@ -33,7 +30,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores ScoreModsContainer modsContainer; RelativeSizeAxes = Axes.X; - Height = height; + Height = 30; CornerRadius = 3; Masking = true; Children = new Drawable[] @@ -55,16 +52,15 @@ namespace osu.Game.Overlays.BeatmapSet.Scores { Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, - Width = 30, - Height = 20, - Margin = new MarginPadding { Left = flag_margin } + Size = new Vector2(30, 20), + Margin = new MarginPadding { Left = 60 } }, new ClickableUsername { Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, User = score.User, - Margin = new MarginPadding { Left = username_margin } + Margin = new MarginPadding { Left = 100 } }, modsContainer = new ScoreModsContainer { @@ -72,16 +68,15 @@ namespace osu.Game.Overlays.BeatmapSet.Scores Origin = Anchor.CentreLeft, AutoSizeAxes = Axes.Y, RelativeSizeAxes = Axes.X, - Width = 0.05f, + Width = 0.06f, RelativePositionAxes = Axes.X, - X = 0.45f + X = 0.42f }, new DrawableRank(score.Rank) { Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, - Width = 30, - Height = 20, + Size = new Vector2(30, 20), FillMode = FillMode.Fit, RelativePositionAxes = Axes.X, X = 0.55f @@ -90,10 +85,11 @@ namespace osu.Game.Overlays.BeatmapSet.Scores { Anchor = Anchor.CentreLeft, Origin = Anchor.CentreRight, - Text = $@"{score.TotalScore}", - Font = @"Exo2.0-MediumItalic", + Text = $@"{score.TotalScore:N0}", + Font = @"Venera", RelativePositionAxes = Axes.X, - X = 0.7f + X = 0.75f, + FixedWidth = true, }, new OsuSpriteText { @@ -102,7 +98,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores Text = $@"{score.Accuracy:P2}", Font = @"Exo2.0-RegularItalic", RelativePositionAxes = Axes.X, - X = 0.8f + X = 0.85f }, new OsuSpriteText { diff --git a/osu.Game/Overlays/BeatmapSet/Scores/DrawableTopScore.cs b/osu.Game/Overlays/BeatmapSet/Scores/DrawableTopScore.cs index 665a563e6e..e3a0a9d613 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/DrawableTopScore.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/DrawableTopScore.cs @@ -45,14 +45,29 @@ namespace osu.Game.Overlays.BeatmapSet.Scores private OnlineScore score; public OnlineScore Score { + get { return score; } set { if (score == value) return; score = value; - setScore(); + avatar.User = username.User = score.User; + flag.FlagName = score.User.Country?.FlagName; + date.Text = $@"achieved {score.Date:MMM d, yyyy}"; + rank.UpdateRank(score.Rank); + + totalScore.Value = $@"{score.TotalScore:N0}"; + accuracy.Value = $@"{score.Accuracy:P2}"; + statistics.Value = $"{score.Statistics["300"]}/{score.Statistics["100"]}/{score.Statistics["50"]}"; + + modsContainer.Clear(); + foreach (Mod mod in score.Mods) + modsContainer.Add(new ModIcon(mod) + { + AutoSizeAxes = Axes.Both, + Scale = new Vector2(0.45f), + }); } - get { return score; } } public DrawableTopScore() @@ -86,18 +101,14 @@ namespace osu.Game.Overlays.BeatmapSet.Scores }, flag = new DrawableFlag { - Width = 30, - Height = 20, - Y = height / 4, - X = height / 2, + Size = new Vector2(30, 20), + Position = new Vector2(height / 2, height / 4), }, username = new ClickableUsername { Origin = Anchor.BottomLeft, TextSize = 30, - Y = height / 4, - X = height / 2, - Margin = new MarginPadding { Bottom = 4 }, + Position = new Vector2(height / 2, avatar_size / 2), }, rankText = new OsuSpriteText { @@ -133,8 +144,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores rank = new DrawableRank(ScoreRank.F) { Origin = Anchor.BottomLeft, - Width = avatar_size, - Height = 40, + Size = new Vector2(avatar_size, 40), FillMode = FillMode.Fit, Y = height / 4, Margin = new MarginPadding { Left = margin } @@ -143,8 +153,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores { Origin = Anchor.BottomLeft, AutoSizeAxes = Axes.Both, - X = height / 2, - Y = height / 4, + Position = new Vector2(height / 2, height / 4), Direction = FillDirection.Horizontal, Spacing = new Vector2(15, 0), Children = new[] @@ -158,8 +167,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores { AutoSizeAxes = Axes.Y, Width = 80, - X = height / 2, - Y = height / 4, + Position = new Vector2(height / 2, height / 4), } } }, @@ -175,26 +183,6 @@ namespace osu.Game.Overlays.BeatmapSet.Scores BorderColour = rankText.Colour = colours.Yellow; } - private void setScore() - { - avatar.User = username.User = score.User; - flag.FlagName = score.User.Country?.FlagName; - date.Text = $@"achieved {score.Date:MMM d, yyyy}"; - rank.UpdateRank(score.Rank); - - totalScore.Value = $@"{score.TotalScore}"; - accuracy.Value = $@"{score.Accuracy:P2}"; - statistics.Value = $"{score.Statistics["300"]}/{score.Statistics["100"]}/{score.Statistics["50"]}"; - - modsContainer.Clear(); - foreach (Mod mod in score.Mods) - modsContainer.Add(new ModIcon(mod) - { - AutoSizeAxes = Axes.Both, - Scale = new Vector2(0.45f), - }); - } - protected override bool OnHover(InputState state) { background.FadeIn(fade_duration, Easing.OutQuint); diff --git a/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs b/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs index 2bbfa0f56a..4b496ed118 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs @@ -27,6 +27,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores private bool isLoading; public bool IsLoading { + get { return isLoading; } set { if (isLoading == value) return; @@ -35,18 +36,33 @@ namespace osu.Game.Overlays.BeatmapSet.Scores foreground.FadeTo(isLoading ? 1 : 0, fade_duration); loadingAnimation.FadeTo(isLoading ? 1 : 0, fade_duration); } - get { return isLoading; } } private IEnumerable scores; public IEnumerable Scores { + get { return scores; } set { scores = value; - updateScores(); + var scoresAmount = scores.Count(); + if (scoresAmount == 0) + { + CleanAllScores(); + return; + } + + topScore.Score = scores.FirstOrDefault(); + topScore.Show(); + + flow.Clear(); + + if (scoresAmount < 2) + return; + + for (int i = 1; i < scoresAmount; i++) + flow.Add(new DrawableScore(i, scores.ElementAt(i))); } - get { return scores; } } public ScoresContainer() @@ -90,27 +106,6 @@ namespace osu.Game.Overlays.BeatmapSet.Scores }; } - private void updateScores() - { - var scoresAmount = scores.Count(); - if (scoresAmount == 0) - { - CleanAllScores(); - return; - } - - topScore.Score = scores.FirstOrDefault(); - topScore.Show(); - - flow.Clear(); - - if (scoresAmount < 2) - return; - - for (int i = 1; i < scoresAmount; i++) - flow.Add(new DrawableScore(i, scores.ElementAt(i))); - } - public void CleanAllScores() { topScore.Hide(); From 60a2d84e09fedab1bd2c969242950e1e63d69f19 Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Wed, 15 Nov 2017 10:43:32 +0300 Subject: [PATCH 0648/1263] Make the x position depends on the avatar size --- osu.Game/Overlays/BeatmapSet/Scores/DrawableTopScore.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/BeatmapSet/Scores/DrawableTopScore.cs b/osu.Game/Overlays/BeatmapSet/Scores/DrawableTopScore.cs index e3a0a9d613..833ed94c0f 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/DrawableTopScore.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/DrawableTopScore.cs @@ -102,13 +102,14 @@ namespace osu.Game.Overlays.BeatmapSet.Scores flag = new DrawableFlag { Size = new Vector2(30, 20), - Position = new Vector2(height / 2, height / 4), + Position = new Vector2(margin * 2 + avatar_size, height / 4), }, username = new ClickableUsername { Origin = Anchor.BottomLeft, TextSize = 30, - Position = new Vector2(height / 2, avatar_size / 2), + Position = new Vector2(margin * 2 + avatar_size, height / 4), + Margin = new MarginPadding { Bottom = 4 } }, rankText = new OsuSpriteText { From 8a407a68b3e94f438cc8fea88a319b8db326370f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 15 Nov 2017 18:48:37 +0900 Subject: [PATCH 0649/1263] Ensure only one information overlay is open at once --- osu.Game/OsuGame.cs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index fc5b607810..e603375e9c 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -255,6 +255,22 @@ namespace osu.Game }; } + // eventually informational overlays should be displayed in a stack, but for now let's only allow one to stay open at a time. + var informationalOverlays = new OverlayContainer[] { beatmapSetOverlay, userProfile }; + foreach (var overlay in informationalOverlays) + { + overlay.StateChanged += state => + { + if (state == Visibility.Hidden) return; + + foreach (var c in informationalOverlays) + { + if (c == overlay) continue; + c.State = Visibility.Hidden; + } + }; + } + settings.StateChanged += delegate { switch (settings.State) From af03d883f168fbc3244fe7f51a4ad24307dbc4bb Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 15 Nov 2017 19:01:30 +0900 Subject: [PATCH 0650/1263] Ensure overlay containers scroll to top when new information is presented --- osu.Game/Graphics/Containers/SectionsContainer.cs | 2 ++ osu.Game/Overlays/BeatmapSetOverlay.cs | 5 ++++- osu.Game/Overlays/UserProfileOverlay.cs | 1 + 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/osu.Game/Graphics/Containers/SectionsContainer.cs b/osu.Game/Graphics/Containers/SectionsContainer.cs index 6e5c3c8183..1e2826189b 100644 --- a/osu.Game/Graphics/Containers/SectionsContainer.cs +++ b/osu.Game/Graphics/Containers/SectionsContainer.cs @@ -139,6 +139,8 @@ namespace osu.Game.Graphics.Containers public void ScrollTo(Drawable section) => scrollContainer.ScrollTo(scrollContainer.GetChildPosInContent(section) - (FixedHeader?.BoundingBox.Height ?? 0)); + public void ScrollToTop() => scrollContainer.ScrollTo(0); + private float lastKnownScroll; protected override void UpdateAfterChildren() { diff --git a/osu.Game/Overlays/BeatmapSetOverlay.cs b/osu.Game/Overlays/BeatmapSetOverlay.cs index ddd146bcb6..940ac433fc 100644 --- a/osu.Game/Overlays/BeatmapSetOverlay.cs +++ b/osu.Game/Overlays/BeatmapSetOverlay.cs @@ -30,6 +30,8 @@ namespace osu.Game.Overlays private APIAccess api; private RulesetStore rulesets; + private readonly ScrollContainer scroll; + // receive input outside our bounds so we can trigger a close event on ourselves. public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => true; @@ -61,7 +63,7 @@ namespace osu.Game.Overlays RelativeSizeAxes = Axes.Both, Colour = OsuColour.Gray(0.2f) }, - new ScrollContainer + scroll = new ScrollContainer { RelativeSizeAxes = Axes.Both, ScrollbarVisible = false, @@ -120,6 +122,7 @@ namespace osu.Game.Overlays { header.BeatmapSet = info.BeatmapSet = set; Show(); + scroll.ScrollTo(0); } } } diff --git a/osu.Game/Overlays/UserProfileOverlay.cs b/osu.Game/Overlays/UserProfileOverlay.cs index ce35f7e547..dd31a43290 100644 --- a/osu.Game/Overlays/UserProfileOverlay.cs +++ b/osu.Game/Overlays/UserProfileOverlay.cs @@ -164,6 +164,7 @@ namespace osu.Game.Overlays } Show(); + sectionsContainer.ScrollToTop(); } private void userLoadComplete(User user) From fda810eb8fc288b085670a18f2091da812c3122f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 15 Nov 2017 19:02:56 +0900 Subject: [PATCH 0651/1263] Remove scrollability from sub-areas in beatmap overaly The areas that are scrollable inside the beatmap overlay make for a very frustrating experience. Let's disable them for now. --- osu.Game/Overlays/BeatmapSet/Info.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/osu.Game/Overlays/BeatmapSet/Info.cs b/osu.Game/Overlays/BeatmapSet/Info.cs index 4a59591a72..bd108a193b 100644 --- a/osu.Game/Overlays/BeatmapSet/Info.cs +++ b/osu.Game/Overlays/BeatmapSet/Info.cs @@ -74,20 +74,18 @@ namespace osu.Game.Overlays.BeatmapSet { RelativeSizeAxes = Axes.Both, Padding = new MarginPadding { Right = metadata_width + BeatmapSetOverlay.RIGHT_WIDTH + spacing * 2 }, - Child = new ScrollContainer + Child = new Container { RelativeSizeAxes = Axes.Both, - ScrollbarVisible = false, Child = description = new MetadataSection("Description"), }, }, - new ScrollContainer + new Container { Anchor = Anchor.TopRight, Origin = Anchor.TopRight, RelativeSizeAxes = Axes.Y, Width = metadata_width, - ScrollbarVisible = false, Padding = new MarginPadding { Horizontal = 10 }, Margin = new MarginPadding { Right = BeatmapSetOverlay.RIGHT_WIDTH + spacing }, Child = new FillFlowContainer From 801104854092a5677e4531e7fb514b98801ee8c1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 15 Nov 2017 20:03:18 +0900 Subject: [PATCH 0652/1263] Fix hard crash when clicking play button with no map selected Resolves #1507. --- osu.Game/Screens/Play/Player.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 675d20fe63..3e57e18963 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -231,6 +231,8 @@ namespace osu.Game.Screens.Play private void applyRateFromMods() { + if (adjustableSourceClock == null) return; + adjustableSourceClock.Rate = 1; foreach (var mod in Beatmap.Value.Mods.Value.OfType()) mod.ApplyToClock(adjustableSourceClock); From bbe555dc3cd2a19ede0a58a80e171ed4cca22fd8 Mon Sep 17 00:00:00 2001 From: naoey Date: Wed, 15 Nov 2017 17:49:41 +0530 Subject: [PATCH 0653/1263] Pass noVideo flag on... --- osu.Game/Overlays/BeatmapSet/Header.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/BeatmapSet/Header.cs b/osu.Game/Overlays/BeatmapSet/Header.cs index 0cfa7be81a..f9998dcca2 100644 --- a/osu.Game/Overlays/BeatmapSet/Header.cs +++ b/osu.Game/Overlays/BeatmapSet/Header.cs @@ -228,7 +228,7 @@ namespace osu.Game.Overlays.BeatmapSet this.beatmaps = beatmaps; } - private void download(bool video) + private void download(bool noVideo) { if (beatmaps.GetExistingDownload(BeatmapSet) != null) { @@ -240,7 +240,7 @@ namespace osu.Game.Overlays.BeatmapSet return; } - beatmaps.Download(BeatmapSet); + beatmaps.Download(BeatmapSet, noVideo); } } } From df53b884eabe7025b8e46b879ce76274a6f28b43 Mon Sep 17 00:00:00 2001 From: naoey Date: Wed, 15 Nov 2017 17:58:02 +0530 Subject: [PATCH 0654/1263] Removed unused stuff. --- osu.Game/Overlays/BeatmapSet/Header.cs | 2 -- osu.Game/Overlays/BeatmapSetOverlay.cs | 2 -- osu.Game/Overlays/Direct/DirectPanel.cs | 7 +------ 3 files changed, 1 insertion(+), 10 deletions(-) diff --git a/osu.Game/Overlays/BeatmapSet/Header.cs b/osu.Game/Overlays/BeatmapSet/Header.cs index f9998dcca2..ed72cf0cc9 100644 --- a/osu.Game/Overlays/BeatmapSet/Header.cs +++ b/osu.Game/Overlays/BeatmapSet/Header.cs @@ -38,8 +38,6 @@ namespace osu.Game.Overlays.BeatmapSet public readonly BeatmapPicker Picker; - private bool isDownloading => beatmaps.GetExistingDownload(BeatmapSet) != null; - private BeatmapSetInfo beatmapSet; public BeatmapSetInfo BeatmapSet { diff --git a/osu.Game/Overlays/BeatmapSetOverlay.cs b/osu.Game/Overlays/BeatmapSetOverlay.cs index 1173390d57..7ae2d323b8 100644 --- a/osu.Game/Overlays/BeatmapSetOverlay.cs +++ b/osu.Game/Overlays/BeatmapSetOverlay.cs @@ -31,7 +31,6 @@ namespace osu.Game.Overlays private APIAccess api; private RulesetStore rulesets; - private BeatmapManager manager; private readonly ScrollContainer scroll; @@ -92,7 +91,6 @@ namespace osu.Game.Overlays { this.api = api; this.rulesets = rulesets; - this.manager = manager; manager.BeatmapSetAdded += beatmap => { diff --git a/osu.Game/Overlays/Direct/DirectPanel.cs b/osu.Game/Overlays/Direct/DirectPanel.cs index 702aef7417..d4f4067fca 100644 --- a/osu.Game/Overlays/Direct/DirectPanel.cs +++ b/osu.Game/Overlays/Direct/DirectPanel.cs @@ -16,7 +16,6 @@ using osu.Game.Graphics.Sprites; using OpenTK.Graphics; using osu.Framework.Input; using osu.Game.Graphics.UserInterface; -using osu.Game.Online.API; using osu.Framework.Logging; using osu.Game.Online.API.Requests; using osu.Framework.Configuration; @@ -34,10 +33,8 @@ namespace osu.Game.Overlays.Direct private Container content; - private APIAccess api; private ProgressBar progressBar; private BeatmapManager beatmaps; - private NotificationOverlay notifications; private BeatmapSetOverlay beatmapSetOverlay; public Track Preview => PlayButton.Preview; @@ -70,11 +67,9 @@ namespace osu.Game.Overlays.Direct [BackgroundDependencyLoader(permitNulls: true)] - private void load(APIAccess api, BeatmapManager beatmaps, OsuColour colours, NotificationOverlay notifications, BeatmapSetOverlay beatmapSetOverlay) + private void load(BeatmapManager beatmaps, OsuColour colours, BeatmapSetOverlay beatmapSetOverlay) { - this.api = api; this.beatmaps = beatmaps; - this.notifications = notifications; this.beatmapSetOverlay = beatmapSetOverlay; AddInternal(content = new Container From f912744acce1aae5f70ed77e5576f0008aafe081 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 16 Nov 2017 00:15:27 +0900 Subject: [PATCH 0655/1263] Fix sizing of ModIcon --- osu.Game/Overlays/Mods/ModButton.cs | 3 --- .../Profile/Sections/Ranks/DrawableScore.cs | 6 +----- osu.Game/Rulesets/UI/ModIcon.cs | 14 ++++++++------ osu.Game/Screens/Play/HUD/ModDisplay.cs | 6 +----- .../Select/Leaderboards/LeaderboardScore.cs | 6 +----- 5 files changed, 11 insertions(+), 24 deletions(-) diff --git a/osu.Game/Overlays/Mods/ModButton.cs b/osu.Game/Overlays/Mods/ModButton.cs index 6bfe70d873..0ead4ea019 100644 --- a/osu.Game/Overlays/Mods/ModButton.cs +++ b/osu.Game/Overlays/Mods/ModButton.cs @@ -207,14 +207,12 @@ namespace osu.Game.Overlays.Mods { Origin = Anchor.BottomRight, Anchor = Anchor.BottomRight, - AutoSizeAxes = Axes.Both, Position = new Vector2(1.5f), }, foregroundIcon = new ModIcon(Mods[0]) { Origin = Anchor.BottomRight, Anchor = Anchor.BottomRight, - AutoSizeAxes = Axes.Both, Position = new Vector2(-1.5f), }, }); @@ -225,7 +223,6 @@ namespace osu.Game.Overlays.Mods { Origin = Anchor.Centre, Anchor = Anchor.Centre, - AutoSizeAxes = Axes.Both, }); } } diff --git a/osu.Game/Overlays/Profile/Sections/Ranks/DrawableScore.cs b/osu.Game/Overlays/Profile/Sections/Ranks/DrawableScore.cs index 5088fe5f67..35f4778047 100644 --- a/osu.Game/Overlays/Profile/Sections/Ranks/DrawableScore.cs +++ b/osu.Game/Overlays/Profile/Sections/Ranks/DrawableScore.cs @@ -163,11 +163,7 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks }); foreach (Mod mod in Score.Mods) - modsContainer.Add(new ModIcon(mod) - { - AutoSizeAxes = Axes.Both, - Scale = new Vector2(0.5f), - }); + modsContainer.Add(new ModIcon(mod) { Scale = new Vector2(0.5f) }); } protected override bool OnClick(InputState state) => true; diff --git a/osu.Game/Rulesets/UI/ModIcon.cs b/osu.Game/Rulesets/UI/ModIcon.cs index 7f7068d341..5ca3d9521b 100644 --- a/osu.Game/Rulesets/UI/ModIcon.cs +++ b/osu.Game/Rulesets/UI/ModIcon.cs @@ -18,7 +18,7 @@ namespace osu.Game.Rulesets.UI private readonly SpriteIcon modIcon; private readonly SpriteIcon background; - private const float background_size = 80; + private const float size = 80; public FontAwesome Icon { @@ -38,23 +38,25 @@ namespace osu.Game.Rulesets.UI TooltipText = mod.Name; + Size = new Vector2(size); + Children = new Drawable[] { background = new SpriteIcon { Origin = Anchor.Centre, Anchor = Anchor.Centre, - Size = new Vector2(background_size), + Size = new Vector2(size), Icon = FontAwesome.fa_osu_mod_bg, + Y = -6.5f, Shadow = true, }, modIcon = new SpriteIcon { - Origin = Anchor.TopCentre, - Anchor = Anchor.TopCentre, + Origin = Anchor.Centre, + Anchor = Anchor.Centre, Colour = OsuColour.Gray(84), - Size = new Vector2(background_size - 35), - Y = 25, + Size = new Vector2(size - 35), Icon = mod.Icon }, }; diff --git a/osu.Game/Screens/Play/HUD/ModDisplay.cs b/osu.Game/Screens/Play/HUD/ModDisplay.cs index 18a3096d7c..fd0e71ece8 100644 --- a/osu.Game/Screens/Play/HUD/ModDisplay.cs +++ b/osu.Game/Screens/Play/HUD/ModDisplay.cs @@ -55,11 +55,7 @@ namespace osu.Game.Screens.Play.HUD iconsContainer.Clear(); foreach (Mod mod in mods) { - iconsContainer.Add(new ModIcon(mod) - { - AutoSizeAxes = Axes.Both, - Scale = new Vector2(0.6f), - }); + iconsContainer.Add(new ModIcon(mod) { Scale = new Vector2(0.6f) }); } if (IsLoaded) diff --git a/osu.Game/Screens/Select/Leaderboards/LeaderboardScore.cs b/osu.Game/Screens/Select/Leaderboards/LeaderboardScore.cs index de381cd2dc..9044938a75 100644 --- a/osu.Game/Screens/Select/Leaderboards/LeaderboardScore.cs +++ b/osu.Game/Screens/Select/Leaderboards/LeaderboardScore.cs @@ -264,11 +264,7 @@ namespace osu.Game.Screens.Select.Leaderboards foreach (Mod mod in Score.Mods) { - modsContainer.Add(new ModIcon(mod) - { - AutoSizeAxes = Axes.Both, - Scale = new Vector2(0.375f) - }); + modsContainer.Add(new ModIcon(mod) { Scale = new Vector2(0.375f) }); } } From 97c5956083779edfcb8d5c8ac9b5b6e4b5b2bdee Mon Sep 17 00:00:00 2001 From: naoey Date: Thu, 16 Nov 2017 15:36:22 +0530 Subject: [PATCH 0656/1263] Make download buttons disappear instead of closing overlay. - Also unbind event handlers - Remove unused field --- osu.Game/Overlays/BeatmapSet/Header.cs | 15 +++++++++++++++ osu.Game/Overlays/BeatmapSetOverlay.cs | 12 ++---------- osu.Game/Overlays/Direct/DirectPanel.cs | 6 ++++++ 3 files changed, 23 insertions(+), 10 deletions(-) diff --git a/osu.Game/Overlays/BeatmapSet/Header.cs b/osu.Game/Overlays/BeatmapSet/Header.cs index ed72cf0cc9..27ef6208be 100644 --- a/osu.Game/Overlays/BeatmapSet/Header.cs +++ b/osu.Game/Overlays/BeatmapSet/Header.cs @@ -51,6 +51,7 @@ namespace osu.Game.Overlays.BeatmapSet title.Text = BeatmapSet.Metadata.Title; artist.Text = BeatmapSet.Metadata.Artist; + downloadButtonsContainer.FadeIn(); noVideoButtons.FadeTo(BeatmapSet.OnlineInfo.HasVideo ? 0 : 1, transition_duration); videoButtons.FadeTo(BeatmapSet.OnlineInfo.HasVideo ? 1 : 0, transition_duration); @@ -224,6 +225,20 @@ namespace osu.Game.Overlays.BeatmapSet { tabsBg.Colour = colours.Gray3; this.beatmaps = beatmaps; + + beatmaps.BeatmapSetAdded += handleBeatmapAdd; + } + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + beatmaps.BeatmapSetAdded -= handleBeatmapAdd; + } + + private void handleBeatmapAdd(BeatmapSetInfo beatmap) + { + if (beatmap.OnlineBeatmapSetID == BeatmapSet.OnlineBeatmapSetID) + downloadButtonsContainer.FadeOut(transition_duration); } private void download(bool noVideo) diff --git a/osu.Game/Overlays/BeatmapSetOverlay.cs b/osu.Game/Overlays/BeatmapSetOverlay.cs index 7ae2d323b8..940ac433fc 100644 --- a/osu.Game/Overlays/BeatmapSetOverlay.cs +++ b/osu.Game/Overlays/BeatmapSetOverlay.cs @@ -24,8 +24,6 @@ namespace osu.Game.Overlays public const float X_PADDING = 40; public const float RIGHT_WIDTH = 275; - private BeatmapSetInfo currentBeatmap; - private readonly Header header; private readonly Info info; @@ -87,16 +85,10 @@ namespace osu.Game.Overlays } [BackgroundDependencyLoader] - private void load(APIAccess api, RulesetStore rulesets, BeatmapManager manager) + private void load(APIAccess api, RulesetStore rulesets) { this.api = api; this.rulesets = rulesets; - - manager.BeatmapSetAdded += beatmap => - { - if (beatmap.OnlineBeatmapSetID == currentBeatmap.OnlineBeatmapSetID) - Hide(); - }; } protected override void PopIn() @@ -128,7 +120,7 @@ namespace osu.Game.Overlays public void ShowBeatmapSet(BeatmapSetInfo set) { - currentBeatmap = header.BeatmapSet = info.BeatmapSet = set; + header.BeatmapSet = info.BeatmapSet = set; Show(); scroll.ScrollTo(0); } diff --git a/osu.Game/Overlays/Direct/DirectPanel.cs b/osu.Game/Overlays/Direct/DirectPanel.cs index d4f4067fca..b8a8528962 100644 --- a/osu.Game/Overlays/Direct/DirectPanel.cs +++ b/osu.Game/Overlays/Direct/DirectPanel.cs @@ -107,6 +107,12 @@ namespace osu.Game.Overlays.Direct beatmaps.BeatmapDownloadBegan += attachDownload; } + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + beatmaps.BeatmapDownloadBegan -= attachDownload; + } + protected override void Update() { base.Update(); From 6c40cf08cce811707cadc5c8e68c6e7d4fe3bc60 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 16 Nov 2017 21:29:07 +0900 Subject: [PATCH 0657/1263] Optimise leaderboard display Adds async loading support and cleans up the code quite a bit in the process. --- .../Graphics/Containers/OsuScrollContainer.cs | 2 +- .../Select/Leaderboards/Leaderboard.cs | 62 +++++---- .../Select/Leaderboards/LeaderboardScore.cs | 130 +++++++----------- 3 files changed, 87 insertions(+), 107 deletions(-) diff --git a/osu.Game/Graphics/Containers/OsuScrollContainer.cs b/osu.Game/Graphics/Containers/OsuScrollContainer.cs index e395f1b7bd..3fc9f439fa 100644 --- a/osu.Game/Graphics/Containers/OsuScrollContainer.cs +++ b/osu.Game/Graphics/Containers/OsuScrollContainer.cs @@ -7,7 +7,7 @@ using OpenTK.Input; namespace osu.Game.Graphics.Containers { - internal class OsuScrollContainer : ScrollContainer + public class OsuScrollContainer : ScrollContainer { /// /// Allows controlling the scroll bar from any position in the container using the right mouse button. diff --git a/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs b/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs index 7d65b8b648..4b1070f236 100644 --- a/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs +++ b/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs @@ -17,19 +17,21 @@ using osu.Game.Graphics.UserInterface; using osu.Game.Rulesets.Scoring; using osu.Game.Online.API; using osu.Game.Online.API.Requests; +using System.Linq; namespace osu.Game.Screens.Select.Leaderboards { public class Leaderboard : Container { private readonly ScrollContainer scrollContainer; - private readonly FillFlowContainer scrollFlow; + private FillFlowContainer scrollFlow; public Action ScoreSelected; private readonly LoadingAnimation loading; private IEnumerable scores; + public IEnumerable Scores { get { return scores; } @@ -41,33 +43,43 @@ namespace osu.Game.Screens.Select.Leaderboards int i = 150; if (scores == null) { - foreach (var c in scrollFlow.Children) - c.FadeOut(i += 10); + if (scrollFlow != null) + { + foreach (var c in scrollFlow.Children) + c.FadeOut(i += 10); - foreach (var c in scrollFlow.Children) - c.LifetimeEnd = Time.Current + i; + foreach (var c in scrollFlow.Children) + c.LifetimeEnd = Time.Current + i; + } return; } - scrollFlow.Clear(); - - i = 0; - foreach (var s in scores) + // schedule because we may not be loaded yet (LoadComponentAsync complains). + Schedule(() => { - var ls = new LeaderboardScore(s, 1 + i) + LoadComponentAsync(new FillFlowContainer { - AlwaysPresent = true, - Action = () => ScoreSelected?.Invoke(s), - State = Visibility.Hidden, - }; - scrollFlow.Add(ls); + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Spacing = new Vector2(0f, 5f), + Padding = new MarginPadding { Top = 10, Bottom = 5 }, + ChildrenEnumerable = scores.Select(s => new LeaderboardScore(s, 1 + i) { Action = () => ScoreSelected?.Invoke(s) }) + }, f => + { + scrollFlow?.Expire(); + scrollContainer.Add(scrollFlow = f); - using (BeginDelayedSequence(i++ * 50, true)) - ls.Show(); - } + i = 0; + foreach (var s in f.Children) + { + using (s.BeginDelayedSequence(i++ * 50, true)) + s.Show(); + } - scrollContainer.ScrollTo(0f, false); + scrollContainer.ScrollTo(0f, false); + }); + }); } } @@ -79,16 +91,6 @@ namespace osu.Game.Screens.Select.Leaderboards { RelativeSizeAxes = Axes.Both, ScrollbarVisible = false, - Children = new Drawable[] - { - scrollFlow = new FillFlowContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Spacing = new Vector2(0f, 5f), - Padding = new MarginPadding { Top = 10, Bottom = 5 }, - }, - }, }, loading = new LoadingAnimation() }; @@ -152,6 +154,8 @@ namespace osu.Game.Screens.Select.Leaderboards if (!scrollContainer.IsScrolledToEnd()) fadeStart -= LeaderboardScore.HEIGHT; + if (scrollFlow == null) return; + foreach (var c in scrollFlow.Children) { var topY = c.ToSpaceOfOtherDrawable(Vector2.Zero, scrollFlow).Y; diff --git a/osu.Game/Screens/Select/Leaderboards/LeaderboardScore.cs b/osu.Game/Screens/Select/Leaderboards/LeaderboardScore.cs index 9044938a75..e9de3fb672 100644 --- a/osu.Game/Screens/Select/Leaderboards/LeaderboardScore.cs +++ b/osu.Game/Screens/Select/Leaderboards/LeaderboardScore.cs @@ -2,9 +2,10 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; +using System.Linq; using OpenTK; using OpenTK.Graphics; -using osu.Framework; +using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -13,14 +14,13 @@ using osu.Framework.Input; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; -using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.UI; using osu.Game.Users; namespace osu.Game.Screens.Select.Leaderboards { - public class LeaderboardScore : OsuClickableContainer, IStateful + public class LeaderboardScore : OsuClickableContainer { public static readonly float HEIGHT = 60; @@ -34,72 +34,16 @@ namespace osu.Game.Screens.Select.Leaderboards private const float background_alpha = 0.25f; private const float rank_width = 30; - private readonly Box background; - private readonly Container content; - private readonly Container avatar; - private readonly DrawableRank scoreRank; - private readonly OsuSpriteText nameLabel; - private readonly GlowingSpriteText scoreLabel; - private readonly ScoreComponentLabel maxCombo; - private readonly ScoreComponentLabel accuracy; - private readonly Container flagBadgeContainer; - private readonly FillFlowContainer modsContainer; - - private Visibility state; - - public Visibility State - { - get { return state; } - set - { - if (state == value) - return; - state = value; - - switch (state) - { - case Visibility.Hidden: - foreach (var d in new Drawable[] { avatar, nameLabel, scoreLabel, scoreRank, flagBadgeContainer, maxCombo, accuracy, modsContainer }) - d.FadeOut(); - - Alpha = 0; - - content.MoveToY(75); - avatar.MoveToX(75); - nameLabel.MoveToX(150); - break; - case Visibility.Visible: - this.FadeIn(200); - content.MoveToY(0, 800, Easing.OutQuint); - - using (BeginDelayedSequence(100, true)) - { - avatar.FadeIn(300, Easing.OutQuint); - nameLabel.FadeIn(350, Easing.OutQuint); - - avatar.MoveToX(0, 300, Easing.OutQuint); - nameLabel.MoveToX(0, 350, Easing.OutQuint); - - using (BeginDelayedSequence(250, true)) - { - scoreLabel.FadeIn(200); - scoreRank.FadeIn(200); - - using (BeginDelayedSequence(50, true)) - { - var drawables = new Drawable[] { flagBadgeContainer, maxCombo, accuracy, modsContainer, }; - for (int i = 0; i < drawables.Length; i++) - drawables[i].FadeIn(100 + i * 50); - } - } - } - - break; - } - - StateChanged?.Invoke(State); - } - } + private Box background; + private Container content; + private Container avatar; + private DrawableRank scoreRank; + private OsuSpriteText nameLabel; + private GlowingSpriteText scoreLabel; + private ScoreComponentLabel maxCombo; + private ScoreComponentLabel accuracy; + private Container flagBadgeContainer; + private FillFlowContainer modsContainer; public LeaderboardScore(Score score, int rank) { @@ -108,7 +52,11 @@ namespace osu.Game.Screens.Select.Leaderboards RelativeSizeAxes = Axes.X; Height = HEIGHT; + } + [BackgroundDependencyLoader] + private void load() + { Children = new Drawable[] { new Container @@ -255,23 +203,51 @@ namespace osu.Game.Screens.Select.Leaderboards Origin = Anchor.BottomRight, AutoSizeAxes = Axes.Both, Direction = FillDirection.Horizontal, + ChildrenEnumerable = Score.Mods.Select(mod => new ModIcon(mod) { Scale = new Vector2(0.375f) }) }, }, }, }, }, }; - - foreach (Mod mod in Score.Mods) - { - modsContainer.Add(new ModIcon(mod) { Scale = new Vector2(0.375f) }); - } } - public void ToggleVisibility() => State = State == Visibility.Visible ? Visibility.Hidden : Visibility.Visible; + public override void Show() + { + foreach (var d in new Drawable[] { avatar, nameLabel, scoreLabel, scoreRank, flagBadgeContainer, maxCombo, accuracy, modsContainer }) + d.FadeOut(); - public override void Hide() => State = Visibility.Hidden; - public override void Show() => State = Visibility.Visible; + Alpha = 0; + + content.MoveToY(75); + avatar.MoveToX(75); + nameLabel.MoveToX(150); + + this.FadeIn(200); + content.MoveToY(0, 800, Easing.OutQuint); + + using (BeginDelayedSequence(100, true)) + { + avatar.FadeIn(300, Easing.OutQuint); + nameLabel.FadeIn(350, Easing.OutQuint); + + avatar.MoveToX(0, 300, Easing.OutQuint); + nameLabel.MoveToX(0, 350, Easing.OutQuint); + + using (BeginDelayedSequence(250, true)) + { + scoreLabel.FadeIn(200); + scoreRank.FadeIn(200); + + using (BeginDelayedSequence(50, true)) + { + var drawables = new Drawable[] { flagBadgeContainer, maxCombo, accuracy, modsContainer, }; + for (int i = 0; i < drawables.Length; i++) + drawables[i].FadeIn(100 + i * 50); + } + } + } + } protected override bool OnHover(InputState state) { From d301ad143596349036fd26ca4f74c48ad1fac2f8 Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Thu, 16 Nov 2017 20:06:49 +0300 Subject: [PATCH 0658/1263] Add supporter icon to the user panel --- osu.Game.Tests/Visual/TestCaseUserPanel.cs | 3 +- osu.Game/Users/UserPanel.cs | 70 ++++++++++++++++++---- 2 files changed, 61 insertions(+), 12 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCaseUserPanel.cs b/osu.Game.Tests/Visual/TestCaseUserPanel.cs index 60932f8424..8523a754f8 100644 --- a/osu.Game.Tests/Visual/TestCaseUserPanel.cs +++ b/osu.Game.Tests/Visual/TestCaseUserPanel.cs @@ -36,7 +36,8 @@ namespace osu.Game.Tests.Visual Username = @"peppy", Id = 2, Country = new Country { FlagName = @"AU" }, - CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c3.jpg" + CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c3.jpg", + IsSupporter = true, }) { Width = 300 }, }, }); diff --git a/osu.Game/Users/UserPanel.cs b/osu.Game/Users/UserPanel.cs index 706ad86bfc..ab4d55027d 100644 --- a/osu.Game/Users/UserPanel.cs +++ b/osu.Game/Users/UserPanel.cs @@ -16,6 +16,7 @@ using osu.Game.Overlays; using osu.Framework.Graphics.UserInterface; using osu.Game.Graphics.UserInterface; using osu.Framework.Graphics.Cursor; +using osu.Game.Graphics.Backgrounds; namespace osu.Game.Users { @@ -43,6 +44,8 @@ namespace osu.Game.Users this.user = user; + FillFlowContainer infoContainer; + Height = height - status_height; Masking = true; CornerRadius = 5; @@ -100,7 +103,7 @@ namespace osu.Game.Users TextSize = 18, Font = @"Exo2.0-SemiBoldItalic", }, - new FillFlowContainer + infoContainer = new FillFlowContainer { Anchor = Anchor.BottomLeft, Origin = Anchor.BottomLeft, @@ -115,16 +118,6 @@ namespace osu.Game.Users Width = 30f, RelativeSizeAxes = Axes.Y, }, - new Container - { - Width = 40f, - RelativeSizeAxes = Axes.Y, - }, - new CircularContainer - { - Width = 20f, - RelativeSizeAxes = Axes.Y, - }, }, }, }, @@ -171,6 +164,13 @@ namespace osu.Game.Users }, }, }; + + if (user.IsSupporter) + infoContainer.Add(new SupporterIcon + { + RelativeSizeAxes = Axes.Y, + Width = 20f, + }); } [BackgroundDependencyLoader(permitNulls: true)] @@ -219,5 +219,53 @@ 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; + } + } } } From 62155e6dd53820d2d5454150ba51f7a6566a9f21 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 16 Nov 2017 20:06:32 +0900 Subject: [PATCH 0659/1263] Make DifficultyCalculator support mod applications Fixes https://github.com/ppy/osu/issues/476. --- .../CatchDifficultyCalculator.cs | 7 +--- osu.Game.Rulesets.Catch/CatchRuleset.cs | 2 +- .../ManiaDifficultyCalculator.cs | 5 +-- osu.Game.Rulesets.Mania/ManiaRuleset.cs | 2 +- .../OsuDifficulty/OsuDifficultyCalculator.cs | 2 +- osu.Game.Rulesets.Osu/OsuRuleset.cs | 3 +- .../TaikoDifficultyCalculator.cs | 2 +- osu.Game.Rulesets.Taiko/TaikoRuleset.cs | 2 +- osu.Game/Beatmaps/DifficultyCalculator.cs | 37 +++++++++++-------- osu.Game/Beatmaps/DummyWorkingBeatmap.cs | 2 +- osu.Game/Rulesets/Ruleset.cs | 3 +- 11 files changed, 35 insertions(+), 32 deletions(-) diff --git a/osu.Game.Rulesets.Catch/CatchDifficultyCalculator.cs b/osu.Game.Rulesets.Catch/CatchDifficultyCalculator.cs index 3c6cc4b1a3..127fde74ef 100644 --- a/osu.Game.Rulesets.Catch/CatchDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Catch/CatchDifficultyCalculator.cs @@ -14,11 +14,8 @@ namespace osu.Game.Rulesets.Catch { } - protected override double CalculateInternal(Dictionary categoryDifficulty) - { - return 0; - } + public override double Calculate(Dictionary categoryDifficulty) => 0; protected override BeatmapConverter CreateBeatmapConverter() => new CatchBeatmapConverter(); } -} \ No newline at end of file +} diff --git a/osu.Game.Rulesets.Catch/CatchRuleset.cs b/osu.Game.Rulesets.Catch/CatchRuleset.cs index 1a9b034cf2..1d5fc0545e 100644 --- a/osu.Game.Rulesets.Catch/CatchRuleset.cs +++ b/osu.Game.Rulesets.Catch/CatchRuleset.cs @@ -95,7 +95,7 @@ namespace osu.Game.Rulesets.Catch public override Drawable CreateIcon() => new SpriteIcon { Icon = FontAwesome.fa_osu_fruits_o }; - public override DifficultyCalculator CreateDifficultyCalculator(Beatmap beatmap) => new CatchDifficultyCalculator(beatmap); + public override DifficultyCalculator CreateDifficultyCalculator(Beatmap beatmap, Mod[] mods = null) => new CatchDifficultyCalculator(beatmap); public override int LegacyID => 2; diff --git a/osu.Game.Rulesets.Mania/ManiaDifficultyCalculator.cs b/osu.Game.Rulesets.Mania/ManiaDifficultyCalculator.cs index 784df1f293..d5c6d21131 100644 --- a/osu.Game.Rulesets.Mania/ManiaDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Mania/ManiaDifficultyCalculator.cs @@ -16,10 +16,7 @@ namespace osu.Game.Rulesets.Mania { } - protected override double CalculateInternal(Dictionary categoryDifficulty) - { - return 0; - } + public override double Calculate(Dictionary categoryDifficulty) => 0; protected override BeatmapConverter CreateBeatmapConverter() => new ManiaBeatmapConverter(true, (int)Math.Max(1, Math.Round(Beatmap.BeatmapInfo.BaseDifficulty.CircleSize))); } diff --git a/osu.Game.Rulesets.Mania/ManiaRuleset.cs b/osu.Game.Rulesets.Mania/ManiaRuleset.cs index c0996cadf9..4eea884891 100644 --- a/osu.Game.Rulesets.Mania/ManiaRuleset.cs +++ b/osu.Game.Rulesets.Mania/ManiaRuleset.cs @@ -107,7 +107,7 @@ namespace osu.Game.Rulesets.Mania public override Drawable CreateIcon() => new SpriteIcon { Icon = FontAwesome.fa_osu_mania_o }; - public override DifficultyCalculator CreateDifficultyCalculator(Beatmap beatmap) => new ManiaDifficultyCalculator(beatmap); + public override DifficultyCalculator CreateDifficultyCalculator(Beatmap beatmap, Mod[] mods = null) => new ManiaDifficultyCalculator(beatmap); public override int LegacyID => 3; diff --git a/osu.Game.Rulesets.Osu/OsuDifficulty/OsuDifficultyCalculator.cs b/osu.Game.Rulesets.Osu/OsuDifficulty/OsuDifficultyCalculator.cs index 457466fd86..6ed45e1f03 100644 --- a/osu.Game.Rulesets.Osu/OsuDifficulty/OsuDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Osu/OsuDifficulty/OsuDifficultyCalculator.cs @@ -26,7 +26,7 @@ namespace osu.Game.Rulesets.Osu.OsuDifficulty (h as Slider)?.Curve?.Calculate(); } - protected override double CalculateInternal(Dictionary categoryDifficulty) + public override double Calculate(Dictionary categoryDifficulty) { OsuDifficultyBeatmap beatmap = new OsuDifficultyBeatmap(Objects); Skill[] skills = diff --git a/osu.Game.Rulesets.Osu/OsuRuleset.cs b/osu.Game.Rulesets.Osu/OsuRuleset.cs index 7650a91d7a..a4828319d1 100644 --- a/osu.Game.Rulesets.Osu/OsuRuleset.cs +++ b/osu.Game.Rulesets.Osu/OsuRuleset.cs @@ -14,6 +14,7 @@ using System.Linq; using osu.Framework.Graphics; using osu.Game.Overlays.Settings; using osu.Framework.Input.Bindings; +using osu.Game.Rulesets.Scoring; namespace osu.Game.Rulesets.Osu { @@ -112,7 +113,7 @@ namespace osu.Game.Rulesets.Osu public override Drawable CreateIcon() => new SpriteIcon { Icon = FontAwesome.fa_osu_osu_o }; - public override DifficultyCalculator CreateDifficultyCalculator(Beatmap beatmap) => new OsuDifficultyCalculator(beatmap); + public override DifficultyCalculator CreateDifficultyCalculator(Beatmap beatmap, Mod[] mods = null) => new OsuDifficultyCalculator(beatmap); public override string Description => "osu!"; diff --git a/osu.Game.Rulesets.Taiko/TaikoDifficultyCalculator.cs b/osu.Game.Rulesets.Taiko/TaikoDifficultyCalculator.cs index de97658e35..57986cd198 100644 --- a/osu.Game.Rulesets.Taiko/TaikoDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Taiko/TaikoDifficultyCalculator.cs @@ -36,7 +36,7 @@ namespace osu.Game.Rulesets.Taiko { } - protected override double CalculateInternal(Dictionary categoryDifficulty) + public override double Calculate(Dictionary categoryDifficulty) { // Fill our custom DifficultyHitObject class, that carries additional information difficultyHitObjects.Clear(); diff --git a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs index ea0f0eae1a..99ae36967a 100644 --- a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs +++ b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs @@ -97,7 +97,7 @@ namespace osu.Game.Rulesets.Taiko public override Drawable CreateIcon() => new SpriteIcon { Icon = FontAwesome.fa_osu_taiko_o }; - public override DifficultyCalculator CreateDifficultyCalculator(Beatmap beatmap) => new TaikoDifficultyCalculator(beatmap); + public override DifficultyCalculator CreateDifficultyCalculator(Beatmap beatmap, Mod[] mods = null) => new TaikoDifficultyCalculator(beatmap); public override int LegacyID => 1; diff --git a/osu.Game/Beatmaps/DifficultyCalculator.cs b/osu.Game/Beatmaps/DifficultyCalculator.cs index bb6a292d9d..f6cc535aca 100644 --- a/osu.Game/Beatmaps/DifficultyCalculator.cs +++ b/osu.Game/Beatmaps/DifficultyCalculator.cs @@ -3,6 +3,10 @@ using osu.Game.Rulesets.Objects; using System.Collections.Generic; +using osu.Game.Rulesets.Mods; +using osu.Framework.Timing; +using System.Linq; +using osu.Framework.Extensions.IEnumerableExtensions; namespace osu.Game.Beatmaps { @@ -10,41 +14,44 @@ namespace osu.Game.Beatmaps { protected double TimeRate = 1; - protected abstract double CalculateInternal(Dictionary categoryDifficulty); - - private void loadTiming() - { - // TODO: Handle mods - const int audio_rate = 100; - TimeRate = audio_rate / 100.0; - } - - public double Calculate(Dictionary categoryDifficulty = null) - { - loadTiming(); - double difficulty = CalculateInternal(categoryDifficulty); - return difficulty; - } + public abstract double Calculate(Dictionary categoryDifficulty = null); } public abstract class DifficultyCalculator : DifficultyCalculator where T : HitObject { protected readonly Beatmap Beatmap; + protected readonly Mod[] Mods; protected List Objects; protected DifficultyCalculator(Beatmap beatmap) + : this(beatmap, null) + { + } + + protected DifficultyCalculator(Beatmap beatmap, Mod[] mods) { Beatmap = beatmap; + Mods = mods ?? new Mod[0]; Objects = CreateBeatmapConverter().Convert(beatmap).HitObjects; foreach (var h in Objects) h.ApplyDefaults(beatmap.ControlPointInfo, beatmap.BeatmapInfo.BaseDifficulty); + ApplyMods(mods); + PreprocessHitObjects(); } + protected virtual void ApplyMods(Mod[] mods) + { + var clock = new StopwatchClock(); + mods.OfType().ForEach(m => m.ApplyToClock(clock)); + + TimeRate = clock.Rate; + } + protected virtual void PreprocessHitObjects() { } diff --git a/osu.Game/Beatmaps/DummyWorkingBeatmap.cs b/osu.Game/Beatmaps/DummyWorkingBeatmap.cs index b9376849c1..c15d585eb2 100644 --- a/osu.Game/Beatmaps/DummyWorkingBeatmap.cs +++ b/osu.Game/Beatmaps/DummyWorkingBeatmap.cs @@ -59,7 +59,7 @@ namespace osu.Game.Beatmaps throw new NotImplementedException(); } - public override DifficultyCalculator CreateDifficultyCalculator(Beatmap beatmap) => null; + public override DifficultyCalculator CreateDifficultyCalculator(Beatmap beatmap, Mod[] mods = null) => null; public override string Description => "dummy"; diff --git a/osu.Game/Rulesets/Ruleset.cs b/osu.Game/Rulesets/Ruleset.cs index 587c2fc659..e8919c4bda 100644 --- a/osu.Game/Rulesets/Ruleset.cs +++ b/osu.Game/Rulesets/Ruleset.cs @@ -10,6 +10,7 @@ using osu.Game.Beatmaps; using osu.Game.Graphics; using osu.Game.Overlays.Settings; using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.UI; namespace osu.Game.Rulesets @@ -47,7 +48,7 @@ namespace osu.Game.Rulesets /// public abstract RulesetContainer CreateRulesetContainerWith(WorkingBeatmap beatmap, bool isForCurrentRuleset); - public abstract DifficultyCalculator CreateDifficultyCalculator(Beatmap beatmap); + public abstract DifficultyCalculator CreateDifficultyCalculator(Beatmap beatmap, Mod[] mods = null); public virtual Drawable CreateIcon() => new SpriteIcon { Icon = FontAwesome.fa_question_circle }; From 18f2e92a48b4ba9e044143d04972470980666fc4 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 16 Nov 2017 20:35:57 +0900 Subject: [PATCH 0660/1263] Rework mod applications to hitobject/rulesetcontainer for DifficultyCalculator --- osu.Game.Rulesets.Mania/Mods/ManiaMod.cs | 6 ++--- osu.Game.Rulesets.Osu/Mods/OsuMod.cs | 27 ++++++++++++------- osu.Game/Beatmaps/DifficultyCalculator.cs | 4 +++ osu.Game/Rulesets/Mods/IApplicableMod.cs | 22 --------------- .../Rulesets/Mods/IApplicableToHitObject.cs | 20 ++++++++++++++ .../Mods/IApplicableToRulesetContainer.cs | 21 +++++++++++++++ osu.Game/Rulesets/Mods/ModAutoplay.cs | 4 +-- osu.Game/Rulesets/UI/RulesetContainer.cs | 6 ++++- osu.Game/osu.Game.csproj | 3 ++- 9 files changed, 74 insertions(+), 39 deletions(-) delete mode 100644 osu.Game/Rulesets/Mods/IApplicableMod.cs create mode 100644 osu.Game/Rulesets/Mods/IApplicableToHitObject.cs create mode 100644 osu.Game/Rulesets/Mods/IApplicableToRulesetContainer.cs diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaMod.cs b/osu.Game.Rulesets.Mania/Mods/ManiaMod.cs index 037c3bd567..164309c227 100644 --- a/osu.Game.Rulesets.Mania/Mods/ManiaMod.cs +++ b/osu.Game.Rulesets.Mania/Mods/ManiaMod.cs @@ -86,18 +86,17 @@ namespace osu.Game.Rulesets.Mania.Mods public override Type[] IncompatibleMods => new[] { typeof(ModFlashlight) }; } - public class ManiaModRandom : Mod, IApplicableMod + public class ManiaModRandom : Mod, IApplicableToRulesetContainer { public override string Name => "Random"; public override string ShortenedName => "RD"; - public override FontAwesome Icon => FontAwesome.fa_osu_dice; + public override FontAwesome Icon => FontAwesome.fa_osu_dice; public override string Description => @"Shuffle around the notes!"; public override double ScoreMultiplier => 1; public void ApplyToRulesetContainer(RulesetContainer rulesetContainer) { int availableColumns = ((ManiaRulesetContainer)rulesetContainer).AvailableColumns; - var shuffledColumns = Enumerable.Range(0, availableColumns).OrderBy(item => RNG.Next()).ToList(); rulesetContainer.Objects.OfType().ForEach(h => h.Column = shuffledColumns[h.Column]); @@ -188,6 +187,7 @@ namespace osu.Game.Rulesets.Mania.Mods base.ApplyToRulesetContainer(rulesetContainer); } + protected override Score CreateReplayScore(Beatmap beatmap) => new Score { User = new User { Username = "osu!topus!" }, diff --git a/osu.Game.Rulesets.Osu/Mods/OsuMod.cs b/osu.Game.Rulesets.Osu/Mods/OsuMod.cs index 2970055bff..596fe27504 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuMod.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuMod.cs @@ -33,22 +33,29 @@ namespace osu.Game.Rulesets.Osu.Mods public override double ScoreMultiplier => 1.06; } - public class OsuModHardRock : ModHardRock, IApplicableMod + public class OsuModHardRock : ModHardRock, IApplicableToHitObject { public override double ScoreMultiplier => 1.06; public override bool Ranked => true; - public void ApplyToRulesetContainer(RulesetContainer rulesetContainer) + public void ApplyToHitObject(OsuHitObject hitObject) + { + hitObject.Position = new Vector2(hitObject.Position.X, OsuPlayfield.BASE_SIZE.Y - hitObject.Y); + + var slider = hitObject as Slider; + if (slider == null) + return; + + var newControlPoints = new List(); + slider.ControlPoints.ForEach(c => newControlPoints.Add(new Vector2(c.X, OsuPlayfield.BASE_SIZE.Y - c.Y))); + + slider.ControlPoints = newControlPoints; + slider.Curve?.Calculate(); // Recalculate the slider curve + } + + public void ApplyToHitObjects(RulesetContainer rulesetContainer) { - rulesetContainer.Objects.OfType().ForEach(h => h.Position = new Vector2(h.Position.X, OsuPlayfield.BASE_SIZE.Y - h.Y)); - rulesetContainer.Objects.OfType().ForEach(s => - { - var newControlPoints = new List(); - s.ControlPoints.ForEach(c => newControlPoints.Add(new Vector2(c.X, OsuPlayfield.BASE_SIZE.Y - c.Y))); - s.ControlPoints = newControlPoints; - s.Curve?.Calculate(); // Recalculate the slider curve - }); } } diff --git a/osu.Game/Beatmaps/DifficultyCalculator.cs b/osu.Game/Beatmaps/DifficultyCalculator.cs index f6cc535aca..54dab07b31 100644 --- a/osu.Game/Beatmaps/DifficultyCalculator.cs +++ b/osu.Game/Beatmaps/DifficultyCalculator.cs @@ -49,6 +49,10 @@ namespace osu.Game.Beatmaps var clock = new StopwatchClock(); mods.OfType().ForEach(m => m.ApplyToClock(clock)); + foreach (var mod in mods.OfType>()) + foreach (var obj in Objects) + mod.ApplyToHitObject(obj); + TimeRate = clock.Rate; } diff --git a/osu.Game/Rulesets/Mods/IApplicableMod.cs b/osu.Game/Rulesets/Mods/IApplicableMod.cs deleted file mode 100644 index 1957952720..0000000000 --- a/osu.Game/Rulesets/Mods/IApplicableMod.cs +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) 2007-2017 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using osu.Game.Rulesets.Objects; -using osu.Game.Rulesets.UI; - -namespace osu.Game.Rulesets.Mods -{ - /// - /// An interface for mods that are applied to a RulesetContainer. - /// - /// The type of HitObject the RulesetContainer contains. - public interface IApplicableMod - where TObject : HitObject - { - /// - /// Applies the mod to a RulesetContainer. - /// - /// The RulesetContainer to apply the mod to. - void ApplyToRulesetContainer(RulesetContainer rulesetContainer); - } -} diff --git a/osu.Game/Rulesets/Mods/IApplicableToHitObject.cs b/osu.Game/Rulesets/Mods/IApplicableToHitObject.cs new file mode 100644 index 0000000000..099234d9c1 --- /dev/null +++ b/osu.Game/Rulesets/Mods/IApplicableToHitObject.cs @@ -0,0 +1,20 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Game.Rulesets.Objects; + +namespace osu.Game.Rulesets.Mods +{ + /// + /// An interface for s that can be applied to s. + /// + public interface IApplicableToHitObject + where TObject : HitObject + { + /// + /// Applies this to a . + /// + /// The to apply to. + void ApplyToHitObject(TObject hitObject); + } +} diff --git a/osu.Game/Rulesets/Mods/IApplicableToRulesetContainer.cs b/osu.Game/Rulesets/Mods/IApplicableToRulesetContainer.cs new file mode 100644 index 0000000000..9b23dd58f9 --- /dev/null +++ b/osu.Game/Rulesets/Mods/IApplicableToRulesetContainer.cs @@ -0,0 +1,21 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.UI; + +namespace osu.Game.Rulesets.Mods +{ + /// + /// An interface for s that can be applied to s. + /// + public interface IApplicableToRulesetContainer + where TObject : HitObject + { + /// + /// Applies this to a . + /// + /// The to apply to. + void ApplyToRulesetContainer(RulesetContainer rulesetContainer); + } +} diff --git a/osu.Game/Rulesets/Mods/ModAutoplay.cs b/osu.Game/Rulesets/Mods/ModAutoplay.cs index ece0deba84..d94d4ba0db 100644 --- a/osu.Game/Rulesets/Mods/ModAutoplay.cs +++ b/osu.Game/Rulesets/Mods/ModAutoplay.cs @@ -10,7 +10,7 @@ using osu.Game.Rulesets.UI; namespace osu.Game.Rulesets.Mods { - public abstract class ModAutoplay : ModAutoplay, IApplicableMod + public abstract class ModAutoplay : ModAutoplay, IApplicableToRulesetContainer where T : HitObject { protected abstract Score CreateReplayScore(Beatmap beatmap); @@ -30,4 +30,4 @@ namespace osu.Game.Rulesets.Mods public override double ScoreMultiplier => 0; public override Type[] IncompatibleMods => new[] { typeof(ModRelax), typeof(ModSuddenDeath), typeof(ModNoFail) }; } -} \ No newline at end of file +} diff --git a/osu.Game/Rulesets/UI/RulesetContainer.cs b/osu.Game/Rulesets/UI/RulesetContainer.cs index 278814ea7e..6726d94995 100644 --- a/osu.Game/Rulesets/UI/RulesetContainer.cs +++ b/osu.Game/Rulesets/UI/RulesetContainer.cs @@ -212,7 +212,11 @@ namespace osu.Game.Rulesets.UI if (mods == null) return; - foreach (var mod in mods.OfType>()) + foreach (var mod in mods.OfType>()) + foreach (var obj in Beatmap.HitObjects) + mod.ApplyToHitObject(obj); + + foreach (var mod in mods.OfType>()) mod.ApplyToRulesetContainer(this); } diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index ac1498c9d9..7b479bdba2 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -549,9 +549,10 @@ - + + From 5781b45b3903393570025c567a7071446b08f9f5 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 16 Nov 2017 20:41:26 +0900 Subject: [PATCH 0661/1263] Set TimeRate after mod application --- osu.Game/Beatmaps/DifficultyCalculator.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game/Beatmaps/DifficultyCalculator.cs b/osu.Game/Beatmaps/DifficultyCalculator.cs index 54dab07b31..f101cfbfb8 100644 --- a/osu.Game/Beatmaps/DifficultyCalculator.cs +++ b/osu.Game/Beatmaps/DifficultyCalculator.cs @@ -48,12 +48,11 @@ namespace osu.Game.Beatmaps { var clock = new StopwatchClock(); mods.OfType().ForEach(m => m.ApplyToClock(clock)); + TimeRate = clock.Rate; foreach (var mod in mods.OfType>()) foreach (var obj in Objects) mod.ApplyToHitObject(obj); - - TimeRate = clock.Rate; } protected virtual void PreprocessHitObjects() From cc1720241e8d63fb3d9d56333eb348d89933eafb Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 17 Nov 2017 12:35:03 +0900 Subject: [PATCH 0662/1263] Fix DifficultyCalculator using incorrect mods --- osu.Game/Beatmaps/DifficultyCalculator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Beatmaps/DifficultyCalculator.cs b/osu.Game/Beatmaps/DifficultyCalculator.cs index f101cfbfb8..34c6bb95ff 100644 --- a/osu.Game/Beatmaps/DifficultyCalculator.cs +++ b/osu.Game/Beatmaps/DifficultyCalculator.cs @@ -39,7 +39,7 @@ namespace osu.Game.Beatmaps foreach (var h in Objects) h.ApplyDefaults(beatmap.ControlPointInfo, beatmap.BeatmapInfo.BaseDifficulty); - ApplyMods(mods); + ApplyMods(Mods); PreprocessHitObjects(); } From 7892eefd6899bf6c0a64d397f300d77bc3576e92 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 17 Nov 2017 14:23:52 +0900 Subject: [PATCH 0663/1263] Fix up mod application + beatmap/hitobject references --- .../OsuDifficulty/OsuDifficultyCalculator.cs | 13 ++++++++++--- osu.Game.Rulesets.Osu/OsuRuleset.cs | 2 +- .../TaikoDifficultyCalculator.cs | 2 +- osu.Game/Beatmaps/DifficultyCalculator.cs | 18 +++++++++--------- 4 files changed, 21 insertions(+), 14 deletions(-) diff --git a/osu.Game.Rulesets.Osu/OsuDifficulty/OsuDifficultyCalculator.cs b/osu.Game.Rulesets.Osu/OsuDifficulty/OsuDifficultyCalculator.cs index 6ed45e1f03..9f279ccae4 100644 --- a/osu.Game.Rulesets.Osu/OsuDifficulty/OsuDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Osu/OsuDifficulty/OsuDifficultyCalculator.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using osu.Game.Beatmaps; +using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu.Beatmaps; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.OsuDifficulty.Preprocessing; @@ -16,19 +17,25 @@ namespace osu.Game.Rulesets.Osu.OsuDifficulty private const int section_length = 400; private const double difficulty_multiplier = 0.0675; - public OsuDifficultyCalculator(Beatmap beatmap) : base(beatmap) + public OsuDifficultyCalculator(Beatmap beatmap) + : base(beatmap) + { + } + + public OsuDifficultyCalculator(Beatmap beatmap, Mod[] mods) + : base(beatmap, mods) { } protected override void PreprocessHitObjects() { - foreach (OsuHitObject h in Objects) + foreach (OsuHitObject h in Beatmap.HitObjects) (h as Slider)?.Curve?.Calculate(); } public override double Calculate(Dictionary categoryDifficulty) { - OsuDifficultyBeatmap beatmap = new OsuDifficultyBeatmap(Objects); + OsuDifficultyBeatmap beatmap = new OsuDifficultyBeatmap(Beatmap.HitObjects); Skill[] skills = { new Aim(), diff --git a/osu.Game.Rulesets.Osu/OsuRuleset.cs b/osu.Game.Rulesets.Osu/OsuRuleset.cs index a4828319d1..8b7a014ea8 100644 --- a/osu.Game.Rulesets.Osu/OsuRuleset.cs +++ b/osu.Game.Rulesets.Osu/OsuRuleset.cs @@ -113,7 +113,7 @@ namespace osu.Game.Rulesets.Osu public override Drawable CreateIcon() => new SpriteIcon { Icon = FontAwesome.fa_osu_osu_o }; - public override DifficultyCalculator CreateDifficultyCalculator(Beatmap beatmap, Mod[] mods = null) => new OsuDifficultyCalculator(beatmap); + public override DifficultyCalculator CreateDifficultyCalculator(Beatmap beatmap, Mod[] mods = null) => new OsuDifficultyCalculator(beatmap, mods); public override string Description => "osu!"; diff --git a/osu.Game.Rulesets.Taiko/TaikoDifficultyCalculator.cs b/osu.Game.Rulesets.Taiko/TaikoDifficultyCalculator.cs index 57986cd198..adb7ace5f9 100644 --- a/osu.Game.Rulesets.Taiko/TaikoDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Taiko/TaikoDifficultyCalculator.cs @@ -41,7 +41,7 @@ namespace osu.Game.Rulesets.Taiko // Fill our custom DifficultyHitObject class, that carries additional information difficultyHitObjects.Clear(); - foreach (var hitObject in Objects) + foreach (var hitObject in Beatmap.HitObjects) difficultyHitObjects.Add(new TaikoHitObjectDifficulty(hitObject)); // Sort DifficultyHitObjects by StartTime of the HitObjects - just to make sure. diff --git a/osu.Game/Beatmaps/DifficultyCalculator.cs b/osu.Game/Beatmaps/DifficultyCalculator.cs index 34c6bb95ff..3c32b718bc 100644 --- a/osu.Game/Beatmaps/DifficultyCalculator.cs +++ b/osu.Game/Beatmaps/DifficultyCalculator.cs @@ -19,11 +19,9 @@ namespace osu.Game.Beatmaps public abstract class DifficultyCalculator : DifficultyCalculator where T : HitObject { - protected readonly Beatmap Beatmap; + protected readonly Beatmap Beatmap; protected readonly Mod[] Mods; - protected List Objects; - protected DifficultyCalculator(Beatmap beatmap) : this(beatmap, null) { @@ -31,13 +29,9 @@ namespace osu.Game.Beatmaps protected DifficultyCalculator(Beatmap beatmap, Mod[] mods) { - Beatmap = beatmap; + Beatmap = CreateBeatmapConverter().Convert(beatmap); Mods = mods ?? new Mod[0]; - Objects = CreateBeatmapConverter().Convert(beatmap).HitObjects; - - foreach (var h in Objects) - h.ApplyDefaults(beatmap.ControlPointInfo, beatmap.BeatmapInfo.BaseDifficulty); ApplyMods(Mods); @@ -50,9 +44,15 @@ namespace osu.Game.Beatmaps mods.OfType().ForEach(m => m.ApplyToClock(clock)); TimeRate = clock.Rate; + foreach (var mod in Mods.OfType()) + mod.ApplyToDifficulty(Beatmap.BeatmapInfo.BaseDifficulty); + foreach (var mod in mods.OfType>()) - foreach (var obj in Objects) + foreach (var obj in Beatmap.HitObjects) mod.ApplyToHitObject(obj); + + foreach (var h in Beatmap.HitObjects) + h.ApplyDefaults(Beatmap.ControlPointInfo, Beatmap.BeatmapInfo.BaseDifficulty); } protected virtual void PreprocessHitObjects() From ac6213d1fadd8362580b482de0b1355981a25c8e Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 17 Nov 2017 14:26:33 +0900 Subject: [PATCH 0664/1263] CI fixes --- osu.Game.Rulesets.Catch/CatchDifficultyCalculator.cs | 2 +- osu.Game.Rulesets.Mania/ManiaDifficultyCalculator.cs | 2 +- osu.Game.Rulesets.Osu/Mods/OsuMod.cs | 1 - osu.Game.Rulesets.Osu/OsuDifficulty/OsuDifficultyCalculator.cs | 2 +- osu.Game.Rulesets.Osu/OsuRuleset.cs | 1 - osu.Game.Rulesets.Taiko/TaikoDifficultyCalculator.cs | 2 +- osu.Game/Beatmaps/DifficultyCalculator.cs | 2 +- osu.Game/Rulesets/Mods/IApplicableToHitObject.cs | 2 +- osu.Game/Rulesets/Ruleset.cs | 1 - 9 files changed, 6 insertions(+), 9 deletions(-) diff --git a/osu.Game.Rulesets.Catch/CatchDifficultyCalculator.cs b/osu.Game.Rulesets.Catch/CatchDifficultyCalculator.cs index 127fde74ef..db88e04dd0 100644 --- a/osu.Game.Rulesets.Catch/CatchDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Catch/CatchDifficultyCalculator.cs @@ -14,7 +14,7 @@ namespace osu.Game.Rulesets.Catch { } - public override double Calculate(Dictionary categoryDifficulty) => 0; + public override double Calculate(Dictionary categoryDifficulty = null) => 0; protected override BeatmapConverter CreateBeatmapConverter() => new CatchBeatmapConverter(); } diff --git a/osu.Game.Rulesets.Mania/ManiaDifficultyCalculator.cs b/osu.Game.Rulesets.Mania/ManiaDifficultyCalculator.cs index d5c6d21131..070fc2b4dd 100644 --- a/osu.Game.Rulesets.Mania/ManiaDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Mania/ManiaDifficultyCalculator.cs @@ -16,7 +16,7 @@ namespace osu.Game.Rulesets.Mania { } - public override double Calculate(Dictionary categoryDifficulty) => 0; + public override double Calculate(Dictionary categoryDifficulty = null) => 0; protected override BeatmapConverter CreateBeatmapConverter() => new ManiaBeatmapConverter(true, (int)Math.Max(1, Math.Round(Beatmap.BeatmapInfo.BaseDifficulty.CircleSize))); } diff --git a/osu.Game.Rulesets.Osu/Mods/OsuMod.cs b/osu.Game.Rulesets.Osu/Mods/OsuMod.cs index 596fe27504..71349285b3 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuMod.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuMod.cs @@ -9,7 +9,6 @@ using osu.Game.Rulesets.Osu.Objects; using System; using System.Collections.Generic; using System.Linq; -using osu.Framework.Extensions.IEnumerableExtensions; using osu.Game.Rulesets.Osu.UI; using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.UI; diff --git a/osu.Game.Rulesets.Osu/OsuDifficulty/OsuDifficultyCalculator.cs b/osu.Game.Rulesets.Osu/OsuDifficulty/OsuDifficultyCalculator.cs index 9f279ccae4..f7909f8335 100644 --- a/osu.Game.Rulesets.Osu/OsuDifficulty/OsuDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Osu/OsuDifficulty/OsuDifficultyCalculator.cs @@ -33,7 +33,7 @@ namespace osu.Game.Rulesets.Osu.OsuDifficulty (h as Slider)?.Curve?.Calculate(); } - public override double Calculate(Dictionary categoryDifficulty) + public override double Calculate(Dictionary categoryDifficulty = null) { OsuDifficultyBeatmap beatmap = new OsuDifficultyBeatmap(Beatmap.HitObjects); Skill[] skills = diff --git a/osu.Game.Rulesets.Osu/OsuRuleset.cs b/osu.Game.Rulesets.Osu/OsuRuleset.cs index 8b7a014ea8..9c11474f97 100644 --- a/osu.Game.Rulesets.Osu/OsuRuleset.cs +++ b/osu.Game.Rulesets.Osu/OsuRuleset.cs @@ -14,7 +14,6 @@ using System.Linq; using osu.Framework.Graphics; using osu.Game.Overlays.Settings; using osu.Framework.Input.Bindings; -using osu.Game.Rulesets.Scoring; namespace osu.Game.Rulesets.Osu { diff --git a/osu.Game.Rulesets.Taiko/TaikoDifficultyCalculator.cs b/osu.Game.Rulesets.Taiko/TaikoDifficultyCalculator.cs index adb7ace5f9..e06582500f 100644 --- a/osu.Game.Rulesets.Taiko/TaikoDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Taiko/TaikoDifficultyCalculator.cs @@ -36,7 +36,7 @@ namespace osu.Game.Rulesets.Taiko { } - public override double Calculate(Dictionary categoryDifficulty) + public override double Calculate(Dictionary categoryDifficulty = null) { // Fill our custom DifficultyHitObject class, that carries additional information difficultyHitObjects.Clear(); diff --git a/osu.Game/Beatmaps/DifficultyCalculator.cs b/osu.Game/Beatmaps/DifficultyCalculator.cs index 3c32b718bc..351154623e 100644 --- a/osu.Game/Beatmaps/DifficultyCalculator.cs +++ b/osu.Game/Beatmaps/DifficultyCalculator.cs @@ -27,7 +27,7 @@ namespace osu.Game.Beatmaps { } - protected DifficultyCalculator(Beatmap beatmap, Mod[] mods) + protected DifficultyCalculator(Beatmap beatmap, Mod[] mods = null) { Beatmap = CreateBeatmapConverter().Convert(beatmap); Mods = mods ?? new Mod[0]; diff --git a/osu.Game/Rulesets/Mods/IApplicableToHitObject.cs b/osu.Game/Rulesets/Mods/IApplicableToHitObject.cs index 099234d9c1..7f39def343 100644 --- a/osu.Game/Rulesets/Mods/IApplicableToHitObject.cs +++ b/osu.Game/Rulesets/Mods/IApplicableToHitObject.cs @@ -8,7 +8,7 @@ namespace osu.Game.Rulesets.Mods /// /// An interface for s that can be applied to s. /// - public interface IApplicableToHitObject + public interface IApplicableToHitObject where TObject : HitObject { /// diff --git a/osu.Game/Rulesets/Ruleset.cs b/osu.Game/Rulesets/Ruleset.cs index e8919c4bda..ed2fdf4157 100644 --- a/osu.Game/Rulesets/Ruleset.cs +++ b/osu.Game/Rulesets/Ruleset.cs @@ -10,7 +10,6 @@ using osu.Game.Beatmaps; using osu.Game.Graphics; using osu.Game.Overlays.Settings; using osu.Game.Rulesets.Mods; -using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.UI; namespace osu.Game.Rulesets From 95fd323c6b122cd768a31a889eaa464319390212 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 17 Nov 2017 14:37:06 +0900 Subject: [PATCH 0665/1263] Fix ManiaDifficultyCalculator possibly failing due to nullref --- osu.Game.Rulesets.Catch/CatchDifficultyCalculator.cs | 2 +- osu.Game.Rulesets.Mania/ManiaDifficultyCalculator.cs | 2 +- .../OsuDifficulty/OsuDifficultyCalculator.cs | 2 +- osu.Game.Rulesets.Taiko/TaikoDifficultyCalculator.cs | 2 +- osu.Game/Beatmaps/DifficultyCalculator.cs | 9 ++------- 5 files changed, 6 insertions(+), 11 deletions(-) diff --git a/osu.Game.Rulesets.Catch/CatchDifficultyCalculator.cs b/osu.Game.Rulesets.Catch/CatchDifficultyCalculator.cs index db88e04dd0..b77be9d1f0 100644 --- a/osu.Game.Rulesets.Catch/CatchDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Catch/CatchDifficultyCalculator.cs @@ -16,6 +16,6 @@ namespace osu.Game.Rulesets.Catch public override double Calculate(Dictionary categoryDifficulty = null) => 0; - protected override BeatmapConverter CreateBeatmapConverter() => new CatchBeatmapConverter(); + protected override BeatmapConverter CreateBeatmapConverter(Beatmap beatmap) => new CatchBeatmapConverter(); } } diff --git a/osu.Game.Rulesets.Mania/ManiaDifficultyCalculator.cs b/osu.Game.Rulesets.Mania/ManiaDifficultyCalculator.cs index 070fc2b4dd..67bc347535 100644 --- a/osu.Game.Rulesets.Mania/ManiaDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Mania/ManiaDifficultyCalculator.cs @@ -18,6 +18,6 @@ namespace osu.Game.Rulesets.Mania public override double Calculate(Dictionary categoryDifficulty = null) => 0; - protected override BeatmapConverter CreateBeatmapConverter() => new ManiaBeatmapConverter(true, (int)Math.Max(1, Math.Round(Beatmap.BeatmapInfo.BaseDifficulty.CircleSize))); + protected override BeatmapConverter CreateBeatmapConverter(Beatmap beatmap) => new ManiaBeatmapConverter(true, (int)Math.Max(1, Math.Round(beatmap.BeatmapInfo.BaseDifficulty.CircleSize))); } } diff --git a/osu.Game.Rulesets.Osu/OsuDifficulty/OsuDifficultyCalculator.cs b/osu.Game.Rulesets.Osu/OsuDifficulty/OsuDifficultyCalculator.cs index f7909f8335..537874f643 100644 --- a/osu.Game.Rulesets.Osu/OsuDifficulty/OsuDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Osu/OsuDifficulty/OsuDifficultyCalculator.cs @@ -74,6 +74,6 @@ namespace osu.Game.Rulesets.Osu.OsuDifficulty return starRating; } - protected override BeatmapConverter CreateBeatmapConverter() => new OsuBeatmapConverter(); + protected override BeatmapConverter CreateBeatmapConverter(Beatmap beatmap) => new OsuBeatmapConverter(); } } diff --git a/osu.Game.Rulesets.Taiko/TaikoDifficultyCalculator.cs b/osu.Game.Rulesets.Taiko/TaikoDifficultyCalculator.cs index e06582500f..e881942fbf 100644 --- a/osu.Game.Rulesets.Taiko/TaikoDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Taiko/TaikoDifficultyCalculator.cs @@ -134,6 +134,6 @@ namespace osu.Game.Rulesets.Taiko return difficulty; } - protected override BeatmapConverter CreateBeatmapConverter() => new TaikoBeatmapConverter(true); + protected override BeatmapConverter CreateBeatmapConverter(Beatmap beatmap) => new TaikoBeatmapConverter(true); } } diff --git a/osu.Game/Beatmaps/DifficultyCalculator.cs b/osu.Game/Beatmaps/DifficultyCalculator.cs index 351154623e..f58f433cb2 100644 --- a/osu.Game/Beatmaps/DifficultyCalculator.cs +++ b/osu.Game/Beatmaps/DifficultyCalculator.cs @@ -22,14 +22,9 @@ namespace osu.Game.Beatmaps protected readonly Beatmap Beatmap; protected readonly Mod[] Mods; - protected DifficultyCalculator(Beatmap beatmap) - : this(beatmap, null) - { - } - protected DifficultyCalculator(Beatmap beatmap, Mod[] mods = null) { - Beatmap = CreateBeatmapConverter().Convert(beatmap); + Beatmap = CreateBeatmapConverter(beatmap).Convert(beatmap); Mods = mods ?? new Mod[0]; @@ -59,6 +54,6 @@ namespace osu.Game.Beatmaps { } - protected abstract BeatmapConverter CreateBeatmapConverter(); + protected abstract BeatmapConverter CreateBeatmapConverter(Beatmap beatmap); } } From 38fe95d94aa1d27f12a12c5f46de7cfb72ccfcfe Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 16 Nov 2017 17:35:10 +0900 Subject: [PATCH 0666/1263] Add basic display for pp in TestCasePerformancePoints --- .../Tests/TestCasePerformancePoints.cs | 13 ++ .../osu.Game.Rulesets.Catch.csproj | 1 + .../Tests/TestCasePerformancePoints.cs | 13 ++ .../osu.Game.Rulesets.Mania.csproj | 1 + .../Tests/TestCasePerformancePoints.cs | 13 ++ .../osu.Game.Rulesets.Osu.csproj | 1 + .../Tests/TestCasePerformancePoints.cs | 13 ++ .../osu.Game.Rulesets.Taiko.csproj | 1 + .../Tests/Visual/TestCasePerformancePoints.cs | 214 ++++++++++++++++++ osu.Game/osu.Game.csproj | 1 + 10 files changed, 271 insertions(+) create mode 100644 osu.Game.Rulesets.Catch/Tests/TestCasePerformancePoints.cs create mode 100644 osu.Game.Rulesets.Mania/Tests/TestCasePerformancePoints.cs create mode 100644 osu.Game.Rulesets.Osu/Tests/TestCasePerformancePoints.cs create mode 100644 osu.Game.Rulesets.Taiko/Tests/TestCasePerformancePoints.cs create mode 100644 osu.Game/Tests/Visual/TestCasePerformancePoints.cs diff --git a/osu.Game.Rulesets.Catch/Tests/TestCasePerformancePoints.cs b/osu.Game.Rulesets.Catch/Tests/TestCasePerformancePoints.cs new file mode 100644 index 0000000000..071367b305 --- /dev/null +++ b/osu.Game.Rulesets.Catch/Tests/TestCasePerformancePoints.cs @@ -0,0 +1,13 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +namespace osu.Game.Rulesets.Catch.Tests +{ + public class TestCasePerformancePoints : osu.Game.Tests.Visual.TestCasePerformancePoints + { + public TestCasePerformancePoints() + : base(new CatchRuleset(new RulesetInfo())) + { + } + } +} diff --git a/osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj b/osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj index a666984b95..6822643fb5 100644 --- a/osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj +++ b/osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj @@ -65,6 +65,7 @@ + diff --git a/osu.Game.Rulesets.Mania/Tests/TestCasePerformancePoints.cs b/osu.Game.Rulesets.Mania/Tests/TestCasePerformancePoints.cs new file mode 100644 index 0000000000..420465c045 --- /dev/null +++ b/osu.Game.Rulesets.Mania/Tests/TestCasePerformancePoints.cs @@ -0,0 +1,13 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +namespace osu.Game.Rulesets.Mania.Tests +{ + public class TestCasePerformancePoints : osu.Game.Tests.Visual.TestCasePerformancePoints + { + public TestCasePerformancePoints() + : base(new ManiaRuleset(new RulesetInfo())) + { + } + } +} diff --git a/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj b/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj index 6f45a64d92..7c97ff05a7 100644 --- a/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj +++ b/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj @@ -82,6 +82,7 @@ + diff --git a/osu.Game.Rulesets.Osu/Tests/TestCasePerformancePoints.cs b/osu.Game.Rulesets.Osu/Tests/TestCasePerformancePoints.cs new file mode 100644 index 0000000000..b430803907 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Tests/TestCasePerformancePoints.cs @@ -0,0 +1,13 @@ +// 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.Tests +{ + public class TestCasePerformancePoints : osu.Game.Tests.Visual.TestCasePerformancePoints + { + public TestCasePerformancePoints() + : base(new OsuRuleset(new RulesetInfo())) + { + } + } +} diff --git a/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj b/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj index 3c90749777..97ddf7d46f 100644 --- a/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj +++ b/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj @@ -85,6 +85,7 @@ + diff --git a/osu.Game.Rulesets.Taiko/Tests/TestCasePerformancePoints.cs b/osu.Game.Rulesets.Taiko/Tests/TestCasePerformancePoints.cs new file mode 100644 index 0000000000..a60c79fc6a --- /dev/null +++ b/osu.Game.Rulesets.Taiko/Tests/TestCasePerformancePoints.cs @@ -0,0 +1,13 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +namespace osu.Game.Rulesets.Taiko.Tests +{ + public class TestCasePerformancePoints : osu.Game.Tests.Visual.TestCasePerformancePoints + { + public TestCasePerformancePoints() + : base(new TaikoRuleset(new RulesetInfo())) + { + } + } +} diff --git a/osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj b/osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj index bf627d205a..0b4e6e43f2 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 @@ + diff --git a/osu.Game/Tests/Visual/TestCasePerformancePoints.cs b/osu.Game/Tests/Visual/TestCasePerformancePoints.cs new file mode 100644 index 0000000000..d3a6071fb8 --- /dev/null +++ b/osu.Game/Tests/Visual/TestCasePerformancePoints.cs @@ -0,0 +1,214 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System.Collections.Generic; +using System.Linq; +using OpenTK; +using OpenTK.Graphics; +using osu.Framework.Allocation; +using osu.Framework.Extensions.IEnumerableExtensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Input; +using osu.Game.Beatmaps; +using osu.Game.Graphics.Sprites; +using osu.Game.Overlays; +using osu.Game.Overlays.Music; +using osu.Game.Rulesets; + +namespace osu.Game.Tests.Visual +{ + public abstract class TestCasePerformancePoints : OsuTestCase + { + public TestCasePerformancePoints(Ruleset ruleset) + { + Children = new Drawable[] + { + new Container + { + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + RelativeSizeAxes = Axes.Y, + Width = 300, + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Black, + Alpha = 0.5f, + }, + new ScrollContainer(Direction.Vertical) + { + RelativeSizeAxes = Axes.Both, + Child = new BeatmapList(ruleset) + } + } + }, + new PpDisplay(ruleset) + }; + } + + private class BeatmapList : CompositeDrawable + { + private readonly Container beatmapDisplays; + private readonly Ruleset ruleset; + + public BeatmapList(Ruleset ruleset) + { + this.ruleset = ruleset; + + RelativeSizeAxes = Axes.X; + AutoSizeAxes = Axes.Y; + InternalChild = beatmapDisplays = new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical, + Spacing = new Vector2(0, 4) + }; + } + + [BackgroundDependencyLoader] + private void load(OsuGameBase osuGame, BeatmapManager beatmaps) + { + var sets = beatmaps.GetAllUsableBeatmapSets(); + var allBeatmaps = sets.SelectMany(s => s.Beatmaps).Where(b => ruleset.LegacyID < 0 || b.RulesetID == ruleset.LegacyID); + + allBeatmaps.ForEach(b => beatmapDisplays.Add(new BeatmapDisplay(b))); + } + + private class BeatmapDisplay : CompositeDrawable + { + private readonly OsuSpriteText text; + private readonly BeatmapInfo beatmap; + + private BeatmapManager beatmaps; + private OsuGameBase osuGame; + + private bool isSelected; + + public BeatmapDisplay(BeatmapInfo beatmap) + { + this.beatmap = beatmap; + + AutoSizeAxes = Axes.Both; + InternalChild = text = new OsuSpriteText(); + } + + protected override bool OnClick(InputState state) + { + if (osuGame.Beatmap.Value.BeatmapInfo.ID == beatmap.ID) + return false; + + osuGame.Beatmap.Value = beatmaps.GetWorkingBeatmap(beatmap); + isSelected = true; + return true; + } + + protected override bool OnHover(InputState state) + { + if (isSelected) + return false; + this.FadeColour(Color4.Yellow, 100); + return true; + } + + protected override void OnHoverLost(InputState state) + { + if (isSelected) + return; + this.FadeColour(Color4.White, 100); + } + + [BackgroundDependencyLoader] + private void load(OsuGameBase osuGame, BeatmapManager beatmaps) + { + this.osuGame = osuGame; + this.beatmaps = beatmaps; + + var working = beatmaps.GetWorkingBeatmap(beatmap); + text.Text = $"{beatmap.Metadata.Artist} - {beatmap.Metadata.Title} ({beatmap.Metadata.AuthorString}) [{beatmap.Version}]"; + + osuGame.Beatmap.ValueChanged += beatmapChanged; + } + + private void beatmapChanged(WorkingBeatmap newBeatmap) + { + if (isSelected) + this.FadeColour(Color4.White, 100); + isSelected = false; + } + } + } + + private class PpDisplay : CompositeDrawable + { + private readonly Container strainsContainer; + private readonly OsuSpriteText totalPp; + + private readonly Ruleset ruleset; + + public PpDisplay(Ruleset ruleset) + { + this.ruleset = ruleset; + + RelativeSizeAxes = Axes.Y; + Width = 400; + + InternalChildren = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Black, + Alpha = 0.2f + }, + totalPp = new OsuSpriteText { TextSize = 18 }, + new Container + { + AutoSizeAxes = Axes.Both, + Y = 26, + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Black, + Alpha = 0.2f, + }, + strainsContainer = new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Vertical, + Spacing = new Vector2(0, 5) + } + } + } + }; + } + + [BackgroundDependencyLoader] + private void load(OsuGameBase osuGame) + { + osuGame.Beatmap.ValueChanged += beatmapChanged; + } + + private void beatmapChanged(WorkingBeatmap beatmap) + { + var diffCalculator = ruleset.CreateDifficultyCalculator(beatmap.Beatmap); + + var strains = new Dictionary(); + double pp = diffCalculator.Calculate(strains); + + totalPp.Text = $"Total PP: {pp.ToString("n2")}"; + + strainsContainer.Clear(); + foreach (var kvp in strains) + strainsContainer.Add(new OsuSpriteText { Text = $"{kvp.Key} : {kvp.Value}" }); + } + } + } +} diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 7b479bdba2..8f0ce14305 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -775,6 +775,7 @@ + From 1e023f04195009f0551d19d43f0ccdb68a3350dc Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 17 Nov 2017 12:35:23 +0900 Subject: [PATCH 0667/1263] Implement PerformanceCalculator testcase --- osu.Game.Rulesets.Osu/OsuRuleset.cs | 3 + .../Scoring/OsuPerformanceCalculator.cs | 189 ++++++++++++++++++ .../osu.Game.Rulesets.Osu.csproj | 1 + osu.Game/Rulesets/Ruleset.cs | 2 + .../Rulesets/Scoring/PerformanceCalculator.cs | 35 ++++ .../Tests/Visual/TestCasePerformancePoints.cs | 172 +++++++++------- osu.Game/osu.Game.csproj | 1 + 7 files changed, 336 insertions(+), 67 deletions(-) create mode 100644 osu.Game.Rulesets.Osu/Scoring/OsuPerformanceCalculator.cs create mode 100644 osu.Game/Rulesets/Scoring/PerformanceCalculator.cs diff --git a/osu.Game.Rulesets.Osu/OsuRuleset.cs b/osu.Game.Rulesets.Osu/OsuRuleset.cs index 9c11474f97..4a0a5ce0c9 100644 --- a/osu.Game.Rulesets.Osu/OsuRuleset.cs +++ b/osu.Game.Rulesets.Osu/OsuRuleset.cs @@ -14,6 +14,7 @@ using System.Linq; using osu.Framework.Graphics; using osu.Game.Overlays.Settings; using osu.Framework.Input.Bindings; +using osu.Game.Rulesets.Scoring; namespace osu.Game.Rulesets.Osu { @@ -114,6 +115,8 @@ namespace osu.Game.Rulesets.Osu public override DifficultyCalculator CreateDifficultyCalculator(Beatmap beatmap, Mod[] mods = null) => new OsuDifficultyCalculator(beatmap, mods); + public override PerformanceCalculator CreatePerformanceCalculator(Beatmap beatmap, Score score) => new OsuPerformanceCalculator(this, beatmap, score); + public override string Description => "osu!"; public override SettingsSubsection CreateSettings() => new OsuSettings(); diff --git a/osu.Game.Rulesets.Osu/Scoring/OsuPerformanceCalculator.cs b/osu.Game.Rulesets.Osu/Scoring/OsuPerformanceCalculator.cs new file mode 100644 index 0000000000..32469b1bf7 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Scoring/OsuPerformanceCalculator.cs @@ -0,0 +1,189 @@ +// 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.Extensions.IEnumerableExtensions; +using osu.Game.Beatmaps; +using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Osu.Beatmaps; +using osu.Game.Rulesets.Osu.Mods; +using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Rulesets.Scoring; + +namespace osu.Game.Rulesets.Osu.Scoring +{ + public class OsuPerformanceCalculator : PerformanceCalculator + { + private readonly int countHitCircles; + private readonly int beatmapMaxCombo; + + private Mod[] mods; + private double accuracy; + private int scoreMaxCombo; + private int count300; + private int count100; + private int count50; + private int countMiss; + + public OsuPerformanceCalculator(Ruleset ruleset, Beatmap beatmap, Score score) + : base(ruleset, beatmap, score) + { + countHitCircles = Beatmap.HitObjects.Count(h => h is HitCircle); + + beatmapMaxCombo = Beatmap.HitObjects.Count(); + beatmapMaxCombo += Beatmap.HitObjects.OfType().Sum(s => s.RepeatCount + s.Ticks.Count()); + } + + public override double Calculate(Dictionary categoryRatings = null) + { + mods = Score.Mods; + accuracy = Score.Accuracy; + scoreMaxCombo = Score.MaxCombo; + count300 = Convert.ToInt32(Score.Statistics["300"]); + count100 = Convert.ToInt32(Score.Statistics["100"]); + count50 = Convert.ToInt32(Score.Statistics["50"]); + countMiss = Convert.ToInt32(Score.Statistics["x"]); + + // Don't count scores made with supposedly unranked mods + if (mods.Any(m => m is OsuModRelax || m is OsuModAutopilot || m is OsuModAutoplay)) + return 0; + + // Custom multipliers for NoFail and SpunOut. + double multiplier = 1.12f; // This is being adjusted to keep the final pp value scaled around what it used to be when changing things + + if (mods.Any(m => m is OsuModNoFail)) + multiplier *= 0.90f; + + if (mods.Any(m => m is OsuModSpunOut)) + multiplier *= 0.95f; + + double aimValue = computeAimValue(); + double speedValue = computeSpeedValue(); + double accuracyValue = computeAccuracyValue(); + double totalValue = + Math.Pow( + Math.Pow(aimValue, 1.1f) + + Math.Pow(speedValue, 1.1f) + + Math.Pow(accuracyValue, 1.1f), 1.0f / 1.1f + ) * multiplier; + + if (categoryRatings != null) + { + categoryRatings.Add("Aim", aimValue.ToString("0.00")); + categoryRatings.Add("Speed", speedValue.ToString("0.00")); + categoryRatings.Add("Accuracy", accuracyValue.ToString("0.00")); + } + + return totalValue; + } + + private double computeAimValue() + { + double aimValue = Math.Pow(5.0f * Math.Max(1.0f, double.Parse(Attributes["Aim"]) / 0.0675f) - 4.0f, 3.0f) / 100000.0f; + + // Longer maps are worth more + double LengthBonus = 0.95f + 0.4f * Math.Min(1.0f, totalHits / 2000.0f) + + (totalHits > 2000 ? Math.Log10(totalHits / 2000.0f) * 0.5f : 0.0f); + + aimValue *= LengthBonus; + + // Penalize misses exponentially. This mainly fixes tag4 maps and the likes until a per-hitobject solution is available + aimValue *= Math.Pow(0.97f, countMiss); + + // Combo scaling + if (beatmapMaxCombo > 0) + aimValue *= Math.Min(Math.Pow(scoreMaxCombo, 0.8f) / Math.Pow(beatmapMaxCombo, 0.8f), 1.0f); + + double approachRate = Beatmap.BeatmapInfo.BaseDifficulty.ApproachRate; + double approachRateFactor = 1.0f; + if (approachRate > 10.33f) + approachRateFactor += 0.45f * (approachRate - 10.33f); + else if (approachRate < 8.0f) + { + // HD is worth more with lower ar! + if (mods.Any(h => h is OsuModHidden)) + approachRateFactor += 0.02f * (8.0f - approachRate); + else + approachRateFactor += 0.01f * (8.0f - approachRate); + } + + aimValue *= approachRateFactor; + + if (mods.Any(h => h is OsuModHidden)) + aimValue *= 1.18f; + + if (mods.Any(h => h is OsuModFlashlight)) + { + // Apply length bonus again if flashlight is on simply because it becomes a lot harder on longer maps. + aimValue *= 1.45f * LengthBonus; + } + + // Scale the aim value with accuracy _slightly_ + aimValue *= 0.5f + accuracy / 2.0f; + // It is important to also consider accuracy difficulty when doing that + aimValue *= 0.98f + (Math.Pow(Beatmap.BeatmapInfo.BaseDifficulty.OverallDifficulty, 2) / 2500); + + return aimValue; + } + + private double computeSpeedValue() + { + double speedValue = Math.Pow(5.0f * Math.Max(1.0f, double.Parse(Attributes["Speed"]) / 0.0675f) - 4.0f, 3.0f) / 100000.0f; + + // Longer maps are worth more + speedValue *= 0.95f + 0.4f * Math.Min(1.0f, totalHits / 2000.0f) + + (totalHits > 2000 ? Math.Log10(totalHits / 2000.0f) * 0.5f : 0.0f); + + // Penalize misses exponentially. This mainly fixes tag4 maps and the likes until a per-hitobject solution is available + speedValue *= Math.Pow(0.97f, countMiss); + + // Combo scaling + if (beatmapMaxCombo > 0) + speedValue *= Math.Min(Math.Pow(scoreMaxCombo, 0.8f) / Math.Pow(beatmapMaxCombo, 0.8f), 1.0f); + + // Scale the speed value with accuracy _slightly_ + speedValue *= 0.5f + accuracy / 2.0f; + // It is important to also consider accuracy difficulty when doing that + speedValue *= 0.98f + (Math.Pow(Beatmap.BeatmapInfo.BaseDifficulty.OverallDifficulty, 2) / 2500); + + return speedValue; + } + + private double computeAccuracyValue() + { + // This percentage only considers HitCircles of any value - in this part of the calculation we focus on hitting the timing hit window + double betterAccuracyPercentage = 0; + int amountHitObjectsWithAccuracy = countHitCircles; + + if (amountHitObjectsWithAccuracy > 0) + betterAccuracyPercentage = ((count300 - (totalHits - amountHitObjectsWithAccuracy)) * 6 + count100 * 2 + count50) / (amountHitObjectsWithAccuracy * 6); + else + betterAccuracyPercentage = 0; + + // It is possible to reach a negative accuracy with this formula. Cap it at zero - zero points + if (betterAccuracyPercentage < 0) + betterAccuracyPercentage = 0; + + // Lots of arbitrary values from testing. + // Considering to use derivation from perfect accuracy in a probabilistic manner - assume normal distribution + double accuracyValue = Math.Pow(1.52163f, Beatmap.BeatmapInfo.BaseDifficulty.OverallDifficulty) * Math.Pow(betterAccuracyPercentage, 24) * 2.83f; + + // Bonus for many hitcircles - it's harder to keep good accuracy up for longer + accuracyValue *= Math.Min(1.15f, Math.Pow(amountHitObjectsWithAccuracy / 1000.0f, 0.3f)); + + if (mods.Any(m => m is OsuModHidden)) + accuracyValue *= 1.02f; + if (mods.Any(m => m is OsuModFlashlight)) + accuracyValue *= 1.02f; + + return accuracyValue; + } + + private double totalHits => count300 + count100 + count50 + countMiss; + private double totalSuccessfulHits => count300 + count100 + count50; + + protected override BeatmapConverter CreateBeatmapConverter() => new OsuBeatmapConverter(); + } +} diff --git a/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj b/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj index 97ddf7d46f..2be057de40 100644 --- a/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj +++ b/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj @@ -89,6 +89,7 @@ + diff --git a/osu.Game/Rulesets/Ruleset.cs b/osu.Game/Rulesets/Ruleset.cs index ed2fdf4157..226a897126 100644 --- a/osu.Game/Rulesets/Ruleset.cs +++ b/osu.Game/Rulesets/Ruleset.cs @@ -49,6 +49,8 @@ namespace osu.Game.Rulesets public abstract DifficultyCalculator CreateDifficultyCalculator(Beatmap beatmap, Mod[] mods = null); + public virtual PerformanceCalculator CreatePerformanceCalculator(Beatmap beatmap, Score score) => null; + public virtual Drawable CreateIcon() => new SpriteIcon { Icon = FontAwesome.fa_question_circle }; public abstract string Description { get; } diff --git a/osu.Game/Rulesets/Scoring/PerformanceCalculator.cs b/osu.Game/Rulesets/Scoring/PerformanceCalculator.cs new file mode 100644 index 0000000000..49b7ac54c6 --- /dev/null +++ b/osu.Game/Rulesets/Scoring/PerformanceCalculator.cs @@ -0,0 +1,35 @@ +// 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.Objects; + +namespace osu.Game.Rulesets.Scoring +{ + public abstract class PerformanceCalculator + { + public abstract double Calculate(Dictionary categoryDifficulty = null); + } + + public abstract class PerformanceCalculator : PerformanceCalculator + where TObject : HitObject + { + private readonly Dictionary attributes = new Dictionary(); + protected IDictionary Attributes => attributes; + + protected readonly Beatmap Beatmap; + protected readonly Score Score; + + public PerformanceCalculator(Ruleset ruleset, Beatmap beatmap, Score score) + { + Beatmap = CreateBeatmapConverter().Convert(beatmap); + Score = score; + + var diffCalc = ruleset.CreateDifficultyCalculator(beatmap); + diffCalc.Calculate(attributes); + } + + protected abstract BeatmapConverter CreateBeatmapConverter(); + } +} diff --git a/osu.Game/Tests/Visual/TestCasePerformancePoints.cs b/osu.Game/Tests/Visual/TestCasePerformancePoints.cs index d3a6071fb8..7e8b9de954 100644 --- a/osu.Game/Tests/Visual/TestCasePerformancePoints.cs +++ b/osu.Game/Tests/Visual/TestCasePerformancePoints.cs @@ -14,9 +14,12 @@ using osu.Framework.Graphics.Sprites; using osu.Framework.Input; using osu.Game.Beatmaps; using osu.Game.Graphics.Sprites; +using osu.Game.Online.API; +using osu.Game.Online.API.Requests; using osu.Game.Overlays; using osu.Game.Overlays.Music; using osu.Game.Rulesets; +using osu.Game.Rulesets.Scoring; namespace osu.Game.Tests.Visual { @@ -24,30 +27,51 @@ namespace osu.Game.Tests.Visual { public TestCasePerformancePoints(Ruleset ruleset) { - Children = new Drawable[] + Child = new FillFlowContainer { - new Container + RelativeSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Children = new Drawable[] { - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, - RelativeSizeAxes = Axes.Y, - Width = 300, - Children = new Drawable[] + new Container { - new Box + RelativeSizeAxes = Axes.Both, + Width = 0.25f, + Children = new Drawable[] { - RelativeSizeAxes = Axes.Both, - Colour = Color4.Black, - Alpha = 0.5f, - }, - new ScrollContainer(Direction.Vertical) - { - RelativeSizeAxes = Axes.Both, - Child = new BeatmapList(ruleset) + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Black, + Alpha = 0.5f, + }, + new ScrollContainer(Direction.Vertical) + { + RelativeSizeAxes = Axes.Both, + Child = new BeatmapList(ruleset) + } } - } - }, - new PpDisplay(ruleset) + }, + new Container + { + RelativeSizeAxes = Axes.Both, + Width = 0.75f, + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Black, + Alpha = 0.5f, + }, + new ScrollContainer(Direction.Vertical) + { + RelativeSizeAxes = Axes.Both, + Child = new ScoreList { RelativeSizeAxes = Axes.Both } + } + } + }, + } }; } @@ -144,70 +168,84 @@ namespace osu.Game.Tests.Visual } } - private class PpDisplay : CompositeDrawable + private class ScoreList : CompositeDrawable { - private readonly Container strainsContainer; - private readonly OsuSpriteText totalPp; + private readonly FillFlowContainer scores; + private APIAccess api; - private readonly Ruleset ruleset; - - public PpDisplay(Ruleset ruleset) + public ScoreList() { - this.ruleset = ruleset; - - RelativeSizeAxes = Axes.Y; - Width = 400; - - InternalChildren = new Drawable[] + InternalChild = scores = new FillFlowContainer { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = Color4.Black, - Alpha = 0.2f - }, - totalPp = new OsuSpriteText { TextSize = 18 }, - new Container - { - AutoSizeAxes = Axes.Both, - Y = 26, - Children = new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = Color4.Black, - Alpha = 0.2f, - }, - strainsContainer = new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Vertical, - Spacing = new Vector2(0, 5) - } - } - } + RelativeSizeAxes = Axes.Both, + Direction = FillDirection.Vertical, + Spacing = new Vector2(0, 4) }; } [BackgroundDependencyLoader] - private void load(OsuGameBase osuGame) + private void load(OsuGameBase osuGame, APIAccess api) { + this.api = api; osuGame.Beatmap.ValueChanged += beatmapChanged; } - private void beatmapChanged(WorkingBeatmap beatmap) + private GetScoresRequest lastRequest; + private void beatmapChanged(WorkingBeatmap newBeatmap) { - var diffCalculator = ruleset.CreateDifficultyCalculator(beatmap.Beatmap); + lastRequest?.Cancel(); + scores.Clear(); - var strains = new Dictionary(); - double pp = diffCalculator.Calculate(strains); + lastRequest = new GetScoresRequest(newBeatmap.BeatmapInfo); + lastRequest.Success += res => res.Scores.ForEach(s => scores.Add(new ScoreDisplay(s, newBeatmap.Beatmap))); + api.Queue(lastRequest); + } - totalPp.Text = $"Total PP: {pp.ToString("n2")}"; + private class ScoreDisplay : CompositeDrawable + { + private readonly OsuSpriteText playerName; + private readonly GridContainer attributeGrid; - strainsContainer.Clear(); - foreach (var kvp in strains) - strainsContainer.Add(new OsuSpriteText { Text = $"{kvp.Key} : {kvp.Value}" }); + private readonly Score score; + private readonly Beatmap beatmap; + + public ScoreDisplay(Score score, Beatmap beatmap) + { + this.score = score; + this.beatmap = beatmap; + + RelativeSizeAxes = Axes.X; + Height = 16; + InternalChild = new GridContainer + { + RelativeSizeAxes = Axes.Both, + Content = new[] + { + new Drawable[] { playerName = new OsuSpriteText() }, + new Drawable[] { attributeGrid = new GridContainer { RelativeSizeAxes = Axes.Both } } + }, + RowDimensions = new[] + { + new Dimension(GridSizeMode.Relative, 0.75f), + new Dimension(GridSizeMode.Relative, 0.25f) + } + }; + } + + [BackgroundDependencyLoader] + private void load() + { + var ruleset = beatmap.BeatmapInfo.Ruleset.CreateInstance(); + var calculator = ruleset.CreatePerformanceCalculator(beatmap, score); + if (calculator == null) + return; + + var attributes = new Dictionary(); + double performance = calculator.Calculate(attributes); + + playerName.Text = $"{score.PP} | {performance.ToString("0.00")} | {score.PP / performance}"; + // var attributeRow = + } } } } diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 8f0ce14305..a7f79b1ecd 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -620,6 +620,7 @@ + From 1ed2ce324fa5766d6c6c5b766902b7e09ebd5201 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 17 Nov 2017 14:23:15 +0900 Subject: [PATCH 0668/1263] Further improvements to TestCasePerformancePoints --- .../Tests/Visual/TestCasePerformancePoints.cs | 255 +++++++++++++----- 1 file changed, 193 insertions(+), 62 deletions(-) diff --git a/osu.Game/Tests/Visual/TestCasePerformancePoints.cs b/osu.Game/Tests/Visual/TestCasePerformancePoints.cs index 7e8b9de954..3a1fc20060 100644 --- a/osu.Game/Tests/Visual/TestCasePerformancePoints.cs +++ b/osu.Game/Tests/Visual/TestCasePerformancePoints.cs @@ -6,19 +6,23 @@ using System.Linq; using OpenTK; using OpenTK.Graphics; using osu.Framework.Allocation; +using osu.Framework.Caching; using osu.Framework.Extensions.IEnumerableExtensions; 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; +using osu.Game.Graphics.UserInterface; using osu.Game.Online.API; using osu.Game.Online.API.Requests; using osu.Game.Overlays; using osu.Game.Overlays.Music; using osu.Game.Rulesets; +using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Scoring; namespace osu.Game.Tests.Visual @@ -27,50 +31,77 @@ namespace osu.Game.Tests.Visual { public TestCasePerformancePoints(Ruleset ruleset) { - Child = new FillFlowContainer + Child = new GridContainer { RelativeSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - Children = new Drawable[] + Content = new[] { - new Container + new Drawable[] { - RelativeSizeAxes = Axes.Both, - Width = 0.25f, - Children = new Drawable[] + new Container { - new Box + RelativeSizeAxes = Axes.Both, + Children = new Drawable[] { - RelativeSizeAxes = Axes.Both, - Colour = Color4.Black, - Alpha = 0.5f, - }, - new ScrollContainer(Direction.Vertical) - { - RelativeSizeAxes = Axes.Both, - Child = new BeatmapList(ruleset) + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Black, + Alpha = 0.5f, + }, + new ScrollContainer(Direction.Vertical) + { + RelativeSizeAxes = Axes.Both, + Child = new BeatmapList(ruleset) + } } - } - }, - new Container - { - RelativeSizeAxes = Axes.Both, - Width = 0.75f, - Children = new Drawable[] + }, + null, + new Container { - new Box + RelativeSizeAxes = Axes.Both, + Children = new Drawable[] { - RelativeSizeAxes = Axes.Both, - Colour = Color4.Black, - Alpha = 0.5f, - }, - new ScrollContainer(Direction.Vertical) - { - RelativeSizeAxes = Axes.Both, - Child = new ScoreList { RelativeSizeAxes = Axes.Both } + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Black, + Alpha = 0.5f, + }, + new ScrollContainer(Direction.Vertical) + { + RelativeSizeAxes = Axes.Both, + Child = new StarRatingGrid() + } } - } - }, + }, + null, + new Container + { + RelativeSizeAxes = Axes.Both, + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Black, + Alpha = 0.5f, + }, + new ScrollContainer(Direction.Vertical) + { + RelativeSizeAxes = Axes.Both, + Child = new PerformanceList() + } + } + }, + } + }, + ColumnDimensions = new[] + { + new Dimension(), + new Dimension(GridSizeMode.Absolute, 20), + new Dimension(), + new Dimension(GridSizeMode.Absolute, 20) } }; } @@ -104,7 +135,7 @@ namespace osu.Game.Tests.Visual allBeatmaps.ForEach(b => beatmapDisplays.Add(new BeatmapDisplay(b))); } - private class BeatmapDisplay : CompositeDrawable + private class BeatmapDisplay : CompositeDrawable, IHasTooltip { private readonly OsuSpriteText text; private readonly BeatmapInfo beatmap; @@ -114,6 +145,8 @@ namespace osu.Game.Tests.Visual private bool isSelected; + public string TooltipText => text.Text; + public BeatmapDisplay(BeatmapInfo beatmap) { this.beatmap = beatmap; @@ -168,16 +201,19 @@ namespace osu.Game.Tests.Visual } } - private class ScoreList : CompositeDrawable + private class PerformanceList : CompositeDrawable { - private readonly FillFlowContainer scores; + private readonly FillFlowContainer scores; private APIAccess api; - public ScoreList() + public PerformanceList() { - InternalChild = scores = new FillFlowContainer + RelativeSizeAxes = Axes.X; + AutoSizeAxes = Axes.Y; + InternalChild = scores = new FillFlowContainer { - RelativeSizeAxes = Axes.Both, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, Direction = FillDirection.Vertical, Spacing = new Vector2(0, 4) }; @@ -197,39 +233,25 @@ namespace osu.Game.Tests.Visual scores.Clear(); lastRequest = new GetScoresRequest(newBeatmap.BeatmapInfo); - lastRequest.Success += res => res.Scores.ForEach(s => scores.Add(new ScoreDisplay(s, newBeatmap.Beatmap))); + lastRequest.Success += res => res.Scores.ForEach(s => scores.Add(new PerformanceDisplay(s, newBeatmap.Beatmap))); api.Queue(lastRequest); } - private class ScoreDisplay : CompositeDrawable + private class PerformanceDisplay : CompositeDrawable { - private readonly OsuSpriteText playerName; - private readonly GridContainer attributeGrid; + private readonly OsuSpriteText text; private readonly Score score; private readonly Beatmap beatmap; - public ScoreDisplay(Score score, Beatmap beatmap) + public PerformanceDisplay(Score score, Beatmap beatmap) { this.score = score; this.beatmap = beatmap; RelativeSizeAxes = Axes.X; - Height = 16; - InternalChild = new GridContainer - { - RelativeSizeAxes = Axes.Both, - Content = new[] - { - new Drawable[] { playerName = new OsuSpriteText() }, - new Drawable[] { attributeGrid = new GridContainer { RelativeSizeAxes = Axes.Both } } - }, - RowDimensions = new[] - { - new Dimension(GridSizeMode.Relative, 0.75f), - new Dimension(GridSizeMode.Relative, 0.25f) - } - }; + AutoSizeAxes = Axes.Y; + InternalChild = text = new OsuSpriteText(); } [BackgroundDependencyLoader] @@ -243,8 +265,117 @@ namespace osu.Game.Tests.Visual var attributes = new Dictionary(); double performance = calculator.Calculate(attributes); - playerName.Text = $"{score.PP} | {performance.ToString("0.00")} | {score.PP / performance}"; - // var attributeRow = + text.Text = $"{score.User.Username} -> online: {score.PP:n2}pp | local: {performance:n2}pp"; + } + } + } + + private class StarRatingGrid : CompositeDrawable + { + private readonly FillFlowContainer modFlow; + private readonly OsuSpriteText totalText; + private readonly FillFlowContainer categoryTexts; + + public StarRatingGrid() + { + RelativeSizeAxes = Axes.X; + AutoSizeAxes = Axes.Y; + InternalChild = new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Children = new Drawable[] + { + modFlow = new FillFlowContainer + { + Name = "Checkbox flow", + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Spacing = new Vector2(4, 4) + }, + new FillFlowContainer + { + Name = "Information display", + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Spacing = new Vector2(0, 4), + Direction = FillDirection.Vertical, + Children = new Drawable[] + { + totalText = new OsuSpriteText { TextSize = 24 }, + categoryTexts = new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical + } + } + } + } + }; + } + + [BackgroundDependencyLoader] + private void load(OsuGameBase osuGame) + { + osuGame.Beatmap.ValueChanged += beatmapChanged; + } + + private Cached informationCache = new Cached(); + + private Ruleset ruleset; + private WorkingBeatmap beatmap; + + private void beatmapChanged(WorkingBeatmap newBeatmap) + { + beatmap = newBeatmap; + + modFlow.Clear(); + + ruleset = newBeatmap.BeatmapInfo.Ruleset.CreateInstance(); + foreach (var mod in ruleset.GetAllMods()) + { + var checkBox = new OsuCheckbox + { + RelativeSizeAxes = Axes.None, + Width = 50, + LabelText = mod.ShortenedName + }; + + checkBox.Current.ValueChanged += v => informationCache.Invalidate(); + modFlow.Add(checkBox); + } + + informationCache.Invalidate(); + } + + protected override void Update() + { + base.Update(); + + if (ruleset == null) + return; + + if (!informationCache.IsValid) + { + totalText.Text = string.Empty; + categoryTexts.Clear(); + + var allMods = ruleset.GetAllMods().ToList(); + Mod[] activeMods = modFlow.Where(c => c.Current.Value).Select(c => allMods.First(m => m.ShortenedName == c.LabelText)).ToArray(); + + var diffCalc = ruleset.CreateDifficultyCalculator(beatmap.Beatmap, activeMods); + if (diffCalc != null) + { + var categories = new Dictionary(); + double totalSr = diffCalc.Calculate(categories); + + totalText.Text = $"Star rating: {totalSr:n2}"; + foreach (var kvp in categories) + categoryTexts.Add(new OsuSpriteText { Text = $"{kvp.Key}: {kvp.Value:n2}" }); + } + + informationCache.Validate(); } } } From 825aa6570ee766028a50492575ba5e12212c7f31 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 17 Nov 2017 14:29:19 +0900 Subject: [PATCH 0669/1263] Fix rebase issues --- osu.Game.Rulesets.Osu/OsuRuleset.cs | 1 + osu.Game/Rulesets/Ruleset.cs | 1 + 2 files changed, 2 insertions(+) diff --git a/osu.Game.Rulesets.Osu/OsuRuleset.cs b/osu.Game.Rulesets.Osu/OsuRuleset.cs index 4a0a5ce0c9..de2e8233de 100644 --- a/osu.Game.Rulesets.Osu/OsuRuleset.cs +++ b/osu.Game.Rulesets.Osu/OsuRuleset.cs @@ -15,6 +15,7 @@ using osu.Framework.Graphics; using osu.Game.Overlays.Settings; using osu.Framework.Input.Bindings; using osu.Game.Rulesets.Scoring; +using osu.Game.Rulesets.Osu.Scoring; namespace osu.Game.Rulesets.Osu { diff --git a/osu.Game/Rulesets/Ruleset.cs b/osu.Game/Rulesets/Ruleset.cs index 226a897126..d787da6a0a 100644 --- a/osu.Game/Rulesets/Ruleset.cs +++ b/osu.Game/Rulesets/Ruleset.cs @@ -10,6 +10,7 @@ using osu.Game.Beatmaps; using osu.Game.Graphics; using osu.Game.Overlays.Settings; using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.UI; namespace osu.Game.Rulesets From bf44b3d0efd0ddc8da9d2016de75b756c5127484 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 17 Nov 2017 16:54:50 +0900 Subject: [PATCH 0670/1263] Cleanups --- .../Tests/TestCasePerformancePoints.cs | 2 +- .../Tests/TestCasePerformancePoints.cs | 2 +- .../OsuDifficulty/OsuDifficultyCalculator.cs | 2 +- .../OsuDifficulty/Skills/Skill.cs | 4 ++-- .../Scoring/OsuPerformanceCalculator.cs | 15 +++++++-------- .../Tests/TestCasePerformancePoints.cs | 2 +- .../Tests/TestCasePerformancePoints.cs | 2 +- .../Rulesets/Scoring/PerformanceCalculator.cs | 2 +- .../Tests/Visual/TestCasePerformancePoints.cs | 16 ++++++---------- 9 files changed, 21 insertions(+), 26 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Tests/TestCasePerformancePoints.cs b/osu.Game.Rulesets.Catch/Tests/TestCasePerformancePoints.cs index 071367b305..6643316f15 100644 --- a/osu.Game.Rulesets.Catch/Tests/TestCasePerformancePoints.cs +++ b/osu.Game.Rulesets.Catch/Tests/TestCasePerformancePoints.cs @@ -3,7 +3,7 @@ namespace osu.Game.Rulesets.Catch.Tests { - public class TestCasePerformancePoints : osu.Game.Tests.Visual.TestCasePerformancePoints + public class TestCasePerformancePoints : Game.Tests.Visual.TestCasePerformancePoints { public TestCasePerformancePoints() : base(new CatchRuleset(new RulesetInfo())) diff --git a/osu.Game.Rulesets.Mania/Tests/TestCasePerformancePoints.cs b/osu.Game.Rulesets.Mania/Tests/TestCasePerformancePoints.cs index 420465c045..e60808b1a6 100644 --- a/osu.Game.Rulesets.Mania/Tests/TestCasePerformancePoints.cs +++ b/osu.Game.Rulesets.Mania/Tests/TestCasePerformancePoints.cs @@ -3,7 +3,7 @@ namespace osu.Game.Rulesets.Mania.Tests { - public class TestCasePerformancePoints : osu.Game.Tests.Visual.TestCasePerformancePoints + public class TestCasePerformancePoints : Game.Tests.Visual.TestCasePerformancePoints { public TestCasePerformancePoints() : base(new ManiaRuleset(new RulesetInfo())) diff --git a/osu.Game.Rulesets.Osu/OsuDifficulty/OsuDifficultyCalculator.cs b/osu.Game.Rulesets.Osu/OsuDifficulty/OsuDifficultyCalculator.cs index 537874f643..3ab1a60443 100644 --- a/osu.Game.Rulesets.Osu/OsuDifficulty/OsuDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Osu/OsuDifficulty/OsuDifficultyCalculator.cs @@ -57,7 +57,7 @@ namespace osu.Game.Rulesets.Osu.OsuDifficulty } foreach (Skill s in skills) - s.Process(h); + s.Process(h, TimeRate); } double aimRating = Math.Sqrt(skills[0].DifficultyValue()) * difficulty_multiplier; diff --git a/osu.Game.Rulesets.Osu/OsuDifficulty/Skills/Skill.cs b/osu.Game.Rulesets.Osu/OsuDifficulty/Skills/Skill.cs index b9632e18e2..ae75a4449b 100644 --- a/osu.Game.Rulesets.Osu/OsuDifficulty/Skills/Skill.cs +++ b/osu.Game.Rulesets.Osu/OsuDifficulty/Skills/Skill.cs @@ -38,9 +38,9 @@ namespace osu.Game.Rulesets.Osu.OsuDifficulty.Skills /// /// Process an and update current strain values accordingly. /// - public void Process(OsuDifficultyHitObject current) + public void Process(OsuDifficultyHitObject current, double timeRate) { - currentStrain *= strainDecay(current.DeltaTime); + currentStrain *= strainDecay(current.DeltaTime / timeRate); if (!(current.BaseObject is Spinner)) currentStrain += StrainValueOf(current) * SkillMultiplier; diff --git a/osu.Game.Rulesets.Osu/Scoring/OsuPerformanceCalculator.cs b/osu.Game.Rulesets.Osu/Scoring/OsuPerformanceCalculator.cs index 32469b1bf7..93003925ef 100644 --- a/osu.Game.Rulesets.Osu/Scoring/OsuPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Osu/Scoring/OsuPerformanceCalculator.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; using System.Linq; -using osu.Framework.Extensions.IEnumerableExtensions; using osu.Game.Beatmaps; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu.Beatmaps; @@ -32,7 +31,7 @@ namespace osu.Game.Rulesets.Osu.Scoring { countHitCircles = Beatmap.HitObjects.Count(h => h is HitCircle); - beatmapMaxCombo = Beatmap.HitObjects.Count(); + beatmapMaxCombo = Beatmap.HitObjects.Count; beatmapMaxCombo += Beatmap.HitObjects.OfType().Sum(s => s.RepeatCount + s.Ticks.Count()); } @@ -84,10 +83,10 @@ namespace osu.Game.Rulesets.Osu.Scoring double aimValue = Math.Pow(5.0f * Math.Max(1.0f, double.Parse(Attributes["Aim"]) / 0.0675f) - 4.0f, 3.0f) / 100000.0f; // Longer maps are worth more - double LengthBonus = 0.95f + 0.4f * Math.Min(1.0f, totalHits / 2000.0f) + + double lengthBonus = 0.95f + 0.4f * Math.Min(1.0f, totalHits / 2000.0f) + (totalHits > 2000 ? Math.Log10(totalHits / 2000.0f) * 0.5f : 0.0f); - aimValue *= LengthBonus; + aimValue *= lengthBonus; // Penalize misses exponentially. This mainly fixes tag4 maps and the likes until a per-hitobject solution is available aimValue *= Math.Pow(0.97f, countMiss); @@ -117,13 +116,13 @@ namespace osu.Game.Rulesets.Osu.Scoring if (mods.Any(h => h is OsuModFlashlight)) { // Apply length bonus again if flashlight is on simply because it becomes a lot harder on longer maps. - aimValue *= 1.45f * LengthBonus; + aimValue *= 1.45f * lengthBonus; } // Scale the aim value with accuracy _slightly_ aimValue *= 0.5f + accuracy / 2.0f; // It is important to also consider accuracy difficulty when doing that - aimValue *= 0.98f + (Math.Pow(Beatmap.BeatmapInfo.BaseDifficulty.OverallDifficulty, 2) / 2500); + aimValue *= 0.98f + Math.Pow(Beatmap.BeatmapInfo.BaseDifficulty.OverallDifficulty, 2) / 2500; return aimValue; } @@ -146,7 +145,7 @@ namespace osu.Game.Rulesets.Osu.Scoring // Scale the speed value with accuracy _slightly_ speedValue *= 0.5f + accuracy / 2.0f; // It is important to also consider accuracy difficulty when doing that - speedValue *= 0.98f + (Math.Pow(Beatmap.BeatmapInfo.BaseDifficulty.OverallDifficulty, 2) / 2500); + speedValue *= 0.98f + Math.Pow(Beatmap.BeatmapInfo.BaseDifficulty.OverallDifficulty, 2) / 2500; return speedValue; } @@ -154,7 +153,7 @@ namespace osu.Game.Rulesets.Osu.Scoring private double computeAccuracyValue() { // This percentage only considers HitCircles of any value - in this part of the calculation we focus on hitting the timing hit window - double betterAccuracyPercentage = 0; + double betterAccuracyPercentage; int amountHitObjectsWithAccuracy = countHitCircles; if (amountHitObjectsWithAccuracy > 0) diff --git a/osu.Game.Rulesets.Osu/Tests/TestCasePerformancePoints.cs b/osu.Game.Rulesets.Osu/Tests/TestCasePerformancePoints.cs index b430803907..36590b484f 100644 --- a/osu.Game.Rulesets.Osu/Tests/TestCasePerformancePoints.cs +++ b/osu.Game.Rulesets.Osu/Tests/TestCasePerformancePoints.cs @@ -3,7 +3,7 @@ namespace osu.Game.Rulesets.Osu.Tests { - public class TestCasePerformancePoints : osu.Game.Tests.Visual.TestCasePerformancePoints + public class TestCasePerformancePoints : Game.Tests.Visual.TestCasePerformancePoints { public TestCasePerformancePoints() : base(new OsuRuleset(new RulesetInfo())) diff --git a/osu.Game.Rulesets.Taiko/Tests/TestCasePerformancePoints.cs b/osu.Game.Rulesets.Taiko/Tests/TestCasePerformancePoints.cs index a60c79fc6a..269aca2cd9 100644 --- a/osu.Game.Rulesets.Taiko/Tests/TestCasePerformancePoints.cs +++ b/osu.Game.Rulesets.Taiko/Tests/TestCasePerformancePoints.cs @@ -3,7 +3,7 @@ namespace osu.Game.Rulesets.Taiko.Tests { - public class TestCasePerformancePoints : osu.Game.Tests.Visual.TestCasePerformancePoints + public class TestCasePerformancePoints : Game.Tests.Visual.TestCasePerformancePoints { public TestCasePerformancePoints() : base(new TaikoRuleset(new RulesetInfo())) diff --git a/osu.Game/Rulesets/Scoring/PerformanceCalculator.cs b/osu.Game/Rulesets/Scoring/PerformanceCalculator.cs index 49b7ac54c6..359d6589ed 100644 --- a/osu.Game/Rulesets/Scoring/PerformanceCalculator.cs +++ b/osu.Game/Rulesets/Scoring/PerformanceCalculator.cs @@ -21,7 +21,7 @@ namespace osu.Game.Rulesets.Scoring protected readonly Beatmap Beatmap; protected readonly Score Score; - public PerformanceCalculator(Ruleset ruleset, Beatmap beatmap, Score score) + protected PerformanceCalculator(Ruleset ruleset, Beatmap beatmap, Score score) { Beatmap = CreateBeatmapConverter().Convert(beatmap); Score = score; diff --git a/osu.Game/Tests/Visual/TestCasePerformancePoints.cs b/osu.Game/Tests/Visual/TestCasePerformancePoints.cs index 3a1fc20060..cd1005593e 100644 --- a/osu.Game/Tests/Visual/TestCasePerformancePoints.cs +++ b/osu.Game/Tests/Visual/TestCasePerformancePoints.cs @@ -12,15 +12,12 @@ 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; using osu.Game.Graphics.UserInterface; using osu.Game.Online.API; using osu.Game.Online.API.Requests; -using osu.Game.Overlays; -using osu.Game.Overlays.Music; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Scoring; @@ -29,7 +26,7 @@ namespace osu.Game.Tests.Visual { public abstract class TestCasePerformancePoints : OsuTestCase { - public TestCasePerformancePoints(Ruleset ruleset) + protected TestCasePerformancePoints(Ruleset ruleset) { Child = new GridContainer { @@ -49,7 +46,7 @@ namespace osu.Game.Tests.Visual Colour = Color4.Black, Alpha = 0.5f, }, - new ScrollContainer(Direction.Vertical) + new ScrollContainer { RelativeSizeAxes = Axes.Both, Child = new BeatmapList(ruleset) @@ -68,7 +65,7 @@ namespace osu.Game.Tests.Visual Colour = Color4.Black, Alpha = 0.5f, }, - new ScrollContainer(Direction.Vertical) + new ScrollContainer { RelativeSizeAxes = Axes.Both, Child = new StarRatingGrid() @@ -87,7 +84,7 @@ namespace osu.Game.Tests.Visual Colour = Color4.Black, Alpha = 0.5f, }, - new ScrollContainer(Direction.Vertical) + new ScrollContainer { RelativeSizeAxes = Axes.Both, Child = new PerformanceList() @@ -127,7 +124,7 @@ namespace osu.Game.Tests.Visual } [BackgroundDependencyLoader] - private void load(OsuGameBase osuGame, BeatmapManager beatmaps) + private void load(BeatmapManager beatmaps) { var sets = beatmaps.GetAllUsableBeatmapSets(); var allBeatmaps = sets.SelectMany(s => s.Beatmaps).Where(b => ruleset.LegacyID < 0 || b.RulesetID == ruleset.LegacyID); @@ -186,7 +183,6 @@ namespace osu.Game.Tests.Visual this.osuGame = osuGame; this.beatmaps = beatmaps; - var working = beatmaps.GetWorkingBeatmap(beatmap); text.Text = $"{beatmap.Metadata.Artist} - {beatmap.Metadata.Title} ({beatmap.Metadata.AuthorString}) [{beatmap.Version}]"; osuGame.Beatmap.ValueChanged += beatmapChanged; @@ -372,7 +368,7 @@ namespace osu.Game.Tests.Visual totalText.Text = $"Star rating: {totalSr:n2}"; foreach (var kvp in categories) - categoryTexts.Add(new OsuSpriteText { Text = $"{kvp.Key}: {kvp.Value:n2}" }); + categoryTexts.Add(new OsuSpriteText { Text = $"{kvp.Key}: {kvp.Value}" }); } informationCache.Validate(); From 5d753427f6edf05ee9a788c39d273d86146a403a Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 17 Nov 2017 17:28:22 +0900 Subject: [PATCH 0671/1263] Fix up DT not affecting hitobject densities --- .../OsuDifficulty/OsuDifficultyCalculator.cs | 4 ++-- .../OsuDifficulty/Preprocessing/OsuDifficultyBeatmap.cs | 8 ++++---- .../OsuDifficulty/Preprocessing/OsuDifficultyHitObject.cs | 8 ++++++-- osu.Game.Rulesets.Osu/OsuDifficulty/Skills/Skill.cs | 4 ++-- osu.Game/Tests/Visual/TestCasePerformancePoints.cs | 3 ++- 5 files changed, 16 insertions(+), 11 deletions(-) diff --git a/osu.Game.Rulesets.Osu/OsuDifficulty/OsuDifficultyCalculator.cs b/osu.Game.Rulesets.Osu/OsuDifficulty/OsuDifficultyCalculator.cs index 3ab1a60443..4f41d3b8e2 100644 --- a/osu.Game.Rulesets.Osu/OsuDifficulty/OsuDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Osu/OsuDifficulty/OsuDifficultyCalculator.cs @@ -35,7 +35,7 @@ namespace osu.Game.Rulesets.Osu.OsuDifficulty public override double Calculate(Dictionary categoryDifficulty = null) { - OsuDifficultyBeatmap beatmap = new OsuDifficultyBeatmap(Beatmap.HitObjects); + OsuDifficultyBeatmap beatmap = new OsuDifficultyBeatmap(Beatmap.HitObjects, TimeRate); Skill[] skills = { new Aim(), @@ -57,7 +57,7 @@ namespace osu.Game.Rulesets.Osu.OsuDifficulty } foreach (Skill s in skills) - s.Process(h, TimeRate); + s.Process(h); } double aimRating = Math.Sqrt(skills[0].DifficultyValue()) * difficulty_multiplier; diff --git a/osu.Game.Rulesets.Osu/OsuDifficulty/Preprocessing/OsuDifficultyBeatmap.cs b/osu.Game.Rulesets.Osu/OsuDifficulty/Preprocessing/OsuDifficultyBeatmap.cs index c6ecc3a506..f8e9423e29 100644 --- a/osu.Game.Rulesets.Osu/OsuDifficulty/Preprocessing/OsuDifficultyBeatmap.cs +++ b/osu.Game.Rulesets.Osu/OsuDifficulty/Preprocessing/OsuDifficultyBeatmap.cs @@ -20,12 +20,12 @@ namespace osu.Game.Rulesets.Osu.OsuDifficulty.Preprocessing /// Creates an enumerator, which preprocesses a list of s recieved as input, wrapping them as /// which contains extra data required for difficulty calculation. /// - public OsuDifficultyBeatmap(List objects) + public OsuDifficultyBeatmap(List objects, double timeRate) { // Sort OsuHitObjects by StartTime - they are not correctly ordered in some cases. // This should probably happen before the objects reach the difficulty calculator. objects.Sort((a, b) => a.StartTime.CompareTo(b.StartTime)); - difficultyObjects = createDifficultyObjectEnumerator(objects); + difficultyObjects = createDifficultyObjectEnumerator(objects, timeRate); } /// @@ -67,7 +67,7 @@ namespace osu.Game.Rulesets.Osu.OsuDifficulty.Preprocessing IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); - private IEnumerator createDifficultyObjectEnumerator(List objects) + private IEnumerator createDifficultyObjectEnumerator(List objects, double timeRate) { // We will process OsuHitObjects in groups of three to form a triangle, so we can calculate an angle for each object. OsuHitObject[] triangle = new OsuHitObject[3]; @@ -87,7 +87,7 @@ namespace osu.Game.Rulesets.Osu.OsuDifficulty.Preprocessing triangle[1] = triangle[0]; triangle[0] = objects[i]; - yield return new OsuDifficultyHitObject(triangle); + yield return new OsuDifficultyHitObject(triangle, timeRate); } } } diff --git a/osu.Game.Rulesets.Osu/OsuDifficulty/Preprocessing/OsuDifficultyHitObject.cs b/osu.Game.Rulesets.Osu/OsuDifficulty/Preprocessing/OsuDifficultyHitObject.cs index bdeb62df3e..17d95990d5 100644 --- a/osu.Game.Rulesets.Osu/OsuDifficulty/Preprocessing/OsuDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Osu/OsuDifficulty/Preprocessing/OsuDifficultyHitObject.cs @@ -33,13 +33,17 @@ namespace osu.Game.Rulesets.Osu.OsuDifficulty.Preprocessing private const int normalized_radius = 52; + private readonly double timeRate; + private readonly OsuHitObject[] t; /// /// Initializes the object calculating extra data required for difficulty calculation. /// - public OsuDifficultyHitObject(OsuHitObject[] triangle) + public OsuDifficultyHitObject(OsuHitObject[] triangle, double timeRate) { + this.timeRate = timeRate; + t = triangle; BaseObject = t[0]; setDistances(); @@ -63,7 +67,7 @@ namespace osu.Game.Rulesets.Osu.OsuDifficulty.Preprocessing private void setTimingValues() { // Every timing inverval is hard capped at the equivalent of 375 BPM streaming speed as a safety measure. - DeltaTime = Math.Max(40, t[0].StartTime - t[1].StartTime); + DeltaTime = Math.Max(40, t[0].StartTime - t[1].StartTime) / timeRate; TimeUntilHit = 450; // BaseObject.PreEmpt; } } diff --git a/osu.Game.Rulesets.Osu/OsuDifficulty/Skills/Skill.cs b/osu.Game.Rulesets.Osu/OsuDifficulty/Skills/Skill.cs index ae75a4449b..b9632e18e2 100644 --- a/osu.Game.Rulesets.Osu/OsuDifficulty/Skills/Skill.cs +++ b/osu.Game.Rulesets.Osu/OsuDifficulty/Skills/Skill.cs @@ -38,9 +38,9 @@ namespace osu.Game.Rulesets.Osu.OsuDifficulty.Skills /// /// Process an and update current strain values accordingly. /// - public void Process(OsuDifficultyHitObject current, double timeRate) + public void Process(OsuDifficultyHitObject current) { - currentStrain *= strainDecay(current.DeltaTime / timeRate); + currentStrain *= strainDecay(current.DeltaTime); if (!(current.BaseObject is Spinner)) currentStrain += StrainValueOf(current) * SkillMultiplier; diff --git a/osu.Game/Tests/Visual/TestCasePerformancePoints.cs b/osu.Game/Tests/Visual/TestCasePerformancePoints.cs index cd1005593e..6b2ab6433b 100644 --- a/osu.Game/Tests/Visual/TestCasePerformancePoints.cs +++ b/osu.Game/Tests/Visual/TestCasePerformancePoints.cs @@ -183,7 +183,8 @@ namespace osu.Game.Tests.Visual this.osuGame = osuGame; this.beatmaps = beatmaps; - text.Text = $"{beatmap.Metadata.Artist} - {beatmap.Metadata.Title} ({beatmap.Metadata.AuthorString}) [{beatmap.Version}]"; + var working = beatmaps.GetWorkingBeatmap(beatmap); + text.Text = $"{working.Metadata.Artist} - {working.Metadata.Title} ({working.Metadata.AuthorString}) [{working.BeatmapInfo.Version}]"; osuGame.Beatmap.ValueChanged += beatmapChanged; } From 8bd59ff0b3614f1a39e33e8e0309246e7ca6c0b4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 17 Nov 2017 17:40:10 +0900 Subject: [PATCH 0672/1263] Fix osu! logo occasionally being in the wrong state on entering the main menu --- osu.Game/Screens/Menu/ButtonSystem.cs | 60 +++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/osu.Game/Screens/Menu/ButtonSystem.cs b/osu.Game/Screens/Menu/ButtonSystem.cs index af16fbd71c..ac597cd9d7 100644 --- a/osu.Game/Screens/Menu/ButtonSystem.cs +++ b/osu.Game/Screens/Menu/ButtonSystem.cs @@ -55,6 +55,8 @@ namespace osu.Game.Screens.Menu // osuLogo.SizeForFlow relies on loading to be complete. buttonFlow.Position = new Vector2(WEDGE_WIDTH * 2 - (BUTTON_WIDTH + this.logo.SizeForFlow / 4), 0); + + updateLogoState(); } } @@ -217,6 +219,8 @@ namespace osu.Game.Screens.Menu if (state == MenuState.TopLevel) buttonArea.FinishTransforms(true); + updateLogoState(lastState); + using (buttonArea.BeginDelayedSequence(lastState == MenuState.Initial ? 150 : 0, true)) { switch (state) @@ -320,6 +324,62 @@ namespace osu.Game.Screens.Menu } } + private void updateLogoState(MenuState lastState = MenuState.Initial) + { + switch (state) + { + case MenuState.Exit: + case MenuState.Initial: + trackingPosition = false; + + logo?.Delay(150) + .Schedule(() => + { + toolbar?.Hide(); + + logo.ClearTransforms(targetMember: nameof(Position)); + logo.RelativePositionAxes = Axes.Both; + + logo.MoveTo(new Vector2(0.5f), 800, Easing.OutExpo); + logo.ScaleTo(1, 800, Easing.OutExpo); + }); + + break; + case MenuState.TopLevel: + case MenuState.Play: + logo.ClearTransforms(targetMember: nameof(Position)); + logo.RelativePositionAxes = Axes.None; + + trackingPosition = true; + + switch (lastState) + { + case MenuState.Initial: + logo.ScaleTo(0.5f, 200, Easing.In); + + trackingPosition = false; + + logo + .MoveTo(iconTrackingPosition, lastState == MenuState.EnteringMode ? 0 : 200, Easing.In) + .OnComplete(o => + { + trackingPosition = true; + + o.Impact(); + toolbar?.Show(); + }); + break; + default: + logo.ScaleTo(0.5f, 200, Easing.OutQuint); + break; + } + break; + case MenuState.EnteringMode: + trackingPosition = true; + break; + } + } + private Vector2 iconTrackingPosition => logo.Parent.ToLocalSpace(iconFacade.ScreenSpaceDrawQuad.Centre); private bool trackingPosition; From d62da4334eae5a8b710f189bdee3862d6563dfbf Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Fri, 17 Nov 2017 12:26:13 +0300 Subject: [PATCH 0673/1263] Add and place all the bottom bar objects --- .../Edit/Components/BottomBarContainer.cs | 44 +++++++++ .../Edit/Components/PlaybackContainer.cs | 9 ++ .../Edit/Components/TimeInfoContainer.cs | 9 ++ .../Timelines/Summary/SummaryTimeline.cs | 98 ++++++++----------- osu.Game/Screens/Edit/Editor.cs | 40 +++++--- osu.Game/osu.Game.csproj | 3 + 6 files changed, 130 insertions(+), 73 deletions(-) create mode 100644 osu.Game/Screens/Edit/Components/BottomBarContainer.cs create mode 100644 osu.Game/Screens/Edit/Components/PlaybackContainer.cs create mode 100644 osu.Game/Screens/Edit/Components/TimeInfoContainer.cs diff --git a/osu.Game/Screens/Edit/Components/BottomBarContainer.cs b/osu.Game/Screens/Edit/Components/BottomBarContainer.cs new file mode 100644 index 0000000000..d1813a9c7b --- /dev/null +++ b/osu.Game/Screens/Edit/Components/BottomBarContainer.cs @@ -0,0 +1,44 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Game.Graphics; + +namespace osu.Game.Screens.Edit.Components +{ + public class BottomBarContainer : Container + { + private const float corner_radius = 5; + private const float contents_padding = 15; + + private readonly Drawable background; + private readonly Container content; + + protected override Container Content => content; + + public BottomBarContainer() + { + Masking = true; + CornerRadius = corner_radius; + + InternalChildren = new[] + { + background = new Box { RelativeSizeAxes = Axes.Both }, + content = new Container + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding { Horizontal = contents_padding }, + } + }; + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + background.Colour = colours.Gray1; + } + } +} diff --git a/osu.Game/Screens/Edit/Components/PlaybackContainer.cs b/osu.Game/Screens/Edit/Components/PlaybackContainer.cs new file mode 100644 index 0000000000..aeed10357b --- /dev/null +++ b/osu.Game/Screens/Edit/Components/PlaybackContainer.cs @@ -0,0 +1,9 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +namespace osu.Game.Screens.Edit.Components +{ + public class PlaybackContainer : BottomBarContainer + { + } +} diff --git a/osu.Game/Screens/Edit/Components/TimeInfoContainer.cs b/osu.Game/Screens/Edit/Components/TimeInfoContainer.cs new file mode 100644 index 0000000000..739a67219d --- /dev/null +++ b/osu.Game/Screens/Edit/Components/TimeInfoContainer.cs @@ -0,0 +1,9 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +namespace osu.Game.Screens.Edit.Components +{ + public class TimeInfoContainer : BottomBarContainer + { + } +} diff --git a/osu.Game/Screens/Edit/Components/Timelines/Summary/SummaryTimeline.cs b/osu.Game/Screens/Edit/Components/Timelines/Summary/SummaryTimeline.cs index 4d925f7584..4543679363 100644 --- a/osu.Game/Screens/Edit/Components/Timelines/Summary/SummaryTimeline.cs +++ b/osu.Game/Screens/Edit/Components/Timelines/Summary/SummaryTimeline.cs @@ -16,83 +16,66 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary /// /// The timeline that sits at the bottom of the editor. /// - public class SummaryTimeline : CompositeDrawable + public class SummaryTimeline : BottomBarContainer { - private const float corner_radius = 5; - private const float contents_padding = 15; - public Bindable Beatmap = new Bindable(); - private readonly Drawable background; - private readonly Drawable timelineBar; public SummaryTimeline() { - Masking = true; - CornerRadius = corner_radius; - TimelinePart markerPart, controlPointPart, bookmarkPart, breakPart; - InternalChildren = new[] + Children = new[] { - background = new Box { RelativeSizeAxes = Axes.Both }, - new Container + markerPart = new MarkerPart { RelativeSizeAxes = Axes.Both }, + controlPointPart = new ControlPointPart + { + Anchor = Anchor.Centre, + Origin = Anchor.BottomCentre, + RelativeSizeAxes = Axes.Both, + Height = 0.35f + }, + bookmarkPart = new BookmarkPart + { + Anchor = Anchor.Centre, + Origin = Anchor.TopCentre, + RelativeSizeAxes = Axes.Both, + Height = 0.35f + }, + timelineBar = new Container { RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding { Left = contents_padding, Right = contents_padding }, - Children = new[] + Children = new Drawable[] { - markerPart = new MarkerPart { RelativeSizeAxes = Axes.Both }, - controlPointPart = new ControlPointPart + new Circle { - Anchor = Anchor.Centre, - Origin = Anchor.BottomCentre, - RelativeSizeAxes = Axes.Both, - Height = 0.35f + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreRight, + Size = new Vector2(5) }, - bookmarkPart = new BookmarkPart + new Box { - Anchor = Anchor.Centre, - Origin = Anchor.TopCentre, - RelativeSizeAxes = Axes.Both, - Height = 0.35f + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + RelativeSizeAxes = Axes.X, + Height = 1, + EdgeSmoothness = new Vector2(0, 1), }, - timelineBar = new Container + new Circle { - RelativeSizeAxes = Axes.Both, - Children = new Drawable[] - { - new Circle - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreRight, - Size = new Vector2(5) - }, - new Box - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - RelativeSizeAxes = Axes.X, - Height = 1, - EdgeSmoothness = new Vector2(0, 1), - }, - new Circle - { - Anchor = Anchor.CentreRight, - Origin = Anchor.CentreLeft, - Size = new Vector2(5) - }, - } + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreLeft, + Size = new Vector2(5) }, - breakPart = new BreakPart - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Both, - Height = 0.25f - } } + }, + breakPart = new BreakPart + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Height = 0.25f } }; @@ -105,7 +88,6 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary [BackgroundDependencyLoader] private void load(OsuColour colours) { - background.Colour = colours.Gray1; timelineBar.Colour = colours.Gray5; } } diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 74e55e58ad..2aef9b11e2 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -17,6 +17,7 @@ using osu.Game.Graphics.UserInterface; using osu.Game.Screens.Edit.Screens; using osu.Game.Screens.Edit.Screens.Compose; using osu.Game.Screens.Edit.Screens.Design; +using osu.Game.Screens.Edit.Components; namespace osu.Game.Screens.Edit { @@ -34,7 +35,9 @@ namespace osu.Game.Screens.Edit public Editor() { EditorMenuBar menuBar; + TimeInfoContainer timeInfo; SummaryTimeline timeline; + PlaybackContainer playback; Children = new[] { @@ -84,23 +87,30 @@ namespace osu.Game.Screens.Edit new Container { RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding { Top = 5, Bottom = 5, Left = 10, Right = 10 }, - Child = new FillFlowContainer + Padding = new MarginPadding { Vertical = 5, Horizontal = 10 }, + Children = new Drawable[] { - Name = "Bottom bar", - RelativeSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - Spacing = new Vector2(10, 0), - Children = new[] + timeInfo = new TimeInfoContainer { - timeline = new SummaryTimeline - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Both, - Width = 0.65f - } - } + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + RelativeSizeAxes = Axes.Both, + Width = 0.17f + }, + timeline = new SummaryTimeline + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Width = 0.65f + }, + playback = new PlaybackContainer + { + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + RelativeSizeAxes = Axes.Both, + Width = 0.17f + }, } } } diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 7b479bdba2..63dbb06491 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -294,6 +294,9 @@ + + + From d75e3d8e818e68f8b6e2f6024fcc41a4f37dca32 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 17 Nov 2017 18:35:54 +0900 Subject: [PATCH 0674/1263] Use lazy for WorkingBeatmap component loading --- osu.Game/Beatmaps/WorkingBeatmap.cs | 129 +++++++++++----------------- 1 file changed, 50 insertions(+), 79 deletions(-) diff --git a/osu.Game/Beatmaps/WorkingBeatmap.cs b/osu.Game/Beatmaps/WorkingBeatmap.cs index 959e71d48d..9ae87bc0a7 100644 --- a/osu.Game/Beatmaps/WorkingBeatmap.cs +++ b/osu.Game/Beatmaps/WorkingBeatmap.cs @@ -28,16 +28,10 @@ namespace osu.Game.Beatmaps Metadata = beatmapInfo.Metadata ?? BeatmapSetInfo?.Metadata ?? new BeatmapMetadata(); Mods.ValueChanged += mods => applyRateAdjustments(); - } - private void applyRateAdjustments() - { - var t = track; - if (t == null) return; - - t.ResetSpeedAdjustments(); - foreach (var mod in Mods.Value.OfType()) - mod.ApplyToClock(t); + beatmap = new Lazy(populateBeatmap); + background = new Lazy(populateBackground); + track = new Lazy(populateTrack); } protected abstract Beatmap GetBeatmap(); @@ -45,98 +39,75 @@ namespace osu.Game.Beatmaps protected abstract Track GetTrack(); protected virtual Waveform GetWaveform() => new Waveform(); - private Beatmap beatmap; - private readonly object beatmapLock = new object(); - public Beatmap Beatmap + public bool BeatmapLoaded => beatmap.IsValueCreated; + public Beatmap Beatmap => beatmap.Value; + private readonly Lazy beatmap; + + private Beatmap populateBeatmap() { - get - { - lock (beatmapLock) - { - if (beatmap != null) return beatmap; + var b = GetBeatmap() ?? new Beatmap(); - beatmap = GetBeatmap() ?? new Beatmap(); + // use the database-backed info. + b.BeatmapInfo = BeatmapInfo; - // use the database-backed info. - beatmap.BeatmapInfo = BeatmapInfo; - - return beatmap; - } - } + return b; } - private readonly object backgroundLock = new object(); - private Texture background; - public Texture Background + public bool BackgroundLoaded => background.IsValueCreated; + public Texture Background => background.Value; + private Lazy background; + + private Texture populateBackground() => GetBackground(); + + public bool TrackLoaded => track.IsValueCreated; + public Track Track => track.Value; + private Lazy track; + + private Track populateTrack() { - get - { - lock (backgroundLock) - { - return background ?? (background = GetBackground()); - } - } + // we want to ensure that we always have a track, even if it's a fake one. + var t = GetTrack() ?? new TrackVirtual(); + applyRateAdjustments(t); + return t; } - private Track track; - private readonly object trackLock = new object(); - public Track Track - { - get - { - lock (trackLock) - { - if (track != null) return track; + public bool WaveformLoaded => waveform.IsValueCreated; + public Waveform Waveform => waveform.Value; + private Lazy waveform; - // we want to ensure that we always have a track, even if it's a fake one. - track = GetTrack() ?? new TrackVirtual(); - - applyRateAdjustments(); - return track; - } - } - } - - private Waveform waveform; - private readonly object waveformLock = new object(); - public Waveform Waveform - { - get - { - lock (waveformLock) - return waveform ?? (waveform = GetWaveform()); - } - } - - public bool TrackLoaded => track != null; + private Waveform populateWaveform() => GetWaveform(); public void TransferTo(WorkingBeatmap other) { - lock (trackLock) - { - if (track != null && BeatmapInfo.AudioEquals(other.BeatmapInfo)) - other.track = track; - } + if (track.IsValueCreated && track.Value != null && BeatmapInfo.AudioEquals(other.BeatmapInfo)) + other.track = track; - if (background != null && BeatmapInfo.BackgroundEquals(other.BeatmapInfo)) + if (background.IsValueCreated && background.Value != null && BeatmapInfo.BackgroundEquals(other.BeatmapInfo)) other.background = background; } public virtual void Dispose() { - background?.Dispose(); - background = null; - - waveform?.Dispose(); + if (BackgroundLoaded) Background.Dispose(); + if (WaveformLoaded) Waveform.Dispose(); } public void DisposeTrack() { - lock (trackLock) - { - track?.Dispose(); - track = null; - } + if (!track.IsValueCreated) return; + + track.Value?.Dispose(); + track = null; + } + + private void applyRateAdjustments(Track t = null) + { + if (t == null && track.IsValueCreated) t = track.Value; + if (t == null) return; + + t.ResetSpeedAdjustments(); + foreach (var mod in Mods.Value.OfType()) + mod.ApplyToClock(t); } } } From b3aae2340b7dcd4816efe7c860b7ac7725c5f054 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 17 Nov 2017 18:36:24 +0900 Subject: [PATCH 0675/1263] Avoid accessing beatmaps from BeatSyncedContainer until they are loaded --- osu.Game/Graphics/Containers/BeatSyncedContainer.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/osu.Game/Graphics/Containers/BeatSyncedContainer.cs b/osu.Game/Graphics/Containers/BeatSyncedContainer.cs index 123ef0662d..fb85af12cb 100644 --- a/osu.Game/Graphics/Containers/BeatSyncedContainer.cs +++ b/osu.Game/Graphics/Containers/BeatSyncedContainer.cs @@ -35,9 +35,12 @@ namespace osu.Game.Graphics.Containers protected override void Update() { - var track = Beatmap.Value.Track; + if (!Beatmap.Value.TrackLoaded || !Beatmap.Value.BeatmapLoaded) return; - if (track == null) + var track = Beatmap.Value.Track; + var beatmap = Beatmap.Value.Beatmap; + + if (track == null || beatmap == null) return; double currentTrackTime = track.Length > 0 ? track.CurrentTime + EarlyActivationMilliseconds : Clock.CurrentTime; From 6b591ac77f4d4f2c4c173fcf41248f18ef76c183 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 17 Nov 2017 19:12:30 +0900 Subject: [PATCH 0676/1263] Add missing initialisation --- osu.Game/Beatmaps/WorkingBeatmap.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Beatmaps/WorkingBeatmap.cs b/osu.Game/Beatmaps/WorkingBeatmap.cs index 9ae87bc0a7..c9acbefd87 100644 --- a/osu.Game/Beatmaps/WorkingBeatmap.cs +++ b/osu.Game/Beatmaps/WorkingBeatmap.cs @@ -32,6 +32,7 @@ namespace osu.Game.Beatmaps beatmap = new Lazy(populateBeatmap); background = new Lazy(populateBackground); track = new Lazy(populateTrack); + waveform = new Lazy(populateWaveform); } protected abstract Beatmap GetBeatmap(); @@ -73,7 +74,7 @@ namespace osu.Game.Beatmaps public bool WaveformLoaded => waveform.IsValueCreated; public Waveform Waveform => waveform.Value; - private Lazy waveform; + private readonly Lazy waveform; private Waveform populateWaveform() => GetWaveform(); From cc04d5bc616f32046d930bf42dca434fdd097c51 Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Fri, 17 Nov 2017 13:35:41 +0300 Subject: [PATCH 0677/1263] Add all the objects to the PlaybackContainer --- .../Edit/Components/BottomBarContainer.cs | 4 + .../Edit/Components/PlaybackContainer.cs | 161 ++++++++++++++++++ .../Timelines/Summary/SummaryTimeline.cs | 4 - osu.Game/Screens/Edit/Editor.cs | 2 + 4 files changed, 167 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Edit/Components/BottomBarContainer.cs b/osu.Game/Screens/Edit/Components/BottomBarContainer.cs index d1813a9c7b..b230032937 100644 --- a/osu.Game/Screens/Edit/Components/BottomBarContainer.cs +++ b/osu.Game/Screens/Edit/Components/BottomBarContainer.cs @@ -2,9 +2,11 @@ // 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.Beatmaps; using osu.Game.Graphics; namespace osu.Game.Screens.Edit.Components @@ -14,6 +16,8 @@ namespace osu.Game.Screens.Edit.Components private const float corner_radius = 5; private const float contents_padding = 15; + public Bindable Beatmap = new Bindable(); + private readonly Drawable background; private readonly Container content; diff --git a/osu.Game/Screens/Edit/Components/PlaybackContainer.cs b/osu.Game/Screens/Edit/Components/PlaybackContainer.cs index aeed10357b..23484464bf 100644 --- a/osu.Game/Screens/Edit/Components/PlaybackContainer.cs +++ b/osu.Game/Screens/Edit/Components/PlaybackContainer.cs @@ -1,9 +1,170 @@ // 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.Audio.Track; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.UserInterface; +using osu.Framework.Input; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osu.Game.Graphics.UserInterface; + namespace osu.Game.Screens.Edit.Components { public class PlaybackContainer : BottomBarContainer { + private readonly IconButton playButton; + + private bool lastTrackState; + private Track track => Beatmap.Value.Track; + + public PlaybackContainer() + { + PlaybackTabControl tabs; + + Children = new Drawable[] + { + playButton = new IconButton + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.Centre, + Scale = new Vector2(1.4f), + IconScale = new Vector2(1.4f), + Icon = FontAwesome.fa_play_circle_o, + Action = play, + Padding = new MarginPadding { Left = 20 } + }, + new OsuSpriteText + { + Origin = Anchor.BottomLeft, + Text = "Playback Speed", + RelativePositionAxes = Axes.Y, + Y = 0.5f, + Padding = new MarginPadding { Left = 45 } + }, + new Container + { + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + RelativeSizeAxes = Axes.Both, + Height = 0.5f, + Padding = new MarginPadding { Left = 45 }, + Child = tabs = new PlaybackTabControl(), + } + }; + + tabs.AddItem(0.25); + tabs.AddItem(0.75); + tabs.AddItem(1); + + tabs.Current.ValueChanged += newValue => track.Tempo.Value = newValue; + } + + private void play() + { + if (track.IsRunning) + track.Stop(); + else + track.Start(); + } + + protected override void Update() + { + base.Update(); + + var currentTrackState = track.IsRunning; + if (currentTrackState == lastTrackState) + return; + + playButton.Icon = currentTrackState ? FontAwesome.fa_pause_circle_o : FontAwesome.fa_play_circle_o; + + lastTrackState = currentTrackState; + } + + private class PlaybackTabControl : OsuTabControl + { + protected override TabItem CreateTabItem(double value) => new PlaybackTabItem(value); + + protected override Dropdown CreateDropdown() => null; + + public PlaybackTabControl() + { + RelativeSizeAxes = Axes.Both; + TabContainer.Spacing = new Vector2(20, 0); + } + + public class PlaybackTabItem : TabItem + { + private const float fade_duration = 100; + + private readonly OsuSpriteText text; + private readonly OsuSpriteText textBold; + + public PlaybackTabItem(double value) : base(value) + { + AutoSizeAxes = Axes.X; + RelativeSizeAxes = Axes.Y; + + Children = new Drawable[] + { + text = new OsuSpriteText + { + Origin = Anchor.TopCentre, + Anchor = Anchor.TopCentre, + Text = $"{value:P0}", + TextSize = 14, + }, + textBold = new OsuSpriteText + { + Origin = Anchor.TopCentre, + Anchor = Anchor.TopCentre, + Text = $"{value:P0}", + TextSize = 14, + Font = @"Exo2.0-Bold", + Alpha = 0, + AlwaysPresent = true, + }, + }; + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + text.Colour = colours.Gray5; + } + + protected override bool OnHover(InputState state) + { + if (!Active) + toBold(); + return true; + } + + protected override void OnHoverLost(InputState state) + { + if (!Active) + toNormal(); + } + + private void toBold() + { + text.FadeOut(fade_duration); + textBold.FadeIn(fade_duration); + } + + private void toNormal() + { + text.FadeIn(fade_duration); + textBold.FadeOut(fade_duration); + } + + protected override void OnActivated() => toBold(); + + protected override void OnDeactivated() => toNormal(); + } + } } } diff --git a/osu.Game/Screens/Edit/Components/Timelines/Summary/SummaryTimeline.cs b/osu.Game/Screens/Edit/Components/Timelines/Summary/SummaryTimeline.cs index 4543679363..a63d02a0a5 100644 --- a/osu.Game/Screens/Edit/Components/Timelines/Summary/SummaryTimeline.cs +++ b/osu.Game/Screens/Edit/Components/Timelines/Summary/SummaryTimeline.cs @@ -3,11 +3,9 @@ using OpenTK; 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.Beatmaps; using osu.Game.Graphics; using osu.Game.Screens.Edit.Components.Timelines.Summary.Parts; @@ -18,8 +16,6 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary /// public class SummaryTimeline : BottomBarContainer { - public Bindable Beatmap = new Bindable(); - private readonly Drawable timelineBar; public SummaryTimeline() diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 2aef9b11e2..51af6e2f5e 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -117,7 +117,9 @@ namespace osu.Game.Screens.Edit }, }; + timeInfo.Beatmap.BindTo(Beatmap); timeline.Beatmap.BindTo(Beatmap); + playback.Beatmap.BindTo(Beatmap); menuBar.Mode.ValueChanged += onModeChanged; } From 1680c0905fb06f5201561cd8c37dadbb821048a4 Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Fri, 17 Nov 2017 14:02:07 +0300 Subject: [PATCH 0678/1263] Fix track tempo could be less than 1 on exiting the editor --- osu.Game/Screens/Edit/Editor.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 51af6e2f5e..6865debd27 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -166,6 +166,7 @@ namespace osu.Game.Screens.Edit protected override bool OnExiting(Screen next) { Background.FadeColour(Color4.White, 500); + Beatmap.Value.Track.Tempo.Value = 1; Beatmap.Value.Track?.Start(); return base.OnExiting(next); } From 07e0aba01c1aafa7f70c0ba91caba80d9a480e52 Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Fri, 17 Nov 2017 14:10:13 +0300 Subject: [PATCH 0679/1263] Remove using --- osu.Game/Screens/Edit/Editor.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 6865debd27..fd85db595a 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -10,7 +10,6 @@ using osu.Framework.Graphics.Shapes; using osu.Game.Graphics; using osu.Game.Screens.Edit.Menus; using osu.Game.Screens.Edit.Components.Timelines.Summary; -using OpenTK; using osu.Framework.Allocation; using osu.Framework.Graphics.UserInterface; using osu.Game.Graphics.UserInterface; From 433f4f03a108f80e12776ef24af3d198ba7e6838 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 17 Nov 2017 20:19:49 +0900 Subject: [PATCH 0680/1263] Actually initialise DifficultyCalculator with mods --- osu.Game/Rulesets/Scoring/PerformanceCalculator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Scoring/PerformanceCalculator.cs b/osu.Game/Rulesets/Scoring/PerformanceCalculator.cs index 359d6589ed..000e279d11 100644 --- a/osu.Game/Rulesets/Scoring/PerformanceCalculator.cs +++ b/osu.Game/Rulesets/Scoring/PerformanceCalculator.cs @@ -26,7 +26,7 @@ namespace osu.Game.Rulesets.Scoring Beatmap = CreateBeatmapConverter().Convert(beatmap); Score = score; - var diffCalc = ruleset.CreateDifficultyCalculator(beatmap); + var diffCalc = ruleset.CreateDifficultyCalculator(beatmap, score.Mods); diffCalc.Calculate(attributes); } From c7ffe6fe5873c5d489e123b7b7e3d11162d9d074 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 17 Nov 2017 20:27:44 +0900 Subject: [PATCH 0681/1263] Fix timeRate dividing incorrectly --- .../OsuDifficulty/Preprocessing/OsuDifficultyHitObject.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/OsuDifficulty/Preprocessing/OsuDifficultyHitObject.cs b/osu.Game.Rulesets.Osu/OsuDifficulty/Preprocessing/OsuDifficultyHitObject.cs index 17d95990d5..05738f1a7d 100644 --- a/osu.Game.Rulesets.Osu/OsuDifficulty/Preprocessing/OsuDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Osu/OsuDifficulty/Preprocessing/OsuDifficultyHitObject.cs @@ -67,7 +67,7 @@ namespace osu.Game.Rulesets.Osu.OsuDifficulty.Preprocessing private void setTimingValues() { // Every timing inverval is hard capped at the equivalent of 375 BPM streaming speed as a safety measure. - DeltaTime = Math.Max(40, t[0].StartTime - t[1].StartTime) / timeRate; + DeltaTime = Math.Max(40, (t[0].StartTime - t[1].StartTime) / timeRate); TimeUntilHit = 450; // BaseObject.PreEmpt; } } From c221cfd30c0cb2d7ecca73461b028e5b2dee34b9 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 17 Nov 2017 20:28:41 +0900 Subject: [PATCH 0682/1263] Fix slider cursor positions not being taken into account --- osu.Game.Rulesets.Osu/Objects/Slider.cs | 6 ++++ .../Preprocessing/OsuDifficultyHitObject.cs | 36 ++++++++++++++++++- 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Slider.cs b/osu.Game.Rulesets.Osu/Objects/Slider.cs index 112fcb1a30..2f6b5c7e68 100644 --- a/osu.Game.Rulesets.Osu/Objects/Slider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Slider.cs @@ -45,6 +45,12 @@ namespace osu.Game.Rulesets.Osu.Objects set { Curve.Distance = value; } } + /// + /// The position of the cursor at the point of completion of this . + /// This is set and used by difficulty calculation. + /// + internal Vector2? CursorPosition; + public List RepeatSamples { get; set; } = new List(); public int RepeatCount { get; set; } = 1; diff --git a/osu.Game.Rulesets.Osu/OsuDifficulty/Preprocessing/OsuDifficultyHitObject.cs b/osu.Game.Rulesets.Osu/OsuDifficulty/Preprocessing/OsuDifficultyHitObject.cs index 05738f1a7d..48f9bcce32 100644 --- a/osu.Game.Rulesets.Osu/OsuDifficulty/Preprocessing/OsuDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Osu/OsuDifficulty/Preprocessing/OsuDifficultyHitObject.cs @@ -2,6 +2,8 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; +using System.Linq; +using OpenTK; using osu.Game.Rulesets.Osu.Objects; namespace osu.Game.Rulesets.Osu.OsuDifficulty.Preprocessing @@ -61,7 +63,39 @@ namespace osu.Game.Rulesets.Osu.OsuDifficulty.Preprocessing scalingFactor *= 1 + smallCircleBonus; } - Distance = (t[0].StackedPosition - t[1].StackedPosition).Length * scalingFactor; + Vector2 lastCursorPosition = t[1].StackedPosition; + + var lastSlider = t[1] as Slider; + if (lastSlider != null) + { + if (lastSlider.CursorPosition == null) + { + float approxFollowCircleRadius = (float)(lastSlider.Radius * scalingFactor * 3); + + var computeVertex = new Action(t => + { + var diff = lastSlider.PositionAt(t) - lastCursorPosition; + float dist = diff.Length; + + if (dist > approxFollowCircleRadius) + { + // The cursor would be outside the follow circle, we need to move it + diff.Normalize(); // Obtain direction of diff + dist -= approxFollowCircleRadius; + lastCursorPosition += diff * dist; + } + }); + + var scoringTimes = lastSlider.Ticks.Select(t => t.StartTime).Concat(lastSlider.RepeatPoints.Select(r => r.StartTime)).OrderBy(t => t); + foreach (var time in scoringTimes) + computeVertex(time); + computeVertex(lastSlider.EndTime); + + lastSlider.CursorPosition = lastCursorPosition; + } + } + + Distance = (BaseObject.StackedPosition - lastCursorPosition).Length * scalingFactor; } private void setTimingValues() From 9260f5b64e85267cd1c2db349a86cf7e46f1116a Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 17 Nov 2017 20:57:45 +0900 Subject: [PATCH 0683/1263] Rework to avoid access to modified closures --- .../Preprocessing/OsuDifficultyHitObject.cs | 54 ++++++++++--------- 1 file changed, 29 insertions(+), 25 deletions(-) diff --git a/osu.Game.Rulesets.Osu/OsuDifficulty/Preprocessing/OsuDifficultyHitObject.cs b/osu.Game.Rulesets.Osu/OsuDifficulty/Preprocessing/OsuDifficultyHitObject.cs index 48f9bcce32..fd58ca9e6b 100644 --- a/osu.Game.Rulesets.Osu/OsuDifficulty/Preprocessing/OsuDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Osu/OsuDifficulty/Preprocessing/OsuDifficultyHitObject.cs @@ -68,31 +68,8 @@ namespace osu.Game.Rulesets.Osu.OsuDifficulty.Preprocessing var lastSlider = t[1] as Slider; if (lastSlider != null) { - if (lastSlider.CursorPosition == null) - { - float approxFollowCircleRadius = (float)(lastSlider.Radius * scalingFactor * 3); - - var computeVertex = new Action(t => - { - var diff = lastSlider.PositionAt(t) - lastCursorPosition; - float dist = diff.Length; - - if (dist > approxFollowCircleRadius) - { - // The cursor would be outside the follow circle, we need to move it - diff.Normalize(); // Obtain direction of diff - dist -= approxFollowCircleRadius; - lastCursorPosition += diff * dist; - } - }); - - var scoringTimes = lastSlider.Ticks.Select(t => t.StartTime).Concat(lastSlider.RepeatPoints.Select(r => r.StartTime)).OrderBy(t => t); - foreach (var time in scoringTimes) - computeVertex(time); - computeVertex(lastSlider.EndTime); - - lastSlider.CursorPosition = lastCursorPosition; - } + computeSliderCursorPosition(lastSlider); + lastCursorPosition = lastSlider.CursorPosition ?? lastCursorPosition; } Distance = (BaseObject.StackedPosition - lastCursorPosition).Length * scalingFactor; @@ -104,5 +81,32 @@ namespace osu.Game.Rulesets.Osu.OsuDifficulty.Preprocessing DeltaTime = Math.Max(40, (t[0].StartTime - t[1].StartTime) / timeRate); TimeUntilHit = 450; // BaseObject.PreEmpt; } + + private void computeSliderCursorPosition(Slider slider) + { + if (slider.CursorPosition != null) + return; + slider.CursorPosition = slider.StackedPosition; + + float approxFollowCircleRadius = (float)(slider.Radius * 3); + var computeVertex = new Action(t => + { + var diff = slider.PositionAt(t) - slider.CursorPosition.Value; + float dist = diff.Length; + + if (dist > approxFollowCircleRadius) + { + // The cursor would be outside the follow circle, we need to move it + diff.Normalize(); // Obtain direction of diff + dist -= approxFollowCircleRadius; + slider.CursorPosition += diff * dist; + } + }); + + var scoringTimes = slider.Ticks.Select(t => t.StartTime).Concat(slider.RepeatPoints.Select(r => r.StartTime)).OrderBy(t => t); + foreach (var time in scoringTimes) + computeVertex(time); + computeVertex(slider.EndTime); + } } } From eb03b0db302236fbbbd18538ffafdf683620944c Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 17 Nov 2017 21:28:59 +0900 Subject: [PATCH 0684/1263] Consider slider lengths as part of Distance --- osu.Game.Rulesets.Osu/Objects/Slider.cs | 12 +++++++++--- .../Preprocessing/OsuDifficultyHitObject.cs | 15 +++++++++------ 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Slider.cs b/osu.Game.Rulesets.Osu/Objects/Slider.cs index 2f6b5c7e68..39ec753fe1 100644 --- a/osu.Game.Rulesets.Osu/Objects/Slider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Slider.cs @@ -46,10 +46,16 @@ namespace osu.Game.Rulesets.Osu.Objects } /// - /// The position of the cursor at the point of completion of this . - /// This is set and used by difficulty calculation. + /// The position of the cursor at the point of completion of this if it was hit + /// with as few movements as possible. This is set and used by difficulty calculation. /// - internal Vector2? CursorPosition; + internal Vector2? LazyEndPosition; + + /// + /// The distance travelled by the cursor upon completion of this if it was hit + /// with as few movements as possible. This is set and used by difficulty calculation. + /// + internal float LazyTravelDistance; public List RepeatSamples { get; set; } = new List(); public int RepeatCount { get; set; } = 1; diff --git a/osu.Game.Rulesets.Osu/OsuDifficulty/Preprocessing/OsuDifficultyHitObject.cs b/osu.Game.Rulesets.Osu/OsuDifficulty/Preprocessing/OsuDifficultyHitObject.cs index fd58ca9e6b..972677a6f1 100644 --- a/osu.Game.Rulesets.Osu/OsuDifficulty/Preprocessing/OsuDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Osu/OsuDifficulty/Preprocessing/OsuDifficultyHitObject.cs @@ -64,15 +64,17 @@ namespace osu.Game.Rulesets.Osu.OsuDifficulty.Preprocessing } Vector2 lastCursorPosition = t[1].StackedPosition; + float lastTravelDistance = 0; var lastSlider = t[1] as Slider; if (lastSlider != null) { computeSliderCursorPosition(lastSlider); - lastCursorPosition = lastSlider.CursorPosition ?? lastCursorPosition; + lastCursorPosition = lastSlider.LazyEndPosition ?? lastCursorPosition; + lastTravelDistance = lastSlider.LazyTravelDistance; } - Distance = (BaseObject.StackedPosition - lastCursorPosition).Length * scalingFactor; + Distance = (lastTravelDistance + (BaseObject.StackedPosition - lastCursorPosition).Length) * scalingFactor; } private void setTimingValues() @@ -84,14 +86,14 @@ namespace osu.Game.Rulesets.Osu.OsuDifficulty.Preprocessing private void computeSliderCursorPosition(Slider slider) { - if (slider.CursorPosition != null) + if (slider.LazyEndPosition != null) return; - slider.CursorPosition = slider.StackedPosition; + slider.LazyEndPosition = slider.StackedPosition; float approxFollowCircleRadius = (float)(slider.Radius * 3); var computeVertex = new Action(t => { - var diff = slider.PositionAt(t) - slider.CursorPosition.Value; + var diff = slider.PositionAt(t) - slider.LazyEndPosition.Value; float dist = diff.Length; if (dist > approxFollowCircleRadius) @@ -99,7 +101,8 @@ namespace osu.Game.Rulesets.Osu.OsuDifficulty.Preprocessing // The cursor would be outside the follow circle, we need to move it diff.Normalize(); // Obtain direction of diff dist -= approxFollowCircleRadius; - slider.CursorPosition += diff * dist; + slider.LazyEndPosition += diff * dist; + slider.LazyTravelDistance += dist; } }); From 1a6b0f5b3f235ef02340a072fdc717d5101587bf Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 17 Nov 2017 21:46:43 +0900 Subject: [PATCH 0685/1263] Update framework --- osu-framework | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu-framework b/osu-framework index c95b9350ed..887db793c7 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit c95b9350edb6305cfefdf08f902f6f73d336736b +Subproject commit 887db793c705b45071aea5e0c1cc931a7887165f From 4ced1b64906507ae871753cc55f63542e4970671 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 17 Nov 2017 22:10:24 +0900 Subject: [PATCH 0686/1263] Use more of the properties --- osu.Game/Beatmaps/WorkingBeatmap.cs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/osu.Game/Beatmaps/WorkingBeatmap.cs b/osu.Game/Beatmaps/WorkingBeatmap.cs index c9acbefd87..cd080b7bbe 100644 --- a/osu.Game/Beatmaps/WorkingBeatmap.cs +++ b/osu.Game/Beatmaps/WorkingBeatmap.cs @@ -80,10 +80,10 @@ namespace osu.Game.Beatmaps public void TransferTo(WorkingBeatmap other) { - if (track.IsValueCreated && track.Value != null && BeatmapInfo.AudioEquals(other.BeatmapInfo)) + if (track.IsValueCreated && Track != null && BeatmapInfo.AudioEquals(other.BeatmapInfo)) other.track = track; - if (background.IsValueCreated && background.Value != null && BeatmapInfo.BackgroundEquals(other.BeatmapInfo)) + if (background.IsValueCreated && Background != null && BeatmapInfo.BackgroundEquals(other.BeatmapInfo)) other.background = background; } @@ -95,15 +95,12 @@ namespace osu.Game.Beatmaps public void DisposeTrack() { - if (!track.IsValueCreated) return; - - track.Value?.Dispose(); - track = null; + if (TrackLoaded) Track.Dispose(); } private void applyRateAdjustments(Track t = null) { - if (t == null && track.IsValueCreated) t = track.Value; + if (t == null && track.IsValueCreated) t = Track; if (t == null) return; t.ResetSpeedAdjustments(); From ddf402d9486bc4632bdee6b21216ad9262c6b1dd Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 17 Nov 2017 22:14:28 +0900 Subject: [PATCH 0687/1263] Add nullchecks in Disposal where population methods return nulls --- osu.Game/Beatmaps/WorkingBeatmap.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Beatmaps/WorkingBeatmap.cs b/osu.Game/Beatmaps/WorkingBeatmap.cs index cd080b7bbe..1d4ed75688 100644 --- a/osu.Game/Beatmaps/WorkingBeatmap.cs +++ b/osu.Game/Beatmaps/WorkingBeatmap.cs @@ -89,13 +89,13 @@ namespace osu.Game.Beatmaps public virtual void Dispose() { - if (BackgroundLoaded) Background.Dispose(); - if (WaveformLoaded) Waveform.Dispose(); + if (BackgroundLoaded) Background?.Dispose(); + if (WaveformLoaded) Waveform?.Dispose(); } public void DisposeTrack() { - if (TrackLoaded) Track.Dispose(); + if (TrackLoaded) Track?.Dispose(); } private void applyRateAdjustments(Track t = null) From 7492ab6495204cac230cb7225dbc98bcf4e6327b Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Sat, 18 Nov 2017 01:48:50 +0300 Subject: [PATCH 0688/1263] Use GridContainer to place the bottom bar objects --- osu.Game/Screens/Edit/Editor.cs | 48 +++++++++++++++++++-------------- 1 file changed, 28 insertions(+), 20 deletions(-) diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index fd85db595a..c94da8c5c5 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -87,30 +87,38 @@ namespace osu.Game.Screens.Edit { RelativeSizeAxes = Axes.Both, Padding = new MarginPadding { Vertical = 5, Horizontal = 10 }, - Children = new Drawable[] + Child = new GridContainer { - timeInfo = new TimeInfoContainer + RelativeSizeAxes = Axes.Both, + ColumnDimensions = new Dimension[] { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - RelativeSizeAxes = Axes.Both, - Width = 0.17f + new Dimension(GridSizeMode.Auto), + new Dimension(GridSizeMode.Relative, 0.67f), + new Dimension(GridSizeMode.Auto), }, - timeline = new SummaryTimeline + Content = new Drawable[][] { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Both, - Width = 0.65f - }, - playback = new PlaybackContainer - { - Anchor = Anchor.CentreRight, - Origin = Anchor.CentreRight, - RelativeSizeAxes = Axes.Both, - Width = 0.17f - }, - } + new Drawable[] + { + new Container + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding { Right = 10 }, + Child = timeInfo = new TimeInfoContainer { RelativeSizeAxes = Axes.Both }, + }, + timeline = new SummaryTimeline + { + RelativeSizeAxes = Axes.Both, + }, + new Container + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding { Left = 10 }, + Child = playback = new PlaybackContainer { RelativeSizeAxes = Axes.Both }, + } + }, + } + }, } } }, From 0b8fed4e5a8e2d1d5b59b77b45a0d0abe7001f3c Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Sat, 18 Nov 2017 01:51:23 +0300 Subject: [PATCH 0689/1263] Remove useless Dimention params --- osu.Game/Screens/Edit/Editor.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index c94da8c5c5..be6a168982 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -92,9 +92,9 @@ namespace osu.Game.Screens.Edit RelativeSizeAxes = Axes.Both, ColumnDimensions = new Dimension[] { - new Dimension(GridSizeMode.Auto), + new Dimension(), new Dimension(GridSizeMode.Relative, 0.67f), - new Dimension(GridSizeMode.Auto), + new Dimension(), }, Content = new Drawable[][] { From 58e72631087b491fb04e6dc641568cccb3b8b53f Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Sat, 18 Nov 2017 03:09:09 +0300 Subject: [PATCH 0690/1263] CI fixes --- osu.Game/Screens/Edit/Editor.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index be6a168982..9093bf5629 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -90,13 +90,13 @@ namespace osu.Game.Screens.Edit Child = new GridContainer { RelativeSizeAxes = Axes.Both, - ColumnDimensions = new Dimension[] + ColumnDimensions = new[] { new Dimension(), new Dimension(GridSizeMode.Relative, 0.67f), new Dimension(), }, - Content = new Drawable[][] + Content = new[] { new Drawable[] { @@ -105,7 +105,7 @@ namespace osu.Game.Screens.Edit RelativeSizeAxes = Axes.Both, Padding = new MarginPadding { Right = 10 }, Child = timeInfo = new TimeInfoContainer { RelativeSizeAxes = Axes.Both }, - }, + }, timeline = new SummaryTimeline { RelativeSizeAxes = Axes.Both, From f6ea5b0590a6033ce15ce10e4a374eadf2e31463 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 18 Nov 2017 10:34:17 +0900 Subject: [PATCH 0691/1263] Remove duplicated code --- osu.Game/Screens/Menu/ButtonSystem.cs | 43 --------------------------- 1 file changed, 43 deletions(-) diff --git a/osu.Game/Screens/Menu/ButtonSystem.cs b/osu.Game/Screens/Menu/ButtonSystem.cs index ac597cd9d7..2a0666ade5 100644 --- a/osu.Game/Screens/Menu/ButtonSystem.cs +++ b/osu.Game/Screens/Menu/ButtonSystem.cs @@ -227,23 +227,9 @@ namespace osu.Game.Screens.Menu { case MenuState.Exit: case MenuState.Initial: - trackingPosition = false; - buttonAreaBackground.ScaleTo(Vector2.One, 500, Easing.Out); buttonArea.FadeOut(300); - logo?.Delay(150) - .Schedule(() => - { - toolbar?.Hide(); - - logo.ClearTransforms(targetMember: nameof(Position)); - logo.RelativePositionAxes = Axes.Both; - - logo.MoveTo(new Vector2(0.5f), 800, Easing.OutExpo); - logo.ScaleTo(1, 800, Easing.OutExpo); - }); - foreach (Button b in buttonsTopLevel) b.State = ButtonState.Contracted; @@ -256,33 +242,6 @@ namespace osu.Game.Screens.Menu case MenuState.TopLevel: buttonAreaBackground.ScaleTo(Vector2.One, 200, Easing.Out); - logo.ClearTransforms(targetMember: nameof(Position)); - logo.RelativePositionAxes = Axes.None; - - trackingPosition = true; - - switch (lastState) - { - case MenuState.Initial: - logo.ScaleTo(0.5f, 200, Easing.In); - - trackingPosition = false; - - logo - .MoveTo(iconTrackingPosition, lastState == MenuState.EnteringMode ? 0 : 200, Easing.In) - .OnComplete(o => - { - trackingPosition = true; - - o.Impact(); - toolbar?.Show(); - }); - break; - default: - logo.ScaleTo(0.5f, 200, Easing.OutQuint); - break; - } - buttonArea.FadeIn(300); foreach (Button b in buttonsTopLevel) @@ -301,8 +260,6 @@ namespace osu.Game.Screens.Menu case MenuState.EnteringMode: buttonAreaBackground.ScaleTo(new Vector2(2, 0), 300, Easing.InSine); - trackingPosition = true; - buttonsTopLevel.ForEach(b => b.ContractStyle = 1); buttonsPlay.ForEach(b => b.ContractStyle = 1); backButton.ContractStyle = 1; From 322dd1bd05ac899c4210969dc8c5c699456ae698 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 18 Nov 2017 10:35:17 +0900 Subject: [PATCH 0692/1263] Rename variables to make more sense --- osu.Game/Screens/Menu/ButtonSystem.cs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/osu.Game/Screens/Menu/ButtonSystem.cs b/osu.Game/Screens/Menu/ButtonSystem.cs index 2a0666ade5..1b2b6a4d11 100644 --- a/osu.Game/Screens/Menu/ButtonSystem.cs +++ b/osu.Game/Screens/Menu/ButtonSystem.cs @@ -287,7 +287,7 @@ namespace osu.Game.Screens.Menu { case MenuState.Exit: case MenuState.Initial: - trackingPosition = false; + logoTracking = false; logo?.Delay(150) .Schedule(() => @@ -307,20 +307,20 @@ namespace osu.Game.Screens.Menu logo.ClearTransforms(targetMember: nameof(Position)); logo.RelativePositionAxes = Axes.None; - trackingPosition = true; + logoTracking = true; switch (lastState) { case MenuState.Initial: logo.ScaleTo(0.5f, 200, Easing.In); - trackingPosition = false; + logoTracking = false; logo - .MoveTo(iconTrackingPosition, lastState == MenuState.EnteringMode ? 0 : 200, Easing.In) + .MoveTo(logoTrackingPosition, lastState == MenuState.EnteringMode ? 0 : 200, Easing.In) .OnComplete(o => { - trackingPosition = true; + logoTracking = true; o.Impact(); toolbar?.Show(); @@ -332,14 +332,14 @@ namespace osu.Game.Screens.Menu } break; case MenuState.EnteringMode: - trackingPosition = true; + logoTracking = true; break; } } - private Vector2 iconTrackingPosition => logo.Parent.ToLocalSpace(iconFacade.ScreenSpaceDrawQuad.Centre); + private Vector2 logoTrackingPosition => logo.Parent.ToLocalSpace(iconFacade.ScreenSpaceDrawQuad.Centre); - private bool trackingPosition; + private bool logoTracking; protected override void Update() { @@ -350,8 +350,8 @@ namespace osu.Game.Screens.Menu if (logo != null) { - if (trackingPosition) - logo.Position = iconTrackingPosition; + if (logoTracking) + logo.Position = logoTrackingPosition; iconFacade.Width = logo.SizeForFlow * 0.5f; } From a741d6cea72bed93900cdc5e585ce032a7f97a01 Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Sat, 18 Nov 2017 04:46:02 +0300 Subject: [PATCH 0693/1263] Fix incorrect score indexes in leaderboard --- osu.Game/Screens/Select/Leaderboards/Leaderboard.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs b/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs index 4b1070f236..6b421ed433 100644 --- a/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs +++ b/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs @@ -64,7 +64,7 @@ namespace osu.Game.Screens.Select.Leaderboards AutoSizeAxes = Axes.Y, Spacing = new Vector2(0f, 5f), Padding = new MarginPadding { Top = 10, Bottom = 5 }, - ChildrenEnumerable = scores.Select(s => new LeaderboardScore(s, 1 + i) { Action = () => ScoreSelected?.Invoke(s) }) + ChildrenEnumerable = scores.Select((s, index) => new LeaderboardScore(s, index + 1) { Action = () => ScoreSelected?.Invoke(s) }) }, f => { scrollFlow?.Expire(); From c2d1de34fccff8b98bff003662a907c89df99796 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 18 Nov 2017 11:19:15 +0900 Subject: [PATCH 0694/1263] Fix logo not always returning to the correct state when rapidly changing menus Fixes #1005 for real --- osu.Game/Screens/Menu/ButtonSystem.cs | 44 +++++++++++++++------------ 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/osu.Game/Screens/Menu/ButtonSystem.cs b/osu.Game/Screens/Menu/ButtonSystem.cs index 1b2b6a4d11..844b1e1819 100644 --- a/osu.Game/Screens/Menu/ButtonSystem.cs +++ b/osu.Game/Screens/Menu/ButtonSystem.cs @@ -17,6 +17,7 @@ using OpenTK.Graphics; using OpenTK.Input; using osu.Framework.Audio.Sample; using osu.Framework.Audio; +using osu.Framework.Threading; namespace osu.Game.Screens.Menu { @@ -281,25 +282,30 @@ namespace osu.Game.Screens.Menu } } + private ScheduledDelegate logoDelayedAction; + private void updateLogoState(MenuState lastState = MenuState.Initial) { + if (logo == null) return; + + logoDelayedAction?.Cancel(); + switch (state) { case MenuState.Exit: case MenuState.Initial: logoTracking = false; - logo?.Delay(150) - .Schedule(() => - { - toolbar?.Hide(); + logoDelayedAction = Scheduler.AddDelayed(() => + { + toolbar?.Hide(); - logo.ClearTransforms(targetMember: nameof(Position)); - logo.RelativePositionAxes = Axes.Both; + logo.ClearTransforms(targetMember: nameof(Position)); + logo.RelativePositionAxes = Axes.Both; - logo.MoveTo(new Vector2(0.5f), 800, Easing.OutExpo); - logo.ScaleTo(1, 800, Easing.OutExpo); - }); + logo.MoveTo(new Vector2(0.5f), 800, Easing.OutExpo); + logo.ScaleTo(1, 800, Easing.OutExpo); + }, 150); break; case MenuState.TopLevel: @@ -307,26 +313,24 @@ namespace osu.Game.Screens.Menu logo.ClearTransforms(targetMember: nameof(Position)); logo.RelativePositionAxes = Axes.None; - logoTracking = true; - switch (lastState) { case MenuState.Initial: + logoTracking = false; logo.ScaleTo(0.5f, 200, Easing.In); - logoTracking = false; + logo.MoveTo(logoTrackingPosition, lastState == MenuState.EnteringMode ? 0 : 200, Easing.In); - logo - .MoveTo(logoTrackingPosition, lastState == MenuState.EnteringMode ? 0 : 200, Easing.In) - .OnComplete(o => - { - logoTracking = true; + logoDelayedAction = Scheduler.AddDelayed(() => + { + logoTracking = true; - o.Impact(); - toolbar?.Show(); - }); + logo.Impact(); + toolbar?.Show(); + }, 200); break; default: + logoTracking = true; logo.ScaleTo(0.5f, 200, Easing.OutQuint); break; } From 68d4e420dde4b189a0d00a7c458f1a2c8c672c13 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 18 Nov 2017 12:18:55 +0900 Subject: [PATCH 0695/1263] Update framework --- osu-framework | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu-framework b/osu-framework index 887db793c7..f27e36d405 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit 887db793c705b45071aea5e0c1cc931a7887165f +Subproject commit f27e36d405dd3f041e19defd59ecbb389ba84617 From 34d8f94f99178ac14c34f7aff5618edcd00bb822 Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Sat, 18 Nov 2017 08:24:09 +0300 Subject: [PATCH 0696/1263] Add track timer --- .../Edit/Components/BottomBarContainer.cs | 2 ++ .../Edit/Components/PlaybackContainer.cs | 11 +++--- .../Edit/Components/TimeInfoContainer.cs | 36 +++++++++++++++++++ 3 files changed, 43 insertions(+), 6 deletions(-) diff --git a/osu.Game/Screens/Edit/Components/BottomBarContainer.cs b/osu.Game/Screens/Edit/Components/BottomBarContainer.cs index b230032937..d65355b5f4 100644 --- a/osu.Game/Screens/Edit/Components/BottomBarContainer.cs +++ b/osu.Game/Screens/Edit/Components/BottomBarContainer.cs @@ -2,6 +2,7 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using osu.Framework.Allocation; +using osu.Framework.Audio.Track; using osu.Framework.Configuration; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -17,6 +18,7 @@ namespace osu.Game.Screens.Edit.Components private const float contents_padding = 15; public Bindable Beatmap = new Bindable(); + protected Track Track => Beatmap.Value.Track; private readonly Drawable background; private readonly Container content; diff --git a/osu.Game/Screens/Edit/Components/PlaybackContainer.cs b/osu.Game/Screens/Edit/Components/PlaybackContainer.cs index 23484464bf..9640d91615 100644 --- a/osu.Game/Screens/Edit/Components/PlaybackContainer.cs +++ b/osu.Game/Screens/Edit/Components/PlaybackContainer.cs @@ -19,7 +19,6 @@ namespace osu.Game.Screens.Edit.Components private readonly IconButton playButton; private bool lastTrackState; - private Track track => Beatmap.Value.Track; public PlaybackContainer() { @@ -60,22 +59,22 @@ namespace osu.Game.Screens.Edit.Components tabs.AddItem(0.75); tabs.AddItem(1); - tabs.Current.ValueChanged += newValue => track.Tempo.Value = newValue; + tabs.Current.ValueChanged += newValue => Track.Tempo.Value = newValue; } private void play() { - if (track.IsRunning) - track.Stop(); + if (Track.IsRunning) + Track.Stop(); else - track.Start(); + Track.Start(); } protected override void Update() { base.Update(); - var currentTrackState = track.IsRunning; + var currentTrackState = Track.IsRunning; if (currentTrackState == lastTrackState) return; diff --git a/osu.Game/Screens/Edit/Components/TimeInfoContainer.cs b/osu.Game/Screens/Edit/Components/TimeInfoContainer.cs index 739a67219d..4a07ab4434 100644 --- a/osu.Game/Screens/Edit/Components/TimeInfoContainer.cs +++ b/osu.Game/Screens/Edit/Components/TimeInfoContainer.cs @@ -1,9 +1,45 @@ // 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.Sprites; +using System; + namespace osu.Game.Screens.Edit.Components { public class TimeInfoContainer : BottomBarContainer { + private const int count_duration = 150; + + private readonly OsuSpriteText trackTimer; + private double savedTime; + + public TimeInfoContainer() + { + Children = new Drawable[] + { + trackTimer = new OsuSpriteText + { + Origin = Anchor.BottomLeft, + RelativePositionAxes = Axes.Y, + TextSize = 22, + FixedWidth = true, + Y = 0.5f, + } + }; + } + + protected override void Update() + { + base.Update(); + + var currentTime = Track.CurrentTime; + + if (savedTime == currentTime) + return; + + trackTimer.Text = TimeSpan.FromMilliseconds(currentTime).ToString(@"mm\:ss\:fff"); + savedTime = currentTime; + } } } From 4ee3a89c129fb4bf64c6cd716e45abe17af7745f Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Sat, 18 Nov 2017 08:35:00 +0300 Subject: [PATCH 0697/1263] Remove using --- osu.Game/Screens/Edit/Components/PlaybackContainer.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Components/PlaybackContainer.cs b/osu.Game/Screens/Edit/Components/PlaybackContainer.cs index 9640d91615..a88983e3e4 100644 --- a/osu.Game/Screens/Edit/Components/PlaybackContainer.cs +++ b/osu.Game/Screens/Edit/Components/PlaybackContainer.cs @@ -3,7 +3,6 @@ using OpenTK; using osu.Framework.Allocation; -using osu.Framework.Audio.Track; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.UserInterface; From de4d8eb1965a82d5d59c8bc0d87476cdec03d539 Mon Sep 17 00:00:00 2001 From: Brayzure Date: Sat, 18 Nov 2017 01:28:09 -0500 Subject: [PATCH 0698/1263] Implement Sudden Death and Perfect - Two additional fail conditions --- osu.Game/Rulesets/Scoring/ScoreProcessor.cs | 23 ++++++++++++++++++--- osu.Game/Screens/Play/Player.cs | 6 ++++++ 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs index 4dd88600b2..f579b94c69 100644 --- a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs +++ b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs @@ -66,6 +66,8 @@ namespace osu.Game.Rulesets.Scoring /// protected virtual bool HasCompleted => false; + public int strictFail = 0; + /// /// Whether this ScoreProcessor has already triggered the failed state. /// @@ -76,6 +78,16 @@ namespace osu.Game.Rulesets.Scoring /// protected virtual bool FailCondition => Health.Value == Health.MinValue; + /// + /// The conditions for failing if the Sudden Death mod is enabled. + /// + protected virtual bool SuddenDeathFailCondition => Combo.Value != HighestCombo.Value; + + /// + /// The conditions for failing if the Perfect mod is enabled. + /// + protected virtual bool PerfectFailCondition => Accuracy.Value != 1; + protected ScoreProcessor() { Combo.ValueChanged += delegate { HighestCombo.Value = Math.Max(HighestCombo.Value, Combo.Value); }; @@ -121,11 +133,16 @@ namespace osu.Game.Rulesets.Scoring /// protected void UpdateFailed() { - if (HasFailed || !FailCondition) + if (HasFailed) return; - if (Failed?.Invoke() != false) - HasFailed = true; + if(FailCondition || + (strictFail==1 && SuddenDeathFailCondition) || + (strictFail==2 && PerfectFailCondition)) + { + if (Failed?.Invoke() != false) + HasFailed = true; + } } /// diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 3e57e18963..2603fee769 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -227,6 +227,12 @@ namespace osu.Game.Screens.Play // Bind ScoreProcessor to ourselves scoreProcessor.AllJudged += onCompletion; scoreProcessor.Failed += onFail; + + if (Beatmap.Value.Mods.Value.Any(m => m.Name == "Sudden Death")) + scoreProcessor.strictFail = 1; + + if (Beatmap.Value.Mods.Value.Any(m => m.Name == "Perfect")) + scoreProcessor.strictFail = 2; } private void applyRateFromMods() From 60778593c34ec95f7432d924e218daf91ccf1437 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 18 Nov 2017 22:24:42 +0900 Subject: [PATCH 0699/1263] Make pressing space twice at main menu a bit smoother --- osu.Game/Screens/Menu/ButtonSystem.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Screens/Menu/ButtonSystem.cs b/osu.Game/Screens/Menu/ButtonSystem.cs index 844b1e1819..c3bd7c1f37 100644 --- a/osu.Game/Screens/Menu/ButtonSystem.cs +++ b/osu.Game/Screens/Menu/ButtonSystem.cs @@ -315,6 +315,7 @@ namespace osu.Game.Screens.Menu switch (lastState) { + case MenuState.TopLevel: // coming from toplevel to play case MenuState.Initial: logoTracking = false; logo.ScaleTo(0.5f, 200, Easing.In); From 87f13688692bce3d25ff9f52e8778b56546103a6 Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Sat, 18 Nov 2017 18:19:35 +0300 Subject: [PATCH 0700/1263] Add KudosuInfo container in the kudosu section --- .../Profile/Sections/Kudosu/KudosuInfo.cs | 146 ++++++++++++++++++ .../Profile/Sections/KudosuSection.cs | 10 ++ osu.Game/Overlays/UserProfileOverlay.cs | 2 +- osu.Game/osu.Game.csproj | 1 + 4 files changed, 158 insertions(+), 1 deletion(-) create mode 100644 osu.Game/Overlays/Profile/Sections/Kudosu/KudosuInfo.cs diff --git a/osu.Game/Overlays/Profile/Sections/Kudosu/KudosuInfo.cs b/osu.Game/Overlays/Profile/Sections/Kudosu/KudosuInfo.cs new file mode 100644 index 0000000000..14d2ef39f8 --- /dev/null +++ b/osu.Game/Overlays/Profile/Sections/Kudosu/KudosuInfo.cs @@ -0,0 +1,146 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using OpenTK; +using OpenTK.Graphics; +using osu.Framework.Configuration; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Input; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osu.Game.Users; + +namespace osu.Game.Overlays.Profile.Sections.Kudosu +{ + public class KudosuInfo : Container + { + private const int content_text_size = 19; + + protected readonly Bindable User = new Bindable(); + + public KudosuInfo(Bindable user) + { + User.BindTo(user); + + SubSection total; + SubSection avaliable; + + RelativeSizeAxes = Axes.X; + Height = 130; + Masking = true; + CornerRadius = 3; + EdgeEffect = new EdgeEffectParameters + { + Type = EdgeEffectType.Shadow, + Offset = new Vector2(0f, 1f), + Radius = 2.5f, + Colour = Color4.Black.Opacity(0.2f), + }; + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = OsuColour.Gray(0.2f) + }, + new GridContainer + { + RelativeSizeAxes = Axes.Both, + Content = new[] + { + new Drawable[] + { + total = new SubSection("Total Kudosu Earned"), + avaliable = new SubSection("Kudosu Avaliable"), + } + } + } + }; + + total.TextFlow.Text = "Based on how much of a contribution the user has made to " + + "beatmap moderation. See this link for more information."; + + avaliable.TextFlow.Text = "Kudosu can be traded for kudosu stars, which will help your beatmap get " + + "more attention. This is the number of kudosu you haven't traded in yet."; + + User.ValueChanged += newUser => + { + total.KudosuValue = newUser == null ? 0 : newUser.Kudosu.Total; + avaliable.KudosuValue = newUser == null ? 0 : newUser.Kudosu.Available; + }; + } + + protected override bool OnClick(InputState state) => true; + + private class SubSection : Container + { + public readonly TextFlowContainer TextFlow; + + private readonly OsuSpriteText valueText; + + private int kudosuValue; + public int KudosuValue + { + get { return kudosuValue; } + set + { + if (kudosuValue == value) + return; + kudosuValue = value; + + valueText.Text = kudosuValue.ToString(); + } + } + + public SubSection(string header) + { + RelativeSizeAxes = Axes.Both; + Padding = new MarginPadding { Horizontal = 10, Top = 10 }; + Child = new FillFlowContainer + { + AutoSizeAxes = Axes.Y, + RelativeSizeAxes = Axes.X, + Direction = FillDirection.Vertical, + Spacing = new Vector2(0, 5), + Children = new Drawable[] + { + new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(5, 0), + Children = new Drawable[] + { + new OsuSpriteText + { + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + Text = header + ":", + TextSize = 20, + Font = @"Exo2.0-RegularItalic", + }, + valueText = new OsuSpriteText + { + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + Text = "0", + TextSize = 40, + UseFullGlyphHeight = false, + Font = @"Exo2.0-RegularItalic" + } + } + }, + TextFlow = new TextFlowContainer(t => { t.TextSize = 19; }) + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + } + } + }; + } + } + } +} diff --git a/osu.Game/Overlays/Profile/Sections/KudosuSection.cs b/osu.Game/Overlays/Profile/Sections/KudosuSection.cs index 3c36368fd7..907c26e5e8 100644 --- a/osu.Game/Overlays/Profile/Sections/KudosuSection.cs +++ b/osu.Game/Overlays/Profile/Sections/KudosuSection.cs @@ -1,6 +1,8 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using osu.Game.Overlays.Profile.Sections.Kudosu; + namespace osu.Game.Overlays.Profile.Sections { public class KudosuSection : ProfileSection @@ -8,5 +10,13 @@ namespace osu.Game.Overlays.Profile.Sections public override string Title => "Kudosu!"; public override string Identifier => "kudosu"; + + public KudosuSection() + { + Children = new[] + { + new KudosuInfo(User), + }; + } } } diff --git a/osu.Game/Overlays/UserProfileOverlay.cs b/osu.Game/Overlays/UserProfileOverlay.cs index dd31a43290..7374a9aa44 100644 --- a/osu.Game/Overlays/UserProfileOverlay.cs +++ b/osu.Game/Overlays/UserProfileOverlay.cs @@ -97,7 +97,7 @@ namespace osu.Game.Overlays //new MedalsSection(), new HistoricalSection(), new BeatmapsSection(), - //new KudosuSection() + new KudosuSection() }; tabs = new ProfileTabControl { diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 7b479bdba2..b9d8e36ff3 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -288,6 +288,7 @@ + From 915ccf3c84b8229b73d2068eecaf39324f348ba6 Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Sat, 18 Nov 2017 18:41:00 +0300 Subject: [PATCH 0701/1263] Fix some layout issues --- .../Profile/Sections/Kudosu/KudosuInfo.cs | 34 ++++++++----------- 1 file changed, 14 insertions(+), 20 deletions(-) diff --git a/osu.Game/Overlays/Profile/Sections/Kudosu/KudosuInfo.cs b/osu.Game/Overlays/Profile/Sections/Kudosu/KudosuInfo.cs index 14d2ef39f8..3fe0bfd9e2 100644 --- a/osu.Game/Overlays/Profile/Sections/Kudosu/KudosuInfo.cs +++ b/osu.Game/Overlays/Profile/Sections/Kudosu/KudosuInfo.cs @@ -17,26 +17,24 @@ namespace osu.Game.Overlays.Profile.Sections.Kudosu { public class KudosuInfo : Container { - private const int content_text_size = 19; - - protected readonly Bindable User = new Bindable(); + private readonly Bindable user = new Bindable(); public KudosuInfo(Bindable user) { - User.BindTo(user); + this.user.BindTo(user); SubSection total; SubSection avaliable; RelativeSizeAxes = Axes.X; - Height = 130; + AutoSizeAxes = Axes.Y; Masking = true; CornerRadius = 3; EdgeEffect = new EdgeEffectParameters { Type = EdgeEffectType.Shadow, Offset = new Vector2(0f, 1f), - Radius = 2.5f, + Radius = 3f, Colour = Color4.Black.Opacity(0.2f), }; Children = new Drawable[] @@ -46,18 +44,12 @@ namespace osu.Game.Overlays.Profile.Sections.Kudosu RelativeSizeAxes = Axes.Both, Colour = OsuColour.Gray(0.2f) }, - new GridContainer + total = new SubSection("Total Kudosu Earned"), + avaliable = new SubSection("Kudosu Avaliable") { - RelativeSizeAxes = Axes.Both, - Content = new[] - { - new Drawable[] - { - total = new SubSection("Total Kudosu Earned"), - avaliable = new SubSection("Kudosu Avaliable"), - } - } - } + RelativePositionAxes = Axes.X, + X = 0.5f, + }, }; total.TextFlow.Text = "Based on how much of a contribution the user has made to " + @@ -66,7 +58,7 @@ namespace osu.Game.Overlays.Profile.Sections.Kudosu avaliable.TextFlow.Text = "Kudosu can be traded for kudosu stars, which will help your beatmap get " + "more attention. This is the number of kudosu you haven't traded in yet."; - User.ValueChanged += newUser => + this.user.ValueChanged += newUser => { total.KudosuValue = newUser == null ? 0 : newUser.Kudosu.Total; avaliable.KudosuValue = newUser == null ? 0 : newUser.Kudosu.Available; @@ -97,8 +89,10 @@ namespace osu.Game.Overlays.Profile.Sections.Kudosu public SubSection(string header) { - RelativeSizeAxes = Axes.Both; - Padding = new MarginPadding { Horizontal = 10, Top = 10 }; + RelativeSizeAxes = Axes.X; + Width = 0.5f; + AutoSizeAxes = Axes.Y; + Padding = new MarginPadding { Horizontal = 10, Top = 10, Bottom = 20 }; Child = new FillFlowContainer { AutoSizeAxes = Axes.Y, From 2ff88c86eafc4509b7b0c1d430a34e1f52fd3c09 Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Sat, 18 Nov 2017 18:53:21 +0300 Subject: [PATCH 0702/1263] CI fixes --- osu.Game/Overlays/Profile/Sections/Kudosu/KudosuInfo.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/Profile/Sections/Kudosu/KudosuInfo.cs b/osu.Game/Overlays/Profile/Sections/Kudosu/KudosuInfo.cs index 3fe0bfd9e2..1982059065 100644 --- a/osu.Game/Overlays/Profile/Sections/Kudosu/KudosuInfo.cs +++ b/osu.Game/Overlays/Profile/Sections/Kudosu/KudosuInfo.cs @@ -57,11 +57,11 @@ namespace osu.Game.Overlays.Profile.Sections.Kudosu avaliable.TextFlow.Text = "Kudosu can be traded for kudosu stars, which will help your beatmap get " + "more attention. This is the number of kudosu you haven't traded in yet."; - + this.user.ValueChanged += newUser => { - total.KudosuValue = newUser == null ? 0 : newUser.Kudosu.Total; - avaliable.KudosuValue = newUser == null ? 0 : newUser.Kudosu.Available; + total.KudosuValue = newUser?.Kudosu.Total ?? 0; + avaliable.KudosuValue = newUser?.Kudosu.Available ?? 0; }; } From 9325730f5da306916c4270a9eea14f1f975732b1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 19 Nov 2017 00:53:59 +0900 Subject: [PATCH 0703/1263] Fix leaderboard fadeout causing constant flow changes Also cleans up logic significantly. --- .../Select/Leaderboards/Leaderboard.cs | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs b/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs index 6b421ed433..d896da5319 100644 --- a/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs +++ b/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs @@ -40,20 +40,12 @@ namespace osu.Game.Screens.Select.Leaderboards scores = value; getScoresRequest?.Cancel(); - int i = 150; + scrollFlow?.FadeOut(200); + scrollFlow?.Expire(); + scrollFlow = null; + if (scores == null) - { - if (scrollFlow != null) - { - foreach (var c in scrollFlow.Children) - c.FadeOut(i += 10); - - foreach (var c in scrollFlow.Children) - c.LifetimeEnd = Time.Current + i; - } - return; - } // schedule because we may not be loaded yet (LoadComponentAsync complains). Schedule(() => @@ -67,10 +59,9 @@ namespace osu.Game.Screens.Select.Leaderboards ChildrenEnumerable = scores.Select((s, index) => new LeaderboardScore(s, index + 1) { Action = () => ScoreSelected?.Invoke(s) }) }, f => { - scrollFlow?.Expire(); scrollContainer.Add(scrollFlow = f); - i = 0; + int i = 0; foreach (var s in f.Children) { using (s.BeginDelayedSequence(i++ * 50, true)) From 7d2bbc50a365ba8f864443bbdec238fb69d6bf27 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 19 Nov 2017 01:42:13 +0900 Subject: [PATCH 0704/1263] Add unique constraint on OnlineBeatmapID --- osu.Game/Database/OsuDbContext.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Database/OsuDbContext.cs b/osu.Game/Database/OsuDbContext.cs index 928c355696..9c1413b93b 100644 --- a/osu.Game/Database/OsuDbContext.cs +++ b/osu.Game/Database/OsuDbContext.cs @@ -78,6 +78,7 @@ namespace osu.Game.Database { base.OnModelCreating(modelBuilder); + modelBuilder.Entity().HasIndex(b => b.OnlineBeatmapID).IsUnique(); modelBuilder.Entity().HasIndex(b => b.MD5Hash).IsUnique(); modelBuilder.Entity().HasIndex(b => b.Hash).IsUnique(); From d704e9cf7e12d784a23adb72b50ff4ce64004b98 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 19 Nov 2017 01:45:07 +0900 Subject: [PATCH 0705/1263] Ensure we correctly handle importing beatmaps/sets when the onlineID already exists locally --- osu.Game/Beatmaps/BeatmapManager.cs | 39 ++++++++++++++++++----------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index ff0abd3d78..2e74adbf45 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -483,14 +483,20 @@ namespace osu.Game.Beatmaps using (var stream = new StreamReader(reader.GetStream(mapName))) metadata = BeatmapDecoder.GetDecoder(stream).Decode(stream).Metadata; - beatmapSet = new BeatmapSetInfo + // check if a set already exists with the same online id. + beatmapSet = beatmaps.BeatmapSets.FirstOrDefault(b => b.OnlineBeatmapSetID == metadata.OnlineBeatmapSetID); + + if (beatmapSet == null) { - OnlineBeatmapSetID = metadata.OnlineBeatmapSetID, - Beatmaps = new List(), - Hash = hash, - Files = fileInfos, - Metadata = metadata - }; + beatmapSet = new BeatmapSetInfo + { + OnlineBeatmapSetID = metadata.OnlineBeatmapSetID, + Beatmaps = new List(), + Hash = hash, + Files = fileInfos, + Metadata = metadata + }; + } var mapNames = reader.Filenames.Where(f => f.EndsWith(".osu")); @@ -510,16 +516,21 @@ namespace osu.Game.Beatmaps beatmap.BeatmapInfo.Hash = ms.ComputeSHA2Hash(); beatmap.BeatmapInfo.MD5Hash = ms.ComputeMD5Hash(); - // TODO: Diff beatmap metadata with set metadata and leave it here if necessary - beatmap.BeatmapInfo.Metadata = null; + var existing = beatmaps.Beatmaps.FirstOrDefault(b => b.Hash == beatmap.BeatmapInfo.Hash || b.OnlineBeatmapID == beatmap.BeatmapInfo.OnlineBeatmapID); - RulesetInfo ruleset = rulesets.GetRuleset(beatmap.BeatmapInfo.RulesetID); + if (existing == null) + { + // TODO: Diff beatmap metadata with set metadata and leave it here if necessary + beatmap.BeatmapInfo.Metadata = null; - // TODO: this should be done in a better place once we actually need to dynamically update it. - beatmap.BeatmapInfo.Ruleset = ruleset; - beatmap.BeatmapInfo.StarDifficulty = ruleset?.CreateInstance()?.CreateDifficultyCalculator(beatmap).Calculate() ?? 0; + RulesetInfo ruleset = rulesets.GetRuleset(beatmap.BeatmapInfo.RulesetID); - beatmapSet.Beatmaps.Add(beatmap.BeatmapInfo); + // TODO: this should be done in a better place once we actually need to dynamically update it. + beatmap.BeatmapInfo.Ruleset = ruleset; + beatmap.BeatmapInfo.StarDifficulty = ruleset?.CreateInstance()?.CreateDifficultyCalculator(beatmap).Calculate() ?? 0; + + beatmapSet.Beatmaps.Add(beatmap.BeatmapInfo); + } } } From 42646413038e1c19b1ed489b5bf2ac35c28f9192 Mon Sep 17 00:00:00 2001 From: jorolf Date: Sat, 18 Nov 2017 18:27:30 +0100 Subject: [PATCH 0706/1263] fix missing text appearing when request returns nothing but beatmaps are already there --- .../Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs b/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs index 834328ca0e..4bfb8107b4 100644 --- a/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs @@ -40,7 +40,7 @@ namespace osu.Game.Overlays.Profile.Sections.Beatmaps ShowMoreButton.FadeTo(sets.Count == ItemsPerPage ? 1 : 0); ShowMoreLoading.Hide(); - if (!sets.Any()) + if (!sets.Any() && VisiblePages == 1) { MissingText.Show(); return; From 9aaefb5e97b95689c22377f0d478d41a7de993e7 Mon Sep 17 00:00:00 2001 From: jorolf Date: Sat, 18 Nov 2017 20:09:31 +0100 Subject: [PATCH 0707/1263] same for PaginatedScoreContainer --- .../Overlays/Profile/Sections/Ranks/PaginatedScoreContainer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Profile/Sections/Ranks/PaginatedScoreContainer.cs b/osu.Game/Overlays/Profile/Sections/Ranks/PaginatedScoreContainer.cs index bb383cac0d..dc30934990 100644 --- a/osu.Game/Overlays/Profile/Sections/Ranks/PaginatedScoreContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/Ranks/PaginatedScoreContainer.cs @@ -41,7 +41,7 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks ShowMoreButton.FadeTo(scores.Count == ItemsPerPage ? 1 : 0); ShowMoreLoading.Hide(); - if (!scores.Any()) + if (!scores.Any() && VisiblePages == 1) { MissingText.Show(); return; From 0b5614e4ee27dff86a9b5bfe7950495cedd14990 Mon Sep 17 00:00:00 2001 From: Aergwyn Date: Sat, 18 Nov 2017 22:12:15 +0100 Subject: [PATCH 0708/1263] fix result screen not showing name of mapper --- osu.Game/Screens/Ranking/ResultsPageScore.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Ranking/ResultsPageScore.cs b/osu.Game/Screens/Ranking/ResultsPageScore.cs index b01410cff5..9104473b82 100644 --- a/osu.Game/Screens/Ranking/ResultsPageScore.cs +++ b/osu.Game/Screens/Ranking/ResultsPageScore.cs @@ -324,7 +324,7 @@ namespace osu.Game.Screens.Ranking title.Colour = artist.Colour = colours.BlueDarker; versionMapper.Colour = colours.Gray8; - versionMapper.Text = $"{beatmap.Version} - mapped by {beatmap.Metadata.Author}"; + versionMapper.Text = $"{beatmap.Version} - mapped by {beatmap.Metadata.Author.Username}"; title.Current = localisation.GetUnicodePreference(beatmap.Metadata.TitleUnicode, beatmap.Metadata.Title); artist.Current = localisation.GetUnicodePreference(beatmap.Metadata.ArtistUnicode, beatmap.Metadata.Artist); } From 492120e88cf9ae2b43dc535c19b6c2f19a895b53 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 19 Nov 2017 16:02:08 +0900 Subject: [PATCH 0709/1263] Add migration for unique constraint on online id --- ...eatmapOnlineIDUniqueConstraint.Designer.cs | 302 ++++++++++++++++++ ...5731_AddBeatmapOnlineIDUniqueConstraint.cs | 25 ++ .../Migrations/OsuDbContextModelSnapshot.cs | 3 + osu.Game/osu.Game.csproj | 4 + 4 files changed, 334 insertions(+) create mode 100644 osu.Game/Migrations/20171119065731_AddBeatmapOnlineIDUniqueConstraint.Designer.cs create mode 100644 osu.Game/Migrations/20171119065731_AddBeatmapOnlineIDUniqueConstraint.cs diff --git a/osu.Game/Migrations/20171119065731_AddBeatmapOnlineIDUniqueConstraint.Designer.cs b/osu.Game/Migrations/20171119065731_AddBeatmapOnlineIDUniqueConstraint.Designer.cs new file mode 100644 index 0000000000..b2f81a729a --- /dev/null +++ b/osu.Game/Migrations/20171119065731_AddBeatmapOnlineIDUniqueConstraint.Designer.cs @@ -0,0 +1,302 @@ +// +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage; +using osu.Game.Database; +using System; + +namespace osu.Game.Migrations +{ + [DbContext(typeof(OsuDbContext))] + [Migration("20171119065731_AddBeatmapOnlineIDUniqueConstraint")] + partial class AddBeatmapOnlineIDUniqueConstraint + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "2.0.0-rtm-26452"); + + modelBuilder.Entity("osu.Game.Beatmaps.BeatmapDifficulty", b => + { + b.Property("ID") + .ValueGeneratedOnAdd(); + + b.Property("ApproachRate"); + + b.Property("CircleSize"); + + b.Property("DrainRate"); + + b.Property("OverallDifficulty"); + + b.Property("SliderMultiplier"); + + b.Property("SliderTickRate"); + + b.HasKey("ID"); + + b.ToTable("BeatmapDifficulty"); + }); + + modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b => + { + b.Property("ID") + .ValueGeneratedOnAdd(); + + b.Property("AudioLeadIn"); + + b.Property("BaseDifficultyID"); + + b.Property("BeatDivisor"); + + b.Property("BeatmapSetInfoID"); + + b.Property("Countdown"); + + b.Property("DistanceSpacing"); + + b.Property("GridSize"); + + b.Property("Hash"); + + b.Property("Hidden"); + + b.Property("LetterboxInBreaks"); + + b.Property("MD5Hash"); + + b.Property("MetadataID"); + + b.Property("OnlineBeatmapID"); + + b.Property("Path"); + + b.Property("RulesetID"); + + b.Property("SpecialStyle"); + + b.Property("StackLeniency"); + + b.Property("StarDifficulty"); + + b.Property("StoredBookmarks"); + + b.Property("TimelineZoom"); + + b.Property("Version"); + + b.Property("WidescreenStoryboard"); + + b.HasKey("ID"); + + b.HasIndex("BaseDifficultyID"); + + b.HasIndex("BeatmapSetInfoID"); + + b.HasIndex("Hash") + .IsUnique(); + + b.HasIndex("MD5Hash") + .IsUnique(); + + b.HasIndex("MetadataID"); + + b.HasIndex("OnlineBeatmapID") + .IsUnique(); + + b.HasIndex("RulesetID"); + + b.ToTable("BeatmapInfo"); + }); + + modelBuilder.Entity("osu.Game.Beatmaps.BeatmapMetadata", b => + { + b.Property("ID") + .ValueGeneratedOnAdd(); + + b.Property("Artist"); + + b.Property("ArtistUnicode"); + + b.Property("AudioFile"); + + b.Property("AuthorString") + .HasColumnName("Author"); + + b.Property("BackgroundFile"); + + b.Property("PreviewTime"); + + b.Property("Source"); + + b.Property("Tags"); + + b.Property("Title"); + + b.Property("TitleUnicode"); + + b.HasKey("ID"); + + b.ToTable("BeatmapMetadata"); + }); + + modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b => + { + b.Property("ID") + .ValueGeneratedOnAdd(); + + b.Property("BeatmapSetInfoID"); + + b.Property("FileInfoID"); + + b.Property("Filename") + .IsRequired(); + + b.HasKey("ID"); + + b.HasIndex("BeatmapSetInfoID"); + + b.HasIndex("FileInfoID"); + + b.ToTable("BeatmapSetFileInfo"); + }); + + modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b => + { + b.Property("ID") + .ValueGeneratedOnAdd(); + + b.Property("DeletePending"); + + b.Property("Hash"); + + b.Property("MetadataID"); + + b.Property("OnlineBeatmapSetID"); + + b.Property("Protected"); + + b.HasKey("ID"); + + b.HasIndex("DeletePending"); + + b.HasIndex("Hash") + .IsUnique(); + + b.HasIndex("MetadataID"); + + b.HasIndex("OnlineBeatmapSetID") + .IsUnique(); + + b.ToTable("BeatmapSetInfo"); + }); + + modelBuilder.Entity("osu.Game.Input.Bindings.DatabasedKeyBinding", b => + { + b.Property("ID") + .ValueGeneratedOnAdd(); + + b.Property("IntAction") + .HasColumnName("Action"); + + b.Property("KeysString") + .HasColumnName("Keys"); + + b.Property("RulesetID"); + + b.Property("Variant"); + + b.HasKey("ID"); + + b.HasIndex("IntAction"); + + b.HasIndex("Variant"); + + b.ToTable("KeyBinding"); + }); + + modelBuilder.Entity("osu.Game.IO.FileInfo", b => + { + b.Property("ID") + .ValueGeneratedOnAdd(); + + b.Property("Hash"); + + b.Property("ReferenceCount"); + + b.HasKey("ID"); + + b.HasIndex("Hash") + .IsUnique(); + + b.HasIndex("ReferenceCount"); + + b.ToTable("FileInfo"); + }); + + modelBuilder.Entity("osu.Game.Rulesets.RulesetInfo", b => + { + b.Property("ID") + .ValueGeneratedOnAdd(); + + b.Property("Available"); + + b.Property("InstantiationInfo"); + + b.Property("Name"); + + b.HasKey("ID"); + + b.HasIndex("Available"); + + b.ToTable("RulesetInfo"); + }); + + modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b => + { + b.HasOne("osu.Game.Beatmaps.BeatmapDifficulty", "BaseDifficulty") + .WithMany() + .HasForeignKey("BaseDifficultyID") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo", "BeatmapSet") + .WithMany("Beatmaps") + .HasForeignKey("BeatmapSetInfoID") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata") + .WithMany("Beatmaps") + .HasForeignKey("MetadataID"); + + b.HasOne("osu.Game.Rulesets.RulesetInfo", "Ruleset") + .WithMany() + .HasForeignKey("RulesetID") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b => + { + b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo") + .WithMany("Files") + .HasForeignKey("BeatmapSetInfoID") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("osu.Game.IO.FileInfo", "FileInfo") + .WithMany() + .HasForeignKey("FileInfoID") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b => + { + b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata") + .WithMany("BeatmapSets") + .HasForeignKey("MetadataID"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/osu.Game/Migrations/20171119065731_AddBeatmapOnlineIDUniqueConstraint.cs b/osu.Game/Migrations/20171119065731_AddBeatmapOnlineIDUniqueConstraint.cs new file mode 100644 index 0000000000..d3830ec0f5 --- /dev/null +++ b/osu.Game/Migrations/20171119065731_AddBeatmapOnlineIDUniqueConstraint.cs @@ -0,0 +1,25 @@ +using Microsoft.EntityFrameworkCore.Migrations; +using System; +using System.Collections.Generic; + +namespace osu.Game.Migrations +{ + public partial class AddBeatmapOnlineIDUniqueConstraint : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateIndex( + name: "IX_BeatmapInfo_OnlineBeatmapID", + table: "BeatmapInfo", + column: "OnlineBeatmapID", + unique: true); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropIndex( + name: "IX_BeatmapInfo_OnlineBeatmapID", + table: "BeatmapInfo"); + } + } +} diff --git a/osu.Game/Migrations/OsuDbContextModelSnapshot.cs b/osu.Game/Migrations/OsuDbContextModelSnapshot.cs index 7029dcdcd5..e3f1cf798b 100644 --- a/osu.Game/Migrations/OsuDbContextModelSnapshot.cs +++ b/osu.Game/Migrations/OsuDbContextModelSnapshot.cs @@ -103,6 +103,9 @@ namespace osu.Game.Migrations b.HasIndex("MetadataID"); + b.HasIndex("OnlineBeatmapID") + .IsUnique(); + b.HasIndex("RulesetID"); b.ToTable("BeatmapInfo"); diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 7b479bdba2..3b4434d1f4 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -279,6 +279,10 @@ 20171025071459_AddMissingIndexRules.cs + + + 20171119065731_AddBeatmapOnlineIDUniqueConstraint.cs + From fe7f9cccaa0520791ff08064fd5a851b0eaf423d Mon Sep 17 00:00:00 2001 From: jorolf Date: Sun, 19 Nov 2017 14:16:00 +0100 Subject: [PATCH 0710/1263] BeatmapSetCover can display other types of covers now --- .../Beatmaps/Drawables/BeatmapSetCover.cs | 27 +++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/osu.Game/Beatmaps/Drawables/BeatmapSetCover.cs b/osu.Game/Beatmaps/Drawables/BeatmapSetCover.cs index 614ebc236b..ba79db3f48 100644 --- a/osu.Game/Beatmaps/Drawables/BeatmapSetCover.cs +++ b/osu.Game/Beatmaps/Drawables/BeatmapSetCover.cs @@ -11,21 +11,44 @@ namespace osu.Game.Beatmaps.Drawables public class BeatmapSetCover : Sprite { private readonly BeatmapSetInfo set; - public BeatmapSetCover(BeatmapSetInfo set) + private readonly BeatmapSetCoverType type; + + public BeatmapSetCover(BeatmapSetInfo set, BeatmapSetCoverType type = BeatmapSetCoverType.Cover) { if (set == null) throw new ArgumentNullException(nameof(set)); this.set = set; + this.type = type; } [BackgroundDependencyLoader] private void load(TextureStore textures) { - string resource = set.OnlineInfo.Covers.Cover; + string resource = null; + + switch (type) + { + case BeatmapSetCoverType.Cover: + resource = set.OnlineInfo.Covers.Cover; + break; + case BeatmapSetCoverType.Card: + resource = set.OnlineInfo.Covers.Card; + break; + case BeatmapSetCoverType.List: + resource = set.OnlineInfo.Covers.List; + break; + } if (resource != null) Texture = textures.Get(resource); } } + + public enum BeatmapSetCoverType + { + Cover, + Card, + List, + } } From 1f379cab8fcdaa8b1b5d1497e18b2bae313d2cc1 Mon Sep 17 00:00:00 2001 From: jorolf Date: Sun, 19 Nov 2017 14:17:14 +0100 Subject: [PATCH 0711/1263] move BeatmapMetadataContainer to a separate class --- .../Sections/BeatmapMetadataContainer.cs | 60 +++++++++++++++++++ .../Profile/Sections/Ranks/DrawableScore.cs | 44 +------------- osu.Game/osu.Game.csproj | 1 + 3 files changed, 62 insertions(+), 43 deletions(-) create mode 100644 osu.Game/Overlays/Profile/Sections/BeatmapMetadataContainer.cs diff --git a/osu.Game/Overlays/Profile/Sections/BeatmapMetadataContainer.cs b/osu.Game/Overlays/Profile/Sections/BeatmapMetadataContainer.cs new file mode 100644 index 0000000000..5104f98f9d --- /dev/null +++ b/osu.Game/Overlays/Profile/Sections/BeatmapMetadataContainer.cs @@ -0,0 +1,60 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Cursor; +using osu.Framework.Localisation; +using osu.Game.Beatmaps; +using osu.Game.Graphics.Containers; +using osu.Game.Graphics.Sprites; +namespace osu.Game.Overlays.Profile.Sections +{ + public class BeatmapMetadataContainer : OsuHoverContainer, IHasTooltip + { + private readonly BeatmapInfo beatmap; + + public BeatmapMetadataContainer(BeatmapInfo beatmap) + { + this.beatmap = beatmap; + AutoSizeAxes = Axes.Both; + TooltipText = $"{beatmap.Metadata.Artist} - {beatmap.Metadata.Title}"; + } + + public string TooltipText { get; } + + [BackgroundDependencyLoader(true)] + private void load(LocalisationEngine locale, BeatmapSetOverlay beatmapSetOverlay) + { + Action = () => + { + if (beatmap.OnlineBeatmapSetID.HasValue) beatmapSetOverlay?.ShowBeatmapSet(beatmap.OnlineBeatmapSetID.Value); + }; + + Child = new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Children = new Drawable[] + { + new OsuSpriteText + { + Current = locale.GetUnicodePreference( + $"{beatmap.Metadata.TitleUnicode ?? beatmap.Metadata.Title} [{beatmap.Version}] ", + $"{beatmap.Metadata.Title ?? beatmap.Metadata.TitleUnicode} [{beatmap.Version}] " + ), + TextSize = 15, + Font = "Exo2.0-SemiBoldItalic", + }, + new OsuSpriteText + { + Current = locale.GetUnicodePreference(beatmap.Metadata.ArtistUnicode, beatmap.Metadata.Artist), + TextSize = 12, + Padding = new MarginPadding { Top = 3 }, + Font = "Exo2.0-RegularItalic", + }, + }, + }; + } + } +} diff --git a/osu.Game/Overlays/Profile/Sections/Ranks/DrawableScore.cs b/osu.Game/Overlays/Profile/Sections/Ranks/DrawableScore.cs index 35f4778047..6c475cbb26 100644 --- a/osu.Game/Overlays/Profile/Sections/Ranks/DrawableScore.cs +++ b/osu.Game/Overlays/Profile/Sections/Ranks/DrawableScore.cs @@ -14,10 +14,8 @@ using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.UI; using OpenTK.Graphics; using osu.Framework.Graphics.Shapes; -using osu.Framework.Graphics.Cursor; using osu.Framework.Input; using osu.Framework.Extensions.Color4Extensions; -using osu.Game.Graphics.Containers; namespace osu.Game.Overlays.Profile.Sections.Ranks { @@ -130,37 +128,7 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks Depth = -1, }); - metadata.Add(new MetadataContainer(Score.Beatmap.Metadata.Title, Score.Beatmap.Metadata.Artist) - { - AutoSizeAxes = Axes.Both, - Action = () => - { - if (Score.Beatmap.OnlineBeatmapSetID.HasValue) beatmapSetOverlay?.ShowBeatmapSet(Score.Beatmap.OnlineBeatmapSetID.Value); - }, - Child = new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Children = new Drawable[] - { - new OsuSpriteText - { - Current = locale.GetUnicodePreference( - $"{Score.Beatmap.Metadata.TitleUnicode ?? Score.Beatmap.Metadata.Title} [{Score.Beatmap.Version}] ", - $"{Score.Beatmap.Metadata.Title ?? Score.Beatmap.Metadata.TitleUnicode} [{Score.Beatmap.Version}] " - ), - TextSize = 15, - Font = "Exo2.0-SemiBoldItalic", - }, - new OsuSpriteText - { - Current = locale.GetUnicodePreference(Score.Beatmap.Metadata.ArtistUnicode, Score.Beatmap.Metadata.Artist), - TextSize = 12, - Padding = new MarginPadding { Top = 3 }, - Font = "Exo2.0-RegularItalic", - }, - }, - }, - }); + metadata.Add(new BeatmapMetadataContainer(Score.Beatmap)); foreach (Mod mod in Score.Mods) modsContainer.Add(new ModIcon(mod) { Scale = new Vector2(0.5f) }); @@ -181,15 +149,5 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks underscoreLine.FadeIn(fade_duration, Easing.OutQuint); base.OnHoverLost(state); } - - private class MetadataContainer : OsuHoverContainer, IHasTooltip - { - public string TooltipText { get; set; } - - public MetadataContainer(string title, string artist) - { - TooltipText = $"{artist} - {title}"; - } - } } } diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 7b479bdba2..c5493ea59f 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -287,6 +287,7 @@ + From 48b44e8e4eb0f29c2430ca286438dd8b69ee9cc2 Mon Sep 17 00:00:00 2001 From: jorolf Date: Sun, 19 Nov 2017 14:18:14 +0100 Subject: [PATCH 0712/1263] add a user most played beatmaps request/response --- .../API/Requests/GetBeatmapSetsResponse.cs | 2 +- .../API/Requests/GetUserBeatmapsRequest.cs | 15 ++++- .../GetUserMostPlayedBeatmapsRequest.cs | 67 +++++++++++++++++++ osu.Game/osu.Game.csproj | 1 + 4 files changed, 82 insertions(+), 3 deletions(-) create mode 100644 osu.Game/Online/API/Requests/GetUserMostPlayedBeatmapsRequest.cs diff --git a/osu.Game/Online/API/Requests/GetBeatmapSetsResponse.cs b/osu.Game/Online/API/Requests/GetBeatmapSetsResponse.cs index 9e412a9b8b..d187cabf31 100644 --- a/osu.Game/Online/API/Requests/GetBeatmapSetsResponse.cs +++ b/osu.Game/Online/API/Requests/GetBeatmapSetsResponse.cs @@ -65,7 +65,7 @@ namespace osu.Game.Online.API.Requests Ranked = ranked, LastUpdated = lastUpdated, }, - Beatmaps = beatmaps.Select(b => b.ToBeatmap(rulesets)).ToList(), + Beatmaps = beatmaps?.Select(b => b.ToBeatmap(rulesets)).ToList(), }; } diff --git a/osu.Game/Online/API/Requests/GetUserBeatmapsRequest.cs b/osu.Game/Online/API/Requests/GetUserBeatmapsRequest.cs index a66799f404..9c3a32ec9e 100644 --- a/osu.Game/Online/API/Requests/GetUserBeatmapsRequest.cs +++ b/osu.Game/Online/API/Requests/GetUserBeatmapsRequest.cs @@ -1,18 +1,19 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System; using Humanizer; using System.Collections.Generic; namespace osu.Game.Online.API.Requests { - public class GetUserBeatmapsRequest : APIRequest> + public class GetUserBeatmapsRequest : APIRequest> { private readonly long userId; private readonly int offset; private readonly BeatmapSetType type; - public GetUserBeatmapsRequest(long userId, BeatmapSetType type, int offset = 0) + protected GetUserBeatmapsRequest(long userId, BeatmapSetType type, int offset = 0) { this.userId = userId; this.offset = offset; @@ -22,6 +23,16 @@ namespace osu.Game.Online.API.Requests protected override string Target => $@"users/{userId}/beatmapsets/{type.ToString().Underscore()}?offset={offset}"; } + public class GetUserBeatmapsRequest : GetUserBeatmapsRequest + { + public GetUserBeatmapsRequest(long userID, BeatmapSetType type, int offset = 0) + : base(userID, type, offset) + { + if(type == BeatmapSetType.MostPlayed) + throw new ArgumentException("Please use " + nameof(GetUserMostPlayedBeatmapsRequest) + " instead"); + } + } + public enum BeatmapSetType { MostPlayed, diff --git a/osu.Game/Online/API/Requests/GetUserMostPlayedBeatmapsRequest.cs b/osu.Game/Online/API/Requests/GetUserMostPlayedBeatmapsRequest.cs new file mode 100644 index 0000000000..33b755450b --- /dev/null +++ b/osu.Game/Online/API/Requests/GetUserMostPlayedBeatmapsRequest.cs @@ -0,0 +1,67 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using System.Linq; +using Newtonsoft.Json; +using osu.Framework.Extensions; +using osu.Game.Beatmaps; +using osu.Game.Rulesets; + +namespace osu.Game.Online.API.Requests +{ + public class GetUserMostPlayedBeatmapsRequest : GetUserBeatmapsRequest + { + public GetUserMostPlayedBeatmapsRequest(long userID, BeatmapSetType type, int offset = 0) + : base(userID, type, offset) + { + if (type != BeatmapSetType.MostPlayed) + throw new ArgumentException("Please use " + nameof(GetUserBeatmapsRequest) + " instead"); + } + } + + public class UserMostPlayedBeatmapsResponse + { + [JsonProperty("beatmap_id")] + public int BeatmapID; + + [JsonProperty("count")] + public int PlayCount; + + [JsonProperty] + private BeatmapResponse beatmap; + + [JsonProperty] + private GetBeatmapSetsResponse beatmapSet; + + public BeatmapInfo GetBeatmapInfo(RulesetStore rulesets) + { + BeatmapSetInfo setInfo = beatmapSet.ToBeatmapSet(rulesets); + return new BeatmapInfo + { + OnlineBeatmapID = beatmap.Id, + OnlineBeatmapSetID = setInfo.OnlineBeatmapSetID, + Ruleset = rulesets.AvailableRulesets.FirstOrDefault(ruleset => ruleset.Name.Equals(beatmap.Mode)), + StarDifficulty = beatmap.DifficultyRating, + Version = beatmap.Version, + Metadata = setInfo.Metadata, + BeatmapSet = setInfo, + }; + } + + private class BeatmapResponse + { + [JsonProperty] + public int Id; + + [JsonProperty] + public string Mode; + + [JsonProperty("difficulty_rating")] + public double DifficultyRating; + + [JsonProperty] + public string Version; + } + } +} diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index c5493ea59f..9fc1674c45 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -282,6 +282,7 @@ + From 4281d76bcf8d8e0c7f56424f8faa863c7aa02dfd Mon Sep 17 00:00:00 2001 From: jorolf Date: Sun, 19 Nov 2017 14:19:05 +0100 Subject: [PATCH 0713/1263] historical section now shows the most played beatmaps --- .../Historical/MostPlayedBeatmapDrawable.cs | 160 ++++++++++++++++++ .../PaginatedMostPlayedBeatmapContainer.cs | 52 ++++++ .../Profile/Sections/HistoricalSection.cs | 8 +- osu.Game/osu.Game.csproj | 2 + 4 files changed, 221 insertions(+), 1 deletion(-) create mode 100644 osu.Game/Overlays/Profile/Sections/Historical/MostPlayedBeatmapDrawable.cs create mode 100644 osu.Game/Overlays/Profile/Sections/Historical/PaginatedMostPlayedBeatmapContainer.cs diff --git a/osu.Game/Overlays/Profile/Sections/Historical/MostPlayedBeatmapDrawable.cs b/osu.Game/Overlays/Profile/Sections/Historical/MostPlayedBeatmapDrawable.cs new file mode 100644 index 0000000000..0f419ad44e --- /dev/null +++ b/osu.Game/Overlays/Profile/Sections/Historical/MostPlayedBeatmapDrawable.cs @@ -0,0 +1,160 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Allocation; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Input; +using osu.Game.Beatmaps; +using osu.Game.Beatmaps.Drawables; +using osu.Game.Graphics; +using osu.Game.Graphics.Containers; +using osu.Game.Graphics.Sprites; +using OpenTK; +using OpenTK.Graphics; + +namespace osu.Game.Overlays.Profile.Sections.Historical +{ + public class MostPlayedBeatmapDrawable : Container + { + private readonly BeatmapInfo beatmap; + private readonly OsuHoverContainer mapperContainer; + + private readonly EdgeEffectParameters edgeEffectNormal = new EdgeEffectParameters + { + Type = EdgeEffectType.Shadow, + Offset = new Vector2(0, 1f), + Radius = 2f, + Colour = Color4.Black.Opacity(0.25f), + }; + + private readonly EdgeEffectParameters edgeEffectHovered = new EdgeEffectParameters + { + Type = EdgeEffectType.Shadow, + Offset = new Vector2(0, 5f), + Radius = 10f, + Colour = Color4.Black.Opacity(0.25f), + }; + + public MostPlayedBeatmapDrawable(BeatmapInfo beatmap, int playCount) + { + this.beatmap = beatmap; + RelativeSizeAxes = Axes.X; + Height = 50; + Margin = new MarginPadding { Bottom = 10 }; + Masking = true; + EdgeEffect = edgeEffectNormal; + + Children = new Drawable[] + { + new Box //Background for this container, otherwise the shadow would be visible + { + RelativeSizeAxes = Axes.Both, + Colour = OsuColour.Gray(0.2f), + }, + new Box //Image Background while loading + { + Size = new Vector2(80, 50), + Colour = Color4.Black, + }, + new DelayedLoadWrapper(new BeatmapSetCover(beatmap.BeatmapSet, BeatmapSetCoverType.List) + { + RelativeSizeAxes = Axes.Both, + FillMode = FillMode.Fit, + }), + new FillFlowContainer + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding(10) { Left = 90 }, + Direction = FillDirection.Vertical, + Children = new Drawable[] + { + new Container + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Children = new Drawable[] + { + new BeatmapMetadataContainer(beatmap), + new FillFlowContainer + { + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Children = new [] + { + new OsuSpriteText + { + Anchor = Anchor.BottomRight, + Origin = Anchor.BottomRight, + Text = playCount.ToString(), + TextSize = 18, + Font = @"Exo2.0-SemiBoldItalic" + }, + new OsuSpriteText + { + Anchor = Anchor.BottomRight, + Origin = Anchor.BottomRight, + Text = @"times played ", + TextSize = 12, + Font = @"Exo2.0-RegularItalic" + }, + } + } + }, + }, + new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Horizontal, + Children = new Drawable[] + { + new OsuSpriteText + { + Text = @"mapped by ", + TextSize = 12, + }, + mapperContainer = new OsuHoverContainer + { + AutoSizeAxes = Axes.Both, + Children = new Drawable[] + { + new OsuSpriteText + { + Text = beatmap.Metadata.AuthorString, + TextSize = 12, + Font = @"Exo2.0-MediumItalic" + } + } + }, + } + }, + }, + } + }; + } + + [BackgroundDependencyLoader(true)] + private void load(UserProfileOverlay profileOverlay) + { + if(profileOverlay != null) + mapperContainer.Action = () => profileOverlay.ShowUser(beatmap.BeatmapSet.Metadata.Author); + } + + protected override bool OnHover(InputState state) + { + TweenEdgeEffectTo(edgeEffectHovered, 120, Easing.OutQuint); + return base.OnHover(state); + } + + protected override void OnHoverLost(InputState state) + { + TweenEdgeEffectTo(edgeEffectNormal, 120, Easing.OutQuint); + base.OnHoverLost(state); + } + } +} diff --git a/osu.Game/Overlays/Profile/Sections/Historical/PaginatedMostPlayedBeatmapContainer.cs b/osu.Game/Overlays/Profile/Sections/Historical/PaginatedMostPlayedBeatmapContainer.cs new file mode 100644 index 0000000000..d42e00b1a5 --- /dev/null +++ b/osu.Game/Overlays/Profile/Sections/Historical/PaginatedMostPlayedBeatmapContainer.cs @@ -0,0 +1,52 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System.Linq; +using osu.Framework.Configuration; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Beatmaps; +using osu.Game.Online.API.Requests; +using osu.Game.Users; + +namespace osu.Game.Overlays.Profile.Sections.Historical +{ + public class PaginatedMostPlayedBeatmapContainer : PaginatedContainer + { + public PaginatedMostPlayedBeatmapContainer(Bindable user) + :base(user, "Most Played Beatmaps", "No performance records. :(") + { + ItemsPerPage = 5; + + ItemsContainer.Direction = FillDirection.Vertical; + } + + protected override void ShowMore() + { + base.ShowMore(); + + var req = new GetUserMostPlayedBeatmapsRequest(User.Value.Id, BeatmapSetType.MostPlayed, VisiblePages++ * ItemsPerPage); + + req.Success += beatmaps => + { + ShowMoreButton.FadeTo(beatmaps.Count == ItemsPerPage ? 1 : 0); + ShowMoreLoading.Hide(); + + if (!beatmaps.Any() && VisiblePages == 1) + { + MissingText.Show(); + return; + } + + MissingText.Hide(); + + foreach (var beatmap in beatmaps) + { + ItemsContainer.Add(new MostPlayedBeatmapDrawable(beatmap.GetBeatmapInfo(Rulesets), beatmap.PlayCount)); + } + }; + + Api.Queue(req); + } + } +} diff --git a/osu.Game/Overlays/Profile/Sections/HistoricalSection.cs b/osu.Game/Overlays/Profile/Sections/HistoricalSection.cs index a4d043d20a..ab99abdccd 100644 --- a/osu.Game/Overlays/Profile/Sections/HistoricalSection.cs +++ b/osu.Game/Overlays/Profile/Sections/HistoricalSection.cs @@ -1,7 +1,9 @@ // 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.Online.API.Requests; +using osu.Game.Overlays.Profile.Sections.Historical; using osu.Game.Overlays.Profile.Sections.Ranks; namespace osu.Game.Overlays.Profile.Sections @@ -14,7 +16,11 @@ namespace osu.Game.Overlays.Profile.Sections public HistoricalSection() { - Child = new PaginatedScoreContainer(ScoreType.Recent, User, "Recent Plays (24h)", "No performance records. :("); + Children = new Drawable[] + { + new PaginatedMostPlayedBeatmapContainer(User), + new PaginatedScoreContainer(ScoreType.Recent, User, "Recent Plays (24h)", "No performance records. :("), + }; } } } diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 9fc1674c45..fd8e03f623 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -290,6 +290,8 @@ + + From 66c51c7b44a1d3f99187decbb465a884606bc102 Mon Sep 17 00:00:00 2001 From: jorolf Date: Sun, 19 Nov 2017 14:33:50 +0100 Subject: [PATCH 0714/1263] cleanup --- osu.Game/Online/API/Requests/GetUserBeatmapsRequest.cs | 2 +- .../Online/API/Requests/GetUserMostPlayedBeatmapsRequest.cs | 1 - .../Sections/Historical/PaginatedMostPlayedBeatmapContainer.cs | 1 - osu.Game/Overlays/Profile/Sections/Ranks/DrawableScore.cs | 3 +-- 4 files changed, 2 insertions(+), 5 deletions(-) diff --git a/osu.Game/Online/API/Requests/GetUserBeatmapsRequest.cs b/osu.Game/Online/API/Requests/GetUserBeatmapsRequest.cs index 9c3a32ec9e..dca0395e3a 100644 --- a/osu.Game/Online/API/Requests/GetUserBeatmapsRequest.cs +++ b/osu.Game/Online/API/Requests/GetUserBeatmapsRequest.cs @@ -7,7 +7,7 @@ using System.Collections.Generic; namespace osu.Game.Online.API.Requests { - public class GetUserBeatmapsRequest : APIRequest> + public abstract class GetUserBeatmapsRequest : APIRequest> { private readonly long userId; private readonly int offset; diff --git a/osu.Game/Online/API/Requests/GetUserMostPlayedBeatmapsRequest.cs b/osu.Game/Online/API/Requests/GetUserMostPlayedBeatmapsRequest.cs index 33b755450b..cdc156be05 100644 --- a/osu.Game/Online/API/Requests/GetUserMostPlayedBeatmapsRequest.cs +++ b/osu.Game/Online/API/Requests/GetUserMostPlayedBeatmapsRequest.cs @@ -4,7 +4,6 @@ using System; using System.Linq; using Newtonsoft.Json; -using osu.Framework.Extensions; using osu.Game.Beatmaps; using osu.Game.Rulesets; diff --git a/osu.Game/Overlays/Profile/Sections/Historical/PaginatedMostPlayedBeatmapContainer.cs b/osu.Game/Overlays/Profile/Sections/Historical/PaginatedMostPlayedBeatmapContainer.cs index d42e00b1a5..916f1f437a 100644 --- a/osu.Game/Overlays/Profile/Sections/Historical/PaginatedMostPlayedBeatmapContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/Historical/PaginatedMostPlayedBeatmapContainer.cs @@ -5,7 +5,6 @@ using System.Linq; using osu.Framework.Configuration; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Game.Beatmaps; using osu.Game.Online.API.Requests; using osu.Game.Users; diff --git a/osu.Game/Overlays/Profile/Sections/Ranks/DrawableScore.cs b/osu.Game/Overlays/Profile/Sections/Ranks/DrawableScore.cs index 6c475cbb26..4d210f399e 100644 --- a/osu.Game/Overlays/Profile/Sections/Ranks/DrawableScore.cs +++ b/osu.Game/Overlays/Profile/Sections/Ranks/DrawableScore.cs @@ -9,7 +9,6 @@ using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Rulesets.Mods; using osu.Game.Screens.Select.Leaderboards; -using osu.Framework.Localisation; using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.UI; using OpenTK.Graphics; @@ -113,7 +112,7 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks } [BackgroundDependencyLoader(true)] - private void load(OsuColour colour, LocalisationEngine locale, BeatmapSetOverlay beatmapSetOverlay) + private void load(OsuColour colour) { coloredBackground.Colour = underscoreLine.Colour = colour.Gray4; From 8919e98d13adcdbef4a51609a10701b221d1009c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 20 Nov 2017 11:32:20 +0900 Subject: [PATCH 0715/1263] Fix CI issue --- osu.Game/Beatmaps/BeatmapManager.cs | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 2e74adbf45..006269f186 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -484,19 +484,14 @@ namespace osu.Game.Beatmaps metadata = BeatmapDecoder.GetDecoder(stream).Decode(stream).Metadata; // check if a set already exists with the same online id. - beatmapSet = beatmaps.BeatmapSets.FirstOrDefault(b => b.OnlineBeatmapSetID == metadata.OnlineBeatmapSetID); - - if (beatmapSet == null) + beatmapSet = beatmaps.BeatmapSets.FirstOrDefault(b => b.OnlineBeatmapSetID == metadata.OnlineBeatmapSetID) ?? new BeatmapSetInfo { - beatmapSet = new BeatmapSetInfo - { - OnlineBeatmapSetID = metadata.OnlineBeatmapSetID, - Beatmaps = new List(), - Hash = hash, - Files = fileInfos, - Metadata = metadata - }; - } + OnlineBeatmapSetID = metadata.OnlineBeatmapSetID, + Beatmaps = new List(), + Hash = hash, + Files = fileInfos, + Metadata = metadata + }; var mapNames = reader.Filenames.Where(f => f.EndsWith(".osu")); From ecc2877be6457420e3a978428ffff5949ee5d815 Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Mon, 20 Nov 2017 09:29:26 +0300 Subject: [PATCH 0716/1263] Fix possible null and adjust timeline width --- osu.Game/Screens/Edit/Editor.cs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 9093bf5629..52baadd442 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -93,8 +93,7 @@ namespace osu.Game.Screens.Edit ColumnDimensions = new[] { new Dimension(), - new Dimension(GridSizeMode.Relative, 0.67f), - new Dimension(), + new Dimension(GridSizeMode.Relative, 0.65f), }, Content = new[] { @@ -173,8 +172,11 @@ namespace osu.Game.Screens.Edit protected override bool OnExiting(Screen next) { Background.FadeColour(Color4.White, 500); - Beatmap.Value.Track.Tempo.Value = 1; - Beatmap.Value.Track?.Start(); + if (Beatmap.Value.Track != null) + { + Beatmap.Value.Track.Tempo.Value = 1; + Beatmap.Value.Track.Start(); + } return base.OnExiting(next); } } From da30d76f9b08b1435db366b5b0004cb704fd5f94 Mon Sep 17 00:00:00 2001 From: Brayzure Date: Mon, 20 Nov 2017 02:15:29 -0500 Subject: [PATCH 0717/1263] Implement Score Processor Mod Interface - Add a delegate whenever we want to register an additional fail condition --- .../Mods/IApplicableToScoreProcessor.cs | 15 +++++++ osu.Game/Rulesets/Mods/ModPerfect.cs | 16 ++++++- osu.Game/Rulesets/Mods/ModSuddenDeath.cs | 15 ++++++- osu.Game/Rulesets/Scoring/ScoreProcessor.cs | 43 ++++++++++--------- osu.Game/Screens/Play/Player.cs | 12 ++++-- osu.Game/osu.Game.csproj | 1 + 6 files changed, 74 insertions(+), 28 deletions(-) create mode 100644 osu.Game/Rulesets/Mods/IApplicableToScoreProcessor.cs diff --git a/osu.Game/Rulesets/Mods/IApplicableToScoreProcessor.cs b/osu.Game/Rulesets/Mods/IApplicableToScoreProcessor.cs new file mode 100644 index 0000000000..db9b713c59 --- /dev/null +++ b/osu.Game/Rulesets/Mods/IApplicableToScoreProcessor.cs @@ -0,0 +1,15 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Game.Rulesets.Scoring; + +namespace osu.Game.Rulesets.Mods +{ + /// + /// An interface for mods that make general adjustments to score processor. + /// + public interface IApplicableToScoreProcessor + { + void ApplyToScoreProcessor(ScoreProcessor scoreProcessor); + } +} diff --git a/osu.Game/Rulesets/Mods/ModPerfect.cs b/osu.Game/Rulesets/Mods/ModPerfect.cs index 082370ea5d..7b79493d65 100644 --- a/osu.Game/Rulesets/Mods/ModPerfect.cs +++ b/osu.Game/Rulesets/Mods/ModPerfect.cs @@ -1,12 +1,24 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using osu.Game.Rulesets.Scoring; + namespace osu.Game.Rulesets.Mods { - public abstract class ModPerfect : ModSuddenDeath + public abstract class ModPerfect : ModSuddenDeath, IApplicableToScoreProcessor { public override string Name => "Perfect"; public override string ShortenedName => "PF"; public override string Description => "SS or quit."; + + public bool onFailCheck(ScoreProcessor scoreProcessor) + { + return scoreProcessor.Accuracy.Value != 1; + } + + public virtual void ApplyToScoreProcessor(ScoreProcessor scoreProcessor) + { + scoreProcessor.FailChecker += onFailCheck; + } } -} \ No newline at end of file +} diff --git a/osu.Game/Rulesets/Mods/ModSuddenDeath.cs b/osu.Game/Rulesets/Mods/ModSuddenDeath.cs index 999cb40f89..c71442fa28 100644 --- a/osu.Game/Rulesets/Mods/ModSuddenDeath.cs +++ b/osu.Game/Rulesets/Mods/ModSuddenDeath.cs @@ -3,10 +3,11 @@ using System; using osu.Game.Graphics; +using osu.Game.Rulesets.Scoring; namespace osu.Game.Rulesets.Mods { - public abstract class ModSuddenDeath : Mod + public abstract class ModSuddenDeath : Mod, IApplicableToScoreProcessor { public override string Name => "Sudden Death"; public override string ShortenedName => "SD"; @@ -16,5 +17,15 @@ namespace osu.Game.Rulesets.Mods public override double ScoreMultiplier => 1; public override bool Ranked => true; public override Type[] IncompatibleMods => new[] { typeof(ModNoFail), typeof(ModRelax), typeof(ModAutoplay) }; + + public bool onFailCheck(ScoreProcessor scoreProcessor) + { + return scoreProcessor.Combo.Value != scoreProcessor.HighestCombo.Value; + } + + public virtual void ApplyToScoreProcessor(ScoreProcessor scoreProcessor) + { + scoreProcessor.FailChecker += onFailCheck; + } } -} \ No newline at end of file +} diff --git a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs index f579b94c69..997dfc2a58 100644 --- a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs +++ b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs @@ -3,6 +3,7 @@ using System; using System.Diagnostics; +using System.Collections.Generic; using osu.Framework.Configuration; using osu.Game.Beatmaps; using osu.Game.Rulesets.Judgements; @@ -31,6 +32,11 @@ namespace osu.Game.Rulesets.Scoring /// public event Action NewJudgement; + /// + /// Invoked when we want to check if a failure condition has been fulfilled + /// + public event Func FailChecker; + /// /// The current total score. /// @@ -66,8 +72,6 @@ namespace osu.Game.Rulesets.Scoring /// protected virtual bool HasCompleted => false; - public int strictFail = 0; - /// /// Whether this ScoreProcessor has already triggered the failed state. /// @@ -78,16 +82,6 @@ namespace osu.Game.Rulesets.Scoring /// protected virtual bool FailCondition => Health.Value == Health.MinValue; - /// - /// The conditions for failing if the Sudden Death mod is enabled. - /// - protected virtual bool SuddenDeathFailCondition => Combo.Value != HighestCombo.Value; - - /// - /// The conditions for failing if the Perfect mod is enabled. - /// - protected virtual bool PerfectFailCondition => Accuracy.Value != 1; - protected ScoreProcessor() { Combo.ValueChanged += delegate { HighestCombo.Value = Math.Max(HighestCombo.Value, Combo.Value); }; @@ -133,16 +127,11 @@ namespace osu.Game.Rulesets.Scoring /// protected void UpdateFailed() { - if (HasFailed) + if (HasFailed || !FailCondition) return; - if(FailCondition || - (strictFail==1 && SuddenDeathFailCondition) || - (strictFail==2 && PerfectFailCondition)) - { - if (Failed?.Invoke() != false) - HasFailed = true; - } + if (Failed?.Invoke() != false) + HasFailed = true; } /// @@ -157,6 +146,18 @@ namespace osu.Game.Rulesets.Scoring AllJudged?.Invoke(); } + protected void CheckAlternateFailConditions() + { + if (HasFailed) + return; + + if (FailChecker?.Invoke(this) == true) + { + if (Failed?.Invoke() != false) + HasFailed = true; + } + } + /// /// Retrieve a score populated with data for the current play this processor is responsible for. /// @@ -233,6 +234,8 @@ namespace osu.Game.Rulesets.Scoring OnNewJudgement(judgement); updateScore(); + CheckAlternateFailConditions(); + NotifyNewJudgement(judgement); UpdateFailed(); } diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 2603fee769..0bff13a46a 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -228,11 +228,15 @@ namespace osu.Game.Screens.Play scoreProcessor.AllJudged += onCompletion; scoreProcessor.Failed += onFail; - if (Beatmap.Value.Mods.Value.Any(m => m.Name == "Sudden Death")) - scoreProcessor.strictFail = 1; + applyAlternateFailConditions(); + } - if (Beatmap.Value.Mods.Value.Any(m => m.Name == "Perfect")) - scoreProcessor.strictFail = 2; + private void applyAlternateFailConditions() + { + foreach(var mod in Beatmap.Value.Mods.Value.OfType()) + { + mod.ApplyToScoreProcessor(scoreProcessor); + } } private void applyRateFromMods() diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 7b479bdba2..5306f0df4a 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -294,6 +294,7 @@ + From 6df18ffb7accaeeb96254af4818350e1859235b1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 20 Nov 2017 18:14:30 +0900 Subject: [PATCH 0718/1263] FocusedTextBox should not handle repeated escapes --- osu.Game/Graphics/UserInterface/FocusedTextBox.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Graphics/UserInterface/FocusedTextBox.cs b/osu.Game/Graphics/UserInterface/FocusedTextBox.cs index fe060f70f0..206c7a839d 100644 --- a/osu.Game/Graphics/UserInterface/FocusedTextBox.cs +++ b/osu.Game/Graphics/UserInterface/FocusedTextBox.cs @@ -38,7 +38,7 @@ namespace osu.Game.Graphics.UserInterface protected override bool OnKeyDown(InputState state, KeyDownEventArgs args) { - if (args.Key == Key.Escape) + if (!args.Repeat && args.Key == Key.Escape) { if (Text.Length > 0) Text = string.Empty; From 165ac8cdec031195c565a4dfbad2d26a8ba218b0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 20 Nov 2017 21:21:34 +0900 Subject: [PATCH 0719/1263] Update framework --- osu-framework | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu-framework b/osu-framework index f27e36d405..14eb531c00 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit f27e36d405dd3f041e19defd59ecbb389ba84617 +Subproject commit 14eb531c0056b8569f21b3571890383ffbea768e From 6d74fd254c389d71fe2af0c712e3307f2ad92518 Mon Sep 17 00:00:00 2001 From: Brayzure Date: Mon, 20 Nov 2017 20:25:14 -0500 Subject: [PATCH 0720/1263] Remove Extraneous Using Statement - System.Collections.Generic was leftover from a previous attempt --- osu.Game/Rulesets/Scoring/ScoreProcessor.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs index 997dfc2a58..c3ae887a9f 100644 --- a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs +++ b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs @@ -3,7 +3,6 @@ using System; using System.Diagnostics; -using System.Collections.Generic; using osu.Framework.Configuration; using osu.Game.Beatmaps; using osu.Game.Rulesets.Judgements; From 2b0295ed86660cd9729abfe616e3ad6a24e282c8 Mon Sep 17 00:00:00 2001 From: Brayzure Date: Mon, 20 Nov 2017 20:49:31 -0500 Subject: [PATCH 0721/1263] Proper Public Method Case - onFailCheck to OnFailCheck --- osu.Game/Rulesets/Mods/ModPerfect.cs | 4 ++-- osu.Game/Rulesets/Mods/ModSuddenDeath.cs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game/Rulesets/Mods/ModPerfect.cs b/osu.Game/Rulesets/Mods/ModPerfect.cs index 7b79493d65..cf7bf141c3 100644 --- a/osu.Game/Rulesets/Mods/ModPerfect.cs +++ b/osu.Game/Rulesets/Mods/ModPerfect.cs @@ -11,14 +11,14 @@ namespace osu.Game.Rulesets.Mods public override string ShortenedName => "PF"; public override string Description => "SS or quit."; - public bool onFailCheck(ScoreProcessor scoreProcessor) + public bool OnFailCheck(ScoreProcessor scoreProcessor) { return scoreProcessor.Accuracy.Value != 1; } public virtual void ApplyToScoreProcessor(ScoreProcessor scoreProcessor) { - scoreProcessor.FailChecker += onFailCheck; + scoreProcessor.FailChecker += OnFailCheck; } } } diff --git a/osu.Game/Rulesets/Mods/ModSuddenDeath.cs b/osu.Game/Rulesets/Mods/ModSuddenDeath.cs index c71442fa28..6675c41bd4 100644 --- a/osu.Game/Rulesets/Mods/ModSuddenDeath.cs +++ b/osu.Game/Rulesets/Mods/ModSuddenDeath.cs @@ -18,14 +18,14 @@ namespace osu.Game.Rulesets.Mods public override bool Ranked => true; public override Type[] IncompatibleMods => new[] { typeof(ModNoFail), typeof(ModRelax), typeof(ModAutoplay) }; - public bool onFailCheck(ScoreProcessor scoreProcessor) + public bool OnFailCheck(ScoreProcessor scoreProcessor) { return scoreProcessor.Combo.Value != scoreProcessor.HighestCombo.Value; } public virtual void ApplyToScoreProcessor(ScoreProcessor scoreProcessor) { - scoreProcessor.FailChecker += onFailCheck; + scoreProcessor.FailChecker += OnFailCheck; } } } From 4f6263ef868e64a473c5189531d3f19e6cbe9005 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 21 Nov 2017 11:49:42 +0900 Subject: [PATCH 0722/1263] Make many internal classes and methods public This is important when using dynamic compiling to rapidly iterate. Until we actually split projects out into pieces (like the abstract ruleset project we have talked about) there is no advantage to using internal in the osu! game code. --- osu.Game/Beatmaps/Drawables/BeatmapBackgroundSprite.cs | 2 +- osu.Game/Beatmaps/DummyWorkingBeatmap.cs | 2 +- osu.Game/Graphics/UserInterface/DialogButton.cs | 2 +- osu.Game/Graphics/UserInterface/Volume/VolumeControl.cs | 4 ++-- .../Graphics/UserInterface/Volume/VolumeControlReceptor.cs | 2 +- osu.Game/Graphics/UserInterface/Volume/VolumeMeter.cs | 4 ++-- osu.Game/Online/API/OAuth.cs | 2 +- osu.Game/Online/API/OAuthToken.cs | 2 +- osu.Game/Online/Multiplayer/GameType.cs | 2 +- osu.Game/Overlays/ChatOverlay.cs | 2 +- osu.Game/Overlays/KeyBinding/KeyBindingRow.cs | 2 +- osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs | 2 +- osu.Game/Overlays/LoginOverlay.cs | 2 +- osu.Game/Overlays/Music/FilterControl.cs | 2 +- osu.Game/Overlays/Music/PlaylistItem.cs | 2 +- osu.Game/Overlays/Music/PlaylistList.cs | 2 +- osu.Game/Overlays/Settings/SettingsItem.cs | 6 +++--- osu.Game/Overlays/Settings/SettingsLabel.cs | 2 +- osu.Game/Overlays/Settings/Sidebar.cs | 6 +++--- osu.Game/Overlays/SettingsOverlay.cs | 2 +- osu.Game/Overlays/Toolbar/ToolbarChatButton.cs | 4 ++-- osu.Game/Overlays/Toolbar/ToolbarDirectButton.cs | 4 ++-- osu.Game/Overlays/Toolbar/ToolbarHomeButton.cs | 4 ++-- osu.Game/Overlays/Toolbar/ToolbarModeSelector.cs | 2 +- osu.Game/Overlays/Toolbar/ToolbarMusicButton.cs | 4 ++-- osu.Game/Overlays/Toolbar/ToolbarNotificationButton.cs | 4 ++-- osu.Game/Overlays/Toolbar/ToolbarOverlayToggleButton.cs | 2 +- osu.Game/Overlays/Toolbar/ToolbarSettingsButton.cs | 4 ++-- osu.Game/Overlays/Toolbar/ToolbarSocialButton.cs | 4 ++-- osu.Game/Overlays/Toolbar/ToolbarUserArea.cs | 2 +- osu.Game/Overlays/Toolbar/ToolbarUserButton.cs | 2 +- osu.Game/Rulesets/Judgements/Judgement.cs | 6 +++--- .../Rulesets/Objects/Legacy/Catch/ConvertHitObjectParser.cs | 2 +- .../Rulesets/Objects/Legacy/Mania/ConvertHitObjectParser.cs | 2 +- .../Rulesets/Objects/Legacy/Osu/ConvertHitObjectParser.cs | 2 +- .../Rulesets/Objects/Legacy/Taiko/ConvertHitObjectParser.cs | 2 +- osu.Game/Rulesets/Timing/LinearScrollingContainer.cs | 2 +- osu.Game/Rulesets/UI/Playfield.cs | 2 +- osu.Game/Rulesets/UI/RulesetContainer.cs | 2 +- osu.Game/Screens/Charts/ChartInfo.cs | 2 +- osu.Game/Screens/Charts/ChartListing.cs | 2 +- osu.Game/Screens/Direct/OnlineListing.cs | 2 +- .../Edit/Components/Timelines/Summary/Parts/BookmarkPart.cs | 2 +- .../Edit/Components/Timelines/Summary/Parts/BreakPart.cs | 2 +- .../Components/Timelines/Summary/Parts/ControlPointPart.cs | 2 +- .../Edit/Components/Timelines/Summary/Parts/MarkerPart.cs | 2 +- .../Edit/Components/Timelines/Summary/Parts/TimelinePart.cs | 2 +- .../Summary/Visualisations/DurationVisualisation.cs | 2 +- .../Timelines/Summary/Visualisations/PointVisualisation.cs | 2 +- osu.Game/Screens/Edit/Screens/Design/Design.cs | 2 +- osu.Game/Screens/Menu/ButtonSystem.cs | 6 +++--- osu.Game/Screens/Menu/Intro.cs | 2 +- osu.Game/Screens/Menu/OsuLogo.cs | 2 +- osu.Game/Screens/Multiplayer/Lobby.cs | 2 +- osu.Game/Screens/Multiplayer/Match.cs | 2 +- osu.Game/Screens/Multiplayer/MatchCreate.cs | 2 +- osu.Game/Screens/Ranking/ResultsPage.cs | 2 +- osu.Game/Screens/Ranking/ResultsPageRanking.cs | 4 ++-- osu.Game/Screens/Ranking/ResultsPageScore.cs | 2 +- osu.Game/Screens/Select/BeatmapCarousel.cs | 4 ++-- osu.Game/Screens/Select/BeatmapInfoWedge.cs | 2 +- .../Screens/Tournament/Components/VisualiserContainer.cs | 2 +- 62 files changed, 81 insertions(+), 81 deletions(-) diff --git a/osu.Game/Beatmaps/Drawables/BeatmapBackgroundSprite.cs b/osu.Game/Beatmaps/Drawables/BeatmapBackgroundSprite.cs index 0ac8d12591..e4904786c7 100644 --- a/osu.Game/Beatmaps/Drawables/BeatmapBackgroundSprite.cs +++ b/osu.Game/Beatmaps/Drawables/BeatmapBackgroundSprite.cs @@ -7,7 +7,7 @@ using osu.Framework.Graphics.Sprites; namespace osu.Game.Beatmaps.Drawables { - internal class BeatmapBackgroundSprite : Sprite + public class BeatmapBackgroundSprite : Sprite { private readonly WorkingBeatmap working; diff --git a/osu.Game/Beatmaps/DummyWorkingBeatmap.cs b/osu.Game/Beatmaps/DummyWorkingBeatmap.cs index c15d585eb2..c187aa592a 100644 --- a/osu.Game/Beatmaps/DummyWorkingBeatmap.cs +++ b/osu.Game/Beatmaps/DummyWorkingBeatmap.cs @@ -11,7 +11,7 @@ using osu.Game.Rulesets.UI; namespace osu.Game.Beatmaps { - internal class DummyWorkingBeatmap : WorkingBeatmap + public class DummyWorkingBeatmap : WorkingBeatmap { private readonly OsuGameBase game; diff --git a/osu.Game/Graphics/UserInterface/DialogButton.cs b/osu.Game/Graphics/UserInterface/DialogButton.cs index 289ccbf5cd..bb62815a7b 100644 --- a/osu.Game/Graphics/UserInterface/DialogButton.cs +++ b/osu.Game/Graphics/UserInterface/DialogButton.cs @@ -66,7 +66,7 @@ namespace osu.Game.Graphics.UserInterface } private float textSize = 28; - internal float TextSize + public float TextSize { get { diff --git a/osu.Game/Graphics/UserInterface/Volume/VolumeControl.cs b/osu.Game/Graphics/UserInterface/Volume/VolumeControl.cs index 8c777f491b..273a2279bf 100644 --- a/osu.Game/Graphics/UserInterface/Volume/VolumeControl.cs +++ b/osu.Game/Graphics/UserInterface/Volume/VolumeControl.cs @@ -11,7 +11,7 @@ using osu.Game.Input.Bindings; namespace osu.Game.Graphics.UserInterface.Volume { - internal class VolumeControl : OverlayContainer + public class VolumeControl : OverlayContainer { private readonly VolumeMeter volumeMeterMaster; @@ -119,4 +119,4 @@ namespace osu.Game.Graphics.UserInterface.Volume this.Delay(1000).Schedule(Hide, out popOutDelegate); } } -} \ No newline at end of file +} diff --git a/osu.Game/Graphics/UserInterface/Volume/VolumeControlReceptor.cs b/osu.Game/Graphics/UserInterface/Volume/VolumeControlReceptor.cs index c222fecb5d..7c740f16ce 100644 --- a/osu.Game/Graphics/UserInterface/Volume/VolumeControlReceptor.cs +++ b/osu.Game/Graphics/UserInterface/Volume/VolumeControlReceptor.cs @@ -8,7 +8,7 @@ using osu.Game.Input.Bindings; namespace osu.Game.Graphics.UserInterface.Volume { - internal class VolumeControlReceptor : Container, IKeyBindingHandler + public class VolumeControlReceptor : Container, IKeyBindingHandler { public Func ActionRequested; diff --git a/osu.Game/Graphics/UserInterface/Volume/VolumeMeter.cs b/osu.Game/Graphics/UserInterface/Volume/VolumeMeter.cs index 81c4fa9bae..d55b16563d 100644 --- a/osu.Game/Graphics/UserInterface/Volume/VolumeMeter.cs +++ b/osu.Game/Graphics/UserInterface/Volume/VolumeMeter.cs @@ -13,7 +13,7 @@ using osu.Game.Input.Bindings; namespace osu.Game.Graphics.UserInterface.Volume { - internal class VolumeMeter : Container, IKeyBindingHandler + public class VolumeMeter : Container, IKeyBindingHandler { private readonly Box meterFill; public BindableDouble Bindable { get; } = new BindableDouble(); @@ -108,4 +108,4 @@ namespace osu.Game.Graphics.UserInterface.Volume public bool OnReleased(GlobalAction action) => false; } -} \ No newline at end of file +} diff --git a/osu.Game/Online/API/OAuth.cs b/osu.Game/Online/API/OAuth.cs index ca38f72904..322688ced9 100644 --- a/osu.Game/Online/API/OAuth.cs +++ b/osu.Game/Online/API/OAuth.cs @@ -6,7 +6,7 @@ using osu.Framework.IO.Network; namespace osu.Game.Online.API { - internal class OAuth + public class OAuth { private readonly string clientId; private readonly string clientSecret; diff --git a/osu.Game/Online/API/OAuthToken.cs b/osu.Game/Online/API/OAuthToken.cs index 2abd7b6c1f..0c9dc26b59 100644 --- a/osu.Game/Online/API/OAuthToken.cs +++ b/osu.Game/Online/API/OAuthToken.cs @@ -8,7 +8,7 @@ using Newtonsoft.Json; namespace osu.Game.Online.API { [Serializable] - internal class OAuthToken + public class OAuthToken { /// /// OAuth 2.0 access token. diff --git a/osu.Game/Online/Multiplayer/GameType.cs b/osu.Game/Online/Multiplayer/GameType.cs index c94b409d1b..7bec0e94bb 100644 --- a/osu.Game/Online/Multiplayer/GameType.cs +++ b/osu.Game/Online/Multiplayer/GameType.cs @@ -100,7 +100,7 @@ namespace osu.Game.Online.Multiplayer } } - internal class VersusRow : FillFlowContainer + public class VersusRow : FillFlowContainer { public VersusRow(Color4 first, Color4 second, float size) { diff --git a/osu.Game/Overlays/ChatOverlay.cs b/osu.Game/Overlays/ChatOverlay.cs index 24fc322199..c5ffc5a2f1 100644 --- a/osu.Game/Overlays/ChatOverlay.cs +++ b/osu.Game/Overlays/ChatOverlay.cs @@ -58,7 +58,7 @@ namespace osu.Game.Overlays private readonly Box chatBackground; private readonly Box tabBackground; - public Bindable ChatHeight { get; internal set; } + public Bindable ChatHeight { get; public set; } private readonly Container channelSelectionContainer; private readonly ChannelSelectionOverlay channelSelection; diff --git a/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs b/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs index 4141a502a0..509a4f3856 100644 --- a/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs +++ b/osu.Game/Overlays/KeyBinding/KeyBindingRow.cs @@ -19,7 +19,7 @@ using OpenTK.Input; namespace osu.Game.Overlays.KeyBinding { - internal class KeyBindingRow : Container, IFilterable + public class KeyBindingRow : Container, IFilterable { private readonly object action; private readonly IEnumerable bindings; diff --git a/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs b/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs index 2ff5d7b81f..30ff0ab026 100644 --- a/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs +++ b/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs @@ -55,7 +55,7 @@ namespace osu.Game.Overlays.KeyBinding } } - internal class ResetButton : OsuButton + public class ResetButton : OsuButton { [BackgroundDependencyLoader] private void load(OsuColour colours) diff --git a/osu.Game/Overlays/LoginOverlay.cs b/osu.Game/Overlays/LoginOverlay.cs index 0a47637589..fe3a846eb2 100644 --- a/osu.Game/Overlays/LoginOverlay.cs +++ b/osu.Game/Overlays/LoginOverlay.cs @@ -13,7 +13,7 @@ using osu.Game.Graphics.Cursor; namespace osu.Game.Overlays { - internal class LoginOverlay : OsuFocusedOverlayContainer + public class LoginOverlay : OsuFocusedOverlayContainer { private LoginSettings settingsSection; diff --git a/osu.Game/Overlays/Music/FilterControl.cs b/osu.Game/Overlays/Music/FilterControl.cs index 56cd6e864b..52d311e501 100644 --- a/osu.Game/Overlays/Music/FilterControl.cs +++ b/osu.Game/Overlays/Music/FilterControl.cs @@ -13,7 +13,7 @@ using System; namespace osu.Game.Overlays.Music { - internal class FilterControl : Container + public class FilterControl : Container { public readonly FilterTextBox Search; diff --git a/osu.Game/Overlays/Music/PlaylistItem.cs b/osu.Game/Overlays/Music/PlaylistItem.cs index 723b3f4e96..8168929f9c 100644 --- a/osu.Game/Overlays/Music/PlaylistItem.cs +++ b/osu.Game/Overlays/Music/PlaylistItem.cs @@ -17,7 +17,7 @@ using OpenTK; namespace osu.Game.Overlays.Music { - internal class PlaylistItem : Container, IFilterable, IDraggable + public class PlaylistItem : Container, IFilterable, IDraggable { private const float fade_duration = 100; diff --git a/osu.Game/Overlays/Music/PlaylistList.cs b/osu.Game/Overlays/Music/PlaylistList.cs index 6f1eaded7f..af01cdc451 100644 --- a/osu.Game/Overlays/Music/PlaylistList.cs +++ b/osu.Game/Overlays/Music/PlaylistList.cs @@ -14,7 +14,7 @@ using OpenTK; namespace osu.Game.Overlays.Music { - internal class PlaylistList : CompositeDrawable + public class PlaylistList : CompositeDrawable { public Action OnSelect; diff --git a/osu.Game/Overlays/Settings/SettingsItem.cs b/osu.Game/Overlays/Settings/SettingsItem.cs index a3933b775e..d9aac58c54 100644 --- a/osu.Game/Overlays/Settings/SettingsItem.cs +++ b/osu.Game/Overlays/Settings/SettingsItem.cs @@ -135,7 +135,7 @@ namespace osu.Game.Overlays.Settings private class RestoreDefaultValueButton : Box, IHasTooltip { private Bindable bindable; - internal Bindable Bindable + public Bindable Bindable { get { return bindable; } set @@ -185,13 +185,13 @@ namespace osu.Game.Overlays.Settings UpdateState(); } - internal void SetButtonColour(Color4 buttonColour) + public void SetButtonColour(Color4 buttonColour) { this.buttonColour = buttonColour; UpdateState(); } - internal void UpdateState() + public void UpdateState() { if (bindable == null) return; diff --git a/osu.Game/Overlays/Settings/SettingsLabel.cs b/osu.Game/Overlays/Settings/SettingsLabel.cs index 7d1364ef41..6a1d3ae72c 100644 --- a/osu.Game/Overlays/Settings/SettingsLabel.cs +++ b/osu.Game/Overlays/Settings/SettingsLabel.cs @@ -7,7 +7,7 @@ using osu.Game.Graphics; namespace osu.Game.Overlays.Settings { - internal class SettingsLabel : SettingsItem + public class SettingsLabel : SettingsItem { protected override Drawable CreateControl() => null; diff --git a/osu.Game/Overlays/Settings/Sidebar.cs b/osu.Game/Overlays/Settings/Sidebar.cs index 55167188a3..4e51ae3a2e 100644 --- a/osu.Game/Overlays/Settings/Sidebar.cs +++ b/osu.Game/Overlays/Settings/Sidebar.cs @@ -18,8 +18,8 @@ namespace osu.Game.Overlays.Settings public class Sidebar : Container, IStateful { private readonly FillFlowContainer content; - internal const float DEFAULT_WIDTH = ToolbarButton.WIDTH; - internal const int EXPANDED_WIDTH = 200; + public const float DEFAULT_WIDTH = ToolbarButton.WIDTH; + public const int EXPANDED_WIDTH = 200; public event Action StateChanged; @@ -137,4 +137,4 @@ namespace osu.Game.Overlays.Settings Contracted, Expanded, } -} \ No newline at end of file +} diff --git a/osu.Game/Overlays/SettingsOverlay.cs b/osu.Game/Overlays/SettingsOverlay.cs index ddef5d1001..798fa00032 100644 --- a/osu.Game/Overlays/SettingsOverlay.cs +++ b/osu.Game/Overlays/SettingsOverlay.cs @@ -20,7 +20,7 @@ namespace osu.Game.Overlays { public abstract class SettingsOverlay : OsuFocusedOverlayContainer { - internal const float CONTENT_MARGINS = 10; + public const float CONTENT_MARGINS = 10; public const float TRANSITION_LENGTH = 600; diff --git a/osu.Game/Overlays/Toolbar/ToolbarChatButton.cs b/osu.Game/Overlays/Toolbar/ToolbarChatButton.cs index 2e2786851c..ed206e7e1d 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarChatButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarChatButton.cs @@ -6,7 +6,7 @@ using osu.Game.Graphics; namespace osu.Game.Overlays.Toolbar { - internal class ToolbarChatButton : ToolbarOverlayToggleButton + public class ToolbarChatButton : ToolbarOverlayToggleButton { public ToolbarChatButton() { @@ -19,4 +19,4 @@ namespace osu.Game.Overlays.Toolbar StateContainer = chat; } } -} \ No newline at end of file +} diff --git a/osu.Game/Overlays/Toolbar/ToolbarDirectButton.cs b/osu.Game/Overlays/Toolbar/ToolbarDirectButton.cs index dacb6d67b8..7d25440e2c 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarDirectButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarDirectButton.cs @@ -6,7 +6,7 @@ using osu.Game.Graphics; namespace osu.Game.Overlays.Toolbar { - internal class ToolbarDirectButton : ToolbarOverlayToggleButton + public class ToolbarDirectButton : ToolbarOverlayToggleButton { public ToolbarDirectButton() { @@ -19,4 +19,4 @@ namespace osu.Game.Overlays.Toolbar StateContainer = direct; } } -} \ No newline at end of file +} diff --git a/osu.Game/Overlays/Toolbar/ToolbarHomeButton.cs b/osu.Game/Overlays/Toolbar/ToolbarHomeButton.cs index 431cc73887..9f020cada5 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarHomeButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarHomeButton.cs @@ -5,7 +5,7 @@ using osu.Game.Graphics; namespace osu.Game.Overlays.Toolbar { - internal class ToolbarHomeButton : ToolbarButton + public class ToolbarHomeButton : ToolbarButton { public ToolbarHomeButton() { @@ -14,4 +14,4 @@ namespace osu.Game.Overlays.Toolbar TooltipSub = "Return to the main menu"; } } -} \ No newline at end of file +} diff --git a/osu.Game/Overlays/Toolbar/ToolbarModeSelector.cs b/osu.Game/Overlays/Toolbar/ToolbarModeSelector.cs index da72ae0347..319dd63bc9 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarModeSelector.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarModeSelector.cs @@ -14,7 +14,7 @@ using osu.Game.Rulesets; namespace osu.Game.Overlays.Toolbar { - internal class ToolbarModeSelector : Container + public class ToolbarModeSelector : Container { private const float padding = 10; diff --git a/osu.Game/Overlays/Toolbar/ToolbarMusicButton.cs b/osu.Game/Overlays/Toolbar/ToolbarMusicButton.cs index 82599b9a0d..d150aacdf9 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarMusicButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarMusicButton.cs @@ -6,7 +6,7 @@ using osu.Game.Graphics; namespace osu.Game.Overlays.Toolbar { - internal class ToolbarMusicButton : ToolbarOverlayToggleButton + public class ToolbarMusicButton : ToolbarOverlayToggleButton { public ToolbarMusicButton() { @@ -19,4 +19,4 @@ namespace osu.Game.Overlays.Toolbar StateContainer = music; } } -} \ No newline at end of file +} diff --git a/osu.Game/Overlays/Toolbar/ToolbarNotificationButton.cs b/osu.Game/Overlays/Toolbar/ToolbarNotificationButton.cs index dcadc4bf56..e11a22d675 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarNotificationButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarNotificationButton.cs @@ -7,7 +7,7 @@ using osu.Game.Graphics; namespace osu.Game.Overlays.Toolbar { - internal class ToolbarNotificationButton : ToolbarOverlayToggleButton + public class ToolbarNotificationButton : ToolbarOverlayToggleButton { protected override Anchor TooltipAnchor => Anchor.TopRight; @@ -24,4 +24,4 @@ namespace osu.Game.Overlays.Toolbar StateContainer = notificationOverlay; } } -} \ No newline at end of file +} diff --git a/osu.Game/Overlays/Toolbar/ToolbarOverlayToggleButton.cs b/osu.Game/Overlays/Toolbar/ToolbarOverlayToggleButton.cs index 28ecf6ad03..69fdd27d5d 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarOverlayToggleButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarOverlayToggleButton.cs @@ -9,7 +9,7 @@ using osu.Game.Graphics; namespace osu.Game.Overlays.Toolbar { - internal class ToolbarOverlayToggleButton : ToolbarButton + public class ToolbarOverlayToggleButton : ToolbarButton { private readonly Box stateBackground; diff --git a/osu.Game/Overlays/Toolbar/ToolbarSettingsButton.cs b/osu.Game/Overlays/Toolbar/ToolbarSettingsButton.cs index 2eb8c15dcf..cf4f664e81 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarSettingsButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarSettingsButton.cs @@ -6,7 +6,7 @@ using osu.Game.Graphics; namespace osu.Game.Overlays.Toolbar { - internal class ToolbarSettingsButton : ToolbarOverlayToggleButton + public class ToolbarSettingsButton : ToolbarOverlayToggleButton { public ToolbarSettingsButton() { @@ -21,4 +21,4 @@ namespace osu.Game.Overlays.Toolbar StateContainer = settings; } } -} \ No newline at end of file +} diff --git a/osu.Game/Overlays/Toolbar/ToolbarSocialButton.cs b/osu.Game/Overlays/Toolbar/ToolbarSocialButton.cs index ed36fd8f9e..234d6f0f9a 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarSocialButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarSocialButton.cs @@ -6,7 +6,7 @@ using osu.Game.Graphics; namespace osu.Game.Overlays.Toolbar { - internal class ToolbarSocialButton : ToolbarOverlayToggleButton + public class ToolbarSocialButton : ToolbarOverlayToggleButton { public ToolbarSocialButton() { @@ -19,4 +19,4 @@ namespace osu.Game.Overlays.Toolbar StateContainer = chat; } } -} \ No newline at end of file +} diff --git a/osu.Game/Overlays/Toolbar/ToolbarUserArea.cs b/osu.Game/Overlays/Toolbar/ToolbarUserArea.cs index 95a25fcb86..4562464dfe 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarUserArea.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarUserArea.cs @@ -9,7 +9,7 @@ using OpenTK; namespace osu.Game.Overlays.Toolbar { - internal class ToolbarUserArea : Container + public class ToolbarUserArea : Container { public LoginOverlay LoginOverlay; private ToolbarUserButton button; diff --git a/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs b/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs index deacfbb9ec..3714094924 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs @@ -12,7 +12,7 @@ using OpenTK.Graphics; namespace osu.Game.Overlays.Toolbar { - internal class ToolbarUserButton : ToolbarButton, IOnlineComponent + public class ToolbarUserButton : ToolbarButton, IOnlineComponent { private readonly UpdateableAvatar avatar; diff --git a/osu.Game/Rulesets/Judgements/Judgement.cs b/osu.Game/Rulesets/Judgements/Judgement.cs index 2b5c4aae95..5ad18e67ee 100644 --- a/osu.Game/Rulesets/Judgements/Judgement.cs +++ b/osu.Game/Rulesets/Judgements/Judgement.cs @@ -20,12 +20,12 @@ namespace osu.Game.Rulesets.Judgements /// /// The combo prior to this judgement occurring. /// - internal int ComboAtJudgement; + public int ComboAtJudgement; /// /// The highest combo achieved prior to this judgement occurring. /// - internal int HighestComboAtJudgement; + public int HighestComboAtJudgement; /// /// Whether a successful hit occurred. @@ -41,7 +41,7 @@ namespace osu.Game.Rulesets.Judgements /// The offset from a perfect hit at which this judgement occurred. /// Populated when added via . /// - public double TimeOffset { get; internal set; } + public double TimeOffset { get; public set; } /// /// Whether the should affect the combo portion of the score. diff --git a/osu.Game/Rulesets/Objects/Legacy/Catch/ConvertHitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/Catch/ConvertHitObjectParser.cs index c7f7802191..667f921e04 100644 --- a/osu.Game/Rulesets/Objects/Legacy/Catch/ConvertHitObjectParser.cs +++ b/osu.Game/Rulesets/Objects/Legacy/Catch/ConvertHitObjectParser.cs @@ -11,7 +11,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Catch /// /// A HitObjectParser to parse legacy osu!catch Beatmaps. /// - internal class ConvertHitObjectParser : Legacy.ConvertHitObjectParser + public class ConvertHitObjectParser : Legacy.ConvertHitObjectParser { protected override HitObject CreateHit(Vector2 position, bool newCombo) { diff --git a/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHitObjectParser.cs index 7141876b8b..86dd40b06e 100644 --- a/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHitObjectParser.cs +++ b/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHitObjectParser.cs @@ -11,7 +11,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Mania /// /// A HitObjectParser to parse legacy osu!mania Beatmaps. /// - internal class ConvertHitObjectParser : Legacy.ConvertHitObjectParser + public class ConvertHitObjectParser : Legacy.ConvertHitObjectParser { protected override HitObject CreateHit(Vector2 position, bool newCombo) { diff --git a/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertHitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertHitObjectParser.cs index 00fe171f0f..24c205db13 100644 --- a/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertHitObjectParser.cs +++ b/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertHitObjectParser.cs @@ -11,7 +11,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Osu /// /// A HitObjectParser to parse legacy osu! Beatmaps. /// - internal class ConvertHitObjectParser : Legacy.ConvertHitObjectParser + public class ConvertHitObjectParser : Legacy.ConvertHitObjectParser { protected override HitObject CreateHit(Vector2 position, bool newCombo) { diff --git a/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertHitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertHitObjectParser.cs index 5929c5a907..0554cfd97d 100644 --- a/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertHitObjectParser.cs +++ b/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertHitObjectParser.cs @@ -11,7 +11,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Taiko /// /// A HitObjectParser to parse legacy osu!taiko Beatmaps. /// - internal class ConvertHitObjectParser : Legacy.ConvertHitObjectParser + public class ConvertHitObjectParser : Legacy.ConvertHitObjectParser { protected override HitObject CreateHit(Vector2 position, bool newCombo) { diff --git a/osu.Game/Rulesets/Timing/LinearScrollingContainer.cs b/osu.Game/Rulesets/Timing/LinearScrollingContainer.cs index f8e87bc022..b093cf3303 100644 --- a/osu.Game/Rulesets/Timing/LinearScrollingContainer.cs +++ b/osu.Game/Rulesets/Timing/LinearScrollingContainer.cs @@ -8,7 +8,7 @@ namespace osu.Game.Rulesets.Timing /// /// A which scrolls linearly relative to the start time. /// - internal class LinearScrollingContainer : ScrollingContainer + public class LinearScrollingContainer : ScrollingContainer { private readonly MultiplierControlPoint controlPoint; diff --git a/osu.Game/Rulesets/UI/Playfield.cs b/osu.Game/Rulesets/UI/Playfield.cs index 0270751946..b4a26344d5 100644 --- a/osu.Game/Rulesets/UI/Playfield.cs +++ b/osu.Game/Rulesets/UI/Playfield.cs @@ -20,7 +20,7 @@ namespace osu.Game.Rulesets.UI /// public HitObjectContainer HitObjects { get; protected set; } - internal Container ScaledContent; + public Container ScaledContent; /// /// Whether we are currently providing the local user a gameplay cursor. diff --git a/osu.Game/Rulesets/UI/RulesetContainer.cs b/osu.Game/Rulesets/UI/RulesetContainer.cs index 6726d94995..a5ac9c201a 100644 --- a/osu.Game/Rulesets/UI/RulesetContainer.cs +++ b/osu.Game/Rulesets/UI/RulesetContainer.cs @@ -61,7 +61,7 @@ namespace osu.Game.Rulesets.UI /// A visual representation of a . /// /// The ruleset being repesented. - internal RulesetContainer(Ruleset ruleset) + public RulesetContainer(Ruleset ruleset) { Ruleset = ruleset; } diff --git a/osu.Game/Screens/Charts/ChartInfo.cs b/osu.Game/Screens/Charts/ChartInfo.cs index b5ac5e4945..32577f3e05 100644 --- a/osu.Game/Screens/Charts/ChartInfo.cs +++ b/osu.Game/Screens/Charts/ChartInfo.cs @@ -3,7 +3,7 @@ namespace osu.Game.Screens.Charts { - internal class ChartInfo : ScreenWhiteBox + public class ChartInfo : ScreenWhiteBox { } } diff --git a/osu.Game/Screens/Charts/ChartListing.cs b/osu.Game/Screens/Charts/ChartListing.cs index 7bc6f0fa03..41c2a01600 100644 --- a/osu.Game/Screens/Charts/ChartListing.cs +++ b/osu.Game/Screens/Charts/ChartListing.cs @@ -6,7 +6,7 @@ using System.Collections.Generic; namespace osu.Game.Screens.Charts { - internal class ChartListing : ScreenWhiteBox + public class ChartListing : ScreenWhiteBox { protected override IEnumerable PossibleChildren => new[] { typeof(ChartInfo) diff --git a/osu.Game/Screens/Direct/OnlineListing.cs b/osu.Game/Screens/Direct/OnlineListing.cs index 9ce23c2863..ff6c599e6f 100644 --- a/osu.Game/Screens/Direct/OnlineListing.cs +++ b/osu.Game/Screens/Direct/OnlineListing.cs @@ -3,7 +3,7 @@ namespace osu.Game.Screens.Direct { - internal class OnlineListing : ScreenWhiteBox + public class OnlineListing : ScreenWhiteBox { } } diff --git a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/BookmarkPart.cs b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/BookmarkPart.cs index 1793cb4334..cdb2985473 100644 --- a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/BookmarkPart.cs +++ b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/BookmarkPart.cs @@ -11,7 +11,7 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts /// /// The part of the timeline that displays bookmarks. /// - internal class BookmarkPart : TimelinePart + public class BookmarkPart : TimelinePart { protected override void LoadBeatmap(WorkingBeatmap beatmap) { diff --git a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/BreakPart.cs b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/BreakPart.cs index 004491d489..380f8e2c7b 100644 --- a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/BreakPart.cs +++ b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/BreakPart.cs @@ -12,7 +12,7 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts /// /// The part of the timeline that displays breaks in the song. /// - internal class BreakPart : TimelinePart + public class BreakPart : TimelinePart { protected override void LoadBeatmap(WorkingBeatmap beatmap) { diff --git a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/ControlPointPart.cs b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/ControlPointPart.cs index d230578e13..405befb80a 100644 --- a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/ControlPointPart.cs +++ b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/ControlPointPart.cs @@ -14,7 +14,7 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts /// /// The part of the timeline that displays the control points. /// - internal class ControlPointPart : TimelinePart + public class ControlPointPart : TimelinePart { protected override void LoadBeatmap(WorkingBeatmap beatmap) { 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 0bdd081907..367cf4337d 100644 --- a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/MarkerPart.cs +++ b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/MarkerPart.cs @@ -15,7 +15,7 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts /// /// The part of the timeline that displays the current position of the song. /// - internal class MarkerPart : TimelinePart + public class MarkerPart : TimelinePart { private readonly Drawable marker; diff --git a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/TimelinePart.cs b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/TimelinePart.cs index 378ce78c67..229d06ef09 100644 --- a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/TimelinePart.cs +++ b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/TimelinePart.cs @@ -13,7 +13,7 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts /// /// Represents a part of the summary timeline.. /// - internal abstract class TimelinePart : CompositeDrawable + public abstract class TimelinePart : CompositeDrawable { public Bindable Beatmap = new Bindable(); diff --git a/osu.Game/Screens/Edit/Components/Timelines/Summary/Visualisations/DurationVisualisation.cs b/osu.Game/Screens/Edit/Components/Timelines/Summary/Visualisations/DurationVisualisation.cs index aee8e250c3..91f5e9b222 100644 --- a/osu.Game/Screens/Edit/Components/Timelines/Summary/Visualisations/DurationVisualisation.cs +++ b/osu.Game/Screens/Edit/Components/Timelines/Summary/Visualisations/DurationVisualisation.cs @@ -10,7 +10,7 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Visualisations /// /// Represents a spanning point on a timeline part. /// - internal class DurationVisualisation : Container + public class DurationVisualisation : Container { protected DurationVisualisation(double startTime, double endTime) { diff --git a/osu.Game/Screens/Edit/Components/Timelines/Summary/Visualisations/PointVisualisation.cs b/osu.Game/Screens/Edit/Components/Timelines/Summary/Visualisations/PointVisualisation.cs index 9d7272808b..4719db37d1 100644 --- a/osu.Game/Screens/Edit/Components/Timelines/Summary/Visualisations/PointVisualisation.cs +++ b/osu.Game/Screens/Edit/Components/Timelines/Summary/Visualisations/PointVisualisation.cs @@ -10,7 +10,7 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Visualisations /// /// Represents a singular point on a timeline part. /// - internal class PointVisualisation : Box + public class PointVisualisation : Box { protected PointVisualisation(double startTime) { diff --git a/osu.Game/Screens/Edit/Screens/Design/Design.cs b/osu.Game/Screens/Edit/Screens/Design/Design.cs index e527d7dad9..edd5ae1a1e 100644 --- a/osu.Game/Screens/Edit/Screens/Design/Design.cs +++ b/osu.Game/Screens/Edit/Screens/Design/Design.cs @@ -9,7 +9,7 @@ using OpenTK.Graphics; namespace osu.Game.Screens.Edit.Screens.Design { - internal class Design : EditorScreen + public class Design : EditorScreen { public Design() { diff --git a/osu.Game/Screens/Menu/ButtonSystem.cs b/osu.Game/Screens/Menu/ButtonSystem.cs index c3bd7c1f37..5a4a5f07b5 100644 --- a/osu.Game/Screens/Menu/ButtonSystem.cs +++ b/osu.Game/Screens/Menu/ButtonSystem.cs @@ -39,10 +39,10 @@ namespace osu.Game.Screens.Menu private readonly FlowContainerWithOrigin buttonFlow; //todo: make these non-internal somehow. - internal const float BUTTON_AREA_HEIGHT = 100; + public const float BUTTON_AREA_HEIGHT = 100; - internal const float BUTTON_WIDTH = 140f; - internal const float WEDGE_WIDTH = 20; + public const float BUTTON_WIDTH = 140f; + public const float WEDGE_WIDTH = 20; private OsuLogo logo; diff --git a/osu.Game/Screens/Menu/Intro.cs b/osu.Game/Screens/Menu/Intro.cs index 987e29d6d6..d7beb34a2f 100644 --- a/osu.Game/Screens/Menu/Intro.cs +++ b/osu.Game/Screens/Menu/Intro.cs @@ -25,7 +25,7 @@ namespace osu.Game.Screens.Menu /// /// Whether we have loaded the menu previously. /// - internal bool DidLoadMenu; + public bool DidLoadMenu; private MainMenu mainMenu; private SampleChannel welcome; diff --git a/osu.Game/Screens/Menu/OsuLogo.cs b/osu.Game/Screens/Menu/OsuLogo.cs index fb8e755b61..252f2d37b5 100644 --- a/osu.Game/Screens/Menu/OsuLogo.cs +++ b/osu.Game/Screens/Menu/OsuLogo.cs @@ -226,7 +226,7 @@ namespace osu.Game.Screens.Menu /// /// The animation to be performed /// If true, the new animation is delayed until all previous transforms finish. If false, existing transformed are cleared. - internal void AppendAnimatingAction(Action action, bool waitForPrevious) + public void AppendAnimatingAction(Action action, bool waitForPrevious) { Action runnableAction = () => { diff --git a/osu.Game/Screens/Multiplayer/Lobby.cs b/osu.Game/Screens/Multiplayer/Lobby.cs index d34da46ec3..b297835ca9 100644 --- a/osu.Game/Screens/Multiplayer/Lobby.cs +++ b/osu.Game/Screens/Multiplayer/Lobby.cs @@ -6,7 +6,7 @@ using System.Collections.Generic; namespace osu.Game.Screens.Multiplayer { - internal class Lobby : ScreenWhiteBox + public class Lobby : ScreenWhiteBox { protected override IEnumerable PossibleChildren => new[] { typeof(MatchCreate), diff --git a/osu.Game/Screens/Multiplayer/Match.cs b/osu.Game/Screens/Multiplayer/Match.cs index a0843bfcae..e50a7199a4 100644 --- a/osu.Game/Screens/Multiplayer/Match.cs +++ b/osu.Game/Screens/Multiplayer/Match.cs @@ -12,7 +12,7 @@ using osu.Framework.Graphics; namespace osu.Game.Screens.Multiplayer { - internal class Match : ScreenWhiteBox + public class Match : ScreenWhiteBox { protected override IEnumerable PossibleChildren => new[] { typeof(MatchSongSelect), diff --git a/osu.Game/Screens/Multiplayer/MatchCreate.cs b/osu.Game/Screens/Multiplayer/MatchCreate.cs index f28261fa7f..c232c38d08 100644 --- a/osu.Game/Screens/Multiplayer/MatchCreate.cs +++ b/osu.Game/Screens/Multiplayer/MatchCreate.cs @@ -6,7 +6,7 @@ using System.Collections.Generic; namespace osu.Game.Screens.Multiplayer { - internal class MatchCreate : ScreenWhiteBox + public class MatchCreate : ScreenWhiteBox { protected override IEnumerable PossibleChildren => new[] { typeof(Match) diff --git a/osu.Game/Screens/Ranking/ResultsPage.cs b/osu.Game/Screens/Ranking/ResultsPage.cs index 7f381ebf99..037d5ada09 100644 --- a/osu.Game/Screens/Ranking/ResultsPage.cs +++ b/osu.Game/Screens/Ranking/ResultsPage.cs @@ -14,7 +14,7 @@ using OpenTK.Graphics; namespace osu.Game.Screens.Ranking { - internal class ResultsPage : Container + public class ResultsPage : Container { protected readonly Score Score; protected readonly WorkingBeatmap Beatmap; diff --git a/osu.Game/Screens/Ranking/ResultsPageRanking.cs b/osu.Game/Screens/Ranking/ResultsPageRanking.cs index d316dc7fb4..c9d1061bd1 100644 --- a/osu.Game/Screens/Ranking/ResultsPageRanking.cs +++ b/osu.Game/Screens/Ranking/ResultsPageRanking.cs @@ -12,7 +12,7 @@ using osu.Framework.Graphics.Shapes; namespace osu.Game.Screens.Ranking { - internal class ResultsPageRanking : ResultsPage + public class ResultsPageRanking : ResultsPage { public ResultsPageRanking(Score score, WorkingBeatmap beatmap = null) : base(score, beatmap) { @@ -39,4 +39,4 @@ namespace osu.Game.Screens.Ranking }; } } -} \ No newline at end of file +} diff --git a/osu.Game/Screens/Ranking/ResultsPageScore.cs b/osu.Game/Screens/Ranking/ResultsPageScore.cs index 9104473b82..911b688669 100644 --- a/osu.Game/Screens/Ranking/ResultsPageScore.cs +++ b/osu.Game/Screens/Ranking/ResultsPageScore.cs @@ -26,7 +26,7 @@ using osu.Framework.Graphics.Shapes; namespace osu.Game.Screens.Ranking { - internal class ResultsPageScore : ResultsPage + public class ResultsPageScore : ResultsPage { private ScoreCounter scoreCounter; diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index f4dcf9a69e..452f8c484c 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -23,7 +23,7 @@ using osu.Game.Graphics.Cursor; namespace osu.Game.Screens.Select { - internal class BeatmapCarousel : OsuScrollContainer + public class BeatmapCarousel : OsuScrollContainer { public BeatmapInfo SelectedBeatmap => selectedPanel?.Beatmap; @@ -116,7 +116,7 @@ namespace osu.Game.Screens.Select Schedule(() => removeGroup(groups.Find(b => b.BeatmapSet.ID == beatmapSet.ID))); } - internal void UpdateBeatmap(BeatmapInfo beatmap) + public void UpdateBeatmap(BeatmapInfo beatmap) { // todo: this method should not run more than once for the same BeatmapSetInfo. var set = manager.QueryBeatmapSet(s => s.ID == beatmap.BeatmapSetInfoID); diff --git a/osu.Game/Screens/Select/BeatmapInfoWedge.cs b/osu.Game/Screens/Select/BeatmapInfoWedge.cs index dc3b012328..22cb718d0a 100644 --- a/osu.Game/Screens/Select/BeatmapInfoWedge.cs +++ b/osu.Game/Screens/Select/BeatmapInfoWedge.cs @@ -22,7 +22,7 @@ using osu.Framework.Graphics.Shapes; namespace osu.Game.Screens.Select { - internal class BeatmapInfoWedge : OverlayContainer + public class BeatmapInfoWedge : OverlayContainer { private static readonly Vector2 wedged_container_shear = new Vector2(0.15f, 0); diff --git a/osu.Game/Screens/Tournament/Components/VisualiserContainer.cs b/osu.Game/Screens/Tournament/Components/VisualiserContainer.cs index 3dd7207607..d2b2feb68d 100644 --- a/osu.Game/Screens/Tournament/Components/VisualiserContainer.cs +++ b/osu.Game/Screens/Tournament/Components/VisualiserContainer.cs @@ -12,7 +12,7 @@ using System.Linq; namespace osu.Game.Screens.Tournament.Components { - internal class VisualiserContainer : Container + public class VisualiserContainer : Container { /// /// Number of lines in the visualiser. From 2610cadd3cf4dfedda929a26f4abc91a047a65e7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 21 Nov 2017 12:11:29 +0900 Subject: [PATCH 0723/1263] CI fixes --- osu.Game/Overlays/ChatOverlay.cs | 2 +- osu.Game/Rulesets/Judgements/Judgement.cs | 2 +- osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs | 2 +- osu.Game/Rulesets/UI/RulesetContainer.cs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game/Overlays/ChatOverlay.cs b/osu.Game/Overlays/ChatOverlay.cs index c5ffc5a2f1..9f40a08ad2 100644 --- a/osu.Game/Overlays/ChatOverlay.cs +++ b/osu.Game/Overlays/ChatOverlay.cs @@ -58,7 +58,7 @@ namespace osu.Game.Overlays private readonly Box chatBackground; private readonly Box tabBackground; - public Bindable ChatHeight { get; public set; } + public Bindable ChatHeight { get; set; } private readonly Container channelSelectionContainer; private readonly ChannelSelectionOverlay channelSelection; diff --git a/osu.Game/Rulesets/Judgements/Judgement.cs b/osu.Game/Rulesets/Judgements/Judgement.cs index 5ad18e67ee..d804111a7f 100644 --- a/osu.Game/Rulesets/Judgements/Judgement.cs +++ b/osu.Game/Rulesets/Judgements/Judgement.cs @@ -41,7 +41,7 @@ namespace osu.Game.Rulesets.Judgements /// The offset from a perfect hit at which this judgement occurred. /// Populated when added via . /// - public double TimeOffset { get; public set; } + public double TimeOffset { get; set; } /// /// Whether the should affect the combo portion of the score. diff --git a/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs index b5e3f837fc..d4f9c7191a 100644 --- a/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs +++ b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs @@ -15,7 +15,7 @@ namespace osu.Game.Rulesets.Objects.Legacy /// /// A HitObjectParser to parse legacy Beatmaps. /// - internal abstract class ConvertHitObjectParser : HitObjectParser + public abstract class ConvertHitObjectParser : HitObjectParser { public override HitObject Parse(string text) { diff --git a/osu.Game/Rulesets/UI/RulesetContainer.cs b/osu.Game/Rulesets/UI/RulesetContainer.cs index a5ac9c201a..ec26f6f310 100644 --- a/osu.Game/Rulesets/UI/RulesetContainer.cs +++ b/osu.Game/Rulesets/UI/RulesetContainer.cs @@ -61,7 +61,7 @@ namespace osu.Game.Rulesets.UI /// A visual representation of a . /// /// The ruleset being repesented. - public RulesetContainer(Ruleset ruleset) + protected RulesetContainer(Ruleset ruleset) { Ruleset = ruleset; } From 5db2d383ed750e8d273f4dc514ae71e9a5c40d37 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 21 Nov 2017 11:48:27 +0900 Subject: [PATCH 0724/1263] Remove temporary variable in beatmap background update --- osu.Game/Screens/Backgrounds/BackgroundScreenBeatmap.cs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/osu.Game/Screens/Backgrounds/BackgroundScreenBeatmap.cs b/osu.Game/Screens/Backgrounds/BackgroundScreenBeatmap.cs index 29a422892f..7ae3f6931e 100644 --- a/osu.Game/Screens/Backgrounds/BackgroundScreenBeatmap.cs +++ b/osu.Game/Screens/Backgrounds/BackgroundScreenBeatmap.cs @@ -32,9 +32,7 @@ namespace osu.Game.Screens.Backgrounds Schedule(() => { - var newBackground = new BeatmapBackground(beatmap); - - LoadComponentAsync(newBackground, delegate + LoadComponentAsync(new BeatmapBackground(beatmap), b => { float newDepth = 0; if (background != null) @@ -45,8 +43,8 @@ namespace osu.Game.Screens.Backgrounds background.Expire(); } - newBackground.Depth = newDepth; - Add(background = newBackground); + b.Depth = newDepth; + Add(background = b); background.BlurSigma = blurTarget; }); }); From e7654254d2bad68e5423b5ddb00f75d21f3d7ce2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 21 Nov 2017 11:48:49 +0900 Subject: [PATCH 0725/1263] Remove unused code --- osu.Game/Screens/Select/Leaderboards/LeaderboardScore.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/osu.Game/Screens/Select/Leaderboards/LeaderboardScore.cs b/osu.Game/Screens/Select/Leaderboards/LeaderboardScore.cs index e9de3fb672..7b50d36b44 100644 --- a/osu.Game/Screens/Select/Leaderboards/LeaderboardScore.cs +++ b/osu.Game/Screens/Select/Leaderboards/LeaderboardScore.cs @@ -1,7 +1,6 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using System; using System.Linq; using OpenTK; using OpenTK.Graphics; @@ -24,8 +23,6 @@ namespace osu.Game.Screens.Select.Leaderboards { public static readonly float HEIGHT = 60; - public event Action StateChanged; - public readonly int RankPosition; public readonly Score Score; From be9c99ade3dc676d6389a2260dc71cfa5a6ef4f9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 21 Nov 2017 11:49:21 +0900 Subject: [PATCH 0726/1263] Remove AsyncLoadWrapper dependence --- osu.Game/Screens/Select/BeatmapInfoWedge.cs | 126 ++++++++++---------- 1 file changed, 66 insertions(+), 60 deletions(-) diff --git a/osu.Game/Screens/Select/BeatmapInfoWedge.cs b/osu.Game/Screens/Select/BeatmapInfoWedge.cs index 22cb718d0a..c4176be4d9 100644 --- a/osu.Game/Screens/Select/BeatmapInfoWedge.cs +++ b/osu.Game/Screens/Select/BeatmapInfoWedge.cs @@ -26,7 +26,7 @@ namespace osu.Game.Screens.Select { private static readonly Vector2 wedged_container_shear = new Vector2(0.15f, 0); - private Drawable beatmapInfoContainer; + private Drawable info; public BeatmapInfoWedge() { @@ -65,29 +65,34 @@ namespace osu.Game.Screens.Select public void UpdateBeatmap(WorkingBeatmap beatmap) { - var lastContainer = beatmapInfoContainer; - float newDepth = lastContainer?.Depth + 1 ?? 0; - - Add(beatmapInfoContainer = new AsyncLoadWrapper( - new BufferedWedgeInfo(beatmap) - { - Shear = -Shear, - OnLoadComplete = d => - { - this.FadeIn(250); - - lastContainer?.FadeOut(250); - lastContainer?.Expire(); - } - }) + LoadComponentAsync(new BufferedWedgeInfo(beatmap) { - Depth = newDepth, + Shear = -Shear, + Depth = info?.Depth + 1 ?? 0, + }, newInfo => + { + // ensure we ourselves are visible if not already. + if (!IsPresent) + this.FadeIn(250); + + info?.FadeOut(250); + info?.Expire(); + + Add(info = newInfo); }); } public class BufferedWedgeInfo : BufferedContainer { + private readonly WorkingBeatmap beatmap; + public BufferedWedgeInfo(WorkingBeatmap beatmap) + { + this.beatmap = beatmap; + } + + [BackgroundDependencyLoader] + private void load() { BeatmapInfo beatmapInfo = beatmap.BeatmapInfo; BeatmapMetadata metadata = beatmapInfo.Metadata ?? beatmap.BeatmapSetInfo?.Metadata ?? new BeatmapMetadata(); @@ -206,13 +211,13 @@ namespace osu.Game.Screens.Select Font = @"Exo2.0-Medium", Text = "mapped by ", TextSize = 15, - }, + }, new OsuSpriteText { Font = @"Exo2.0-Bold", Text = metadata.Author.Username, TextSize = 15, - }, + }, } }, new FillFlowContainer @@ -244,38 +249,39 @@ namespace osu.Game.Screens.Select AutoSizeAxes = Axes.Both; Children = new Drawable[] { - new SpriteIcon - { - Icon = FontAwesome.fa_square, - Origin = Anchor.Centre, - Colour = new Color4(68, 17, 136, 255), - Rotation = 45, - Size = new Vector2(20), - }, - new SpriteIcon - { - Icon = statistic.Icon, - Origin = Anchor.Centre, - Colour = new Color4(255, 221, 85, 255), - Scale = new Vector2(0.8f), - Size = new Vector2(20), - }, - new OsuSpriteText - { - Margin = new MarginPadding { Left = 13 }, - Font = @"Exo2.0-Bold", - Colour = new Color4(255, 221, 85, 255), - Text = statistic.Content, - TextSize = 17, - Origin = Anchor.CentreLeft - }, + new SpriteIcon + { + Icon = FontAwesome.fa_square, + Origin = Anchor.Centre, + Colour = new Color4(68, 17, 136, 255), + Rotation = 45, + Size = new Vector2(20), + }, + new SpriteIcon + { + Icon = statistic.Icon, + Origin = Anchor.Centre, + Colour = new Color4(255, 221, 85, 255), + Scale = new Vector2(0.8f), + Size = new Vector2(20), + }, + new OsuSpriteText + { + Margin = new MarginPadding { Left = 13 }, + Font = @"Exo2.0-Bold", + Colour = new Color4(255, 221, 85, 255), + Text = statistic.Content, + TextSize = 17, + Origin = Anchor.CentreLeft + }, }; } } private class DifficultyColourBar : DifficultyColouredContainer { - public DifficultyColourBar(BeatmapInfo beatmap) : base(beatmap) + public DifficultyColourBar(BeatmapInfo beatmap) + : base(beatmap) { } @@ -286,21 +292,21 @@ namespace osu.Game.Screens.Select Children = new Drawable[] { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = AccentColour, - Width = full_opacity_ratio, - }, - new Box - { - RelativeSizeAxes = Axes.Both, - RelativePositionAxes = Axes.Both, - Colour = AccentColour, - Alpha = 0.5f, - X = full_opacity_ratio, - Width = 1 - full_opacity_ratio, - } + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = AccentColour, + Width = full_opacity_ratio, + }, + new Box + { + RelativeSizeAxes = Axes.Both, + RelativePositionAxes = Axes.Both, + Colour = AccentColour, + Alpha = 0.5f, + X = full_opacity_ratio, + Width = 1 - full_opacity_ratio, + } }; } } From bd616c13070bd2a850b23168a2e4d00b6b8350e6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 21 Nov 2017 12:29:46 +0900 Subject: [PATCH 0727/1263] Simplify some property access --- .../Containers/BeatSyncedContainer.cs | 6 ++--- osu.Game/Screens/Select/BeatmapInfoWedge.cs | 25 ++++++++++--------- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/osu.Game/Graphics/Containers/BeatSyncedContainer.cs b/osu.Game/Graphics/Containers/BeatSyncedContainer.cs index fb85af12cb..d5d75c9e29 100644 --- a/osu.Game/Graphics/Containers/BeatSyncedContainer.cs +++ b/osu.Game/Graphics/Containers/BeatSyncedContainer.cs @@ -45,8 +45,8 @@ namespace osu.Game.Graphics.Containers double currentTrackTime = track.Length > 0 ? track.CurrentTime + EarlyActivationMilliseconds : Clock.CurrentTime; - TimingControlPoint timingPoint = Beatmap.Value.Beatmap.ControlPointInfo.TimingPointAt(currentTrackTime); - EffectControlPoint effectPoint = Beatmap.Value.Beatmap.ControlPointInfo.EffectPointAt(currentTrackTime); + TimingControlPoint timingPoint = beatmap.ControlPointInfo.TimingPointAt(currentTrackTime); + EffectControlPoint effectPoint = beatmap.ControlPointInfo.EffectPointAt(currentTrackTime); if (timingPoint.BeatLength == 0) return; @@ -67,7 +67,7 @@ namespace osu.Game.Graphics.Containers return; using (BeginDelayedSequence(-TimeSinceLastBeat, true)) - OnNewBeat(beatIndex, timingPoint, effectPoint, Beatmap.Value.Track.CurrentAmplitudes); + OnNewBeat(beatIndex, timingPoint, effectPoint, track.CurrentAmplitudes); lastBeat = beatIndex; lastTimingPoint = timingPoint; diff --git a/osu.Game/Screens/Select/BeatmapInfoWedge.cs b/osu.Game/Screens/Select/BeatmapInfoWedge.cs index c4176be4d9..391cfc20db 100644 --- a/osu.Game/Screens/Select/BeatmapInfoWedge.cs +++ b/osu.Game/Screens/Select/BeatmapInfoWedge.cs @@ -84,42 +84,43 @@ namespace osu.Game.Screens.Select public class BufferedWedgeInfo : BufferedContainer { - private readonly WorkingBeatmap beatmap; + private readonly WorkingBeatmap working; - public BufferedWedgeInfo(WorkingBeatmap beatmap) + public BufferedWedgeInfo(WorkingBeatmap working) { - this.beatmap = beatmap; + this.working = working; } [BackgroundDependencyLoader] private void load() { - BeatmapInfo beatmapInfo = beatmap.BeatmapInfo; - BeatmapMetadata metadata = beatmapInfo.Metadata ?? beatmap.BeatmapSetInfo?.Metadata ?? new BeatmapMetadata(); + BeatmapInfo beatmapInfo = working.BeatmapInfo; + BeatmapMetadata metadata = beatmapInfo.Metadata ?? working.BeatmapSetInfo?.Metadata ?? new BeatmapMetadata(); + Beatmap beatmap = working.Beatmap; List labels = new List(); - if (beatmap.Beatmap != null) + if (beatmap != null) { - HitObject lastObject = beatmap.Beatmap.HitObjects.LastOrDefault(); + 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.Beatmap.HitObjects.Count == 0 ? "-" : TimeSpan.FromMilliseconds(endTime - beatmap.Beatmap.HitObjects.First().StartTime).ToString(@"m\:ss"), + 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.Beatmap), + Content = getBPMRange(beatmap), })); //get statistics from the current ruleset. - labels.AddRange(beatmapInfo.Ruleset.CreateInstance().GetBeatmapStatistics(beatmap).Select(s => new InfoLabel(s))); + labels.AddRange(beatmapInfo.Ruleset.CreateInstance().GetBeatmapStatistics(working).Select(s => new InfoLabel(s))); } PixelSnapping = true; @@ -145,7 +146,7 @@ namespace osu.Game.Screens.Select Children = new[] { // Zoomed-in and cropped beatmap background - new BeatmapBackgroundSprite(beatmap) + new BeatmapBackgroundSprite(working) { RelativeSizeAxes = Axes.Both, Anchor = Anchor.Centre, @@ -154,7 +155,7 @@ namespace osu.Game.Screens.Select }, }, }, - new DifficultyColourBar(beatmap.BeatmapInfo) + new DifficultyColourBar(beatmapInfo) { RelativeSizeAxes = Axes.Y, Width = 20, From a2fc5b67eca47975c54d5682eac93d6946d21c14 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 21 Nov 2017 12:30:06 +0900 Subject: [PATCH 0728/1263] Formatting fix --- osu.Game.Rulesets.Osu/OsuRuleset.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/OsuRuleset.cs b/osu.Game.Rulesets.Osu/OsuRuleset.cs index 9c11474f97..c87328d87c 100644 --- a/osu.Game.Rulesets.Osu/OsuRuleset.cs +++ b/osu.Game.Rulesets.Osu/OsuRuleset.cs @@ -30,7 +30,7 @@ namespace osu.Game.Rulesets.Osu }; public override IEnumerable GetBeatmapStatistics(WorkingBeatmap beatmap) => new[] - { + { new BeatmapStatistic { Name = @"Circle count", From 66f72baa39aa9d9eb8baf9d2293c601f5edf4706 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 21 Nov 2017 12:40:05 +0900 Subject: [PATCH 0729/1263] Avoid LogoVisualisation accessing the track before it's loaded --- osu.Game/Screens/Menu/LogoVisualisation.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Menu/LogoVisualisation.cs b/osu.Game/Screens/Menu/LogoVisualisation.cs index 3e7662a441..7c1b914bf5 100644 --- a/osu.Game/Screens/Menu/LogoVisualisation.cs +++ b/osu.Game/Screens/Menu/LogoVisualisation.cs @@ -85,7 +85,7 @@ namespace osu.Game.Screens.Menu private void updateAmplitudes() { - var track = beatmap.Value.Track; + var track = beatmap.Value.TrackLoaded ? beatmap.Value.Track : null; float[] temporalAmplitudes = track?.CurrentAmplitudes.FrequencyAmplitudes ?? new float[256]; From 553a7947d7a927efca806feca47c29798c6734ef Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 21 Nov 2017 12:40:19 +0900 Subject: [PATCH 0730/1263] Remove AsyncLoadWrapper dependence in MusicController --- osu.Game/Overlays/MusicController.cs | 42 +++++++++++++--------------- 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/osu.Game/Overlays/MusicController.cs b/osu.Game/Overlays/MusicController.cs index a99ce89a36..4f57ea1bcd 100644 --- a/osu.Game/Overlays/MusicController.cs +++ b/osu.Game/Overlays/MusicController.cs @@ -37,7 +37,7 @@ namespace osu.Game.Overlays private const float bottom_black_area_height = 55; - private Drawable currentBackground; + private Drawable background; private ProgressBar progressBar; private IconButton prevButton; @@ -120,7 +120,7 @@ namespace osu.Game.Overlays }, Children = new[] { - currentBackground = new Background(), + background = new Background(), title = new OsuSpriteText { Origin = Anchor.BottomCentre, @@ -334,6 +334,7 @@ namespace osu.Game.Overlays pendingBeatmapSwitch = Schedule(delegate { + // todo: this can likely be replaced with WorkingBeatmap.GetBeatmapAsync() Task.Run(() => { if (beatmap?.Beatmap == null) //this is not needed if a placeholder exists @@ -352,29 +353,26 @@ namespace osu.Game.Overlays } }); - playerContainer.Add(new AsyncLoadWrapper(new Background(beatmap) + LoadComponentAsync(new Background(beatmap) { Depth = float.MaxValue }, newBackground => { - OnLoadComplete = newBackground => + switch (direction) { - switch (direction) - { - case TransformDirection.Next: - newBackground.Position = new Vector2(400, 0); - newBackground.MoveToX(0, 500, Easing.OutCubic); - currentBackground.MoveToX(-400, 500, Easing.OutCubic); - break; - case TransformDirection.Prev: - newBackground.Position = new Vector2(-400, 0); - newBackground.MoveToX(0, 500, Easing.OutCubic); - currentBackground.MoveToX(400, 500, Easing.OutCubic); - break; - } - currentBackground.Expire(); - currentBackground = newBackground; + case TransformDirection.Next: + newBackground.Position = new Vector2(400, 0); + newBackground.MoveToX(0, 500, Easing.OutCubic); + background.MoveToX(-400, 500, Easing.OutCubic); + break; + case TransformDirection.Prev: + newBackground.Position = new Vector2(-400, 0); + newBackground.MoveToX(0, 500, Easing.OutCubic); + background.MoveToX(400, 500, Easing.OutCubic); + break; } - }) - { - Depth = float.MaxValue, + + background.Expire(); + background = newBackground; + + playerContainer.Add(newBackground); }); }); } From 8e63a7dd8dd6478eba9089024e39456f89716fb9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 21 Nov 2017 14:42:49 +0900 Subject: [PATCH 0731/1263] Handle more exceptions when checking for updates Should resolve #849. --- osu.Desktop/Overlays/VersionManager.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/osu.Desktop/Overlays/VersionManager.cs b/osu.Desktop/Overlays/VersionManager.cs index 8c17e18ed8..3d66e6754c 100644 --- a/osu.Desktop/Overlays/VersionManager.cs +++ b/osu.Desktop/Overlays/VersionManager.cs @@ -198,10 +198,9 @@ namespace osu.Desktop.Overlays } } } - catch (HttpRequestException) + catch (Exception) { - //likely have no internet connection. - //we'll ignore this and retry later. + // we'll ignore this and retry later. can be triggered by no internet connection or thread abortion. } finally { From 62dcc316e265063c9e8e386a9a2a4d7ff7ce7607 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 21 Nov 2017 15:02:16 +0900 Subject: [PATCH 0732/1263] Remove unnecessary using --- osu.Desktop/Overlays/VersionManager.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Desktop/Overlays/VersionManager.cs b/osu.Desktop/Overlays/VersionManager.cs index 3d66e6754c..9e13003c3f 100644 --- a/osu.Desktop/Overlays/VersionManager.cs +++ b/osu.Desktop/Overlays/VersionManager.cs @@ -3,7 +3,6 @@ using System; using System.Diagnostics; -using System.Net.Http; using osu.Framework.Allocation; using osu.Framework.Development; using osu.Framework.Graphics; From 1b27ce6198eaa525deb2560ee75f76d7e3d9570d Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 21 Nov 2017 17:09:22 +0900 Subject: [PATCH 0733/1263] Cleanup + renaming --- .../Scoring/TaikoScoreProcessor.cs | 2 +- osu.Game/Rulesets/Mods/ModPerfect.cs | 10 +--------- osu.Game/Rulesets/Mods/ModSuddenDeath.cs | 9 +++------ osu.Game/Rulesets/Scoring/ScoreProcessor.cs | 12 ++++++------ 4 files changed, 11 insertions(+), 22 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs b/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs index 0e5df329d8..0048566b15 100644 --- a/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs +++ b/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs @@ -53,7 +53,7 @@ namespace osu.Game.Rulesets.Taiko.Scoring /// /// Taiko fails at the end of the map if the player has not half-filled their HP bar. /// - protected override bool FailCondition => Hits == MaxHits && Health.Value <= 0.5; + protected override bool DefaultFailCondition => Hits == MaxHits && Health.Value <= 0.5; private double hpIncreaseTick; private double hpIncreaseGreat; diff --git a/osu.Game/Rulesets/Mods/ModPerfect.cs b/osu.Game/Rulesets/Mods/ModPerfect.cs index cf7bf141c3..e7887c8fc4 100644 --- a/osu.Game/Rulesets/Mods/ModPerfect.cs +++ b/osu.Game/Rulesets/Mods/ModPerfect.cs @@ -11,14 +11,6 @@ namespace osu.Game.Rulesets.Mods public override string ShortenedName => "PF"; public override string Description => "SS or quit."; - public bool OnFailCheck(ScoreProcessor scoreProcessor) - { - return scoreProcessor.Accuracy.Value != 1; - } - - public virtual void ApplyToScoreProcessor(ScoreProcessor scoreProcessor) - { - scoreProcessor.FailChecker += OnFailCheck; - } + protected override bool FailCondition(ScoreProcessor scoreProcessor) => scoreProcessor.Accuracy.Value != 1; } } diff --git a/osu.Game/Rulesets/Mods/ModSuddenDeath.cs b/osu.Game/Rulesets/Mods/ModSuddenDeath.cs index 6675c41bd4..17350fdaa4 100644 --- a/osu.Game/Rulesets/Mods/ModSuddenDeath.cs +++ b/osu.Game/Rulesets/Mods/ModSuddenDeath.cs @@ -18,14 +18,11 @@ namespace osu.Game.Rulesets.Mods public override bool Ranked => true; public override Type[] IncompatibleMods => new[] { typeof(ModNoFail), typeof(ModRelax), typeof(ModAutoplay) }; - public bool OnFailCheck(ScoreProcessor scoreProcessor) + public void ApplyToScoreProcessor(ScoreProcessor scoreProcessor) { - return scoreProcessor.Combo.Value != scoreProcessor.HighestCombo.Value; + scoreProcessor.FailConditions += FailCondition; } - public virtual void ApplyToScoreProcessor(ScoreProcessor scoreProcessor) - { - scoreProcessor.FailChecker += OnFailCheck; - } + protected virtual bool FailCondition(ScoreProcessor scoreProcessor) => scoreProcessor.Combo.Value != scoreProcessor.HighestCombo.Value; } } diff --git a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs index c3ae887a9f..de8a510590 100644 --- a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs +++ b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs @@ -32,9 +32,9 @@ namespace osu.Game.Rulesets.Scoring public event Action NewJudgement; /// - /// Invoked when we want to check if a failure condition has been fulfilled + /// Additional conditions on top of that cause a failing state. /// - public event Func FailChecker; + public event Func FailConditions; /// /// The current total score. @@ -77,9 +77,9 @@ namespace osu.Game.Rulesets.Scoring public virtual bool HasFailed { get; private set; } /// - /// The conditions for failing. + /// The default conditions for failing. /// - protected virtual bool FailCondition => Health.Value == Health.MinValue; + protected virtual bool DefaultFailCondition => Health.Value == Health.MinValue; protected ScoreProcessor() { @@ -126,7 +126,7 @@ namespace osu.Game.Rulesets.Scoring /// protected void UpdateFailed() { - if (HasFailed || !FailCondition) + if (HasFailed || !DefaultFailCondition) return; if (Failed?.Invoke() != false) @@ -150,7 +150,7 @@ namespace osu.Game.Rulesets.Scoring if (HasFailed) return; - if (FailChecker?.Invoke(this) == true) + if (FailConditions?.Invoke(this) == true) { if (Failed?.Invoke() != false) HasFailed = true; From 18b9828c49548192048b84b74fcd35b515823c53 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 21 Nov 2017 17:11:07 +0900 Subject: [PATCH 0734/1263] Merge UpdateFailed and CheckAlternateFailConditions --- osu.Game/Rulesets/Scoring/ScoreProcessor.cs | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs index de8a510590..7b26e50dd8 100644 --- a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs +++ b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs @@ -126,7 +126,10 @@ namespace osu.Game.Rulesets.Scoring /// protected void UpdateFailed() { - if (HasFailed || !DefaultFailCondition) + if (HasFailed) + return; + + if (!DefaultFailCondition && FailConditions?.Invoke(this) != true) return; if (Failed?.Invoke() != false) @@ -145,18 +148,6 @@ namespace osu.Game.Rulesets.Scoring AllJudged?.Invoke(); } - protected void CheckAlternateFailConditions() - { - if (HasFailed) - return; - - if (FailConditions?.Invoke(this) == true) - { - if (Failed?.Invoke() != false) - HasFailed = true; - } - } - /// /// Retrieve a score populated with data for the current play this processor is responsible for. /// @@ -233,8 +224,6 @@ namespace osu.Game.Rulesets.Scoring OnNewJudgement(judgement); updateScore(); - CheckAlternateFailConditions(); - NotifyNewJudgement(judgement); UpdateFailed(); } From fea56322f0aadcdb1b48a82f4836a47d268cd213 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 21 Nov 2017 17:28:51 +0900 Subject: [PATCH 0735/1263] Fix SD not failing for the first note --- osu.Game/Rulesets/Mods/ModSuddenDeath.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Mods/ModSuddenDeath.cs b/osu.Game/Rulesets/Mods/ModSuddenDeath.cs index 17350fdaa4..bc42c69cbe 100644 --- a/osu.Game/Rulesets/Mods/ModSuddenDeath.cs +++ b/osu.Game/Rulesets/Mods/ModSuddenDeath.cs @@ -23,6 +23,6 @@ namespace osu.Game.Rulesets.Mods scoreProcessor.FailConditions += FailCondition; } - protected virtual bool FailCondition(ScoreProcessor scoreProcessor) => scoreProcessor.Combo.Value != scoreProcessor.HighestCombo.Value; + protected virtual bool FailCondition(ScoreProcessor scoreProcessor) => scoreProcessor.Combo.Value == 0; } } From c30d31e03746efd290ca09ae82cd0701a3ce2e33 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 21 Nov 2017 17:30:19 +0900 Subject: [PATCH 0736/1263] Remove extra alternateFailConditions function in Player --- osu.Game/Screens/Play/Player.cs | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 0bff13a46a..cd2818398d 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -228,15 +228,8 @@ namespace osu.Game.Screens.Play scoreProcessor.AllJudged += onCompletion; scoreProcessor.Failed += onFail; - applyAlternateFailConditions(); - } - - private void applyAlternateFailConditions() - { - foreach(var mod in Beatmap.Value.Mods.Value.OfType()) - { - mod.ApplyToScoreProcessor(scoreProcessor); - } + foreach (var mod in Beatmap.Value.Mods.Value.OfType()) + mod.ApplyToScoreProcessor(scoreProcessor); } private void applyRateFromMods() From 0d1b5ae44f6f64529775d10fdd4adef5f5cf3d17 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 21 Nov 2017 17:51:07 +0900 Subject: [PATCH 0737/1263] Adjust bottom bar sizing as suggested --- osu.Game/Screens/Edit/Editor.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 52baadd442..e2971deb75 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -92,8 +92,9 @@ namespace osu.Game.Screens.Edit RelativeSizeAxes = Axes.Both, ColumnDimensions = new[] { + new Dimension(GridSizeMode.Absolute, 220), new Dimension(), - new Dimension(GridSizeMode.Relative, 0.65f), + new Dimension(GridSizeMode.Absolute, 220) }, Content = new[] { From 217554f587d40582ce51b2c5630c8a0e4402791d Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 21 Nov 2017 18:06:24 +0900 Subject: [PATCH 0738/1263] Remove redundant interface --- osu.Game/Rulesets/Mods/ModPerfect.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Mods/ModPerfect.cs b/osu.Game/Rulesets/Mods/ModPerfect.cs index e7887c8fc4..59539d2b2c 100644 --- a/osu.Game/Rulesets/Mods/ModPerfect.cs +++ b/osu.Game/Rulesets/Mods/ModPerfect.cs @@ -5,7 +5,7 @@ using osu.Game.Rulesets.Scoring; namespace osu.Game.Rulesets.Mods { - public abstract class ModPerfect : ModSuddenDeath, IApplicableToScoreProcessor + public abstract class ModPerfect : ModSuddenDeath { public override string Name => "Perfect"; public override string ShortenedName => "PF"; From 41498ffad3f6b26b8ceb17696ec970ad8aa044c6 Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Tue, 21 Nov 2017 12:22:19 +0300 Subject: [PATCH 0739/1263] Apply suggestions --- .../Screens/Edit/Components/PlaybackContainer.cs | 14 +++----------- .../Screens/Edit/Components/TimeInfoContainer.cs | 9 +-------- 2 files changed, 4 insertions(+), 19 deletions(-) diff --git a/osu.Game/Screens/Edit/Components/PlaybackContainer.cs b/osu.Game/Screens/Edit/Components/PlaybackContainer.cs index a88983e3e4..a7d1db4802 100644 --- a/osu.Game/Screens/Edit/Components/PlaybackContainer.cs +++ b/osu.Game/Screens/Edit/Components/PlaybackContainer.cs @@ -17,8 +17,6 @@ namespace osu.Game.Screens.Edit.Components { private readonly IconButton playButton; - private bool lastTrackState; - public PlaybackContainer() { PlaybackTabControl tabs; @@ -32,7 +30,7 @@ namespace osu.Game.Screens.Edit.Components Scale = new Vector2(1.4f), IconScale = new Vector2(1.4f), Icon = FontAwesome.fa_play_circle_o, - Action = play, + Action = playPause, Padding = new MarginPadding { Left = 20 } }, new OsuSpriteText @@ -61,7 +59,7 @@ namespace osu.Game.Screens.Edit.Components tabs.Current.ValueChanged += newValue => Track.Tempo.Value = newValue; } - private void play() + private void playPause() { if (Track.IsRunning) Track.Stop(); @@ -73,13 +71,7 @@ namespace osu.Game.Screens.Edit.Components { base.Update(); - var currentTrackState = Track.IsRunning; - if (currentTrackState == lastTrackState) - return; - - playButton.Icon = currentTrackState ? FontAwesome.fa_pause_circle_o : FontAwesome.fa_play_circle_o; - - lastTrackState = currentTrackState; + playButton.Icon = Track.IsRunning ? FontAwesome.fa_pause_circle_o : FontAwesome.fa_play_circle_o; } private class PlaybackTabControl : OsuTabControl diff --git a/osu.Game/Screens/Edit/Components/TimeInfoContainer.cs b/osu.Game/Screens/Edit/Components/TimeInfoContainer.cs index 4a07ab4434..b9b6867ea6 100644 --- a/osu.Game/Screens/Edit/Components/TimeInfoContainer.cs +++ b/osu.Game/Screens/Edit/Components/TimeInfoContainer.cs @@ -12,7 +12,6 @@ namespace osu.Game.Screens.Edit.Components private const int count_duration = 150; private readonly OsuSpriteText trackTimer; - private double savedTime; public TimeInfoContainer() { @@ -33,13 +32,7 @@ namespace osu.Game.Screens.Edit.Components { base.Update(); - var currentTime = Track.CurrentTime; - - if (savedTime == currentTime) - return; - - trackTimer.Text = TimeSpan.FromMilliseconds(currentTime).ToString(@"mm\:ss\:fff"); - savedTime = currentTime; + trackTimer.Text = TimeSpan.FromMilliseconds(Track.CurrentTime).ToString(@"mm\:ss\:fff"); } } } From ca1814eb190c01a703821401a65be4b2a93ab7d0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 21 Nov 2017 18:38:54 +0900 Subject: [PATCH 0740/1263] Update framework --- osu-framework | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu-framework b/osu-framework index 14eb531c00..83925a8407 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit 14eb531c0056b8569f21b3571890383ffbea768e +Subproject commit 83925a84072ec9da0d008c82256294b765321c0b From c2fcb2f9c7b31267acd3aadbd1cefa708107e148 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 21 Nov 2017 18:45:12 +0900 Subject: [PATCH 0741/1263] Fix info wedge not displaying --- osu.Game/Screens/Select/BeatmapInfoWedge.cs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/osu.Game/Screens/Select/BeatmapInfoWedge.cs b/osu.Game/Screens/Select/BeatmapInfoWedge.cs index 391cfc20db..5ced60a9da 100644 --- a/osu.Game/Screens/Select/BeatmapInfoWedge.cs +++ b/osu.Game/Screens/Select/BeatmapInfoWedge.cs @@ -43,12 +43,6 @@ namespace osu.Game.Screens.Select }; } - protected override void LoadComplete() - { - base.LoadComplete(); - AlwaysPresent = true; - } - protected override bool BlockPassThroughMouse => false; protected override void PopIn() From aff217cd03a47b7e8245cff3806ea21204145c1f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 21 Nov 2017 19:47:12 +0900 Subject: [PATCH 0742/1263] Fix early access to beatmap in LogoVisualisation Missed this one.. --- osu.Game/Screens/Menu/LogoVisualisation.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game/Screens/Menu/LogoVisualisation.cs b/osu.Game/Screens/Menu/LogoVisualisation.cs index 7c1b914bf5..5b86fd6ca3 100644 --- a/osu.Game/Screens/Menu/LogoVisualisation.cs +++ b/osu.Game/Screens/Menu/LogoVisualisation.cs @@ -86,11 +86,10 @@ namespace osu.Game.Screens.Menu private void updateAmplitudes() { var track = beatmap.Value.TrackLoaded ? beatmap.Value.Track : null; + var effect = beatmap.Value.BeatmapLoaded ? beatmap.Value.Beatmap.ControlPointInfo.EffectPointAt(track?.CurrentTime ?? Time.Current) : null; float[] temporalAmplitudes = track?.CurrentAmplitudes.FrequencyAmplitudes ?? new float[256]; - var effect = beatmap.Value.Beatmap.ControlPointInfo.EffectPointAt(track?.CurrentTime ?? Time.Current); - for (int i = 0; i < bars_per_visualiser; i++) { if (track?.IsRunning ?? false) From decee415dd3b9961912a18dd0aa3ac73d57c26fe Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 21 Nov 2017 19:54:08 +0900 Subject: [PATCH 0743/1263] Calculate real AR based on PreEmpt time --- .../Scoring/OsuPerformanceCalculator.cs | 22 ++++++++++++++----- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Scoring/OsuPerformanceCalculator.cs b/osu.Game.Rulesets.Osu/Scoring/OsuPerformanceCalculator.cs index 93003925ef..0b6bb1c4af 100644 --- a/osu.Game.Rulesets.Osu/Scoring/OsuPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Osu/Scoring/OsuPerformanceCalculator.cs @@ -49,6 +49,17 @@ namespace osu.Game.Rulesets.Osu.Scoring if (mods.Any(m => m is OsuModRelax || m is OsuModAutopilot || m is OsuModAutoplay)) return 0; + // Todo: In the future we should apply changes to PreEmpt/AR at an OsuHitObject/BaseDifficulty level, but this is done + // locally for now as doing so would modify animations and other things unexpectedly + // DO NOT MODIFY THIS + double ar = Beatmap.BeatmapInfo.BaseDifficulty.ApproachRate; + if (mods.Any(m => m is OsuModHardRock)) + ar = Math.Min(10, ar * 1.4); + if (mods.Any(m => m is OsuModEasy)) + ar = Math.Max(0, ar / 2); + double preEmpt = BeatmapDifficulty.DifficultyRange(ar, 1800, 1200, 450); + realApproachRate = preEmpt > 1200 ? (1800 - preEmpt) / 120 : (1200 - preEmpt) / 150 + 5; + // Custom multipliers for NoFail and SpunOut. double multiplier = 1.12f; // This is being adjusted to keep the final pp value scaled around what it used to be when changing things @@ -95,17 +106,16 @@ namespace osu.Game.Rulesets.Osu.Scoring if (beatmapMaxCombo > 0) aimValue *= Math.Min(Math.Pow(scoreMaxCombo, 0.8f) / Math.Pow(beatmapMaxCombo, 0.8f), 1.0f); - double approachRate = Beatmap.BeatmapInfo.BaseDifficulty.ApproachRate; double approachRateFactor = 1.0f; - if (approachRate > 10.33f) - approachRateFactor += 0.45f * (approachRate - 10.33f); - else if (approachRate < 8.0f) + if (realApproachRate > 10.33f) + approachRateFactor += 0.45f * (realApproachRate - 10.33f); + else if (realApproachRate < 8.0f) { // HD is worth more with lower ar! if (mods.Any(h => h is OsuModHidden)) - approachRateFactor += 0.02f * (8.0f - approachRate); + approachRateFactor += 0.02f * (8.0f - realApproachRate); else - approachRateFactor += 0.01f * (8.0f - approachRate); + approachRateFactor += 0.01f * (8.0f - realApproachRate); } aimValue *= approachRateFactor; From f9ad4b6acbc122bf505e55a9f351ed24f9df586a Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 21 Nov 2017 19:54:53 +0900 Subject: [PATCH 0744/1263] Make categoryDifficulties return doubles to improve decimal accuracy --- .../CatchDifficultyCalculator.cs | 2 +- .../ManiaDifficultyCalculator.cs | 2 +- .../OsuDifficulty/OsuDifficultyCalculator.cs | 6 +++--- .../Scoring/OsuPerformanceCalculator.cs | 13 +++++++------ .../TaikoDifficultyCalculator.cs | 6 +++--- osu.Game/Beatmaps/DifficultyCalculator.cs | 2 +- osu.Game/Rulesets/Scoring/PerformanceCalculator.cs | 6 +++--- osu.Game/Tests/Visual/TestCasePerformancePoints.cs | 6 +++--- 8 files changed, 22 insertions(+), 21 deletions(-) diff --git a/osu.Game.Rulesets.Catch/CatchDifficultyCalculator.cs b/osu.Game.Rulesets.Catch/CatchDifficultyCalculator.cs index b77be9d1f0..369290fcbd 100644 --- a/osu.Game.Rulesets.Catch/CatchDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Catch/CatchDifficultyCalculator.cs @@ -14,7 +14,7 @@ namespace osu.Game.Rulesets.Catch { } - public override double Calculate(Dictionary categoryDifficulty = null) => 0; + public override double Calculate(Dictionary categoryDifficulty = null) => 0; protected override BeatmapConverter CreateBeatmapConverter(Beatmap beatmap) => new CatchBeatmapConverter(); } diff --git a/osu.Game.Rulesets.Mania/ManiaDifficultyCalculator.cs b/osu.Game.Rulesets.Mania/ManiaDifficultyCalculator.cs index 67bc347535..e0763284a6 100644 --- a/osu.Game.Rulesets.Mania/ManiaDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Mania/ManiaDifficultyCalculator.cs @@ -16,7 +16,7 @@ namespace osu.Game.Rulesets.Mania { } - public override double Calculate(Dictionary categoryDifficulty = null) => 0; + public override double Calculate(Dictionary categoryDifficulty = null) => 0; protected override BeatmapConverter CreateBeatmapConverter(Beatmap beatmap) => new ManiaBeatmapConverter(true, (int)Math.Max(1, Math.Round(beatmap.BeatmapInfo.BaseDifficulty.CircleSize))); } diff --git a/osu.Game.Rulesets.Osu/OsuDifficulty/OsuDifficultyCalculator.cs b/osu.Game.Rulesets.Osu/OsuDifficulty/OsuDifficultyCalculator.cs index 4f41d3b8e2..3d185ab694 100644 --- a/osu.Game.Rulesets.Osu/OsuDifficulty/OsuDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Osu/OsuDifficulty/OsuDifficultyCalculator.cs @@ -33,7 +33,7 @@ namespace osu.Game.Rulesets.Osu.OsuDifficulty (h as Slider)?.Curve?.Calculate(); } - public override double Calculate(Dictionary categoryDifficulty = null) + public override double Calculate(Dictionary categoryDifficulty = null) { OsuDifficultyBeatmap beatmap = new OsuDifficultyBeatmap(Beatmap.HitObjects, TimeRate); Skill[] skills = @@ -67,8 +67,8 @@ namespace osu.Game.Rulesets.Osu.OsuDifficulty if (categoryDifficulty != null) { - categoryDifficulty.Add("Aim", aimRating.ToString("0.00")); - categoryDifficulty.Add("Speed", speedRating.ToString("0.00")); + categoryDifficulty.Add("Aim", aimRating); + categoryDifficulty.Add("Speed", speedRating); } return starRating; diff --git a/osu.Game.Rulesets.Osu/Scoring/OsuPerformanceCalculator.cs b/osu.Game.Rulesets.Osu/Scoring/OsuPerformanceCalculator.cs index 0b6bb1c4af..cc5abb36b5 100644 --- a/osu.Game.Rulesets.Osu/Scoring/OsuPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Osu/Scoring/OsuPerformanceCalculator.cs @@ -19,6 +19,7 @@ namespace osu.Game.Rulesets.Osu.Scoring private readonly int beatmapMaxCombo; private Mod[] mods; + private double realApproachRate; private double accuracy; private int scoreMaxCombo; private int count300; @@ -35,7 +36,7 @@ namespace osu.Game.Rulesets.Osu.Scoring beatmapMaxCombo += Beatmap.HitObjects.OfType().Sum(s => s.RepeatCount + s.Ticks.Count()); } - public override double Calculate(Dictionary categoryRatings = null) + public override double Calculate(Dictionary categoryRatings = null) { mods = Score.Mods; accuracy = Score.Accuracy; @@ -81,9 +82,9 @@ namespace osu.Game.Rulesets.Osu.Scoring if (categoryRatings != null) { - categoryRatings.Add("Aim", aimValue.ToString("0.00")); - categoryRatings.Add("Speed", speedValue.ToString("0.00")); - categoryRatings.Add("Accuracy", accuracyValue.ToString("0.00")); + categoryRatings.Add("Aim", aimValue); + categoryRatings.Add("Speed", speedValue); + categoryRatings.Add("Accuracy", accuracyValue); } return totalValue; @@ -91,7 +92,7 @@ namespace osu.Game.Rulesets.Osu.Scoring private double computeAimValue() { - double aimValue = Math.Pow(5.0f * Math.Max(1.0f, double.Parse(Attributes["Aim"]) / 0.0675f) - 4.0f, 3.0f) / 100000.0f; + double aimValue = Math.Pow(5.0f * Math.Max(1.0f, Attributes["Aim"] / 0.0675f) - 4.0f, 3.0f) / 100000.0f; // Longer maps are worth more double lengthBonus = 0.95f + 0.4f * Math.Min(1.0f, totalHits / 2000.0f) + @@ -139,7 +140,7 @@ namespace osu.Game.Rulesets.Osu.Scoring private double computeSpeedValue() { - double speedValue = Math.Pow(5.0f * Math.Max(1.0f, double.Parse(Attributes["Speed"]) / 0.0675f) - 4.0f, 3.0f) / 100000.0f; + double speedValue = Math.Pow(5.0f * Math.Max(1.0f, Attributes["Speed"] / 0.0675f) - 4.0f, 3.0f) / 100000.0f; // Longer maps are worth more speedValue *= 0.95f + 0.4f * Math.Min(1.0f, totalHits / 2000.0f) + diff --git a/osu.Game.Rulesets.Taiko/TaikoDifficultyCalculator.cs b/osu.Game.Rulesets.Taiko/TaikoDifficultyCalculator.cs index e881942fbf..394036df39 100644 --- a/osu.Game.Rulesets.Taiko/TaikoDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Taiko/TaikoDifficultyCalculator.cs @@ -36,7 +36,7 @@ namespace osu.Game.Rulesets.Taiko { } - public override double Calculate(Dictionary categoryDifficulty = null) + public override double Calculate(Dictionary categoryDifficulty = null) { // Fill our custom DifficultyHitObject class, that carries additional information difficultyHitObjects.Clear(); @@ -53,8 +53,8 @@ namespace osu.Game.Rulesets.Taiko if (categoryDifficulty != null) { - categoryDifficulty.Add("Strain", starRating.ToString("0.00", CultureInfo.InvariantCulture)); - categoryDifficulty.Add("Hit window 300", (35 /*HitObjectManager.HitWindow300*/ / TimeRate).ToString("0.00", CultureInfo.InvariantCulture)); + categoryDifficulty.Add("Strain", starRating); + categoryDifficulty.Add("Hit window 300", (35 /*HitObjectManager.HitWindow300*/ / TimeRate)); } return starRating; diff --git a/osu.Game/Beatmaps/DifficultyCalculator.cs b/osu.Game/Beatmaps/DifficultyCalculator.cs index f58f433cb2..687e1b2177 100644 --- a/osu.Game/Beatmaps/DifficultyCalculator.cs +++ b/osu.Game/Beatmaps/DifficultyCalculator.cs @@ -14,7 +14,7 @@ namespace osu.Game.Beatmaps { protected double TimeRate = 1; - public abstract double Calculate(Dictionary categoryDifficulty = null); + public abstract double Calculate(Dictionary categoryDifficulty = null); } public abstract class DifficultyCalculator : DifficultyCalculator where T : HitObject diff --git a/osu.Game/Rulesets/Scoring/PerformanceCalculator.cs b/osu.Game/Rulesets/Scoring/PerformanceCalculator.cs index 000e279d11..4f603049db 100644 --- a/osu.Game/Rulesets/Scoring/PerformanceCalculator.cs +++ b/osu.Game/Rulesets/Scoring/PerformanceCalculator.cs @@ -9,14 +9,14 @@ namespace osu.Game.Rulesets.Scoring { public abstract class PerformanceCalculator { - public abstract double Calculate(Dictionary categoryDifficulty = null); + public abstract double Calculate(Dictionary categoryDifficulty = null); } public abstract class PerformanceCalculator : PerformanceCalculator where TObject : HitObject { - private readonly Dictionary attributes = new Dictionary(); - protected IDictionary Attributes => attributes; + private readonly Dictionary attributes = new Dictionary(); + protected IDictionary Attributes => attributes; protected readonly Beatmap Beatmap; protected readonly Score Score; diff --git a/osu.Game/Tests/Visual/TestCasePerformancePoints.cs b/osu.Game/Tests/Visual/TestCasePerformancePoints.cs index 6b2ab6433b..80167e5e1f 100644 --- a/osu.Game/Tests/Visual/TestCasePerformancePoints.cs +++ b/osu.Game/Tests/Visual/TestCasePerformancePoints.cs @@ -259,7 +259,7 @@ namespace osu.Game.Tests.Visual if (calculator == null) return; - var attributes = new Dictionary(); + var attributes = new Dictionary(); double performance = calculator.Calculate(attributes); text.Text = $"{score.User.Username} -> online: {score.PP:n2}pp | local: {performance:n2}pp"; @@ -364,12 +364,12 @@ namespace osu.Game.Tests.Visual var diffCalc = ruleset.CreateDifficultyCalculator(beatmap.Beatmap, activeMods); if (diffCalc != null) { - var categories = new Dictionary(); + var categories = new Dictionary(); double totalSr = diffCalc.Calculate(categories); totalText.Text = $"Star rating: {totalSr:n2}"; foreach (var kvp in categories) - categoryTexts.Add(new OsuSpriteText { Text = $"{kvp.Key}: {kvp.Value}" }); + categoryTexts.Add(new OsuSpriteText { Text = $"{kvp.Key}: {kvp.Value:n2}" }); } informationCache.Validate(); From 2603219350db896caf0b0a6b312df6394da3dba7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 21 Nov 2017 22:27:56 +0900 Subject: [PATCH 0745/1263] Load beatmap carousel panels asynchronously --- .../Beatmaps/Drawables/BeatmapSetHeader.cs | 54 +++++++++---------- osu.Game/Screens/Select/BeatmapCarousel.cs | 13 ++++- 2 files changed, 38 insertions(+), 29 deletions(-) diff --git a/osu.Game/Beatmaps/Drawables/BeatmapSetHeader.cs b/osu.Game/Beatmaps/Drawables/BeatmapSetHeader.cs index 8a589ccd30..917376969b 100644 --- a/osu.Game/Beatmaps/Drawables/BeatmapSetHeader.cs +++ b/osu.Game/Beatmaps/Drawables/BeatmapSetHeader.cs @@ -11,7 +11,6 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Cursor; -using osu.Framework.Graphics.Sprites; using osu.Framework.Localisation; using osu.Game.Graphics.Sprites; using osu.Framework.Graphics.Shapes; @@ -28,10 +27,8 @@ namespace osu.Game.Beatmaps.Drawables public Action RestoreHiddenRequested; - private readonly SpriteText title; - private readonly SpriteText artist; - private readonly WorkingBeatmap beatmap; + private readonly FillFlowContainer difficultyIcons; public BeatmapSetHeader(WorkingBeatmap beatmap) @@ -41,6 +38,25 @@ namespace osu.Game.Beatmaps.Drawables this.beatmap = beatmap; + difficultyIcons = new FillFlowContainer + { + Margin = new MarginPadding { Top = 5 }, + AutoSizeAxes = Axes.Both, + }; + } + + protected override void Selected() + { + base.Selected(); + GainedSelection?.Invoke(this); + } + + [BackgroundDependencyLoader] + private void load(LocalisationEngine localisation) + { + if (localisation == null) + throw new ArgumentNullException(nameof(localisation)); + Children = new Drawable[] { new DelayedLoadWrapper( @@ -60,44 +76,26 @@ namespace osu.Game.Beatmaps.Drawables AutoSizeAxes = Axes.Both, Children = new Drawable[] { - title = new OsuSpriteText + new OsuSpriteText { Font = @"Exo2.0-BoldItalic", + Current = localisation.GetUnicodePreference(beatmap.Metadata.TitleUnicode, beatmap.Metadata.Title), TextSize = 22, Shadow = true, }, - artist = new OsuSpriteText + new OsuSpriteText { Font = @"Exo2.0-SemiBoldItalic", + Current = localisation.GetUnicodePreference(beatmap.Metadata.ArtistUnicode, beatmap.Metadata.Artist), TextSize = 17, Shadow = true, }, - difficultyIcons = new FillFlowContainer - { - Margin = new MarginPadding { Top = 5 }, - AutoSizeAxes = Axes.Both, - } + difficultyIcons } } }; } - protected override void Selected() - { - base.Selected(); - GainedSelection?.Invoke(this); - } - - [BackgroundDependencyLoader] - private void load(LocalisationEngine localisation) - { - if (localisation == null) - throw new ArgumentNullException(nameof(localisation)); - - title.Current = localisation.GetUnicodePreference(beatmap.Metadata.TitleUnicode, beatmap.Metadata.Title); - artist.Current = localisation.GetUnicodePreference(beatmap.Metadata.ArtistUnicode, beatmap.Metadata.Artist); - } - private class PanelBackground : BufferedContainer { public PanelBackground(WorkingBeatmap working) @@ -185,4 +183,4 @@ namespace osu.Game.Beatmaps.Drawables } } } -} \ No newline at end of file +} diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index 452f8c484c..b0a636dfb3 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -572,7 +572,18 @@ namespace osu.Game.Screens.Select // Makes sure headers are always _below_ panels, // and depth flows downward. panel.Depth = i + (panel is BeatmapSetHeader ? panels.Count : 0); - scrollableContent.Add(panel); + + switch (panel.LoadState) + { + case LoadState.NotLoaded: + LoadComponentAsync(panel); + break; + case LoadState.Loading: + break; + default: + scrollableContent.Add(panel); + break; + } } } From 5e70b7a9f7633a8dfa3bbb48fa3936560d25db48 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 21 Nov 2017 11:50:24 +0900 Subject: [PATCH 0746/1263] Add async load methods for WorkingBeatmap properties --- osu.Game/Beatmaps/WorkingBeatmap.cs | 38 ++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/osu.Game/Beatmaps/WorkingBeatmap.cs b/osu.Game/Beatmaps/WorkingBeatmap.cs index 1d4ed75688..2a8178882e 100644 --- a/osu.Game/Beatmaps/WorkingBeatmap.cs +++ b/osu.Game/Beatmaps/WorkingBeatmap.cs @@ -8,6 +8,7 @@ using osu.Game.Rulesets.Mods; using System; using System.Collections.Generic; using System.Linq; +using System.Threading.Tasks; namespace osu.Game.Beatmaps { @@ -29,10 +30,10 @@ namespace osu.Game.Beatmaps Mods.ValueChanged += mods => applyRateAdjustments(); - beatmap = new Lazy(populateBeatmap); - background = new Lazy(populateBackground); - track = new Lazy(populateTrack); - waveform = new Lazy(populateWaveform); + beatmap = new AsyncLazy(populateBeatmap); + background = new AsyncLazy(populateBackground); + track = new AsyncLazy(populateTrack); + waveform = new AsyncLazy(populateWaveform); } protected abstract Beatmap GetBeatmap(); @@ -41,8 +42,10 @@ namespace osu.Game.Beatmaps protected virtual Waveform GetWaveform() => new Waveform(); public bool BeatmapLoaded => beatmap.IsValueCreated; - public Beatmap Beatmap => beatmap.Value; - private readonly Lazy beatmap; + public Beatmap Beatmap => beatmap.Value.Result; + public async Task GetBeatmapAsync() => await beatmap.Value; + + private readonly AsyncLazy beatmap; private Beatmap populateBeatmap() { @@ -55,14 +58,16 @@ namespace osu.Game.Beatmaps } public bool BackgroundLoaded => background.IsValueCreated; - public Texture Background => background.Value; - private Lazy background; + public Texture Background => background.Value.Result; + public async Task GetBackgroundAsync() => await background.Value; + private AsyncLazy background; private Texture populateBackground() => GetBackground(); public bool TrackLoaded => track.IsValueCreated; - public Track Track => track.Value; - private Lazy track; + public Track Track => track.Value.Result; + public async Task GetTrackAsync() => await track.Value; + private AsyncLazy track; private Track populateTrack() { @@ -73,8 +78,9 @@ namespace osu.Game.Beatmaps } public bool WaveformLoaded => waveform.IsValueCreated; - public Waveform Waveform => waveform.Value; - private readonly Lazy waveform; + public Waveform Waveform => waveform.Value.Result; + public async Task GetWaveformAsync() => await waveform.Value; + private readonly AsyncLazy waveform; private Waveform populateWaveform() => GetWaveform(); @@ -107,5 +113,13 @@ namespace osu.Game.Beatmaps foreach (var mod in Mods.Value.OfType()) mod.ApplyToClock(t); } + + public class AsyncLazy : Lazy> + { + public AsyncLazy(Func valueFactory) + : base(() => Task.Run(valueFactory)) + { + } + } } } From b3b1f2018e46a0123ce932be3c765e4ac55ce0dd Mon Sep 17 00:00:00 2001 From: Miterosan Date: Tue, 21 Nov 2017 15:13:00 +0100 Subject: [PATCH 0747/1263] Fix osu crashing if a invalid gamerule is given in the game.ini --- osu.Game/OsuGame.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index e603375e9c..4745733bd9 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -109,7 +109,7 @@ namespace osu.Game dependencies.Cache(this); configRuleset = LocalConfig.GetBindable(OsuSetting.Ruleset); - Ruleset.Value = RulesetStore.GetRuleset(configRuleset.Value); + Ruleset.Value = RulesetStore.GetRuleset(configRuleset.Value) ?? RulesetStore.AvailableRulesets.First(); Ruleset.ValueChanged += r => configRuleset.Value = r.ID ?? 0; } From a033eb46d3361e321aaccf24e7569adfdaa988c5 Mon Sep 17 00:00:00 2001 From: FreezyLemon Date: Tue, 21 Nov 2017 16:12:23 +0100 Subject: [PATCH 0748/1263] Changed to LoadComponentAsync call instead of adding an AsyncLoadWrapper instance. --- osu.Game/Overlays/Direct/PlayButton.cs | 11 ++++----- osu.Game/Overlays/Profile/ProfileHeader.cs | 10 ++++---- osu.Game/Screens/Multiplayer/DrawableRoom.cs | 21 +++++++++-------- osu.Game/Screens/Multiplayer/RoomInspector.cs | 23 +++++++++++-------- osu.Game/Screens/Play/Player.cs | 3 ++- 5 files changed, 37 insertions(+), 31 deletions(-) diff --git a/osu.Game/Overlays/Direct/PlayButton.cs b/osu.Game/Overlays/Direct/PlayButton.cs index 9317bc06cf..7fff2821e3 100644 --- a/osu.Game/Overlays/Direct/PlayButton.cs +++ b/osu.Game/Overlays/Direct/PlayButton.cs @@ -146,18 +146,17 @@ namespace osu.Game.Overlays.Direct loading = true; - Add(new AsyncLoadWrapper(trackLoader = new TrackLoader($"https://b.ppy.sh/preview/{BeatmapSet.OnlineBeatmapSetID}.mp3") - { - OnLoadComplete = d => + LoadComponentAsync(trackLoader = new TrackLoader($"https://b.ppy.sh/preview/{BeatmapSet.OnlineBeatmapSetID}.mp3"), + d => { - // we may have been replaced by another loader + // We may have been replaced by another loader if (trackLoader != d) return; Preview = (d as TrackLoader)?.Preview; Playing.TriggerChange(); loading = false; - }, - })); + Add(trackLoader); + }); } private class TrackLoader : Drawable diff --git a/osu.Game/Overlays/Profile/ProfileHeader.cs b/osu.Game/Overlays/Profile/ProfileHeader.cs index 22e34be34c..6a9247e73b 100644 --- a/osu.Game/Overlays/Profile/ProfileHeader.cs +++ b/osu.Game/Overlays/Profile/ProfileHeader.cs @@ -316,18 +316,18 @@ namespace osu.Game.Overlays.Profile private void loadUser() { - coverContainer.Add(new AsyncLoadWrapper(new UserCoverBackground(user) + LoadComponentAsync(new UserCoverBackground(user) { RelativeSizeAxes = Axes.Both, Anchor = Anchor.Centre, Origin = Anchor.Centre, FillMode = FillMode.Fill, OnLoadComplete = d => d.FadeInFromZero(200) - }) + }, + ucb => { - Masking = true, - RelativeSizeAxes = Axes.Both, - Depth = float.MaxValue + ucb.Depth = float.MaxValue; + coverContainer.Add(ucb); }); if (user.IsSupporter) supporterTag.Show(); diff --git a/osu.Game/Screens/Multiplayer/DrawableRoom.cs b/osu.Game/Screens/Multiplayer/DrawableRoom.cs index d2f88224c2..dd69ec9db1 100644 --- a/osu.Game/Screens/Multiplayer/DrawableRoom.cs +++ b/osu.Game/Screens/Multiplayer/DrawableRoom.cs @@ -228,16 +228,19 @@ namespace osu.Game.Screens.Multiplayer if (value != null) { coverContainer.FadeIn(transition_duration); - coverContainer.Children = new[] + + LoadComponentAsync(new BeatmapSetCover(value.BeatmapSet) { - new AsyncLoadWrapper(new BeatmapSetCover(value.BeatmapSet) - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - FillMode = FillMode.Fill, - OnLoadComplete = d => d.FadeInFromZero(400, Easing.Out), - }) { RelativeSizeAxes = Axes.Both }, - }; + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + FillMode = FillMode.Fill, + OnLoadComplete = d => d.FadeInFromZero(400, Easing.Out), + }, + bsc => + { + bsc.RelativeSizeAxes = Axes.Both; + coverContainer.Add(bsc); + }); beatmapTitle.Current = localisation.GetUnicodePreference(value.Metadata.TitleUnicode, value.Metadata.Title); beatmapDash.Text = @" - "; diff --git a/osu.Game/Screens/Multiplayer/RoomInspector.cs b/osu.Game/Screens/Multiplayer/RoomInspector.cs index 66ce51b428..fec35d3d7e 100644 --- a/osu.Game/Screens/Multiplayer/RoomInspector.cs +++ b/osu.Game/Screens/Multiplayer/RoomInspector.cs @@ -329,17 +329,20 @@ namespace osu.Game.Screens.Multiplayer if (value != null) { coverContainer.FadeIn(transition_duration); - coverContainer.Children = new[] + + LoadComponentAsync(new BeatmapSetCover(value.BeatmapSet) { - new AsyncLoadWrapper(new BeatmapSetCover(value.BeatmapSet) - { - RelativeSizeAxes = Axes.Both, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - FillMode = FillMode.Fill, - OnLoadComplete = d => d.FadeInFromZero(400, Easing.Out), - }) { RelativeSizeAxes = Axes.Both }, - }; + RelativeSizeAxes = Axes.Both, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + FillMode = FillMode.Fill, + OnLoadComplete = d => d.FadeInFromZero(400, Easing.Out), + }, + bsc => + { + bsc.RelativeSizeAxes = Axes.Both; + coverContainer.Add(bsc); + }); beatmapTitle.Current = localisation.GetUnicodePreference(value.Metadata.TitleUnicode, value.Metadata.Title); beatmapDash.Text = @" - "; diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index cd2818398d..5f7ef03218 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -248,7 +248,8 @@ namespace osu.Game.Screens.Play storyboard = beatmap.Storyboard.CreateDrawable(Beatmap.Value); storyboard.Masking = true; - storyboardContainer.Add(asyncLoad ? new AsyncLoadWrapper(storyboard) { RelativeSizeAxes = Axes.Both } : (Drawable)storyboard); + if (asyncLoad) LoadComponentAsync(storyboard, s => storyboardContainer.Add(s)); + else storyboardContainer.Add((Drawable)storyboard); } public void Restart() From 870807c26588b0e967d94174bbc54104a1be58b0 Mon Sep 17 00:00:00 2001 From: FreezyLemon Date: Tue, 21 Nov 2017 16:17:33 +0100 Subject: [PATCH 0749/1263] Switched over to the new LoadWrapper class for all delayed loading. --- osu.Game/Beatmaps/Drawables/BeatmapSetHeader.cs | 4 ++-- osu.Game/Overlays/BeatmapSet/Header.cs | 4 ++-- osu.Game/Overlays/Direct/DirectPanel.cs | 2 +- osu.Game/Screens/Select/Leaderboards/LeaderboardScore.cs | 2 +- osu.Game/Users/UpdateableAvatar.cs | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/osu.Game/Beatmaps/Drawables/BeatmapSetHeader.cs b/osu.Game/Beatmaps/Drawables/BeatmapSetHeader.cs index 8a589ccd30..3644c1b26f 100644 --- a/osu.Game/Beatmaps/Drawables/BeatmapSetHeader.cs +++ b/osu.Game/Beatmaps/Drawables/BeatmapSetHeader.cs @@ -43,7 +43,7 @@ namespace osu.Game.Beatmaps.Drawables Children = new Drawable[] { - new DelayedLoadWrapper( + new LoadWrapper( new PanelBackground(beatmap) { RelativeSizeAxes = Axes.Both, @@ -185,4 +185,4 @@ namespace osu.Game.Beatmaps.Drawables } } } -} \ No newline at end of file +} diff --git a/osu.Game/Overlays/BeatmapSet/Header.cs b/osu.Game/Overlays/BeatmapSet/Header.cs index 96bb613f9f..3c7266bb57 100644 --- a/osu.Game/Overlays/BeatmapSet/Header.cs +++ b/osu.Game/Overlays/BeatmapSet/Header.cs @@ -31,7 +31,7 @@ namespace osu.Game.Overlays.BeatmapSet private readonly AuthorInfo author; public Details Details; - private DelayedLoadWrapper cover; + private LoadWrapper cover; public readonly BeatmapPicker Picker; @@ -52,7 +52,7 @@ namespace osu.Game.Overlays.BeatmapSet videoButtons.FadeTo(BeatmapSet.OnlineInfo.HasVideo ? 1 : 0, transition_duration); cover?.FadeOut(400, Easing.Out); - coverContainer.Add(cover = new DelayedLoadWrapper(new BeatmapSetCover(BeatmapSet) + coverContainer.Add(cover = new LoadWrapper(new BeatmapSetCover(BeatmapSet) { Anchor = Anchor.Centre, Origin = Anchor.Centre, diff --git a/osu.Game/Overlays/Direct/DirectPanel.cs b/osu.Game/Overlays/Direct/DirectPanel.cs index ef89c0022b..692e561435 100644 --- a/osu.Game/Overlays/Direct/DirectPanel.cs +++ b/osu.Game/Overlays/Direct/DirectPanel.cs @@ -219,7 +219,7 @@ namespace osu.Game.Overlays.Direct return icons; } - protected Drawable CreateBackground() => new DelayedLoadWrapper(new BeatmapSetCover(SetInfo) + protected Drawable CreateBackground() => new LoadWrapper(new BeatmapSetCover(SetInfo) { Anchor = Anchor.Centre, Origin = Anchor.Centre, diff --git a/osu.Game/Screens/Select/Leaderboards/LeaderboardScore.cs b/osu.Game/Screens/Select/Leaderboards/LeaderboardScore.cs index 7b50d36b44..92fc6aef2b 100644 --- a/osu.Game/Screens/Select/Leaderboards/LeaderboardScore.cs +++ b/osu.Game/Screens/Select/Leaderboards/LeaderboardScore.cs @@ -99,7 +99,7 @@ namespace osu.Game.Screens.Select.Leaderboards Padding = new MarginPadding(edge_margin), Children = new Drawable[] { - avatar = new DelayedLoadWrapper( + avatar = new LoadWrapper( new Avatar(Score.User) { RelativeSizeAxes = Axes.Both, diff --git a/osu.Game/Users/UpdateableAvatar.cs b/osu.Game/Users/UpdateableAvatar.cs index 7c020fce91..12a189f18f 100644 --- a/osu.Game/Users/UpdateableAvatar.cs +++ b/osu.Game/Users/UpdateableAvatar.cs @@ -40,7 +40,7 @@ namespace osu.Game.Users { displayedAvatar?.FadeOut(300); displayedAvatar?.Expire(); - Add(displayedAvatar = new DelayedLoadWrapper(new Avatar(user) + Add(displayedAvatar = new LoadWrapper(new Avatar(user) { RelativeSizeAxes = Axes.Both, OnLoadComplete = d => d.FadeInFromZero(200), From fd7ac9b6fcdb1a476499d5f89714565f62dfa132 Mon Sep 17 00:00:00 2001 From: FreezyLemon Date: Tue, 21 Nov 2017 16:18:32 +0100 Subject: [PATCH 0750/1263] Switched to the new LoadWrapper class for asynchronous loading (LoadComponentAsync not used here since it's not possible to call that method on a component that has not finished loading, and we're in the constructor where it would be called) --- osu.Game/Users/UserPanel.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Users/UserPanel.cs b/osu.Game/Users/UserPanel.cs index ab4d55027d..e4fdcb4c1b 100644 --- a/osu.Game/Users/UserPanel.cs +++ b/osu.Game/Users/UserPanel.cs @@ -58,7 +58,7 @@ namespace osu.Game.Users Children = new Drawable[] { - new AsyncLoadWrapper(new UserCoverBackground(user) + new LoadWrapper(new UserCoverBackground(user) { RelativeSizeAxes = Axes.Both, Anchor = Anchor.Centre, From 2203a8430000b00d539bbfc29000556a789d0a54 Mon Sep 17 00:00:00 2001 From: FreezyLemon Date: Tue, 21 Nov 2017 19:16:44 +0100 Subject: [PATCH 0751/1263] Small fixes and style corrections --- osu.Game/Overlays/BeatmapSet/Header.cs | 21 +++++++++-------- osu.Game/Overlays/Direct/DirectPanel.cs | 23 ++++++++++--------- osu.Game/Screens/Multiplayer/DrawableRoom.cs | 7 ++---- osu.Game/Screens/Multiplayer/RoomInspector.cs | 6 +---- osu.Game/Users/UpdateableAvatar.cs | 12 ++++++---- 5 files changed, 33 insertions(+), 36 deletions(-) diff --git a/osu.Game/Overlays/BeatmapSet/Header.cs b/osu.Game/Overlays/BeatmapSet/Header.cs index 3c7266bb57..5fed0c096a 100644 --- a/osu.Game/Overlays/BeatmapSet/Header.cs +++ b/osu.Game/Overlays/BeatmapSet/Header.cs @@ -52,17 +52,18 @@ namespace osu.Game.Overlays.BeatmapSet videoButtons.FadeTo(BeatmapSet.OnlineInfo.HasVideo ? 1 : 0, transition_duration); cover?.FadeOut(400, Easing.Out); - coverContainer.Add(cover = new LoadWrapper(new BeatmapSetCover(BeatmapSet) - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Both, - FillMode = FillMode.Fill, - OnLoadComplete = d => + coverContainer.Add(cover = new LoadWrapper( + new BeatmapSetCover(BeatmapSet) { - d.FadeInFromZero(400, Easing.Out); - }, - }) + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + FillMode = FillMode.Fill, + OnLoadComplete = d => + { + d.FadeInFromZero(400, Easing.Out); + }, + }) { RelativeSizeAxes = Axes.Both, TimeBeforeLoad = 300 diff --git a/osu.Game/Overlays/Direct/DirectPanel.cs b/osu.Game/Overlays/Direct/DirectPanel.cs index 692e561435..98aa5ef0cb 100644 --- a/osu.Game/Overlays/Direct/DirectPanel.cs +++ b/osu.Game/Overlays/Direct/DirectPanel.cs @@ -219,18 +219,19 @@ namespace osu.Game.Overlays.Direct return icons; } - protected Drawable CreateBackground() => new LoadWrapper(new BeatmapSetCover(SetInfo) - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Both, - FillMode = FillMode.Fill, - OnLoadComplete = d => + protected Drawable CreateBackground() => new LoadWrapper( + new BeatmapSetCover(SetInfo) { - d.FadeInFromZero(400, Easing.Out); - BlackBackground.Delay(400).FadeOut(); - }, - }) + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + FillMode = FillMode.Fill, + OnLoadComplete = d => + { + d.FadeInFromZero(400, Easing.Out); + BlackBackground.Delay(400).FadeOut(); + }, + }) { RelativeSizeAxes = Axes.Both, TimeBeforeLoad = 300 diff --git a/osu.Game/Screens/Multiplayer/DrawableRoom.cs b/osu.Game/Screens/Multiplayer/DrawableRoom.cs index dd69ec9db1..77e32752e4 100644 --- a/osu.Game/Screens/Multiplayer/DrawableRoom.cs +++ b/osu.Game/Screens/Multiplayer/DrawableRoom.cs @@ -229,6 +229,7 @@ namespace osu.Game.Screens.Multiplayer { coverContainer.FadeIn(transition_duration); + LoadComponentAsync(new BeatmapSetCover(value.BeatmapSet) { Anchor = Anchor.Centre, @@ -236,11 +237,7 @@ namespace osu.Game.Screens.Multiplayer FillMode = FillMode.Fill, OnLoadComplete = d => d.FadeInFromZero(400, Easing.Out), }, - bsc => - { - bsc.RelativeSizeAxes = Axes.Both; - coverContainer.Add(bsc); - }); + bsc => coverContainer.Add(bsc)); beatmapTitle.Current = localisation.GetUnicodePreference(value.Metadata.TitleUnicode, value.Metadata.Title); beatmapDash.Text = @" - "; diff --git a/osu.Game/Screens/Multiplayer/RoomInspector.cs b/osu.Game/Screens/Multiplayer/RoomInspector.cs index fec35d3d7e..30c2aa8505 100644 --- a/osu.Game/Screens/Multiplayer/RoomInspector.cs +++ b/osu.Game/Screens/Multiplayer/RoomInspector.cs @@ -338,11 +338,7 @@ namespace osu.Game.Screens.Multiplayer FillMode = FillMode.Fill, OnLoadComplete = d => d.FadeInFromZero(400, Easing.Out), }, - bsc => - { - bsc.RelativeSizeAxes = Axes.Both; - coverContainer.Add(bsc); - }); + bsc => coverContainer.Add(bsc)); beatmapTitle.Current = localisation.GetUnicodePreference(value.Metadata.TitleUnicode, value.Metadata.Title); beatmapDash.Text = @" - "; diff --git a/osu.Game/Users/UpdateableAvatar.cs b/osu.Game/Users/UpdateableAvatar.cs index 12a189f18f..02018ee1f4 100644 --- a/osu.Game/Users/UpdateableAvatar.cs +++ b/osu.Game/Users/UpdateableAvatar.cs @@ -40,11 +40,13 @@ namespace osu.Game.Users { displayedAvatar?.FadeOut(300); displayedAvatar?.Expire(); - Add(displayedAvatar = new LoadWrapper(new Avatar(user) - { - RelativeSizeAxes = Axes.Both, - OnLoadComplete = d => d.FadeInFromZero(200), - })); + Add(displayedAvatar = new LoadWrapper( + new Avatar(user) + { + RelativeSizeAxes = Axes.Both, + OnLoadComplete = d => d.FadeInFromZero(200), + }) + ); } } } From bf0184c06dc1cbef794c3e617bdb97caa7145bf1 Mon Sep 17 00:00:00 2001 From: FreezyLemon Date: Tue, 21 Nov 2017 19:34:01 +0100 Subject: [PATCH 0752/1263] One more small style fix --- osu.Game/Overlays/BeatmapSet/Header.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/osu.Game/Overlays/BeatmapSet/Header.cs b/osu.Game/Overlays/BeatmapSet/Header.cs index 5fed0c096a..b9d04e7b55 100644 --- a/osu.Game/Overlays/BeatmapSet/Header.cs +++ b/osu.Game/Overlays/BeatmapSet/Header.cs @@ -59,10 +59,7 @@ namespace osu.Game.Overlays.BeatmapSet Origin = Anchor.Centre, RelativeSizeAxes = Axes.Both, FillMode = FillMode.Fill, - OnLoadComplete = d => - { - d.FadeInFromZero(400, Easing.Out); - }, + OnLoadComplete = d => d.FadeInFromZero(400, Easing.Out), }) { RelativeSizeAxes = Axes.Both, From 1d41e7cc8a8ea5a750004bbfe8ad1cd4936521da Mon Sep 17 00:00:00 2001 From: FreezyLemon Date: Tue, 21 Nov 2017 20:15:42 +0100 Subject: [PATCH 0753/1263] Removed newline at end --- osu.Game/Screens/Multiplayer/DrawableRoom.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Multiplayer/DrawableRoom.cs b/osu.Game/Screens/Multiplayer/DrawableRoom.cs index 77e32752e4..60a0bd7a82 100644 --- a/osu.Game/Screens/Multiplayer/DrawableRoom.cs +++ b/osu.Game/Screens/Multiplayer/DrawableRoom.cs @@ -229,7 +229,7 @@ namespace osu.Game.Screens.Multiplayer { coverContainer.FadeIn(transition_duration); - + LoadComponentAsync(new BeatmapSetCover(value.BeatmapSet) { Anchor = Anchor.Centre, @@ -260,4 +260,4 @@ namespace osu.Game.Screens.Multiplayer participantInfo.Participants = value; } } -} +} \ No newline at end of file From 63d366ea4b77941e61dc90abb0aa1748e7dd7e7c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 22 Nov 2017 10:54:33 +0900 Subject: [PATCH 0754/1263] Bindables should be readonly --- osu.Game/Screens/Edit/Components/BottomBarContainer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Components/BottomBarContainer.cs b/osu.Game/Screens/Edit/Components/BottomBarContainer.cs index d65355b5f4..0e57407928 100644 --- a/osu.Game/Screens/Edit/Components/BottomBarContainer.cs +++ b/osu.Game/Screens/Edit/Components/BottomBarContainer.cs @@ -17,7 +17,7 @@ namespace osu.Game.Screens.Edit.Components private const float corner_radius = 5; private const float contents_padding = 15; - public Bindable Beatmap = new Bindable(); + public readonly Bindable Beatmap = new Bindable(); protected Track Track => Beatmap.Value.Track; private readonly Drawable background; From 461c8e8be0805956eaa4a98c5f8f28512780c394 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 22 Nov 2017 10:55:06 +0900 Subject: [PATCH 0755/1263] Clean up state change logic --- .../Edit/Components/PlaybackContainer.cs | 23 +++++++------------ 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/osu.Game/Screens/Edit/Components/PlaybackContainer.cs b/osu.Game/Screens/Edit/Components/PlaybackContainer.cs index a7d1db4802..67478dd94c 100644 --- a/osu.Game/Screens/Edit/Components/PlaybackContainer.cs +++ b/osu.Game/Screens/Edit/Components/PlaybackContainer.cs @@ -128,32 +128,25 @@ namespace osu.Game.Screens.Edit.Components protected override bool OnHover(InputState state) { - if (!Active) - toBold(); + updateState(); return true; } protected override void OnHoverLost(InputState state) { - if (!Active) - toNormal(); + updateState(); } - private void toBold() + + private void updateState() { - text.FadeOut(fade_duration); - textBold.FadeIn(fade_duration); + text.FadeTo(Active || IsHovered ? 0 : 1, fade_duration); + textBold.FadeTo(Active || IsHovered ? 1 : 0, fade_duration); } - private void toNormal() - { - text.FadeIn(fade_duration); - textBold.FadeOut(fade_duration); - } + protected override void OnActivated() => updateState(); - protected override void OnActivated() => toBold(); - - protected override void OnDeactivated() => toNormal(); + protected override void OnDeactivated() => updateState(); } } } From c06d6d0bbb86bce8c116d6bf291f61d8b72a6dad Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 22 Nov 2017 10:59:31 +0900 Subject: [PATCH 0756/1263] Rename weird method --- osu.Game/Screens/Edit/Components/PlaybackContainer.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Edit/Components/PlaybackContainer.cs b/osu.Game/Screens/Edit/Components/PlaybackContainer.cs index 67478dd94c..a133c88c84 100644 --- a/osu.Game/Screens/Edit/Components/PlaybackContainer.cs +++ b/osu.Game/Screens/Edit/Components/PlaybackContainer.cs @@ -30,7 +30,7 @@ namespace osu.Game.Screens.Edit.Components Scale = new Vector2(1.4f), IconScale = new Vector2(1.4f), Icon = FontAwesome.fa_play_circle_o, - Action = playPause, + Action = togglePause, Padding = new MarginPadding { Left = 20 } }, new OsuSpriteText @@ -59,7 +59,7 @@ namespace osu.Game.Screens.Edit.Components tabs.Current.ValueChanged += newValue => Track.Tempo.Value = newValue; } - private void playPause() + private void togglePause() { if (Track.IsRunning) Track.Stop(); From 855acc9401c1ae3a36c3fbbe27b7f0d6d054b16e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 22 Nov 2017 11:17:10 +0900 Subject: [PATCH 0757/1263] Fix leading space before percent sign --- osu.Game/Screens/Edit/Components/PlaybackContainer.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Edit/Components/PlaybackContainer.cs b/osu.Game/Screens/Edit/Components/PlaybackContainer.cs index a133c88c84..0698d874a1 100644 --- a/osu.Game/Screens/Edit/Components/PlaybackContainer.cs +++ b/osu.Game/Screens/Edit/Components/PlaybackContainer.cs @@ -104,14 +104,14 @@ namespace osu.Game.Screens.Edit.Components { Origin = Anchor.TopCentre, Anchor = Anchor.TopCentre, - Text = $"{value:P0}", + Text = $"{value:0%}", TextSize = 14, }, textBold = new OsuSpriteText { Origin = Anchor.TopCentre, Anchor = Anchor.TopCentre, - Text = $"{value:P0}", + Text = $"{value:0%}", TextSize = 14, Font = @"Exo2.0-Bold", Alpha = 0, From ff5404e57f2489d7419ab6b8556796632d838773 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 22 Nov 2017 11:21:48 +0900 Subject: [PATCH 0758/1263] Remove need for AlwaysPresent Also self-contains the tab options inside the tab control. --- .../Edit/Components/PlaybackContainer.cs | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/osu.Game/Screens/Edit/Components/PlaybackContainer.cs b/osu.Game/Screens/Edit/Components/PlaybackContainer.cs index 0698d874a1..746052f2c2 100644 --- a/osu.Game/Screens/Edit/Components/PlaybackContainer.cs +++ b/osu.Game/Screens/Edit/Components/PlaybackContainer.cs @@ -1,12 +1,16 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System.Globalization; +using System.Linq; using OpenTK; using osu.Framework.Allocation; +using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.UserInterface; using osu.Framework.Input; +using osu.Game.Beatmaps; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; @@ -52,10 +56,6 @@ namespace osu.Game.Screens.Edit.Components } }; - tabs.AddItem(0.25); - tabs.AddItem(0.75); - tabs.AddItem(1); - tabs.Current.ValueChanged += newValue => Track.Tempo.Value = newValue; } @@ -76,6 +76,8 @@ namespace osu.Game.Screens.Edit.Components private class PlaybackTabControl : OsuTabControl { + private static double[] tempo_values = new [] { 0.5, 0.75, 1 }; + protected override TabItem CreateTabItem(double value) => new PlaybackTabItem(value); protected override Dropdown CreateDropdown() => null; @@ -83,7 +85,9 @@ namespace osu.Game.Screens.Edit.Components public PlaybackTabControl() { RelativeSizeAxes = Axes.Both; - TabContainer.Spacing = new Vector2(20, 0); + TabContainer.Spacing = Vector2.Zero; + + tempo_values.ForEach(AddItem); } public class PlaybackTabItem : TabItem @@ -95,8 +99,9 @@ namespace osu.Game.Screens.Edit.Components public PlaybackTabItem(double value) : base(value) { - AutoSizeAxes = Axes.X; - RelativeSizeAxes = Axes.Y; + RelativeSizeAxes = Axes.Both; + + Width = 1f / tempo_values.Length; Children = new Drawable[] { @@ -115,7 +120,6 @@ namespace osu.Game.Screens.Edit.Components TextSize = 14, Font = @"Exo2.0-Bold", Alpha = 0, - AlwaysPresent = true, }, }; } From 0f8499c58027d5e675d85d4e47e487d6bffbd5c6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 22 Nov 2017 11:22:46 +0900 Subject: [PATCH 0759/1263] Rename to PlaybackControl and add a TestCase --- .../Visual/TestCasePlaybackControl.cs | 27 +++++++++++++++++++ osu.Game.Tests/osu.Game.Tests.csproj | 1 + ...laybackContainer.cs => PlaybackControl.cs} | 4 +-- osu.Game/Screens/Edit/Editor.cs | 4 +-- osu.Game/osu.Game.csproj | 2 +- 5 files changed, 33 insertions(+), 5 deletions(-) create mode 100644 osu.Game.Tests/Visual/TestCasePlaybackControl.cs rename osu.Game/Screens/Edit/Components/{PlaybackContainer.cs => PlaybackControl.cs} (95%) diff --git a/osu.Game.Tests/Visual/TestCasePlaybackControl.cs b/osu.Game.Tests/Visual/TestCasePlaybackControl.cs new file mode 100644 index 0000000000..f5fb4b6032 --- /dev/null +++ b/osu.Game.Tests/Visual/TestCasePlaybackControl.cs @@ -0,0 +1,27 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE + +using osu.Framework.Graphics; +using osu.Game.Beatmaps; +using osu.Game.Screens.Edit.Components; +using osu.Game.Tests.Beatmaps; +using OpenTK; + +namespace osu.Game.Tests.Visual +{ + public class TestCasePlaybackControl : OsuTestCase + { + public TestCasePlaybackControl() + { + var playback = new PlaybackControl() + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Size = new Vector2(200,100) + }; + playback.Beatmap.Value = new TestWorkingBeatmap(new Beatmap()); + + Add(playback); + } + } +} diff --git a/osu.Game.Tests/osu.Game.Tests.csproj b/osu.Game.Tests/osu.Game.Tests.csproj index 974bde9319..9bba09b1a7 100644 --- a/osu.Game.Tests/osu.Game.Tests.csproj +++ b/osu.Game.Tests/osu.Game.Tests.csproj @@ -124,6 +124,7 @@ + diff --git a/osu.Game/Screens/Edit/Components/PlaybackContainer.cs b/osu.Game/Screens/Edit/Components/PlaybackControl.cs similarity index 95% rename from osu.Game/Screens/Edit/Components/PlaybackContainer.cs rename to osu.Game/Screens/Edit/Components/PlaybackControl.cs index 746052f2c2..5017d9e1a4 100644 --- a/osu.Game/Screens/Edit/Components/PlaybackContainer.cs +++ b/osu.Game/Screens/Edit/Components/PlaybackControl.cs @@ -17,11 +17,11 @@ using osu.Game.Graphics.UserInterface; namespace osu.Game.Screens.Edit.Components { - public class PlaybackContainer : BottomBarContainer + public class PlaybackControl : BottomBarContainer { private readonly IconButton playButton; - public PlaybackContainer() + public PlaybackControl() { PlaybackTabControl tabs; diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index e2971deb75..607ff792d8 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -36,7 +36,7 @@ namespace osu.Game.Screens.Edit EditorMenuBar menuBar; TimeInfoContainer timeInfo; SummaryTimeline timeline; - PlaybackContainer playback; + PlaybackControl playback; Children = new[] { @@ -114,7 +114,7 @@ namespace osu.Game.Screens.Edit { RelativeSizeAxes = Axes.Both, Padding = new MarginPadding { Left = 10 }, - Child = playback = new PlaybackContainer { RelativeSizeAxes = Axes.Both }, + Child = playback = new PlaybackControl { RelativeSizeAxes = Axes.Both }, } }, } diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 048735358e..0752b31495 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -299,7 +299,7 @@ - + From 27fb5983525c73415a116b93d25cb0dac446ab12 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 22 Nov 2017 11:34:54 +0900 Subject: [PATCH 0760/1263] Update colours to match design --- .../Screens/Edit/Components/PlaybackControl.cs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Edit/Components/PlaybackControl.cs b/osu.Game/Screens/Edit/Components/PlaybackControl.cs index 5017d9e1a4..56fca6bf9e 100644 --- a/osu.Game/Screens/Edit/Components/PlaybackControl.cs +++ b/osu.Game/Screens/Edit/Components/PlaybackControl.cs @@ -4,6 +4,7 @@ using System.Globalization; using System.Linq; using OpenTK; +using OpenTK.Graphics; using osu.Framework.Allocation; using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Graphics; @@ -92,7 +93,7 @@ namespace osu.Game.Screens.Edit.Components public class PlaybackTabItem : TabItem { - private const float fade_duration = 100; + private const float fade_duration = 200; private readonly OsuSpriteText text; private readonly OsuSpriteText textBold; @@ -124,10 +125,14 @@ namespace osu.Game.Screens.Edit.Components }; } + private Color4 hoveredColour; + private Color4 normalColour; + [BackgroundDependencyLoader] private void load(OsuColour colours) { - text.Colour = colours.Gray5; + text.Colour = normalColour = colours.YellowDarker; + textBold.Colour = hoveredColour = colours.Yellow; } protected override bool OnHover(InputState state) @@ -144,8 +149,9 @@ namespace osu.Game.Screens.Edit.Components private void updateState() { - text.FadeTo(Active || IsHovered ? 0 : 1, fade_duration); - textBold.FadeTo(Active || IsHovered ? 1 : 0, fade_duration); + text.FadeColour(Active || IsHovered ? hoveredColour : normalColour, fade_duration, Easing.OutQuint); + text.FadeTo(Active ? 0 : 1, fade_duration, Easing.OutQuint); + textBold.FadeTo(Active ? 1 : 0, fade_duration, Easing.OutQuint); } protected override void OnActivated() => updateState(); From e3c5a599b6eba4057385397ba8beb3ff10abafad Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 22 Nov 2017 11:36:29 +0900 Subject: [PATCH 0761/1263] Tidy some regressions --- osu.Game.Tests/Visual/TestCasePlaybackControl.cs | 2 +- osu.Game/Screens/Edit/Components/PlaybackControl.cs | 5 +---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCasePlaybackControl.cs b/osu.Game.Tests/Visual/TestCasePlaybackControl.cs index f5fb4b6032..bd2b011dbc 100644 --- a/osu.Game.Tests/Visual/TestCasePlaybackControl.cs +++ b/osu.Game.Tests/Visual/TestCasePlaybackControl.cs @@ -13,7 +13,7 @@ namespace osu.Game.Tests.Visual { public TestCasePlaybackControl() { - var playback = new PlaybackControl() + var playback = new PlaybackControl { Anchor = Anchor.Centre, Origin = Anchor.Centre, diff --git a/osu.Game/Screens/Edit/Components/PlaybackControl.cs b/osu.Game/Screens/Edit/Components/PlaybackControl.cs index 56fca6bf9e..bb814a0423 100644 --- a/osu.Game/Screens/Edit/Components/PlaybackControl.cs +++ b/osu.Game/Screens/Edit/Components/PlaybackControl.cs @@ -1,8 +1,6 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using System.Globalization; -using System.Linq; using OpenTK; using OpenTK.Graphics; using osu.Framework.Allocation; @@ -11,7 +9,6 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.UserInterface; using osu.Framework.Input; -using osu.Game.Beatmaps; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; @@ -77,7 +74,7 @@ namespace osu.Game.Screens.Edit.Components private class PlaybackTabControl : OsuTabControl { - private static double[] tempo_values = new [] { 0.5, 0.75, 1 }; + private static readonly double[] tempo_values = { 0.5, 0.75, 1 }; protected override TabItem CreateTabItem(double value) => new PlaybackTabItem(value); From 36d45f633d65e38a0929ed577c8b28ec2786b4f3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 22 Nov 2017 11:57:09 +0900 Subject: [PATCH 0762/1263] Reorder methods --- osu.Game/Screens/Edit/Components/PlaybackControl.cs | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/osu.Game/Screens/Edit/Components/PlaybackControl.cs b/osu.Game/Screens/Edit/Components/PlaybackControl.cs index bb814a0423..5ffa66c43e 100644 --- a/osu.Game/Screens/Edit/Components/PlaybackControl.cs +++ b/osu.Game/Screens/Edit/Components/PlaybackControl.cs @@ -138,11 +138,9 @@ namespace osu.Game.Screens.Edit.Components return true; } - protected override void OnHoverLost(InputState state) - { - updateState(); - } - + protected override void OnHoverLost(InputState state) => updateState(); + protected override void OnActivated() => updateState(); + protected override void OnDeactivated() => updateState(); private void updateState() { @@ -150,10 +148,6 @@ namespace osu.Game.Screens.Edit.Components text.FadeTo(Active ? 0 : 1, fade_duration, Easing.OutQuint); textBold.FadeTo(Active ? 1 : 0, fade_duration, Easing.OutQuint); } - - protected override void OnActivated() => updateState(); - - protected override void OnDeactivated() => updateState(); } } } From 757bb6911e6e7db4e4cbadaec7bb58858afc9780 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 22 Nov 2017 12:06:31 +0900 Subject: [PATCH 0763/1263] Fix license header from wrong project --- osu.Game.Tests/Visual/TestCasePlaybackControl.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/TestCasePlaybackControl.cs b/osu.Game.Tests/Visual/TestCasePlaybackControl.cs index bd2b011dbc..ff59bb7bfd 100644 --- a/osu.Game.Tests/Visual/TestCasePlaybackControl.cs +++ b/osu.Game.Tests/Visual/TestCasePlaybackControl.cs @@ -1,5 +1,5 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using osu.Framework.Graphics; using osu.Game.Beatmaps; From 782a739370fbe9f02a0ad389397248caaab8bed9 Mon Sep 17 00:00:00 2001 From: Brayzure Date: Tue, 21 Nov 2017 23:00:00 -0500 Subject: [PATCH 0764/1263] Fix Results Screen After Failing Last Note Fixes a bug where if you failed on the last hitobject, the AllJudged event will have already been invoked. --- osu.Game/Rulesets/Scoring/ScoreProcessor.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs index 7b26e50dd8..e129a81116 100644 --- a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs +++ b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs @@ -224,8 +224,8 @@ namespace osu.Game.Rulesets.Scoring OnNewJudgement(judgement); updateScore(); - NotifyNewJudgement(judgement); UpdateFailed(); + NotifyNewJudgement(judgement); } protected void RemoveJudgement(Judgement judgement) From 36027f8700f3c9ae9aab3026640c5119a32b477b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 22 Nov 2017 13:54:38 +0900 Subject: [PATCH 0765/1263] Update readme to mention using visualtests always forever --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index ad56178132..ce77e840f6 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,8 @@ This is still heavily under development and is not intended for end-user use. Th We welcome all contributions, but keep in mind that we already have a lot of the UI designed. If you wish to work on something with the intention on having it included in the official distribution, please open an issue for discussion and we will give you what you need from a design perspective to proceed. If you want to make *changes* to the design, we recommend you open an issue with your intentions before spending too much time, to ensure no effort is wasted. +Please make sure you are familiar with the [development and testing](https://github.com/ppy/osu-framework/wiki/Development-and-Testing) procedure we have setup. New component development, and where possible, bug fixing and debugging existing components **should always be done under VisualTests**. + Contributions can be made via pull requests to this repository. We hope to credit and reward larger contributions via a [bounty system](https://www.bountysource.com/teams/ppy). If you're unsure of what you can help with, check out the [list of open issues](https://github.com/ppy/osu-framework/issues). Note that while we already have certain standards in place, nothing is set in stone. If you have an issue with the way code is structured; with any libraries we are using; with any processes involved with contributing, *please* bring it up. I welcome all feedback so we can make contributing to this project as pain-free as possible. From 5646ba4b2442c587e5f7e9070b6862d3f50c3175 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 22 Nov 2017 14:04:32 +0900 Subject: [PATCH 0766/1263] Fix incorrect issues link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ce77e840f6..484807d94d 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ We welcome all contributions, but keep in mind that we already have a lot of the Please make sure you are familiar with the [development and testing](https://github.com/ppy/osu-framework/wiki/Development-and-Testing) procedure we have setup. New component development, and where possible, bug fixing and debugging existing components **should always be done under VisualTests**. -Contributions can be made via pull requests to this repository. We hope to credit and reward larger contributions via a [bounty system](https://www.bountysource.com/teams/ppy). If you're unsure of what you can help with, check out the [list of open issues](https://github.com/ppy/osu-framework/issues). +Contributions can be made via pull requests to this repository. We hope to credit and reward larger contributions via a [bounty system](https://www.bountysource.com/teams/ppy). If you're unsure of what you can help with, check out the [list of open issues](https://github.com/ppy/osu/issues). Note that while we already have certain standards in place, nothing is set in stone. If you have an issue with the way code is structured; with any libraries we are using; with any processes involved with contributing, *please* bring it up. I welcome all feedback so we can make contributing to this project as pain-free as possible. From 7de10a5877ac5a6636475a9389ea02d41577a513 Mon Sep 17 00:00:00 2001 From: Dan Balasescu <1329837+smoogipoo@users.noreply.github.com> Date: Wed, 22 Nov 2017 18:14:40 +0900 Subject: [PATCH 0767/1263] Fix invalid cast from noun to verb --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 484807d94d..856536d22d 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ This is still heavily under development and is not intended for end-user use. Th We welcome all contributions, but keep in mind that we already have a lot of the UI designed. If you wish to work on something with the intention on having it included in the official distribution, please open an issue for discussion and we will give you what you need from a design perspective to proceed. If you want to make *changes* to the design, we recommend you open an issue with your intentions before spending too much time, to ensure no effort is wasted. -Please make sure you are familiar with the [development and testing](https://github.com/ppy/osu-framework/wiki/Development-and-Testing) procedure we have setup. New component development, and where possible, bug fixing and debugging existing components **should always be done under VisualTests**. +Please make sure you are familiar with the [development and testing](https://github.com/ppy/osu-framework/wiki/Development-and-Testing) procedure we have set up. New component development, and where possible, bug fixing and debugging existing components **should always be done under VisualTests**. Contributions can be made via pull requests to this repository. We hope to credit and reward larger contributions via a [bounty system](https://www.bountysource.com/teams/ppy). If you're unsure of what you can help with, check out the [list of open issues](https://github.com/ppy/osu/issues). From e5dfe4ff2e3f75da2bc0a878ced26c7d23c4737d Mon Sep 17 00:00:00 2001 From: Aergwyn Date: Wed, 22 Nov 2017 11:35:25 +0100 Subject: [PATCH 0768/1263] Make error more verbose when beatmap import fails (#1537) Add name of beatmap set to error message if import fails --- osu.Game/Beatmaps/BeatmapManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 006269f186..f461317ce1 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -165,7 +165,7 @@ namespace osu.Game.Beatmaps catch (Exception e) { e = e.InnerException ?? e; - Logger.Error(e, @"Could not import beatmap set"); + Logger.Error(e, $@"Could not import beatmap set ({Path.GetFileName(path)})"); } } From 0af3aea716cddafb248f3802852fe4c9a95d8e20 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 22 Nov 2017 19:38:12 +0900 Subject: [PATCH 0769/1263] Update framework --- osu-framework | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu-framework b/osu-framework index 83925a8407..c6fd291492 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit 83925a84072ec9da0d008c82256294b765321c0b +Subproject commit c6fd2914926f2a6df23eda536c0310f072581b1b From 7d428875b8c0a4537ef3bde6531393ca3edc0459 Mon Sep 17 00:00:00 2001 From: FreezyLemon Date: Wed, 22 Nov 2017 15:46:04 +0100 Subject: [PATCH 0770/1263] Changed LoadWrapper back to DelayedLoadWrapper and fixed the implementation (dependent on framework change, delay now in ctor) --- osu.Game/Beatmaps/Drawables/BeatmapSetHeader.cs | 10 ++++------ osu.Game/Overlays/BeatmapSet/Header.cs | 8 ++++---- osu.Game/Overlays/Direct/DirectPanel.cs | 6 +++--- .../Screens/Select/Leaderboards/LeaderboardScore.cs | 6 +++--- osu.Game/Users/UpdateableAvatar.cs | 5 +++-- osu.Game/Users/UserPanel.cs | 2 +- 6 files changed, 18 insertions(+), 19 deletions(-) diff --git a/osu.Game/Beatmaps/Drawables/BeatmapSetHeader.cs b/osu.Game/Beatmaps/Drawables/BeatmapSetHeader.cs index 3644c1b26f..ec39f86c5c 100644 --- a/osu.Game/Beatmaps/Drawables/BeatmapSetHeader.cs +++ b/osu.Game/Beatmaps/Drawables/BeatmapSetHeader.cs @@ -43,16 +43,14 @@ namespace osu.Game.Beatmaps.Drawables Children = new Drawable[] { - new LoadWrapper( + new DelayedLoadWrapper( new PanelBackground(beatmap) { RelativeSizeAxes = Axes.Both, OnLoadComplete = d => d.FadeInFromZero(400, Easing.Out), - } - ) - { - TimeBeforeLoad = 300, - }, + }, + 300 + ), new FillFlowContainer { Direction = FillDirection.Vertical, diff --git a/osu.Game/Overlays/BeatmapSet/Header.cs b/osu.Game/Overlays/BeatmapSet/Header.cs index b9d04e7b55..9bf14e1f90 100644 --- a/osu.Game/Overlays/BeatmapSet/Header.cs +++ b/osu.Game/Overlays/BeatmapSet/Header.cs @@ -31,7 +31,7 @@ namespace osu.Game.Overlays.BeatmapSet private readonly AuthorInfo author; public Details Details; - private LoadWrapper cover; + private DelayedLoadWrapper cover; public readonly BeatmapPicker Picker; @@ -52,7 +52,7 @@ namespace osu.Game.Overlays.BeatmapSet videoButtons.FadeTo(BeatmapSet.OnlineInfo.HasVideo ? 1 : 0, transition_duration); cover?.FadeOut(400, Easing.Out); - coverContainer.Add(cover = new LoadWrapper( + coverContainer.Add(cover = new DelayedLoadWrapper( new BeatmapSetCover(BeatmapSet) { Anchor = Anchor.Centre, @@ -60,10 +60,10 @@ namespace osu.Game.Overlays.BeatmapSet RelativeSizeAxes = Axes.Both, FillMode = FillMode.Fill, OnLoadComplete = d => d.FadeInFromZero(400, Easing.Out), - }) + }, + 300) { RelativeSizeAxes = Axes.Both, - TimeBeforeLoad = 300 }); } } diff --git a/osu.Game/Overlays/Direct/DirectPanel.cs b/osu.Game/Overlays/Direct/DirectPanel.cs index 98aa5ef0cb..bef8697552 100644 --- a/osu.Game/Overlays/Direct/DirectPanel.cs +++ b/osu.Game/Overlays/Direct/DirectPanel.cs @@ -219,7 +219,7 @@ namespace osu.Game.Overlays.Direct return icons; } - protected Drawable CreateBackground() => new LoadWrapper( + protected Drawable CreateBackground() => new DelayedLoadWrapper( new BeatmapSetCover(SetInfo) { Anchor = Anchor.Centre, @@ -231,10 +231,10 @@ namespace osu.Game.Overlays.Direct d.FadeInFromZero(400, Easing.Out); BlackBackground.Delay(400).FadeOut(); }, - }) + }, + 300) { RelativeSizeAxes = Axes.Both, - TimeBeforeLoad = 300 }; public class Statistic : FillFlowContainer diff --git a/osu.Game/Screens/Select/Leaderboards/LeaderboardScore.cs b/osu.Game/Screens/Select/Leaderboards/LeaderboardScore.cs index 92fc6aef2b..14cd7e6f07 100644 --- a/osu.Game/Screens/Select/Leaderboards/LeaderboardScore.cs +++ b/osu.Game/Screens/Select/Leaderboards/LeaderboardScore.cs @@ -99,7 +99,7 @@ namespace osu.Game.Screens.Select.Leaderboards Padding = new MarginPadding(edge_margin), Children = new Drawable[] { - avatar = new LoadWrapper( + avatar = new DelayedLoadWrapper( new Avatar(Score.User) { RelativeSizeAxes = Axes.Both, @@ -112,9 +112,9 @@ namespace osu.Game.Screens.Select.Leaderboards Radius = 1, Colour = Color4.Black.Opacity(0.2f), }, - }) + }, + 500) { - TimeBeforeLoad = 500, RelativeSizeAxes = Axes.None, Size = new Vector2(HEIGHT - edge_margin * 2, HEIGHT - edge_margin * 2), }, diff --git a/osu.Game/Users/UpdateableAvatar.cs b/osu.Game/Users/UpdateableAvatar.cs index 02018ee1f4..1700046653 100644 --- a/osu.Game/Users/UpdateableAvatar.cs +++ b/osu.Game/Users/UpdateableAvatar.cs @@ -40,12 +40,13 @@ namespace osu.Game.Users { displayedAvatar?.FadeOut(300); displayedAvatar?.Expire(); - Add(displayedAvatar = new LoadWrapper( + Add(displayedAvatar = new DelayedLoadWrapper( new Avatar(user) { RelativeSizeAxes = Axes.Both, OnLoadComplete = d => d.FadeInFromZero(200), - }) + }, + 500) ); } } diff --git a/osu.Game/Users/UserPanel.cs b/osu.Game/Users/UserPanel.cs index e4fdcb4c1b..923c62f8ef 100644 --- a/osu.Game/Users/UserPanel.cs +++ b/osu.Game/Users/UserPanel.cs @@ -58,7 +58,7 @@ namespace osu.Game.Users Children = new Drawable[] { - new LoadWrapper(new UserCoverBackground(user) + new DelayedLoadWrapper(new UserCoverBackground(user) { RelativeSizeAxes = Axes.Both, Anchor = Anchor.Centre, From 18b0b77f0ae27c1dddd976a6ae7e7405463e1656 Mon Sep 17 00:00:00 2001 From: FreezyLemon Date: Wed, 22 Nov 2017 21:41:50 +0100 Subject: [PATCH 0771/1263] Added requested changes. Mainly changing lambdas to direct function references. --- osu.Game/Overlays/Profile/ProfileHeader.cs | 9 +++------ osu.Game/Screens/Multiplayer/DrawableRoom.cs | 4 ++-- osu.Game/Screens/Multiplayer/RoomInspector.cs | 2 +- osu.Game/Screens/Play/Player.cs | 6 ++++-- 4 files changed, 10 insertions(+), 11 deletions(-) diff --git a/osu.Game/Overlays/Profile/ProfileHeader.cs b/osu.Game/Overlays/Profile/ProfileHeader.cs index 6a9247e73b..c7bc5c1d93 100644 --- a/osu.Game/Overlays/Profile/ProfileHeader.cs +++ b/osu.Game/Overlays/Profile/ProfileHeader.cs @@ -322,13 +322,10 @@ namespace osu.Game.Overlays.Profile Anchor = Anchor.Centre, Origin = Anchor.Centre, FillMode = FillMode.Fill, - OnLoadComplete = d => d.FadeInFromZero(200) + OnLoadComplete = d => d.FadeInFromZero(200), + Depth = float.MaxValue, }, - ucb => - { - ucb.Depth = float.MaxValue; - coverContainer.Add(ucb); - }); + coverContainer.Add); if (user.IsSupporter) supporterTag.Show(); diff --git a/osu.Game/Screens/Multiplayer/DrawableRoom.cs b/osu.Game/Screens/Multiplayer/DrawableRoom.cs index 60a0bd7a82..0ba4aaa364 100644 --- a/osu.Game/Screens/Multiplayer/DrawableRoom.cs +++ b/osu.Game/Screens/Multiplayer/DrawableRoom.cs @@ -237,7 +237,7 @@ namespace osu.Game.Screens.Multiplayer FillMode = FillMode.Fill, OnLoadComplete = d => d.FadeInFromZero(400, Easing.Out), }, - bsc => coverContainer.Add(bsc)); + coverContainer.Add); beatmapTitle.Current = localisation.GetUnicodePreference(value.Metadata.TitleUnicode, value.Metadata.Title); beatmapDash.Text = @" - "; @@ -260,4 +260,4 @@ namespace osu.Game.Screens.Multiplayer participantInfo.Participants = value; } } -} \ No newline at end of file +} diff --git a/osu.Game/Screens/Multiplayer/RoomInspector.cs b/osu.Game/Screens/Multiplayer/RoomInspector.cs index 30c2aa8505..8d7401500f 100644 --- a/osu.Game/Screens/Multiplayer/RoomInspector.cs +++ b/osu.Game/Screens/Multiplayer/RoomInspector.cs @@ -338,7 +338,7 @@ namespace osu.Game.Screens.Multiplayer FillMode = FillMode.Fill, OnLoadComplete = d => d.FadeInFromZero(400, Easing.Out), }, - bsc => coverContainer.Add(bsc)); + coverContainer.Add); beatmapTitle.Current = localisation.GetUnicodePreference(value.Metadata.TitleUnicode, value.Metadata.Title); beatmapDash.Text = @" - "; diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 5f7ef03218..1e1b7bac93 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -248,8 +248,10 @@ namespace osu.Game.Screens.Play storyboard = beatmap.Storyboard.CreateDrawable(Beatmap.Value); storyboard.Masking = true; - if (asyncLoad) LoadComponentAsync(storyboard, s => storyboardContainer.Add(s)); - else storyboardContainer.Add((Drawable)storyboard); + if (asyncLoad) + LoadComponentAsync(storyboard, storyboardContainer.Add); + else + storyboardContainer.Add(storyboard); } public void Restart() From 0df5432f5ebe25ea320f181c3183d3edb483b526 Mon Sep 17 00:00:00 2001 From: Aergwyn Date: Wed, 22 Nov 2017 21:45:18 +0100 Subject: [PATCH 0772/1263] removed line that set metadata per beatmap to null --- osu.Game/Beatmaps/BeatmapManager.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index f461317ce1..eb10b23c6f 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -515,9 +515,6 @@ namespace osu.Game.Beatmaps if (existing == null) { - // TODO: Diff beatmap metadata with set metadata and leave it here if necessary - beatmap.BeatmapInfo.Metadata = null; - RulesetInfo ruleset = rulesets.GetRuleset(beatmap.BeatmapInfo.RulesetID); // TODO: this should be done in a better place once we actually need to dynamically update it. From 57f2d8556bd9caacf2bc6616da73a64bf485ff64 Mon Sep 17 00:00:00 2001 From: jorolf Date: Wed, 22 Nov 2017 22:00:17 +0100 Subject: [PATCH 0773/1263] add a visual test --- .../Visual/TestCaseHistoricalSection.cs | 43 +++++++++++++++++++ osu.Game.Tests/osu.Game.Tests.csproj | 1 + 2 files changed, 44 insertions(+) create mode 100644 osu.Game.Tests/Visual/TestCaseHistoricalSection.cs diff --git a/osu.Game.Tests/Visual/TestCaseHistoricalSection.cs b/osu.Game.Tests/Visual/TestCaseHistoricalSection.cs new file mode 100644 index 0000000000..e67f389969 --- /dev/null +++ b/osu.Game.Tests/Visual/TestCaseHistoricalSection.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 System; +using System.Collections.Generic; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Game.Graphics; +using osu.Game.Overlays.Profile.Sections; +using osu.Game.Overlays.Profile.Sections.Historical; +using osu.Game.Users; + +namespace osu.Game.Tests.Visual +{ + internal class TestCaseHistoricalSection : OsuTestCase + { + public override string Description => "User's History"; + + public override IReadOnlyList RequiredTypes => new [] { typeof(HistoricalSection), typeof(MostPlayedBeatmapDrawable)}; + + + public TestCaseHistoricalSection() + { + HistoricalSection section; + + Add(new Box + { + RelativeSizeAxes = Axes.Both, + Colour = OsuColour.Gray(0.2f) + }); + + Add(new ScrollContainer + { + RelativeSizeAxes = Axes.Both, + Child = section = new HistoricalSection(), + }); + + AddStep("Show peppy", () => section.User.Value = new User { Id = 2 }); + AddStep("Show WubWoofWolf", () => section.User.Value = new User { Id = 39828 }); + } + } +} diff --git a/osu.Game.Tests/osu.Game.Tests.csproj b/osu.Game.Tests/osu.Game.Tests.csproj index 9bba09b1a7..b093989b45 100644 --- a/osu.Game.Tests/osu.Game.Tests.csproj +++ b/osu.Game.Tests/osu.Game.Tests.csproj @@ -110,6 +110,7 @@ + From 288c21dfece72710df16f641119f59e6b661f881 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 23 Nov 2017 16:00:33 +0900 Subject: [PATCH 0774/1263] Move TestCase descriptions to attributes Depends on https://github.com/ppy/osu-framework/pull/1186. --- osu.Game.Rulesets.Mania/Tests/TestCaseManiaPlayfield.cs | 2 -- osu.Game.Rulesets.Taiko/Tests/TestCaseTaikoPlayfield.cs | 2 -- osu.Game.Tests/Visual/TestCaseAllPlayers.cs | 1 - osu.Game.Tests/Visual/TestCaseBeatSyncedContainer.cs | 2 -- osu.Game.Tests/Visual/TestCaseBeatmapDetailArea.cs | 5 ++--- osu.Game.Tests/Visual/TestCaseBeatmapDetails.cs | 4 ++-- osu.Game.Tests/Visual/TestCaseBeatmapOptionsOverlay.cs | 4 ++-- osu.Game.Tests/Visual/TestCaseBeatmapScoresContainer.cs | 5 ++--- osu.Game.Tests/Visual/TestCaseBeatmapSetOverlay.cs | 2 -- osu.Game.Tests/Visual/TestCaseBreadcrumbs.cs | 2 -- osu.Game.Tests/Visual/TestCaseBreakOverlay.cs | 4 +--- osu.Game.Tests/Visual/TestCaseChatDisplay.cs | 4 ++-- osu.Game.Tests/Visual/TestCaseContextMenu.cs | 2 -- osu.Game.Tests/Visual/TestCaseDialogOverlay.cs | 2 -- osu.Game.Tests/Visual/TestCaseDirect.cs | 2 -- osu.Game.Tests/Visual/TestCaseDrawableRoom.cs | 2 -- osu.Game.Tests/Visual/TestCaseDrawings.cs | 4 ++-- osu.Game.Tests/Visual/TestCaseGamefield.cs | 2 -- osu.Game.Tests/Visual/TestCaseGraph.cs | 4 +--- osu.Game.Tests/Visual/TestCaseIconButton.cs | 2 -- osu.Game.Tests/Visual/TestCaseKeyConfiguration.cs | 2 -- osu.Game.Tests/Visual/TestCaseKeyCounter.cs | 2 -- osu.Game.Tests/Visual/TestCaseLeaderboard.cs | 4 ++-- osu.Game.Tests/Visual/TestCaseMedalOverlay.cs | 2 -- osu.Game.Tests/Visual/TestCaseMenuButtonSystem.cs | 4 ++-- osu.Game.Tests/Visual/TestCaseMenuOverlays.cs | 4 ++-- osu.Game.Tests/Visual/TestCaseMods.cs | 4 ++-- osu.Game.Tests/Visual/TestCaseMusicController.cs | 2 -- osu.Game.Tests/Visual/TestCaseNotificationOverlay.cs | 2 -- osu.Game.Tests/Visual/TestCaseOnScreenDisplay.cs | 2 -- osu.Game.Tests/Visual/TestCasePlaySongSelect.cs | 2 -- osu.Game.Tests/Visual/TestCaseReplay.cs | 2 -- osu.Game.Tests/Visual/TestCaseReplaySettingsOverlay.cs | 2 -- osu.Game.Tests/Visual/TestCaseResults.cs | 2 -- osu.Game.Tests/Visual/TestCaseRoomInspector.cs | 2 -- osu.Game.Tests/Visual/TestCaseScoreCounter.cs | 2 -- osu.Game.Tests/Visual/TestCaseSettings.cs | 2 -- osu.Game.Tests/Visual/TestCaseSkipButton.cs | 2 -- osu.Game.Tests/Visual/TestCaseSocial.cs | 2 -- osu.Game.Tests/Visual/TestCaseSongProgress.cs | 2 -- osu.Game.Tests/Visual/TestCaseStoryboard.cs | 2 -- osu.Game.Tests/Visual/TestCaseTabControl.cs | 4 ++-- osu.Game.Tests/Visual/TestCaseTextAwesome.cs | 2 -- osu.Game.Tests/Visual/TestCaseTwoLayerButton.cs | 4 ++-- osu.Game.Tests/Visual/TestCaseUserPanel.cs | 2 -- osu.Game.Tests/Visual/TestCaseUserProfile.cs | 2 -- osu.Game.Tests/Visual/TestCaseUserRanks.cs | 2 -- osu.Game/Tests/Visual/TestCasePlayer.cs | 2 -- 48 files changed, 26 insertions(+), 99 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Tests/TestCaseManiaPlayfield.cs b/osu.Game.Rulesets.Mania/Tests/TestCaseManiaPlayfield.cs index 802d4cc99d..aab784f177 100644 --- a/osu.Game.Rulesets.Mania/Tests/TestCaseManiaPlayfield.cs +++ b/osu.Game.Rulesets.Mania/Tests/TestCaseManiaPlayfield.cs @@ -26,8 +26,6 @@ namespace osu.Game.Rulesets.Mania.Tests private const double start_time = 500; private const double duration = 500; - public override string Description => @"Mania playfield"; - protected override double TimePerAction => 200; private RulesetInfo maniaRuleset; diff --git a/osu.Game.Rulesets.Taiko/Tests/TestCaseTaikoPlayfield.cs b/osu.Game.Rulesets.Taiko/Tests/TestCaseTaikoPlayfield.cs index 059d297401..555f9bb0da 100644 --- a/osu.Game.Rulesets.Taiko/Tests/TestCaseTaikoPlayfield.cs +++ b/osu.Game.Rulesets.Taiko/Tests/TestCaseTaikoPlayfield.cs @@ -30,8 +30,6 @@ namespace osu.Game.Rulesets.Taiko.Tests private const double default_duration = 1000; private const float scroll_time = 1000; - public override string Description => "Taiko playfield"; - protected override double TimePerAction => default_duration * 2; private readonly Random rng = new Random(1337); diff --git a/osu.Game.Tests/Visual/TestCaseAllPlayers.cs b/osu.Game.Tests/Visual/TestCaseAllPlayers.cs index 8c63e1a274..62b99487a9 100644 --- a/osu.Game.Tests/Visual/TestCaseAllPlayers.cs +++ b/osu.Game.Tests/Visual/TestCaseAllPlayers.cs @@ -5,6 +5,5 @@ namespace osu.Game.Tests.Visual { public class TestCaseAllPlayers : TestCasePlayer { - public override string Description => @"Showing everything to play the game."; } } diff --git a/osu.Game.Tests/Visual/TestCaseBeatSyncedContainer.cs b/osu.Game.Tests/Visual/TestCaseBeatSyncedContainer.cs index a5156c155b..18555574ba 100644 --- a/osu.Game.Tests/Visual/TestCaseBeatSyncedContainer.cs +++ b/osu.Game.Tests/Visual/TestCaseBeatSyncedContainer.cs @@ -19,8 +19,6 @@ namespace osu.Game.Tests.Visual { internal class TestCaseBeatSyncedContainer : OsuTestCase { - public override string Description => @"Tests beat synced containers."; - private readonly MusicController mc; public TestCaseBeatSyncedContainer() diff --git a/osu.Game.Tests/Visual/TestCaseBeatmapDetailArea.cs b/osu.Game.Tests/Visual/TestCaseBeatmapDetailArea.cs index 7dffa6d590..215d1ee5b1 100644 --- a/osu.Game.Tests/Visual/TestCaseBeatmapDetailArea.cs +++ b/osu.Game.Tests/Visual/TestCaseBeatmapDetailArea.cs @@ -9,10 +9,9 @@ using OpenTK; namespace osu.Game.Tests.Visual { [TestFixture] + [Description("PlaySongSelect leaderboard/details area")] internal class TestCaseBeatmapDetailArea : OsuTestCase { - public override string Description => @"Beatmap details in song select"; - public TestCaseBeatmapDetailArea() { Add(new BeatmapDetailArea @@ -23,4 +22,4 @@ namespace osu.Game.Tests.Visual }); } } -} \ No newline at end of file +} diff --git a/osu.Game.Tests/Visual/TestCaseBeatmapDetails.cs b/osu.Game.Tests/Visual/TestCaseBeatmapDetails.cs index b31eded9a0..248ec6d43d 100644 --- a/osu.Game.Tests/Visual/TestCaseBeatmapDetails.cs +++ b/osu.Game.Tests/Visual/TestCaseBeatmapDetails.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.ComponentModel; using System.Linq; using osu.Framework.Graphics; using osu.Game.Beatmaps; @@ -8,10 +9,9 @@ using osu.Game.Screens.Select; namespace osu.Game.Tests.Visual { + [Description("PlaySongSelect beatmap details")] internal class TestCaseBeatmapDetails : OsuTestCase { - public override string Description => "BeatmapDetails tab of BeatmapDetailArea"; - public TestCaseBeatmapDetails() { BeatmapDetails details; diff --git a/osu.Game.Tests/Visual/TestCaseBeatmapOptionsOverlay.cs b/osu.Game.Tests/Visual/TestCaseBeatmapOptionsOverlay.cs index bdc2e0e105..e114fac96e 100644 --- a/osu.Game.Tests/Visual/TestCaseBeatmapOptionsOverlay.cs +++ b/osu.Game.Tests/Visual/TestCaseBeatmapOptionsOverlay.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.ComponentModel; using osu.Game.Graphics; using osu.Game.Screens.Select.Options; using OpenTK.Graphics; @@ -8,10 +9,9 @@ using OpenTK.Input; namespace osu.Game.Tests.Visual { + [Description("bottom beatmap details")] internal class TestCaseBeatmapOptionsOverlay : OsuTestCase { - public override string Description => @"Beatmap options in song select"; - public TestCaseBeatmapOptionsOverlay() { var overlay = new BeatmapOptionsOverlay(); diff --git a/osu.Game.Tests/Visual/TestCaseBeatmapScoresContainer.cs b/osu.Game.Tests/Visual/TestCaseBeatmapScoresContainer.cs index 8cae3feae2..cef8797f20 100644 --- a/osu.Game.Tests/Visual/TestCaseBeatmapScoresContainer.cs +++ b/osu.Game.Tests/Visual/TestCaseBeatmapScoresContainer.cs @@ -3,7 +3,6 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.MathUtils; using osu.Game.Graphics; @@ -14,13 +13,13 @@ using osu.Game.Rulesets.Osu.Mods; using osu.Game.Rulesets.Scoring; using osu.Game.Users; using System.Collections.Generic; +using osu.Framework.Graphics.Containers; namespace osu.Game.Tests.Visual { + [System.ComponentModel.Description("in BeatmapOverlay")] public class TestCaseBeatmapScoresContainer : OsuTestCase { - public override string Description => "BeatmapOverlay scores container"; - private readonly IEnumerable scores; private readonly IEnumerable anotherScores; private readonly OnlineScore topScore; diff --git a/osu.Game.Tests/Visual/TestCaseBeatmapSetOverlay.cs b/osu.Game.Tests/Visual/TestCaseBeatmapSetOverlay.cs index c2de4ec05d..c24e13b7fb 100644 --- a/osu.Game.Tests/Visual/TestCaseBeatmapSetOverlay.cs +++ b/osu.Game.Tests/Visual/TestCaseBeatmapSetOverlay.cs @@ -14,8 +14,6 @@ namespace osu.Game.Tests.Visual { internal class TestCaseBeatmapSetOverlay : OsuTestCase { - public override string Description => @"view online beatmap sets"; - private readonly BeatmapSetOverlay overlay; public TestCaseBeatmapSetOverlay() diff --git a/osu.Game.Tests/Visual/TestCaseBreadcrumbs.cs b/osu.Game.Tests/Visual/TestCaseBreadcrumbs.cs index 97c343f8ac..50abd11e79 100644 --- a/osu.Game.Tests/Visual/TestCaseBreadcrumbs.cs +++ b/osu.Game.Tests/Visual/TestCaseBreadcrumbs.cs @@ -8,8 +8,6 @@ namespace osu.Game.Tests.Visual { internal class TestCaseBreadcrumbs : OsuTestCase { - public override string Description => @"breadcrumb > control"; - public TestCaseBreadcrumbs() { BreadcrumbControl c; diff --git a/osu.Game.Tests/Visual/TestCaseBreakOverlay.cs b/osu.Game.Tests/Visual/TestCaseBreakOverlay.cs index 206ca308cf..dcb3b74654 100644 --- a/osu.Game.Tests/Visual/TestCaseBreakOverlay.cs +++ b/osu.Game.Tests/Visual/TestCaseBreakOverlay.cs @@ -10,8 +10,6 @@ namespace osu.Game.Tests.Visual { internal class TestCaseBreakOverlay : OsuTestCase { - public override string Description => @"Tests breaks behavior"; - private readonly BreakOverlay breakOverlay; public TestCaseBreakOverlay() @@ -88,4 +86,4 @@ namespace osu.Game.Tests.Visual }; } } -} \ No newline at end of file +} diff --git a/osu.Game.Tests/Visual/TestCaseChatDisplay.cs b/osu.Game.Tests/Visual/TestCaseChatDisplay.cs index 847593fcec..85ee224a5e 100644 --- a/osu.Game.Tests/Visual/TestCaseChatDisplay.cs +++ b/osu.Game.Tests/Visual/TestCaseChatDisplay.cs @@ -1,15 +1,15 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System.ComponentModel; using osu.Framework.Graphics.Containers; using osu.Game.Overlays; namespace osu.Game.Tests.Visual { + [Description("Testing chat api and overlay")] internal class TestCaseChatDisplay : OsuTestCase { - public override string Description => @"Testing chat api and overlay"; - public TestCaseChatDisplay() { Add(new ChatOverlay diff --git a/osu.Game.Tests/Visual/TestCaseContextMenu.cs b/osu.Game.Tests/Visual/TestCaseContextMenu.cs index 91a766f8c7..6f5cb398d7 100644 --- a/osu.Game.Tests/Visual/TestCaseContextMenu.cs +++ b/osu.Game.Tests/Visual/TestCaseContextMenu.cs @@ -15,8 +15,6 @@ namespace osu.Game.Tests.Visual { internal class TestCaseContextMenu : OsuTestCase { - public override string Description => @"Menu visible on right click"; - private const int start_time = 0; private const int duration = 1000; diff --git a/osu.Game.Tests/Visual/TestCaseDialogOverlay.cs b/osu.Game.Tests/Visual/TestCaseDialogOverlay.cs index a031125b3a..f1aba908f0 100644 --- a/osu.Game.Tests/Visual/TestCaseDialogOverlay.cs +++ b/osu.Game.Tests/Visual/TestCaseDialogOverlay.cs @@ -9,8 +9,6 @@ namespace osu.Game.Tests.Visual { internal class TestCaseDialogOverlay : OsuTestCase { - public override string Description => @"Display dialogs"; - public TestCaseDialogOverlay() { DialogOverlay overlay; diff --git a/osu.Game.Tests/Visual/TestCaseDirect.cs b/osu.Game.Tests/Visual/TestCaseDirect.cs index 2d8677c391..ede17fa775 100644 --- a/osu.Game.Tests/Visual/TestCaseDirect.cs +++ b/osu.Game.Tests/Visual/TestCaseDirect.cs @@ -11,8 +11,6 @@ namespace osu.Game.Tests.Visual { public class TestCaseDirect : OsuTestCase { - public override string Description => @"osu!direct overlay"; - private DirectOverlay direct; private RulesetStore rulesets; diff --git a/osu.Game.Tests/Visual/TestCaseDrawableRoom.cs b/osu.Game.Tests/Visual/TestCaseDrawableRoom.cs index 7113bcbff5..a51cf8ca95 100644 --- a/osu.Game.Tests/Visual/TestCaseDrawableRoom.cs +++ b/osu.Game.Tests/Visual/TestCaseDrawableRoom.cs @@ -14,8 +14,6 @@ namespace osu.Game.Tests.Visual { internal class TestCaseDrawableRoom : OsuTestCase { - public override string Description => @"Select your favourite room"; - private RulesetStore rulesets; protected override void LoadComplete() diff --git a/osu.Game.Tests/Visual/TestCaseDrawings.cs b/osu.Game.Tests/Visual/TestCaseDrawings.cs index c805d88cb4..e5692b29de 100644 --- a/osu.Game.Tests/Visual/TestCaseDrawings.cs +++ b/osu.Game.Tests/Visual/TestCaseDrawings.cs @@ -2,15 +2,15 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System.Collections.Generic; +using System.ComponentModel; using osu.Game.Screens.Tournament; using osu.Game.Screens.Tournament.Teams; namespace osu.Game.Tests.Visual { + [Description("for tournament use")] internal class TestCaseDrawings : OsuTestCase { - public override string Description => "Tournament drawings"; - public TestCaseDrawings() { Add(new Drawings diff --git a/osu.Game.Tests/Visual/TestCaseGamefield.cs b/osu.Game.Tests/Visual/TestCaseGamefield.cs index af86b6ec06..0d8f4cb5f7 100644 --- a/osu.Game.Tests/Visual/TestCaseGamefield.cs +++ b/osu.Game.Tests/Visual/TestCaseGamefield.cs @@ -7,8 +7,6 @@ namespace osu.Game.Tests.Visual { internal class TestCaseGamefield : OsuTestCase { - public override string Description => @"Showing hitobjects and what not."; - protected override void LoadComplete() { base.LoadComplete(); diff --git a/osu.Game.Tests/Visual/TestCaseGraph.cs b/osu.Game.Tests/Visual/TestCaseGraph.cs index 714f284879..fb1a3ef3f6 100644 --- a/osu.Game.Tests/Visual/TestCaseGraph.cs +++ b/osu.Game.Tests/Visual/TestCaseGraph.cs @@ -10,8 +10,6 @@ namespace osu.Game.Tests.Visual { internal class TestCaseGraph : OsuTestCase { - public override string Description => "graph"; - public TestCaseGraph() { BarGraph graph; @@ -36,4 +34,4 @@ namespace osu.Game.Tests.Visual AddStep("Right to left", () => graph.Direction = BarDirection.RightToLeft); } } -} \ No newline at end of file +} diff --git a/osu.Game.Tests/Visual/TestCaseIconButton.cs b/osu.Game.Tests/Visual/TestCaseIconButton.cs index acde9df4a9..345316708e 100644 --- a/osu.Game.Tests/Visual/TestCaseIconButton.cs +++ b/osu.Game.Tests/Visual/TestCaseIconButton.cs @@ -14,8 +14,6 @@ namespace osu.Game.Tests.Visual { public class TestCaseIconButton : OsuTestCase { - public override string Description => "Various display modes of icon buttons"; - public TestCaseIconButton() { Child = new FillFlowContainer diff --git a/osu.Game.Tests/Visual/TestCaseKeyConfiguration.cs b/osu.Game.Tests/Visual/TestCaseKeyConfiguration.cs index e473ce8778..d39ac12a60 100644 --- a/osu.Game.Tests/Visual/TestCaseKeyConfiguration.cs +++ b/osu.Game.Tests/Visual/TestCaseKeyConfiguration.cs @@ -9,8 +9,6 @@ namespace osu.Game.Tests.Visual { private readonly KeyBindingOverlay overlay; - public override string Description => @"Key configuration"; - public TestCaseKeyConfiguration() { Child = overlay = new KeyBindingOverlay(); diff --git a/osu.Game.Tests/Visual/TestCaseKeyCounter.cs b/osu.Game.Tests/Visual/TestCaseKeyCounter.cs index 622fb15f4f..df122b7132 100644 --- a/osu.Game.Tests/Visual/TestCaseKeyCounter.cs +++ b/osu.Game.Tests/Visual/TestCaseKeyCounter.cs @@ -10,8 +10,6 @@ namespace osu.Game.Tests.Visual { internal class TestCaseKeyCounter : OsuTestCase { - public override string Description => @"Tests key counter"; - public TestCaseKeyCounter() { KeyCounterCollection kc = new KeyCounterCollection diff --git a/osu.Game.Tests/Visual/TestCaseLeaderboard.cs b/osu.Game.Tests/Visual/TestCaseLeaderboard.cs index 832003e6ab..9d6fb3a4ec 100644 --- a/osu.Game.Tests/Visual/TestCaseLeaderboard.cs +++ b/osu.Game.Tests/Visual/TestCaseLeaderboard.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.ComponentModel; using osu.Framework.Graphics; using osu.Game.Rulesets.Scoring; using osu.Game.Screens.Select.Leaderboards; @@ -9,10 +10,9 @@ using OpenTK; namespace osu.Game.Tests.Visual { + [Description("PlaySongSelect leaderboard")] internal class TestCaseLeaderboard : OsuTestCase { - public override string Description => @"From song select"; - private readonly Leaderboard leaderboard; private void newScores() diff --git a/osu.Game.Tests/Visual/TestCaseMedalOverlay.cs b/osu.Game.Tests/Visual/TestCaseMedalOverlay.cs index 9a26eefd63..fbee27668c 100644 --- a/osu.Game.Tests/Visual/TestCaseMedalOverlay.cs +++ b/osu.Game.Tests/Visual/TestCaseMedalOverlay.cs @@ -11,8 +11,6 @@ namespace osu.Game.Tests.Visual { internal class TestCaseMedalOverlay : OsuTestCase { - public override string Description => @"medal get!"; - public override IReadOnlyList RequiredTypes => new[] { typeof(MedalOverlay), diff --git a/osu.Game.Tests/Visual/TestCaseMenuButtonSystem.cs b/osu.Game.Tests/Visual/TestCaseMenuButtonSystem.cs index 0b50c9cf47..b5310f0fb0 100644 --- a/osu.Game.Tests/Visual/TestCaseMenuButtonSystem.cs +++ b/osu.Game.Tests/Visual/TestCaseMenuButtonSystem.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.ComponentModel; using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Shapes; using osu.Game.Screens.Menu; @@ -8,10 +9,9 @@ using OpenTK.Graphics; namespace osu.Game.Tests.Visual { + [Description("main menu")] internal class TestCaseMenuButtonSystem : OsuTestCase { - public override string Description => @"Main menu button system"; - public TestCaseMenuButtonSystem() { Add(new Box diff --git a/osu.Game.Tests/Visual/TestCaseMenuOverlays.cs b/osu.Game.Tests/Visual/TestCaseMenuOverlays.cs index e27de96bee..94a69f0029 100644 --- a/osu.Game.Tests/Visual/TestCaseMenuOverlays.cs +++ b/osu.Game.Tests/Visual/TestCaseMenuOverlays.cs @@ -1,16 +1,16 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System.ComponentModel; using osu.Framework.Graphics.Containers; using osu.Framework.Logging; using osu.Game.Screens.Play; namespace osu.Game.Tests.Visual { + [Description("player pause/fail screens")] internal class TestCaseMenuOverlays : OsuTestCase { - public override string Description => @"Tests pause and fail overlays"; - public TestCaseMenuOverlays() { FailOverlay failOverlay; diff --git a/osu.Game.Tests/Visual/TestCaseMods.cs b/osu.Game.Tests/Visual/TestCaseMods.cs index 0447d6582d..5270ac0dc9 100644 --- a/osu.Game.Tests/Visual/TestCaseMods.cs +++ b/osu.Game.Tests/Visual/TestCaseMods.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.ComponentModel; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Game.Overlays.Mods; @@ -10,10 +11,9 @@ using OpenTK; namespace osu.Game.Tests.Visual { + [Description("mod select and icon display")] internal class TestCaseMods : OsuTestCase { - public override string Description => @"Mod select overlay and in-game display"; - private ModSelectOverlay modSelect; private ModDisplay modDisplay; diff --git a/osu.Game.Tests/Visual/TestCaseMusicController.cs b/osu.Game.Tests/Visual/TestCaseMusicController.cs index 323c32bf10..3c544bb968 100644 --- a/osu.Game.Tests/Visual/TestCaseMusicController.cs +++ b/osu.Game.Tests/Visual/TestCaseMusicController.cs @@ -13,8 +13,6 @@ namespace osu.Game.Tests.Visual { internal class TestCaseMusicController : OsuTestCase { - public override string Description => @"Tests music controller ui."; - private readonly Bindable beatmapBacking = new Bindable(); public TestCaseMusicController() diff --git a/osu.Game.Tests/Visual/TestCaseNotificationOverlay.cs b/osu.Game.Tests/Visual/TestCaseNotificationOverlay.cs index ed331076b2..3dca860909 100644 --- a/osu.Game.Tests/Visual/TestCaseNotificationOverlay.cs +++ b/osu.Game.Tests/Visual/TestCaseNotificationOverlay.cs @@ -15,8 +15,6 @@ namespace osu.Game.Tests.Visual [TestFixture] internal class TestCaseNotificationOverlay : OsuTestCase { - public override string Description => @"I handle notifications"; - private readonly NotificationOverlay manager; public TestCaseNotificationOverlay() diff --git a/osu.Game.Tests/Visual/TestCaseOnScreenDisplay.cs b/osu.Game.Tests/Visual/TestCaseOnScreenDisplay.cs index 8749d240f8..c3a755f3ca 100644 --- a/osu.Game.Tests/Visual/TestCaseOnScreenDisplay.cs +++ b/osu.Game.Tests/Visual/TestCaseOnScreenDisplay.cs @@ -12,8 +12,6 @@ namespace osu.Game.Tests.Visual private FrameworkConfigManager config; private Bindable frameSyncMode; - public override string Description => @"Make it easier to see setting changes"; - protected override void LoadComplete() { base.LoadComplete(); diff --git a/osu.Game.Tests/Visual/TestCasePlaySongSelect.cs b/osu.Game.Tests/Visual/TestCasePlaySongSelect.cs index 37dd60a25c..7c070fd3df 100644 --- a/osu.Game.Tests/Visual/TestCasePlaySongSelect.cs +++ b/osu.Game.Tests/Visual/TestCasePlaySongSelect.cs @@ -22,8 +22,6 @@ namespace osu.Game.Tests.Visual { private BeatmapManager manager; - public override string Description => @"with fake data"; - private RulesetStore rulesets; private DependencyContainer dependencies; diff --git a/osu.Game.Tests/Visual/TestCaseReplay.cs b/osu.Game.Tests/Visual/TestCaseReplay.cs index 2e56daccfc..62c8a64916 100644 --- a/osu.Game.Tests/Visual/TestCaseReplay.cs +++ b/osu.Game.Tests/Visual/TestCaseReplay.cs @@ -10,8 +10,6 @@ namespace osu.Game.Tests.Visual { internal class TestCaseReplay : TestCasePlayer { - public override string Description => @"Testing replay playback."; - protected override Player CreatePlayer(WorkingBeatmap beatmap, Ruleset ruleset) { beatmap.Mods.Value = beatmap.Mods.Value.Concat(new[] { ruleset.GetAutoplayMod() }); diff --git a/osu.Game.Tests/Visual/TestCaseReplaySettingsOverlay.cs b/osu.Game.Tests/Visual/TestCaseReplaySettingsOverlay.cs index 3105a7d588..22a2d717e4 100644 --- a/osu.Game.Tests/Visual/TestCaseReplaySettingsOverlay.cs +++ b/osu.Game.Tests/Visual/TestCaseReplaySettingsOverlay.cs @@ -10,8 +10,6 @@ namespace osu.Game.Tests.Visual { internal class TestCaseReplaySettingsOverlay : OsuTestCase { - public override string Description => @"Settings visible in replay/auto"; - public TestCaseReplaySettingsOverlay() { ExampleContainer container; diff --git a/osu.Game.Tests/Visual/TestCaseResults.cs b/osu.Game.Tests/Visual/TestCaseResults.cs index 62154a535a..f1bbb8fed6 100644 --- a/osu.Game.Tests/Visual/TestCaseResults.cs +++ b/osu.Game.Tests/Visual/TestCaseResults.cs @@ -15,8 +15,6 @@ namespace osu.Game.Tests.Visual { private BeatmapManager beatmaps; - public override string Description => @"Results after playing."; - [BackgroundDependencyLoader] private void load(BeatmapManager beatmaps) { diff --git a/osu.Game.Tests/Visual/TestCaseRoomInspector.cs b/osu.Game.Tests/Visual/TestCaseRoomInspector.cs index e6b57c970b..51b6ae8e50 100644 --- a/osu.Game.Tests/Visual/TestCaseRoomInspector.cs +++ b/osu.Game.Tests/Visual/TestCaseRoomInspector.cs @@ -13,8 +13,6 @@ namespace osu.Game.Tests.Visual { internal class TestCaseRoomInspector : OsuTestCase { - public override string Description => @"from the multiplayer lobby"; - private RulesetStore rulesets; protected override void LoadComplete() diff --git a/osu.Game.Tests/Visual/TestCaseScoreCounter.cs b/osu.Game.Tests/Visual/TestCaseScoreCounter.cs index 543ff12fcb..5a04000900 100644 --- a/osu.Game.Tests/Visual/TestCaseScoreCounter.cs +++ b/osu.Game.Tests/Visual/TestCaseScoreCounter.cs @@ -12,8 +12,6 @@ namespace osu.Game.Tests.Visual { internal class TestCaseScoreCounter : OsuTestCase { - public override string Description => @"Tests multiple counters"; - public TestCaseScoreCounter() { int numerator = 0, denominator = 0; diff --git a/osu.Game.Tests/Visual/TestCaseSettings.cs b/osu.Game.Tests/Visual/TestCaseSettings.cs index dfc0b66e21..63d798cd53 100644 --- a/osu.Game.Tests/Visual/TestCaseSettings.cs +++ b/osu.Game.Tests/Visual/TestCaseSettings.cs @@ -7,8 +7,6 @@ namespace osu.Game.Tests.Visual { internal class TestCaseSettings : OsuTestCase { - public override string Description => @"Tests the settings overlay"; - private readonly SettingsOverlay settings; public TestCaseSettings() diff --git a/osu.Game.Tests/Visual/TestCaseSkipButton.cs b/osu.Game.Tests/Visual/TestCaseSkipButton.cs index 49be015adf..40c8baaac8 100644 --- a/osu.Game.Tests/Visual/TestCaseSkipButton.cs +++ b/osu.Game.Tests/Visual/TestCaseSkipButton.cs @@ -7,8 +7,6 @@ namespace osu.Game.Tests.Visual { internal class TestCaseSkipButton : OsuTestCase { - public override string Description => @"Skip skip skippediskip"; - protected override void LoadComplete() { base.LoadComplete(); diff --git a/osu.Game.Tests/Visual/TestCaseSocial.cs b/osu.Game.Tests/Visual/TestCaseSocial.cs index 4f90e4ceff..ff0707c8ab 100644 --- a/osu.Game.Tests/Visual/TestCaseSocial.cs +++ b/osu.Game.Tests/Visual/TestCaseSocial.cs @@ -8,8 +8,6 @@ namespace osu.Game.Tests.Visual { public class TestCaseSocial : OsuTestCase { - public override string Description => @"social browser overlay"; - public TestCaseSocial() { SocialOverlay s = new SocialOverlay diff --git a/osu.Game.Tests/Visual/TestCaseSongProgress.cs b/osu.Game.Tests/Visual/TestCaseSongProgress.cs index 96ff76e9c6..1e6886cda9 100644 --- a/osu.Game.Tests/Visual/TestCaseSongProgress.cs +++ b/osu.Game.Tests/Visual/TestCaseSongProgress.cs @@ -12,8 +12,6 @@ namespace osu.Game.Tests.Visual { internal class TestCaseSongProgress : OsuTestCase { - public override string Description => @"With fake data"; - private readonly SongProgress progress; private readonly SongProgressGraph graph; diff --git a/osu.Game.Tests/Visual/TestCaseStoryboard.cs b/osu.Game.Tests/Visual/TestCaseStoryboard.cs index c6ef3f4ecf..1dad106cbe 100644 --- a/osu.Game.Tests/Visual/TestCaseStoryboard.cs +++ b/osu.Game.Tests/Visual/TestCaseStoryboard.cs @@ -16,8 +16,6 @@ namespace osu.Game.Tests.Visual { internal class TestCaseStoryboard : OsuTestCase { - public override string Description => @"Tests storyboards."; - private readonly Bindable beatmapBacking = new Bindable(); private readonly Container storyboardContainer; diff --git a/osu.Game.Tests/Visual/TestCaseTabControl.cs b/osu.Game.Tests/Visual/TestCaseTabControl.cs index 6db74f2cfb..44a1732e16 100644 --- a/osu.Game.Tests/Visual/TestCaseTabControl.cs +++ b/osu.Game.Tests/Visual/TestCaseTabControl.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.ComponentModel; using osu.Framework.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; @@ -9,10 +10,9 @@ using OpenTK; namespace osu.Game.Tests.Visual { + [Description("SongSelect filter control")] public class TestCaseTabControl : OsuTestCase { - public override string Description => @"Filter for song select"; - public TestCaseTabControl() { OsuSpriteText text; diff --git a/osu.Game.Tests/Visual/TestCaseTextAwesome.cs b/osu.Game.Tests/Visual/TestCaseTextAwesome.cs index beec5ab271..37905a1883 100644 --- a/osu.Game.Tests/Visual/TestCaseTextAwesome.cs +++ b/osu.Game.Tests/Visual/TestCaseTextAwesome.cs @@ -12,8 +12,6 @@ namespace osu.Game.Tests.Visual { internal class TestCaseTextAwesome : OsuTestCase { - public override string Description => @"Tests display of icons"; - public TestCaseTextAwesome() { FillFlowContainer flow; diff --git a/osu.Game.Tests/Visual/TestCaseTwoLayerButton.cs b/osu.Game.Tests/Visual/TestCaseTwoLayerButton.cs index 83e0e4b442..bd5c10d147 100644 --- a/osu.Game.Tests/Visual/TestCaseTwoLayerButton.cs +++ b/osu.Game.Tests/Visual/TestCaseTwoLayerButton.cs @@ -1,14 +1,14 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System.ComponentModel; using osu.Game.Graphics.UserInterface; namespace osu.Game.Tests.Visual { + [Description("mostly back button")] internal class TestCaseTwoLayerButton : OsuTestCase { - public override string Description => @"Mostly back button"; - public TestCaseTwoLayerButton() { Add(new BackButton()); diff --git a/osu.Game.Tests/Visual/TestCaseUserPanel.cs b/osu.Game.Tests/Visual/TestCaseUserPanel.cs index 8523a754f8..8d94a0c90f 100644 --- a/osu.Game.Tests/Visual/TestCaseUserPanel.cs +++ b/osu.Game.Tests/Visual/TestCaseUserPanel.cs @@ -10,8 +10,6 @@ namespace osu.Game.Tests.Visual { internal class TestCaseUserPanel : OsuTestCase { - public override string Description => @"Panels for displaying a user's status"; - public TestCaseUserPanel() { UserPanel flyte; diff --git a/osu.Game.Tests/Visual/TestCaseUserProfile.cs b/osu.Game.Tests/Visual/TestCaseUserProfile.cs index f5fced2915..90daf1e996 100644 --- a/osu.Game.Tests/Visual/TestCaseUserProfile.cs +++ b/osu.Game.Tests/Visual/TestCaseUserProfile.cs @@ -10,8 +10,6 @@ namespace osu.Game.Tests.Visual { internal class TestCaseUserProfile : OsuTestCase { - public override string Description => "Tests user's profile page."; - public TestCaseUserProfile() { var profile = new UserProfileOverlay(); diff --git a/osu.Game.Tests/Visual/TestCaseUserRanks.cs b/osu.Game.Tests/Visual/TestCaseUserRanks.cs index e17f0e1a46..eb0678203c 100644 --- a/osu.Game.Tests/Visual/TestCaseUserRanks.cs +++ b/osu.Game.Tests/Visual/TestCaseUserRanks.cs @@ -15,8 +15,6 @@ namespace osu.Game.Tests.Visual { internal class TestCaseUserRanks : OsuTestCase { - public override string Description => "showing your latest achievements"; - public override IReadOnlyList RequiredTypes => new[] { typeof(DrawableScore), typeof(RanksSection) }; public TestCaseUserRanks() diff --git a/osu.Game/Tests/Visual/TestCasePlayer.cs b/osu.Game/Tests/Visual/TestCasePlayer.cs index 5965be9717..cef85b65f1 100644 --- a/osu.Game/Tests/Visual/TestCasePlayer.cs +++ b/osu.Game/Tests/Visual/TestCasePlayer.cs @@ -23,8 +23,6 @@ namespace osu.Game.Tests.Visual protected Player Player; - public override string Description => @"Showing everything to play the game."; - /// /// Create a TestCase which runs through the Player screen. /// From f3a84a01dac463f17e287fdcd43a715f3eba1948 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 23 Nov 2017 16:20:50 +0900 Subject: [PATCH 0775/1263] Update framework --- osu-framework | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu-framework b/osu-framework index c6fd291492..eea84aaefc 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit c6fd2914926f2a6df23eda536c0310f072581b1b +Subproject commit eea84aaefcc7a1a6732d105ba319272dd9744901 From 182454032526775db3f92fb71cf474cbcb40370d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 23 Nov 2017 11:15:21 +0900 Subject: [PATCH 0776/1263] Schedule calls to correct thread These could be fired from an async worker thread (for instance, maintenance operations). --- osu.Game/Screens/Select/SongSelect.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 5500d06136..24a7b3db90 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -203,8 +203,8 @@ namespace osu.Game.Screens.Select Push(new Editor()); } - private void onBeatmapRestored(BeatmapInfo b) => carousel.UpdateBeatmap(b); - private void onBeatmapHidden(BeatmapInfo b) => carousel.UpdateBeatmap(b); + private void onBeatmapRestored(BeatmapInfo b) => Schedule(() => carousel.UpdateBeatmap(b)); + private void onBeatmapHidden(BeatmapInfo b) => Schedule(() => carousel.UpdateBeatmap(b)); private void carouselBeatmapsLoaded() { From 85827f83eb6d54ea119260e120013f02e9904af2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 23 Nov 2017 17:03:56 +0900 Subject: [PATCH 0777/1263] Perform a reload on objects when Refreshing them Previously, it was possible for an object to be "refreshed" with a stale cached state from the current thread's context. This ensures a check against the database is performed as well. Resolves #1562. --- osu.Game/Database/DatabaseBackedStore.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Database/DatabaseBackedStore.cs b/osu.Game/Database/DatabaseBackedStore.cs index bc1b7132eb..d8c3ce6694 100644 --- a/osu.Game/Database/DatabaseBackedStore.cs +++ b/osu.Game/Database/DatabaseBackedStore.cs @@ -35,6 +35,7 @@ namespace osu.Game.Database var id = obj.ID; obj = lookupSource?.SingleOrDefault(t => t.ID == id) ?? context.Find(id); + context.Entry(obj).Reload(); } /// From d6f532171b83a9c58c19ef99843643233430e05b Mon Sep 17 00:00:00 2001 From: FreezyLemon Date: Thu, 23 Nov 2017 09:11:52 +0100 Subject: [PATCH 0778/1263] Implementation fix (since the default delay is now 500 and not 0 this is necessary to ensure the same functionality) --- osu.Game/Users/UserPanel.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Users/UserPanel.cs b/osu.Game/Users/UserPanel.cs index 923c62f8ef..1f235e3893 100644 --- a/osu.Game/Users/UserPanel.cs +++ b/osu.Game/Users/UserPanel.cs @@ -65,7 +65,7 @@ namespace osu.Game.Users Origin = Anchor.Centre, FillMode = FillMode.Fill, OnLoadComplete = d => d.FadeInFromZero(200), - }) { RelativeSizeAxes = Axes.Both }, + }, 0) { RelativeSizeAxes = Axes.Both }, new Box { RelativeSizeAxes = Axes.Both, From 2cc2323791b59fa615db3371b89cc3f5dd64ff9a Mon Sep 17 00:00:00 2001 From: FreezyLemon Date: Thu, 23 Nov 2017 09:12:23 +0100 Subject: [PATCH 0779/1263] Style changes (removing newline from before second constructor parameter) --- osu.Game/Beatmaps/Drawables/BeatmapSetHeader.cs | 4 +--- osu.Game/Overlays/BeatmapSet/Header.cs | 3 +-- osu.Game/Overlays/Direct/DirectPanel.cs | 3 +-- osu.Game/Screens/Select/Leaderboards/LeaderboardScore.cs | 3 +-- osu.Game/Users/UpdateableAvatar.cs | 3 +-- 5 files changed, 5 insertions(+), 11 deletions(-) diff --git a/osu.Game/Beatmaps/Drawables/BeatmapSetHeader.cs b/osu.Game/Beatmaps/Drawables/BeatmapSetHeader.cs index ec39f86c5c..5b84fa7c6e 100644 --- a/osu.Game/Beatmaps/Drawables/BeatmapSetHeader.cs +++ b/osu.Game/Beatmaps/Drawables/BeatmapSetHeader.cs @@ -48,9 +48,7 @@ namespace osu.Game.Beatmaps.Drawables { RelativeSizeAxes = Axes.Both, OnLoadComplete = d => d.FadeInFromZero(400, Easing.Out), - }, - 300 - ), + }, 300), new FillFlowContainer { Direction = FillDirection.Vertical, diff --git a/osu.Game/Overlays/BeatmapSet/Header.cs b/osu.Game/Overlays/BeatmapSet/Header.cs index 9bf14e1f90..195ff63ca5 100644 --- a/osu.Game/Overlays/BeatmapSet/Header.cs +++ b/osu.Game/Overlays/BeatmapSet/Header.cs @@ -60,8 +60,7 @@ namespace osu.Game.Overlays.BeatmapSet RelativeSizeAxes = Axes.Both, FillMode = FillMode.Fill, OnLoadComplete = d => d.FadeInFromZero(400, Easing.Out), - }, - 300) + }, 300) { RelativeSizeAxes = Axes.Both, }); diff --git a/osu.Game/Overlays/Direct/DirectPanel.cs b/osu.Game/Overlays/Direct/DirectPanel.cs index bef8697552..2e842af614 100644 --- a/osu.Game/Overlays/Direct/DirectPanel.cs +++ b/osu.Game/Overlays/Direct/DirectPanel.cs @@ -231,8 +231,7 @@ namespace osu.Game.Overlays.Direct d.FadeInFromZero(400, Easing.Out); BlackBackground.Delay(400).FadeOut(); }, - }, - 300) + }, 300) { RelativeSizeAxes = Axes.Both, }; diff --git a/osu.Game/Screens/Select/Leaderboards/LeaderboardScore.cs b/osu.Game/Screens/Select/Leaderboards/LeaderboardScore.cs index 14cd7e6f07..0d898ad7d2 100644 --- a/osu.Game/Screens/Select/Leaderboards/LeaderboardScore.cs +++ b/osu.Game/Screens/Select/Leaderboards/LeaderboardScore.cs @@ -112,8 +112,7 @@ namespace osu.Game.Screens.Select.Leaderboards Radius = 1, Colour = Color4.Black.Opacity(0.2f), }, - }, - 500) + }, 500) { RelativeSizeAxes = Axes.None, Size = new Vector2(HEIGHT - edge_margin * 2, HEIGHT - edge_margin * 2), diff --git a/osu.Game/Users/UpdateableAvatar.cs b/osu.Game/Users/UpdateableAvatar.cs index 1700046653..895407064c 100644 --- a/osu.Game/Users/UpdateableAvatar.cs +++ b/osu.Game/Users/UpdateableAvatar.cs @@ -45,8 +45,7 @@ namespace osu.Game.Users { RelativeSizeAxes = Axes.Both, OnLoadComplete = d => d.FadeInFromZero(200), - }, - 500) + }, 500) ); } } From 2ff21bbc6c1caabf2e0e6ad95375d2586fc5ed05 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 23 Nov 2017 17:29:20 +0900 Subject: [PATCH 0780/1263] Move descriptions to constructor --- .../Profile/Sections/Kudosu/KudosuInfo.cs | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/osu.Game/Overlays/Profile/Sections/Kudosu/KudosuInfo.cs b/osu.Game/Overlays/Profile/Sections/Kudosu/KudosuInfo.cs index 1982059065..975a09fe18 100644 --- a/osu.Game/Overlays/Profile/Sections/Kudosu/KudosuInfo.cs +++ b/osu.Game/Overlays/Profile/Sections/Kudosu/KudosuInfo.cs @@ -23,8 +23,8 @@ namespace osu.Game.Overlays.Profile.Sections.Kudosu { this.user.BindTo(user); - SubSection total; - SubSection avaliable; + CountSection total; + CountSection avaliable; RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; @@ -44,20 +44,20 @@ namespace osu.Game.Overlays.Profile.Sections.Kudosu RelativeSizeAxes = Axes.Both, Colour = OsuColour.Gray(0.2f) }, - total = new SubSection("Total Kudosu Earned"), - avaliable = new SubSection("Kudosu Avaliable") + total = new CountSection( + "Total Kudosu Earned", + "Based on how much of a contribution the user has made to beatmap moderation. See this link for more information." + ), + avaliable = new CountSection( + "Kudosu Avaliable", + "Kudosu can be traded for kudosu stars, which will help your beatmap get more attention. This is the number of kudosu you haven't traded in yet." + ) { RelativePositionAxes = Axes.X, X = 0.5f, }, }; - total.TextFlow.Text = "Based on how much of a contribution the user has made to " + - "beatmap moderation. See this link for more information."; - - avaliable.TextFlow.Text = "Kudosu can be traded for kudosu stars, which will help your beatmap get " + - "more attention. This is the number of kudosu you haven't traded in yet."; - this.user.ValueChanged += newUser => { total.KudosuValue = newUser?.Kudosu.Total ?? 0; @@ -67,7 +67,7 @@ namespace osu.Game.Overlays.Profile.Sections.Kudosu protected override bool OnClick(InputState state) => true; - private class SubSection : Container + private class CountSection : Container { public readonly TextFlowContainer TextFlow; @@ -87,7 +87,7 @@ namespace osu.Game.Overlays.Profile.Sections.Kudosu } } - public SubSection(string header) + public CountSection(string header, string description) { RelativeSizeAxes = Axes.X; Width = 0.5f; @@ -131,6 +131,7 @@ namespace osu.Game.Overlays.Profile.Sections.Kudosu { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, + Text = description } } }; From 6d9951d9afdc664dab13bc348296d62aa271b740 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 23 Nov 2017 17:31:43 +0900 Subject: [PATCH 0781/1263] Use FillFlow rather than manually specifying positions --- .../Profile/Sections/Kudosu/KudosuInfo.cs | 26 +++++++++++-------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/osu.Game/Overlays/Profile/Sections/Kudosu/KudosuInfo.cs b/osu.Game/Overlays/Profile/Sections/Kudosu/KudosuInfo.cs index 975a09fe18..2639bd7686 100644 --- a/osu.Game/Overlays/Profile/Sections/Kudosu/KudosuInfo.cs +++ b/osu.Game/Overlays/Profile/Sections/Kudosu/KudosuInfo.cs @@ -44,18 +44,22 @@ namespace osu.Game.Overlays.Profile.Sections.Kudosu RelativeSizeAxes = Axes.Both, Colour = OsuColour.Gray(0.2f) }, - total = new CountSection( - "Total Kudosu Earned", - "Based on how much of a contribution the user has made to beatmap moderation. See this link for more information." - ), - avaliable = new CountSection( - "Kudosu Avaliable", - "Kudosu can be traded for kudosu stars, which will help your beatmap get more attention. This is the number of kudosu you haven't traded in yet." - ) + new FillFlowContainer { - RelativePositionAxes = Axes.X, - X = 0.5f, - }, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Children = new[] + { + total = new CountSection( + "Total Kudosu Earned", + "Based on how much of a contribution the user has made to beatmap moderation. See this link for more information." + ), + avaliable = new CountSection( + "Kudosu Avaliable", + "Kudosu can be traded for kudosu stars, which will help your beatmap get more attention. This is the number of kudosu you haven't traded in yet." + ), + } + } }; this.user.ValueChanged += newUser => From cf4fc05be3567c9233a78735986b02ad6be3aa86 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 23 Nov 2017 17:33:46 +0900 Subject: [PATCH 0782/1263] Fix nullref on disposing BeatmapSetOverlay before load Only affects VisualTests --- osu.Game/Overlays/BeatmapSet/Header.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/BeatmapSet/Header.cs b/osu.Game/Overlays/BeatmapSet/Header.cs index 27ef6208be..b02df76996 100644 --- a/osu.Game/Overlays/BeatmapSet/Header.cs +++ b/osu.Game/Overlays/BeatmapSet/Header.cs @@ -232,7 +232,7 @@ namespace osu.Game.Overlays.BeatmapSet protected override void Dispose(bool isDisposing) { base.Dispose(isDisposing); - beatmaps.BeatmapSetAdded -= handleBeatmapAdd; + if (beatmaps != null) beatmaps.BeatmapSetAdded -= handleBeatmapAdd; } private void handleBeatmapAdd(BeatmapSetInfo beatmap) From 30db2ce18a1f96a728d1591eaf5ef980ae9477e8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 23 Nov 2017 17:37:02 +0900 Subject: [PATCH 0783/1263] Rename KudosuValue to count and remove pointless local storage --- .../Profile/Sections/Kudosu/KudosuInfo.cs | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/osu.Game/Overlays/Profile/Sections/Kudosu/KudosuInfo.cs b/osu.Game/Overlays/Profile/Sections/Kudosu/KudosuInfo.cs index 2639bd7686..4520abdd6d 100644 --- a/osu.Game/Overlays/Profile/Sections/Kudosu/KudosuInfo.cs +++ b/osu.Game/Overlays/Profile/Sections/Kudosu/KudosuInfo.cs @@ -64,8 +64,8 @@ namespace osu.Game.Overlays.Profile.Sections.Kudosu this.user.ValueChanged += newUser => { - total.KudosuValue = newUser?.Kudosu.Total ?? 0; - avaliable.KudosuValue = newUser?.Kudosu.Available ?? 0; + total.Count = newUser?.Kudosu.Total ?? 0; + avaliable.Count = newUser?.Kudosu.Available ?? 0; }; } @@ -77,18 +77,9 @@ namespace osu.Game.Overlays.Profile.Sections.Kudosu private readonly OsuSpriteText valueText; - private int kudosuValue; - public int KudosuValue + public int Count { - get { return kudosuValue; } - set - { - if (kudosuValue == value) - return; - kudosuValue = value; - - valueText.Text = kudosuValue.ToString(); - } + set { valueText.Text = value.ToString(); } } public CountSection(string header, string description) From fe559f4b62245d66e2f6b6b0ae9a4ffa2f60fb7b Mon Sep 17 00:00:00 2001 From: naoey Date: Mon, 20 Nov 2017 10:36:26 +0530 Subject: [PATCH 0784/1263] Add respective query params to GetScoreRequest based on selected tab. --- .../Online/API/Requests/GetScoresRequest.cs | 25 +++++++++++++++-- osu.Game/Screens/Select/BeatmapDetailArea.cs | 1 + .../Select/Leaderboards/Leaderboard.cs | 28 ++++++++++++++++++- 3 files changed, 51 insertions(+), 3 deletions(-) diff --git a/osu.Game/Online/API/Requests/GetScoresRequest.cs b/osu.Game/Online/API/Requests/GetScoresRequest.cs index 3777e10a31..a52db4496a 100644 --- a/osu.Game/Online/API/Requests/GetScoresRequest.cs +++ b/osu.Game/Online/API/Requests/GetScoresRequest.cs @@ -10,19 +10,22 @@ using osu.Game.Rulesets; using osu.Game.Users; using osu.Game.Rulesets.Replays; using osu.Game.Rulesets.Scoring; +using osu.Game.Screens.Select.Leaderboards; namespace osu.Game.Online.API.Requests { public class GetScoresRequest : APIRequest { private readonly BeatmapInfo beatmap; + private readonly LeaderboardScope scope; - public GetScoresRequest(BeatmapInfo beatmap) + public GetScoresRequest(BeatmapInfo beatmap, LeaderboardScope scope = LeaderboardScope.Global) { if (!beatmap.OnlineBeatmapID.HasValue) throw new InvalidOperationException($"Cannot lookup a beatmap's scores without having a populated {nameof(BeatmapInfo.OnlineBeatmapID)}."); this.beatmap = beatmap; + this.scope = scope; Success += onSuccess; } @@ -33,7 +36,25 @@ namespace osu.Game.Online.API.Requests score.ApplyBeatmap(beatmap); } - protected override string Target => $@"beatmaps/{beatmap.OnlineBeatmapID}/scores"; + private string mapScopeToQuery() + { + switch(scope) + { + case LeaderboardScope.Global: + return @"?type=global"; + + case LeaderboardScope.Friends: + return @"?type=friend"; + + case LeaderboardScope.Country: + return @"?type=country"; + + default: + return String.Empty; + } + } + + protected override string Target => $@"beatmaps/{beatmap.OnlineBeatmapID}/scores{mapScopeToQuery()}"; } public class GetScoresResponse diff --git a/osu.Game/Screens/Select/BeatmapDetailArea.cs b/osu.Game/Screens/Select/BeatmapDetailArea.cs index a676516300..790a8421a2 100644 --- a/osu.Game/Screens/Select/BeatmapDetailArea.cs +++ b/osu.Game/Screens/Select/BeatmapDetailArea.cs @@ -52,6 +52,7 @@ namespace osu.Game.Screens.Select default: Details.Hide(); + Leaderboard.Scope = (LeaderboardScope) tab - 1; Leaderboard.Show(); break; } diff --git a/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs b/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs index d896da5319..20ab09e83e 100644 --- a/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs +++ b/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs @@ -74,6 +74,19 @@ namespace osu.Game.Screens.Select.Leaderboards } } + private LeaderboardScope scope = LeaderboardScope.Global; + public LeaderboardScope Scope + { + get { return scope; } + set + { + if (value == scope) return; + + scope = value; + updateScores(); + } + } + public Leaderboard() { Children = new Drawable[] @@ -120,6 +133,11 @@ namespace osu.Game.Screens.Select.Leaderboards { if (!IsLoaded) return; + if (Scope == LeaderboardScope.Local) + { + // TODO: get local scores from wherever here. + } + Scores = null; getScoresRequest?.Cancel(); @@ -127,7 +145,7 @@ namespace osu.Game.Screens.Select.Leaderboards loading.Show(); - getScoresRequest = new GetScoresRequest(Beatmap); + getScoresRequest = new GetScoresRequest(Beatmap, Scope); getScoresRequest.Success += r => { Scores = r.Scores; @@ -165,4 +183,12 @@ namespace osu.Game.Screens.Select.Leaderboards } } } + + public enum LeaderboardScope + { + Local, + Country, + Global, + Friends, + } } From a58bd72c6ede87d84a2c2d2c22d05e69d34e37ad Mon Sep 17 00:00:00 2001 From: naoey Date: Mon, 20 Nov 2017 17:07:41 +0530 Subject: [PATCH 0785/1263] Add placeholder when there are no scores. --- .../Select/Leaderboards/Leaderboard.cs | 56 ++++++++++++++++--- 1 file changed, 49 insertions(+), 7 deletions(-) diff --git a/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs b/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs index 20ab09e83e..b5cd729739 100644 --- a/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs +++ b/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs @@ -18,13 +18,18 @@ using osu.Game.Rulesets.Scoring; using osu.Game.Online.API; using osu.Game.Online.API.Requests; using System.Linq; +using osu.Game.Graphics.Sprites; +using osu.Game.Graphics; namespace osu.Game.Screens.Select.Leaderboards { public class Leaderboard : Container { + private const double fade_duration = 200; + private readonly ScrollContainer scrollContainer; private FillFlowContainer scrollFlow; + private Container placeholderContainer; public Action ScoreSelected; @@ -40,13 +45,19 @@ namespace osu.Game.Screens.Select.Leaderboards scores = value; getScoresRequest?.Cancel(); - scrollFlow?.FadeOut(200); - scrollFlow?.Expire(); + placeholderContainer.FadeOut(fade_duration); + scrollFlow?.FadeOut(fade_duration).Expire(); scrollFlow = null; if (scores == null) return; + if (scores.Count() == 0) + { + placeholderContainer.FadeIn(fade_duration); + return; + } + // schedule because we may not be loaded yet (LoadComponentAsync complains). Schedule(() => { @@ -74,7 +85,7 @@ namespace osu.Game.Screens.Select.Leaderboards } } - private LeaderboardScope scope = LeaderboardScope.Global; + private LeaderboardScope scope; public LeaderboardScope Scope { get { return scope; } @@ -96,7 +107,36 @@ namespace osu.Game.Screens.Select.Leaderboards RelativeSizeAxes = Axes.Both, ScrollbarVisible = false, }, - loading = new LoadingAnimation() + loading = new LoadingAnimation(), + placeholderContainer = new Container + { + Alpha = 0, + RelativeSizeAxes = Axes.Both, + Children = new Drawable[] + { + new FillFlowContainer + { + Direction = FillDirection.Horizontal, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + AutoSizeAxes = Axes.Both, + Children = new Drawable[] + { + new SpriteIcon + { + Icon = FontAwesome.fa_exclamation_circle, + Size = new Vector2(26), + Margin = new MarginPadding { Right = 10 }, + }, + new OsuSpriteText + { + Text = @"No records yet!", + TextSize = 22, + }, + } + }, + }, + }, }; } @@ -133,14 +173,16 @@ namespace osu.Game.Screens.Select.Leaderboards { if (!IsLoaded) return; + Scores = null; + getScoresRequest?.Cancel(); + if (Scope == LeaderboardScope.Local) { // TODO: get local scores from wherever here. + Scores = Enumerable.Empty(); + return; } - Scores = null; - getScoresRequest?.Cancel(); - if (api == null || Beatmap?.OnlineBeatmapID == null) return; loading.Show(); From 487483eaddf0833aa39c3f4c305fcb75404a78bb Mon Sep 17 00:00:00 2001 From: naoey Date: Mon, 20 Nov 2017 18:53:50 +0530 Subject: [PATCH 0786/1263] Move loader hiding to a better place. --- osu.Game/Screens/Select/Leaderboards/Leaderboard.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs b/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs index b5cd729739..2567110ef6 100644 --- a/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs +++ b/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs @@ -52,6 +52,8 @@ namespace osu.Game.Screens.Select.Leaderboards if (scores == null) return; + loading.Hide(); + if (scores.Count() == 0) { placeholderContainer.FadeIn(fade_duration); @@ -191,7 +193,6 @@ namespace osu.Game.Screens.Select.Leaderboards getScoresRequest.Success += r => { Scores = r.Scores; - loading.Hide(); }; api.Queue(getScoresRequest); } From 096e98b5d3aaeebb67c528b65c1aad44756d0597 Mon Sep 17 00:00:00 2001 From: Unknown Date: Tue, 21 Nov 2017 19:44:38 +0530 Subject: [PATCH 0787/1263] Add game mode query to request. - Also update scores when game mode is changed --- .../Online/API/Requests/GetScoresRequest.cs | 44 ++++++++++++++++--- .../Select/Leaderboards/Leaderboard.cs | 14 +++--- 2 files changed, 48 insertions(+), 10 deletions(-) diff --git a/osu.Game/Online/API/Requests/GetScoresRequest.cs b/osu.Game/Online/API/Requests/GetScoresRequest.cs index a52db4496a..37b3cc55f1 100644 --- a/osu.Game/Online/API/Requests/GetScoresRequest.cs +++ b/osu.Game/Online/API/Requests/GetScoresRequest.cs @@ -11,6 +11,7 @@ using osu.Game.Users; using osu.Game.Rulesets.Replays; using osu.Game.Rulesets.Scoring; using osu.Game.Screens.Select.Leaderboards; +using System.Collections.Specialized; namespace osu.Game.Online.API.Requests { @@ -18,14 +19,26 @@ namespace osu.Game.Online.API.Requests { private readonly BeatmapInfo beatmap; private readonly LeaderboardScope scope; + private readonly RulesetInfo ruleset; - public GetScoresRequest(BeatmapInfo beatmap, LeaderboardScope scope = LeaderboardScope.Global) + public GetScoresRequest(BeatmapInfo beatmap) + { + if (!beatmap.OnlineBeatmapID.HasValue) + throw new InvalidOperationException($"Cannot lookup a beatmap's scores without having a populated {nameof(BeatmapInfo.OnlineBeatmapID)}."); + + this.beatmap = beatmap; + + Success += onSuccess; + } + + public GetScoresRequest(BeatmapInfo beatmap, LeaderboardScope scope, RulesetInfo ruleset) { if (!beatmap.OnlineBeatmapID.HasValue) throw new InvalidOperationException($"Cannot lookup a beatmap's scores without having a populated {nameof(BeatmapInfo.OnlineBeatmapID)}."); this.beatmap = beatmap; this.scope = scope; + this.ruleset = ruleset; Success += onSuccess; } @@ -41,20 +54,41 @@ namespace osu.Game.Online.API.Requests switch(scope) { case LeaderboardScope.Global: - return @"?type=global"; + return @"type=global"; case LeaderboardScope.Friends: - return @"?type=friend"; + return @"type=friend"; case LeaderboardScope.Country: - return @"?type=country"; + return @"type=country"; default: return String.Empty; } } - protected override string Target => $@"beatmaps/{beatmap.OnlineBeatmapID}/scores{mapScopeToQuery()}"; + private string mapRulesetToQuery() + { + switch(ruleset.Name) + { + case @"osu!": + return @"mode=osu"; + + case @"osu!taiko": + return @"mode=taiko"; + + case @"osu!catch": + return @"mode=catch"; + + case @"osu!mania": + return @"mode=mania"; + + default: + return String.Empty; + } + } + + protected override string Target => $@"beatmaps/{beatmap.OnlineBeatmapID}/scores?{mapScopeToQuery()}&{mapRulesetToQuery()}"; } public class GetScoresResponse diff --git a/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs b/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs index 2567110ef6..3bc520e8e6 100644 --- a/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs +++ b/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs @@ -146,6 +146,8 @@ namespace osu.Game.Screens.Select.Leaderboards private BeatmapInfo beatmap; + private OsuGame osuGame; + private ScheduledDelegate pendingBeatmapSwitch; public BeatmapInfo Beatmap @@ -164,9 +166,12 @@ namespace osu.Game.Screens.Select.Leaderboards } [BackgroundDependencyLoader(permitNulls: true)] - private void load(APIAccess api) + private void load(APIAccess api, OsuGame osuGame) { this.api = api; + this.osuGame = osuGame; + + osuGame.Ruleset.ValueChanged += r => updateScores(); } private GetScoresRequest getScoresRequest; @@ -176,7 +181,8 @@ namespace osu.Game.Screens.Select.Leaderboards if (!IsLoaded) return; Scores = null; - getScoresRequest?.Cancel(); + + if (api == null || Beatmap?.OnlineBeatmapID == null) return; if (Scope == LeaderboardScope.Local) { @@ -185,11 +191,9 @@ namespace osu.Game.Screens.Select.Leaderboards return; } - if (api == null || Beatmap?.OnlineBeatmapID == null) return; - loading.Show(); - getScoresRequest = new GetScoresRequest(Beatmap, Scope); + getScoresRequest = new GetScoresRequest(Beatmap, Scope, osuGame.Ruleset.Value); getScoresRequest.Success += r => { Scores = r.Scores; From b6de1ce5b649011c6d60d8050215cfcc0a0c7517 Mon Sep 17 00:00:00 2001 From: naoey Date: Wed, 22 Nov 2017 09:56:01 +0530 Subject: [PATCH 0788/1263] Handle query params better. --- .../Online/API/Requests/GetScoresRequest.cs | 58 +++++++++++-------- .../Select/Leaderboards/Leaderboard.cs | 2 +- 2 files changed, 34 insertions(+), 26 deletions(-) diff --git a/osu.Game/Online/API/Requests/GetScoresRequest.cs b/osu.Game/Online/API/Requests/GetScoresRequest.cs index 37b3cc55f1..534a209609 100644 --- a/osu.Game/Online/API/Requests/GetScoresRequest.cs +++ b/osu.Game/Online/API/Requests/GetScoresRequest.cs @@ -12,6 +12,7 @@ using osu.Game.Rulesets.Replays; using osu.Game.Rulesets.Scoring; using osu.Game.Screens.Select.Leaderboards; using System.Collections.Specialized; +using osu.Framework.IO.Network; namespace osu.Game.Online.API.Requests { @@ -31,7 +32,7 @@ namespace osu.Game.Online.API.Requests Success += onSuccess; } - public GetScoresRequest(BeatmapInfo beatmap, LeaderboardScope scope, RulesetInfo ruleset) + public GetScoresRequest(BeatmapInfo beatmap, RulesetInfo ruleset, LeaderboardScope scope = LeaderboardScope.Global) { if (!beatmap.OnlineBeatmapID.HasValue) throw new InvalidOperationException($"Cannot lookup a beatmap's scores without having a populated {nameof(BeatmapInfo.OnlineBeatmapID)}."); @@ -49,46 +50,53 @@ namespace osu.Game.Online.API.Requests score.ApplyBeatmap(beatmap); } - private string mapScopeToQuery() + protected override WebRequest CreateWebRequest() { + var req = base.CreateWebRequest(); + switch(scope) { + default: case LeaderboardScope.Global: - return @"type=global"; + req.AddParameter(@"type", @"global"); + break; case LeaderboardScope.Friends: - return @"type=friend"; + req.AddParameter(@"type", @"friend"); + break; case LeaderboardScope.Country: - return @"type=country"; - - default: - return String.Empty; + req.AddParameter(@"type", @"country"); + break; } - } - private string mapRulesetToQuery() - { - switch(ruleset.Name) + if (ruleset != null) { - case @"osu!": - return @"mode=osu"; + switch (ruleset.Name) + { + default: + case @"osu!": + req.AddParameter(@"mode", @"osu"); + break; - case @"osu!taiko": - return @"mode=taiko"; - - case @"osu!catch": - return @"mode=catch"; - - case @"osu!mania": - return @"mode=mania"; + case @"osu!taiko": + req.AddParameter(@"mode", @"taiko"); + break; - default: - return String.Empty; + case @"osu!catch": + req.AddParameter(@"mode", @"catch"); + break; + + case @"osu!mania": + req.AddParameter(@"mode", @"mania"); + break; + } } + + return req; } - protected override string Target => $@"beatmaps/{beatmap.OnlineBeatmapID}/scores?{mapScopeToQuery()}&{mapRulesetToQuery()}"; + protected override string Target => $@"beatmaps/{beatmap.OnlineBeatmapID}/scores"; } public class GetScoresResponse diff --git a/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs b/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs index 3bc520e8e6..3b7e30dafe 100644 --- a/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs +++ b/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs @@ -193,7 +193,7 @@ namespace osu.Game.Screens.Select.Leaderboards loading.Show(); - getScoresRequest = new GetScoresRequest(Beatmap, Scope, osuGame.Ruleset.Value); + getScoresRequest = new GetScoresRequest(Beatmap, osuGame.Ruleset.Value, Scope); getScoresRequest.Success += r => { Scores = r.Scores; From d93911ae9745ac56692e90f6ad9c63f6c7b907f3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 23 Nov 2017 18:09:42 +0900 Subject: [PATCH 0789/1263] Improve user ratings calculations to make more sense Closes #1552. --- osu.Game/Beatmaps/BeatmapMetrics.cs | 2 +- osu.Game/Graphics/UserInterface/Bar.cs | 3 ++- osu.Game/Screens/Select/Details/UserRatings.cs | 16 +++++++++++----- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapMetrics.cs b/osu.Game/Beatmaps/BeatmapMetrics.cs index 730cf635da..e0cd5f10e7 100644 --- a/osu.Game/Beatmaps/BeatmapMetrics.cs +++ b/osu.Game/Beatmaps/BeatmapMetrics.cs @@ -12,7 +12,7 @@ namespace osu.Game.Beatmaps public class BeatmapMetrics { /// - /// Total vote counts of user ratings on a scale of 0..length. + /// Total vote counts of user ratings on a scale of 0..10 where 0 is unused (probably will be fixed at API?). /// public IEnumerable Ratings { get; set; } diff --git a/osu.Game/Graphics/UserInterface/Bar.cs b/osu.Game/Graphics/UserInterface/Bar.cs index 20df553142..c25a9bf5e9 100644 --- a/osu.Game/Graphics/UserInterface/Bar.cs +++ b/osu.Game/Graphics/UserInterface/Bar.cs @@ -20,6 +20,7 @@ namespace osu.Game.Graphics.UserInterface private const Easing easing = Easing.InOutCubic; private float length; + /// /// Length of the bar, ranges from 0 to 1 /// @@ -134,4 +135,4 @@ namespace osu.Game.Graphics.UserInterface Vertical = TopToBottom | BottomToTop, Horizontal = LeftToRight | RightToLeft, } -} \ No newline at end of file +} diff --git a/osu.Game/Screens/Select/Details/UserRatings.cs b/osu.Game/Screens/Select/Details/UserRatings.cs index 2153eb150c..0741407049 100644 --- a/osu.Game/Screens/Select/Details/UserRatings.cs +++ b/osu.Game/Screens/Select/Details/UserRatings.cs @@ -29,11 +29,17 @@ namespace osu.Game.Screens.Select.Details if (value == metrics) return; metrics = value; - var ratings = Metrics.Ratings.ToList(); - negativeRatings.Text = ratings.GetRange(0, ratings.Count / 2 + 1).Sum().ToString(); - positiveRatings.Text = ratings.GetRange(ratings.Count / 2 + 1, ratings.Count / 2).Sum().ToString(); - ratingsBar.Length = (float)ratings.GetRange(0, ratings.Count / 2 + 1).Sum() / ratings.Sum(); - graph.Values = Metrics.Ratings.Select(r => (float)r); + const int rating_range = 10; + + var ratings = Metrics.Ratings.ToList().GetRange(1, rating_range); // adjust for API returning weird empty data at 0. + + var negativeCount = ratings.GetRange(0, rating_range / 2).Sum(); + var totalCount = ratings.Sum(); + + negativeRatings.Text = negativeCount.ToString(); + positiveRatings.Text = (totalCount - negativeCount).ToString(); + ratingsBar.Length = (float)negativeCount / totalCount; + graph.Values = ratings.GetRange(0, rating_range).Select(r => (float)r); } } From 38f5c55f80d18239ba80dca2dd558b78dcb00d61 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 23 Nov 2017 18:11:35 +0900 Subject: [PATCH 0790/1263] Remove not-accessed field --- osu.Game/Overlays/Profile/Sections/Kudosu/KudosuInfo.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/osu.Game/Overlays/Profile/Sections/Kudosu/KudosuInfo.cs b/osu.Game/Overlays/Profile/Sections/Kudosu/KudosuInfo.cs index 4520abdd6d..8a835634b8 100644 --- a/osu.Game/Overlays/Profile/Sections/Kudosu/KudosuInfo.cs +++ b/osu.Game/Overlays/Profile/Sections/Kudosu/KudosuInfo.cs @@ -73,8 +73,6 @@ namespace osu.Game.Overlays.Profile.Sections.Kudosu private class CountSection : Container { - public readonly TextFlowContainer TextFlow; - private readonly OsuSpriteText valueText; public int Count @@ -122,7 +120,7 @@ namespace osu.Game.Overlays.Profile.Sections.Kudosu } } }, - TextFlow = new TextFlowContainer(t => { t.TextSize = 19; }) + new TextFlowContainer(t => { t.TextSize = 19; }) { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, From 52c971cd75abacac52ef2b153b948ece5bc336f0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 23 Nov 2017 18:58:25 +0900 Subject: [PATCH 0791/1263] Fix using incorrect Description attribute --- osu.Game.Tests/Visual/TestCaseBeatmapDetailArea.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/TestCaseBeatmapDetailArea.cs b/osu.Game.Tests/Visual/TestCaseBeatmapDetailArea.cs index 215d1ee5b1..1a64994d0e 100644 --- a/osu.Game.Tests/Visual/TestCaseBeatmapDetailArea.cs +++ b/osu.Game.Tests/Visual/TestCaseBeatmapDetailArea.cs @@ -9,7 +9,7 @@ using OpenTK; namespace osu.Game.Tests.Visual { [TestFixture] - [Description("PlaySongSelect leaderboard/details area")] + [System.ComponentModel.Description("PlaySongSelect leaderboard/details area")] internal class TestCaseBeatmapDetailArea : OsuTestCase { public TestCaseBeatmapDetailArea() From 6d88396139f3f88695f1aa877f2b844954a89917 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 23 Nov 2017 20:22:15 +0900 Subject: [PATCH 0792/1263] Update framework --- osu-framework | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu-framework b/osu-framework index eea84aaefc..d87dab204b 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit eea84aaefcc7a1a6732d105ba319272dd9744901 +Subproject commit d87dab204b3df50f62e6070b1970c135ea647d78 From 9db6ef6657c70d8f49809c6f04a1fba23b3988df Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 23 Nov 2017 20:23:47 +0900 Subject: [PATCH 0793/1263] Fix unfixed regressions --- osu.Game/Overlays/Direct/PlayButton.cs | 2 +- osu.Game/Screens/Select/Leaderboards/LeaderboardScore.cs | 8 ++++---- osu.Game/Users/UpdateableAvatar.cs | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/osu.Game/Overlays/Direct/PlayButton.cs b/osu.Game/Overlays/Direct/PlayButton.cs index 7fff2821e3..75a3358d51 100644 --- a/osu.Game/Overlays/Direct/PlayButton.cs +++ b/osu.Game/Overlays/Direct/PlayButton.cs @@ -152,7 +152,7 @@ namespace osu.Game.Overlays.Direct // We may have been replaced by another loader if (trackLoader != d) return; - Preview = (d as TrackLoader)?.Preview; + Preview = d?.Preview; Playing.TriggerChange(); loading = false; Add(trackLoader); diff --git a/osu.Game/Screens/Select/Leaderboards/LeaderboardScore.cs b/osu.Game/Screens/Select/Leaderboards/LeaderboardScore.cs index 0d898ad7d2..03466439ad 100644 --- a/osu.Game/Screens/Select/Leaderboards/LeaderboardScore.cs +++ b/osu.Game/Screens/Select/Leaderboards/LeaderboardScore.cs @@ -33,7 +33,7 @@ namespace osu.Game.Screens.Select.Leaderboards private Box background; private Container content; - private Container avatar; + private Drawable avatar; private DrawableRank scoreRank; private OsuSpriteText nameLabel; private GlowingSpriteText scoreLabel; @@ -97,7 +97,7 @@ namespace osu.Game.Screens.Select.Leaderboards { RelativeSizeAxes = Axes.Both, Padding = new MarginPadding(edge_margin), - Children = new Drawable[] + Children = new[] { avatar = new DelayedLoadWrapper( new Avatar(Score.User) @@ -112,7 +112,7 @@ namespace osu.Game.Screens.Select.Leaderboards Radius = 1, Colour = Color4.Black.Opacity(0.2f), }, - }, 500) + }) { RelativeSizeAxes = Axes.None, Size = new Vector2(HEIGHT - edge_margin * 2, HEIGHT - edge_margin * 2), @@ -210,7 +210,7 @@ namespace osu.Game.Screens.Select.Leaderboards public override void Show() { - foreach (var d in new Drawable[] { avatar, nameLabel, scoreLabel, scoreRank, flagBadgeContainer, maxCombo, accuracy, modsContainer }) + foreach (var d in new[] { avatar, nameLabel, scoreLabel, scoreRank, flagBadgeContainer, maxCombo, accuracy, modsContainer }) d.FadeOut(); Alpha = 0; diff --git a/osu.Game/Users/UpdateableAvatar.cs b/osu.Game/Users/UpdateableAvatar.cs index 895407064c..d55c0caad7 100644 --- a/osu.Game/Users/UpdateableAvatar.cs +++ b/osu.Game/Users/UpdateableAvatar.cs @@ -11,7 +11,7 @@ namespace osu.Game.Users /// public class UpdateableAvatar : Container { - private Container displayedAvatar; + private Drawable displayedAvatar; private User user; @@ -45,7 +45,7 @@ namespace osu.Game.Users { RelativeSizeAxes = Axes.Both, OnLoadComplete = d => d.FadeInFromZero(200), - }, 500) + }) ); } } From a60e53c3828c6077e0803b93d0223ccda39e21ad Mon Sep 17 00:00:00 2001 From: FreezyLemon Date: Thu, 23 Nov 2017 12:31:18 +0100 Subject: [PATCH 0794/1263] Changed the text updates into a scheduled (async) operation, and implemented this in the updateStatistics and clearStats methods --- osu.Game/Screens/Select/BeatmapDetails.cs | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/osu.Game/Screens/Select/BeatmapDetails.cs b/osu.Game/Screens/Select/BeatmapDetails.cs index d7c509d979..6eaed67534 100644 --- a/osu.Game/Screens/Select/BeatmapDetails.cs +++ b/osu.Game/Screens/Select/BeatmapDetails.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 OpenTK; using OpenTK.Graphics; using osu.Framework.Allocation; @@ -187,9 +188,7 @@ namespace osu.Game.Screens.Select ratingsContainer.FadeIn(transition_duration); advanced.Beatmap = Beatmap; - description.Text = Beatmap.Version; - source.Text = Beatmap.Metadata.Source; - tags.Text = Beatmap.Metadata.Tags; + loadDetailsAsync(Beatmap); var requestedBeatmap = Beatmap; if (requestedBeatmap.Metrics == null) @@ -213,6 +212,19 @@ namespace osu.Game.Screens.Select displayMetrics(requestedBeatmap.Metrics, false); } + private void loadDetailsAsync(BeatmapInfo beatmap) + { + if (description == null || source == null || tags == null) + throw new InvalidOperationException($@"Requires all {nameof(MetadataSection)} elements to be non-null."); + + Schedule(() => + { + description.Text = Beatmap?.Version; + source.Text = Beatmap?.Metadata?.Source; + tags.Text = Beatmap?.Metadata?.Tags; + }); + } + private void displayMetrics(BeatmapMetrics metrics, bool failOnMissing = true) { var hasRatings = metrics?.Ratings?.Any() ?? false; @@ -258,9 +270,7 @@ namespace osu.Game.Screens.Select private void clearStats() { - description.Text = null; - source.Text = null; - tags.Text = null; + loadDetailsAsync(null); advanced.Beatmap = new BeatmapInfo { StarDifficulty = 0, From 9565a9c352524645895c66771af64086c9d53951 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 23 Nov 2017 20:42:07 +0900 Subject: [PATCH 0795/1263] Fix TestCasePlayer not working as expected --- osu.Game/Screens/Play/Player.cs | 6 ++- osu.Game/Tests/Visual/ScreenTestCase.cs | 52 +++++++++++++++++++++++++ osu.Game/Tests/Visual/TestCasePlayer.cs | 17 ++++---- osu.Game/osu.Game.csproj | 1 + 4 files changed, 65 insertions(+), 11 deletions(-) create mode 100644 osu.Game/Tests/Visual/ScreenTestCase.cs diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 1e1b7bac93..a19305778c 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 int RestartCount; private IAdjustableClock adjustableSourceClock; @@ -158,7 +160,7 @@ namespace osu.Game.Screens.Play FramedClock = offsetClock, OnRetry = Restart, OnQuit = Exit, - CheckCanPause = () => ValidForResume && !HasFailed && !RulesetContainer.HasReplayLoaded, + CheckCanPause = () => AllowPause && ValidForResume && !HasFailed && !RulesetContainer.HasReplayLoaded, Retries = RestartCount, OnPause = () => { hudOverlay.KeyCounter.IsCounting = pauseContainer.IsPaused; @@ -355,7 +357,7 @@ namespace osu.Game.Screens.Play protected override bool OnExiting(Screen next) { - if (HasFailed || !ValidForResume || pauseContainer?.AllowExit != false || RulesetContainer?.HasReplayLoaded != false) + if (!AllowPause || HasFailed || !ValidForResume || pauseContainer?.AllowExit != false || RulesetContainer?.HasReplayLoaded != false) { // In the case of replays, we may have changed the playback rate. applyRateFromMods(); diff --git a/osu.Game/Tests/Visual/ScreenTestCase.cs b/osu.Game/Tests/Visual/ScreenTestCase.cs new file mode 100644 index 0000000000..11ff97cbf8 --- /dev/null +++ b/osu.Game/Tests/Visual/ScreenTestCase.cs @@ -0,0 +1,52 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Screens; +using osu.Game.Screens; + +namespace osu.Game.Tests.Visual +{ + /// + /// A test case which can be used to test a screen (that relies on OnEntering being called to execute startup instructions). + /// + public abstract class ScreenTestCase : OsuTestCase + { + private readonly TestOsuScreen baseScreen; + + protected ScreenTestCase() + { + Add(baseScreen = new TestOsuScreen()); + } + + protected void LoadScreen(OsuScreen screen) => baseScreen.LoadScreen(screen); + + public class TestOsuScreen : OsuScreen + { + public TestOsuScreen() + { + } + + private OsuScreen nextScreen; + + public void LoadScreen(OsuScreen screen) => Schedule(() => + { + nextScreen = screen; + + if (IsCurrentScreen) + { + Push(screen); + nextScreen = null; + } + else + MakeCurrent(); + }); + + protected override void OnResuming(Screen last) + { + base.OnResuming(last); + if (nextScreen != null) + LoadScreen(nextScreen); + } + } + } +} diff --git a/osu.Game/Tests/Visual/TestCasePlayer.cs b/osu.Game/Tests/Visual/TestCasePlayer.cs index cef85b65f1..f3a6d1efc3 100644 --- a/osu.Game/Tests/Visual/TestCasePlayer.cs +++ b/osu.Game/Tests/Visual/TestCasePlayer.cs @@ -17,7 +17,7 @@ using OpenTK.Graphics; namespace osu.Game.Tests.Visual { - public abstract class TestCasePlayer : OsuTestCase + public abstract class TestCasePlayer : ScreenTestCase { private readonly Type ruleset; @@ -44,6 +44,7 @@ namespace osu.Game.Tests.Visual { RelativeSizeAxes = Framework.Graphics.Axes.Both, Colour = Color4.Black, + Depth = int.MaxValue }); string instantiation = ruleset?.AssemblyQualifiedName; @@ -77,19 +78,17 @@ namespace osu.Game.Tests.Visual if (Player != null) Remove(Player); - Add(Player = CreatePlayer(working, instance)); + LoadScreen(CreatePlayer(working, instance)); } - protected virtual Player CreatePlayer(WorkingBeatmap beatmap, Ruleset ruleset) + protected virtual Player CreatePlayer(WorkingBeatmap beatmap, Ruleset ruleset) => new Player { - return new Player - { - InitialBeatmap = beatmap - }; - } + InitialBeatmap = beatmap, + AllowPause = false + }; private const string test_beatmap_data = -@"osu file format v14 + @"osu file format v14 [General] AudioLeadIn: 500 diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 87c8275512..2aefde2916 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -784,6 +784,7 @@ + From 4e96c5aea25a91f72154322fcffefcb67d7658fc Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 23 Nov 2017 19:27:25 +0900 Subject: [PATCH 0796/1263] Fix TestCaseButtonSystem not working Was missing an osu! logo --- osu.Game.Tests/Visual/TestCaseButtonSystem.cs | 33 +++++++++++++++++++ .../Visual/TestCaseMenuButtonSystem.cs | 25 -------------- osu.Game.Tests/osu.Game.Tests.csproj | 2 +- 3 files changed, 34 insertions(+), 26 deletions(-) create mode 100644 osu.Game.Tests/Visual/TestCaseButtonSystem.cs delete mode 100644 osu.Game.Tests/Visual/TestCaseMenuButtonSystem.cs diff --git a/osu.Game.Tests/Visual/TestCaseButtonSystem.cs b/osu.Game.Tests/Visual/TestCaseButtonSystem.cs new file mode 100644 index 0000000000..d260de69f1 --- /dev/null +++ b/osu.Game.Tests/Visual/TestCaseButtonSystem.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 osu.Framework.Graphics; +using osu.Framework.Graphics.Colour; +using osu.Framework.Graphics.Shapes; +using osu.Game.Screens.Menu; +using OpenTK.Graphics; + +namespace osu.Game.Tests.Visual +{ + internal class TestCaseButtonSystem : OsuTestCase + { + public TestCaseButtonSystem() + { + OsuLogo logo; + ButtonSystem buttons; + + Children = new Drawable[] + { + new Box + { + Colour = ColourInfo.GradientVertical(Color4.Gray, Color4.WhiteSmoke), + RelativeSizeAxes = Axes.Both, + }, + buttons = new ButtonSystem(), + logo = new OsuLogo() + }; + + buttons.SetOsuLogo(logo); + } + } +} diff --git a/osu.Game.Tests/Visual/TestCaseMenuButtonSystem.cs b/osu.Game.Tests/Visual/TestCaseMenuButtonSystem.cs deleted file mode 100644 index b5310f0fb0..0000000000 --- a/osu.Game.Tests/Visual/TestCaseMenuButtonSystem.cs +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) 2007-2017 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using System.ComponentModel; -using osu.Framework.Graphics.Colour; -using osu.Framework.Graphics.Shapes; -using osu.Game.Screens.Menu; -using OpenTK.Graphics; - -namespace osu.Game.Tests.Visual -{ - [Description("main menu")] - internal class TestCaseMenuButtonSystem : OsuTestCase - { - public TestCaseMenuButtonSystem() - { - Add(new Box - { - Colour = ColourInfo.GradientVertical(Color4.Gray, Color4.WhiteSmoke), - RelativeSizeAxes = Framework.Graphics.Axes.Both, - }); - Add(new ButtonSystem()); - } - } -} diff --git a/osu.Game.Tests/osu.Game.Tests.csproj b/osu.Game.Tests/osu.Game.Tests.csproj index 9bba09b1a7..312a564f71 100644 --- a/osu.Game.Tests/osu.Game.Tests.csproj +++ b/osu.Game.Tests/osu.Game.Tests.csproj @@ -116,7 +116,7 @@ - + From dbb03bcff28ead54b2d0239b2847aba012c5a411 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 23 Nov 2017 23:30:57 +0900 Subject: [PATCH 0797/1263] Handle the case where a map hasn't been rated yet --- osu.Game/Screens/Select/Details/UserRatings.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Select/Details/UserRatings.cs b/osu.Game/Screens/Select/Details/UserRatings.cs index 0741407049..997e0baec3 100644 --- a/osu.Game/Screens/Select/Details/UserRatings.cs +++ b/osu.Game/Screens/Select/Details/UserRatings.cs @@ -38,7 +38,7 @@ namespace osu.Game.Screens.Select.Details negativeRatings.Text = negativeCount.ToString(); positiveRatings.Text = (totalCount - negativeCount).ToString(); - ratingsBar.Length = (float)negativeCount / totalCount; + ratingsBar.Length = totalCount == 0 ? 0 : (float)negativeCount / totalCount; graph.Values = ratings.GetRange(0, rating_range).Select(r => (float)r); } } From 95fbe6a4a2852e162f0fd1173f3603ea79c652a3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 23 Nov 2017 23:42:43 +0900 Subject: [PATCH 0798/1263] Update framework --- osu-framework | 2 +- osu.Game/Tests/Visual/ScreenTestCase.cs | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/osu-framework b/osu-framework index d87dab204b..fe49ccb3c8 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit d87dab204b3df50f62e6070b1970c135ea647d78 +Subproject commit fe49ccb3c8f8661d653752d225ae1dc183944bb4 diff --git a/osu.Game/Tests/Visual/ScreenTestCase.cs b/osu.Game/Tests/Visual/ScreenTestCase.cs index 11ff97cbf8..2f0831d84a 100644 --- a/osu.Game/Tests/Visual/ScreenTestCase.cs +++ b/osu.Game/Tests/Visual/ScreenTestCase.cs @@ -22,10 +22,6 @@ namespace osu.Game.Tests.Visual public class TestOsuScreen : OsuScreen { - public TestOsuScreen() - { - } - private OsuScreen nextScreen; public void LoadScreen(OsuScreen screen) => Schedule(() => From e3a230320ae1aa3b1f2279b539d0e97b416d48fc Mon Sep 17 00:00:00 2001 From: Aergwyn Date: Thu, 23 Nov 2017 19:46:58 +0100 Subject: [PATCH 0799/1263] compare metdata and remove duplicate from beatmap to prevent redundant storage --- osu.Game/Beatmaps/BeatmapManager.cs | 4 ++++ osu.Game/Beatmaps/BeatmapMetadata.cs | 18 ++++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index eb10b23c6f..ca715b8d1e 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -515,6 +515,10 @@ namespace osu.Game.Beatmaps if (existing == null) { + // Exclude beatmap-metadata if it's equal to beatmapset-metadata + if (metadata.Equals(beatmap.Metadata)) + beatmap.BeatmapInfo.Metadata = null; + RulesetInfo ruleset = rulesets.GetRuleset(beatmap.BeatmapInfo.RulesetID); // TODO: this should be done in a better place once we actually need to dynamically update it. diff --git a/osu.Game/Beatmaps/BeatmapMetadata.cs b/osu.Game/Beatmaps/BeatmapMetadata.cs index 89f9ebf47a..2cd8e2669f 100644 --- a/osu.Game/Beatmaps/BeatmapMetadata.cs +++ b/osu.Game/Beatmaps/BeatmapMetadata.cs @@ -66,5 +66,23 @@ namespace osu.Game.Beatmaps Source, Tags }.Where(s => !string.IsNullOrEmpty(s)).ToArray(); + + public override bool Equals(object other) + { + var otherMetadata = other as BeatmapMetadata; + if (otherMetadata == null) return false; + + return (onlineBeatmapSetID?.Equals(otherMetadata.onlineBeatmapSetID) ?? false) + && (Title?.Equals(otherMetadata.Title) ?? false) + && (TitleUnicode?.Equals(otherMetadata.TitleUnicode) ?? false) + && (Artist?.Equals(otherMetadata.Artist) ?? false) + && (ArtistUnicode?.Equals(otherMetadata.ArtistUnicode) ?? false) + && (AuthorString?.Equals(otherMetadata.AuthorString) ?? false) + && (Source?.Equals(otherMetadata.Source) ?? false) + && (Tags?.Equals(otherMetadata.Tags) ?? false) + && PreviewTime.Equals(otherMetadata.PreviewTime) + && (AudioFile?.Equals(otherMetadata.AudioFile) ?? false) + && (BackgroundFile?.Equals(otherMetadata.BackgroundFile) ?? false); + } } } From 11d406aa0c2d3acaf6137538af20f9de85d41639 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 24 Nov 2017 11:49:10 +0900 Subject: [PATCH 0800/1263] Fix osu!catch conversion expecting full positional data, rather than just X. Closes #1367. --- osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapConverter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapConverter.cs b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapConverter.cs index 0e4935aa7a..7126b6586d 100644 --- a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapConverter.cs +++ b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapConverter.cs @@ -18,7 +18,7 @@ namespace osu.Game.Rulesets.Catch.Beatmaps protected override IEnumerable ConvertHitObject(HitObject obj, Beatmap beatmap) { var curveData = obj as IHasCurve; - var positionData = obj as IHasPosition; + var positionData = obj as IHasXPosition; var comboData = obj as IHasCombo; if (positionData == null) From 7ff39d62a1e52170c43026bd98cc94554878493d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 24 Nov 2017 12:46:15 +0900 Subject: [PATCH 0801/1263] Fix SpriteIcon potentially not updating texture during a load race condition Better fix for #1577. --- osu.Game/Graphics/SpriteIcon.cs | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/osu.Game/Graphics/SpriteIcon.cs b/osu.Game/Graphics/SpriteIcon.cs index ca108bfa7a..e752b1d91a 100644 --- a/osu.Game/Graphics/SpriteIcon.cs +++ b/osu.Game/Graphics/SpriteIcon.cs @@ -57,19 +57,31 @@ namespace osu.Game.Graphics private void load(FontStore store) { this.store = store; - updateTexture(); } + protected override void LoadComplete() + { + base.LoadComplete(); + updateTexture(); + } + + private FontAwesome loadedIcon; private void updateTexture() { - var texture = store?.Get(((char)icon).ToString()); + var loadableIcon = icon; + + if (loadableIcon == loadedIcon) return; + + var texture = store?.Get(((char)loadableIcon).ToString()); spriteMain.Texture = texture; spriteShadow.Texture = texture; if (Size == Vector2.Zero) Size = new Vector2(texture?.DisplayWidth ?? 0, texture?.DisplayHeight ?? 0); + + loadedIcon = loadableIcon; } public override bool Invalidate(Invalidation invalidation = Invalidation.All, Drawable source = null, bool shallPropagate = true) From a4b67b2559741f61b57859304ffff02372843c66 Mon Sep 17 00:00:00 2001 From: Dan Balasescu <1329837+smoogipoo@users.noreply.github.com> Date: Fri, 24 Nov 2017 12:56:52 +0900 Subject: [PATCH 0802/1263] Fix CI --- osu.Game.Rulesets.Taiko/TaikoDifficultyCalculator.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/TaikoDifficultyCalculator.cs b/osu.Game.Rulesets.Taiko/TaikoDifficultyCalculator.cs index 394036df39..e74c12fa5d 100644 --- a/osu.Game.Rulesets.Taiko/TaikoDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Taiko/TaikoDifficultyCalculator.cs @@ -5,7 +5,6 @@ using osu.Game.Beatmaps; using osu.Game.Rulesets.Taiko.Beatmaps; using osu.Game.Rulesets.Taiko.Objects; using System.Collections.Generic; -using System.Globalization; using System; namespace osu.Game.Rulesets.Taiko @@ -54,7 +53,7 @@ namespace osu.Game.Rulesets.Taiko if (categoryDifficulty != null) { categoryDifficulty.Add("Strain", starRating); - categoryDifficulty.Add("Hit window 300", (35 /*HitObjectManager.HitWindow300*/ / TimeRate)); + categoryDifficulty.Add("Hit window 300", 35 /*HitObjectManager.HitWindow300*/ / TimeRate); } return starRating; From 09facdc83810ecd90275a8a46b6582576b2e7b7e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 24 Nov 2017 18:34:20 +0900 Subject: [PATCH 0803/1263] Add a setting to toggle showing converted beatmaps --- osu.Game/Configuration/OsuConfigManager.cs | 4 +++- .../Sections/Gameplay/SongSelectSettings.cs | 7 ++++++- osu.Game/Screens/Select/FilterControl.cs | 15 ++++++++++++--- osu.Game/Screens/Select/FilterCriteria.cs | 3 ++- 4 files changed, 23 insertions(+), 6 deletions(-) diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs index b3e99fce06..c087a5afb7 100644 --- a/osu.Game/Configuration/OsuConfigManager.cs +++ b/osu.Game/Configuration/OsuConfigManager.cs @@ -16,6 +16,7 @@ namespace osu.Game.Configuration Set(OsuSetting.Ruleset, 0, 0, int.MaxValue); Set(OsuSetting.BeatmapDetailTab, BeatmapDetailTab.Details); + Set(OsuSetting.ShowConvertedBeatmaps, true); Set(OsuSetting.DisplayStarsMinimum, 0.0, 0, 10, 0.1); Set(OsuSetting.DisplayStarsMaximum, 10.0, 0, 10, 0.1); @@ -112,6 +113,7 @@ namespace osu.Game.Configuration SnakingOutSliders, ShowFpsDisplay, ChatDisplayHeight, - Version + Version, + ShowConvertedBeatmaps } } diff --git a/osu.Game/Overlays/Settings/Sections/Gameplay/SongSelectSettings.cs b/osu.Game/Overlays/Settings/Sections/Gameplay/SongSelectSettings.cs index 07a8e7464a..9875ee8004 100644 --- a/osu.Game/Overlays/Settings/Sections/Gameplay/SongSelectSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Gameplay/SongSelectSettings.cs @@ -17,6 +17,11 @@ namespace osu.Game.Overlays.Settings.Sections.Gameplay { Children = new Drawable[] { + new SettingsCheckbox + { + LabelText = "Show converted beatmaps", + Bindable = config.GetBindable(OsuSetting.ShowConvertedBeatmaps), + }, new SettingsSlider { LabelText = "Display beatmaps from", @@ -33,7 +38,7 @@ namespace osu.Game.Overlays.Settings.Sections.Gameplay { LabelText = "Random beatmap selection", Bindable = config.GetBindable(OsuSetting.SelectionRandomType), - }, + } }; } diff --git a/osu.Game/Screens/Select/FilterControl.cs b/osu.Game/Screens/Select/FilterControl.cs index e83613125b..1b86cec613 100644 --- a/osu.Game/Screens/Select/FilterControl.cs +++ b/osu.Game/Screens/Select/FilterControl.cs @@ -15,6 +15,7 @@ using osu.Game.Screens.Select.Filter; using Container = osu.Framework.Graphics.Containers.Container; using osu.Framework.Input; using osu.Framework.Graphics.Shapes; +using osu.Game.Configuration; using osu.Game.Rulesets; namespace osu.Game.Screens.Select @@ -60,6 +61,7 @@ namespace osu.Game.Screens.Select Group = group, Sort = sort, SearchText = searchTextBox.Text, + AllowConvertedBeatmaps = showConverted, Ruleset = ruleset }; @@ -163,17 +165,24 @@ namespace osu.Game.Screens.Select private readonly Bindable ruleset = new Bindable(); + private Bindable showConverted; + [BackgroundDependencyLoader(permitNulls: true)] - private void load(OsuColour colours, OsuGame osu) + private void load(OsuColour colours, OsuGame osu, OsuConfigManager config) { sortTabs.AccentColour = colours.GreenLight; + showConverted = config.GetBindable(OsuSetting.ShowConvertedBeatmaps); + showConverted.ValueChanged += val => updateCriteria(); + if (osu != null) ruleset.BindTo(osu.Ruleset); - ruleset.ValueChanged += val => FilterChanged?.Invoke(CreateCriteria()); + ruleset.ValueChanged += val => updateCriteria(); ruleset.TriggerChange(); } + private void updateCriteria() => FilterChanged?.Invoke(CreateCriteria()); + protected override bool OnMouseDown(InputState state, MouseDownEventArgs args) => true; protected override bool OnMouseMove(InputState state) => true; @@ -182,4 +191,4 @@ namespace osu.Game.Screens.Select protected override bool OnDragStart(InputState state) => true; } -} \ No newline at end of file +} diff --git a/osu.Game/Screens/Select/FilterCriteria.cs b/osu.Game/Screens/Select/FilterCriteria.cs index 6c1fb1703d..c1355bfa63 100644 --- a/osu.Game/Screens/Select/FilterCriteria.cs +++ b/osu.Game/Screens/Select/FilterCriteria.cs @@ -16,6 +16,7 @@ namespace osu.Game.Screens.Select public SortMode Sort; public string SearchText; public RulesetInfo Ruleset; + public bool AllowConvertedBeatmaps; public void Filter(List groups) { @@ -23,7 +24,7 @@ namespace osu.Game.Screens.Select { var set = g.BeatmapSet; - bool hasCurrentMode = set.Beatmaps.Any(bm => bm.RulesetID == (Ruleset?.ID ?? 0)); + bool hasCurrentMode = AllowConvertedBeatmaps || set.Beatmaps.Any(bm => bm.RulesetID == (Ruleset?.ID ?? 0)); bool match = hasCurrentMode; From c5a78e54e97f29dac7f471c5bb87de89782e0629 Mon Sep 17 00:00:00 2001 From: Unknown Date: Fri, 24 Nov 2017 18:40:52 +0530 Subject: [PATCH 0804/1263] Add a retry button for when scores request fails. --- .../Select/Leaderboards/Leaderboard.cs | 103 +++++++++++++++++- 1 file changed, 97 insertions(+), 6 deletions(-) diff --git a/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs b/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs index 3b7e30dafe..b25479704c 100644 --- a/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs +++ b/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs @@ -20,6 +20,8 @@ using osu.Game.Online.API.Requests; using System.Linq; using osu.Game.Graphics.Sprites; using osu.Game.Graphics; +using osu.Framework.Logging; +using System.Net; namespace osu.Game.Screens.Select.Leaderboards { @@ -29,7 +31,8 @@ namespace osu.Game.Screens.Select.Leaderboards private readonly ScrollContainer scrollContainer; private FillFlowContainer scrollFlow; - private Container placeholderContainer; + private Container noResultsPlaceholder; + private Container retryPlaceholder; public Action ScoreSelected; @@ -44,19 +47,20 @@ namespace osu.Game.Screens.Select.Leaderboards { scores = value; getScoresRequest?.Cancel(); + getScoresRequest = null; - placeholderContainer.FadeOut(fade_duration); + noResultsPlaceholder.FadeOut(fade_duration); scrollFlow?.FadeOut(fade_duration).Expire(); scrollFlow = null; + loading.Hide(); + if (scores == null) return; - loading.Hide(); - if (scores.Count() == 0) { - placeholderContainer.FadeIn(fade_duration); + noResultsPlaceholder.FadeIn(fade_duration); return; } @@ -110,7 +114,7 @@ namespace osu.Game.Screens.Select.Leaderboards ScrollbarVisible = false, }, loading = new LoadingAnimation(), - placeholderContainer = new Container + noResultsPlaceholder = new Container { Alpha = 0, RelativeSizeAxes = Axes.Both, @@ -139,6 +143,35 @@ namespace osu.Game.Screens.Select.Leaderboards }, }, }, + retryPlaceholder = new Container + { + Alpha = 0, + RelativeSizeAxes = Axes.Both, + Children = new Drawable[] + { + new FillFlowContainer + { + Direction = FillDirection.Horizontal, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + AutoSizeAxes = Axes.Both, + Children = new Drawable[] + { + new RetryButton + { + Action = updateScores, + Margin = new MarginPadding { Right = 10 }, + }, + new OsuSpriteText + { + Anchor = Anchor.TopLeft, + Text = @"An error occurred!", + TextSize = 22, + }, + } + }, + }, + }, }; } @@ -180,6 +213,8 @@ namespace osu.Game.Screens.Select.Leaderboards { if (!IsLoaded) return; + retryPlaceholder.FadeOut(fade_duration); + Scores = null; if (api == null || Beatmap?.OnlineBeatmapID == null) return; @@ -198,6 +233,17 @@ namespace osu.Game.Screens.Select.Leaderboards { Scores = r.Scores; }; + getScoresRequest.Failure += e => + { + // TODO: check why failure is repeatedly invoked even on successful requests + if (e is WebException) + { + Scores = null; + retryPlaceholder.FadeIn(fade_duration); + Logger.Error(e, @"Couldn't fetch beatmap scores!"); + } + }; + api.Queue(getScoresRequest); } @@ -229,6 +275,51 @@ namespace osu.Game.Screens.Select.Leaderboards } } } + + private class RetryButton : ClickableContainer + { + private SpriteIcon icon; + + public RetryButton() + { + Height = 26; + Width = 26; + Children = new Drawable[] + { + icon = new SpriteIcon + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Icon = FontAwesome.fa_refresh, + Size = new Vector2(26), + } + }; + } + + protected override bool OnHover(Framework.Input.InputState state) + { + icon.ScaleTo(1.4f, 400, Easing.OutQuint); + return base.OnHover(state); + } + + protected override void OnHoverLost(Framework.Input.InputState state) + { + icon.ScaleTo(1f, 400, Easing.OutQuint); + base.OnHoverLost(state); + } + + protected override bool OnMouseDown(Framework.Input.InputState state, Framework.Input.MouseDownEventArgs args) + { + icon.ScaleTo(0.8f, 200, Easing.InElastic); + return base.OnMouseDown(state, args); + } + + protected override bool OnMouseUp(Framework.Input.InputState state, Framework.Input.MouseUpEventArgs args) + { + icon.ScaleTo(1.2f, 400, Easing.OutElastic).Then().ScaleTo(1f, 400, Easing.OutElastic); + return base.OnMouseUp(state, args); + } + } } public enum LeaderboardScope From 21d5d107381f28a8efb2642ba0cd88bf05459ce3 Mon Sep 17 00:00:00 2001 From: jorolf Date: Fri, 24 Nov 2017 22:48:56 +0100 Subject: [PATCH 0805/1263] replace BeatmapResponse with BeatmapInfo --- .../Visual/TestCaseHistoricalSection.cs | 2 +- osu.Game/Beatmaps/BeatmapInfo.cs | 1 + .../GetUserMostPlayedBeatmapsRequest.cs | 32 +++---------------- 3 files changed, 7 insertions(+), 28 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCaseHistoricalSection.cs b/osu.Game.Tests/Visual/TestCaseHistoricalSection.cs index e67f389969..d75f9116ce 100644 --- a/osu.Game.Tests/Visual/TestCaseHistoricalSection.cs +++ b/osu.Game.Tests/Visual/TestCaseHistoricalSection.cs @@ -17,7 +17,7 @@ namespace osu.Game.Tests.Visual { public override string Description => "User's History"; - public override IReadOnlyList RequiredTypes => new [] { typeof(HistoricalSection), typeof(MostPlayedBeatmapDrawable)}; + public override IReadOnlyList RequiredTypes => new [] { typeof(HistoricalSection), typeof(PaginatedMostPlayedBeatmapContainer), typeof(MostPlayedBeatmapDrawable) }; public TestCaseHistoricalSection() diff --git a/osu.Game/Beatmaps/BeatmapInfo.cs b/osu.Game/Beatmaps/BeatmapInfo.cs index 022d64db03..f3a9694982 100644 --- a/osu.Game/Beatmaps/BeatmapInfo.cs +++ b/osu.Game/Beatmaps/BeatmapInfo.cs @@ -115,6 +115,7 @@ namespace osu.Game.Beatmaps // Metadata public string Version { get; set; } + [JsonProperty("difficulty_rating")] public double StarDifficulty { get; set; } public bool Equals(BeatmapInfo other) diff --git a/osu.Game/Online/API/Requests/GetUserMostPlayedBeatmapsRequest.cs b/osu.Game/Online/API/Requests/GetUserMostPlayedBeatmapsRequest.cs index cdc156be05..2d08f09d20 100644 --- a/osu.Game/Online/API/Requests/GetUserMostPlayedBeatmapsRequest.cs +++ b/osu.Game/Online/API/Requests/GetUserMostPlayedBeatmapsRequest.cs @@ -2,7 +2,6 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; -using System.Linq; using Newtonsoft.Json; using osu.Game.Beatmaps; using osu.Game.Rulesets; @@ -28,7 +27,7 @@ namespace osu.Game.Online.API.Requests public int PlayCount; [JsonProperty] - private BeatmapResponse beatmap; + private BeatmapInfo beatmap; [JsonProperty] private GetBeatmapSetsResponse beatmapSet; @@ -36,31 +35,10 @@ namespace osu.Game.Online.API.Requests public BeatmapInfo GetBeatmapInfo(RulesetStore rulesets) { BeatmapSetInfo setInfo = beatmapSet.ToBeatmapSet(rulesets); - return new BeatmapInfo - { - OnlineBeatmapID = beatmap.Id, - OnlineBeatmapSetID = setInfo.OnlineBeatmapSetID, - Ruleset = rulesets.AvailableRulesets.FirstOrDefault(ruleset => ruleset.Name.Equals(beatmap.Mode)), - StarDifficulty = beatmap.DifficultyRating, - Version = beatmap.Version, - Metadata = setInfo.Metadata, - BeatmapSet = setInfo, - }; - } - - private class BeatmapResponse - { - [JsonProperty] - public int Id; - - [JsonProperty] - public string Mode; - - [JsonProperty("difficulty_rating")] - public double DifficultyRating; - - [JsonProperty] - public string Version; + beatmap.BeatmapSet = setInfo; + beatmap.OnlineBeatmapSetID = setInfo.OnlineBeatmapSetID; + beatmap.Metadata = setInfo.Metadata; + return beatmap; } } } From 6b3347d6acfabc2df1dd0444ca97a31637c8d214 Mon Sep 17 00:00:00 2001 From: jorolf Date: Fri, 24 Nov 2017 22:59:21 +0100 Subject: [PATCH 0806/1263] remove description --- osu.Game.Tests/Visual/TestCaseHistoricalSection.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCaseHistoricalSection.cs b/osu.Game.Tests/Visual/TestCaseHistoricalSection.cs index d75f9116ce..37bb935787 100644 --- a/osu.Game.Tests/Visual/TestCaseHistoricalSection.cs +++ b/osu.Game.Tests/Visual/TestCaseHistoricalSection.cs @@ -15,8 +15,6 @@ namespace osu.Game.Tests.Visual { internal class TestCaseHistoricalSection : OsuTestCase { - public override string Description => "User's History"; - public override IReadOnlyList RequiredTypes => new [] { typeof(HistoricalSection), typeof(PaginatedMostPlayedBeatmapContainer), typeof(MostPlayedBeatmapDrawable) }; From d955229ee5cff6ce146e1ce2184e90ea429fb602 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Sat, 25 Nov 2017 21:29:23 +0800 Subject: [PATCH 0807/1263] Handle user rating metrics when no maps by using more linq. --- osu.Game/Screens/Select/Details/UserRatings.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Select/Details/UserRatings.cs b/osu.Game/Screens/Select/Details/UserRatings.cs index 997e0baec3..19bcad367e 100644 --- a/osu.Game/Screens/Select/Details/UserRatings.cs +++ b/osu.Game/Screens/Select/Details/UserRatings.cs @@ -31,15 +31,15 @@ namespace osu.Game.Screens.Select.Details const int rating_range = 10; - var ratings = Metrics.Ratings.ToList().GetRange(1, rating_range); // adjust for API returning weird empty data at 0. + var ratings = Metrics.Ratings.Skip(1).Take(rating_range); // adjust for API returning weird empty data at 0. - var negativeCount = ratings.GetRange(0, rating_range / 2).Sum(); + var negativeCount = ratings.Take(rating_range / 2).Sum(); var totalCount = ratings.Sum(); negativeRatings.Text = negativeCount.ToString(); positiveRatings.Text = (totalCount - negativeCount).ToString(); ratingsBar.Length = totalCount == 0 ? 0 : (float)negativeCount / totalCount; - graph.Values = ratings.GetRange(0, rating_range).Select(r => (float)r); + graph.Values = ratings.Take(rating_range).Select(r => (float)r); } } From f6a33b3ea2c4a78c899303ef51911bf507937090 Mon Sep 17 00:00:00 2001 From: Unknown Date: Sat, 25 Nov 2017 14:45:57 +0100 Subject: [PATCH 0808/1263] fix osu!direct download reloading all panels This fixes the recreation of all panels when a download completes. Also fixes NullReference when you download without ever opening the details of one Set. --- osu.Game/Overlays/BeatmapSet/Header.cs | 2 +- osu.Game/Overlays/DirectOverlay.cs | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/osu.Game/Overlays/BeatmapSet/Header.cs b/osu.Game/Overlays/BeatmapSet/Header.cs index af59b21713..4135aef268 100644 --- a/osu.Game/Overlays/BeatmapSet/Header.cs +++ b/osu.Game/Overlays/BeatmapSet/Header.cs @@ -234,7 +234,7 @@ namespace osu.Game.Overlays.BeatmapSet private void handleBeatmapAdd(BeatmapSetInfo beatmap) { - if (beatmap.OnlineBeatmapSetID == BeatmapSet.OnlineBeatmapSetID) + if (beatmap.OnlineBeatmapSetID == BeatmapSet?.OnlineBeatmapSetID) downloadButtonsContainer.FadeOut(transition_duration); } diff --git a/osu.Game/Overlays/DirectOverlay.cs b/osu.Game/Overlays/DirectOverlay.cs index 6f7fabb910..11dd9dd976 100644 --- a/osu.Game/Overlays/DirectOverlay.cs +++ b/osu.Game/Overlays/DirectOverlay.cs @@ -65,8 +65,6 @@ namespace osu.Game.Overlays } ResultAmounts = new ResultCounts(distinctCount(artists), distinctCount(songs), distinctCount(tags)); - - recreatePanels(Filter.DisplayStyleControl.DisplayStyle.Value); } } @@ -282,7 +280,11 @@ namespace osu.Game.Overlays var sets = response.Select(r => r.ToBeatmapSet(rulesets)).Where(b => !presentOnlineIds.Contains(b.OnlineBeatmapSetID)).ToList(); // may not need scheduling; loads async internally. - Schedule(() => BeatmapSets = sets); + Schedule(() => + { + BeatmapSets = sets; + recreatePanels(Filter.DisplayStyleControl.DisplayStyle.Value); + }); }); }; From 5da1466e284b584c636a5cf6f2c00c8280d04e3b Mon Sep 17 00:00:00 2001 From: Unknown Date: Sat, 25 Nov 2017 15:05:59 +0100 Subject: [PATCH 0809/1263] requested changes use IEquatable instead of overriding Equals and `==` operator for primitive types. --- osu.Game/Beatmaps/BeatmapMetadata.cs | 31 ++++++++++++++-------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapMetadata.cs b/osu.Game/Beatmaps/BeatmapMetadata.cs index 2cd8e2669f..22a64820bc 100644 --- a/osu.Game/Beatmaps/BeatmapMetadata.cs +++ b/osu.Game/Beatmaps/BeatmapMetadata.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.ComponentModel.DataAnnotations.Schema; using System.Linq; @@ -9,7 +10,7 @@ using osu.Game.Users; namespace osu.Game.Beatmaps { - public class BeatmapMetadata + public class BeatmapMetadata : IEquatable { [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int ID { get; set; } @@ -67,22 +68,22 @@ namespace osu.Game.Beatmaps Tags }.Where(s => !string.IsNullOrEmpty(s)).ToArray(); - public override bool Equals(object other) + public bool Equals(BeatmapMetadata other) { - var otherMetadata = other as BeatmapMetadata; - if (otherMetadata == null) return false; + if (other == null) + return false; - return (onlineBeatmapSetID?.Equals(otherMetadata.onlineBeatmapSetID) ?? false) - && (Title?.Equals(otherMetadata.Title) ?? false) - && (TitleUnicode?.Equals(otherMetadata.TitleUnicode) ?? false) - && (Artist?.Equals(otherMetadata.Artist) ?? false) - && (ArtistUnicode?.Equals(otherMetadata.ArtistUnicode) ?? false) - && (AuthorString?.Equals(otherMetadata.AuthorString) ?? false) - && (Source?.Equals(otherMetadata.Source) ?? false) - && (Tags?.Equals(otherMetadata.Tags) ?? false) - && PreviewTime.Equals(otherMetadata.PreviewTime) - && (AudioFile?.Equals(otherMetadata.AudioFile) ?? false) - && (BackgroundFile?.Equals(otherMetadata.BackgroundFile) ?? false); + return onlineBeatmapSetID == other.onlineBeatmapSetID + && (Title?.Equals(other.Title) ?? false) + && (TitleUnicode?.Equals(other.TitleUnicode) ?? false) + && (Artist?.Equals(other.Artist) ?? false) + && (ArtistUnicode?.Equals(other.ArtistUnicode) ?? false) + && (AuthorString?.Equals(other.AuthorString) ?? false) + && (Source?.Equals(other.Source) ?? false) + && (Tags?.Equals(other.Tags) ?? false) + && PreviewTime == other.PreviewTime + && (AudioFile?.Equals(other.AudioFile) ?? false) + && (BackgroundFile?.Equals(other.BackgroundFile) ?? false); } } } From 0b3f75505ef530a9960fec3f816b7f40cbaaf474 Mon Sep 17 00:00:00 2001 From: Unknown Date: Sat, 25 Nov 2017 20:59:03 +0530 Subject: [PATCH 0810/1263] Don't break VisualTests and add a real beatmap step. --- osu.Game.Tests/Visual/TestCaseLeaderboard.cs | 65 ++++++++++++++++--- .../Select/Leaderboards/Leaderboard.cs | 6 +- 2 files changed, 60 insertions(+), 11 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCaseLeaderboard.cs b/osu.Game.Tests/Visual/TestCaseLeaderboard.cs index 9d6fb3a4ec..ad4aa63aa8 100644 --- a/osu.Game.Tests/Visual/TestCaseLeaderboard.cs +++ b/osu.Game.Tests/Visual/TestCaseLeaderboard.cs @@ -6,15 +6,43 @@ using osu.Framework.Graphics; using osu.Game.Rulesets.Scoring; using osu.Game.Screens.Select.Leaderboards; using osu.Game.Users; +using osu.Framework.Allocation; using OpenTK; +using System.Linq; +using osu.Game.Beatmaps; +using osu.Game.Rulesets; namespace osu.Game.Tests.Visual { [Description("PlaySongSelect leaderboard")] internal class TestCaseLeaderboard : OsuTestCase { + private RulesetStore rulesets; + private readonly Leaderboard leaderboard; + public TestCaseLeaderboard() + { + Add(leaderboard = new Leaderboard + { + Origin = Anchor.Centre, + Anchor = Anchor.Centre, + Size = new Vector2(550f, 450f), + Scope = LeaderboardScope.Global, + }); + + AddStep(@"New Scores", newScores); + AddStep(@"Empty Scores", () => leaderboard.Scores = Enumerable.Empty()); + AddStep(@"Real beatmap", realBeatmap); + newScores(); + } + + [BackgroundDependencyLoader] + private void load(RulesetStore rulesets) + { + this.rulesets = rulesets; + } + private void newScores() { var scores = new[] @@ -204,17 +232,36 @@ namespace osu.Game.Tests.Visual leaderboard.Scores = scores; } - public TestCaseLeaderboard() + private void realBeatmap() { - Add(leaderboard = new Leaderboard + leaderboard.Beatmap = new BeatmapInfo { - Origin = Anchor.Centre, - Anchor = Anchor.Centre, - Size = new Vector2(550f, 450f), - }); - - AddStep(@"New Scores", newScores); - newScores(); + StarDifficulty = 1.36, + Version = @"BASIC", + OnlineBeatmapID = 1113057, + Ruleset = rulesets.GetRuleset(0), + BaseDifficulty = new BeatmapDifficulty + { + CircleSize = 4, + DrainRate = 6.5f, + OverallDifficulty = 6.5f, + ApproachRate = 5, + }, + OnlineInfo = new BeatmapOnlineInfo + { + Length = 115000, + CircleCount = 265, + SliderCount = 71, + PlayCount = 47906, + PassCount = 19899, + }, + Metrics = new BeatmapMetrics + { + Ratings = Enumerable.Range(0, 11), + Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6), + Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6), + }, + }; } } } diff --git a/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs b/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs index b25479704c..824a54d372 100644 --- a/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs +++ b/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs @@ -51,6 +51,7 @@ namespace osu.Game.Screens.Select.Leaderboards noResultsPlaceholder.FadeOut(fade_duration); scrollFlow?.FadeOut(fade_duration).Expire(); + scrollContainer.Clear(true); // scores stick around in scrollFlow in VisualTests without this for some reason scrollFlow = null; loading.Hide(); @@ -204,7 +205,8 @@ namespace osu.Game.Screens.Select.Leaderboards this.api = api; this.osuGame = osuGame; - osuGame.Ruleset.ValueChanged += r => updateScores(); + if (osuGame != null) + osuGame.Ruleset.ValueChanged += r => updateScores(); } private GetScoresRequest getScoresRequest; @@ -228,7 +230,7 @@ namespace osu.Game.Screens.Select.Leaderboards loading.Show(); - getScoresRequest = new GetScoresRequest(Beatmap, osuGame.Ruleset.Value, Scope); + getScoresRequest = new GetScoresRequest(Beatmap, osuGame?.Ruleset.Value, Scope); getScoresRequest.Success += r => { Scores = r.Scores; From ae9ce2f122fa29a65dee21db065a532201141f7e Mon Sep 17 00:00:00 2001 From: Unknown Date: Sat, 25 Nov 2017 21:23:36 +0530 Subject: [PATCH 0811/1263] Unbind ruleset event from leaderboard. --- osu.Game/Screens/Select/Leaderboards/Leaderboard.cs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs b/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs index 824a54d372..3bea1d4bfd 100644 --- a/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs +++ b/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs @@ -22,6 +22,7 @@ using osu.Game.Graphics.Sprites; using osu.Game.Graphics; using osu.Framework.Logging; using System.Net; +using osu.Game.Rulesets; namespace osu.Game.Screens.Select.Leaderboards { @@ -206,11 +207,21 @@ namespace osu.Game.Screens.Select.Leaderboards this.osuGame = osuGame; if (osuGame != null) - osuGame.Ruleset.ValueChanged += r => updateScores(); + osuGame.Ruleset.ValueChanged += handleRulesetChange; + } + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + if (osuGame != null) + osuGame.Ruleset.ValueChanged -= handleRulesetChange; } private GetScoresRequest getScoresRequest; + private void handleRulesetChange(RulesetInfo ruleset) => updateScores(); + private void updateScores() { if (!IsLoaded) return; From 7be55df7904df2c8d75367577afa6e34f7cf76d9 Mon Sep 17 00:00:00 2001 From: Unknown Date: Sat, 25 Nov 2017 19:09:05 +0100 Subject: [PATCH 0812/1263] fix being stuck in gameplay if exit is pressed too fast The reliance on `pauseOverlay.Alpha == 1` created a race condition that, when you pressed Exit while the pauseoverlay is still fading in, could get you stuck in gameplay. The game wants to show the pause overlay but also thinks it's already paused and returns early. --- osu.Game/Screens/Play/PauseContainer.cs | 2 -- osu.Game/Screens/Play/Player.cs | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/osu.Game/Screens/Play/PauseContainer.cs b/osu.Game/Screens/Play/PauseContainer.cs index eed5cd1c20..5f5eeb63a0 100644 --- a/osu.Game/Screens/Play/PauseContainer.cs +++ b/osu.Game/Screens/Play/PauseContainer.cs @@ -22,8 +22,6 @@ namespace osu.Game.Screens.Play { public bool IsPaused { get; private set; } - public bool AllowExit => IsPaused && pauseOverlay.Alpha == 1; - public Func CheckCanPause; private const double pause_cooldown = 1000; diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index a19305778c..55eee5ce7d 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -357,7 +357,7 @@ namespace osu.Game.Screens.Play protected override bool OnExiting(Screen next) { - if (!AllowPause || HasFailed || !ValidForResume || pauseContainer?.AllowExit != false || RulesetContainer?.HasReplayLoaded != false) + if (!AllowPause || HasFailed || !ValidForResume || pauseContainer?.IsPaused != false || RulesetContainer?.HasReplayLoaded != false) { // In the case of replays, we may have changed the playback rate. applyRateFromMods(); From f4f732ca4381768d5f54508b90fe06683f2bad0c Mon Sep 17 00:00:00 2001 From: Unknown Date: Sun, 26 Nov 2017 11:19:42 +0530 Subject: [PATCH 0813/1263] Remove unnecessary null check and tweak transform a bit. --- .../Online/API/Requests/GetScoresRequest.cs | 31 +++++++++---------- .../Select/Leaderboards/Leaderboard.cs | 8 ++--- 2 files changed, 18 insertions(+), 21 deletions(-) diff --git a/osu.Game/Online/API/Requests/GetScoresRequest.cs b/osu.Game/Online/API/Requests/GetScoresRequest.cs index 534a209609..b9db836898 100644 --- a/osu.Game/Online/API/Requests/GetScoresRequest.cs +++ b/osu.Game/Online/API/Requests/GetScoresRequest.cs @@ -70,27 +70,24 @@ namespace osu.Game.Online.API.Requests break; } - if (ruleset != null) + switch (ruleset?.Name) { - switch (ruleset.Name) - { - default: - case @"osu!": - req.AddParameter(@"mode", @"osu"); - break; + default: + case @"osu!": + req.AddParameter(@"mode", @"osu"); + break; - case @"osu!taiko": - req.AddParameter(@"mode", @"taiko"); - break; + case @"osu!taiko": + req.AddParameter(@"mode", @"taiko"); + break; - case @"osu!catch": - req.AddParameter(@"mode", @"catch"); - break; + case @"osu!catch": + req.AddParameter(@"mode", @"catch"); + break; - case @"osu!mania": - req.AddParameter(@"mode", @"mania"); - break; - } + case @"osu!mania": + req.AddParameter(@"mode", @"mania"); + break; } return req; diff --git a/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs b/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs index 3bea1d4bfd..ef6ba01393 100644 --- a/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs +++ b/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs @@ -232,6 +232,8 @@ namespace osu.Game.Screens.Select.Leaderboards if (api == null || Beatmap?.OnlineBeatmapID == null) return; + loading.Show(); + if (Scope == LeaderboardScope.Local) { // TODO: get local scores from wherever here. @@ -239,8 +241,6 @@ namespace osu.Game.Screens.Select.Leaderboards return; } - loading.Show(); - getScoresRequest = new GetScoresRequest(Beatmap, osuGame?.Ruleset.Value, Scope); getScoresRequest.Success += r => { @@ -323,13 +323,13 @@ namespace osu.Game.Screens.Select.Leaderboards protected override bool OnMouseDown(Framework.Input.InputState state, Framework.Input.MouseDownEventArgs args) { - icon.ScaleTo(0.8f, 200, Easing.InElastic); + icon.ScaleTo(0.8f, 800, Easing.InElastic); return base.OnMouseDown(state, args); } protected override bool OnMouseUp(Framework.Input.InputState state, Framework.Input.MouseUpEventArgs args) { - icon.ScaleTo(1.2f, 400, Easing.OutElastic).Then().ScaleTo(1f, 400, Easing.OutElastic); + icon.ScaleTo(1.2f, 800, Easing.OutElastic).Then().ScaleTo(1f, 800, Easing.OutElastic); return base.OnMouseUp(state, args); } } From b261d32588887474cd439200a1d371523b680e70 Mon Sep 17 00:00:00 2001 From: Unknown Date: Sun, 26 Nov 2017 12:25:48 +0530 Subject: [PATCH 0814/1263] Put retry button in a BeatSyncedContainer and change error message. --- .../Select/Leaderboards/Leaderboard.cs | 53 ++++++++++++++----- 1 file changed, 40 insertions(+), 13 deletions(-) diff --git a/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs b/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs index ef6ba01393..8ea577d8c0 100644 --- a/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs +++ b/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs @@ -23,6 +23,9 @@ using osu.Game.Graphics; using osu.Framework.Logging; using System.Net; using osu.Game.Rulesets; +using osu.Framework.Input; +using osu.Game.Beatmaps.ControlPoints; +using osu.Framework.Audio.Track; namespace osu.Game.Screens.Select.Leaderboards { @@ -167,7 +170,7 @@ namespace osu.Game.Screens.Select.Leaderboards new OsuSpriteText { Anchor = Anchor.TopLeft, - Text = @"An error occurred!", + Text = @"Couldn't retrieve scores!", TextSize = 22, }, } @@ -289,47 +292,71 @@ namespace osu.Game.Screens.Select.Leaderboards } } - private class RetryButton : ClickableContainer + private class RetryButton : BeatSyncedContainer { private SpriteIcon icon; + public Action Action; + public RetryButton() { Height = 26; Width = 26; - Children = new Drawable[] + Child = new ClickableContainer { - icon = new SpriteIcon + AutoSizeAxes = Axes.Both, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Action = () => Action?.Invoke(), + Child = icon = new SpriteIcon { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, Icon = FontAwesome.fa_refresh, Size = new Vector2(26), - } + }, }; } - protected override bool OnHover(Framework.Input.InputState state) + private bool rightWard; + + protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, TrackAmplitudes amplitudes) + { + var duration = timingPoint.BeatLength / 2; + + icon.RotateTo(rightWard ? 3 : -3, duration * 2, Easing.OutCubic); + icon.Animate( + i => i.MoveToY(-3, duration, Easing.Out), + i => i.ScaleTo(IsHovered ? 1.3f : 1.1f, duration, Easing.Out) + ).Then( + i => i.MoveToY(0, duration, Easing.In), + i => i.ScaleTo(IsHovered ? 1.4f : 1f, duration, Easing.In) + ); + + rightWard = !rightWard; + } + + protected override bool OnHover(InputState state) { icon.ScaleTo(1.4f, 400, Easing.OutQuint); return base.OnHover(state); } - protected override void OnHoverLost(Framework.Input.InputState state) + protected override void OnHoverLost(InputState state) { + icon.ClearTransforms(); icon.ScaleTo(1f, 400, Easing.OutQuint); base.OnHoverLost(state); } - protected override bool OnMouseDown(Framework.Input.InputState state, Framework.Input.MouseDownEventArgs args) + protected override bool OnMouseDown(InputState state, MouseDownEventArgs args) { - icon.ScaleTo(0.8f, 800, Easing.InElastic); + icon.ClearTransforms(); + icon.ScaleTo(0.8f, 400, Easing.InElastic); return base.OnMouseDown(state, args); } - protected override bool OnMouseUp(Framework.Input.InputState state, Framework.Input.MouseUpEventArgs args) + protected override bool OnMouseUp(InputState state, MouseUpEventArgs args) { - icon.ScaleTo(1.2f, 800, Easing.OutElastic).Then().ScaleTo(1f, 800, Easing.OutElastic); + icon.ScaleTo(1.2f, 400, Easing.OutElastic).Then().ScaleTo(1f, 400, Easing.OutElastic); return base.OnMouseUp(state, args); } } From 421231550496456baebdbc345f0c8fe97a0bf61d Mon Sep 17 00:00:00 2001 From: Unknown Date: Sun, 26 Nov 2017 12:50:20 +0530 Subject: [PATCH 0815/1263] Use a single placeholder container for empty and retry. --- .../Select/Leaderboards/Leaderboard.cs | 97 +++++++++---------- 1 file changed, 45 insertions(+), 52 deletions(-) diff --git a/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs b/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs index 8ea577d8c0..31e79022c3 100644 --- a/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs +++ b/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs @@ -35,8 +35,8 @@ namespace osu.Game.Screens.Select.Leaderboards private readonly ScrollContainer scrollContainer; private FillFlowContainer scrollFlow; - private Container noResultsPlaceholder; - private Container retryPlaceholder; + private Container placeholderContainer; + private FillFlowContainer placeholderFlow; public Action ScoreSelected; @@ -53,7 +53,7 @@ namespace osu.Game.Screens.Select.Leaderboards getScoresRequest?.Cancel(); getScoresRequest = null; - noResultsPlaceholder.FadeOut(fade_duration); + placeholderContainer.FadeOut(fade_duration); scrollFlow?.FadeOut(fade_duration).Expire(); scrollContainer.Clear(true); // scores stick around in scrollFlow in VisualTests without this for some reason scrollFlow = null; @@ -65,7 +65,22 @@ namespace osu.Game.Screens.Select.Leaderboards if (scores.Count() == 0) { - noResultsPlaceholder.FadeIn(fade_duration); + placeholderFlow.Children = new Drawable[] + { + new SpriteIcon + { + Icon = FontAwesome.fa_exclamation_circle, + Size = new Vector2(26), + Margin = new MarginPadding { Right = 10 }, + }, + new OsuSpriteText + { + Text = @"No records yet!", + TextSize = 22, + }, + }; + + placeholderContainer.FadeIn(fade_duration); return; } @@ -119,61 +134,18 @@ namespace osu.Game.Screens.Select.Leaderboards ScrollbarVisible = false, }, loading = new LoadingAnimation(), - noResultsPlaceholder = new Container + placeholderContainer = new Container { Alpha = 0, RelativeSizeAxes = Axes.Both, Children = new Drawable[] { - new FillFlowContainer + placeholderFlow = new FillFlowContainer { Direction = FillDirection.Horizontal, Anchor = Anchor.Centre, Origin = Anchor.Centre, AutoSizeAxes = Axes.Both, - Children = new Drawable[] - { - new SpriteIcon - { - Icon = FontAwesome.fa_exclamation_circle, - Size = new Vector2(26), - Margin = new MarginPadding { Right = 10 }, - }, - new OsuSpriteText - { - Text = @"No records yet!", - TextSize = 22, - }, - } - }, - }, - }, - retryPlaceholder = new Container - { - Alpha = 0, - RelativeSizeAxes = Axes.Both, - Children = new Drawable[] - { - new FillFlowContainer - { - Direction = FillDirection.Horizontal, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - AutoSizeAxes = Axes.Both, - Children = new Drawable[] - { - new RetryButton - { - Action = updateScores, - Margin = new MarginPadding { Right = 10 }, - }, - new OsuSpriteText - { - Anchor = Anchor.TopLeft, - Text = @"Couldn't retrieve scores!", - TextSize = 22, - }, - } }, }, }, @@ -229,8 +201,6 @@ namespace osu.Game.Screens.Select.Leaderboards { if (!IsLoaded) return; - retryPlaceholder.FadeOut(fade_duration); - Scores = null; if (api == null || Beatmap?.OnlineBeatmapID == null) return; @@ -255,7 +225,21 @@ namespace osu.Game.Screens.Select.Leaderboards if (e is WebException) { Scores = null; - retryPlaceholder.FadeIn(fade_duration); + placeholderFlow.Children = new Drawable[] + { + new RetryButton + { + Action = updateScores, + Margin = new MarginPadding { Right = 10 }, + }, + new OsuSpriteText + { + Anchor = Anchor.TopLeft, + Text = @"Couldn't retrieve scores!", + TextSize = 22, + }, + }; + placeholderContainer.FadeIn(fade_duration); Logger.Error(e, @"Couldn't fetch beatmap scores!"); } }; @@ -298,6 +282,8 @@ namespace osu.Game.Screens.Select.Leaderboards public Action Action; + private OsuColour colours; + public RetryButton() { Height = 26; @@ -316,6 +302,12 @@ namespace osu.Game.Screens.Select.Leaderboards }; } + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + this.colours = colours; + } + private bool rightWard; protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, TrackAmplitudes amplitudes) @@ -350,6 +342,7 @@ namespace osu.Game.Screens.Select.Leaderboards protected override bool OnMouseDown(InputState state, MouseDownEventArgs args) { icon.ClearTransforms(); + icon.FlashColour(colours.Yellow, 400); icon.ScaleTo(0.8f, 400, Easing.InElastic); return base.OnMouseDown(state, args); } From 69e388dd52a5ab0d25ce62b7397caf14811c51bf Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 26 Nov 2017 05:08:20 +0900 Subject: [PATCH 0816/1263] Adjust background blur rate --- osu.Game/Screens/Play/Player.cs | 2 +- osu.Game/Screens/Select/SongSelect.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index a19305778c..e27b76e458 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -310,7 +310,7 @@ namespace osu.Game.Screens.Play if (!loadedSuccessfully) return; - (Background as BackgroundScreenBeatmap)?.BlurTo(Vector2.Zero, 1500, Easing.OutQuint); + (Background as BackgroundScreenBeatmap)?.BlurTo(Vector2.Zero, 1000, Easing.OutQuint); dimLevel.ValueChanged += dimLevel_ValueChanged; showStoryboard.ValueChanged += showStoryboard_ValueChanged; diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 24a7b3db90..68437180ac 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -413,7 +413,7 @@ namespace osu.Game.Screens.Select if (backgroundModeBeatmap != null) { backgroundModeBeatmap.Beatmap = beatmap; - backgroundModeBeatmap.BlurTo(background_blur, 1000); + backgroundModeBeatmap.BlurTo(background_blur, 750, Easing.OutQuint); backgroundModeBeatmap.FadeTo(1, 250); } From df16a019ed13e07e1de9ed0c480be55a90717e8b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 26 Nov 2017 17:07:35 +0900 Subject: [PATCH 0817/1263] Add a global reduction of audio track volume Music is overpowering compared to our current game samples. We will need to do further adjustments on this, but for now let's reduce the track volume globally. --- osu.Game/OsuGameBase.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 50639e3427..8eaa20f781 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -5,6 +5,7 @@ using System; using System.Diagnostics; using System.Reflection; using osu.Framework.Allocation; +using osu.Framework.Audio; using osu.Framework.Configuration; using osu.Framework.Development; using osu.Framework.Graphics; @@ -137,6 +138,10 @@ namespace osu.Game Beatmap = new NonNullableBindable(defaultBeatmap); BeatmapManager.DefaultBeatmap = defaultBeatmap; + // tracks play so loud our samples can't keep up. + // this adds a global reduction of track volume for the time being. + Audio.Track.AddAdjustment(AdjustableProperty.Volume, new BindableDouble(0.8)); + Beatmap.ValueChanged += b => { var trackLoaded = lastBeatmap?.TrackLoaded ?? false; From 7cdb8305304969e7d1ae741400428e71c24a5b8f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 25 Nov 2017 23:05:28 +0900 Subject: [PATCH 0818/1263] Fix broken app.config default --- osu.Desktop.Deploy/App.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Desktop.Deploy/App.config b/osu.Desktop.Deploy/App.config index 2fae7a5e1c..2fbea810f6 100644 --- a/osu.Desktop.Deploy/App.config +++ b/osu.Desktop.Deploy/App.config @@ -13,7 +13,7 @@ Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/maste - + From 22075ac7c9cf2b1f46f133a983eaf5a4bde06d72 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 25 Nov 2017 23:05:46 +0900 Subject: [PATCH 0819/1263] Ensure deploy script can work without a github token --- osu.Desktop.Deploy/Program.cs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/osu.Desktop.Deploy/Program.cs b/osu.Desktop.Deploy/Program.cs index 54fb50d0f8..e90fb1e567 100644 --- a/osu.Desktop.Deploy/Program.cs +++ b/osu.Desktop.Deploy/Program.cs @@ -145,6 +145,8 @@ namespace osu.Desktop.Deploy /// private static void checkReleaseFiles() { + if (!canGitHub) return; + var releaseLines = getReleaseLines(); //ensure we have all files necessary @@ -157,6 +159,8 @@ namespace osu.Desktop.Deploy private static void pruneReleases() { + if (!canGitHub) return; + write("Pruning RELEASES..."); var releaseLines = getReleaseLines().ToList(); @@ -190,7 +194,7 @@ namespace osu.Desktop.Deploy private static void uploadBuild(string version) { - if (string.IsNullOrEmpty(GitHubAccessToken) || string.IsNullOrEmpty(codeSigningCertPath)) + if (!canGitHub || string.IsNullOrEmpty(CodeSigningCertificate)) return; write("Publishing to GitHub..."); @@ -228,8 +232,12 @@ namespace osu.Desktop.Deploy private static void openGitHubReleasePage() => Process.Start(GitHubReleasePage); + private static bool canGitHub => !string.IsNullOrEmpty(GitHubAccessToken); + private static void checkGitHubReleases() { + if (!canGitHub) return; + write("Checking GitHub releases..."); var req = new JsonWebRequest>($"{GitHubApiEndpoint}"); req.AuthenticatedBlockingPerform(); From 4067b6129b8e8b557e478a8a20f280f63299e1c8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 26 Nov 2017 04:16:36 +0900 Subject: [PATCH 0820/1263] Add visual highlighting on song select panel hover Prerequisite for adding hover sound effects. Didn't feel right without this change. --- osu.Game/Beatmaps/Drawables/Panel.cs | 52 ++++++++++++++++++++++++---- 1 file changed, 46 insertions(+), 6 deletions(-) diff --git a/osu.Game/Beatmaps/Drawables/Panel.cs b/osu.Game/Beatmaps/Drawables/Panel.cs index d6ed306b39..5fbc858b00 100644 --- a/osu.Game/Beatmaps/Drawables/Panel.cs +++ b/osu.Game/Beatmaps/Drawables/Panel.cs @@ -3,12 +3,15 @@ using System; using osu.Framework; +using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Input; using OpenTK; using OpenTK.Graphics; using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics.Shapes; +using osu.Game.Graphics; namespace osu.Game.Beatmaps.Drawables { @@ -22,6 +25,10 @@ namespace osu.Game.Beatmaps.Drawables private readonly Container nestedContainer; + private readonly Container borderContainer; + + private readonly Box hoverLayer; + protected override Container Content => nestedContainer; protected Panel() @@ -29,20 +36,53 @@ namespace osu.Game.Beatmaps.Drawables Height = MAX_HEIGHT; RelativeSizeAxes = Axes.X; - AddInternal(nestedContainer = new Container + AddInternal(borderContainer = new Container { RelativeSizeAxes = Axes.Both, Masking = true, CornerRadius = 10, BorderColour = new Color4(221, 255, 255, 255), + Children = new Drawable[] + { + nestedContainer = new Container + { + RelativeSizeAxes = Axes.Both, + }, + hoverLayer = new Box + { + RelativeSizeAxes = Axes.Both, + Alpha = 0, + Blending = new BlendingParameters { Mode = BlendingMode.Additive }, + }, + } }); Alpha = 0; } + + protected override bool OnHover(InputState state) + { + hoverLayer.FadeIn(100, Easing.OutQuint); + + return base.OnHover(state); + } + + protected override void OnHoverLost(InputState state) + { + hoverLayer.FadeOut(1000, Easing.OutQuint); + base.OnHoverLost(state); + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + hoverLayer.Colour = colours.Blue.Opacity(0.1f); + } + public void SetMultiplicativeAlpha(float alpha) { - nestedContainer.Alpha = alpha; + borderContainer.Alpha = alpha; } protected override void LoadComplete() @@ -94,8 +134,8 @@ namespace osu.Game.Beatmaps.Drawables protected virtual void Selected() { - nestedContainer.BorderThickness = 2.5f; - nestedContainer.EdgeEffect = new EdgeEffectParameters + borderContainer.BorderThickness = 2.5f; + borderContainer.EdgeEffect = new EdgeEffectParameters { Type = EdgeEffectType.Glow, Colour = new Color4(130, 204, 255, 150), @@ -106,8 +146,8 @@ namespace osu.Game.Beatmaps.Drawables protected virtual void Deselected() { - nestedContainer.BorderThickness = 0; - nestedContainer.EdgeEffect = new EdgeEffectParameters + borderContainer.BorderThickness = 0; + borderContainer.EdgeEffect = new EdgeEffectParameters { Type = EdgeEffectType.Shadow, Offset = new Vector2(1), From 07d6a700286e489685cbe389993d237309dfbfe1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 25 Nov 2017 23:11:18 +0900 Subject: [PATCH 0821/1263] New sound effects with better names --- .../Graphics/Containers/OsuClickableContainer.cs | 2 +- .../Containers/OsuFocusedOverlayContainer.cs | 4 ++-- osu.Game/Graphics/UserInterface/OsuButton.cs | 2 +- osu.Game/Graphics/UserInterface/OsuMenu.cs | 2 +- osu.Game/Screens/Menu/Button.cs | 2 +- osu.Game/Screens/Menu/ButtonSystem.cs | 14 +++++++------- osu.Game/Screens/Menu/OsuLogo.cs | 4 ++-- osu.Game/Screens/OsuScreen.cs | 2 +- 8 files changed, 16 insertions(+), 16 deletions(-) diff --git a/osu.Game/Graphics/Containers/OsuClickableContainer.cs b/osu.Game/Graphics/Containers/OsuClickableContainer.cs index 11c049ed3e..ce3780cf78 100644 --- a/osu.Game/Graphics/Containers/OsuClickableContainer.cs +++ b/osu.Game/Graphics/Containers/OsuClickableContainer.cs @@ -17,7 +17,7 @@ namespace osu.Game.Graphics.Containers private void load(AudioManager audio) { SampleHover = audio.Sample.Get(@"UI/generic-hover"); - SampleClick = audio.Sample.Get(@"UI/generic-click"); + SampleClick = audio.Sample.Get(@"UI/generic-select"); } protected override bool OnHover(InputState state) diff --git a/osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs b/osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs index 4ea4f4cdc3..c788df3066 100644 --- a/osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs +++ b/osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs @@ -16,8 +16,8 @@ namespace osu.Game.Graphics.Containers [BackgroundDependencyLoader] private void load(AudioManager audio) { - samplePopIn = audio.Sample.Get(@"UI/melodic-5"); - samplePopOut = audio.Sample.Get(@"UI/melodic-4"); + samplePopIn = audio.Sample.Get(@"UI/overlay-pop-in"); + samplePopOut = audio.Sample.Get(@"UI/overlay-pop-out"); StateChanged += onStateChanged; } diff --git a/osu.Game/Graphics/UserInterface/OsuButton.cs b/osu.Game/Graphics/UserInterface/OsuButton.cs index ccc23e3ff6..5bbfab97e5 100644 --- a/osu.Game/Graphics/UserInterface/OsuButton.cs +++ b/osu.Game/Graphics/UserInterface/OsuButton.cs @@ -70,7 +70,7 @@ namespace osu.Game.Graphics.UserInterface }, }); - sampleClick = audio.Sample.Get(@"UI/generic-click"); + sampleClick = audio.Sample.Get(@"UI/generic-select"); sampleHover = audio.Sample.Get(@"UI/generic-hover"); Enabled.ValueChanged += enabled_ValueChanged; diff --git a/osu.Game/Graphics/UserInterface/OsuMenu.cs b/osu.Game/Graphics/UserInterface/OsuMenu.cs index 3fd5481152..7f16d73613 100644 --- a/osu.Game/Graphics/UserInterface/OsuMenu.cs +++ b/osu.Game/Graphics/UserInterface/OsuMenu.cs @@ -72,7 +72,7 @@ namespace osu.Game.Graphics.UserInterface private void load(AudioManager audio) { sampleHover = audio.Sample.Get(@"UI/generic-hover"); - sampleClick = audio.Sample.Get(@"UI/generic-click"); + sampleClick = audio.Sample.Get(@"UI/generic-select"); BackgroundColour = Color4.Transparent; BackgroundColourHover = OsuColour.FromHex(@"172023"); diff --git a/osu.Game/Screens/Menu/Button.cs b/osu.Game/Screens/Menu/Button.cs index ccd61643ce..5e55166c19 100644 --- a/osu.Game/Screens/Menu/Button.cs +++ b/osu.Game/Screens/Menu/Button.cs @@ -174,7 +174,7 @@ namespace osu.Game.Screens.Menu [BackgroundDependencyLoader] private void load(AudioManager audio) { - sampleHover = audio.Sample.Get(@"Menu/hover"); + sampleHover = audio.Sample.Get(@"Menu/button-hover"); if (!string.IsNullOrEmpty(sampleName)) sampleClick = audio.Sample.Get($@"Menu/{sampleName}"); } diff --git a/osu.Game/Screens/Menu/ButtonSystem.cs b/osu.Game/Screens/Menu/ButtonSystem.cs index 5a4a5f07b5..af5df2f8ec 100644 --- a/osu.Game/Screens/Menu/ButtonSystem.cs +++ b/osu.Game/Screens/Menu/ButtonSystem.cs @@ -117,13 +117,13 @@ namespace osu.Game.Screens.Menu }, }; - buttonsPlay.Add(new Button(@"solo", @"select-6", FontAwesome.fa_user, new Color4(102, 68, 204, 255), () => OnSolo?.Invoke(), WEDGE_WIDTH, Key.P)); - buttonsPlay.Add(new Button(@"multi", @"select-5", FontAwesome.fa_users, new Color4(94, 63, 186, 255), () => OnMulti?.Invoke(), 0, Key.M)); - buttonsPlay.Add(new Button(@"chart", @"select-5", FontAwesome.fa_osu_charts, new Color4(80, 53, 160, 255), () => OnChart?.Invoke())); + buttonsPlay.Add(new Button(@"solo", @"button-solo-select", FontAwesome.fa_user, new Color4(102, 68, 204, 255), () => OnSolo?.Invoke(), WEDGE_WIDTH, Key.P)); + buttonsPlay.Add(new Button(@"multi", @"button-generic-select", FontAwesome.fa_users, new Color4(94, 63, 186, 255), () => OnMulti?.Invoke(), 0, Key.M)); + buttonsPlay.Add(new Button(@"chart", @"button-generic-select", FontAwesome.fa_osu_charts, new Color4(80, 53, 160, 255), () => OnChart?.Invoke())); - buttonsTopLevel.Add(new Button(@"play", @"select-1", FontAwesome.fa_osu_logo, new Color4(102, 68, 204, 255), onPlay, WEDGE_WIDTH, Key.P)); - buttonsTopLevel.Add(new Button(@"osu!editor", @"select-5", FontAwesome.fa_osu_edit_o, new Color4(238, 170, 0, 255), () => OnEdit?.Invoke(), 0, Key.E)); - buttonsTopLevel.Add(new Button(@"osu!direct", string.Empty, FontAwesome.fa_osu_chevron_down_o, new Color4(165, 204, 0, 255), () => OnDirect?.Invoke(), 0, Key.D)); + buttonsTopLevel.Add(new Button(@"play", @"button-play-select", FontAwesome.fa_osu_logo, new Color4(102, 68, 204, 255), onPlay, WEDGE_WIDTH, Key.P)); + buttonsTopLevel.Add(new Button(@"osu!editor", @"button-generic-select", FontAwesome.fa_osu_edit_o, new Color4(238, 170, 0, 255), () => OnEdit?.Invoke(), 0, Key.E)); + buttonsTopLevel.Add(new Button(@"osu!direct", @"button-direct-select", FontAwesome.fa_osu_chevron_down_o, new Color4(165, 204, 0, 255), () => OnDirect?.Invoke(), 0, Key.D)); buttonsTopLevel.Add(new Button(@"exit", string.Empty, FontAwesome.fa_osu_cross_o, new Color4(238, 51, 153, 255), onExit, 0, Key.Q)); buttonFlow.AddRange(buttonsPlay); @@ -134,7 +134,7 @@ namespace osu.Game.Screens.Menu private void load(AudioManager audio, OsuGame game = null) { toolbar = game?.Toolbar; - sampleBack = audio.Sample.Get(@"Menu/select-4"); + sampleBack = audio.Sample.Get(@"Menu/button-back-select"); } protected override bool OnKeyDown(InputState state, KeyDownEventArgs args) diff --git a/osu.Game/Screens/Menu/OsuLogo.cs b/osu.Game/Screens/Menu/OsuLogo.cs index 252f2d37b5..2679368099 100644 --- a/osu.Game/Screens/Menu/OsuLogo.cs +++ b/osu.Game/Screens/Menu/OsuLogo.cs @@ -248,8 +248,8 @@ namespace osu.Game.Screens.Menu [BackgroundDependencyLoader] private void load(TextureStore textures, AudioManager audio) { - sampleClick = audio.Sample.Get(@"Menu/select-2"); - sampleBeat = audio.Sample.Get(@"Menu/heartbeat"); + sampleClick = audio.Sample.Get(@"Menu/osu-logo-select"); + sampleBeat = audio.Sample.Get(@"Menu/osu-logo-heartbeat"); logo.Texture = textures.Get(@"Menu/logo"); ripple.Texture = textures.Get(@"Menu/logo"); diff --git a/osu.Game/Screens/OsuScreen.cs b/osu.Game/Screens/OsuScreen.cs index f5ff9ea036..76ee4a607e 100644 --- a/osu.Game/Screens/OsuScreen.cs +++ b/osu.Game/Screens/OsuScreen.cs @@ -70,7 +70,7 @@ namespace osu.Game.Screens if (osuGame != null) Ruleset.BindTo(osuGame.Ruleset); - sampleExit = audio.Sample.Get(@"UI/melodic-1"); + sampleExit = audio.Sample.Get(@"UI/screen-back"); } protected override void OnResuming(Screen last) From ae48b858276d75c0f8b69e784505a0a85598a649 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 25 Nov 2017 23:29:08 +0900 Subject: [PATCH 0822/1263] Don't play logo select sample when actions are playing their own --- osu.Game/Screens/Menu/ButtonSystem.cs | 10 ++++++---- osu.Game/Screens/Menu/OsuLogo.cs | 10 ++++++---- osu.Game/Screens/Select/SongSelect.cs | 6 +++++- 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/osu.Game/Screens/Menu/ButtonSystem.cs b/osu.Game/Screens/Menu/ButtonSystem.cs index af5df2f8ec..ce7856c5a9 100644 --- a/osu.Game/Screens/Menu/ButtonSystem.cs +++ b/osu.Game/Screens/Menu/ButtonSystem.cs @@ -180,19 +180,21 @@ namespace osu.Game.Screens.Menu State = MenuState.TopLevel; } - private void onOsuLogo() + private bool onOsuLogo() { switch (state) { + default: + return true; case MenuState.Initial: State = MenuState.TopLevel; - return; + return true; case MenuState.TopLevel: buttonsTopLevel.First().TriggerOnClick(); - return; + return false; case MenuState.Play: buttonsPlay.First().TriggerOnClick(); - return; + return false; } } diff --git a/osu.Game/Screens/Menu/OsuLogo.cs b/osu.Game/Screens/Menu/OsuLogo.cs index 2679368099..9ca12702e5 100644 --- a/osu.Game/Screens/Menu/OsuLogo.cs +++ b/osu.Game/Screens/Menu/OsuLogo.cs @@ -48,7 +48,10 @@ namespace osu.Game.Screens.Menu private readonly Triangles triangles; - public Action Action; + /// + /// Return value decides whether the logo should play its own sample for the click action. + /// + public Func Action; public float SizeForFlow => logo == null ? 0 : logo.DrawSize.X * logo.Scale.X * logoBounceContainer.Scale.X * logoHoverContainer.Scale.X * 0.74f; @@ -354,13 +357,12 @@ namespace osu.Game.Screens.Menu { if (!interactive) return false; - sampleClick.Play(); + if (Action?.Invoke() ?? true) + sampleClick.Play(); flashLayer.ClearTransforms(); flashLayer.Alpha = 0.4f; flashLayer.FadeOut(1500, Easing.OutExpo); - - Action?.Invoke(); return true; } diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 24a7b3db90..fcf459182f 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -332,7 +332,11 @@ namespace osu.Game.Screens.Select logo.FadeIn(logo_transition, Easing.OutQuint); logo.ScaleTo(0.4f, logo_transition, Easing.OutQuint); - logo.Action = () => carouselRaisedStart(); + logo.Action = () => + { + carouselRaisedStart(); + return true; + }; } protected override void LogoExiting(OsuLogo logo) From af499df6ddfdb7fdee0fa836a00614d37104f080 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 26 Nov 2017 01:52:52 +0900 Subject: [PATCH 0823/1263] Make a base OsuButton class to handle default samples --- .../Visual/TestCaseReplaySettingsOverlay.cs | 2 +- osu.Game/Graphics/UserInterface/OsuButton.cs | 103 ++-------------- .../Graphics/UserInterface/TriangleButton.cs | 111 ++++++++++++++++++ .../KeyBinding/KeyBindingsSubsection.cs | 2 +- .../Sections/Maintenance/GeneralSettings.cs | 6 +- osu.Game/Overlays/Settings/SettingsButton.cs | 2 +- osu.Game/Screens/Tournament/Drawings.cs | 8 +- osu.Game/osu.Game.csproj | 3 +- 8 files changed, 131 insertions(+), 106 deletions(-) create mode 100644 osu.Game/Graphics/UserInterface/TriangleButton.cs diff --git a/osu.Game.Tests/Visual/TestCaseReplaySettingsOverlay.cs b/osu.Game.Tests/Visual/TestCaseReplaySettingsOverlay.cs index 22a2d717e4..badb98e6b7 100644 --- a/osu.Game.Tests/Visual/TestCaseReplaySettingsOverlay.cs +++ b/osu.Game.Tests/Visual/TestCaseReplaySettingsOverlay.cs @@ -22,7 +22,7 @@ namespace osu.Game.Tests.Visual Add(container = new ExampleContainer()); - AddStep(@"Add button", () => container.Add(new OsuButton + AddStep(@"Add button", () => container.Add(new TriangleButton { RelativeSizeAxes = Axes.X, Text = @"Button", diff --git a/osu.Game/Graphics/UserInterface/OsuButton.cs b/osu.Game/Graphics/UserInterface/OsuButton.cs index 5bbfab97e5..884a3037a5 100644 --- a/osu.Game/Graphics/UserInterface/OsuButton.cs +++ b/osu.Game/Graphics/UserInterface/OsuButton.cs @@ -1,87 +1,22 @@ // 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 OpenTK.Graphics; using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Audio.Sample; -using osu.Framework.Extensions.Color4Extensions; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; -using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.UserInterface; using osu.Framework.Input; -using osu.Game.Graphics.Backgrounds; -using osu.Game.Graphics.Sprites; namespace osu.Game.Graphics.UserInterface { - public class OsuButton : Button, IFilterable + /// + /// A button with added default sound effects. + /// + public class OsuButton : Button { - private Box hover; - private SampleChannel sampleClick; private SampleChannel sampleHover; - protected Triangles Triangles; - - public OsuButton() - { - Height = 40; - } - - protected override SpriteText CreateText() => new OsuSpriteText - { - Depth = -1, - Origin = Anchor.Centre, - Anchor = Anchor.Centre, - Font = @"Exo2.0-Bold", - }; - - public override bool HandleInput => Action != null; - - [BackgroundDependencyLoader] - private void load(OsuColour colours, AudioManager audio) - { - if (Action == null) - Colour = OsuColour.Gray(0.5f); - - BackgroundColour = colours.BlueDark; - - Content.Masking = true; - Content.CornerRadius = 5; - - AddRange(new Drawable[] - { - Triangles = new Triangles - { - RelativeSizeAxes = Axes.Both, - ColourDark = colours.BlueDarker, - ColourLight = colours.Blue, - }, - hover = new Box - { - RelativeSizeAxes = Axes.Both, - Blending = BlendingMode.Additive, - Colour = Color4.White.Opacity(0.1f), - Alpha = 0, - }, - }); - - sampleClick = audio.Sample.Get(@"UI/generic-select"); - sampleHover = audio.Sample.Get(@"UI/generic-hover"); - - Enabled.ValueChanged += enabled_ValueChanged; - Enabled.TriggerChange(); - } - - private void enabled_ValueChanged(bool enabled) - { - this.FadeColour(enabled ? Color4.White : Color4.Gray, 200, Easing.OutQuint); - } - protected override bool OnClick(InputState state) { sampleClick?.Play(); @@ -91,36 +26,14 @@ namespace osu.Game.Graphics.UserInterface protected override bool OnHover(InputState state) { sampleHover?.Play(); - hover.FadeIn(200); return base.OnHover(state); } - protected override void OnHoverLost(InputState state) + [BackgroundDependencyLoader] + private void load(OsuColour colours, AudioManager audio) { - hover.FadeOut(200); - base.OnHoverLost(state); - } - - protected override bool OnMouseDown(InputState state, MouseDownEventArgs args) - { - Content.ScaleTo(0.9f, 4000, Easing.OutQuint); - return base.OnMouseDown(state, args); - } - - protected override bool OnMouseUp(InputState state, MouseUpEventArgs args) - { - Content.ScaleTo(1, 1000, Easing.OutElastic); - return base.OnMouseUp(state, args); - } - - public IEnumerable FilterTerms => new[] { Text }; - - public bool MatchingFilter - { - set - { - this.FadeTo(value ? 1 : 0); - } + sampleClick = audio.Sample.Get(@"UI/generic-select"); + sampleHover = audio.Sample.Get(@"UI/generic-hover"); } } } diff --git a/osu.Game/Graphics/UserInterface/TriangleButton.cs b/osu.Game/Graphics/UserInterface/TriangleButton.cs new file mode 100644 index 0000000000..33a8a8f99b --- /dev/null +++ b/osu.Game/Graphics/UserInterface/TriangleButton.cs @@ -0,0 +1,111 @@ +// 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 OpenTK.Graphics; +using osu.Framework.Allocation; +using osu.Framework.Audio; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Input; +using osu.Game.Graphics.Backgrounds; +using osu.Game.Graphics.Sprites; + +namespace osu.Game.Graphics.UserInterface +{ + public class TriangleButton : OsuButton, IFilterable + { + private Box hover; + + protected Triangles Triangles; + + public TriangleButton() + { + Height = 40; + } + + protected override SpriteText CreateText() => new OsuSpriteText + { + Depth = -1, + Origin = Anchor.Centre, + Anchor = Anchor.Centre, + Font = @"Exo2.0-Bold", + }; + + public override bool HandleInput => Action != null; + + [BackgroundDependencyLoader] + private void load(OsuColour colours, AudioManager audio) + { + if (Action == null) + Colour = OsuColour.Gray(0.5f); + + BackgroundColour = colours.BlueDark; + + Content.Masking = true; + Content.CornerRadius = 5; + + AddRange(new Drawable[] + { + Triangles = new Triangles + { + RelativeSizeAxes = Axes.Both, + ColourDark = colours.BlueDarker, + ColourLight = colours.Blue, + }, + hover = new Box + { + RelativeSizeAxes = Axes.Both, + Blending = BlendingMode.Additive, + Colour = Color4.White.Opacity(0.1f), + Alpha = 0, + }, + }); + + Enabled.ValueChanged += enabled_ValueChanged; + Enabled.TriggerChange(); + } + + private void enabled_ValueChanged(bool enabled) + { + this.FadeColour(enabled ? Color4.White : Color4.Gray, 200, Easing.OutQuint); + } + + protected override bool OnHover(InputState state) + { + hover.FadeIn(200); + return base.OnHover(state); + } + + protected override void OnHoverLost(InputState state) + { + hover.FadeOut(200); + base.OnHoverLost(state); + } + + protected override bool OnMouseDown(InputState state, MouseDownEventArgs args) + { + Content.ScaleTo(0.9f, 4000, Easing.OutQuint); + return base.OnMouseDown(state, args); + } + + protected override bool OnMouseUp(InputState state, MouseUpEventArgs args) + { + Content.ScaleTo(1, 1000, Easing.OutElastic); + return base.OnMouseUp(state, args); + } + + public IEnumerable FilterTerms => new[] { Text }; + + public bool MatchingFilter + { + set + { + this.FadeTo(value ? 1 : 0); + } + } + } +} diff --git a/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs b/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs index 30ff0ab026..c670cc0153 100644 --- a/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs +++ b/osu.Game/Overlays/KeyBinding/KeyBindingsSubsection.cs @@ -55,7 +55,7 @@ namespace osu.Game.Overlays.KeyBinding } } - public class ResetButton : OsuButton + public class ResetButton : TriangleButton { [BackgroundDependencyLoader] private void load(OsuColour colours) diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs index 4c82a9ae4b..4f4f381ae1 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs @@ -12,9 +12,9 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance { public class GeneralSettings : SettingsSubsection { - private OsuButton importButton; - private OsuButton deleteButton; - private OsuButton restoreButton; + private TriangleButton importButton; + private TriangleButton deleteButton; + private TriangleButton restoreButton; protected override string Header => "General"; diff --git a/osu.Game/Overlays/Settings/SettingsButton.cs b/osu.Game/Overlays/Settings/SettingsButton.cs index 5320cef850..19493f6c70 100644 --- a/osu.Game/Overlays/Settings/SettingsButton.cs +++ b/osu.Game/Overlays/Settings/SettingsButton.cs @@ -6,7 +6,7 @@ using osu.Game.Graphics.UserInterface; namespace osu.Game.Overlays.Settings { - public class SettingsButton : OsuButton + public class SettingsButton : TriangleButton { public SettingsButton() { diff --git a/osu.Game/Screens/Tournament/Drawings.cs b/osu.Game/Screens/Tournament/Drawings.cs index e540782fc1..3e7ab56c99 100644 --- a/osu.Game/Screens/Tournament/Drawings.cs +++ b/osu.Game/Screens/Tournament/Drawings.cs @@ -193,21 +193,21 @@ namespace osu.Game.Screens.Tournament Children = new Drawable[] { - new OsuButton + new TriangleButton { RelativeSizeAxes = Axes.X, Text = "Begin random", Action = teamsContainer.StartScrolling, }, - new OsuButton + new TriangleButton { RelativeSizeAxes = Axes.X, Text = "Stop random", Action = teamsContainer.StopScrolling, }, - new OsuButton + new TriangleButton { RelativeSizeAxes = Axes.X, @@ -232,7 +232,7 @@ namespace osu.Game.Screens.Tournament Children = new Drawable[] { - new OsuButton + new TriangleButton { RelativeSizeAxes = Axes.X, diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 2aefde2916..a26ad963cf 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -271,6 +271,7 @@ + 20171019041408_InitialCreate.cs @@ -366,7 +367,7 @@ - + From 8d7c891882532151187f8b600d9281736cc5bb08 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 26 Nov 2017 01:53:03 +0900 Subject: [PATCH 0824/1263] Add hover and click sound effects to settings sidebar buttons --- osu.Game/Overlays/Settings/SidebarButton.cs | 28 +++++++++------------ 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/osu.Game/Overlays/Settings/SidebarButton.cs b/osu.Game/Overlays/Settings/SidebarButton.cs index b39c8ab7cf..4b8366f0fc 100644 --- a/osu.Game/Overlays/Settings/SidebarButton.cs +++ b/osu.Game/Overlays/Settings/SidebarButton.cs @@ -12,14 +12,14 @@ using osu.Framework.Graphics.Sprites; using osu.Framework.Input; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; +using osu.Game.Graphics.UserInterface; namespace osu.Game.Overlays.Settings { - public class SidebarButton : Container + public class SidebarButton : OsuButton { private readonly SpriteIcon drawableIcon; private readonly SpriteText headerText; - private readonly Box backgroundBox; private readonly Box selectionIndicator; private readonly Container text; public Action Action; @@ -61,17 +61,14 @@ namespace osu.Game.Overlays.Settings public SidebarButton() { + BackgroundColour = OsuColour.Gray(60); + Background.Alpha = 0; + Height = Sidebar.DEFAULT_WIDTH; RelativeSizeAxes = Axes.X; - Children = new Drawable[] + + AddRange(new Drawable[] { - backgroundBox = new Box - { - RelativeSizeAxes = Axes.Both, - Blending = BlendingMode.Additive, - Colour = OsuColour.Gray(60), - Alpha = 0, - }, text = new Container { Width = Sidebar.DEFAULT_WIDTH, @@ -101,7 +98,7 @@ namespace osu.Game.Overlays.Settings Anchor = Anchor.CentreRight, Origin = Anchor.CentreRight, } - }; + }); } [BackgroundDependencyLoader] @@ -113,20 +110,19 @@ namespace osu.Game.Overlays.Settings protected override bool OnClick(InputState state) { Action?.Invoke(section); - backgroundBox.FlashColour(Color4.White, 400); - return true; + return base.OnClick(state); } protected override bool OnHover(InputState state) { - backgroundBox.FadeTo(0.4f, 200); + Background.FadeTo(0.4f, 200); return base.OnHover(state); } protected override void OnHoverLost(InputState state) { - backgroundBox.FadeTo(0, 200); + Background.FadeTo(0, 200); base.OnHoverLost(state); } } -} \ No newline at end of file +} From 8f57bf2498f628b0b751390714e4554faeb7617b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 26 Nov 2017 02:10:25 +0900 Subject: [PATCH 0825/1263] Add choices of hover sample sets --- osu.Game/Graphics/UserInterface/OsuButton.cs | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/OsuButton.cs b/osu.Game/Graphics/UserInterface/OsuButton.cs index 884a3037a5..3b2377c06b 100644 --- a/osu.Game/Graphics/UserInterface/OsuButton.cs +++ b/osu.Game/Graphics/UserInterface/OsuButton.cs @@ -1,9 +1,11 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System.ComponentModel; using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Audio.Sample; +using osu.Framework.Extensions; using osu.Framework.Graphics.UserInterface; using osu.Framework.Input; @@ -17,6 +19,8 @@ namespace osu.Game.Graphics.UserInterface private SampleChannel sampleClick; private SampleChannel sampleHover; + protected HoverSampleSet SampleSet = HoverSampleSet.Normal; + protected override bool OnClick(InputState state) { sampleClick?.Play(); @@ -30,10 +34,20 @@ namespace osu.Game.Graphics.UserInterface } [BackgroundDependencyLoader] - private void load(OsuColour colours, AudioManager audio) + private void load(AudioManager audio) { - sampleClick = audio.Sample.Get(@"UI/generic-select"); - sampleHover = audio.Sample.Get(@"UI/generic-hover"); + sampleClick = audio.Sample.Get($@"UI/generic-select{SampleSet.GetDescription()}"); + sampleHover = audio.Sample.Get($@"UI/generic-hover{SampleSet.GetDescription()}"); + } + + public enum HoverSampleSet + { + [Description("")] + Normal, + [Description("-soft")] + Soft, + [Description("-softer")] + Softer } } } From ac7e373f40252ef301b624418e44f36892197bb0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 26 Nov 2017 02:41:18 +0900 Subject: [PATCH 0826/1263] Add hover/click sound effects to more stuff everywhere --- .../Containers/OsuClickableContainer.cs | 28 +++------ .../UserInterface/HoverClickSounds.cs | 62 +++++++++++++++++++ osu.Game/Graphics/UserInterface/OsuButton.cs | 39 +----------- .../Graphics/UserInterface/OsuCheckbox.cs | 3 +- .../Graphics/UserInterface/OsuDropdown.cs | 9 ++- .../Graphics/UserInterface/OsuSliderBar.cs | 3 +- .../Graphics/UserInterface/OsuTabControl.cs | 3 +- .../Graphics/UserInterface/PageTabControl.cs | 1 + osu.Game/Overlays/Chat/ChatLine.cs | 2 +- osu.Game/Overlays/Chat/ChatTabControl.cs | 3 +- osu.Game/Overlays/Toolbar/ToolbarButton.cs | 5 +- osu.Game/Users/UserPanel.cs | 3 +- osu.Game/osu.Game.csproj | 1 + 13 files changed, 95 insertions(+), 67 deletions(-) create mode 100644 osu.Game/Graphics/UserInterface/HoverClickSounds.cs diff --git a/osu.Game/Graphics/Containers/OsuClickableContainer.cs b/osu.Game/Graphics/Containers/OsuClickableContainer.cs index ce3780cf78..c9117ed159 100644 --- a/osu.Game/Graphics/Containers/OsuClickableContainer.cs +++ b/osu.Game/Graphics/Containers/OsuClickableContainer.cs @@ -2,34 +2,24 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using osu.Framework.Allocation; -using osu.Framework.Audio; -using osu.Framework.Audio.Sample; using osu.Framework.Graphics.Containers; -using osu.Framework.Input; +using osu.Game.Graphics.UserInterface; namespace osu.Game.Graphics.Containers { public class OsuClickableContainer : ClickableContainer { - protected SampleChannel SampleClick, SampleHover; + private readonly HoverSampleSet sampleSet; + + public OsuClickableContainer(HoverSampleSet sampleSet = HoverSampleSet.Normal) + { + this.sampleSet = sampleSet; + } [BackgroundDependencyLoader] - private void load(AudioManager audio) + private void load() { - SampleHover = audio.Sample.Get(@"UI/generic-hover"); - SampleClick = audio.Sample.Get(@"UI/generic-select"); - } - - protected override bool OnHover(InputState state) - { - SampleHover?.Play(); - return base.OnHover(state); - } - - protected override bool OnClick(InputState state) - { - SampleClick?.Play(); - return base.OnClick(state); + AddInternal(new HoverClickSounds(sampleSet)); } } } diff --git a/osu.Game/Graphics/UserInterface/HoverClickSounds.cs b/osu.Game/Graphics/UserInterface/HoverClickSounds.cs new file mode 100644 index 0000000000..eace307610 --- /dev/null +++ b/osu.Game/Graphics/UserInterface/HoverClickSounds.cs @@ -0,0 +1,62 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System.ComponentModel; +using osu.Framework.Allocation; +using osu.Framework.Audio; +using osu.Framework.Audio.Sample; +using osu.Framework.Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Input; + +namespace osu.Game.Graphics.UserInterface +{ + /// + /// Adds hover and click sounds to a drawable. + /// Does not draw anything. + /// + public class HoverClickSounds : CompositeDrawable + { + private SampleChannel sampleClick; + private SampleChannel sampleHover; + + protected readonly HoverSampleSet SampleSet; + + public HoverClickSounds(HoverSampleSet sampleSet = HoverSampleSet.Normal) + { + SampleSet = sampleSet; + RelativeSizeAxes = Axes.Both; + AlwaysPresent = true; + } + + protected override bool OnClick(InputState state) + { + sampleClick?.Play(); + return base.OnClick(state); + } + + protected override bool OnHover(InputState state) + { + sampleHover?.Play(); + return base.OnHover(state); + } + + [BackgroundDependencyLoader] + private void load(AudioManager audio) + { + sampleClick = audio.Sample.Get($@"UI/generic-select{SampleSet.GetDescription()}"); + sampleHover = audio.Sample.Get($@"UI/generic-hover{SampleSet.GetDescription()}"); + } + } + + public enum HoverSampleSet + { + [Description("")] + Loud, + [Description("-soft")] + Normal, + [Description("-softer")] + Soft + } +} diff --git a/osu.Game/Graphics/UserInterface/OsuButton.cs b/osu.Game/Graphics/UserInterface/OsuButton.cs index 3b2377c06b..081e59d3a7 100644 --- a/osu.Game/Graphics/UserInterface/OsuButton.cs +++ b/osu.Game/Graphics/UserInterface/OsuButton.cs @@ -1,13 +1,7 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using System.ComponentModel; -using osu.Framework.Allocation; -using osu.Framework.Audio; -using osu.Framework.Audio.Sample; -using osu.Framework.Extensions; using osu.Framework.Graphics.UserInterface; -using osu.Framework.Input; namespace osu.Game.Graphics.UserInterface { @@ -16,38 +10,9 @@ namespace osu.Game.Graphics.UserInterface /// public class OsuButton : Button { - private SampleChannel sampleClick; - private SampleChannel sampleHover; - - protected HoverSampleSet SampleSet = HoverSampleSet.Normal; - - protected override bool OnClick(InputState state) + public OsuButton() { - sampleClick?.Play(); - return base.OnClick(state); - } - - protected override bool OnHover(InputState state) - { - sampleHover?.Play(); - return base.OnHover(state); - } - - [BackgroundDependencyLoader] - private void load(AudioManager audio) - { - sampleClick = audio.Sample.Get($@"UI/generic-select{SampleSet.GetDescription()}"); - sampleHover = audio.Sample.Get($@"UI/generic-hover{SampleSet.GetDescription()}"); - } - - public enum HoverSampleSet - { - [Description("")] - Normal, - [Description("-soft")] - Soft, - [Description("-softer")] - Softer + Add(new HoverClickSounds(HoverSampleSet.Loud)); } } } diff --git a/osu.Game/Graphics/UserInterface/OsuCheckbox.cs b/osu.Game/Graphics/UserInterface/OsuCheckbox.cs index 68ff99e593..40ff1243dc 100644 --- a/osu.Game/Graphics/UserInterface/OsuCheckbox.cs +++ b/osu.Game/Graphics/UserInterface/OsuCheckbox.cs @@ -70,7 +70,8 @@ namespace osu.Game.Graphics.UserInterface Anchor = Anchor.CentreRight, Origin = Anchor.CentreRight, Margin = new MarginPadding { Right = 5 }, - } + }, + new HoverClickSounds() }; Nub.Current.BindTo(Current); diff --git a/osu.Game/Graphics/UserInterface/OsuDropdown.cs b/osu.Game/Graphics/UserInterface/OsuDropdown.cs index f605804aaa..4401b509fd 100644 --- a/osu.Game/Graphics/UserInterface/OsuDropdown.cs +++ b/osu.Game/Graphics/UserInterface/OsuDropdown.cs @@ -33,7 +33,6 @@ namespace osu.Game.Graphics.UserInterface if (accentColour == default(Color4)) accentColour = colours.PinkDarker; updateAccentColour(); - } private void updateAccentColour() @@ -137,6 +136,8 @@ namespace osu.Game.Graphics.UserInterface nonAccentHoverColour = colours.PinkDarker; nonAccentSelectedColour = Color4.Black.Opacity(0.5f); updateColours(); + + AddInternal(new HoverClickSounds(HoverSampleSet.Soft)); } protected override void UpdateForegroundColour() @@ -183,7 +184,7 @@ namespace osu.Game.Graphics.UserInterface { Origin = Anchor.CentreLeft, Anchor = Anchor.CentreLeft, - } + }, }; } } @@ -237,8 +238,10 @@ namespace osu.Game.Graphics.UserInterface Origin = Anchor.CentreRight, Margin = new MarginPadding { Right = 4 }, Size = new Vector2(20), - } + }, }; + + AddInternal(new HoverClickSounds()); } [BackgroundDependencyLoader] diff --git a/osu.Game/Graphics/UserInterface/OsuSliderBar.cs b/osu.Game/Graphics/UserInterface/OsuSliderBar.cs index 3dd3596c30..fd75269610 100644 --- a/osu.Game/Graphics/UserInterface/OsuSliderBar.cs +++ b/osu.Game/Graphics/UserInterface/OsuSliderBar.cs @@ -88,7 +88,8 @@ namespace osu.Game.Graphics.UserInterface { Origin = Anchor.TopCentre, Expanded = true, - } + }, + new HoverClickSounds() }; Current.DisabledChanged += disabled => diff --git a/osu.Game/Graphics/UserInterface/OsuTabControl.cs b/osu.Game/Graphics/UserInterface/OsuTabControl.cs index b053195030..decbf57ad1 100644 --- a/osu.Game/Graphics/UserInterface/OsuTabControl.cs +++ b/osu.Game/Graphics/UserInterface/OsuTabControl.cs @@ -131,7 +131,8 @@ namespace osu.Game.Graphics.UserInterface Colour = Color4.White, Origin = Anchor.BottomLeft, Anchor = Anchor.BottomLeft, - } + }, + new HoverClickSounds() }; } diff --git a/osu.Game/Graphics/UserInterface/PageTabControl.cs b/osu.Game/Graphics/UserInterface/PageTabControl.cs index 6b97e54ecd..c69857a5c4 100644 --- a/osu.Game/Graphics/UserInterface/PageTabControl.cs +++ b/osu.Game/Graphics/UserInterface/PageTabControl.cs @@ -57,6 +57,7 @@ namespace osu.Game.Graphics.UserInterface Origin = Anchor.BottomLeft, Anchor = Anchor.BottomLeft, }, + new HoverClickSounds() }; } diff --git a/osu.Game/Overlays/Chat/ChatLine.cs b/osu.Game/Overlays/Chat/ChatLine.cs index 4db6bdf5e4..32f933ff42 100644 --- a/osu.Game/Overlays/Chat/ChatLine.cs +++ b/osu.Game/Overlays/Chat/ChatLine.cs @@ -222,7 +222,7 @@ namespace osu.Game.Overlays.Chat } - private class MessageSender : ClickableContainer, IHasContextMenu + private class MessageSender : OsuClickableContainer, IHasContextMenu { private readonly User sender; diff --git a/osu.Game/Overlays/Chat/ChatTabControl.cs b/osu.Game/Overlays/Chat/ChatTabControl.cs index 9f1028c168..f58ee8f819 100644 --- a/osu.Game/Overlays/Chat/ChatTabControl.cs +++ b/osu.Game/Overlays/Chat/ChatTabControl.cs @@ -17,6 +17,7 @@ using OpenTK; using OpenTK.Graphics; using osu.Framework.Configuration; using System; +using osu.Game.Graphics.Containers; namespace osu.Game.Overlays.Chat { @@ -259,7 +260,7 @@ namespace osu.Game.Overlays.Chat }; } - public class CloseButton : ClickableContainer + public class CloseButton : OsuClickableContainer { private readonly SpriteIcon icon; diff --git a/osu.Game/Overlays/Toolbar/ToolbarButton.cs b/osu.Game/Overlays/Toolbar/ToolbarButton.cs index cb17216679..c039f9d311 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarButton.cs @@ -13,6 +13,7 @@ using OpenTK; using OpenTK.Graphics; using osu.Framework.Graphics.Shapes; using osu.Game.Graphics.Containers; +using osu.Game.Graphics.UserInterface; namespace osu.Game.Overlays.Toolbar { @@ -74,7 +75,7 @@ namespace osu.Game.Overlays.Toolbar private readonly SpriteText tooltip2; protected FillFlowContainer Flow; - public ToolbarButton() + public ToolbarButton() : base(HoverSampleSet.Loud) { Width = WIDTH; RelativeSizeAxes = Axes.Y; @@ -195,4 +196,4 @@ namespace osu.Game.Overlays.Toolbar }; } } -} \ No newline at end of file +} diff --git a/osu.Game/Users/UserPanel.cs b/osu.Game/Users/UserPanel.cs index 1f235e3893..d056afcf54 100644 --- a/osu.Game/Users/UserPanel.cs +++ b/osu.Game/Users/UserPanel.cs @@ -17,10 +17,11 @@ 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; namespace osu.Game.Users { - public class UserPanel : ClickableContainer, IHasContextMenu + public class UserPanel : OsuClickableContainer, IHasContextMenu { private readonly User user; private const float height = 100; diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index a26ad963cf..415286f9a8 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -271,6 +271,7 @@ + From 0c6a1257777136f23696e270d7a65ebc7c64814b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 26 Nov 2017 02:52:55 +0900 Subject: [PATCH 0827/1263] Remove custom colour handling --- osu.Game/Graphics/UserInterface/TriangleButton.cs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/TriangleButton.cs b/osu.Game/Graphics/UserInterface/TriangleButton.cs index 33a8a8f99b..9fbdf6832f 100644 --- a/osu.Game/Graphics/UserInterface/TriangleButton.cs +++ b/osu.Game/Graphics/UserInterface/TriangleButton.cs @@ -4,7 +4,6 @@ using System.Collections.Generic; using OpenTK.Graphics; using osu.Framework.Allocation; -using osu.Framework.Audio; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -38,11 +37,8 @@ namespace osu.Game.Graphics.UserInterface public override bool HandleInput => Action != null; [BackgroundDependencyLoader] - private void load(OsuColour colours, AudioManager audio) + private void load(OsuColour colours) { - if (Action == null) - Colour = OsuColour.Gray(0.5f); - BackgroundColour = colours.BlueDark; Content.Masking = true; From 880418fd0d83c5005145b68e3c7d8ca5e4aaa2db Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 26 Nov 2017 03:27:16 +0900 Subject: [PATCH 0828/1263] Split out click and hover sound layers --- .../UserInterface/HoverClickSounds.cs | 30 +---------- .../Graphics/UserInterface/HoverSounds.cs | 54 +++++++++++++++++++ osu.Game/osu.Game.csproj | 1 + 3 files changed, 57 insertions(+), 28 deletions(-) create mode 100644 osu.Game/Graphics/UserInterface/HoverSounds.cs diff --git a/osu.Game/Graphics/UserInterface/HoverClickSounds.cs b/osu.Game/Graphics/UserInterface/HoverClickSounds.cs index eace307610..0fac1c8092 100644 --- a/osu.Game/Graphics/UserInterface/HoverClickSounds.cs +++ b/osu.Game/Graphics/UserInterface/HoverClickSounds.cs @@ -1,13 +1,10 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using System.ComponentModel; using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Audio.Sample; using osu.Framework.Extensions; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; using osu.Framework.Input; namespace osu.Game.Graphics.UserInterface @@ -16,18 +13,12 @@ namespace osu.Game.Graphics.UserInterface /// Adds hover and click sounds to a drawable. /// Does not draw anything. /// - public class HoverClickSounds : CompositeDrawable + public class HoverClickSounds : HoverSounds { private SampleChannel sampleClick; - private SampleChannel sampleHover; - protected readonly HoverSampleSet SampleSet; - - public HoverClickSounds(HoverSampleSet sampleSet = HoverSampleSet.Normal) + public HoverClickSounds(HoverSampleSet sampleSet = HoverSampleSet.Normal) : base(sampleSet) { - SampleSet = sampleSet; - RelativeSizeAxes = Axes.Both; - AlwaysPresent = true; } protected override bool OnClick(InputState state) @@ -36,27 +27,10 @@ namespace osu.Game.Graphics.UserInterface return base.OnClick(state); } - protected override bool OnHover(InputState state) - { - sampleHover?.Play(); - return base.OnHover(state); - } - [BackgroundDependencyLoader] private void load(AudioManager audio) { sampleClick = audio.Sample.Get($@"UI/generic-select{SampleSet.GetDescription()}"); - sampleHover = audio.Sample.Get($@"UI/generic-hover{SampleSet.GetDescription()}"); } } - - public enum HoverSampleSet - { - [Description("")] - Loud, - [Description("-soft")] - Normal, - [Description("-softer")] - Soft - } } diff --git a/osu.Game/Graphics/UserInterface/HoverSounds.cs b/osu.Game/Graphics/UserInterface/HoverSounds.cs new file mode 100644 index 0000000000..d26ad35c49 --- /dev/null +++ b/osu.Game/Graphics/UserInterface/HoverSounds.cs @@ -0,0 +1,54 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System.ComponentModel; +using osu.Framework.Allocation; +using osu.Framework.Audio; +using osu.Framework.Audio.Sample; +using osu.Framework.Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Input; + +namespace osu.Game.Graphics.UserInterface +{ + /// + /// Adds hover sounds to a drawable. + /// Does not draw anything. + /// + public class HoverSounds : CompositeDrawable + { + private SampleChannel sampleHover; + + protected readonly HoverSampleSet SampleSet; + + public HoverSounds(HoverSampleSet sampleSet = HoverSampleSet.Normal) + { + SampleSet = sampleSet; + RelativeSizeAxes = Axes.Both; + AlwaysPresent = true; + } + + protected override bool OnHover(InputState state) + { + sampleHover?.Play(); + return base.OnHover(state); + } + + [BackgroundDependencyLoader] + private void load(AudioManager audio) + { + sampleHover = audio.Sample.Get($@"UI/generic-hover{SampleSet.GetDescription()}"); + } + } + + public enum HoverSampleSet + { + [Description("")] + Loud, + [Description("-soft")] + Normal, + [Description("-softer")] + Soft + } +} diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 415286f9a8..ce9e8eff9c 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -272,6 +272,7 @@ + From c5aacb75c63f43c6c2a185640f0ddba26c2dd237 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 26 Nov 2017 03:28:11 +0900 Subject: [PATCH 0829/1263] Add hover sounds to mod buttons --- osu.Game/Overlays/Mods/ModButton.cs | 6 ++++-- osu.Game/Overlays/Mods/ModButtonEmpty.cs | 3 --- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/osu.Game/Overlays/Mods/ModButton.cs b/osu.Game/Overlays/Mods/ModButton.cs index 0ead4ea019..f2a3da4145 100644 --- a/osu.Game/Overlays/Mods/ModButton.cs +++ b/osu.Game/Overlays/Mods/ModButton.cs @@ -17,6 +17,7 @@ using osu.Game.Rulesets.UI; using System; using System.Linq; using osu.Framework.Graphics.Cursor; +using osu.Game.Graphics.UserInterface; namespace osu.Game.Overlays.Mods { @@ -31,7 +32,7 @@ namespace osu.Game.Overlays.Mods private readonly Container iconsContainer; private SampleChannel sampleOn, sampleOff; - public Action Action; // Passed the selected mod or null if none + public new Action Action; // Passed the selected mod or null if none public string TooltipText => (SelectedMod?.Description ?? Mods.FirstOrDefault()?.Description) ?? string.Empty; @@ -148,7 +149,7 @@ namespace osu.Game.Overlays.Mods // the mods from Mod, only multiple if Mod is a MultiMod - public override Mod SelectedMod => Mods.ElementAtOrDefault(SelectedIndex); + public virtual Mod SelectedMod => Mods.ElementAtOrDefault(SelectedIndex); [BackgroundDependencyLoader] private void load(AudioManager audio) @@ -253,6 +254,7 @@ namespace osu.Game.Overlays.Mods Anchor = Anchor.TopCentre, TextSize = 18, }, + new HoverClickSounds() }; Mod = mod; diff --git a/osu.Game/Overlays/Mods/ModButtonEmpty.cs b/osu.Game/Overlays/Mods/ModButtonEmpty.cs index 638c2a0e47..f776c174d2 100644 --- a/osu.Game/Overlays/Mods/ModButtonEmpty.cs +++ b/osu.Game/Overlays/Mods/ModButtonEmpty.cs @@ -3,7 +3,6 @@ using OpenTK; using osu.Framework.Graphics.Containers; -using osu.Game.Rulesets.Mods; namespace osu.Game.Overlays.Mods { @@ -12,8 +11,6 @@ namespace osu.Game.Overlays.Mods /// public class ModButtonEmpty : Container { - public virtual Mod SelectedMod => null; - public ModButtonEmpty() { Size = new Vector2(100f); From 5aa6615107756963ac9c5b03dceb3acf53c311f4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 26 Nov 2017 03:30:05 +0900 Subject: [PATCH 0830/1263] Add confirm-selection sound in song select --- osu.Game/Screens/Select/PlaySongSelect.cs | 10 +++++++++- osu.Game/Screens/Select/SongSelect.cs | 2 +- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Select/PlaySongSelect.cs b/osu.Game/Screens/Select/PlaySongSelect.cs index e0a3693371..992bfa52ee 100644 --- a/osu.Game/Screens/Select/PlaySongSelect.cs +++ b/osu.Game/Screens/Select/PlaySongSelect.cs @@ -4,6 +4,8 @@ using System.Linq; using OpenTK.Input; using osu.Framework.Allocation; +using osu.Framework.Audio; +using osu.Framework.Audio.Sample; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Input; @@ -42,9 +44,13 @@ namespace osu.Game.Screens.Select beatmapDetails.Leaderboard.ScoreSelected += s => Push(new Results(s)); } + private SampleChannel sampleConfirm; + [BackgroundDependencyLoader] - private void load(OsuColour colours) + private void load(OsuColour colours, AudioManager audio) { + sampleConfirm = audio.Sample.Get($@"SongSelect/confirm-selection"); + Footer.AddButton(@"mods", colours.Yellow, modSelect, Key.F1, float.MaxValue); BeatmapOptions.AddButton(@"Remove", @"from unplayed", FontAwesome.fa_times_circle_o, colours.Purple, null, Key.Number1); @@ -128,6 +134,8 @@ namespace osu.Game.Screens.Select Beatmap.Value.Track.Looping = false; Beatmap.Disabled = true; + sampleConfirm?.Play(); + LoadComponentAsync(player = new PlayerLoader(new Player()), l => Push(player)); } } diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index fcf459182f..b232f2edad 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -335,7 +335,7 @@ namespace osu.Game.Screens.Select logo.Action = () => { carouselRaisedStart(); - return true; + return false; }; } From 9c90d9ca457c57e1ef0fb4d63021ad2b5d6510a0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 26 Nov 2017 04:16:36 +0900 Subject: [PATCH 0831/1263] Add panel hover effects --- osu.Game/Beatmaps/Drawables/Panel.cs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/osu.Game/Beatmaps/Drawables/Panel.cs b/osu.Game/Beatmaps/Drawables/Panel.cs index d6ed306b39..32c1a31de6 100644 --- a/osu.Game/Beatmaps/Drawables/Panel.cs +++ b/osu.Game/Beatmaps/Drawables/Panel.cs @@ -3,12 +3,15 @@ using System; using osu.Framework; +using osu.Framework.Audio; +using osu.Framework.Audio.Sample; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Input; using OpenTK; using OpenTK.Graphics; using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.MathUtils; namespace osu.Game.Beatmaps.Drawables { @@ -40,6 +43,20 @@ namespace osu.Game.Beatmaps.Drawables Alpha = 0; } + private SampleChannel sampleHover; + + protected override bool OnHover(InputState state) + { + sampleHover?.Play(); + return base.OnHover(state); + } + + [BackgroundDependencyLoader] + private void load(AudioManager audio, OsuColour colours) + { + sampleHover = audio.Sample.Get($@"SongSelect/song-ping-variation-{RNG.Next(1, 5)}"); + } + public void SetMultiplicativeAlpha(float alpha) { nestedContainer.Alpha = alpha; From 671b3d01ff83d9550fcf1b65cfcccdf5d352181d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 26 Nov 2017 04:59:55 +0900 Subject: [PATCH 0832/1263] Fix OsuClickableContainer's local content geting overwritten --- .../Containers/OsuClickableContainer.cs | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/osu.Game/Graphics/Containers/OsuClickableContainer.cs b/osu.Game/Graphics/Containers/OsuClickableContainer.cs index c9117ed159..8df533ad6e 100644 --- a/osu.Game/Graphics/Containers/OsuClickableContainer.cs +++ b/osu.Game/Graphics/Containers/OsuClickableContainer.cs @@ -2,6 +2,7 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using osu.Framework.Allocation; +using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Graphics.UserInterface; @@ -11,6 +12,10 @@ namespace osu.Game.Graphics.Containers { private readonly HoverSampleSet sampleSet; + private readonly Container content = new Container { RelativeSizeAxes = Axes.Both }; + + protected override Container Content => content; + public OsuClickableContainer(HoverSampleSet sampleSet = HoverSampleSet.Normal) { this.sampleSet = sampleSet; @@ -19,7 +24,17 @@ namespace osu.Game.Graphics.Containers [BackgroundDependencyLoader] private void load() { - AddInternal(new HoverClickSounds(sampleSet)); + if (AutoSizeAxes != Axes.None) + { + content.RelativeSizeAxes = RelativeSizeAxes; + content.AutoSizeAxes = AutoSizeAxes; + } + + InternalChildren = new Drawable[] + { + content, + new HoverClickSounds(sampleSet) + }; } } } From ae201f0ef5dcdf1f4bbae80082ee214739ad7862 Mon Sep 17 00:00:00 2001 From: Unknown Date: Sun, 26 Nov 2017 15:03:49 +0530 Subject: [PATCH 0833/1263] R# --- osu.Game/Online/API/Requests/GetScoresRequest.cs | 1 - osu.Game/Screens/Select/Leaderboards/Leaderboard.cs | 9 +++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/osu.Game/Online/API/Requests/GetScoresRequest.cs b/osu.Game/Online/API/Requests/GetScoresRequest.cs index b9db836898..54d656eeca 100644 --- a/osu.Game/Online/API/Requests/GetScoresRequest.cs +++ b/osu.Game/Online/API/Requests/GetScoresRequest.cs @@ -11,7 +11,6 @@ using osu.Game.Users; using osu.Game.Rulesets.Replays; using osu.Game.Rulesets.Scoring; using osu.Game.Screens.Select.Leaderboards; -using System.Collections.Specialized; using osu.Framework.IO.Network; namespace osu.Game.Online.API.Requests diff --git a/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs b/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs index 31e79022c3..62bd292710 100644 --- a/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs +++ b/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs @@ -34,9 +34,10 @@ namespace osu.Game.Screens.Select.Leaderboards private const double fade_duration = 200; private readonly ScrollContainer scrollContainer; + private readonly Container placeholderContainer; + private readonly FillFlowContainer placeholderFlow; + private FillFlowContainer scrollFlow; - private Container placeholderContainer; - private FillFlowContainer placeholderFlow; public Action ScoreSelected; @@ -63,7 +64,7 @@ namespace osu.Game.Screens.Select.Leaderboards if (scores == null) return; - if (scores.Count() == 0) + if (!scores.Any()) { placeholderFlow.Children = new Drawable[] { @@ -278,7 +279,7 @@ namespace osu.Game.Screens.Select.Leaderboards private class RetryButton : BeatSyncedContainer { - private SpriteIcon icon; + private readonly SpriteIcon icon; public Action Action; From ba0b16dc0b49a2f852f46eadbf321b1509356126 Mon Sep 17 00:00:00 2001 From: Aergwyn Date: Sun, 26 Nov 2017 19:00:30 +0100 Subject: [PATCH 0834/1263] setting BeatmapSets as list to prevent endless LINQ query chain --- osu.Game/Overlays/DirectOverlay.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/DirectOverlay.cs b/osu.Game/Overlays/DirectOverlay.cs index 11dd9dd976..b49ac269a9 100644 --- a/osu.Game/Overlays/DirectOverlay.cs +++ b/osu.Game/Overlays/DirectOverlay.cs @@ -50,7 +50,7 @@ namespace osu.Game.Overlays { if (beatmapSets?.Equals(value) ?? false) return; - beatmapSets = value; + beatmapSets = value?.ToList(); if (beatmapSets == null) return; From ae55d392de9a05f9d878d79a319e4a39070a1bd3 Mon Sep 17 00:00:00 2001 From: Unknown Date: Sat, 25 Nov 2017 15:28:39 +0100 Subject: [PATCH 0835/1263] only use `==` for comparion on primitive types --- osu.Game/Beatmaps/BeatmapMetadata.cs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapMetadata.cs b/osu.Game/Beatmaps/BeatmapMetadata.cs index 22a64820bc..a78ef25166 100644 --- a/osu.Game/Beatmaps/BeatmapMetadata.cs +++ b/osu.Game/Beatmaps/BeatmapMetadata.cs @@ -74,16 +74,16 @@ namespace osu.Game.Beatmaps return false; return onlineBeatmapSetID == other.onlineBeatmapSetID - && (Title?.Equals(other.Title) ?? false) - && (TitleUnicode?.Equals(other.TitleUnicode) ?? false) - && (Artist?.Equals(other.Artist) ?? false) - && (ArtistUnicode?.Equals(other.ArtistUnicode) ?? false) - && (AuthorString?.Equals(other.AuthorString) ?? false) - && (Source?.Equals(other.Source) ?? false) - && (Tags?.Equals(other.Tags) ?? false) + && Title == other.Title + && TitleUnicode == other.TitleUnicode + && Artist == other.Artist + && ArtistUnicode == other.ArtistUnicode + && AuthorString == other.AuthorString + && Source == other.Source + && Tags == other.Tags && PreviewTime == other.PreviewTime - && (AudioFile?.Equals(other.AudioFile) ?? false) - && (BackgroundFile?.Equals(other.BackgroundFile) ?? false); + && AudioFile == other.AudioFile + && BackgroundFile == other.BackgroundFile; } } } From 02fa1f9dd6c5418f68bccfd12d4015479855766b Mon Sep 17 00:00:00 2001 From: jorolf Date: Sun, 26 Nov 2017 21:52:35 +0100 Subject: [PATCH 0836/1263] move shared stuff between MostPlayedBeatmapDrawable and DrawableScore to DrawableBeatmapRow --- .../Profile/Sections/DrawableBeatmapRow.cs | 118 +++++++++++ .../Historical/MostPlayedBeatmapDrawable.cs | 188 +++++++----------- .../Ranks/DrawablePerformanceScore.cs | 4 +- .../Profile/Sections/Ranks/DrawableScore.cs | 119 ++--------- .../Sections/Ranks/DrawableTotalScore.cs | 2 +- osu.Game/osu.Game.csproj | 1 + 6 files changed, 213 insertions(+), 219 deletions(-) create mode 100644 osu.Game/Overlays/Profile/Sections/DrawableBeatmapRow.cs diff --git a/osu.Game/Overlays/Profile/Sections/DrawableBeatmapRow.cs b/osu.Game/Overlays/Profile/Sections/DrawableBeatmapRow.cs new file mode 100644 index 0000000000..f6800a5f32 --- /dev/null +++ b/osu.Game/Overlays/Profile/Sections/DrawableBeatmapRow.cs @@ -0,0 +1,118 @@ +using osu.Framework.Allocation; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Input; +using osu.Game.Graphics; +using OpenTK; +using OpenTK.Graphics; + +namespace osu.Game.Overlays.Profile.Sections +{ + public abstract class DrawableBeatmapRow : Container + { + private const int fade_duration = 200; + + private Box underscoreLine; + private readonly Box coloredBackground; + private readonly Container background; + + protected abstract Drawable CreatePicture(); + + protected FillFlowContainer LeftFlowContainer { get; private set; } + protected FillFlowContainer RightFlowContainer { get; private set; } + + protected override Container Content { get; } + + protected DrawableBeatmapRow() + { + RelativeSizeAxes = Axes.X; + Height = 60; + InternalChildren = new Drawable[] + { + background = new Container + { + RelativeSizeAxes = Axes.Both, + Masking = true, + CornerRadius = 3, + Alpha = 0, + EdgeEffect = new EdgeEffectParameters + { + Type = EdgeEffectType.Shadow, + Offset = new Vector2(0f, 1f), + Radius = 1f, + Colour = Color4.Black.Opacity(0.2f), + }, + Child = coloredBackground = new Box { RelativeSizeAxes = Axes.Both } + }, + Content = new Container + { + RelativeSizeAxes = Axes.Both, + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Width = 0.97f, + }, + }; + } + + [BackgroundDependencyLoader(true)] + private void load(OsuColour colour) + { + AddRange(new Drawable[] + { + underscoreLine = new Box + { + Anchor = Anchor.BottomCentre, + Origin = Anchor.BottomCentre, + RelativeSizeAxes = Axes.X, + Height = 1, + }, + new FillFlowContainer + { + RelativeSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Children = new[] + { + CreatePicture(), + LeftFlowContainer = new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Margin = new MarginPadding { Left = 10 }, + Direction = FillDirection.Vertical, + }, + } + }, + RightFlowContainer = new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + Direction = FillDirection.Vertical, + }, + }); + + coloredBackground.Colour = underscoreLine.Colour = colour.Gray4; + } + + protected override bool OnClick(InputState state) => true; + + protected override bool OnHover(InputState state) + { + background.FadeIn(fade_duration, Easing.OutQuint); + underscoreLine.FadeOut(fade_duration, Easing.OutQuint); + return true; + } + + protected override void OnHoverLost(InputState state) + { + background.FadeOut(fade_duration, Easing.OutQuint); + underscoreLine.FadeIn(fade_duration, Easing.OutQuint); + base.OnHoverLost(state); + } + } +} diff --git a/osu.Game/Overlays/Profile/Sections/Historical/MostPlayedBeatmapDrawable.cs b/osu.Game/Overlays/Profile/Sections/Historical/MostPlayedBeatmapDrawable.cs index 0f419ad44e..446af667f2 100644 --- a/osu.Game/Overlays/Profile/Sections/Historical/MostPlayedBeatmapDrawable.cs +++ b/osu.Game/Overlays/Profile/Sections/Historical/MostPlayedBeatmapDrawable.cs @@ -2,14 +2,11 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using osu.Framework.Allocation; -using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; -using osu.Framework.Input; using osu.Game.Beatmaps; using osu.Game.Beatmaps.Drawables; -using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using OpenTK; @@ -17,144 +14,99 @@ using OpenTK.Graphics; namespace osu.Game.Overlays.Profile.Sections.Historical { - public class MostPlayedBeatmapDrawable : Container + public class MostPlayedBeatmapDrawable : DrawableBeatmapRow { private readonly BeatmapInfo beatmap; - private readonly OsuHoverContainer mapperContainer; - - private readonly EdgeEffectParameters edgeEffectNormal = new EdgeEffectParameters - { - Type = EdgeEffectType.Shadow, - Offset = new Vector2(0, 1f), - Radius = 2f, - Colour = Color4.Black.Opacity(0.25f), - }; - - private readonly EdgeEffectParameters edgeEffectHovered = new EdgeEffectParameters - { - Type = EdgeEffectType.Shadow, - Offset = new Vector2(0, 5f), - Radius = 10f, - Colour = Color4.Black.Opacity(0.25f), - }; + private readonly int playCount; + private OsuHoverContainer mapperContainer; public MostPlayedBeatmapDrawable(BeatmapInfo beatmap, int playCount) { this.beatmap = beatmap; - RelativeSizeAxes = Axes.X; - Height = 50; - Margin = new MarginPadding { Bottom = 10 }; - Masking = true; - EdgeEffect = edgeEffectNormal; + this.playCount = playCount; + } + protected override Drawable CreatePicture() => new Container + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + AutoSizeAxes = Axes.Both, Children = new Drawable[] { - new Box //Background for this container, otherwise the shadow would be visible - { - RelativeSizeAxes = Axes.Both, - Colour = OsuColour.Gray(0.2f), - }, new Box //Image Background while loading { - Size = new Vector2(80, 50), - Colour = Color4.Black, + Size = new Vector2(80, 50), + Colour = Color4.Black, }, new DelayedLoadWrapper(new BeatmapSetCover(beatmap.BeatmapSet, BeatmapSetCoverType.List) { RelativeSizeAxes = Axes.Both, FillMode = FillMode.Fit, }), - new FillFlowContainer - { - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding(10) { Left = 90 }, - Direction = FillDirection.Vertical, - Children = new Drawable[] - { - new Container - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Children = new Drawable[] - { - new BeatmapMetadataContainer(beatmap), - new FillFlowContainer - { - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - Children = new [] - { - new OsuSpriteText - { - Anchor = Anchor.BottomRight, - Origin = Anchor.BottomRight, - Text = playCount.ToString(), - TextSize = 18, - Font = @"Exo2.0-SemiBoldItalic" - }, - new OsuSpriteText - { - Anchor = Anchor.BottomRight, - Origin = Anchor.BottomRight, - Text = @"times played ", - TextSize = 12, - Font = @"Exo2.0-RegularItalic" - }, - } - } - }, - }, - new FillFlowContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Direction = FillDirection.Horizontal, - Children = new Drawable[] - { - new OsuSpriteText - { - Text = @"mapped by ", - TextSize = 12, - }, - mapperContainer = new OsuHoverContainer - { - AutoSizeAxes = Axes.Both, - Children = new Drawable[] - { - new OsuSpriteText - { - Text = beatmap.Metadata.AuthorString, - TextSize = 12, - Font = @"Exo2.0-MediumItalic" - } - } - }, - } - }, - }, - } - }; - } + }, + }; [BackgroundDependencyLoader(true)] private void load(UserProfileOverlay profileOverlay) { + LeftFlowContainer.Add(new BeatmapMetadataContainer(beatmap)); + LeftFlowContainer.Add(new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Horizontal, + Children = new Drawable[] + { + new OsuSpriteText + { + Text = @"mapped by ", + TextSize = 12, + }, + mapperContainer = new OsuHoverContainer + { + AutoSizeAxes = Axes.Both, + Children = new Drawable[] + { + new OsuSpriteText + { + Text = beatmap.Metadata.AuthorString, + TextSize = 12, + Font = @"Exo2.0-MediumItalic" + } + } + }, + } + }); + + RightFlowContainer.Add(new FillFlowContainer + { + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Children = new[] + { + new OsuSpriteText + { + Anchor = Anchor.BottomRight, + Origin = Anchor.BottomRight, + Text = playCount.ToString(), + TextSize = 18, + Font = @"Exo2.0-SemiBoldItalic" + }, + new OsuSpriteText + { + Anchor = Anchor.BottomRight, + Origin = Anchor.BottomRight, + Text = @"times played ", + TextSize = 12, + Font = @"Exo2.0-RegularItalic" + }, + } + }); + if(profileOverlay != null) mapperContainer.Action = () => profileOverlay.ShowUser(beatmap.BeatmapSet.Metadata.Author); } - - protected override bool OnHover(InputState state) - { - TweenEdgeEffectTo(edgeEffectHovered, 120, Easing.OutQuint); - return base.OnHover(state); - } - - protected override void OnHoverLost(InputState state) - { - TweenEdgeEffectTo(edgeEffectNormal, 120, Easing.OutQuint); - base.OnHoverLost(state); - } } } diff --git a/osu.Game/Overlays/Profile/Sections/Ranks/DrawablePerformanceScore.cs b/osu.Game/Overlays/Profile/Sections/Ranks/DrawablePerformanceScore.cs index e6ba5b26ac..cd13d14575 100644 --- a/osu.Game/Overlays/Profile/Sections/Ranks/DrawablePerformanceScore.cs +++ b/osu.Game/Overlays/Profile/Sections/Ranks/DrawablePerformanceScore.cs @@ -23,7 +23,7 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks private void load(OsuColour colour) { double pp = Score.PP ?? 0; - Stats.Add(new OsuSpriteText + RightFlowContainer.Add(new OsuSpriteText { Text = $"{pp:0}pp", Anchor = Anchor.TopRight, @@ -34,7 +34,7 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks if (weight.HasValue) { - Stats.Add(new OsuSpriteText + RightFlowContainer.Add(new OsuSpriteText { Text = $"weighted: {pp * weight:0}pp ({weight:P0})", Anchor = Anchor.TopRight, diff --git a/osu.Game/Overlays/Profile/Sections/Ranks/DrawableScore.cs b/osu.Game/Overlays/Profile/Sections/Ranks/DrawableScore.cs index 4d210f399e..db7647ce0e 100644 --- a/osu.Game/Overlays/Profile/Sections/Ranks/DrawableScore.cs +++ b/osu.Game/Overlays/Profile/Sections/Ranks/DrawableScore.cs @@ -11,24 +11,14 @@ using osu.Game.Rulesets.Mods; using osu.Game.Screens.Select.Leaderboards; using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.UI; -using OpenTK.Graphics; -using osu.Framework.Graphics.Shapes; -using osu.Framework.Input; -using osu.Framework.Extensions.Color4Extensions; namespace osu.Game.Overlays.Profile.Sections.Ranks { - public abstract class DrawableScore : Container + public abstract class DrawableScore : DrawableBeatmapRow { - private const int fade_duration = 200; - - protected readonly FillFlowContainer Stats; private readonly FillFlowContainer metadata; private readonly ScoreModsContainer modsContainer; protected readonly Score Score; - private readonly Box underscoreLine; - private readonly Box coloredBackground; - private readonly Container background; protected DrawableScore(Score score) { @@ -38,85 +28,21 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks Height = 60; Children = new Drawable[] { - background = new Container + modsContainer = new ScoreModsContainer { - RelativeSizeAxes = Axes.Both, - Masking = true, - CornerRadius = 3, - Alpha = 0, - EdgeEffect = new EdgeEffectParameters - { - Type = EdgeEffectType.Shadow, - Offset = new Vector2(0f, 1f), - Radius = 1f, - Colour = Color4.Black.Opacity(0.2f), - }, - Child = coloredBackground = new Box { RelativeSizeAxes = Axes.Both } - }, - new Container - { - RelativeSizeAxes = Axes.Both, - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - Width = 0.97f, - Children = new Drawable[] - { - underscoreLine = new Box - { - Anchor = Anchor.BottomCentre, - Origin = Anchor.BottomCentre, - RelativeSizeAxes = Axes.X, - Height = 1, - }, - new DrawableRank(score.Rank) - { - RelativeSizeAxes = Axes.Y, - Width = 60, - FillMode = FillMode.Fit, - }, - Stats = new FillFlowContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Anchor = Anchor.CentreRight, - Origin = Anchor.CentreRight, - Direction = FillDirection.Vertical, - }, - metadata = new FillFlowContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Margin = new MarginPadding { Left = 70 }, - Direction = FillDirection.Vertical, - Child = new OsuSpriteText - { - Text = score.Date.LocalDateTime.ToShortDateString(), - TextSize = 11, - Colour = OsuColour.Gray(0xAA), - Depth = -1, - }, - }, - modsContainer = new ScoreModsContainer - { - AutoSizeAxes = Axes.Y, - Anchor = Anchor.CentreRight, - Origin = Anchor.CentreRight, - Width = 60, - Margin = new MarginPadding { Right = 160 } - } - } - }, + AutoSizeAxes = Axes.Y, + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + Width = 60, + Margin = new MarginPadding { Right = 160 } + } }; } [BackgroundDependencyLoader(true)] private void load(OsuColour colour) { - coloredBackground.Colour = underscoreLine.Colour = colour.Gray4; - - Stats.Add(new OsuSpriteText + RightFlowContainer.Add(new OsuSpriteText { Text = $"accuracy: {Score.Accuracy:P2}", Anchor = Anchor.TopRight, @@ -127,26 +53,23 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks Depth = -1, }); - metadata.Add(new BeatmapMetadataContainer(Score.Beatmap)); + LeftFlowContainer.Add(new BeatmapMetadataContainer(Score.Beatmap)); + LeftFlowContainer.Add(new OsuSpriteText + { + Text = Score.Date.LocalDateTime.ToShortDateString(), + TextSize = 11, + Colour = OsuColour.Gray(0xAA), + }); foreach (Mod mod in Score.Mods) modsContainer.Add(new ModIcon(mod) { Scale = new Vector2(0.5f) }); } - protected override bool OnClick(InputState state) => true; - - protected override bool OnHover(InputState state) + protected override Drawable CreatePicture() => new DrawableRank(Score.Rank) { - background.FadeIn(fade_duration, Easing.OutQuint); - underscoreLine.FadeOut(fade_duration, Easing.OutQuint); - return true; - } - - protected override void OnHoverLost(InputState state) - { - background.FadeOut(fade_duration, Easing.OutQuint); - underscoreLine.FadeIn(fade_duration, Easing.OutQuint); - base.OnHoverLost(state); - } + RelativeSizeAxes = Axes.Y, + Width = 60, + FillMode = FillMode.Fit, + }; } } diff --git a/osu.Game/Overlays/Profile/Sections/Ranks/DrawableTotalScore.cs b/osu.Game/Overlays/Profile/Sections/Ranks/DrawableTotalScore.cs index 537b208b39..1539142f1d 100644 --- a/osu.Game/Overlays/Profile/Sections/Ranks/DrawableTotalScore.cs +++ b/osu.Game/Overlays/Profile/Sections/Ranks/DrawableTotalScore.cs @@ -18,7 +18,7 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks [BackgroundDependencyLoader] private void load() { - Stats.Add(new OsuSpriteText + RightFlowContainer.Add(new OsuSpriteText { Text = Score.TotalScore.ToString("#,###"), Anchor = Anchor.TopRight, diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 4921c4ce05..b774602b76 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -294,6 +294,7 @@ + From 4c68090e59d2139c6bc53033c423b138c7963f3e Mon Sep 17 00:00:00 2001 From: jorolf Date: Sun, 26 Nov 2017 22:06:03 +0100 Subject: [PATCH 0837/1263] separate GetUserBeatmapsRequest and GetUserMostPlayedBeatmapsRequest --- .../API/Requests/GetUserBeatmapsRequest.cs | 16 ++-------------- .../Requests/GetUserMostPlayedBeatmapsRequest.cs | 16 ++++++++++------ .../PaginatedMostPlayedBeatmapContainer.cs | 2 +- 3 files changed, 13 insertions(+), 21 deletions(-) diff --git a/osu.Game/Online/API/Requests/GetUserBeatmapsRequest.cs b/osu.Game/Online/API/Requests/GetUserBeatmapsRequest.cs index dca0395e3a..691f8496d9 100644 --- a/osu.Game/Online/API/Requests/GetUserBeatmapsRequest.cs +++ b/osu.Game/Online/API/Requests/GetUserBeatmapsRequest.cs @@ -1,19 +1,18 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using System; using Humanizer; using System.Collections.Generic; namespace osu.Game.Online.API.Requests { - public abstract class GetUserBeatmapsRequest : APIRequest> + public class GetUserBeatmapsRequest : APIRequest> { private readonly long userId; private readonly int offset; private readonly BeatmapSetType type; - protected GetUserBeatmapsRequest(long userId, BeatmapSetType type, int offset = 0) + public GetUserBeatmapsRequest(long userId, BeatmapSetType type, int offset = 0) { this.userId = userId; this.offset = offset; @@ -23,19 +22,8 @@ namespace osu.Game.Online.API.Requests protected override string Target => $@"users/{userId}/beatmapsets/{type.ToString().Underscore()}?offset={offset}"; } - public class GetUserBeatmapsRequest : GetUserBeatmapsRequest - { - public GetUserBeatmapsRequest(long userID, BeatmapSetType type, int offset = 0) - : base(userID, type, offset) - { - if(type == BeatmapSetType.MostPlayed) - throw new ArgumentException("Please use " + nameof(GetUserMostPlayedBeatmapsRequest) + " instead"); - } - } - public enum BeatmapSetType { - MostPlayed, Favourite, RankedAndApproved, Unranked, diff --git a/osu.Game/Online/API/Requests/GetUserMostPlayedBeatmapsRequest.cs b/osu.Game/Online/API/Requests/GetUserMostPlayedBeatmapsRequest.cs index 2d08f09d20..c45ef734e6 100644 --- a/osu.Game/Online/API/Requests/GetUserMostPlayedBeatmapsRequest.cs +++ b/osu.Game/Online/API/Requests/GetUserMostPlayedBeatmapsRequest.cs @@ -1,21 +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 Newtonsoft.Json; using osu.Game.Beatmaps; using osu.Game.Rulesets; +using System.Collections.Generic; namespace osu.Game.Online.API.Requests { - public class GetUserMostPlayedBeatmapsRequest : GetUserBeatmapsRequest + public class GetUserMostPlayedBeatmapsRequest : APIRequest> { - public GetUserMostPlayedBeatmapsRequest(long userID, BeatmapSetType type, int offset = 0) - : base(userID, type, offset) + private readonly long userId; + private readonly int offset; + + public GetUserMostPlayedBeatmapsRequest(long userId, int offset = 0) { - if (type != BeatmapSetType.MostPlayed) - throw new ArgumentException("Please use " + nameof(GetUserBeatmapsRequest) + " instead"); + this.userId = userId; + this.offset = offset; } + + protected override string Target => $@"users/{userId}/beatmapsets/most_played?offset={offset}"; } public class UserMostPlayedBeatmapsResponse diff --git a/osu.Game/Overlays/Profile/Sections/Historical/PaginatedMostPlayedBeatmapContainer.cs b/osu.Game/Overlays/Profile/Sections/Historical/PaginatedMostPlayedBeatmapContainer.cs index 916f1f437a..b7df60a7a2 100644 --- a/osu.Game/Overlays/Profile/Sections/Historical/PaginatedMostPlayedBeatmapContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/Historical/PaginatedMostPlayedBeatmapContainer.cs @@ -24,7 +24,7 @@ namespace osu.Game.Overlays.Profile.Sections.Historical { base.ShowMore(); - var req = new GetUserMostPlayedBeatmapsRequest(User.Value.Id, BeatmapSetType.MostPlayed, VisiblePages++ * ItemsPerPage); + var req = new GetUserMostPlayedBeatmapsRequest(User.Value.Id, VisiblePages++ * ItemsPerPage); req.Success += beatmaps => { From 70b6071898afa38590f00ca43accedb6b808e754 Mon Sep 17 00:00:00 2001 From: jorolf Date: Sun, 26 Nov 2017 22:13:52 +0100 Subject: [PATCH 0838/1263] add license header --- osu.Game/Overlays/Profile/Sections/DrawableBeatmapRow.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Profile/Sections/DrawableBeatmapRow.cs b/osu.Game/Overlays/Profile/Sections/DrawableBeatmapRow.cs index f6800a5f32..4d2affd77c 100644 --- a/osu.Game/Overlays/Profile/Sections/DrawableBeatmapRow.cs +++ b/osu.Game/Overlays/Profile/Sections/DrawableBeatmapRow.cs @@ -1,4 +1,7 @@ -using osu.Framework.Allocation; +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; From f189de437a38450c4a1d568a51c3e013d54ced8b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 27 Nov 2017 10:01:44 +0900 Subject: [PATCH 0839/1263] Simplify blending assignment --- osu.Game/Beatmaps/Drawables/Panel.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Beatmaps/Drawables/Panel.cs b/osu.Game/Beatmaps/Drawables/Panel.cs index 5fbc858b00..e4b7e55012 100644 --- a/osu.Game/Beatmaps/Drawables/Panel.cs +++ b/osu.Game/Beatmaps/Drawables/Panel.cs @@ -52,7 +52,7 @@ namespace osu.Game.Beatmaps.Drawables { RelativeSizeAxes = Axes.Both, Alpha = 0, - Blending = new BlendingParameters { Mode = BlendingMode.Additive }, + Blending = BlendingMode.Additive, }, } }); From b34e724b8d17a1fda502683659e2d5b3e4c44d7b Mon Sep 17 00:00:00 2001 From: FreezyLemon Date: Mon, 27 Nov 2017 08:18:09 +0100 Subject: [PATCH 0840/1263] Changed MetadataSection so that the Text setter loads the new text in async before displaying it. --- osu.Game/Screens/Select/BeatmapDetails.cs | 24 ++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Select/BeatmapDetails.cs b/osu.Game/Screens/Select/BeatmapDetails.cs index 6eaed67534..1b2108a6c8 100644 --- a/osu.Game/Screens/Select/BeatmapDetails.cs +++ b/osu.Game/Screens/Select/BeatmapDetails.cs @@ -316,7 +316,7 @@ namespace osu.Game.Screens.Select private class MetadataSection : Container { - private readonly TextFlowContainer textFlow; + private TextFlowContainer textFlow; public string Text { @@ -329,11 +329,29 @@ namespace osu.Game.Screens.Select } this.FadeIn(transition_duration); - textFlow.Clear(); - textFlow.AddText(value, s => s.TextSize = 14); + addTextAsync(value); } } + private void addTextAsync(string text) + { + var newTextFlow = new TextFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Colour = textFlow.Colour, + }; + + newTextFlow.AddText(text, s => s.TextSize = 14); + + LoadComponentAsync(newTextFlow, d => + { + var textContainer = (InternalChild as FillFlowContainer); + textContainer.Remove(textFlow); + textContainer.Add(textFlow = d); + }); + } + public Color4 TextColour { get { return textFlow.Colour; } From d49ee295d99e0438fd016c7e00d2bd13255f0d41 Mon Sep 17 00:00:00 2001 From: FreezyLemon Date: Mon, 27 Nov 2017 08:47:36 +0100 Subject: [PATCH 0841/1263] Removed unnecessary schedule and null checks --- osu.Game/Screens/Select/BeatmapDetails.cs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/osu.Game/Screens/Select/BeatmapDetails.cs b/osu.Game/Screens/Select/BeatmapDetails.cs index 1b2108a6c8..f203f5cdc4 100644 --- a/osu.Game/Screens/Select/BeatmapDetails.cs +++ b/osu.Game/Screens/Select/BeatmapDetails.cs @@ -217,12 +217,9 @@ namespace osu.Game.Screens.Select if (description == null || source == null || tags == null) throw new InvalidOperationException($@"Requires all {nameof(MetadataSection)} elements to be non-null."); - Schedule(() => - { - description.Text = Beatmap?.Version; - source.Text = Beatmap?.Metadata?.Source; - tags.Text = Beatmap?.Metadata?.Tags; - }); + description.Text = beatmap.Version; + source.Text = beatmap.Metadata?.Source; + tags.Text = beatmap.Metadata?.Tags; } private void displayMetrics(BeatmapMetrics metrics, bool failOnMissing = true) From ac0942df8681714a92cddbfb1a146637c02d8b11 Mon Sep 17 00:00:00 2001 From: FreezyLemon Date: Mon, 27 Nov 2017 08:48:12 +0100 Subject: [PATCH 0842/1263] Removed unnecessary private method to update the metadata --- osu.Game/Screens/Select/BeatmapDetails.cs | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/osu.Game/Screens/Select/BeatmapDetails.cs b/osu.Game/Screens/Select/BeatmapDetails.cs index f203f5cdc4..892156cc22 100644 --- a/osu.Game/Screens/Select/BeatmapDetails.cs +++ b/osu.Game/Screens/Select/BeatmapDetails.cs @@ -188,7 +188,9 @@ namespace osu.Game.Screens.Select ratingsContainer.FadeIn(transition_duration); advanced.Beatmap = Beatmap; - loadDetailsAsync(Beatmap); + description.Text = Beatmap.Version; + source.Text = Beatmap.Metadata.Source; + tags.Text = Beatmap.Metadata.Tags; var requestedBeatmap = Beatmap; if (requestedBeatmap.Metrics == null) @@ -212,16 +214,6 @@ namespace osu.Game.Screens.Select displayMetrics(requestedBeatmap.Metrics, false); } - private void loadDetailsAsync(BeatmapInfo beatmap) - { - if (description == null || source == null || tags == null) - throw new InvalidOperationException($@"Requires all {nameof(MetadataSection)} elements to be non-null."); - - description.Text = beatmap.Version; - source.Text = beatmap.Metadata?.Source; - tags.Text = beatmap.Metadata?.Tags; - } - private void displayMetrics(BeatmapMetrics metrics, bool failOnMissing = true) { var hasRatings = metrics?.Ratings?.Any() ?? false; @@ -267,7 +259,10 @@ namespace osu.Game.Screens.Select private void clearStats() { - loadDetailsAsync(null); + description.Text = null; + source.Text = null; + tags.Text = null; + advanced.Beatmap = new BeatmapInfo { StarDifficulty = 0, From 507da0dfb74cf97ae08199e9238a2b078508dd44 Mon Sep 17 00:00:00 2001 From: FreezyLemon Date: Mon, 27 Nov 2017 08:48:47 +0100 Subject: [PATCH 0843/1263] Renamed addTextAsync to setTextAsync --- osu.Game/Screens/Select/BeatmapDetails.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Select/BeatmapDetails.cs b/osu.Game/Screens/Select/BeatmapDetails.cs index 892156cc22..8bb7b45d7d 100644 --- a/osu.Game/Screens/Select/BeatmapDetails.cs +++ b/osu.Game/Screens/Select/BeatmapDetails.cs @@ -321,11 +321,11 @@ namespace osu.Game.Screens.Select } this.FadeIn(transition_duration); - addTextAsync(value); + setTextAsync(value); } } - private void addTextAsync(string text) + private void setTextAsync(string text) { var newTextFlow = new TextFlowContainer { From b4513497d68ec54e447e18c1ebe4b8ec6c264a3c Mon Sep 17 00:00:00 2001 From: FreezyLemon Date: Mon, 27 Nov 2017 08:52:26 +0100 Subject: [PATCH 0844/1263] Added a textContainer reference to MetadataSection so casting is no longer required for setting new text --- osu.Game/Screens/Select/BeatmapDetails.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Select/BeatmapDetails.cs b/osu.Game/Screens/Select/BeatmapDetails.cs index 8bb7b45d7d..2c188319e5 100644 --- a/osu.Game/Screens/Select/BeatmapDetails.cs +++ b/osu.Game/Screens/Select/BeatmapDetails.cs @@ -308,6 +308,7 @@ namespace osu.Game.Screens.Select private class MetadataSection : Container { + private readonly FillFlowContainer textContainer; private TextFlowContainer textFlow; public string Text @@ -338,7 +339,6 @@ namespace osu.Game.Screens.Select LoadComponentAsync(newTextFlow, d => { - var textContainer = (InternalChild as FillFlowContainer); textContainer.Remove(textFlow); textContainer.Add(textFlow = d); }); @@ -355,7 +355,7 @@ namespace osu.Game.Screens.Select RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; - InternalChild = new FillFlowContainer + InternalChild = textContainer = new FillFlowContainer { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, From 82a9b57277e72fa83a354de26c493af4d44c6b6d Mon Sep 17 00:00:00 2001 From: FreezyLemon Date: Mon, 27 Nov 2017 08:58:09 +0100 Subject: [PATCH 0845/1263] Removed unnecessary "using" statement --- osu.Game/Screens/Select/BeatmapDetails.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Screens/Select/BeatmapDetails.cs b/osu.Game/Screens/Select/BeatmapDetails.cs index 2c188319e5..3cd6c3b107 100644 --- a/osu.Game/Screens/Select/BeatmapDetails.cs +++ b/osu.Game/Screens/Select/BeatmapDetails.cs @@ -1,7 +1,6 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using System; using OpenTK; using OpenTK.Graphics; using osu.Framework.Allocation; From cbd7e1ca0de651a7067aad53053e0d01125d0012 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 27 Nov 2017 18:01:00 +0900 Subject: [PATCH 0846/1263] Update submodules --- osu-framework | 2 +- osu-resources | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu-framework b/osu-framework index fe49ccb3c8..d92cec7645 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit fe49ccb3c8f8661d653752d225ae1dc183944bb4 +Subproject commit d92cec764538da2e7ed95bfb566f6bc81a9667c8 diff --git a/osu-resources b/osu-resources index 1750ab8f67..4287ee8043 160000 --- a/osu-resources +++ b/osu-resources @@ -1 +1 @@ -Subproject commit 1750ab8f6761ab35592fd46da71fbe0c141bfd93 +Subproject commit 4287ee8043fb1419017359bc3a5db5dc06bc643f From 760f7d02d9f757fb47002a4ea1c2b34699ccca84 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 27 Nov 2017 18:12:52 +0900 Subject: [PATCH 0847/1263] Remove AlwaysPresent (not actually required) --- osu.Game/Graphics/UserInterface/HoverSounds.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Graphics/UserInterface/HoverSounds.cs b/osu.Game/Graphics/UserInterface/HoverSounds.cs index d26ad35c49..24dbe37567 100644 --- a/osu.Game/Graphics/UserInterface/HoverSounds.cs +++ b/osu.Game/Graphics/UserInterface/HoverSounds.cs @@ -26,7 +26,6 @@ namespace osu.Game.Graphics.UserInterface { SampleSet = sampleSet; RelativeSizeAxes = Axes.Both; - AlwaysPresent = true; } protected override bool OnHover(InputState state) From 51372d7cdaf209a868aa92f5847308a77d4f20da Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 27 Nov 2017 18:19:06 +0900 Subject: [PATCH 0848/1263] Remove HandleInput override from TriangleButton --- osu.Game/Graphics/UserInterface/TriangleButton.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/TriangleButton.cs b/osu.Game/Graphics/UserInterface/TriangleButton.cs index 9fbdf6832f..675e03aef8 100644 --- a/osu.Game/Graphics/UserInterface/TriangleButton.cs +++ b/osu.Game/Graphics/UserInterface/TriangleButton.cs @@ -34,8 +34,6 @@ namespace osu.Game.Graphics.UserInterface Font = @"Exo2.0-Bold", }; - public override bool HandleInput => Action != null; - [BackgroundDependencyLoader] private void load(OsuColour colours) { From 96d42b3e5b6a42ed5947d4485116e2d16f718902 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 27 Nov 2017 18:20:13 +0900 Subject: [PATCH 0849/1263] Fix redundant string interpolation --- osu.Game/Screens/Select/PlaySongSelect.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Select/PlaySongSelect.cs b/osu.Game/Screens/Select/PlaySongSelect.cs index 992bfa52ee..bba6ddf577 100644 --- a/osu.Game/Screens/Select/PlaySongSelect.cs +++ b/osu.Game/Screens/Select/PlaySongSelect.cs @@ -49,7 +49,7 @@ namespace osu.Game.Screens.Select [BackgroundDependencyLoader] private void load(OsuColour colours, AudioManager audio) { - sampleConfirm = audio.Sample.Get($@"SongSelect/confirm-selection"); + sampleConfirm = audio.Sample.Get(@"SongSelect/confirm-selection"); Footer.AddButton(@"mods", colours.Yellow, modSelect, Key.F1, float.MaxValue); From bf5ea027efd9813dbcaf78ba54268ae3da665b8d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 27 Nov 2017 18:26:20 +0900 Subject: [PATCH 0850/1263] Add xmldoc to TriangleButton --- osu.Game/Graphics/UserInterface/TriangleButton.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Graphics/UserInterface/TriangleButton.cs b/osu.Game/Graphics/UserInterface/TriangleButton.cs index 675e03aef8..61e9705064 100644 --- a/osu.Game/Graphics/UserInterface/TriangleButton.cs +++ b/osu.Game/Graphics/UserInterface/TriangleButton.cs @@ -15,6 +15,9 @@ using osu.Game.Graphics.Sprites; namespace osu.Game.Graphics.UserInterface { + /// + /// A button with moving triangles in the background. + /// public class TriangleButton : OsuButton, IFilterable { private Box hover; From 2c53be7853145c2f699104026572eb3e36449100 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 27 Nov 2017 18:39:13 +0900 Subject: [PATCH 0851/1263] Fix possible invalid cast when generating mania patterns --- osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs b/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs index f6d30ad3fa..d5a799b4ed 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs @@ -138,8 +138,8 @@ namespace osu.Game.Rulesets.Mania.Beatmaps Pattern newPattern = conversion.Generate(); lastPattern = newPattern; - var stairPatternGenerator = (HitObjectPatternGenerator)conversion; - lastStair = stairPatternGenerator.StairType; + var stairPatternGenerator = conversion as HitObjectPatternGenerator; + lastStair = stairPatternGenerator?.StairType ?? lastStair; return newPattern.HitObjects; } From 3a01bfc1ef88b89ef8e214fbd981c716f69dd1a1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 27 Nov 2017 18:53:19 +0900 Subject: [PATCH 0852/1263] Remove unnecessary new prefix --- osu.Game/Overlays/Mods/ModButton.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Mods/ModButton.cs b/osu.Game/Overlays/Mods/ModButton.cs index f2a3da4145..77b7c3add2 100644 --- a/osu.Game/Overlays/Mods/ModButton.cs +++ b/osu.Game/Overlays/Mods/ModButton.cs @@ -32,7 +32,7 @@ namespace osu.Game.Overlays.Mods private readonly Container iconsContainer; private SampleChannel sampleOn, sampleOff; - public new Action Action; // Passed the selected mod or null if none + public Action Action; // Passed the selected mod or null if none public string TooltipText => (SelectedMod?.Description ?? Mods.FirstOrDefault()?.Description) ?? string.Empty; From bf8d15108e0085204ff7143cf6c208b04bb35620 Mon Sep 17 00:00:00 2001 From: Santeri Nogelainen Date: Mon, 27 Nov 2017 13:39:01 +0200 Subject: [PATCH 0853/1263] headerbutton now derives from osubutton --- .../Overlays/BeatmapSet/DownloadButton.cs | 2 +- .../Overlays/BeatmapSet/FavouriteButton.cs | 3 +- osu.Game/Overlays/BeatmapSet/HeaderButton.cs | 42 +++++++++---------- 3 files changed, 24 insertions(+), 23 deletions(-) diff --git a/osu.Game/Overlays/BeatmapSet/DownloadButton.cs b/osu.Game/Overlays/BeatmapSet/DownloadButton.cs index 18a0cfd968..b256f82a22 100644 --- a/osu.Game/Overlays/BeatmapSet/DownloadButton.cs +++ b/osu.Game/Overlays/BeatmapSet/DownloadButton.cs @@ -14,10 +14,10 @@ namespace osu.Game.Overlays.BeatmapSet public DownloadButton(string title, string subtitle) { Width = 120; - RelativeSizeAxes = Axes.Y; Child = new Container { + Depth = -1, RelativeSizeAxes = Axes.Both, Padding = new MarginPadding { Horizontal = 10 }, Children = new Drawable[] diff --git a/osu.Game/Overlays/BeatmapSet/FavouriteButton.cs b/osu.Game/Overlays/BeatmapSet/FavouriteButton.cs index 9fd4ac177c..af4c56c614 100644 --- a/osu.Game/Overlays/BeatmapSet/FavouriteButton.cs +++ b/osu.Game/Overlays/BeatmapSet/FavouriteButton.cs @@ -17,7 +17,6 @@ namespace osu.Game.Overlays.BeatmapSet public FavouriteButton() { - RelativeSizeAxes = Axes.Y; Container pink; SpriteIcon icon; @@ -25,6 +24,7 @@ namespace osu.Game.Overlays.BeatmapSet { pink = new Container { + Depth = -1, RelativeSizeAxes = Axes.Both, Alpha = 0f, Children = new Drawable[] @@ -45,6 +45,7 @@ namespace osu.Game.Overlays.BeatmapSet }, icon = new SpriteIcon { + Depth = -1, Anchor = Anchor.Centre, Origin = Anchor.Centre, Icon = FontAwesome.fa_heart_o, diff --git a/osu.Game/Overlays/BeatmapSet/HeaderButton.cs b/osu.Game/Overlays/BeatmapSet/HeaderButton.cs index 3075020fe6..4616128f1a 100644 --- a/osu.Game/Overlays/BeatmapSet/HeaderButton.cs +++ b/osu.Game/Overlays/BeatmapSet/HeaderButton.cs @@ -5,12 +5,15 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Game.Graphics; +using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.Backgrounds; using osu.Game.Graphics.Containers; +using osu.Framework.Audio; +using osu.Framework.Allocation; namespace osu.Game.Overlays.BeatmapSet { - public class HeaderButton : OsuClickableContainer + public class HeaderButton : OsuButton { private readonly Container content; @@ -18,28 +21,25 @@ namespace osu.Game.Overlays.BeatmapSet public HeaderButton() { - CornerRadius = 3; - Masking = true; + Height = 0; + RelativeSizeAxes = Axes.Y; - InternalChildren = new Drawable[] + AddInternal(content = new Container { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = OsuColour.FromHex(@"094c5f"), - }, - new Triangles - { - RelativeSizeAxes = Axes.Both, - ColourLight = OsuColour.FromHex(@"0f7c9b"), - ColourDark = OsuColour.FromHex(@"094c5f"), - TriangleScale = 1.5f, - }, - content = new Container - { - RelativeSizeAxes = Axes.Both, - }, - }; + RelativeSizeAxes = Axes.Both + }); } + + [BackgroundDependencyLoader] + private void load(OsuColour colours, AudioManager audio) + { + Masking = true; + CornerRadius = 3; + BackgroundColour = OsuColour.FromHex(@"094c5f"); + Triangles.ColourLight = OsuColour.FromHex(@"0f7c9b"); + Triangles.ColourDark = OsuColour.FromHex(@"094c5f"); + Triangles.TriangleScale = 1.5f; + } + } } From 96f782e75a65e61f6f54c8bf225cf3ffe8b5b816 Mon Sep 17 00:00:00 2001 From: Santeri Nogelainen Date: Mon, 27 Nov 2017 13:51:56 +0200 Subject: [PATCH 0854/1263] fix object reference issue maybe? --- osu.Game/Overlays/BeatmapSet/HeaderButton.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/BeatmapSet/HeaderButton.cs b/osu.Game/Overlays/BeatmapSet/HeaderButton.cs index 4616128f1a..2296a4e8c0 100644 --- a/osu.Game/Overlays/BeatmapSet/HeaderButton.cs +++ b/osu.Game/Overlays/BeatmapSet/HeaderButton.cs @@ -36,9 +36,9 @@ namespace osu.Game.Overlays.BeatmapSet Masking = true; CornerRadius = 3; BackgroundColour = OsuColour.FromHex(@"094c5f"); - Triangles.ColourLight = OsuColour.FromHex(@"0f7c9b"); - Triangles.ColourDark = OsuColour.FromHex(@"094c5f"); - Triangles.TriangleScale = 1.5f; + this.Triangles.ColourLight = OsuColour.FromHex(@"0f7c9b"); + this.Triangles.ColourDark = OsuColour.FromHex(@"094c5f"); + this.Triangles.TriangleScale = 1.5f; } } From d87235a2891e64708a7e617af753e420eb4efa3e Mon Sep 17 00:00:00 2001 From: Aergwyn Date: Mon, 27 Nov 2017 20:08:16 +0100 Subject: [PATCH 0855/1263] prevent inserting duplicate metadata --- osu.Game/Beatmaps/BeatmapStore.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/osu.Game/Beatmaps/BeatmapStore.cs b/osu.Game/Beatmaps/BeatmapStore.cs index 3875202e32..ef658d2ff6 100644 --- a/osu.Game/Beatmaps/BeatmapStore.cs +++ b/osu.Game/Beatmaps/BeatmapStore.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 Microsoft.EntityFrameworkCore; using osu.Game.Database; @@ -32,6 +33,15 @@ namespace osu.Game.Beatmaps { var context = GetContext(); + foreach (var beatmap in beatmapSet.Beatmaps.Where(b => b.Metadata != null)) + { + var contextMetadata = context.Set().Local.SingleOrDefault(e => e.Equals(beatmap.Metadata)); + if (contextMetadata != null) + beatmap.Metadata = contextMetadata; + else + context.BeatmapMetadata.Attach(beatmap.Metadata); + } + context.BeatmapSetInfo.Attach(beatmapSet); context.SaveChanges(); From c058065a3ab78258ec24ef90a33738a4a8b1af69 Mon Sep 17 00:00:00 2001 From: Aergwyn Date: Mon, 27 Nov 2017 20:24:01 +0100 Subject: [PATCH 0856/1263] remove unnecessary using --- osu.Game/Beatmaps/BeatmapStore.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Beatmaps/BeatmapStore.cs b/osu.Game/Beatmaps/BeatmapStore.cs index ef658d2ff6..352f793aac 100644 --- a/osu.Game/Beatmaps/BeatmapStore.cs +++ b/osu.Game/Beatmaps/BeatmapStore.cs @@ -2,7 +2,6 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; -using System.Collections.Generic; using System.Linq; using Microsoft.EntityFrameworkCore; using osu.Game.Database; From 7f068c0c683c297d4d1257ebe58eca6db26be55c Mon Sep 17 00:00:00 2001 From: jorolf Date: Mon, 27 Nov 2017 21:13:01 +0100 Subject: [PATCH 0857/1263] correct string mistake --- .../Sections/Historical/PaginatedMostPlayedBeatmapContainer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Profile/Sections/Historical/PaginatedMostPlayedBeatmapContainer.cs b/osu.Game/Overlays/Profile/Sections/Historical/PaginatedMostPlayedBeatmapContainer.cs index b7df60a7a2..cec0e9a775 100644 --- a/osu.Game/Overlays/Profile/Sections/Historical/PaginatedMostPlayedBeatmapContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/Historical/PaginatedMostPlayedBeatmapContainer.cs @@ -13,7 +13,7 @@ namespace osu.Game.Overlays.Profile.Sections.Historical public class PaginatedMostPlayedBeatmapContainer : PaginatedContainer { public PaginatedMostPlayedBeatmapContainer(Bindable user) - :base(user, "Most Played Beatmaps", "No performance records. :(") + :base(user, "Most Played Beatmaps", "No records. :(") { ItemsPerPage = 5; From 86de6f8252d52a5f7d327fda28484dbe371813e6 Mon Sep 17 00:00:00 2001 From: Santeri Date: Tue, 28 Nov 2017 00:09:58 +0200 Subject: [PATCH 0858/1263] derives from trianglebutton rather than osubutton --- osu.Game/Overlays/BeatmapSet/DownloadButton.cs | 4 ++-- osu.Game/Overlays/BeatmapSet/FavouriteButton.cs | 4 ++-- osu.Game/Overlays/BeatmapSet/HeaderButton.cs | 16 ++++------------ 3 files changed, 8 insertions(+), 16 deletions(-) diff --git a/osu.Game/Overlays/BeatmapSet/DownloadButton.cs b/osu.Game/Overlays/BeatmapSet/DownloadButton.cs index b256f82a22..47787d2ced 100644 --- a/osu.Game/Overlays/BeatmapSet/DownloadButton.cs +++ b/osu.Game/Overlays/BeatmapSet/DownloadButton.cs @@ -15,7 +15,7 @@ namespace osu.Game.Overlays.BeatmapSet { Width = 120; - Child = new Container + Add(new Container { Depth = -1, RelativeSizeAxes = Axes.Both, @@ -53,7 +53,7 @@ namespace osu.Game.Overlays.BeatmapSet Margin = new MarginPadding { Right = 5 }, }, }, - }; + }); } } } diff --git a/osu.Game/Overlays/BeatmapSet/FavouriteButton.cs b/osu.Game/Overlays/BeatmapSet/FavouriteButton.cs index af4c56c614..77be4da5f8 100644 --- a/osu.Game/Overlays/BeatmapSet/FavouriteButton.cs +++ b/osu.Game/Overlays/BeatmapSet/FavouriteButton.cs @@ -20,7 +20,7 @@ namespace osu.Game.Overlays.BeatmapSet Container pink; SpriteIcon icon; - Children = new Drawable[] + AddRange(new Drawable[] { pink = new Container { @@ -52,7 +52,7 @@ namespace osu.Game.Overlays.BeatmapSet Size = new Vector2(18), Shadow = false, }, - }; + }); Favourited.ValueChanged += value => { diff --git a/osu.Game/Overlays/BeatmapSet/HeaderButton.cs b/osu.Game/Overlays/BeatmapSet/HeaderButton.cs index 2296a4e8c0..6c7edb252e 100644 --- a/osu.Game/Overlays/BeatmapSet/HeaderButton.cs +++ b/osu.Game/Overlays/BeatmapSet/HeaderButton.cs @@ -13,21 +13,13 @@ using osu.Framework.Allocation; namespace osu.Game.Overlays.BeatmapSet { - public class HeaderButton : OsuButton + public class HeaderButton : TriangleButton { - private readonly Container content; - - protected override Container Content => content; public HeaderButton() { Height = 0; RelativeSizeAxes = Axes.Y; - - AddInternal(content = new Container - { - RelativeSizeAxes = Axes.Both - }); } [BackgroundDependencyLoader] @@ -36,9 +28,9 @@ namespace osu.Game.Overlays.BeatmapSet Masking = true; CornerRadius = 3; BackgroundColour = OsuColour.FromHex(@"094c5f"); - this.Triangles.ColourLight = OsuColour.FromHex(@"0f7c9b"); - this.Triangles.ColourDark = OsuColour.FromHex(@"094c5f"); - this.Triangles.TriangleScale = 1.5f; + Triangles.ColourLight = OsuColour.FromHex(@"0f7c9b"); + Triangles.ColourDark = OsuColour.FromHex(@"094c5f"); + Triangles.TriangleScale = 1.5f; } } From 49949bf6984d712a0e3267f7f23350180983888d Mon Sep 17 00:00:00 2001 From: Santeri Date: Tue, 28 Nov 2017 00:20:44 +0200 Subject: [PATCH 0859/1263] fix minor param/directive errors --- osu.Game/Overlays/BeatmapSet/HeaderButton.cs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/osu.Game/Overlays/BeatmapSet/HeaderButton.cs b/osu.Game/Overlays/BeatmapSet/HeaderButton.cs index 6c7edb252e..cfcf26d0bd 100644 --- a/osu.Game/Overlays/BeatmapSet/HeaderButton.cs +++ b/osu.Game/Overlays/BeatmapSet/HeaderButton.cs @@ -2,12 +2,8 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; using osu.Game.Graphics; using osu.Game.Graphics.UserInterface; -using osu.Game.Graphics.Backgrounds; -using osu.Game.Graphics.Containers; using osu.Framework.Audio; using osu.Framework.Allocation; @@ -23,7 +19,7 @@ namespace osu.Game.Overlays.BeatmapSet } [BackgroundDependencyLoader] - private void load(OsuColour colours, AudioManager audio) + private void load() { Masking = true; CornerRadius = 3; From e9277d8cb1e1d1d0db6b9cfbc638f34a6c3fe346 Mon Sep 17 00:00:00 2001 From: Santeri Date: Tue, 28 Nov 2017 00:27:58 +0200 Subject: [PATCH 0860/1263] last directive error... --- osu.Game/Overlays/BeatmapSet/HeaderButton.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Overlays/BeatmapSet/HeaderButton.cs b/osu.Game/Overlays/BeatmapSet/HeaderButton.cs index cfcf26d0bd..371e438a34 100644 --- a/osu.Game/Overlays/BeatmapSet/HeaderButton.cs +++ b/osu.Game/Overlays/BeatmapSet/HeaderButton.cs @@ -4,7 +4,6 @@ using osu.Framework.Graphics; using osu.Game.Graphics; using osu.Game.Graphics.UserInterface; -using osu.Framework.Audio; using osu.Framework.Allocation; namespace osu.Game.Overlays.BeatmapSet From 473eba9776e1d8cfcb54ca65f9a8f7619202c168 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 28 Nov 2017 12:09:44 +0900 Subject: [PATCH 0861/1263] Remove precision limitation on chat height to allow pixel-perfect dragging --- osu.Game/Configuration/OsuConfigManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs index c087a5afb7..1a7d29e907 100644 --- a/osu.Game/Configuration/OsuConfigManager.cs +++ b/osu.Game/Configuration/OsuConfigManager.cs @@ -22,7 +22,7 @@ namespace osu.Game.Configuration Set(OsuSetting.SelectionRandomType, SelectionRandomType.RandomPermutation); - Set(OsuSetting.ChatDisplayHeight, ChatOverlay.DEFAULT_HEIGHT, 0.2, 1, 0.01); + Set(OsuSetting.ChatDisplayHeight, ChatOverlay.DEFAULT_HEIGHT, 0.2, 1); // Online settings Set(OsuSetting.Username, string.Empty); From ac1fb5118c6b075de0d333a6f49665b6396b8d53 Mon Sep 17 00:00:00 2001 From: Unknown Date: Tue, 28 Nov 2017 11:35:39 +0530 Subject: [PATCH 0862/1263] Fix line endings and derp that was causing request failures. --- osu.Game/Screens/Select/Leaderboards/Leaderboard.cs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs b/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs index 62bd292710..5574dd69a1 100644 --- a/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs +++ b/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs @@ -24,7 +24,7 @@ using osu.Framework.Logging; using System.Net; using osu.Game.Rulesets; using osu.Framework.Input; -using osu.Game.Beatmaps.ControlPoints; +using osu.Game.Beatmaps.ControlPoints; using osu.Framework.Audio.Track; namespace osu.Game.Screens.Select.Leaderboards @@ -51,7 +51,6 @@ namespace osu.Game.Screens.Select.Leaderboards set { scores = value; - getScoresRequest?.Cancel(); getScoresRequest = null; placeholderContainer.FadeOut(fade_duration); @@ -202,6 +201,8 @@ namespace osu.Game.Screens.Select.Leaderboards { if (!IsLoaded) return; + getScoresRequest?.Cancel(); + Scores = null; if (api == null || Beatmap?.OnlineBeatmapID == null) return; @@ -318,7 +319,7 @@ namespace osu.Game.Screens.Select.Leaderboards icon.RotateTo(rightWard ? 3 : -3, duration * 2, Easing.OutCubic); icon.Animate( i => i.MoveToY(-3, duration, Easing.Out), - i => i.ScaleTo(IsHovered ? 1.3f : 1.1f, duration, Easing.Out) + i => i.ScaleTo(IsHovered ? 1.3f : 1.1f, duration, Easing.Out) ).Then( i => i.MoveToY(0, duration, Easing.In), i => i.ScaleTo(IsHovered ? 1.4f : 1f, duration, Easing.In) @@ -350,7 +351,7 @@ namespace osu.Game.Screens.Select.Leaderboards protected override bool OnMouseUp(InputState state, MouseUpEventArgs args) { - icon.ScaleTo(1.2f, 400, Easing.OutElastic).Then().ScaleTo(1f, 400, Easing.OutElastic); + icon.ScaleTo(1.2f, 400, Easing.OutElastic); return base.OnMouseUp(state, args); } } From 84702211ecd93318003af357324386f0267a6d5f Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 28 Nov 2017 15:17:02 +0900 Subject: [PATCH 0863/1263] Rewrite mania auto generator to properly account for overlapping objects --- .../Replays/ManiaAutoGenerator.cs | 109 +++++------------- 1 file changed, 29 insertions(+), 80 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Replays/ManiaAutoGenerator.cs b/osu.Game.Rulesets.Mania/Replays/ManiaAutoGenerator.cs index 64982532a7..35ca868d5a 100644 --- a/osu.Game.Rulesets.Mania/Replays/ManiaAutoGenerator.cs +++ b/osu.Game.Rulesets.Mania/Replays/ManiaAutoGenerator.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.Beatmaps; using osu.Game.Rulesets.Mania.Objects; @@ -13,7 +14,7 @@ namespace osu.Game.Rulesets.Mania.Replays { internal class ManiaAutoGenerator : AutoGenerator { - private const double release_delay = 20; + public const double RELEASE_DELAY = 20; private readonly int availableColumns; @@ -32,102 +33,50 @@ namespace osu.Game.Rulesets.Mania.Replays // Todo: Realistically this shouldn't be needed, but the first frame is skipped with the way replays are currently handled Replay.Frames.Add(new ReplayFrame(-100000, null, null, ReplayButtonState.None)); - double[] holdEndTimes = new double[availableColumns]; - for (int i = 0; i < availableColumns; i++) - holdEndTimes[i] = double.NegativeInfinity; + var pointGroups = generateActionPoints().GroupBy(a => a.Time).OrderBy(g => g.First().Time); - // Notes are handled row-by-row - foreach (var objGroup in Beatmap.HitObjects.GroupBy(h => h.StartTime)) + int activeColumns = 0; + foreach (var group in pointGroups) { - double groupTime = objGroup.Key; - - int activeColumns = 0; - - // Get the previously held-down active columns - for (int i = 0; i < availableColumns; i++) + foreach (var point in group) { - if (holdEndTimes[i] > groupTime) - activeColumns |= 1 << i; + if (point is HitPoint) + activeColumns |= 1 << point.Column; + if (point is ReleasePoint) + activeColumns ^= 1 << point.Column; } - // Add on the group columns, keeping track of the held notes for the next rows - foreach (var obj in objGroup) - { - var holdNote = obj as HoldNote; - if (holdNote != null) - holdEndTimes[obj.Column] = Math.Max(holdEndTimes[obj.Column], holdNote.EndTime); - - activeColumns |= 1 << obj.Column; - } - - Replay.Frames.Add(new ReplayFrame(groupTime, activeColumns, null, ReplayButtonState.None)); - - // Add the release frames. We can't do this with the loop above because we need activeColumns to be fully populated - foreach (var obj in objGroup.GroupBy(h => (h as IHasEndTime)?.EndTime ?? h.StartTime + release_delay).OrderBy(h => h.Key)) - { - var groupEndTime = obj.Key; - - int activeColumnsAtEnd = 0; - for (int i = 0; i < availableColumns; i++) - { - if (holdEndTimes[i] > groupEndTime) - activeColumnsAtEnd |= 1 << i; - } - - Replay.Frames.Add(new ReplayFrame(groupEndTime, activeColumnsAtEnd, 0, ReplayButtonState.None)); - } + Replay.Frames.Add(new ReplayFrame(group.First().Time, activeColumns, 0, ReplayButtonState.None)); } - Replay.Frames = Replay.Frames - // Pick the maximum activeColumns for all frames at the same time - .GroupBy(f => f.Time) - .Select(g => new ReplayFrame(g.First().Time, maxMouseX(g), 0, ReplayButtonState.None)) - // The addition of release frames above maybe result in unordered frames, but we need them ordered - .OrderBy(f => f.Time) - .ToList(); - return Replay; } - /// - /// Finds the maximum by count of bits from a grouping of s. - /// - /// The grouping to search. - /// The maximum by count of bits. - private float maxMouseX(IGrouping group) + private IEnumerable generateActionPoints() { - int currentCount = -1; - int currentMax = 0; - - foreach (var val in group) + foreach (var obj in Beatmap.HitObjects) { - int newCount = countBits((int)(val.MouseX ?? 0)); - if (newCount > currentCount) - { - currentCount = newCount; - currentMax = (int)(val.MouseX ?? 0); - } + yield return new HitPoint { Time = obj.StartTime, Column = obj.Column }; + yield return new ReleasePoint { Time = ((obj as IHasEndTime)?.EndTime ?? obj.StartTime) + RELEASE_DELAY, Column = obj.Column }; } - - return currentMax; } - /// - /// Counts the number of bits set in a value. - /// - /// The value to count. - /// The number of set bits. - private int countBits(int value) + private interface IActionPoint { - int count = 0; - while (value > 0) - { - if ((value & 1) > 0) - count++; - value >>= 1; - } + double Time { get; set; } + int Column { get; set; } + } - return count; + private struct HitPoint : IActionPoint + { + public double Time { get; set; } + public int Column { get; set; } + } + + private struct ReleasePoint : IActionPoint + { + public double Time { get; set; } + public int Column { get; set; } } } } From b97cab4f29166a03a46ae9e415a60432b79d34fa Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 28 Nov 2017 15:27:20 +0900 Subject: [PATCH 0864/1263] Make ManiaFramedReplayInputHandler properly account for special keys These are interleaved into the playfield, so we have to use the playfield's columns' actions. --- .../Replays/ManiaFramedReplayInputHandler.cs | 16 +++++++++++++--- .../UI/ManiaRulesetContainer.cs | 2 +- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Replays/ManiaFramedReplayInputHandler.cs b/osu.Game.Rulesets.Mania/Replays/ManiaFramedReplayInputHandler.cs index e352997f2c..8440e4347d 100644 --- a/osu.Game.Rulesets.Mania/Replays/ManiaFramedReplayInputHandler.cs +++ b/osu.Game.Rulesets.Mania/Replays/ManiaFramedReplayInputHandler.cs @@ -2,29 +2,39 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System.Collections.Generic; +using System.Linq; using osu.Framework.Input; +using osu.Game.Rulesets.Mania.UI; using osu.Game.Rulesets.Replays; namespace osu.Game.Rulesets.Mania.Replays { internal class ManiaFramedReplayInputHandler : FramedReplayInputHandler { - public ManiaFramedReplayInputHandler(Replay replay) + private readonly ManiaRulesetContainer container; + + public ManiaFramedReplayInputHandler(Replay replay, ManiaRulesetContainer container) : base(replay) { + this.container = container; } + protected override bool AtImportantFrame => CurrentFrame.MouseX != PreviousFrame.MouseX; + + private ManiaPlayfield playfield; public override List GetPendingStates() { var actions = new List(); - int activeColumns = (int)(CurrentFrame.MouseX ?? 0); + if (playfield == null) + playfield = (ManiaPlayfield)container.Playfield; + int activeColumns = (int)(CurrentFrame.MouseX ?? 0); int counter = 0; while (activeColumns > 0) { if ((activeColumns & 1) > 0) - actions.Add(ManiaAction.Key1 + counter); + actions.Add(playfield.Columns.ElementAt(counter).Action); counter++; activeColumns >>= 1; } diff --git a/osu.Game.Rulesets.Mania/UI/ManiaRulesetContainer.cs b/osu.Game.Rulesets.Mania/UI/ManiaRulesetContainer.cs index 08acd46c57..cbbcb84b31 100644 --- a/osu.Game.Rulesets.Mania/UI/ManiaRulesetContainer.cs +++ b/osu.Game.Rulesets.Mania/UI/ManiaRulesetContainer.cs @@ -124,6 +124,6 @@ namespace osu.Game.Rulesets.Mania.UI protected override SpeedAdjustmentContainer CreateSpeedAdjustmentContainer(MultiplierControlPoint controlPoint) => new ManiaSpeedAdjustmentContainer(controlPoint, ScrollingAlgorithm.Basic); - protected override FramedReplayInputHandler CreateReplayInputHandler(Replay replay) => new ManiaFramedReplayInputHandler(replay); + protected override FramedReplayInputHandler CreateReplayInputHandler(Replay replay) => new ManiaFramedReplayInputHandler(replay, this); } } From e832f163e7174873ae2d68058e6e51ecc1218cf8 Mon Sep 17 00:00:00 2001 From: Unknown Date: Tue, 28 Nov 2017 11:57:29 +0530 Subject: [PATCH 0865/1263] Add failure test case. - Only show failure if request wasn't cancelled --- osu.Game.Tests/Visual/TestCaseLeaderboard.cs | 23 +++++++- .../Select/Leaderboards/Leaderboard.cs | 59 +++++++++---------- 2 files changed, 49 insertions(+), 33 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCaseLeaderboard.cs b/osu.Game.Tests/Visual/TestCaseLeaderboard.cs index ad4aa63aa8..52daf95810 100644 --- a/osu.Game.Tests/Visual/TestCaseLeaderboard.cs +++ b/osu.Game.Tests/Visual/TestCaseLeaderboard.cs @@ -9,6 +9,7 @@ using osu.Game.Users; using osu.Framework.Allocation; using OpenTK; using System.Linq; +using System.Net; using osu.Game.Beatmaps; using osu.Game.Rulesets; @@ -19,11 +20,11 @@ namespace osu.Game.Tests.Visual { private RulesetStore rulesets; - private readonly Leaderboard leaderboard; + private readonly FailableLeaderboard leaderboard; public TestCaseLeaderboard() { - Add(leaderboard = new Leaderboard + Add(leaderboard = new FailableLeaderboard { Origin = Anchor.Centre, Anchor = Anchor.Centre, @@ -33,8 +34,8 @@ namespace osu.Game.Tests.Visual AddStep(@"New Scores", newScores); AddStep(@"Empty Scores", () => leaderboard.Scores = Enumerable.Empty()); + AddStep(@"Network failure", networkFailure); AddStep(@"Real beatmap", realBeatmap); - newScores(); } [BackgroundDependencyLoader] @@ -263,5 +264,21 @@ namespace osu.Game.Tests.Visual }, }; } + + private void networkFailure() + { + leaderboard.Beatmap = new BeatmapInfo(); + } + + private class FailableLeaderboard : Leaderboard + { + protected override void UpdateScores() + { + if (Beatmap?.OnlineBeatmapID == null) + OnUpdateFailed(new WebException()); + else + base.UpdateScores(); + } + } } } diff --git a/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs b/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs index 5574dd69a1..8fd04e2c25 100644 --- a/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs +++ b/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs @@ -21,7 +21,6 @@ using System.Linq; using osu.Game.Graphics.Sprites; using osu.Game.Graphics; using osu.Framework.Logging; -using System.Net; using osu.Game.Rulesets; using osu.Framework.Input; using osu.Game.Beatmaps.ControlPoints; @@ -51,7 +50,6 @@ namespace osu.Game.Screens.Select.Leaderboards set { scores = value; - getScoresRequest = null; placeholderContainer.FadeOut(fade_duration); scrollFlow?.FadeOut(fade_duration).Expire(); @@ -120,7 +118,7 @@ namespace osu.Game.Screens.Select.Leaderboards if (value == scope) return; scope = value; - updateScores(); + UpdateScores(); } } @@ -171,7 +169,7 @@ namespace osu.Game.Screens.Select.Leaderboards Scores = null; pendingBeatmapSwitch?.Cancel(); - pendingBeatmapSwitch = Schedule(updateScores); + pendingBeatmapSwitch = Schedule(UpdateScores); } } @@ -195,13 +193,14 @@ namespace osu.Game.Screens.Select.Leaderboards private GetScoresRequest getScoresRequest; - private void handleRulesetChange(RulesetInfo ruleset) => updateScores(); + private void handleRulesetChange(RulesetInfo ruleset) => UpdateScores(); - private void updateScores() + protected virtual void UpdateScores() { if (!IsLoaded) return; getScoresRequest?.Cancel(); + getScoresRequest = null; Scores = null; @@ -221,34 +220,34 @@ namespace osu.Game.Screens.Select.Leaderboards { Scores = r.Scores; }; - getScoresRequest.Failure += e => - { - // TODO: check why failure is repeatedly invoked even on successful requests - if (e is WebException) - { - Scores = null; - placeholderFlow.Children = new Drawable[] - { - new RetryButton - { - Action = updateScores, - Margin = new MarginPadding { Right = 10 }, - }, - new OsuSpriteText - { - Anchor = Anchor.TopLeft, - Text = @"Couldn't retrieve scores!", - TextSize = 22, - }, - }; - placeholderContainer.FadeIn(fade_duration); - Logger.Error(e, @"Couldn't fetch beatmap scores!"); - } - }; + getScoresRequest.Failure += OnUpdateFailed; api.Queue(getScoresRequest); } + protected void OnUpdateFailed(Exception e) + { + if (e is OperationCanceledException) return; + + Scores = null; + placeholderFlow.Children = new Drawable[] + { + new RetryButton + { + Action = UpdateScores, + Margin = new MarginPadding { Right = 10 }, + }, + new OsuSpriteText + { + Anchor = Anchor.TopLeft, + Text = @"Couldn't retrieve scores!", + TextSize = 22, + }, + }; + placeholderContainer.FadeIn(fade_duration); + Logger.Error(e, @"Couldn't fetch beatmap scores!"); + } + protected override void Update() { base.Update(); From a30cd42ba2cb43b7535a60c4345bd6c77d26b464 Mon Sep 17 00:00:00 2001 From: Unknown Date: Tue, 28 Nov 2017 14:38:35 +0530 Subject: [PATCH 0866/1263] Make retry button not look drunk. --- osu.Game/Screens/Select/Leaderboards/Leaderboard.cs | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs b/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs index 8fd04e2c25..e80f502e73 100644 --- a/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs +++ b/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs @@ -299,6 +299,7 @@ namespace osu.Game.Screens.Select.Leaderboards { Icon = FontAwesome.fa_refresh, Size = new Vector2(26), + Shadow = true, }, }; } @@ -309,13 +310,10 @@ namespace osu.Game.Screens.Select.Leaderboards this.colours = colours; } - private bool rightWard; - protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, TrackAmplitudes amplitudes) { var duration = timingPoint.BeatLength / 2; - icon.RotateTo(rightWard ? 3 : -3, duration * 2, Easing.OutCubic); icon.Animate( i => i.MoveToY(-3, duration, Easing.Out), i => i.ScaleTo(IsHovered ? 1.3f : 1.1f, duration, Easing.Out) @@ -323,8 +321,6 @@ namespace osu.Game.Screens.Select.Leaderboards i => i.MoveToY(0, duration, Easing.In), i => i.ScaleTo(IsHovered ? 1.4f : 1f, duration, Easing.In) ); - - rightWard = !rightWard; } protected override bool OnHover(InputState state) @@ -342,15 +338,13 @@ namespace osu.Game.Screens.Select.Leaderboards protected override bool OnMouseDown(InputState state, MouseDownEventArgs args) { - icon.ClearTransforms(); - icon.FlashColour(colours.Yellow, 400); - icon.ScaleTo(0.8f, 400, Easing.InElastic); + icon.FadeColour(colours.Yellow, 400); return base.OnMouseDown(state, args); } protected override bool OnMouseUp(InputState state, MouseUpEventArgs args) { - icon.ScaleTo(1.2f, 400, Easing.OutElastic); + icon.FadeColour(Color4.White, 400); return base.OnMouseUp(state, args); } } From bd88df2722a589e4d7e7454a9c390937cb3d3193 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 24 Nov 2017 14:39:39 +0900 Subject: [PATCH 0867/1263] Add note about sequential execution of ConvertHitObject --- osu.Game/Beatmaps/BeatmapConverter.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Beatmaps/BeatmapConverter.cs b/osu.Game/Beatmaps/BeatmapConverter.cs index 962c790fb2..6132322f1e 100644 --- a/osu.Game/Beatmaps/BeatmapConverter.cs +++ b/osu.Game/Beatmaps/BeatmapConverter.cs @@ -80,6 +80,7 @@ namespace osu.Game.Beatmaps /// /// Performs the conversion of a hit object. + /// This method generally executed sequentially for all objects in a beatmap. /// /// The hit object to convert. /// The un-converted Beatmap. From 2deb33ac4190a0e2e43975199e5b4039a95606de Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 24 Nov 2017 14:49:38 +0900 Subject: [PATCH 0868/1263] Add basic fruit scaling support --- osu.Game.Rulesets.Catch/Objects/CatchBaseHit.cs | 11 +++++++++++ .../Objects/Drawable/DrawableCatchHitObject.cs | 3 +++ 2 files changed, 14 insertions(+) diff --git a/osu.Game.Rulesets.Catch/Objects/CatchBaseHit.cs b/osu.Game.Rulesets.Catch/Objects/CatchBaseHit.cs index 2f33cf1093..aac25a1fa7 100644 --- a/osu.Game.Rulesets.Catch/Objects/CatchBaseHit.cs +++ b/osu.Game.Rulesets.Catch/Objects/CatchBaseHit.cs @@ -1,6 +1,8 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using osu.Game.Beatmaps; +using osu.Game.Beatmaps.ControlPoints; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Types; using OpenTK.Graphics; @@ -20,5 +22,14 @@ namespace osu.Game.Rulesets.Catch.Objects /// The next fruit starts a new combo. Used for explodey. /// public virtual bool LastInCombo { get; set; } + + public float Scale { get; set; } = 1; + + public override void ApplyDefaults(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) + { + base.ApplyDefaults(controlPointInfo, difficulty); + + Scale = 1.0f - 0.7f * (difficulty.CircleSize - 5) / 5; + } } } diff --git a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableCatchHitObject.cs b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableCatchHitObject.cs index e057bf3d8e..02efd81da3 100644 --- a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableCatchHitObject.cs +++ b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableCatchHitObject.cs @@ -5,6 +5,7 @@ using System; using osu.Framework.Graphics; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Objects.Drawables; +using OpenTK; namespace osu.Game.Rulesets.Catch.Objects.Drawable { @@ -17,6 +18,8 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable : base(hitObject) { HitObject = hitObject; + + Scale = new Vector2(HitObject.Scale); } } From 8f3fd7092e3692e31cb9e13d03fe3fe0306fd8b3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 28 Nov 2017 18:37:41 +0900 Subject: [PATCH 0869/1263] CatchBaseHit -> CatchHitObject Also moves default scale to CatchHitObject. --- osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapConverter.cs | 4 ++-- osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs | 6 +++--- osu.Game.Rulesets.Catch/CatchDifficultyCalculator.cs | 4 ++-- .../Objects/{CatchBaseHit.cs => CatchHitObject.cs} | 4 +++- .../Objects/Drawable/DrawableCatchHitObject.cs | 8 ++++---- .../Objects/Drawable/DrawableJuiceStream.cs | 4 ++-- osu.Game.Rulesets.Catch/Objects/Drawable/Pieces/Pulp.cs | 2 +- osu.Game.Rulesets.Catch/Objects/Droplet.cs | 2 +- osu.Game.Rulesets.Catch/Objects/Fruit.cs | 2 +- osu.Game.Rulesets.Catch/Objects/JuiceStream.cs | 6 +++--- osu.Game.Rulesets.Catch/Scoring/CatchScoreProcessor.cs | 6 +++--- osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs | 2 +- osu.Game.Rulesets.Catch/UI/CatchRulesetContainer.cs | 8 ++++---- osu.Game.Rulesets.Catch/UI/Catcher.cs | 2 +- osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj | 2 +- 15 files changed, 32 insertions(+), 30 deletions(-) rename osu.Game.Rulesets.Catch/Objects/{CatchBaseHit.cs => CatchHitObject.cs} (86%) diff --git a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapConverter.cs b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapConverter.cs index 7126b6586d..6b9ec8b9a4 100644 --- a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapConverter.cs +++ b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapConverter.cs @@ -11,11 +11,11 @@ using osu.Game.Rulesets.Objects; namespace osu.Game.Rulesets.Catch.Beatmaps { - internal class CatchBeatmapConverter : BeatmapConverter + internal class CatchBeatmapConverter : BeatmapConverter { protected override IEnumerable ValidConversionTypes { get; } = new[] { typeof(IHasXPosition) }; - protected override IEnumerable ConvertHitObject(HitObject obj, Beatmap beatmap) + protected override IEnumerable ConvertHitObject(HitObject obj, Beatmap beatmap) { var curveData = obj as IHasCurve; var positionData = obj as IHasXPosition; diff --git a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs index 7fac19d135..b2f7fdabfc 100644 --- a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs +++ b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs @@ -6,9 +6,9 @@ using osu.Game.Rulesets.Catch.Objects; namespace osu.Game.Rulesets.Catch.Beatmaps { - internal class CatchBeatmapProcessor : BeatmapProcessor + internal class CatchBeatmapProcessor : BeatmapProcessor { - public override void PostProcess(Beatmap beatmap) + public override void PostProcess(Beatmap beatmap) { if (beatmap.ComboColors.Count == 0) return; @@ -16,7 +16,7 @@ namespace osu.Game.Rulesets.Catch.Beatmaps int comboIndex = 0; int colourIndex = 0; - CatchBaseHit lastObj = null; + CatchHitObject lastObj = null; foreach (var obj in beatmap.HitObjects) { diff --git a/osu.Game.Rulesets.Catch/CatchDifficultyCalculator.cs b/osu.Game.Rulesets.Catch/CatchDifficultyCalculator.cs index b77be9d1f0..4740458dfb 100644 --- a/osu.Game.Rulesets.Catch/CatchDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Catch/CatchDifficultyCalculator.cs @@ -8,7 +8,7 @@ using System.Collections.Generic; namespace osu.Game.Rulesets.Catch { - public class CatchDifficultyCalculator : DifficultyCalculator + public class CatchDifficultyCalculator : DifficultyCalculator { public CatchDifficultyCalculator(Beatmap beatmap) : base(beatmap) { @@ -16,6 +16,6 @@ namespace osu.Game.Rulesets.Catch public override double Calculate(Dictionary categoryDifficulty = null) => 0; - protected override BeatmapConverter CreateBeatmapConverter(Beatmap beatmap) => new CatchBeatmapConverter(); + protected override BeatmapConverter CreateBeatmapConverter(Beatmap beatmap) => new CatchBeatmapConverter(); } } diff --git a/osu.Game.Rulesets.Catch/Objects/CatchBaseHit.cs b/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs similarity index 86% rename from osu.Game.Rulesets.Catch/Objects/CatchBaseHit.cs rename to osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs index aac25a1fa7..cb4e6453ce 100644 --- a/osu.Game.Rulesets.Catch/Objects/CatchBaseHit.cs +++ b/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs @@ -9,8 +9,10 @@ using OpenTK.Graphics; namespace osu.Game.Rulesets.Catch.Objects { - public abstract class CatchBaseHit : HitObject, IHasXPosition, IHasCombo + public abstract class CatchHitObject : HitObject, IHasXPosition, IHasCombo { + public const double OBJECT_RADIUS = 44; + public float X { get; set; } public Color4 ComboColour { get; set; } = Color4.Gray; diff --git a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableCatchHitObject.cs b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableCatchHitObject.cs index 02efd81da3..b90a06b94e 100644 --- a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableCatchHitObject.cs +++ b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableCatchHitObject.cs @@ -10,7 +10,7 @@ using OpenTK; namespace osu.Game.Rulesets.Catch.Objects.Drawable { public abstract class DrawableCatchHitObject : DrawableCatchHitObject - where TObject : CatchBaseHit + where TObject : CatchHitObject { public new TObject HitObject; @@ -23,9 +23,9 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable } } - public abstract class DrawableCatchHitObject : DrawableScrollingHitObject + public abstract class DrawableCatchHitObject : DrawableScrollingHitObject { - protected DrawableCatchHitObject(CatchBaseHit hitObject) + protected DrawableCatchHitObject(CatchHitObject hitObject) : base(hitObject) { RelativePositionAxes = Axes.Both; @@ -33,7 +33,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable Y = (float)HitObject.StartTime; } - public Func CheckPosition; + public Func CheckPosition; protected override void CheckForJudgements(bool userTriggered, double timeOffset) { diff --git a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableJuiceStream.cs b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableJuiceStream.cs index afda91d0b4..bfb674d1b4 100644 --- a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableJuiceStream.cs +++ b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableJuiceStream.cs @@ -25,7 +25,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable RelativeChildSize = new Vector2(1, (float)HitObject.Duration) }; - foreach (CatchBaseHit tick in s.Ticks) + foreach (CatchHitObject tick in s.Ticks) { TinyDroplet tiny = tick as TinyDroplet; if (tiny != null) @@ -44,7 +44,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable } } - protected override void AddNested(DrawableHitObject h) + protected override void AddNested(DrawableHitObject h) { ((DrawableCatchHitObject)h).CheckPosition = o => CheckPosition?.Invoke(o) ?? false; dropletContainer.Add(h); diff --git a/osu.Game.Rulesets.Catch/Objects/Drawable/Pieces/Pulp.cs b/osu.Game.Rulesets.Catch/Objects/Drawable/Pieces/Pulp.cs index 00ddd365e3..2de266b3f0 100644 --- a/osu.Game.Rulesets.Catch/Objects/Drawable/Pieces/Pulp.cs +++ b/osu.Game.Rulesets.Catch/Objects/Drawable/Pieces/Pulp.cs @@ -13,7 +13,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable.Pieces { public class Pulp : Circle, IHasAccentColour { - public const float PULP_SIZE = 20; + public const float PULP_SIZE = (float)CatchHitObject.OBJECT_RADIUS / 2.2f; public Pulp() { diff --git a/osu.Game.Rulesets.Catch/Objects/Droplet.cs b/osu.Game.Rulesets.Catch/Objects/Droplet.cs index b1206e0d75..a2bdf830e5 100644 --- a/osu.Game.Rulesets.Catch/Objects/Droplet.cs +++ b/osu.Game.Rulesets.Catch/Objects/Droplet.cs @@ -3,7 +3,7 @@ namespace osu.Game.Rulesets.Catch.Objects { - public class Droplet : CatchBaseHit + public class Droplet : CatchHitObject { } } diff --git a/osu.Game.Rulesets.Catch/Objects/Fruit.cs b/osu.Game.Rulesets.Catch/Objects/Fruit.cs index fc55f83969..5f1060fb51 100644 --- a/osu.Game.Rulesets.Catch/Objects/Fruit.cs +++ b/osu.Game.Rulesets.Catch/Objects/Fruit.cs @@ -3,7 +3,7 @@ namespace osu.Game.Rulesets.Catch.Objects { - public class Fruit : CatchBaseHit + public class Fruit : CatchHitObject { } } diff --git a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs index 6462f6f6a8..bf9f0bd44b 100644 --- a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs +++ b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs @@ -15,7 +15,7 @@ using osu.Framework.Lists; namespace osu.Game.Rulesets.Catch.Objects { - public class JuiceStream : CatchBaseHit, IHasCurve + public class JuiceStream : CatchHitObject, IHasCurve { /// /// Positional distance that results in a duration of one second, before any speed adjustments. @@ -42,11 +42,11 @@ namespace osu.Game.Rulesets.Catch.Objects TickDistance = scoringDistance / difficulty.SliderTickRate; } - public IEnumerable Ticks + public IEnumerable Ticks { get { - SortedList ticks = new SortedList((a, b) => a.StartTime.CompareTo(b.StartTime)); + SortedList ticks = new SortedList((a, b) => a.StartTime.CompareTo(b.StartTime)); if (TickDistance == 0) return ticks; diff --git a/osu.Game.Rulesets.Catch/Scoring/CatchScoreProcessor.cs b/osu.Game.Rulesets.Catch/Scoring/CatchScoreProcessor.cs index 66a5636b74..0806c4b29d 100644 --- a/osu.Game.Rulesets.Catch/Scoring/CatchScoreProcessor.cs +++ b/osu.Game.Rulesets.Catch/Scoring/CatchScoreProcessor.cs @@ -10,14 +10,14 @@ using osu.Game.Rulesets.UI; namespace osu.Game.Rulesets.Catch.Scoring { - internal class CatchScoreProcessor : ScoreProcessor + internal class CatchScoreProcessor : ScoreProcessor { - public CatchScoreProcessor(RulesetContainer rulesetContainer) + public CatchScoreProcessor(RulesetContainer rulesetContainer) : base(rulesetContainer) { } - protected override void SimulateAutoplay(Beatmap beatmap) + protected override void SimulateAutoplay(Beatmap beatmap) { foreach (var obj in beatmap.HitObjects) { diff --git a/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs b/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs index 987eef5e45..33903f649e 100644 --- a/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs +++ b/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs @@ -66,7 +66,7 @@ namespace osu.Game.Rulesets.Catch.UI catcher.Size = new Vector2(catcherContainer.DrawSize.Y); } - public bool CheckIfWeCanCatch(CatchBaseHit obj) => Math.Abs(catcher.Position.X - obj.X) < catcher.DrawSize.X / DrawSize.X / 2; + public bool CheckIfWeCanCatch(CatchHitObject obj) => Math.Abs(catcher.Position.X - obj.X) < catcher.DrawSize.X / DrawSize.X / 2; public override void Add(DrawableHitObject h) { diff --git a/osu.Game.Rulesets.Catch/UI/CatchRulesetContainer.cs b/osu.Game.Rulesets.Catch/UI/CatchRulesetContainer.cs index 92912eb177..fda63fa977 100644 --- a/osu.Game.Rulesets.Catch/UI/CatchRulesetContainer.cs +++ b/osu.Game.Rulesets.Catch/UI/CatchRulesetContainer.cs @@ -13,7 +13,7 @@ using osu.Game.Rulesets.UI; namespace osu.Game.Rulesets.Catch.UI { - public class CatchRulesetContainer : ScrollingRulesetContainer + public class CatchRulesetContainer : ScrollingRulesetContainer { public CatchRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap, bool isForCurrentRuleset) : base(ruleset, beatmap, isForCurrentRuleset) @@ -22,15 +22,15 @@ namespace osu.Game.Rulesets.Catch.UI public override ScoreProcessor CreateScoreProcessor() => new CatchScoreProcessor(this); - protected override BeatmapProcessor CreateBeatmapProcessor() => new CatchBeatmapProcessor(); + protected override BeatmapProcessor CreateBeatmapProcessor() => new CatchBeatmapProcessor(); - protected override BeatmapConverter CreateBeatmapConverter() => new CatchBeatmapConverter(); + protected override BeatmapConverter CreateBeatmapConverter() => new CatchBeatmapConverter(); protected override Playfield CreatePlayfield() => new CatchPlayfield(); public override PassThroughInputManager CreateInputManager() => new CatchInputManager(Ruleset.RulesetInfo); - protected override DrawableHitObject GetVisualRepresentation(CatchBaseHit h) + protected override DrawableHitObject GetVisualRepresentation(CatchHitObject h) { var fruit = h as Fruit; if (fruit != null) diff --git a/osu.Game.Rulesets.Catch/UI/Catcher.cs b/osu.Game.Rulesets.Catch/UI/Catcher.cs index 87fe95ed2f..3a32b84639 100644 --- a/osu.Game.Rulesets.Catch/UI/Catcher.cs +++ b/osu.Game.Rulesets.Catch/UI/Catcher.cs @@ -157,7 +157,7 @@ namespace osu.Game.Rulesets.Catch.UI caughtFruit.Add(fruit); - if (((CatchBaseHit)fruit.HitObject).LastInCombo) + if (((CatchHitObject)fruit.HitObject).LastInCombo) explode(); } diff --git a/osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj b/osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj index a666984b95..e8763ec5d3 100644 --- a/osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj +++ b/osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj @@ -57,7 +57,7 @@ - + From b517523f4a602161708b0148319f489009d99fac Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 28 Nov 2017 18:39:45 +0900 Subject: [PATCH 0870/1263] Add back CatcherArea to simplify layout --- ...tCaseCatcher.cs => TestCaseCatcherArea.cs} | 12 +- osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs | 24 +- .../UI/CatchRulesetContainer.cs | 2 +- osu.Game.Rulesets.Catch/UI/Catcher.cs | 193 -------------- osu.Game.Rulesets.Catch/UI/CatcherArea.cs | 238 ++++++++++++++++++ .../osu.Game.Rulesets.Catch.csproj | 4 +- 6 files changed, 252 insertions(+), 221 deletions(-) rename osu.Game.Rulesets.Catch/Tests/{TestCaseCatcher.cs => TestCaseCatcherArea.cs} (71%) delete mode 100644 osu.Game.Rulesets.Catch/UI/Catcher.cs create mode 100644 osu.Game.Rulesets.Catch/UI/CatcherArea.cs diff --git a/osu.Game.Rulesets.Catch/Tests/TestCaseCatcher.cs b/osu.Game.Rulesets.Catch/Tests/TestCaseCatcherArea.cs similarity index 71% rename from osu.Game.Rulesets.Catch/Tests/TestCaseCatcher.cs rename to osu.Game.Rulesets.Catch/Tests/TestCaseCatcherArea.cs index 341612b760..21c24aed93 100644 --- a/osu.Game.Rulesets.Catch/Tests/TestCaseCatcher.cs +++ b/osu.Game.Rulesets.Catch/Tests/TestCaseCatcherArea.cs @@ -8,17 +8,16 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Game.Rulesets.Catch.UI; using osu.Game.Tests.Visual; -using OpenTK; namespace osu.Game.Rulesets.Catch.Tests { [TestFixture] [Ignore("getting CI working")] - internal class TestCaseCatcher : OsuTestCase + internal class TestCaseCatcherArea : OsuTestCase { public override IReadOnlyList RequiredTypes => new[] { - typeof(Catcher), + typeof(CatcherArea), }; [BackgroundDependencyLoader] @@ -29,13 +28,10 @@ namespace osu.Game.Rulesets.Catch.Tests new CatchInputManager(rulesets.GetRuleset(2)) { RelativeSizeAxes = Axes.Both, - Child = new Catcher + Child = new CatcherArea() { - RelativePositionAxes = Axes.Both, - RelativeSizeAxes = Axes.Both, Anchor = Anchor.BottomLeft, - Origin = Anchor.BottomLeft, - Size = new Vector2(1, 0.2f), + Origin = Anchor.BottomLeft } }, }; diff --git a/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs b/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs index 33903f649e..f59ba13edd 100644 --- a/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs +++ b/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs @@ -1,11 +1,11 @@ // 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.Graphics; using osu.Game.Rulesets.UI; using OpenTK; using osu.Framework.Graphics.Containers; +using osu.Game.Beatmaps; using osu.Game.Rulesets.Catch.Objects; using osu.Game.Rulesets.Catch.Objects.Drawable; using osu.Game.Rulesets.Judgements; @@ -20,10 +20,9 @@ namespace osu.Game.Rulesets.Catch.UI protected override Container Content => content; private readonly Container content; - private readonly Container catcherContainer; - private readonly Catcher catcher; + private readonly CatcherArea catcherArea; - public CatchPlayfield() + public CatchPlayfield(BeatmapDifficulty difficulty) : base(Axes.Y) { Container explodingFruitContainer; @@ -43,19 +42,11 @@ namespace osu.Game.Rulesets.Catch.UI { RelativeSizeAxes = Axes.Both, }, - catcherContainer = new Container + catcherArea = new CatcherArea(difficulty) { - RelativeSizeAxes = Axes.X, + ExplodingFruitTarget = explodingFruitContainer, Anchor = Anchor.BottomLeft, Origin = Anchor.TopLeft, - Height = 180, - Child = catcher = new Catcher - { - ExplodingFruitTarget = explodingFruitContainer, - RelativePositionAxes = Axes.Both, - Origin = Anchor.TopCentre, - X = 0.5f, - } } }; } @@ -63,10 +54,9 @@ namespace osu.Game.Rulesets.Catch.UI protected override void Update() { base.Update(); - catcher.Size = new Vector2(catcherContainer.DrawSize.Y); } - public bool CheckIfWeCanCatch(CatchHitObject obj) => Math.Abs(catcher.Position.X - obj.X) < catcher.DrawSize.X / DrawSize.X / 2; + public bool CheckIfWeCanCatch(CatchHitObject obj) => catcherArea.CanCatch(obj); public override void Add(DrawableHitObject h) { @@ -88,7 +78,7 @@ namespace osu.Game.Rulesets.Catch.UI (judgedObject.Parent as Container)?.Remove(judgedObject); (judgedObject.Parent as Container)?.Remove(judgedObject); - catcher.Add(judgedObject, screenPosition); + catcherArea.Add(judgedObject, screenPosition); } } } diff --git a/osu.Game.Rulesets.Catch/UI/CatchRulesetContainer.cs b/osu.Game.Rulesets.Catch/UI/CatchRulesetContainer.cs index fda63fa977..3ed9090098 100644 --- a/osu.Game.Rulesets.Catch/UI/CatchRulesetContainer.cs +++ b/osu.Game.Rulesets.Catch/UI/CatchRulesetContainer.cs @@ -26,7 +26,7 @@ namespace osu.Game.Rulesets.Catch.UI protected override BeatmapConverter CreateBeatmapConverter() => new CatchBeatmapConverter(); - protected override Playfield CreatePlayfield() => new CatchPlayfield(); + protected override Playfield CreatePlayfield() => new CatchPlayfield(Beatmap.BeatmapInfo.BaseDifficulty); public override PassThroughInputManager CreateInputManager() => new CatchInputManager(Ruleset.RulesetInfo); diff --git a/osu.Game.Rulesets.Catch/UI/Catcher.cs b/osu.Game.Rulesets.Catch/UI/Catcher.cs deleted file mode 100644 index 3a32b84639..0000000000 --- a/osu.Game.Rulesets.Catch/UI/Catcher.cs +++ /dev/null @@ -1,193 +0,0 @@ -// Copyright (c) 2007-2017 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using System; -using System.Linq; -using osu.Framework.Allocation; -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.Framework.MathUtils; -using osu.Game.Rulesets.Catch.Objects; -using osu.Game.Rulesets.Objects.Drawables; -using OpenTK; - -namespace osu.Game.Rulesets.Catch.UI -{ - public class Catcher : Container, IKeyBindingHandler - { - private Texture texture; - - private Container caughtFruit; - - public Container ExplodingFruitTarget; - - [BackgroundDependencyLoader] - private void load(TextureStore textures) - { - texture = textures.Get(@"Play/Catch/fruit-catcher-idle"); - - Children = new Drawable[] - { - createCatcherSprite(), - caughtFruit = new Container - { - Anchor = Anchor.TopCentre, - Origin = Anchor.BottomCentre, - } - }; - } - - private int currentDirection; - - private bool dashing; - - protected bool Dashing - { - get { return dashing; } - set - { - if (value == dashing) return; - - dashing = value; - - if (dashing) - Schedule(addAdditiveSprite); - } - } - - private void addAdditiveSprite() - { - if (!dashing) return; - - var additive = createCatcherSprite(); - - additive.RelativePositionAxes = Axes.Both; - additive.Blending = BlendingMode.Additive; - additive.Position = Position; - additive.Scale = Scale; - - ((Container)Parent).Add(additive); - - additive.FadeTo(0.4f).FadeOut(800, Easing.OutQuint).Expire(); - - Scheduler.AddDelayed(addAdditiveSprite, 50); - } - - private Sprite createCatcherSprite() => new Sprite - { - RelativeSizeAxes = Axes.Both, - FillMode = FillMode.Fit, - Texture = texture, - OriginPosition = new Vector2(DrawWidth / 2, 10) //temporary until the sprite is aligned correctly. - }; - - public bool OnPressed(CatchAction action) - { - switch (action) - { - case CatchAction.MoveLeft: - currentDirection--; - return true; - case CatchAction.MoveRight: - currentDirection++; - return true; - case CatchAction.Dash: - Dashing = true; - return true; - } - - return false; - } - - public bool OnReleased(CatchAction action) - { - switch (action) - { - case CatchAction.MoveLeft: - currentDirection++; - return true; - case CatchAction.MoveRight: - currentDirection--; - return true; - case CatchAction.Dash: - Dashing = false; - return true; - } - - return false; - } - - /// - /// The relative space to cover in 1 millisecond. based on 1 game pixel per millisecond as in osu-stable. - /// - private const double base_speed = 1.0 / 512; - - protected override void Update() - { - base.Update(); - - if (currentDirection == 0) return; - - double dashModifier = Dashing ? 1 : 0.5; - - Scale = new Vector2(Math.Sign(currentDirection), 1); - X = (float)MathHelper.Clamp(X + Math.Sign(currentDirection) * Clock.ElapsedFrameTime * base_speed * dashModifier, 0, 1); - } - - public void Add(DrawableHitObject fruit, Vector2 absolutePosition) - { - fruit.RelativePositionAxes = Axes.None; - fruit.Position = new Vector2(ToLocalSpace(absolutePosition).X - DrawSize.X / 2, 0); - - fruit.Anchor = Anchor.TopCentre; - fruit.Origin = Anchor.BottomCentre; - fruit.Scale *= 0.7f; - fruit.LifetimeEnd = double.MaxValue; - - float distance = fruit.DrawSize.X / 2 * fruit.Scale.X; - - while (caughtFruit.Any(f => f.LifetimeEnd == double.MaxValue && Vector2Extensions.DistanceSquared(f.Position, fruit.Position) < distance * distance)) - { - fruit.X += RNG.Next(-5, 5); - fruit.Y -= RNG.Next(0, 5); - } - - caughtFruit.Add(fruit); - - if (((CatchHitObject)fruit.HitObject).LastInCombo) - explode(); - } - - private void explode() - { - var fruit = caughtFruit.ToArray(); - - foreach (var f in fruit) - { - var originalX = f.X * Scale.X; - - if (ExplodingFruitTarget != null) - { - f.Anchor = Anchor.TopLeft; - f.Position = caughtFruit.ToSpaceOfOtherDrawable(f.DrawPosition, ExplodingFruitTarget); - - caughtFruit.Remove(f); - - ExplodingFruitTarget.Add(f); - } - - f.MoveToY(f.Y - 50, 250, Easing.OutSine) - .Then() - .MoveToY(f.Y + 50, 500, Easing.InSine); - - f.MoveToX(f.X + originalX * 6, 1000); - f.FadeOut(750); - - f.Expire(); - } - } - } -} diff --git a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs new file mode 100644 index 0000000000..1cc810201f --- /dev/null +++ b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs @@ -0,0 +1,238 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using System.Linq; +using osu.Framework.Allocation; +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.Framework.MathUtils; +using osu.Game.Beatmaps; +using osu.Game.Rulesets.Catch.Objects; +using osu.Game.Rulesets.Objects.Drawables; +using OpenTK; + +namespace osu.Game.Rulesets.Catch.UI +{ + public class CatcherArea : Container + { + public const float CATCHER_SIZE = 172; + + private readonly Catcher catcher; + + public Container ExplodingFruitTarget + { + set { catcher.ExplodingFruitTarget = value; } + } + + public CatcherArea(BeatmapDifficulty difficulty = null) + { + RelativeSizeAxes = Axes.X; + Height = CATCHER_SIZE; + Child = catcher = new Catcher(difficulty) + { + AdditiveTarget = this, + }; + } + + public void Add(DrawableHitObject fruit, Vector2 absolutePosition) + { + fruit.RelativePositionAxes = Axes.None; + fruit.Position = new Vector2(catcher.ToLocalSpace(absolutePosition).X - catcher.DrawSize.X / 2, 0); + + fruit.Anchor = Anchor.TopCentre; + fruit.Origin = Anchor.BottomCentre; + fruit.Scale *= 0.7f; + fruit.LifetimeEnd = double.MaxValue; + + catcher.Add(fruit); + } + + public bool CanCatch(CatchHitObject obj) => Math.Abs(catcher.Position.X - obj.X) < catcher.DrawSize.X / DrawSize.X / 2; + + public class Catcher : Container, IKeyBindingHandler + { + private Texture texture; + + private Container caughtFruit; + + public Container ExplodingFruitTarget; + + public Container AdditiveTarget; + + public Catcher(BeatmapDifficulty difficulty = null) + { + RelativePositionAxes = Axes.X; + X = 0.5f; + + Origin = Anchor.BottomCentre; + Anchor = Anchor.BottomLeft; + + Size = new Vector2(CATCHER_SIZE); + } + + [BackgroundDependencyLoader] + private void load(TextureStore textures) + { + texture = textures.Get(@"Play/Catch/fruit-catcher-idle"); + + Children = new Drawable[] + { + createCatcherSprite(), + caughtFruit = new Container + { + Anchor = Anchor.TopCentre, + Origin = Anchor.BottomCentre, + } + }; + } + + private int currentDirection; + + private bool dashing; + + protected bool Dashing + { + get { return dashing; } + set + { + if (value == dashing) return; + + dashing = value; + + if (dashing) + Schedule(addAdditiveSprite); + } + } + + private void addAdditiveSprite() + { + if (!dashing || AdditiveTarget == null) return; + + var additive = createCatcherSprite(); + + additive.Anchor = Anchor; + additive.OriginPosition = additive.OriginPosition + new Vector2(DrawWidth / 2, DrawHeight); // also temporary to align sprite correctly. + additive.Position = Position; + additive.Scale = Scale; + additive.RelativePositionAxes = RelativePositionAxes; + additive.Blending = BlendingMode.Additive; + + AdditiveTarget.Add(additive); + + additive.FadeTo(0.4f).FadeOut(800, Easing.OutQuint).Expire(); + + Scheduler.AddDelayed(addAdditiveSprite, 50); + } + + private Sprite createCatcherSprite() => new Sprite + { + Size = new Vector2(CATCHER_SIZE), + FillMode = FillMode.Fill, + Texture = texture, + OriginPosition = new Vector2(-3, 10) // temporary until the sprite is aligned correctly. + }; + + public void Add(DrawableHitObject fruit) + { + float distance = fruit.DrawSize.X / 2 * fruit.Scale.X; + + while (caughtFruit.Any(f => f.LifetimeEnd == double.MaxValue && Vector2Extensions.DistanceSquared(f.Position, fruit.Position) < distance * distance)) + { + fruit.X += RNG.Next(-5, 5); + fruit.Y -= RNG.Next(0, 5); + } + + caughtFruit.Add(fruit); + + if (((CatchHitObject)fruit.HitObject).LastInCombo) + explode(); + } + + public bool OnPressed(CatchAction action) + { + switch (action) + { + case CatchAction.MoveLeft: + currentDirection--; + return true; + case CatchAction.MoveRight: + currentDirection++; + return true; + case CatchAction.Dash: + Dashing = true; + return true; + } + + return false; + } + + public bool OnReleased(CatchAction action) + { + switch (action) + { + case CatchAction.MoveLeft: + currentDirection++; + return true; + case CatchAction.MoveRight: + currentDirection--; + return true; + case CatchAction.Dash: + Dashing = false; + return true; + } + + return false; + } + + /// + /// The relative space to cover in 1 millisecond. based on 1 game pixel per millisecond as in osu-stable. + /// + public const double BASE_SPEED = 1.0 / 512; + + protected override void Update() + { + base.Update(); + + if (currentDirection == 0) return; + + double dashModifier = Dashing ? 1 : 0.5; + + Scale = new Vector2(Math.Sign(currentDirection), 1); + X = (float)MathHelper.Clamp(X + Math.Sign(currentDirection) * Clock.ElapsedFrameTime * BASE_SPEED * dashModifier, 0, 1); + } + + private void explode() + { + var fruit = caughtFruit.ToArray(); + + foreach (var f in fruit) + { + var originalX = f.X * Scale.X; + + if (ExplodingFruitTarget != null) + { + f.Anchor = Anchor.TopLeft; + f.Position = caughtFruit.ToSpaceOfOtherDrawable(f.DrawPosition, ExplodingFruitTarget); + + caughtFruit.Remove(f); + + ExplodingFruitTarget.Add(f); + } + + f.MoveToY(f.Y - 50, 250, Easing.OutSine) + .Then() + .MoveToY(f.Y + 50, 500, Easing.InSine); + + f.MoveToX(f.X + originalX * 6, 1000); + f.FadeOut(750); + + f.Expire(); + } + } + } + } +} diff --git a/osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj b/osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj index e8763ec5d3..bf60bc01bb 100644 --- a/osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj +++ b/osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj @@ -63,10 +63,10 @@ - + - + From 5ae9b4c79152e0e9489cf5e5c3a8e4267a6a92c4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 28 Nov 2017 18:18:39 +0900 Subject: [PATCH 0871/1263] Make CatchStacker testcase more useful --- osu.Game.Rulesets.Catch/Tests/TestCaseCatchStacker.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Tests/TestCaseCatchStacker.cs b/osu.Game.Rulesets.Catch/Tests/TestCaseCatchStacker.cs index a890a8a386..4672ab5746 100644 --- a/osu.Game.Rulesets.Catch/Tests/TestCaseCatchStacker.cs +++ b/osu.Game.Rulesets.Catch/Tests/TestCaseCatchStacker.cs @@ -19,8 +19,8 @@ namespace osu.Game.Rulesets.Catch.Tests { var beatmap = new Beatmap(); - for (int i = 0; i < 256; i++) - beatmap.HitObjects.Add(new Fruit { X = 0.5f, StartTime = i * 100, NewCombo = i % 8 == 0 }); + for (int i = 0; i < 512; i++) + beatmap.HitObjects.Add(new Fruit { X = 0.5f + (i / 2048f * ((i % 10) - 5)), StartTime = i * 100, NewCombo = i % 8 == 0 }); return beatmap; } From b11de50df28577b7a6408219b34fbbdadfa362ff Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 28 Nov 2017 18:42:50 +0900 Subject: [PATCH 0872/1263] Cleanups --- osu.Game.Rulesets.Catch/Tests/TestCaseCatchStacker.cs | 2 +- osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs | 5 ----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Tests/TestCaseCatchStacker.cs b/osu.Game.Rulesets.Catch/Tests/TestCaseCatchStacker.cs index 4672ab5746..1c5f34f2e5 100644 --- a/osu.Game.Rulesets.Catch/Tests/TestCaseCatchStacker.cs +++ b/osu.Game.Rulesets.Catch/Tests/TestCaseCatchStacker.cs @@ -20,7 +20,7 @@ namespace osu.Game.Rulesets.Catch.Tests var beatmap = new Beatmap(); for (int i = 0; i < 512; i++) - beatmap.HitObjects.Add(new Fruit { X = 0.5f + (i / 2048f * ((i % 10) - 5)), StartTime = i * 100, NewCombo = i % 8 == 0 }); + beatmap.HitObjects.Add(new Fruit { X = 0.5f + i / 2048f * (i % 10 - 5), StartTime = i * 100, NewCombo = i % 8 == 0 }); return beatmap; } diff --git a/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs b/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs index f59ba13edd..6fd0793500 100644 --- a/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs +++ b/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs @@ -51,11 +51,6 @@ namespace osu.Game.Rulesets.Catch.UI }; } - protected override void Update() - { - base.Update(); - } - public bool CheckIfWeCanCatch(CatchHitObject obj) => catcherArea.CanCatch(obj); public override void Add(DrawableHitObject h) From f8c296877b96378506f3dab6d7698986740da380 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 28 Nov 2017 18:57:28 +0900 Subject: [PATCH 0873/1263] Add testcase for mania beatmap conversion (currently ignored) --- .../Tests/TestCaseBeatmapConversion.cs | 173 ++++++++++++++++++ .../osu.Game.Rulesets.Mania.csproj | 1 + 2 files changed, 174 insertions(+) create mode 100644 osu.Game.Rulesets.Mania/Tests/TestCaseBeatmapConversion.cs diff --git a/osu.Game.Rulesets.Mania/Tests/TestCaseBeatmapConversion.cs b/osu.Game.Rulesets.Mania/Tests/TestCaseBeatmapConversion.cs new file mode 100644 index 0000000000..a8a3e9527b --- /dev/null +++ b/osu.Game.Rulesets.Mania/Tests/TestCaseBeatmapConversion.cs @@ -0,0 +1,173 @@ +// 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.Game.Beatmaps; +using osu.Game.Rulesets.Mania.Objects; +using osu.Game.Rulesets.Mania.Replays; +using osu.Game.Tests.Visual; + +namespace osu.Game.Rulesets.Mania.Tests +{ + [Ignore("getting CI working")] + public class TestCaseAutoGeneration : OsuTestCase + { + [Test] + public void TestSingleNote() + { + // | | + // | - | + // | | + + var beatmap = new Beatmap(); + beatmap.HitObjects.Add(new Note { StartTime = 1000 }); + + var generated = new ManiaAutoGenerator(beatmap, 1).Generate(); + + Assert.IsTrue(generated.Frames.Count == 3, "Replay must have 3 frames"); + Assert.AreEqual(1000, generated.Frames[1].Time, "Incorrect hit time"); + Assert.AreEqual(1000 + ManiaAutoGenerator.RELEASE_DELAY, generated.Frames[2].Time, "Incorrect release time"); + Assert.AreEqual(1, generated.Frames[1].MouseX, "Key 0 has not been pressed"); + Assert.AreEqual(0, generated.Frames[2].MouseX, "Key 0 has not been released"); + } + + [Test] + public void TestSingleHoldNote() + { + // | | + // | * | + // | * | + // | * | + // | | + + var beatmap = new Beatmap(); + beatmap.HitObjects.Add(new HoldNote { StartTime = 1000, Duration = 2000 }); + + var generated = new ManiaAutoGenerator(beatmap, 1).Generate(); + + Assert.IsTrue(generated.Frames.Count == 3, "Replay must have 3 frames"); + Assert.AreEqual(1000, generated.Frames[1].Time, "Incorrect hit time"); + Assert.AreEqual(3000 + ManiaAutoGenerator.RELEASE_DELAY, generated.Frames[2].Time, "Incorrect release time"); + Assert.AreEqual(1, generated.Frames[1].MouseX, "Key 0 has not been pressed"); + Assert.AreEqual(0, generated.Frames[2].MouseX, "Key 0 has not been released"); + } + + [Test] + public void TestSingleNoteChord() + { + // | | | + // | - | - | + // | | | + + var beatmap = new Beatmap(); + beatmap.HitObjects.Add(new Note { StartTime = 1000 }); + beatmap.HitObjects.Add(new Note { StartTime = 1000, Column = 1 }); + + var generated = new ManiaAutoGenerator(beatmap, 2).Generate(); + + Assert.IsTrue(generated.Frames.Count == 3, "Replay must have 3 frames"); + Assert.AreEqual(1000, generated.Frames[1].Time, "Incorrect hit time"); + Assert.AreEqual(1000 + ManiaAutoGenerator.RELEASE_DELAY, generated.Frames[2].Time, "Incorrect release time"); + Assert.AreEqual(3, generated.Frames[1].MouseX, "Keys 1 and 2 have not been pressed"); + Assert.AreEqual(0, generated.Frames[2].MouseX, "Keys 1 and 2 have not been released"); + } + + [Test] + public void TestHoldNoteChord() + { + // | | | + // | * | * | + // | * | * | + // | * | * | + // | | | + + var beatmap = new Beatmap(); + beatmap.HitObjects.Add(new HoldNote { StartTime = 1000, Duration = 2000 }); + beatmap.HitObjects.Add(new HoldNote { StartTime = 1000, Duration = 2000, Column = 1 }); + + var generated = new ManiaAutoGenerator(beatmap, 2).Generate(); + + Assert.IsTrue(generated.Frames.Count == 3, "Replay must have 3 frames"); + Assert.AreEqual(1000, generated.Frames[1].Time, "Incorrect hit time"); + Assert.AreEqual(3000 + ManiaAutoGenerator.RELEASE_DELAY, generated.Frames[2].Time, "Incorrect release time"); + Assert.AreEqual(3, generated.Frames[1].MouseX, "Keys 1 and 2 have not been pressed"); + Assert.AreEqual(0, generated.Frames[2].MouseX, "Keys 1 and 2 have not been released"); + } + + [Test] + public void TestSingleNoteStair() + { + // | | | + // | | - | + // | - | | + // | | | + + var beatmap = new Beatmap(); + beatmap.HitObjects.Add(new Note { StartTime = 1000 }); + beatmap.HitObjects.Add(new Note { StartTime = 2000, Column = 1 }); + + var generated = new ManiaAutoGenerator(beatmap, 2).Generate(); + + Assert.IsTrue(generated.Frames.Count == 5, "Replay must have 5 frames"); + Assert.AreEqual(1000, generated.Frames[1].Time, "Incorrect first note hit time"); + Assert.AreEqual(1000 + ManiaAutoGenerator.RELEASE_DELAY, generated.Frames[2].Time, "Incorrect first note release time"); + Assert.AreEqual(2000, generated.Frames[3].Time, "Incorrect second note hit time"); + Assert.AreEqual(2000 + ManiaAutoGenerator.RELEASE_DELAY, generated.Frames[4].Time, "Incorrect second note release time"); + Assert.AreEqual(1, generated.Frames[1].MouseX, "Key 1 has not been pressed"); + Assert.AreEqual(0, generated.Frames[2].MouseX, "Key 1 has not been released"); + Assert.AreEqual(2, generated.Frames[3].MouseX, "Key 2 has not been pressed"); + Assert.AreEqual(0, generated.Frames[4].MouseX, "Key 2 has not been released"); + } + + [Test] + public void TestHoldNoteStair() + { + // | | | + // | | * | + // | * | * | + // | * | * | + // | * | | + // | | | + + var beatmap = new Beatmap(); + beatmap.HitObjects.Add(new HoldNote { StartTime = 1000, Duration = 2000 }); + beatmap.HitObjects.Add(new HoldNote { StartTime = 2000, Duration = 2000, Column = 1 }); + + var generated = new ManiaAutoGenerator(beatmap, 2).Generate(); + + Assert.IsTrue(generated.Frames.Count == 5, "Replay must have 5 frames"); + Assert.AreEqual(1000, generated.Frames[1].Time, "Incorrect first note hit time"); + Assert.AreEqual(3000 + ManiaAutoGenerator.RELEASE_DELAY, generated.Frames[3].Time, "Incorrect first note release time"); + Assert.AreEqual(2000, generated.Frames[2].Time, "Incorrect second note hit time"); + Assert.AreEqual(4000 + ManiaAutoGenerator.RELEASE_DELAY, generated.Frames[4].Time, "Incorrect second note release time"); + Assert.AreEqual(1, generated.Frames[1].MouseX, "Key 1 has not been pressed"); + Assert.AreEqual(3, generated.Frames[2].MouseX, "Keys 1 and 2 have not been pressed"); + Assert.AreEqual(2, generated.Frames[3].MouseX, "Key 1 has not been released"); + Assert.AreEqual(0, generated.Frames[4].MouseX, "Key 2 has not been released"); + } + + [Test] + public void TestHoldNoteWithReleasePress() + { + // | | | + // | * | - | + // | * | | + // | * | | + // | | | + + var beatmap = new Beatmap(); + beatmap.HitObjects.Add(new HoldNote { StartTime = 1000, Duration = 2000 - ManiaAutoGenerator.RELEASE_DELAY }); + beatmap.HitObjects.Add(new Note { StartTime = 3000, Column = 1 }); + + var generated = new ManiaAutoGenerator(beatmap, 2).Generate(); + + Assert.IsTrue(generated.Frames.Count == 4, "Replay must have 4 frames"); + Assert.AreEqual(1000, generated.Frames[1].Time, "Incorrect first note hit time"); + Assert.AreEqual(3000, generated.Frames[2].Time, "Incorrect second note press time + first note release time"); + Assert.AreEqual(3000 + ManiaAutoGenerator.RELEASE_DELAY, generated.Frames[3].Time, "Incorrect second note release time"); + Assert.AreEqual(1, generated.Frames[1].MouseX, "Key 1 has not been pressed"); + Assert.AreEqual(2, generated.Frames[2].MouseX, "Key 1 has not been released or key 2 has not been pressed"); + Assert.AreEqual(0, generated.Frames[3].MouseX, "Keys 1 and 2 have not been released"); + } + } +} diff --git a/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj b/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj index 6f45a64d92..3bd195e2f0 100644 --- a/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj +++ b/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj @@ -80,6 +80,7 @@ + From 567e378bbbbfb25d9919637683789e7f9fc73367 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 28 Nov 2017 19:02:39 +0900 Subject: [PATCH 0874/1263] CI fixes --- osu.Game.Rulesets.Mania/Replays/ManiaAutoGenerator.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game.Rulesets.Mania/Replays/ManiaAutoGenerator.cs b/osu.Game.Rulesets.Mania/Replays/ManiaAutoGenerator.cs index 35ca868d5a..2f336d834f 100644 --- a/osu.Game.Rulesets.Mania/Replays/ManiaAutoGenerator.cs +++ b/osu.Game.Rulesets.Mania/Replays/ManiaAutoGenerator.cs @@ -1,7 +1,6 @@ // 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.Game.Beatmaps; From eaf2b1d94df6eb7f02621243e81bb858b5953987 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 28 Nov 2017 19:06:46 +0900 Subject: [PATCH 0875/1263] Remove line that shouldn't have been added yet --- .../Replays/ManiaFramedReplayInputHandler.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Replays/ManiaFramedReplayInputHandler.cs b/osu.Game.Rulesets.Mania/Replays/ManiaFramedReplayInputHandler.cs index 8440e4347d..12534d6eb4 100644 --- a/osu.Game.Rulesets.Mania/Replays/ManiaFramedReplayInputHandler.cs +++ b/osu.Game.Rulesets.Mania/Replays/ManiaFramedReplayInputHandler.cs @@ -19,8 +19,6 @@ namespace osu.Game.Rulesets.Mania.Replays this.container = container; } - protected override bool AtImportantFrame => CurrentFrame.MouseX != PreviousFrame.MouseX; - private ManiaPlayfield playfield; public override List GetPendingStates() { From cc9e06e16196710572154c111c8ee51bb9417bbd Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 28 Nov 2017 19:07:00 +0900 Subject: [PATCH 0876/1263] Remove unused elements --- osu.Game.Rulesets.Mania/Mods/ManiaMod.cs | 14 +------------- .../Replays/ManiaAutoGenerator.cs | 6 +----- 2 files changed, 2 insertions(+), 18 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaMod.cs b/osu.Game.Rulesets.Mania/Mods/ManiaMod.cs index 164309c227..dfc9993bde 100644 --- a/osu.Game.Rulesets.Mania/Mods/ManiaMod.cs +++ b/osu.Game.Rulesets.Mania/Mods/ManiaMod.cs @@ -176,22 +176,10 @@ namespace osu.Game.Rulesets.Mania.Mods public class ManiaModAutoplay : ModAutoplay { - private int availableColumns; - - public override void ApplyToRulesetContainer(RulesetContainer rulesetContainer) - { - // Todo: This shouldn't be done, we should be getting a ManiaBeatmap which should store AvailableColumns - // But this is dependent on a _lot_ of refactoring - var maniaRulesetContainer = (ManiaRulesetContainer)rulesetContainer; - availableColumns = maniaRulesetContainer.AvailableColumns; - - base.ApplyToRulesetContainer(rulesetContainer); - } - protected override Score CreateReplayScore(Beatmap beatmap) => new Score { User = new User { Username = "osu!topus!" }, - Replay = new ManiaAutoGenerator(beatmap, availableColumns).Generate(), + Replay = new ManiaAutoGenerator(beatmap).Generate(), }; } } diff --git a/osu.Game.Rulesets.Mania/Replays/ManiaAutoGenerator.cs b/osu.Game.Rulesets.Mania/Replays/ManiaAutoGenerator.cs index 2f336d834f..85d840ed70 100644 --- a/osu.Game.Rulesets.Mania/Replays/ManiaAutoGenerator.cs +++ b/osu.Game.Rulesets.Mania/Replays/ManiaAutoGenerator.cs @@ -15,13 +15,9 @@ namespace osu.Game.Rulesets.Mania.Replays { public const double RELEASE_DELAY = 20; - private readonly int availableColumns; - - public ManiaAutoGenerator(Beatmap beatmap, int availableColumns) + public ManiaAutoGenerator(Beatmap beatmap) : base(beatmap) { - this.availableColumns = availableColumns; - Replay = new Replay { User = new User { Username = @"Autoplay" } }; } From 375f2710d417eb182362ce3007224eb053c2e611 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 28 Nov 2017 19:09:17 +0900 Subject: [PATCH 0877/1263] Rename file --- .../{TestCaseBeatmapConversion.cs => TestCaseAutoGeneration.cs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename osu.Game.Rulesets.Mania/Tests/{TestCaseBeatmapConversion.cs => TestCaseAutoGeneration.cs} (100%) diff --git a/osu.Game.Rulesets.Mania/Tests/TestCaseBeatmapConversion.cs b/osu.Game.Rulesets.Mania/Tests/TestCaseAutoGeneration.cs similarity index 100% rename from osu.Game.Rulesets.Mania/Tests/TestCaseBeatmapConversion.cs rename to osu.Game.Rulesets.Mania/Tests/TestCaseAutoGeneration.cs From 00f9f97850cedb827118e998e85dfbf82b707af1 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 28 Nov 2017 19:13:10 +0900 Subject: [PATCH 0878/1263] Fix compile errors (rider didn't warn me about these) --- .../Tests/TestCaseAutoGeneration.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Tests/TestCaseAutoGeneration.cs b/osu.Game.Rulesets.Mania/Tests/TestCaseAutoGeneration.cs index a8a3e9527b..805553eafc 100644 --- a/osu.Game.Rulesets.Mania/Tests/TestCaseAutoGeneration.cs +++ b/osu.Game.Rulesets.Mania/Tests/TestCaseAutoGeneration.cs @@ -22,7 +22,7 @@ namespace osu.Game.Rulesets.Mania.Tests var beatmap = new Beatmap(); beatmap.HitObjects.Add(new Note { StartTime = 1000 }); - var generated = new ManiaAutoGenerator(beatmap, 1).Generate(); + var generated = new ManiaAutoGenerator(beatmap).Generate(); Assert.IsTrue(generated.Frames.Count == 3, "Replay must have 3 frames"); Assert.AreEqual(1000, generated.Frames[1].Time, "Incorrect hit time"); @@ -43,7 +43,7 @@ namespace osu.Game.Rulesets.Mania.Tests var beatmap = new Beatmap(); beatmap.HitObjects.Add(new HoldNote { StartTime = 1000, Duration = 2000 }); - var generated = new ManiaAutoGenerator(beatmap, 1).Generate(); + var generated = new ManiaAutoGenerator(beatmap).Generate(); Assert.IsTrue(generated.Frames.Count == 3, "Replay must have 3 frames"); Assert.AreEqual(1000, generated.Frames[1].Time, "Incorrect hit time"); @@ -63,7 +63,7 @@ namespace osu.Game.Rulesets.Mania.Tests beatmap.HitObjects.Add(new Note { StartTime = 1000 }); beatmap.HitObjects.Add(new Note { StartTime = 1000, Column = 1 }); - var generated = new ManiaAutoGenerator(beatmap, 2).Generate(); + var generated = new ManiaAutoGenerator(beatmap).Generate(); Assert.IsTrue(generated.Frames.Count == 3, "Replay must have 3 frames"); Assert.AreEqual(1000, generated.Frames[1].Time, "Incorrect hit time"); @@ -85,7 +85,7 @@ namespace osu.Game.Rulesets.Mania.Tests beatmap.HitObjects.Add(new HoldNote { StartTime = 1000, Duration = 2000 }); beatmap.HitObjects.Add(new HoldNote { StartTime = 1000, Duration = 2000, Column = 1 }); - var generated = new ManiaAutoGenerator(beatmap, 2).Generate(); + var generated = new ManiaAutoGenerator(beatmap).Generate(); Assert.IsTrue(generated.Frames.Count == 3, "Replay must have 3 frames"); Assert.AreEqual(1000, generated.Frames[1].Time, "Incorrect hit time"); @@ -106,7 +106,7 @@ namespace osu.Game.Rulesets.Mania.Tests beatmap.HitObjects.Add(new Note { StartTime = 1000 }); beatmap.HitObjects.Add(new Note { StartTime = 2000, Column = 1 }); - var generated = new ManiaAutoGenerator(beatmap, 2).Generate(); + var generated = new ManiaAutoGenerator(beatmap).Generate(); Assert.IsTrue(generated.Frames.Count == 5, "Replay must have 5 frames"); Assert.AreEqual(1000, generated.Frames[1].Time, "Incorrect first note hit time"); @@ -133,7 +133,7 @@ namespace osu.Game.Rulesets.Mania.Tests beatmap.HitObjects.Add(new HoldNote { StartTime = 1000, Duration = 2000 }); beatmap.HitObjects.Add(new HoldNote { StartTime = 2000, Duration = 2000, Column = 1 }); - var generated = new ManiaAutoGenerator(beatmap, 2).Generate(); + var generated = new ManiaAutoGenerator(beatmap).Generate(); Assert.IsTrue(generated.Frames.Count == 5, "Replay must have 5 frames"); Assert.AreEqual(1000, generated.Frames[1].Time, "Incorrect first note hit time"); @@ -159,7 +159,7 @@ namespace osu.Game.Rulesets.Mania.Tests beatmap.HitObjects.Add(new HoldNote { StartTime = 1000, Duration = 2000 - ManiaAutoGenerator.RELEASE_DELAY }); beatmap.HitObjects.Add(new Note { StartTime = 3000, Column = 1 }); - var generated = new ManiaAutoGenerator(beatmap, 2).Generate(); + var generated = new ManiaAutoGenerator(beatmap).Generate(); Assert.IsTrue(generated.Frames.Count == 4, "Replay must have 4 frames"); Assert.AreEqual(1000, generated.Frames[1].Time, "Incorrect first note hit time"); From 2bb61e51ac6f95065ab28c6f9b9febc15650180b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 28 Nov 2017 19:43:26 +0900 Subject: [PATCH 0879/1263] Add catcher scale based on CircleSize --- .../Tests/TestCaseCatchStacker.cs | 14 +++++++-- .../Tests/TestCaseCatcherArea.cs | 30 ++++++++++++------- osu.Game.Rulesets.Catch/UI/CatcherArea.cs | 12 ++++---- 3 files changed, 39 insertions(+), 17 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Tests/TestCaseCatchStacker.cs b/osu.Game.Rulesets.Catch/Tests/TestCaseCatchStacker.cs index 1c5f34f2e5..586de17f15 100644 --- a/osu.Game.Rulesets.Catch/Tests/TestCaseCatchStacker.cs +++ b/osu.Game.Rulesets.Catch/Tests/TestCaseCatchStacker.cs @@ -11,13 +11,23 @@ namespace osu.Game.Rulesets.Catch.Tests [Ignore("getting CI working")] public class TestCaseCatchStacker : Game.Tests.Visual.TestCasePlayer { - public TestCaseCatchStacker() : base(typeof(CatchRuleset)) + public TestCaseCatchStacker() + : base(typeof(CatchRuleset)) { } protected override Beatmap CreateBeatmap() { - var beatmap = new Beatmap(); + var beatmap = new Beatmap + { + BeatmapInfo = new BeatmapInfo + { + BaseDifficulty = new BeatmapDifficulty + { + CircleSize = 6, + } + } + }; for (int i = 0; i < 512; i++) beatmap.HitObjects.Add(new Fruit { X = 0.5f + i / 2048f * (i % 10 - 5), StartTime = i * 100, NewCombo = i % 8 == 0 }); diff --git a/osu.Game.Rulesets.Catch/Tests/TestCaseCatcherArea.cs b/osu.Game.Rulesets.Catch/Tests/TestCaseCatcherArea.cs index 21c24aed93..84ca08f97e 100644 --- a/osu.Game.Rulesets.Catch/Tests/TestCaseCatcherArea.cs +++ b/osu.Game.Rulesets.Catch/Tests/TestCaseCatcherArea.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Graphics; +using osu.Game.Beatmaps; using osu.Game.Rulesets.Catch.UI; using osu.Game.Tests.Visual; @@ -15,26 +16,35 @@ namespace osu.Game.Rulesets.Catch.Tests [Ignore("getting CI working")] internal class TestCaseCatcherArea : OsuTestCase { + private RulesetInfo catchRuleset; + public override IReadOnlyList RequiredTypes => new[] { typeof(CatcherArea), }; - [BackgroundDependencyLoader] - private void load(RulesetStore rulesets) + public TestCaseCatcherArea() { - Children = new Drawable[] + AddSliderStep("CircleSize", 0, 8, 5, craeteCatcher); + } + + private void craeteCatcher(float size) + { + Child = new CatchInputManager(catchRuleset) { - new CatchInputManager(rulesets.GetRuleset(2)) + RelativeSizeAxes = Axes.Both, + Child = new CatcherArea(new BeatmapDifficulty { CircleSize = size }) { - RelativeSizeAxes = Axes.Both, - Child = new CatcherArea() - { - Anchor = Anchor.BottomLeft, - Origin = Anchor.BottomLeft - } + Anchor = Anchor.CentreLeft, + Origin = Anchor.BottomLeft }, }; } + + [BackgroundDependencyLoader] + private void load(RulesetStore rulesets) + { + catchRuleset = rulesets.GetRuleset(2); + } } } diff --git a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs index 1cc810201f..203db1bb8c 100644 --- a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs +++ b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs @@ -51,7 +51,7 @@ namespace osu.Game.Rulesets.Catch.UI catcher.Add(fruit); } - public bool CanCatch(CatchHitObject obj) => Math.Abs(catcher.Position.X - obj.X) < catcher.DrawSize.X / DrawSize.X / 2; + public bool CanCatch(CatchHitObject obj) => Math.Abs(catcher.Position.X - obj.X) < catcher.DrawSize.X * Math.Abs(catcher.Scale.X) / DrawSize.X / 2; public class Catcher : Container, IKeyBindingHandler { @@ -68,10 +68,12 @@ namespace osu.Game.Rulesets.Catch.UI RelativePositionAxes = Axes.X; X = 0.5f; - Origin = Anchor.BottomCentre; - Anchor = Anchor.BottomLeft; + Origin = Anchor.TopCentre; + Anchor = Anchor.TopLeft; Size = new Vector2(CATCHER_SIZE); + if (difficulty != null) + Scale = new Vector2(1.0f - 0.7f * (difficulty.CircleSize - 5) / 5); } [BackgroundDependencyLoader] @@ -115,7 +117,7 @@ namespace osu.Game.Rulesets.Catch.UI var additive = createCatcherSprite(); additive.Anchor = Anchor; - additive.OriginPosition = additive.OriginPosition + new Vector2(DrawWidth / 2, DrawHeight); // also temporary to align sprite correctly. + additive.OriginPosition = additive.OriginPosition + new Vector2(DrawWidth / 2, 0); // also temporary to align sprite correctly. additive.Position = Position; additive.Scale = Scale; additive.RelativePositionAxes = RelativePositionAxes; @@ -201,7 +203,7 @@ namespace osu.Game.Rulesets.Catch.UI double dashModifier = Dashing ? 1 : 0.5; - Scale = new Vector2(Math.Sign(currentDirection), 1); + Scale = new Vector2(Math.Abs(Scale.X) * Math.Sign(currentDirection), Scale.Y); X = (float)MathHelper.Clamp(X + Math.Sign(currentDirection) * Clock.ElapsedFrameTime * BASE_SPEED * dashModifier, 0, 1); } From 23b4d2163ca2fc5f8128fbc814aef37b7e544292 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 28 Nov 2017 21:30:03 +0900 Subject: [PATCH 0880/1263] Fix spelling and grammar --- osu.Game.Rulesets.Catch/Tests/TestCaseCatcherArea.cs | 4 ++-- osu.Game/Beatmaps/BeatmapConverter.cs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Tests/TestCaseCatcherArea.cs b/osu.Game.Rulesets.Catch/Tests/TestCaseCatcherArea.cs index 84ca08f97e..538f6930ed 100644 --- a/osu.Game.Rulesets.Catch/Tests/TestCaseCatcherArea.cs +++ b/osu.Game.Rulesets.Catch/Tests/TestCaseCatcherArea.cs @@ -25,10 +25,10 @@ namespace osu.Game.Rulesets.Catch.Tests public TestCaseCatcherArea() { - AddSliderStep("CircleSize", 0, 8, 5, craeteCatcher); + AddSliderStep("CircleSize", 0, 8, 5, createCatcher); } - private void craeteCatcher(float size) + private void createCatcher(float size) { Child = new CatchInputManager(catchRuleset) { diff --git a/osu.Game/Beatmaps/BeatmapConverter.cs b/osu.Game/Beatmaps/BeatmapConverter.cs index 6132322f1e..e087eebbfe 100644 --- a/osu.Game/Beatmaps/BeatmapConverter.cs +++ b/osu.Game/Beatmaps/BeatmapConverter.cs @@ -80,7 +80,7 @@ namespace osu.Game.Beatmaps /// /// Performs the conversion of a hit object. - /// This method generally executed sequentially for all objects in a beatmap. + /// This method is generally executed sequentially for all objects in a beatmap. /// /// The hit object to convert. /// The un-converted Beatmap. From 7db7fb91ddc35c5408ac47273e2e0a3b3674526d Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 28 Nov 2017 21:45:24 +0900 Subject: [PATCH 0881/1263] Ignore ruleset testcases from CI --- osu.Game.Rulesets.Catch/Tests/TestCasePerformancePoints.cs | 3 +++ osu.Game.Rulesets.Mania/Tests/TestCasePerformancePoints.cs | 3 +++ osu.Game.Rulesets.Osu/Tests/TestCasePerformancePoints.cs | 3 +++ osu.Game.Rulesets.Taiko/Tests/TestCasePerformancePoints.cs | 3 +++ 4 files changed, 12 insertions(+) diff --git a/osu.Game.Rulesets.Catch/Tests/TestCasePerformancePoints.cs b/osu.Game.Rulesets.Catch/Tests/TestCasePerformancePoints.cs index 6643316f15..0d2dc14160 100644 --- a/osu.Game.Rulesets.Catch/Tests/TestCasePerformancePoints.cs +++ b/osu.Game.Rulesets.Catch/Tests/TestCasePerformancePoints.cs @@ -1,8 +1,11 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using NUnit.Framework; + namespace osu.Game.Rulesets.Catch.Tests { + [Ignore("getting CI working")] public class TestCasePerformancePoints : Game.Tests.Visual.TestCasePerformancePoints { public TestCasePerformancePoints() diff --git a/osu.Game.Rulesets.Mania/Tests/TestCasePerformancePoints.cs b/osu.Game.Rulesets.Mania/Tests/TestCasePerformancePoints.cs index e60808b1a6..8aa8c6b799 100644 --- a/osu.Game.Rulesets.Mania/Tests/TestCasePerformancePoints.cs +++ b/osu.Game.Rulesets.Mania/Tests/TestCasePerformancePoints.cs @@ -1,8 +1,11 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using NUnit.Framework; + namespace osu.Game.Rulesets.Mania.Tests { + [Ignore("getting CI working")] public class TestCasePerformancePoints : Game.Tests.Visual.TestCasePerformancePoints { public TestCasePerformancePoints() diff --git a/osu.Game.Rulesets.Osu/Tests/TestCasePerformancePoints.cs b/osu.Game.Rulesets.Osu/Tests/TestCasePerformancePoints.cs index 36590b484f..25a6110459 100644 --- a/osu.Game.Rulesets.Osu/Tests/TestCasePerformancePoints.cs +++ b/osu.Game.Rulesets.Osu/Tests/TestCasePerformancePoints.cs @@ -1,8 +1,11 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using NUnit.Framework; + namespace osu.Game.Rulesets.Osu.Tests { + [Ignore("getting CI working")] public class TestCasePerformancePoints : Game.Tests.Visual.TestCasePerformancePoints { public TestCasePerformancePoints() diff --git a/osu.Game.Rulesets.Taiko/Tests/TestCasePerformancePoints.cs b/osu.Game.Rulesets.Taiko/Tests/TestCasePerformancePoints.cs index 269aca2cd9..96d5b20b6e 100644 --- a/osu.Game.Rulesets.Taiko/Tests/TestCasePerformancePoints.cs +++ b/osu.Game.Rulesets.Taiko/Tests/TestCasePerformancePoints.cs @@ -1,8 +1,11 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using NUnit.Framework; + namespace osu.Game.Rulesets.Taiko.Tests { + [Ignore("getting CI working")] public class TestCasePerformancePoints : Game.Tests.Visual.TestCasePerformancePoints { public TestCasePerformancePoints() From f807d26caecf0ce8e08c6a97f54a4b73851610a3 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 28 Nov 2017 21:46:13 +0900 Subject: [PATCH 0882/1263] Use ranked property of mods rather than checking for individual mods --- osu.Game.Rulesets.Osu/Scoring/OsuPerformanceCalculator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Scoring/OsuPerformanceCalculator.cs b/osu.Game.Rulesets.Osu/Scoring/OsuPerformanceCalculator.cs index cc5abb36b5..cd6b6c5e27 100644 --- a/osu.Game.Rulesets.Osu/Scoring/OsuPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Osu/Scoring/OsuPerformanceCalculator.cs @@ -47,7 +47,7 @@ namespace osu.Game.Rulesets.Osu.Scoring countMiss = Convert.ToInt32(Score.Statistics["x"]); // Don't count scores made with supposedly unranked mods - if (mods.Any(m => m is OsuModRelax || m is OsuModAutopilot || m is OsuModAutoplay)) + if (mods.Any(m => !m.Ranked)) return 0; // Todo: In the future we should apply changes to PreEmpt/AR at an OsuHitObject/BaseDifficulty level, but this is done From 66fa10869623e096d82bcd0142b09341c84c1171 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 28 Nov 2017 22:24:56 +0900 Subject: [PATCH 0883/1263] Vertically centre the panels in osu!direct --- osu.Game/Overlays/DirectOverlay.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/DirectOverlay.cs b/osu.Game/Overlays/DirectOverlay.cs index b49ac269a9..0b7a30797d 100644 --- a/osu.Game/Overlays/DirectOverlay.cs +++ b/osu.Game/Overlays/DirectOverlay.cs @@ -220,7 +220,11 @@ namespace osu.Game.Overlays switch (displayStyle) { case PanelDisplayStyle.Grid: - return new DirectGridPanel(b); + return new DirectGridPanel(b) + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + }; default: return new DirectListPanel(b); } From 898c49c19db9ab54cd5eaf2bd91156aaac5b573d Mon Sep 17 00:00:00 2001 From: Santeri Date: Tue, 28 Nov 2017 16:14:32 +0200 Subject: [PATCH 0884/1263] remove unnecessary assignments --- osu.Game/Overlays/BeatmapSet/HeaderButton.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game/Overlays/BeatmapSet/HeaderButton.cs b/osu.Game/Overlays/BeatmapSet/HeaderButton.cs index 371e438a34..cddc05c554 100644 --- a/osu.Game/Overlays/BeatmapSet/HeaderButton.cs +++ b/osu.Game/Overlays/BeatmapSet/HeaderButton.cs @@ -20,8 +20,6 @@ namespace osu.Game.Overlays.BeatmapSet [BackgroundDependencyLoader] private void load() { - Masking = true; - CornerRadius = 3; BackgroundColour = OsuColour.FromHex(@"094c5f"); Triangles.ColourLight = OsuColour.FromHex(@"0f7c9b"); Triangles.ColourDark = OsuColour.FromHex(@"094c5f"); From 1aa79a2d884a6daf4cba7837fe0d1f1eca8ab4ce Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 29 Nov 2017 01:26:21 +0900 Subject: [PATCH 0885/1263] Hide inspectcode output from appveyor console --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 9048428590..78e0e6da4e 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -21,5 +21,5 @@ build: parallel: true verbosity: minimal after_build: - - cmd: inspectcode /o="inspectcodereport.xml" /caches-home="inspectcode" osu.sln + - cmd: inspectcode /o="inspectcodereport.xml" /caches-home="inspectcode" osu.sln > NUL - cmd: NVika parsereport "inspectcodereport.xml" --treatwarningsaserrors \ No newline at end of file From 6f5803b5eb39a2103096f83e3731c9763ff08900 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 29 Nov 2017 01:51:22 +0900 Subject: [PATCH 0886/1263] Shallow clone submodules --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 78e0e6da4e..ea9a1fa3bf 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -9,7 +9,7 @@ cache: - inspectcode -> appveyor.yml - packages -> **\packages.config install: - - cmd: git submodule update --init --recursive + - cmd: git submodule update --init --recursive --depth=5 - cmd: choco install resharper-clt -y - cmd: choco install nvika -y - cmd: appveyor DownloadFile https://github.com/peppy/CodeFileSanity/releases/download/v0.2.3/CodeFileSanity.exe From 6a4cc933603cf102108f1e354af006b05b871940 Mon Sep 17 00:00:00 2001 From: Aergwyn Date: Tue, 28 Nov 2017 21:26:13 +0100 Subject: [PATCH 0887/1263] fixes crash if all beatmaps of a set are hidden --- osu.Game/Screens/Select/BeatmapCarousel.cs | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index b0a636dfb3..e0f3137cec 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -45,7 +45,7 @@ namespace osu.Game.Screens.Select Task.Run(() => { - newGroups = value.Select(createGroup).ToList(); + newGroups = value.Select(createGroup).Where(g => g != null).ToList(); criteria.Filter(newGroups); }).ContinueWith(t => { @@ -124,16 +124,24 @@ namespace osu.Game.Screens.Select // todo: this method should be smarter as to not recreate panels that haven't changed, etc. var group = groups.Find(b => b.BeatmapSet.ID == set.ID); + BeatmapGroup newGroup; if (group == null) - return; + { + newGroup = createGroup(set); - int i = groups.IndexOf(group); - groups.RemoveAt(i); + if (newGroup != null) + groups.Add(newGroup); + } + else + { + int i = groups.IndexOf(group); + groups.RemoveAt(i); - var newGroup = createGroup(set); + newGroup = createGroup(set); - if (newGroup != null) - groups.Insert(i, newGroup); + if (newGroup != null) + groups.Insert(i, newGroup); + } bool hadSelection = selectedGroup == group; From 3bdf82d8df16ed910920c56938c3a74811a49602 Mon Sep 17 00:00:00 2001 From: Aergwyn Date: Tue, 28 Nov 2017 21:38:11 +0100 Subject: [PATCH 0888/1263] refactor newly added code to be less redundant --- osu.Game/Screens/Select/BeatmapCarousel.cs | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index e0f3137cec..3f42ae11ac 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -124,23 +124,18 @@ namespace osu.Game.Screens.Select // todo: this method should be smarter as to not recreate panels that haven't changed, etc. var group = groups.Find(b => b.BeatmapSet.ID == set.ID); - BeatmapGroup newGroup; - if (group == null) - { - newGroup = createGroup(set); - - if (newGroup != null) - groups.Add(newGroup); - } - else - { - int i = groups.IndexOf(group); + int i = groups.IndexOf(group); + if (i >= 0) groups.RemoveAt(i); - newGroup = createGroup(set); + var newGroup = createGroup(set); - if (newGroup != null) + if (newGroup != null) + { + if (i >= 0) groups.Insert(i, newGroup); + else + groups.Add(newGroup); } bool hadSelection = selectedGroup == group; From 8370d7694638d2de0f495e673b73b5687a654ff1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 29 Nov 2017 12:27:18 +0900 Subject: [PATCH 0889/1263] Quieten nuget --- appveyor.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index ea9a1fa3bf..9cf68803a2 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -15,11 +15,11 @@ install: - cmd: appveyor DownloadFile https://github.com/peppy/CodeFileSanity/releases/download/v0.2.3/CodeFileSanity.exe before_build: - cmd: CodeFileSanity.exe - - cmd: nuget restore + - cmd: nuget restore -verbosity quiet build: project: osu.sln parallel: true verbosity: minimal after_build: - - cmd: inspectcode /o="inspectcodereport.xml" /caches-home="inspectcode" osu.sln > NUL + - cmd: inspectcode --o="inspectcodereport.xml" --projects:osu.Game* --caches-home="inspectcode" osu.sln > NUL - cmd: NVika parsereport "inspectcodereport.xml" --treatwarningsaserrors \ No newline at end of file From d1afbf80557773f00936865a860a8714e4a7b645 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 29 Nov 2017 13:10:13 +0900 Subject: [PATCH 0890/1263] Load Player-based TestCases asynchronously --- osu.Game/Tests/Visual/TestCasePlayer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Tests/Visual/TestCasePlayer.cs b/osu.Game/Tests/Visual/TestCasePlayer.cs index f3a6d1efc3..64da838494 100644 --- a/osu.Game/Tests/Visual/TestCasePlayer.cs +++ b/osu.Game/Tests/Visual/TestCasePlayer.cs @@ -78,7 +78,7 @@ namespace osu.Game.Tests.Visual if (Player != null) Remove(Player); - LoadScreen(CreatePlayer(working, instance)); + LoadComponentAsync(CreatePlayer(working, instance), LoadScreen); } protected virtual Player CreatePlayer(WorkingBeatmap beatmap, Ruleset ruleset) => new Player From 1136db15562454e6c44d23b7d23030d9e1d501d9 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 29 Nov 2017 14:20:15 +0900 Subject: [PATCH 0891/1263] Fix mania replays not defining important frames Resolves https://github.com/ppy/osu/issues/1495 . --- .../Replays/ManiaAutoGenerator.cs | 9 +++++---- .../Replays/ManiaReplayFrame.cs | 17 +++++++++++++++++ .../osu.Game.Rulesets.Mania.csproj | 1 + osu.Game/Rulesets/Replays/ReplayFrame.cs | 4 ++-- 4 files changed, 25 insertions(+), 6 deletions(-) create mode 100644 osu.Game.Rulesets.Mania/Replays/ManiaReplayFrame.cs diff --git a/osu.Game.Rulesets.Mania/Replays/ManiaAutoGenerator.cs b/osu.Game.Rulesets.Mania/Replays/ManiaAutoGenerator.cs index 64982532a7..58fb43aa83 100644 --- a/osu.Game.Rulesets.Mania/Replays/ManiaAutoGenerator.cs +++ b/osu.Game.Rulesets.Mania/Replays/ManiaAutoGenerator.cs @@ -30,7 +30,7 @@ namespace osu.Game.Rulesets.Mania.Replays public override Replay Generate() { // Todo: Realistically this shouldn't be needed, but the first frame is skipped with the way replays are currently handled - Replay.Frames.Add(new ReplayFrame(-100000, null, null, ReplayButtonState.None)); + Replay.Frames.Add(new ManiaReplayFrame(-100000, null, null, ReplayButtonState.None)); double[] holdEndTimes = new double[availableColumns]; for (int i = 0; i < availableColumns; i++) @@ -60,7 +60,7 @@ namespace osu.Game.Rulesets.Mania.Replays activeColumns |= 1 << obj.Column; } - Replay.Frames.Add(new ReplayFrame(groupTime, activeColumns, null, ReplayButtonState.None)); + Replay.Frames.Add(new ManiaReplayFrame(groupTime, activeColumns, null, ReplayButtonState.None)); // Add the release frames. We can't do this with the loop above because we need activeColumns to be fully populated foreach (var obj in objGroup.GroupBy(h => (h as IHasEndTime)?.EndTime ?? h.StartTime + release_delay).OrderBy(h => h.Key)) @@ -74,14 +74,15 @@ namespace osu.Game.Rulesets.Mania.Replays activeColumnsAtEnd |= 1 << i; } - Replay.Frames.Add(new ReplayFrame(groupEndTime, activeColumnsAtEnd, 0, ReplayButtonState.None)); + Replay.Frames.Add(new ManiaReplayFrame(groupEndTime, activeColumnsAtEnd, 0, ReplayButtonState.None)); } } Replay.Frames = Replay.Frames // Pick the maximum activeColumns for all frames at the same time .GroupBy(f => f.Time) - .Select(g => new ReplayFrame(g.First().Time, maxMouseX(g), 0, ReplayButtonState.None)) + .Select(g => new ManiaReplayFrame(g.First().Time, maxMouseX(g), 0, ReplayButtonState.None)) + .Cast() // The addition of release frames above maybe result in unordered frames, but we need them ordered .OrderBy(f => f.Time) .ToList(); diff --git a/osu.Game.Rulesets.Mania/Replays/ManiaReplayFrame.cs b/osu.Game.Rulesets.Mania/Replays/ManiaReplayFrame.cs new file mode 100644 index 0000000000..c27ffa1875 --- /dev/null +++ b/osu.Game.Rulesets.Mania/Replays/ManiaReplayFrame.cs @@ -0,0 +1,17 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Game.Rulesets.Replays; + +namespace osu.Game.Rulesets.Mania.Replays +{ + public class ManiaReplayFrame : ReplayFrame + { + public override bool IsImportant => MouseX > 0; + + public ManiaReplayFrame(double time, float? mouseX, float? mouseY, ReplayButtonState buttonState) + : base(time, mouseX, mouseY, buttonState) + { + } + } +} diff --git a/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj b/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj index 6f45a64d92..22f858c2ea 100644 --- a/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj +++ b/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj @@ -72,6 +72,7 @@ + diff --git a/osu.Game/Rulesets/Replays/ReplayFrame.cs b/osu.Game/Rulesets/Replays/ReplayFrame.cs index b0f62e5271..02c969f648 100644 --- a/osu.Game/Rulesets/Replays/ReplayFrame.cs +++ b/osu.Game/Rulesets/Replays/ReplayFrame.cs @@ -9,7 +9,7 @@ namespace osu.Game.Rulesets.Replays { public Vector2 Position => new Vector2(MouseX ?? 0, MouseY ?? 0); - public bool IsImportant => MouseX.HasValue && MouseY.HasValue && (MouseLeft || MouseRight); + public virtual bool IsImportant => MouseX.HasValue && MouseY.HasValue && (MouseLeft || MouseRight); public float? MouseX; public float? MouseY; @@ -68,4 +68,4 @@ namespace osu.Game.Rulesets.Replays return $"{Time}\t({MouseX},{MouseY})\t{MouseLeft}\t{MouseRight}\t{MouseLeft1}\t{MouseRight1}\t{MouseLeft2}\t{MouseRight2}\t{ButtonState}"; } } -} \ No newline at end of file +} From bc3f11fdb87983e0faeab1acd96aa2e526f89f52 Mon Sep 17 00:00:00 2001 From: FreezyLemon Date: Wed, 29 Nov 2017 06:24:13 +0100 Subject: [PATCH 0892/1263] Added PlaysSamples property to prevent certain DrawableHitObjects from playing their samples on hit. Also added this to TaikoObjects so their hitsounds won't be played (will be done by the TaikoRulesetContainer) --- .../Objects/Drawables/DrawableTaikoHitObject.cs | 2 ++ osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs | 5 ++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs index 7976cbbbc1..8ebfaaea38 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs @@ -14,6 +14,8 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables { public override Vector2 OriginPosition => new Vector2(DrawHeight / 2); + protected override bool PlaysSamples => false; + protected readonly Vector2 BaseSize; protected readonly TaikoPiece MainPiece; diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index 941cedca3f..12f4fc4f31 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -59,6 +59,9 @@ namespace osu.Game.Rulesets.Objects.Drawables private readonly List judgements = new List(); public IReadOnlyList Judgements => judgements; + // Override in inheriting classes to prevent from playing samples on hit + protected virtual bool PlaysSamples => true; + protected List Samples = new List(); public readonly Bindable State = new Bindable(); @@ -92,7 +95,7 @@ namespace osu.Game.Rulesets.Objects.Drawables { UpdateState(state); - if (State == ArmedState.Hit) + if (State == ArmedState.Hit && PlaysSamples) PlaySamples(); }; From 3e8db8c5e1020031f51a874db7d0c7059a54e3b0 Mon Sep 17 00:00:00 2001 From: FreezyLemon Date: Wed, 29 Nov 2017 06:27:25 +0100 Subject: [PATCH 0893/1263] Enabled strong taiko hitobjects playing samples again. Also removes the first hitsound from the strong hitobject so only the "hitfinish" sound gets played. --- .../Objects/Drawables/DrawableHitStrong.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHitStrong.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHitStrong.cs index c07eaf4d8b..eced24a8da 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHitStrong.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHitStrong.cs @@ -16,6 +16,8 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables /// private const double second_hit_window = 30; + protected override bool PlaysSamples => true; + private double firstHitTime; private bool firstKeyHeld; private TaikoAction firstHitAction; @@ -53,6 +55,15 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables return base.OnReleased(action); } + protected override void LoadComplete() + { + base.LoadComplete(); + + if (Samples.Count > 1) + // Removes the "normal" hitsound, leaving only the hitfinish one + Samples.RemoveAt(0); + } + public override bool OnPressed(TaikoAction action) { if (AllJudged) From c00fb47236253aba363c6b2df67a1937a73ec932 Mon Sep 17 00:00:00 2001 From: FreezyLemon Date: Wed, 29 Nov 2017 06:28:08 +0100 Subject: [PATCH 0894/1263] Added hitsound handling to the TaikoRulesetContainer so every KeyDown can play a hitsound (instead of the DrawableHitObjects) --- .../UI/TaikoRulesetContainer.cs | 44 ++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoRulesetContainer.cs b/osu.Game.Rulesets.Taiko/UI/TaikoRulesetContainer.cs index 48ee0a5b42..e3765c4252 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoRulesetContainer.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoRulesetContainer.cs @@ -2,8 +2,11 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using osu.Framework.Allocation; +using osu.Framework.Audio; using osu.Framework.Graphics; +using osu.Framework.Input.Bindings; using osu.Game.Beatmaps; +using osu.Game.Input; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Replays; @@ -15,21 +18,45 @@ using osu.Game.Rulesets.Taiko.Scoring; using osu.Game.Rulesets.UI; using osu.Game.Rulesets.Taiko.Replays; using OpenTK; +using OpenTK.Input; using System.Linq; using osu.Framework.Input; +using System.Collections.Generic; namespace osu.Game.Rulesets.Taiko.UI { public class TaikoRulesetContainer : ScrollingRulesetContainer { + private readonly HashSet centreKeys = new HashSet(); + private readonly HashSet rimKeys = new HashSet(); + private AudioManager audio; + private IEnumerable keyBindings; + public TaikoRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap, bool isForCurrentRuleset) : base(ruleset, beatmap, isForCurrentRuleset) { } [BackgroundDependencyLoader] - private void load() + private void load(AudioManager audio, KeyBindingStore store) { + keyBindings = store.Query(Ruleset.RulesetInfo.ID, Ruleset.AvailableVariants?.First() ?? 0).Cast(); + if (keyBindings.Count() == 0) + keyBindings = Ruleset.GetDefaultKeyBindings(); + + foreach (var kb in keyBindings) + { + var key = (Key)(kb.KeyCombination.Keys as InputKey[]).First(); + var action = kb.GetAction(); + + if (action == TaikoAction.LeftCentre || action == TaikoAction.RightCentre) + centreKeys.Add(key); + + if (action == TaikoAction.LeftRim || action == TaikoAction.RightRim) + rimKeys.Add(key); + } + + this.audio = audio; loadBarLines(); } @@ -77,6 +104,21 @@ namespace osu.Game.Rulesets.Taiko.UI } } + protected override bool OnKeyDown(InputState state, KeyDownEventArgs args) + { + var sampleBank = Beatmap.ControlPointInfo.SoundPointAt(WorkingBeatmap.Track.CurrentTime).SampleBank ?? "normal"; + string sampleName = ""; + + if (centreKeys.Contains(args.Key)) + sampleName = "hitnormal"; + + else if (rimKeys.Contains(args.Key)) + sampleName = "hitclap"; + + audio.Sample.Get($"Gameplay/{sampleBank}-{sampleName}")?.Play(); + return base.OnKeyDown(state, args); + } + protected override Vector2 GetPlayfieldAspectAdjust() { const float default_relative_height = TaikoPlayfield.DEFAULT_HEIGHT / 768; From e3232dd754528a8e2136f6326e20d2671fb60b7d Mon Sep 17 00:00:00 2001 From: FreezyLemon Date: Wed, 29 Nov 2017 06:51:00 +0100 Subject: [PATCH 0895/1263] Added if to ignore more (for our purposes) useless keydowns --- .../UI/TaikoRulesetContainer.cs | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoRulesetContainer.cs b/osu.Game.Rulesets.Taiko/UI/TaikoRulesetContainer.cs index e3765c4252..f72d253a73 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoRulesetContainer.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoRulesetContainer.cs @@ -106,16 +106,20 @@ namespace osu.Game.Rulesets.Taiko.UI protected override bool OnKeyDown(InputState state, KeyDownEventArgs args) { - var sampleBank = Beatmap.ControlPointInfo.SoundPointAt(WorkingBeatmap.Track.CurrentTime).SampleBank ?? "normal"; - string sampleName = ""; + if (!args.Repeat) + { + var sampleBank = Beatmap.ControlPointInfo.SoundPointAt(WorkingBeatmap.Track.CurrentTime).SampleBank ?? "normal"; + string sampleName = ""; - if (centreKeys.Contains(args.Key)) - sampleName = "hitnormal"; + if (centreKeys.Contains(args.Key)) + sampleName = "hitnormal"; - else if (rimKeys.Contains(args.Key)) - sampleName = "hitclap"; + else if (rimKeys.Contains(args.Key)) + sampleName = "hitclap"; + + audio.Sample.Get($"Gameplay/{sampleBank}-{sampleName}")?.Play(); + } - audio.Sample.Get($"Gameplay/{sampleBank}-{sampleName}")?.Play(); return base.OnKeyDown(state, args); } From 6fd550dc91de4557157a317de1897fd29f901184 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 29 Nov 2017 15:47:10 +0900 Subject: [PATCH 0896/1263] Simplify/sanitize construction of ManiaReplayFrame --- osu.Game.Rulesets.Mania/Replays/ManiaAutoGenerator.cs | 10 +++++----- osu.Game.Rulesets.Mania/Replays/ManiaReplayFrame.cs | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Replays/ManiaAutoGenerator.cs b/osu.Game.Rulesets.Mania/Replays/ManiaAutoGenerator.cs index 58fb43aa83..ca80bf8413 100644 --- a/osu.Game.Rulesets.Mania/Replays/ManiaAutoGenerator.cs +++ b/osu.Game.Rulesets.Mania/Replays/ManiaAutoGenerator.cs @@ -30,7 +30,7 @@ namespace osu.Game.Rulesets.Mania.Replays public override Replay Generate() { // Todo: Realistically this shouldn't be needed, but the first frame is skipped with the way replays are currently handled - Replay.Frames.Add(new ManiaReplayFrame(-100000, null, null, ReplayButtonState.None)); + Replay.Frames.Add(new ManiaReplayFrame(-100000, 0)); double[] holdEndTimes = new double[availableColumns]; for (int i = 0; i < availableColumns; i++) @@ -60,7 +60,7 @@ namespace osu.Game.Rulesets.Mania.Replays activeColumns |= 1 << obj.Column; } - Replay.Frames.Add(new ManiaReplayFrame(groupTime, activeColumns, null, ReplayButtonState.None)); + Replay.Frames.Add(new ManiaReplayFrame(groupTime, activeColumns)); // Add the release frames. We can't do this with the loop above because we need activeColumns to be fully populated foreach (var obj in objGroup.GroupBy(h => (h as IHasEndTime)?.EndTime ?? h.StartTime + release_delay).OrderBy(h => h.Key)) @@ -74,14 +74,14 @@ namespace osu.Game.Rulesets.Mania.Replays activeColumnsAtEnd |= 1 << i; } - Replay.Frames.Add(new ManiaReplayFrame(groupEndTime, activeColumnsAtEnd, 0, ReplayButtonState.None)); + Replay.Frames.Add(new ManiaReplayFrame(groupEndTime, activeColumnsAtEnd)); } } Replay.Frames = Replay.Frames // Pick the maximum activeColumns for all frames at the same time .GroupBy(f => f.Time) - .Select(g => new ManiaReplayFrame(g.First().Time, maxMouseX(g), 0, ReplayButtonState.None)) + .Select(g => new ManiaReplayFrame(g.First().Time, maxMouseX(g))) .Cast() // The addition of release frames above maybe result in unordered frames, but we need them ordered .OrderBy(f => f.Time) @@ -95,7 +95,7 @@ namespace osu.Game.Rulesets.Mania.Replays /// /// The grouping to search. /// The maximum by count of bits. - private float maxMouseX(IGrouping group) + private int maxMouseX(IGrouping group) { int currentCount = -1; int currentMax = 0; diff --git a/osu.Game.Rulesets.Mania/Replays/ManiaReplayFrame.cs b/osu.Game.Rulesets.Mania/Replays/ManiaReplayFrame.cs index c27ffa1875..8473d23b89 100644 --- a/osu.Game.Rulesets.Mania/Replays/ManiaReplayFrame.cs +++ b/osu.Game.Rulesets.Mania/Replays/ManiaReplayFrame.cs @@ -9,8 +9,8 @@ namespace osu.Game.Rulesets.Mania.Replays { public override bool IsImportant => MouseX > 0; - public ManiaReplayFrame(double time, float? mouseX, float? mouseY, ReplayButtonState buttonState) - : base(time, mouseX, mouseY, buttonState) + public ManiaReplayFrame(double time, int activeColumns) + : base(time, (float)activeColumns, null, ReplayButtonState.None) { } } From 8c30fd490c373492e219bead97d5ae9fc7e57bf9 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 29 Nov 2017 16:22:11 +0900 Subject: [PATCH 0897/1263] Add HitObjectComposer class --- osu.Game.Rulesets.Catch/Edit/HitObjectComposer.cs | 10 ++++++++++ osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj | 1 + osu.Game.Rulesets.Mania/Edit/HitObjectComposer.cs | 10 ++++++++++ osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj | 1 + osu.Game.Rulesets.Osu/Edit/HitObjectComposer.cs | 10 ++++++++++ osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj | 1 + osu.Game.Rulesets.Taiko/Edit/HitObjectComposer.cs | 10 ++++++++++ osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj | 1 + osu.Game/Rulesets/Edit/HitObjectComposer.cs | 10 ++++++++++ osu.Game/osu.Game.csproj | 1 + 10 files changed, 55 insertions(+) create mode 100644 osu.Game.Rulesets.Catch/Edit/HitObjectComposer.cs create mode 100644 osu.Game.Rulesets.Mania/Edit/HitObjectComposer.cs create mode 100644 osu.Game.Rulesets.Osu/Edit/HitObjectComposer.cs create mode 100644 osu.Game.Rulesets.Taiko/Edit/HitObjectComposer.cs create mode 100644 osu.Game/Rulesets/Edit/HitObjectComposer.cs diff --git a/osu.Game.Rulesets.Catch/Edit/HitObjectComposer.cs b/osu.Game.Rulesets.Catch/Edit/HitObjectComposer.cs new file mode 100644 index 0000000000..01351fd00c --- /dev/null +++ b/osu.Game.Rulesets.Catch/Edit/HitObjectComposer.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.Catch.Edit +{ + public class HitObjectComposer : Rulesets.Edit.HitObjectComposer + { + + } +} diff --git a/osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj b/osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj index bf60bc01bb..30c088ac85 100644 --- a/osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj +++ b/osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj @@ -48,6 +48,7 @@ + diff --git a/osu.Game.Rulesets.Mania/Edit/HitObjectComposer.cs b/osu.Game.Rulesets.Mania/Edit/HitObjectComposer.cs new file mode 100644 index 0000000000..aa0d43dc75 --- /dev/null +++ b/osu.Game.Rulesets.Mania/Edit/HitObjectComposer.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.Mania.Edit +{ + public class HitObjectComposer : Rulesets.Edit.HitObjectComposer + { + + } +} diff --git a/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj b/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj index 6f45a64d92..1470ee57b1 100644 --- a/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj +++ b/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj @@ -53,6 +53,7 @@ + diff --git a/osu.Game.Rulesets.Osu/Edit/HitObjectComposer.cs b/osu.Game.Rulesets.Osu/Edit/HitObjectComposer.cs new file mode 100644 index 0000000000..921fb72fdf --- /dev/null +++ b/osu.Game.Rulesets.Osu/Edit/HitObjectComposer.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.Edit +{ + public class HitObjectComposer : Rulesets.Edit.HitObjectComposer + { + + } +} diff --git a/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj b/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj index 3c90749777..32a0a34ff2 100644 --- a/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj +++ b/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj @@ -49,6 +49,7 @@ + diff --git a/osu.Game.Rulesets.Taiko/Edit/HitObjectComposer.cs b/osu.Game.Rulesets.Taiko/Edit/HitObjectComposer.cs new file mode 100644 index 0000000000..e524b4cdc7 --- /dev/null +++ b/osu.Game.Rulesets.Taiko/Edit/HitObjectComposer.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.Taiko.Edit +{ + public class HitObjectComposer : Rulesets.Edit.HitObjectComposer + { + + } +} diff --git a/osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj b/osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj index bf627d205a..41881fc250 100644 --- a/osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj +++ b/osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj @@ -46,6 +46,7 @@ + diff --git a/osu.Game/Rulesets/Edit/HitObjectComposer.cs b/osu.Game/Rulesets/Edit/HitObjectComposer.cs new file mode 100644 index 0000000000..2724334ed4 --- /dev/null +++ b/osu.Game/Rulesets/Edit/HitObjectComposer.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.Edit +{ + public class HitObjectComposer + { + + } +} diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index ce9e8eff9c..b707a3382e 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -559,6 +559,7 @@ + From 2ec24f58c8e5c30e9c3cd681f55869f971b4f80e Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 29 Nov 2017 16:30:59 +0900 Subject: [PATCH 0898/1263] Add testcase for editor compose --- .../Visual/TestCaseEditorCompose.cs | 47 +++++++++++++++++++ osu.Game.Tests/osu.Game.Tests.csproj | 1 + 2 files changed, 48 insertions(+) create mode 100644 osu.Game.Tests/Visual/TestCaseEditorCompose.cs diff --git a/osu.Game.Tests/Visual/TestCaseEditorCompose.cs b/osu.Game.Tests/Visual/TestCaseEditorCompose.cs new file mode 100644 index 0000000000..9f060a9ec4 --- /dev/null +++ b/osu.Game.Tests/Visual/TestCaseEditorCompose.cs @@ -0,0 +1,47 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using osu.Framework.Allocation; +using osu.Game.Beatmaps; +using osu.Game.Screens.Edit.Screens.Compose; + +namespace osu.Game.Tests.Visual +{ + public class TestCaseEditorCompose : OsuTestCase + { + private readonly Random random; + private readonly Compose compose; + + public TestCaseEditorCompose() + { + random = new Random(1337); + + Add(compose = new Compose()); + AddStep("Next beatmap", nextBeatmap); + } + + private OsuGameBase osuGame; + private BeatmapManager beatmaps; + + [BackgroundDependencyLoader] + private void load(OsuGameBase osuGame, BeatmapManager beatmaps) + { + this.osuGame = osuGame; + this.beatmaps = beatmaps; + + compose.Beatmap.BindTo(osuGame.Beatmap); + nextBeatmap(); + } + + private void nextBeatmap() + { + var sets = beatmaps.GetAllUsableBeatmapSets(); + if (sets.Count == 0) + return; + + var b = sets[random.Next(0, sets.Count)].Beatmaps[0]; + osuGame.Beatmap.Value = beatmaps.GetWorkingBeatmap(b); + } + } +} diff --git a/osu.Game.Tests/osu.Game.Tests.csproj b/osu.Game.Tests/osu.Game.Tests.csproj index 312a564f71..34f79987c5 100644 --- a/osu.Game.Tests/osu.Game.Tests.csproj +++ b/osu.Game.Tests/osu.Game.Tests.csproj @@ -105,6 +105,7 @@ + From f586cbac3285e2b2a8e8586276bd660e9736ddb0 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 29 Nov 2017 16:47:36 +0900 Subject: [PATCH 0899/1263] Restructure Compose to use grids and eventually support HitObjectContainer --- .../Screens/Edit/Screens/Compose/Compose.cs | 66 ++++++++++++------- 1 file changed, 44 insertions(+), 22 deletions(-) diff --git a/osu.Game/Screens/Edit/Screens/Compose/Compose.cs b/osu.Game/Screens/Edit/Screens/Compose/Compose.cs index 2349c261cf..67e66eecdf 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Compose.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Compose.cs @@ -12,40 +12,62 @@ namespace osu.Game.Screens.Edit.Screens.Compose { public class Compose : EditorScreen { + private const float vertical_margins = 10; + private const float horizontal_margins = 20; + public Compose() { ScrollableTimeline timeline; - Children = new[] + Children = new Drawable[] { - new Container + new GridContainer { - Name = "Timeline", - RelativeSizeAxes = Axes.X, - Height = 110, - Children = new Drawable[] + RelativeSizeAxes = Axes.Both, + Content = new[] { - new Box + new Drawable[] { - RelativeSizeAxes = Axes.Both, - Colour = Color4.Black.Opacity(0.5f) - }, - new Container - { - Name = "Content", - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding { Horizontal = 17, Vertical = 10 }, - Children = new Drawable[] + new Container { - new Container + Name = "Timeline", + RelativeSizeAxes = Axes.Both, + Children = new Drawable[] { - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding { Right = 115 }, - Child = timeline = new ScrollableTimeline { RelativeSizeAxes = Axes.Both } + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Black.Opacity(0.5f) + }, + new Container + { + Name = "Timeline content", + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding { Horizontal = horizontal_margins, Vertical = vertical_margins }, + Children = new Drawable[] + { + new Container + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding { Right = 115 }, + Child = timeline = new ScrollableTimeline { RelativeSizeAxes = Axes.Both } + } + } + } } } + }, + new Drawable[] + { + new Container + { + Name = "Composer content", + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding { Horizontal = horizontal_margins, Vertical = vertical_margins }, + } } - } - } + }, + RowDimensions = new[] { new Dimension(GridSizeMode.Absolute, 110) } + }, }; timeline.Beatmap.BindTo(Beatmap); From 1ea089eb743c0f7b4eca26f5fc70e943a89d341f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 29 Nov 2017 15:53:41 +0900 Subject: [PATCH 0900/1263] Update framework --- osu-framework | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu-framework b/osu-framework index d92cec7645..4fc866eee3 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit d92cec764538da2e7ed95bfb566f6bc81a9667c8 +Subproject commit 4fc866eee3803f88b155150e32e021b9c21e647f From bad970d1d1f0b0feee09c54ab3b5ee7918458d90 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 29 Nov 2017 17:25:55 +0900 Subject: [PATCH 0901/1263] Add wait steps to ensure the player is completely loaded before continuing --- osu.Game/Tests/Visual/TestCasePlayer.cs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/osu.Game/Tests/Visual/TestCasePlayer.cs b/osu.Game/Tests/Visual/TestCasePlayer.cs index 64da838494..d9951e002b 100644 --- a/osu.Game/Tests/Visual/TestCasePlayer.cs +++ b/osu.Game/Tests/Visual/TestCasePlayer.cs @@ -50,7 +50,11 @@ namespace osu.Game.Tests.Visual string instantiation = ruleset?.AssemblyQualifiedName; foreach (var r in rulesets.AvailableRulesets.Where(rs => instantiation == null || rs.InstantiationInfo == instantiation)) - AddStep(r.Name, () => loadPlayerFor(r)); + { + Player p = null; + AddStep(r.Name, () => p = loadPlayerFor(r)); + AddUntilStep(() => p.IsLoaded); + } } protected virtual Beatmap CreateBeatmap() @@ -64,7 +68,7 @@ namespace osu.Game.Tests.Visual return beatmap; } - private void loadPlayerFor(RulesetInfo r) + private Player loadPlayerFor(RulesetInfo r) { var beatmap = CreateBeatmap(); @@ -78,7 +82,11 @@ namespace osu.Game.Tests.Visual if (Player != null) Remove(Player); - LoadComponentAsync(CreatePlayer(working, instance), LoadScreen); + var player = CreatePlayer(working, instance); + + LoadComponentAsync(player, LoadScreen); + + return player; } protected virtual Player CreatePlayer(WorkingBeatmap beatmap, Ruleset ruleset) => new Player From 309eb4edd752b95d108770f2df55f6efdcd6ac2c Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 29 Nov 2017 17:46:12 +0900 Subject: [PATCH 0902/1263] Integrate HitObjectComposer into Compose Also removes the other rulesets' HitObjectComposers for now. --- .../Edit/HitObjectComposer.cs | 10 -------- .../osu.Game.Rulesets.Catch.csproj | 1 - .../Edit/HitObjectComposer.cs | 10 -------- .../osu.Game.Rulesets.Mania.csproj | 1 - ...ectComposer.cs => OsuHitObjectComposer.cs} | 7 ++++-- osu.Game.Rulesets.Osu/OsuRuleset.cs | 4 ++++ .../osu.Game.Rulesets.Osu.csproj | 2 +- .../Edit/HitObjectComposer.cs | 10 -------- .../osu.Game.Rulesets.Taiko.csproj | 1 - osu.Game/Rulesets/Edit/HitObjectComposer.cs | 23 +++++++++++++++++- osu.Game/Rulesets/Ruleset.cs | 3 +++ .../Screens/Edit/Screens/Compose/Compose.cs | 24 ++++++++++++++++++- 12 files changed, 58 insertions(+), 38 deletions(-) delete mode 100644 osu.Game.Rulesets.Catch/Edit/HitObjectComposer.cs delete mode 100644 osu.Game.Rulesets.Mania/Edit/HitObjectComposer.cs rename osu.Game.Rulesets.Osu/Edit/{HitObjectComposer.cs => OsuHitObjectComposer.cs} (52%) delete mode 100644 osu.Game.Rulesets.Taiko/Edit/HitObjectComposer.cs diff --git a/osu.Game.Rulesets.Catch/Edit/HitObjectComposer.cs b/osu.Game.Rulesets.Catch/Edit/HitObjectComposer.cs deleted file mode 100644 index 01351fd00c..0000000000 --- a/osu.Game.Rulesets.Catch/Edit/HitObjectComposer.cs +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright (c) 2007-2017 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -namespace osu.Game.Rulesets.Catch.Edit -{ - public class HitObjectComposer : Rulesets.Edit.HitObjectComposer - { - - } -} diff --git a/osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj b/osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj index 30c088ac85..bf60bc01bb 100644 --- a/osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj +++ b/osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj @@ -48,7 +48,6 @@ - diff --git a/osu.Game.Rulesets.Mania/Edit/HitObjectComposer.cs b/osu.Game.Rulesets.Mania/Edit/HitObjectComposer.cs deleted file mode 100644 index aa0d43dc75..0000000000 --- a/osu.Game.Rulesets.Mania/Edit/HitObjectComposer.cs +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright (c) 2007-2017 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -namespace osu.Game.Rulesets.Mania.Edit -{ - public class HitObjectComposer : Rulesets.Edit.HitObjectComposer - { - - } -} diff --git a/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj b/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj index 1470ee57b1..6f45a64d92 100644 --- a/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj +++ b/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj @@ -53,7 +53,6 @@ - diff --git a/osu.Game.Rulesets.Osu/Edit/HitObjectComposer.cs b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs similarity index 52% rename from osu.Game.Rulesets.Osu/Edit/HitObjectComposer.cs rename to osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs index 921fb72fdf..18dfbb6711 100644 --- a/osu.Game.Rulesets.Osu/Edit/HitObjectComposer.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs @@ -3,8 +3,11 @@ namespace osu.Game.Rulesets.Osu.Edit { - public class HitObjectComposer : Rulesets.Edit.HitObjectComposer + public class OsuHitObjectComposer : Rulesets.Edit.HitObjectComposer { - + public OsuHitObjectComposer(Ruleset ruleset) + : base(ruleset) + { + } } } diff --git a/osu.Game.Rulesets.Osu/OsuRuleset.cs b/osu.Game.Rulesets.Osu/OsuRuleset.cs index c87328d87c..64e76d6022 100644 --- a/osu.Game.Rulesets.Osu/OsuRuleset.cs +++ b/osu.Game.Rulesets.Osu/OsuRuleset.cs @@ -14,6 +14,8 @@ using System.Linq; using osu.Framework.Graphics; using osu.Game.Overlays.Settings; using osu.Framework.Input.Bindings; +using osu.Game.Rulesets.Osu.Edit; +using osu.Game.Rulesets.Edit; namespace osu.Game.Rulesets.Osu { @@ -114,6 +116,8 @@ namespace osu.Game.Rulesets.Osu public override DifficultyCalculator CreateDifficultyCalculator(Beatmap beatmap, Mod[] mods = null) => new OsuDifficultyCalculator(beatmap, mods); + public override HitObjectComposer CreateHitObjectComposer() => new OsuHitObjectComposer(this); + public override string Description => "osu!"; public override SettingsSubsection CreateSettings() => new OsuSettings(); diff --git a/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj b/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj index 32a0a34ff2..34f9bdf972 100644 --- a/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj +++ b/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj @@ -49,7 +49,7 @@ - + diff --git a/osu.Game.Rulesets.Taiko/Edit/HitObjectComposer.cs b/osu.Game.Rulesets.Taiko/Edit/HitObjectComposer.cs deleted file mode 100644 index e524b4cdc7..0000000000 --- a/osu.Game.Rulesets.Taiko/Edit/HitObjectComposer.cs +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright (c) 2007-2017 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -namespace osu.Game.Rulesets.Taiko.Edit -{ - public class HitObjectComposer : Rulesets.Edit.HitObjectComposer - { - - } -} diff --git a/osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj b/osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj index 41881fc250..bf627d205a 100644 --- a/osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj +++ b/osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj @@ -46,7 +46,6 @@ - diff --git a/osu.Game/Rulesets/Edit/HitObjectComposer.cs b/osu.Game/Rulesets/Edit/HitObjectComposer.cs index 2724334ed4..da31f6ba66 100644 --- a/osu.Game/Rulesets/Edit/HitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/HitObjectComposer.cs @@ -1,10 +1,31 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; + namespace osu.Game.Rulesets.Edit { - public class HitObjectComposer + public abstract class HitObjectComposer : CompositeDrawable { + private readonly Ruleset ruleset; + public HitObjectComposer(Ruleset ruleset) + { + this.ruleset = ruleset; + + RelativeSizeAxes = Axes.Both; + } + + [BackgroundDependencyLoader] + private void load(OsuGameBase osuGame) + { + try + { + InternalChild = ruleset.CreateRulesetContainerWith(osuGame.Beatmap.Value, true); + } + catch { } + } } } diff --git a/osu.Game/Rulesets/Ruleset.cs b/osu.Game/Rulesets/Ruleset.cs index ed2fdf4157..dfa9ea5125 100644 --- a/osu.Game/Rulesets/Ruleset.cs +++ b/osu.Game/Rulesets/Ruleset.cs @@ -9,6 +9,7 @@ using osu.Framework.Input.Bindings; using osu.Game.Beatmaps; using osu.Game.Graphics; using osu.Game.Overlays.Settings; +using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.UI; @@ -49,6 +50,8 @@ namespace osu.Game.Rulesets public abstract DifficultyCalculator CreateDifficultyCalculator(Beatmap beatmap, Mod[] mods = null); + public virtual HitObjectComposer CreateHitObjectComposer() => null; + public virtual Drawable CreateIcon() => new SpriteIcon { Icon = FontAwesome.fa_question_circle }; public abstract string Description { get; } diff --git a/osu.Game/Screens/Edit/Screens/Compose/Compose.cs b/osu.Game/Screens/Edit/Screens/Compose/Compose.cs index 67e66eecdf..8cfb04da06 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Compose.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Compose.cs @@ -1,11 +1,14 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System; using OpenTK.Graphics; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; +using osu.Framework.Timing; +using osu.Game.Beatmaps; using osu.Game.Screens.Edit.Screens.Compose.Timeline; namespace osu.Game.Screens.Edit.Screens.Compose @@ -15,6 +18,8 @@ namespace osu.Game.Screens.Edit.Screens.Compose private const float vertical_margins = 10; private const float horizontal_margins = 20; + private readonly Container composerContainer; + public Compose() { ScrollableTimeline timeline; @@ -58,7 +63,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose }, new Drawable[] { - new Container + composerContainer = new Container { Name = "Composer content", RelativeSizeAxes = Axes.Both, @@ -71,6 +76,23 @@ namespace osu.Game.Screens.Edit.Screens.Compose }; timeline.Beatmap.BindTo(Beatmap); + + Beatmap.ValueChanged += beatmapChanged; + } + + private void beatmapChanged(WorkingBeatmap newBeatmap) + { + var ruleset = newBeatmap.BeatmapInfo.Ruleset.CreateInstance(); + var composer = ruleset.CreateHitObjectComposer(); + if (composer == null) + { + // Todo: Handle this + //throw new InvalidOperationException($"Ruleset {ruleset.Description} doesn't support hitobject composition."); + return; + } + + composerContainer.Add(composer); + composerContainer.Clock = new InterpolatingFramedClock((IAdjustableClock)newBeatmap.Track ?? new StopwatchClock()); } } } From 7cbca37e2df471b03f20232cc1eb58a074b383b4 Mon Sep 17 00:00:00 2001 From: Dan Balasescu <1329837+smoogipoo@users.noreply.github.com> Date: Wed, 29 Nov 2017 18:18:36 +0900 Subject: [PATCH 0903/1263] Remove redundant cast --- osu.Game.Rulesets.Mania/Replays/ManiaReplayFrame.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Mania/Replays/ManiaReplayFrame.cs b/osu.Game.Rulesets.Mania/Replays/ManiaReplayFrame.cs index 8473d23b89..d1bc7da911 100644 --- a/osu.Game.Rulesets.Mania/Replays/ManiaReplayFrame.cs +++ b/osu.Game.Rulesets.Mania/Replays/ManiaReplayFrame.cs @@ -10,7 +10,7 @@ namespace osu.Game.Rulesets.Mania.Replays public override bool IsImportant => MouseX > 0; public ManiaReplayFrame(double time, int activeColumns) - : base(time, (float)activeColumns, null, ReplayButtonState.None) + : base(time, activeColumns, null, ReplayButtonState.None) { } } From ee35422efc0396ec7800933ae4e2e51abfb45140 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 29 Nov 2017 18:38:12 +0900 Subject: [PATCH 0904/1263] Handle rulesets that don't support composition a bit better --- osu.Game/Screens/Edit/Editor.cs | 1 + osu.Game/Screens/Edit/Screens/Compose/Compose.cs | 10 +++++----- osu.Game/Screens/Edit/Screens/EditorScreen.cs | 3 +++ 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 607ff792d8..bc86c683c7 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -154,6 +154,7 @@ namespace osu.Game.Screens.Edit } currentScreen.Beatmap.BindTo(Beatmap); + currentScreen.ExitRequested = Exit; screenContainer.Add(currentScreen); } diff --git a/osu.Game/Screens/Edit/Screens/Compose/Compose.cs b/osu.Game/Screens/Edit/Screens/Compose/Compose.cs index 8cfb04da06..6954995340 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Compose.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Compose.cs @@ -7,6 +7,7 @@ using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; +using osu.Framework.Logging; using osu.Framework.Timing; using osu.Game.Beatmaps; using osu.Game.Screens.Edit.Screens.Compose.Timeline; @@ -76,18 +77,17 @@ namespace osu.Game.Screens.Edit.Screens.Compose }; timeline.Beatmap.BindTo(Beatmap); - Beatmap.ValueChanged += beatmapChanged; } private void beatmapChanged(WorkingBeatmap newBeatmap) { - var ruleset = newBeatmap.BeatmapInfo.Ruleset.CreateInstance(); - var composer = ruleset.CreateHitObjectComposer(); + var ruleset = newBeatmap.BeatmapInfo.Ruleset?.CreateInstance(); + var composer = ruleset?.CreateHitObjectComposer(); if (composer == null) { - // Todo: Handle this - //throw new InvalidOperationException($"Ruleset {ruleset.Description} doesn't support hitobject composition."); + Logger.Log($"Ruleset {ruleset.Description} doesn't support hitobject composition."); + ExitRequested?.Invoke(); return; } diff --git a/osu.Game/Screens/Edit/Screens/EditorScreen.cs b/osu.Game/Screens/Edit/Screens/EditorScreen.cs index ac248930d8..9a158d20f1 100644 --- a/osu.Game/Screens/Edit/Screens/EditorScreen.cs +++ b/osu.Game/Screens/Edit/Screens/EditorScreen.cs @@ -1,6 +1,7 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System; using osu.Framework.Configuration; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -10,6 +11,8 @@ namespace osu.Game.Screens.Edit.Screens { public class EditorScreen : Container { + public Action ExitRequested; + public readonly Bindable Beatmap = new Bindable(); protected override Container Content => content; From d69fa0966f83887c5d26cb4f0dcb2fe17621f8d8 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 29 Nov 2017 18:42:54 +0900 Subject: [PATCH 0905/1263] Generate ManiaReplayFrame instead of ReplayFrame --- osu.Game.Rulesets.Mania/Replays/ManiaAutoGenerator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Mania/Replays/ManiaAutoGenerator.cs b/osu.Game.Rulesets.Mania/Replays/ManiaAutoGenerator.cs index 44297c1fb1..153fee3ab6 100644 --- a/osu.Game.Rulesets.Mania/Replays/ManiaAutoGenerator.cs +++ b/osu.Game.Rulesets.Mania/Replays/ManiaAutoGenerator.cs @@ -41,7 +41,7 @@ namespace osu.Game.Rulesets.Mania.Replays activeColumns ^= 1 << point.Column; } - Replay.Frames.Add(new ReplayFrame(group.First().Time, activeColumns, 0, ReplayButtonState.None)); + Replay.Frames.Add(new ManiaReplayFrame(group.First().Time, activeColumns)); } return Replay; From 801d81ecfcae0cfc2c912c233c07ce2eb98470af Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 29 Nov 2017 19:00:08 +0900 Subject: [PATCH 0906/1263] Add a notice when not logged in --- .../Tests/Visual/TestCasePerformancePoints.cs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/osu.Game/Tests/Visual/TestCasePerformancePoints.cs b/osu.Game/Tests/Visual/TestCasePerformancePoints.cs index 80167e5e1f..6da14e9b12 100644 --- a/osu.Game/Tests/Visual/TestCasePerformancePoints.cs +++ b/osu.Game/Tests/Visual/TestCasePerformancePoints.cs @@ -12,6 +12,7 @@ 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; @@ -220,6 +221,17 @@ namespace osu.Game.Tests.Visual private void load(OsuGameBase osuGame, APIAccess api) { this.api = api; + + if (!api.IsLoggedIn) + { + InternalChild = new SpriteText + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Text = "Please login to see online scores", + }; + } + osuGame.Beatmap.ValueChanged += beatmapChanged; } @@ -229,6 +241,9 @@ namespace osu.Game.Tests.Visual lastRequest?.Cancel(); scores.Clear(); + if (!api.IsLoggedIn) + return; + lastRequest = new GetScoresRequest(newBeatmap.BeatmapInfo); lastRequest.Success += res => res.Scores.ForEach(s => scores.Add(new PerformanceDisplay(s, newBeatmap.Beatmap))); api.Queue(lastRequest); From 6dd6f08bd05a3f14d8c262e99e17978512309c37 Mon Sep 17 00:00:00 2001 From: mattiapette Date: Wed, 29 Nov 2017 11:51:56 +0100 Subject: [PATCH 0907/1263] Random song selection when entering the select menu with default osu theme or invalid beatmap --- 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 a0b788d777..6fcaff7976 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -211,7 +211,7 @@ namespace osu.Game.Screens.Select if (Beatmap.Value.BeatmapSetInfo?.DeletePending == false) carousel.SelectBeatmap(Beatmap.Value.BeatmapInfo, false); else - carousel.SelectNext(); + carousel.SelectNextRandom(); } private void carouselRaisedStart(InputState state = null) From 2b7bf285e4bc860074058bf163aac32e9aaf78a1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 29 Nov 2017 20:07:00 +0900 Subject: [PATCH 0908/1263] Improve code quality --- osu.Game/Screens/Select/BeatmapDetails.cs | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/osu.Game/Screens/Select/BeatmapDetails.cs b/osu.Game/Screens/Select/BeatmapDetails.cs index 3cd6c3b107..eb313319bd 100644 --- a/osu.Game/Screens/Select/BeatmapDetails.cs +++ b/osu.Game/Screens/Select/BeatmapDetails.cs @@ -320,26 +320,25 @@ namespace osu.Game.Screens.Select return; } - this.FadeIn(transition_duration); setTextAsync(value); } } private void setTextAsync(string text) { - var newTextFlow = new TextFlowContainer + LoadComponentAsync(new TextFlowContainer(s => s.TextSize = 14) { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, Colour = textFlow.Colour, - }; - - newTextFlow.AddText(text, s => s.TextSize = 14); - - LoadComponentAsync(newTextFlow, d => + Text = text + }, loaded => { - textContainer.Remove(textFlow); - textContainer.Add(textFlow = d); + textFlow?.Expire(); + textContainer.Add(textFlow = loaded); + + // fade in if we haven't yet. + this.FadeIn(transition_duration); }); } From b2fc50247c053b1563f69a744664b4b407501e70 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 29 Nov 2017 20:13:00 +0900 Subject: [PATCH 0909/1263] Hide metadata by default to avoid initial jump when no data present --- osu.Game/Screens/Select/BeatmapDetails.cs | 65 ++++++++++++----------- 1 file changed, 33 insertions(+), 32 deletions(-) diff --git a/osu.Game/Screens/Select/BeatmapDetails.cs b/osu.Game/Screens/Select/BeatmapDetails.cs index eb313319bd..a9a778fe17 100644 --- a/osu.Game/Screens/Select/BeatmapDetails.cs +++ b/osu.Game/Screens/Select/BeatmapDetails.cs @@ -310,6 +310,39 @@ namespace osu.Game.Screens.Select private readonly FillFlowContainer textContainer; private TextFlowContainer textFlow; + public MetadataSection(string title) + { + RelativeSizeAxes = Axes.X; + AutoSizeAxes = Axes.Y; + Alpha = 0; + + InternalChild = textContainer = new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Spacing = new Vector2(spacing / 2), + Children = new Drawable[] + { + new Container + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Child = new OsuSpriteText + { + Text = title, + Font = @"Exo2.0-Bold", + TextSize = 14, + }, + }, + textFlow = new TextFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + }, + }, + }; + } + public string Text { set @@ -347,38 +380,6 @@ namespace osu.Game.Screens.Select get { return textFlow.Colour; } set { textFlow.Colour = value; } } - - public MetadataSection(string title) - { - RelativeSizeAxes = Axes.X; - AutoSizeAxes = Axes.Y; - - InternalChild = textContainer = new FillFlowContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Spacing = new Vector2(spacing / 2), - Children = new Drawable[] - { - new Container - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Child = new OsuSpriteText - { - Text = title, - Font = @"Exo2.0-Bold", - TextSize = 14, - }, - }, - textFlow = new TextFlowContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - }, - }, - }; - } } private class DimmedLoadingAnimation : VisibilityContainer From a0c33499352682b894fc8f84321badc3ca722107 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 30 Nov 2017 00:45:37 +0900 Subject: [PATCH 0910/1263] Add LangVer.props and osu.Game.props for common csproj properties --- LangVer.props | 6 ++++++ osu.Desktop.Deploy/osu.Desktop.Deploy.csproj | 5 +---- osu.Desktop/osu.Desktop.csproj | 6 +----- osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj | 5 +---- osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj | 5 +---- osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj | 5 +---- osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj | 5 +---- osu.Game.Tests/osu.Game.Tests.csproj | 5 +---- osu.Game.props | 9 +++++++++ osu.Game/osu.Game.csproj | 5 +---- 10 files changed, 23 insertions(+), 33 deletions(-) create mode 100644 LangVer.props create mode 100644 osu.Game.props diff --git a/LangVer.props b/LangVer.props new file mode 100644 index 0000000000..2ff5e95378 --- /dev/null +++ b/LangVer.props @@ -0,0 +1,6 @@ + + + + 6 + + \ No newline at end of file diff --git a/osu.Desktop.Deploy/osu.Desktop.Deploy.csproj b/osu.Desktop.Deploy/osu.Desktop.Deploy.csproj index 6727a86a91..316d85db47 100644 --- a/osu.Desktop.Deploy/osu.Desktop.Deploy.csproj +++ b/osu.Desktop.Deploy/osu.Desktop.Deploy.csproj @@ -1,5 +1,6 @@  + Debug @@ -22,7 +23,6 @@ DEBUG;TRACE prompt 4 - 6 AnyCPU @@ -102,9 +102,6 @@ - - osu.licenseheader - PreserveNewest diff --git a/osu.Desktop/osu.Desktop.csproj b/osu.Desktop/osu.Desktop.csproj index 91c0da6f65..bf259c48ba 100644 --- a/osu.Desktop/osu.Desktop.csproj +++ b/osu.Desktop/osu.Desktop.csproj @@ -1,5 +1,6 @@  + {419659FD-72EA-4678-9EB8-B22A746CED70} Debug @@ -62,7 +63,6 @@ false - 6 none @@ -98,7 +98,6 @@ full AnyCPU false - 6 prompt --tests @@ -174,9 +173,6 @@ - - osu.licenseheader - diff --git a/osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj b/osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj index b7916f674e..b855e6178b 100644 --- a/osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj +++ b/osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj @@ -1,5 +1,6 @@  + Debug @@ -21,7 +22,6 @@ prompt 4 false - 6 pdbonly @@ -74,9 +74,6 @@ - - osu.licenseheader - diff --git a/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj b/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj index 19832d733e..b91f38cd3d 100644 --- a/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj +++ b/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj @@ -1,5 +1,6 @@  + Debug @@ -21,7 +22,6 @@ prompt 4 false - 6 pdbonly @@ -99,9 +99,6 @@ - - osu.licenseheader - diff --git a/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj b/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj index 2be057de40..05fb71afdf 100644 --- a/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj +++ b/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj @@ -1,5 +1,6 @@  + Debug @@ -22,7 +23,6 @@ prompt 4 false - 6 pdbonly @@ -105,9 +105,6 @@ - - osu.licenseheader - diff --git a/osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj b/osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj index 0b4e6e43f2..7b86fd921f 100644 --- a/osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj +++ b/osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj @@ -1,5 +1,6 @@  + Debug @@ -21,7 +22,6 @@ prompt 4 false - 6 pdbonly @@ -96,9 +96,6 @@ - - osu.licenseheader - diff --git a/osu.Game.Tests/osu.Game.Tests.csproj b/osu.Game.Tests/osu.Game.Tests.csproj index 312a564f71..8e7bfaa166 100644 --- a/osu.Game.Tests/osu.Game.Tests.csproj +++ b/osu.Game.Tests/osu.Game.Tests.csproj @@ -1,5 +1,6 @@  + Debug AnyCPU @@ -19,7 +20,6 @@ 4 false false - 6 true @@ -45,9 +45,6 @@ - - osu.licenseheader - diff --git a/osu.Game.props b/osu.Game.props new file mode 100644 index 0000000000..61d5bea511 --- /dev/null +++ b/osu.Game.props @@ -0,0 +1,9 @@ + + + + + + osu.licenseheader + + + \ No newline at end of file diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index ccd1bd03dc..aebd250489 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -1,5 +1,6 @@  + {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D} Debug @@ -61,7 +62,6 @@ false - 6 none @@ -195,9 +195,6 @@ - - osu.licenseheader - From 006d67993905fac5c22f786cabc6f61134d58326 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 30 Nov 2017 00:53:07 +0900 Subject: [PATCH 0911/1263] Migrate to C#7 --- LangVer.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LangVer.props b/LangVer.props index 2ff5e95378..e6a8b4b38c 100644 --- a/LangVer.props +++ b/LangVer.props @@ -1,6 +1,6 @@ - 6 + 7 \ No newline at end of file From 36be171c298d5c9aa43257d0b5b855d07b06bac9 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 30 Nov 2017 02:06:03 +0900 Subject: [PATCH 0912/1263] Fix up/clean up csprojs for C#7 support --- LangVer.props | 4 +++- osu.Desktop.Deploy/osu.Desktop.Deploy.csproj | 3 +-- osu.Desktop/osu.Desktop.csproj | 2 +- osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj | 1 - osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj | 1 - osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj | 1 - osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj | 1 - osu.Game.Tests/osu.Game.Tests.csproj | 2 +- osu.Game.props | 2 +- osu.Game/osu.Game.csproj | 2 +- 10 files changed, 8 insertions(+), 11 deletions(-) diff --git a/LangVer.props b/LangVer.props index e6a8b4b38c..c3aee0505a 100644 --- a/LangVer.props +++ b/LangVer.props @@ -1,5 +1,7 @@ - + + + 7 diff --git a/osu.Desktop.Deploy/osu.Desktop.Deploy.csproj b/osu.Desktop.Deploy/osu.Desktop.Deploy.csproj index 316d85db47..3bec56d322 100644 --- a/osu.Desktop.Deploy/osu.Desktop.Deploy.csproj +++ b/osu.Desktop.Deploy/osu.Desktop.Deploy.csproj @@ -1,7 +1,6 @@  - - + Debug AnyCPU diff --git a/osu.Desktop/osu.Desktop.csproj b/osu.Desktop/osu.Desktop.csproj index bf259c48ba..e4e9807754 100644 --- a/osu.Desktop/osu.Desktop.csproj +++ b/osu.Desktop/osu.Desktop.csproj @@ -1,5 +1,5 @@  - + {419659FD-72EA-4678-9EB8-B22A746CED70} diff --git a/osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj b/osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj index b855e6178b..4605a1f50e 100644 --- a/osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj +++ b/osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj @@ -1,7 +1,6 @@  - Debug AnyCPU diff --git a/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj b/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj index b91f38cd3d..ec6f59b5be 100644 --- a/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj +++ b/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj @@ -1,7 +1,6 @@  - Debug AnyCPU diff --git a/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj b/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj index 05fb71afdf..5a0581f48b 100644 --- a/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj +++ b/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj @@ -1,7 +1,6 @@  - Debug AnyCPU diff --git a/osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj b/osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj index 7b86fd921f..72e9e6a061 100644 --- a/osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj +++ b/osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj @@ -1,7 +1,6 @@  - Debug AnyCPU diff --git a/osu.Game.Tests/osu.Game.Tests.csproj b/osu.Game.Tests/osu.Game.Tests.csproj index 8e7bfaa166..b4242052d5 100644 --- a/osu.Game.Tests/osu.Game.Tests.csproj +++ b/osu.Game.Tests/osu.Game.Tests.csproj @@ -1,5 +1,5 @@  - + Debug diff --git a/osu.Game.props b/osu.Game.props index 61d5bea511..4173adb509 100644 --- a/osu.Game.props +++ b/osu.Game.props @@ -1,5 +1,5 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index aebd250489..f814cbb3d3 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -1,5 +1,5 @@  - + {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D} From 7451bdaa0ee56b82f5fd22af1016b203adc5b29d Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 30 Nov 2017 02:06:24 +0900 Subject: [PATCH 0913/1263] Update DotSettings --- osu.sln.DotSettings | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/osu.sln.DotSettings b/osu.sln.DotSettings index fdfbf25144..92ef2d1021 100644 --- a/osu.sln.DotSettings +++ b/osu.sln.DotSettings @@ -34,6 +34,7 @@ HINT WARNING WARNING + HINT WARNING WARNING DO_NOT_SHOW @@ -44,13 +45,16 @@ WARNING ERROR HINT + HINT HINT WARNING WARNING + DO_NOT_SHOW DO_NOT_SHOW HINT HINT HINT + HINT WARNING WARNING WARNING @@ -149,6 +153,7 @@ WARNING WARNING WARNING + HINT WARNING WARNING HINT From d402222f1778fa5e9d43f91354a7d8a6238670fa Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 30 Nov 2017 05:05:07 +0900 Subject: [PATCH 0914/1263] Fix DisposeTrack and improve AsyncLazy to support disposal --- osu.Game/Beatmaps/WorkingBeatmap.cs | 63 +++++++++++++++++++++++++---- osu.Game/OsuGameBase.cs | 2 +- 2 files changed, 56 insertions(+), 9 deletions(-) diff --git a/osu.Game/Beatmaps/WorkingBeatmap.cs b/osu.Game/Beatmaps/WorkingBeatmap.cs index 2a8178882e..93ba51367a 100644 --- a/osu.Game/Beatmaps/WorkingBeatmap.cs +++ b/osu.Game/Beatmaps/WorkingBeatmap.cs @@ -31,7 +31,7 @@ namespace osu.Game.Beatmaps Mods.ValueChanged += mods => applyRateAdjustments(); beatmap = new AsyncLazy(populateBeatmap); - background = new AsyncLazy(populateBackground); + background = new AsyncLazy(populateBackground, b => b == null || !b.IsDisposed); track = new AsyncLazy(populateTrack); waveform = new AsyncLazy(populateWaveform); } @@ -99,10 +99,11 @@ namespace osu.Game.Beatmaps if (WaveformLoaded) Waveform?.Dispose(); } - public void DisposeTrack() - { - if (TrackLoaded) Track?.Dispose(); - } + /// + /// Eagerly dispose of the audio track associated with this (if any). + /// Accessing track again will load a fresh instance. + /// + public void RecycleTrack() => track.Recycle(); private void applyRateAdjustments(Track t = null) { @@ -114,11 +115,57 @@ namespace osu.Game.Beatmaps mod.ApplyToClock(t); } - public class AsyncLazy : Lazy> + public class AsyncLazy { - public AsyncLazy(Func valueFactory) - : base(() => Task.Run(valueFactory)) + private Lazy> lazy; + private readonly Func valueFactory; + private readonly Func stillValidFunction; + + public AsyncLazy(Func valueFactory, Func stillValidFunction = null) { + this.valueFactory = valueFactory; + this.stillValidFunction = stillValidFunction; + + init(); + } + + public void Recycle() + { + if (!IsValueCreated) return; + + (lazy.Value.Result as IDisposable)?.Dispose(); + + init(); + } + + public bool IsValueCreated + { + get + { + ensureValid(); + return lazy.IsValueCreated; + } + } + + public Task Value + { + get + { + ensureValid(); + return lazy.Value; + } + } + + private void ensureValid() + { + if (!lazy.IsValueCreated || (stillValidFunction?.Invoke(lazy.Value.Result) ?? true)) return; + + init(); + } + + private void init() + { + lazy = new Lazy>(() => Task.Run(valueFactory)); } } } diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 8eaa20f781..0ddff5e5aa 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -154,7 +154,7 @@ namespace osu.Game Debug.Assert(lastBeatmap != null); Debug.Assert(lastBeatmap.Track != null); - lastBeatmap.DisposeTrack(); + lastBeatmap.RecycleTrack(); } Audio.Track.AddItem(b.Track); From acb2cafa581da379df2ec85e6a69969f67694d13 Mon Sep 17 00:00:00 2001 From: Aergwyn Date: Wed, 29 Nov 2017 21:09:08 +0100 Subject: [PATCH 0915/1263] fix wedge not appearing --- osu.Game/Screens/Select/SongSelect.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index a0b788d777..b07e68f50e 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -263,10 +263,7 @@ namespace osu.Game.Screens.Select beatmapNoDebounce = beatmap; if (beatmap == null) - { - if (!Beatmap.IsDefault) - performLoad(); - } + performLoad(); else { if (beatmap.BeatmapSetInfoID == beatmapNoDebounce?.BeatmapSetInfoID) From cd653c1cbc5a5f11652ddfda35e4690502b2f4c0 Mon Sep 17 00:00:00 2001 From: Aergwyn Date: Wed, 29 Nov 2017 21:28:02 +0100 Subject: [PATCH 0916/1263] split storyboard loading into `GetStoryboard()` --- osu.Game/Beatmaps/BeatmapManager.cs | 32 ++++++++++++++++++++++------- osu.Game/Beatmaps/WorkingBeatmap.cs | 2 ++ 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 0641cabcd8..a5578bcfde 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -25,6 +25,7 @@ using osu.Game.Online.API; using osu.Game.Online.API.Requests; using osu.Game.Overlays.Notifications; using osu.Game.Rulesets; +using osu.Game.Storyboards; namespace osu.Game.Beatmaps { @@ -577,13 +578,6 @@ namespace osu.Game.Beatmaps beatmap = decoder.Decode(stream); } - if (beatmap == null || BeatmapSetInfo.StoryboardFile == null) - return beatmap; - - using (var stream = new StreamReader(store.GetStream(getPathForFile(BeatmapSetInfo.StoryboardFile)))) - decoder.Decode(stream, beatmap); - - return beatmap; } catch @@ -623,6 +617,30 @@ namespace osu.Game.Beatmaps } protected override Waveform GetWaveform() => new Waveform(store.GetStream(getPathForFile(Metadata.AudioFile))); + + protected override Storyboard GetStoryboard() + { + try + { + Beatmap beatmap = Beatmap; + + if (beatmap == null || BeatmapSetInfo.StoryboardFile == null) + return new Storyboard(); + + BeatmapDecoder decoder; + using (var stream = new StreamReader(store.GetStream(getPathForFile(BeatmapInfo.Path)))) + decoder = BeatmapDecoder.GetDecoder(stream); + + using (var stream = new StreamReader(store.GetStream(getPathForFile(BeatmapSetInfo.StoryboardFile)))) + decoder.Decode(stream, beatmap); + + return beatmap.Storyboard; + } + catch + { + return new Storyboard(); + } + } } /// diff --git a/osu.Game/Beatmaps/WorkingBeatmap.cs b/osu.Game/Beatmaps/WorkingBeatmap.cs index 2a8178882e..456bf29387 100644 --- a/osu.Game/Beatmaps/WorkingBeatmap.cs +++ b/osu.Game/Beatmaps/WorkingBeatmap.cs @@ -9,6 +9,7 @@ using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using osu.Game.Storyboards; namespace osu.Game.Beatmaps { @@ -40,6 +41,7 @@ namespace osu.Game.Beatmaps protected abstract Texture GetBackground(); protected abstract Track GetTrack(); protected virtual Waveform GetWaveform() => new Waveform(); + protected virtual Storyboard GetStoryboard() => new Storyboard(); public bool BeatmapLoaded => beatmap.IsValueCreated; public Beatmap Beatmap => beatmap.Value.Result; From 96f5bd33237440dcb6d327f18ec2562945d5e0b4 Mon Sep 17 00:00:00 2001 From: Aergwyn Date: Wed, 29 Nov 2017 21:54:04 +0100 Subject: [PATCH 0917/1263] remove Storyboard from Beatmap, add it to WorkingBeatmap --- osu.Game/Beatmaps/Beatmap.cs | 6 ------ osu.Game/Beatmaps/WorkingBeatmap.cs | 9 +++++++++ osu.Game/Storyboards/Storyboard.cs | 27 ++++++++++++++++++++++++++- 3 files changed, 35 insertions(+), 7 deletions(-) diff --git a/osu.Game/Beatmaps/Beatmap.cs b/osu.Game/Beatmaps/Beatmap.cs index 35b6cc2b02..2c437f8a18 100644 --- a/osu.Game/Beatmaps/Beatmap.cs +++ b/osu.Game/Beatmaps/Beatmap.cs @@ -41,11 +41,6 @@ namespace osu.Game.Beatmaps /// public double TotalBreakTime => Breaks.Sum(b => b.Duration); - /// - /// The Beatmap's Storyboard. - /// - public Storyboard Storyboard = new Storyboard(); - /// /// Constructs a new beatmap. /// @@ -57,7 +52,6 @@ namespace osu.Game.Beatmaps Breaks = original?.Breaks ?? Breaks; ComboColors = original?.ComboColors ?? ComboColors; HitObjects = original?.HitObjects ?? HitObjects; - Storyboard = original?.Storyboard ?? Storyboard; if (original == null && Metadata == null) { diff --git a/osu.Game/Beatmaps/WorkingBeatmap.cs b/osu.Game/Beatmaps/WorkingBeatmap.cs index 456bf29387..cd6e1bb8c2 100644 --- a/osu.Game/Beatmaps/WorkingBeatmap.cs +++ b/osu.Game/Beatmaps/WorkingBeatmap.cs @@ -35,6 +35,7 @@ namespace osu.Game.Beatmaps background = new AsyncLazy(populateBackground); track = new AsyncLazy(populateTrack); waveform = new AsyncLazy(populateWaveform); + storyboard = new AsyncLazy(populateStoryboard); } protected abstract Beatmap GetBeatmap(); @@ -86,6 +87,13 @@ namespace osu.Game.Beatmaps private Waveform populateWaveform() => GetWaveform(); + public bool StoryboardLoaded => storyboard.IsValueCreated; + public Storyboard Storyboard => storyboard.Value.Result; + public async Task GetStoryboardAsync() => await storyboard.Value; + private readonly AsyncLazy storyboard; + + private Storyboard populateStoryboard() => GetStoryboard(); + public void TransferTo(WorkingBeatmap other) { if (track.IsValueCreated && Track != null && BeatmapInfo.AudioEquals(other.BeatmapInfo)) @@ -99,6 +107,7 @@ namespace osu.Game.Beatmaps { if (BackgroundLoaded) Background?.Dispose(); if (WaveformLoaded) Waveform?.Dispose(); + if (StoryboardLoaded) Storyboard?.Dispose(); } public void DisposeTrack() diff --git a/osu.Game/Storyboards/Storyboard.cs b/osu.Game/Storyboards/Storyboard.cs index 59cbe74650..4eca910c1e 100644 --- a/osu.Game/Storyboards/Storyboard.cs +++ b/osu.Game/Storyboards/Storyboard.cs @@ -5,10 +5,11 @@ using osu.Game.Beatmaps; using osu.Game.Storyboards.Drawables; using System.Collections.Generic; using System.Linq; +using System; namespace osu.Game.Storyboards { - public class Storyboard + public class Storyboard : IDisposable { private readonly Dictionary layers = new Dictionary(); public IEnumerable Layers => layers.Values; @@ -59,5 +60,29 @@ namespace osu.Game.Storyboards } return drawable; } + + #region Disposal + + ~Storyboard() + { + Dispose(false); + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + private bool isDisposed; + + protected virtual void Dispose(bool isDisposing) + { + if (isDisposed) + return; + isDisposed = true; + } + + #endregion } } From 14fdf98abc0aa6981ddf5d56c263c3b3a0446a7b Mon Sep 17 00:00:00 2001 From: jorolf Date: Wed, 29 Nov 2017 23:08:46 +0100 Subject: [PATCH 0918/1263] rename GetBeatmapSetsResponse --- .../{GetBeatmapSetsResponse.cs => APIResponseBeatmapSet.cs} | 6 +++--- osu.Game/Online/API/Requests/GetBeatmapSetRequest.cs | 2 +- osu.Game/Online/API/Requests/GetUserBeatmapsRequest.cs | 2 +- .../Online/API/Requests/GetUserMostPlayedBeatmapsRequest.cs | 2 +- osu.Game/Online/API/Requests/SearchBeatmapSetsRequest.cs | 2 +- osu.Game/osu.Game.csproj | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) rename osu.Game/Online/API/Requests/{GetBeatmapSetsResponse.cs => APIResponseBeatmapSet.cs} (91%) diff --git a/osu.Game/Online/API/Requests/GetBeatmapSetsResponse.cs b/osu.Game/Online/API/Requests/APIResponseBeatmapSet.cs similarity index 91% rename from osu.Game/Online/API/Requests/GetBeatmapSetsResponse.cs rename to osu.Game/Online/API/Requests/APIResponseBeatmapSet.cs index d187cabf31..90d99446c7 100644 --- a/osu.Game/Online/API/Requests/GetBeatmapSetsResponse.cs +++ b/osu.Game/Online/API/Requests/APIResponseBeatmapSet.cs @@ -10,7 +10,7 @@ using System; namespace osu.Game.Online.API.Requests { - public class GetBeatmapSetsResponse : BeatmapMetadata // todo: this is a bit wrong... + public class APIResponseBeatmapSet : BeatmapMetadata // todo: this is a bit wrong... { [JsonProperty(@"covers")] private BeatmapSetOnlineCovers covers { get; set; } @@ -45,7 +45,7 @@ namespace osu.Game.Online.API.Requests } [JsonProperty(@"beatmaps")] - private IEnumerable beatmaps { get; set; } + private IEnumerable beatmaps { get; set; } public BeatmapSetInfo ToBeatmapSet(RulesetStore rulesets) { @@ -69,7 +69,7 @@ namespace osu.Game.Online.API.Requests }; } - private class GetBeatmapSetsBeatmapResponse : BeatmapMetadata + private class APIResponseSetsBeatmap : BeatmapMetadata { [JsonProperty(@"id")] private int onlineBeatmapID { get; set; } diff --git a/osu.Game/Online/API/Requests/GetBeatmapSetRequest.cs b/osu.Game/Online/API/Requests/GetBeatmapSetRequest.cs index e0fdc9adf2..1e6ceaafc6 100644 --- a/osu.Game/Online/API/Requests/GetBeatmapSetRequest.cs +++ b/osu.Game/Online/API/Requests/GetBeatmapSetRequest.cs @@ -3,7 +3,7 @@ namespace osu.Game.Online.API.Requests { - public class GetBeatmapSetRequest : APIRequest + public class GetBeatmapSetRequest : APIRequest { private readonly int beatmapSetId; diff --git a/osu.Game/Online/API/Requests/GetUserBeatmapsRequest.cs b/osu.Game/Online/API/Requests/GetUserBeatmapsRequest.cs index 691f8496d9..173562e04d 100644 --- a/osu.Game/Online/API/Requests/GetUserBeatmapsRequest.cs +++ b/osu.Game/Online/API/Requests/GetUserBeatmapsRequest.cs @@ -6,7 +6,7 @@ using System.Collections.Generic; namespace osu.Game.Online.API.Requests { - public class GetUserBeatmapsRequest : APIRequest> + public class GetUserBeatmapsRequest : APIRequest> { private readonly long userId; private readonly int offset; diff --git a/osu.Game/Online/API/Requests/GetUserMostPlayedBeatmapsRequest.cs b/osu.Game/Online/API/Requests/GetUserMostPlayedBeatmapsRequest.cs index c45ef734e6..80409fc3b9 100644 --- a/osu.Game/Online/API/Requests/GetUserMostPlayedBeatmapsRequest.cs +++ b/osu.Game/Online/API/Requests/GetUserMostPlayedBeatmapsRequest.cs @@ -34,7 +34,7 @@ namespace osu.Game.Online.API.Requests private BeatmapInfo beatmap; [JsonProperty] - private GetBeatmapSetsResponse beatmapSet; + private APIResponseBeatmapSet beatmapSet; public BeatmapInfo GetBeatmapInfo(RulesetStore rulesets) { diff --git a/osu.Game/Online/API/Requests/SearchBeatmapSetsRequest.cs b/osu.Game/Online/API/Requests/SearchBeatmapSetsRequest.cs index 56858b3d56..4e6c70124f 100644 --- a/osu.Game/Online/API/Requests/SearchBeatmapSetsRequest.cs +++ b/osu.Game/Online/API/Requests/SearchBeatmapSetsRequest.cs @@ -9,7 +9,7 @@ using osu.Game.Rulesets; namespace osu.Game.Online.API.Requests { - public class SearchBeatmapSetsRequest : APIRequest> + public class SearchBeatmapSetsRequest : APIRequest> { private readonly string query; private readonly RulesetInfo ruleset; diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index b774602b76..947300cba0 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -285,7 +285,7 @@ - + From a7a9569aee3c4f8e9adfdfb754d39f2a47aa656b Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 30 Nov 2017 13:53:57 +0900 Subject: [PATCH 0919/1263] Don't exit when we don't have composer for now --- osu.Game/Screens/Edit/Screens/Compose/Compose.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Screens/Compose/Compose.cs b/osu.Game/Screens/Edit/Screens/Compose/Compose.cs index 6954995340..fea439bfb8 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Compose.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Compose.cs @@ -87,7 +87,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose if (composer == null) { Logger.Log($"Ruleset {ruleset.Description} doesn't support hitobject composition."); - ExitRequested?.Invoke(); + // ExitRequested?.Invoke(); return; } From abd61256911a9ff7e52cc5390895ec3c9e226fd1 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 30 Nov 2017 14:00:17 +0900 Subject: [PATCH 0920/1263] Make sure that composerContainer is cleared for testing purposes --- osu.Game/Screens/Edit/Screens/Compose/Compose.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Screens/Compose/Compose.cs b/osu.Game/Screens/Edit/Screens/Compose/Compose.cs index fea439bfb8..7e4ce74c5c 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Compose.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Compose.cs @@ -82,6 +82,8 @@ namespace osu.Game.Screens.Edit.Screens.Compose private void beatmapChanged(WorkingBeatmap newBeatmap) { + composerContainer.Clear(); + var ruleset = newBeatmap.BeatmapInfo.Ruleset?.CreateInstance(); var composer = ruleset?.CreateHitObjectComposer(); if (composer == null) @@ -91,7 +93,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose return; } - composerContainer.Add(composer); + composerContainer.Child = composer; composerContainer.Clock = new InterpolatingFramedClock((IAdjustableClock)newBeatmap.Track ?? new StopwatchClock()); } } From ead745697875d10bb96fd786c72cbf2e074bac41 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 30 Nov 2017 15:43:19 +0900 Subject: [PATCH 0921/1263] Add compose radio buttons + testcase --- .../TestCaseEditorComposeRadioButtons.cs | 34 ++++++ osu.Game.Tests/osu.Game.Tests.csproj | 1 + .../RadioButtons/DrawableRadioButton.cs | 107 ++++++++++++++++++ .../Compose/RadioButtons/RadioButton.cs | 20 ++++ .../RadioButtons/RadioButtonCollection.cs | 48 ++++++++ osu.Game/osu.Game.csproj | 5 +- 6 files changed, 214 insertions(+), 1 deletion(-) create mode 100644 osu.Game.Tests/Visual/TestCaseEditorComposeRadioButtons.cs create mode 100644 osu.Game/Screens/Edit/Screens/Compose/RadioButtons/DrawableRadioButton.cs create mode 100644 osu.Game/Screens/Edit/Screens/Compose/RadioButtons/RadioButton.cs create mode 100644 osu.Game/Screens/Edit/Screens/Compose/RadioButtons/RadioButtonCollection.cs diff --git a/osu.Game.Tests/Visual/TestCaseEditorComposeRadioButtons.cs b/osu.Game.Tests/Visual/TestCaseEditorComposeRadioButtons.cs new file mode 100644 index 0000000000..55ceac6fd8 --- /dev/null +++ b/osu.Game.Tests/Visual/TestCaseEditorComposeRadioButtons.cs @@ -0,0 +1,34 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using System.Collections.Generic; +using osu.Framework.Graphics; +using osu.Framework.Graphics.UserInterface; +using osu.Game.Screens.Edit.Screens.Compose.RadioButtons; + +namespace osu.Game.Tests.Visual +{ + public class TestCaseEditorComposeRadioButtons : OsuTestCase + { + public override IReadOnlyList RequiredTypes => new[] { typeof(DrawableRadioButton) }; + + public TestCaseEditorComposeRadioButtons() + { + Add(new RadioButtonCollection + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Width = 150, + Items = new[] + { + new RadioButton { Text = "Item 1", Action = () => { } }, + new RadioButton { Text = "Item 2", Action = () => { } }, + new RadioButton { Text = "Item 3", Action = () => { } }, + new RadioButton { Text = "Item 4", Action = () => { } }, + new RadioButton { Text = "Item 5", Action = () => { } } + } + }); + } + } +} diff --git a/osu.Game.Tests/osu.Game.Tests.csproj b/osu.Game.Tests/osu.Game.Tests.csproj index 34f79987c5..ae88fb004f 100644 --- a/osu.Game.Tests/osu.Game.Tests.csproj +++ b/osu.Game.Tests/osu.Game.Tests.csproj @@ -106,6 +106,7 @@ + diff --git a/osu.Game/Screens/Edit/Screens/Compose/RadioButtons/DrawableRadioButton.cs b/osu.Game/Screens/Edit/Screens/Compose/RadioButtons/DrawableRadioButton.cs new file mode 100644 index 0000000000..4ac36cc07e --- /dev/null +++ b/osu.Game/Screens/Edit/Screens/Compose/RadioButtons/DrawableRadioButton.cs @@ -0,0 +1,107 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using OpenTK; +using OpenTK.Graphics; +using osu.Framework.Allocation; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Input; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osu.Game.Graphics.UserInterface; + +namespace osu.Game.Screens.Edit.Screens.Compose.RadioButtons +{ + public class DrawableRadioButton : TriangleButton + { + private static readonly Color4 DefaultBackgroundColour = OsuColour.FromHex("333"); + private static readonly Color4 DefaultBubbleColour = DefaultBackgroundColour.Darken(0.5f); + private static readonly Color4 SelectedBackgroundColour = OsuColour.FromHex("1188aa"); + private static readonly Color4 SelectedBubbleColour = SelectedBackgroundColour.Lighten(0.5f); + + /// + /// Invoked when this has been selected. + /// + public Action Selected; + + private Drawable bubble; + + public DrawableRadioButton(RadioButton button) + { + Text = button.Text; + Action = button.Action; + + RelativeSizeAxes = Axes.X; + } + + [BackgroundDependencyLoader] + private void load() + { + Triangles.Alpha = 0; + BackgroundColour = DefaultBackgroundColour; + + Add(bubble = new CircularContainer + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + RelativeSizeAxes = Axes.Both, + FillMode = FillMode.Fit, + Scale = new Vector2(0.5f), + X = 10, + Masking = true, + Colour = DefaultBubbleColour, + Blending = BlendingMode.Additive, + Child = new Box { RelativeSizeAxes = Axes.Both } + }); + } + + private bool isSelected; + + public void Deselect() + { + if (!isSelected) + return; + isSelected = false; + + BackgroundColour = DefaultBackgroundColour; + bubble.Colour = DefaultBubbleColour; + } + + public void Select() + { + if (isSelected) + return; + isSelected = true; + Selected?.Invoke(this); + + BackgroundColour = SelectedBackgroundColour; + bubble.Colour = SelectedBubbleColour; + } + + protected override bool OnClick(InputState state) + { + if (isSelected) + return true; + + if (!Enabled) + return true; + + Select(); + + return base.OnClick(state); + } + + protected override SpriteText CreateText() => new OsuSpriteText + { + Depth = -1, + Origin = Anchor.CentreLeft, + Anchor = Anchor.CentreLeft, + X = 40f + }; + } +} diff --git a/osu.Game/Screens/Edit/Screens/Compose/RadioButtons/RadioButton.cs b/osu.Game/Screens/Edit/Screens/Compose/RadioButtons/RadioButton.cs new file mode 100644 index 0000000000..3ef89d2a2b --- /dev/null +++ b/osu.Game/Screens/Edit/Screens/Compose/RadioButtons/RadioButton.cs @@ -0,0 +1,20 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; + +namespace osu.Game.Screens.Edit.Screens.Compose.RadioButtons +{ + public class RadioButton + { + /// + /// The text that should be displayed in this button. + /// + public string Text; + + /// + /// The that should be invoked when this button is selected. + /// + public Action Action; + } +} diff --git a/osu.Game/Screens/Edit/Screens/Compose/RadioButtons/RadioButtonCollection.cs b/osu.Game/Screens/Edit/Screens/Compose/RadioButtons/RadioButtonCollection.cs new file mode 100644 index 0000000000..557e8e1ee8 --- /dev/null +++ b/osu.Game/Screens/Edit/Screens/Compose/RadioButtons/RadioButtonCollection.cs @@ -0,0 +1,48 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System.Collections.Generic; +using System.Linq; +using OpenTK; +using osu.Framework.Extensions.IEnumerableExtensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; + +namespace osu.Game.Screens.Edit.Screens.Compose.RadioButtons +{ + public class RadioButtonCollection : CompositeDrawable + { + public IReadOnlyList Items + { + set + { + buttonContainer.Clear(); + value.ForEach(addButton); + } + } + + private readonly FlowContainer buttonContainer; + + public RadioButtonCollection() + { + AutoSizeAxes = Axes.Y; + + InternalChild = buttonContainer = new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical, + Spacing = new Vector2(0, 5) + }; + } + + private void addButton(RadioButton button) => buttonContainer.Add(new DrawableRadioButton(button) { Selected = buttonSelected }); + + private DrawableRadioButton currentlySelected; + private void buttonSelected(DrawableRadioButton drawableButton) + { + currentlySelected?.Deselect(); + currentlySelected = drawableButton; + } + } +} diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index b4ab8a4cf2..1064665a0e 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -306,7 +306,6 @@ - @@ -316,6 +315,10 @@ + + + + From 36cfa552f43e6ec9f1e3da59022601a524bb0f0d Mon Sep 17 00:00:00 2001 From: Nicolas Brassard Date: Wed, 29 Nov 2017 23:03:26 -0800 Subject: [PATCH 0922/1263] Fix SensitivitySlider keyboard control --- osu.Game/Overlays/Settings/Sections/Input/MouseSettings.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/Input/MouseSettings.cs b/osu.Game/Overlays/Settings/Sections/Input/MouseSettings.cs index 5ebac37cc8..53704ec72d 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/MouseSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/MouseSettings.cs @@ -80,6 +80,8 @@ namespace osu.Game.Overlays.Settings.Sections.Input set { + KeyboardStep = 0.01f; + BindableDouble doubleValue = (BindableDouble)value; // create a second layer of bindable so we can only handle state changes when not being dragged. @@ -105,8 +107,6 @@ namespace osu.Game.Overlays.Settings.Sections.Input public SensitivitySlider() { - KeyboardStep = 0.01f; - Current.ValueChanged += newValue => { if (!isDragging && Sensitivity != null) @@ -133,4 +133,4 @@ namespace osu.Game.Overlays.Settings.Sections.Input public override string TooltipText => Current.Disabled ? "Enable raw input to adjust sensitivity" : Current.Value.ToString(@"0.##x"); } } -} \ No newline at end of file +} From 73e41f9dded5128bb4df51efc5ffc74e107828fe Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 30 Nov 2017 16:57:30 +0900 Subject: [PATCH 0923/1263] Add constructors to RadioButton --- .../Visual/TestCaseEditorComposeRadioButtons.cs | 10 +++++----- .../Screens/Compose/RadioButtons/RadioButton.cs | 14 +++++++++++++- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCaseEditorComposeRadioButtons.cs b/osu.Game.Tests/Visual/TestCaseEditorComposeRadioButtons.cs index 55ceac6fd8..c259ca666e 100644 --- a/osu.Game.Tests/Visual/TestCaseEditorComposeRadioButtons.cs +++ b/osu.Game.Tests/Visual/TestCaseEditorComposeRadioButtons.cs @@ -22,11 +22,11 @@ namespace osu.Game.Tests.Visual Width = 150, Items = new[] { - new RadioButton { Text = "Item 1", Action = () => { } }, - new RadioButton { Text = "Item 2", Action = () => { } }, - new RadioButton { Text = "Item 3", Action = () => { } }, - new RadioButton { Text = "Item 4", Action = () => { } }, - new RadioButton { Text = "Item 5", Action = () => { } } + new RadioButton("Item 1", () => { }), + new RadioButton("Item 2", () => { }), + new RadioButton("Item 3", () => { }), + new RadioButton("Item 4", () => { }), + new RadioButton("Item 5", () => { }) } }); } diff --git a/osu.Game/Screens/Edit/Screens/Compose/RadioButtons/RadioButton.cs b/osu.Game/Screens/Edit/Screens/Compose/RadioButtons/RadioButton.cs index 3ef89d2a2b..bec2d1903d 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/RadioButtons/RadioButton.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/RadioButtons/RadioButton.cs @@ -5,7 +5,7 @@ using System; namespace osu.Game.Screens.Edit.Screens.Compose.RadioButtons { - public class RadioButton + public struct RadioButton { /// /// The text that should be displayed in this button. @@ -16,5 +16,17 @@ namespace osu.Game.Screens.Edit.Screens.Compose.RadioButtons /// The that should be invoked when this button is selected. /// public Action Action; + + public RadioButton(string text) + { + Text = text; + Action = null; + } + + public RadioButton(string text, Action action) + { + Text = text; + Action = action; + } } } From 456bbe25f38e34253cf77b9057e20022add7e9e5 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 30 Nov 2017 16:58:14 +0900 Subject: [PATCH 0924/1263] Implement toolbox into HitObjectComposer --- .../Edit/OsuHitObjectComposer.cs | 11 +++ osu.Game/Rulesets/Edit/HitObjectComposer.cs | 67 ++++++++++++++++++- osu.Game/Rulesets/Edit/ToolboxGroup.cs | 19 ++++++ .../Edit/Tools/HitObjectCompositionTool.cs | 10 +++ .../Rulesets/Edit/Tools/ICompositionTool.cs | 10 +++ osu.Game/Rulesets/Edit/Tools/SelectionTool.cs | 7 ++ .../Screens/Edit/Screens/Compose/Compose.cs | 1 - osu.Game/osu.Game.csproj | 4 ++ 8 files changed, 126 insertions(+), 3 deletions(-) create mode 100644 osu.Game/Rulesets/Edit/ToolboxGroup.cs create mode 100644 osu.Game/Rulesets/Edit/Tools/HitObjectCompositionTool.cs create mode 100644 osu.Game/Rulesets/Edit/Tools/ICompositionTool.cs create mode 100644 osu.Game/Rulesets/Edit/Tools/SelectionTool.cs diff --git a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs index 18dfbb6711..851e572163 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs @@ -1,6 +1,10 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System.Collections.Generic; +using osu.Game.Rulesets.Edit.Tools; +using osu.Game.Rulesets.Osu.Objects; + namespace osu.Game.Rulesets.Osu.Edit { public class OsuHitObjectComposer : Rulesets.Edit.HitObjectComposer @@ -9,5 +13,12 @@ namespace osu.Game.Rulesets.Osu.Edit : base(ruleset) { } + + protected override IReadOnlyList CompositionTools => new ICompositionTool[] + { + new HitObjectCompositionTool(), + new HitObjectCompositionTool(), + new HitObjectCompositionTool() + }; } } diff --git a/osu.Game/Rulesets/Edit/HitObjectComposer.cs b/osu.Game/Rulesets/Edit/HitObjectComposer.cs index da31f6ba66..8c4969cec5 100644 --- a/osu.Game/Rulesets/Edit/HitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/HitObjectComposer.cs @@ -1,9 +1,20 @@ // 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.Allocation; +using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Logging; +using osu.Framework.Timing; +using osu.Game.Rulesets.Edit.Tools; +using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.UI; +using osu.Game.Screens.Edit.Screens.Compose.RadioButtons; +using osu.Game.Screens.Play.ReplaySettings; namespace osu.Game.Rulesets.Edit { @@ -21,11 +32,63 @@ namespace osu.Game.Rulesets.Edit [BackgroundDependencyLoader] private void load(OsuGameBase osuGame) { + RulesetContainer rulesetContainer; try { - InternalChild = ruleset.CreateRulesetContainerWith(osuGame.Beatmap.Value, true); + rulesetContainer = ruleset.CreateRulesetContainerWith(osuGame.Beatmap.Value, true); } - catch { } + catch (Exception e) + { + Logger.Log($"Could not load this beatmap sucessfully ({e})!", LoggingTarget.Runtime, LogLevel.Error); + return; + } + + RadioButtonCollection toolboxCollection; + InternalChild = new GridContainer + { + RelativeSizeAxes = Axes.Both, + Content = new[] + { + new Drawable[] + { + new FillFlowContainer + { + Name = "Sidebar", + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding { Right = 10 }, + Children = new Drawable[] + { + new ToolboxGroup { Child = toolboxCollection = new RadioButtonCollection { RelativeSizeAxes = Axes.X } } + } + }, + new Container + { + RelativeSizeAxes = Axes.Both, + Masking = true, + Child = rulesetContainer + } + }, + }, + ColumnDimensions = new[] + { + new Dimension(GridSizeMode.Absolute, 200), + } + }; + + rulesetContainer.Clock = new InterpolatingFramedClock((IAdjustableClock)osuGame.Beatmap.Value.Track ?? new StopwatchClock()); + + toolboxCollection.Items = + new[] { new RadioButton("Select", () => setCompositionTool(new SelectionTool())) } + .Concat( + CompositionTools.Select(t => new RadioButton(t.Name, () => setCompositionTool(t))) + ) + .ToList(); } + + private void setCompositionTool(ICompositionTool tool) + { + } + + protected abstract IReadOnlyList CompositionTools { get; } } } diff --git a/osu.Game/Rulesets/Edit/ToolboxGroup.cs b/osu.Game/Rulesets/Edit/ToolboxGroup.cs new file mode 100644 index 0000000000..70e4d3a0c5 --- /dev/null +++ b/osu.Game/Rulesets/Edit/ToolboxGroup.cs @@ -0,0 +1,19 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Graphics; +using osu.Game.Screens.Play.ReplaySettings; + +namespace osu.Game.Rulesets.Edit +{ + public class ToolboxGroup : ReplayGroup + { + protected override string Title => "toolbox"; + + public ToolboxGroup() + { + RelativeSizeAxes = Axes.X; + Width = 1; + } + } +} diff --git a/osu.Game/Rulesets/Edit/Tools/HitObjectCompositionTool.cs b/osu.Game/Rulesets/Edit/Tools/HitObjectCompositionTool.cs new file mode 100644 index 0000000000..914cbd11ca --- /dev/null +++ b/osu.Game/Rulesets/Edit/Tools/HitObjectCompositionTool.cs @@ -0,0 +1,10 @@ +using osu.Game.Rulesets.Objects; + +namespace osu.Game.Rulesets.Edit.Tools +{ + public class HitObjectCompositionTool : ICompositionTool + where T : HitObject + { + public string Name => typeof(T).Name; + } +} diff --git a/osu.Game/Rulesets/Edit/Tools/ICompositionTool.cs b/osu.Game/Rulesets/Edit/Tools/ICompositionTool.cs new file mode 100644 index 0000000000..eba873f0cf --- /dev/null +++ b/osu.Game/Rulesets/Edit/Tools/ICompositionTool.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.Edit.Tools +{ + public interface ICompositionTool + { + string Name { get; } + } +} diff --git a/osu.Game/Rulesets/Edit/Tools/SelectionTool.cs b/osu.Game/Rulesets/Edit/Tools/SelectionTool.cs new file mode 100644 index 0000000000..9f3ef78a02 --- /dev/null +++ b/osu.Game/Rulesets/Edit/Tools/SelectionTool.cs @@ -0,0 +1,7 @@ +namespace osu.Game.Rulesets.Edit.Tools +{ + public class SelectionTool : ICompositionTool + { + public string Name => "Select"; + } +} diff --git a/osu.Game/Screens/Edit/Screens/Compose/Compose.cs b/osu.Game/Screens/Edit/Screens/Compose/Compose.cs index 7e4ce74c5c..5eeaf3205d 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Compose.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Compose.cs @@ -94,7 +94,6 @@ namespace osu.Game.Screens.Edit.Screens.Compose } composerContainer.Child = composer; - composerContainer.Clock = new InterpolatingFramedClock((IAdjustableClock)newBeatmap.Track ?? new StopwatchClock()); } } } diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 1064665a0e..886d3313c6 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -562,7 +562,11 @@ + + + + From e5353bb53e2a898a523c542854b6911ed30687ea Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 30 Nov 2017 17:38:55 +0900 Subject: [PATCH 0925/1263] Add border to playfield, add shadow to toolbox buttons --- osu.Game/Rulesets/Edit/HitObjectComposer.cs | 15 ++++++++++++++- .../Compose/RadioButtons/DrawableRadioButton.cs | 8 ++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Edit/HitObjectComposer.cs b/osu.Game/Rulesets/Edit/HitObjectComposer.cs index 8c4969cec5..ed057dbb03 100644 --- a/osu.Game/Rulesets/Edit/HitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/HitObjectComposer.cs @@ -4,10 +4,12 @@ using System; using System.Collections.Generic; using System.Linq; +using OpenTK.Graphics; using osu.Framework.Allocation; using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; using osu.Framework.Logging; using osu.Framework.Timing; using osu.Game.Rulesets.Edit.Tools; @@ -65,7 +67,18 @@ namespace osu.Game.Rulesets.Edit { RelativeSizeAxes = Axes.Both, Masking = true, - Child = rulesetContainer + BorderColour = Color4.White, + BorderThickness = 2, + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Alpha = 0, + AlwaysPresent = true, + }, + rulesetContainer + } } }, }, diff --git a/osu.Game/Screens/Edit/Screens/Compose/RadioButtons/DrawableRadioButton.cs b/osu.Game/Screens/Edit/Screens/Compose/RadioButtons/DrawableRadioButton.cs index 4ac36cc07e..690a50bb11 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/RadioButtons/DrawableRadioButton.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/RadioButtons/DrawableRadioButton.cs @@ -45,6 +45,14 @@ namespace osu.Game.Screens.Edit.Screens.Compose.RadioButtons Triangles.Alpha = 0; BackgroundColour = DefaultBackgroundColour; + Content.EdgeEffect = new EdgeEffectParameters + { + Type = EdgeEffectType.Shadow, + Radius = 2, + Offset = new Vector2(0, 1), + Colour = Color4.Black.Opacity(0.5f) + }; + Add(bubble = new CircularContainer { Anchor = Anchor.CentreLeft, From 33adf569a4d825ac3ffd90d251785ada52ec4b5c Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 30 Nov 2017 17:39:06 +0900 Subject: [PATCH 0926/1263] Don't select a new beatmap in load() --- osu.Game.Tests/Visual/TestCaseEditorCompose.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game.Tests/Visual/TestCaseEditorCompose.cs b/osu.Game.Tests/Visual/TestCaseEditorCompose.cs index 9f060a9ec4..d52f27f4ab 100644 --- a/osu.Game.Tests/Visual/TestCaseEditorCompose.cs +++ b/osu.Game.Tests/Visual/TestCaseEditorCompose.cs @@ -31,7 +31,6 @@ namespace osu.Game.Tests.Visual this.beatmaps = beatmaps; compose.Beatmap.BindTo(osuGame.Beatmap); - nextBeatmap(); } private void nextBeatmap() From efa39f38ca1fbd03ad880f010670111f6a7f52f2 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 30 Nov 2017 18:48:00 +0900 Subject: [PATCH 0927/1263] CI fixes --- .../Edit/OsuHitObjectComposer.cs | 3 ++- .../TestCaseEditorComposeRadioButtons.cs | 1 - osu.Game/Rulesets/Edit/HitObjectComposer.cs | 5 +---- .../Screens/Edit/Screens/Compose/Compose.cs | 11 +++++++--- .../RadioButtons/DrawableRadioButton.cs | 20 +++++++++---------- .../RadioButtons/RadioButtonCollection.cs | 1 - 6 files changed, 21 insertions(+), 20 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs index 851e572163..8a919e0178 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs @@ -2,12 +2,13 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System.Collections.Generic; +using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Edit.Tools; using osu.Game.Rulesets.Osu.Objects; namespace osu.Game.Rulesets.Osu.Edit { - public class OsuHitObjectComposer : Rulesets.Edit.HitObjectComposer + public class OsuHitObjectComposer : HitObjectComposer { public OsuHitObjectComposer(Ruleset ruleset) : base(ruleset) diff --git a/osu.Game.Tests/Visual/TestCaseEditorComposeRadioButtons.cs b/osu.Game.Tests/Visual/TestCaseEditorComposeRadioButtons.cs index c259ca666e..8c2a07b536 100644 --- a/osu.Game.Tests/Visual/TestCaseEditorComposeRadioButtons.cs +++ b/osu.Game.Tests/Visual/TestCaseEditorComposeRadioButtons.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; using osu.Framework.Graphics; -using osu.Framework.Graphics.UserInterface; using osu.Game.Screens.Edit.Screens.Compose.RadioButtons; namespace osu.Game.Tests.Visual diff --git a/osu.Game/Rulesets/Edit/HitObjectComposer.cs b/osu.Game/Rulesets/Edit/HitObjectComposer.cs index ed057dbb03..9297c82ba4 100644 --- a/osu.Game/Rulesets/Edit/HitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/HitObjectComposer.cs @@ -6,17 +6,14 @@ using System.Collections.Generic; using System.Linq; using OpenTK.Graphics; using osu.Framework.Allocation; -using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Logging; using osu.Framework.Timing; using osu.Game.Rulesets.Edit.Tools; -using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.UI; using osu.Game.Screens.Edit.Screens.Compose.RadioButtons; -using osu.Game.Screens.Play.ReplaySettings; namespace osu.Game.Rulesets.Edit { @@ -24,7 +21,7 @@ namespace osu.Game.Rulesets.Edit { private readonly Ruleset ruleset; - public HitObjectComposer(Ruleset ruleset) + protected HitObjectComposer(Ruleset ruleset) { this.ruleset = ruleset; diff --git a/osu.Game/Screens/Edit/Screens/Compose/Compose.cs b/osu.Game/Screens/Edit/Screens/Compose/Compose.cs index 5eeaf3205d..6bc7356f26 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Compose.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Compose.cs @@ -1,14 +1,12 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using System; using OpenTK.Graphics; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Logging; -using osu.Framework.Timing; using osu.Game.Beatmaps; using osu.Game.Screens.Edit.Screens.Compose.Timeline; @@ -85,7 +83,14 @@ namespace osu.Game.Screens.Edit.Screens.Compose composerContainer.Clear(); var ruleset = newBeatmap.BeatmapInfo.Ruleset?.CreateInstance(); - var composer = ruleset?.CreateHitObjectComposer(); + if (ruleset == null) + { + Logger.Log("Beatmap doesn't have a ruleset assigned."); + // ExitRequested?.Invoke(); + return; + } + + var composer = ruleset.CreateHitObjectComposer(); if (composer == null) { Logger.Log($"Ruleset {ruleset.Description} doesn't support hitobject composition."); diff --git a/osu.Game/Screens/Edit/Screens/Compose/RadioButtons/DrawableRadioButton.cs b/osu.Game/Screens/Edit/Screens/Compose/RadioButtons/DrawableRadioButton.cs index 690a50bb11..b3c9983db9 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/RadioButtons/DrawableRadioButton.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/RadioButtons/DrawableRadioButton.cs @@ -19,10 +19,10 @@ namespace osu.Game.Screens.Edit.Screens.Compose.RadioButtons { public class DrawableRadioButton : TriangleButton { - private static readonly Color4 DefaultBackgroundColour = OsuColour.FromHex("333"); - private static readonly Color4 DefaultBubbleColour = DefaultBackgroundColour.Darken(0.5f); - private static readonly Color4 SelectedBackgroundColour = OsuColour.FromHex("1188aa"); - private static readonly Color4 SelectedBubbleColour = SelectedBackgroundColour.Lighten(0.5f); + private static readonly Color4 default_background_colour = OsuColour.FromHex("333"); + private static readonly Color4 default_bubble_colour = default_background_colour.Darken(0.5f); + private static readonly Color4 selected_background_colour = OsuColour.FromHex("1188aa"); + private static readonly Color4 selected_bubble_colour = selected_background_colour.Lighten(0.5f); /// /// Invoked when this has been selected. @@ -43,7 +43,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose.RadioButtons private void load() { Triangles.Alpha = 0; - BackgroundColour = DefaultBackgroundColour; + BackgroundColour = default_background_colour; Content.EdgeEffect = new EdgeEffectParameters { @@ -62,7 +62,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose.RadioButtons Scale = new Vector2(0.5f), X = 10, Masking = true, - Colour = DefaultBubbleColour, + Colour = default_bubble_colour, Blending = BlendingMode.Additive, Child = new Box { RelativeSizeAxes = Axes.Both } }); @@ -76,8 +76,8 @@ namespace osu.Game.Screens.Edit.Screens.Compose.RadioButtons return; isSelected = false; - BackgroundColour = DefaultBackgroundColour; - bubble.Colour = DefaultBubbleColour; + BackgroundColour = default_background_colour; + bubble.Colour = default_bubble_colour; } public void Select() @@ -87,8 +87,8 @@ namespace osu.Game.Screens.Edit.Screens.Compose.RadioButtons isSelected = true; Selected?.Invoke(this); - BackgroundColour = SelectedBackgroundColour; - bubble.Colour = SelectedBubbleColour; + BackgroundColour = selected_background_colour; + bubble.Colour = selected_bubble_colour; } protected override bool OnClick(InputState state) diff --git a/osu.Game/Screens/Edit/Screens/Compose/RadioButtons/RadioButtonCollection.cs b/osu.Game/Screens/Edit/Screens/Compose/RadioButtons/RadioButtonCollection.cs index 557e8e1ee8..8a3194b72e 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/RadioButtons/RadioButtonCollection.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/RadioButtons/RadioButtonCollection.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 OpenTK; using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Graphics; From bf386598b6abe4be1758bf2b7045a26cb3208679 Mon Sep 17 00:00:00 2001 From: FreezyLemon Date: Thu, 30 Nov 2017 10:58:32 +0100 Subject: [PATCH 0928/1263] Added a new "undelete" button that restores every beatmap with "DeletePending" set to true. --- osu.Game/Beatmaps/BeatmapManager.cs | 22 +++++++++++++++++++ .../Sections/Maintenance/GeneralSettings.cs | 14 ++++++++++++ 2 files changed, 36 insertions(+) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 0641cabcd8..376cbe183a 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -338,6 +338,28 @@ namespace osu.Game.Beatmaps } } + public void Undelete(BeatmapSetInfo beatmapSet) + { + lock (importContext) + { + var context = importContext.Value; + + using (var transaction = context.BeginTransaction()) + { + context.ChangeTracker.AutoDetectChangesEnabled = false; + + var iFiles = new FileStore(() => context, storage); + var iBeatmaps = createBeatmapStore(() => context); + + if (iBeatmaps.Undelete(beatmapSet)) + iFiles.Reference(beatmapSet.Files.Select(f => f.FileInfo).ToArray()); + + context.ChangeTracker.AutoDetectChangesEnabled = true; + context.SaveChanges(transaction); + } + } + } + /// /// Delete a beatmap difficulty. /// diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs index 4f4f381ae1..dcad5ab52c 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs @@ -15,6 +15,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance private TriangleButton importButton; private TriangleButton deleteButton; private TriangleButton restoreButton; + private TriangleButton undeleteButton; protected override string Header => "General"; @@ -55,6 +56,19 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance }).ContinueWith(t => Schedule(() => restoreButton.Enabled.Value = true)); } }, + undeleteButton = new SettingsButton + { + Text = "Restore all recently deleted beatmaps", + Action = () => + { + undeleteButton.Enabled.Value = false; + Task.Run(() => + { + foreach (var bs in beatmaps.QueryBeatmapSets(bs => bs.DeletePending).ToList()) + beatmaps.Undelete(bs); + }).ContinueWith(t => Schedule(() => undeleteButton.Enabled.Value = true)); + } + }, }; } } From b09ba19d3fa45a3b650014f6f7ec057d788ca5d3 Mon Sep 17 00:00:00 2001 From: FreezyLemon Date: Thu, 30 Nov 2017 11:02:53 +0100 Subject: [PATCH 0929/1263] Used the already-existing private method to undelete a mapset --- osu.Game/Beatmaps/BeatmapManager.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 376cbe183a..cfebaf083e 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -351,8 +351,7 @@ namespace osu.Game.Beatmaps var iFiles = new FileStore(() => context, storage); var iBeatmaps = createBeatmapStore(() => context); - if (iBeatmaps.Undelete(beatmapSet)) - iFiles.Reference(beatmapSet.Files.Select(f => f.FileInfo).ToArray()); + undelete(iBeatmaps, iFiles, beatmapSet); context.ChangeTracker.AutoDetectChangesEnabled = true; context.SaveChanges(transaction); From 677f3653eb04ed29b7c99f7c21079691ccc6ce67 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 30 Nov 2017 19:19:34 +0900 Subject: [PATCH 0930/1263] Hide osu! playfield cursor --- .../Edit/OsuEditPlayfield.cs | 13 +++++++++++++ .../Edit/OsuEditRulesetContainer.cs | 19 +++++++++++++++++++ .../Edit/OsuHitObjectComposer.cs | 4 ++++ osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs | 8 +++++++- .../osu.Game.Rulesets.Osu.csproj | 2 ++ osu.Game/Rulesets/Edit/HitObjectComposer.cs | 5 ++++- 6 files changed, 49 insertions(+), 2 deletions(-) create mode 100644 osu.Game.Rulesets.Osu/Edit/OsuEditPlayfield.cs create mode 100644 osu.Game.Rulesets.Osu/Edit/OsuEditRulesetContainer.cs diff --git a/osu.Game.Rulesets.Osu/Edit/OsuEditPlayfield.cs b/osu.Game.Rulesets.Osu/Edit/OsuEditPlayfield.cs new file mode 100644 index 0000000000..d5fc1b606b --- /dev/null +++ b/osu.Game.Rulesets.Osu/Edit/OsuEditPlayfield.cs @@ -0,0 +1,13 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Graphics.Cursor; +using osu.Game.Rulesets.Osu.UI; + +namespace osu.Game.Rulesets.Osu.Edit +{ + public class OsuEditPlayfield : OsuPlayfield + { + protected override CursorContainer CreateCursor() => null; + } +} diff --git a/osu.Game.Rulesets.Osu/Edit/OsuEditRulesetContainer.cs b/osu.Game.Rulesets.Osu/Edit/OsuEditRulesetContainer.cs new file mode 100644 index 0000000000..1e9e4b4686 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Edit/OsuEditRulesetContainer.cs @@ -0,0 +1,19 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Game.Beatmaps; +using osu.Game.Rulesets.Osu.UI; +using osu.Game.Rulesets.UI; + +namespace osu.Game.Rulesets.Osu.Edit +{ + public class OsuEditRulesetContainer : OsuRulesetContainer + { + public OsuEditRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap, bool isForCurrentRuleset) + : base(ruleset, beatmap, isForCurrentRuleset) + { + } + + protected override Playfield CreatePlayfield() => new OsuEditPlayfield(); + } +} diff --git a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs index 8a919e0178..ec3aa4661c 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs @@ -2,9 +2,11 @@ // 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.Edit; using osu.Game.Rulesets.Edit.Tools; using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Rulesets.UI; namespace osu.Game.Rulesets.Osu.Edit { @@ -15,6 +17,8 @@ namespace osu.Game.Rulesets.Osu.Edit { } + protected override RulesetContainer CreateRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap) => new OsuEditRulesetContainer(ruleset, beatmap, true); + protected override IReadOnlyList CompositionTools => new ICompositionTool[] { new HitObjectCompositionTool(), diff --git a/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs b/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs index 89f6a4e255..387a098a5a 100644 --- a/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs +++ b/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs @@ -13,6 +13,7 @@ using System.Linq; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Osu.Judgements; using osu.Game.Rulesets.Osu.UI.Cursor; +using osu.Framework.Graphics.Cursor; namespace osu.Game.Rulesets.Osu.UI { @@ -65,7 +66,10 @@ namespace osu.Game.Rulesets.Osu.UI protected override void LoadComplete() { base.LoadComplete(); - AddInternal(new GameplayCursor()); + + var cursor = CreateCursor(); + if (cursor != null) + AddInternal(cursor); } public override void Add(DrawableHitObject h) @@ -102,5 +106,7 @@ namespace osu.Game.Rulesets.Osu.UI judgementLayer.Add(explosion); } + + protected virtual CursorContainer CreateCursor() => new GameplayCursor(); } } diff --git a/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj b/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj index c527265c40..bc343ece05 100644 --- a/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj +++ b/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj @@ -49,6 +49,8 @@ + + diff --git a/osu.Game/Rulesets/Edit/HitObjectComposer.cs b/osu.Game/Rulesets/Edit/HitObjectComposer.cs index 9297c82ba4..1e47ea4e63 100644 --- a/osu.Game/Rulesets/Edit/HitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/HitObjectComposer.cs @@ -11,6 +11,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Logging; using osu.Framework.Timing; +using osu.Game.Beatmaps; using osu.Game.Rulesets.Edit.Tools; using osu.Game.Rulesets.UI; using osu.Game.Screens.Edit.Screens.Compose.RadioButtons; @@ -34,7 +35,7 @@ namespace osu.Game.Rulesets.Edit RulesetContainer rulesetContainer; try { - rulesetContainer = ruleset.CreateRulesetContainerWith(osuGame.Beatmap.Value, true); + rulesetContainer = CreateRulesetContainer(ruleset, osuGame.Beatmap.Value); } catch (Exception e) { @@ -99,6 +100,8 @@ namespace osu.Game.Rulesets.Edit { } + protected virtual RulesetContainer CreateRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap) => ruleset.CreateRulesetContainerWith(beatmap, true); + protected abstract IReadOnlyList CompositionTools { get; } } } From e9cbef88f17021032a5cce26d6a616b4648c5a6b Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 30 Nov 2017 19:49:55 +0900 Subject: [PATCH 0931/1263] Improve selection/deselection behaviour of RadioButtonCollections --- .../TestCaseEditorComposeRadioButtons.cs | 10 ++- .../RadioButtons/DrawableRadioButton.cs | 72 ++++++++++--------- .../Compose/RadioButtons/RadioButton.cs | 31 ++++++-- .../RadioButtons/RadioButtonCollection.cs | 26 +++++-- 4 files changed, 93 insertions(+), 46 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCaseEditorComposeRadioButtons.cs b/osu.Game.Tests/Visual/TestCaseEditorComposeRadioButtons.cs index 8c2a07b536..f8669cde4b 100644 --- a/osu.Game.Tests/Visual/TestCaseEditorComposeRadioButtons.cs +++ b/osu.Game.Tests/Visual/TestCaseEditorComposeRadioButtons.cs @@ -14,7 +14,8 @@ namespace osu.Game.Tests.Visual public TestCaseEditorComposeRadioButtons() { - Add(new RadioButtonCollection + RadioButtonCollection collection; + Add(collection = new RadioButtonCollection { Anchor = Anchor.Centre, Origin = Anchor.Centre, @@ -28,6 +29,13 @@ namespace osu.Game.Tests.Visual new RadioButton("Item 5", () => { }) } }); + + for (int i = 0; i < collection.Items.Count; i++) + { + int l = i; + AddStep($"Select item {l + 1}", () => collection.Items[l].Select()); + AddStep($"Deselect item {l + 1}", () => collection.Items[l].Deselect()); + } } } } diff --git a/osu.Game/Screens/Edit/Screens/Compose/RadioButtons/DrawableRadioButton.cs b/osu.Game/Screens/Edit/Screens/Compose/RadioButtons/DrawableRadioButton.cs index b3c9983db9..a6c0f48f1f 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/RadioButtons/DrawableRadioButton.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/RadioButtons/DrawableRadioButton.cs @@ -27,16 +27,34 @@ namespace osu.Game.Screens.Edit.Screens.Compose.RadioButtons /// /// Invoked when this has been selected. /// - public Action Selected; + public Action Selected; private Drawable bubble; + private readonly RadioButton button; + public DrawableRadioButton(RadioButton button) { + this.button = button; + Text = button.Text; Action = button.Action; RelativeSizeAxes = Axes.X; + + bubble = new CircularContainer + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + RelativeSizeAxes = Axes.Both, + FillMode = FillMode.Fit, + Scale = new Vector2(0.5f), + X = 10, + Masking = true, + Colour = default_bubble_colour, + Blending = BlendingMode.Additive, + Child = new Box { RelativeSizeAxes = Axes.Both } + }; } [BackgroundDependencyLoader] @@ -53,53 +71,41 @@ namespace osu.Game.Screens.Edit.Screens.Compose.RadioButtons Colour = Color4.Black.Opacity(0.5f) }; - Add(bubble = new CircularContainer + Add(bubble); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + button.Selected.ValueChanged += v => { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - RelativeSizeAxes = Axes.Both, - FillMode = FillMode.Fit, - Scale = new Vector2(0.5f), - X = 10, - Masking = true, - Colour = default_bubble_colour, - Blending = BlendingMode.Additive, - Child = new Box { RelativeSizeAxes = Axes.Both } - }); + updateSelectionState(); + if (v) + Selected?.Invoke(button); + }; + + updateSelectionState(); } - private bool isSelected; - - public void Deselect() + private void updateSelectionState() { - if (!isSelected) + if (!IsLoaded) return; - isSelected = false; - BackgroundColour = default_background_colour; - bubble.Colour = default_bubble_colour; - } - - public void Select() - { - if (isSelected) - return; - isSelected = true; - Selected?.Invoke(this); - - BackgroundColour = selected_background_colour; - bubble.Colour = selected_bubble_colour; + BackgroundColour = button.Selected ? selected_background_colour : default_background_colour; + bubble.Colour = button.Selected ? selected_bubble_colour : default_bubble_colour; } protected override bool OnClick(InputState state) { - if (isSelected) + if (button.Selected) return true; if (!Enabled) return true; - Select(); + button.Selected.Value = true; return base.OnClick(state); } diff --git a/osu.Game/Screens/Edit/Screens/Compose/RadioButtons/RadioButton.cs b/osu.Game/Screens/Edit/Screens/Compose/RadioButtons/RadioButton.cs index bec2d1903d..055362d9e1 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/RadioButtons/RadioButton.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/RadioButtons/RadioButton.cs @@ -2,11 +2,18 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; +using osu.Framework.Configuration; namespace osu.Game.Screens.Edit.Screens.Compose.RadioButtons { - public struct RadioButton + public class RadioButton { + /// + /// Whether this is selected. + /// + /// + public readonly BindableBool Selected; + /// /// The text that should be displayed in this button. /// @@ -17,16 +24,28 @@ namespace osu.Game.Screens.Edit.Screens.Compose.RadioButtons /// public Action Action; + public RadioButton(string text, Action action) + { + Text = text; + Action = action; + Selected = new BindableBool(); + } + public RadioButton(string text) + : this(text, null) { Text = text; Action = null; } - public RadioButton(string text, Action action) - { - Text = text; - Action = action; - } + /// + /// Selects this . + /// + public void Select() => Selected.Value = true; + + /// + /// Deselects this . + /// + public void Deselect() => Selected.Value = false; } } diff --git a/osu.Game/Screens/Edit/Screens/Compose/RadioButtons/RadioButtonCollection.cs b/osu.Game/Screens/Edit/Screens/Compose/RadioButtons/RadioButtonCollection.cs index 8a3194b72e..ad24a1da52 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/RadioButtons/RadioButtonCollection.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/RadioButtons/RadioButtonCollection.cs @@ -11,10 +11,16 @@ namespace osu.Game.Screens.Edit.Screens.Compose.RadioButtons { public class RadioButtonCollection : CompositeDrawable { + private IReadOnlyList items; public IReadOnlyList Items { + get { return items; } set { + if (items == value) + return; + items = value; + buttonContainer.Clear(); value.ForEach(addButton); } @@ -35,13 +41,21 @@ namespace osu.Game.Screens.Edit.Screens.Compose.RadioButtons }; } - private void addButton(RadioButton button) => buttonContainer.Add(new DrawableRadioButton(button) { Selected = buttonSelected }); - - private DrawableRadioButton currentlySelected; - private void buttonSelected(DrawableRadioButton drawableButton) + private RadioButton currentlySelected; + private void addButton(RadioButton button) { - currentlySelected?.Deselect(); - currentlySelected = drawableButton; + button.Selected.ValueChanged += v => + { + if (v) + { + currentlySelected?.Deselect(); + currentlySelected = button; + } + else + currentlySelected = null; + }; + + buttonContainer.Add(new DrawableRadioButton(button)); } } } From 7e34b0f08dcc504b81833487530111117eada6c9 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 30 Nov 2017 19:53:52 +0900 Subject: [PATCH 0932/1263] Remove SelectionTool, make Select the default tool --- osu.Game/Rulesets/Edit/HitObjectComposer.cs | 4 +++- osu.Game/Rulesets/Edit/Tools/SelectionTool.cs | 7 ------- 2 files changed, 3 insertions(+), 8 deletions(-) delete mode 100644 osu.Game/Rulesets/Edit/Tools/SelectionTool.cs diff --git a/osu.Game/Rulesets/Edit/HitObjectComposer.cs b/osu.Game/Rulesets/Edit/HitObjectComposer.cs index 1e47ea4e63..b06af84ec8 100644 --- a/osu.Game/Rulesets/Edit/HitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/HitObjectComposer.cs @@ -89,11 +89,13 @@ namespace osu.Game.Rulesets.Edit rulesetContainer.Clock = new InterpolatingFramedClock((IAdjustableClock)osuGame.Beatmap.Value.Track ?? new StopwatchClock()); toolboxCollection.Items = - new[] { new RadioButton("Select", () => setCompositionTool(new SelectionTool())) } + new[] { new RadioButton("Select", () => setCompositionTool(null)) } .Concat( CompositionTools.Select(t => new RadioButton(t.Name, () => setCompositionTool(t))) ) .ToList(); + + toolboxCollection.Items[0].Select(); } private void setCompositionTool(ICompositionTool tool) diff --git a/osu.Game/Rulesets/Edit/Tools/SelectionTool.cs b/osu.Game/Rulesets/Edit/Tools/SelectionTool.cs deleted file mode 100644 index 9f3ef78a02..0000000000 --- a/osu.Game/Rulesets/Edit/Tools/SelectionTool.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace osu.Game.Rulesets.Edit.Tools -{ - public class SelectionTool : ICompositionTool - { - public string Name => "Select"; - } -} From 89772f4efd889836f60480ba3de93cd73598caf9 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 30 Nov 2017 19:54:58 +0900 Subject: [PATCH 0933/1263] A few resharper fixes --- .../Edit/Screens/Compose/RadioButtons/DrawableRadioButton.cs | 3 +-- .../Edit/Screens/Compose/RadioButtons/RadioButtonCollection.cs | 2 +- osu.Game/osu.Game.csproj | 1 - 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Edit/Screens/Compose/RadioButtons/DrawableRadioButton.cs b/osu.Game/Screens/Edit/Screens/Compose/RadioButtons/DrawableRadioButton.cs index a6c0f48f1f..48cc7f3379 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/RadioButtons/DrawableRadioButton.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/RadioButtons/DrawableRadioButton.cs @@ -29,8 +29,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose.RadioButtons /// public Action Selected; - private Drawable bubble; - + private readonly Drawable bubble; private readonly RadioButton button; public DrawableRadioButton(RadioButton button) diff --git a/osu.Game/Screens/Edit/Screens/Compose/RadioButtons/RadioButtonCollection.cs b/osu.Game/Screens/Edit/Screens/Compose/RadioButtons/RadioButtonCollection.cs index ad24a1da52..08473eaeba 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/RadioButtons/RadioButtonCollection.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/RadioButtons/RadioButtonCollection.cs @@ -17,7 +17,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose.RadioButtons get { return items; } set { - if (items == value) + if (ReferenceEquals(items, value)) return; items = value; diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 886d3313c6..e1425ff8b8 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -564,7 +564,6 @@ - From e8cbde3ae18746e0b96f17e6ddea0114590085b0 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 30 Nov 2017 21:56:12 +0900 Subject: [PATCH 0934/1263] Add overlay/underlay --- osu.Game/Rulesets/Edit/HitObjectComposer.cs | 14 ++++++++---- osu.Game/Rulesets/Edit/PlayfieldOverlay.cs | 24 +++++++++++++++++++++ osu.Game/Rulesets/Edit/PlayfieldUnderlay.cs | 21 ++++++++++++++++++ osu.Game/Rulesets/UI/RulesetContainer.cs | 10 ++++----- osu.Game/osu.Game.csproj | 2 ++ 5 files changed, 62 insertions(+), 9 deletions(-) create mode 100644 osu.Game/Rulesets/Edit/PlayfieldOverlay.cs create mode 100644 osu.Game/Rulesets/Edit/PlayfieldUnderlay.cs diff --git a/osu.Game/Rulesets/Edit/HitObjectComposer.cs b/osu.Game/Rulesets/Edit/HitObjectComposer.cs index b06af84ec8..3aa633115b 100644 --- a/osu.Game/Rulesets/Edit/HitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/HitObjectComposer.cs @@ -22,6 +22,8 @@ namespace osu.Game.Rulesets.Edit { private readonly Ruleset ruleset; + protected ICompositionTool CurrentTool { get; private set; } + protected HitObjectComposer(Ruleset ruleset) { this.ruleset = ruleset; @@ -75,7 +77,9 @@ namespace osu.Game.Rulesets.Edit Alpha = 0, AlwaysPresent = true, }, - rulesetContainer + CreateUnderlay(rulesetContainer.Playfield), + rulesetContainer, + CreateOverlay(rulesetContainer.Playfield) } } }, @@ -98,12 +102,14 @@ namespace osu.Game.Rulesets.Edit toolboxCollection.Items[0].Select(); } - private void setCompositionTool(ICompositionTool tool) - { - } + private void setCompositionTool(ICompositionTool tool) => CurrentTool = tool; protected virtual RulesetContainer CreateRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap) => ruleset.CreateRulesetContainerWith(beatmap, true); + protected virtual PlayfieldUnderlay CreateUnderlay(Playfield playfield) => new PlayfieldUnderlay(playfield); + + protected virtual PlayfieldOverlay CreateOverlay(Playfield playfield) => new PlayfieldOverlay(playfield); + protected abstract IReadOnlyList CompositionTools { get; } } } diff --git a/osu.Game/Rulesets/Edit/PlayfieldOverlay.cs b/osu.Game/Rulesets/Edit/PlayfieldOverlay.cs new file mode 100644 index 0000000000..2138079784 --- /dev/null +++ b/osu.Game/Rulesets/Edit/PlayfieldOverlay.cs @@ -0,0 +1,24 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE + +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Rulesets.UI; + +namespace osu.Game.Rulesets.Edit +{ + public class PlayfieldOverlay : CompositeDrawable + { + + private Playfield playfield; + + public PlayfieldOverlay(Playfield playfield) + { + this.playfield = playfield; + + RelativeSizeAxes = Axes.Both; + + } + + } +} diff --git a/osu.Game/Rulesets/Edit/PlayfieldUnderlay.cs b/osu.Game/Rulesets/Edit/PlayfieldUnderlay.cs new file mode 100644 index 0000000000..7a18c59613 --- /dev/null +++ b/osu.Game/Rulesets/Edit/PlayfieldUnderlay.cs @@ -0,0 +1,21 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE + +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Rulesets.UI; + +namespace osu.Game.Rulesets.Edit +{ + public class PlayfieldUnderlay : CompositeDrawable + { + private readonly Playfield playfield; + + public PlayfieldUnderlay(Playfield playfield) + { + this.playfield = playfield; + + RelativeSizeAxes = Axes.Both; + } + } +} diff --git a/osu.Game/Rulesets/UI/RulesetContainer.cs b/osu.Game/Rulesets/UI/RulesetContainer.cs index ec26f6f310..69bf6bba29 100644 --- a/osu.Game/Rulesets/UI/RulesetContainer.cs +++ b/osu.Game/Rulesets/UI/RulesetContainer.cs @@ -55,6 +55,11 @@ namespace osu.Game.Rulesets.UI public abstract IEnumerable Objects { get; } + /// + /// The playfield. + /// + public Playfield Playfield { get; protected set; } + protected readonly Ruleset Ruleset; /// @@ -135,11 +140,6 @@ namespace osu.Game.Rulesets.UI public override ScoreProcessor CreateScoreProcessor() => new ScoreProcessor(this); - /// - /// The playfield. - /// - public Playfield Playfield { get; private set; } - protected override Container Content => content; private Container content; diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index e1425ff8b8..ad1370890f 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -302,6 +302,8 @@ + + From c0c051aa32166fc378e7d13051ecfd932cc04cc7 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 30 Nov 2017 21:58:41 +0900 Subject: [PATCH 0935/1263] Remove unused parameter for now --- osu.Game/Rulesets/Edit/HitObjectComposer.cs | 4 ++-- osu.Game/Rulesets/Edit/PlayfieldOverlay.cs | 9 ++------- osu.Game/Rulesets/Edit/PlayfieldUnderlay.cs | 7 +------ 3 files changed, 5 insertions(+), 15 deletions(-) diff --git a/osu.Game/Rulesets/Edit/HitObjectComposer.cs b/osu.Game/Rulesets/Edit/HitObjectComposer.cs index 3aa633115b..f55b7b0531 100644 --- a/osu.Game/Rulesets/Edit/HitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/HitObjectComposer.cs @@ -106,9 +106,9 @@ namespace osu.Game.Rulesets.Edit protected virtual RulesetContainer CreateRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap) => ruleset.CreateRulesetContainerWith(beatmap, true); - protected virtual PlayfieldUnderlay CreateUnderlay(Playfield playfield) => new PlayfieldUnderlay(playfield); + protected virtual PlayfieldUnderlay CreateUnderlay(Playfield playfield) => new PlayfieldUnderlay(); - protected virtual PlayfieldOverlay CreateOverlay(Playfield playfield) => new PlayfieldOverlay(playfield); + protected virtual PlayfieldOverlay CreateOverlay(Playfield playfield) => new PlayfieldOverlay(); protected abstract IReadOnlyList CompositionTools { get; } } diff --git a/osu.Game/Rulesets/Edit/PlayfieldOverlay.cs b/osu.Game/Rulesets/Edit/PlayfieldOverlay.cs index 2138079784..4f5658e39c 100644 --- a/osu.Game/Rulesets/Edit/PlayfieldOverlay.cs +++ b/osu.Game/Rulesets/Edit/PlayfieldOverlay.cs @@ -3,22 +3,17 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Game.Rulesets.UI; namespace osu.Game.Rulesets.Edit { public class PlayfieldOverlay : CompositeDrawable { - - private Playfield playfield; - - public PlayfieldOverlay(Playfield playfield) + public PlayfieldOverlay() { - this.playfield = playfield; - RelativeSizeAxes = Axes.Both; } + } } diff --git a/osu.Game/Rulesets/Edit/PlayfieldUnderlay.cs b/osu.Game/Rulesets/Edit/PlayfieldUnderlay.cs index 7a18c59613..e9198c71c6 100644 --- a/osu.Game/Rulesets/Edit/PlayfieldUnderlay.cs +++ b/osu.Game/Rulesets/Edit/PlayfieldUnderlay.cs @@ -3,18 +3,13 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Game.Rulesets.UI; namespace osu.Game.Rulesets.Edit { public class PlayfieldUnderlay : CompositeDrawable { - private readonly Playfield playfield; - - public PlayfieldUnderlay(Playfield playfield) + public PlayfieldUnderlay() { - this.playfield = playfield; - RelativeSizeAxes = Axes.Both; } } From 52ba68e25dd1fb873608d548507b7f4cd7945445 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 30 Nov 2017 22:21:02 +0900 Subject: [PATCH 0936/1263] Add/fix up license headers --- osu.Game/Rulesets/Edit/PlayfieldOverlay.cs | 2 +- osu.Game/Rulesets/Edit/PlayfieldUnderlay.cs | 2 +- osu.Game/Rulesets/Edit/Tools/HitObjectCompositionTool.cs | 3 +++ 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/osu.Game/Rulesets/Edit/PlayfieldOverlay.cs b/osu.Game/Rulesets/Edit/PlayfieldOverlay.cs index 4f5658e39c..58b15e3de2 100644 --- a/osu.Game/Rulesets/Edit/PlayfieldOverlay.cs +++ b/osu.Game/Rulesets/Edit/PlayfieldOverlay.cs @@ -1,5 +1,5 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; diff --git a/osu.Game/Rulesets/Edit/PlayfieldUnderlay.cs b/osu.Game/Rulesets/Edit/PlayfieldUnderlay.cs index e9198c71c6..bace5258f8 100644 --- a/osu.Game/Rulesets/Edit/PlayfieldUnderlay.cs +++ b/osu.Game/Rulesets/Edit/PlayfieldUnderlay.cs @@ -1,5 +1,5 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; diff --git a/osu.Game/Rulesets/Edit/Tools/HitObjectCompositionTool.cs b/osu.Game/Rulesets/Edit/Tools/HitObjectCompositionTool.cs index 914cbd11ca..dd182dcbdb 100644 --- a/osu.Game/Rulesets/Edit/Tools/HitObjectCompositionTool.cs +++ b/osu.Game/Rulesets/Edit/Tools/HitObjectCompositionTool.cs @@ -1,3 +1,6 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + using osu.Game.Rulesets.Objects; namespace osu.Game.Rulesets.Edit.Tools From 016057ab014954b09c5510ed9ae2142cf2f1d6f3 Mon Sep 17 00:00:00 2001 From: Aergwyn Date: Thu, 30 Nov 2017 16:49:53 +0100 Subject: [PATCH 0937/1263] readd storyboard to beatmap + minor cleanup --- osu.Game/Beatmaps/Beatmap.cs | 6 ++++++ osu.Game/Beatmaps/BeatmapManager.cs | 17 +++++------------ osu.Game/Screens/Play/Player.cs | 4 ++-- 3 files changed, 13 insertions(+), 14 deletions(-) diff --git a/osu.Game/Beatmaps/Beatmap.cs b/osu.Game/Beatmaps/Beatmap.cs index 2c437f8a18..35b6cc2b02 100644 --- a/osu.Game/Beatmaps/Beatmap.cs +++ b/osu.Game/Beatmaps/Beatmap.cs @@ -41,6 +41,11 @@ namespace osu.Game.Beatmaps /// public double TotalBreakTime => Breaks.Sum(b => b.Duration); + /// + /// The Beatmap's Storyboard. + /// + public Storyboard Storyboard = new Storyboard(); + /// /// Constructs a new beatmap. /// @@ -52,6 +57,7 @@ namespace osu.Game.Beatmaps Breaks = original?.Breaks ?? Breaks; ComboColors = original?.ComboColors ?? ComboColors; HitObjects = original?.HitObjects ?? HitObjects; + Storyboard = original?.Storyboard ?? Storyboard; if (original == null && Metadata == null) { diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index a5578bcfde..4f7c0051c1 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -569,16 +569,11 @@ namespace osu.Game.Beatmaps { try { - Beatmap beatmap; - - BeatmapDecoder decoder; using (var stream = new StreamReader(store.GetStream(getPathForFile(BeatmapInfo.Path)))) { - decoder = BeatmapDecoder.GetDecoder(stream); - beatmap = decoder.Decode(stream); + BeatmapDecoder decoder = BeatmapDecoder.GetDecoder(stream); + return decoder.Decode(stream); } - - return beatmap; } catch { @@ -622,9 +617,7 @@ namespace osu.Game.Beatmaps { try { - Beatmap beatmap = Beatmap; - - if (beatmap == null || BeatmapSetInfo.StoryboardFile == null) + if (Beatmap == null || BeatmapSetInfo.StoryboardFile == null) return new Storyboard(); BeatmapDecoder decoder; @@ -632,9 +625,9 @@ namespace osu.Game.Beatmaps decoder = BeatmapDecoder.GetDecoder(stream); using (var stream = new StreamReader(store.GetStream(getPathForFile(BeatmapSetInfo.StoryboardFile)))) - decoder.Decode(stream, beatmap); + decoder.Decode(stream, Beatmap); - return beatmap.Storyboard; + return Beatmap.Storyboard; } catch { diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index dc746b305c..b5b09504da 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -245,7 +245,7 @@ namespace osu.Game.Screens.Play private void initializeStoryboard(bool asyncLoad) { - var beatmap = Beatmap.Value.Beatmap; + var beatmap = Beatmap.Value; storyboard = beatmap.Storyboard.CreateDrawable(Beatmap.Value); storyboard.Masking = true; @@ -388,7 +388,7 @@ namespace osu.Game.Screens.Play initializeStoryboard(true); var beatmap = Beatmap.Value; - var storyboardVisible = showStoryboard && beatmap.Beatmap.Storyboard.HasDrawable; + var storyboardVisible = showStoryboard && beatmap.Storyboard.HasDrawable; storyboardContainer.FadeColour(new Color4(opacity, opacity, opacity, 1), 800); storyboardContainer.FadeTo(storyboardVisible && opacity > 0 ? 1 : 0); From c16925059c992cc428d8cf71862d74ca9a063d1a Mon Sep 17 00:00:00 2001 From: Aergwyn Date: Thu, 30 Nov 2017 19:16:13 +0100 Subject: [PATCH 0938/1263] split parsing a beatmap and parsing a storyboard --- .../Beatmaps/Formats/OsuLegacyDecoderTest.cs | 12 +- .../Beatmaps/IO/OszArchiveReaderTest.cs | 2 +- osu.Game.Tests/Visual/TestCaseStoryboard.cs | 2 +- osu.Game/Beatmaps/Beatmap.cs | 6 - osu.Game/Beatmaps/BeatmapManager.cs | 16 +- osu.Game/Beatmaps/Formats/BeatmapDecoder.cs | 25 +- osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs | 400 ++++++++++-------- osu.Game/Tests/Visual/TestCasePlayer.cs | 2 +- 8 files changed, 262 insertions(+), 203 deletions(-) diff --git a/osu.Game.Tests/Beatmaps/Formats/OsuLegacyDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/OsuLegacyDecoderTest.cs index 95b691e07f..175e07f99c 100644 --- a/osu.Game.Tests/Beatmaps/Formats/OsuLegacyDecoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/OsuLegacyDecoderTest.cs @@ -22,7 +22,7 @@ namespace osu.Game.Tests.Beatmaps.Formats var decoder = new OsuLegacyDecoder(); using (var stream = Resource.OpenResource("Soleily - Renatus (Gamu) [Insane].osu")) { - var beatmap = decoder.Decode(new StreamReader(stream)); + var beatmap = decoder.DecodeBeatmap(new StreamReader(stream)); var meta = beatmap.BeatmapInfo.Metadata; Assert.AreEqual(241526, meta.OnlineBeatmapSetID); Assert.AreEqual("Soleily", meta.Artist); @@ -44,7 +44,7 @@ namespace osu.Game.Tests.Beatmaps.Formats var decoder = new OsuLegacyDecoder(); using (var stream = Resource.OpenResource("Soleily - Renatus (Gamu) [Insane].osu")) { - var beatmapInfo = decoder.Decode(new StreamReader(stream)).BeatmapInfo; + var beatmapInfo = decoder.DecodeBeatmap(new StreamReader(stream)).BeatmapInfo; Assert.AreEqual(0, beatmapInfo.AudioLeadIn); Assert.AreEqual(false, beatmapInfo.Countdown); Assert.AreEqual(0.7f, beatmapInfo.StackLeniency); @@ -61,7 +61,7 @@ namespace osu.Game.Tests.Beatmaps.Formats var decoder = new OsuLegacyDecoder(); using (var stream = Resource.OpenResource("Soleily - Renatus (Gamu) [Insane].osu")) { - var beatmap = decoder.Decode(new StreamReader(stream)).BeatmapInfo; + var beatmap = decoder.DecodeBeatmap(new StreamReader(stream)).BeatmapInfo; int[] expectedBookmarks = { 11505, 22054, 32604, 43153, 53703, 64252, 74802, 85351, @@ -84,7 +84,7 @@ namespace osu.Game.Tests.Beatmaps.Formats var decoder = new OsuLegacyDecoder(); using (var stream = Resource.OpenResource("Soleily - Renatus (Gamu) [Insane].osu")) { - var beatmap = decoder.Decode(new StreamReader(stream)); + var beatmap = decoder.DecodeBeatmap(new StreamReader(stream)); var difficulty = beatmap.BeatmapInfo.BaseDifficulty; Assert.AreEqual(6.5f, difficulty.DrainRate); Assert.AreEqual(4, difficulty.CircleSize); @@ -101,7 +101,7 @@ namespace osu.Game.Tests.Beatmaps.Formats var decoder = new OsuLegacyDecoder(); using (var stream = Resource.OpenResource("Soleily - Renatus (Gamu) [Insane].osu")) { - var beatmap = decoder.Decode(new StreamReader(stream)); + var beatmap = decoder.DecodeBeatmap(new StreamReader(stream)); Color4[] expected = { new Color4(142, 199, 255, 255), @@ -123,7 +123,7 @@ namespace osu.Game.Tests.Beatmaps.Formats var decoder = new OsuLegacyDecoder(); using (var stream = Resource.OpenResource("Soleily - Renatus (Gamu) [Insane].osu")) { - var beatmap = decoder.Decode(new StreamReader(stream)); + var beatmap = decoder.DecodeBeatmap(new StreamReader(stream)); var curveData = beatmap.HitObjects[0] as IHasCurve; var positionData = beatmap.HitObjects[0] as IHasPosition; diff --git a/osu.Game.Tests/Beatmaps/IO/OszArchiveReaderTest.cs b/osu.Game.Tests/Beatmaps/IO/OszArchiveReaderTest.cs index 12bbde5b57..7b30a4f1fe 100644 --- a/osu.Game.Tests/Beatmaps/IO/OszArchiveReaderTest.cs +++ b/osu.Game.Tests/Beatmaps/IO/OszArchiveReaderTest.cs @@ -50,7 +50,7 @@ namespace osu.Game.Tests.Beatmaps.IO BeatmapMetadata meta; using (var stream = new StreamReader(reader.GetStream("Soleily - Renatus (Deif) [Platter].osu"))) - meta = BeatmapDecoder.GetDecoder(stream).Decode(stream).Metadata; + meta = BeatmapDecoder.GetDecoder(stream).DecodeBeatmap(stream).Metadata; Assert.AreEqual(241526, meta.OnlineBeatmapSetID); Assert.AreEqual("Soleily", meta.Artist); diff --git a/osu.Game.Tests/Visual/TestCaseStoryboard.cs b/osu.Game.Tests/Visual/TestCaseStoryboard.cs index 1dad106cbe..0a158f5662 100644 --- a/osu.Game.Tests/Visual/TestCaseStoryboard.cs +++ b/osu.Game.Tests/Visual/TestCaseStoryboard.cs @@ -79,7 +79,7 @@ namespace osu.Game.Tests.Visual var decoupledClock = new DecoupleableInterpolatingFramedClock { IsCoupled = true }; storyboardContainer.Clock = decoupledClock; - storyboard = working.Beatmap.Storyboard.CreateDrawable(beatmapBacking); + storyboard = working.Storyboard.CreateDrawable(beatmapBacking); storyboard.Passing = false; storyboardContainer.Add(storyboard); diff --git a/osu.Game/Beatmaps/Beatmap.cs b/osu.Game/Beatmaps/Beatmap.cs index 35b6cc2b02..2c437f8a18 100644 --- a/osu.Game/Beatmaps/Beatmap.cs +++ b/osu.Game/Beatmaps/Beatmap.cs @@ -41,11 +41,6 @@ namespace osu.Game.Beatmaps /// public double TotalBreakTime => Breaks.Sum(b => b.Duration); - /// - /// The Beatmap's Storyboard. - /// - public Storyboard Storyboard = new Storyboard(); - /// /// Constructs a new beatmap. /// @@ -57,7 +52,6 @@ namespace osu.Game.Beatmaps Breaks = original?.Breaks ?? Breaks; ComboColors = original?.ComboColors ?? ComboColors; HitObjects = original?.HitObjects ?? HitObjects; - Storyboard = original?.Storyboard ?? Storyboard; if (original == null && Metadata == null) { diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 4f7c0051c1..e5f2064ee3 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -495,7 +495,7 @@ namespace osu.Game.Beatmaps BeatmapMetadata metadata; using (var stream = new StreamReader(reader.GetStream(mapName))) - metadata = BeatmapDecoder.GetDecoder(stream).Decode(stream).Metadata; + metadata = BeatmapDecoder.GetDecoder(stream).DecodeBeatmap(stream).Metadata; // check if a set already exists with the same online id. beatmapSet = beatmaps.BeatmapSets.FirstOrDefault(b => b.OnlineBeatmapSetID == metadata.OnlineBeatmapSetID) ?? new BeatmapSetInfo @@ -519,7 +519,7 @@ namespace osu.Game.Beatmaps ms.Position = 0; var decoder = BeatmapDecoder.GetDecoder(sr); - Beatmap beatmap = decoder.Decode(sr); + Beatmap beatmap = decoder.DecodeBeatmap(sr); beatmap.BeatmapInfo.Path = name; beatmap.BeatmapInfo.Hash = ms.ComputeSHA2Hash(); @@ -572,7 +572,7 @@ namespace osu.Game.Beatmaps using (var stream = new StreamReader(store.GetStream(getPathForFile(BeatmapInfo.Path)))) { BeatmapDecoder decoder = BeatmapDecoder.GetDecoder(stream); - return decoder.Decode(stream); + return decoder.DecodeBeatmap(stream); } } catch @@ -615,19 +615,17 @@ namespace osu.Game.Beatmaps protected override Storyboard GetStoryboard() { + if (BeatmapSetInfo?.StoryboardFile == null) + return new Storyboard(); + try { - if (Beatmap == null || BeatmapSetInfo.StoryboardFile == null) - return new Storyboard(); - BeatmapDecoder decoder; using (var stream = new StreamReader(store.GetStream(getPathForFile(BeatmapInfo.Path)))) decoder = BeatmapDecoder.GetDecoder(stream); using (var stream = new StreamReader(store.GetStream(getPathForFile(BeatmapSetInfo.StoryboardFile)))) - decoder.Decode(stream, Beatmap); - - return Beatmap.Storyboard; + return decoder.DecodeStoryboard(stream); } catch { diff --git a/osu.Game/Beatmaps/Formats/BeatmapDecoder.cs b/osu.Game/Beatmaps/Formats/BeatmapDecoder.cs index 7e1a87085c..d785618780 100644 --- a/osu.Game/Beatmaps/Formats/BeatmapDecoder.cs +++ b/osu.Game/Beatmaps/Formats/BeatmapDecoder.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.IO; +using osu.Game.Storyboards; namespace osu.Game.Beatmaps.Formats { @@ -35,17 +36,12 @@ namespace osu.Game.Beatmaps.Formats decoders[magic] = typeof(T); } - public virtual Beatmap Decode(StreamReader stream) + public virtual Beatmap DecodeBeatmap(StreamReader stream) { - return ParseFile(stream); + return ParseBeatmap(stream); } - public virtual void Decode(StreamReader stream, Beatmap beatmap) - { - ParseFile(stream, beatmap); - } - - protected virtual Beatmap ParseFile(StreamReader stream) + protected virtual Beatmap ParseBeatmap(StreamReader stream) { var beatmap = new Beatmap { @@ -56,10 +52,19 @@ namespace osu.Game.Beatmaps.Formats }, }; - ParseFile(stream, beatmap); + ParseBeatmap(stream, beatmap); return beatmap; } - protected abstract void ParseFile(StreamReader stream, Beatmap beatmap); + protected abstract void ParseBeatmap(StreamReader stream, Beatmap beatmap); + + public virtual Storyboard DecodeStoryboard(StreamReader stream) + { + var storyboard = new Storyboard(); + ParseStoryboard(stream, storyboard); + return storyboard; + } + + protected abstract void ParseStoryboard(StreamReader stream, Storyboard storyboard); } } diff --git a/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs b/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs index 11631e9447..e0af018059 100644 --- a/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs +++ b/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs @@ -54,20 +54,135 @@ namespace osu.Game.Beatmaps.Formats beatmapVersion = int.Parse(header.Substring(17)); } - private enum Section + // + + protected override Beatmap ParseBeatmap(StreamReader stream) { - None, - General, - Editor, - Metadata, - Difficulty, - Events, - TimingPoints, - Colours, - HitObjects, - Variables, + return new LegacyBeatmap(base.ParseBeatmap(stream)); } + public override Beatmap DecodeBeatmap(StreamReader stream) + { + return new LegacyBeatmap(base.DecodeBeatmap(stream)); + } + + protected override void ParseBeatmap(StreamReader stream, Beatmap beatmap) + { + if (beatmap == null) + throw new ArgumentNullException(nameof(beatmap)); + if (stream == null) + throw new ArgumentNullException(nameof(stream)); + + beatmap.BeatmapInfo.BeatmapVersion = beatmapVersion; + + Section section = Section.None; + bool hasCustomColours = false; + + string line; + while ((line = stream.ReadLine()) != null) + { + if (string.IsNullOrWhiteSpace(line)) + continue; + + if (line.StartsWith("//")) + continue; + + if (line.StartsWith(@"osu file format v")) + { + beatmap.BeatmapInfo.BeatmapVersion = int.Parse(line.Substring(17)); + continue; + } + + if (line.StartsWith(@"[") && line.EndsWith(@"]")) + { + if (!Enum.TryParse(line.Substring(1, line.Length - 2), out section)) + throw new InvalidDataException($@"Unknown osu section {line}"); + continue; + } + + switch (section) + { + case Section.General: + handleGeneral(beatmap, line); + break; + case Section.Editor: + handleEditor(beatmap, line); + break; + case Section.Metadata: + handleMetadata(beatmap, line); + break; + case Section.Difficulty: + handleDifficulty(beatmap, line); + break; + case Section.Events: + handleEvents(beatmap, line); + break; + case Section.TimingPoints: + handleTimingPoints(beatmap, line); + break; + case Section.Colours: + handleColours(beatmap, line, ref hasCustomColours); + break; + case Section.HitObjects: + + // If the ruleset wasn't specified, assume the osu!standard ruleset. + if (parser == null) + parser = new Rulesets.Objects.Legacy.Osu.ConvertHitObjectParser(); + + var obj = parser.Parse(line); + + if (obj != null) + beatmap.HitObjects.Add(obj); + + break; + case Section.Variables: + handleVariables(line); + break; + } + } + + foreach (var hitObject in beatmap.HitObjects) + hitObject.ApplyDefaults(beatmap.ControlPointInfo, beatmap.BeatmapInfo.BaseDifficulty); + } + + protected override void ParseStoryboard(StreamReader stream, Storyboard storyboard) + { + if (storyboard == null) + throw new ArgumentNullException(nameof(storyboard)); + if (stream == null) + throw new ArgumentNullException(nameof(stream)); + + Section section = Section.None; + StoryboardSprite storyboardSprite = null; + CommandTimelineGroup timelineGroup = null; + + string line; + while ((line = stream.ReadLine()) != null) + { + if (string.IsNullOrWhiteSpace(line)) + continue; + + if (line.StartsWith("//")) + continue; + + if (line.StartsWith(@"[") && line.EndsWith(@"]")) + { + if (!Enum.TryParse(line.Substring(1, line.Length - 2), out section)) + throw new InvalidDataException($@"Unknown osu section {line}"); + continue; + } + + switch (section) + { + case Section.Events: + handleEvents(storyboard, line, ref storyboardSprite, ref timelineGroup); + break; + } + } + } + + // + private void handleGeneral(Beatmap beatmap, string line) { if (beatmap == null) @@ -240,38 +355,49 @@ namespace osu.Game.Beatmaps.Formats } } - /// - /// Decodes any beatmap variables present in a line into their real values. - /// - /// The line which may contains variables. - private void decodeVariables(ref string line) - { - if (line == null) - throw new ArgumentNullException(nameof(line)); - - while (line.IndexOf('$') >= 0) - { - string origLine = line; - string[] split = line.Split(','); - for (int i = 0; i < split.Length; i++) - { - var item = split[i]; - if (item.StartsWith("$") && variables.ContainsKey(item)) - split[i] = variables[item]; - } - - line = string.Join(",", split); - if (line == origLine) break; - } - } - - private void handleEvents(Beatmap beatmap, string line, ref StoryboardSprite storyboardSprite, ref CommandTimelineGroup timelineGroup) + private void handleEvents(Beatmap beatmap, string line) { if (line == null) throw new ArgumentNullException(nameof(line)); if (beatmap == null) throw new ArgumentNullException(nameof(beatmap)); + decodeVariables(ref line); + + string[] split = line.Split(','); + + EventType type; + if (!Enum.TryParse(split[0], out type)) + throw new InvalidDataException($@"Unknown event type {split[0]}"); + + switch (type) + { + case EventType.Background: + string filename = split[2].Trim('"'); + beatmap.BeatmapInfo.Metadata.BackgroundFile = filename; + break; + case EventType.Break: + var breakEvent = new BreakPeriod + { + StartTime = double.Parse(split[1], NumberFormatInfo.InvariantInfo), + EndTime = double.Parse(split[2], NumberFormatInfo.InvariantInfo) + }; + + if (!breakEvent.HasEffect) + return; + + beatmap.Breaks.Add(breakEvent); + break; + } + } + + private void handleEvents(Storyboard storyboard, string line, ref StoryboardSprite storyboardSprite, ref CommandTimelineGroup timelineGroup) + { + if (line == null) + throw new ArgumentNullException(nameof(line)); + if (storyboard == null) + throw new ArgumentNullException(nameof(storyboard)); + var depth = 0; while (line.StartsWith(" ") || line.StartsWith("_")) { @@ -293,26 +419,6 @@ namespace osu.Game.Beatmaps.Formats switch (type) { - case EventType.Video: - case EventType.Background: - string filename = split[2].Trim('"'); - - if (type == EventType.Background) - beatmap.BeatmapInfo.Metadata.BackgroundFile = filename; - - break; - case EventType.Break: - var breakEvent = new BreakPeriod - { - StartTime = double.Parse(split[1], NumberFormatInfo.InvariantInfo), - EndTime = double.Parse(split[2], NumberFormatInfo.InvariantInfo) - }; - - if (!breakEvent.HasEffect) - return; - - beatmap.Breaks.Add(breakEvent); - break; case EventType.Sprite: { var layer = parseLayer(split[1]); @@ -321,7 +427,7 @@ namespace osu.Game.Beatmaps.Formats var x = float.Parse(split[4], NumberFormatInfo.InvariantInfo); var y = float.Parse(split[5], NumberFormatInfo.InvariantInfo); storyboardSprite = new StoryboardSprite(path, origin, new Vector2(x, y)); - beatmap.Storyboard.GetLayer(layer).Add(storyboardSprite); + storyboard.GetLayer(layer).Add(storyboardSprite); } break; case EventType.Animation: @@ -335,7 +441,7 @@ namespace osu.Game.Beatmaps.Formats var frameDelay = double.Parse(split[7], NumberFormatInfo.InvariantInfo); var loopType = split.Length > 8 ? (AnimationLoopType)Enum.Parse(typeof(AnimationLoopType), split[8]) : AnimationLoopType.LoopForever; storyboardSprite = new StoryboardAnimation(path, origin, new Vector2(x, y), frameCount, frameDelay, loopType); - beatmap.Storyboard.GetLayer(layer).Add(storyboardSprite); + storyboard.GetLayer(layer).Add(storyboardSprite); } break; case EventType.Sample: @@ -344,7 +450,7 @@ namespace osu.Game.Beatmaps.Formats var layer = parseLayer(split[2]); var path = cleanFilename(split[3]); var volume = split.Length > 4 ? float.Parse(split[4], CultureInfo.InvariantCulture) : 100; - beatmap.Storyboard.GetLayer(layer).Add(new StoryboardSample(path, time, volume)); + storyboard.GetLayer(layer).Add(new StoryboardSample(path, time, volume)); } break; } @@ -456,9 +562,15 @@ namespace osu.Game.Beatmaps.Formats var type = split[4]; switch (type) { - case "A": timelineGroup?.BlendingMode.Add(easing, startTime, endTime, BlendingMode.Additive, startTime == endTime ? BlendingMode.Additive : BlendingMode.Inherit); break; - case "H": timelineGroup?.FlipH.Add(easing, startTime, endTime, true, startTime == endTime); break; - case "V": timelineGroup?.FlipV.Add(easing, startTime, endTime, true, startTime == endTime); break; + case "A": + timelineGroup?.BlendingMode.Add(easing, startTime, endTime, BlendingMode.Additive, startTime == endTime ? BlendingMode.Additive : BlendingMode.Inherit); + break; + case "H": + timelineGroup?.FlipH.Add(easing, startTime, endTime, true, startTime == endTime); + break; + case "V": + timelineGroup?.FlipV.Add(easing, startTime, endTime, true, startTime == endTime); + break; } } break; @@ -471,30 +583,6 @@ namespace osu.Game.Beatmaps.Formats } } - private static string cleanFilename(string path) - => FileSafety.PathStandardise(path.Trim('\"')); - - private static Anchor parseOrigin(string value) - { - var origin = (LegacyOrigins)Enum.Parse(typeof(LegacyOrigins), value); - switch (origin) - { - case LegacyOrigins.TopLeft: return Anchor.TopLeft; - case LegacyOrigins.TopCentre: return Anchor.TopCentre; - case LegacyOrigins.TopRight: return Anchor.TopRight; - case LegacyOrigins.CentreLeft: return Anchor.CentreLeft; - case LegacyOrigins.Centre: return Anchor.Centre; - case LegacyOrigins.CentreRight: return Anchor.CentreRight; - case LegacyOrigins.BottomLeft: return Anchor.BottomLeft; - case LegacyOrigins.BottomCentre: return Anchor.BottomCentre; - case LegacyOrigins.BottomRight: return Anchor.BottomRight; - } - throw new InvalidDataException($@"Unknown origin: {value}"); - } - - private static string parseLayer(string value) - => Enum.Parse(typeof(StoryLayer), value).ToString(); - private void handleTimingPoints(Beatmap beatmap, string line) { if (beatmap == null) @@ -632,97 +720,57 @@ namespace osu.Game.Beatmaps.Formats variables[pair.Key] = pair.Value; } - protected override Beatmap ParseFile(StreamReader stream) + // + + /// + /// Decodes any beatmap variables present in a line into their real values. + /// + /// The line which may contains variables. + private void decodeVariables(ref string line) { - return new LegacyBeatmap(base.ParseFile(stream)); - } + if (line == null) + throw new ArgumentNullException(nameof(line)); - public override Beatmap Decode(StreamReader stream) - { - return new LegacyBeatmap(base.Decode(stream)); - } - - protected override void ParseFile(StreamReader stream, Beatmap beatmap) - { - if (beatmap == null) - throw new ArgumentNullException(nameof(beatmap)); - if (stream == null) - throw new ArgumentNullException(nameof(stream)); - - beatmap.BeatmapInfo.BeatmapVersion = beatmapVersion; - - Section section = Section.None; - bool hasCustomColours = false; - StoryboardSprite storyboardSprite = null; - CommandTimelineGroup timelineGroup = null; - - string line; - while ((line = stream.ReadLine()) != null) + while (line.IndexOf('$') >= 0) { - if (string.IsNullOrWhiteSpace(line)) - continue; - - if (line.StartsWith("//")) - continue; - - if (line.StartsWith(@"osu file format v")) + string origLine = line; + string[] split = line.Split(','); + for (int i = 0; i < split.Length; i++) { - beatmap.BeatmapInfo.BeatmapVersion = int.Parse(line.Substring(17)); - continue; + var item = split[i]; + if (item.StartsWith("$") && variables.ContainsKey(item)) + split[i] = variables[item]; } - if (line.StartsWith(@"[") && line.EndsWith(@"]")) - { - if (!Enum.TryParse(line.Substring(1, line.Length - 2), out section)) - throw new InvalidDataException($@"Unknown osu section {line}"); - continue; - } - - switch (section) - { - case Section.General: - handleGeneral(beatmap, line); - break; - case Section.Editor: - handleEditor(beatmap, line); - break; - case Section.Metadata: - handleMetadata(beatmap, line); - break; - case Section.Difficulty: - handleDifficulty(beatmap, line); - break; - case Section.Events: - handleEvents(beatmap, line, ref storyboardSprite, ref timelineGroup); - break; - case Section.TimingPoints: - handleTimingPoints(beatmap, line); - break; - case Section.Colours: - handleColours(beatmap, line, ref hasCustomColours); - break; - case Section.HitObjects: - - // If the ruleset wasn't specified, assume the osu!standard ruleset. - if (parser == null) - parser = new Rulesets.Objects.Legacy.Osu.ConvertHitObjectParser(); - - var obj = parser.Parse(line); - - if (obj != null) - beatmap.HitObjects.Add(obj); - - break; - case Section.Variables: - handleVariables(line); - break; - } + line = string.Join(",", split); + if (line == origLine) break; } - - foreach (var hitObject in beatmap.HitObjects) - hitObject.ApplyDefaults(beatmap.ControlPointInfo, beatmap.BeatmapInfo.BaseDifficulty); } + private static string cleanFilename(string path) + => FileSafety.PathStandardise(path.Trim('\"')); + + private static Anchor parseOrigin(string value) + { + var origin = (LegacyOrigins)Enum.Parse(typeof(LegacyOrigins), value); + switch (origin) + { + case LegacyOrigins.TopLeft: return Anchor.TopLeft; + case LegacyOrigins.TopCentre: return Anchor.TopCentre; + case LegacyOrigins.TopRight: return Anchor.TopRight; + case LegacyOrigins.CentreLeft: return Anchor.CentreLeft; + case LegacyOrigins.Centre: return Anchor.Centre; + case LegacyOrigins.CentreRight: return Anchor.CentreRight; + case LegacyOrigins.BottomLeft: return Anchor.BottomLeft; + case LegacyOrigins.BottomCentre: return Anchor.BottomCentre; + case LegacyOrigins.BottomRight: return Anchor.BottomRight; + } + throw new InvalidDataException($@"Unknown origin: {value}"); + } + + private static string parseLayer(string value) + => Enum.Parse(typeof(StoryLayer), value).ToString(); + private KeyValuePair splitKeyVal(string line, char separator) { if (line == null) @@ -737,6 +785,20 @@ namespace osu.Game.Beatmaps.Formats ); } + private enum Section + { + None, + General, + Editor, + Metadata, + Difficulty, + Events, + TimingPoints, + Colours, + HitObjects, + Variables, + } + internal enum LegacySampleBank { None = 0, diff --git a/osu.Game/Tests/Visual/TestCasePlayer.cs b/osu.Game/Tests/Visual/TestCasePlayer.cs index d9951e002b..d17f20ff2f 100644 --- a/osu.Game/Tests/Visual/TestCasePlayer.cs +++ b/osu.Game/Tests/Visual/TestCasePlayer.cs @@ -63,7 +63,7 @@ namespace osu.Game.Tests.Visual using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(test_beatmap_data))) using (var reader = new StreamReader(stream)) - beatmap = BeatmapDecoder.GetDecoder(reader).Decode(reader); + beatmap = BeatmapDecoder.GetDecoder(reader).DecodeBeatmap(reader); return beatmap; } From be018a63c6fa0edfc20d9dc94b505f7b060192f1 Mon Sep 17 00:00:00 2001 From: Aergwyn Date: Thu, 30 Nov 2017 19:17:11 +0100 Subject: [PATCH 0939/1263] remove unnecessary lines --- osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs b/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs index e0af018059..47e35f231f 100644 --- a/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs +++ b/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs @@ -54,8 +54,6 @@ namespace osu.Game.Beatmaps.Formats beatmapVersion = int.Parse(header.Substring(17)); } - // - protected override Beatmap ParseBeatmap(StreamReader stream) { return new LegacyBeatmap(base.ParseBeatmap(stream)); @@ -181,8 +179,6 @@ namespace osu.Game.Beatmaps.Formats } } - // - private void handleGeneral(Beatmap beatmap, string line) { if (beatmap == null) @@ -720,8 +716,6 @@ namespace osu.Game.Beatmaps.Formats variables[pair.Key] = pair.Value; } - // - /// /// Decodes any beatmap variables present in a line into their real values. /// From 7080711cb24184c5561d25a782c113210f797749 Mon Sep 17 00:00:00 2001 From: Aergwyn Date: Thu, 30 Nov 2017 20:13:10 +0100 Subject: [PATCH 0940/1263] remove unnecessary `using` --- osu.Game/Beatmaps/Beatmap.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Beatmaps/Beatmap.cs b/osu.Game/Beatmaps/Beatmap.cs index 2c437f8a18..c8390310d4 100644 --- a/osu.Game/Beatmaps/Beatmap.cs +++ b/osu.Game/Beatmaps/Beatmap.cs @@ -8,7 +8,6 @@ using System.Collections.Generic; using System.Linq; using osu.Game.Beatmaps.ControlPoints; using osu.Game.IO.Serialization; -using osu.Game.Storyboards; namespace osu.Game.Beatmaps { From 76a1c7db3b68318229daca40cd06385088e6ca62 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 28 Nov 2017 21:22:57 +0900 Subject: [PATCH 0941/1263] Hyperdash preparation --- .../Beatmaps/CatchBeatmapProcessor.cs | 8 +++++ .../Tests/TestCaseFruit.cs | 36 +++++++++++++++++++ .../Tests/TestCaseHyperdash.cs | 26 ++++++++++++++ .../osu.Game.Rulesets.Catch.csproj | 2 ++ 4 files changed, 72 insertions(+) create mode 100644 osu.Game.Rulesets.Catch/Tests/TestCaseFruit.cs create mode 100644 osu.Game.Rulesets.Catch/Tests/TestCaseHyperdash.cs diff --git a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs index b2f7fdabfc..8a19afcd39 100644 --- a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs +++ b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.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.Catch.Objects; @@ -18,6 +19,8 @@ namespace osu.Game.Rulesets.Catch.Beatmaps CatchHitObject lastObj = null; + convertHyperDash(beatmap.HitObjects); + foreach (var obj in beatmap.HitObjects) { if (obj.NewCombo) @@ -34,5 +37,10 @@ namespace osu.Game.Rulesets.Catch.Beatmaps lastObj = obj; } } + + private void convertHyperDash(List objects) + { + + } } } diff --git a/osu.Game.Rulesets.Catch/Tests/TestCaseFruit.cs b/osu.Game.Rulesets.Catch/Tests/TestCaseFruit.cs new file mode 100644 index 0000000000..0ced95edf9 --- /dev/null +++ b/osu.Game.Rulesets.Catch/Tests/TestCaseFruit.cs @@ -0,0 +1,36 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE + +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Rulesets.Catch.Objects; +using osu.Game.Rulesets.Catch.Objects.Drawable; +using osu.Game.Tests.Visual; +using OpenTK; + +namespace osu.Game.Rulesets.Catch.Tests +{ + public class TestCaseFruit : OsuTestCase + { + public TestCaseFruit() + { + Add(new GridContainer + { + RelativeSizeAxes = Axes.Both, + Content = new[] + { + new Drawable[] + { + new DrawableFruit(new Fruit()) { Position = new Vector2(0.5f) }, + new DrawableFruit(new Fruit()) { Position = new Vector2(0.5f) }, + }, + new Drawable[] + { + new DrawableFruit(new Fruit()) { Position = new Vector2(0.5f) }, + new DrawableFruit(new Fruit()) { Position = new Vector2(0.5f) }, + } + } + }); + } + } +} diff --git a/osu.Game.Rulesets.Catch/Tests/TestCaseHyperdash.cs b/osu.Game.Rulesets.Catch/Tests/TestCaseHyperdash.cs new file mode 100644 index 0000000000..822743debc --- /dev/null +++ b/osu.Game.Rulesets.Catch/Tests/TestCaseHyperdash.cs @@ -0,0 +1,26 @@ +using NUnit.Framework; +using osu.Game.Beatmaps; +using osu.Game.Rulesets.Catch.Objects; + +namespace osu.Game.Rulesets.Catch.Tests +{ + [TestFixture] + [Ignore("getting CI working")] + public class TestCaseHyperdash : Game.Tests.Visual.TestCasePlayer + { + public TestCaseHyperdash() + : base(typeof(CatchRuleset)) + { + } + + protected override Beatmap CreateBeatmap() + { + var beatmap = new Beatmap(); + + for (int i = 0; i < 512; i++) + beatmap.HitObjects.Add(new Fruit { X = 0.5f + (i % 2 == 0 ? -0.4f : 0.4f), StartTime = i * 100, NewCombo = i % 8 == 0 }); + + return beatmap; + } + } +} \ No newline at end of file diff --git a/osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj b/osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj index b7916f674e..4e819fb58b 100644 --- a/osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj +++ b/osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj @@ -67,6 +67,8 @@ + + From f6591851c3a6f7ac3d198e940a813019046fbe55 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 30 Nov 2017 22:01:49 +0900 Subject: [PATCH 0942/1263] Implement a selection dragger box --- osu.Game/Rulesets/Edit/PlayfieldOverlay.cs | 50 ++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/osu.Game/Rulesets/Edit/PlayfieldOverlay.cs b/osu.Game/Rulesets/Edit/PlayfieldOverlay.cs index 58b15e3de2..77aeed42e3 100644 --- a/osu.Game/Rulesets/Edit/PlayfieldOverlay.cs +++ b/osu.Game/Rulesets/Edit/PlayfieldOverlay.cs @@ -1,19 +1,69 @@ // 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.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Primitives; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Input; +using OpenTK; +using OpenTK.Graphics; namespace osu.Game.Rulesets.Edit { public class PlayfieldOverlay : CompositeDrawable { + private readonly Drawable dragBox; + public PlayfieldOverlay() { RelativeSizeAxes = Axes.Both; + InternalChildren = new[] + { + dragBox = new Container + { + Masking = true, + BorderColour = Color4.White, + BorderThickness = 2, + MaskingSmoothness = 1, + Child = new Box + { + RelativeSizeAxes = Axes.Both, + Alpha = 0, + AlwaysPresent = true + } + } + }; } + private Vector2 dragStartPos; + protected override bool OnDragStart(InputState state) + { + dragStartPos = ToLocalSpace(state.Mouse.NativeState.Position); + return true; + } + + protected override bool OnDrag(InputState state) + { + var dragPos = ToLocalSpace(state.Mouse.NativeState.Position); + var dragRectangle = RectangleF.FromLTRB( + Math.Min(dragStartPos.X, dragPos.X), + Math.Min(dragStartPos.Y, dragPos.Y), + Math.Max(dragStartPos.X, dragPos.X), + Math.Max(dragStartPos.Y, dragPos.Y)); + + dragBox.Position = dragRectangle.Location; + dragBox.Size = dragRectangle.Size; + + return true; + } + + protected override bool OnDragEnd(InputState state) + { + return true; + } } } From edb9b1907905ac6afefd62169cdbb8634df3669b Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 1 Dec 2017 13:53:18 +0900 Subject: [PATCH 0943/1263] Make JoinNullCheckWithAssignment a hint --- osu.sln.DotSettings | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.sln.DotSettings b/osu.sln.DotSettings index 92ef2d1021..76929dcbb3 100644 --- a/osu.sln.DotSettings +++ b/osu.sln.DotSettings @@ -49,7 +49,7 @@ HINT WARNING WARNING - DO_NOT_SHOW + HINT DO_NOT_SHOW HINT HINT From a73dfd692bd433f47f2847bbc385a46d62f30979 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 1 Dec 2017 13:53:32 +0900 Subject: [PATCH 0944/1263] Merge LangVer.props and osu.Game.props --- LangVer.props | 8 -------- osu.Game.props | 6 +++++- 2 files changed, 5 insertions(+), 9 deletions(-) delete mode 100644 LangVer.props diff --git a/LangVer.props b/LangVer.props deleted file mode 100644 index c3aee0505a..0000000000 --- a/LangVer.props +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - 7 - - \ No newline at end of file diff --git a/osu.Game.props b/osu.Game.props index 4173adb509..60a5e97944 100644 --- a/osu.Game.props +++ b/osu.Game.props @@ -1,6 +1,10 @@ - + + + + 7 + osu.licenseheader From 19051dd52962642c0323ce8d0355bcb529cc7845 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 1 Dec 2017 16:44:49 +0900 Subject: [PATCH 0945/1263] Update framework --- osu-framework | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu-framework b/osu-framework index 4fc866eee3..87d68cda00 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit 4fc866eee3803f88b155150e32e021b9c21e647f +Subproject commit 87d68cda0015d51dc3da56d2322fa10d399fc4ed From 881745d7561bb25a67c03978a33ee214b09fbc20 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 1 Dec 2017 15:08:12 +0900 Subject: [PATCH 0946/1263] Initial implementation of hyperdash calculation --- .../Beatmaps/CatchBeatmapProcessor.cs | 43 +++++++++++++++ .../Objects/CatchHitObject.cs | 2 + .../Objects/Drawable/DrawableFruit.cs | 15 ++++++ .../Tests/TestCaseHyperdash.cs | 52 +++++++++---------- osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs | 2 +- 5 files changed, 87 insertions(+), 27 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs index 8a19afcd39..d225cdca55 100644 --- a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs +++ b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs @@ -1,9 +1,13 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System; using System.Collections.Generic; using osu.Game.Beatmaps; using osu.Game.Rulesets.Catch.Objects; +using osu.Game.Rulesets.Catch.UI; +using osu.Game.Rulesets.Objects.Types; +using OpenTK; namespace osu.Game.Rulesets.Catch.Beatmaps { @@ -40,7 +44,46 @@ namespace osu.Game.Rulesets.Catch.Beatmaps private void convertHyperDash(List objects) { + // todo: add difficulty adjust. + const double catcher_width = CatcherArea.CATCHER_SIZE / CatchPlayfield.BASE_WIDTH; + const double catcher_width_half = catcher_width / 2; + int lastDirection = 0; + double lastExcess = catcher_width_half; + + int objCount = objects.Count; + + for (int i = 0; i < objCount - 1; i++) + { + CatchHitObject currentObject = objects[i]; + + // not needed? + if (currentObject is TinyDroplet) continue; + + CatchHitObject nextObject = objects[i + 1]; + while (nextObject is TinyDroplet) + { + if (++i == objCount - 1) break; + nextObject = objects[i + 1]; + } + + int thisDirection = nextObject.X > currentObject.X ? 1 : -1; + double timeToNext = nextObject.StartTime - ((currentObject as IHasEndTime)?.EndTime ?? currentObject.StartTime) - 4; + double distanceToNext = Math.Abs(nextObject.X - currentObject.X) - (lastDirection == thisDirection ? lastExcess : catcher_width_half); + + if (timeToNext * CatcherArea.Catcher.BASE_SPEED < distanceToNext) + { + currentObject.HyperDash = true; + lastExcess = catcher_width_half; + } + else + { + //currentObject.DistanceToHyperDash = timeToNext - distanceToNext; + lastExcess = MathHelper.Clamp(timeToNext - distanceToNext, 0, catcher_width_half); + } + + lastDirection = thisDirection; + } } } } diff --git a/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs b/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs index cb4e6453ce..bae2edd055 100644 --- a/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs +++ b/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs @@ -27,6 +27,8 @@ namespace osu.Game.Rulesets.Catch.Objects public float Scale { get; set; } = 1; + public bool HyperDash { get; set; } + public override void ApplyDefaults(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) { base.ApplyDefaults(controlPointInfo, difficulty); diff --git a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableFruit.cs b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableFruit.cs index 4c28a9d021..9f46bbd3a4 100644 --- a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableFruit.cs +++ b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableFruit.cs @@ -7,6 +7,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.MathUtils; using osu.Game.Rulesets.Catch.Objects.Drawable.Pieces; using OpenTK; +using OpenTK.Graphics; namespace osu.Game.Rulesets.Catch.Objects.Drawable { @@ -70,6 +71,20 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable } } }; + + if (HitObject.HyperDash) + { + Add(new Pulp + { + RelativePositionAxes = Axes.Both, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + AccentColour = Color4.Red, + Blending = BlendingMode.Additive, + Alpha = 0.5f, + Scale = new Vector2(2) + }); + } } } } diff --git a/osu.Game.Rulesets.Catch/Tests/TestCaseHyperdash.cs b/osu.Game.Rulesets.Catch/Tests/TestCaseHyperdash.cs index 822743debc..5b0e1fb93c 100644 --- a/osu.Game.Rulesets.Catch/Tests/TestCaseHyperdash.cs +++ b/osu.Game.Rulesets.Catch/Tests/TestCaseHyperdash.cs @@ -1,26 +1,26 @@ -using NUnit.Framework; -using osu.Game.Beatmaps; -using osu.Game.Rulesets.Catch.Objects; - -namespace osu.Game.Rulesets.Catch.Tests -{ - [TestFixture] - [Ignore("getting CI working")] - public class TestCaseHyperdash : Game.Tests.Visual.TestCasePlayer - { - public TestCaseHyperdash() - : base(typeof(CatchRuleset)) - { - } - - protected override Beatmap CreateBeatmap() - { - var beatmap = new Beatmap(); - - for (int i = 0; i < 512; i++) - beatmap.HitObjects.Add(new Fruit { X = 0.5f + (i % 2 == 0 ? -0.4f : 0.4f), StartTime = i * 100, NewCombo = i % 8 == 0 }); - - return beatmap; - } - } -} \ No newline at end of file +using NUnit.Framework; +using osu.Game.Beatmaps; +using osu.Game.Rulesets.Catch.Objects; + +namespace osu.Game.Rulesets.Catch.Tests +{ + [TestFixture] + [Ignore("getting CI working")] + public class TestCaseHyperdash : Game.Tests.Visual.TestCasePlayer + { + public TestCaseHyperdash() + : base(typeof(CatchRuleset)) + { + } + + protected override Beatmap CreateBeatmap() + { + var beatmap = new Beatmap(); + + for (int i = 0; i < 512; i++) + beatmap.HitObjects.Add(new Fruit { X = 0.5f + (i % 8 < 4 ? -0.4f : 0.4f), StartTime = i * 100, NewCombo = i % 8 == 0 }); + + return beatmap; + } + } +} diff --git a/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs b/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs index 6fd0793500..3cfdcafc48 100644 --- a/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs +++ b/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs @@ -15,7 +15,7 @@ namespace osu.Game.Rulesets.Catch.UI { public class CatchPlayfield : ScrollingPlayfield { - public static readonly float BASE_WIDTH = 512; + public const float BASE_WIDTH = 512; protected override Container Content => content; private readonly Container content; From 0b95e36675b2131ae7eb0ca5185678f8d432a627 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 1 Dec 2017 18:00:20 +0900 Subject: [PATCH 0947/1263] Fix RelativeChildSize error temporarily --- .../Edit/Components/Timelines/Summary/Parts/TimelinePart.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/TimelinePart.cs b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/TimelinePart.cs index 229d06ef09..8a19784be9 100644 --- a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/TimelinePart.cs +++ b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/TimelinePart.cs @@ -40,7 +40,7 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts return; } - timeline.RelativeChildSize = new Vector2((float)Math.Max(1, Beatmap.Value.Track.Length), 1); + timeline.RelativeChildSize = Beatmap.Value.Track.Length == double.PositiveInfinity ? Vector2.One : new Vector2((float)Math.Max(1, Beatmap.Value.Track.Length), 1); } protected void Add(Drawable visualisation) => timeline.Add(visualisation); From 5be00cb0ecd9990a6c277a268725655d001775dd Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 1 Dec 2017 18:40:55 +0900 Subject: [PATCH 0948/1263] Add todo --- .../Edit/Components/Timelines/Summary/Parts/TimelinePart.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/TimelinePart.cs b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/TimelinePart.cs index 8a19784be9..df95a5c384 100644 --- a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/TimelinePart.cs +++ b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/TimelinePart.cs @@ -40,6 +40,7 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts return; } + // Todo: This should be handled more gracefully timeline.RelativeChildSize = Beatmap.Value.Track.Length == double.PositiveInfinity ? Vector2.One : new Vector2((float)Math.Max(1, Beatmap.Value.Track.Length), 1); } From 51cae24a26933ce468b858ae91dd13382039b837 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 1 Dec 2017 19:24:48 +0900 Subject: [PATCH 0949/1263] Add basic hyperdash movement Doesn't restrict direction yet. Also improves readability of fruit catch detection. --- .../Beatmaps/CatchBeatmapProcessor.cs | 2 +- .../Objects/CatchHitObject.cs | 10 +- osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs | 2 +- osu.Game.Rulesets.Catch/UI/CatcherArea.cs | 104 ++++++++++++++++-- 4 files changed, 108 insertions(+), 10 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs index d225cdca55..e12d7f3fd3 100644 --- a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs +++ b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs @@ -73,7 +73,7 @@ namespace osu.Game.Rulesets.Catch.Beatmaps if (timeToNext * CatcherArea.Catcher.BASE_SPEED < distanceToNext) { - currentObject.HyperDash = true; + currentObject.HyperDashTarget = nextObject; lastExcess = catcher_width_half; } else diff --git a/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs b/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs index bae2edd055..38757d4928 100644 --- a/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs +++ b/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs @@ -27,7 +27,15 @@ namespace osu.Game.Rulesets.Catch.Objects public float Scale { get; set; } = 1; - public bool HyperDash { get; set; } + /// + /// Whether this fruit can initiate a hyperdash. + /// + public bool HyperDash => HyperDashTarget != null; + + /// + /// The target fruit if we are to initiate a hyperdash. + /// + public CatchHitObject HyperDashTarget; public override void ApplyDefaults(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) { diff --git a/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs b/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs index 3cfdcafc48..76dbfa77c6 100644 --- a/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs +++ b/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs @@ -51,7 +51,7 @@ namespace osu.Game.Rulesets.Catch.UI }; } - public bool CheckIfWeCanCatch(CatchHitObject obj) => catcherArea.CanCatch(obj); + public bool CheckIfWeCanCatch(CatchHitObject obj) => catcherArea.AttemptCatch(obj); public override void Add(DrawableHitObject h) { diff --git a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs index 203db1bb8c..2785647cbd 100644 --- a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs +++ b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs @@ -14,6 +14,7 @@ using osu.Game.Beatmaps; using osu.Game.Rulesets.Catch.Objects; using osu.Game.Rulesets.Objects.Drawables; using OpenTK; +using OpenTK.Graphics; namespace osu.Game.Rulesets.Catch.UI { @@ -51,7 +52,7 @@ namespace osu.Game.Rulesets.Catch.UI catcher.Add(fruit); } - public bool CanCatch(CatchHitObject obj) => Math.Abs(catcher.Position.X - obj.X) < catcher.DrawSize.X * Math.Abs(catcher.Scale.X) / DrawSize.X / 2; + public bool AttemptCatch(CatchHitObject obj) => catcher.AttemptCatch(obj); public class Catcher : Container, IKeyBindingHandler { @@ -105,14 +106,35 @@ namespace osu.Game.Rulesets.Catch.UI dashing = value; - if (dashing) - Schedule(addAdditiveSprite); + Trail |= dashing; } } - private void addAdditiveSprite() + private bool trail; + + /// + /// Activate or deactive the trail. Will be automatically deactivated when conditions to keep the trail displayed are no longer met. + /// + protected bool Trail { - if (!dashing || AdditiveTarget == null) return; + get { return trail; } + set + { + if (value == trail) return; + + trail = value; + + if (Trail) + beginTrail(); + } + } + + private void beginTrail() + { + Trail &= dashing || HyperDashing; + Trail &= AdditiveTarget != null; + + if (!Trail) return; var additive = createCatcherSprite(); @@ -120,6 +142,7 @@ namespace osu.Game.Rulesets.Catch.UI additive.OriginPosition = additive.OriginPosition + new Vector2(DrawWidth / 2, 0); // also temporary to align sprite correctly. additive.Position = Position; additive.Scale = Scale; + additive.Colour = HyperDashing ? Color4.Red : Color4.White; additive.RelativePositionAxes = RelativePositionAxes; additive.Blending = BlendingMode.Additive; @@ -127,7 +150,7 @@ namespace osu.Game.Rulesets.Catch.UI additive.FadeTo(0.4f).FadeOut(800, Easing.OutQuint).Expire(); - Scheduler.AddDelayed(addAdditiveSprite, 50); + Scheduler.AddDelayed(beginTrail, HyperDashing ? 25 : 50); } private Sprite createCatcherSprite() => new Sprite @@ -138,6 +161,10 @@ namespace osu.Game.Rulesets.Catch.UI OriginPosition = new Vector2(-3, 10) // temporary until the sprite is aligned correctly. }; + /// + /// Add a caught fruit to the catcher's stack. + /// + /// The fruit that was caught. public void Add(DrawableHitObject fruit) { float distance = fruit.DrawSize.X / 2 * fruit.Scale.X; @@ -150,8 +177,35 @@ namespace osu.Game.Rulesets.Catch.UI caughtFruit.Add(fruit); - if (((CatchHitObject)fruit.HitObject).LastInCombo) + var catchObject = (CatchHitObject)fruit.HitObject; + + if (catchObject.LastInCombo) explode(); + + updateHyperDashState(catchObject, true); + } + + /// + /// Let the catcher attempt to catch a fruit. + /// + /// The fruit to catch. + /// Whether the catch is possible. + public bool AttemptCatch(CatchHitObject fruit) + { + const double relative_catcher_width = CATCHER_SIZE / 2; + + // this stuff wil disappear once we move fruit to non-relative coordinate space in the future. + var catchObjectPosition = fruit.X * CatchPlayfield.BASE_WIDTH; + var catcherPosition = Position.X * CatchPlayfield.BASE_WIDTH; + + var validCatch = + catchObjectPosition >= catcherPosition - relative_catcher_width / 2 && + catchObjectPosition <= catcherPosition + relative_catcher_width / 2; + + // if we are hypderdashing in teh next hit is not, let's change our state here (it's our only opportunity to handle missed fruit currently). + updateHyperDashState(fruit, false); + + return validCatch; } public bool OnPressed(CatchAction action) @@ -203,10 +257,46 @@ namespace osu.Game.Rulesets.Catch.UI double dashModifier = Dashing ? 1 : 0.5; + if (hyperDashModifier != 1) + dashModifier = hyperDashModifier; + Scale = new Vector2(Math.Abs(Scale.X) * Math.Sign(currentDirection), Scale.Y); X = (float)MathHelper.Clamp(X + Math.Sign(currentDirection) * Clock.ElapsedFrameTime * BASE_SPEED * dashModifier, 0, 1); } + /// + /// Whether we are hypderdashing or not. + /// + protected bool HyperDashing => hyperDashModifier != 1; + + private double hyperDashModifier = 1; + + /// + /// Update whether we are hyper or not. + /// + /// The fruit to use as a condition for deciding our new state. + /// Whether to allow entering hyperdash or not. If false, we will only exit if required, but never enter. + private void updateHyperDashState(CatchHitObject fruit, bool allowBegin) + { + const float transition_length = 180; + + if (!fruit.HyperDash) + { + hyperDashModifier = 1; + this.FadeColour(Color4.White, transition_length, Easing.OutQuint); + this.FadeTo(1, transition_length, Easing.OutQuint); + return; + } + + if (allowBegin) + { + hyperDashModifier = Math.Abs(fruit.HyperDashTarget.X - fruit.X) / Math.Abs(fruit.HyperDashTarget.StartTime - fruit.StartTime) / BASE_SPEED; + this.FadeColour(Color4.AliceBlue, transition_length, Easing.OutQuint); + this.FadeTo(0.5f, transition_length, Easing.OutQuint); + Trail = true; + } + } + private void explode() { var fruit = caughtFruit.ToArray(); From 07081f400cfcc68846d64f268880d5994b1763cb Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 1 Dec 2017 19:33:20 +0900 Subject: [PATCH 0950/1263] Make hyperdash testcase easier to win --- osu.Game.Rulesets.Catch/Tests/TestCaseHyperdash.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Catch/Tests/TestCaseHyperdash.cs b/osu.Game.Rulesets.Catch/Tests/TestCaseHyperdash.cs index 5b0e1fb93c..a39c727a61 100644 --- a/osu.Game.Rulesets.Catch/Tests/TestCaseHyperdash.cs +++ b/osu.Game.Rulesets.Catch/Tests/TestCaseHyperdash.cs @@ -18,7 +18,7 @@ namespace osu.Game.Rulesets.Catch.Tests var beatmap = new Beatmap(); for (int i = 0; i < 512; i++) - beatmap.HitObjects.Add(new Fruit { X = 0.5f + (i % 8 < 4 ? -0.4f : 0.4f), StartTime = i * 100, NewCombo = i % 8 == 0 }); + beatmap.HitObjects.Add(new Fruit { X = i % 8 < 4 ? 0.02f : 0.98f, StartTime = i * 100, NewCombo = i % 8 == 0 }); return beatmap; } From 445bb70ef5b2d70a9c1552d72d4b5439209a3d4d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 1 Dec 2017 19:58:00 +0900 Subject: [PATCH 0951/1263] Add hyperdash visual testing to TestCaseCatcherArea Also tidies up hyperdash state logic --- .../Tests/TestCaseCatcherArea.cs | 14 +++- osu.Game.Rulesets.Catch/UI/CatcherArea.cs | 84 +++++++++---------- 2 files changed, 54 insertions(+), 44 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Tests/TestCaseCatcherArea.cs b/osu.Game.Rulesets.Catch/Tests/TestCaseCatcherArea.cs index 538f6930ed..daa3e12800 100644 --- a/osu.Game.Rulesets.Catch/Tests/TestCaseCatcherArea.cs +++ b/osu.Game.Rulesets.Catch/Tests/TestCaseCatcherArea.cs @@ -17,6 +17,7 @@ namespace osu.Game.Rulesets.Catch.Tests internal class TestCaseCatcherArea : OsuTestCase { private RulesetInfo catchRuleset; + private TestCatcherArea catcherArea; public override IReadOnlyList RequiredTypes => new[] { @@ -26,6 +27,7 @@ namespace osu.Game.Rulesets.Catch.Tests public TestCaseCatcherArea() { AddSliderStep("CircleSize", 0, 8, 5, createCatcher); + AddToggleStep("Hyperdash", t => catcherArea.ToggleHyperDash(t)); } private void createCatcher(float size) @@ -33,7 +35,7 @@ namespace osu.Game.Rulesets.Catch.Tests Child = new CatchInputManager(catchRuleset) { RelativeSizeAxes = Axes.Both, - Child = new CatcherArea(new BeatmapDifficulty { CircleSize = size }) + Child = catcherArea = new TestCatcherArea(new BeatmapDifficulty { CircleSize = size }) { Anchor = Anchor.CentreLeft, Origin = Anchor.BottomLeft @@ -46,5 +48,15 @@ namespace osu.Game.Rulesets.Catch.Tests { catchRuleset = rulesets.GetRuleset(2); } + + private class TestCatcherArea : CatcherArea + { + public TestCatcherArea(BeatmapDifficulty beatmapDifficulty) + : base(beatmapDifficulty) + { + } + + public void ToggleHyperDash(bool status) => MovableCatcher.HyperDashModifier = status ? 2 : 1; + } } } diff --git a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs index 2785647cbd..52f06d4396 100644 --- a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs +++ b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs @@ -22,18 +22,18 @@ namespace osu.Game.Rulesets.Catch.UI { public const float CATCHER_SIZE = 172; - private readonly Catcher catcher; + protected readonly Catcher MovableCatcher; public Container ExplodingFruitTarget { - set { catcher.ExplodingFruitTarget = value; } + set { MovableCatcher.ExplodingFruitTarget = value; } } public CatcherArea(BeatmapDifficulty difficulty = null) { RelativeSizeAxes = Axes.X; Height = CATCHER_SIZE; - Child = catcher = new Catcher(difficulty) + Child = MovableCatcher = new Catcher(difficulty) { AdditiveTarget = this, }; @@ -42,17 +42,17 @@ namespace osu.Game.Rulesets.Catch.UI public void Add(DrawableHitObject fruit, Vector2 absolutePosition) { fruit.RelativePositionAxes = Axes.None; - fruit.Position = new Vector2(catcher.ToLocalSpace(absolutePosition).X - catcher.DrawSize.X / 2, 0); + fruit.Position = new Vector2(MovableCatcher.ToLocalSpace(absolutePosition).X - MovableCatcher.DrawSize.X / 2, 0); fruit.Anchor = Anchor.TopCentre; fruit.Origin = Anchor.BottomCentre; fruit.Scale *= 0.7f; fruit.LifetimeEnd = double.MaxValue; - catcher.Add(fruit); + MovableCatcher.Add(fruit); } - public bool AttemptCatch(CatchHitObject obj) => catcher.AttemptCatch(obj); + public bool AttemptCatch(CatchHitObject obj) => MovableCatcher.AttemptCatch(obj); public class Catcher : Container, IKeyBindingHandler { @@ -181,8 +181,6 @@ namespace osu.Game.Rulesets.Catch.UI if (catchObject.LastInCombo) explode(); - - updateHyperDashState(catchObject, true); } /// @@ -202,12 +200,45 @@ namespace osu.Game.Rulesets.Catch.UI catchObjectPosition >= catcherPosition - relative_catcher_width / 2 && catchObjectPosition <= catcherPosition + relative_catcher_width / 2; - // if we are hypderdashing in teh next hit is not, let's change our state here (it's our only opportunity to handle missed fruit currently). - updateHyperDashState(fruit, false); + if (validCatch && fruit.HyperDash) + HyperDashModifier = Math.Abs(fruit.HyperDashTarget.X - fruit.X) / Math.Abs(fruit.HyperDashTarget.StartTime - fruit.StartTime) / BASE_SPEED; + else + HyperDashModifier = 1; return validCatch; } + /// + /// Whether we are hypderdashing or not. + /// + public bool HyperDashing => hyperDashModifier != 1; + + private double hyperDashModifier = 1; + + public double HyperDashModifier + { + get { return hyperDashModifier; } + set + { + if (value == hyperDashModifier) return; + hyperDashModifier = value; + + const float transition_length = 180; + + if (HyperDashing) + { + this.FadeColour(Color4.Yellow, transition_length, Easing.OutQuint); + this.FadeTo(0.2f, transition_length, Easing.OutQuint); + Trail = true; + } + else + { + this.FadeColour(Color4.White, transition_length, Easing.OutQuint); + this.FadeTo(1, transition_length, Easing.OutQuint); + } + } + } + public bool OnPressed(CatchAction action) { switch (action) @@ -264,39 +295,6 @@ namespace osu.Game.Rulesets.Catch.UI X = (float)MathHelper.Clamp(X + Math.Sign(currentDirection) * Clock.ElapsedFrameTime * BASE_SPEED * dashModifier, 0, 1); } - /// - /// Whether we are hypderdashing or not. - /// - protected bool HyperDashing => hyperDashModifier != 1; - - private double hyperDashModifier = 1; - - /// - /// Update whether we are hyper or not. - /// - /// The fruit to use as a condition for deciding our new state. - /// Whether to allow entering hyperdash or not. If false, we will only exit if required, but never enter. - private void updateHyperDashState(CatchHitObject fruit, bool allowBegin) - { - const float transition_length = 180; - - if (!fruit.HyperDash) - { - hyperDashModifier = 1; - this.FadeColour(Color4.White, transition_length, Easing.OutQuint); - this.FadeTo(1, transition_length, Easing.OutQuint); - return; - } - - if (allowBegin) - { - hyperDashModifier = Math.Abs(fruit.HyperDashTarget.X - fruit.X) / Math.Abs(fruit.HyperDashTarget.StartTime - fruit.StartTime) / BASE_SPEED; - this.FadeColour(Color4.AliceBlue, transition_length, Easing.OutQuint); - this.FadeTo(0.5f, transition_length, Easing.OutQuint); - Trail = true; - } - } - private void explode() { var fruit = caughtFruit.ToArray(); From 25207c51b5ed04bf50c38f94527d4448d41506aa Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 1 Dec 2017 20:07:28 +0900 Subject: [PATCH 0952/1263] Add directionality --- osu.Game.Rulesets.Catch/UI/CatcherArea.cs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs index 52f06d4396..265f19c744 100644 --- a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs +++ b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs @@ -201,7 +201,10 @@ namespace osu.Game.Rulesets.Catch.UI catchObjectPosition <= catcherPosition + relative_catcher_width / 2; if (validCatch && fruit.HyperDash) + { HyperDashModifier = Math.Abs(fruit.HyperDashTarget.X - fruit.X) / Math.Abs(fruit.HyperDashTarget.StartTime - fruit.StartTime) / BASE_SPEED; + HyperDashDirection = fruit.HyperDashTarget.X - fruit.X; + } else HyperDashModifier = 1; @@ -215,6 +218,8 @@ namespace osu.Game.Rulesets.Catch.UI private double hyperDashModifier = 1; + public double HyperDashDirection; + public double HyperDashModifier { get { return hyperDashModifier; } @@ -233,6 +238,7 @@ namespace osu.Game.Rulesets.Catch.UI } else { + HyperDashDirection = 0; this.FadeColour(Color4.White, transition_length, Easing.OutQuint); this.FadeTo(1, transition_length, Easing.OutQuint); } @@ -286,13 +292,15 @@ namespace osu.Game.Rulesets.Catch.UI if (currentDirection == 0) return; + var direction = Math.Sign(currentDirection); + double dashModifier = Dashing ? 1 : 0.5; - if (hyperDashModifier != 1) + if (hyperDashModifier != 1 && (HyperDashDirection == 0 || direction == Math.Sign(HyperDashDirection))) dashModifier = hyperDashModifier; - Scale = new Vector2(Math.Abs(Scale.X) * Math.Sign(currentDirection), Scale.Y); - X = (float)MathHelper.Clamp(X + Math.Sign(currentDirection) * Clock.ElapsedFrameTime * BASE_SPEED * dashModifier, 0, 1); + Scale = new Vector2(Math.Abs(Scale.X) * direction, Scale.Y); + X = (float)MathHelper.Clamp(X + direction * Clock.ElapsedFrameTime * BASE_SPEED * dashModifier, 0, 1); } private void explode() From 273793f1852d5ee0792c39bcbb1414f5806c428e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 1 Dec 2017 20:08:49 +0900 Subject: [PATCH 0953/1263] Add comments --- osu.Game.Rulesets.Catch/UI/CatcherArea.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs index 265f19c744..984aaf98ee 100644 --- a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs +++ b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs @@ -218,8 +218,14 @@ namespace osu.Game.Rulesets.Catch.UI private double hyperDashModifier = 1; + /// + /// The direction in which hyperdash is allowed. 0 allows both directions. + /// public double HyperDashDirection; + /// + /// The speed modifier resultant from hyperdash. Will trigger hyperdash when not equal to 1. + /// public double HyperDashModifier { get { return hyperDashModifier; } From bf606522c1c3cd33ec90d70d1290fbfd5114d3aa Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 1 Dec 2017 20:13:32 +0900 Subject: [PATCH 0954/1263] Make hyperdash testcase easier to win again --- osu.Game.Rulesets.Catch/Tests/TestCaseHyperdash.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Catch/Tests/TestCaseHyperdash.cs b/osu.Game.Rulesets.Catch/Tests/TestCaseHyperdash.cs index a39c727a61..a0eb5f0054 100644 --- a/osu.Game.Rulesets.Catch/Tests/TestCaseHyperdash.cs +++ b/osu.Game.Rulesets.Catch/Tests/TestCaseHyperdash.cs @@ -18,7 +18,8 @@ namespace osu.Game.Rulesets.Catch.Tests var beatmap = new Beatmap(); for (int i = 0; i < 512; i++) - beatmap.HitObjects.Add(new Fruit { X = i % 8 < 4 ? 0.02f : 0.98f, StartTime = i * 100, NewCombo = i % 8 == 0 }); + if (i % 5 < 3) + beatmap.HitObjects.Add(new Fruit { X = i % 10 < 5 ? 0.02f : 0.98f, StartTime = i * 100, NewCombo = i % 8 == 0 }); return beatmap; } From e75d73ac1cb8b86ee16d679a59b80e8b98999a2d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 1 Dec 2017 20:13:46 +0900 Subject: [PATCH 0955/1263] Change hyperdash colour again --- osu.Game.Rulesets.Catch/UI/CatcherArea.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs index 984aaf98ee..2bb0f3cd18 100644 --- a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs +++ b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs @@ -238,7 +238,7 @@ namespace osu.Game.Rulesets.Catch.UI if (HyperDashing) { - this.FadeColour(Color4.Yellow, transition_length, Easing.OutQuint); + this.FadeColour(Color4.OrangeRed, transition_length, Easing.OutQuint); this.FadeTo(0.2f, transition_length, Easing.OutQuint); Trail = true; } From 79e1bf3394f696df2c88742bb0943d3b01051125 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 1 Dec 2017 20:14:42 +0900 Subject: [PATCH 0956/1263] Remove unused testcase --- .../Tests/TestCaseFruit.cs | 36 ------------------- .../osu.Game.Rulesets.Catch.csproj | 1 - 2 files changed, 37 deletions(-) delete mode 100644 osu.Game.Rulesets.Catch/Tests/TestCaseFruit.cs diff --git a/osu.Game.Rulesets.Catch/Tests/TestCaseFruit.cs b/osu.Game.Rulesets.Catch/Tests/TestCaseFruit.cs deleted file mode 100644 index 0ced95edf9..0000000000 --- a/osu.Game.Rulesets.Catch/Tests/TestCaseFruit.cs +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (c) 2007-2017 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE - -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Game.Rulesets.Catch.Objects; -using osu.Game.Rulesets.Catch.Objects.Drawable; -using osu.Game.Tests.Visual; -using OpenTK; - -namespace osu.Game.Rulesets.Catch.Tests -{ - public class TestCaseFruit : OsuTestCase - { - public TestCaseFruit() - { - Add(new GridContainer - { - RelativeSizeAxes = Axes.Both, - Content = new[] - { - new Drawable[] - { - new DrawableFruit(new Fruit()) { Position = new Vector2(0.5f) }, - new DrawableFruit(new Fruit()) { Position = new Vector2(0.5f) }, - }, - new Drawable[] - { - new DrawableFruit(new Fruit()) { Position = new Vector2(0.5f) }, - new DrawableFruit(new Fruit()) { Position = new Vector2(0.5f) }, - } - } - }); - } - } -} diff --git a/osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj b/osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj index 4e819fb58b..264f5c41be 100644 --- a/osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj +++ b/osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj @@ -67,7 +67,6 @@ - From 997cdfaee42ebb67e15bc0bcbe1162c89b0bbe6c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 1 Dec 2017 20:31:54 +0900 Subject: [PATCH 0957/1263] Add missing licence header --- osu.Game.Rulesets.Catch/Tests/TestCaseHyperdash.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Catch/Tests/TestCaseHyperdash.cs b/osu.Game.Rulesets.Catch/Tests/TestCaseHyperdash.cs index a0eb5f0054..ce3f79bae2 100644 --- a/osu.Game.Rulesets.Catch/Tests/TestCaseHyperdash.cs +++ b/osu.Game.Rulesets.Catch/Tests/TestCaseHyperdash.cs @@ -1,4 +1,7 @@ -using NUnit.Framework; +// 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.Game.Beatmaps; using osu.Game.Rulesets.Catch.Objects; From 8c3ae9430b53273b95f258279560b6396d9a7b41 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 1 Dec 2017 20:39:58 +0900 Subject: [PATCH 0958/1263] Add difficulty scaling considerations to hyperdash initialisation --- .../Beatmaps/CatchBeatmapProcessor.cs | 29 ++++++++++--------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs index e12d7f3fd3..9901dbde18 100644 --- a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs +++ b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Linq; using osu.Game.Beatmaps; using osu.Game.Rulesets.Catch.Objects; using osu.Game.Rulesets.Catch.UI; @@ -23,7 +24,7 @@ namespace osu.Game.Rulesets.Catch.Beatmaps CatchHitObject lastObj = null; - convertHyperDash(beatmap.HitObjects); + initialiseHyperDash(beatmap.HitObjects); foreach (var obj in beatmap.HitObjects) { @@ -42,14 +43,13 @@ namespace osu.Game.Rulesets.Catch.Beatmaps } } - private void convertHyperDash(List objects) + private void initialiseHyperDash(List objects) { // todo: add difficulty adjust. - const double catcher_width = CatcherArea.CATCHER_SIZE / CatchPlayfield.BASE_WIDTH; - const double catcher_width_half = catcher_width / 2; + double halfCatcherWidth = CatcherArea.CATCHER_SIZE * (objects.FirstOrDefault()?.Scale ?? 1) / CatchPlayfield.BASE_WIDTH / 2; int lastDirection = 0; - double lastExcess = catcher_width_half; + double lastExcess = halfCatcherWidth; int objCount = objects.Count; @@ -58,28 +58,29 @@ namespace osu.Game.Rulesets.Catch.Beatmaps CatchHitObject currentObject = objects[i]; // not needed? - if (currentObject is TinyDroplet) continue; + // if (currentObject is TinyDroplet) continue; CatchHitObject nextObject = objects[i + 1]; - while (nextObject is TinyDroplet) - { - if (++i == objCount - 1) break; - nextObject = objects[i + 1]; - } + + // while (nextObject is TinyDroplet) + // { + // if (++i == objCount - 1) break; + // nextObject = objects[i + 1]; + // } int thisDirection = nextObject.X > currentObject.X ? 1 : -1; double timeToNext = nextObject.StartTime - ((currentObject as IHasEndTime)?.EndTime ?? currentObject.StartTime) - 4; - double distanceToNext = Math.Abs(nextObject.X - currentObject.X) - (lastDirection == thisDirection ? lastExcess : catcher_width_half); + double distanceToNext = Math.Abs(nextObject.X - currentObject.X) - (lastDirection == thisDirection ? lastExcess : halfCatcherWidth); if (timeToNext * CatcherArea.Catcher.BASE_SPEED < distanceToNext) { currentObject.HyperDashTarget = nextObject; - lastExcess = catcher_width_half; + lastExcess = halfCatcherWidth; } else { //currentObject.DistanceToHyperDash = timeToNext - distanceToNext; - lastExcess = MathHelper.Clamp(timeToNext - distanceToNext, 0, catcher_width_half); + lastExcess = MathHelper.Clamp(timeToNext - distanceToNext, 0, halfCatcherWidth); } lastDirection = thisDirection; From 75327959356327ec3599a4348c0b3099b9e625ae Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 1 Dec 2017 22:43:49 +0900 Subject: [PATCH 0959/1263] Lock during validity checks --- osu.Game/Beatmaps/WorkingBeatmap.cs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/osu.Game/Beatmaps/WorkingBeatmap.cs b/osu.Game/Beatmaps/WorkingBeatmap.cs index 93ba51367a..8c96074352 100644 --- a/osu.Game/Beatmaps/WorkingBeatmap.cs +++ b/osu.Game/Beatmaps/WorkingBeatmap.cs @@ -121,6 +121,8 @@ namespace osu.Game.Beatmaps private readonly Func valueFactory; private readonly Func stillValidFunction; + private readonly object initLock = new object(); + public AsyncLazy(Func valueFactory, Func stillValidFunction = null) { this.valueFactory = valueFactory; @@ -134,7 +136,6 @@ namespace osu.Game.Beatmaps if (!IsValueCreated) return; (lazy.Value.Result as IDisposable)?.Dispose(); - init(); } @@ -158,9 +159,11 @@ namespace osu.Game.Beatmaps private void ensureValid() { - if (!lazy.IsValueCreated || (stillValidFunction?.Invoke(lazy.Value.Result) ?? true)) return; - - init(); + lock (initLock) + { + if (!lazy.IsValueCreated || (stillValidFunction?.Invoke(lazy.Value.Result) ?? true)) return; + init(); + } } private void init() From ee75f90ab33545e51ab8a919b88a3a000eb60ae5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 1 Dec 2017 22:44:25 +0900 Subject: [PATCH 0960/1263] Update framework --- osu-framework | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu-framework b/osu-framework index 87d68cda00..cc013fc406 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit 87d68cda0015d51dc3da56d2322fa10d399fc4ed +Subproject commit cc013fc4063dda0843f38c1c73568a413abcf229 From cf859a6cf2449896e38e5acd431176e2d20d8192 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Sat, 2 Dec 2017 00:26:02 +0900 Subject: [PATCH 0961/1263] Make the dragger attach to objects it surrounds Plus a lot more implementation. --- osu-framework | 2 +- .../Objects/Drawables/DrawableSlider.cs | 4 ++ .../Objects/Drawables/Pieces/SliderBody.cs | 5 +- .../Visual/TestCaseEditorCompose.cs | 2 + .../Visual/TestCaseEditorPlayfieldOverlay.cs | 54 +++++++++++++++ osu.Game.Tests/osu.Game.Tests.csproj | 1 + osu.Game/Rulesets/Edit/HitObjectComposer.cs | 6 +- osu.Game/Rulesets/Edit/PlayfieldOverlay.cs | 68 +++++++++++++++++-- osu.Game/Rulesets/Edit/SelectionDragger.cs | 12 ++++ .../Objects/Drawables/DrawableHitObject.cs | 12 ++++ osu.Game/Rulesets/UI/RulesetContainer.cs | 17 ++--- osu.Game/osu.Game.csproj | 2 + 12 files changed, 167 insertions(+), 18 deletions(-) create mode 100644 osu.Game.Tests/Visual/TestCaseEditorPlayfieldOverlay.cs create mode 100644 osu.Game/Rulesets/Edit/SelectionDragger.cs diff --git a/osu-framework b/osu-framework index 4fc866eee3..d231ca9f79 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit 4fc866eee3803f88b155150e32e021b9c21e647f +Subproject commit d231ca9f79936f3a7f3cff0c7721587755ae168c diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs index 74454ca555..7e6892e70b 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs @@ -9,6 +9,7 @@ using System.Collections.Generic; using System.Linq; using osu.Framework.Graphics.Containers; using osu.Game.Rulesets.Osu.Judgements; +using osu.Framework.Graphics.Primitives; namespace osu.Game.Rulesets.Osu.Objects.Drawables { @@ -165,6 +166,9 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables } public Drawable ProxiedLayer => initialCircle.ApproachCircle; + + public override Vector2 SelectionPoint => body.Position; + public override Quad SelectionQuad => body.PathDrawQuad; } internal interface ISliderProgress diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBody.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBody.cs index 2082e9a27b..75c2c15084 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBody.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBody.cs @@ -14,6 +14,7 @@ using osu.Game.Configuration; using OpenTK; using OpenTK.Graphics.ES30; using OpenTK.Graphics; +using osu.Framework.Graphics.Primitives; namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces { @@ -49,6 +50,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces } } + public Quad PathDrawQuad => container.ScreenSpaceDrawQuad; + private int textureWidth => (int)PathWidth * 2; private readonly Slider slider; @@ -182,4 +185,4 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces SetRange(start, end); } } -} \ No newline at end of file +} diff --git a/osu.Game.Tests/Visual/TestCaseEditorCompose.cs b/osu.Game.Tests/Visual/TestCaseEditorCompose.cs index d52f27f4ab..226329a852 100644 --- a/osu.Game.Tests/Visual/TestCaseEditorCompose.cs +++ b/osu.Game.Tests/Visual/TestCaseEditorCompose.cs @@ -2,8 +2,10 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; +using System.Collections.Generic; using osu.Framework.Allocation; using osu.Game.Beatmaps; +using osu.Game.Rulesets.Edit; using osu.Game.Screens.Edit.Screens.Compose; namespace osu.Game.Tests.Visual diff --git a/osu.Game.Tests/Visual/TestCaseEditorPlayfieldOverlay.cs b/osu.Game.Tests/Visual/TestCaseEditorPlayfieldOverlay.cs new file mode 100644 index 0000000000..f0da23955d --- /dev/null +++ b/osu.Game.Tests/Visual/TestCaseEditorPlayfieldOverlay.cs @@ -0,0 +1,54 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using System.Collections.Generic; +using OpenTK; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Timing; +using osu.Game.Rulesets.Edit; +using osu.Game.Rulesets.Objects.Types; +using osu.Game.Rulesets.Osu.Edit; +using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Rulesets.Osu.Objects.Drawables; +using osu.Game.Rulesets.Osu.UI; + +namespace osu.Game.Tests.Visual +{ + public class TestCaseEditorPlayfieldOverlay : OsuTestCase + { + public override IReadOnlyList RequiredTypes => new[] { typeof(PlayfieldOverlay) }; + + public TestCaseEditorPlayfieldOverlay() + { + var playfield = new OsuEditPlayfield(); + playfield.Add(new DrawableHitCircle(new HitCircle { Position = new Vector2(256, 192), Scale = 0.5f })); + playfield.Add(new DrawableHitCircle(new HitCircle { Position = new Vector2(344, 148), Scale = 0.5f })); + playfield.Add(new DrawableSlider(new Slider + { + ControlPoints = new List + { + new Vector2(128, 256), + new Vector2(344, 256), + }, + Distance = 400, + Position = new Vector2(128, 256), + Velocity = 1, + TickDistance = 100, + Scale = 0.5f + })); + + Children = new Drawable[] + { + new Container + { + RelativeSizeAxes = Axes.Both, + Clock = new FramedClock(new StopwatchClock()), + Child = playfield + }, + new PlayfieldOverlay(playfield) + }; + } + } +} diff --git a/osu.Game.Tests/osu.Game.Tests.csproj b/osu.Game.Tests/osu.Game.Tests.csproj index ae88fb004f..b8dce4e4f6 100644 --- a/osu.Game.Tests/osu.Game.Tests.csproj +++ b/osu.Game.Tests/osu.Game.Tests.csproj @@ -110,6 +110,7 @@ + diff --git a/osu.Game/Rulesets/Edit/HitObjectComposer.cs b/osu.Game/Rulesets/Edit/HitObjectComposer.cs index f55b7b0531..41958df29b 100644 --- a/osu.Game/Rulesets/Edit/HitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/HitObjectComposer.cs @@ -77,7 +77,7 @@ namespace osu.Game.Rulesets.Edit Alpha = 0, AlwaysPresent = true, }, - CreateUnderlay(rulesetContainer.Playfield), + CreateUnderlay(), rulesetContainer, CreateOverlay(rulesetContainer.Playfield) } @@ -106,9 +106,9 @@ namespace osu.Game.Rulesets.Edit protected virtual RulesetContainer CreateRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap) => ruleset.CreateRulesetContainerWith(beatmap, true); - protected virtual PlayfieldUnderlay CreateUnderlay(Playfield playfield) => new PlayfieldUnderlay(); + protected virtual PlayfieldUnderlay CreateUnderlay() => new PlayfieldUnderlay(); - protected virtual PlayfieldOverlay CreateOverlay(Playfield playfield) => new PlayfieldOverlay(); + protected virtual PlayfieldOverlay CreateOverlay(Playfield playfield) => new PlayfieldOverlay(playfield); protected abstract IReadOnlyList CompositionTools { get; } } diff --git a/osu.Game/Rulesets/Edit/PlayfieldOverlay.cs b/osu.Game/Rulesets/Edit/PlayfieldOverlay.cs index 77aeed42e3..98b3bce265 100644 --- a/osu.Game/Rulesets/Edit/PlayfieldOverlay.cs +++ b/osu.Game/Rulesets/Edit/PlayfieldOverlay.cs @@ -9,15 +9,27 @@ using osu.Framework.Graphics.Shapes; using osu.Framework.Input; using OpenTK; using OpenTK.Graphics; +using System.Collections.Generic; +using osu.Game.Rulesets.Objects.Drawables; +using osu.Game.Rulesets.UI; +using System.Linq; +using osu.Game.Graphics; namespace osu.Game.Rulesets.Edit { public class PlayfieldOverlay : CompositeDrawable { - private readonly Drawable dragBox; + private readonly static Color4 selection_normal_colour = Color4.White; + private readonly static Color4 selection_attached_colour = OsuColour.FromHex("eeaa00"); - public PlayfieldOverlay() + private readonly Container dragBox; + + private readonly Playfield playfield; + + public PlayfieldOverlay(Playfield playfield) { + this.playfield = playfield; + RelativeSizeAxes = Axes.Both; InternalChildren = new[] @@ -31,25 +43,31 @@ namespace osu.Game.Rulesets.Edit Child = new Box { RelativeSizeAxes = Axes.Both, - Alpha = 0, - AlwaysPresent = true + Alpha = 0.1f } } }; } private Vector2 dragStartPos; + private RectangleF dragRectangle; + private List capturedHitObjects = new List(); protected override bool OnDragStart(InputState state) { dragStartPos = ToLocalSpace(state.Mouse.NativeState.Position); + dragBox.Position = dragStartPos; + dragBox.Size = Vector2.Zero; + dragBox.FadeTo(1); + dragBox.FadeColour(selection_normal_colour); + dragBox.BorderThickness = 2; return true; } protected override bool OnDrag(InputState state) { var dragPos = ToLocalSpace(state.Mouse.NativeState.Position); - var dragRectangle = RectangleF.FromLTRB( + dragRectangle = RectangleF.FromLTRB( Math.Min(dragStartPos.X, dragPos.X), Math.Min(dragStartPos.Y, dragPos.Y), Math.Max(dragStartPos.X, dragPos.X), @@ -58,11 +76,51 @@ namespace osu.Game.Rulesets.Edit dragBox.Position = dragRectangle.Location; dragBox.Size = dragRectangle.Size; + updateCapturedHitObjects(); + return true; } + private void updateCapturedHitObjects() + { + capturedHitObjects.Clear(); + + foreach (var obj in playfield.HitObjects.Objects) + { + if (!obj.IsAlive || !obj.IsPresent) + continue; + + var objectPosition = obj.Parent.ToScreenSpace(obj.SelectionPoint); + if (dragRectangle.Contains(ToLocalSpace(objectPosition))) + capturedHitObjects.Add(obj); + } + } + protected override bool OnDragEnd(InputState state) { + if (capturedHitObjects.Count == 0) + dragBox.FadeOut(400, Easing.OutQuint); + else + { + // Move the rectangle to cover the hitobjects + var topLeft = new Vector2(float.MaxValue, float.MaxValue); + var bottomRight = new Vector2(float.MinValue, float.MinValue); + + foreach (var obj in capturedHitObjects) + { + topLeft = Vector2.ComponentMin(topLeft, ToLocalSpace(obj.SelectionQuad.TopLeft)); + bottomRight = Vector2.ComponentMax(bottomRight, ToLocalSpace(obj.SelectionQuad.BottomRight)); + } + + topLeft -= new Vector2(5); + bottomRight += new Vector2(5); + + dragBox.MoveTo(topLeft, 200, Easing.OutQuint) + .ResizeTo(bottomRight - topLeft, 200, Easing.OutQuint) + .FadeColour(selection_attached_colour, 200, Easing.OutQuint); + dragBox.BorderThickness = 3; + } + return true; } } diff --git a/osu.Game/Rulesets/Edit/SelectionDragger.cs b/osu.Game/Rulesets/Edit/SelectionDragger.cs new file mode 100644 index 0000000000..35ea3a375e --- /dev/null +++ b/osu.Game/Rulesets/Edit/SelectionDragger.cs @@ -0,0 +1,12 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Graphics.Containers; + +namespace osu.Game.Rulesets.Edit +{ + public class SelectionDragger : CompositeDrawable + { + + } +} diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index 941cedca3f..9eecb9b4f5 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -14,6 +14,8 @@ using osu.Game.Audio; using System.Linq; using osu.Game.Graphics; using osu.Framework.Configuration; +using OpenTK; +using osu.Framework.Graphics.Primitives; namespace osu.Game.Rulesets.Objects.Drawables { @@ -38,6 +40,16 @@ namespace osu.Game.Rulesets.Objects.Drawables { HitObject = hitObject; } + + /// + /// The local point that causes this to be selected in the Editor. + /// + public virtual Vector2 SelectionPoint => DrawPosition; + + /// + /// The local rectangle that outlines this for selections in the Editor. + /// + public virtual Quad SelectionQuad => ScreenSpaceDrawQuad; } public abstract class DrawableHitObject : DrawableHitObject diff --git a/osu.Game/Rulesets/UI/RulesetContainer.cs b/osu.Game/Rulesets/UI/RulesetContainer.cs index 69bf6bba29..5b4565e8a8 100644 --- a/osu.Game/Rulesets/UI/RulesetContainer.cs +++ b/osu.Game/Rulesets/UI/RulesetContainer.cs @@ -55,10 +55,11 @@ namespace osu.Game.Rulesets.UI public abstract IEnumerable Objects { get; } + private Playfield playfield; /// /// The playfield. /// - public Playfield Playfield { get; protected set; } + public Playfield Playfield => playfield ?? (playfield = CreatePlayfield()); protected readonly Ruleset Ruleset; @@ -95,6 +96,12 @@ namespace osu.Game.Rulesets.UI Replay = replay; ReplayInputManager.ReplayInputHandler = replay != null ? CreateReplayInputHandler(replay) : null; } + + /// + /// Creates a Playfield. + /// + /// The Playfield. + protected abstract Playfield CreatePlayfield(); } /// @@ -198,7 +205,7 @@ namespace osu.Game.Rulesets.UI }); AddInternal(KeyBindingInputManager); - KeyBindingInputManager.Add(Playfield = CreatePlayfield()); + KeyBindingInputManager.Add(Playfield); loadObjects(); } @@ -286,12 +293,6 @@ namespace osu.Game.Rulesets.UI /// The HitObject to make drawable. /// The DrawableHitObject. protected abstract DrawableHitObject GetVisualRepresentation(TObject h); - - /// - /// Creates a Playfield. - /// - /// The Playfield. - protected abstract Playfield CreatePlayfield(); } /// diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index ad1370890f..c12ecc8b14 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -304,6 +304,7 @@ + @@ -567,6 +568,7 @@ + From 806c0e3b2629f708c80fe8f5d63e2b5fa0f62156 Mon Sep 17 00:00:00 2001 From: Aergwyn Date: Fri, 1 Dec 2017 17:43:33 +0100 Subject: [PATCH 0962/1263] restructured OsuLegacyDecoder into LegacyDecoder Beatmap works, Storyboard not... --- .../Beatmaps/Formats/OsuLegacyDecoderTest.cs | 12 +- osu.Game/Beatmaps/Formats/BeatmapDecoder.cs | 7 +- .../Beatmaps/Formats/LegacyBeatmapDecoder.cs | 401 +++++++++ osu.Game/Beatmaps/Formats/LegacyDecoder.cs | 182 ++++ .../Formats/LegacyStoryboardDecoder.cs | 261 ++++++ osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs | 837 ------------------ .../Objects/Legacy/ConvertHitObjectParser.cs | 4 +- osu.Game/osu.Game.csproj | 4 +- 8 files changed, 857 insertions(+), 851 deletions(-) create mode 100644 osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs create mode 100644 osu.Game/Beatmaps/Formats/LegacyDecoder.cs create mode 100644 osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs delete mode 100644 osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs diff --git a/osu.Game.Tests/Beatmaps/Formats/OsuLegacyDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/OsuLegacyDecoderTest.cs index 175e07f99c..2ef1b796d1 100644 --- a/osu.Game.Tests/Beatmaps/Formats/OsuLegacyDecoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/OsuLegacyDecoderTest.cs @@ -19,7 +19,7 @@ namespace osu.Game.Tests.Beatmaps.Formats [Test] public void TestDecodeMetadata() { - var decoder = new OsuLegacyDecoder(); + var decoder = new LegacyBeatmapDecoder(); using (var stream = Resource.OpenResource("Soleily - Renatus (Gamu) [Insane].osu")) { var beatmap = decoder.DecodeBeatmap(new StreamReader(stream)); @@ -41,7 +41,7 @@ namespace osu.Game.Tests.Beatmaps.Formats [Test] public void TestDecodeGeneral() { - var decoder = new OsuLegacyDecoder(); + var decoder = new LegacyBeatmapDecoder(); using (var stream = Resource.OpenResource("Soleily - Renatus (Gamu) [Insane].osu")) { var beatmapInfo = decoder.DecodeBeatmap(new StreamReader(stream)).BeatmapInfo; @@ -58,7 +58,7 @@ namespace osu.Game.Tests.Beatmaps.Formats [Test] public void TestDecodeEditor() { - var decoder = new OsuLegacyDecoder(); + var decoder = new LegacyBeatmapDecoder(); using (var stream = Resource.OpenResource("Soleily - Renatus (Gamu) [Insane].osu")) { var beatmap = decoder.DecodeBeatmap(new StreamReader(stream)).BeatmapInfo; @@ -81,7 +81,7 @@ namespace osu.Game.Tests.Beatmaps.Formats [Test] public void TestDecodeDifficulty() { - var decoder = new OsuLegacyDecoder(); + var decoder = new LegacyBeatmapDecoder(); using (var stream = Resource.OpenResource("Soleily - Renatus (Gamu) [Insane].osu")) { var beatmap = decoder.DecodeBeatmap(new StreamReader(stream)); @@ -98,7 +98,7 @@ namespace osu.Game.Tests.Beatmaps.Formats [Test] public void TestDecodeColors() { - var decoder = new OsuLegacyDecoder(); + var decoder = new LegacyBeatmapDecoder(); using (var stream = Resource.OpenResource("Soleily - Renatus (Gamu) [Insane].osu")) { var beatmap = decoder.DecodeBeatmap(new StreamReader(stream)); @@ -120,7 +120,7 @@ namespace osu.Game.Tests.Beatmaps.Formats [Test] public void TestDecodeHitObjects() { - var decoder = new OsuLegacyDecoder(); + var decoder = new LegacyBeatmapDecoder(); using (var stream = Resource.OpenResource("Soleily - Renatus (Gamu) [Insane].osu")) { var beatmap = decoder.DecodeBeatmap(new StreamReader(stream)); diff --git a/osu.Game/Beatmaps/Formats/BeatmapDecoder.cs b/osu.Game/Beatmaps/Formats/BeatmapDecoder.cs index d785618780..1ecc6c0ee0 100644 --- a/osu.Game/Beatmaps/Formats/BeatmapDecoder.cs +++ b/osu.Game/Beatmaps/Formats/BeatmapDecoder.cs @@ -14,7 +14,7 @@ namespace osu.Game.Beatmaps.Formats static BeatmapDecoder() { - OsuLegacyDecoder.Register(); + LegacyDecoder.Register(); } public static BeatmapDecoder GetDecoder(StreamReader stream) @@ -36,10 +36,7 @@ namespace osu.Game.Beatmaps.Formats decoders[magic] = typeof(T); } - public virtual Beatmap DecodeBeatmap(StreamReader stream) - { - return ParseBeatmap(stream); - } + public virtual Beatmap DecodeBeatmap(StreamReader stream) => ParseBeatmap(stream); protected virtual Beatmap ParseBeatmap(StreamReader stream) { diff --git a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs new file mode 100644 index 0000000000..c8e6d6cfea --- /dev/null +++ b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs @@ -0,0 +1,401 @@ +// 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.Globalization; +using System.IO; +using OpenTK.Graphics; +using osu.Game.Beatmaps.Timing; +using osu.Game.Beatmaps.Legacy; +using osu.Game.Rulesets.Objects.Legacy; +using osu.Game.Beatmaps.ControlPoints; +using osu.Game.Storyboards; +using OpenTK; +using osu.Framework.Graphics; +using osu.Framework.IO.File; + +namespace osu.Game.Beatmaps.Formats +{ + public class LegacyBeatmapDecoder : LegacyDecoder + { + private ConvertHitObjectParser parser; + private bool hasCustomColours = false; + + private LegacySampleBank defaultSampleBank; + private int defaultSampleVolume = 100; + + public LegacyBeatmapDecoder() + { + } + + public LegacyBeatmapDecoder(string header) + { + beatmapVersion = int.Parse(header.Substring(17)); + } + + protected override void processSection(Section section, string line) + { + switch (section) + { + case Section.General: + handleGeneral(line); + break; + case Section.Editor: + handleEditor(line); + break; + case Section.Metadata: + handleMetadata(line); + break; + case Section.Difficulty: + handleDifficulty(line); + break; + case Section.Events: + handleEvents(line); + break; + case Section.TimingPoints: + handleTimingPoints(line); + break; + case Section.Colours: + handleColours(line); + break; + case Section.HitObjects: + handleHitObjects(line); + break; + case Section.Variables: + handleVariables(line); + break; + } + } + + private void handleGeneral(string line) + { + var pair = splitKeyVal(line, ':'); + + var metadata = beatmap.BeatmapInfo.Metadata; + switch (pair.Key) + { + case @"AudioFilename": + metadata.AudioFile = pair.Value; + break; + case @"AudioLeadIn": + beatmap.BeatmapInfo.AudioLeadIn = int.Parse(pair.Value); + break; + case @"PreviewTime": + metadata.PreviewTime = int.Parse(pair.Value); + break; + case @"Countdown": + beatmap.BeatmapInfo.Countdown = int.Parse(pair.Value) == 1; + break; + case @"SampleSet": + defaultSampleBank = (LegacySampleBank)Enum.Parse(typeof(LegacySampleBank), pair.Value); + break; + case @"SampleVolume": + defaultSampleVolume = int.Parse(pair.Value); + break; + case @"StackLeniency": + beatmap.BeatmapInfo.StackLeniency = float.Parse(pair.Value, NumberFormatInfo.InvariantInfo); + break; + case @"Mode": + beatmap.BeatmapInfo.RulesetID = int.Parse(pair.Value); + + switch (beatmap.BeatmapInfo.RulesetID) + { + case 0: + parser = new Rulesets.Objects.Legacy.Osu.ConvertHitObjectParser(); + break; + case 1: + parser = new Rulesets.Objects.Legacy.Taiko.ConvertHitObjectParser(); + break; + case 2: + parser = new Rulesets.Objects.Legacy.Catch.ConvertHitObjectParser(); + break; + case 3: + parser = new Rulesets.Objects.Legacy.Mania.ConvertHitObjectParser(); + break; + } + break; + case @"LetterboxInBreaks": + beatmap.BeatmapInfo.LetterboxInBreaks = int.Parse(pair.Value) == 1; + break; + case @"SpecialStyle": + beatmap.BeatmapInfo.SpecialStyle = int.Parse(pair.Value) == 1; + break; + case @"WidescreenStoryboard": + beatmap.BeatmapInfo.WidescreenStoryboard = int.Parse(pair.Value) == 1; + break; + } + } + + private void handleEditor(string line) + { + var pair = splitKeyVal(line, ':'); + + switch (pair.Key) + { + case @"Bookmarks": + beatmap.BeatmapInfo.StoredBookmarks = pair.Value; + break; + case @"DistanceSpacing": + beatmap.BeatmapInfo.DistanceSpacing = double.Parse(pair.Value, NumberFormatInfo.InvariantInfo); + break; + case @"BeatDivisor": + beatmap.BeatmapInfo.BeatDivisor = int.Parse(pair.Value); + break; + case @"GridSize": + beatmap.BeatmapInfo.GridSize = int.Parse(pair.Value); + break; + case @"TimelineZoom": + beatmap.BeatmapInfo.TimelineZoom = double.Parse(pair.Value, NumberFormatInfo.InvariantInfo); + break; + } + } + + private void handleMetadata(string line) + { + var pair = splitKeyVal(line, ':'); + + var metadata = beatmap.BeatmapInfo.Metadata; + switch (pair.Key) + { + case @"Title": + metadata.Title = pair.Value; + break; + case @"TitleUnicode": + metadata.TitleUnicode = pair.Value; + break; + case @"Artist": + metadata.Artist = pair.Value; + break; + case @"ArtistUnicode": + metadata.ArtistUnicode = pair.Value; + break; + case @"Creator": + metadata.AuthorString = pair.Value; + break; + case @"Version": + beatmap.BeatmapInfo.Version = pair.Value; + break; + case @"Source": + beatmap.BeatmapInfo.Metadata.Source = pair.Value; + break; + case @"Tags": + beatmap.BeatmapInfo.Metadata.Tags = pair.Value; + break; + case @"BeatmapID": + beatmap.BeatmapInfo.OnlineBeatmapID = int.Parse(pair.Value); + break; + case @"BeatmapSetID": + beatmap.BeatmapInfo.OnlineBeatmapSetID = int.Parse(pair.Value); + metadata.OnlineBeatmapSetID = int.Parse(pair.Value); + break; + } + } + + private void handleDifficulty(string line) + { + var pair = splitKeyVal(line, ':'); + + var difficulty = beatmap.BeatmapInfo.BaseDifficulty; + switch (pair.Key) + { + case @"HPDrainRate": + difficulty.DrainRate = float.Parse(pair.Value, NumberFormatInfo.InvariantInfo); + break; + case @"CircleSize": + difficulty.CircleSize = float.Parse(pair.Value, NumberFormatInfo.InvariantInfo); + break; + case @"OverallDifficulty": + difficulty.OverallDifficulty = float.Parse(pair.Value, NumberFormatInfo.InvariantInfo); + break; + case @"ApproachRate": + difficulty.ApproachRate = float.Parse(pair.Value, NumberFormatInfo.InvariantInfo); + break; + case @"SliderMultiplier": + difficulty.SliderMultiplier = float.Parse(pair.Value, NumberFormatInfo.InvariantInfo); + break; + case @"SliderTickRate": + difficulty.SliderTickRate = float.Parse(pair.Value, NumberFormatInfo.InvariantInfo); + break; + } + } + + private void handleEvents(string line) + { + decodeVariables(ref line); + + string[] split = line.Split(','); + + EventType type; + if (!Enum.TryParse(split[0], out type)) + throw new InvalidDataException($@"Unknown event type {split[0]}"); + + switch (type) + { + case EventType.Background: + string filename = split[2].Trim('"'); + beatmap.BeatmapInfo.Metadata.BackgroundFile = filename; + break; + case EventType.Break: + var breakEvent = new BreakPeriod + { + StartTime = double.Parse(split[1], NumberFormatInfo.InvariantInfo), + EndTime = double.Parse(split[2], NumberFormatInfo.InvariantInfo) + }; + + if (!breakEvent.HasEffect) + return; + + beatmap.Breaks.Add(breakEvent); + break; + } + } + + private void handleTimingPoints(string line) + { + string[] split = line.Split(','); + + double time = double.Parse(split[0].Trim(), NumberFormatInfo.InvariantInfo); + double beatLength = double.Parse(split[1].Trim(), NumberFormatInfo.InvariantInfo); + double speedMultiplier = beatLength < 0 ? 100.0 / -beatLength : 1; + + TimeSignatures timeSignature = TimeSignatures.SimpleQuadruple; + if (split.Length >= 3) + timeSignature = split[2][0] == '0' ? TimeSignatures.SimpleQuadruple : (TimeSignatures)int.Parse(split[2]); + + LegacySampleBank sampleSet = defaultSampleBank; + if (split.Length >= 4) + sampleSet = (LegacySampleBank)int.Parse(split[3]); + + //SampleBank sampleBank = SampleBank.Default; + //if (split.Length >= 5) + // sampleBank = (SampleBank)int.Parse(split[4]); + + int sampleVolume = defaultSampleVolume; + if (split.Length >= 6) + sampleVolume = int.Parse(split[5]); + + bool timingChange = true; + if (split.Length >= 7) + timingChange = split[6][0] == '1'; + + bool kiaiMode = false; + bool omitFirstBarSignature = false; + if (split.Length >= 8) + { + int effectFlags = int.Parse(split[7]); + kiaiMode = (effectFlags & 1) > 0; + omitFirstBarSignature = (effectFlags & 8) > 0; + } + + string stringSampleSet = sampleSet.ToString().ToLower(); + if (stringSampleSet == @"none") + stringSampleSet = @"normal"; + + DifficultyControlPoint difficultyPoint = beatmap.ControlPointInfo.DifficultyPointAt(time); + SoundControlPoint soundPoint = beatmap.ControlPointInfo.SoundPointAt(time); + EffectControlPoint effectPoint = beatmap.ControlPointInfo.EffectPointAt(time); + + if (timingChange) + { + beatmap.ControlPointInfo.TimingPoints.Add(new TimingControlPoint + { + Time = time, + BeatLength = beatLength, + TimeSignature = timeSignature + }); + } + + if (speedMultiplier != difficultyPoint.SpeedMultiplier) + { + beatmap.ControlPointInfo.DifficultyPoints.RemoveAll(x => x.Time == time); + beatmap.ControlPointInfo.DifficultyPoints.Add(new DifficultyControlPoint + { + Time = time, + SpeedMultiplier = speedMultiplier + }); + } + + if (stringSampleSet != soundPoint.SampleBank || sampleVolume != soundPoint.SampleVolume) + { + beatmap.ControlPointInfo.SoundPoints.Add(new SoundControlPoint + { + Time = time, + SampleBank = stringSampleSet, + SampleVolume = sampleVolume + }); + } + + if (kiaiMode != effectPoint.KiaiMode || omitFirstBarSignature != effectPoint.OmitFirstBarLine) + { + beatmap.ControlPointInfo.EffectPoints.Add(new EffectControlPoint + { + Time = time, + KiaiMode = kiaiMode, + OmitFirstBarLine = omitFirstBarSignature + }); + } + } + + private void handleColours(string line) + { + var pair = splitKeyVal(line, ':'); + + string[] split = pair.Value.Split(','); + + if (split.Length != 3) + throw new InvalidOperationException($@"Color specified in incorrect format (should be R,G,B): {pair.Value}"); + + byte r, g, b; + if (!byte.TryParse(split[0], out r) || !byte.TryParse(split[1], out g) || !byte.TryParse(split[2], out b)) + throw new InvalidOperationException(@"Color must be specified with 8-bit integer components"); + + if (!hasCustomColours) + { + beatmap.ComboColors.Clear(); + hasCustomColours = true; + } + + // Note: the combo index specified in the beatmap is discarded + if (pair.Key.StartsWith(@"Combo")) + { + beatmap.ComboColors.Add(new Color4 + { + R = r / 255f, + G = g / 255f, + B = b / 255f, + A = 1f, + }); + } + } + + private void handleHitObjects(string line) + { + // If the ruleset wasn't specified, assume the osu!standard ruleset. + if (parser == null) + parser = new Rulesets.Objects.Legacy.Osu.ConvertHitObjectParser(); + + var obj = parser.Parse(line); + + if (obj != null) + beatmap.HitObjects.Add(obj); + } + + private void handleVariables(string line) + { + var pair = splitKeyVal(line, '='); + variables[pair.Key] = pair.Value; + } + + private KeyValuePair splitKeyVal(string line, char separator) + { + var split = line.Trim().Split(new[] { separator }, 2); + + return new KeyValuePair + ( + split[0].Trim(), + split.Length > 1 ? split[1].Trim() : string.Empty + ); + } + } +} diff --git a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs new file mode 100644 index 0000000000..00b06d28d2 --- /dev/null +++ b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs @@ -0,0 +1,182 @@ +// 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.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using osu.Game.Beatmaps.Legacy; +using osu.Game.Storyboards; + +namespace osu.Game.Beatmaps.Formats +{ + public abstract class LegacyDecoder : BeatmapDecoder + { + public static void Register() + { + AddDecoder(@"osu file format v14"); + AddDecoder(@"osu file format v13"); + AddDecoder(@"osu file format v12"); + AddDecoder(@"osu file format v11"); + AddDecoder(@"osu file format v10"); + AddDecoder(@"osu file format v9"); + AddDecoder(@"osu file format v8"); + AddDecoder(@"osu file format v7"); + AddDecoder(@"osu file format v6"); + AddDecoder(@"osu file format v5"); + AddDecoder(@"osu file format v4"); + AddDecoder(@"osu file format v3"); + // TODO: differences between versions + } + + protected Beatmap beatmap; + protected Storyboard storyboard; + + protected int beatmapVersion; + protected readonly Dictionary variables = new Dictionary(); + + public override Beatmap DecodeBeatmap(StreamReader stream) => new LegacyBeatmap(base.DecodeBeatmap(stream)); + + protected override Beatmap ParseBeatmap(StreamReader stream) => new LegacyBeatmap(base.ParseBeatmap(stream)); + + protected override void ParseBeatmap(StreamReader stream, Beatmap beatmap) + { + if (stream == null) + throw new ArgumentNullException(nameof(stream)); + if (beatmap == null) + throw new ArgumentNullException(nameof(beatmap)); + + this.beatmap = beatmap; + this.beatmap.BeatmapInfo.BeatmapVersion = beatmapVersion; + + ParseContent(stream); + + foreach (var hitObject in this.beatmap.HitObjects) + hitObject.ApplyDefaults(this.beatmap.ControlPointInfo, this.beatmap.BeatmapInfo.BaseDifficulty); + } + + protected override void ParseStoryboard(StreamReader stream, Storyboard storyboard) + { + if (stream == null) + throw new ArgumentNullException(nameof(stream)); + if (storyboard == null) + throw new ArgumentNullException(nameof(storyboard)); + + this.storyboard = storyboard; + + ParseContent(stream); + } + + protected void ParseContent(StreamReader stream) + { + Section section = Section.None; + + string line; + while ((line = stream.ReadLine()) != null) + { + if (string.IsNullOrWhiteSpace(line)) + continue; + + if (line.StartsWith("//")) + continue; + + if (line.StartsWith(@"osu file format v")) + { + beatmap.BeatmapInfo.BeatmapVersion = int.Parse(line.Substring(17)); + continue; + } + + if (line.StartsWith(@"[") && line.EndsWith(@"]")) + { + if (!Enum.TryParse(line.Substring(1, line.Length - 2), out section)) + throw new InvalidDataException($@"Unknown osu section {line}"); + continue; + } + + processSection(section, line); + } + } + + protected abstract void processSection(Section section, string line); + + /// + /// Decodes any beatmap variables present in a line into their real values. + /// + /// The line which may contains variables. + protected void decodeVariables(ref string line) + { + while (line.IndexOf('$') >= 0) + { + string origLine = line; + string[] split = line.Split(','); + for (int i = 0; i < split.Length; i++) + { + var item = split[i]; + if (item.StartsWith("$") && variables.ContainsKey(item)) + split[i] = variables[item]; + } + + line = string.Join(",", split); + if (line == origLine) + break; + } + } + + protected enum Section + { + None, + General, + Editor, + Metadata, + Difficulty, + Events, + TimingPoints, + Colours, + HitObjects, + Variables, + } + + internal enum LegacySampleBank + { + None = 0, + Normal = 1, + Soft = 2, + Drum = 3 + } + + internal enum EventType + { + Background = 0, + Video = 1, + Break = 2, + Colour = 3, + Sprite = 4, + Sample = 5, + Animation = 6 + } + + internal enum LegacyOrigins + { + TopLeft, + Centre, + CentreLeft, + TopRight, + BottomCentre, + TopCentre, + Custom, + CentreRight, + BottomLeft, + BottomRight + }; + + internal enum StoryLayer + { + Background = 0, + Fail = 1, + Pass = 2, + Foreground = 3 + } + } +} diff --git a/osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs new file mode 100644 index 0000000000..9362676245 --- /dev/null +++ b/osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs @@ -0,0 +1,261 @@ +// 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.Globalization; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using OpenTK; +using OpenTK.Graphics; +using osu.Framework.Graphics; +using osu.Framework.IO.File; +using osu.Game.Storyboards; + +namespace osu.Game.Beatmaps.Formats +{ + public class LegacyStoryboardDecoder : LegacyDecoder + { + private StoryboardSprite storyboardSprite = null; + private CommandTimelineGroup timelineGroup = null; + + public LegacyStoryboardDecoder() + { + } + + public LegacyStoryboardDecoder(string header) + { + beatmapVersion = int.Parse(header.Substring(17)); + } + + protected override void processSection(Section section, string line) + { + switch (section) + { + case Section.Events: + handleEvents(line); + break; + } + } + + private void handleEvents(string line) + { + var depth = 0; + while (line.StartsWith(" ") || line.StartsWith("_")) + { + ++depth; + line = line.Substring(1); + } + + decodeVariables(ref line); + + string[] split = line.Split(','); + + if (depth == 0) + { + storyboardSprite = null; + + EventType type; + if (!Enum.TryParse(split[0], out type)) + throw new InvalidDataException($@"Unknown event type {split[0]}"); + + switch (type) + { + case EventType.Sprite: + { + var layer = parseLayer(split[1]); + var origin = parseOrigin(split[2]); + var path = cleanFilename(split[3]); + var x = float.Parse(split[4], NumberFormatInfo.InvariantInfo); + var y = float.Parse(split[5], NumberFormatInfo.InvariantInfo); + storyboardSprite = new StoryboardSprite(path, origin, new Vector2(x, y)); + storyboard.GetLayer(layer).Add(storyboardSprite); + } + break; + case EventType.Animation: + { + var layer = parseLayer(split[1]); + var origin = parseOrigin(split[2]); + var path = cleanFilename(split[3]); + var x = float.Parse(split[4], NumberFormatInfo.InvariantInfo); + var y = float.Parse(split[5], NumberFormatInfo.InvariantInfo); + var frameCount = int.Parse(split[6]); + var frameDelay = double.Parse(split[7], NumberFormatInfo.InvariantInfo); + var loopType = split.Length > 8 ? (AnimationLoopType)Enum.Parse(typeof(AnimationLoopType), split[8]) : AnimationLoopType.LoopForever; + storyboardSprite = new StoryboardAnimation(path, origin, new Vector2(x, y), frameCount, frameDelay, loopType); + storyboard.GetLayer(layer).Add(storyboardSprite); + } + break; + case EventType.Sample: + { + var time = double.Parse(split[1], CultureInfo.InvariantCulture); + var layer = parseLayer(split[2]); + var path = cleanFilename(split[3]); + var volume = split.Length > 4 ? float.Parse(split[4], CultureInfo.InvariantCulture) : 100; + storyboard.GetLayer(layer).Add(new StoryboardSample(path, time, volume)); + } + break; + } + } + else + { + if (depth < 2) + timelineGroup = storyboardSprite?.TimelineGroup; + + var commandType = split[0]; + switch (commandType) + { + case "T": + { + var triggerName = split[1]; + var startTime = split.Length > 2 ? double.Parse(split[2], CultureInfo.InvariantCulture) : double.MinValue; + var endTime = split.Length > 3 ? double.Parse(split[3], CultureInfo.InvariantCulture) : double.MaxValue; + var groupNumber = split.Length > 4 ? int.Parse(split[4]) : 0; + timelineGroup = storyboardSprite?.AddTrigger(triggerName, startTime, endTime, groupNumber); + } + break; + case "L": + { + var startTime = double.Parse(split[1], CultureInfo.InvariantCulture); + var loopCount = int.Parse(split[2]); + timelineGroup = storyboardSprite?.AddLoop(startTime, loopCount); + } + break; + default: + { + if (string.IsNullOrEmpty(split[3])) + split[3] = split[2]; + + var easing = (Easing)int.Parse(split[1]); + var startTime = double.Parse(split[2], CultureInfo.InvariantCulture); + var endTime = double.Parse(split[3], CultureInfo.InvariantCulture); + + switch (commandType) + { + case "F": + { + var startValue = float.Parse(split[4], CultureInfo.InvariantCulture); + var endValue = split.Length > 5 ? float.Parse(split[5], CultureInfo.InvariantCulture) : startValue; + timelineGroup?.Alpha.Add(easing, startTime, endTime, startValue, endValue); + } + break; + case "S": + { + var startValue = float.Parse(split[4], CultureInfo.InvariantCulture); + var endValue = split.Length > 5 ? float.Parse(split[5], CultureInfo.InvariantCulture) : startValue; + timelineGroup?.Scale.Add(easing, startTime, endTime, new Vector2(startValue), new Vector2(endValue)); + } + break; + case "V": + { + var startX = float.Parse(split[4], CultureInfo.InvariantCulture); + var startY = float.Parse(split[5], CultureInfo.InvariantCulture); + var endX = split.Length > 6 ? float.Parse(split[6], CultureInfo.InvariantCulture) : startX; + var endY = split.Length > 7 ? float.Parse(split[7], CultureInfo.InvariantCulture) : startY; + timelineGroup?.Scale.Add(easing, startTime, endTime, new Vector2(startX, startY), new Vector2(endX, endY)); + } + break; + case "R": + { + var startValue = float.Parse(split[4], CultureInfo.InvariantCulture); + var endValue = split.Length > 5 ? float.Parse(split[5], CultureInfo.InvariantCulture) : startValue; + timelineGroup?.Rotation.Add(easing, startTime, endTime, MathHelper.RadiansToDegrees(startValue), MathHelper.RadiansToDegrees(endValue)); + } + break; + case "M": + { + var startX = float.Parse(split[4], CultureInfo.InvariantCulture); + var startY = float.Parse(split[5], CultureInfo.InvariantCulture); + var endX = split.Length > 6 ? float.Parse(split[6], CultureInfo.InvariantCulture) : startX; + var endY = split.Length > 7 ? float.Parse(split[7], CultureInfo.InvariantCulture) : startY; + timelineGroup?.X.Add(easing, startTime, endTime, startX, endX); + timelineGroup?.Y.Add(easing, startTime, endTime, startY, endY); + } + break; + case "MX": + { + var startValue = float.Parse(split[4], CultureInfo.InvariantCulture); + var endValue = split.Length > 5 ? float.Parse(split[5], CultureInfo.InvariantCulture) : startValue; + timelineGroup?.X.Add(easing, startTime, endTime, startValue, endValue); + } + break; + case "MY": + { + var startValue = float.Parse(split[4], CultureInfo.InvariantCulture); + var endValue = split.Length > 5 ? float.Parse(split[5], CultureInfo.InvariantCulture) : startValue; + timelineGroup?.Y.Add(easing, startTime, endTime, startValue, endValue); + } + break; + case "C": + { + var startRed = float.Parse(split[4], CultureInfo.InvariantCulture); + var startGreen = float.Parse(split[5], CultureInfo.InvariantCulture); + var startBlue = float.Parse(split[6], CultureInfo.InvariantCulture); + var endRed = split.Length > 7 ? float.Parse(split[7], CultureInfo.InvariantCulture) : startRed; + var endGreen = split.Length > 8 ? float.Parse(split[8], CultureInfo.InvariantCulture) : startGreen; + var endBlue = split.Length > 9 ? float.Parse(split[9], CultureInfo.InvariantCulture) : startBlue; + timelineGroup?.Colour.Add(easing, startTime, endTime, + new Color4(startRed / 255f, startGreen / 255f, startBlue / 255f, 1), + new Color4(endRed / 255f, endGreen / 255f, endBlue / 255f, 1)); + } + break; + case "P": + { + var type = split[4]; + switch (type) + { + case "A": + timelineGroup?.BlendingMode.Add(easing, startTime, endTime, BlendingMode.Additive, startTime == endTime ? BlendingMode.Additive : BlendingMode.Inherit); + break; + case "H": + timelineGroup?.FlipH.Add(easing, startTime, endTime, true, startTime == endTime); + break; + case "V": + timelineGroup?.FlipV.Add(easing, startTime, endTime, true, startTime == endTime); + break; + } + } + break; + default: + throw new InvalidDataException($@"Unknown command type: {commandType}"); + } + } + break; + } + } + } + + private static string parseLayer(string value) => Enum.Parse(typeof(StoryLayer), value).ToString(); + + private static Anchor parseOrigin(string value) + { + var origin = (LegacyOrigins)Enum.Parse(typeof(LegacyOrigins), value); + switch (origin) + { + case LegacyOrigins.TopLeft: + return Anchor.TopLeft; + case LegacyOrigins.TopCentre: + return Anchor.TopCentre; + case LegacyOrigins.TopRight: + return Anchor.TopRight; + case LegacyOrigins.CentreLeft: + return Anchor.CentreLeft; + case LegacyOrigins.Centre: + return Anchor.Centre; + case LegacyOrigins.CentreRight: + return Anchor.CentreRight; + case LegacyOrigins.BottomLeft: + return Anchor.BottomLeft; + case LegacyOrigins.BottomCentre: + return Anchor.BottomCentre; + case LegacyOrigins.BottomRight: + return Anchor.BottomRight; + } + throw new InvalidDataException($@"Unknown origin: {value}"); + } + + private static string cleanFilename(string path) => FileSafety.PathStandardise(path.Trim('\"')); + } +} diff --git a/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs b/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs deleted file mode 100644 index 47e35f231f..0000000000 --- a/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs +++ /dev/null @@ -1,837 +0,0 @@ -// Copyright (c) 2007-2017 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using System; -using System.Collections.Generic; -using System.Globalization; -using System.IO; -using OpenTK.Graphics; -using osu.Game.Beatmaps.Timing; -using osu.Game.Beatmaps.Legacy; -using osu.Game.Rulesets.Objects.Legacy; -using osu.Game.Beatmaps.ControlPoints; -using osu.Game.Storyboards; -using OpenTK; -using osu.Framework.Graphics; -using osu.Framework.IO.File; - -namespace osu.Game.Beatmaps.Formats -{ - public class OsuLegacyDecoder : BeatmapDecoder - { - public static void Register() - { - AddDecoder(@"osu file format v14"); - AddDecoder(@"osu file format v13"); - AddDecoder(@"osu file format v12"); - AddDecoder(@"osu file format v11"); - AddDecoder(@"osu file format v10"); - AddDecoder(@"osu file format v9"); - AddDecoder(@"osu file format v8"); - AddDecoder(@"osu file format v7"); - AddDecoder(@"osu file format v6"); - AddDecoder(@"osu file format v5"); - AddDecoder(@"osu file format v4"); - AddDecoder(@"osu file format v3"); - // TODO: differences between versions - } - - private ConvertHitObjectParser parser; - - private readonly Dictionary variables = new Dictionary(); - - private LegacySampleBank defaultSampleBank; - private int defaultSampleVolume = 100; - - private readonly int beatmapVersion; - - public OsuLegacyDecoder() - { - } - - public OsuLegacyDecoder(string header) - { - beatmapVersion = int.Parse(header.Substring(17)); - } - - protected override Beatmap ParseBeatmap(StreamReader stream) - { - return new LegacyBeatmap(base.ParseBeatmap(stream)); - } - - public override Beatmap DecodeBeatmap(StreamReader stream) - { - return new LegacyBeatmap(base.DecodeBeatmap(stream)); - } - - protected override void ParseBeatmap(StreamReader stream, Beatmap beatmap) - { - if (beatmap == null) - throw new ArgumentNullException(nameof(beatmap)); - if (stream == null) - throw new ArgumentNullException(nameof(stream)); - - beatmap.BeatmapInfo.BeatmapVersion = beatmapVersion; - - Section section = Section.None; - bool hasCustomColours = false; - - string line; - while ((line = stream.ReadLine()) != null) - { - if (string.IsNullOrWhiteSpace(line)) - continue; - - if (line.StartsWith("//")) - continue; - - if (line.StartsWith(@"osu file format v")) - { - beatmap.BeatmapInfo.BeatmapVersion = int.Parse(line.Substring(17)); - continue; - } - - if (line.StartsWith(@"[") && line.EndsWith(@"]")) - { - if (!Enum.TryParse(line.Substring(1, line.Length - 2), out section)) - throw new InvalidDataException($@"Unknown osu section {line}"); - continue; - } - - switch (section) - { - case Section.General: - handleGeneral(beatmap, line); - break; - case Section.Editor: - handleEditor(beatmap, line); - break; - case Section.Metadata: - handleMetadata(beatmap, line); - break; - case Section.Difficulty: - handleDifficulty(beatmap, line); - break; - case Section.Events: - handleEvents(beatmap, line); - break; - case Section.TimingPoints: - handleTimingPoints(beatmap, line); - break; - case Section.Colours: - handleColours(beatmap, line, ref hasCustomColours); - break; - case Section.HitObjects: - - // If the ruleset wasn't specified, assume the osu!standard ruleset. - if (parser == null) - parser = new Rulesets.Objects.Legacy.Osu.ConvertHitObjectParser(); - - var obj = parser.Parse(line); - - if (obj != null) - beatmap.HitObjects.Add(obj); - - break; - case Section.Variables: - handleVariables(line); - break; - } - } - - foreach (var hitObject in beatmap.HitObjects) - hitObject.ApplyDefaults(beatmap.ControlPointInfo, beatmap.BeatmapInfo.BaseDifficulty); - } - - protected override void ParseStoryboard(StreamReader stream, Storyboard storyboard) - { - if (storyboard == null) - throw new ArgumentNullException(nameof(storyboard)); - if (stream == null) - throw new ArgumentNullException(nameof(stream)); - - Section section = Section.None; - StoryboardSprite storyboardSprite = null; - CommandTimelineGroup timelineGroup = null; - - string line; - while ((line = stream.ReadLine()) != null) - { - if (string.IsNullOrWhiteSpace(line)) - continue; - - if (line.StartsWith("//")) - continue; - - if (line.StartsWith(@"[") && line.EndsWith(@"]")) - { - if (!Enum.TryParse(line.Substring(1, line.Length - 2), out section)) - throw new InvalidDataException($@"Unknown osu section {line}"); - continue; - } - - switch (section) - { - case Section.Events: - handleEvents(storyboard, line, ref storyboardSprite, ref timelineGroup); - break; - } - } - } - - private void handleGeneral(Beatmap beatmap, string line) - { - if (beatmap == null) - throw new ArgumentNullException(nameof(beatmap)); - if (line == null) - throw new ArgumentNullException(nameof(line)); - - var pair = splitKeyVal(line, ':'); - - var metadata = beatmap.BeatmapInfo.Metadata; - switch (pair.Key) - { - case @"AudioFilename": - metadata.AudioFile = pair.Value; - break; - case @"AudioLeadIn": - beatmap.BeatmapInfo.AudioLeadIn = int.Parse(pair.Value); - break; - case @"PreviewTime": - metadata.PreviewTime = int.Parse(pair.Value); - break; - case @"Countdown": - beatmap.BeatmapInfo.Countdown = int.Parse(pair.Value) == 1; - break; - case @"SampleSet": - defaultSampleBank = (LegacySampleBank)Enum.Parse(typeof(LegacySampleBank), pair.Value); - break; - case @"SampleVolume": - defaultSampleVolume = int.Parse(pair.Value); - break; - case @"StackLeniency": - beatmap.BeatmapInfo.StackLeniency = float.Parse(pair.Value, NumberFormatInfo.InvariantInfo); - break; - case @"Mode": - beatmap.BeatmapInfo.RulesetID = int.Parse(pair.Value); - - switch (beatmap.BeatmapInfo.RulesetID) - { - case 0: - parser = new Rulesets.Objects.Legacy.Osu.ConvertHitObjectParser(); - break; - case 1: - parser = new Rulesets.Objects.Legacy.Taiko.ConvertHitObjectParser(); - break; - case 2: - parser = new Rulesets.Objects.Legacy.Catch.ConvertHitObjectParser(); - break; - case 3: - parser = new Rulesets.Objects.Legacy.Mania.ConvertHitObjectParser(); - break; - } - break; - case @"LetterboxInBreaks": - beatmap.BeatmapInfo.LetterboxInBreaks = int.Parse(pair.Value) == 1; - break; - case @"SpecialStyle": - beatmap.BeatmapInfo.SpecialStyle = int.Parse(pair.Value) == 1; - break; - case @"WidescreenStoryboard": - beatmap.BeatmapInfo.WidescreenStoryboard = int.Parse(pair.Value) == 1; - break; - } - } - - private void handleEditor(Beatmap beatmap, string line) - { - if (beatmap == null) - throw new ArgumentNullException(nameof(beatmap)); - if (line == null) - throw new ArgumentNullException(nameof(line)); - - var pair = splitKeyVal(line, ':'); - - switch (pair.Key) - { - case @"Bookmarks": - beatmap.BeatmapInfo.StoredBookmarks = pair.Value; - break; - case @"DistanceSpacing": - beatmap.BeatmapInfo.DistanceSpacing = double.Parse(pair.Value, NumberFormatInfo.InvariantInfo); - break; - case @"BeatDivisor": - beatmap.BeatmapInfo.BeatDivisor = int.Parse(pair.Value); - break; - case @"GridSize": - beatmap.BeatmapInfo.GridSize = int.Parse(pair.Value); - break; - case @"TimelineZoom": - beatmap.BeatmapInfo.TimelineZoom = double.Parse(pair.Value, NumberFormatInfo.InvariantInfo); - break; - } - } - - private void handleMetadata(Beatmap beatmap, string line) - { - if (beatmap == null) - throw new ArgumentNullException(nameof(beatmap)); - if (line == null) - throw new ArgumentNullException(nameof(line)); - - var pair = splitKeyVal(line, ':'); - - var metadata = beatmap.BeatmapInfo.Metadata; - switch (pair.Key) - { - case @"Title": - metadata.Title = pair.Value; - break; - case @"TitleUnicode": - metadata.TitleUnicode = pair.Value; - break; - case @"Artist": - metadata.Artist = pair.Value; - break; - case @"ArtistUnicode": - metadata.ArtistUnicode = pair.Value; - break; - case @"Creator": - metadata.AuthorString = pair.Value; - break; - case @"Version": - beatmap.BeatmapInfo.Version = pair.Value; - break; - case @"Source": - beatmap.BeatmapInfo.Metadata.Source = pair.Value; - break; - case @"Tags": - beatmap.BeatmapInfo.Metadata.Tags = pair.Value; - break; - case @"BeatmapID": - beatmap.BeatmapInfo.OnlineBeatmapID = int.Parse(pair.Value); - break; - case @"BeatmapSetID": - beatmap.BeatmapInfo.OnlineBeatmapSetID = int.Parse(pair.Value); - metadata.OnlineBeatmapSetID = int.Parse(pair.Value); - break; - } - } - - private void handleDifficulty(Beatmap beatmap, string line) - { - if (beatmap == null) - throw new ArgumentNullException(nameof(beatmap)); - if (line == null) - throw new ArgumentNullException(nameof(line)); - - var pair = splitKeyVal(line, ':'); - - var difficulty = beatmap.BeatmapInfo.BaseDifficulty; - switch (pair.Key) - { - case @"HPDrainRate": - difficulty.DrainRate = float.Parse(pair.Value, NumberFormatInfo.InvariantInfo); - break; - case @"CircleSize": - difficulty.CircleSize = float.Parse(pair.Value, NumberFormatInfo.InvariantInfo); - break; - case @"OverallDifficulty": - difficulty.OverallDifficulty = float.Parse(pair.Value, NumberFormatInfo.InvariantInfo); - break; - case @"ApproachRate": - difficulty.ApproachRate = float.Parse(pair.Value, NumberFormatInfo.InvariantInfo); - break; - case @"SliderMultiplier": - difficulty.SliderMultiplier = float.Parse(pair.Value, NumberFormatInfo.InvariantInfo); - break; - case @"SliderTickRate": - difficulty.SliderTickRate = float.Parse(pair.Value, NumberFormatInfo.InvariantInfo); - break; - } - } - - private void handleEvents(Beatmap beatmap, string line) - { - if (line == null) - throw new ArgumentNullException(nameof(line)); - if (beatmap == null) - throw new ArgumentNullException(nameof(beatmap)); - - decodeVariables(ref line); - - string[] split = line.Split(','); - - EventType type; - if (!Enum.TryParse(split[0], out type)) - throw new InvalidDataException($@"Unknown event type {split[0]}"); - - switch (type) - { - case EventType.Background: - string filename = split[2].Trim('"'); - beatmap.BeatmapInfo.Metadata.BackgroundFile = filename; - break; - case EventType.Break: - var breakEvent = new BreakPeriod - { - StartTime = double.Parse(split[1], NumberFormatInfo.InvariantInfo), - EndTime = double.Parse(split[2], NumberFormatInfo.InvariantInfo) - }; - - if (!breakEvent.HasEffect) - return; - - beatmap.Breaks.Add(breakEvent); - break; - } - } - - private void handleEvents(Storyboard storyboard, string line, ref StoryboardSprite storyboardSprite, ref CommandTimelineGroup timelineGroup) - { - if (line == null) - throw new ArgumentNullException(nameof(line)); - if (storyboard == null) - throw new ArgumentNullException(nameof(storyboard)); - - var depth = 0; - while (line.StartsWith(" ") || line.StartsWith("_")) - { - ++depth; - line = line.Substring(1); - } - - decodeVariables(ref line); - - string[] split = line.Split(','); - - if (depth == 0) - { - storyboardSprite = null; - - EventType type; - if (!Enum.TryParse(split[0], out type)) - throw new InvalidDataException($@"Unknown event type {split[0]}"); - - switch (type) - { - case EventType.Sprite: - { - var layer = parseLayer(split[1]); - var origin = parseOrigin(split[2]); - var path = cleanFilename(split[3]); - var x = float.Parse(split[4], NumberFormatInfo.InvariantInfo); - var y = float.Parse(split[5], NumberFormatInfo.InvariantInfo); - storyboardSprite = new StoryboardSprite(path, origin, new Vector2(x, y)); - storyboard.GetLayer(layer).Add(storyboardSprite); - } - break; - case EventType.Animation: - { - var layer = parseLayer(split[1]); - var origin = parseOrigin(split[2]); - var path = cleanFilename(split[3]); - var x = float.Parse(split[4], NumberFormatInfo.InvariantInfo); - var y = float.Parse(split[5], NumberFormatInfo.InvariantInfo); - var frameCount = int.Parse(split[6]); - var frameDelay = double.Parse(split[7], NumberFormatInfo.InvariantInfo); - var loopType = split.Length > 8 ? (AnimationLoopType)Enum.Parse(typeof(AnimationLoopType), split[8]) : AnimationLoopType.LoopForever; - storyboardSprite = new StoryboardAnimation(path, origin, new Vector2(x, y), frameCount, frameDelay, loopType); - storyboard.GetLayer(layer).Add(storyboardSprite); - } - break; - case EventType.Sample: - { - var time = double.Parse(split[1], CultureInfo.InvariantCulture); - var layer = parseLayer(split[2]); - var path = cleanFilename(split[3]); - var volume = split.Length > 4 ? float.Parse(split[4], CultureInfo.InvariantCulture) : 100; - storyboard.GetLayer(layer).Add(new StoryboardSample(path, time, volume)); - } - break; - } - } - else - { - if (depth < 2) - timelineGroup = storyboardSprite?.TimelineGroup; - - var commandType = split[0]; - switch (commandType) - { - case "T": - { - var triggerName = split[1]; - var startTime = split.Length > 2 ? double.Parse(split[2], CultureInfo.InvariantCulture) : double.MinValue; - var endTime = split.Length > 3 ? double.Parse(split[3], CultureInfo.InvariantCulture) : double.MaxValue; - var groupNumber = split.Length > 4 ? int.Parse(split[4]) : 0; - timelineGroup = storyboardSprite?.AddTrigger(triggerName, startTime, endTime, groupNumber); - } - break; - case "L": - { - var startTime = double.Parse(split[1], CultureInfo.InvariantCulture); - var loopCount = int.Parse(split[2]); - timelineGroup = storyboardSprite?.AddLoop(startTime, loopCount); - } - break; - default: - { - if (string.IsNullOrEmpty(split[3])) - split[3] = split[2]; - - var easing = (Easing)int.Parse(split[1]); - var startTime = double.Parse(split[2], CultureInfo.InvariantCulture); - var endTime = double.Parse(split[3], CultureInfo.InvariantCulture); - - switch (commandType) - { - case "F": - { - var startValue = float.Parse(split[4], CultureInfo.InvariantCulture); - var endValue = split.Length > 5 ? float.Parse(split[5], CultureInfo.InvariantCulture) : startValue; - timelineGroup?.Alpha.Add(easing, startTime, endTime, startValue, endValue); - } - break; - case "S": - { - var startValue = float.Parse(split[4], CultureInfo.InvariantCulture); - var endValue = split.Length > 5 ? float.Parse(split[5], CultureInfo.InvariantCulture) : startValue; - timelineGroup?.Scale.Add(easing, startTime, endTime, new Vector2(startValue), new Vector2(endValue)); - } - break; - case "V": - { - var startX = float.Parse(split[4], CultureInfo.InvariantCulture); - var startY = float.Parse(split[5], CultureInfo.InvariantCulture); - var endX = split.Length > 6 ? float.Parse(split[6], CultureInfo.InvariantCulture) : startX; - var endY = split.Length > 7 ? float.Parse(split[7], CultureInfo.InvariantCulture) : startY; - timelineGroup?.Scale.Add(easing, startTime, endTime, new Vector2(startX, startY), new Vector2(endX, endY)); - } - break; - case "R": - { - var startValue = float.Parse(split[4], CultureInfo.InvariantCulture); - var endValue = split.Length > 5 ? float.Parse(split[5], CultureInfo.InvariantCulture) : startValue; - timelineGroup?.Rotation.Add(easing, startTime, endTime, MathHelper.RadiansToDegrees(startValue), MathHelper.RadiansToDegrees(endValue)); - } - break; - case "M": - { - var startX = float.Parse(split[4], CultureInfo.InvariantCulture); - var startY = float.Parse(split[5], CultureInfo.InvariantCulture); - var endX = split.Length > 6 ? float.Parse(split[6], CultureInfo.InvariantCulture) : startX; - var endY = split.Length > 7 ? float.Parse(split[7], CultureInfo.InvariantCulture) : startY; - timelineGroup?.X.Add(easing, startTime, endTime, startX, endX); - timelineGroup?.Y.Add(easing, startTime, endTime, startY, endY); - } - break; - case "MX": - { - var startValue = float.Parse(split[4], CultureInfo.InvariantCulture); - var endValue = split.Length > 5 ? float.Parse(split[5], CultureInfo.InvariantCulture) : startValue; - timelineGroup?.X.Add(easing, startTime, endTime, startValue, endValue); - } - break; - case "MY": - { - var startValue = float.Parse(split[4], CultureInfo.InvariantCulture); - var endValue = split.Length > 5 ? float.Parse(split[5], CultureInfo.InvariantCulture) : startValue; - timelineGroup?.Y.Add(easing, startTime, endTime, startValue, endValue); - } - break; - case "C": - { - var startRed = float.Parse(split[4], CultureInfo.InvariantCulture); - var startGreen = float.Parse(split[5], CultureInfo.InvariantCulture); - var startBlue = float.Parse(split[6], CultureInfo.InvariantCulture); - var endRed = split.Length > 7 ? float.Parse(split[7], CultureInfo.InvariantCulture) : startRed; - var endGreen = split.Length > 8 ? float.Parse(split[8], CultureInfo.InvariantCulture) : startGreen; - var endBlue = split.Length > 9 ? float.Parse(split[9], CultureInfo.InvariantCulture) : startBlue; - timelineGroup?.Colour.Add(easing, startTime, endTime, - new Color4(startRed / 255f, startGreen / 255f, startBlue / 255f, 1), - new Color4(endRed / 255f, endGreen / 255f, endBlue / 255f, 1)); - } - break; - case "P": - { - var type = split[4]; - switch (type) - { - case "A": - timelineGroup?.BlendingMode.Add(easing, startTime, endTime, BlendingMode.Additive, startTime == endTime ? BlendingMode.Additive : BlendingMode.Inherit); - break; - case "H": - timelineGroup?.FlipH.Add(easing, startTime, endTime, true, startTime == endTime); - break; - case "V": - timelineGroup?.FlipV.Add(easing, startTime, endTime, true, startTime == endTime); - break; - } - } - break; - default: - throw new InvalidDataException($@"Unknown command type: {commandType}"); - } - } - break; - } - } - } - - private void handleTimingPoints(Beatmap beatmap, string line) - { - if (beatmap == null) - throw new ArgumentNullException(nameof(beatmap)); - if (line == null) - throw new ArgumentNullException(nameof(line)); - - string[] split = line.Split(','); - - double time = double.Parse(split[0].Trim(), NumberFormatInfo.InvariantInfo); - double beatLength = double.Parse(split[1].Trim(), NumberFormatInfo.InvariantInfo); - double speedMultiplier = beatLength < 0 ? 100.0 / -beatLength : 1; - - TimeSignatures timeSignature = TimeSignatures.SimpleQuadruple; - if (split.Length >= 3) - timeSignature = split[2][0] == '0' ? TimeSignatures.SimpleQuadruple : (TimeSignatures)int.Parse(split[2]); - - LegacySampleBank sampleSet = defaultSampleBank; - if (split.Length >= 4) - sampleSet = (LegacySampleBank)int.Parse(split[3]); - - //SampleBank sampleBank = SampleBank.Default; - //if (split.Length >= 5) - // sampleBank = (SampleBank)int.Parse(split[4]); - - int sampleVolume = defaultSampleVolume; - if (split.Length >= 6) - sampleVolume = int.Parse(split[5]); - - bool timingChange = true; - if (split.Length >= 7) - timingChange = split[6][0] == '1'; - - bool kiaiMode = false; - bool omitFirstBarSignature = false; - if (split.Length >= 8) - { - int effectFlags = int.Parse(split[7]); - kiaiMode = (effectFlags & 1) > 0; - omitFirstBarSignature = (effectFlags & 8) > 0; - } - - string stringSampleSet = sampleSet.ToString().ToLower(); - if (stringSampleSet == @"none") - stringSampleSet = @"normal"; - - DifficultyControlPoint difficultyPoint = beatmap.ControlPointInfo.DifficultyPointAt(time); - SoundControlPoint soundPoint = beatmap.ControlPointInfo.SoundPointAt(time); - EffectControlPoint effectPoint = beatmap.ControlPointInfo.EffectPointAt(time); - - if (timingChange) - { - beatmap.ControlPointInfo.TimingPoints.Add(new TimingControlPoint - { - Time = time, - BeatLength = beatLength, - TimeSignature = timeSignature - }); - } - - if (speedMultiplier != difficultyPoint.SpeedMultiplier) - { - beatmap.ControlPointInfo.DifficultyPoints.RemoveAll(x => x.Time == time); - beatmap.ControlPointInfo.DifficultyPoints.Add(new DifficultyControlPoint - { - Time = time, - SpeedMultiplier = speedMultiplier - }); - } - - if (stringSampleSet != soundPoint.SampleBank || sampleVolume != soundPoint.SampleVolume) - { - beatmap.ControlPointInfo.SoundPoints.Add(new SoundControlPoint - { - Time = time, - SampleBank = stringSampleSet, - SampleVolume = sampleVolume - }); - } - - if (kiaiMode != effectPoint.KiaiMode || omitFirstBarSignature != effectPoint.OmitFirstBarLine) - { - beatmap.ControlPointInfo.EffectPoints.Add(new EffectControlPoint - { - Time = time, - KiaiMode = kiaiMode, - OmitFirstBarLine = omitFirstBarSignature - }); - } - } - - private void handleColours(Beatmap beatmap, string line, ref bool hasCustomColours) - { - if (beatmap == null) - throw new ArgumentNullException(nameof(beatmap)); - if (line == null) - throw new ArgumentNullException(nameof(line)); - - var pair = splitKeyVal(line, ':'); - - string[] split = pair.Value.Split(','); - - if (split.Length != 3) - throw new InvalidOperationException($@"Color specified in incorrect format (should be R,G,B): {pair.Value}"); - - byte r, g, b; - if (!byte.TryParse(split[0], out r) || !byte.TryParse(split[1], out g) || !byte.TryParse(split[2], out b)) - throw new InvalidOperationException(@"Color must be specified with 8-bit integer components"); - - if (!hasCustomColours) - { - beatmap.ComboColors.Clear(); - hasCustomColours = true; - } - - // Note: the combo index specified in the beatmap is discarded - if (pair.Key.StartsWith(@"Combo")) - { - beatmap.ComboColors.Add(new Color4 - { - R = r / 255f, - G = g / 255f, - B = b / 255f, - A = 1f, - }); - } - } - - private void handleVariables(string line) - { - if (line == null) - throw new ArgumentNullException(nameof(line)); - - var pair = splitKeyVal(line, '='); - variables[pair.Key] = pair.Value; - } - - /// - /// Decodes any beatmap variables present in a line into their real values. - /// - /// The line which may contains variables. - private void decodeVariables(ref string line) - { - if (line == null) - throw new ArgumentNullException(nameof(line)); - - while (line.IndexOf('$') >= 0) - { - string origLine = line; - string[] split = line.Split(','); - for (int i = 0; i < split.Length; i++) - { - var item = split[i]; - if (item.StartsWith("$") && variables.ContainsKey(item)) - split[i] = variables[item]; - } - - line = string.Join(",", split); - if (line == origLine) break; - } - } - - private static string cleanFilename(string path) - => FileSafety.PathStandardise(path.Trim('\"')); - - private static Anchor parseOrigin(string value) - { - var origin = (LegacyOrigins)Enum.Parse(typeof(LegacyOrigins), value); - switch (origin) - { - case LegacyOrigins.TopLeft: return Anchor.TopLeft; - case LegacyOrigins.TopCentre: return Anchor.TopCentre; - case LegacyOrigins.TopRight: return Anchor.TopRight; - case LegacyOrigins.CentreLeft: return Anchor.CentreLeft; - case LegacyOrigins.Centre: return Anchor.Centre; - case LegacyOrigins.CentreRight: return Anchor.CentreRight; - case LegacyOrigins.BottomLeft: return Anchor.BottomLeft; - case LegacyOrigins.BottomCentre: return Anchor.BottomCentre; - case LegacyOrigins.BottomRight: return Anchor.BottomRight; - } - throw new InvalidDataException($@"Unknown origin: {value}"); - } - - private static string parseLayer(string value) - => Enum.Parse(typeof(StoryLayer), value).ToString(); - - private KeyValuePair splitKeyVal(string line, char separator) - { - if (line == null) - throw new ArgumentNullException(nameof(line)); - - var split = line.Trim().Split(new[] { separator }, 2); - - return new KeyValuePair - ( - split[0].Trim(), - split.Length > 1 ? split[1].Trim() : string.Empty - ); - } - - private enum Section - { - None, - General, - Editor, - Metadata, - Difficulty, - Events, - TimingPoints, - Colours, - HitObjects, - Variables, - } - - internal enum LegacySampleBank - { - None = 0, - Normal = 1, - Soft = 2, - Drum = 3 - } - - internal enum EventType - { - Background = 0, - Video = 1, - Break = 2, - Colour = 3, - Sprite = 4, - Sample = 5, - Animation = 6 - } - - internal enum LegacyOrigins - { - TopLeft, - Centre, - CentreLeft, - TopRight, - BottomCentre, - TopCentre, - Custom, - CentreRight, - BottomLeft, - BottomRight - }; - - internal enum StoryLayer - { - Background = 0, - Fail = 1, - Pass = 2, - Foreground = 3 - } - } -} diff --git a/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs index d4f9c7191a..4300f76e9d 100644 --- a/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs +++ b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs @@ -177,8 +177,8 @@ namespace osu.Game.Rulesets.Objects.Legacy string[] split = str.Split(':'); - var bank = (OsuLegacyDecoder.LegacySampleBank)Convert.ToInt32(split[0]); - var addbank = (OsuLegacyDecoder.LegacySampleBank)Convert.ToInt32(split[1]); + var bank = (LegacyBeatmapDecoder.LegacySampleBank)Convert.ToInt32(split[0]); + var addbank = (LegacyBeatmapDecoder.LegacySampleBank)Convert.ToInt32(split[1]); // Let's not implement this for now, because this doesn't fit nicely into the bank structure //string sampleFile = split2.Length > 4 ? split2[4] : string.Empty; diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index ccd1bd03dc..4c33b2d266 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -269,6 +269,8 @@ + + @@ -312,7 +314,7 @@ - + From db50ad794e716f0221eca657c59e9d4616cabd65 Mon Sep 17 00:00:00 2001 From: Aergwyn Date: Fri, 1 Dec 2017 17:58:11 +0100 Subject: [PATCH 0963/1263] CI adjustments - removing unnecessary `using`s - name Fields/Methods according to rules - removing unnecessary initializations --- .../Beatmaps/Formats/LegacyBeatmapDecoder.cs | 90 ++++++++----------- osu.Game/Beatmaps/Formats/LegacyDecoder.cs | 47 ++++++---- .../Formats/LegacyStoryboardDecoder.cs | 17 ++-- .../Objects/Legacy/ConvertHitObjectParser.cs | 4 +- 4 files changed, 76 insertions(+), 82 deletions(-) diff --git a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs index c8e6d6cfea..61e9bbc11d 100644 --- a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs @@ -7,34 +7,20 @@ using System.Globalization; using System.IO; using OpenTK.Graphics; using osu.Game.Beatmaps.Timing; -using osu.Game.Beatmaps.Legacy; using osu.Game.Rulesets.Objects.Legacy; using osu.Game.Beatmaps.ControlPoints; -using osu.Game.Storyboards; -using OpenTK; -using osu.Framework.Graphics; -using osu.Framework.IO.File; namespace osu.Game.Beatmaps.Formats { public class LegacyBeatmapDecoder : LegacyDecoder { + private bool hasCustomColours; private ConvertHitObjectParser parser; - private bool hasCustomColours = false; private LegacySampleBank defaultSampleBank; private int defaultSampleVolume = 100; - public LegacyBeatmapDecoder() - { - } - - public LegacyBeatmapDecoder(string header) - { - beatmapVersion = int.Parse(header.Substring(17)); - } - - protected override void processSection(Section section, string line) + protected override void ProcessSection(Section section, string line) { switch (section) { @@ -72,20 +58,20 @@ namespace osu.Game.Beatmaps.Formats { var pair = splitKeyVal(line, ':'); - var metadata = beatmap.BeatmapInfo.Metadata; + var metadata = Beatmap.BeatmapInfo.Metadata; switch (pair.Key) { case @"AudioFilename": metadata.AudioFile = pair.Value; break; case @"AudioLeadIn": - beatmap.BeatmapInfo.AudioLeadIn = int.Parse(pair.Value); + Beatmap.BeatmapInfo.AudioLeadIn = int.Parse(pair.Value); break; case @"PreviewTime": metadata.PreviewTime = int.Parse(pair.Value); break; case @"Countdown": - beatmap.BeatmapInfo.Countdown = int.Parse(pair.Value) == 1; + Beatmap.BeatmapInfo.Countdown = int.Parse(pair.Value) == 1; break; case @"SampleSet": defaultSampleBank = (LegacySampleBank)Enum.Parse(typeof(LegacySampleBank), pair.Value); @@ -94,12 +80,12 @@ namespace osu.Game.Beatmaps.Formats defaultSampleVolume = int.Parse(pair.Value); break; case @"StackLeniency": - beatmap.BeatmapInfo.StackLeniency = float.Parse(pair.Value, NumberFormatInfo.InvariantInfo); + Beatmap.BeatmapInfo.StackLeniency = float.Parse(pair.Value, NumberFormatInfo.InvariantInfo); break; case @"Mode": - beatmap.BeatmapInfo.RulesetID = int.Parse(pair.Value); + Beatmap.BeatmapInfo.RulesetID = int.Parse(pair.Value); - switch (beatmap.BeatmapInfo.RulesetID) + switch (Beatmap.BeatmapInfo.RulesetID) { case 0: parser = new Rulesets.Objects.Legacy.Osu.ConvertHitObjectParser(); @@ -116,13 +102,13 @@ namespace osu.Game.Beatmaps.Formats } break; case @"LetterboxInBreaks": - beatmap.BeatmapInfo.LetterboxInBreaks = int.Parse(pair.Value) == 1; + Beatmap.BeatmapInfo.LetterboxInBreaks = int.Parse(pair.Value) == 1; break; case @"SpecialStyle": - beatmap.BeatmapInfo.SpecialStyle = int.Parse(pair.Value) == 1; + Beatmap.BeatmapInfo.SpecialStyle = int.Parse(pair.Value) == 1; break; case @"WidescreenStoryboard": - beatmap.BeatmapInfo.WidescreenStoryboard = int.Parse(pair.Value) == 1; + Beatmap.BeatmapInfo.WidescreenStoryboard = int.Parse(pair.Value) == 1; break; } } @@ -134,19 +120,19 @@ namespace osu.Game.Beatmaps.Formats switch (pair.Key) { case @"Bookmarks": - beatmap.BeatmapInfo.StoredBookmarks = pair.Value; + Beatmap.BeatmapInfo.StoredBookmarks = pair.Value; break; case @"DistanceSpacing": - beatmap.BeatmapInfo.DistanceSpacing = double.Parse(pair.Value, NumberFormatInfo.InvariantInfo); + Beatmap.BeatmapInfo.DistanceSpacing = double.Parse(pair.Value, NumberFormatInfo.InvariantInfo); break; case @"BeatDivisor": - beatmap.BeatmapInfo.BeatDivisor = int.Parse(pair.Value); + Beatmap.BeatmapInfo.BeatDivisor = int.Parse(pair.Value); break; case @"GridSize": - beatmap.BeatmapInfo.GridSize = int.Parse(pair.Value); + Beatmap.BeatmapInfo.GridSize = int.Parse(pair.Value); break; case @"TimelineZoom": - beatmap.BeatmapInfo.TimelineZoom = double.Parse(pair.Value, NumberFormatInfo.InvariantInfo); + Beatmap.BeatmapInfo.TimelineZoom = double.Parse(pair.Value, NumberFormatInfo.InvariantInfo); break; } } @@ -155,7 +141,7 @@ namespace osu.Game.Beatmaps.Formats { var pair = splitKeyVal(line, ':'); - var metadata = beatmap.BeatmapInfo.Metadata; + var metadata = Beatmap.BeatmapInfo.Metadata; switch (pair.Key) { case @"Title": @@ -174,19 +160,19 @@ namespace osu.Game.Beatmaps.Formats metadata.AuthorString = pair.Value; break; case @"Version": - beatmap.BeatmapInfo.Version = pair.Value; + Beatmap.BeatmapInfo.Version = pair.Value; break; case @"Source": - beatmap.BeatmapInfo.Metadata.Source = pair.Value; + Beatmap.BeatmapInfo.Metadata.Source = pair.Value; break; case @"Tags": - beatmap.BeatmapInfo.Metadata.Tags = pair.Value; + Beatmap.BeatmapInfo.Metadata.Tags = pair.Value; break; case @"BeatmapID": - beatmap.BeatmapInfo.OnlineBeatmapID = int.Parse(pair.Value); + Beatmap.BeatmapInfo.OnlineBeatmapID = int.Parse(pair.Value); break; case @"BeatmapSetID": - beatmap.BeatmapInfo.OnlineBeatmapSetID = int.Parse(pair.Value); + Beatmap.BeatmapInfo.OnlineBeatmapSetID = int.Parse(pair.Value); metadata.OnlineBeatmapSetID = int.Parse(pair.Value); break; } @@ -196,7 +182,7 @@ namespace osu.Game.Beatmaps.Formats { var pair = splitKeyVal(line, ':'); - var difficulty = beatmap.BeatmapInfo.BaseDifficulty; + var difficulty = Beatmap.BeatmapInfo.BaseDifficulty; switch (pair.Key) { case @"HPDrainRate": @@ -222,7 +208,7 @@ namespace osu.Game.Beatmaps.Formats private void handleEvents(string line) { - decodeVariables(ref line); + DecodeVariables(ref line); string[] split = line.Split(','); @@ -234,7 +220,7 @@ namespace osu.Game.Beatmaps.Formats { case EventType.Background: string filename = split[2].Trim('"'); - beatmap.BeatmapInfo.Metadata.BackgroundFile = filename; + Beatmap.BeatmapInfo.Metadata.BackgroundFile = filename; break; case EventType.Break: var breakEvent = new BreakPeriod @@ -246,7 +232,7 @@ namespace osu.Game.Beatmaps.Formats if (!breakEvent.HasEffect) return; - beatmap.Breaks.Add(breakEvent); + Beatmap.Breaks.Add(breakEvent); break; } } @@ -292,13 +278,13 @@ namespace osu.Game.Beatmaps.Formats if (stringSampleSet == @"none") stringSampleSet = @"normal"; - DifficultyControlPoint difficultyPoint = beatmap.ControlPointInfo.DifficultyPointAt(time); - SoundControlPoint soundPoint = beatmap.ControlPointInfo.SoundPointAt(time); - EffectControlPoint effectPoint = beatmap.ControlPointInfo.EffectPointAt(time); + DifficultyControlPoint difficultyPoint = Beatmap.ControlPointInfo.DifficultyPointAt(time); + SoundControlPoint soundPoint = Beatmap.ControlPointInfo.SoundPointAt(time); + EffectControlPoint effectPoint = Beatmap.ControlPointInfo.EffectPointAt(time); if (timingChange) { - beatmap.ControlPointInfo.TimingPoints.Add(new TimingControlPoint + Beatmap.ControlPointInfo.TimingPoints.Add(new TimingControlPoint { Time = time, BeatLength = beatLength, @@ -308,8 +294,8 @@ namespace osu.Game.Beatmaps.Formats if (speedMultiplier != difficultyPoint.SpeedMultiplier) { - beatmap.ControlPointInfo.DifficultyPoints.RemoveAll(x => x.Time == time); - beatmap.ControlPointInfo.DifficultyPoints.Add(new DifficultyControlPoint + Beatmap.ControlPointInfo.DifficultyPoints.RemoveAll(x => x.Time == time); + Beatmap.ControlPointInfo.DifficultyPoints.Add(new DifficultyControlPoint { Time = time, SpeedMultiplier = speedMultiplier @@ -318,7 +304,7 @@ namespace osu.Game.Beatmaps.Formats if (stringSampleSet != soundPoint.SampleBank || sampleVolume != soundPoint.SampleVolume) { - beatmap.ControlPointInfo.SoundPoints.Add(new SoundControlPoint + Beatmap.ControlPointInfo.SoundPoints.Add(new SoundControlPoint { Time = time, SampleBank = stringSampleSet, @@ -328,7 +314,7 @@ namespace osu.Game.Beatmaps.Formats if (kiaiMode != effectPoint.KiaiMode || omitFirstBarSignature != effectPoint.OmitFirstBarLine) { - beatmap.ControlPointInfo.EffectPoints.Add(new EffectControlPoint + Beatmap.ControlPointInfo.EffectPoints.Add(new EffectControlPoint { Time = time, KiaiMode = kiaiMode, @@ -352,14 +338,14 @@ namespace osu.Game.Beatmaps.Formats if (!hasCustomColours) { - beatmap.ComboColors.Clear(); + Beatmap.ComboColors.Clear(); hasCustomColours = true; } // Note: the combo index specified in the beatmap is discarded if (pair.Key.StartsWith(@"Combo")) { - beatmap.ComboColors.Add(new Color4 + Beatmap.ComboColors.Add(new Color4 { R = r / 255f, G = g / 255f, @@ -378,13 +364,13 @@ namespace osu.Game.Beatmaps.Formats var obj = parser.Parse(line); if (obj != null) - beatmap.HitObjects.Add(obj); + Beatmap.HitObjects.Add(obj); } private void handleVariables(string line) { var pair = splitKeyVal(line, '='); - variables[pair.Key] = pair.Value; + Variables[pair.Key] = pair.Value; } private KeyValuePair splitKeyVal(string line, char separator) diff --git a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs index 00b06d28d2..249b106962 100644 --- a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs @@ -4,15 +4,12 @@ using System; using System.Collections.Generic; using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using osu.Game.Beatmaps.Legacy; using osu.Game.Storyboards; namespace osu.Game.Beatmaps.Formats { - public abstract class LegacyDecoder : BeatmapDecoder + public class LegacyDecoder : BeatmapDecoder { public static void Register() { @@ -31,11 +28,20 @@ namespace osu.Game.Beatmaps.Formats // TODO: differences between versions } - protected Beatmap beatmap; - protected Storyboard storyboard; + public LegacyDecoder() + { + } - protected int beatmapVersion; - protected readonly Dictionary variables = new Dictionary(); + public LegacyDecoder(string header) + { + BeatmapVersion = int.Parse(header.Substring(17)); + } + + protected Beatmap Beatmap; + protected Storyboard Storyboard; + + protected int BeatmapVersion; + protected readonly Dictionary Variables = new Dictionary(); public override Beatmap DecodeBeatmap(StreamReader stream) => new LegacyBeatmap(base.DecodeBeatmap(stream)); @@ -48,13 +54,13 @@ namespace osu.Game.Beatmaps.Formats if (beatmap == null) throw new ArgumentNullException(nameof(beatmap)); - this.beatmap = beatmap; - this.beatmap.BeatmapInfo.BeatmapVersion = beatmapVersion; + Beatmap = beatmap; + Beatmap.BeatmapInfo.BeatmapVersion = BeatmapVersion; ParseContent(stream); - foreach (var hitObject in this.beatmap.HitObjects) - hitObject.ApplyDefaults(this.beatmap.ControlPointInfo, this.beatmap.BeatmapInfo.BaseDifficulty); + foreach (var hitObject in Beatmap.HitObjects) + hitObject.ApplyDefaults(Beatmap.ControlPointInfo, Beatmap.BeatmapInfo.BaseDifficulty); } protected override void ParseStoryboard(StreamReader stream, Storyboard storyboard) @@ -64,7 +70,7 @@ namespace osu.Game.Beatmaps.Formats if (storyboard == null) throw new ArgumentNullException(nameof(storyboard)); - this.storyboard = storyboard; + Storyboard = storyboard; ParseContent(stream); } @@ -84,7 +90,7 @@ namespace osu.Game.Beatmaps.Formats if (line.StartsWith(@"osu file format v")) { - beatmap.BeatmapInfo.BeatmapVersion = int.Parse(line.Substring(17)); + Beatmap.BeatmapInfo.BeatmapVersion = int.Parse(line.Substring(17)); continue; } @@ -95,17 +101,20 @@ namespace osu.Game.Beatmaps.Formats continue; } - processSection(section, line); + ProcessSection(section, line); } } - protected abstract void processSection(Section section, string line); + protected virtual void ProcessSection(Section section, string line) + { + + } /// /// Decodes any beatmap variables present in a line into their real values. /// /// The line which may contains variables. - protected void decodeVariables(ref string line) + protected void DecodeVariables(ref string line) { while (line.IndexOf('$') >= 0) { @@ -114,8 +123,8 @@ namespace osu.Game.Beatmaps.Formats for (int i = 0; i < split.Length; i++) { var item = split[i]; - if (item.StartsWith("$") && variables.ContainsKey(item)) - split[i] = variables[item]; + if (item.StartsWith("$") && Variables.ContainsKey(item)) + split[i] = Variables[item]; } line = string.Join(",", split); diff --git a/osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs index 9362676245..576eaead11 100644 --- a/osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs @@ -2,7 +2,6 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; -using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; @@ -18,8 +17,8 @@ namespace osu.Game.Beatmaps.Formats { public class LegacyStoryboardDecoder : LegacyDecoder { - private StoryboardSprite storyboardSprite = null; - private CommandTimelineGroup timelineGroup = null; + private StoryboardSprite storyboardSprite; + private CommandTimelineGroup timelineGroup; public LegacyStoryboardDecoder() { @@ -27,10 +26,10 @@ namespace osu.Game.Beatmaps.Formats public LegacyStoryboardDecoder(string header) { - beatmapVersion = int.Parse(header.Substring(17)); + BeatmapVersion = int.Parse(header.Substring(17)); } - protected override void processSection(Section section, string line) + protected override void ProcessSection(Section section, string line) { switch (section) { @@ -49,7 +48,7 @@ namespace osu.Game.Beatmaps.Formats line = line.Substring(1); } - decodeVariables(ref line); + DecodeVariables(ref line); string[] split = line.Split(','); @@ -71,7 +70,7 @@ namespace osu.Game.Beatmaps.Formats var x = float.Parse(split[4], NumberFormatInfo.InvariantInfo); var y = float.Parse(split[5], NumberFormatInfo.InvariantInfo); storyboardSprite = new StoryboardSprite(path, origin, new Vector2(x, y)); - storyboard.GetLayer(layer).Add(storyboardSprite); + Storyboard.GetLayer(layer).Add(storyboardSprite); } break; case EventType.Animation: @@ -85,7 +84,7 @@ namespace osu.Game.Beatmaps.Formats var frameDelay = double.Parse(split[7], NumberFormatInfo.InvariantInfo); var loopType = split.Length > 8 ? (AnimationLoopType)Enum.Parse(typeof(AnimationLoopType), split[8]) : AnimationLoopType.LoopForever; storyboardSprite = new StoryboardAnimation(path, origin, new Vector2(x, y), frameCount, frameDelay, loopType); - storyboard.GetLayer(layer).Add(storyboardSprite); + Storyboard.GetLayer(layer).Add(storyboardSprite); } break; case EventType.Sample: @@ -94,7 +93,7 @@ namespace osu.Game.Beatmaps.Formats var layer = parseLayer(split[2]); var path = cleanFilename(split[3]); var volume = split.Length > 4 ? float.Parse(split[4], CultureInfo.InvariantCulture) : 100; - storyboard.GetLayer(layer).Add(new StoryboardSample(path, time, volume)); + Storyboard.GetLayer(layer).Add(new StoryboardSample(path, time, volume)); } break; } diff --git a/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs index 4300f76e9d..0d7d617405 100644 --- a/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs +++ b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs @@ -177,8 +177,8 @@ namespace osu.Game.Rulesets.Objects.Legacy string[] split = str.Split(':'); - var bank = (LegacyBeatmapDecoder.LegacySampleBank)Convert.ToInt32(split[0]); - var addbank = (LegacyBeatmapDecoder.LegacySampleBank)Convert.ToInt32(split[1]); + var bank = (LegacyDecoder.LegacySampleBank)Convert.ToInt32(split[0]); + var addbank = (LegacyDecoder.LegacySampleBank)Convert.ToInt32(split[1]); // Let's not implement this for now, because this doesn't fit nicely into the bank structure //string sampleFile = split2.Length > 4 ? split2[4] : string.Empty; From de94082b1e142174f8d2275c3369b990df0f3ca3 Mon Sep 17 00:00:00 2001 From: gtensha Date: Fri, 1 Dec 2017 18:10:39 +0100 Subject: [PATCH 0964/1263] Fix filename casing to compile on Linux --- osu.Game/osu.Game.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index f814cbb3d3..8b6bdefc6c 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -280,7 +280,7 @@ 20171025071459_AddMissingIndexRules.cs - + 20171119065731_AddBeatmapOnlineIDUniqueConstraint.cs From a49f3479a2dcc111a821a6891814553443526ec7 Mon Sep 17 00:00:00 2001 From: Aergwyn Date: Fri, 1 Dec 2017 19:11:52 +0100 Subject: [PATCH 0965/1263] Split retrieving of beatmap and storyboard decoder Storyboard works again. Not satisfied with the solution though. --- .../Beatmaps/IO/OszArchiveReaderTest.cs | 2 +- osu.Game/Beatmaps/BeatmapManager.cs | 10 +- osu.Game/Beatmaps/Formats/BeatmapDecoder.cs | 67 ---------- osu.Game/Beatmaps/Formats/Decoder.cs | 120 ++++++++++++++++++ .../Beatmaps/Formats/LegacyBeatmapDecoder.cs | 9 ++ osu.Game/Beatmaps/Formats/LegacyDecoder.cs | 40 ++---- .../Formats/LegacyStoryboardDecoder.cs | 3 - osu.Game/Tests/Visual/TestCasePlayer.cs | 2 +- osu.Game/osu.Game.csproj | 2 +- 9 files changed, 151 insertions(+), 104 deletions(-) delete mode 100644 osu.Game/Beatmaps/Formats/BeatmapDecoder.cs create mode 100644 osu.Game/Beatmaps/Formats/Decoder.cs diff --git a/osu.Game.Tests/Beatmaps/IO/OszArchiveReaderTest.cs b/osu.Game.Tests/Beatmaps/IO/OszArchiveReaderTest.cs index 7b30a4f1fe..22b1d16f7d 100644 --- a/osu.Game.Tests/Beatmaps/IO/OszArchiveReaderTest.cs +++ b/osu.Game.Tests/Beatmaps/IO/OszArchiveReaderTest.cs @@ -50,7 +50,7 @@ namespace osu.Game.Tests.Beatmaps.IO BeatmapMetadata meta; using (var stream = new StreamReader(reader.GetStream("Soleily - Renatus (Deif) [Platter].osu"))) - meta = BeatmapDecoder.GetDecoder(stream).DecodeBeatmap(stream).Metadata; + meta = Decoder.GetBeatmapDecoder(stream).DecodeBeatmap(stream).Metadata; Assert.AreEqual(241526, meta.OnlineBeatmapSetID); Assert.AreEqual("Soleily", meta.Artist); diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index e5f2064ee3..e0d6ac214e 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -495,7 +495,7 @@ namespace osu.Game.Beatmaps BeatmapMetadata metadata; using (var stream = new StreamReader(reader.GetStream(mapName))) - metadata = BeatmapDecoder.GetDecoder(stream).DecodeBeatmap(stream).Metadata; + metadata = Decoder.GetBeatmapDecoder(stream).DecodeBeatmap(stream).Metadata; // check if a set already exists with the same online id. beatmapSet = beatmaps.BeatmapSets.FirstOrDefault(b => b.OnlineBeatmapSetID == metadata.OnlineBeatmapSetID) ?? new BeatmapSetInfo @@ -518,7 +518,7 @@ namespace osu.Game.Beatmaps raw.CopyTo(ms); ms.Position = 0; - var decoder = BeatmapDecoder.GetDecoder(sr); + var decoder = Decoder.GetBeatmapDecoder(sr); Beatmap beatmap = decoder.DecodeBeatmap(sr); beatmap.BeatmapInfo.Path = name; @@ -571,7 +571,7 @@ namespace osu.Game.Beatmaps { using (var stream = new StreamReader(store.GetStream(getPathForFile(BeatmapInfo.Path)))) { - BeatmapDecoder decoder = BeatmapDecoder.GetDecoder(stream); + Decoder decoder = Decoder.GetBeatmapDecoder(stream); return decoder.DecodeBeatmap(stream); } } @@ -620,9 +620,9 @@ namespace osu.Game.Beatmaps try { - BeatmapDecoder decoder; + Decoder decoder; using (var stream = new StreamReader(store.GetStream(getPathForFile(BeatmapInfo.Path)))) - decoder = BeatmapDecoder.GetDecoder(stream); + decoder = Decoder.GetStoryboardDecoder(stream); using (var stream = new StreamReader(store.GetStream(getPathForFile(BeatmapSetInfo.StoryboardFile)))) return decoder.DecodeStoryboard(stream); diff --git a/osu.Game/Beatmaps/Formats/BeatmapDecoder.cs b/osu.Game/Beatmaps/Formats/BeatmapDecoder.cs deleted file mode 100644 index 1ecc6c0ee0..0000000000 --- a/osu.Game/Beatmaps/Formats/BeatmapDecoder.cs +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright (c) 2007-2017 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using System; -using System.Collections.Generic; -using System.IO; -using osu.Game.Storyboards; - -namespace osu.Game.Beatmaps.Formats -{ - public abstract class BeatmapDecoder - { - private static readonly Dictionary decoders = new Dictionary(); - - static BeatmapDecoder() - { - LegacyDecoder.Register(); - } - - public static BeatmapDecoder GetDecoder(StreamReader stream) - { - if (stream == null) - throw new ArgumentNullException(nameof(stream)); - - string line; - do { line = stream.ReadLine()?.Trim(); } - while (line != null && line.Length == 0); - - if (line == null || !decoders.ContainsKey(line)) - throw new IOException(@"Unknown file format"); - return (BeatmapDecoder)Activator.CreateInstance(decoders[line], line); - } - - protected static void AddDecoder(string magic) where T : BeatmapDecoder - { - decoders[magic] = typeof(T); - } - - public virtual Beatmap DecodeBeatmap(StreamReader stream) => ParseBeatmap(stream); - - protected virtual Beatmap ParseBeatmap(StreamReader stream) - { - var beatmap = new Beatmap - { - BeatmapInfo = new BeatmapInfo - { - Metadata = new BeatmapMetadata(), - BaseDifficulty = new BeatmapDifficulty(), - }, - }; - - ParseBeatmap(stream, beatmap); - return beatmap; - } - - protected abstract void ParseBeatmap(StreamReader stream, Beatmap beatmap); - - public virtual Storyboard DecodeStoryboard(StreamReader stream) - { - var storyboard = new Storyboard(); - ParseStoryboard(stream, storyboard); - return storyboard; - } - - protected abstract void ParseStoryboard(StreamReader stream, Storyboard storyboard); - } -} diff --git a/osu.Game/Beatmaps/Formats/Decoder.cs b/osu.Game/Beatmaps/Formats/Decoder.cs new file mode 100644 index 0000000000..75e660bc8d --- /dev/null +++ b/osu.Game/Beatmaps/Formats/Decoder.cs @@ -0,0 +1,120 @@ +// 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.IO; +using osu.Game.Storyboards; + +namespace osu.Game.Beatmaps.Formats +{ + public abstract class Decoder + { + private static readonly Dictionary beatmapDecoders = new Dictionary(); + private static readonly Dictionary storyboardDecoders = new Dictionary(); + + static Decoder() + { + LegacyDecoder.Register(); + } + + /// + /// Retrieves a to parse s. + /// + /// A stream pointing to the to retrieve the version from. + public static Decoder GetBeatmapDecoder(StreamReader stream) + { + string line = readFirstLine(stream); + + if (line == null || !beatmapDecoders.ContainsKey(line)) + throw new IOException(@"Unknown file format"); + return (Decoder)Activator.CreateInstance(beatmapDecoders[line], line); + } + + /// + /// Retrieves a to parse s. + /// + /// A stream pointing to the to retrieve the version from. + public static Decoder GetStoryboardDecoder(StreamReader stream) + { + string line = readFirstLine(stream); + + if (line == null || !storyboardDecoders.ContainsKey(line)) + throw new IOException(@"Unknown file format"); + return (Decoder)Activator.CreateInstance(storyboardDecoders[line], line); + } + + private static string readFirstLine(StreamReader stream) + { + if (stream == null) + throw new ArgumentNullException(nameof(stream)); + + string line; + do + { line = stream.ReadLine()?.Trim(); } + while (line != null && line.Length == 0); + + return line; + } + + /// + /// Adds the to the list of and decoder. + /// + /// Type to decode a with. + /// /// Type to decode a with. + /// A string representation of the version. + protected static void AddDecoder(string version) where A : Decoder where B : Decoder + { + beatmapDecoders[version] = typeof(A); + storyboardDecoders[version] = typeof(B); + } + + /// + /// Adds the to the list of decoder. + /// + /// Type to decode a with. + /// A string representation of the version. + protected static void AddBeatmapDecoder(string version) where T : Decoder + { + beatmapDecoders[version] = typeof(T); + } + + /// + /// Adds the to the list of decoder. + /// + /// Type to decode a with. + /// A string representation of the version. + protected static void AddStoryboardDecoder(string version) where T : Decoder + { + storyboardDecoders[version] = typeof(T); + } + + public virtual Beatmap DecodeBeatmap(StreamReader stream) => ParseBeatmap(stream); + + protected virtual Beatmap ParseBeatmap(StreamReader stream) + { + var beatmap = new Beatmap + { + BeatmapInfo = new BeatmapInfo + { + Metadata = new BeatmapMetadata(), + BaseDifficulty = new BeatmapDifficulty(), + }, + }; + + ParseBeatmap(stream, beatmap); + return beatmap; + } + + protected abstract void ParseBeatmap(StreamReader stream, Beatmap beatmap); + + public virtual Storyboard DecodeStoryboard(StreamReader stream) + { + var storyboard = new Storyboard(); + ParseStoryboard(stream, storyboard); + return storyboard; + } + + protected abstract void ParseStoryboard(StreamReader stream, Storyboard storyboard); + } +} diff --git a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs index 61e9bbc11d..17215a935c 100644 --- a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs @@ -20,6 +20,15 @@ namespace osu.Game.Beatmaps.Formats private LegacySampleBank defaultSampleBank; private int defaultSampleVolume = 100; + public LegacyBeatmapDecoder() + { + } + + public LegacyBeatmapDecoder(string header) + { + BeatmapVersion = int.Parse(header.Substring(17)); + } + protected override void ProcessSection(Section section, string line) { switch (section) diff --git a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs index 249b106962..b060de5120 100644 --- a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs @@ -9,34 +9,25 @@ using osu.Game.Storyboards; namespace osu.Game.Beatmaps.Formats { - public class LegacyDecoder : BeatmapDecoder + public abstract class LegacyDecoder : Decoder { public static void Register() { - AddDecoder(@"osu file format v14"); - AddDecoder(@"osu file format v13"); - AddDecoder(@"osu file format v12"); - AddDecoder(@"osu file format v11"); - AddDecoder(@"osu file format v10"); - AddDecoder(@"osu file format v9"); - AddDecoder(@"osu file format v8"); - AddDecoder(@"osu file format v7"); - AddDecoder(@"osu file format v6"); - AddDecoder(@"osu file format v5"); - AddDecoder(@"osu file format v4"); - AddDecoder(@"osu file format v3"); + AddDecoder(@"osu file format v14"); + AddDecoder(@"osu file format v13"); + AddDecoder(@"osu file format v12"); + AddDecoder(@"osu file format v11"); + AddDecoder(@"osu file format v10"); + AddDecoder(@"osu file format v9"); + AddDecoder(@"osu file format v8"); + AddDecoder(@"osu file format v7"); + AddDecoder(@"osu file format v6"); + AddDecoder(@"osu file format v5"); + AddDecoder(@"osu file format v4"); + AddDecoder(@"osu file format v3"); // TODO: differences between versions } - public LegacyDecoder() - { - } - - public LegacyDecoder(string header) - { - BeatmapVersion = int.Parse(header.Substring(17)); - } - protected Beatmap Beatmap; protected Storyboard Storyboard; @@ -105,10 +96,7 @@ namespace osu.Game.Beatmaps.Formats } } - protected virtual void ProcessSection(Section section, string line) - { - - } + protected abstract void ProcessSection(Section section, string line); /// /// Decodes any beatmap variables present in a line into their real values. diff --git a/osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs index 576eaead11..317f99b9d5 100644 --- a/osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs @@ -4,9 +4,6 @@ using System; using System.Globalization; using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using OpenTK; using OpenTK.Graphics; using osu.Framework.Graphics; diff --git a/osu.Game/Tests/Visual/TestCasePlayer.cs b/osu.Game/Tests/Visual/TestCasePlayer.cs index d17f20ff2f..bca2cc02d0 100644 --- a/osu.Game/Tests/Visual/TestCasePlayer.cs +++ b/osu.Game/Tests/Visual/TestCasePlayer.cs @@ -63,7 +63,7 @@ namespace osu.Game.Tests.Visual using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(test_beatmap_data))) using (var reader = new StreamReader(stream)) - beatmap = BeatmapDecoder.GetDecoder(reader).DecodeBeatmap(reader); + beatmap = Game.Beatmaps.Formats.Decoder.GetBeatmapDecoder(reader).DecodeBeatmap(reader); return beatmap; } diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 4c33b2d266..1b1576b4c3 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -313,7 +313,7 @@ - + From c466296b14479ac0e8e6d290fd5db77a3a07ba86 Mon Sep 17 00:00:00 2001 From: Aergwyn Date: Fri, 1 Dec 2017 22:05:01 +0100 Subject: [PATCH 0966/1263] reverted split at Decoder, moved logic down I'm done experimenting, sorry - `Decoder` only returns a "Beatmap"`Decoder` now - "Storyboard"`Decoder` is retrieved from a "Beatmap"`Decoder` - moved parse methods down in the hierarchy where I forgot to do that - renamed `OsuLegacyDecoderTest` to `LegacyDecoderTest` --- ...acyDecoderTest.cs => LegacyDecoderTest.cs} | 2 +- .../Beatmaps/IO/OszArchiveReaderTest.cs | 2 +- osu.Game.Tests/osu.Game.Tests.csproj | 2 +- osu.Game/Beatmaps/BeatmapManager.cs | 10 +-- osu.Game/Beatmaps/Formats/Decoder.cs | 64 +++----------- .../Beatmaps/Formats/LegacyBeatmapDecoder.cs | 88 +++++++++++-------- osu.Game/Beatmaps/Formats/LegacyDecoder.cs | 64 +++++--------- .../Formats/LegacyStoryboardDecoder.cs | 24 +++-- osu.Game/Tests/Visual/TestCasePlayer.cs | 2 +- 9 files changed, 115 insertions(+), 143 deletions(-) rename osu.Game.Tests/Beatmaps/Formats/{OsuLegacyDecoderTest.cs => LegacyDecoderTest.cs} (97%) diff --git a/osu.Game.Tests/Beatmaps/Formats/OsuLegacyDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/LegacyDecoderTest.cs similarity index 97% rename from osu.Game.Tests/Beatmaps/Formats/OsuLegacyDecoderTest.cs rename to osu.Game.Tests/Beatmaps/Formats/LegacyDecoderTest.cs index 2ef1b796d1..4266afa526 100644 --- a/osu.Game.Tests/Beatmaps/Formats/OsuLegacyDecoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/LegacyDecoderTest.cs @@ -14,7 +14,7 @@ using osu.Game.Rulesets.Objects.Types; namespace osu.Game.Tests.Beatmaps.Formats { [TestFixture] - public class OsuLegacyDecoderTest + public class LegacyDecoderTest { [Test] public void TestDecodeMetadata() diff --git a/osu.Game.Tests/Beatmaps/IO/OszArchiveReaderTest.cs b/osu.Game.Tests/Beatmaps/IO/OszArchiveReaderTest.cs index 22b1d16f7d..ffe735c89f 100644 --- a/osu.Game.Tests/Beatmaps/IO/OszArchiveReaderTest.cs +++ b/osu.Game.Tests/Beatmaps/IO/OszArchiveReaderTest.cs @@ -50,7 +50,7 @@ namespace osu.Game.Tests.Beatmaps.IO BeatmapMetadata meta; using (var stream = new StreamReader(reader.GetStream("Soleily - Renatus (Deif) [Platter].osu"))) - meta = Decoder.GetBeatmapDecoder(stream).DecodeBeatmap(stream).Metadata; + meta = Decoder.GetDecoder(stream).DecodeBeatmap(stream).Metadata; Assert.AreEqual(241526, meta.OnlineBeatmapSetID); Assert.AreEqual("Soleily", meta.Artist); diff --git a/osu.Game.Tests/osu.Game.Tests.csproj b/osu.Game.Tests/osu.Game.Tests.csproj index 312a564f71..7d7adf5983 100644 --- a/osu.Game.Tests/osu.Game.Tests.csproj +++ b/osu.Game.Tests/osu.Game.Tests.csproj @@ -89,7 +89,7 @@ - + diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index e0d6ac214e..00182d5d85 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -495,7 +495,7 @@ namespace osu.Game.Beatmaps BeatmapMetadata metadata; using (var stream = new StreamReader(reader.GetStream(mapName))) - metadata = Decoder.GetBeatmapDecoder(stream).DecodeBeatmap(stream).Metadata; + metadata = Decoder.GetDecoder(stream).DecodeBeatmap(stream).Metadata; // check if a set already exists with the same online id. beatmapSet = beatmaps.BeatmapSets.FirstOrDefault(b => b.OnlineBeatmapSetID == metadata.OnlineBeatmapSetID) ?? new BeatmapSetInfo @@ -518,7 +518,7 @@ namespace osu.Game.Beatmaps raw.CopyTo(ms); ms.Position = 0; - var decoder = Decoder.GetBeatmapDecoder(sr); + var decoder = Decoder.GetDecoder(sr); Beatmap beatmap = decoder.DecodeBeatmap(sr); beatmap.BeatmapInfo.Path = name; @@ -571,7 +571,7 @@ namespace osu.Game.Beatmaps { using (var stream = new StreamReader(store.GetStream(getPathForFile(BeatmapInfo.Path)))) { - Decoder decoder = Decoder.GetBeatmapDecoder(stream); + Decoder decoder = Decoder.GetDecoder(stream); return decoder.DecodeBeatmap(stream); } } @@ -622,10 +622,10 @@ namespace osu.Game.Beatmaps { Decoder decoder; using (var stream = new StreamReader(store.GetStream(getPathForFile(BeatmapInfo.Path)))) - decoder = Decoder.GetStoryboardDecoder(stream); + decoder = Decoder.GetDecoder(stream); using (var stream = new StreamReader(store.GetStream(getPathForFile(BeatmapSetInfo.StoryboardFile)))) - return decoder.DecodeStoryboard(stream); + return decoder.GetStoryboardDecoder().DecodeStoryboard(stream); } catch { diff --git a/osu.Game/Beatmaps/Formats/Decoder.cs b/osu.Game/Beatmaps/Formats/Decoder.cs index 75e660bc8d..e157150651 100644 --- a/osu.Game/Beatmaps/Formats/Decoder.cs +++ b/osu.Game/Beatmaps/Formats/Decoder.cs @@ -10,8 +10,7 @@ namespace osu.Game.Beatmaps.Formats { public abstract class Decoder { - private static readonly Dictionary beatmapDecoders = new Dictionary(); - private static readonly Dictionary storyboardDecoders = new Dictionary(); + private static readonly Dictionary decoders = new Dictionary(); static Decoder() { @@ -19,32 +18,10 @@ namespace osu.Game.Beatmaps.Formats } /// - /// Retrieves a to parse s. + /// Retrieves a to parse a . /// - /// A stream pointing to the to retrieve the version from. - public static Decoder GetBeatmapDecoder(StreamReader stream) - { - string line = readFirstLine(stream); - - if (line == null || !beatmapDecoders.ContainsKey(line)) - throw new IOException(@"Unknown file format"); - return (Decoder)Activator.CreateInstance(beatmapDecoders[line], line); - } - - /// - /// Retrieves a to parse s. - /// - /// A stream pointing to the to retrieve the version from. - public static Decoder GetStoryboardDecoder(StreamReader stream) - { - string line = readFirstLine(stream); - - if (line == null || !storyboardDecoders.ContainsKey(line)) - throw new IOException(@"Unknown file format"); - return (Decoder)Activator.CreateInstance(storyboardDecoders[line], line); - } - - private static string readFirstLine(StreamReader stream) + /// A stream pointing to the . + public static Decoder GetDecoder(StreamReader stream) { if (stream == null) throw new ArgumentNullException(nameof(stream)); @@ -54,44 +31,27 @@ namespace osu.Game.Beatmaps.Formats { line = stream.ReadLine()?.Trim(); } while (line != null && line.Length == 0); - return line; + if (line == null || !decoders.ContainsKey(line)) + throw new IOException(@"Unknown file format"); + return (Decoder)Activator.CreateInstance(decoders[line], line); } /// /// Adds the to the list of and decoder. /// - /// Type to decode a with. - /// /// Type to decode a with. - /// A string representation of the version. - protected static void AddDecoder(string version) where A : Decoder where B : Decoder - { - beatmapDecoders[version] = typeof(A); - storyboardDecoders[version] = typeof(B); - } - - /// - /// Adds the to the list of decoder. - /// /// Type to decode a with. /// A string representation of the version. - protected static void AddBeatmapDecoder(string version) where T : Decoder + protected static void AddDecoder(string version) where T : Decoder { - beatmapDecoders[version] = typeof(T); + decoders[version] = typeof(T); } /// - /// Adds the to the list of decoder. + /// Retrieves a to parse a /// - /// Type to decode a with. - /// A string representation of the version. - protected static void AddStoryboardDecoder(string version) where T : Decoder - { - storyboardDecoders[version] = typeof(T); - } + public abstract Decoder GetStoryboardDecoder(); - public virtual Beatmap DecodeBeatmap(StreamReader stream) => ParseBeatmap(stream); - - protected virtual Beatmap ParseBeatmap(StreamReader stream) + public virtual Beatmap DecodeBeatmap(StreamReader stream) { var beatmap = new Beatmap { diff --git a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs index 17215a935c..29cf7dd913 100644 --- a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs @@ -2,18 +2,20 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; -using System.Collections.Generic; using System.Globalization; using System.IO; using OpenTK.Graphics; using osu.Game.Beatmaps.Timing; using osu.Game.Rulesets.Objects.Legacy; using osu.Game.Beatmaps.ControlPoints; +using System.Collections.Generic; namespace osu.Game.Beatmaps.Formats { public class LegacyBeatmapDecoder : LegacyDecoder { + private Beatmap beatmap; + private bool hasCustomColours; private ConvertHitObjectParser parser; @@ -29,6 +31,22 @@ namespace osu.Game.Beatmaps.Formats BeatmapVersion = int.Parse(header.Substring(17)); } + protected override void ParseBeatmap(StreamReader stream, Beatmap beatmap) + { + if (stream == null) + throw new ArgumentNullException(nameof(stream)); + if (beatmap == null) + throw new ArgumentNullException(nameof(beatmap)); + + this.beatmap = beatmap; + this.beatmap.BeatmapInfo.BeatmapVersion = BeatmapVersion; + + ParseContent(stream); + + foreach (var hitObject in this.beatmap.HitObjects) + hitObject.ApplyDefaults(this.beatmap.ControlPointInfo, this.beatmap.BeatmapInfo.BaseDifficulty); + } + protected override void ProcessSection(Section section, string line) { switch (section) @@ -67,20 +85,20 @@ namespace osu.Game.Beatmaps.Formats { var pair = splitKeyVal(line, ':'); - var metadata = Beatmap.BeatmapInfo.Metadata; + var metadata = beatmap.BeatmapInfo.Metadata; switch (pair.Key) { case @"AudioFilename": metadata.AudioFile = pair.Value; break; case @"AudioLeadIn": - Beatmap.BeatmapInfo.AudioLeadIn = int.Parse(pair.Value); + beatmap.BeatmapInfo.AudioLeadIn = int.Parse(pair.Value); break; case @"PreviewTime": metadata.PreviewTime = int.Parse(pair.Value); break; case @"Countdown": - Beatmap.BeatmapInfo.Countdown = int.Parse(pair.Value) == 1; + beatmap.BeatmapInfo.Countdown = int.Parse(pair.Value) == 1; break; case @"SampleSet": defaultSampleBank = (LegacySampleBank)Enum.Parse(typeof(LegacySampleBank), pair.Value); @@ -89,12 +107,12 @@ namespace osu.Game.Beatmaps.Formats defaultSampleVolume = int.Parse(pair.Value); break; case @"StackLeniency": - Beatmap.BeatmapInfo.StackLeniency = float.Parse(pair.Value, NumberFormatInfo.InvariantInfo); + beatmap.BeatmapInfo.StackLeniency = float.Parse(pair.Value, NumberFormatInfo.InvariantInfo); break; case @"Mode": - Beatmap.BeatmapInfo.RulesetID = int.Parse(pair.Value); + beatmap.BeatmapInfo.RulesetID = int.Parse(pair.Value); - switch (Beatmap.BeatmapInfo.RulesetID) + switch (beatmap.BeatmapInfo.RulesetID) { case 0: parser = new Rulesets.Objects.Legacy.Osu.ConvertHitObjectParser(); @@ -111,13 +129,13 @@ namespace osu.Game.Beatmaps.Formats } break; case @"LetterboxInBreaks": - Beatmap.BeatmapInfo.LetterboxInBreaks = int.Parse(pair.Value) == 1; + beatmap.BeatmapInfo.LetterboxInBreaks = int.Parse(pair.Value) == 1; break; case @"SpecialStyle": - Beatmap.BeatmapInfo.SpecialStyle = int.Parse(pair.Value) == 1; + beatmap.BeatmapInfo.SpecialStyle = int.Parse(pair.Value) == 1; break; case @"WidescreenStoryboard": - Beatmap.BeatmapInfo.WidescreenStoryboard = int.Parse(pair.Value) == 1; + beatmap.BeatmapInfo.WidescreenStoryboard = int.Parse(pair.Value) == 1; break; } } @@ -129,19 +147,19 @@ namespace osu.Game.Beatmaps.Formats switch (pair.Key) { case @"Bookmarks": - Beatmap.BeatmapInfo.StoredBookmarks = pair.Value; + beatmap.BeatmapInfo.StoredBookmarks = pair.Value; break; case @"DistanceSpacing": - Beatmap.BeatmapInfo.DistanceSpacing = double.Parse(pair.Value, NumberFormatInfo.InvariantInfo); + beatmap.BeatmapInfo.DistanceSpacing = double.Parse(pair.Value, NumberFormatInfo.InvariantInfo); break; case @"BeatDivisor": - Beatmap.BeatmapInfo.BeatDivisor = int.Parse(pair.Value); + beatmap.BeatmapInfo.BeatDivisor = int.Parse(pair.Value); break; case @"GridSize": - Beatmap.BeatmapInfo.GridSize = int.Parse(pair.Value); + beatmap.BeatmapInfo.GridSize = int.Parse(pair.Value); break; case @"TimelineZoom": - Beatmap.BeatmapInfo.TimelineZoom = double.Parse(pair.Value, NumberFormatInfo.InvariantInfo); + beatmap.BeatmapInfo.TimelineZoom = double.Parse(pair.Value, NumberFormatInfo.InvariantInfo); break; } } @@ -150,7 +168,7 @@ namespace osu.Game.Beatmaps.Formats { var pair = splitKeyVal(line, ':'); - var metadata = Beatmap.BeatmapInfo.Metadata; + var metadata = beatmap.BeatmapInfo.Metadata; switch (pair.Key) { case @"Title": @@ -169,19 +187,19 @@ namespace osu.Game.Beatmaps.Formats metadata.AuthorString = pair.Value; break; case @"Version": - Beatmap.BeatmapInfo.Version = pair.Value; + beatmap.BeatmapInfo.Version = pair.Value; break; case @"Source": - Beatmap.BeatmapInfo.Metadata.Source = pair.Value; + beatmap.BeatmapInfo.Metadata.Source = pair.Value; break; case @"Tags": - Beatmap.BeatmapInfo.Metadata.Tags = pair.Value; + beatmap.BeatmapInfo.Metadata.Tags = pair.Value; break; case @"BeatmapID": - Beatmap.BeatmapInfo.OnlineBeatmapID = int.Parse(pair.Value); + beatmap.BeatmapInfo.OnlineBeatmapID = int.Parse(pair.Value); break; case @"BeatmapSetID": - Beatmap.BeatmapInfo.OnlineBeatmapSetID = int.Parse(pair.Value); + beatmap.BeatmapInfo.OnlineBeatmapSetID = int.Parse(pair.Value); metadata.OnlineBeatmapSetID = int.Parse(pair.Value); break; } @@ -191,7 +209,7 @@ namespace osu.Game.Beatmaps.Formats { var pair = splitKeyVal(line, ':'); - var difficulty = Beatmap.BeatmapInfo.BaseDifficulty; + var difficulty = beatmap.BeatmapInfo.BaseDifficulty; switch (pair.Key) { case @"HPDrainRate": @@ -229,7 +247,7 @@ namespace osu.Game.Beatmaps.Formats { case EventType.Background: string filename = split[2].Trim('"'); - Beatmap.BeatmapInfo.Metadata.BackgroundFile = filename; + beatmap.BeatmapInfo.Metadata.BackgroundFile = filename; break; case EventType.Break: var breakEvent = new BreakPeriod @@ -241,7 +259,7 @@ namespace osu.Game.Beatmaps.Formats if (!breakEvent.HasEffect) return; - Beatmap.Breaks.Add(breakEvent); + beatmap.Breaks.Add(breakEvent); break; } } @@ -287,13 +305,13 @@ namespace osu.Game.Beatmaps.Formats if (stringSampleSet == @"none") stringSampleSet = @"normal"; - DifficultyControlPoint difficultyPoint = Beatmap.ControlPointInfo.DifficultyPointAt(time); - SoundControlPoint soundPoint = Beatmap.ControlPointInfo.SoundPointAt(time); - EffectControlPoint effectPoint = Beatmap.ControlPointInfo.EffectPointAt(time); + DifficultyControlPoint difficultyPoint = beatmap.ControlPointInfo.DifficultyPointAt(time); + SoundControlPoint soundPoint = beatmap.ControlPointInfo.SoundPointAt(time); + EffectControlPoint effectPoint = beatmap.ControlPointInfo.EffectPointAt(time); if (timingChange) { - Beatmap.ControlPointInfo.TimingPoints.Add(new TimingControlPoint + beatmap.ControlPointInfo.TimingPoints.Add(new TimingControlPoint { Time = time, BeatLength = beatLength, @@ -303,8 +321,8 @@ namespace osu.Game.Beatmaps.Formats if (speedMultiplier != difficultyPoint.SpeedMultiplier) { - Beatmap.ControlPointInfo.DifficultyPoints.RemoveAll(x => x.Time == time); - Beatmap.ControlPointInfo.DifficultyPoints.Add(new DifficultyControlPoint + beatmap.ControlPointInfo.DifficultyPoints.RemoveAll(x => x.Time == time); + beatmap.ControlPointInfo.DifficultyPoints.Add(new DifficultyControlPoint { Time = time, SpeedMultiplier = speedMultiplier @@ -313,7 +331,7 @@ namespace osu.Game.Beatmaps.Formats if (stringSampleSet != soundPoint.SampleBank || sampleVolume != soundPoint.SampleVolume) { - Beatmap.ControlPointInfo.SoundPoints.Add(new SoundControlPoint + beatmap.ControlPointInfo.SoundPoints.Add(new SoundControlPoint { Time = time, SampleBank = stringSampleSet, @@ -323,7 +341,7 @@ namespace osu.Game.Beatmaps.Formats if (kiaiMode != effectPoint.KiaiMode || omitFirstBarSignature != effectPoint.OmitFirstBarLine) { - Beatmap.ControlPointInfo.EffectPoints.Add(new EffectControlPoint + beatmap.ControlPointInfo.EffectPoints.Add(new EffectControlPoint { Time = time, KiaiMode = kiaiMode, @@ -347,14 +365,14 @@ namespace osu.Game.Beatmaps.Formats if (!hasCustomColours) { - Beatmap.ComboColors.Clear(); + beatmap.ComboColors.Clear(); hasCustomColours = true; } // Note: the combo index specified in the beatmap is discarded if (pair.Key.StartsWith(@"Combo")) { - Beatmap.ComboColors.Add(new Color4 + beatmap.ComboColors.Add(new Color4 { R = r / 255f, G = g / 255f, @@ -373,7 +391,7 @@ namespace osu.Game.Beatmaps.Formats var obj = parser.Parse(line); if (obj != null) - Beatmap.HitObjects.Add(obj); + beatmap.HitObjects.Add(obj); } private void handleVariables(string line) diff --git a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs index b060de5120..85d77d93bc 100644 --- a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs @@ -13,57 +13,36 @@ namespace osu.Game.Beatmaps.Formats { public static void Register() { - AddDecoder(@"osu file format v14"); - AddDecoder(@"osu file format v13"); - AddDecoder(@"osu file format v12"); - AddDecoder(@"osu file format v11"); - AddDecoder(@"osu file format v10"); - AddDecoder(@"osu file format v9"); - AddDecoder(@"osu file format v8"); - AddDecoder(@"osu file format v7"); - AddDecoder(@"osu file format v6"); - AddDecoder(@"osu file format v5"); - AddDecoder(@"osu file format v4"); - AddDecoder(@"osu file format v3"); + AddDecoder(@"osu file format v14"); + AddDecoder(@"osu file format v13"); + AddDecoder(@"osu file format v12"); + AddDecoder(@"osu file format v11"); + AddDecoder(@"osu file format v10"); + AddDecoder(@"osu file format v9"); + AddDecoder(@"osu file format v8"); + AddDecoder(@"osu file format v7"); + AddDecoder(@"osu file format v6"); + AddDecoder(@"osu file format v5"); + AddDecoder(@"osu file format v4"); + AddDecoder(@"osu file format v3"); // TODO: differences between versions } - protected Beatmap Beatmap; - protected Storyboard Storyboard; - protected int BeatmapVersion; protected readonly Dictionary Variables = new Dictionary(); - public override Beatmap DecodeBeatmap(StreamReader stream) => new LegacyBeatmap(base.DecodeBeatmap(stream)); + public override Decoder GetStoryboardDecoder() => new LegacyStoryboardDecoder(BeatmapVersion); - protected override Beatmap ParseBeatmap(StreamReader stream) => new LegacyBeatmap(base.ParseBeatmap(stream)); + public override Beatmap DecodeBeatmap(StreamReader stream) => new LegacyBeatmap(base.DecodeBeatmap(stream)); protected override void ParseBeatmap(StreamReader stream, Beatmap beatmap) { - if (stream == null) - throw new ArgumentNullException(nameof(stream)); - if (beatmap == null) - throw new ArgumentNullException(nameof(beatmap)); - - Beatmap = beatmap; - Beatmap.BeatmapInfo.BeatmapVersion = BeatmapVersion; - - ParseContent(stream); - - foreach (var hitObject in Beatmap.HitObjects) - hitObject.ApplyDefaults(Beatmap.ControlPointInfo, Beatmap.BeatmapInfo.BaseDifficulty); + throw new NotImplementedException(); } protected override void ParseStoryboard(StreamReader stream, Storyboard storyboard) { - if (stream == null) - throw new ArgumentNullException(nameof(stream)); - if (storyboard == null) - throw new ArgumentNullException(nameof(storyboard)); - - Storyboard = storyboard; - - ParseContent(stream); + throw new NotImplementedException(); } protected void ParseContent(StreamReader stream) @@ -79,11 +58,12 @@ namespace osu.Game.Beatmaps.Formats if (line.StartsWith("//")) continue; - if (line.StartsWith(@"osu file format v")) - { - Beatmap.BeatmapInfo.BeatmapVersion = int.Parse(line.Substring(17)); - continue; - } + // It's already set in ParseBeatmap... why do it again? + //if (line.StartsWith(@"osu file format v")) + //{ + // Beatmap.BeatmapInfo.BeatmapVersion = int.Parse(line.Substring(17)); + // continue; + //} if (line.StartsWith(@"[") && line.EndsWith(@"]")) { diff --git a/osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs index 317f99b9d5..aca92f3969 100644 --- a/osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs @@ -14,6 +14,8 @@ namespace osu.Game.Beatmaps.Formats { public class LegacyStoryboardDecoder : LegacyDecoder { + private Storyboard storyboard; + private StoryboardSprite storyboardSprite; private CommandTimelineGroup timelineGroup; @@ -21,9 +23,21 @@ namespace osu.Game.Beatmaps.Formats { } - public LegacyStoryboardDecoder(string header) + public LegacyStoryboardDecoder(int beatmapVersion) { - BeatmapVersion = int.Parse(header.Substring(17)); + BeatmapVersion = beatmapVersion; + } + + protected override void ParseStoryboard(StreamReader stream, Storyboard storyboard) + { + if (stream == null) + throw new ArgumentNullException(nameof(stream)); + if (storyboard == null) + throw new ArgumentNullException(nameof(storyboard)); + + this.storyboard = storyboard; + + ParseContent(stream); } protected override void ProcessSection(Section section, string line) @@ -67,7 +81,7 @@ namespace osu.Game.Beatmaps.Formats var x = float.Parse(split[4], NumberFormatInfo.InvariantInfo); var y = float.Parse(split[5], NumberFormatInfo.InvariantInfo); storyboardSprite = new StoryboardSprite(path, origin, new Vector2(x, y)); - Storyboard.GetLayer(layer).Add(storyboardSprite); + storyboard.GetLayer(layer).Add(storyboardSprite); } break; case EventType.Animation: @@ -81,7 +95,7 @@ namespace osu.Game.Beatmaps.Formats var frameDelay = double.Parse(split[7], NumberFormatInfo.InvariantInfo); var loopType = split.Length > 8 ? (AnimationLoopType)Enum.Parse(typeof(AnimationLoopType), split[8]) : AnimationLoopType.LoopForever; storyboardSprite = new StoryboardAnimation(path, origin, new Vector2(x, y), frameCount, frameDelay, loopType); - Storyboard.GetLayer(layer).Add(storyboardSprite); + storyboard.GetLayer(layer).Add(storyboardSprite); } break; case EventType.Sample: @@ -90,7 +104,7 @@ namespace osu.Game.Beatmaps.Formats var layer = parseLayer(split[2]); var path = cleanFilename(split[3]); var volume = split.Length > 4 ? float.Parse(split[4], CultureInfo.InvariantCulture) : 100; - Storyboard.GetLayer(layer).Add(new StoryboardSample(path, time, volume)); + storyboard.GetLayer(layer).Add(new StoryboardSample(path, time, volume)); } break; } diff --git a/osu.Game/Tests/Visual/TestCasePlayer.cs b/osu.Game/Tests/Visual/TestCasePlayer.cs index bca2cc02d0..35d16d14a5 100644 --- a/osu.Game/Tests/Visual/TestCasePlayer.cs +++ b/osu.Game/Tests/Visual/TestCasePlayer.cs @@ -63,7 +63,7 @@ namespace osu.Game.Tests.Visual using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(test_beatmap_data))) using (var reader = new StreamReader(stream)) - beatmap = Game.Beatmaps.Formats.Decoder.GetBeatmapDecoder(reader).DecodeBeatmap(reader); + beatmap = Game.Beatmaps.Formats.Decoder.GetDecoder(reader).DecodeBeatmap(reader); return beatmap; } From e07b85311b29cff6c5b057cb2eb574be5948cb36 Mon Sep 17 00:00:00 2001 From: Aergwyn Date: Fri, 1 Dec 2017 22:15:10 +0100 Subject: [PATCH 0967/1263] removed unnecessary using --- osu.Game/Tests/Visual/TestCasePlayer.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Tests/Visual/TestCasePlayer.cs b/osu.Game/Tests/Visual/TestCasePlayer.cs index 35d16d14a5..106f0fa8f3 100644 --- a/osu.Game/Tests/Visual/TestCasePlayer.cs +++ b/osu.Game/Tests/Visual/TestCasePlayer.cs @@ -8,7 +8,6 @@ using System.Text; using osu.Framework.Allocation; using osu.Framework.Graphics.Shapes; using osu.Game.Beatmaps; -using osu.Game.Beatmaps.Formats; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; using osu.Game.Screens.Play; From 5a7c4772bd57453466f9cc2f3599f54b7882ce22 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Sat, 2 Dec 2017 19:53:11 +0900 Subject: [PATCH 0968/1263] Remove PlayfieldUnderlay for now --- osu.Game/Rulesets/Edit/HitObjectComposer.cs | 3 --- osu.Game/Rulesets/Edit/PlayfieldUnderlay.cs | 16 ---------------- osu.Game/osu.Game.csproj | 1 - 3 files changed, 20 deletions(-) delete mode 100644 osu.Game/Rulesets/Edit/PlayfieldUnderlay.cs diff --git a/osu.Game/Rulesets/Edit/HitObjectComposer.cs b/osu.Game/Rulesets/Edit/HitObjectComposer.cs index f55b7b0531..767e8ade46 100644 --- a/osu.Game/Rulesets/Edit/HitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/HitObjectComposer.cs @@ -77,7 +77,6 @@ namespace osu.Game.Rulesets.Edit Alpha = 0, AlwaysPresent = true, }, - CreateUnderlay(rulesetContainer.Playfield), rulesetContainer, CreateOverlay(rulesetContainer.Playfield) } @@ -106,8 +105,6 @@ namespace osu.Game.Rulesets.Edit protected virtual RulesetContainer CreateRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap) => ruleset.CreateRulesetContainerWith(beatmap, true); - protected virtual PlayfieldUnderlay CreateUnderlay(Playfield playfield) => new PlayfieldUnderlay(); - protected virtual PlayfieldOverlay CreateOverlay(Playfield playfield) => new PlayfieldOverlay(); protected abstract IReadOnlyList CompositionTools { get; } diff --git a/osu.Game/Rulesets/Edit/PlayfieldUnderlay.cs b/osu.Game/Rulesets/Edit/PlayfieldUnderlay.cs deleted file mode 100644 index bace5258f8..0000000000 --- a/osu.Game/Rulesets/Edit/PlayfieldUnderlay.cs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) 2007-2017 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; - -namespace osu.Game.Rulesets.Edit -{ - public class PlayfieldUnderlay : CompositeDrawable - { - public PlayfieldUnderlay() - { - RelativeSizeAxes = Axes.Both; - } - } -} diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index ad1370890f..ee5834890f 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -303,7 +303,6 @@ - From a80059032cdc94a37a83b78fd86b4466be095c61 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Sat, 2 Dec 2017 20:24:10 +0900 Subject: [PATCH 0969/1263] Remove PlayfieldOverlay --- osu.Game/Rulesets/Edit/HitObjectComposer.cs | 5 +---- osu.Game/Rulesets/Edit/PlayfieldOverlay.cs | 19 ------------------- osu.Game/osu.Game.csproj | 1 - 3 files changed, 1 insertion(+), 24 deletions(-) delete mode 100644 osu.Game/Rulesets/Edit/PlayfieldOverlay.cs diff --git a/osu.Game/Rulesets/Edit/HitObjectComposer.cs b/osu.Game/Rulesets/Edit/HitObjectComposer.cs index 767e8ade46..3184b84e98 100644 --- a/osu.Game/Rulesets/Edit/HitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/HitObjectComposer.cs @@ -77,8 +77,7 @@ namespace osu.Game.Rulesets.Edit Alpha = 0, AlwaysPresent = true, }, - rulesetContainer, - CreateOverlay(rulesetContainer.Playfield) + rulesetContainer } } }, @@ -105,8 +104,6 @@ namespace osu.Game.Rulesets.Edit protected virtual RulesetContainer CreateRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap) => ruleset.CreateRulesetContainerWith(beatmap, true); - protected virtual PlayfieldOverlay CreateOverlay(Playfield playfield) => new PlayfieldOverlay(); - protected abstract IReadOnlyList CompositionTools { get; } } } diff --git a/osu.Game/Rulesets/Edit/PlayfieldOverlay.cs b/osu.Game/Rulesets/Edit/PlayfieldOverlay.cs deleted file mode 100644 index 58b15e3de2..0000000000 --- a/osu.Game/Rulesets/Edit/PlayfieldOverlay.cs +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) 2007-2017 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; - -namespace osu.Game.Rulesets.Edit -{ - public class PlayfieldOverlay : CompositeDrawable - { - public PlayfieldOverlay() - { - RelativeSizeAxes = Axes.Both; - - } - - - } -} diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index ee5834890f..e1425ff8b8 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -302,7 +302,6 @@ - From c14d68e685143e00f8d37a2c1bc3d4f9d883378e Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Sat, 2 Dec 2017 20:30:18 +0900 Subject: [PATCH 0970/1263] Use OsuColour for radio buttons --- .../RadioButtons/DrawableRadioButton.cs | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/osu.Game/Screens/Edit/Screens/Compose/RadioButtons/DrawableRadioButton.cs b/osu.Game/Screens/Edit/Screens/Compose/RadioButtons/DrawableRadioButton.cs index 48cc7f3379..10b6c07f3d 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/RadioButtons/DrawableRadioButton.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/RadioButtons/DrawableRadioButton.cs @@ -19,16 +19,16 @@ namespace osu.Game.Screens.Edit.Screens.Compose.RadioButtons { public class DrawableRadioButton : TriangleButton { - private static readonly Color4 default_background_colour = OsuColour.FromHex("333"); - private static readonly Color4 default_bubble_colour = default_background_colour.Darken(0.5f); - private static readonly Color4 selected_background_colour = OsuColour.FromHex("1188aa"); - private static readonly Color4 selected_bubble_colour = selected_background_colour.Lighten(0.5f); - /// /// Invoked when this has been selected. /// public Action Selected; + private Color4 defaultBackgroundColour; + private Color4 defaultBubbleColour; + private Color4 selectedBackgroundColour; + private Color4 selectedBubbleColour; + private readonly Drawable bubble; private readonly RadioButton button; @@ -50,17 +50,20 @@ namespace osu.Game.Screens.Edit.Screens.Compose.RadioButtons Scale = new Vector2(0.5f), X = 10, Masking = true, - Colour = default_bubble_colour, Blending = BlendingMode.Additive, Child = new Box { RelativeSizeAxes = Axes.Both } }; } [BackgroundDependencyLoader] - private void load() + private void load(OsuColour colours) { + defaultBackgroundColour = colours.Gray3; + defaultBubbleColour = defaultBackgroundColour.Darken(0.5f); + selectedBackgroundColour = colours.BlueDark; + selectedBubbleColour = selectedBackgroundColour.Lighten(0.5f); + Triangles.Alpha = 0; - BackgroundColour = default_background_colour; Content.EdgeEffect = new EdgeEffectParameters { @@ -92,8 +95,8 @@ namespace osu.Game.Screens.Edit.Screens.Compose.RadioButtons if (!IsLoaded) return; - BackgroundColour = button.Selected ? selected_background_colour : default_background_colour; - bubble.Colour = button.Selected ? selected_bubble_colour : default_bubble_colour; + BackgroundColour = button.Selected ? selectedBackgroundColour : defaultBackgroundColour; + bubble.Colour = button.Selected ? selectedBubbleColour : defaultBubbleColour; } protected override bool OnClick(InputState state) From cd20d6df160b1b4617b4f8035dc31ee52063588f Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Sat, 2 Dec 2017 20:31:10 +0900 Subject: [PATCH 0971/1263] Apply suggested changes --- osu.Game/Screens/Edit/Editor.cs | 1 - .../Edit/Screens/Compose/RadioButtons/RadioButtonCollection.cs | 2 +- osu.Game/Screens/Edit/Screens/EditorScreen.cs | 2 -- 3 files changed, 1 insertion(+), 4 deletions(-) diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index bc86c683c7..607ff792d8 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -154,7 +154,6 @@ namespace osu.Game.Screens.Edit } currentScreen.Beatmap.BindTo(Beatmap); - currentScreen.ExitRequested = Exit; screenContainer.Add(currentScreen); } diff --git a/osu.Game/Screens/Edit/Screens/Compose/RadioButtons/RadioButtonCollection.cs b/osu.Game/Screens/Edit/Screens/Compose/RadioButtons/RadioButtonCollection.cs index 08473eaeba..5f1def4a2e 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/RadioButtons/RadioButtonCollection.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/RadioButtons/RadioButtonCollection.cs @@ -22,7 +22,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose.RadioButtons items = value; buttonContainer.Clear(); - value.ForEach(addButton); + items.ForEach(addButton); } } diff --git a/osu.Game/Screens/Edit/Screens/EditorScreen.cs b/osu.Game/Screens/Edit/Screens/EditorScreen.cs index 9a158d20f1..773975d493 100644 --- a/osu.Game/Screens/Edit/Screens/EditorScreen.cs +++ b/osu.Game/Screens/Edit/Screens/EditorScreen.cs @@ -11,8 +11,6 @@ namespace osu.Game.Screens.Edit.Screens { public class EditorScreen : Container { - public Action ExitRequested; - public readonly Bindable Beatmap = new Bindable(); protected override Container Content => content; From 2852337b04c0160a6b52e5376acdf73e09af4fd8 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Sat, 2 Dec 2017 20:35:47 +0900 Subject: [PATCH 0972/1263] Remove unused using --- osu.Game/Screens/Edit/Screens/EditorScreen.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Screens/EditorScreen.cs b/osu.Game/Screens/Edit/Screens/EditorScreen.cs index 773975d493..ac248930d8 100644 --- a/osu.Game/Screens/Edit/Screens/EditorScreen.cs +++ b/osu.Game/Screens/Edit/Screens/EditorScreen.cs @@ -1,7 +1,6 @@ // 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.Configuration; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; From 2bbfe0dda1bd886791dc628594822060820ec67b Mon Sep 17 00:00:00 2001 From: Aergwyn Date: Sat, 2 Dec 2017 15:28:00 +0100 Subject: [PATCH 0973/1263] expanded BeatmapDecoder tests, added StoryboardDecoder tests --- .../Formats/LegacyBeatmapDecoderTest.cs | 214 ++ .../Beatmaps/Formats/LegacyDecoderTest.cs | 146 -- .../Formats/LegacyStoryboardDecoderTest.cs | 89 + ...ni Yoroshiku (RLC) [Winber1's Extreme].osu | 1997 +++++++++++++++++ osu.Game.Tests/osu.Game.Tests.csproj | 4 +- 5 files changed, 2303 insertions(+), 147 deletions(-) create mode 100644 osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs delete mode 100644 osu.Game.Tests/Beatmaps/Formats/LegacyDecoderTest.cs create mode 100644 osu.Game.Tests/Beatmaps/Formats/LegacyStoryboardDecoderTest.cs create mode 100644 osu.Game.Tests/Resources/Himeringo - Yotsuya-san ni Yoroshiku (RLC) [Winber1's Extreme].osu diff --git a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs new file mode 100644 index 0000000000..86413af4b6 --- /dev/null +++ b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs @@ -0,0 +1,214 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System.IO; +using NUnit.Framework; +using OpenTK; +using OpenTK.Graphics; +using osu.Game.Tests.Resources; +using System.Linq; +using osu.Game.Audio; +using osu.Game.Rulesets.Objects.Types; +using osu.Game.Beatmaps.Formats; +using osu.Game.Beatmaps.Timing; + +namespace osu.Game.Tests.Beatmaps.Formats +{ + [TestFixture] + public class LegacyBeatmapDecoderTest + { + [Test] + public void TestDecodeBeatmapGeneral() + { + var decoder = new LegacyBeatmapDecoder(); + using (var resStream = Resource.OpenResource("Soleily - Renatus (Gamu) [Insane].osu")) + using (var stream = new StreamReader(resStream)) + { + var beatmap = decoder.DecodeBeatmap(stream); + var beatmapInfo = beatmap.BeatmapInfo; + var metadata = beatmap.Metadata; + + Assert.AreEqual("03. Renatus - Soleily 192kbps.mp3", metadata.AudioFile); + Assert.AreEqual(0, beatmapInfo.AudioLeadIn); + Assert.AreEqual(164471, metadata.PreviewTime); + Assert.IsFalse(beatmapInfo.Countdown); + Assert.AreEqual(0.7f, beatmapInfo.StackLeniency); + Assert.IsTrue(beatmapInfo.RulesetID == 0); + Assert.IsFalse(beatmapInfo.LetterboxInBreaks); + Assert.IsFalse(beatmapInfo.SpecialStyle); + Assert.IsFalse(beatmapInfo.WidescreenStoryboard); + } + } + + [Test] + public void TestDecodeBeatmapEditor() + { + var decoder = new LegacyBeatmapDecoder(); + using (var resStream = Resource.OpenResource("Soleily - Renatus (Gamu) [Insane].osu")) + using (var stream = new StreamReader(resStream)) + { + var beatmapInfo = decoder.DecodeBeatmap(stream).BeatmapInfo; + + int[] expectedBookmarks = + { + 11505, 22054, 32604, 43153, 53703, 64252, 74802, 85351, + 95901, 106450, 116999, 119637, 130186, 140735, 151285, + 161834, 164471, 175020, 185570, 196119, 206669, 209306 + }; + Assert.AreEqual(expectedBookmarks.Length, beatmapInfo.Bookmarks.Length); + for (int i = 0; i < expectedBookmarks.Length; i++) + Assert.AreEqual(expectedBookmarks[i], beatmapInfo.Bookmarks[i]); + Assert.AreEqual(1.8, beatmapInfo.DistanceSpacing); + Assert.AreEqual(4, beatmapInfo.BeatDivisor); + Assert.AreEqual(4, beatmapInfo.GridSize); + Assert.AreEqual(2, beatmapInfo.TimelineZoom); + } + } + + [Test] + public void TestDecodeBeatmapMetadata() + { + var decoder = new LegacyBeatmapDecoder(); + using (var resStream = Resource.OpenResource("Soleily - Renatus (Gamu) [Insane].osu")) + using (var stream = new StreamReader(resStream)) + { + var beatmap = decoder.DecodeBeatmap(stream); + var beatmapInfo = beatmap.BeatmapInfo; + var metadata = beatmap.Metadata; + + Assert.AreEqual("Renatus", metadata.Title); + Assert.AreEqual("Renatus", metadata.TitleUnicode); + Assert.AreEqual("Soleily", metadata.Artist); + Assert.AreEqual("Soleily", metadata.ArtistUnicode); + Assert.AreEqual("Gamu", metadata.AuthorString); + Assert.AreEqual("Insane", beatmapInfo.Version); + Assert.AreEqual(string.Empty, metadata.Source); + Assert.AreEqual("MBC7 Unisphere 地球ヤバイEP Chikyu Yabai", metadata.Tags); + Assert.AreEqual(557821, beatmapInfo.OnlineBeatmapID); + Assert.AreEqual(241526, metadata.OnlineBeatmapSetID); + } + } + + [Test] + public void TestDecodeBeatmapDifficulty() + { + var decoder = new LegacyBeatmapDecoder(); + using (var resStream = Resource.OpenResource("Soleily - Renatus (Gamu) [Insane].osu")) + using (var stream = new StreamReader(resStream)) + { + var difficulty = decoder.DecodeBeatmap(stream).BeatmapInfo.BaseDifficulty; + + Assert.AreEqual(6.5f, difficulty.DrainRate); + Assert.AreEqual(4, difficulty.CircleSize); + Assert.AreEqual(8, difficulty.OverallDifficulty); + Assert.AreEqual(9, difficulty.ApproachRate); + Assert.AreEqual(1.8f, difficulty.SliderMultiplier); + Assert.AreEqual(2, difficulty.SliderTickRate); + } + } + + [Test] + public void TestDecodeBeatmapEvents() + { + var decoder = new LegacyBeatmapDecoder(); + using (var resStream = Resource.OpenResource("Soleily - Renatus (Gamu) [Insane].osu")) + using (var stream = new StreamReader(resStream)) + { + var beatmap = decoder.DecodeBeatmap(stream); + var metadata = beatmap.Metadata; + var breakPoint = beatmap.Breaks[0]; + + Assert.AreEqual("machinetop_background.jpg", metadata.BackgroundFile); + Assert.AreEqual(122474, breakPoint.StartTime); + Assert.AreEqual(140135, breakPoint.EndTime); + Assert.IsTrue(breakPoint.HasEffect); + } + } + + [Test] + public void TestDecodeBeatmapTimingPoints() + { + var decoder = new LegacyBeatmapDecoder(); + using (var resStream = Resource.OpenResource("Soleily - Renatus (Gamu) [Insane].osu")) + using (var stream = new StreamReader(resStream)) + { + var beatmap = decoder.DecodeBeatmap(stream); + var controlPoints = beatmap.ControlPointInfo; + + Assert.AreEqual(4, controlPoints.TimingPoints.Count); + var timingPoint = controlPoints.TimingPoints[0]; + Assert.AreEqual(956, timingPoint.Time); + Assert.AreEqual(329.67032967033d, timingPoint.BeatLength); + Assert.AreEqual(TimeSignatures.SimpleQuadruple, timingPoint.TimeSignature); + + Assert.AreEqual(5, controlPoints.DifficultyPoints.Count); + var difficultyPoint = controlPoints.DifficultyPoints[0]; + Assert.AreEqual(116999, difficultyPoint.Time); + Assert.AreEqual(0.75000000000000189d, difficultyPoint.SpeedMultiplier); + + Assert.AreEqual(34, controlPoints.SoundPoints.Count); + var soundPoint = controlPoints.SoundPoints[0]; + Assert.AreEqual(956, soundPoint.Time); + Assert.AreEqual("soft", soundPoint.SampleBank); + Assert.AreEqual(60, soundPoint.SampleVolume); + + Assert.AreEqual(8, controlPoints.EffectPoints.Count); + var effectPoint = controlPoints.EffectPoints[0]; + Assert.AreEqual(53703, effectPoint.Time); + Assert.IsTrue(effectPoint.KiaiMode); + Assert.IsFalse(effectPoint.OmitFirstBarLine); + } + } + + [Test] + public void TestDecodeBeatmapColors() + { + var decoder = new LegacyBeatmapDecoder(); + using (var resStream = Resource.OpenResource("Soleily - Renatus (Gamu) [Insane].osu")) + using (var stream = new StreamReader(resStream)) + { + var comboColors = decoder.DecodeBeatmap(stream).ComboColors; + + Color4[] expectedColors = + { + new Color4(142, 199, 255, 255), + new Color4(255, 128, 128, 255), + new Color4(128, 255, 255, 255), + new Color4(128, 255, 128, 255), + new Color4(255, 187, 255, 255), + new Color4(255, 177, 140, 255), + }; + Assert.AreEqual(expectedColors.Length, comboColors.Count); + for (int i = 0; i < expectedColors.Length; i++) + Assert.AreEqual(expectedColors[i], comboColors[i]); + } + } + + [Test] + public void TestDecodeBeatmapHitObjects() + { + var decoder = new LegacyBeatmapDecoder(); + using (var resStream = Resource.OpenResource("Soleily - Renatus (Gamu) [Insane].osu")) + using (var stream = new StreamReader(resStream)) + { + var hitObjects = decoder.DecodeBeatmap(stream).HitObjects; + + var curveData = hitObjects[0] as IHasCurve; + var positionData = hitObjects[0] as IHasPosition; + + Assert.IsNotNull(positionData); + Assert.IsNotNull(curveData); + Assert.AreEqual(new Vector2(192, 168), positionData.Position); + Assert.AreEqual(956, hitObjects[0].StartTime); + Assert.IsTrue(hitObjects[0].Samples.Any(s => s.Name == SampleInfo.HIT_NORMAL)); + + positionData = hitObjects[1] as IHasPosition; + + Assert.IsNotNull(positionData); + Assert.AreEqual(new Vector2(304, 56), positionData.Position); + Assert.AreEqual(1285, hitObjects[1].StartTime); + Assert.IsTrue(hitObjects[1].Samples.Any(s => s.Name == SampleInfo.HIT_CLAP)); + } + } + } +} diff --git a/osu.Game.Tests/Beatmaps/Formats/LegacyDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/LegacyDecoderTest.cs deleted file mode 100644 index 4266afa526..0000000000 --- a/osu.Game.Tests/Beatmaps/Formats/LegacyDecoderTest.cs +++ /dev/null @@ -1,146 +0,0 @@ -// Copyright (c) 2007-2017 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using System.IO; -using NUnit.Framework; -using OpenTK; -using OpenTK.Graphics; -using osu.Game.Beatmaps.Formats; -using osu.Game.Tests.Resources; -using System.Linq; -using osu.Game.Audio; -using osu.Game.Rulesets.Objects.Types; - -namespace osu.Game.Tests.Beatmaps.Formats -{ - [TestFixture] - public class LegacyDecoderTest - { - [Test] - public void TestDecodeMetadata() - { - var decoder = new LegacyBeatmapDecoder(); - using (var stream = Resource.OpenResource("Soleily - Renatus (Gamu) [Insane].osu")) - { - var beatmap = decoder.DecodeBeatmap(new StreamReader(stream)); - var meta = beatmap.BeatmapInfo.Metadata; - Assert.AreEqual(241526, meta.OnlineBeatmapSetID); - Assert.AreEqual("Soleily", meta.Artist); - Assert.AreEqual("Soleily", meta.ArtistUnicode); - Assert.AreEqual("03. Renatus - Soleily 192kbps.mp3", meta.AudioFile); - Assert.AreEqual("Gamu", meta.AuthorString); - Assert.AreEqual("machinetop_background.jpg", meta.BackgroundFile); - Assert.AreEqual(164471, meta.PreviewTime); - Assert.AreEqual(string.Empty, meta.Source); - Assert.AreEqual("MBC7 Unisphere 地球ヤバイEP Chikyu Yabai", meta.Tags); - Assert.AreEqual("Renatus", meta.Title); - Assert.AreEqual("Renatus", meta.TitleUnicode); - } - } - - [Test] - public void TestDecodeGeneral() - { - var decoder = new LegacyBeatmapDecoder(); - using (var stream = Resource.OpenResource("Soleily - Renatus (Gamu) [Insane].osu")) - { - var beatmapInfo = decoder.DecodeBeatmap(new StreamReader(stream)).BeatmapInfo; - Assert.AreEqual(0, beatmapInfo.AudioLeadIn); - Assert.AreEqual(false, beatmapInfo.Countdown); - Assert.AreEqual(0.7f, beatmapInfo.StackLeniency); - Assert.AreEqual(false, beatmapInfo.SpecialStyle); - Assert.IsTrue(beatmapInfo.RulesetID == 0); - Assert.AreEqual(false, beatmapInfo.LetterboxInBreaks); - Assert.AreEqual(false, beatmapInfo.WidescreenStoryboard); - } - } - - [Test] - public void TestDecodeEditor() - { - var decoder = new LegacyBeatmapDecoder(); - using (var stream = Resource.OpenResource("Soleily - Renatus (Gamu) [Insane].osu")) - { - var beatmap = decoder.DecodeBeatmap(new StreamReader(stream)).BeatmapInfo; - int[] expectedBookmarks = - { - 11505, 22054, 32604, 43153, 53703, 64252, 74802, 85351, - 95901, 106450, 116999, 119637, 130186, 140735, 151285, - 161834, 164471, 175020, 185570, 196119, 206669, 209306 - }; - Assert.AreEqual(expectedBookmarks.Length, beatmap.Bookmarks.Length); - for (int i = 0; i < expectedBookmarks.Length; i++) - Assert.AreEqual(expectedBookmarks[i], beatmap.Bookmarks[i]); - Assert.AreEqual(1.8, beatmap.DistanceSpacing); - Assert.AreEqual(4, beatmap.BeatDivisor); - Assert.AreEqual(4, beatmap.GridSize); - Assert.AreEqual(2, beatmap.TimelineZoom); - } - } - - [Test] - public void TestDecodeDifficulty() - { - var decoder = new LegacyBeatmapDecoder(); - using (var stream = Resource.OpenResource("Soleily - Renatus (Gamu) [Insane].osu")) - { - var beatmap = decoder.DecodeBeatmap(new StreamReader(stream)); - var difficulty = beatmap.BeatmapInfo.BaseDifficulty; - Assert.AreEqual(6.5f, difficulty.DrainRate); - Assert.AreEqual(4, difficulty.CircleSize); - Assert.AreEqual(8, difficulty.OverallDifficulty); - Assert.AreEqual(9, difficulty.ApproachRate); - Assert.AreEqual(1.8f, difficulty.SliderMultiplier); - Assert.AreEqual(2, difficulty.SliderTickRate); - } - } - - [Test] - public void TestDecodeColors() - { - var decoder = new LegacyBeatmapDecoder(); - using (var stream = Resource.OpenResource("Soleily - Renatus (Gamu) [Insane].osu")) - { - var beatmap = decoder.DecodeBeatmap(new StreamReader(stream)); - Color4[] expected = - { - new Color4(142, 199, 255, 255), - new Color4(255, 128, 128, 255), - new Color4(128, 255, 255, 255), - new Color4(128, 255, 128, 255), - new Color4(255, 187, 255, 255), - new Color4(255, 177, 140, 255), - }; - Assert.AreEqual(expected.Length, beatmap.ComboColors.Count); - for (int i = 0; i < expected.Length; i++) - Assert.AreEqual(expected[i], beatmap.ComboColors[i]); - } - } - - [Test] - public void TestDecodeHitObjects() - { - var decoder = new LegacyBeatmapDecoder(); - using (var stream = Resource.OpenResource("Soleily - Renatus (Gamu) [Insane].osu")) - { - var beatmap = decoder.DecodeBeatmap(new StreamReader(stream)); - - var curveData = beatmap.HitObjects[0] as IHasCurve; - var positionData = beatmap.HitObjects[0] as IHasPosition; - - Assert.IsNotNull(positionData); - Assert.IsNotNull(curveData); - Assert.AreEqual(new Vector2(192, 168), positionData.Position); - Assert.AreEqual(956, beatmap.HitObjects[0].StartTime); - Assert.IsTrue(beatmap.HitObjects[0].Samples.Any(s => s.Name == SampleInfo.HIT_NORMAL)); - - positionData = beatmap.HitObjects[1] as IHasPosition; - - Assert.IsNotNull(positionData); - Assert.AreEqual(new Vector2(304, 56), positionData.Position); - Assert.AreEqual(1285, beatmap.HitObjects[1].StartTime); - Assert.IsTrue(beatmap.HitObjects[1].Samples.Any(s => s.Name == SampleInfo.HIT_CLAP)); - } - } - } -} diff --git a/osu.Game.Tests/Beatmaps/Formats/LegacyStoryboardDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/LegacyStoryboardDecoderTest.cs new file mode 100644 index 0000000000..a42318883c --- /dev/null +++ b/osu.Game.Tests/Beatmaps/Formats/LegacyStoryboardDecoderTest.cs @@ -0,0 +1,89 @@ +// 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.IO; +using System.Linq; +using NUnit.Framework; +using OpenTK; +using osu.Framework.Graphics; +using osu.Game.Beatmaps.Formats; +using osu.Game.Storyboards; +using osu.Game.Tests.Resources; + +namespace osu.Game.Tests.Beatmaps.Formats +{ + [TestFixture] + public class LegacyStoryboardDecoderTest + { + [Test] + public void TestDecodeStoryboardEvents() + { + var decoder = new LegacyBeatmapDecoder(); + using (var resStream = Resource.OpenResource("Himeringo - Yotsuya-san ni Yoroshiku (RLC) [Winber1's Extreme].osu")) + using (var stream = new StreamReader(resStream)) + { + var storyboard = decoder.GetStoryboardDecoder().DecodeStoryboard(stream); + + Assert.IsTrue(storyboard.HasDrawable); + Assert.AreEqual(4, storyboard.Layers.Count()); + + StoryboardLayer background = storyboard.Layers.FirstOrDefault(l => l.Depth == 3); + Assert.IsNotNull(background); + Assert.AreEqual(16, background.Elements.Count()); + Assert.IsTrue(background.EnabledWhenFailing); + Assert.IsTrue(background.EnabledWhenPassing); + Assert.AreEqual("Background", background.Name); + + StoryboardLayer fail = storyboard.Layers.FirstOrDefault(l => l.Depth == 2); + Assert.IsNotNull(fail); + Assert.AreEqual(0, fail.Elements.Count()); + Assert.IsTrue(fail.EnabledWhenFailing); + Assert.IsFalse(fail.EnabledWhenPassing); + Assert.AreEqual("Fail", fail.Name); + + StoryboardLayer pass = storyboard.Layers.FirstOrDefault(l => l.Depth == 1); + Assert.IsNotNull(pass); + Assert.AreEqual(0, pass.Elements.Count()); + Assert.IsFalse(pass.EnabledWhenFailing); + Assert.IsTrue(pass.EnabledWhenPassing); + Assert.AreEqual("Pass", pass.Name); + + StoryboardLayer foreground = storyboard.Layers.FirstOrDefault(l => l.Depth == 0); + Assert.IsNotNull(foreground); + Assert.AreEqual(151, foreground.Elements.Count()); + Assert.IsTrue(foreground.EnabledWhenFailing); + Assert.IsTrue(foreground.EnabledWhenPassing); + Assert.AreEqual("Foreground", foreground.Name); + + int spriteCount = background.Elements.Where(x => x.GetType() == typeof(StoryboardSprite)).Count(); + int animationCount = background.Elements.Where(x => x.GetType() == typeof(StoryboardAnimation)).Count(); + int sampleCount = background.Elements.Where(x => x.GetType() == typeof(StoryboardSample)).Count(); + + Assert.AreEqual(15, spriteCount); + Assert.AreEqual(1, animationCount); + Assert.AreEqual(0, sampleCount); + Assert.AreEqual(background.Elements.Count(), spriteCount + animationCount + sampleCount); + + var sprite = background.Elements.ElementAt(0) as StoryboardSprite; + Assert.IsTrue(sprite.HasCommands); + Assert.AreEqual(new Vector2(320, 240), sprite.InitialPosition); + Assert.IsTrue(sprite.IsDrawable); + Assert.AreEqual(Anchor.Centre, sprite.Origin); + Assert.AreEqual("SB/lyric/ja-21.png", sprite.Path); + + var animation = background.Elements.ElementAt(12) as StoryboardAnimation; + Assert.AreEqual(141175, animation.EndTime); + Assert.AreEqual(10, animation.FrameCount); + Assert.AreEqual(30, animation.FrameDelay); + Assert.IsTrue(animation.HasCommands); + Assert.AreEqual(new Vector2(320, 240), animation.InitialPosition); + Assert.IsTrue(animation.IsDrawable); + Assert.AreEqual(AnimationLoopType.LoopForever, animation.LoopType); + Assert.AreEqual(Anchor.Centre, animation.Origin); + Assert.AreEqual("SB/red jitter/red_0000.jpg", animation.Path); + Assert.AreEqual(78993, animation.StartTime); + } + } + } +} diff --git a/osu.Game.Tests/Resources/Himeringo - Yotsuya-san ni Yoroshiku (RLC) [Winber1's Extreme].osu b/osu.Game.Tests/Resources/Himeringo - Yotsuya-san ni Yoroshiku (RLC) [Winber1's Extreme].osu new file mode 100644 index 0000000000..f7b33fa6a8 --- /dev/null +++ b/osu.Game.Tests/Resources/Himeringo - Yotsuya-san ni Yoroshiku (RLC) [Winber1's Extreme].osu @@ -0,0 +1,1997 @@ +osu file format v13 + +[General] +AudioFilename: yotsuya192.mp3 +AudioLeadIn: 0 +PreviewTime: 71220 +Countdown: 0 +SampleSet: Soft +StackLeniency: 0.7 +Mode: 0 +LetterboxInBreaks: 0 +WidescreenStoryboard: 1 + +[Editor] +Bookmarks: 24456,34275,43002,53911,71366,88820,99729,117184,143366,152093,160820,169547 +DistanceSpacing: 1.4 +BeatDivisor: 4 +GridSize: 4 +TimelineZoom: 1 + +[Metadata] +Title:Yotsuya-san ni Yoroshiku +TitleUnicode:四ツ谷さんによろしく +Artist:Himeringo +ArtistUnicode:ひめりんご +Creator:RLC +Version:Winber1's Extreme +Source: +Tags:flask nyquill winber1 skystar amamiya yuko cheesiest onosakihito utaite leave it to eight hatsune miku vocaloid +BeatmapID:378781 +BeatmapSetID:100049 + +[Difficulty] +HPDrainRate:6 +CircleSize:4 +OverallDifficulty:8.5 +ApproachRate:9.5 +SliderMultiplier:1.9 +SliderTickRate:1 + +[Events] +//Background and Video events +0,0,"primary.jpg",0,0 +//Break Periods +//Storyboard Layer 0 (Background) +Sprite,Background,Centre,"SB\lyric\ja-21.png",320,240 + S,0,117175,,0.8 + F,0,117175,117584,0,1 + M,0,117175,118675,192,393,-12,393 + F,0,117584,118402,1 + F,0,118402,118675,1,0 +Sprite,Background,Centre,"SB\lyric\ja-22.png",320,240 + S,0,118675,,0.8 + F,0,118675,119084,0,1 + M,0,118675,119629,150,393,23,393 + F,0,119084,119357,1 + F,0,119357,119629,1,0 +Sprite,Background,Centre,"SB\lyric\ja-22-repeat.png",320,240 + S,0,119357,,0.8 + M,0,119629,,196,393 + F,0,119629,119902,0,1 + M,0,119629,121947,196,393,-58,393 + F,0,119902,121675,1 + F,0,121675,121947,1,0 +Sprite,Background,Centre,"SB\lyric\ja-23.png",320,240 + S,0,121947,,0.8 + F,0,121947,122357,0,1 + M,0,121947,123038,158,393,23,393 + F,0,122357,122766,1 + F,0,122766,123038,1,0 +Sprite,Background,Centre,"SB\lyric\ja-24.png",320,240 + S,0,123038,,0.8 + F,0,123038,123447,0,1 + M,0,123038,123720,249,393,187,393 + F,0,123447,123720,1 +Sprite,Background,Centre,"SB\lyric\en-21.png",320,240 + S,0,117175,,0.6 + F,0,117175,117584,0,1 + M,0,117175,117925,641,425,551,425 + F,0,117584,118402,1 + M,0,117925,118675,551,425,461,425 + F,0,118402,118675,1,0 +Sprite,Background,Centre,"SB\lyric\en-22.png",320,240 + S,0,118675,,0.6 + F,0,118675,119084,0,1 + M,0,118675,119152,616,425,554,425 + F,0,119084,119357,1 + M,0,119152,119629,554,425,489,425 + F,0,119357,119629,1,0 +Sprite,Background,Centre,"SB\lyric\en-22-repeat.png",320,240 + S,0,119629,,0.6 + F,0,119629,120038,0,1 + M,0,119629,121947,683,425,417,425 + F,0,120038,121675,1 + F,0,121675,121947,1,0 +Sprite,Background,Centre,"SB\lyric\en-23.png",320,240 + S,0,121947,,0.6 + F,0,121947,122357,0,1 + M,0,121947,123038,617,425,487,425 + F,0,122357,122766,1 + F,0,122766,123038,1,0 +Sprite,Background,Centre,"SB\lyric\en-24.png",320,240 + S,0,123038,,0.6 + F,0,123038,123447,0,1 + M,0,123038,123720,515,425,446,425 +Sprite,Background,Centre,"SB\lower mask.png",320,240 + S,0,117175,,0.625 + R,0,117175,,0.0001 + M,0,117175,123720,320,330 +Sprite,Background,Centre,"SB\black.jpg",320,240 + F,0,-97,,1 + F,0,20084,23357,1,0 + F,0,23357,24447,0 + F,0,24447,25470,0,1 + F,0,25538,26629,0,1 + F,0,27720,28811,0.5,1 + F,0,29902,30993,0,1 + F,0,32084,33175,0.5,1 + F,0,34266,,0 + F,0,70266,,1 + S,0,70266,,1.267815 + R,0,70266,,0.0001 + F,0,71357,,0 + F,0,71357,,0 + F,0,86629,,1 + F,0,87720,88538,1,0 + F,0,88538,,0 + M,0,108877,116493,314,289,312,322 + F,0,116084,,1 + F,0,117175,117720,0,0.5 + F,0,117720,118266,0.5,0 + F,0,118266,118811,0,0.5 + F,0,118811,119357,0.5,0 + F,0,119357,119902,0,0.5 + F,0,119902,120447,0.5,0 + F,0,120447,120993,0,0.5 + F,0,120993,121538,0.5,0 + F,0,121538,122084,0,0.5 + F,0,122084,122629,0.5,0 + F,0,122629,123175,0,0.5 + F,0,123175,123686,0.5,0 + F,0,123720,,1 + F,0,126175,,1,0.07840011 + F,0,141175,,1 + F,0,143357,144447,0,1 + F,0,145538,146629,0.5,1 + F,0,147720,148811,0,1 + F,0,149902,150993,0.5,1 + F,0,150993,,1 + F,0,152084,,0 + F,0,171447,,1 + F,0,171447,177720,1 +Animation,Background,Centre,"SB\red jitter\red_0000.jpg",320,240,10,30,LoopForever + S,0,78993,,1.001 + R,0,78993,,0.0001 + F,0,78993,80084,0,1 + F,0,80084,,1 + F,0,86629,,0 + F,0,133538,134629,0.9180929,1 + F,0,141175,,1 +Sprite,Background,Centre,"SB\brown.jpg",320,240 + M,0,71357,,320,240 + S,0,71357,,1.001 + R,0,71357,,0.0001 + F,0,71357,80084,1 + F,0,80084,81175,1,0 +Sprite,Background,Centre,"SB\blue.jpg",320,240 + S,0,126175,,1.001 + R,0,126175,,0.0001 + F,0,126175,134629,1 + F,0,134629,135720,1,0 +Sprite,Background,Centre,"SB\cloud2.png",320,240 + S,0,126175,,4.659974 + R,0,126175,,0.0001 + M,0,126175,135175,72,29,474,29 + F,0,133538,135175,0.4690581,0 +//Storyboard Layer 1 (Fail) +//Storyboard Layer 2 (Pass) +//Storyboard Layer 3 (Foreground) +Sprite,Foreground,Centre,"SB\lyric\ja-1.png",320,240 + S,0,53902,,0.8 + F,0,53902,54993,0,1 + M,0,53902,58266,232,393,263,393 + F,0,54993,57175,1 + F,0,57175,58266,1,0 +Sprite,Foreground,Centre,"SB\lyric\en-1.png",320,240 + S,0,53902,,0.6 + F,0,53902,54993,0,1 + M,0,53902,58266,404,425,373,425 + F,0,54993,57175,1 + F,0,57175,58266,1,0 +Sprite,Foreground,Centre,"SB\lyric\ja-2.png",320,240 + S,0,58266,,0.8 + F,0,58266,59357,0,1 + M,0,58266,62629,232,393,263,393 + F,0,59357,61538,1 + F,0,61538,,1 + F,0,61538,,1 + F,0,61538,62357,1,0 +Sprite,Foreground,Centre,"SB\lyric\ja-3.png",320,240 + S,0,62629,,0.8 + F,0,62629,63720,0,1 + M,0,62629,66447,232,393,263,393 + F,0,63720,65357,1 + F,0,65357,66447,1,0 +Sprite,Foreground,Centre,"SB\lyric\ja-4.png",320,240 + S,0,66447,,0.8 + F,0,66447,67538,0,1 + M,0,66447,70266,232,393,263,393 + F,0,67538,69175,1 + F,0,69175,70266,1,0 +Sprite,Foreground,Centre,"SB\lyric\ja-5.png",320,240 + S,0,70266,,0.5 + M,0,70266,70402,179,335 +Sprite,Foreground,Centre,"SB\lyric\ja-5.png",320,240 + S,0,70402,,0.8 + M,0,70402,70538,469,297 +Sprite,Foreground,Centre,"SB\lyric\ja-5.png",320,240 + S,0,70538,,1.1 + M,0,70538,70675,255,158 +Sprite,Foreground,Centre,"SB\lyric\ja-5RED.png",320,240 + S,0,70675,,1.3 + F,0,70675,70947,1 + M,0,70675,71220,320,240 + F,0,70947,71357,1,0 +Sprite,Foreground,Centre,"SB\lyric\ja-6-1.png",320,240 + S,0,71357,,0.8 + M,0,71357,71902,320,393 +Sprite,Foreground,Centre,"SB\lyric\ja-6-2.png",320,240 + S,0,71902,,0.8 + M,0,71902,72447,320,393 +Sprite,Foreground,Centre,"SB\lyric\ja-6-3.png",320,240 + S,0,72447,,0.8 + M,0,72447,72857,320,393 +Sprite,Foreground,Centre,"SB\lyric\ja-7.png",320,240 + S,0,72857,,0.8 + M,0,72857,73947,320,393 +Sprite,Foreground,Centre,"SB\lyric\ja-8.png",320,240 + S,0,73947,,0.8 + M,0,73947,76129,320,393 +Sprite,Foreground,Centre,"SB\lyric\ja-9.png",320,240 + S,0,76129,,0.8 + M,0,76129,77220,320,393 +Sprite,Foreground,Centre,"SB\lyric\ja-10-2.png",320,240 + S,0,78311,,0.8 + M,0,78311,80084,376,393 +Sprite,Foreground,Centre,"SB\lyric\ja-10-1.png",320,240 + S,0,77220,,0.8 + M,0,77220,80084,264,393 +Animation,Foreground,Centre,"SB\lyric\11-1\ja-11-1_0000.png",320,240,10,30,LoopForever + S,0,80084,,0.8 + M,0,80084,81584,230,326 +Animation,Foreground,Centre,"SB\lyric\11-2\ja-11-2_0000.png",320,240,10,30,LoopForever + S,0,80629,,1.1 + M,0,80629,81584,325,305 +Animation,Foreground,Centre,"SB\lyric\11-3\ja-11-3_0000.png",320,240,10,30,LoopForever + S,0,81175,,1.3 + M,0,81175,81584,425,284 +Animation,Foreground,Centre,"SB\lyric\12\ja-12_0000.png",320,240,10,30,LoopForever + S,0,81584,,1.1 + M,0,81584,82675,306,214 +Animation,Foreground,Centre,"SB\lyric\13\ja-13_0000.png",320,240,10,30,LoopForever + S,0,82675,,0.8 + M,0,82675,84857,315,294 +Animation,Foreground,Centre,"SB\lyric\14\ja-14_0000.png",320,240,10,30,LoopForever + S,0,84857,,1.1 + M,0,84857,85947,320,222 +Animation,Foreground,Centre,"SB\lyric\15-1\ja-15-1_0000.png",320,240,10,30,LoopForever + S,0,85947,,0.8 + M,0,85947,86629,269,393 +Sprite,Foreground,Centre,"SB\lyric\ja-15-1.png",320,240 + S,0,86629,,0.8 + M,0,86629,87720,269,393 + F,0,87720,88538,1,0 +Sprite,Foreground,Centre,"SB\lyric\ja-15-2.png",320,240 + S,0,87175,,0.8 + M,0,87175,87720,373,393 + F,0,87720,88538,1,0 +Sprite,Foreground,Centre,"SB\lyric\ja-16.png",320,240 + S,0,99720,,0.8 + F,0,99720,100811,0,1 + M,0,99720,104084,232,393,263,393 + F,0,100811,102993,1 + F,0,102993,104084,1,0 +Sprite,Foreground,Centre,"SB\lyric\ja-17.png",320,240 + S,0,104084,,0.8 + F,0,104084,105175,0,1 + M,0,104084,108447,232,393,263,393 + F,0,105175,107357,1 + F,0,107357,108175,1,0 +Sprite,Foreground,Centre,"SB\lyric\ja-18.png",320,240 + S,0,108447,,0.8 + F,0,108447,109538,0,1 + M,0,108447,112266,232,393,263,393 + F,0,109538,111175,1 + F,0,111175,112266,1,0 +Sprite,Foreground,Centre,"SB\lyric\ja-19.png",320,240 + S,0,112266,,0.8 + F,0,112266,113357,0,1 + M,0,112266,116084,232,393,263,393 + F,0,113357,114993,1 + F,0,114993,116084,1,0 +Sprite,Foreground,Centre,"SB\lyric\ja-20_1.png",320,240 + S,0,116084,,0.5 + M,0,116084,116220,478,319 +Sprite,Foreground,Centre,"SB\lyric\ja-20_1.png",320,240 + S,0,116220,,0.8 + M,0,116220,116357,160,257 +Sprite,Foreground,Centre,"SB\lyric\ja-20_1.png",320,240 + S,0,116357,,1.1 + M,0,116357,116493,393,161 +Sprite,Foreground,Centre,"SB\lyric\ja-20RED.png",320,240 + M,0,116493,,320,240 + S,0,116493,,1.3 + F,0,116493,116766,1 + F,0,116766,117175,1,0 +Sprite,Foreground,Centre,"SB\lyric\ja-24RED.png",320,240 + M,0,123720,,187,393 + S,0,123720,,0.8 + F,0,123720,124811,1 + F,0,124811,125902,1,0 +Sprite,Foreground,Centre,"SB\lyric\ja-25-1.png",320,240 + S,0,125766,,0.8 + M,0,125766,126175,156,312 +Sprite,Foreground,Centre,"SB\lyric\ja-25-2.png",320,240 + S,0,126175,,0.8 + M,0,126175,126993,156,312 + F,0,127538,127811,1,0 +Sprite,Foreground,Centre,"SB\lyric\ja-25-3.png",320,240 + S,0,126447,,1.1 + R,0,126447,,-0.189046 + M,0,126447,126993,306,288 + F,0,127538,,1 + F,0,127538,127811,1,0 +Sprite,Foreground,Centre,"SB\lyric\ja-25-4.png",320,240 + M,0,126993,,388,400 + S,0,126993,,1.3 + R,0,126993,,0.1785437 + F,0,127538,127811,1,0 +Sprite,Foreground,Centre,"SB\lyric\ja-26.png",320,240 + S,0,127402,,0.8 + F,0,127402,127538,0,1 + M,0,127402,128084,315,201 + R,0,127402,128084,0.1050253 + F,0,127538,128084,1 + M,0,128084,128493,315,201,315,236 + F,0,128084,128493,1,0 + R,0,128084,128493,0.1050253,0.3360815 +Sprite,Foreground,Centre,"SB\lyric\ja-27.png",320,240 + S,0,128493,,0.9 + F,0,128493,128629,0,1 + M,0,128493,130266,191,426 + R,0,128493,130266,0.06301453 + F,0,128629,130266,1 + M,0,130266,130675,191,426,191,458 + F,0,130266,130675,1,0 + R,0,130266,130675,0.06301453,0.2835687 +Sprite,Foreground,Centre,"SB\lyric\ja-28.png",320,240 + S,0,130675,,0.8 + R,0,130675,,-0.1155283 + F,0,130675,130811,0,1 + M,0,130675,131357,320,240 + F,0,130811,131357,1 + F,0,131357,131766,1,0 +Sprite,Foreground,Centre,"SB\lyric\ja-29.png",320,240 + S,0,131766,,0.8 + F,0,131766,131902,0,1 + M,0,131766,133538,230,154 + R,0,131766,133538,0.1260309 + F,0,131902,133538,1 + M,0,133538,134629,230,154,230,206 + F,0,133538,134629,1,0 + R,0,133538,134629,0.1260309,0.2835693 +Animation,Foreground,Centre,"SB\lyric\12\ja-12_0000.png",320,240,10,30,LoopForever + S,0,136129,,1.1 + M,0,136129,137220,306,214 +Animation,Foreground,Centre,"SB\lyric\13\ja-13_0000.png",320,240,10,30,LoopForever + S,0,137220,,0.8 + M,0,137220,139402,315,294 +Animation,Foreground,Centre,"SB\lyric\14\ja-14_0000.png",320,240,10,30,LoopForever + S,0,139402,,1.1 + M,0,139402,140493,320,222 +Animation,Foreground,Centre,"SB\lyric\30-1\ja-30-1_0000.png",320,240,10,30,LoopForever + S,0,134629,,0.8 + M,0,134629,136129,153,292 +Animation,Foreground,Centre,"SB\lyric\30-2\ja-30-2_0000.png",320,240,10,30,LoopForever + S,0,135175,,1.1 + M,0,135175,136129,333,216 +Animation,Foreground,Centre,"SB\lyric\30-3\ja-30-3_0000.png",320,240,10,30,LoopForever + S,0,135720,,1.3 + M,0,135720,136129,485,133 +Animation,Foreground,Centre,"SB\lyric\34-1\ja-34-1_0000.png",320,240,10,30,LoopForever + S,0,140493,,0.8 + M,0,140493,141175,269,393 +Sprite,Foreground,Centre,"SB\lyric\ja-34-1.png",320,240 + S,0,141175,,0.8 + M,0,141175,143357,269,393 + F,0,142266,143357,1,0 +Sprite,Foreground,Centre,"SB\lyric\ja-34-2.png",320,240 + S,0,141720,,0.8 + M,0,141720,143357,391,393 + F,0,142266,143357,1,0 +Sprite,Foreground,Centre,"SB\lyric\en-2.png",320,240 + S,0,58266,,0.6 + F,0,58266,59357,0,1 + M,0,58266,62629,404,425,373,425 + F,0,59357,61538,1 + F,0,61538,62357,1,0 +Sprite,Foreground,Centre,"SB\lyric\en-3.png",320,240 + S,0,62629,,0.6 + F,0,62629,63720,0,1 + M,0,62629,66447,404,425,373,425 + F,0,63720,65357,1 + F,0,65357,66447,1,0 +Sprite,Foreground,Centre,"SB\lyric\en-4.png",320,240 + S,0,66447,,0.6 + F,0,66447,67538,0,1 + M,0,66447,70266,404,425,373,425 + F,0,67538,69175,1 + F,0,69175,70266,1,0 +Sprite,Foreground,Centre,"SB\lyric\en-5.png",320,240 + F,0,70266,,1 + S,0,70266,,0.4 + M,0,70266,70402,436,192 +Sprite,Foreground,Centre,"SB\lyric\en-5.png",320,240 + S,0,70402,,0.6 + M,0,70402,70538,181,97 +Sprite,Foreground,Centre,"SB\lyric\en-5.png",320,240 + S,0,70538,,0.8 + M,0,70538,70675,391,392 +Sprite,Foreground,Centre,"SB\lyric\en-5RED.png",320,240 + M,0,70675,,320,294 + F,0,70675,70947,1 + F,0,70947,71357,1,0 +Sprite,Foreground,Centre,"SB\lyric\en-6-1.png",320,240 + S,0,71357,,0.7885935 + M,0,71357,71902,320,425 +Sprite,Foreground,Centre,"SB\lyric\en-6-2.png",320,240 + S,0,71902,,0.7357419 + M,0,71902,72447,320,425 +Sprite,Foreground,Centre,"SB\lyric\en-6-3.png",320,240 + S,0,72447,,0.8084131 + M,0,72447,72857,320,425 +Sprite,Foreground,Centre,"SB\lyric\en-7.png",320,240 + S,0,72857,,0.8018063 + M,0,72857,73947,320,425 +Sprite,Foreground,Centre,"SB\lyric\en-8.png",320,240 + S,0,73947,,0.6961035 + M,0,73947,76129,320,425 +Sprite,Foreground,Centre,"SB\lyric\en-9.png",320,240 + S,0,76129,,0.762168 + M,0,76129,77220,320,425 +Sprite,Foreground,Centre,"SB\lyric\en-10-1.png",320,240 + S,0,77220,,0.6564645 + M,0,77220,80084,262,425 +Sprite,Foreground,Centre,"SB\lyric\en-10-2.png",320,240 + S,0,78311,,0.5837936 + M,0,78311,80084,411,425 +Sprite,Foreground,Centre,"SB\lyric\en-16.png",320,240 + S,0,99720,,0.6 + F,0,99720,100811,0,1 + M,0,99720,104084,404,425,373,425 + F,0,100811,102993,1 + F,0,102993,104084,1,0 +Sprite,Foreground,Centre,"SB\lyric\en-17-1.png",320,240 + S,0,104084,,0.6 + F,0,104084,105175,0,1 + M,0,104084,108447,404,425,373,425 + F,0,105175,107357,1 + F,0,107357,108175,1,0 +Sprite,Foreground,Centre,"SB\lyric\en-17-2.png",320,240 + S,0,104084,,0.6 + F,0,104084,105175,0,1 + M,0,104084,108175,232,457,263,457 + F,0,105175,107357,1 + F,0,107357,108175,1,0 +Sprite,Foreground,Centre,"SB\lyric\en-18.png",320,240 + S,0,108447,,0.6 + F,0,108447,109538,0,1 + M,0,108447,112266,404,425,373,425 + F,0,109538,111175,1 + F,0,111175,112266,1,0 +Sprite,Foreground,Centre,"SB\lyric\en-19.png",320,240 + S,0,112266,,0.6 + F,0,112266,113357,0,1 + M,0,112266,116084,404,425,373,425 + F,0,113357,114993,1 + F,0,114993,116084,1,0 +Sprite,Foreground,Centre,"SB\lyric\en-20-1.png",320,240 + S,0,116084,,0.4 + M,0,116084,116220,205,167 +Sprite,Foreground,Centre,"SB\lyric\en-20-1.png",320,240 + S,0,116220,,0.6 + M,0,116220,116357,389,252 +Sprite,Foreground,Centre,"SB\lyric\en-20-1.png",320,240 + S,0,116357,,0.8 + M,0,116357,116493,220,395 +Sprite,Foreground,Centre,"SB\lyric\en-20RED.png",320,240 + M,0,116493,,320,293 + F,0,116493,116766,1 + F,0,116766,117175,1,0 +Sprite,Foreground,Centre,"SB\lyric\en-24RED.png",320,240 + M,0,123720,,446,425 + S,0,123720,,0.6 + F,0,123720,124811,1 + F,0,124811,125902,1,0 +Sprite,Foreground,Centre,"SB\lyric\en-25-1.png",320,240 + S,0,125766,,0.6 + M,0,125766,126175,408,240 +Sprite,Foreground,Centre,"SB\lyric\en-25-2.png",320,240 + S,0,126175,,0.6 + M,0,126175,126993,408,240 + F,0,127538,127811,1,0 +Sprite,Foreground,Centre,"SB\lyric\en-25-3.png",320,240 + M,0,126447,,525,277 + S,0,126447,,0.8 + R,0,126447,,0.189046 + F,0,127538,127811,1,0 +Sprite,Foreground,Centre,"SB\lyric\en-25-4.png",320,240 + M,0,126993,,219,400 + S,0,126993,,1 + R,0,126993,,-0.1260309 + F,0,126993,127402,1,0 +Sprite,Foreground,Centre,"SB\lyric\en-26.png",320,240 + S,0,127402,,0.7 + F,0,127402,127538,0,1 + M,0,127402,128084,416,325 + R,0,127402,128084,-0.1680408 + F,0,127538,128084,1 + M,0,128084,128493,416,325,416,391 + F,0,128084,128493,1,0 + R,0,128084,128493,-0.1680408,-0.3990967 +Sprite,Foreground,Centre,"SB\lyric\en-27.png",320,240 + S,0,128493,,0.6 + F,0,128493,128629,0,1 + M,0,128493,130266,443,226 + R,0,128493,130266,-0.08402039 + F,0,128629,130266,1 + M,0,130266,130675,443,226,443,252 + F,0,130266,130675,1,0 + R,0,130266,130675,-0.08402039,-0.2310565 +Sprite,Foreground,Centre,"SB\lyric\en-28.png",320,240 + S,0,130675,,0.7 + R,0,130675,,0.273067 + F,0,130675,130811,0,1 + M,0,130675,131357,140,303 + F,0,130811,131357,1 + F,0,131357,131766,1,0 +Sprite,Foreground,Centre,"SB\lyric\en-29.png",320,240 + S,0,131766,,0.7 + F,0,131766,131902,0,1 + M,0,131766,133538,438,257 + R,0,131766,133538,-0.1890472 + F,0,131902,133538,1 + M,0,133538,134629,438,257,438,314 + F,0,133538,134629,1,0 + R,0,133538,134629,-0.1890472,-0.4306067 +Animation,Foreground,Centre,"SB\lyric\11-1\en-11-1_0000.png",320,240,10,30,LoopForever + S,0,80357,,0.6 + M,0,80357,81584,336,384 +Animation,Foreground,Centre,"SB\lyric\11-2\en-11-2_0000.png",320,240,10,30,LoopForever + S,0,80902,,0.8 + M,0,80902,81993,142,245 +Animation,Foreground,Centre,"SB\lyric\11-3\en-11-3_0000.png",320,240,10,30,LoopForever + S,0,81447,,1 + M,0,81447,81993,413,164 +Animation,Foreground,Centre,"SB\lyric\12\en-12_0000.png",320,240,10,30,LoopForever + S,0,81993,,0.8 + M,0,81993,83357,255,360 +Animation,Foreground,Centre,"SB\lyric\13\en-13_0000.png",320,240,10,30,LoopForever + S,0,83357,,0.6 + M,0,83357,85538,222,140 +Animation,Foreground,Centre,"SB\lyric\14\en-14_0000.png",320,240,10,30,LoopForever + S,0,85538,,1 + M,0,85538,86357,437,300 +Animation,Foreground,Centre,"SB\lyric\15-1\en-15-1_0000.png",320,240,10,30,LoopForever + F,0,86357,,1 + S,0,86357,,0.6564642 + M,0,86357,86629,237,430 +Sprite,Foreground,Centre,"SB\lyric\en-15-1.png",320,240 + S,0,86629,,0.6630707 + M,0,86629,87720,234,430 + F,0,86629,87720,1 + F,0,87720,88538,1,0 +Sprite,Foreground,Centre,"SB\lyric\en-15-2.png",320,240 + S,0,87175,,0.7423482 + M,0,87175,87720,417,430 + F,0,87175,87720,1 + F,0,87720,88538,1,0 +Animation,Foreground,Centre,"SB\lyric\30-1\en-30-1_0000.png",320,240,10,30,LoopForever + F,0,134902,,1 + S,0,134902,,0.6 + M,0,134902,136129,419,374 +Animation,Foreground,Centre,"SB\lyric\30-2\en-30-2_0000.png",320,240,10,30,LoopForever + S,0,135447,,0.6 + M,0,135447,136811,156,164 +Animation,Foreground,Centre,"SB\lyric\30-3\en-30-3_0000.png",320,240,10,30,LoopForever + S,0,135993,,0.6 + M,0,135993,136811,128,404 +Animation,Foreground,Centre,"SB\lyric\12\en-12_0000.png",320,240,10,30,LoopForever + S,0,136811,,0.8 + M,0,136811,137902,439,391 +Animation,Foreground,Centre,"SB\lyric\13\en-13_0000.png",320,240,10,30,LoopForever + S,0,137902,,0.6 + M,0,137902,140084,450,142 +Animation,Foreground,Centre,"SB\lyric\14\en-14_0000.png",320,240,10,30,LoopForever + S,0,140084,,1 + M,0,140084,140902,191,294 +Animation,Foreground,Centre,"SB\lyric\34-1\en-34-1_0000.png",320,240,10,30,LoopForever + S,0,140902,,0.6 + M,0,140902,141175,286,425 +Sprite,Foreground,Centre,"SB\lyric\en-34-1-1.png",320,240 + S,0,141175,,0.6 + M,0,141175,142266,286,425 + F,0,142266,143357,1,0 +Sprite,Foreground,Centre,"SB\lyric\en-34-1-2.png",320,240 + S,0,141175,,0.6 + M,0,141175,142266,286,425 + F,0,142266,143357,1,0 +Sprite,Foreground,Centre,"SB\lyric\en-34-2.png",320,240 + S,0,141720,,0.6 + M,0,141720,142266,451,425 + F,0,142266,143357,1,0 +Sprite,Foreground,Centre,"SB\lyric\y1\intro-ja-1.png",320,240 + S,0,25538,,0.6 + M,0,25538,27720,50,240 + M,0,27720,27857,50,240,50,247 + F,0,27720,28538,1,0 + R,0,27720,28538,0,0.3567487 + M,0,27857,27993,50,247,50,263 + M,0,27993,28129,50,263,50,290 + M,0,28129,28266,50,290,50,321 + M,0,28266,28402,50,321,50,360 + M,0,28402,28538,50,360,50,408 +Sprite,Foreground,Centre,"SB\lyric\y1\intro-ja-2.png",320,240 + S,0,25538,,0.6 + M,0,25538,28947,104,240 + M,0,28947,29084,104,240,104,248 + F,0,28947,29766,1,0 + R,0,28947,29766,0,-0.4095996 + M,0,29084,29220,104,248,104,263 + M,0,29220,29357,104,263,104,287 + M,0,29357,29493,104,287,104,320 + M,0,29493,29629,104,320,104,360 + M,0,29629,29766,104,360,104,409 +Sprite,Foreground,Centre,"SB\lyric\y1\intro-ja-3.png",320,240 + S,0,25538,,0.6 + M,0,25538,28129,158,240 + M,0,28129,28266,158,240,158,249 + F,0,28129,28947,1,0 + R,0,28129,28947,0,-0.2114062 + M,0,28266,28402,158,249,158,263 + M,0,28402,28538,158,263,158,288 + M,0,28538,28675,158,288,158,321 + M,0,28675,28811,158,321,158,360 + M,0,28811,28947,158,360,158,409 +Sprite,Foreground,Centre,"SB\lyric\y1\intro-ja-4.png",320,240 + S,0,25538,,0.6 + M,0,25538,28811,212,240 + M,0,28811,28947,212,240,212,248 + F,0,28811,29629,1,0 + R,0,28811,29629,0,0.4624512 + M,0,28947,29084,212,248,212,263 + M,0,29084,29220,212,263,212,288 + M,0,29220,29357,212,288,212,320 + M,0,29357,29493,212,320,212,360 + M,0,29493,29629,212,360,212,407 +Sprite,Foreground,Centre,"SB\lyric\y1\intro-ja-5.png",320,240 + S,0,25538,,0.6 + M,0,25538,28538,266,240 + M,0,28538,28675,266,240,266,248 + F,0,28538,29357,1,0 + R,0,28538,29357,0,0.2906836 + M,0,28675,28811,266,248,266,264 + M,0,28811,28947,266,264,266,288 + M,0,28947,29084,266,288,266,321 + M,0,29084,29220,266,321,266,358 + M,0,29220,29357,266,358,266,407 +Sprite,Foreground,Centre,"SB\lyric\y1\intro-ja-6.png",320,240 + S,0,25538,,0.6 + M,0,25538,27993,320,240 + M,0,27993,28129,320,240,320,247 + F,0,27993,28811,1,0 + R,0,27993,28811,0,0.2906836 + M,0,28129,28266,320,247,320,263 + M,0,28266,28402,320,263,320,288 + M,0,28402,28538,320,288,320,321 + M,0,28538,28675,320,321,320,360 + M,0,28675,28811,320,360,320,408 +Sprite,Foreground,Centre,"SB\lyric\y1\intro-ja-7.png",320,240 + S,0,25538,,0.6 + M,0,25538,28266,374,240 + M,0,28266,28402,374,240,374,248 + F,0,28266,29084,1,0 + R,0,28266,29084,0,0.1717682 + M,0,28402,28538,374,248,374,264 + M,0,28538,28675,374,264,374,288 + M,0,28675,28811,374,288,374,320 + M,0,28811,28947,374,320,374,359 + M,0,28947,29084,374,359,374,409 +Sprite,Foreground,Centre,"SB\lyric\y1\intro-ja-8.png",320,240 + S,0,25538,,0.6 + M,0,25538,27857,428,240 + M,0,27857,27993,428,240,428,249 + F,0,27857,28675,1,0 + R,0,27857,28675,0,-0.237832 + M,0,27993,28129,428,249,428,263 + M,0,28129,28266,428,263,428,288 + M,0,28266,28402,428,288,428,320 + M,0,28402,28538,428,320,428,358 + M,0,28538,28675,428,358,428,408 +Sprite,Foreground,Centre,"SB\lyric\y1\intro-ja-9.png",320,240 + S,0,25538,,0.6 + M,0,25538,28675,482,240 + M,0,28675,28811,482,240,482,247 + F,0,28675,29493,1,0 + R,0,28675,29493,0,-0.5020905 + M,0,28811,28947,482,247,482,263 + M,0,28947,29084,482,263,482,287 + M,0,29084,29220,482,287,482,320 + M,0,29220,29357,482,320,482,360 + M,0,29357,29493,482,360,482,407 +Sprite,Foreground,Centre,"SB\lyric\y1\intro-ja-10-1.png",320,240 + S,0,25538,,0.6 + M,0,25538,28402,536,240 + M,0,28402,28538,536,240,536,247 + F,0,28402,29220,1,0 + R,0,28402,29220,0,-0.3038965 + M,0,28538,28675,536,247,536,263 + M,0,28675,28811,536,263,536,289 + M,0,28811,28947,536,289,536,321 + M,0,28947,29084,536,321,536,360 + M,0,29084,29220,536,360,536,407 +Sprite,Foreground,Centre,"SB\lyric\y1\intro-ja-11.png",320,240 + S,0,25538,,0.6 + M,0,25538,29084,590,240 + F,0,28947,29902,1,0 + R,0,28947,29902,0,0.6474323 + M,0,29084,29220,590,240,590,247 + M,0,29220,29357,590,247,590,263 + M,0,29357,29493,590,263,590,288 + M,0,29493,29629,590,288,590,320 + M,0,29629,29766,590,320,590,361 + M,0,29766,29902,590,361,590,408 +Sprite,Foreground,Centre,"SB\lyric\y2\introSECOND-ja-1.png",320,240 + S,0,29902,,0.6 + M,0,29902,32084,50,240 + M,0,32084,32221,50,240,50,247 + F,0,32084,32902,1,0 + R,0,32084,32902,0,0.4 + M,0,32221,32357,50,247,50,263 + M,0,32357,32493,50,263,50,290 + M,0,32493,32630,50,290,50,321 + M,0,32630,32766,50,321,50,360 + M,0,32766,32902,50,360,50,408 +Sprite,Foreground,Centre,"SB\lyric\y2\introSECOND-ja-2.png",320,240 + S,0,29902,,0.6 + M,0,29902,33311,104,240 + M,0,33311,33448,104,240,104,248 + F,0,33311,34130,1,0 + R,0,33311,34130,0,-0.4 + M,0,33448,33584,104,248,104,263 + M,0,33584,33721,104,263,104,287 + M,0,33721,33857,104,287,104,320 + M,0,33857,33993,104,320,104,360 + M,0,33993,34130,104,360,104,409 +Sprite,Foreground,Centre,"SB\lyric\y2\introSECOND-ja-3.png",320,240 + S,0,29902,,0.6 + M,0,29902,32493,158,240 + M,0,32493,32630,158,240,158,249 + F,0,32493,33311,1,0 + R,0,32493,33311,0,-0.4 + M,0,32630,32766,158,249,158,263 + M,0,32766,32902,158,263,158,288 + M,0,32902,33039,158,288,158,321 + M,0,33039,33175,158,321,158,360 + M,0,33175,33311,158,360,158,409 +Sprite,Foreground,Centre,"SB\lyric\y2\introSECOND-ja-4.png",320,240 + S,0,29902,,0.6 + M,0,29902,33175,212,240 + M,0,33175,33311,212,240,212,248 + F,0,33175,33993,1,0 + R,0,33175,33993,0,0.4 + M,0,33311,33448,212,248,212,263 + M,0,33448,33584,212,263,212,288 + M,0,33584,33721,212,288,212,320 + M,0,33721,33857,212,320,212,360 + M,0,33857,33993,212,360,212,407 +Sprite,Foreground,Centre,"SB\lyric\y2\introSECOND-ja-5.png",320,240 + S,0,29902,,0.6 + M,0,29902,32902,266,240 + M,0,32902,33039,266,240,266,248 + F,0,32902,33721,1,0 + R,0,32902,33721,0,0.4 + M,0,33039,33175,266,248,266,264 + M,0,33175,33311,266,264,266,288 + M,0,33311,33448,266,288,266,321 + M,0,33448,33584,266,321,266,358 + M,0,33584,33721,266,358,266,407 +Sprite,Foreground,Centre,"SB\lyric\y2\introSECOND-ja-6.png",320,240 + S,0,29902,,0.6 + M,0,29902,32357,320,240 + M,0,32357,32493,320,240,320,247 + F,0,32357,33175,1,0 + R,0,32357,33175,0,0.4 + M,0,32493,32630,320,247,320,263 + M,0,32630,32766,320,263,320,288 + M,0,32766,32902,320,288,320,321 + M,0,32902,33039,320,321,320,360 + M,0,33039,33175,320,360,320,408 +Sprite,Foreground,Centre,"SB\lyric\y2\introSECOND-ja-7.png",320,240 + S,0,29902,,0.6 + M,0,29902,32630,374,240 + M,0,32630,32766,374,240,374,248 + F,0,32630,33448,1,0 + R,0,32630,33448,0,0.4 + M,0,32766,32902,374,248,374,264 + M,0,32902,33039,374,264,374,288 + M,0,33039,33175,374,288,374,320 + M,0,33175,33311,374,320,374,359 + M,0,33311,33448,374,359,374,409 +Sprite,Foreground,Centre,"SB\lyric\y2\introSECOND-ja-8.png",320,240 + S,0,29902,,0.6 + M,0,29902,32221,428,240 + M,0,32221,32357,428,240,428,249 + F,0,32221,33039,1,0 + R,0,32221,33039,0,-0.4 + M,0,32357,32493,428,249,428,263 + M,0,32493,32630,428,263,428,288 + M,0,32630,32766,428,288,428,320 + M,0,32766,32902,428,320,428,358 + M,0,32902,33039,428,358,428,408 +Sprite,Foreground,Centre,"SB\lyric\y2\introSECOND-ja-9.png",320,240 + S,0,29902,,0.6 + M,0,29902,33039,482,240 + M,0,33039,33175,482,240,482,247 + F,0,33039,33857,1,0 + R,0,33039,33857,0,-0.4 + M,0,33175,33311,482,247,482,263 + M,0,33311,33448,482,263,482,287 + M,0,33448,33584,482,287,482,320 + M,0,33584,33721,482,320,482,360 + M,0,33721,33857,482,360,482,407 +Sprite,Foreground,Centre,"SB\lyric\y2\introSECOND-ja-10-1.png",320,240 + S,0,29902,,0.6 + M,0,29902,32766,536,240 + M,0,32766,32902,536,240,536,247 + F,0,32766,33584,1,0 + R,0,32766,33584,0,-0.4 + M,0,32902,33039,536,247,536,263 + M,0,33039,33175,536,263,536,289 + M,0,33175,33311,536,289,536,321 + M,0,33311,33448,536,321,536,360 + M,0,33448,33584,536,360,536,407 +Sprite,Foreground,Centre,"SB\lyric\y2\introSECOND-ja-11.png",320,240 + S,0,29902,,0.6 + M,0,29902,33448,590,240 + F,0,33311,34266,1,0 + R,0,33311,34266,0,0.4 + M,0,33448,33584,590,240,590,247 + M,0,33584,33721,590,247,590,263 + M,0,33721,33857,590,263,590,288 + M,0,33857,33993,590,288,590,320 + M,0,33993,34130,590,320,590,361 + M,0,34130,34266,590,361,590,408 +Sprite,Foreground,Centre,"SB\lyric\y2\introSECOND-ja-1.png",320,240 + S,0,143357,,0.6 + M,0,143357,145539,50,240 + M,0,145539,145676,50,240,50,247 + F,0,145539,146357,1,0 + R,0,145539,146357,0,0.4 + M,0,145676,145812,50,247,50,263 + M,0,145812,145948,50,263,50,290 + M,0,145948,146085,50,290,50,321 + M,0,146085,146221,50,321,50,360 + M,0,146221,146357,50,360,50,408 +Sprite,Foreground,Centre,"SB\lyric\y2\introSECOND-ja-2.png",320,240 + S,0,143357,,0.6 + M,0,143357,146766,104,240 + M,0,146766,146903,104,240,104,248 + F,0,146766,147585,1,0 + R,0,146766,147585,0,-0.4 + M,0,146903,147039,104,248,104,263 + M,0,147039,147176,104,263,104,287 + M,0,147176,147312,104,287,104,320 + M,0,147312,147448,104,320,104,360 + M,0,147448,147585,104,360,104,409 +Sprite,Foreground,Centre,"SB\lyric\y2\introSECOND-ja-3.png",320,240 + S,0,143357,,0.6 + M,0,143357,145948,158,240 + M,0,145948,146085,158,240,158,249 + F,0,145948,146766,1,0 + R,0,145948,146766,0,-0.4 + M,0,146085,146221,158,249,158,263 + M,0,146221,146357,158,263,158,288 + M,0,146357,146494,158,288,158,321 + M,0,146494,146630,158,321,158,360 + M,0,146630,146766,158,360,158,409 +Sprite,Foreground,Centre,"SB\lyric\y2\introSECOND-ja-4.png",320,240 + S,0,143357,,0.6 + M,0,143357,146630,212,240 + M,0,146630,146766,212,240,212,248 + F,0,146630,147448,1,0 + R,0,146630,147448,0,0.4 + M,0,146766,146903,212,248,212,263 + M,0,146903,147039,212,263,212,288 + M,0,147039,147176,212,288,212,320 + M,0,147176,147312,212,320,212,360 + M,0,147312,147448,212,360,212,407 +Sprite,Foreground,Centre,"SB\lyric\y2\introSECOND-ja-5.png",320,240 + S,0,143357,,0.6 + M,0,143357,146357,266,240 + M,0,146357,146494,266,240,266,248 + F,0,146357,147176,1,0 + R,0,146357,147176,0,0.4 + M,0,146494,146630,266,248,266,264 + M,0,146630,146766,266,264,266,288 + M,0,146766,146903,266,288,266,321 + M,0,146903,147039,266,321,266,358 + M,0,147039,147176,266,358,266,407 +Sprite,Foreground,Centre,"SB\lyric\y2\introSECOND-ja-6.png",320,240 + S,0,143357,,0.6 + M,0,143357,145812,320,240 + M,0,145812,145948,320,240,320,247 + F,0,145812,146630,1,0 + R,0,145812,146630,0,0.4 + M,0,145948,146085,320,247,320,263 + M,0,146085,146221,320,263,320,288 + M,0,146221,146357,320,288,320,321 + M,0,146357,146494,320,321,320,360 + M,0,146494,146630,320,360,320,408 +Sprite,Foreground,Centre,"SB\lyric\y2\introSECOND-ja-7.png",320,240 + S,0,143357,,0.6 + M,0,143357,146085,374,240 + M,0,146085,146221,374,240,374,248 + F,0,146085,146903,1,0 + R,0,146085,146903,0,0.4 + M,0,146221,146357,374,248,374,264 + M,0,146357,146494,374,264,374,288 + M,0,146494,146630,374,288,374,320 + M,0,146630,146766,374,320,374,359 + M,0,146766,146903,374,359,374,409 +Sprite,Foreground,Centre,"SB\lyric\y2\introSECOND-ja-8.png",320,240 + S,0,143357,,0.6 + M,0,143357,145676,428,240 + M,0,145676,145812,428,240,428,249 + F,0,145676,146494,1,0 + R,0,145676,146494,0,-0.4 + M,0,145812,145948,428,249,428,263 + M,0,145948,146085,428,263,428,288 + M,0,146085,146221,428,288,428,320 + M,0,146221,146357,428,320,428,358 + M,0,146357,146494,428,358,428,408 +Sprite,Foreground,Centre,"SB\lyric\y2\introSECOND-ja-9.png",320,240 + S,0,143357,,0.6 + M,0,143357,146494,482,240 + M,0,146494,146630,482,240,482,247 + F,0,146494,147312,1,0 + R,0,146494,147312,0,-0.4 + M,0,146630,146766,482,247,482,263 + M,0,146766,146903,482,263,482,287 + M,0,146903,147039,482,287,482,320 + M,0,147039,147176,482,320,482,360 + M,0,147176,147312,482,360,482,407 +Sprite,Foreground,Centre,"SB\lyric\y2\introSECOND-ja-10-1.png",320,240 + S,0,143357,,0.6 + M,0,143357,146221,536,240 + M,0,146221,146357,536,240,536,247 + F,0,146221,147039,1,0 + R,0,146221,147039,0,-0.4 + M,0,146357,146494,536,247,536,263 + M,0,146494,146630,536,263,536,289 + M,0,146630,146766,536,289,536,321 + M,0,146766,146903,536,321,536,360 + M,0,146903,147039,536,360,536,407 +Sprite,Foreground,Centre,"SB\lyric\y2\introSECOND-ja-11.png",320,240 + S,0,143357,,0.6 + M,0,143357,146903,590,240 + F,0,146766,147721,1,0 + R,0,146766,147721,0,0.4 + M,0,146903,147039,590,240,590,247 + M,0,147039,147176,590,247,590,263 + M,0,147176,147312,590,263,590,288 + M,0,147312,147448,590,288,590,320 + M,0,147448,147585,590,320,590,361 + M,0,147585,147721,590,361,590,408 +Sprite,Foreground,Centre,"SB\lyric\z\outroSECOND-ja-1.png",320,240 + S,0,147720,,0.6 + M,0,147720,150993,104,240 + M,0,150993,151130,104,240,104,248 + F,0,150993,151812,1,0 + R,0,150993,151812,0,-0.4 + M,0,151130,151266,104,248,104,263 + M,0,151266,151403,104,263,104,287 + M,0,151403,151539,104,287,104,320 + M,0,151539,151675,104,320,104,360 + M,0,151675,151812,104,360,104,409 +Sprite,Foreground,Centre,"SB\lyric\z\outroSECOND-ja-2.png",320,240 + S,0,147720,,0.6 + M,0,147720,150175,158,240 + M,0,150175,150312,158,240,158,249 + F,0,150175,150993,1,0 + R,0,150175,150993,0,-0.4 + M,0,150312,150448,158,249,158,263 + M,0,150448,150584,158,263,158,288 + M,0,150584,150721,158,288,158,321 + M,0,150721,150857,158,321,158,360 + M,0,150857,150993,158,360,158,409 +Sprite,Foreground,Centre,"SB\lyric\z\outroSECOND-ja-3.png",320,240 + S,0,147720,,0.6 + M,0,147720,150857,212,240 + M,0,150857,150993,212,240,212,248 + F,0,150857,151675,1,0 + R,0,150857,151675,0,0.4 + M,0,150993,151130,212,248,212,263 + M,0,151130,151266,212,263,212,288 + M,0,151266,151403,212,288,212,320 + M,0,151403,151539,212,320,212,360 + M,0,151539,151675,212,360,212,407 +Sprite,Foreground,Centre,"SB\lyric\z\outroSECOND-ja-4.png",320,240 + S,0,147720,,0.6 + M,0,147720,150584,266,240 + M,0,150584,150721,266,240,266,248 + F,0,150584,151403,1,0 + R,0,150584,151403,0,0.4 + M,0,150721,150857,266,248,266,264 + M,0,150857,150993,266,264,266,288 + M,0,150993,151130,266,288,266,321 + M,0,151130,151266,266,321,266,358 + M,0,151266,151403,266,358,266,407 +Sprite,Foreground,Centre,"SB\lyric\z\outroSECOND-ja-5.png",320,240 + S,0,147720,,0.6 + M,0,147720,150039,320,240 + M,0,150039,150175,320,240,320,247 + F,0,150039,150857,1,0 + R,0,150039,150857,0,0.4 + M,0,150175,150312,320,247,320,263 + M,0,150312,150448,320,263,320,288 + M,0,150448,150584,320,288,320,321 + M,0,150584,150721,320,321,320,360 + M,0,150721,150857,320,360,320,408 +Sprite,Foreground,Centre,"SB\lyric\z\outroSECOND-ja-6.png",320,240 + S,0,147720,,0.6 + M,0,147720,150312,374,240 + M,0,150312,150448,374,240,374,248 + F,0,150312,151130,1,0 + R,0,150312,151130,0,0.4 + M,0,150448,150584,374,248,374,264 + M,0,150584,150721,374,264,374,288 + M,0,150721,150857,374,288,374,320 + M,0,150857,150993,374,320,374,359 + M,0,150993,151130,374,359,374,409 +Sprite,Foreground,Centre,"SB\lyric\z\outroSECOND-ja-7.png",320,240 + S,0,147720,,0.6 + M,0,147720,149903,428,240 + M,0,149903,150039,428,240,428,249 + F,0,149903,150721,1,0 + R,0,149903,150721,0,-0.4 + M,0,150039,150175,428,249,428,263 + M,0,150175,150312,428,263,428,288 + M,0,150312,150448,428,288,428,320 + M,0,150448,150584,428,320,428,358 + M,0,150584,150721,428,358,428,408 +Sprite,Foreground,Centre,"SB\lyric\z\outroSECOND-ja-8.png",320,240 + S,0,147720,,0.6 + M,0,147720,150721,482,240 + M,0,150721,150857,482,240,482,247 + F,0,150721,151539,1,0 + R,0,150721,151539,0,-0.4 + M,0,150857,150993,482,247,482,263 + M,0,150993,151130,482,263,482,287 + M,0,151130,151266,482,287,482,320 + M,0,151266,151403,482,320,482,360 + M,0,151403,151539,482,360,482,407 +Sprite,Foreground,Centre,"SB\lyric\z\outroSECOND-ja-9.png",320,240 + S,0,147720,,0.6 + M,0,147720,150448,536,240 + M,0,150448,150584,536,240,536,247 + F,0,150448,151266,1,0 + R,0,150448,151266,0,-0.4 + M,0,150584,150721,536,247,536,263 + M,0,150721,150857,536,263,536,289 + M,0,150857,150993,536,289,536,321 + M,0,150993,151130,536,321,536,360 + M,0,151130,151266,536,360,536,407 +Sprite,Foreground,Centre,"SB\lyric\y1\intro-en1.png",320,240 + S,0,25538,,0.8 + M,0,25538,27720,320,280 + F,0,27720,27993,1,0 +Sprite,Foreground,Centre,"SB\lyric\y2\intro-en2.png",320,240 + M,0,29902,,320,280 + S,0,29902,,0.8 + F,0,32084,32357,1,0 +Sprite,Foreground,Centre,"SB\lyric\z\outro-en1.png",320,240 + M,0,143357,,320,280 + S,0,143357,,0.8 + F,0,145538,145811,1,0 +Sprite,Foreground,Centre,"SB\lyric\z\outro-en2.png",320,240 + M,0,147720,,320,280 + S,0,147720,,0.8 + F,0,149902,150175,1,0 +Sprite,Foreground,Centre,"SB\lyric\ja-34-1-1.png",320,240 + S,0,141174,,0.8 + M,0,141174,143356,343,393 + F,0,142265,143356,1,0 +//Storyboard Sound Samples +//Background Colour Transformations +3,100,163,162,255 + +[TimingPoints] +2629,272.727272727273,4,2,1,30,1,0 +20083,291.26213592233,4,2,1,30,1,0 +21248,288.461538461538,4,2,1,30,1,0 +22329,-181.818181818182,4,2,1,30,0,0 +22473,-181.818181818182,4,2,1,5,0,0 +23356,272.727272727273,4,2,1,5,1,0 +23492,-100,4,2,1,10,0,0 +23628,-100,4,2,1,15,0,0 +23765,-100,4,2,1,20,0,0 +23901,-100,4,2,1,25,0,0 +24037,-100,4,2,1,30,0,0 +24174,-100,4,2,1,35,0,0 +24310,-100,4,2,1,40,0,0 +24446,-117.647058823529,4,1,1,50,0,0 +25333,-100,4,1,1,5,0,0 +25537,-100,4,1,1,50,0,0 +25810,-117.647058823529,4,2,1,50,0,0 +26492,-117.647058823529,4,1,1,50,0,0 +26765,-117.647058823529,4,2,1,50,0,0 +27719,-117.647058823529,4,1,1,50,0,0 +27992,-117.647058823529,4,2,1,50,0,0 +28674,-117.647058823529,4,1,1,50,0,0 +28878,-117.647058823529,4,2,1,5,0,0 +28946,-117.647058823529,4,2,1,50,0,0 +29901,-100,4,1,1,50,0,0 +30174,-117.647058823529,4,2,1,50,0,0 +30856,-117.647058823529,4,1,1,50,0,0 +31128,-117.647058823529,4,2,1,50,0,0 +32083,-117.647058823529,4,1,1,50,0,0 +32356,-117.647058823529,4,2,1,50,0,0 +33242,-117.647058823529,4,1,1,5,0,0 +33310,-117.647058823529,4,1,1,30,0,0 +34265,-100,4,1,1,60,0,0 +42583,-117.647058823529,4,1,1,40,0,0 +42992,-100,4,1,1,60,0,0 +51719,-133.333333333333,4,2,1,60,0,0 +53492,-117.647058823529,4,2,1,80,0,0 +53628,-200,4,2,1,60,0,0 +56015,-200,4,2,1,5,0,0 +56083,-200,4,2,1,60,0,0 +60992,-200,4,2,1,60,0,0 +61060,-200,4,1,1,20,0,0 +61128,-200,4,1,1,60,0,0 +61196,-200,4,1,1,20,0,0 +61265,-200,4,1,1,60,0,0 +61401,-200,4,1,1,20,0,0 +61537,-200,4,1,1,60,0,0 +61605,-200,4,1,1,20,0,0 +61946,-200,4,1,1,60,0,0 +62015,-200,4,1,1,20,0,0 +62355,-200,4,1,1,60,0,0 +62628,-200,4,2,1,60,0,0 +70265,-100,4,1,1,60,0,0 +71356,-90.9090909090909,4,1,1,60,0,1 +78992,-90.9090909090909,4,1,1,40,0,0 +80083,-90.9090909090909,4,1,1,60,0,1 +86628,-117.647058823529,4,1,1,60,0,0 +87719,-117.647058823529,4,1,1,60,0,0 +88810,-100,4,1,1,60,0,0 +97537,-133.333333333333,4,2,1,60,0,0 +99310,-100,4,2,1,80,0,0 +99446,-200,4,2,1,60,0,0 +101833,-200,4,2,1,5,0,0 +101901,-200,4,2,1,60,0,0 +106810,-200,4,2,1,60,0,0 +106878,-200,4,2,1,20,0,0 +106878,-200,4,2,1,60,0,0 +106946,-200,4,1,1,60,0,0 +107015,-200,4,1,1,20,0,0 +107083,-200,4,1,1,60,0,0 +107219,-200,4,1,1,20,0,0 +107355,-200,4,1,1,60,0,0 +107424,-200,4,1,1,20,0,0 +107765,-200,4,1,1,60,0,0 +107833,-200,4,1,1,20,0,0 +108174,-200,4,1,1,60,0,0 +108446,-200,4,2,1,60,0,0 +116083,-200,4,1,1,60,0,0 +117174,-133.333333333333,4,1,1,60,0,1 +123719,-200,4,1,1,20,0,0 +124674,-200,4,1,1,60,0,0 +126174,-90.9090909090909,4,1,1,60,0,1 +127810,-200,4,1,1,60,0,0 +128356,-100,4,1,1,60,0,1 +129992,-200,4,2,1,60,0,0 +130265,-100,4,1,1,60,0,1 +133537,-100,4,1,1,60,0,0 +134628,-100,4,1,1,60,0,1 +141174,-100,4,1,1,60,0,0 +142265,-117.647058823529,4,1,1,60,0,1 +143287,-117.647058823529,4,1,1,5,0,1 +143355,-117.647058823529,4,1,1,5,0,0 +143356,-133.333333333333,4,2,1,60,0,0 +147651,-133.333333333333,4,2,1,5,0,0 +147719,-133.333333333333,4,2,1,60,0,0 +152083,-100,4,1,1,60,0,0 +160810,-83.3333333333333,4,1,1,60,0,1 +162992,-76.9230769230769,4,1,1,60,0,1 +165174,-71.4285714285714,4,1,1,60,0,1 +167356,-117.647058823529,4,1,1,60,0,0 +168446,-117.647058823529,4,1,1,60,0,1 +169537,-117.647058823529,4,2,1,60,0,0 +171310,-117.647058823529,4,2,1,80,0,0 +171446,-117.647058823529,4,2,1,60,0,0 + + +[Colours] +Combo1 : 255,255,255 +Combo2 : 72,255,72 +Combo3 : 255,128,0 +Combo4 : 255,32,32 +Combo5 : 0,128,255 +Combo6 : 255,85,255 +Combo7 : 0,183,0 +Combo8 : 176,112,77 + +[HitObjects] +154,247,22401,6,0,P|56:170|169:171,1,313.500009567261 +169,170,23356,53,0,1:0:0:0: +192,92,23492,1,0,1:0:0:0: +252,40,23629,1,0,1:0:0:0: +332,28,23765,1,0,1:0:0:0: +404,60,23901,1,0,1:0:0:0: +452,124,24038,1,0,1:0:0:0: +456,204,24174,1,0,1:0:0:0: +424,276,24310,1,0,1:0:0:0: +356,316,24447,54,0,P|316:312|272:312,1,80.750001540184,0|0,0:0|2:0,0:0:0:0: +275,311,24651,1,0,2:0:0:0: +275,311,24719,1,2,2:0:0:0: +168,344,24856,1,4,3:0:0:0: +92,264,24992,1,0,0:0:0:0: +96,249,25060,1,0,2:0:0:0: +99,235,25129,1,0,2:0:0:0: +103,221,25197,1,0,2:0:0:0: +106,207,25265,54,0,P|72:144|92:104,1,121.125002310276 +108,208,25538,54,0,P|153:206|208:204,1,95 +260,88,25810,2,0,L|176:84,1,80.750001540184 +304,220,26083,1,2,0:0:0:0: +400,212,26219,1,0,0:0:0:0: +344,132,26356,1,0,0:0:0:0: +356,300,26492,54,0,P|300:360|212:348,1,161.500003080368,0|0,3:0|0:0,0:0:0:0: +200,216,26901,1,0,0:0:0:0: +200,216,27038,1,0,0:0:0:0: +108,328,27174,1,2,0:0:0:0: +108,328,27310,1,0,0:0:0:0: +28,208,27447,1,2,0:0:0:0: +112,244,27583,1,4,3:0:0:0: +112,244,27651,1,0,0:0:0:0: +112,244,27719,54,0,B|104:176|88:116|88:116|104:124|120:128,1,161.500003080368 +208,164,28129,2,0,P|248:159|284:136,1,80.750001540184,0|2,0:0|0:0,0:0:0:0: +212,72,28401,1,0,0:0:0:0: +280,240,28538,1,0,0:0:0:0: +388,140,28674,54,0,P|392:200|372:264,1,121.125002310276,0|0,3:0|0:0,0:0:0:0: +375,257,28947,2,0,P|336:252|288:252,1,80.750001540184,0|2,0:0|0:0,0:0:0:0: +456,308,29219,1,0,0:0:0:0: +376,372,29356,1,2,0:0:0:0: +376,372,29492,1,0,0:0:0:0: +376,372,29629,1,2,0:0:0:0: +376,372,29765,1,4,3:0:0:0: +376,372,29901,54,0,P|331:371|280:368,1,95 +224,248,30174,2,0,P|264:247|312:244,1,80.750001540184 +164,352,30447,1,2,0:0:0:0: +68,360,30583,1,0,0:0:0:0: +108,272,30719,1,0,0:0:0:0: +40,156,30856,54,0,P|44:80|120:36,1,161.500003080368,0|0,3:0|0:0,0:0:0:0: +136,132,31265,1,0,0:0:0:0: +136,132,31401,1,0,0:0:0:0: +256,48,31538,1,2,0:0:0:0: +256,48,31674,1,0,0:0:0:0: +376,132,31810,1,2,0:0:0:0: +312,224,31947,1,4,3:0:0:0: +312,224,32015,1,0,0:0:0:0: +312,224,32083,54,0,B|272:288|312:352|312:352|280:344,1,161.500003080368 +196,324,32492,1,0,0:0:0:0: +312,352,32629,2,0,P|348:340|396:340,1,80.750001540184,2|0,0:0|0:0,0:0:0:0: +484,368,32901,1,0,0:0:0:0: +448,229,33038,54,0,B|430:168|430:168|448:149|456:113,1,121.125002310276,2|0,0:0|0:0,0:0:0:0: +455,116,33310,2,0,L|375:132,1,80.750001540184 +208,44,33583,2,0,L|290:58,1,80.750001540184,2|0,2:0|0:0,0:0:0:0: +295,65,34265,54,0,L|199:47,1,95,4|0,0:0|0:0,0:0:0:0: +76,88,34538,1,8,0:0:0:0: +116,216,34674,1,2,2:0:0:0: +116,216,34742,1,2,2:0:0:0: +116,216,34810,2,0,P|156:244|208:240,1,95,2|0,2:0|0:0,0:0:0:0: +360,152,35083,2,0,P|311:147|268:177,1,95,8|0,0:0|0:0,0:0:0:0: +336,244,35356,54,0,L|384:60,1,190,2|8,2:0|0:0,0:0:0:0: +436,228,35765,1,2,2:0:0:0: +287,76,35901,1,2,2:0:0:0: +462,128,36038,1,2,2:0:0:0: +260,176,36174,1,8,0:0:0:0: +384,60,36310,1,2,2:0:0:0: +360,152,36447,54,0,B|312:224|348:312|348:312|320:300,1,190,4|8,0:0|0:0,0:0:0:0: +204,252,36856,1,2,2:0:0:0: +204,252,36924,1,2,2:0:0:0: +204,252,36992,2,0,P|160:236|104:244,1,95 +232,356,37265,1,8,0:0:0:0: +176,152,37401,1,0,0:0:0:0: +48,332,37538,54,0,L|144:324,1,95,8|2,0:0|2:0,0:0:0:0: +300,244,37810,2,0,L|204:252,1,95,8|2,0:0|2:0,0:0:0:0: +40,320,38083,2,0,L|136:312,1,95,0|2,0:0|2:0,0:0:0:0: +312,252,38356,2,0,P|340:184|308:124,1,142.5,8|0,0:0|0:0,0:0:0:0: +296,120,38629,54,0,P|340:132|390:129,1,95,4|0,0:0|0:0,0:0:0:0: +264,44,38901,2,0,P|224:72|212:116,1,95,8|0,0:0|0:0,0:0:0:0: +252,192,39174,1,2,2:0:0:0: +96,120,39310,1,0,0:0:0:0: +144,284,39447,1,8,0:0:0:0: +256,304,39583,1,2,2:0:0:0: +256,304,39651,1,2,2:0:0:0: +256,304,39719,54,0,B|352:296|420:292|420:292|404:260,1,190,0|8,0:0|0:0,0:0:0:0: +360,196,40129,1,0,0:0:0:0: +320,376,40265,2,0,L|424:371,1,95,2|2,2:0|2:0,0:0:0:0: +456,192,40538,2,0,L|352:197,1,95,8|0,0:0|0:0,0:0:0:0: +416,272,40810,54,0,P|360:192|400:116,1,190,4|8,0:0|0:0,0:0:0:0: +500,84,41219,1,0,0:0:0:0: +380,28,41356,2,0,P|332:20|284:40,1,95,2|0,2:0|0:0,0:0:0:0: +248,164,41629,1,8,0:0:0:0: +120,184,41765,1,2,2:0:0:0: +164,60,41901,54,0,L|68:56,1,95,8|2,0:0|2:0,0:0:0:0: +25,180,42174,2,0,L|121:184,1,95,8|2,0:0|2:0,0:0:0:0: +164,308,42447,1,8,0:0:0:0: +419,236,42583,1,0,0:0:0:0: +398,233,42651,1,0,0:0:0:0: +377,231,42719,1,8,0:0:0:0: +356,230,42788,1,0,0:0:0:0: +335,231,42856,1,8,0:0:0:0: +314,233,42924,1,8,0:0:0:0: +294,237,42992,54,0,P|257:209|249:161,1,95,4|0,0:0|0:0,0:0:0:0: +296,40,43265,1,8,0:0:0:0: +328,168,43401,1,2,2:0:0:0: +328,168,43469,1,2,2:0:0:0: +328,168,43538,2,0,P|376:176|424:152,1,95,2|0,2:0|0:0,0:0:0:0: +480,64,43810,1,8,0:0:0:0: +492,180,43947,1,0,0:0:0:0: +344,320,44083,54,0,P|256:328|197:233,1,190,2|8,2:0|0:0,0:0:0:0: +294,236,44492,1,0,0:0:0:0: +232,160,44629,53,2,2:0:0:0: +244,28,44765,1,2,2:0:0:0: +112,16,44901,1,8,0:0:0:0: +96,148,45038,1,2,2:0:0:0: +96,148,45106,1,0,0:0:0:0: +96,148,45174,54,0,B|72:216|112:268|112:268|88:264,1,142.5,4|0,0:0|0:0,0:0:0:0: +84,264,45447,2,0,P|36:268|0:304,1,95,8|0,0:0|0:0,0:0:0:0: +72,344,45719,2,0,L|272:360,1,190,2|8,2:0|0:0,0:0:0:0: +261,359,46129,1,0,0:0:0:0: +444,296,46265,54,0,P|472:260|472:200,1,95,8|2,0:0|2:0,0:0:0:0: +408,48,46538,2,0,P|397:92|423:146,1,95,8|2,0:0|2:0,0:0:0:0: +384,224,46810,1,2,2:0:0:0: +384,224,46947,2,0,L|288:216,1,95,8|8,0:0|0:0,0:0:0:0: +320,80,47219,1,2,2:0:0:0: +320,80,47288,1,2,2:0:0:0: +320,80,47356,54,0,B|248:68|184:100|184:100|161:85|120:80,1,190,4|8,0:0|0:0,0:0:0:0: +16,144,47765,1,0,0:0:0:0: +4,284,47901,2,0,P|32:323|84:344,1,95,2|0,2:0|0:0,0:0:0:0: +160,368,48174,1,8,0:0:0:0: +268,348,48310,1,0,0:0:0:0: +160,368,48447,54,0,P|206:365|256:364,1,95,2|0,2:0|0:0,0:0:0:0: +440,308,48719,2,0,P|393:305|344:304,1,95,8|0,0:0|0:0,0:0:0:0: +209,229,48992,1,2,2:0:0:0: +232,224,49060,1,0,2:0:0:0: +253,213,49129,1,2,2:0:0:0: +270,196,49197,1,0,2:0:0:0: +282,175,49265,1,8,0:0:0:0: +287,151,49333,1,0,2:0:0:0: +286,127,49401,1,2,2:0:0:0: +279,104,49469,1,2,2:0:0:0: +266,83,49538,54,0,P|312:97|364:86,1,95,4|0,0:0|0:0,0:0:0:0: +195,142,49810,2,0,P|146:137|99:161,1,95,8|0,0:0|0:0,0:0:0:0: +84,288,50083,2,0,P|188:304|264:256,1,190,2|8,2:0|0:0,0:0:0:0: +160,224,50492,1,0,0:0:0:0: +195,142,50629,53,8,0:0:0:0: +172,60,50765,1,2,2:0:0:0: +272,120,50901,53,8,0:0:0:0: +293,37,51038,1,2,2:0:0:0: +348,132,51174,53,8,0:0:0:0: +407,70,51310,1,2,2:0:0:0: +414,174,51447,53,8,0:0:0:0: +416,179,51515,1,8,0:0:0:0: +419,184,51583,1,8,0:0:0:0: +421,189,51651,1,8,0:0:0:0: +424,195,51719,38,0,P|432:231|432:267,1,71.2500027179719,0|0,1:0|0:0,0:0:0:0: +412,356,51992,2,0,P|378:353|336:352,1,71.2500027179719,0|0,1:0|0:0,0:0:0:0: +180,296,52265,1,0,1:0:0:0: +180,296,52401,1,0,1:0:0:0: +180,296,52538,2,0,P|217:294|252:293,1,71.2500027179719,0|0,1:0|0:0,0:0:0:0: +316,216,52810,101,4,3:0:0:0: +280,124,52947,1,0,0:0:0:0: +280,124,53015,1,0,0:0:0:0: +280,124,53083,1,2,0:0:0:0: +212,196,53219,5,4,3:0:0:0: +176,104,53356,1,0,0:0:0:0: +176,104,53424,1,0,0:0:0:0: +176,104,53492,1,2,0:0:0:0: +116,176,53629,1,0,1:0:0:0: +168,308,53765,5,2,0:0:0:0: +168,308,53901,2,0,P|232:300|312:300,1,142.5,4|0,3:0|0:0,0:0:0:0: +368,348,54447,2,0,P|384:312|372:256,1,95,0|0,1:0|1:0,0:0:0:0: +320,204,54856,1,0,0:0:0:0: +448,240,54992,54,0,L|464:184,1,47.5,4|4,3:0|3:0,3:0:0:0: +392,152,55265,2,0,L|388:100,1,47.5,0|4,1:0|3:0,0:0:0:0: +312,80,55538,2,0,L|284:32,1,47.5,0|4,0:0|3:0,0:0:0:0: +228,116,55810,2,0,P|188:112|136:112,1,71.25,0|0,1:0|0:0,0:0:0:0: +156,111,56083,54,0,P|152:152|100:192,1,95,4|0,3:0|0:0,0:0:0:0: +36,184,56492,1,0,0:0:0:0: +72,252,56629,1,0,1:0:0:0: +80,120,56765,1,4,3:0:0:0: +52,48,56901,53,0,1:0:0:0: +114,188,57038,2,0,P|184:184|256:184,1,142.5,0|2,0:0|0:0,0:0:0:0: +352,284,57583,1,0,0:0:0:0: +352,284,57719,1,2,0:0:0:0: +352,284,57856,1,0,0:0:0:0: +352,284,57992,2,0,L|336:344,1,47.5,2|2,0:0|0:0,0:0:0:0: +352,284,58265,54,0,P|288:277|208:276,1,142.5,4|4,3:0|3:0,0:0:0:0: +209,275,58810,2,0,P|180:240|180:184,1,95,0|0,1:0|1:0,0:0:0:0: +204,120,59219,1,0,1:0:0:0: +252,212,59356,54,0,L|304:196,1,47.5,4|0,3:0|0:0,0:0:0:0: +456,76,59629,2,0,L|404:92,1,47.5,0|4,1:0|3:0,0:0:0:0: +260,220,59901,2,0,L|312:204,1,47.5,0|4,0:0|3:0,0:0:0:0: +464,84,60174,2,0,L|412:100,1,47.5,0|0,1:0|0:0,0:0:0:0: +364,152,60447,54,0,P|320:128|268:136,1,95,4|2,3:0|0:0,0:0:0:0: +304,208,60856,1,0,0:0:0:0: +432,289,60992,1,0,1:0:0:0: +415,287,61060,1,0,0:0:0:0: +398,286,61129,1,4,3:0:0:0: +381,285,61197,1,0,0:0:0:0: +364,286,61265,1,0,1:0:0:0: +263,356,61401,1,0,0:0:0:0: +263,356,61469,1,0,0:0:0:0: +263,356,61538,53,0,0:0:0:0: +246,352,61606,1,0,0:0:0:0: +229,349,61674,1,0,0:0:0:0: +212,348,61742,1,0,0:0:0:0: +195,348,61810,1,0,0:0:0:0: +60,362,61947,1,0,0:0:0:0: +48,343,62015,1,0,0:0:0:0: +39,323,62083,1,0,0:0:0:0: +34,302,62151,1,0,0:0:0:0: +34,280,62219,1,0,0:0:0:0: +38,259,62288,1,0,0:0:0:0: +46,239,62356,1,0,0:0:0:0: +46,239,62629,54,0,B|97:232|157:220|157:220|183:242,1,142.5,4|4,3:0|3:0,0:0:0:0: +92,156,63174,2,0,L|189:138,1,95,0|0,1:0|1:0,0:0:0:0: +256,100,63583,1,0,1:0:0:0: +256,176,63719,53,4,3:0:0:0: +256,176,63856,1,4,3:0:0:0: +256,24,63992,1,0,1:0:0:0: +326,138,64129,2,0,L|420:156,1,95,4|4,3:0|3:0,0:0:0:0: +476,208,64538,2,0,P|492:256|476:304,1,95,0|0,1:0|1:0,0:0:0:0: +480,297,65083,1,0,0:0:0:0: +328,224,65219,1,0,0:0:0:0: +340,304,65356,53,0,1:0:0:0: +208,324,65492,1,4,3:0:0:0: +340,304,65629,2,0,P|288:296|260:264,1,95,0|4,1:0|3:0,1:0:0:0: +260,188,66038,1,0,0:0:0:0: +192,224,66174,2,0,L|136:216,1,47.5,0|4,1:0|3:0,0:0:0:0: +24,196,66447,53,2,0:0:0:0: +24,196,66583,1,4,3:0:0:0: +24,196,66719,1,0,1:0:0:0: +24,196,66856,2,0,P|0:152|8:104,1,95,4|0,3:0|0:0,0:0:0:0: +76,140,67265,2,0,P|122:137|172:132,1,95,2|0,0:0|1:0,0:0:0:0: +332,172,67674,1,4,3:0:0:0: +332,172,67810,2,0,L|284:176|236:180,1,95,0|0,1:0|0:0,0:0:0:0: +128,240,68219,1,0,0:0:0:0: +232,276,68356,1,0,1:0:0:0: +120,332,68492,1,4,3:0:0:0: +224,372,68629,54,0,P|268:376|320:356,1,95,4|0,3:0|1:0,0:0:0:0: +360,300,69038,1,4,3:0:0:0: +432,276,69174,2,0,P|452:232|440:180,1,95,2|0,0:0|1:0,0:0:0:0: +344,44,69583,2,0,P|340:92|372:140,1,95,4|0,3:0|0:0,0:0:0:0: +448,88,69992,1,0,1:0:0:0: +448,88,70265,21,0,0:0:0:0: +419,356,70401,1,0,0:0:0:0: +151,324,70538,1,0,0:0:0:0: +180,56,70674,1,0,0:0:0:0: +180,56,71219,37,0,0:0:0:0: +256,300,71356,2,0,L|224:192,1,104.500003189087,4|0,0:0|0:0,0:0:0:0: +202,130,71629,1,8,0:0:0:0: +252,24,71765,53,0,0:0:0:0: +151,324,71901,2,0,L|192:208,1,104.500003189087 +220,124,72174,1,8,0:0:0:0: +352,56,72310,53,0,0:0:0:0: +20,216,72447,2,0,L|124:172,1,104.500003189087 +236,116,72719,1,8,0:0:0:0: +350,191,72856,53,0,0:0:0:0: +468,120,72992,1,0,0:0:0:0: +472,256,73129,1,0,0:0:0:0: +388,120,73265,1,8,0:0:0:0: +511,187,73401,1,0,0:0:0:0: +392,256,73538,54,0,P|284:228|288:144,1,209.000006378174,4|8,0:0|0:0,0:0:0:0: +168,264,73947,1,0,0:0:0:0: +350,191,74083,2,0,P|297:189|236:188,1,104.500003189087 +468,120,74356,2,0,P|415:118|354:117,1,104.500003189087,8|0,0:0|0:0,0:0:0:0: +172,168,74629,54,0,P|184:236|264:260,1,156.750004783631 +172,168,74901,2,0,P|119:164|60:164,1,104.500003189087,8|0,0:0|0:0,0:0:0:0: +20,236,75174,53,0,0:0:0:0: +80,56,75310,1,0,0:0:0:0: +248,132,75447,2,0,P|298:125|352:124,1,104.500003189087,8|8,0:0|0:0,0:0:0:0: +351,123,75651,1,8,0:0:0:0: +351,123,75719,54,0,B|348:186|340:240|340:240|352:251|364:276,1,156.750004783631,12|0,0:0|0:0,0:0:0:0: +372,288,75993,2,0,L|384:180,1,104.500003189087,8|0,0:0|0:0,0:0:0:0: +280,316,76265,2,0,P|232:340|168:328,1,104.500003189087 +220,260,76538,1,8,0:0:0:0: +344,368,76674,53,0,0:0:0:0: +396,176,76810,2,0,L|384:284,1,104.500003189087 +456,348,77083,1,8,0:0:0:0: +308,200,77219,53,0,0:0:0:0: +472,252,77356,1,0,0:0:0:0: +452,116,77492,1,0,0:0:0:0: +352,24,77629,1,8,0:0:0:0: +216,28,77765,1,0,0:0:0:0: +112,116,77901,54,0,B|76:216|144:288|144:288|148:256,1,209.000006378174,4|8,0:0|0:0,0:0:0:0: +196,80,78310,1,0,0:0:0:0: +372,200,78447,2,0,B|332:164|284:148|284:148|224:156|180:184,1,209.000006378174,0|0,0:0|0:0,0:0:0:0: +36,268,78856,1,0,0:0:0:0: +92,368,78992,53,8,0:0:0:0: +110,362,79060,1,0,0:0:0:0: +128,357,79129,1,0,0:0:0:0: +146,353,79197,1,0,0:0:0:0: +165,350,79265,1,0,0:0:0:0: +183,348,79333,1,0,0:0:0:0: +201,346,79401,1,8,0:0:0:0: +219,345,79469,1,0,0:0:0:0: +237,345,79538,1,0,0:0:0:0: +208,236,79674,1,0,0:0:0:0: +370,255,79810,1,8,0:0:0:0: +386,262,79879,1,0,0:0:0:0: +402,268,79947,1,0,0:0:0:0: +417,278,80015,1,0,0:0:0:0: +431,287,80083,6,0,P|408:243|424:184,1,104.500003189087,4|0,0:0|0:0,0:0:0:0: +486,234,80356,1,8,0:0:0:0: +374,350,80492,1,0,0:0:0:0: +286,215,80629,54,0,P|288:159|324:117,1,104.500003189087 +368,192,80901,1,8,0:0:0:0: +182,243,81038,1,0,0:0:0:0: +152,76,81174,54,0,P|168:28|221:-2,1,104.500003189087 +262,103,81447,1,8,0:0:0:0: +105,201,81583,1,0,0:0:0:0: +56,116,81719,53,0,0:0:0:0: +20,248,81856,1,0,0:0:0:0: +152,280,81992,1,8,0:0:0:0: +192,152,82129,1,0,0:0:0:0: +20,248,82265,54,0,P|8:320|64:380,1,156.750004783631 +60,378,82538,2,0,P|114:374|168:372,1,104.500003189087,8|0,0:0|0:0,0:0:0:0: +260,336,82810,2,0,P|280:284|268:232,1,104.500003189087 +260,336,83083,1,8,0:0:0:0: +192,152,83219,1,0,0:0:0:0: +105,201,83356,54,0,P|54:203|-7:209,1,104.500003189087 +56,52,83629,2,0,P|107:54|168:60,1,104.500003189087,8|0,0:0|0:0,0:0:0:0: +312,216,83901,2,0,P|368:184|376:96,1,156.750004783631 +360,88,84174,2,0,P|416:92|472:76,1,104.500003189087,8|0,0:0|0:0,0:0:0:0: +380,284,84447,54,0,P|312:216|200:216,1,209.000006378174,4|8,0:0|0:0,0:0:0:0: +256,340,84856,1,0,0:0:0:0: +164,364,84992,2,0,P|100:356|64:328,1,104.500003189087 +16,208,85265,1,8,0:0:0:0: +140,260,85401,53,0,0:0:0:0: +92,132,85538,2,0,P|120:88|172:64,1,104.500003189087 +192,168,85810,1,8,0:0:0:0: +192,168,85947,1,0,0:0:0:0: +280,64,86083,53,0,0:0:0:0: +404,120,86219,1,0,0:0:0:0: +392,256,86356,1,8,0:0:0:0: +260,284,86492,1,0,0:0:0:0: +304,176,86629,53,0,0:0:0:0: +288,172,87174,53,0,0:0:0:0: +272,168,87719,69,8,0:0:0:0: +257,174,87788,1,0,0:0:0:0: +241,178,87856,2,0,P|202:170|160:168,1,80.750001540184 +136,284,88129,1,8,0:0:0:0: +151,290,88197,1,0,0:0:0:0: +167,294,88265,2,0,P|206:286|248:284,1,80.750001540184 +57,253,88538,1,8,0:0:0:0: +57,253,88810,6,0,P|80:300|72:348,1,95,4|0,0:0|0:0,0:0:0:0: +0,312,89083,1,8,0:0:0:0: +148,344,89219,1,2,2:0:0:0: +96,176,89356,2,0,P|48:168|0:192,1,95,2|0,2:0|0:0,0:0:0:0: +160,232,89629,1,8,0:0:0:0: +148,344,89765,1,0,0:0:0:0: +176,144,89901,54,0,P|264:136|323:231,1,190,2|8,2:0|0:0,0:0:0:0: +336,292,90310,1,0,0:0:0:0: +252,260,90447,53,2,2:0:0:0: +408,236,90583,1,2,2:0:0:0: +244,272,90719,1,8,0:0:0:0: +420,224,90856,1,2,2:0:0:0: +420,224,90924,1,0,0:0:0:0: +420,224,90992,2,0,B|452:152|400:88,1,142.5,4|0,0:0|0:0,0:0:0:0: +401,90,91265,2,0,P|359:95|296:100,1,95,8|0,0:0|0:0,0:0:0:0: +504,64,91538,2,0,L|304:20,1,190,2|8,2:0|0:0,0:0:0:0: +220,80,91947,1,0,0:0:0:0: +60,48,92083,54,0,P|32:84|32:144,1,95,8|2,0:0|2:0,0:0:0:0: +112,292,92356,2,0,P|123:248|97:194,1,95,8|2,0:0|2:0,0:0:0:0: +32,256,92629,1,8,0:0:0:0: +112,116,92765,1,2,2:0:0:0: +208,236,92901,1,8,0:0:0:0: +192,332,93038,1,2,2:0:0:0: +192,332,93106,1,2,2:0:0:0: +192,332,93174,54,0,B|264:344|328:312|328:312|351:327|392:332,1,190,12|8,0:0|0:0,0:0:0:0: +508,268,93583,1,0,0:0:0:0: +384,184,93719,2,0,P|348:152|336:104,1,95,2|0,2:0|0:0,0:0:0:0: +352,16,93992,1,8,0:0:0:0: +244,36,94129,1,0,0:0:0:0: +352,16,94265,54,0,P|306:19|256:20,1,95,2|0,2:0|0:0,0:0:0:0: +228,184,94538,2,0,P|275:187|324:188,1,95,8|0,0:0|0:0,0:0:0:0: +292,104,94810,53,2,2:0:0:0: +144,116,94947,1,2,2:0:0:0: +217,80,95083,53,8,0:0:0:0: +120,192,95219,1,2,2:0:0:0: +156,264,95356,54,0,P|110:250|58:261,1,95,4|0,0:0|0:0,0:0:0:0: +124,352,95629,2,0,P|173:357|220:333,1,95,8|0,0:0|0:0,0:0:0:0: +412,228,95901,2,0,P|308:212|232:260,1,190,2|8,2:0|0:0,0:0:0:0: +340,308,96310,1,0,0:0:0:0: +389,146,96447,37,8,0:0:0:0: +412,228,96583,1,2,2:0:0:0: +300,124,96719,101,8,0:0:0:0: +323,206,96856,1,2,2:0:0:0: +212,104,96992,37,8,0:0:0:0: +235,186,97129,1,2,2:0:0:0: +148,304,97265,53,8,0:0:0:0: +148,304,97333,1,8,0:0:0:0: +148,304,97401,1,8,0:0:0:0: +148,304,97469,1,8,0:0:0:0: +148,304,97538,86,0,P|112:296|72:288,1,71.2500027179719,0|0,1:0|0:0,0:0:0:0: +28,184,97810,2,0,P|65:177|107:173,1,71.2500027179719,0|0,1:0|0:0,1:0:0:0: +232,152,98083,1,0,1:0:0:0: +232,152,98219,1,0,1:0:0:0: +232,152,98356,2,0,P|222:185|217:223,1,71.2500027179719,0|0,1:0|0:0,0:0:0:0: +248,352,98629,101,4,3:0:0:0: +328,324,98765,1,0,0:0:0:0: +328,324,98833,1,0,0:0:0:0: +328,324,98901,1,2,0:0:0:0: +476,288,99038,5,4,3:0:0:0: +392,268,99174,1,0,0:0:0:0: +392,268,99242,1,0,0:0:0:0: +392,268,99310,1,2,0:0:0:0: +448,212,99447,1,0,1:0:0:0: +264,272,99583,5,2,0:0:0:0: +264,272,99719,2,0,P|256:208|312:160,1,142.5,4|0,3:0|0:0,0:0:0:0: +392,156,100265,2,0,P|381:118|335:82,1,95,0|0,1:0|1:0,0:0:0:0: +264,96,100674,1,0,0:0:0:0: +192,72,100810,54,0,L|136:56,1,47.5,4|0,3:0|0:0,0:0:0:0: +32,96,101083,2,0,L|88:112,1,47.5,0|4,1:0|3:0,0:0:0:0: +168,192,101356,2,0,L|112:176,1,47.5,0|4,0:0|3:0,0:0:0:0: +60,228,101629,2,0,P|56:268|56:320,1,71.25,0|0,1:0|0:0,0:0:0:0: +55,299,101901,54,0,P|100:280|144:288,1,95,4|2,3:0|0:0,0:0:0:0: +108,356,102310,1,0,0:0:0:0: +184,356,102447,1,0,1:0:0:0: +188,224,102583,1,4,3:0:0:0: +224,288,102719,53,0,1:0:0:0: +117,193,102856,2,0,P|173:149|245:173,1,142.5,4|8,3:0|1:0,0:0:0:0: +308,304,103401,1,4,3:0:0:0: +308,304,103538,1,0,1:0:0:0: +308,304,103674,1,4,3:0:0:0: +308,304,103810,2,0,L|324:244,1,47.5,0|0,1:0|0:0,0:0:0:0: +308,304,104083,54,0,P|340:352|424:336,1,142.5,4|4,3:0|3:0,0:0:0:0: +456,280,104629,2,0,P|452:231|448:180,1,95,0|0,1:0|1:0,0:0:0:0: +440,108,105038,1,2,0:0:0:0: +340,44,105174,54,0,L|288:60,1,47.5,4|0,3:0|0:0,0:0:0:0: +172,32,105447,2,0,L|188:84,1,47.5,0|4,1:0|3:0,0:0:0:0: +164,192,105719,2,0,L|216:176,1,47.5,0|4,0:0|3:0,0:0:0:0: +324,208,105992,2,0,L|308:156,1,47.5,0|0,1:0|0:0,0:0:0:0: +252,112,106265,54,0,P|208:88|156:96,1,95,4|2,3:0|0:0,0:0:0:0: +192,164,106674,1,0,0:0:0:0: +48,240,106810,1,0,1:0:0:0: +65,242,106879,1,0,0:0:0:0: +82,243,106947,1,4,3:0:0:0: +99,244,107015,1,0,0:0:0:0: +116,243,107083,1,0,1:0:0:0: +180,324,107219,1,0,0:0:0:0: +180,324,107288,1,0,0:0:0:0: +180,324,107356,53,0,0:0:0:0: +197,320,107424,1,0,0:0:0:0: +214,317,107492,1,0,0:0:0:0: +231,316,107560,1,0,0:0:0:0: +248,316,107629,1,0,0:0:0:0: +364,367,107765,1,0,0:0:0:0: +372,347,107833,1,0,0:0:0:0: +376,326,107901,1,0,0:0:0:0: +376,304,107969,1,0,0:0:0:0: +371,283,108038,1,0,0:0:0:0: +362,263,108106,1,0,0:0:0:0: +350,244,108174,1,0,0:0:0:0: +350,244,108447,54,0,B|361:178|372:120|372:120|344:132,1,142.5,4|4,3:0|3:0,0:0:0:0: +268,256,108992,2,0,L|286:157,1,95,0|0,1:0|1:0,0:0:0:0: +256,92,109401,1,4,3:0:0:0: +208,152,109538,53,4,3:0:0:0: +208,152,109674,1,0,0:0:0:0: +88,76,109810,1,0,1:0:0:0: +84,216,109947,2,0,P|36:212|-4:180,1,95,4|4,3:0|3:0,0:0:0:0: +64,144,110356,1,0,1:0:0:0: +24,320,110629,54,0,P|72:321|124:324,1,95,4|2,3:0|0:0,0:0:0:0: +196,348,111038,1,0,0:0:0:0: +184,272,111174,53,0,1:0:0:0: +316,252,111310,1,4,3:0:0:0: +184,272,111447,2,0,P|236:280|264:312,1,95,0|4,1:0|3:0,0:0:0:0: +292,380,111856,1,0,0:0:0:0: +344,324,111992,2,0,L|400:332,1,47.5,0|4,1:0|3:0,0:0:0:0: +488,248,112265,53,2,0:0:0:0: +488,248,112401,1,4,3:0:0:0: +488,248,112538,1,0,1:0:0:0: +488,248,112674,2,0,P|512:204|504:156,1,95,4|0,3:0|0:0,0:0:0:0: +456,104,113083,2,0,P|410:107|360:112,1,95,2|0,0:0|1:0,0:0:0:0: +308,232,113492,1,4,3:0:0:0: +308,232,113629,2,0,P|268:204|212:212,1,95,0|4,1:0|3:0,0:0:0:0: +248,280,114038,1,0,0:0:0:0: +128,348,114174,1,0,1:0:0:0: +148,220,114310,1,4,3:0:0:0: +76,184,114447,54,0,P|108:150|163:141,1,95,4|0,3:0|1:0,0:0:0:0: +228,164,114856,1,0,0:0:0:0: +288,116,114992,2,0,P|336:104|384:112,1,95,4|0,3:0|1:0,0:0:0:0: +468,244,115401,2,0,P|468:196|440:148,1,95,4|0,3:0|0:0,0:0:0:0: +376,188,115810,1,0,1:0:0:0: +376,188,116083,85,0,0:0:0:0: +248,324,116219,1,0,0:0:0:0: +164,156,116356,1,0,0:0:0:0: +288,16,116492,1,0,0:0:0:0: +288,16,117038,53,0,0:0:0:0: +196,56,117174,2,0,P|124:48|48:48,1,142.500005435944,4|0,0:0|0:0,0:0:0:0: +16,140,117583,1,0,0:0:0:0: +72,232,117719,2,0,P|116:256|180:248,1,106.875004076958,8|0,0:0|0:0,0:0:0:0: +184,248,117992,2,0,P|221:249|256:264,1,71.2500027179719,0|0,0:0|0:0,0:0:0:0: +300,340,118265,6,0,P|372:356|440:320,1,142.500005435944 +448,240,118674,1,0,0:0:0:0: +408,160,118810,101,8,0:0:0:0: +464,92,118947,1,0,0:0:0:0: +324,144,119083,5,0,0:0:0:0: +408,160,119219,1,0,0:0:0:0: +256,192,119356,102,0,P|188:196|112:200,1,142.500005435944 +56,120,119765,1,0,0:0:0:0: +72,288,119901,2,0,P|126:282|184:300,1,106.875004076958,8|0,0:0|0:0,0:0:0:0: +192,304,120174,2,0,P|230:306|264:296,1,71.2500027179719 +352,240,120447,6,0,P|416:208|488:228,1,142.500005435944 +428,308,120856,1,0,0:0:0:0: +460,128,120992,101,8,0:0:0:0: +424,36,121129,1,0,0:0:0:0: +360,112,121265,1,0,0:0:0:0: +296,72,121401,1,0,0:0:0:0: +296,72,121469,1,0,0:0:0:0: +296,72,121538,6,0,P|248:96|180:88,1,106.875004076958,4|0,0:0|0:0,0:0:0:0: +194,19,121810,2,0,P|228:5|268:6,1,71.2500027179719 +136,148,122083,102,0,P|106:192|43:219,1,106.875004076958,8|0,0:0|0:0,0:0:0:0: +23,153,122356,2,0,P|45:123|76:103,1,71.2500027179719 +184,256,122629,6,0,P|236:254|284:278,1,106.875004076958 +253,347,122901,2,0,P|218:343|184:329,1,71.2500027179719 +240,164,123174,101,8,0:0:0:0: +204,88,123310,1,0,0:0:0:0: +324,180,123447,5,0,0:0:0:0: +240,164,123583,1,0,0:0:0:0: +292,100,123719,6,0,P|392:132|328:264,1,285,4|0,3:0|0:0,0:0:0:0: +324,180,124674,101,0,0:0:0:0: +324,180,124810,1,0,0:0:0:0: +248,264,124947,1,0,0:0:0:0: +216,152,125083,1,0,0:0:0:0: +136,232,125219,1,0,0:0:0:0: +104,124,125356,1,0,0:0:0:0: +24,200,125492,1,0,0:0:0:0: +72,352,125629,37,0,0:0:0:0: +72,352,125765,1,0,0:0:0:0: +72,352,125901,2,0,P|108:346|152:344,1,71.25,2|0,2:0|0:0,0:0:0:0: +156,324,126174,6,0,P|108:340|48:332,1,104.500003189087 +248,264,126447,2,0,P|300:258|348:274,1,104.500003189087,0|0,0:0|0:0,0:0:0:0: +432,368,126719,1,8,0:0:0:0: +464,248,126856,53,0,0:0:0:0: +292,340,126992,2,0,L|308:184,1,156.750004783631,0|0,0:0|0:0,0:0:0:0: +312,164,127265,2,0,P|300:108|264:76,1,104.500003189087,8|0,0:0|0:0,0:0:0:0: +220,156,127538,1,0,0:0:0:0: +368,76,127674,1,0,0:0:0:0: +200,152,127810,1,8,0:0:0:0: +388,80,127947,53,8,0:0:0:0: +400,96,128015,1,8,0:0:0:0: +412,112,128083,1,8,0:0:0:0: +412,112,128356,54,0,P|348:144|288:96,1,142.5,12|0,0:0|0:0,0:0:0:0: +284,92,128629,2,0,P|238:93|188:88,1,95 +24,176,128901,2,0,P|73:173|120:172,1,95,8|0,0:0|0:0,0:0:0:0: +200,244,129174,53,0,0:0:0:0: +152,384,129310,1,0,0:0:0:0: +304,356,129447,1,8,0:0:0:0: +220,324,129583,1,0,0:0:0:0: +268,188,129719,1,8,0:0:0:0: +288,184,129788,1,0,0:0:0:0: +308,184,129856,1,0,0:0:0:0: +325,188,129924,1,0,0:0:0:0: +342,195,129992,1,2,0:0:0:0: +342,195,130265,54,0,P|320:152|324:100,1,95,4|0,0:0|0:0,0:0:0:0: +428,268,130538,1,8,0:0:0:0: +312,304,130674,1,0,0:0:0:0: +408,92,130810,54,0,P|368:32|284:28,1,142.5,0|0,0:0|0:0,0:0:0:0: +280,32,131083,2,0,P|233:27|180:32,1,95,8|0,0:0|0:0,0:0:0:0: +164,42,131288,1,0,0:0:0:0: +141,54,131356,54,0,B|150:142|150:142|132:163|124:192,1,142.5 +120,204,131629,2,0,P|168:180|208:180,1,95,8|0,0:0|0:0,0:0:0:0: +308,236,131901,53,0,0:0:0:0: +136,320,132038,1,0,0:0:0:0: +228,152,132174,1,8,0:0:0:0: +256,344,132310,1,2,2:0:0:0: +256,344,132379,1,2,2:0:0:0: +256,344,132447,54,0,B|305:335|352:332|352:332|372:280|424:260,1,190,4|8,0:0|0:0,0:0:0:0: +300,256,132856,2,0,P|255:261|204:268,1,95 +120,204,133129,1,0,0:0:0:0: +212,164,133265,53,8,0:0:0:0: +164,20,133401,1,0,0:0:0:0: +312,48,133538,54,0,L|344:88,1,47.5,8|0,0:0|0:0,0:0:0:0: +504,120,133674,2,0,L|453:127,1,47.5 +344,252,133810,2,0,L|362:204,1,47.5 +428,32,133947,2,0,L|409:79,1,47.5,8|0,0:0|0:0,0:0:0:0: +461,234,134083,2,0,L|429:194,1,47.5 +267,161,134219,2,0,L|317:153,1,47.5 +388,140,134356,1,8,0:0:0:0: +394,142,134424,1,0,0:0:0:0: +399,145,134492,1,0,0:0:0:0: +405,148,134560,1,0,0:0:0:0: +411,152,134629,102,0,P|439:208|407:280,1,142.5,4|0,0:0|0:0,0:0:0:0: +372,340,134901,2,0,P|324:341|276:344,1,95,8|0,0:0|0:0,0:0:0:0: +56,308,135174,53,0,0:0:0:0: +200,208,135310,1,8,0:0:0:0: +204,384,135447,1,0,0:0:0:0: +276,244,135583,53,0,0:0:0:0: +128,348,135719,1,0,0:0:0:0: +128,168,135856,2,0,P|168:128|212:124,1,95,0|8,0:0|0:0,0:0:0:0: +20,228,136129,53,0,0:0:0:0: +200,208,136265,1,0,0:0:0:0: +8,128,136401,1,8,0:0:0:0: +186,108,136538,1,0,0:0:0:0: +116,274,136674,1,0,0:0:0:0: +92,64,136810,54,0,B|99:117|112:160|112:160|104:180|96:208,1,142.5,4|0,0:0|0:0,0:0:0:0: +116,274,137083,2,0,P|166:268|212:268,1,95,8|0,0:0|0:0,0:0:0:0: +372,352,137356,1,0,0:0:0:0: +210,267,137492,1,0,0:0:0:0: +372,352,137629,2,0,P|420:340|452:304,1,95,8|0,0:0|0:0,0:0:0:0: +424,216,137901,53,0,0:0:0:0: +448,56,138038,1,0,0:0:0:0: +352,160,138174,5,8,0:0:0:0: +280,16,138310,1,0,0:0:0:0: +264,152,138447,5,0,0:0:0:0: +120,76,138583,1,0,0:0:0:0: +180,188,138719,5,8,0:0:0:0: +24,224,138856,1,0,0:0:0:0: +136,268,138992,70,0,P|184:268|232:272,1,95,4|0,0:0|0:0,0:0:0:0: +332,284,139265,1,8,0:0:0:0: +272,364,139401,53,0,0:0:0:0: +292,188,139538,2,0,P|332:124|408:120,1,142.5 +376,200,139810,2,0,P|425:195|480:188,1,95,8|0,0:0|0:0,0:0:0:0: +368,372,140083,54,0,P|320:368|268:364,1,95 +168,352,140356,1,8,0:0:0:0: +232,276,140492,53,0,0:0:0:0: +220,152,140629,1,0,0:0:0:0: +104,108,140765,1,0,0:0:0:0: +8,188,140901,1,8,0:0:0:0: +4,212,140969,1,0,0:0:0:0: +8,236,141038,1,0,0:0:0:0: +20,256,141106,1,0,0:0:0:0: +38,272,141174,53,0,0:0:0:0: +77,284,141719,53,0,0:0:0:0: +116,292,142265,54,0,B|104:196|8:232|-44:140|4:44|60:20|136:16|172:76|172:76|152:96|152:96|163:120|163:120|144:141|144:141|155:165|155:165|136:188|136:188|156:204|172:236|172:236,1,605.62501155138 +168,224,143356,6,0,P|228:188|304:196,1,142.500005435944,0|2,1:0|0:0,0:0:0:0: +298,193,143697,1,0,0:0:0:0: +298,193,143765,1,0,0:0:0:0: +352,264,143901,1,0,0:0:0:0: +424,212,144038,2,0,P|472:152|464:88,2,142.500005435944,2|2|0,0:0|0:0|0:0,0:0:0:0: +388,132,144719,54,0,L|364:48,1,71.2500027179719,0|0,0:0|0:0,0:0:0:0: +296,112,144992,2,0,P|264:96|224:96,2,71.2500027179719,2|0|0,0:0|0:0|0:0,0:0:0:0: +240,176,145401,53,0,0:0:0:0: +344,308,145538,2,0,P|288:348|216:344,1,142.500005435944,2|0,0:0|0:0,0:0:0:0: +260,260,145947,1,2,0:0:0:0: +172,240,146083,53,0,0:0:0:0: +172,240,146219,1,0,0:0:0:0: +172,240,146356,1,0,0:0:0:0: +172,240,146492,2,0,B|150:244|128:252|128:252|86:238|32:260,1,142.500005435944,2|0,0:0|0:0,0:0:0:0: +124,168,146901,2,0,B|146:164|168:156|168:156|210:170|264:148,1,142.500005435944,2|2,0:0|0:0,0:0:0:0: +276,140,147242,1,0,0:0:0:0: +288,132,147310,1,0,0:0:0:0: +448,180,147447,2,0,B|403:182|360:176|360:176|372:192,1,106.875004076958,2|0,0:0|0:0,0:0:0:0: +380,204,147719,54,0,P|420:264|384:336,1,142.500005435944,4|2,0:0|0:0,0:0:0:0: +397,325,148129,1,0,0:0:0:0: +332,268,148265,1,0,0:0:0:0: +276,332,148401,2,0,P|203:327|128:328,2,142.500005435944,2|2|0,0:0|0:0|0:0,0:0:0:0: +48,264,149083,1,0,0:0:0:0: +48,264,149219,2,0,P|28:196|60:136,2,142.500005435944,2|2|0,0:0|0:0|0:0,0:0:0:0: +112,208,149901,53,2,0:0:0:0: +296,256,150174,1,2,0:0:0:0: +296,256,150242,1,0,0:0:0:0: +296,256,150310,2,0,P|336:252|368:232,1,71.2500027179719,0|0,0:0|0:0,0:0:0:0: +388,72,150583,2,0,P|348:76|316:96,1,71.2500027179719,2|0,0:0|0:0,0:0:0:0: +308,172,150856,2,0,L|460:208,1,142.500005435944,2|0,0:0|0:0,0:0:0:0: +446,204,151265,37,2,0:0:0:0: +446,204,151401,1,0,0:0:0:0: +446,204,151538,5,2,0:0:0:0: +446,204,152083,86,0,P|472:248|464:304,1,95,4|0,0:0|0:0,0:0:0:0: +400,384,152356,1,8,0:0:0:0: +392,264,152492,1,2,2:0:0:0: +392,264,152560,1,2,2:0:0:0: +392,264,152629,2,0,P|348:240|300:240,1,95,2|0,2:0|0:0,0:0:0:0: +328,320,152901,1,8,0:0:0:0: +280,160,153038,1,0,0:0:0:0: +328,320,153174,54,0,L|140:344,1,190,2|8,2:0|0:0,0:0:0:0: +64,296,153583,1,0,0:0:0:0: +176,236,153719,2,2,L|224:244,2,47.5,2|2|2,2:0|2:0|2:0,2:0:0:0: +4,184,153992,1,8,0:0:0:0: +116,124,154129,1,2,2:0:0:0: +116,124,154197,1,2,2:0:0:0: +116,124,154265,54,0,P|136:68|128:32,1,95,4|0,0:0|0:0,0:0:0:0: +16,96,154538,2,0,P|-4:152|4:188,1,95,8|0,0:0|0:0,0:0:0:0: +76,288,154810,2,0,P|124:284|176:284,1,95,2|0,2:0|0:0,0:0:0:0: +292,340,155083,1,8,0:0:0:0: +276,208,155219,1,0,0:0:0:0: +380,312,155356,54,0,P|430:304|488:300,1,95,8|2,0:0|2:0,0:0:0:0: +384,232,155629,2,0,P|434:224|492:220,1,95,8|2,0:0|2:0,0:0:0:0: +312,128,155901,2,0,P|262:120|204:116,1,95,8|2,0:0|2:0,0:0:0:0: +308,48,156174,2,0,P|258:40|200:36,1,95,0|2,0:0|2:0,0:0:0:0: +213,36,156379,1,2,2:0:0:0: +213,36,156447,54,0,P|308:35|408:32,1,190,4|8,0:0|0:0,0:0:0:0: +480,88,156856,1,0,0:0:0:0: +384,232,156992,2,0,P|288:236|236:164,1,190,2|8,2:0|0:0,0:0:0:0: +328,152,157401,1,0,0:0:0:0: +264,324,157538,2,0,P|168:324|64:332,1,190,2|8,2:0|0:0,0:0:0:0: +112,248,157947,1,2,2:0:0:0: +112,248,158015,1,2,2:0:0:0: +112,248,158083,53,2,2:0:0:0: +28,144,158219,1,2,2:0:0:0: +100,32,158356,1,8,0:0:0:0: +228,72,158492,1,2,2:0:0:0: +232,204,158629,54,0,P|264:244|320:256,1,95,4|0,0:0|0:0,0:0:0:0: +484,208,158901,2,0,P|436:189|381:206,1,95,8|0,0:0|0:0,0:0:0:0: +160,328,159174,2,0,P|164:256|216:208,1,142.5,2|2,2:0|2:0,0:0:0:0: +232,204,159447,2,0,P|284:208|320:236,1,95,8|0,0:0|0:0,0:0:0:0: +251,295,159719,54,0,L|215:103,1,190,8|8,0:0|0:0,0:0:0:0: +296,64,160129,1,2,2:0:0:0: +128,152,160265,1,2,2:0:0:0: +105,144,160333,1,2,2:0:0:0: +84,131,160401,1,2,2:0:0:0: +67,114,160469,1,0,2:0:0:0: +54,94,160538,1,8,0:0:0:0: +52,117,160606,1,0,2:0:0:0: +48,140,160674,1,2,2:0:0:0: +37,161,160742,1,2,2:0:0:0: +23,179,160810,6,0,P|5:234|16:292,1,113.999996520996,4|8,0:0|0:0,0:0:0:0: +92,240,161083,2,0,P|103:296|142:341,1,113.999996520996,0|8,0:0|0:0,0:0:0:0: +184,264,161356,2,0,P|222:307|278:326,1,113.999996520996,0|8,0:0|0:0,0:0:0:0: +276,240,161629,2,0,P|331:258|388:247,1,113.999996520996,0|8,0:0|0:0,0:0:0:0: +500,184,161901,54,0,P|518:129|507:71,1,113.999996520996,0|8,0:0|0:0,0:0:0:0: +403,107,162174,2,0,P|391:50|352:5,1,113.999996520996,0|8,0:0|0:0,0:0:0:0: +275,87,162447,2,0,P|236:43|180:24,1,113.999996520996,8|0,0:0|0:0,0:0:0:0: +151,127,162719,2,0,P|96:109|38:120,1,113.999996520996,8|0,0:0|0:0,0:0:0:0: +84,292,162992,53,4,0:0:0:0: +188,228,163129,1,8,0:0:0:0: +200,352,163265,2,0,P|260:344|332:344,1,123.499994346619,0|8,0:0|0:0,0:0:0:0: +512,200,163538,53,0,0:0:0:0: +408,136,163674,1,8,0:0:0:0: +396,260,163810,2,0,P|336:252|264:252,1,123.499994346619,0|8,0:0|0:0,0:0:0:0: +240,80,164083,54,0,P|192:32|128:32,1,123.499994346619,0|8,0:0|0:0,0:0:0:0: +64,176,164356,2,0,P|112:224|176:224,1,123.499994346619,0|8,0:0|0:0,0:0:0:0: +244,72,164629,54,0,P|196:24|132:24,1,123.499994346619,0|8,0:0|0:0,0:0:0:0: +56,184,164901,2,8,P|104:232|168:232,1,123.499994346619,8|8,0:0|0:0,0:0:0:0: +328,128,165174,54,0,P|392:120|448:76,1,132.999995941162,4|8,0:0|0:0,0:0:0:0: +360,212,165447,2,0,B|394:206|416:200|416:200|456:216|500:208,1,132.999995941162,0|8,0:0|0:0,0:0:0:0: +328,300,165719,2,0,P|392:320|452:352,1,132.999995941162,0|8,0:0|0:0,0:0:0:0: +184,300,165992,2,0,P|120:320|60:352,1,132.999995941162,0|8,0:0|0:0,0:0:0:0: +152,212,166265,2,0,B|117:206|96:200|96:200|56:216|12:208,1,132.999995941162,0|8,0:0|0:0,0:0:0:0: +184,128,166538,2,0,P|120:120|64:76,1,132.999995941162,0|8,0:0|0:0,0:0:0:0: +256,80,166810,53,8,0:0:0:0: +256,100,166879,1,0,2:0:0:0: +256,120,166947,1,2,2:0:0:0: +256,140,167015,1,2,2:0:0:0: +256,160,167083,1,2,2:0:0:0: +256,256,167219,1,2,2:0:0:0: +256,256,167288,1,0,2:0:0:0: +256,256,167356,53,4,3:0:0:0: +256,276,167901,53,0,0:0:0:0: +256,296,168447,53,0,0:0:0:0: +256,84,168583,1,8,0:0:0:0: +181,265,168719,1,0,0:0:0:0: +330,115,168856,1,8,0:0:0:0: +150,190,168992,1,0,0:0:0:0: +361,190,169129,1,8,0:0:0:0: +181,115,169265,1,0,0:0:0:0: +330,265,169401,1,8,0:0:0:0: +256,192,169538,38,0,L|344:184,1,80.750001540184,4|0,3:0|0:0,0:0:0:0: +256,192,169810,2,0,L|168:200,1,80.750001540184,4|0,3:0|0:0,0:0:0:0: +256,36,170083,1,4,3:0:0:0: +256,36,170219,1,2,0:0:0:0: +256,36,170356,2,0,L|256:116,1,80.750001540184 +208,260,170629,69,2,0:0:0:0: +191,249,170697,1,0,0:0:0:0: +176,240,170765,1,0,0:0:0:0: +256,192,170901,1,0,0:0:0:0: +304,260,171038,37,2,0:0:0:0: +321,249,171106,1,0,0:0:0:0: +336,240,171174,1,0,0:0:0:0: +256,192,171310,1,0,0:0:0:0: +256,332,171447,101,4,3:0:0:0: diff --git a/osu.Game.Tests/osu.Game.Tests.csproj b/osu.Game.Tests/osu.Game.Tests.csproj index 7d7adf5983..45de8e2411 100644 --- a/osu.Game.Tests/osu.Game.Tests.csproj +++ b/osu.Game.Tests/osu.Game.Tests.csproj @@ -86,10 +86,11 @@ + - + @@ -147,6 +148,7 @@ + \ No newline at end of file From cc76c58f5f250151bb85ad5efa3f6ce008f0cbb0 Mon Sep 17 00:00:00 2001 From: Aergwyn Date: Sat, 2 Dec 2017 16:05:39 +0100 Subject: [PATCH 0974/1263] fall back to .osu file for storyboard if no .osb file is present + CI fixes --- .../Beatmaps/Formats/LegacyStoryboardDecoderTest.cs | 9 +++++---- osu.Game/Beatmaps/BeatmapManager.cs | 6 ++++-- osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs | 7 +++++++ osu.Game/Beatmaps/Formats/LegacyDecoder.cs | 12 ++++++++---- osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs | 6 +++--- 5 files changed, 27 insertions(+), 13 deletions(-) diff --git a/osu.Game.Tests/Beatmaps/Formats/LegacyStoryboardDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/LegacyStoryboardDecoderTest.cs index a42318883c..839932c640 100644 --- a/osu.Game.Tests/Beatmaps/Formats/LegacyStoryboardDecoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/LegacyStoryboardDecoderTest.cs @@ -1,7 +1,6 @@ // 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.IO; using System.Linq; using NUnit.Framework; @@ -56,9 +55,9 @@ namespace osu.Game.Tests.Beatmaps.Formats Assert.IsTrue(foreground.EnabledWhenPassing); Assert.AreEqual("Foreground", foreground.Name); - int spriteCount = background.Elements.Where(x => x.GetType() == typeof(StoryboardSprite)).Count(); - int animationCount = background.Elements.Where(x => x.GetType() == typeof(StoryboardAnimation)).Count(); - int sampleCount = background.Elements.Where(x => x.GetType() == typeof(StoryboardSample)).Count(); + int spriteCount = background.Elements.Count(x => x.GetType() == typeof(StoryboardSprite)); + int animationCount = background.Elements.Count(x => x.GetType() == typeof(StoryboardAnimation)); + int sampleCount = background.Elements.Count(x => x.GetType() == typeof(StoryboardSample)); Assert.AreEqual(15, spriteCount); Assert.AreEqual(1, animationCount); @@ -66,6 +65,7 @@ namespace osu.Game.Tests.Beatmaps.Formats Assert.AreEqual(background.Elements.Count(), spriteCount + animationCount + sampleCount); var sprite = background.Elements.ElementAt(0) as StoryboardSprite; + Assert.NotNull(sprite); Assert.IsTrue(sprite.HasCommands); Assert.AreEqual(new Vector2(320, 240), sprite.InitialPosition); Assert.IsTrue(sprite.IsDrawable); @@ -73,6 +73,7 @@ namespace osu.Game.Tests.Beatmaps.Formats Assert.AreEqual("SB/lyric/ja-21.png", sprite.Path); var animation = background.Elements.ElementAt(12) as StoryboardAnimation; + Assert.NotNull(animation); Assert.AreEqual(141175, animation.EndTime); Assert.AreEqual(10, animation.FrameCount); Assert.AreEqual(30, animation.FrameDelay); diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 00182d5d85..d97cc6a7bf 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -615,7 +615,7 @@ namespace osu.Game.Beatmaps protected override Storyboard GetStoryboard() { - if (BeatmapSetInfo?.StoryboardFile == null) + if (BeatmapInfo?.Path == null && BeatmapSetInfo?.StoryboardFile == null) return new Storyboard(); try @@ -624,7 +624,9 @@ namespace osu.Game.Beatmaps using (var stream = new StreamReader(store.GetStream(getPathForFile(BeatmapInfo.Path)))) decoder = Decoder.GetDecoder(stream); - using (var stream = new StreamReader(store.GetStream(getPathForFile(BeatmapSetInfo.StoryboardFile)))) + // try for .osb first and fall back to .osu + string storyboardFile = BeatmapSetInfo.StoryboardFile ?? BeatmapInfo.Path; + using (var stream = new StreamReader(store.GetStream(getPathForFile(storyboardFile)))) return decoder.GetStoryboardDecoder().DecodeStoryboard(stream); } catch diff --git a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs index 29cf7dd913..b7004dd3eb 100644 --- a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs @@ -47,6 +47,13 @@ namespace osu.Game.Beatmaps.Formats hitObject.ApplyDefaults(this.beatmap.ControlPointInfo, this.beatmap.BeatmapInfo.BaseDifficulty); } + protected override bool ShouldSkipLine(string line) + { + if (base.ShouldSkipLine(line) || line.StartsWith(" ") || line.StartsWith("_")) + return true; + return false; + } + protected override void ProcessSection(Section section, string line) { switch (section) diff --git a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs index 85d77d93bc..96747a870d 100644 --- a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs @@ -52,10 +52,7 @@ namespace osu.Game.Beatmaps.Formats string line; while ((line = stream.ReadLine()) != null) { - if (string.IsNullOrWhiteSpace(line)) - continue; - - if (line.StartsWith("//")) + if (ShouldSkipLine(line)) continue; // It's already set in ParseBeatmap... why do it again? @@ -76,6 +73,13 @@ namespace osu.Game.Beatmaps.Formats } } + protected virtual bool ShouldSkipLine(string line) + { + if (string.IsNullOrWhiteSpace(line) || line.StartsWith("//")) + return true; + return false; + } + protected abstract void ProcessSection(Section section, string line); /// diff --git a/osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs index aca92f3969..8da6a0cefb 100644 --- a/osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs @@ -237,9 +237,9 @@ namespace osu.Game.Beatmaps.Formats } } - private static string parseLayer(string value) => Enum.Parse(typeof(StoryLayer), value).ToString(); + private string parseLayer(string value) => Enum.Parse(typeof(StoryLayer), value).ToString(); - private static Anchor parseOrigin(string value) + private Anchor parseOrigin(string value) { var origin = (LegacyOrigins)Enum.Parse(typeof(LegacyOrigins), value); switch (origin) @@ -266,6 +266,6 @@ namespace osu.Game.Beatmaps.Formats throw new InvalidDataException($@"Unknown origin: {value}"); } - private static string cleanFilename(string path) => FileSafety.PathStandardise(path.Trim('\"')); + private string cleanFilename(string path) => FileSafety.PathStandardise(path.Trim('\"')); } } From ad8cd7eb5de9c97fdafd9e4df3af0a3a83163ada Mon Sep 17 00:00:00 2001 From: Aergwyn Date: Sat, 2 Dec 2017 17:04:42 +0100 Subject: [PATCH 0975/1263] fix possible NullReference? AppVeyor pls? --- osu.Game/Beatmaps/BeatmapManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index d97cc6a7bf..edbda1a685 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -621,7 +621,7 @@ namespace osu.Game.Beatmaps try { Decoder decoder; - using (var stream = new StreamReader(store.GetStream(getPathForFile(BeatmapInfo.Path)))) + using (var stream = new StreamReader(store.GetStream(getPathForFile(BeatmapInfo?.Path)))) decoder = Decoder.GetDecoder(stream); // try for .osb first and fall back to .osu From a1dbd7916b8a890e8a241b0d43f55aed39a1cd2a Mon Sep 17 00:00:00 2001 From: Aergwyn Date: Sun, 3 Dec 2017 14:03:43 +0100 Subject: [PATCH 0976/1263] fixes MusicController constantly trying to start a track In Detail: It tried to start a track if the current one ended even if no BeatmapSets were present. Also if only one BeatmapSet is present if will loop by itself now. --- osu.Game/Overlays/Music/PlaylistOverlay.cs | 6 ++++++ osu.Game/Overlays/MusicController.cs | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Music/PlaylistOverlay.cs b/osu.Game/Overlays/Music/PlaylistOverlay.cs index d05ad85726..eeb1982d91 100644 --- a/osu.Game/Overlays/Music/PlaylistOverlay.cs +++ b/osu.Game/Overlays/Music/PlaylistOverlay.cs @@ -149,6 +149,12 @@ namespace osu.Game.Overlays.Music private void playSpecified(BeatmapInfo info) { beatmapBacking.Value = beatmaps.GetWorkingBeatmap(info, beatmapBacking); + + if (BeatmapSets.Count() == 1) + beatmapBacking.Value.Track.Looping = true; + else + beatmapBacking.Value.Track.Looping = false; + beatmapBacking.Value.Track.Start(); } } diff --git a/osu.Game/Overlays/MusicController.cs b/osu.Game/Overlays/MusicController.cs index 4f57ea1bcd..b30ee8f6fc 100644 --- a/osu.Game/Overlays/MusicController.cs +++ b/osu.Game/Overlays/MusicController.cs @@ -251,7 +251,7 @@ namespace osu.Game.Overlays playButton.Icon = track.IsRunning ? FontAwesome.fa_pause_circle_o : FontAwesome.fa_play_circle_o; - if (track.HasCompleted && !track.Looping && !beatmapBacking.Disabled) + if (track.HasCompleted && !beatmapBacking.Disabled && playlist.BeatmapSets.Any()) next(); } else From 0c9ebcd58c2393910b9a07b407a5c45e31ccccda Mon Sep 17 00:00:00 2001 From: Aergwyn Date: Sun, 3 Dec 2017 14:15:08 +0100 Subject: [PATCH 0977/1263] fix possible NullRef --- osu.Game/Overlays/Music/PlaylistOverlay.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Music/PlaylistOverlay.cs b/osu.Game/Overlays/Music/PlaylistOverlay.cs index eeb1982d91..4bac91edb8 100644 --- a/osu.Game/Overlays/Music/PlaylistOverlay.cs +++ b/osu.Game/Overlays/Music/PlaylistOverlay.cs @@ -150,7 +150,7 @@ namespace osu.Game.Overlays.Music { beatmapBacking.Value = beatmaps.GetWorkingBeatmap(info, beatmapBacking); - if (BeatmapSets.Count() == 1) + if (BeatmapSets?.Count() == 1) beatmapBacking.Value.Track.Looping = true; else beatmapBacking.Value.Track.Looping = false; From dfa74487162de873d71da25c5698561f1677a120 Mon Sep 17 00:00:00 2001 From: Aergwyn Date: Sun, 3 Dec 2017 14:25:12 +0100 Subject: [PATCH 0978/1263] use ?: expression --- osu.Game/Overlays/Music/PlaylistOverlay.cs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/osu.Game/Overlays/Music/PlaylistOverlay.cs b/osu.Game/Overlays/Music/PlaylistOverlay.cs index 4bac91edb8..1874b7ead8 100644 --- a/osu.Game/Overlays/Music/PlaylistOverlay.cs +++ b/osu.Game/Overlays/Music/PlaylistOverlay.cs @@ -149,12 +149,7 @@ namespace osu.Game.Overlays.Music private void playSpecified(BeatmapInfo info) { beatmapBacking.Value = beatmaps.GetWorkingBeatmap(info, beatmapBacking); - - if (BeatmapSets?.Count() == 1) - beatmapBacking.Value.Track.Looping = true; - else - beatmapBacking.Value.Track.Looping = false; - + beatmapBacking.Value.Track.Looping = BeatmapSets?.Count() == 1 ? true : false; beatmapBacking.Value.Track.Start(); } } From 9d13bf36025a8c355a4f5891007fffe62ab8a99a Mon Sep 17 00:00:00 2001 From: Aergwyn Date: Sun, 3 Dec 2017 14:35:23 +0100 Subject: [PATCH 0979/1263] remove redundant expression --- osu.Game/Overlays/Music/PlaylistOverlay.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Music/PlaylistOverlay.cs b/osu.Game/Overlays/Music/PlaylistOverlay.cs index 1874b7ead8..75798bab2d 100644 --- a/osu.Game/Overlays/Music/PlaylistOverlay.cs +++ b/osu.Game/Overlays/Music/PlaylistOverlay.cs @@ -149,7 +149,7 @@ namespace osu.Game.Overlays.Music private void playSpecified(BeatmapInfo info) { beatmapBacking.Value = beatmaps.GetWorkingBeatmap(info, beatmapBacking); - beatmapBacking.Value.Track.Looping = BeatmapSets?.Count() == 1 ? true : false; + beatmapBacking.Value.Track.Looping = BeatmapSets?.Count() == 1; beatmapBacking.Value.Track.Start(); } } From 14096c90cc73a03811c58d305ab8db0f6b22c42a Mon Sep 17 00:00:00 2001 From: Aergwyn Date: Sun, 3 Dec 2017 16:41:21 +0100 Subject: [PATCH 0980/1263] removed looping if only one song is in the list (temporarily) It had one problem in relation to SongSelect disabling it when left and in general that topic belongs to another PR. --- osu.Game/Overlays/Music/PlaylistList.cs | 7 ++++++- osu.Game/Overlays/Music/PlaylistOverlay.cs | 16 +++++++--------- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/osu.Game/Overlays/Music/PlaylistList.cs b/osu.Game/Overlays/Music/PlaylistList.cs index af01cdc451..8db4af6fb2 100644 --- a/osu.Game/Overlays/Music/PlaylistList.cs +++ b/osu.Game/Overlays/Music/PlaylistList.cs @@ -35,7 +35,11 @@ namespace osu.Game.Overlays.Music set { base.Padding = value; } } - public IEnumerable BeatmapSets { set { items.Sets = value; } } + public IEnumerable BeatmapSets + { + get { return items.Sets; } + set { items.Sets = value; } + } public BeatmapSetInfo FirstVisibleSet => items.FirstVisibleSet; public BeatmapSetInfo NextSet => items.NextSet; @@ -81,6 +85,7 @@ namespace osu.Game.Overlays.Music public IEnumerable Sets { + get { return items.Select(x => x.BeatmapSetInfo).ToList(); } set { items.Clear(); diff --git a/osu.Game/Overlays/Music/PlaylistOverlay.cs b/osu.Game/Overlays/Music/PlaylistOverlay.cs index 75798bab2d..54b34aaead 100644 --- a/osu.Game/Overlays/Music/PlaylistOverlay.cs +++ b/osu.Game/Overlays/Music/PlaylistOverlay.cs @@ -29,7 +29,7 @@ namespace osu.Game.Overlays.Music private readonly Bindable beatmapBacking = new Bindable(); - public IEnumerable BeatmapSets; + public IEnumerable BeatmapSets => list.BeatmapSets; [BackgroundDependencyLoader] private void load(OsuGameBase game, BeatmapManager beatmaps, OsuColour colours) @@ -74,11 +74,10 @@ namespace osu.Game.Overlays.Music }, }; - beatmaps.BeatmapSetAdded += s => Schedule(() => list.AddBeatmapSet(s)); - beatmaps.BeatmapSetRemoved += s => Schedule(() => list.RemoveBeatmapSet(s)); - - list.BeatmapSets = BeatmapSets = beatmaps.GetAllUsableBeatmapSets(); + beatmaps.BeatmapSetAdded += delegate (BeatmapSetInfo set) { list.AddBeatmapSet(set); }; + beatmaps.BeatmapSetRemoved += delegate (BeatmapSetInfo set) { list.RemoveBeatmapSet(set); }; + list.BeatmapSets = beatmaps.GetAllUsableBeatmapSets(); beatmapBacking.BindTo(game.Beatmap); @@ -121,7 +120,7 @@ namespace osu.Game.Overlays.Music return; } - playSpecified(set.Beatmaps[0]); + playSpecified(set.Beatmaps.First()); } public void PlayPrevious() @@ -130,7 +129,7 @@ namespace osu.Game.Overlays.Music if (playable != null) { - playSpecified(playable.Beatmaps[0]); + playSpecified(playable.Beatmaps.First()); list.SelectedSet = playable; } } @@ -141,7 +140,7 @@ namespace osu.Game.Overlays.Music if (playable != null) { - playSpecified(playable.Beatmaps[0]); + playSpecified(playable.Beatmaps.First()); list.SelectedSet = playable; } } @@ -149,7 +148,6 @@ namespace osu.Game.Overlays.Music private void playSpecified(BeatmapInfo info) { beatmapBacking.Value = beatmaps.GetWorkingBeatmap(info, beatmapBacking); - beatmapBacking.Value.Track.Looping = BeatmapSets?.Count() == 1; beatmapBacking.Value.Track.Start(); } } From 5f9de399e40d6748a14657fa97da77aa3f916323 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 4 Dec 2017 11:30:25 +0900 Subject: [PATCH 0981/1263] Add keydown override --- osu.Game/Screens/OsuScreen.cs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/osu.Game/Screens/OsuScreen.cs b/osu.Game/Screens/OsuScreen.cs index 76ee4a607e..4a27c7f1ea 100644 --- a/osu.Game/Screens/OsuScreen.cs +++ b/osu.Game/Screens/OsuScreen.cs @@ -13,6 +13,8 @@ using osu.Framework.Audio; using osu.Framework.Graphics; using osu.Game.Rulesets; using osu.Game.Screens.Menu; +using osu.Framework.Input; +using OpenTK.Input; namespace osu.Game.Screens { @@ -73,6 +75,20 @@ namespace osu.Game.Screens sampleExit = audio.Sample.Get(@"UI/screen-back"); } + protected override bool OnKeyDown(InputState state, KeyDownEventArgs args) + { + if (args.Repeat || !IsCurrentScreen) return false; + + switch (args.Key) + { + case Key.Escape: + Exit(); + return true; + } + + return base.OnKeyDown(state, args); + } + protected override void OnResuming(Screen last) { base.OnResuming(last); From 7cfe694a3fd63ac1dd54caddcb87bce80f09e8cb Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 4 Dec 2017 11:37:19 +0900 Subject: [PATCH 0982/1263] Update framework --- osu-framework | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu-framework b/osu-framework index cc013fc406..8c16e6244d 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit cc013fc4063dda0843f38c1c73568a413abcf229 +Subproject commit 8c16e6244d8ca884a743a0d5a1f1ee485f18655c From 011223048b129b213003083279a9f6793e930fb5 Mon Sep 17 00:00:00 2001 From: Aergwyn Date: Mon, 4 Dec 2017 11:47:27 +0100 Subject: [PATCH 0983/1263] fix crash if any amount of maps were restored from main menu also fixes preview not playing if an entire set is restored --- osu.Game/Screens/Select/BeatmapCarousel.cs | 30 ++++++++++++++-------- osu.Game/Screens/Select/SongSelect.cs | 4 +-- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index 3f42ae11ac..47bfe6095f 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -34,7 +34,6 @@ namespace osu.Game.Screens.Select public IEnumerable Beatmaps { get { return groups.Select(g => g.BeatmapSet); } - set { scrollableContent.Clear(false); @@ -44,15 +43,14 @@ namespace osu.Game.Screens.Select List newGroups = null; Task.Run(() => - { - newGroups = value.Select(createGroup).Where(g => g != null).ToList(); - criteria.Filter(newGroups); - }).ContinueWith(t => { Schedule(() => { + newGroups = value.Select(createGroup).Where(g => g != null).ToList(); + criteria.Filter(newGroups); + foreach (var g in newGroups) - if (g != null) addGroup(g); + addGroup(g); computeYPositions(); BeatmapsChanged?.Invoke(); @@ -135,7 +133,7 @@ namespace osu.Game.Screens.Select if (i >= 0) groups.Insert(i, newGroup); else - groups.Add(newGroup); + addGroup(newGroup); } bool hadSelection = selectedGroup == group; @@ -149,8 +147,10 @@ namespace osu.Game.Screens.Select if (hadSelection && newGroup != null) { var newSelection = - newGroup.BeatmapPanels.Find(p => p.Beatmap.ID == selectedPanel?.Beatmap.ID) ?? - newGroup.BeatmapPanels[Math.Min(newGroup.BeatmapPanels.Count - 1, group.BeatmapPanels.IndexOf(selectedPanel))]; + newGroup.BeatmapPanels.Find(p => p.Beatmap.ID == selectedPanel?.Beatmap.ID); + + if(newSelection == null && group != null && selectedPanel != null) + newSelection = newGroup.BeatmapPanels[Math.Min(newGroup.BeatmapPanels.Count - 1, group.BeatmapPanels.IndexOf(selectedPanel))]; selectGroup(newGroup, newSelection); } @@ -350,6 +350,8 @@ namespace osu.Game.Screens.Select private BeatmapGroup createGroup(BeatmapSetInfo beatmapSet) { + beatmapSet = manager.Refresh(beatmapSet); + if (beatmapSet.Beatmaps.All(b => b.Hidden)) return null; @@ -381,6 +383,10 @@ namespace osu.Game.Screens.Select private void addGroup(BeatmapGroup group) { + // prevent duplicates by concurrent independent actions trying to add a group + if (groups.Any(g => g.BeatmapSet.ID == group.BeatmapSet.ID)) + return; + groups.Add(group); panels.Add(group.Header); panels.AddRange(group.BeatmapPanels); @@ -478,7 +484,8 @@ namespace osu.Game.Screens.Select if (panel == null) panel = group.BeatmapPanels.First(); - if (selectedPanel == panel) return; + if (selectedPanel == panel) + return; Trace.Assert(group.BeatmapPanels.Contains(panel), @"Selected panel must be in provided group"); @@ -490,7 +497,8 @@ namespace osu.Game.Screens.Select panel.State = PanelSelectedState.Selected; - if (selectedPanel == panel) return; + if (selectedPanel == panel) + return; selectedPanel = panel; selectedGroup = group; diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 46284226d7..0f72e3fd95 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -255,11 +255,11 @@ namespace osu.Game.Screens.Select UpdateBeatmap(Beatmap.Value); }; - selectionChangedDebounce?.Cancel(); - if (beatmap?.Equals(beatmapNoDebounce) == true) return; + selectionChangedDebounce?.Cancel(); + beatmapNoDebounce = beatmap; if (beatmap == null) From 12665fb8cf83ca2648da32eb72f2f303a3a372d3 Mon Sep 17 00:00:00 2001 From: Aergwyn Date: Mon, 4 Dec 2017 12:11:28 +0100 Subject: [PATCH 0984/1263] remove unnecessary declaration + revert accidental formatting --- osu.Game/Screens/Select/BeatmapCarousel.cs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index 47bfe6095f..fe981f1f2a 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -40,13 +40,11 @@ namespace osu.Game.Screens.Select panels.Clear(); groups.Clear(); - List newGroups = null; - Task.Run(() => { Schedule(() => { - newGroups = value.Select(createGroup).Where(g => g != null).ToList(); + var newGroups = value.Select(createGroup).Where(g => g != null).ToList(); criteria.Filter(newGroups); foreach (var g in newGroups) @@ -484,8 +482,7 @@ namespace osu.Game.Screens.Select if (panel == null) panel = group.BeatmapPanels.First(); - if (selectedPanel == panel) - return; + if (selectedPanel == panel) return; Trace.Assert(group.BeatmapPanels.Contains(panel), @"Selected panel must be in provided group"); @@ -497,8 +494,7 @@ namespace osu.Game.Screens.Select panel.State = PanelSelectedState.Selected; - if (selectedPanel == panel) - return; + if (selectedPanel == panel) return; selectedPanel = panel; selectedGroup = group; From a83add8540d59d40ac19003de9ca1b29a2011512 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 4 Dec 2017 20:30:56 +0900 Subject: [PATCH 0985/1263] Tidy up events --- osu.Game/Overlays/Music/PlaylistList.cs | 10 +++++----- osu.Game/Overlays/Music/PlaylistOverlay.cs | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/osu.Game/Overlays/Music/PlaylistList.cs b/osu.Game/Overlays/Music/PlaylistList.cs index 8db4af6fb2..245b2d36ce 100644 --- a/osu.Game/Overlays/Music/PlaylistList.cs +++ b/osu.Game/Overlays/Music/PlaylistList.cs @@ -52,7 +52,7 @@ namespace osu.Game.Overlays.Music } public void AddBeatmapSet(BeatmapSetInfo beatmapSet) => items.AddBeatmapSet(beatmapSet); - public bool RemoveBeatmapSet(BeatmapSetInfo beatmapSet) => items.RemoveBeatmapSet(beatmapSet); + public void RemoveBeatmapSet(BeatmapSetInfo beatmapSet) => items.RemoveBeatmapSet(beatmapSet); public void Filter(string searchTerm) => items.SearchTerm = searchTerm; @@ -108,12 +108,11 @@ namespace osu.Game.Overlays.Music }); } - public bool RemoveBeatmapSet(BeatmapSetInfo beatmapSet) + public void RemoveBeatmapSet(BeatmapSetInfo beatmapSet) { var itemToRemove = items.FirstOrDefault(i => i.BeatmapSetInfo.ID == beatmapSet.ID); - if (itemToRemove == null) - return false; - return items.Remove(itemToRemove); + if (itemToRemove != null) + items.Remove(itemToRemove); } public BeatmapSetInfo SelectedSet @@ -235,6 +234,7 @@ namespace osu.Game.Overlays.Music private class ItemSearchContainer : FillFlowContainer, IHasFilterableChildren { public IEnumerable FilterTerms => new string[] { }; + public bool MatchingFilter { set diff --git a/osu.Game/Overlays/Music/PlaylistOverlay.cs b/osu.Game/Overlays/Music/PlaylistOverlay.cs index 54b34aaead..2c7c097be2 100644 --- a/osu.Game/Overlays/Music/PlaylistOverlay.cs +++ b/osu.Game/Overlays/Music/PlaylistOverlay.cs @@ -74,8 +74,8 @@ namespace osu.Game.Overlays.Music }, }; - beatmaps.BeatmapSetAdded += delegate (BeatmapSetInfo set) { list.AddBeatmapSet(set); }; - beatmaps.BeatmapSetRemoved += delegate (BeatmapSetInfo set) { list.RemoveBeatmapSet(set); }; + beatmaps.BeatmapSetAdded += list.AddBeatmapSet; + beatmaps.BeatmapSetRemoved += list.RemoveBeatmapSet; list.BeatmapSets = beatmaps.GetAllUsableBeatmapSets(); From 7649a3115704dfae6c3947917f294ad97177b181 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 4 Dec 2017 20:32:50 +0900 Subject: [PATCH 0986/1263] Update framework --- osu-framework | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu-framework b/osu-framework index 8c16e6244d..e21fc5e170 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit 8c16e6244d8ca884a743a0d5a1f1ee485f18655c +Subproject commit e21fc5e1705593151a323007fd66e90044332398 From caee6c1cf1163407734edf6fd68226849aafba66 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 4 Dec 2017 21:40:26 +0900 Subject: [PATCH 0987/1263] Use Restart instead of Start --- osu.Game/Overlays/Music/PlaylistOverlay.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Music/PlaylistOverlay.cs b/osu.Game/Overlays/Music/PlaylistOverlay.cs index 2c7c097be2..cc55a72f24 100644 --- a/osu.Game/Overlays/Music/PlaylistOverlay.cs +++ b/osu.Game/Overlays/Music/PlaylistOverlay.cs @@ -148,7 +148,7 @@ namespace osu.Game.Overlays.Music private void playSpecified(BeatmapInfo info) { beatmapBacking.Value = beatmaps.GetWorkingBeatmap(info, beatmapBacking); - beatmapBacking.Value.Track.Start(); + beatmapBacking.Value.Track.Restart(); } } From b4641142a8e6205a25b175f3c4bae90b40d17e9d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 5 Dec 2017 01:00:06 +0900 Subject: [PATCH 0988/1263] Update framework once more --- osu-framework | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu-framework b/osu-framework index e21fc5e170..d2c6d11f3b 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit e21fc5e1705593151a323007fd66e90044332398 +Subproject commit d2c6d11f3bcc54a5aeb5a16d6563036c7e1f4759 From c1b607fed926eeb2051b8d0ebb6e3869efb9dcc9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 5 Dec 2017 09:56:24 +0900 Subject: [PATCH 0989/1263] Wait until track has restarted before continuing operation I removed this from my previous PR thinking it was not required, but it turned out to be required after all. Just isn't so noticeable when it fails. --- osu.Game/Overlays/Music/PlaylistOverlay.cs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Music/PlaylistOverlay.cs b/osu.Game/Overlays/Music/PlaylistOverlay.cs index cc55a72f24..23bec53014 100644 --- a/osu.Game/Overlays/Music/PlaylistOverlay.cs +++ b/osu.Game/Overlays/Music/PlaylistOverlay.cs @@ -13,6 +13,7 @@ using osu.Game.Beatmaps; using osu.Game.Graphics; using OpenTK; using OpenTK.Graphics; +using System.Threading; namespace osu.Game.Overlays.Music { @@ -148,7 +149,15 @@ namespace osu.Game.Overlays.Music private void playSpecified(BeatmapInfo info) { beatmapBacking.Value = beatmaps.GetWorkingBeatmap(info, beatmapBacking); - beatmapBacking.Value.Track.Restart(); + + var track = beatmapBacking.Value.Track; + + track.Restart(); + + // this is temporary until we have blocking (async.Wait()) audio component methods. + // then we can call RestartAsync().Wait() or the blocking version above. + while (!track.IsRunning) + Thread.Sleep(1); } } From fb6408257a5fa980d0abd728c16cdbc1d42ea22f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 5 Dec 2017 15:54:15 +0900 Subject: [PATCH 0990/1263] Add shader precompile step Resolves https://github.com/ppy/osu-framework/issues/1180 in a way. --- osu.Game/Screens/Loader.cs | 70 +++++++++++++++++++++++++++++++++++--- 1 file changed, 66 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Loader.cs b/osu.Game/Screens/Loader.cs index ca541ea552..ec2e8e0cb1 100644 --- a/osu.Game/Screens/Loader.cs +++ b/osu.Game/Screens/Loader.cs @@ -1,8 +1,12 @@ // 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.Allocation; using osu.Framework.Graphics; +using osu.Framework.Graphics.Shaders; using osu.Game.Screens.Menu; using OpenTK; using osu.Framework.Screens; @@ -33,14 +37,28 @@ namespace osu.Game.Screens logo.FadeInFromZero(5000, Easing.OutQuint); } + private OsuScreen loadScreen; + private ShaderPrecompiler precompiler; + protected override void OnEntering(Screen last) { base.OnEntering(last); - if (showDisclaimer) - LoadComponentAsync(new Disclaimer(), d => Push(d)); - else - LoadComponentAsync(new Intro(), d => Push(d)); + LoadComponentAsync(precompiler = new ShaderPrecompiler(loadIfReady), Add); + LoadComponentAsync(loadScreen = showDisclaimer ? (OsuScreen)new Disclaimer() : new Intro(), s => loadIfReady()); + } + + private void loadIfReady() + { + if (ChildScreen == loadScreen) return; + + if (loadScreen.LoadState != LoadState.Ready) + return; + + if (!precompiler.FinishedCompiling) + return; + + Push(loadScreen); } protected override void LogoSuspending(OsuLogo logo) @@ -54,5 +72,49 @@ namespace osu.Game.Screens { showDisclaimer = game.IsDeployedBuild; } + + /// + /// Compiles a set of shaders before continuing. Attempts to draw some frames between compilation by limiting to one compile per draw frame. + /// + public class ShaderPrecompiler : Drawable + { + private readonly Action onLoaded; + private readonly List loadTargets = new List(); + + public bool FinishedCompiling { get; private set; } + + public ShaderPrecompiler(Action onLoaded) + { + this.onLoaded = onLoaded; + } + + [BackgroundDependencyLoader] + private void load(ShaderManager manager) + { + loadTargets.Add(manager.Load(VertexShaderDescriptor.TEXTURE_2, FragmentShaderDescriptor.TEXTURE_ROUNDED)); + loadTargets.Add(manager.Load(VertexShaderDescriptor.TEXTURE_2, FragmentShaderDescriptor.BLUR)); + loadTargets.Add(manager.Load(VertexShaderDescriptor.TEXTURE_2, FragmentShaderDescriptor.TEXTURE)); + + loadTargets.Add(manager.Load(@"CursorTrail", FragmentShaderDescriptor.TEXTURE)); + + loadTargets.Add(manager.Load(VertexShaderDescriptor.TEXTURE_3, FragmentShaderDescriptor.TEXTURE_ROUNDED)); + loadTargets.Add(manager.Load(VertexShaderDescriptor.TEXTURE_3, FragmentShaderDescriptor.TEXTURE)); + } + + private Shader currentLoadTarget; + + protected override void Update() + { + base.Update(); + + // if our target is null we are done. + if (loadTargets.All(s => s.Loaded)) + { + FinishedCompiling = true; + Expire(); + onLoaded?.Invoke(); + } + } + } } } From b584178e851fa26da60a3027ec3b52708b8bd39a Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 6 Dec 2017 00:37:37 +0900 Subject: [PATCH 0991/1263] Make Beatmap ISerializable and add more JsonIgnores --- osu.Game.Rulesets.Mania/Objects/Note.cs | 2 + .../osu.Game.Rulesets.Mania.csproj | 4 + .../Beatmaps/Formats/OsuJsonDecoderTest.cs | 153 ++++++++++++++++++ osu.Game.Tests/osu.Game.Tests.csproj | 1 + osu.Game/Beatmaps/Beatmap.cs | 8 +- osu.Game/Beatmaps/BeatmapDifficulty.cs | 2 + osu.Game/Beatmaps/BeatmapInfo.cs | 7 + osu.Game/Beatmaps/BeatmapMetadata.cs | 5 + .../ControlPoints/ControlPointInfo.cs | 6 +- .../Converters/TypedListConverter.cs | 83 ++++++++++ .../Converters/Vector2Converter.cs | 35 ++++ .../IO/Serialization/IJsonSerializable.cs | 26 +-- osu.Game/Rulesets/RulesetInfo.cs | 3 + osu.Game/osu.Game.csproj | 2 + 14 files changed, 322 insertions(+), 15 deletions(-) create mode 100644 osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs create mode 100644 osu.Game/IO/Serialization/Converters/TypedListConverter.cs create mode 100644 osu.Game/IO/Serialization/Converters/Vector2Converter.cs diff --git a/osu.Game.Rulesets.Mania/Objects/Note.cs b/osu.Game.Rulesets.Mania/Objects/Note.cs index 3c4ff4216f..c4d5a13352 100644 --- a/osu.Game.Rulesets.Mania/Objects/Note.cs +++ b/osu.Game.Rulesets.Mania/Objects/Note.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 Newtonsoft.Json; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Rulesets.Mania.Judgements; @@ -15,6 +16,7 @@ namespace osu.Game.Rulesets.Mania.Objects /// /// The key-press hit window for this note. /// + [JsonIgnore] public HitWindows HitWindows { get; protected set; } = new HitWindows(); public override void ApplyDefaults(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) diff --git a/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj b/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj index ec6f59b5be..1e11e2e694 100644 --- a/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj +++ b/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj @@ -40,6 +40,10 @@ $(SolutionDir)\packages\OpenTK.3.0.0-git00009\lib\net20\OpenTK.dll True + + $(SolutionDir)\packages\Newtonsoft.Json.10.0.3\lib\net45\Newtonsoft.Json.dll + True + diff --git a/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs new file mode 100644 index 0000000000..1531deb265 --- /dev/null +++ b/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs @@ -0,0 +1,153 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System.IO; +using System.Linq; +using NUnit.Framework; +using osu.Game.Audio; +using osu.Game.Beatmaps; +using osu.Game.Beatmaps.Formats; +using osu.Game.IO.Serialization; +using osu.Game.Rulesets.Objects.Types; +using osu.Game.Tests.Resources; +using OpenTK; +using OpenTK.Graphics; + +namespace osu.Game.Tests.Beatmaps.Formats +{ + [TestFixture] + public class OsuJsonDecoderTest + { + [Test] + public void TestDecodeMetadata() + { + var beatmap = decodeAsJson("Soleily - Renatus (Gamu) [Insane].osu"); + var meta = beatmap.BeatmapInfo.Metadata; + Assert.AreEqual(241526, meta.OnlineBeatmapSetID); + Assert.AreEqual("Soleily", meta.Artist); + Assert.AreEqual("Soleily", meta.ArtistUnicode); + Assert.AreEqual("03. Renatus - Soleily 192kbps.mp3", meta.AudioFile); + Assert.AreEqual("Gamu", meta.AuthorString); + Assert.AreEqual("machinetop_background.jpg", meta.BackgroundFile); + Assert.AreEqual(164471, meta.PreviewTime); + Assert.AreEqual(string.Empty, meta.Source); + Assert.AreEqual("MBC7 Unisphere 地球ヤバイEP Chikyu Yabai", meta.Tags); + Assert.AreEqual("Renatus", meta.Title); + Assert.AreEqual("Renatus", meta.TitleUnicode); + } + + [Test] + public void TestDecodeGeneral() + { + var beatmap = decodeAsJson("Soleily - Renatus (Gamu) [Insane].osu"); + var beatmapInfo = beatmap.BeatmapInfo; + Assert.AreEqual(0, beatmapInfo.AudioLeadIn); + Assert.AreEqual(false, beatmapInfo.Countdown); + Assert.AreEqual(0.7f, beatmapInfo.StackLeniency); + Assert.AreEqual(false, beatmapInfo.SpecialStyle); + Assert.IsTrue(beatmapInfo.RulesetID == 0); + Assert.AreEqual(false, beatmapInfo.LetterboxInBreaks); + Assert.AreEqual(false, beatmapInfo.WidescreenStoryboard); + } + + [Test] + public void TestDecodeEditor() + { + var beatmap = decodeAsJson("Soleily - Renatus (Gamu) [Insane].osu"); + var beatmapInfo = beatmap.BeatmapInfo; + + int[] expectedBookmarks = + { + 11505, 22054, 32604, 43153, 53703, 64252, 74802, 85351, + 95901, 106450, 116999, 119637, 130186, 140735, 151285, + 161834, 164471, 175020, 185570, 196119, 206669, 209306 + }; + Assert.AreEqual(expectedBookmarks.Length, beatmapInfo.Bookmarks.Length); + for (int i = 0; i < expectedBookmarks.Length; i++) + Assert.AreEqual(expectedBookmarks[i], beatmapInfo.Bookmarks[i]); + Assert.AreEqual(1.8, beatmapInfo.DistanceSpacing); + Assert.AreEqual(4, beatmapInfo.BeatDivisor); + Assert.AreEqual(4, beatmapInfo.GridSize); + Assert.AreEqual(2, beatmapInfo.TimelineZoom); + } + + [Test] + public void TestDecodeDifficulty() + { + var beatmap = decodeAsJson("Soleily - Renatus (Gamu) [Insane].osu"); + var difficulty = beatmap.BeatmapInfo.BaseDifficulty; + Assert.AreEqual(6.5f, difficulty.DrainRate); + Assert.AreEqual(4, difficulty.CircleSize); + Assert.AreEqual(8, difficulty.OverallDifficulty); + Assert.AreEqual(9, difficulty.ApproachRate); + Assert.AreEqual(1.8f, difficulty.SliderMultiplier); + Assert.AreEqual(2, difficulty.SliderTickRate); + } + + [Test] + public void TestDecodeColors() + { + var beatmap = decodeAsJson("Soleily - Renatus (Gamu) [Insane].osu"); + Color4[] expected = + { + new Color4(142, 199, 255, 255), + new Color4(255, 128, 128, 255), + new Color4(128, 255, 255, 255), + new Color4(128, 255, 128, 255), + new Color4(255, 187, 255, 255), + new Color4(255, 177, 140, 255), + }; + Assert.AreEqual(expected.Length, beatmap.ComboColors.Count); + for (int i = 0; i < expected.Length; i++) + Assert.AreEqual(expected[i], beatmap.ComboColors[i]); + } + + [Test] + public void TestDecodeHitObjects() + { + var beatmap = decodeAsJson("Soleily - Renatus (Gamu) [Insane].osu"); + + var curveData = beatmap.HitObjects[0] as IHasCurve; + var positionData = beatmap.HitObjects[0] as IHasPosition; + + Assert.IsNotNull(positionData); + Assert.IsNotNull(curveData); + Assert.AreEqual(new Vector2(192, 168), positionData.Position); + Assert.AreEqual(956, beatmap.HitObjects[0].StartTime); + Assert.IsTrue(beatmap.HitObjects[0].Samples.Any(s => s.Name == SampleInfo.HIT_NORMAL)); + + positionData = beatmap.HitObjects[1] as IHasPosition; + + Assert.IsNotNull(positionData); + Assert.AreEqual(new Vector2(304, 56), positionData.Position); + Assert.AreEqual(1285, beatmap.HitObjects[1].StartTime); + Assert.IsTrue(beatmap.HitObjects[1].Samples.Any(s => s.Name == SampleInfo.HIT_CLAP)); + } + + /// + /// Reads a .osu file first with a , serializes the resulting to JSON + /// and then deserializes the result back into a through an . + /// + /// The .osu file to decode. + /// The after being decoded by an . + private Beatmap decodeAsJson(string filename) + { + using (var stream = Resource.OpenResource(filename)) + using (var sr = new StreamReader(stream)) + { + var legacyDecoded = new OsuLegacyDecoder().Decode(sr); + + using (var ms = new MemoryStream()) + using (var sw = new StreamWriter(ms)) + using (var sr2 = new StreamReader(ms)) + { + sw.Write(legacyDecoded.Serialize()); + sw.Flush(); + + ms.Position = 0; + return new OsuJsonDecoder().Decode(sr2); + } + } + } + } +} diff --git a/osu.Game.Tests/osu.Game.Tests.csproj b/osu.Game.Tests/osu.Game.Tests.csproj index 092ccfb9b5..60ce67c7f6 100644 --- a/osu.Game.Tests/osu.Game.Tests.csproj +++ b/osu.Game.Tests/osu.Game.Tests.csproj @@ -83,6 +83,7 @@ + diff --git a/osu.Game/Beatmaps/Beatmap.cs b/osu.Game/Beatmaps/Beatmap.cs index 35b6cc2b02..c331872dda 100644 --- a/osu.Game/Beatmaps/Beatmap.cs +++ b/osu.Game/Beatmaps/Beatmap.cs @@ -9,19 +9,21 @@ using System.Linq; using osu.Game.Beatmaps.ControlPoints; using osu.Game.IO.Serialization; using osu.Game.Storyboards; +using Newtonsoft.Json; +using osu.Game.IO.Serialization.Converters; namespace osu.Game.Beatmaps { /// /// A Beatmap containing converted HitObjects. /// - public class Beatmap + public class Beatmap : IJsonSerializable where T : HitObject { public BeatmapInfo BeatmapInfo = new BeatmapInfo(); public ControlPointInfo ControlPointInfo = new ControlPointInfo(); public List Breaks = new List(); - public readonly List ComboColors = new List + public List ComboColors = new List { new Color4(17, 136, 170, 255), new Color4(102, 136, 0, 255), @@ -29,8 +31,10 @@ namespace osu.Game.Beatmaps new Color4(121, 9, 13, 255) }; + [JsonIgnore] public BeatmapMetadata Metadata => BeatmapInfo?.Metadata ?? BeatmapInfo?.BeatmapSet?.Metadata; + [JsonConverter(typeof(TypedListConverter))] /// /// The HitObjects this Beatmap contains. /// diff --git a/osu.Game/Beatmaps/BeatmapDifficulty.cs b/osu.Game/Beatmaps/BeatmapDifficulty.cs index 0b0fca8292..03fbf9a0a7 100644 --- a/osu.Game/Beatmaps/BeatmapDifficulty.cs +++ b/osu.Game/Beatmaps/BeatmapDifficulty.cs @@ -2,6 +2,7 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System.ComponentModel.DataAnnotations.Schema; +using Newtonsoft.Json; namespace osu.Game.Beatmaps { @@ -13,6 +14,7 @@ namespace osu.Game.Beatmaps public const float DEFAULT_DIFFICULTY = 5; [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + [JsonIgnore] public int ID { get; set; } public float DrainRate { get; set; } = DEFAULT_DIFFICULTY; diff --git a/osu.Game/Beatmaps/BeatmapInfo.cs b/osu.Game/Beatmaps/BeatmapInfo.cs index 022d64db03..6b5f7cb150 100644 --- a/osu.Game/Beatmaps/BeatmapInfo.cs +++ b/osu.Game/Beatmaps/BeatmapInfo.cs @@ -15,6 +15,7 @@ namespace osu.Game.Beatmaps public class BeatmapInfo : IEquatable, IJsonSerializable, IHasPrimaryKey { [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + [JsonIgnore] public int ID { get; set; } //TODO: should be in database @@ -38,13 +39,16 @@ namespace osu.Game.Beatmaps set { onlineBeatmapSetID = value > 0 ? value : null; } } + [JsonIgnore] public int BeatmapSetInfoID { get; set; } [Required] + [JsonIgnore] public BeatmapSetInfo BeatmapSet { get; set; } public BeatmapMetadata Metadata { get; set; } + [JsonIgnore] public int BaseDifficultyID { get; set; } public BeatmapDifficulty BaseDifficulty { get; set; } @@ -60,6 +64,7 @@ namespace osu.Game.Beatmaps [JsonProperty("file_sha2")] public string Hash { get; set; } + [JsonIgnore] public bool Hidden { get; set; } /// @@ -74,6 +79,7 @@ namespace osu.Game.Beatmaps public float StackLeniency { get; set; } public bool SpecialStyle { get; set; } + [JsonIgnore] public int RulesetID { get; set; } public RulesetInfo Ruleset { get; set; } @@ -116,6 +122,7 @@ namespace osu.Game.Beatmaps public string Version { get; set; } public double StarDifficulty { get; set; } + public bool ShouldSerializeStarDifficulty() => false; public bool Equals(BeatmapInfo other) { diff --git a/osu.Game/Beatmaps/BeatmapMetadata.cs b/osu.Game/Beatmaps/BeatmapMetadata.cs index 89f9ebf47a..2efbcd4f15 100644 --- a/osu.Game/Beatmaps/BeatmapMetadata.cs +++ b/osu.Game/Beatmaps/BeatmapMetadata.cs @@ -12,6 +12,7 @@ namespace osu.Game.Beatmaps public class BeatmapMetadata { [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + [JsonIgnore] public int ID { get; set; } private int? onlineBeatmapSetID; @@ -29,7 +30,10 @@ namespace osu.Game.Beatmaps public string Artist { get; set; } public string ArtistUnicode { get; set; } + [JsonIgnore] public List Beatmaps { get; set; } + + [JsonIgnore] public List BeatmapSets { get; set; } /// @@ -56,6 +60,7 @@ namespace osu.Game.Beatmaps public string AudioFile { get; set; } public string BackgroundFile { get; set; } + [JsonIgnore] public string[] SearchableTerms => new[] { Author?.Username, diff --git a/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs b/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs index e46eb8e20a..f24e25f112 100644 --- a/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs +++ b/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Linq; +using Newtonsoft.Json; using osu.Framework.Lists; namespace osu.Game.Beatmaps.ControlPoints @@ -58,18 +59,21 @@ namespace osu.Game.Beatmaps.ControlPoints /// The timing control 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() ?? new TimingControlPoint()).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; + [JsonIgnore] /// /// Finds the mode BPM (most common BPM) represented by the control points. /// @@ -108,4 +112,4 @@ namespace osu.Game.Beatmaps.ControlPoints return list[index - 1]; } } -} \ No newline at end of file +} diff --git a/osu.Game/IO/Serialization/Converters/TypedListConverter.cs b/osu.Game/IO/Serialization/Converters/TypedListConverter.cs new file mode 100644 index 0000000000..1d617422e7 --- /dev/null +++ b/osu.Game/IO/Serialization/Converters/TypedListConverter.cs @@ -0,0 +1,83 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +namespace osu.Game.IO.Serialization.Converters +{ + public class TypedListConverter : JsonConverter + { + public override bool CanConvert(Type objectType) => objectType == typeof(List); + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + var list = new List(); + + var localSerializer = createLocalSerializer(); + + var obj = JObject.Load(reader); + + var lookupTable = new List(); + localSerializer.Populate(obj["LookupTable"].CreateReader(), lookupTable); + + foreach (var tok in obj["Items"]) + { + var itemReader = tok.CreateReader(); + + var typeName = lookupTable[(int)tok["Type"]]; + var instance = (T)Activator.CreateInstance(Type.GetType(typeName)); + localSerializer.Populate(itemReader, instance); + + list.Add(instance); + } + + return list; + } + + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + var list = (List)value; + + var localSerializer = createLocalSerializer(); + + var lookupTable = new List(); + var objects = new List(); + foreach (var item in list) + { + var type = item.GetType().AssemblyQualifiedName; + + int typeId = lookupTable.IndexOf(type); + if (typeId == -1) + { + lookupTable.Add(type); + typeId = lookupTable.Count - 1; + } + + var itemObject = JObject.FromObject(item, localSerializer); + itemObject.AddFirst(new JProperty("Type", typeId)); + objects.Add(itemObject); + } + + writer.WriteStartObject(); + + writer.WritePropertyName("LookupTable"); + localSerializer.Serialize(writer, lookupTable); + + writer.WritePropertyName("Items"); + writer.WriteStartArray(); + foreach (var item in objects) + item.WriteTo(writer); + writer.WriteEndArray(); + + writer.WriteEndObject(); + } + + private JsonSerializer createLocalSerializer() + { + var localSettings = JsonSerializableExtensions.CreateGlobalSettings(); + localSettings.Converters = localSettings.Converters.Where(c => !(c is TypedListConverter)).ToArray(); + return JsonSerializer.Create(localSettings); + } + } +} diff --git a/osu.Game/IO/Serialization/Converters/Vector2Converter.cs b/osu.Game/IO/Serialization/Converters/Vector2Converter.cs new file mode 100644 index 0000000000..4ec27311bc --- /dev/null +++ b/osu.Game/IO/Serialization/Converters/Vector2Converter.cs @@ -0,0 +1,35 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using OpenTK; + +namespace osu.Game.IO.Serialization.Converters +{ + public class Vector2Converter : JsonConverter + { + public override bool CanConvert(Type objectType) => objectType == typeof(Vector2); + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + var obj = JObject.Load(reader); + return new Vector2((float)obj["X"], (float)obj["Y"]); + } + + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + var vector = (Vector2)value; + + writer.WriteStartObject(); + + writer.WritePropertyName("X"); + writer.WriteValue(vector.X); + writer.WritePropertyName("Y"); + writer.WriteValue(vector.Y); + + writer.WriteEndObject(); + } + } +} diff --git a/osu.Game/IO/Serialization/IJsonSerializable.cs b/osu.Game/IO/Serialization/IJsonSerializable.cs index e725742726..8d10f0b291 100644 --- a/osu.Game/IO/Serialization/IJsonSerializable.cs +++ b/osu.Game/IO/Serialization/IJsonSerializable.cs @@ -2,6 +2,7 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using Newtonsoft.Json; +using osu.Game.IO.Serialization.Converters; namespace osu.Game.IO.Serialization { @@ -11,20 +12,21 @@ namespace osu.Game.IO.Serialization public static class JsonSerializableExtensions { - public static string Serialize(this IJsonSerializable obj) - { - return JsonConvert.SerializeObject(obj, new JsonSerializerSettings { ReferenceLoopHandling = ReferenceLoopHandling.Ignore }); - } + public static string Serialize(this IJsonSerializable obj) => JsonConvert.SerializeObject(obj, CreateGlobalSettings()); - public static T Deserialize(this string objString) - { - return JsonConvert.DeserializeObject(objString); - } + public static T Deserialize(this string objString) => JsonConvert.DeserializeObject(objString, CreateGlobalSettings()); - public static T DeepClone(this T obj) - where T : IJsonSerializable + public static void DeserializeInto(this string objString, T target) => JsonConvert.PopulateObject(objString, target, CreateGlobalSettings()); + + public static T DeepClone(this T obj) where T : IJsonSerializable => Deserialize(Serialize(obj)); + + public static JsonSerializerSettings CreateGlobalSettings() => new JsonSerializerSettings { - return Deserialize(Serialize(obj)); - } + ReferenceLoopHandling = ReferenceLoopHandling.Ignore, + Formatting = Formatting.Indented, + ObjectCreationHandling = ObjectCreationHandling.Replace, + DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate, + Converters = new JsonConverter[] { new Vector2Converter() } + }; } } diff --git a/osu.Game/Rulesets/RulesetInfo.cs b/osu.Game/Rulesets/RulesetInfo.cs index 17f07158df..e6e0b98293 100644 --- a/osu.Game/Rulesets/RulesetInfo.cs +++ b/osu.Game/Rulesets/RulesetInfo.cs @@ -3,18 +3,21 @@ using System; using System.ComponentModel.DataAnnotations.Schema; +using Newtonsoft.Json; namespace osu.Game.Rulesets { public class RulesetInfo : IEquatable { [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + [JsonIgnore] public int? ID { get; set; } public string Name { get; set; } public string InstantiationInfo { get; set; } + [JsonIgnore] public bool Available { get; set; } public virtual Ruleset CreateInstance() => (Ruleset)Activator.CreateInstance(Type.GetType(InstantiationInfo), this); diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 4ca6123f04..f50e87b074 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -403,6 +403,8 @@ + + From d2dc7c8937dfe1901494c01c81c4459ef40e86ab Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 6 Dec 2017 00:38:12 +0900 Subject: [PATCH 0992/1263] Add OsuJsonDecoder --- osu.Game/Beatmaps/Formats/BeatmapDecoder.cs | 12 +++++++++- osu.Game/Beatmaps/Formats/OsuJsonDecoder.cs | 25 +++++++++++++++++++++ osu.Game/osu.Game.csproj | 1 + 3 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 osu.Game/Beatmaps/Formats/OsuJsonDecoder.cs diff --git a/osu.Game/Beatmaps/Formats/BeatmapDecoder.cs b/osu.Game/Beatmaps/Formats/BeatmapDecoder.cs index 7e1a87085c..31869e207e 100644 --- a/osu.Game/Beatmaps/Formats/BeatmapDecoder.cs +++ b/osu.Game/Beatmaps/Formats/BeatmapDecoder.cs @@ -14,6 +14,7 @@ namespace osu.Game.Beatmaps.Formats static BeatmapDecoder() { OsuLegacyDecoder.Register(); + OsuJsonDecoder.Register(); } public static BeatmapDecoder GetDecoder(StreamReader stream) @@ -27,7 +28,16 @@ namespace osu.Game.Beatmaps.Formats if (line == null || !decoders.ContainsKey(line)) throw new IOException(@"Unknown file format"); - return (BeatmapDecoder)Activator.CreateInstance(decoders[line], line); + + try + { + return (BeatmapDecoder)Activator.CreateInstance(decoders[line], line); + } + catch + { + // As a default case, try a parameterless constructor + return (BeatmapDecoder)Activator.CreateInstance(decoders[line]); + } } protected static void AddDecoder(string magic) where T : BeatmapDecoder diff --git a/osu.Game/Beatmaps/Formats/OsuJsonDecoder.cs b/osu.Game/Beatmaps/Formats/OsuJsonDecoder.cs new file mode 100644 index 0000000000..392f1b4890 --- /dev/null +++ b/osu.Game/Beatmaps/Formats/OsuJsonDecoder.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.IO; +using osu.Game.IO.Serialization; + +namespace osu.Game.Beatmaps.Formats +{ + public class OsuJsonDecoder : BeatmapDecoder + { + public static void Register() + { + AddDecoder("{"); + } + + protected override void ParseFile(StreamReader stream, Beatmap beatmap) + { + stream.BaseStream.Position = 0; + stream.DiscardBufferedData(); + + string fullText = stream.ReadToEnd(); + fullText.DeserializeInto(beatmap); + } + } +} diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index f50e87b074..9e5d4291ce 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -266,6 +266,7 @@ + From e199ee52252b85ff0b091cc86c6c1c91f1ef2972 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 6 Dec 2017 00:42:17 +0900 Subject: [PATCH 0993/1263] Add a few xmldocs --- osu.Game/IO/Serialization/Converters/TypedListConverter.cs | 6 ++++++ osu.Game/IO/Serialization/Converters/Vector2Converter.cs | 3 +++ 2 files changed, 9 insertions(+) diff --git a/osu.Game/IO/Serialization/Converters/TypedListConverter.cs b/osu.Game/IO/Serialization/Converters/TypedListConverter.cs index 1d617422e7..9c35fae7d4 100644 --- a/osu.Game/IO/Serialization/Converters/TypedListConverter.cs +++ b/osu.Game/IO/Serialization/Converters/TypedListConverter.cs @@ -6,6 +6,12 @@ using Newtonsoft.Json.Linq; namespace osu.Game.IO.Serialization.Converters { + /// + /// A type of that serializes a alongside + /// a lookup table for the types contained. The lookup table is used in deserialization to + /// reconstruct the objects with their original types. + /// + /// The type of objects contained in the this attribute is attached to. public class TypedListConverter : JsonConverter { public override bool CanConvert(Type objectType) => objectType == typeof(List); diff --git a/osu.Game/IO/Serialization/Converters/Vector2Converter.cs b/osu.Game/IO/Serialization/Converters/Vector2Converter.cs index 4ec27311bc..5f21018fd5 100644 --- a/osu.Game/IO/Serialization/Converters/Vector2Converter.cs +++ b/osu.Game/IO/Serialization/Converters/Vector2Converter.cs @@ -8,6 +8,9 @@ using OpenTK; namespace osu.Game.IO.Serialization.Converters { + /// + /// A type of that serializes only the X and Y coordinates of a . + /// public class Vector2Converter : JsonConverter { public override bool CanConvert(Type objectType) => objectType == typeof(Vector2); From 15ed3b4aac3c87ae277c1c53696f02b3c1b1097e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 6 Dec 2017 09:49:12 +0900 Subject: [PATCH 0994/1263] Fix IsValueCreated method not cecking whether the async task was completed Caused potential stutters for components that relied on this check. --- osu.Game/Beatmaps/WorkingBeatmap.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Beatmaps/WorkingBeatmap.cs b/osu.Game/Beatmaps/WorkingBeatmap.cs index 8c96074352..a23d74f288 100644 --- a/osu.Game/Beatmaps/WorkingBeatmap.cs +++ b/osu.Game/Beatmaps/WorkingBeatmap.cs @@ -144,7 +144,7 @@ namespace osu.Game.Beatmaps get { ensureValid(); - return lazy.IsValueCreated; + return lazy.Value.IsCompleted; } } From 988cc27f0e7fc461d0d8c66aa3e0375eb24ffa28 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 6 Dec 2017 11:59:53 +0900 Subject: [PATCH 0995/1263] Update framework --- osu-framework | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu-framework b/osu-framework index d2c6d11f3b..9cd6968a8c 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit d2c6d11f3bcc54a5aeb5a16d6563036c7e1f4759 +Subproject commit 9cd6968a8c4d27415808f5e770d24fec5a44485f From 44edb8724fcabc81456616346a9a25dc55dcb54a Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 6 Dec 2017 13:46:49 +0900 Subject: [PATCH 0996/1263] Add JsonIgnores to CommandTimelineGroup --- osu.Game/Storyboards/CommandTimelineGroup.cs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/osu.Game/Storyboards/CommandTimelineGroup.cs b/osu.Game/Storyboards/CommandTimelineGroup.cs index 332a6f79cb..c6d9202121 100644 --- a/osu.Game/Storyboards/CommandTimelineGroup.cs +++ b/osu.Game/Storyboards/CommandTimelineGroup.cs @@ -6,6 +6,7 @@ using OpenTK.Graphics; using osu.Framework.Graphics; using System.Collections.Generic; using System.Linq; +using Newtonsoft.Json; namespace osu.Game.Storyboards { @@ -23,6 +24,7 @@ namespace osu.Game.Storyboards public CommandTimeline FlipH = new CommandTimeline(); public CommandTimeline FlipV = new CommandTimeline(); + [JsonIgnore] public IEnumerable Timelines { get @@ -39,14 +41,25 @@ namespace osu.Game.Storyboards } } + [JsonIgnore] public double CommandsStartTime => Timelines.Where(t => t.HasCommands).Min(t => t.StartTime); + + [JsonIgnore] public double CommandsEndTime => Timelines.Where(t => t.HasCommands).Max(t => t.EndTime); + + [JsonIgnore] public double CommandsDuration => CommandsEndTime - CommandsStartTime; + [JsonIgnore] public virtual double StartTime => CommandsStartTime; + + [JsonIgnore] public virtual double EndTime => CommandsEndTime; + + [JsonIgnore] public double Duration => EndTime - StartTime; + [JsonIgnore] public bool HasCommands => Timelines.Any(t => t.HasCommands); public virtual IEnumerable.TypedCommand> GetCommands(CommandTimelineSelector timelineSelector, double offset = 0) From 887b81148db1741aaee3f85642beeb536ddc0528 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 6 Dec 2017 14:14:07 +0900 Subject: [PATCH 0997/1263] Don't ignore RulesetId for now --- osu.Game/Beatmaps/BeatmapInfo.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Beatmaps/BeatmapInfo.cs b/osu.Game/Beatmaps/BeatmapInfo.cs index 6b5f7cb150..9450022a01 100644 --- a/osu.Game/Beatmaps/BeatmapInfo.cs +++ b/osu.Game/Beatmaps/BeatmapInfo.cs @@ -79,7 +79,6 @@ namespace osu.Game.Beatmaps public float StackLeniency { get; set; } public bool SpecialStyle { get; set; } - [JsonIgnore] public int RulesetID { get; set; } public RulesetInfo Ruleset { get; set; } From 04ae64e9fd7bb412cb20cb3424d2325afd94ced0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 6 Dec 2017 16:20:49 +0900 Subject: [PATCH 0998/1263] Add missing IsCompleted check to ensureValid --- osu.Game/Beatmaps/WorkingBeatmap.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Beatmaps/WorkingBeatmap.cs b/osu.Game/Beatmaps/WorkingBeatmap.cs index a23d74f288..6378bb7568 100644 --- a/osu.Game/Beatmaps/WorkingBeatmap.cs +++ b/osu.Game/Beatmaps/WorkingBeatmap.cs @@ -161,7 +161,7 @@ namespace osu.Game.Beatmaps { lock (initLock) { - if (!lazy.IsValueCreated || (stillValidFunction?.Invoke(lazy.Value.Result) ?? true)) return; + if (!lazy.IsValueCreated || !lazy.Value.IsCompleted || (stillValidFunction?.Invoke(lazy.Value.Result) ?? true)) return; init(); } } From f9e34dfa3d51415062e8bd7ce677274c7823d274 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 6 Dec 2017 16:23:51 +0900 Subject: [PATCH 0999/1263] Assume that control points are already sequentially-ordered Fixes up deserializing. --- .../UI/ManiaRulesetContainer.cs | 3 +-- .../Visual/TestCaseBeatSyncedContainer.cs | 4 ++-- .../Beatmaps/ControlPoints/ControlPointInfo.cs | 16 ++++++++++------ 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/osu.Game.Rulesets.Mania/UI/ManiaRulesetContainer.cs b/osu.Game.Rulesets.Mania/UI/ManiaRulesetContainer.cs index cbbcb84b31..83306187bd 100644 --- a/osu.Game.Rulesets.Mania/UI/ManiaRulesetContainer.cs +++ b/osu.Game.Rulesets.Mania/UI/ManiaRulesetContainer.cs @@ -9,7 +9,6 @@ using osu.Framework.Allocation; using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Graphics; using osu.Framework.Input; -using osu.Framework.Lists; using osu.Framework.MathUtils; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; @@ -44,7 +43,7 @@ namespace osu.Game.Rulesets.Mania.UI // Generate the bar lines double lastObjectTime = (Objects.LastOrDefault() as IHasEndTime)?.EndTime ?? Objects.LastOrDefault()?.StartTime ?? double.MaxValue; - SortedList timingPoints = Beatmap.ControlPointInfo.TimingPoints; + List timingPoints = Beatmap.ControlPointInfo.TimingPoints; var barLines = new List(); for (int i = 0; i < timingPoints.Count; i++) diff --git a/osu.Game.Tests/Visual/TestCaseBeatSyncedContainer.cs b/osu.Game.Tests/Visual/TestCaseBeatSyncedContainer.cs index 18555574ba..d99485f3a2 100644 --- a/osu.Game.Tests/Visual/TestCaseBeatSyncedContainer.cs +++ b/osu.Game.Tests/Visual/TestCaseBeatSyncedContainer.cs @@ -2,12 +2,12 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; +using System.Collections.Generic; using osu.Framework.Audio.Track; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; -using osu.Framework.Lists; using osu.Framework.Timing; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Graphics.Containers; @@ -137,7 +137,7 @@ namespace osu.Game.Tests.Visual }; } - private SortedList timingPoints => Beatmap.Value.Beatmap.ControlPointInfo.TimingPoints; + private List timingPoints => Beatmap.Value.Beatmap.ControlPointInfo.TimingPoints; private TimingControlPoint getNextTimingPoint(TimingControlPoint current) { if (timingPoints[timingPoints.Count - 1] == current) diff --git a/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs b/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs index f24e25f112..652ae42979 100644 --- a/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs +++ b/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs @@ -5,31 +5,35 @@ using System; using System.Collections.Generic; using System.Linq; using Newtonsoft.Json; -using osu.Framework.Lists; namespace osu.Game.Beatmaps.ControlPoints { + [Serializable] public class ControlPointInfo { + [JsonProperty] /// /// All timing points. /// - public readonly SortedList TimingPoints = new SortedList(Comparer.Default); + public List TimingPoints { get; private set; } = new List(); + [JsonProperty] /// /// All difficulty points. /// - public readonly SortedList DifficultyPoints = new SortedList(Comparer.Default); + public List DifficultyPoints { get; private set; } = new List(); + [JsonProperty] /// /// All sound points. /// - public readonly SortedList SoundPoints = new SortedList(Comparer.Default); + public List SoundPoints { get; private set; } = new List(); + [JsonProperty] /// /// All effect points. /// - public readonly SortedList EffectPoints = new SortedList(Comparer.Default); + public List EffectPoints { get; private set; } = new List(); /// /// Finds the difficulty control point that is active at . @@ -87,7 +91,7 @@ namespace osu.Game.Beatmaps.ControlPoints /// 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 active control point at . - private T binarySearch(SortedList list, double time, T prePoint = null) + private T binarySearch(List list, double time, T prePoint = null) where T : ControlPoint, new() { if (list == null) From ed5f7e5353a77d05203a596cb0c3bee4380fd237 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 6 Dec 2017 16:28:34 +0900 Subject: [PATCH 1000/1263] Make OsuJsonDecoder apply defaults similar to OsuLegacyDecoder --- osu.Game/Beatmaps/Formats/OsuJsonDecoder.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Beatmaps/Formats/OsuJsonDecoder.cs b/osu.Game/Beatmaps/Formats/OsuJsonDecoder.cs index 392f1b4890..ed4b8f3857 100644 --- a/osu.Game/Beatmaps/Formats/OsuJsonDecoder.cs +++ b/osu.Game/Beatmaps/Formats/OsuJsonDecoder.cs @@ -20,6 +20,9 @@ namespace osu.Game.Beatmaps.Formats string fullText = stream.ReadToEnd(); fullText.DeserializeInto(beatmap); + + foreach (var hitObject in beatmap.HitObjects) + hitObject.ApplyDefaults(beatmap.ControlPointInfo, beatmap.BeatmapInfo.BaseDifficulty); } } } From 34596b3368591d2b9eba717a5139854dd1ce4ba1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 6 Dec 2017 21:47:48 +0900 Subject: [PATCH 1001/1263] Rename and comment for clarification --- osu.Game/Beatmaps/WorkingBeatmap.cs | 44 ++++++++++++++++------------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/osu.Game/Beatmaps/WorkingBeatmap.cs b/osu.Game/Beatmaps/WorkingBeatmap.cs index 6378bb7568..bc826ea140 100644 --- a/osu.Game/Beatmaps/WorkingBeatmap.cs +++ b/osu.Game/Beatmaps/WorkingBeatmap.cs @@ -41,7 +41,7 @@ namespace osu.Game.Beatmaps protected abstract Track GetTrack(); protected virtual Waveform GetWaveform() => new Waveform(); - public bool BeatmapLoaded => beatmap.IsValueCreated; + public bool BeatmapLoaded => beatmap.IsResultAvailable; public Beatmap Beatmap => beatmap.Value.Result; public async Task GetBeatmapAsync() => await beatmap.Value; @@ -57,14 +57,14 @@ namespace osu.Game.Beatmaps return b; } - public bool BackgroundLoaded => background.IsValueCreated; + public bool BackgroundLoaded => background.IsResultAvailable; public Texture Background => background.Value.Result; public async Task GetBackgroundAsync() => await background.Value; private AsyncLazy background; private Texture populateBackground() => GetBackground(); - public bool TrackLoaded => track.IsValueCreated; + public bool TrackLoaded => track.IsResultAvailable; public Track Track => track.Value.Result; public async Task GetTrackAsync() => await track.Value; private AsyncLazy track; @@ -77,7 +77,7 @@ namespace osu.Game.Beatmaps return t; } - public bool WaveformLoaded => waveform.IsValueCreated; + public bool WaveformLoaded => waveform.IsResultAvailable; public Waveform Waveform => waveform.Value.Result; public async Task GetWaveformAsync() => await waveform.Value; private readonly AsyncLazy waveform; @@ -86,10 +86,10 @@ namespace osu.Game.Beatmaps public void TransferTo(WorkingBeatmap other) { - if (track.IsValueCreated && Track != null && BeatmapInfo.AudioEquals(other.BeatmapInfo)) + if (track.IsResultAvailable && Track != null && BeatmapInfo.AudioEquals(other.BeatmapInfo)) other.track = track; - if (background.IsValueCreated && Background != null && BeatmapInfo.BackgroundEquals(other.BeatmapInfo)) + if (background.IsResultAvailable && Background != null && BeatmapInfo.BackgroundEquals(other.BeatmapInfo)) other.background = background; } @@ -107,7 +107,7 @@ namespace osu.Game.Beatmaps private void applyRateAdjustments(Track t = null) { - if (t == null && track.IsValueCreated) t = Track; + if (t == null && track.IsResultAvailable) t = Track; if (t == null) return; t.ResetSpeedAdjustments(); @@ -128,22 +128,22 @@ namespace osu.Game.Beatmaps this.valueFactory = valueFactory; this.stillValidFunction = stillValidFunction; - init(); + recreate(); } public void Recycle() { - if (!IsValueCreated) return; + if (!IsResultAvailable) return; (lazy.Value.Result as IDisposable)?.Dispose(); - init(); + recreate(); } - public bool IsValueCreated + public bool IsResultAvailable { get { - ensureValid(); + recreateIfInvalid(); return lazy.Value.IsCompleted; } } @@ -152,24 +152,28 @@ namespace osu.Game.Beatmaps { get { - ensureValid(); + recreateIfInvalid(); return lazy.Value; } } - private void ensureValid() + private void recreateIfInvalid() { lock (initLock) { - if (!lazy.IsValueCreated || !lazy.Value.IsCompleted || (stillValidFunction?.Invoke(lazy.Value.Result) ?? true)) return; - init(); + if (!lazy.IsValueCreated || !lazy.Value.IsCompleted) + // we have not yet been initialised or haven't run the task. + return; + + if (stillValidFunction?.Invoke(lazy.Value.Result) ?? true) + // we are still in a valid state. + return; + + recreate(); } } - private void init() - { - lazy = new Lazy>(() => Task.Run(valueFactory)); - } + private void recreate() => lazy = new Lazy>(() => Task.Run(valueFactory)); } } } From b6b26cfe2565140b2b515ae1c076a0fe72083ab0 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 7 Dec 2017 03:04:36 +0900 Subject: [PATCH 1002/1263] Add basic method to migrate beatmaps to the new JSON format --- osu.Game/Beatmaps/BeatmapManager.cs | 25 ++++++++++++ .../IO/Serialization/IJsonSerializable.cs | 2 +- .../Sections/Maintenance/GeneralSettings.cs | 40 +++++++++++++++++++ 3 files changed, 66 insertions(+), 1 deletion(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 0641cabcd8..c96b889213 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -545,6 +545,31 @@ namespace osu.Game.Beatmaps return beatmapSet; } + public void UpdateContent(BeatmapInfo beatmapInfo, Stream newData) + { + // let's only allow one concurrent update at a time for now. + var context = createContext(); + + using (var transaction = context.BeginTransaction()) + { + // create local stores so we can isolate and thread safely, and share a context/transaction. + var setInfo = beatmapInfo.BeatmapSet; + var existingSetFileInfo = setInfo.Files.First(f => f.FileInfo.Hash == beatmapInfo.Hash); + var existingFileInfo = existingSetFileInfo.FileInfo; + + existingSetFileInfo.FileInfo = files.Add(newData); + files.Dereference(existingFileInfo); + + beatmapInfo.Hash = newData.ComputeSHA2Hash(); + beatmapInfo.MD5Hash = newData.ComputeMD5Hash(); + + context.Update(existingSetFileInfo); + context.Update(beatmapInfo); + + context.SaveChanges(transaction); + } + } + /// /// Returns a list of all usable s. /// diff --git a/osu.Game/IO/Serialization/IJsonSerializable.cs b/osu.Game/IO/Serialization/IJsonSerializable.cs index 8d10f0b291..e192d702ce 100644 --- a/osu.Game/IO/Serialization/IJsonSerializable.cs +++ b/osu.Game/IO/Serialization/IJsonSerializable.cs @@ -16,7 +16,7 @@ namespace osu.Game.IO.Serialization public static T Deserialize(this string objString) => JsonConvert.DeserializeObject(objString, CreateGlobalSettings()); - public static void DeserializeInto(this string objString, T target) => JsonConvert.PopulateObject(objString, target, CreateGlobalSettings()); + public static void DeserializeInto(this string objString, T target) => JsonConvert.DeserializeAnonymousType(objString, target, CreateGlobalSettings()); public static T DeepClone(this T obj) where T : IJsonSerializable => Deserialize(Serialize(obj)); diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs index 4f4f381ae1..a41da6109c 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs @@ -1,12 +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.IO; using System.Linq; using System.Threading.Tasks; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Game.Beatmaps; using osu.Game.Graphics.UserInterface; +using osu.Game.IO.Serialization; namespace osu.Game.Overlays.Settings.Sections.Maintenance { @@ -15,6 +18,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance private TriangleButton importButton; private TriangleButton deleteButton; private TriangleButton restoreButton; + private TriangleButton migrateButton; protected override string Header => "General"; @@ -55,6 +59,42 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance }).ContinueWith(t => Schedule(() => restoreButton.Enabled.Value = true)); } }, + migrateButton = new SettingsButton + { + Text = "Migrate all beatmaps to the new format", + Action = () => + { + migrateButton.Enabled.Value = false; + Task.Run(() => + { + var usableSets = beatmaps.GetAllUsableBeatmapSets(); + foreach (var set in usableSets) + { + foreach (var beatmap in set.Beatmaps) + { + var working = beatmaps.GetWorkingBeatmap(beatmap); + using (var ms = new MemoryStream()) + using (var sw = new StreamWriter(ms)) + { + try + { + sw.Write(working.Beatmap.Serialize()); + } + catch (Exception e) + { + Console.WriteLine(e); + throw; + } + sw.Flush(); + + ms.Position = 0; + beatmaps.UpdateContent(beatmap, ms); + } + } + } + }).ContinueWith(t => Schedule(() => migrateButton.Enabled.Value = true)); + } + } }; } } From 4232a54b32507afeaed5ad317b70ebf9f644160d Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 7 Dec 2017 03:04:56 +0900 Subject: [PATCH 1003/1263] Make TypedListConverter not reconstruct serializers --- .../Converters/TypedListConverter.cs | 20 ++++--------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/osu.Game/IO/Serialization/Converters/TypedListConverter.cs b/osu.Game/IO/Serialization/Converters/TypedListConverter.cs index 9c35fae7d4..f8897a4e9d 100644 --- a/osu.Game/IO/Serialization/Converters/TypedListConverter.cs +++ b/osu.Game/IO/Serialization/Converters/TypedListConverter.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; using Newtonsoft.Json; using Newtonsoft.Json.Linq; @@ -20,12 +19,10 @@ namespace osu.Game.IO.Serialization.Converters { var list = new List(); - var localSerializer = createLocalSerializer(); - var obj = JObject.Load(reader); var lookupTable = new List(); - localSerializer.Populate(obj["LookupTable"].CreateReader(), lookupTable); + serializer.Populate(obj["LookupTable"].CreateReader(), lookupTable); foreach (var tok in obj["Items"]) { @@ -33,7 +30,7 @@ namespace osu.Game.IO.Serialization.Converters var typeName = lookupTable[(int)tok["Type"]]; var instance = (T)Activator.CreateInstance(Type.GetType(typeName)); - localSerializer.Populate(itemReader, instance); + serializer.Populate(itemReader, instance); list.Add(instance); } @@ -45,8 +42,6 @@ namespace osu.Game.IO.Serialization.Converters { var list = (List)value; - var localSerializer = createLocalSerializer(); - var lookupTable = new List(); var objects = new List(); foreach (var item in list) @@ -60,7 +55,7 @@ namespace osu.Game.IO.Serialization.Converters typeId = lookupTable.Count - 1; } - var itemObject = JObject.FromObject(item, localSerializer); + var itemObject = JObject.FromObject(item, serializer); itemObject.AddFirst(new JProperty("Type", typeId)); objects.Add(itemObject); } @@ -68,7 +63,7 @@ namespace osu.Game.IO.Serialization.Converters writer.WriteStartObject(); writer.WritePropertyName("LookupTable"); - localSerializer.Serialize(writer, lookupTable); + serializer.Serialize(writer, lookupTable); writer.WritePropertyName("Items"); writer.WriteStartArray(); @@ -78,12 +73,5 @@ namespace osu.Game.IO.Serialization.Converters writer.WriteEndObject(); } - - private JsonSerializer createLocalSerializer() - { - var localSettings = JsonSerializableExtensions.CreateGlobalSettings(); - localSettings.Converters = localSettings.Converters.Where(c => !(c is TypedListConverter)).ToArray(); - return JsonSerializer.Create(localSettings); - } } } From 9787788081d15fa49071f474db45fca99e01f045 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 7 Dec 2017 03:39:43 +0900 Subject: [PATCH 1004/1263] Revert unintended change --- osu.Game/IO/Serialization/IJsonSerializable.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/IO/Serialization/IJsonSerializable.cs b/osu.Game/IO/Serialization/IJsonSerializable.cs index e192d702ce..8d10f0b291 100644 --- a/osu.Game/IO/Serialization/IJsonSerializable.cs +++ b/osu.Game/IO/Serialization/IJsonSerializable.cs @@ -16,7 +16,7 @@ namespace osu.Game.IO.Serialization public static T Deserialize(this string objString) => JsonConvert.DeserializeObject(objString, CreateGlobalSettings()); - public static void DeserializeInto(this string objString, T target) => JsonConvert.DeserializeAnonymousType(objString, target, CreateGlobalSettings()); + public static void DeserializeInto(this string objString, T target) => JsonConvert.PopulateObject(objString, target, CreateGlobalSettings()); public static T DeepClone(this T obj) where T : IJsonSerializable => Deserialize(Serialize(obj)); From 41b607c1657cfaac915e66dbe0e0a10b7dbdafaa Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 7 Dec 2017 03:40:43 +0900 Subject: [PATCH 1005/1263] Dont serialize hitobject sample properties copied from the control point --- osu.Game/Audio/SampleInfo.cs | 28 +++++++++++++++++++++++--- osu.Game/Rulesets/Objects/HitObject.cs | 14 ++----------- 2 files changed, 27 insertions(+), 15 deletions(-) diff --git a/osu.Game/Audio/SampleInfo.cs b/osu.Game/Audio/SampleInfo.cs index 171a1bdf75..edfda3bdc9 100644 --- a/osu.Game/Audio/SampleInfo.cs +++ b/osu.Game/Audio/SampleInfo.cs @@ -1,8 +1,13 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System; +using Newtonsoft.Json; +using osu.Game.Beatmaps.ControlPoints; + namespace osu.Game.Audio { + [Serializable] public class SampleInfo { public const string HIT_WHISTLE = @"hitwhistle"; @@ -10,19 +15,36 @@ namespace osu.Game.Audio public const string HIT_NORMAL = @"hitnormal"; public const string HIT_CLAP = @"hitclap"; + [JsonIgnore] + public SoundControlPoint ControlPoint; + + private string bank; /// /// The bank to load the sample from. /// - public string Bank; + public string Bank + { + get { return string.IsNullOrEmpty(bank) ? (ControlPoint?.SampleBank ?? "normal") : bank; } + set { bank = value; } + } + + public bool ShouldSerializeBank() => Bank == ControlPoint.SampleBank; /// /// The name of the sample to load. /// - public string Name; + public string Name { get; set; } + private int volume; /// /// The sample volume. /// - public int Volume; + public int Volume + { + get { return volume == 0 ? (ControlPoint?.SampleVolume ?? 0) : volume; } + set { volume = value; } + } + + public bool ShouldSerializeVolume() => Volume == ControlPoint.SampleVolume; } } diff --git a/osu.Game/Rulesets/Objects/HitObject.cs b/osu.Game/Rulesets/Objects/HitObject.cs index c69979d4cf..92220ff8bd 100644 --- a/osu.Game/Rulesets/Objects/HitObject.cs +++ b/osu.Game/Rulesets/Objects/HitObject.cs @@ -48,21 +48,11 @@ namespace osu.Game.Rulesets.Objects Kiai |= effectPoint.KiaiMode; // Initialize first sample - Samples.ForEach(s => initializeSampleInfo(s, soundPoint)); + Samples.ForEach(s => s.ControlPoint = soundPoint); // Initialize any repeat samples var repeatData = this as IHasRepeats; - repeatData?.RepeatSamples?.ForEach(r => r.ForEach(s => initializeSampleInfo(s, soundPoint))); - } - - private void initializeSampleInfo(SampleInfo sample, SoundControlPoint soundPoint) - { - if (sample.Volume == 0) - sample.Volume = soundPoint?.SampleVolume ?? 0; - - // If the bank is not assigned a name, assign it from the control point - if (string.IsNullOrEmpty(sample.Bank)) - sample.Bank = soundPoint?.SampleBank ?? @"normal"; + repeatData?.RepeatSamples?.ForEach(r => r.ForEach(s => s.ControlPoint = soundPoint)); } } } From a8db3a9484cebcadde7ac61445a39c5ba1ef709f Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 7 Dec 2017 04:09:03 +0900 Subject: [PATCH 1006/1263] Add progress notification to migration --- osu.Game/Beatmaps/BeatmapManager.cs | 48 +++++++++++++++++++ .../Sections/Maintenance/GeneralSettings.cs | 29 +---------- 2 files changed, 49 insertions(+), 28 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index c96b889213..6b547afe5d 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -20,6 +20,7 @@ using osu.Game.Beatmaps.IO; using osu.Game.Database; using osu.Game.Graphics; using osu.Game.IO; +using osu.Game.IO.Serialization; using osu.Game.IPC; using osu.Game.Online.API; using osu.Game.Online.API.Requests; @@ -570,6 +571,53 @@ namespace osu.Game.Beatmaps } } + public void MigrateAllToNewFormat() + { + var usableSets = GetAllUsableBeatmapSets(); + + if (usableSets.Count == 0) + return; + + var notification = new ProgressNotification + { + Progress = 0, + State = ProgressNotificationState.Active, + }; + + PostNotification?.Invoke(notification); + + int i = 1; + foreach (var set in usableSets) + { + if (notification.State == ProgressNotificationState.Cancelled) + // user requested abort + return; + + notification.Text = $"Migrating ({i} of {usableSets.Count})"; + notification.Progress = (float)i++ / usableSets.Count; + + foreach (var beatmap in set.Beatmaps) + { + if (notification.State == ProgressNotificationState.Cancelled) + // user requested abort + return; + + var working = GetWorkingBeatmap(beatmap); + using (var ms = new MemoryStream()) + using (var sw = new StreamWriter(ms)) + { + sw.Write(working.Beatmap.Serialize()); + sw.Flush(); + + ms.Position = 0; + UpdateContent(beatmap, ms); + } + } + } + + notification.State = ProgressNotificationState.Completed; + } + /// /// Returns a list of all usable s. /// diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs index a41da6109c..9ae331daf0 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs @@ -65,34 +65,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance Action = () => { migrateButton.Enabled.Value = false; - Task.Run(() => - { - var usableSets = beatmaps.GetAllUsableBeatmapSets(); - foreach (var set in usableSets) - { - foreach (var beatmap in set.Beatmaps) - { - var working = beatmaps.GetWorkingBeatmap(beatmap); - using (var ms = new MemoryStream()) - using (var sw = new StreamWriter(ms)) - { - try - { - sw.Write(working.Beatmap.Serialize()); - } - catch (Exception e) - { - Console.WriteLine(e); - throw; - } - sw.Flush(); - - ms.Position = 0; - beatmaps.UpdateContent(beatmap, ms); - } - } - } - }).ContinueWith(t => Schedule(() => migrateButton.Enabled.Value = true)); + Task.Factory.StartNew(beatmaps.MigrateAllToNewFormat).ContinueWith(t => Schedule(() => migrateButton.Enabled.Value = true), TaskContinuationOptions.LongRunning); } } }; From 0e3b001b133e310064065be3c98f3f13f320321d Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 7 Dec 2017 10:37:51 +0900 Subject: [PATCH 1007/1263] Make maps with storyboards decode correctly with OsuJsonDecoder --- osu.Game/Beatmaps/Formats/OsuJsonDecoder.cs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/osu.Game/Beatmaps/Formats/OsuJsonDecoder.cs b/osu.Game/Beatmaps/Formats/OsuJsonDecoder.cs index ed4b8f3857..d00cbbb8fb 100644 --- a/osu.Game/Beatmaps/Formats/OsuJsonDecoder.cs +++ b/osu.Game/Beatmaps/Formats/OsuJsonDecoder.cs @@ -18,8 +18,16 @@ namespace osu.Game.Beatmaps.Formats stream.BaseStream.Position = 0; stream.DiscardBufferedData(); - string fullText = stream.ReadToEnd(); - fullText.DeserializeInto(beatmap); + try + { + string fullText = stream.ReadToEnd(); + fullText.DeserializeInto(beatmap); + } + catch + { + // Temporary because storyboards are deserialized into beatmaps at the moment + // This try-catch shouldn't exist in the future + } foreach (var hitObject in beatmap.HitObjects) hitObject.ApplyDefaults(beatmap.ControlPointInfo, beatmap.BeatmapInfo.BaseDifficulty); From 9597f9d46ba306fa2be72c46f7fccec7428797a2 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 7 Dec 2017 11:10:20 +0900 Subject: [PATCH 1008/1263] Resharper cleanup --- .../Overlays/Settings/Sections/Maintenance/GeneralSettings.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs index 9ae331daf0..f0f5b434cd 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs @@ -1,15 +1,12 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using System; -using System.IO; using System.Linq; using System.Threading.Tasks; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Game.Beatmaps; using osu.Game.Graphics.UserInterface; -using osu.Game.IO.Serialization; namespace osu.Game.Overlays.Settings.Sections.Maintenance { From ea2c67ca5fe03415fe7a79831738131f8ebb1585 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 7 Dec 2017 11:10:34 +0900 Subject: [PATCH 1009/1263] Fix incorrect serialization condition --- osu.Game/Audio/SampleInfo.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Audio/SampleInfo.cs b/osu.Game/Audio/SampleInfo.cs index edfda3bdc9..f8b5bf33d9 100644 --- a/osu.Game/Audio/SampleInfo.cs +++ b/osu.Game/Audio/SampleInfo.cs @@ -28,7 +28,7 @@ namespace osu.Game.Audio set { bank = value; } } - public bool ShouldSerializeBank() => Bank == ControlPoint.SampleBank; + public bool ShouldSerializeBank() => Bank != ControlPoint.SampleBank; /// /// The name of the sample to load. @@ -45,6 +45,6 @@ namespace osu.Game.Audio set { volume = value; } } - public bool ShouldSerializeVolume() => Volume == ControlPoint.SampleVolume; + public bool ShouldSerializeVolume() => Volume != ControlPoint.SampleVolume; } } From 499ecb4eddebc72913a4747715fb111bff7be6bb Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 7 Dec 2017 11:11:38 +0900 Subject: [PATCH 1010/1263] Add parity checking OsuJsonDecoder test cases --- .../Beatmaps/Formats/OsuJsonDecoderTest.cs | 36 +- ...n - The Unforgiving (Armin) [Marathon].osu | 7102 +++++++++++++++++ osu.Game.Tests/osu.Game.Tests.csproj | 4 + osu.Game.Tests/packages.config | 1 + 4 files changed, 7135 insertions(+), 8 deletions(-) create mode 100644 osu.Game.Tests/Resources/Within Temptation - The Unforgiving (Armin) [Marathon].osu diff --git a/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs index 1531deb265..c3ebcb9e7c 100644 --- a/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs @@ -3,6 +3,7 @@ using System.IO; using System.Linq; +using DeepEqual.Syntax; using NUnit.Framework; using osu.Game.Audio; using osu.Game.Beatmaps; @@ -18,10 +19,13 @@ namespace osu.Game.Tests.Beatmaps.Formats [TestFixture] public class OsuJsonDecoderTest { + private const string beatmap_1 = "Soleily - Renatus (Gamu) [Insane].osu"; + private const string beatmap_2 = "Within Temptation - The Unforgiving (Armin) [Marathon].osu"; + [Test] public void TestDecodeMetadata() { - var beatmap = decodeAsJson("Soleily - Renatus (Gamu) [Insane].osu"); + var beatmap = decodeAsJson(beatmap_1); var meta = beatmap.BeatmapInfo.Metadata; Assert.AreEqual(241526, meta.OnlineBeatmapSetID); Assert.AreEqual("Soleily", meta.Artist); @@ -39,7 +43,7 @@ namespace osu.Game.Tests.Beatmaps.Formats [Test] public void TestDecodeGeneral() { - var beatmap = decodeAsJson("Soleily - Renatus (Gamu) [Insane].osu"); + var beatmap = decodeAsJson(beatmap_1); var beatmapInfo = beatmap.BeatmapInfo; Assert.AreEqual(0, beatmapInfo.AudioLeadIn); Assert.AreEqual(false, beatmapInfo.Countdown); @@ -53,7 +57,7 @@ namespace osu.Game.Tests.Beatmaps.Formats [Test] public void TestDecodeEditor() { - var beatmap = decodeAsJson("Soleily - Renatus (Gamu) [Insane].osu"); + var beatmap = decodeAsJson(beatmap_1); var beatmapInfo = beatmap.BeatmapInfo; int[] expectedBookmarks = @@ -74,7 +78,7 @@ namespace osu.Game.Tests.Beatmaps.Formats [Test] public void TestDecodeDifficulty() { - var beatmap = decodeAsJson("Soleily - Renatus (Gamu) [Insane].osu"); + var beatmap = decodeAsJson(beatmap_1); var difficulty = beatmap.BeatmapInfo.BaseDifficulty; Assert.AreEqual(6.5f, difficulty.DrainRate); Assert.AreEqual(4, difficulty.CircleSize); @@ -87,7 +91,7 @@ namespace osu.Game.Tests.Beatmaps.Formats [Test] public void TestDecodeColors() { - var beatmap = decodeAsJson("Soleily - Renatus (Gamu) [Insane].osu"); + var beatmap = decodeAsJson(beatmap_1); Color4[] expected = { new Color4(142, 199, 255, 255), @@ -105,7 +109,7 @@ namespace osu.Game.Tests.Beatmaps.Formats [Test] public void TestDecodeHitObjects() { - var beatmap = decodeAsJson("Soleily - Renatus (Gamu) [Insane].osu"); + var beatmap = decodeAsJson(beatmap_1); var curveData = beatmap.HitObjects[0] as IHasCurve; var positionData = beatmap.HitObjects[0] as IHasPosition; @@ -124,13 +128,29 @@ namespace osu.Game.Tests.Beatmaps.Formats Assert.IsTrue(beatmap.HitObjects[1].Samples.Any(s => s.Name == SampleInfo.HIT_CLAP)); } + [TestCase(beatmap_1)] + [TestCase(beatmap_2)] + public void TestParity(string beatmap) + { + var beatmaps = decode(beatmap); + beatmaps.jsonDecoded.ShouldDeepEqual(beatmaps.legacyDecoded); + } + /// /// Reads a .osu file first with a , serializes the resulting to JSON /// and then deserializes the result back into a through an . /// /// The .osu file to decode. /// The after being decoded by an . - private Beatmap decodeAsJson(string filename) + private Beatmap decodeAsJson(string filename) => decode(filename).jsonDecoded; + + /// + /// Reads a .osu file first with a , serializes the resulting to JSON + /// and then deserializes the result back into a through an . + /// + /// The .osu file to decode. + /// The after being decoded by an . + private (Beatmap legacyDecoded, Beatmap jsonDecoded) decode(string filename) { using (var stream = Resource.OpenResource(filename)) using (var sr = new StreamReader(stream)) @@ -145,7 +165,7 @@ namespace osu.Game.Tests.Beatmaps.Formats sw.Flush(); ms.Position = 0; - return new OsuJsonDecoder().Decode(sr2); + return (legacyDecoded, new OsuJsonDecoder().Decode(sr2)); } } } diff --git a/osu.Game.Tests/Resources/Within Temptation - The Unforgiving (Armin) [Marathon].osu b/osu.Game.Tests/Resources/Within Temptation - The Unforgiving (Armin) [Marathon].osu new file mode 100644 index 0000000000..4f8e8f820f --- /dev/null +++ b/osu.Game.Tests/Resources/Within Temptation - The Unforgiving (Armin) [Marathon].osu @@ -0,0 +1,7102 @@ +osu file format v9 + +[General] +AudioFilename: Within Temptation - The Unforgiving.mp3 +AudioLeadIn: 2000 +PreviewTime: 2513029 +Countdown: 0 +SampleSet: Soft +StackLeniency: 0.7 +Mode: 0 +LetterboxInBreaks: 1 + +[Editor] +Bookmarks: 3177331 +DistanceSpacing: 0.9 +BeatDivisor: 4 +GridSize: 4 + +[Metadata] +Title:The Unforgiving +Artist:Within Temptation +Creator:Armin +Version:Marathon +Source: +Tags:Gonzvlo narakucrimson Roddie Vass_Bass ErufenRito Glass Card N'FoRcE force HakunoKaemi metal Why not me Shot in the Dark In the Middle of the Night Faster Fire and Ice Iron Where is the edge Sinead Lost Murder A Demon's Fate Stairway to the skies TU Marathon symphonic metal rock Sharon den Adel collab + +[Difficulty] +HPDrainRate:3 +CircleSize:4 +OverallDifficulty:7 +ApproachRate:8 +SliderMultiplier:2 +SliderTickRate:1 + +[Events] +//Background and Video events +0,0,"Within-Temptation.png" +Video,-300,"Mother Maiden_xvid_003.avi" +Video,910191,"Fire And Ice_x264.avi" +Video,648748,"17 Faster_x264_001.avi" +Video,1730578,"19 Sinead_xvid_001.avi" +Video,34667,"Within Temptation-Shot In The _x264_001.avi" +//Break Periods +2,31107,46554 +2,116273,123530 +2,193254,209002 +2,325697,336343 +2,442893,451543 +2,533893,549943 +2,644043,670986 +2,744936,750986 +2,886436,932774 +2,1017706,1021899 +2,1141547,1152290 +2,1285058,1290472 +2,1372331,1382290 +2,1476876,1505227 +2,1575917,1584318 +2,1666307,1676266 +2,1714619,1747493 +2,1825109,1829544 +2,1903058,1916980 +2,1935879,1949288 +2,1981007,1993647 +2,2205454,2225075 +2,2290311,2308242 +2,2394266,2400928 +2,2473072,2486674 +2,2513371,2525630 +2,2555908,2578758 +2,2686971,2696967 +2,2787469,2800847 +2,2889559,2901019 +2,2925673,2939538 +2,3002710,3007686 +2,3086784,3102501 +//Storyboard Layer 0 (Background) +//Storyboard Layer 1 (Fail) +//Storyboard Layer 2 (Pass) +//Storyboard Layer 3 (Foreground) +//Storyboard Sound Samples +//Background Colour Transformations +3,100,163,162,255 + +[TimingPoints] +2406,418.848167539267,4,2,0,100,1,0 +15829,418.848167539267,4,2,0,100,1,0 +34572,565.904267861353,4,1,0,100,1,0 +47011,-100,4,2,1,100,0,0 +95696,566.037735849057,4,2,1,100,1,0 +97111,-100,4,1,0,80,0,1 +97247,-100,4,1,0,82,0,1 +97388,-100,4,1,0,84,0,1 +97530,-100,4,1,0,86,0,1 +97671,-100,4,1,0,90,0,1 +97818,-100,4,1,0,93,0,0 +97960,-100,4,1,0,96,0,1 +98096,-100,4,2,1,100,0,1 +106020,-100,4,1,1,80,0,1 +106233,-100,4,1,1,83,0,1 +106374,-100,4,1,1,86,0,1 +106516,-100,4,1,1,89,0,1 +106657,-100,4,1,1,92,0,1 +106799,-100,4,1,1,95,0,1 +106940,-100,4,2,1,98,0,1 +116073,-100,4,2,1,98,0,0 +124134,-100,4,1,0,100,0,0 +124983,-100,4,2,1,100,0,0 +160926,-100,4,1,0,100,0,0 +161209,-100,4,2,1,100,0,0 +165454,-100,4,1,0,100,0,0 +165737,-100,4,2,1,100,0,0 +169983,-100,4,1,0,100,0,0 +170266,-100,4,2,0,87,0,0 +172671,-100,4,1,0,100,0,0 +173101,-100,4,1,0,81,0,1 +173237,-100,4,1,0,84,0,1 +173379,-100,4,1,0,87,0,1 +173520,-100,4,1,0,90,0,1 +174658,-100,4,2,0,100,0,0 +174941,-100,4,2,1,100,0,1 +182436,-100,4,2,0,100,0,1 +183002,-100,4,1,0,100,0,1 +183714,-100,4,2,0,100,0,0 +183997,-100,4,2,1,100,0,1 +191563,-100,4,1,0,80,0,1 +191775,-100,4,1,0,83,0,1 +191917,-100,4,1,0,86,0,1 +192058,-100,4,1,0,89,0,1 +192200,-100,4,1,0,91,0,1 +192341,-100,4,1,0,93,0,1 +192483,-100,4,1,0,95,0,1 +192624,-100,4,1,0,97,0,1 +192766,-100,4,1,0,98,0,1 +192907,-100,4,1,0,99,0,1 +193054,-100,4,2,0,100,0,0 +209888,-100,4,1,0,63,0,0 +211311,-100,4,2,0,5,0,0 +214708,-100,4,2,0,30,0,0 +215549,-100,4,1,0,15,0,0 +215686,566.037735849057,4,1,0,15,1,0 +215761,-100,4,2,0,5,0,0 +217105,-100,4,2,0,31,0,0 +217884,-100,4,1,0,15,0,0 +218450,-100,4,2,0,30,0,0 +218662,-100,4,1,0,15,0,0 +219299,-100,4,2,0,29,0,0 +219511,-100,4,2,0,36,0,0 +220148,-100,4,1,0,16,0,0 +220289,-100,4,2,0,16,0,0 +220997,-100,4,1,0,16,0,0 +221138,-100,4,2,0,16,0,0 +222341,-100,4,1,0,16,0,0 +222907,-100,4,2,0,16,0,0 +223190,-100,4,1,0,16,0,0 +223473,-100,4,2,0,16,0,0 +224605,-100,4,1,0,16,0,0 +225171,-100,4,2,0,16,0,0 +225454,-100,4,1,0,16,0,0 +226091,-100,4,2,0,16,0,0 +226870,-100,4,1,0,16,0,0 +227436,-100,4,2,0,16,0,0 +227719,-100,4,1,0,16,0,0 +228072,-100,4,2,0,16,0,0 +229134,-100,4,1,0,16,0,0 +229770,-100,4,2,0,16,0,0 +229983,-100,4,1,0,16,0,0 +230195,-100,4,2,0,16,0,0 +231469,-100,4,1,0,16,0,0 +231610,-100,4,2,0,16,0,0 +232318,-100,4,1,0,16,0,0 +232601,-100,4,2,0,33,0,0 +233167,-100,4,2,0,21,0,0 +233733,-100,4,1,0,21,0,0 +243355,-100,4,1,0,41,0,0 +246256,-100,4,1,0,26,0,0 +247954,-100,4,1,0,39,0,0 +250510,-100,4,2,0,40,0,0 +250651,-100,4,2,0,50,0,0 +250793,-100,4,2,0,60,0,0 +251912,-100,4,2,1,100,0,1 +267761,-100,4,2,1,100,0,0 +270025,-100,4,2,1,100,0,1 +270171,-76.9230769230769,4,2,1,83,0,1 +285737,-76.9230769230769,4,1,0,36,0,1 +286162,-76.9230769230769,4,1,0,45,0,1 +286445,-76.9230769230769,4,1,0,52,0,1 +286728,-76.9230769230769,4,1,0,60,0,1 +287011,-76.9230769230769,4,1,0,68,0,1 +287294,-76.9230769230769,4,1,0,76,0,1 +287577,-76.9230769230769,4,1,1,83,0,1 +287855,-76.9230769230769,4,2,1,100,0,0 +288138,-76.9230769230769,4,2,1,100,0,1 +296068,-76.9230769230769,4,1,1,54,0,1 +296351,-76.9230769230769,4,1,1,60,0,1 +296634,-76.9230769230769,4,1,1,71,0,1 +296923,-76.9230769230769,4,2,1,93,0,0 +297195,-76.9230769230769,4,2,1,100,0,1 +306252,-76.9230769230769,4,2,1,100,0,0 +324082,-76.9230769230769,4,2,1,100,0,0 +324152,-76.9230769230769,4,2,1,65,0,0 +337093,300,4,2,1,40,1,0 +346663,-100,4,1,0,70,0,0 +346851,-100,4,2,1,70,0,0 +366193,-100,4,2,1,70,0,0 +384870,-100,4,2,0,70,0,0 +384943,-100,4,1,0,70,0,0 +385138,-100,4,2,1,70,0,0 +388663,-100,4,1,0,70,0,0 +389001,-100,4,2,1,70,0,0 +399493,-100,4,1,0,70,0,0 +399651,-100,4,2,1,70,0,0 +408343,-100,4,1,0,70,0,0 +408943,-100,4,1,0,70,0,0 +409093,-100,4,1,0,70,0,0 +409168,-100,4,2,1,70,0,0 +416593,-100,4,1,0,70,0,0 +416670,-100,4,2,0,70,0,0 +416743,-100,4,1,0,50,0,0 +416893,-100,4,1,0,80,0,0 +416968,-100,4,2,0,70,0,0 +417043,-100,4,1,0,50,0,0 +417193,-100,4,1,0,90,0,0 +417270,-100,4,2,0,70,0,0 +417493,-100,4,1,0,100,0,0 +417568,-100,4,2,0,70,0,0 +418693,-100,4,2,1,70,0,1 +428226,-100,4,1,0,70,0,1 +428451,-100,4,2,1,70,0,1 +436634,-100,4,2,0,70,0,1 +436784,-100,4,1,0,70,0,1 +437830,-100,4,1,0,70,0,0 +437893,-100,4,1,0,70,0,1 +442693,-100,4,1,0,70,0,0 +452001,-100,4,2,1,70,0,0 +461293,-100,4,1,0,70,0,0 +461976,-100,4,2,1,70,0,0 +470293,-100,4,1,0,70,0,0 +471576,-100,4,2,0,70,0,0 +471726,-100,4,1,0,70,0,0 +471876,-100,4,2,1,70,0,0 +475693,-100,4,1,0,70,0,0 +475926,-100,4,1,0,70,0,0 +476526,-100,4,1,0,70,0,0 +476676,-100,4,2,1,70,0,0 +479893,-100,4,1,0,70,0,0 +481176,-100,4,2,0,70,0,0 +481326,-100,4,1,0,70,0,0 +481476,-100,4,2,1,70,0,0 +490693,-100,4,1,0,70,0,1 +490851,-100,4,2,1,70,0,1 +499693,-100,4,1,0,60,0,1 +499993,-100,4,1,0,65,0,1 +500143,-100,4,1,0,70,0,0 +500293,-100,4,1,0,70,0,1 +501276,-100,4,2,0,70,0,1 +501426,-100,4,1,0,70,0,1 +501876,-100,4,2,0,70,0,1 +502326,-100,4,1,0,70,0,1 +502776,-100,4,2,0,70,0,1 +502926,-100,4,1,0,70,0,1 +509293,-100,4,1,0,60,0,1 +509593,-100,4,1,0,65,0,1 +514693,-100,4,1,0,70,0,0 +514709,-100,4,1,0,70,0,0 +563151,-83.3333333333333,4,1,0,70,0,0 +574251,-76.9230769230769,4,1,0,70,0,0 +581893,-76.9230769230769,4,1,0,70,0,1 +591193,-76.9230769230769,4,1,0,70,0,0 +591493,-76.9230769230769,4,1,0,70,0,1 +601093,-76.9230769230769,4,1,0,70,0,1 +603726,-83.3333333333333,4,1,0,70,0,1 +605893,-83.3333333333333,4,1,0,70,0,0 +634993,-83.3333333333333,4,1,0,20,0,0 +648736,500,4,2,1,100,1,0 +710611,-100,4,1,0,63,0,0 +710781,-100,4,1,0,65,0,0 +710857,-100,4,1,0,70,0,0 +710982,-100,4,1,0,76,0,0 +711107,-100,4,1,0,79,0,0 +711232,-100,4,1,0,85,0,0 +711357,-100,4,1,0,91,0,0 +711482,-100,4,1,0,94,0,0 +711781,-100,4,1,0,100,0,0 +712736,-76.9230769230769,4,1,0,100,0,1 +712798,-76.9230769230769,4,2,1,100,0,1 +720498,-76.9230769230769,4,1,0,100,0,0 +720736,-76.9230769230769,4,1,0,100,0,1 +721986,-76.9230769230769,4,2,1,100,0,1 +727986,-76.9230769230769,4,1,0,80,0,1 +728111,-76.9230769230769,4,1,0,83,0,1 +728236,-76.9230769230769,4,1,0,86,0,1 +728361,-76.9230769230769,4,1,0,89,0,1 +728486,-76.9230769230769,4,1,0,92,0,1 +728623,-76.9230769230769,4,1,0,95,0,0 +728736,-76.9230769230769,4,1,0,98,0,1 +744736,-100,4,1,0,100,0,0 +751234,-100,4,2,1,100,0,0 +752611,-100,4,1,0,100,0,0 +752861,-100,4,2,1,100,0,0 +759611,-100,4,1,0,100,0,0 +759861,-100,4,2,0,100,0,0 +760173,-100,4,1,0,100,0,0 +760361,-100,4,2,0,100,0,0 +760673,-100,4,1,0,100,0,0 +760861,-100,4,2,1,100,0,0 +784548,-100,4,2,0,100,0,0 +785111,-100,4,1,0,100,0,0 +785361,-83.3333333333333,4,1,0,100,0,0 +785548,-83.3333333333333,4,2,0,100,0,0 +786111,-83.3333333333333,4,1,0,100,0,0 +786361,-71.4285714285714,4,1,0,100,0,0 +786548,-71.4285714285714,4,2,0,100,0,0 +787111,-62.5,4,1,0,100,0,0 +787548,-62.5,4,2,0,100,0,0 +788111,-55.5555555555556,4,1,0,100,0,0 +788548,-55.5555555555556,4,2,0,100,0,0 +789111,-55.5555555555556,4,1,0,100,0,0 +789361,-50,4,1,0,100,0,0 +789548,-50,4,2,0,100,0,0 +790111,-76.9230769230769,4,1,0,100,0,0 +790736,-76.9230769230769,4,1,0,80,0,0 +790986,-76.9230769230769,4,1,0,85,0,0 +791236,-76.9230769230769,4,1,0,90,0,0 +791486,-76.9230769230769,4,1,0,95,0,0 +791736,-76.9230769230769,4,1,0,100,0,0 +792736,-76.9230769230769,4,1,0,100,0,1 +800486,-76.9230769230769,4,1,0,100,0,0 +800736,-76.9230769230769,4,1,0,100,0,1 +808611,-76.9230769230769,4,1,0,100,0,0 +808736,-76.9230769230769,4,1,0,100,0,1 +824611,-76.9230769230769,4,1,0,100,0,0 +824736,-76.9230769230769,4,1,0,100,0,1 +824861,-76.9230769230769,4,1,0,100,0,0 +852361,-76.9230769230769,4,2,0,100,0,0 +858736,-76.9230769230769,4,1,0,100,0,0 +860736,-66.6666666666667,4,1,0,100,0,1 +868486,-66.6666666666667,4,1,0,100,0,0 +868736,-66.6666666666667,4,1,0,100,0,1 +872361,-66.6666666666667,4,1,0,100,0,1 +873861,-66.6666666666667,4,1,0,100,0,1 +884486,-66.6666666666667,4,1,0,100,0,0 +884736,-66.6666666666667,4,1,0,100,0,1 +886236,-66.6666666666667,4,1,0,100,0,0 +912957,856.959223023638,4,2,0,21,1,0 +941887,-117.647058823529,4,2,0,21,0,0 +972298,-100,4,2,0,21,0,0 +974654,-100,4,2,0,21,0,0 +991894,-117.647058823529,4,2,0,21,0,0 +992858,-100,4,2,0,21,0,0 +1015131,-90.9090909090909,4,2,0,21,0,0 +1015452,-90.9090909090909,4,2,0,5,0,0 +1017701,-100,4,2,0,15,0,0 +1022649,428.571428571429,4,2,1,78,1,0 +1030031,-90.9090909090909,4,2,0,79,0,0 +1031103,-100,4,2,1,79,0,0 +1049960,-100,4,1,0,60,0,0 +1050174,-100,4,2,0,100,0,0 +1051674,-100,4,1,0,60,0,0 +1051889,-100,4,2,0,100,0,0 +1052103,-100,4,1,0,60,0,0 +1052317,-100,4,2,0,100,0,0 +1052531,-100,4,1,0,60,0,0 +1052746,-100,4,2,0,100,0,0 +1052960,-100,4,1,0,60,0,0 +1053174,-100,4,2,0,100,0,0 +1053389,-100,4,1,0,80,0,0 +1053603,-100,4,2,0,100,0,0 +1054246,-100,4,1,0,80,0,0 +1054460,-100,4,2,1,81,0,0 +1067103,-100,4,1,0,80,0,0 +1067317,-100,4,2,1,100,0,0 +1069674,-100,4,1,0,85,0,0 +1069996,-100,4,2,1,85,0,0 +1070531,-100,4,1,0,68,0,0 +1070746,-100,4,2,0,100,0,0 +1071389,-100,4,1,0,80,0,0 +1071603,-100,4,2,0,100,0,0 +1072246,-100,4,1,0,60,0,0 +1072460,-100,4,2,0,100,0,0 +1073103,-100,4,1,0,80,0,0 +1073317,-100,4,2,0,100,0,0 +1073960,-100,4,1,0,60,0,0 +1074174,-100,4,2,0,100,0,0 +1074389,-100,4,1,0,60,0,0 +1074603,-100,4,2,0,100,0,0 +1074817,-100,4,1,0,80,0,0 +1075031,-100,4,2,0,100,0,0 +1075674,-100,4,1,0,60,0,0 +1076317,-100,4,2,0,100,0,0 +1076531,-100,4,1,0,80,0,0 +1076746,-100,4,2,0,100,0,0 +1077389,-100,4,2,1,81,0,0 +1081246,-90.9090909090909,4,2,1,82,0,0 +1082317,-100,4,2,1,80,0,0 +1083281,-100,4,2,1,80,0,0 +1093460,-90.9090909090909,4,2,1,80,0,0 +1094317,-100,4,2,1,80,0,0 +1105674,-100,4,2,1,80,0,0 +1118531,-100,4,1,0,80,0,0 +1118746,-100,4,2,1,80,0,0 +1122014,-100,4,1,0,80,0,0 +1122174,-100,4,2,1,80,0,0 +1128817,-133.333333333333,4,2,1,80,0,0 +1135674,-100,4,2,0,22,0,0 +1137505,444.444444444444,4,2,0,22,1,0 +1139282,461.538461538462,4,2,0,16,1,0 +1140205,571.428571428571,4,2,0,19,1,0 +1141347,571.428571428571,4,2,0,19,1,0 +1150313,454.545454545455,4,2,0,100,1,0 +1153040,-100,4,2,1,100,0,0 +1226981,-72.992700729927,4,2,1,100,0,0 +1241222,-68.0272108843537,4,2,1,100,0,1 +1284868,-105.042016806723,4,1,0,100,0,0 +1291224,-80.7754442649435,4,1,0,100,0,0 +1291299,-80.7754442649435,4,2,1,100,0,0 +1291375,-80.7754442649435,4,1,0,100,0,0 +1291451,-80.7754442649435,4,2,1,100,0,0 +1291527,-80.7754442649435,4,1,0,100,0,0 +1291602,-80.7754442649435,4,2,1,100,0,0 +1291678,-74.6268656716418,4,1,0,100,0,0 +1292133,-72.7272727272727,4,2,1,100,0,0 +1328494,-72.992700729927,4,2,1,100,0,1 +1342147,-72.992700729927,4,2,1,100,0,1 +1342737,-72.992700729927,4,2,1,100,0,0 +1343040,-72.992700729927,4,2,1,100,0,1 +1345025,-63.2911392405063,4,2,1,100,0,1 +1345935,-72.992700729927,4,2,1,100,0,1 +1357585,-72.992700729927,4,2,1,100,0,0 +1372139,-72.992700729927,4,2,1,100,0,0 +1408427,-86.2068965517241,4,2,1,100,0,0 +1409571,-87.5656742556918,4,2,1,100,0,0 +1412071,-87.5656742556918,4,1,0,100,0,0 +1412222,-87.5656742556918,4,2,1,100,0,0 +1415767,-72.992700729927,4,2,1,100,0,1 +1430009,-72.992700729927,4,2,1,100,0,0 +1430312,-72.992700729927,4,2,1,100,0,1 +1430632,-63.2911392405063,4,2,1,100,0,1 +1444706,-63.2911392405063,4,2,1,100,0,0 +1444858,-63.2911392405063,4,2,1,100,0,1 +1473949,-63.2911392405063,4,2,1,100,0,0 +1491562,389.61038961039,4,1,0,80,1,0 +1506367,-200,4,1,0,80,0,0 +1507146,-100,4,1,0,80,0,0 +1550782,-100,4,1,0,80,0,1 +1575717,-100,4,1,0,80,0,0 +1584873,-100,4,2,0,70,0,0 +1587511,-100,4,1,0,80,0,0 +1589938,-200,4,1,0,80,0,0 +1590523,-100,4,1,0,80,0,0 +1619354,-100,4,1,0,80,0,1 +1644289,-100,4,1,0,80,0,0 +1662990,-100,4,2,0,40,0,0 +1678575,-100,4,2,0,70,0,0 +1688315,-100,4,1,0,40,0,0 +1688510,-100,4,1,0,50,0,0 +1688704,-100,4,1,0,60,0,0 +1688899,-100,4,1,0,70,0,0 +1689094,-100,4,1,0,80,0,0 +1689289,-100,4,1,0,80,0,0 +1689484,-100,4,1,0,80,0,0 +1691042,-100,4,1,0,80,0,1 +1714419,-100,4,2,0,40,0,0 +1730551,512.820512820513,4,1,0,100,1,0 +1747667,-181.818181818182,4,2,0,35,0,0 +1763137,-120.481927710843,4,2,1,70,0,0 +1795191,-120.481927710843,4,2,1,90,0,0 +1796192,-90.9090909090909,4,2,1,100,0,1 +1824909,-100,4,2,1,100,0,0 +1830166,-119.760479041916,4,2,1,100,0,0 +1874140,-90.9090909090909,4,2,1,100,0,1 +1902858,-100,4,2,1,100,0,0 +1917477,-120.481927710843,4,2,1,100,0,0 +1950551,-120.481927710843,4,2,1,70,0,0 +1951063,-120.481927710843,4,2,1,60,0,0 +1952088,-90.9090909090909,4,2,1,100,0,1 +1967986,-90.9090909090909,4,2,1,100,0,0 +1968499,-90.9090909090909,4,2,1,100,0,1 +1980807,-90.9090909090909,4,2,1,100,0,0 +1994397,428.571428571429,3,2,0,30,1,0 +1995484,-100,3,2,0,48,0,0 +1995913,-100,3,2,0,30,0,0 +2000627,-100,3,2,0,51,0,0 +2001055,-100,3,2,0,30,0,0 +2045825,-100,3,2,0,40,0,0 +2070163,-100,3,1,0,60,0,0 +2070323,-100,3,2,0,60,0,0 +2071539,-100,3,1,0,50,0,0 +2072825,-100,3,1,0,60,0,0 +2073055,-100,3,2,0,60,0,0 +2073913,-100,3,2,1,60,0,0 +2130682,-100,3,2,1,60,0,1 +2141198,-87.719298245614,3,2,1,60,0,1 +2142484,-100,3,2,1,60,0,1 +2153825,-100,3,2,1,60,0,0 +2189734,-87.719298245614,3,2,1,60,0,0 +2197448,-100,3,2,1,60,0,0 +2245012,-100,3,1,0,60,0,0 +2246397,-100,3,1,0,60,0,1 +2246619,-100,3,2,1,60,0,1 +2269111,-100,3,2,1,60,0,0 +2269539,-100,3,2,1,60,0,1 +2290111,-100,3,2,1,60,0,0 +2308992,447.761194029851,4,2,0,29,1,0 +2316044,-100,4,2,1,51,0,0 +2336305,-100,4,1,0,41,0,0 +2337318,-100,4,2,1,51,0,0 +2350969,-100,4,1,0,41,0,0 +2351865,-133.333333333333,4,2,1,60,0,0 +2365521,-133.333333333333,4,1,0,20,0,0 +2365745,-133.333333333333,4,1,0,30,0,0 +2365969,-100,4,1,0,50,0,0 +2366305,-100,4,1,2,60,0,1 +2379408,-100,4,1,2,70,0,1 +2381087,-100,4,1,2,60,0,1 +2394962,-100,4,1,2,60,0,0 +2402350,-100,4,2,1,55,0,0 +2415223,-100,4,1,0,50,0,0 +2416566,-100,4,2,1,50,0,0 +2429775,-100,4,1,0,50,0,0 +2430671,-133.333333333333,4,2,1,50,0,0 +2444327,-133.333333333333,4,2,1,40,0,0 +2444551,-133.333333333333,4,2,1,50,0,0 +2445111,-100,4,1,2,60,0,1 +2470186,-100,4,1,0,65,0,0 +2488096,-100,4,1,0,65,0,1 +2488214,-100,4,1,0,65,0,0 +2502424,-100,4,1,0,65,0,1 +2502542,-100,4,1,0,65,0,0 +2526162,-100,4,1,0,40,0,0 +2526721,-100,4,1,0,50,0,0 +2527169,-100,4,1,0,60,0,0 +2527499,-100,4,1,2,65,0,1 +2541380,-100,4,1,2,65,0,0 +2541827,-100,4,1,2,65,0,1 +2553021,-100,4,1,2,65,0,1 +2555596,-100,4,1,2,5,0,1 +2556156,-100,4,1,2,56,0,0 +2565180,447.761194029851,4,1,0,100,1,0 +2579508,-100,4,2,0,80,0,0 +2586112,-100,4,1,0,69,0,0 +2643985,-100,4,1,0,69,0,1 +2658314,-100,4,1,0,69,0,1 +2671747,-100,4,1,0,69,0,1 +2672642,-100,4,1,0,69,0,0 +2701539,-90.9090909090909,4,1,0,69,0,0 +2715643,-100,4,1,0,69,0,0 +2729956,-100,4,1,0,69,0,1 +2758612,-76.9230769230769,4,1,0,69,0,0 +2761875,-66.6666666666667,4,1,0,69,0,0 +2801605,-133.333333333333,4,1,0,60,0,0 +2815926,-100,4,1,0,60,0,0 +2844582,-100,4,1,0,60,0,1 +2855329,-100,4,1,0,60,0,0 +2858911,-100,4,1,0,60,0,1 +2873239,-100,4,1,0,60,0,0 +2889304,-100,4,2,0,5,0,0 +2895844,370.37037037037,4,2,0,100,1,0 +2901399,-166.666666666667,4,2,0,50,0,0 +2924269,-200,4,2,0,50,0,0 +2940108,-200,4,2,1,50,0,0 +2952145,-100,4,2,1,75,0,0 +2960479,-133.333333333333,4,2,1,75,0,0 +2962331,-100,4,2,1,75,0,0 +2976220,-100,4,2,1,75,0,0 +3016775,-133.333333333333,4,2,1,75,0,0 +3018627,-100,4,2,1,75,0,0 +3057232,-151.515151515152,4,1,0,60,0,0 +3058719,-100,4,2,0,75,0,0 +3059182,-100,4,2,1,75,0,0 +3082562,-100,4,2,0,10,0,0 +3086775,-100,4,2,0,75,0,0 +3103066,-151.515151515152,4,1,0,60,0,0 +3105571,-151.515151515152,4,2,0,75,0,0 +3106126,-151.515151515152,4,1,0,60,0,0 +3108066,-151.515151515152,4,2,0,75,0,0 +3108437,-151.515151515152,4,1,0,60,0,0 +3108626,-151.515151515152,4,2,0,75,0,0 +3109177,-151.515151515152,4,1,0,60,0,0 +3111029,-151.515151515152,4,2,0,75,0,0 +3111400,-151.515151515152,4,1,0,60,0,0 +3111589,-151.515151515152,4,2,0,75,0,0 +3112140,-151.515151515152,4,1,0,60,0,0 +3117978,-100,4,2,1,75,0,0 +3126214,-100,4,2,1,75,0,0 +3165474,-100,4,2,1,75,0,1 +3176960,-100,4,2,1,75,0,0 +3177325,-100,4,2,1,75,0,1 +3177695,-100,4,2,1,75,0,0 + + +[Colours] +Combo1 : 12,50,233 +Combo2 : 253,225,28 +Combo3 : 185,17,17 +Combo4 : 30,136,35 +SliderBorder : 0,0,0 + +[HitObjects] +40,48,2405,1,4 +144,344,2824,1,0 +256,48,3243,1,2 +368,344,3662,1,0 +472,48,4081,1,2 +336,216,4500,2,0,B|308:146|192:136|171:225|171:225,1,200,0|2 +256,256,5128,1,0 +256,336,5337,1,0 +92,88,5756,5,2 +256,144,6175,1,0 +420,88,6594,1,2 +400,252,7013,1,0 +256,336,7432,1,2 +112,252,7851,1,0 +92,88,8269,1,2 +336,172,8688,6,0,B|308:102|192:92|171:181|171:181,1,200,0|2 +348,348,9526,1,0 +164,348,9945,1,2 +80,160,10364,1,0 +256,40,10782,1,2 +432,160,11201,1,0 +256,196,11620,1,2 +256,196,11830,1,0 +256,196,12039,1,0 +176,316,12458,6,0,B|204:386|320:396|341:307|341:307,1,200,2|0 +80,224,13296,1,2 +256,44,13714,1,0 +432,224,14133,1,2 +112,92,14552,1,0 +256,272,14971,1,2 +400,92,15390,1,0 +456,336,15829,5,4 +256,44,16247,1,0 +56,336,16666,1,2 +256,272,17085,1,0 +88,68,17504,1,2 +424,68,17923,1,0 +168,208,18342,1,2 +256,168,18551,1,0 +344,208,18760,1,0 +176,312,19179,6,0,B|204:382|320:392|341:303|341:303,1,200,2|0 +472,192,20017,1,2 +256,40,20436,1,0 +40,192,20855,1,2 +256,348,21274,1,0 +170,80,21692,2,0,B|179:110|211:135|252:141|252:141|280:151|302:184|280:217|256:223|227:217|199:184|225:151|252:141|252:141|296:135|323:114|337:72,1,400,2|2 +432,288,22949,5,0 +256,352,23368,1,2 +80,288,23787,1,0 +164,159,24205,2,0,B|208:128|256:168|256:168|304:128|348:158|348:158,1,200,2|0 +180,36,25043,1,2 +256,60,25253,1,0 +332,36,25462,1,0 +472,120,25881,6,0,B|402:148|392:264|481:285|481:285,1,200,2|0 +336,372,26719,2,0,B|308:302|192:292|171:381|171:381,1,200,2|0 +40,280,27556,2,0,B|110:252|120:136|31:115|31:115,1,200,2|0 +180,68,28394,5,2 +256,20,28603,1,0 +332,68,28813,1,0 +302,153,29022,1,0 +208,152,29232,1,0 +256,192,29336,12,0,30907 +40,116,47304,5,2 +100,44,47587,1,0 +172,104,47870,2,0,B|200:174|316:184|337:95|337:95,1,200,0|2 +412,44,48719,1,0 +472,116,49002,1,0 +428,304,49568,5,2 +354,355,49851,1,0 +342,265,50134,1,0 +168,265,50700,1,2 +156,355,50983,1,0 +82,304,51266,1,0 +212,171,51832,6,0,B|228:191|256:195|256:195|284:191|300:171,1,100,2|0 +333,86,52397,2,0,B|312:44|256:28|256:28|204:40|177:87,1,200,0|0 +256,112,53246,1,2 +255,112,53529,1,0 +340,252,54095,2,0,B|360:348|360:348,1,100,2|0 +340,252,54661,2,0,B|312:322|196:332|175:243|175:243,1,200,0|2 +151,349,55510,2,0,B|152:348|180:252,1,100,0|0 +256,112,56359,5,2 +300,40,56642,1,0 +212,40,56925,1,0 +184,129,57208,2,0,B|190:177|240:200|272:200|324:184|329:130|329:130,1,200,0|2 +348,227,58057,2,0,B|314:260|257:270|201:259|164:228,1,200,0|0 +104,288,58905,5,2 +256,368,59471,1,0 +408,288,60037,1,2 +408,288,60320,1,0 +256,200,60886,5,0 +336,160,61169,2,0,B|308:95|199:74|172:168|172:168,1,200,2|0 +300,28,62301,1,2 +212,32,62584,1,0 +212,32,63150,1,0 +300,32,63433,1,2 +342,197,63999,6,0,B|325:162|279:159|255:183|255:183|230:158|184:162|169:197|169:197,1,200,0|2 +168,280,64847,2,0,B|185:315|232:318|256:294|256:294|280:318|326:315|344:280|344:280,1,200,0|2 +432,272,65696,5,0 +400,356,65979,1,0 +336,188,66545,1,2 +256,144,66828,1,8 +176,188,67111,1,0 +112,28,67677,5,2 +84,112,67960,1,8 +20,44,68243,1,0 +216,88,68809,2,0,B|229:52|285:46|295:91|295:91,1,100,2|8 +256,164,69375,1,0 +432,112,69941,5,2 +492,48,70223,1,8 +400,28,70506,1,0 +332,196,71072,5,2 +256,244,71355,1,8 +180,196,71638,1,0 +336,284,72204,2,0,B|328:340|376:372|376:372,1,100,2|8 +336,284,72770,2,0,B|308:354|192:364|171:275|171:275,1,200,0|2 +137,371,73619,2,0,B|136:372|185:344|175:284,1,100,8|0 +156,108,74468,5,2 +212,36,74751,1,8 +300,36,75034,1,0 +356,108,75317,1,0 +256,124,75883,5,8 +256,124,76165,1,0 +384,332,76731,1,0 +384,332,77014,1,8 +256,220,77580,5,0 +128,332,78146,1,8 +128,332,78429,1,0 +256,308,78995,5,0 +256,308,79278,1,8 +300,232,79561,1,0 +256,220,79702,1,0 +212,232,79844,1,0 +112,92,80410,1,8 +176,32,80693,2,0,B|202:104|314:115|334:26|334:26,1,200,0|0 +400,92,81542,1,8 +332,248,82107,2,0,B|307:287|271:282|271:282|255:302|255:302|239:282|239:282|203:290|178:248,1,200,0|8 +104,300,82956,5,0 +168,364,83239,1,2 +256,380,83522,1,0 +344,364,83805,1,8 +408,300,84088,1,0 +336,240,84371,6,4,B|310:312|198:323|178:234|178:234,1,200,2|8 +156,152,85220,2,0,B|396:152|396:152,1,200,2|0 +336,64,86069,2,0,B|310:-8|198:-19|178:70|178:70,1,200,8|2 +48,184,87201,6,0,B|8:284|8:284,1,100,8|0 +100,264,87767,2,0,B|124:360|124:360,1,100,2|0 +188,300,88332,2,0,B|276:360|276:360,1,100,8|0 +316,280,88898,5,2 +376,344,89464,1,8 +376,344,89747,1,0 +408,260,90313,1,0 +408,260,90596,1,8 +480,316,91162,1,2 +464,200,91728,6,0,B|504:100|504:100,1,100,8|0 +412,120,92294,2,0,B|388:24|388:24,1,100,2|0 +324,84,92860,2,0,B|236:24|236:24,1,100,8|0 +196,104,93426,1,2 +256,192,93567,12,0,95696 +448,352,96262,5,2 +376,296,96545,1,0 +304,352,96828,1,2 +240,288,97111,1,0 +200,272,97252,1,0 +184,232,97394,1,0 +200,192,97535,1,0 +240,176,97677,1,0 +280,192,97818,1,0 +296,232,97960,5,4 +376,200,98243,2,0,B|488:200|488:200,1,100,2|8 +512,120,98809,2,0,B|512:16|512:16,1,100,0|8 +432,64,99375,5,2 +360,8,99658,1,8 +310,88,99941,2,0,B|340:125|338:201|254:252|176:198|152:135|204:82|204:82,1,300,2|8 +152,8,101073,1,2 +80,64,101356,1,8 +16,128,101639,6,0,B|16:240|16:240,1,100,2|8 +96,272,102205,2,0,B|160:220|260:296|192:368|192:368,1,200,2|0 +288,384,103054,2,0,B|320:352|320:352|400:352|400:352,1,100,8|0 +447,299,103620,1,10 +363,264,103903,1,0 +305,199,104186,2,0,B|287:169|287:138|318:107|318:107|349:76|349:30|287:15|271:45|256:61|256:61|241:45|225:15|163:30|163:76|194:107|194:107|225:138|225:169|208:199,1,500,8|2 +112,208,105884,5,0 +40,160,106167,1,0 +24,200,106309,1,0 +32,248,106450,1,0 +56,280,106592,1,0 +96,296,106733,1,0 +144,292,106875,1,0 +184,272,107016,6,0,B|296:272|296:272,1,100,4|0 +328,352,107582,2,0,B|216:352|216:352,1,100,8|0 +376,272,108148,2,0,B|456:352|456:352,1,100,2|0 +488,264,108714,2,0,B|408:184|408:184,1,100,8|0 +328,196,109280,1,2 +256,144,109563,1,0 +184,196,109846,1,8 +160,108,110129,6,0,B|216:12|216:12,1,100,0|2 +301,25,110695,2,0,B|296:16|352:112,1,100,0|8 +256,144,111262,2,0,B|256:352|256:352,1,200,2|0 +344,368,112111,2,0,B|440:296|440:296,1,100,8|0 +168,368,112677,2,0,B|72:296|72:296,1,100,2|0 +177,242,113243,6,0,B|202:312|316:323|340:236|340:236,1,200,8|2 +256,200,114092,1,0 +320,136,114375,6,0,B|336:96|376:72|424:96|424:96,2,100,8|0|2 +256,72,115224,1,0 +192,136,115507,2,0,B|176:96|136:70|88:96|88:96,2,100,8|8|4 +172,64,124280,5,0 +256,36,124563,1,0 +340,64,124846,1,0 +256,224,125412,1,2 +256,136,125695,1,8 +332,184,125979,6,0,B|404:210|415:322|326:342|326:342,1,200,0|2 +256,376,126828,1,8 +180,340,127111,2,0,B|108:314|97:202|186:182|186:182,1,200,0|2 +256,136,127960,1,8 +256,224,128243,1,0 +380,84,128809,6,0,B|472:28,1,100,2|8 +476,120,129375,2,0,B|368:184|368:184|368:260,1,200,0|0 +456,296,130224,1,8 +384,348,130507,1,0 +128,348,131073,5,2 +56,296,131356,1,8 +144,258,131639,2,0,B|144:184|144:184|36:120,1,200,0|0 +46,32,132488,2,0,B|132:84,1,100,8|0 +256,196,133337,5,2 +300,124,133620,1,8 +212,124,133903,1,0 +184,213,134186,2,0,B|190:261|240:284|272:284|324:268|329:214|329:214,1,200,0|8 +256,196,135035,1,0 +412,284,135601,5,0 +412,284,135884,1,8 +256,372,136450,1,0 +100,284,137016,1,8 +100,284,137299,1,0 +28,229,137582,2,0,B|108:40|108:40,1,200,0|8 +484,163,138714,2,0,B|404:352|404:352,1,200,0|8 +316,348,139563,5,0 +196,44,140412,1,8 +256,196,140979,1,0 +352,96,141545,6,0,B|365:60|421:54|431:99|431:99,1,100,8|0 +296,260,142111,2,0,B|283:296|227:302|217:257|217:257,1,100,0|0 +84,96,142677,2,0,B|97:60|153:54|163:99|163:99,1,100,8|0 +336,176,143526,5,0 +256,132,143809,1,8 +176,176,144092,1,0 +80,328,144658,5,0 +148,268,144941,2,0,B|216:360|216:360,1,100,8|0 +432,328,145790,1,0 +364,268,146073,2,0,B|296:360|296:360,1,100,8|0 +260,182,146922,1,0 +256,264,147205,1,8 +260,180,147488,1,0 +80,56,148054,5,0 +148,116,148337,2,0,B|216:24|216:24,1,100,8|0 +432,56,149186,1,0 +364,116,149469,2,0,B|296:24|296:24,1,100,8|0 +444,204,150318,5,0 +420,292,150601,1,8 +344,340,150884,1,0 +168,340,151450,1,0 +92,292,151733,1,8 +68,204,152016,1,0 +256,216,152865,5,8 +256,216,153148,1,0 +360,92,153714,5,0 +300,24,153997,1,8 +212,24,154280,1,0 +152,92,154563,1,0 +211,267,155129,2,0,B|227:291|305:301|313:244|313:244,1,100,8|0 +256,188,155695,1,0 +165,339,156262,2,0,B|213:380|313:386|352:337|352:337,1,200,8|0 +256,188,157394,1,8 +200,128,157677,2,0,B|170:91|172:15|256:-36|334:18|358:81|306:134|306:134,1,300,0|8 +439,58,159092,5,0 +439,58,159658,5,8 +420,149,159941,1,0 +348,198,160224,1,8 +256,192,160507,1,0 +163,185,160790,1,8 +91,234,161073,1,0 +72,325,161356,1,4 +256,348,162205,5,0 +256,192,162771,5,0 +192,132,163054,1,8 +212,92,163195,1,0 +256,76,163337,1,0 +300,92,163479,1,0 +320,132,163620,1,0 +72,58,164186,5,8 +91,149,164469,1,0 +163,198,164752,1,8 +256,192,165035,1,0 +348,185,165318,1,8 +420,234,165601,1,0 +439,325,165884,1,8 +184,304,166733,6,0,B|190:352|240:375|272:375|324:359|329:305|329:305,1,200 +256,256,167582,1,8 +256,168,167865,1,0 +72,120,168714,5,8 +128,48,168997,1,0 +212,16,169280,1,8 +300,16,169563,1,0 +384,48,169846,1,8 +440,120,170129,1,0 +256,192,170412,12,0,172677 +36,64,173101,5,0 +36,64,173243,1,0 +36,64,173384,1,0 +36,64,173526,1,0 +96,132,173809,1,0 +168,80,174092,1,0 +212,64,174233,1,0 +252,80,174375,1,0 +264,124,174516,1,0 +288,160,174658,1,0 +332,168,174799,1,0 +372,148,174941,5,4 +428,76,175224,2,0,B|496:164|496:164,1,100,0|8 +433,225,175790,2,0,B|404:326|404:326,1,100,0|2 +320,292,176356,1,0 +272,368,176639,1,8 +196,320,176922,2,0,B|160:364|88:360|40:304|80:244|80:244,1,200 +112,168,177771,2,0,B|108:104|44:88|44:88,1,100,8|0 +128,32,178337,6,0,B|236:32|236:32,1,100,2|0 +272,112,178903,1,8 +356,80,179186,2,0,B|396:40|472:52|508:132|436:180|436:180,1,200 +384,232,180035,2,0,B|340:276|372:332|372:332,1,100,8|0 +284,360,180601,2,0,B|164:360,1,100,2|0 +124,300,181167,2,0,B|66:343|-4:276|33:216|72:200|72:200|105:183|173:149|86:10|12:108|12:108,1,400,8|8 +4,16,182582,5,0 +92,8,182865,1,2 +168,56,183148,1,0 +208,76,183290,1,0 +232,112,183431,1,0 +256,152,183573,1,0 +280,112,183714,1,0 +304,76,183856,1,0 +344,56,183997,1,4 +420,8,184280,1,0 +508,16,184563,1,8 +484,102,184846,6,0,B|424:92|391:141|391:141,1,100,0|2 +369,222,185412,2,0,B|439:321|439:321,1,100,0|8 +342,362,185979,2,0,B|316:322|256:308|200:320|168:364,1,200,2|0 +85,303,186828,2,0,B|73:321|143:222,1,100,8|0 +117,136,187394,2,0,B|121:141|88:92|28:102,1,100,2|0 +124,32,187960,5,8 +220,104,188243,2,0,B|199:79|201:28|257:-5|309:30|325:72|290:108|290:108,1,200,2|0 +388,32,189092,1,8 +460,100,189375,5,0 +392,172,189658,1,2 +468,236,189941,1,0 +398,303,190224,2,0,B|383:345|327:359|298:317|327:288|312:232|270:246|256:352|256:352|241:246|199:232|185:288|213:317|185:359|114:345|114:303,1,500,8|0 +68,308,191780,5,0 +26,288,191922,1,0 +16,245,192063,1,0 +40,207,192205,1,0 +81,189,192346,1,0 +110,154,192488,1,0 +125,114,192629,1,0 +104,73,192771,1,0 +62,54,192912,1,0 +21,72,193054,1,4 +256,40,209752,5,2 +144,96,210035,1,0 +184,112,210177,1,0 +212,148,210318,1,0 +216,192,210460,1,0 +256,212,210601,1,0 +296,192,210743,1,0 +300,148,210884,1,0 +328,112,211026,1,0 +368,96,211167,1,4 +256,192,211309,12,0,214563 +256,32,215129,5,2 +236,183,215686,2,0,B|172:199|130:270|147:356|224:381|284:386|309:374|391:320|389:233|322:176|264:182|264:182,1,500,0|0 +256,268,217384,1,0 +448,64,217950,5,0 +256,124,218516,1,0 +256,124,218799,1,0 +64,64,219365,1,0 +64,64,219648,1,0 +176,260,220214,2,0,B|204:195|313:174|340:268|340:268,1,200,0|0 +336,337,221063,2,0,B|308:402|199:423|172:329|172:329,1,200,0|0 +256,299,221912,1,0 +256,40,222478,5,0 +172,164,223044,1,0 +256,204,223327,1,0 +340,164,223610,1,0 +460,300,224176,5,0 +256,360,224742,1,0 +52,300,225308,1,0 +52,300,225591,5,0 +256,360,226157,1,0 +256,360,226440,1,0 +460,300,227006,1,0 +340,164,227572,5,0 +256,204,227855,1,0 +172,164,228138,1,0 +172,76,228421,1,0 +256,32,228704,1,0 +340,76,228987,1,0 +256,120,229270,5,0 +376,252,229836,1,0 +293,287,230119,2,0,B|314:312|312:363|256:396|204:361|188:319|223:283|223:283,1,200 +136,252,230969,1,0 +176,72,231535,2,0,B|204:137|313:158|340:64|340:64,1,200,0|0 +256,32,232384,1,0 +256,32,232667,5,2 +480,192,233233,1,2 +256,356,233799,1,0 +32,192,234365,1,0 +336,320,234931,6,0,B|308:255|199:234|172:328|172:328,1,200,0|0 +436,112,236063,2,0,B|371:140|350:249|444:276|444:276,1,200,0|0 +176,72,237195,2,0,B|204:137|313:158|340:64|340:64,1,200,0|0 +76,272,238327,2,0,B|141:244|162:135|68:108|68:108,1,200,0|0 +256,208,239459,5,0 +472,288,240025,1,0 +424,92,240591,1,0 +256,340,241157,1,0 +88,92,241723,1,0 +40,288,242289,1,0 +256,208,242855,1,0 +256,44,243421,5,0 +460,340,244553,1,0 +52,340,245685,1,0 +81,156,246252,6,0,B|81:80|139:80|196:80|196:156|196:156|196:233|254:233|311:233|311:156|311:156|311:80|368:80|437:80|427:164,1,600 +348,328,248516,2,0,B|300:369|200:375|161:326|161:326,1,200 +168,152,249648,2,0,B|256:200|256:200|364:140,1,200 +257,103,250497,2,0,B|256:64,3,33.3333333333333 +257,103,251063,1,0 +452,228,251912,6,0,B|376:320,1,100,4|0 +256,356,252478,2,0,B|256:236,1,100,8|0 +123,305,253044,2,0,B|60:228,1,100,0|0 +120,156,253610,1,8 +184,61,253893,2,0,B|190:109|240:132|272:132|324:116|329:62|329:62,1,200,0|0 +392,156,254742,1,8 +300,232,255025,5,0 +256,244,255167,1,0 +212,232,255308,1,0 +152,324,255591,1,0 +256,368,255874,1,8 +360,324,256157,1,0 +256,136,256723,5,0 +180,56,257006,2,0,B|120:156,1,100,8|0 +332,56,257572,2,0,B|392:156,1,100,0|0 +256,136,258138,1,8 +184,208,258421,2,0,B|204:248|240:250|256:258|256:258|272:268|280:288|268:302|256:302|256:302|240:302|230:290|240:268|256:260|256:260|268:250|304:252|328:208|328:208,1,300,0|8 +384,272,259553,5,0 +352,296,259695,1,0 +336,332,259836,1,0 +312,364,259978,1,0 +276,380,260119,1,0 +236,380,260261,1,0 +200,364,260402,1,8 +176,332,260544,1,0 +160,296,260685,1,0 +128,272,260827,1,0 +116,236,260969,6,0,B|48:156|137:48|228:96|255:150|255:150|282:196|338:291|530:151|381:54|381:54,1,600,4|8 +304,32,262950,6,0,B|276:16|240:16|240:16,3,50 +216,16,263516,2,0,B|192:28|140:20|140:20,3,50,0|0|8|0 +128,24,264082,2,0,B|100:36|72:76|72:76,3,50 +68,88,264648,2,0,B|68:120|44:152|44:152|48:152,3,50,0|0|8|0 +44,172,265214,2,0,B|32:200|40:248|40:248,3,50 +52,260,265780,2,0,B|64:288|64:324|64:324,3,50,0|0|8|0 +92,336,266346,2,0,B|104:356|144:372|144:372,3,50 +172,364,266912,2,0,B|208:348|248:364|248:364,3,50,0|0|8|0 +260,368,267478,2,0,B|288:372|328:356|328:356,2,50 +256,192,267902,12,4,270025 +128,184,270308,5,0 +148,72,270591,1,8 +256,32,270874,1,0 +364,72,271157,1,8 +384,184,271440,1,0 +256,152,271723,1,8 +201,261,272006,2,0,B|177:291|185:358|259:403|325:356|346:301|306:252|306:252,1,259.999995350838 +396,352,272855,5,8 +256,291,273138,1,0 +116,352,273421,1,8 +200,196,273704,2,0,B|228:163|314:147|339:225|339:225,1,129.999997675419,0|8 +376,112,274270,2,0,B|320:40|192:36|144:112|144:112,1,259.999995350838 +100,252,275119,6,0,B|204:352,1,129.999997675419,8|0 +318,342,275686,2,0,B|412:252,1,129.999997675419,8|0 +275,87,276252,2,0,B|305:44|435:126|257:242|257:242|80:146|188:33|251:98,1,519.999990701676,8|8 +412,252,277667,6,0,B|308:352,1,129.999997675419,0|8 +194,342,278233,2,0,B|100:252,1,129.999997675419,0|8 +230,87,278799,2,0,B|164:90|145:147|174:218|231:190|231:190|260:255|260:255|288:190|288:190|340:215|372:147|366:77|281:88|281:88,1,519.999990701676 +416,240,280214,5,8 +256,348,280497,1,0 +96,240,280780,1,8 +204,64,281063,2,0,B|180:94|188:161|262:206|328:159|349:104|309:55|309:55,1,259.999995350838,0|0 +416,240,281912,6,0,B|480:120,1,129.999997675419,8|0 +304,336,282478,2,0,B|300:305|268:290|247:290|214:300|211:335|211:335,1,129.999997675419,8|0 +34,125,283044,2,0,B|96:240,1,129.999997675419,8|0 +256,40,283893,5,0 +432,156,284176,1,8 +360,348,284459,1,0 +152,348,284742,1,8 +80,156,285025,1,0 +256,188,285308,1,8 +314,247,285874,5,0 +314,247,286016,1,0 +314,247,286157,1,0 +314,247,286299,1,0 +314,247,286440,1,0 +314,247,286582,1,0 +314,247,286723,1,0 +314,247,286865,1,0 +314,247,287006,1,0 +314,247,287148,1,0 +314,247,287289,1,0 +314,247,287431,1,0 +314,247,287572,1,0 +314,247,287714,1,0 +314,247,287855,1,0 +314,247,287997,1,0 +314,247,288138,1,4 +320,40,288421,6,0,B|184:40|184:40,1,129.999997675419,0|8 +420,256,288987,2,0,B|420:120|420:120,1,129.999997675419,0|8 +192,344,289553,2,0,B|328:344|328:344,1,129.999997675419,0|8 +92,128,290119,2,0,B|92:264|92:264,1,129.999997675419,0|8 +256,192,290686,1,0 +256,192,290827,1,0 +256,192,290969,1,8 +408,254,291252,6,0,B|312:350,1,129.999997675419,0|8 +316,38,291818,2,0,B|408:130,1,129.999997675419,0|8 +104,130,292384,2,0,B|195:38,1,129.999997675419,0|8 +195,345,292950,2,0,B|104:254,1,129.999997675419,0|8 +256,192,293516,1,0 +408,130,293799,6,0,B|312:34,1,129.999997675419,8|0 +316,345,294365,2,0,B|408:254,1,129.999997675419,8|0 +104,254,294931,2,0,B|195:345,1,129.999997675419,8|0 +195,38,295497,2,0,B|104:130,1,129.999997675419,8|0 +256,192,296063,5,0 +256,192,296204,1,0 +256,192,296346,1,0 +256,192,296487,1,0 +256,192,296629,1,0 +256,192,296770,1,0 +256,192,296912,1,0 +256,192,297053,1,0 +256,192,297195,1,4 +212,324,297478,6,0,B|215:354|247:369|267:369|301:358|304:324|304:324,1,129.999997675419,0|8 +52,248,298044,2,0,B|84:192|84:192|44:120|44:120,1,129.999997675419,0|8 +312,40,298610,2,0,B|256:72|256:72|184:32|184:32,1,129.999997675419,0|8 +460,248,299176,2,0,B|428:192|428:192|468:120|468:120,1,129.999997675419,0|8 +312,348,299742,6,0,B|256:316|256:316|184:356|184:356,1,129.999997675419,0|8 +80,148,300308,2,0,B|50:151|35:183|35:203|46:237|80:240|80:240,1,129.999997675419,0|8 +300,36,300874,2,0,B|297:66|265:81|245:81|211:70|208:36|208:36,1,129.999997675419,0|8 +432,240,301440,2,0,B|462:237|477:205|477:185|466:151|432:148|432:148,1,129.999997675419,0|8 +256,192,302006,5,0 +136,272,302289,2,0,B|110:298|74:278|74:278|94:314|69:338|69:338,1,129.999997675419,8|0 +256,344,302855,1,8 +376,272,303138,2,0,B|401:298|437:278|437:278|417:314|442:338|442:338,1,129.999997675419,0|8 +256,192,303704,5,0 +136,112,303987,2,0,B|110:86|74:106|74:106|94:70|69:46|69:46,1,129.999997675419,8|0 +256,40,304553,1,8 +376,112,304836,2,0,B|401:86|437:106|437:106|417:70|442:46|442:46,1,129.999997675419,0|8 +256,192,305402,6,0,B|296:256|296:256|360:256,1,129.999997675419,0|8 +256,192,305969,2,0,B|216:256|216:256|152:256,1,129.999997675419,0|12 +196,352,306535,2,0,B|232:352|232:352|256:336|256:336|280:352|280:352|328:352,1,129.999997675419,0|8 +416,256,307101,5,0 +444,120,307384,1,8 +348,40,307667,2,0,B|340:101|275:131|234:131|167:110|161:41|161:41,1,259.999995350838,0|0 +68,120,308516,1,8 +96,256,308799,1,0 +212,348,309082,6,0,B|215:318|247:303|267:303|301:314|304:348|304:348,1,129.999997675419,8|0 +320,192,309648,2,0,B|184:192,1,129.999997675419,8|0 +192,48,310214,2,0,B|256:68|256:68|320:48,1,129.999997675419,8|0 +372,176,310780,2,0,B|256:228|256:228|132:172,1,259.999995350838,12|8 +68,292,311629,1,0 +256,368,311912,1,8 +444,292,312195,1,0 +348,45,312761,6,0,B|341:106|277:136|236:136|169:115|163:46|163:46,1,259.999995350838,0|0 +82,161,313610,2,0,B|124:224|188:240|188:240,1,129.999997675419,8|0 +328,238,314176,2,0,B|388:216|430:161,2,129.999997675419,8|0|8 +256,356,315025,1,0 +256,356,315308,5,12 +328,240,315591,2,0,B|452:304|452:304,1,129.999997675419,0|8 +184,240,316157,2,0,B|60:304|60:304,1,129.999997675419,0|8 +151,91,316723,2,0,B|220:112|256:40|256:40|292:112|364:92,1,259.999995350838,0|0 +256,356,317855,5,0 +380,284,318138,1,8 +380,140,318421,1,0 +256,68,318704,1,8 +132,140,318987,1,0 +132,284,319270,1,8 +256,208,319553,1,0 +256,192,319695,12,0,320686 +256,192,320827,12,0,322101 +255,57,322950,5,0 +115,303,323233,1,8 +256,192,323516,1,0 +396,304,323799,1,8 +256,192,324082,6,0,B|256:292|256:292|312:292|380:264|392:164|368:108|332:60|244:56|164:52|120:144|136:200|120:264|244:292|244:292,1,649.999988377094,4|0 +32,64,337093,5,8 +48,64,337243,1,0 +64,64,337393,1,8 +256,92,337693,2,0,B|256:316|256:316,1,200,8|8 +432,352,338293,2,0,B|368:304|368:224|432:176|432:176,1,200,8|8 +82,178,338893,2,0,B|134:224|144:304|80:352,1,200,8|8 +124,339,339343,5,0 +167,327,339493,1,8 +210,313,339643,1,0 +253,301,339793,1,8 +293,102,340093,2,0,B|313:77|311:26|255:-7|203:28|187:70|222:106|222:106,1,200,8|8 +432,192,340693,1,8 +256,296,340993,1,8 +80,192,341293,1,8 +208,360,341593,5,8 +180,272,341743,1,0 +256,216,341893,1,8 +332,272,342043,1,0 +304,360,342193,1,8 +356,44,342493,6,0,B|152:44,1,200,8|8 +356,124,343093,2,0,B|144:124,2,200,8|8|8 +408,272,343993,1,8 +348,344,344143,1,0 +256,372,344293,1,8 +164,344,344443,1,0 +104,272,344593,1,8 +256,192,344893,1,8 +256,192,345043,12,4,346693 +344,36,346993,5,8 +164,36,347293,1,8 +216,171,347593,2,0,B|230:139|284:129|297:175|297:175,1,100,8|8 +329,245,347893,2,0,B|319:311|199:343|183:245|183:245,2,200,8|8|8 +172,356,348793,1,8 +256,384,348943,1,8 +340,356,349093,1,8 +344,56,349393,6,0,B|432:112|432:112|456:232,1,200,8|8 +168,56,349993,1,8 +168,56,350143,1,0 +168,56,350293,2,0,B|80:112|80:112|56:232,1,200,8|8 +348,328,350893,2,0,B|256:368|256:368|148:320,2,200,8|8|4 +256,172,351793,5,8 +388,48,352093,1,8 +256,172,352393,1,8 +256,260,352543,1,8 +256,172,352693,1,8 +124,48,352993,1,8 +124,238,353293,2,0,B|192:272|192:336|192:336|240:336|256:368|256:368|272:336|320:336|320:336|320:272|393:240,1,400,8|4 +256,40,354193,5,8 +76,340,354493,1,8 +436,340,354793,1,8 +376,272,354943,6,0,B|410:236|410:236|476:237,1,100,0|8 +462,146,355243,2,0,B|412:144|412:144|368:94,1,100,0|8 +296,148,355543,2,0,B|282:116|228:106|215:152|215:152,1,100,0|8 +132,106,355843,2,0,B|99:144|99:144|50:146,1,100,0|8 +51,237,356143,2,0,B|101:236|101:236|136:272,1,100,0|4 +216,236,356443,6,0,B|230:268|284:278|297:232|297:232,1,100,0|8 +332,316,356743,2,0,B|352:288|352:288|384:288|384:288|404:260,2,100,0|8|0 +256,360,357193,1,8 +176,316,357343,2,0,B|156:288|156:288|124:288|124:288|104:260,2,100,0|8|0 +212,232,357793,1,8 +300,232,357943,1,0 +340,152,358093,2,0,B|339:105|339:105|380:70,1,100,8|0 +299,18,358393,2,0,B|256:40|256:40|206:15,1,100,8|0 +132,70,358693,2,0,B|173:105|173:105|172:152,1,100,4|0 +96,200,358993,5,8 +20,248,359143,1,0 +68,324,359293,1,8 +144,276,359443,1,0 +212,340,359593,2,0,B|228:340|228:340|248:332|248:332|256:344|256:344|264:332|264:332|280:340|280:340|296:340,1,100,8|0 +368,276,359893,1,8 +444,324,360043,1,0 +492,248,360193,1,8 +416,200,360343,1,0 +344,144,360493,6,0,B|376:130|386:76|340:63|340:63,1,100,8|0 +256,36,360793,1,8 +168,64,360943,2,0,B|136:78|126:132|172:145|172:145,1,100,0|4 +200,228,361243,1,0 +148,300,361393,2,0,B|100:280|100:280|88:232|88:232,2,100,8|0|8 +211,364,361843,2,0,B|256:341|256:341|306:366,1,100,0|8 +364,300,362143,2,0,B|412:280|412:280|424:232|424:232,2,100,0|8|0 +312,228,362593,1,8 +304,140,362743,5,0 +332,56,362893,1,8 +256,4,363043,1,0 +180,56,363193,1,8 +208,140,363343,1,0 +200,228,363493,5,4 +116,192,363643,1,0 +52,252,363793,1,8 +92,336,363943,1,0 +184,320,364093,1,8 +256,372,364243,1,0 +328,320,364393,1,8 +420,336,364543,1,8 +460,252,364693,1,8 +396,192,364843,1,8 +312,228,364993,1,8 +294,139,365143,6,0,B|280:171|226:181|213:135|213:135,2,100,8|8|8 +295,49,365593,2,0,B|281:17|227:7|214:53|214:53,2,100,8|8|4 +416,181,366193,6,0,B|359:309|142:350|89:164|89:164,1,400,0|8 +117,324,367093,2,0,B|176:384|364:408|416:309|426:294|426:294,2,300,0|0|8 +192,209,368293,2,0,B|160:113|256:41|352:113|320:209,2,300,0|0|8 +96,109,369493,6,0,B|148:5|256:-27|364:5|416:109,2,400,0|8|2 +168,224,370993,2,0,B|200:264|256:276|312:264|344:224,2,200,8|0|8 +32,184,371893,6,0,B|92:224|92:224|104:292|172:316,1,200,0|8 +256,204,372493,1,2 +340,315,372793,2,0,B|408:292|420:224|420:224|480:184,1,200,8|0 +360,120,373393,2,0,B|308:128|308:128|200:84|212:20|256:0|300:20|312:84|204:128|204:128|152:120,1,400,8|8 +40,204,374293,6,0,B|108:192|176:232|184:308,1,200,0|8 +184,308,374743,1,4 +328,308,375043,1,2 +328,308,375193,2,0,B|336:232|404:192|472:204,1,200,8|4 +340,156,375793,6,0,B|276:200|260:256|256:276|256:276|252:256|236:200|172:156,1,300,8|2 +172,84,376393,2,0,B|204:36|256:24|308:36|340:84,2,200,8|0|8 +296,152,377293,6,0,B|312:212|256:236|200:260|216:320,1,200,0|8 +216,150,377893,2,0,B|200:212|256:236|312:260|295:320,2,200,0|8|2 +256,16,378793,1,8 +140,96,379093,6,0,B|92:240|232:308|256:352|256:352|280:308|420:240|372:96,1,600,0|8 +304,120,380143,2,0,B|256:144|208:120,1,100,2|0 +68,100,380593,6,0,B|96:304|292:280|324:388,1,400,8|8 +188,385,381493,2,0,B|220:280|416:304|444:100,1,400,2|0 +304,72,382393,1,8 +184,148,382693,2,0,B|212:192|256:216|256:216|300:192|328:148,1,200,0|8 +208,72,383293,1,0 +256,204,383593,1,8 +374,272,383893,6,0,B|342:312|342:312|296:328,1,100,8|8 +216,328,384193,2,0,B|169:312|169:312|137:272,1,100,8|8 +137,195,384493,2,0,B|169:155|169:155|216:140,1,100,8|8 +296,140,384793,2,0,B|342:155|342:155|374:195,1,100,8|0 +436,232,385093,6,0,B|484:112|484:112|448:48,1,200,4|8 +380,8,385543,1,0 +348,80,385693,2,0,B|296:56|296:56|256:72|256:72|216:56|216:56|164:80,1,200,0|8 +132,8,386143,1,0 +62,50,386293,2,0,B|28:112|28:112|76:232,1,200,0|8 +120,300,386743,6,0,B|176:356|256:372|336:356|392:300,1,300,0|8 +424,228,387343,1,2 +344,240,387493,2,0,B|312:280|256:296|200:280|168:240,1,200,0|8 +88,228,387943,1,0 +140,168,388093,1,0 +256,140,388243,6,0,B|256:88,6,50,8|0|8|0|8|0|4 +256,140,389293,1,4 +296,212,389893,6,0,B|284:339|148:363|68:339,2,300,6|2|8 +256,140,390943,1,0 +216,212,391093,2,0,B|227:339|363:363|443:339,2,300,0|2|8 +368,268,392293,6,0,B|412:280|460:252|460:196|460:196|460:128,1,200,0|8 +472,56,392743,2,0,B|428:44|384:68|380:124|380:124|380:192,1,200 +300,192,393193,2,0,B|300:72|300:72|300:16|256:-4|212:16|212:72|212:72|212:192,1,400,8|8 +132,191,393943,2,0,B|132:124|132:124|128:68|84:44|40:56,1,200,2|0 +52,131,394393,2,0,B|52:196|52:196|52:252|100:280|144:268,1,200,8|0 +296,316,394993,6,0,B|440:264|424:68,1,300,8|2 +344,88,395593,2,0,B|364:244|256:288|148:244|168:88,1,400,8|8 +87,71,396343,2,0,B|72:264|216:316,1,300,2|8 +204,108,397093,6,0,B|336:108|336:108|400:140,1,200,0|8 +360,212,397543,1,2 +308,276,397693,2,0,B|176:276|176:276|112:244,1,200,0|8 +152,172,398143,1,0 +128,96,398293,6,0,B|48:32,2,100,8|0|8 +176,32,398743,2,0,B|256:92|256:92|336:32,1,200,0|8 +384,96,399193,2,0,B|464:32,2,100,8|0|4 +404,256,399793,6,0,B|320:280|320:280|348:340|304:388,1,200,8|0 +256,324,400243,1,0 +205,384,400393,2,0,B|164:340|192:280|192:280|108:256,1,200,8|0 +124,180,400843,2,0,B|204:204|204:204|240:216|260:236|264:244|256:256|248:244|252:236|272:216|308:204|308:204|388:180,1,300,2|2 +364,20,401593,6,0,B|292:24|228:68|216:132,1,200,8|0 +296,132,402043,2,0,B|284:68|220:24|148:20,1,200,2|0 +148,100,402493,1,0 +256,216,402793,1,8 +364,100,403093,6,0,B|384:116|400:144|400:204|400:204|400:292,1,200,0|8 +256,356,403693,1,0 +112,290,403993,2,0,B|112:204|112:204|112:144|128:116|148:100,1,200,8|4 +188,256,404593,6,0,B|200:200|256:164|312:200|324:256,2,200,8|0|8 +112,228,405343,1,0 +40,188,405493,2,0,B|60:160|94:147|128:148|156:160|156:160|176:136|216:120,1,200,2|8 +296,120,405943,2,0,B|336:136|356:160|356:160|384:148|417:147|452:160|472:188,1,200 +400,228,406393,1,8 +256,296,406693,6,0,B|336:344|336:344|448:328,2,200,0|8|2 +256,216,407443,1,0 +256,136,407593,2,0,B|176:88|176:88|64:104,2,200,8|0|8 +324,176,408343,5,0 +324,256,408493,1,0 +256,300,408643,1,0 +188,256,408793,1,0 +188,176,408943,1,0 +256,136,409093,1,4 +392,52,409393,6,0,B|396:144|432:192|496:204,1,200,0|8 +496,124,409843,2,0,B|433:135|397:183|393:275,1,200,2|0 +472,272,410293,2,0,B|468:328|432:360|372:360|372:360|316:360,1,200,0|8 +296,284,410743,1,0 +216,284,410893,1,0 +191,360,411043,6,0,B|140:360|140:360|80:360|44:328|40:272,1,200 +118,275,411493,2,0,B|114:183|78:135|16:124,1,200,2|8 +17,203,411943,2,0,B|80:192|116:144|120:52,1,200 +200,72,412393,6,0,B|196:140|256:164|316:140|312:72,1,200,8|0 +376,136,412843,2,0,B|348:208|256:244|164:208|136:136,1,300,2|0 +25,32,413593,5,8 +24,31,413893,2,0,B|61:43|61:43|53:76|53:76|86:88|86:88|73:121|73:121|94:141|94:141|90:178|-3:154|-27:269|49:343|155:302|155:192|155:192|217:192|217:192|217:228|217:228|225:273|267:302|267:302|295:314|308:351|287:384|253:392|221:384|200:351|213:314|241:302|241:302|283:273|291:228|291:228|291:192|291:192|353:192|353:192|353:302|459:343|537:269|513:154|418:178|414:141|414:141|435:121|435:121|422:88|422:88|455:76|455:76|447:43|447:43|484:31,1,1600,0|4 +340,104,416593,5,0 +256,104,416743,1,0 +300,32,416893,1,0 +212,32,417043,1,0 +172,104,417193,1,0 +212,172,417343,1,0 +300,172,417493,1,4 +460,216,417793,5,0 +392,328,418093,1,4 +252,380,418393,1,0 +252,380,418543,1,0 +252,380,418693,1,4 +120,328,418993,1,8 +52,216,419293,1,0 +208,144,419593,5,8 +296,144,419743,1,0 +328,59,419893,2,0,B|318:-7|198:-39|182:59|182:59,1,200,0|8 +128,132,420343,2,0,B|212:176|212:176|212:304,1,200 +300,281,420793,2,0,B|300:176|300:176|384:132,1,200,8|0 +472,156,421243,1,0 +408,220,421393,5,8 +352,384,421693,2,0,B|288:384|288:384|256:368|256:368|224:384|224:384|136:384|136:384,1,200,0|8 +104,220,422293,1,0 +156,48,422593,5,8 +180,140,422743,2,0,B|220:136|248:100|256:81|256:81|264:100|288:132|336:140,1,200 +356,48,423193,1,8 +256,204,423493,5,4 +324,368,423793,2,0,B|396:300,1,100,8|0 +188,368,424243,2,0,B|116:300,1,100,0|8 +216,153,424693,2,0,B|164:204|200:264|235:275|268:272|296:280|352:228|333:181|292:148|292:148,2,300,0|0|8 +348,44,425893,2,0,B|256:8|256:8|160:44,1,200,0|8 +53,188,426493,6,0,B|120:201|143:318|50:338|50:338,1,200,0|8 +216,360,427093,2,0,B|230:328|284:318|297:364|297:364,1,100,8|8 +344,288,427393,2,0,B|368:244|368:244|344:200,1,100,8|8 +296,132,427693,2,0,B|282:164|228:174|215:128|215:128,1,100,8|8 +168,204,427993,2,0,B|144:247|144:247|168:291,1,100,8|8 +256,248,428293,1,4 +456,340,428593,6,0,B|389:327|366:210|459:190|459:190,1,200,8|8 +336,56,429193,1,8 +256,92,429343,1,0 +176,56,429493,1,8 +256,228,429793,1,8 +334,269,429943,2,0,B|315:331|198:354|174:264|174:264,1,200 +120,332,430393,1,8 +105,147,430693,2,0,B|131:68|197:12|304:11|381:62|408:154,1,400,8|8 +392,332,431593,1,8 +184,248,431893,6,0,B|197:291|228:301|256:310|256:310|279:322|279:350|256:361|232:350|232:322|256:310|256:310|279:301|310:291|328:248,2,300,8|8|8 +328,136,433093,2,0,B|314:92|283:82|256:73|256:73|232:61|232:33|256:22|279:33|279:61|256:73|256:73|232:82|201:92|184:136,2,300,8|8|8 +64,60,434293,5,4 +256,248,434743,1,8 +448,60,435193,1,8 +309,184,435493,2,0,B|378:252|330:333|283:348|239:344|201:354|133:282|153:215|208:180|208:180,1,400,4|8 +86,328,436393,5,8 +256,248,436693,1,0 +426,328,436993,1,0 +304,160,437293,1,0 +328,72,437443,1,0 +256,24,437593,1,0 +184,72,437743,1,0 +208,160,437893,1,4 +336,304,438193,2,0,B|317:366|200:389|176:299|176:299,1,200 +49,138,438793,1,0 +149,31,439093,6,0,B|166:122|257:140|257:140|330:158|366:213|366:267|293:340|220:340|147:267|147:213|184:158|257:140|257:140|348:122|366:31,1,800 +453,145,440593,5,0 +370,358,440893,1,0 +142,357,441193,1,0 +59,145,441493,1,0 +256,20,441793,1,0 +179,207,442093,6,0,B|198:145|315:122|339:212|339:212,1,200 +256,256,442543,1,0 +256,352,442693,1,4 +64,332,452293,6,0,B|64:252|64:252|64:204|96:172|136:172,1,200,4|0 +212,84,452893,2,0,B|212:164|212:164|212:212|180:244|140:244,1,200,8|0 +300,300,453493,6,0,B|300:219|300:219|300:171|332:139|371:139,1,200 +448,50,454093,2,0,B|448:130|448:130|448:178|416:210|376:210,1,200,8|0 +200,232,454693,6,0,B|176:184|176:184|132:184|100:172|80:136|84:96,1,200 +136,36,455143,1,2 +160,108,455293,2,0,B|212:108|212:108|256:128|256:128|300:108|300:108|352:108,1,200,8|0 +376,36,455743,1,2 +428,96,455893,2,0,B|432:136|412:172|380:184|336:184|336:184|312:232,1,200 +128,272,456493,2,0,B|152:324|216:332|244:304|256:296|256:296|268:304|296:332|360:324|384:272,1,300,8|0 +428,208,457093,6,0,B|388:180|336:196|312:240|312:240|256:208|256:208|200:240|200:240|176:196|124:180|84:208,1,400,4|8 +28,152,457843,2,0,B|80:116|136:108|176:124|176:124|216:140,1,200 +295,140,458293,2,0,B|336:124|336:124|376:108|432:116|484:152,2,200,2|0|8 +156,232,459193,6,0,B|356:232,1,200 +424,188,459643,1,2 +476,252,459793,1,0 +432,320,459943,2,0,B|404:372|404:372|324:372|324:372|296:320,1,200,0|2 +216,318,460393,2,0,B|188:372|188:372|108:372|108:372|80:320,1,200,0|2 +36,252,460843,1,0 +88,188,460993,1,0 +216,92,461293,6,0,B|176:52,2,50 +296,92,461593,2,0,B|336:52,2,50 +296,172,461893,2,0,B|384:172|384:172|424:172|456:192|472:232,1,200,4|8 +464,312,462343,2,0,B|424:304|400:280|388:252|388:252|320:252|320:252|296:272,1,200,0|2 +216,272,462793,2,0,B|192:252|192:252|124:252|124:252|112:280|88:304|48:312,1,200,8|0 +40,230,463243,2,0,B|56:192|88:172|128:172|128:172|216:172,1,200,0|2 +216,92,463693,2,0,B|216:56|216:56|216:28|240:4|272:4|296:28|296:56|296:56|296:92,1,200,0|8 +424,192,464293,6,0,B|464:264|464:264|384:352,1,200,0|8 +127,351,464893,2,0,B|48:264|48:264|88:192,1,200,0|8 +140,252,465343,1,0 +164,176,465493,2,0,B|204:188|236:244|204:300|204:300|308:300|308:300|276:244|308:188|348:176,1,400,2|0 +324,100,466243,1,0 +256,144,466393,1,8 +188,104,466543,1,0 +256,56,466693,1,0 +408,108,466993,6,0,B|400:152|364:180|320:184|320:184|284:228|256:216|228:228|192:184|192:184|148:180|112:152|104:108,1,400,8|8 +24,244,467893,2,0,B|148:256|148:256|176:284|212:292,1,200,0|8 +299,292,468343,2,0,B|336:284|364:256|364:256|488:244,1,200,2|0 +448,324,468793,6,0,B|404:328|404:328|336:372|256:388|176:372|108:328|108:328|64:324,1,400,8|8 +96,252,469543,2,0,B|200:208|216:104,1,200,0|2 +295,103,469993,2,0,B|312:208|416:252,1,200,8|0 +360,312,470443,5,0 +296,268,470593,1,0 +256,204,470743,1,0 +216,268,470893,1,0 +152,312,471043,1,0 +216,360,471193,1,0 +296,360,471343,1,0 +380,384,471493,6,0,B|436:368|456:304|432:252|376:236,1,200,4|0 +396,160,471943,1,2 +320,184,472093,2,0,B|300:136|300:136|256:116|256:116|212:136|212:136|192:184,1,200,0|8 +116,160,472543,1,2 +134,236,472693,2,0,B|80:252|56:304|76:368|132:384,1,200,0|8 +156,312,473143,2,0,B|356:312,1,200 +336,236,473593,1,8 +256,236,473743,1,0 +176,236,473893,6,0,B|96:240|44:192|32:124,1,200,2|8 +72,56,474343,2,0,B|152:52|204:100|216:168,1,200 +296,166,474793,2,0,B|308:100|360:52|440:56,1,200,8|2 +479,125,475243,2,0,B|468:192|416:240|336:236,1,200 +256,236,475693,1,0 +212,304,475843,1,0 +256,372,475993,1,0 +300,304,476143,1,0 +256,236,476293,6,0,B|256:32,1,200,4|0 +336,36,476743,1,2 +416,36,476893,2,0,B|416:76|384:112|340:116|340:116|340:160|340:200,1,200,0|8 +172,195,477493,2,0,B|172:160|172:116|172:116|128:112|96:76|96:36,1,200,0|8 +176,36,477943,2,0,B|224:44|244:88|244:88|268:88|268:88|288:44|336:36,1,200 +352,116,478393,6,0,B|332:152|316:156|296:164|296:164|296:220|296:220|296:288,2,200,8|2|8 +160,116,479293,2,0,B|180:152|196:156|216:164|216:164|216:220|216:220|216:288,2,200,0|8|0 +120,184,480043,5,0 +140,260,480193,1,0 +216,288,480343,1,0 +256,356,480493,1,0 +296,288,480643,1,0 +372,260,480793,1,0 +392,184,480943,1,0 +377,106,481093,6,0,B|449:94|503:168|451:239,1,200,4|0 +392,184,481543,2,0,B|341:252|395:327|467:315,1,200,2|0 +412,388,481993,2,0,B|312:372|304:316|320:268|280:280|256:260|232:280|192:268|208:316|200:372|100:388,1,400,8|8 +43,315,482743,2,0,B|116:327|170:252|120:184,1,200,2|0 +59,238,483193,2,0,B|8:168|62:94|135:106,1,200,8|0 +296,264,483793,6,0,B|372:264|372:264|400:240|400:240|432:256|432:256|456:244|456:244|480:244,2,200,8|0|8 +256,196,484543,1,2 +216,120,484693,2,0,B|140:120|140:120|112:144|112:144|80:128|80:128|56:140|56:140|32:140,2,200,0|8|0 +351,32,485593,6,0,B|276:104|360:264|480:68|540:348|412:348|352:348|352:348|295:348,1,500,8|0 +216,348,486493,2,0,B|160:348|160:348|100:348|-28:348|32:68|152:264|236:104|160:32,1,500,2|0 +104,88,487393,5,8 +256,204,487693,1,2 +408,88,487993,1,8 +188,164,488293,5,8 +188,84,488443,1,8 +256,40,488593,1,8 +324,84,488743,1,8 +324,164,488893,1,8 +256,204,489043,1,8 +188,248,489193,1,8 +324,248,489343,1,8 +256,292,489493,6,0,B|256:340,8,50,8|0|8|0|8|0|8|0|8 +324,248,490243,1,0 +296,172,490393,1,8 +216,172,490543,1,0 +188,248,490693,1,4 +176,80,490993,6,0,B|195:18|312:-5|336:85|336:85,1,200,8|8 +396,252,491593,2,0,B|392:192|442:160|442:160,1,100,8|0 +488,240,491893,1,8 +340,340,492193,1,8 +295,265,492343,2,0,B|317:234|297:196|271:187|253:182|228:183|180:218|200:250|227:280|227:280,1,200 +172,340,492793,1,8 +24,240,493093,1,8 +73,165,493243,2,0,B|118:192|116:252,1,100,0|8 +169,78,493693,6,0,B|223:78|223:78|255:46|255:46|287:78|287:78|343:78,1,200,8|8 +375,277,494293,6,0,B|346:370|169:405|133:269|133:269,2,300,8|8|8 +315,126,495493,2,0,B|347:77|317:21|282:6|248:-1|209:2|143:56|170:103|211:148|211:148,2,300,8|8|8 +184,248,496693,2,0,B|197:291|228:301|256:310|256:310|279:322|279:350|256:361|232:350|232:322|256:310|256:310|279:301|310:291|328:248,2,300,8|8|8 +101,109,497893,6,0,B|104:69|146:40|188:52|188:52|217:4|256:6|297:6|321:51|321:51|363:38|412:70|414:121,1,400,8|8 +339,285,498793,2,0,B|332:301|311:315|290:309|290:309|275:333|255:336|232:331|221:310|221:310|202:316|175:303|169:277,2,200,8|8|8 +256,86,499693,5,0 +184,138,499843,1,0 +212,222,499993,1,0 +300,222,500143,1,0 +328,138,500293,1,4 +424,276,500593,5,0 +256,372,500893,1,0 +88,276,501193,1,0 +88,276,501343,1,0 +88,276,501493,1,0 +160,92,501793,1,0 +160,92,501943,1,0 +352,92,502243,1,0 +352,92,502393,1,0 +256,248,502693,5,0 +301,170,502843,2,0,B|283:152|255:151|229:152|210:170,1,100 +338,292,503293,2,0,B|316:352|200:377|175:288|175:288,1,200 +91,154,503893,6,0,B|44:150|21:102|10:42|65:7|131:-10|181:42|166:103|166:103,2,300 +421,154,505093,2,0,B|468:150|491:102|502:42|447:7|381:-10|331:42|346:103|346:103,2,300 +213,259,506293,2,0,B|161:310|197:370|232:381|265:378|293:386|349:334|330:287|289:254|289:254,2,300 +170,74,507493,6,0,B|224:74|224:74|256:42|256:42|288:74|288:74|344:74,1,200 +448,224,508093,1,0 +330,360,508393,2,0,B|315:315|255:300|255:300|195:315|182:360,1,200 +64,224,508993,1,0 +256,152,509293,5,0 +328,100,509443,1,0 +300,16,509593,1,0 +212,16,509743,1,0 +184,100,509893,1,4 +256,264,510193,1,0 +376,72,510493,1,0 +136,76,510793,1,0 +380,73,511093,6,0,B|445:147|468:248|406:346|328:392|268:399|149:402|86:328|25:223|84:96|152:64,1,800 +256,196,512593,1,0 +256,196,512893,5,0 +180,240,513043,1,0 +180,328,513193,1,0 +256,372,513343,1,0 +332,328,513493,1,0 +332,240,513643,1,0 +336,152,513793,6,0,B|368:138|378:84|332:71|332:71,1,100,0|0 +256,32,514093,1,0 +176,72,514243,2,0,B|144:86|134:140|180:153|180:153,1,100 +256,196,514543,1,0 +182,251,514693,2,0,B|256:319|256:319|326:249,1,200,4|0 +335,255,515068,1,0 +344,263,515143,1,0 +352,271,515218,1,0 +360,279,515293,2,0,B|415:295|465:274|495:228|488:171,1,200,8|0 +398,188,515743,1,0 +386,180,515818,1,0 +374,172,515893,2,0,B|318:155|268:176|238:222|245:279,2,200,8|0|8 +356,28,516793,1,8 +176,24,517093,5,0 +80,176,517393,1,8 +88,180,517468,1,0 +96,184,517543,1,0 +104,188,517618,1,0 +112,192,517693,2,0,B|168:175|218:196|248:242|241:299,1,200,8|0 +144,288,518143,1,0 +136,292,518218,1,0 +128,296,518293,2,0,B|73:312|23:291|-7:245|0:188,1,200,8|8 +48,100,518743,1,0 +48,100,518818,1,0 +48,100,518893,2,0,B|124:100|124:100|168:100|208:72|216:32,1,200,0|8 +464,284,519493,2,0,B|388:284|388:284|344:284|304:312|296:352,1,200,4|8 +216,352,519943,6,0,B|168:352,2,50,0|0|8 +296,32,520393,2,0,B|344:32,2,50,8|0|0 +204,68,520693,2,0,B|248:120|248:120|380:120,1,200,0|8 +308,316,521293,2,0,B|264:264|264:264|132:264,1,200,0|8 +24,96,521893,6,0,B|56:136|56:136|156:124|156:124|188:160,1,200,0|8 +256,232,522343,2,0,B|256:280,2,50,0|0|8 +324,159,522643,1,0 +324,159,522793,2,0,B|356:124|356:124|456:136|456:136|488:96,1,200,8|8 +428,16,523243,5,4 +24,288,523693,5,8 +84,368,523843,1,4 +256,120,524293,5,4 +452,156,524593,2,0,B|424:100,2,50,8|0|0 +504,240,524893,2,0,B|456:280|360:252|348:176,1,200,8|0 +163,176,525493,2,0,B|152:252|56:280|8:240,1,200,0|8 +60,156,525943,1,0 +60,156,526093,2,0,B|88:100,2,50,8|0|0 +60,156,526393,1,0 +300,336,526693,6,0,B|340:280|340:280|384:292|440:284|460:248,1,200,0|8 +388,180,527143,2,0,B|404:128,2,50,0|0|8 +124,180,527593,2,0,B|108:128,2,50,8|0|0 +52,249,527893,2,0,B|72:284|128:292|172:280|172:280|212:336,1,200,0|8 +256,140,528493,1,0 +256,140,528793,2,0,B|256:40,2,100,8|0|4 +460,192,529393,6,0,B|528:192,2,50,8|0|0 +360,192,529693,1,8 +52,188,529993,2,0,B|-16:188,2,50,8|0|0 +152,192,530293,1,8 +312,308,530593,1,8 +256,108,530893,1,0 +200,308,531193,1,8 +172,112,531493,6,0,B|172:60|212:16|276:12|316:52,1,200,0|8 +340,272,532093,2,0,B|340:324|300:368|236:372|196:332,1,200,0|8 +56,192,532543,5,0 +56,192,532618,1,0 +56,192,532693,1,0 +8,100,532843,1,4 +460,192,533293,5,8 +504,284,533443,1,4 +256,192,550693,12,4,553093 +48,116,553393,6,0,B|114:126|146:246|48:262|48:262,1,200,0|0 +183,36,553993,2,0,B|193:102|313:134|329:36|329:36,1,200,0|0 +464,262,554593,2,0,B|398:252|366:132|464:116|464:116,1,200,0|0 +300,352,555193,1,0 +328,268,555343,1,0 +256,212,555493,1,0 +184,268,555643,1,0 +212,352,555793,1,0 +108,200,556093,5,0 +168,40,556393,1,0 +344,40,556693,1,0 +404,200,556993,1,0 +256,288,557293,1,0 +256,108,557593,5,0 +212,186,557743,1,0 +301,185,557893,1,4 +174,312,558193,2,0,B|183:356|231:356|255:340|255:340|279:356|327:356|335:308,1,200 +470,164,558793,2,0,B|425:158|418:126|411:107|417:88|417:88|398:95|379:89|351:80|344:41,1,200 +166,43,559393,2,0,B|160:80|132:89|113:95|94:88|94:88|100:107|93:126|86:158|42:164,1,200 +152,288,559993,2,0,B|192:384,1,100 +256,320,560293,1,4 +321,380,560443,2,0,B|360:288,1,100 +295,119,560893,2,0,B|317:88|297:50|271:41|253:36|228:37|180:72|200:104|227:134|227:134,1,200 +56,200,561493,5,0 +128,272,561643,1,0 +164,298,561718,1,0 +181,339,561793,1,0 +256,264,561943,1,0 +331,339,562093,1,0 +348,298,562168,1,0 +384,272,562243,1,0 +432,176,562393,1,0 +360,88,562543,1,0 +256,56,562693,1,4 +152,88,562843,1,0 +80,176,562993,1,0 +213,343,563293,6,0,B|199:287|199:287|254:259|254:259|310:287|310:287|296:343,1,240.000005722046 +437,158,563893,2,0,B|471:123|471:123|465:38|381:32|381:32|341:72,1,240.000005722046 +166,67,564493,2,0,B|131:32|131:32|47:38|41:123|41:123|76:158,1,240.000005722046 +200,248,564943,2,0,B|176:304|176:304|200:360,1,120.000002861023,0|4 +312,358,565243,2,0,B|336:304|336:304|312:248,1,120.000002861023 +256,4,565693,5,0 +456,96,565993,1,0 +456,296,566293,1,0 +256,376,566593,1,0 +56,296,566893,1,0 +56,96,567193,1,0 +191,119,567343,2,0,B|231:167|191:231,1,120.000002861023 +320,229,567643,2,0,B|280:165|320:117,1,120.000002861023 +354,331,568093,6,0,B|303:321|271:347|254:380|254:380|238:347|205:321|155:331,1,240.000005722046 +157,90,568693,2,0,B|207:99|239:73|256:40|256:40|272:73|305:99|355:90,1,240.000005722046 +477,296,569293,1,0 +256,204,569593,1,0 +212,348,569743,1,0 +332,264,569893,1,0 +180,264,570043,1,0 +300,348,570193,1,0 +32,296,570493,1,0 +160,96,570793,6,0,B|182:21|324:-6|353:102|353:102,2,240.000005722046 +112,336,571693,2,0,B|161:288|160:224,1,120.000002861023 +256,280,571993,1,0 +352,229,572143,2,0,B|351:288|400:336,1,120.000002861023,0|4 +356,64,572593,6,0,B|306:48|289:14|289:14|256:31|222:14|222:14|205:48|155:64|155:64,1,240.000005722046,0|0 +376,192,573193,2,0,B|136:192,1,240.000005722046 +356,320,573793,2,0,B|306:336|289:370|289:370|256:353|222:370|222:370|205:336|155:320|155:320,1,240.000005722046 +153,67,574393,6,0,B|200:83|208:137|192:165|172:188|144:206|71:203|65:157|70:105|70:105,1,259.999995350838,0|4 +359,67,574993,2,0,B|311:83|303:137|319:165|339:188|367:206|440:203|446:157|441:105|441:105,1,259.999995350838 +367,348,575593,2,0,B|297:348|297:348|256:306|256:306|215:348|215:348|143:348,1,259.999995350838 +64,128,576193,1,0 +364,64,576493,2,0,B|328:10|256:-25|183:10|147:64,1,259.999995350838 +196,179,576943,2,0,B|224:208|286:211|320:176,1,129.999997675419,0|4 +138,298,577393,2,0,B|171:339|257:370|336:339|373:299,1,259.999995350838 +440,144,577993,5,0 +256,32,578293,1,0 +72,144,578593,1,0 +180,308,578893,1,0 +256,360,579043,1,0 +336,296,579193,1,0 +304,216,579343,1,0 +208,216,579493,1,4 +128,152,579643,5,0 +92,56,579793,2,0,B|172:44|212:104|212:104,1,129.999997675419 +303,99,580093,2,0,B|347:46|420:56,1,129.999997675419 +384,152,580393,1,0 +304,216,580543,1,0 +410,291,580693,5,4 +400,311,580768,1,0 +383,327,580843,1,0 +364,339,580918,1,0 +343,345,580993,1,0 +322,347,581068,1,0 +299,342,581143,1,0 +278,333,581218,1,0 +260,320,581293,1,4 +234,333,581368,1,0 +213,342,581443,1,0 +190,347,581518,1,0 +169,345,581593,1,0 +148,339,581668,1,0 +129,327,581743,1,0 +112,311,581818,1,0 +102,291,581893,1,4 +188,252,582043,5,0 +324,252,582193,1,0 +256,188,582343,1,0 +352,152,582493,1,0 +160,152,582643,1,0 +256,92,582793,1,0 +256,92,582943,1,0 +160,52,583093,6,0,B|96:52|32:108|44:192|104:240,1,259.999995350838,0|0 +256,312,583543,1,0 +408,240,583693,2,0,B|468:192|480:108|416:52|352:52,1,259.999995350838 +352,152,584143,1,0 +340,296,584293,2,0,B|316:228|256:200|256:200|196:228|172:296,1,259.999995350838 +256,312,584743,1,0 +172,294,584893,2,0,B|52:244,1,129.999997675419 +36,152,585193,2,0,B|156:204,1,129.999997675419 +236,232,585493,6,0,B|252:180|216:136|216:136|72:72,1,259.999995350838 +292,108,585943,2,0,B|408:44,1,129.999997675419 +320,184,586243,2,0,B|452:184,1,129.999997675419 +312,268,586543,1,0 +312,268,586693,6,0,B|432:316,1,129.999997675419,4|0 +332,376,586993,2,0,B|296:328|292:256|360:184|444:200,1,259.999995350838 +180,376,587593,2,0,B|216:328|220:256|152:184|68:200,1,259.999995350838 +96,124,588043,2,0,B|172:128|216:172,1,129.999997675419 +416,124,588343,2,0,B|340:128|296:172,1,129.999997675419 +140,52,588793,2,0,B|200:64|256:108|256:108|312:64|372:52,1,259.999995350838 +256,12,589243,1,0 +256,12,589393,1,0 +372,224,589693,5,0 +140,224,589993,1,0 +292,360,590293,2,0,B|337:315|305:263|275:254|246:256|222:249|174:294|190:335|226:364|226:364,2,259.999995350838 +364,141,591193,1,0 +256,101,591343,1,0 +148,141,591493,1,4 +363,54,591793,6,0,B|327:0|255:-35|182:0|146:54,2,259.999995350838 +256,103,592543,1,0 +362,150,592693,2,0,B|326:204|254:239|181:204|145:150,1,259.999995350838 +138,299,593143,1,0 +380,297,593443,1,0 +379,296,593593,1,0 +368,184,593893,6,0,B|308:180|244:244|252:324|304:376,1,259.999995350838 +380,288,594343,1,0 +272,320,594493,2,0,B|224:272|152:288,1,129.999997675419 +64,216,594793,2,0,B|20:272|52:340,1,129.999997675419 +144,200,595093,6,0,B|204:204|268:140|260:60|208:8,1,259.999995350838 +132,92,595543,1,0 +240,64,595693,2,0,B|288:112|360:96,1,129.999997675419 +448,168,595993,2,0,B|492:112|460:44,2,129.999997675419,0|0|4 +136,320,596593,1,0 +136,320,596743,1,0 +376,320,597043,1,0 +376,320,597193,1,0 +376,320,597493,6,0,B|424:268|422:191|375:126|311:112,1,259.999995350838 +136,320,597943,2,0,B|87:268|89:191|136:126|200:112,1,259.999995350838 +256,48,598393,1,0 +196,348,598693,2,0,B|256:392|316:348,1,129.999997675419 +256,272,598993,1,0 +256,272,599143,1,0 +308,144,599293,6,0,B|304:76|344:16|432:0|492:60,1,259.999995350838 +412,132,599743,1,0 +336,276,599893,2,0,B|340:204|256:148|172:204|176:276,1,259.999995350838 +100,132,600343,1,0 +25,55,600493,2,0,B|79:0|167:15|207:75|203:143,1,259.999995350838 +256,272,600943,1,0 +256,192,601018,12,0,602293 +256,192,602368,12,0,603493 +180,344,603793,6,0,B|205:286|205:286|257:262|257:262|310:286|310:286|334:344,1,240.000005722046 +488,176,604393,2,0,B|434:168|426:130|417:108|424:85|424:85|402:93|379:86|346:75|337:29,1,240.000005722046 +172,32,604993,2,0,B|164:76|131:86|108:93|86:85|86:85|93:108|85:130|76:168|24:176,1,240.000005722046 +168,320,605593,1,0 +256,360,605743,1,0 +344,320,605893,1,4 +453,145,606193,5,0 +256,20,606493,1,0 +59,145,606793,1,0 +142,357,607093,1,0 +370,358,607393,1,0 +256,188,607693,1,0 +315,98,607843,2,0,B|259:68|186:76|145:139|146:199,1,240.000005722046 +197,285,608293,2,0,B|250:314|325:307|366:246|366:183,1,240.000005722046 +464,288,608893,5,0 +256,156,609193,1,0 +48,288,609493,1,0 +166,112,609793,2,0,B|184:57|256:39|256:39|328:57|344:112,1,240.000005722046 +320,192,610243,2,0,B|320:256|255:272|255:272|182:292|198:370,1,240.000005722046 +314,370,610693,2,0,B|330:292|256:272|256:272|192:256|192:192,1,240.000005722046,4|0 +384,80,611293,5,0 +128,80,611593,1,0 +128,304,611893,1,0 +384,304,612193,1,0 +256,128,612493,1,0 +165,185,612643,2,0,B|217:196|249:228|257:252|257:252|265:228|289:196|352:183,1,240.000005722046 +346,280,613093,6,0,B|327:359|188:394|160:272|160:272,1,240.000005722046 +64,88,613693,1,0 +228,32,613993,2,0,B|256:24|256:24|284:32,4,60.0000014305115 +164,136,614443,2,0,B|200:136|200:136|224:112|224:112|256:152|256:152|288:112|288:112|312:136|312:136|352:136,1,240.000005722046 +420,208,614893,1,0 +368,300,615043,1,0 +256,344,615193,1,0 +144,300,615343,1,0 +92,208,615493,1,4 +420,48,615793,5,0 +92,48,616093,1,0 +92,336,616393,1,0 +420,336,616693,1,0 +256,40,616993,1,0 +88,200,617293,1,0 +160,272,617443,1,0 +256,304,617593,1,0 +352,272,617743,1,0 +424,200,617893,1,0 +164,76,618193,6,0,B|183:155|322:190|350:68|350:68,1,240.000005722046 +345,308,618793,2,0,B|323:230|188:196|161:312|161:312,1,240.000005722046 +388,192,619393,1,0 +124,192,619693,1,0 +200,108,619843,2,0,B|256:128|256:128|312:108,1,120.000002861023 +256,16,620143,1,0 +396,48,620293,6,0,B|451:66|469:138|469:138|451:210|396:226,1,240.000005722046 +116,336,620893,2,0,B|61:318|43:246|43:246|61:174|116:158,1,240.000005722046 +388,280,621493,5,0 +256,48,621793,1,0 +124,280,622093,1,0 +56,196,622243,2,0,B|116:172|116:172|136:116|136:116,1,120.000002861023 +202,192,622543,2,0,B|256:218|256:218|309:192,1,120.000002861023 +377,119,622843,2,0,B|376:116|396:172|396:172|456:196,1,120.000002861023 +400,288,623143,1,0 +304,344,623293,1,0 +256,360,623368,1,0 +208,344,623443,1,0 +128,272,623593,5,0 +160,168,623743,1,0 +256,128,623893,1,0 +352,168,624043,1,0 +384,272,624193,1,0 +256,248,624343,1,0 +352,168,624493,5,0 +368,112,624568,1,0 +352,64,624643,1,0 +312,24,624718,1,0 +256,8,624793,1,0 +200,24,624868,1,0 +160,64,624943,1,0 +144,112,625018,1,0 +160,168,625093,1,4 +84,244,625243,5,0 +152,336,625393,1,0 +256,364,625543,1,0 +360,336,625693,1,0 +428,244,625843,1,0 +428,140,625993,1,0 +360,48,626143,1,0 +256,20,626293,1,0 +152,48,626443,1,0 +84,140,626593,1,0 +206,158,626743,6,0,B|222:129|256:125|289:129|305:158,1,120.000002861023 +376,240,627043,1,0 +304,320,627193,2,0,B|287:349|254:353|220:349|204:320,1,120.000002861023 +136,240,627493,1,0 +256,248,627643,1,0 +312,144,627793,5,0 +312,144,627868,1,0 +312,144,627943,1,0 +344,48,628093,1,0 +256,0,628243,1,0 +168,48,628393,1,0 +200,144,628543,1,0 +96,168,628693,5,0 +88,272,628843,1,0 +192,320,628993,1,0 +256,232,629143,1,0 +312,144,629293,1,0 +416,168,629443,1,0 +424,272,629593,1,0 +320,320,629743,1,0 +256,232,629893,1,0 +200,144,630043,5,0 +208,40,630193,1,0 +256,16,630268,1,0 +304,40,630343,1,0 +312,144,630493,1,0 +416,200,630643,2,0,B|488:304,1,120.000002861023 +408,376,630943,2,0,B|339:277,1,120.000002861023 +256,344,631243,1,0 +172,277,631393,2,0,B|104:376,1,120.000002861023 +27,298,631693,2,0,B|96:200,1,120.000002861023 +93,91,631993,5,0 +206,63,632143,2,0,B|222:33|255:29|289:33|305:63,1,120.000002861023 +419,91,632443,1,0 +352,176,632593,1,0 +360,184,632668,1,0 +368,192,632743,1,0 +400,296,632893,2,0,B|456:278|456:278|476:222,1,120.000002861023 +308,356,633193,2,0,B|289:356|289:356|265:346|265:346|256:360|256:360|246:346|246:346|227:356|227:356|208:356,1,120.000002861023 +35,222,633493,2,0,B|55:278|55:278|112:296,1,120.000002861023 +184,96,633793,5,0 +256,272,633943,1,0 +328,96,634093,1,0 +160,200,634243,1,0 +352,200,634393,1,0 +256,32,634543,1,0 +256,168,634693,5,4 +352,328,634993,5,0 +400,88,635293,1,0 +160,40,635593,1,0 +112,248,635893,1,0 +276,357,636193,5,0 +431,167,636493,1,0 +242,12,636793,1,0 +102,173,637093,1,0 +205,350,637393,5,0 +425,244,637693,1,0 +319,23,637993,1,0 +124,110,638293,1,0 +138,310,638593,5,0 +383,315,638893,1,0 +389,71,639193,1,0 +175,59,639493,1,0 +99,249,639793,5,0 +319,358,640093,1,0 +427,138,640393,1,0 +239,38,640693,1,0 +89,186,640993,5,0 +252,369,641293,1,0 +435,206,641593,1,0 +297,43,641893,1,0 +107,116,642193,5,0 +177,351,642493,1,0 +412,281,642793,1,0 +304,240,642943,5,0 +256,224,643018,1,0 +208,240,643093,1,0 +136,155,643243,2,0,B|187:189|256:155|307:103|307:51|290:17|256:0|221:17|204:51|204:103|256:155|324:189|376:155,1,480.000011444092 +40,44,671736,6,0,B|40:164,1,100,8|8 +120,184,672236,2,0,B|120:76,1,100,8|0 +200,126,672736,2,0,B|217:74|276:53|341:72|356:135,1,200,4|8 +436,72,673486,1,0 +484,148,673736,1,8 +412,204,673986,2,0,B|408:244|424:280|464:296|464:296,1,100,0|8 +404,368,674486,5,0 +325,319,674736,2,0,B|299:294|264:292|232:320|232:320|204:348|157:346|140:313,1,200,8|8 +64,352,675486,2,0,B|16:316|12:208|68:160,1,200 +122,106,676236,2,0,B|174:90|190:38,1,100,8|0 +267,84,676736,2,0,B|243:131|281:187|370:171|373:107|349:70,1,200,8|8 +428,28,677486,5,0 +488,96,677736,1,8 +424,160,677986,1,0 +484,225,678236,2,0,B|470:274|470:274|486:322,1,100,8|0 +412,368,678736,2,0,B|308:368,1,100,8|0 +252,300,679236,1,8 +184,360,679486,5,0 +108,312,679736,2,0,B|48:328|4:284|4:204|68:188|68:188,1,200,8|8 +148,148,680486,2,0,B|194:117|188:60,1,100,0|8 +268,20,680986,1,0 +332,80,681236,2,0,B|448:48,1,100,8|0 +484,124,681736,2,0,B|388:152,1,100,8|0 +376,244,682236,6,0,B|492:212,1,100,8|0 +496,304,682736,1,8 +328,373,683236,2,0,B|313:319|252:296|191:320|176:383,1,200,8|8 +88,328,683986,2,0,B|16:248|48:136|48:136,1,200 +120,192,684736,2,0,B|124:75|216:16,1,200,8|8 +280,80,685486,5,0 +360,32,685736,2,0,B|480:32|480:32,1,100,8|0 +488,120,686236,2,0,B|440:128|440:168|488:176,1,100,8|0 +432,248,686736,2,0,B|480:256|480:296|432:304,1,100,8|0 +360,360,687236,1,8 +288,304,687486,5,0 +216,360,687736,2,0,B|104:360|104:360,1,100,8|0 +72,280,688236,2,0,B|184:280|184:280,1,100,8|0 +136,200,688736,2,0,B|85:203|44:162|36:100|88:60,1,200,12|8 +169,24,689486,1,0 +256,56,689736,2,0,B|360:36,1,100,8|0 +424,88,690236,6,0,B|444:188,1,100,8|0 +368,232,690736,1,8 +216,344,691236,2,0,B|223:318|255:306|287:319|295:351,1,100,8|0 +144,232,692236,1,8 +68,186,692486,2,0,B|88:88,1,100,0|8 +256,200,693236,5,8 +336,72,693736,1,8 +256,24,693986,1,0 +176,72,694236,1,8 +177,236,694736,2,0,B|198:284|254:310|321:285|336:232,1,200,8|8 +408,280,695486,1,0 +408,280,695736,5,8 +256,368,696236,1,8 +104,280,696736,1,4 +104,104,697236,1,8 +256,16,697736,1,8 +408,104,698236,5,8 +408,104,698486,1,0 +408,104,698736,1,8 +338,275,699236,2,0,B|315:320|259:346|192:321|176:269,1,200,8|8 +175,175,699986,2,0,B|198:130|254:104|321:129|337:181,1,200 +257,228,700736,5,8 +256,48,701236,1,8 +176,320,701736,1,8 +256,360,701986,1,0 +336,320,702236,1,8 +352,144,702736,2,0,B|287:143|287:143|255:127|255:127|223:143|223:143|151:143,1,200,8|8 +300,32,703736,5,8 +212,32,703986,1,0 +60,121,704486,6,0,B|94:207|94:207|50:304,1,200,8|0 +49,304,705236,1,8 +124,344,705486,2,0,B|169:247|169:247|257:217,1,200,8|0 +452,120,706236,1,8 +452,120,706486,2,0,B|417:207|417:207|462:304,1,200,8|0 +463,304,707236,1,8 +387,343,707486,2,0,B|342:247|342:247|254:217,1,200,8|0 +158,53,708236,1,8 +158,53,708486,2,0,B|223:52|223:52|255:36|255:36|287:52|287:52|359:52,1,200,8|0 +352,138,709236,1,8 +352,138,709486,2,0,B|287:139|287:139|255:155|255:155|223:139|223:139|151:139,1,200,8|0 +256,285,710236,5,8 +100,340,710486,1,8 +204,340,710736,5,0 +180,304,710861,1,0 +180,260,710986,1,0 +212,220,711111,1,0 +256,208,711236,1,0 +300,220,711361,1,0 +332,260,711486,1,0 +332,304,711611,1,0 +308,340,711736,1,0 +412,340,711986,37,0 +452,164,712486,21,0 +370,97,712736,2,0,B|340:54|262:14|173:45|137:104,1,259.999995350838,4|8 +370,287,713736,2,0,B|340:330|262:370|173:339|137:280,1,259.999995350838,0|8 +194,214,714486,2,0,B|258:263|325:207,1,129.999997675419,0|8 +256,144,714986,1,8 +96,288,715486,6,0,B|32:240|16:192|16:192|32:128|112:80,1,259.999995350838,8|8 +256,192,716236,1,8 +416,288,716486,2,0,B|480:240|496:192|496:192|480:128|400:80,1,259.999995350838,8|0 +200,76,717236,6,0,B|214:55|253:35|298:50|316:80,1,129.999997675419,8|0 +256,336,717736,1,8 +160,180,717986,2,0,B|174:243|252:283|341:252|352:168,2,259.999995350838,8|8|8 +320,344,719236,6,0,B|184:344,1,129.999997675419,8|0 +440,168,719736,2,0,B|360:36,1,129.999997675419,8|0 +72,168,720236,2,0,B|152:36,1,129.999997675419,8|0 +256,216,720736,2,0,B|256:296|256:296|360:292|368:200|340:136|304:100|196:92|156:152|149:244|204:280,1,519.999990701676,4|0 +348,360,722236,5,8 +256,384,722486,1,0 +172,360,722736,1,8 +256,208,723236,1,8 +299,22,723736,1,8 +214,25,723986,2,0,B|173:80|209:160|333:145|330:56|296:19,1,259.999995350838,8|8 +404,172,724986,5,8 +344,240,725236,1,8 +256,260,725486,1,0 +168,236,725736,1,8 +108,172,725986,1,0 +140,340,726486,2,0,B|170:383|248:423|337:392|373:333,1,259.999995350838,8|0 +316,268,727236,2,0,B|252:317|185:261,1,129.999997675419,8|0 +256,176,727736,5,8 +160,128,727986,1,0 +192,96,728111,1,0 +212,48,728236,1,0 +256,20,728361,1,0 +300,48,728486,1,0 +320,96,728611,1,0 +352,128,728736,1,4 +400,224,728986,6,0,B|400:288|400:288|464:352,1,129.999997675419 +352,368,729486,1,0 +279,292,729736,2,0,B|297:263|279:224|217:231|219:275|235:294,1,129.999997675419 +160,368,730236,1,0 +61,333,730486,2,0,B|107:286|107:286|107:222,1,129.999997675419 +195,167,730986,2,0,B|256:143|256:143|316:167,1,129.999997675419 +379,84,731486,2,0,B|256:35|256:35|135:84,1,259.999995350838 +207,173,732236,5,0 +305,174,732486,2,0,B|373:206|373:323|285:353|256:323|256:323|212:279|226:235|285:235|299:279|256:323|256:323|212:353|138:309|138:206|214:170,1,649.999988377094 +162,79,733986,1,0 +350,79,734486,1,0 +365,286,734986,2,0,B|335:243|257:203|168:234|132:293,1,259.999995350838 +195,370,735736,6,0,B|259:419|326:363,2,129.999997675419 +137,282,736486,1,0 +79,182,736736,2,0,B|202:174|221:20|153:-13|84:20|84:89|187:123|256:20|256:20|309:109|412:102|451:11|334:-40|296:20|329:166|352:180|459:186,1,779.999986052513,4|0 +344,248,738486,5,0 +256,192,738736,1,0 +168,248,738986,1,0 +355,355,739486,2,0,B|280:360|256:287|256:287|232:360|155:355,1,259.999995350838 +80,288,740236,1,0 +58,186,740486,6,0,B|28:128|76:66|76:66|158:49|196:100,1,259.999995350838 +256,184,741236,2,0,B|256:216|256:216|240:232|240:232|272:240|272:240|256:256|256:256|256:280,2,129.999997675419 +316,99,741986,2,0,B|354:49|436:66|436:66|484:128|454:186,1,259.999995350838 +315,349,742986,6,0,B|251:398|184:342,1,129.999997675419 +205,246,743486,1,0 +307,246,743736,1,0 +368,160,743986,5,0 +324,156,744111,1,0 +288,132,744236,1,0 +256,100,744361,1,0 +224,132,744486,1,0 +188,156,744611,1,0 +144,160,744736,1,4 +256,12,751736,5,8 +181,62,751986,1,0 +209,150,752236,1,8 +301,150,752486,1,0 +329,62,752736,1,4 +328,243,753236,2,0,B|313:297|252:320|191:296|176:233,1,200,8|8 +344,356,754236,5,8 +256,384,754486,1,0 +168,356,754736,1,8 +126,200,755236,1,8 +183,128,755486,2,0,B|233:132|253:72|253:72|273:132|336:128,1,200 +385,200,756236,1,8 +296,240,756486,2,0,B|288:216|259:203|225:213|217:244,1,100,0|8 +256,372,757236,5,8 +416,228,757736,1,8 +356,56,758236,1,8 +156,56,758736,1,8 +84,228,759236,1,8 +141,298,759486,5,0 +200,225,759736,1,4 +183,187,759861,1,0 +188,145,759986,1,0 +213,111,760111,1,0 +256,94,760236,1,0 +298,111,760361,1,0 +323,145,760486,1,0 +328,187,760611,1,0 +311,225,760736,1,0 +370,298,760986,5,0 +308,368,761236,2,0,B|196:368|196:368,1,100,8|0 +176,280,761736,2,0,B|200:272|213:243|203:209|172:201,1,100,8|0 +256,152,762236,1,8 +336,204,762486,2,0,B|310:211|300:245|313:274|337:282,1,100,0|8 +344,60,763236,2,0,B|256:12|256:12|168:60,1,200,8|8 +169,139,763986,2,0,B|256:186|256:186|344:138,1,200 +256,100,764736,5,8 +256,260,765236,1,8 +120,344,765736,1,8 +256,260,766236,1,8 +392,344,766736,1,8 +446,187,767236,5,8 +385,127,767486,1,0 +368,40,767736,1,8 +296,100,767986,2,0,B|289:126|255:136|226:123|218:99,1,100,0|8 +143,40,768486,1,0 +126,127,768736,1,12 +65,192,768986,1,0 +126,256,769236,5,8 +144,343,769486,1,0 +218,284,769736,2,0,B|226:261|255:248|289:258|296:284,1,100,8|0 +368,343,770236,1,8 +385,256,770486,1,0 +446,192,770736,1,8 +376,38,771236,5,8 +300,84,771486,2,0,B|324:131|286:187|197:171|194:107|218:70,1,200 +135,38,772236,1,8 +100,120,772486,5,0 +40,52,772736,1,8 +57,216,773236,1,8 +181,324,773736,2,0,B|196:375|260:399|323:374|338:309,1,200,8|8 +454,216,774736,1,8 +472,52,775236,5,8 +412,120,775486,1,0 +376,38,775736,1,8 +300,200,776236,2,0,B|324:153|286:97|197:113|194:177|218:214,1,200,8|8 +328,320,777236,2,0,B|278:316|258:376|258:376|238:316|175:320,1,200,8|8 +100,120,778236,5,8 +40,52,778486,1,0 +135,38,778736,1,8 +337,193,779236,2,0,B|314:148|258:122|191:147|175:199,1,200,8|8 +177,284,779986,2,0,B|193:332|254:358|327:334|336:280,1,200 +256,240,780736,5,8 +340,56,781236,1,8 +172,56,781736,1,8 +256,104,781986,1,0 +340,56,782236,1,8 +352,228,782736,2,0,B|287:229|287:229|255:245|255:245|223:229|223:229|151:229,1,200,8|8 +360,352,783736,5,8 +256,384,783986,1,8 +152,352,784236,1,8 +173,256,784486,2,0,B|185:285|256:336|325:292|350:244,1,200,8|0 +256,196,785236,1,0 +309,100,785486,2,0,B|336:52|291:-27|183:-4|172:77|210:125,1,240.000005722046 +112,168,786236,1,0 +128,272,786486,6,0,B|168:232|213:263|213:263|256:289|303:260|303:260|356:231|392:283|392:283,1,279.99999332428 +400,367,787236,1,0 +400,367,787486,2,0,B|354:412|303:377|303:377|254:347|200:380|200:380|140:413|99:354|99:354,1,320 +92,204,788236,5,0 +92,204,788486,2,0,B|135:142|257:127|384:123|441:224|441:224,1,359.999982833863 +442,299,789236,1,0 +442,299,789486,2,0,B|390:365|256:382|119:384|55:280|55:280,1,400 +106,180,790236,5,0 +32,87,790486,1,0 +160,64,790736,1,0 +200,100,790861,1,0 +216,156,790986,1,0 +208,212,791111,1,0 +256,244,791236,1,0 +304,212,791361,1,0 +296,156,791486,1,0 +312,100,791611,1,0 +356,64,791736,1,0 +484,96,791986,5,0 +412,196,792236,1,0 +412,196,792361,1,0 +412,196,792486,1,0 +370,318,792736,2,0,B|340:361|262:401|173:370|137:311,1,259.999995350838,4|0 +316,168,793736,6,0,B|345:220|295:307|176:281|164:192|206:139,1,259.999995350838 +160,68,794486,1,0 +256,8,794736,1,0 +352,68,794986,1,0 +360,240,795486,2,0,B|402:240|402:240|442:240|458:272|458:296|458:296|458:320|442:352|402:352|402:352|354:352|354:352,1,259.999995350838 +256,320,796236,1,0 +152,352,796486,2,0,B|158:352|110:352|110:352|70:352|54:320|54:296|54:296|54:272|70:240|110:240|110:240|152:240,1,259.999995350838 +200,144,797236,6,0,B|256:176|256:176|312:144,1,129.999997675419 +312,48,797736,2,0,B|255:15|255:15|199:47,1,129.999997675419 +368,232,798486,2,0,B|254:297|254:297|142:232,1,259.999995350838 +88,320,799236,6,0,B|200:384,1,129.999997675419 +311,384,799736,2,0,B|424:320,1,129.999997675419 +475,229,800236,1,0 +437,131,800486,1,0 +334,121,800736,2,0,B|354:55|308:3|254:-3|182:5|140:90|200:154|254:187|254:187|312:220|421:280|335:420|211:416|164:335|177:272,1,779.999986052513,4|0 +72,290,802486,5,0 +13,204,802736,1,0 +143,53,803236,2,0,B|173:10|251:-30|340:1|376:60,1,259.999995350838 +370,149,803986,2,0,B|340:192|262:232|173:201|137:142,1,259.999995350838 +192,360,804986,6,0,B|336:360,1,129.999997675419 +324,268,805486,2,0,B|180:268,1,129.999997675419 +128,177,805986,2,0,B|408:177,1,259.999995350838 +206,47,806986,6,0,B|216:16|254:0|298:13|307:47,1,129.999997675419 +304,152,807486,1,0 +256,168,807611,1,0 +208,152,807736,1,0 +128,216,807986,1,0 +160,256,808111,1,0 +208,280,808236,1,0 +256,288,808361,1,0 +304,280,808486,1,0 +352,256,808611,1,0 +384,216,808736,1,4 +464,128,808986,6,0,B|496:256,1,129.999997675419 +320,352,809486,2,0,B|192:384,1,129.999997675419 +16,254,809986,2,0,B|48:128,1,129.999997675419 +197,23,810486,6,0,B|168:76|217:160|334:136|346:48|305:-4,1,259.999995350838 +416,64,811236,1,0 +370,149,811486,2,0,B|340:192|262:232|173:201|137:142,1,259.999995350838 +96,64,812236,1,0 +48,160,812486,2,0,B|96:272|224:320|288:320|416:272|464:160,1,519.999990701676 +512,256,813736,1,0 +512,256,813986,5,0 +256,368,814486,1,0 +0,256,814986,1,0 +0,256,815236,1,0 +72,176,815486,5,0 +104,216,815611,1,0 +110,268,815736,1,0 +208,312,815986,1,0 +256,296,816111,1,0 +304,312,816236,1,0 +402,268,816486,1,0 +408,216,816611,1,0 +440,176,816736,1,4 +360,120,816986,6,0,B|391:110|407:72|394:28|360:19,1,129.999997675419 +256,0,817486,2,0,B|256:128,1,129.999997675419 +152,120,817986,2,0,B|121:110|105:72|118:28|152:19,2,129.999997675419 +215,203,818736,1,0 +300,206,818986,2,0,B|341:261|305:341|181:326|184:237|218:200,1,259.999995350838 +352,352,819986,1,0 +256,384,820236,1,0 +160,352,820486,1,0 +92,159,820986,5,0 +149,69,821236,1,0 +256,36,821486,1,0 +362,69,821736,1,0 +419,159,821986,1,0 +349,362,822486,5,0 +307,353,822611,1,0 +273,328,822736,1,0 +238,302,822861,1,0 +213,260,822986,1,0 +196,226,823111,1,0 +187,183,823236,1,0 +187,140,823361,1,0 +213,106,823486,1,0 +256,89,823611,1,0 +298,106,823736,1,0 +324,140,823861,1,0 +324,183,823986,1,0 +315,226,824111,1,0 +298,260,824236,1,0 +273,302,824361,1,0 +238,328,824486,1,0 +204,353,824611,1,0 +162,362,824736,1,4 +40,240,824986,6,0,B|71:230|87:192|74:148|40:139,1,129.999997675419 +205,34,825486,2,0,B|215:65|253:81|297:68|306:34,1,129.999997675419 +472,144,825986,2,0,B|441:154|425:192|438:236|472:245,1,129.999997675419 +307,350,826486,2,0,B|297:319|259:303|215:316|206:350,1,129.999997675419 +128,56,827236,5,0 +384,56,827736,1,0 +148,348,828236,1,0 +256,296,828486,1,0 +364,348,828736,1,0 +24,104,829236,2,0,B|93:112|135:188|104:277|12:281,1,259.999995350838 +148,36,830236,5,0 +256,88,830486,1,0 +364,36,830736,1,0 +488,280,831236,2,0,B|419:272|377:196|408:107|500:103,1,259.999995350838 +306,327,832236,2,0,B|296:358|258:374|214:361|205:327,1,129.999997675419 +256,192,832736,5,4 +64,48,833236,1,0 +184,280,833736,5,0 +152,152,833986,1,0 +256,80,834236,1,0 +360,152,834486,1,0 +328,280,834736,1,4 +448,48,835236,5,0 +256,192,835736,1,0 +64,336,836236,5,0 +152,240,836486,2,0,B|121:230|105:192|118:148|152:139,1,129.999997675419 +360,240,837236,2,0,B|391:230|407:192|394:148|360:139,1,129.999997675419 +440,336,838236,1,0 +358,236,838486,2,0,B|305:220|265:252|257:292|257:292|249:252|205:218|151:239,1,259.999995350838 +72,336,839236,1,0 +24,216,839486,5,0 +72,96,839736,1,0 +200,32,839986,1,0 +184,80,840111,1,0 +208,128,840236,1,0 +256,144,840361,1,0 +304,128,840486,1,0 +328,80,840611,1,0 +312,32,840736,1,4 +440,96,840986,1,0 +488,216,841236,1,0 +390,300,841486,5,0 +341,342,841611,1,0 +328,280,841736,1,0 +184,280,841986,1,0 +171,342,842111,1,0 +122,300,842236,1,0 +87,178,842486,5,0 +195,106,842736,2,0,B|207:67|256:59|256:59|288:43|272:11|240:11|224:43|256:59|256:59|302:67|321:111,1,259.999995350838 +424,176,843486,1,0 +424,176,843611,1,0 +424,176,843736,1,0 +376,296,843986,1,0 +256,352,844236,1,0 +136,296,844486,1,0 +136,296,844611,1,0 +136,296,844736,1,4 +88,176,844986,1,0 +204,101,845236,2,0,B|214:70|252:54|296:67|305:101,1,129.999997675419 +384,352,845986,5,0 +360,304,846111,1,0 +304,288,846236,1,0 +256,320,846361,1,0 +208,288,846486,1,0 +152,304,846611,1,0 +128,352,846736,1,4 +208,192,846986,5,0 +256,208,847111,1,0 +304,192,847236,1,0 +400,128,847486,1,0 +416,80,847611,1,0 +384,32,847736,1,0 +328,24,847861,1,0 +288,56,847986,1,0 +256,88,848111,1,0 +224,56,848236,1,0 +184,24,848361,1,0 +128,32,848486,1,0 +96,80,848611,1,0 +112,128,848736,1,0 +152,248,848986,5,0 +152,248,849111,1,0 +152,248,849236,1,0 +144,376,849486,1,0 +144,376,849611,1,0 +144,376,849736,1,0 +256,320,849986,1,0 +256,320,850111,1,0 +256,320,850236,1,0 +368,376,850486,1,0 +368,376,850611,1,0 +368,376,850736,1,0 +360,248,850986,1,0 +360,248,851111,1,0 +360,248,851236,1,0 +256,192,851486,5,0 +256,192,851611,1,0 +256,192,851736,1,4 +256,320,851986,1,4 +95,186,852486,6,0,B|159:153|207:57|191:25|127:-7|95:25|63:89|223:153|255:81|255:81|287:25|255:-7|223:25|255:81|255:81|285:136|415:121|383:89|479:-39|301:-25|223:89|431:196|431:196,1,909.999983727932,4|2 +312,280,854486,2,0,B|298:259|259:239|214:254|196:284,1,129.999997675419,0|2 +256,381,854986,1,0 +370,173,855486,2,0,B|340:130|262:90|173:121|137:180,1,259.999995350838,2|0 +208,28,856236,1,2 +304,28,856486,1,0 +256,192,856611,12,0,858236 +256,192,859486,12,4,860736 +191,69,860986,6,0,B|204:43|254:19|302:36|324:74,1,149.999995529652,0|0 +448,172,861486,2,0,B|384:212|384:212|368:304,1,149.999995529652 +256,376,861986,1,0 +140,285,862236,2,0,B|128:212|128:212|64:172,1,149.999995529652 +169,47,862736,2,0,B|216:69|216:133|216:133|256:153|256:153|296:133|296:133|292:69|347:45,1,299.999991059304 +301,358,863736,1,0 +211,358,863986,2,0,B|157:296|201:201|345:218|341:321|296:365,1,299.999991059304 +73,188,864986,5,0 +138,89,865236,1,0 +256,48,865486,1,0 +373,89,865736,1,0 +438,188,865986,1,0 +178,345,866486,2,0,B|212:367|256:331|256:331|284:311|284:279|256:259|228:279|228:311|256:331|256:331|296:367|336:343,1,299.999991059304 +321,225,867236,2,0,B|308:199|258:175|210:192|188:230,1,149.999995529652 +96,148,867736,5,0 +128,108,867861,1,0 +164,80,867986,1,0 +212,64,868111,1,0 +256,56,868236,1,0 +300,64,868361,1,0 +348,80,868486,1,0 +384,108,868611,1,0 +416,148,868736,1,4 +256,224,868986,5,0 +208,364,869236,1,0 +328,276,869486,1,0 +184,276,869736,1,0 +304,364,869986,1,0 +256,224,870236,5,0 +128,112,870486,2,0,B|160:61|249:17|350:49|391:118,1,299.999991059304 +256,200,871236,1,0 +126,291,871486,2,0,B|158:341|247:386|348:354|389:284,1,299.999991059304 +256,200,872236,1,0 +113,156,872486,6,0,B|35:111|52:28|108:-8|156:-7|216:29|209:95|209:95|224:62|256:174|288:62|304:94|304:94|292:32|356:-16|412:-6|465:38|473:120|387:160,1,749.999977648259,0|0 +372,298,873986,2,0,B|311:279|266:316|256:361|256:361|247:316|197:277|136:301,1,299.999991059304 +256,20,874986,5,0 +128,116,875236,1,0 +184,260,875486,1,0 +328,260,875736,1,0 +384,116,875986,1,0 +256,156,876236,5,0 +256,156,876361,1,0 +256,156,876486,1,0 +256,156,876611,1,0 +256,156,876736,1,4 +256,308,876986,5,0 +400,356,877236,1,0 +488,236,877486,1,0 +400,116,877736,1,0 +256,156,877986,1,0 +256,308,878236,1,0 +112,364,878486,1,0 +24,236,878736,1,0 +112,116,878986,1,0 +408,64,879486,6,0,B|459:96|503:185|471:286|402:327,1,299.999991059304 +256,192,880236,1,0 +104,64,880486,2,0,B|53:96|9:185|41:286|110:327,1,299.999991059304 +322,237,881236,2,0,B|309:263|259:287|211:270|189:232,1,149.999995529652 +320,147,881736,2,0,B|307:121|257:97|209:114|187:152,1,149.999995529652 +388,304,882486,6,0,B|356:355|267:399|166:367|125:298,1,299.999991059304 +256,192,883236,1,0 +184,60,883486,1,0 +256,32,883611,1,0 +328,60,883736,1,0 +396,196,883986,1,0 +341,251,884111,1,0 +326,324,884236,1,0 +256,360,884361,1,0 +185,324,884486,1,0 +170,251,884611,1,0 +115,196,884736,1,4 +256,192,884861,12,0,886236 +128,128,933524,5,2 +214,104,933953,1,0 +152,42,934381,1,2 +65,65,934810,1,0 +42,152,935238,1,2 +104,214,935667,1,0 +190,190,936095,1,2 +212,228,936310,1,0 +256,244,936524,1,0 +300,228,936738,1,0 +323,189,936952,5,2 +408,170,937381,1,0 +470,232,937809,1,2 +447,319,938238,1,0 +360,342,938666,1,2 +298,280,939095,1,0 +323,189,939523,1,2 +384,256,939952,1,0 +160,112,940380,5,2 +212,38,940809,1,0 +300,38,941237,1,2 +352,112,941666,1,0 +292,181,942094,2,0,B|272:153|230:153|219:184|219:184,1,84.9999964535238,2|0 +256,260,942951,1,2 +212,288,943165,1,0 +228,340,943380,1,0 +280,340,943594,1,0 +300,292,943808,1,2 +396,256,944236,6,0,B|468:192,1,84.9999964535238,0|2 +416,32,945093,2,0,B|376:108,1,84.9999964535238,0|2 +256,48,945950,1,0 +135,107,946379,2,0,B|96:32,1,84.9999964535238,2|0 +52,199,947236,2,0,B|116:256,1,84.9999964535238,2|0 +292,328,948093,6,0,B|272:356|230:356|219:325|219:325,1,84.9999964535238,2|0 +324,208,948950,2,0,B|352:124,1,84.9999964535238,2|0 +188,208,949807,2,0,B|160:124,1,84.9999964535238,2|0 +256,64,950449,1,0 +256,64,950664,5,2 +400,160,951092,1,0 +340,324,951521,1,2 +172,324,951949,1,0 +112,160,952378,1,2 +256,64,952806,1,0 +256,200,953235,5,2 +188,328,953663,1,0 +256,356,953877,1,0 +324,328,954092,1,2 +428,228,954520,1,0 +392,92,954948,1,2 +256,40,955377,1,0 +120,92,955805,1,2 +84,228,956234,1,0 +220,208,956662,6,0,B|240:236|282:236|293:205|293:205,1,84.9999964535238,2|0 +292,352,957519,2,0,B|272:324|230:324|219:355|219:355,1,84.9999964535238,2|0 +124,244,958376,1,2 +256,140,958805,1,0 +392,244,959233,1,2 +412,80,959662,1,0 +256,264,960090,1,2 +100,80,960519,1,0 +100,80,960733,1,0 +100,80,960947,5,2 +256,348,961376,1,0 +412,80,961804,1,2 +100,304,962233,5,0 +256,36,962661,1,2 +412,304,963090,1,0 +191,224,963518,1,2 +256,276,963732,1,0 +320,224,963947,1,0 +294,150,964161,1,0 +217,150,964375,1,2 +256,360,964804,5,0 +88,256,965232,1,2 +160,64,965660,1,0 +352,64,966089,1,2 +424,256,966517,1,0 +256,192,966946,1,2 +256,192,967160,1,0 +256,192,967374,1,0 +256,192,967589,1,0 +256,192,967803,5,2 +220,352,968231,2,0,B|240:380|282:380|293:349|293:349,1,84.9999964535238,0|2 +364,197,969088,1,0 +396,120,969303,1,0 +148,197,969731,1,0 +116,120,969945,1,0 +256,32,970374,5,2 +256,200,970802,1,0 +256,368,971231,1,2 +196,300,971445,2,0,B|224:300|224:300|256:284|256:284|288:300|288:300|320:300,1,127.499994680286,0|2 +439,128,972516,2,0,B|452:96|439:66|439:66,1,50 +352,57,972945,6,0,B|398:112|337:186|274:153|255:116|255:116|237:84|198:18|65:115|168:182|168:182,1,400,2|2 +120,348,975087,5,0 +178,278,975301,2,0,B|193:324|256:356|318:324|334:278,1,200 +392,348,976372,1,2 +355,173,976801,2,0,B|335:114|257:75|179:114|160:173,1,250 +95,106,978086,5,2 +256,24,978515,1,0 +256,24,978729,1,0 +256,328,979372,1,2 +336,168,979800,2,0,B|312:128|256:112|256:112|200:128|176:168,1,200,0|0 +417,106,981300,5,0 +417,106,981514,1,2 +256,24,981943,1,0 +295,191,982371,2,0,B|282:170|254:162|254:162|226:170|214:191,1,100,2|0 +216,280,983014,2,0,B|232:280|232:280|248:272|248:272|256:280|256:280|256:264|256:264|264:272|264:272|280:280|280:280|296:280,1,100 +344,351,983657,2,0,B|320:383|280:383|256:359|256:359|232:383|192:383|168:351,1,200,2|0 +80,328,984728,5,0 +144,264,984942,1,2 +56,240,985156,1,0 +256,56,985799,1,0 +368,264,986227,1,0 +456,240,986442,1,0 +432,328,986656,1,2 +56,264,987513,6,0,B|102:249|134:186|102:124|56:108,1,200,0|2 +256,92,988798,1,0 +256,92,989013,2,0,B|256:292,1,200 +256,292,990084,1,2 +456,264,990512,2,0,B|410:249|378:186|410:124|456:108,1,200 +256,36,991798,1,2 +196,108,992012,2,0,B|224:108|224:108|256:124|256:124|288:108|288:108|320:108,1,127.499994680286 +346,348,993083,5,2 +256,312,993297,1,0 +168,349,993512,2,0,B|111:265|160:184|191:152|261:139|319:160|356:186|407:266|341:356,1,500 +217,61,996939,6,0,B|224:83|256:100|287:83|295:61,1,100,2|0 +168,192,997796,1,2 +335,302,998225,2,0,B|320:348|257:380|195:348|179:302,1,200,0|2 +344,192,999510,1,0 +188,56,999939,5,2 +256,100,1000153,1,0 +324,56,1000367,1,0 +424,200,1000796,2,0,B|464:228|464:228|480:284,1,100,0|2 +348,360,1001653,1,0 +220,204,1002081,2,0,B|197:237|216:270|229:282|257:288|280:279|295:269|315:237|289:201,1,200,2|0 +164,360,1003367,5,2 +88,200,1003795,2,0,B|48:228|48:228|32:284,1,100 +144,60,1004652,1,2 +194,232,1005081,2,0,B|208:276|208:276|256:300|256:300|304:276|304:276|320:228,1,200 +369,59,1006366,1,2 +448,224,1006795,6,0,B|419:326,1,100,0|2 +256,240,1007651,2,0,B|256:136,1,100,0|2 +64,224,1008508,2,0,B|93:326,1,100,0|2 +256,48,1009794,5,2 +400,152,1010222,1,0 +348,328,1010651,1,2 +164,328,1011079,1,0 +112,152,1011508,1,2 +256,48,1011936,1,0 +256,196,1012793,5,2 +256,348,1013864,5,0 +256,348,1014079,1,2 +256,52,1014507,1,0 +45,192,1015364,2,0,B|61:143|110:127|175:143|142:192|158:256|239:240|256:192|256:192|272:240|353:256|369:192|336:143|401:127|450:143|466:192,1,549.999983608723,2|0 +179,48,1022649,6,0,B|194:94|257:126|319:94|335:48,1,200,8|0 +340,239,1023506,2,0,B|301:254|270:239|255:208|255:208|240:239|209:254|171:239,1,200,8|0 +172,349,1024148,2,0,B|210:333|241:349|256:379|256:379|271:349|302:333|340:349,1,200,0|0 +432,296,1024791,1,0 +456,64,1025220,1,8 +256,152,1025648,5,0 +64,64,1026077,1,8 +112,152,1026291,1,0 +174,64,1026506,2,0,B|201:28|256:10|256:10|310:28|337:64,1,200,0|8 +424,256,1027363,5,0 +360,336,1027577,1,0 +256,368,1027791,1,8 +152,336,1028006,1,0 +88,256,1028220,1,0 +256,40,1028648,1,8 +424,256,1029077,1,0 +408,56,1029506,5,8 +345,355,1029934,1,0 +282,199,1030148,2,0,B|309:172|361:186|361:251|309:263|309:263|270:277|256:315|256:315|243:277|204:263|204:263|152:251|152:186|204:172|230:199,1,439.999986886979 +167,355,1031220,1,8 +73,146,1031648,2,0,B|75:82|134:16|220:36|257:81|257:81|289:32|366:25|442:61|436:157,1,500 +400,256,1032934,1,8 +221,364,1033363,2,0,B|198:331|217:298|230:286|258:280|281:289|296:299|316:331|290:367,1,200,0|8 +112,256,1034220,5,0 +96,144,1034434,1,0 +200,184,1034648,1,8 +312,184,1034863,1,0 +416,144,1035077,1,0 +400,256,1035291,1,0 +333,336,1035506,6,0,B|318:290|255:258|193:290|177:336,1,200,8|0 +96,256,1036148,1,0 +64,152,1036363,2,8,B|160:120|160:120|192:24,1,200,8|0 +320,26,1037220,2,0,B|352:120|352:120|448:152,1,200,8|0 +336,240,1037863,2,0,B|288:240|288:240|256:200|256:200|224:240|224:240|176:240,1,200 +256,320,1038506,1,0 +64,192,1038934,5,8 +256,48,1039363,1,0 +304,184,1039577,1,0 +180,96,1039791,1,8 +332,96,1040006,1,0 +208,184,1040220,1,0 +448,192,1040648,1,8 +216,336,1041077,2,0,B|222:356|256:370|290:356|297:336,1,100 +333,189,1041506,2,0,B|370:117|336:59|311:34|253:28|214:34|176:54|137:117|184:193,2,400,8|8|8 +348,360,1043648,5,0 +256,320,1043863,1,0 +164,360,1044077,2,0,B|118:376|53:357|33:292|50:246,1,200,8|0 +21,137,1044720,1,0 +131,108,1044934,1,8 +160,217,1045148,1,0 +160,216,1045363,2,0,B|256:172|256:260|352:216,1,200,0|8 +460,28,1046220,1,0 +460,28,1046648,6,0,B|480:76|460:124,1,100,8|0 +348,84,1047077,2,0,B|280:176|348:268,1,200,0|8 +356,368,1047720,1,0 +256,336,1047934,1,0 +156,368,1048148,1,0 +163,268,1048363,2,0,B|231:175|163:83,1,200,8|0 +4,192,1049220,5,8 +256,352,1049648,1,0 +256,352,1049863,1,0 +256,352,1050077,6,0,B|352:328,1,100,4|0 +476,252,1050506,2,0,B|380:228,1,100,2|0 +256,148,1050934,2,0,B|352:124,1,100,2|0 +476,48,1051363,2,0,B|380:24,1,100,2|0 +256,48,1051791,6,0,B|160:92|160:4|64:48,1,200,0|0 +100,144,1052434,1,0 +100,144,1052648,2,0,B|120:192|100:240,1,100 +36,320,1053077,2,0,B|129:388|221:320,1,200,0|4 +256,224,1053720,1,0 +291,320,1053934,2,0,B|383:388|476:320,1,200 +512,116,1054791,6,0,B|416:144,1,100 +328,100,1055220,2,0,B|260:192|328:284,1,200,8|0 +312,384,1055863,1,0 +228,332,1056077,2,0,B|200:284|192:240,1,100,8|0 +191,144,1056506,2,0,B|200:100|228:52,1,100 +256,192,1056934,6,0,B|160:236|160:148|64:192,1,200,8|0 +256,192,1057791,2,0,B|352:148|352:236|448:192,1,200,8|0 +492,104,1058434,5,0 +396,112,1058649,2,0,B|354:80|348:28,1,100,8|0 +256,92,1059077,2,0,B|256:192,1,100,0|0 +115,112,1059506,2,0,B|157:80|164:27,1,100,8|0 +20,104,1059934,6,0,B|-48:196|20:288,1,200,0|8 +72,372,1060577,1,0 +160,324,1060791,2,0,B|256:276|352:324,1,200,0|8 +488,192,1061649,6,0,B|508:96,1,100 +372,152,1062077,2,0,B|352:56,1,100,8|0 +256,164,1062506,2,0,B|210:148|145:167|125:232|142:278,1,200,0|8 +370,277,1063363,2,0,B|387:232|367:167|302:148|256:164,1,200,0|8 +136,128,1064006,5,0 +208,76,1064220,2,0,B|256:96|304:76,1,100 +376,128,1064649,2,0,B|476:144,1,100,8|0 +512,272,1065077,6,0,B|413:256,1,100 +348,332,1065506,2,0,B|256:400|164:332,1,200,8|0 +164,52,1066363,2,0,B|256:-16|348:52,1,200,8|0 +356,152,1067006,1,0 +256,192,1067220,1,4 +156,152,1067434,1,0 +160,280,1067649,6,0,B|256:324|256:236|352:280,2,200,0|8|0 +68,320,1068720,1,0 +156,368,1068934,6,0,B|204:388|252:368,1,100,8|0 +356,192,1069363,2,0,B|308:172|260:192,1,100 +258,192,1069791,1,4 +100,276,1070220,1,0 +28,44,1070649,5,4 +120,88,1070863,1,0 +220,84,1071077,2,0,B|320:76,1,100 +412,32,1071506,2,0,B|442:133|378:220,1,200 +424,308,1072149,1,0 +328,340,1072363,1,0 +244,288,1072577,2,0,B|200:316|184:368,1,100 +88,340,1073006,1,0 +120,244,1073220,2,0,B|29:183|23:77,1,200 +112,28,1073863,1,0 +200,80,1074077,6,0,B|202:131|167:170,1,100 +116,260,1074506,2,0,B|216:280,1,100 +297,279,1074934,2,0,B|396:260,1,100 +345,171,1075363,2,0,B|309:131|312:80,1,100 +404,29,1075791,5,0 +481,103,1076006,1,0 +486,209,1076220,1,0 +445,308,1076434,1,0 +348,353,1076649,2,0,B|256:285|164:353,1,200,0|0 +70,309,1077291,1,0 +52,220,1077506,6,0,B|12:191|1:121|51:72|100:71,1,200,8|2 +186,99,1078149,2,0,B|225:127|236:197|186:246|137:247,1,200,0|0 +204,324,1078791,1,2 +304,324,1079006,1,0 +374,247,1079220,2,0,B|325:246|275:197|286:127|326:99,1,200,8|2 +411,71,1079863,2,0,B|460:72|510:121|499:191|460:220,1,200,0|0 +452,320,1080506,1,2 +360,356,1080720,1,0 +300,276,1080934,1,8 +368,204,1081149,1,0 +375,94,1081363,6,0,B|345:34|301:49|256:20|183:94|183:167|256:212|330:167|330:94|256:20|212:49|168:34|138:94,1,439.999986886979,0|2 +144,204,1082434,1,0 +212,276,1082649,1,8 +152,356,1082863,1,0 +60,320,1083077,1,2 +256,368,1083506,5,8 +344,184,1083934,1,0 +256,136,1084149,1,0 +168,184,1084363,1,8 +334,320,1084791,6,0,B|319:274|256:242|194:274|178:320,1,200,0|8 +88,192,1085434,1,0 +178,64,1085649,2,0,B|193:110|256:142|318:110|334:64,1,200,0|8 +424,192,1086291,1,0 +256,328,1086506,5,0 +96,80,1086934,1,8 +416,80,1087363,1,0 +256,194,1087577,1,0 +126,330,1087791,2,0,B|66:314|68:260|85:226|136:209|170:243|170:243|136:174|170:123|187:89|254:60|324:89|341:123|375:174|341:243|341:243|385:204|452:231|448:316|387:332,1,800,8|8 +432,144,1089720,1,8 +256,192,1089934,1,8 +80,144,1090149,1,0 +256,304,1090363,5,8 +200,120,1090577,1,8 +344,232,1090791,1,0 +168,232,1091006,1,8 +312,120,1091220,1,4 +114,294,1091649,6,0,B|68:279|36:216|68:154|114:138,1,200,2|8 +160,48,1092291,1,0 +256,80,1092506,1,2 +352,48,1092720,1,0 +398,138,1092934,2,0,B|444:154|476:216|444:279|398:294,1,200,8|0 +345,359,1093577,2,0,B|276:403|203:333|201:270|252:276|303:269|300:333|221:403|159:358,1,329.999990165234,2|8 +96,288,1094434,1,0 +176,224,1094649,2,0,B|194:180|256:154|319:178|340:230,1,200,2|0 +416,288,1095291,1,0 +337,343,1095506,6,0,B|319:387|257:413|194:389|173:337,1,200,8|2 +256,292,1096149,1,0 +205,208,1096363,1,8 +306,208,1096577,1,0 +376,130,1096791,2,0,B|380:64|353:-4|258:-45|163:0|124:60|137:130,1,400,2|2 +64,200,1097863,5,0 +64,200,1098077,1,8 +216,360,1098506,2,0,B|200:332|211:298|231:286|256:274|280:285|300:295|321:325|297:370,1,200,0|8 +448,200,1099363,1,0 +297,32,1099791,2,0,B|313:60|302:94|282:106|257:118|233:107|213:97|192:67|216:22,2,200,2|0|8 +156,200,1101077,5,2 +179,297,1101291,1,0 +272,322,1101506,1,10 +341,249,1101720,1,0 +317,152,1101934,1,0 +220,128,1102149,1,0 +146,223,1102363,1,8 +193,321,1102577,1,0 +298,327,1102791,1,0 +355,233,1103006,1,0 +308,134,1103220,5,8 +203,128,1103434,1,8 +149,253,1103649,1,8 +227,345,1103863,1,0 +342,321,1104077,1,8 +376,205,1104291,1,0 +297,113,1104506,1,8 +183,137,1104720,1,0 +147,263,1104934,5,12 +327,301,1105363,1,0 +365,121,1105791,1,8 +185,83,1106220,6,0,B|144:55|77:57|40:114|45:163,1,200,0|8 +76,260,1106863,1,0 +160,192,1107077,2,0,B|256:236|256:148|352:192,1,200,0|8 +436,124,1107720,5,0 +466,221,1107934,2,0,B|471:269|434:326|367:328|327:301,1,200,0|8 +256,232,1108577,1,0 +172,176,1108791,6,0,B|152:128|172:80,1,100 +340,208,1109220,2,0,B|360:256|340:304,1,100,8|0 +163,360,1109649,6,0,B|118:376|53:357|33:292|49:246,1,200,0|8 +16,152,1110291,1,0 +108,116,1110506,2,0,B|84:20,1,100 +224,76,1110934,2,0,B|248:173,1,100,8|0 +336,128,1111363,6,0,B|440:173|428:287,1,200,0|8 +84,287,1112220,2,0,B|71:173|176:128,1,200,0|8 +352,348,1113077,6,0,B|256:304|256:392|160:348,1,200,0|8 +112,276,1113720,1,0 +208,260,1113934,2,0,B|188:212|208:164,1,100 +304,164,1114363,2,0,B|324:212|304:260,1,100,8|0 +128,192,1114791,2,0,B|132:124|160:60|256:28|352:60|380:124|384:192,1,400,0|0 +332,328,1116077,1,8 +180,56,1116506,1,0 +372,12,1116934,6,0,B|440:104|372:196,1,200,8|0 +140,372,1117791,2,0,B|72:280|140:188,1,200,8|0 +184,96,1118434,1,0 +300,108,1118649,6,0,B|300:192|212:192|212:280,2,200,4|0|8 +256,20,1119720,1,0 +212,108,1119934,2,0,B|212:192|300:192|300:280,1,200,0|8 +256,364,1120577,1,0 +163,360,1120791,6,0,B|118:376|53:357|33:292|49:246,1,200,0|8 +348,360,1121649,2,0,B|394:376|459:357|479:292|462:246,1,200,0|4 +452,148,1122291,5,0 +356,124,1122506,2,0,B|311:153|308:207,1,100 +352,280,1122934,2,0,B|304:304|256:280|256:280|208:304|160:280,1,200,8|0 +204,207,1123577,2,0,B|200:153|156:124,1,100,0|8 +60,148,1124006,1,8 +60,148,1124220,6,0,B|72:48,1,100 +160,100,1124649,2,0,B|208:124|256:100|256:100|304:76|352:100,1,200,8|0 +440,48,1125291,1,0 +440,48,1125506,6,0,B|452:148,1,100,8|0 +376,268,1125934,2,0,B|364:168,1,100,8|0 +456,304,1126363,6,0,B|436:348|376:380|316:348|296:304,1,200,8|0 +256,192,1127006,1,0 +147,168,1127220,2,0,B|136:268,1,100,8|8 +55,303,1127649,2,0,B|76:348|136:380|196:348|216:303,2,200,8|4|0 +64,220,1128720,1,0 +111,151,1128934,6,0,B|88:80,1,74.9999977648259 +208,32,1129363,2,0,B|224:68|208:104,1,74.9999977648259 +304,156,1129791,2,0,B|288:120|304:84,1,74.9999977648259 +424,80,1130220,2,0,B|400:151,1,74.9999977648259 +482,201,1130649,5,0 +458,275,1130863,1,0 +397,322,1131077,1,0 +320,325,1131291,1,0 +256,284,1131506,1,0 +192,325,1131720,1,0 +115,322,1131934,1,0 +54,275,1132149,1,0 +30,201,1132363,1,0 +256,192,1132470,12,2,1135791 +80,56,1136220,5,0 +212,252,1136649,2,0,B|196:224|207:190|227:178|252:166|276:177|296:187|317:217|293:262,1,200,2|0 +432,56,1137505,1,2 +369,247,1137949,2,0,B|379:196|354:120|287:88|223:88|161:122|127:184|140:247,1,400,0|2 +68,288,1139060,1,0 +48,200,1139282,5,2 +256,224,1139743,1,0 +464,200,1140205,1,2 +346,34,1140776,2,0,B|307:69|273:52|256:35|256:35|238:52|204:69|164:31,1,200,0|2 +256,320,1153040,5,8 +256,252,1153343,1,8 +256,240,1153494,1,8 +256,228,1153646,1,8 +256,216,1153797,1,0 +256,204,1153949,1,4 +380,136,1154252,6,0,B|412:196,1,66.6666666666667,0|8 +456,124,1154555,2,0,B|423:62,1,66.6666666666667,0|0 +324,64,1154858,2,2,B|256:92|188:64,1,133.333333333333,2|0 +88,62,1155312,2,0,B|56:124,1,66.6666666666667,8|0 +99,197,1155616,2,0,B|132:136,1,66.6666666666667,0|0 +256,228,1156070,6,0,B|256:296,2,66.6666666666667,0|8|0 +256,140,1156525,1,0 +196,80,1156676,2,2,B|256:53|256:53|316:80,1,133.333333333333,2|0 +388,140,1157131,2,0,B|456:156,2,66.6666666666667,8|0|0 +316,201,1157585,6,0,B|255:227|255:227|195:201,1,133.333333333333,4|0 +124,140,1158040,2,0,B|56:156,1,66.6666666666667,8|0 +44,336,1158494,2,2,B|184:304,1,133.333333333333,2|0 +256,256,1158949,2,0,B|256:324,1,66.6666666666667,8|0 +468,336,1159403,6,0,B|328:304,1,133.333333333333,4|0 +324,212,1159858,2,0,B|360:152,1,66.6666666666667,8|0 +256,140,1160161,1,0 +188,212,1160312,2,0,B|152:152,1,66.6666666666667,2|0 +204,52,1160616,5,8 +228,40,1160767,1,8 +256,36,1160919,1,8 +288,40,1161070,1,0 +316,52,1161222,1,4 +468,156,1161525,6,0,B|468:224,1,66.6666666666667,0|8 +468,316,1161828,1,0 +380,344,1161979,1,0 +288,352,1162131,2,0,B|288:284|288:284|336:228,1,133.333333333333,2|0 +248,192,1162585,6,0,B|200:248,1,66.6666666666667,8|0 +140,312,1162888,1,0 +80,244,1163040,2,0,B|176:140,1,133.333333333333,0|0 +256,100,1163494,2,0,B|256:30,2,66.6666666666667,8|0|0 +337,141,1163949,2,0,B|432:244,1,133.333333333333,2|0 +339,268,1164403,2,0,B|305:222|256:203|206:222|172:268,1,200,8|4 +172,93,1165161,5,0 +171,92,1165312,2,0,B|205:137|256:156|305:137|339:92,1,200,8|2 +358,254,1166070,2,0,B|332:320,1,66.6666666666667,0|8 +256,360,1166373,1,0 +179,319,1166525,2,0,B|154:254,1,66.6666666666667,0|4 +316,112,1166979,6,0,B|304:44,2,66.6666666666667,8|8|8 +256,180,1167434,1,0 +196,112,1167585,2,8,B|208:44,2,66.6666666666667,8|8|0 +152,224,1168040,6,0,B|216:252,1,66.6666666666667,8|8 +360,224,1168343,2,0,B|296:252,1,66.6666666666667,0|4 +256,32,1168949,5,8 +420,112,1169252,1,0 +494,80,1169403,2,2,B|462:12|375:0|319:68|343:144|343:144|356:188|356:188|379:259|323:287,1,400,2|0 +144,268,1170616,2,0,B|136:232|144:200,1,66.6666666666667,0|8 +172,120,1170919,1,0 +224,56,1171070,2,0,B|256:32|288:56,1,66.6666666666667,0|2 +340,120,1171373,1,0 +367,199,1171525,2,0,B|376:232|368:268,1,66.6666666666667,0|8 +187,287,1172131,6,0,B|132:260|154:188|154:188|168:144|168:144|192:68|136:0|48:12|16:80,1,400,4|2 +24,164,1173191,1,0 +92,112,1173343,1,0 +164,68,1173494,2,0,B|196:48|232:60|259:88|259:88|283:112,1,133.333333333333,8|0 +328,184,1173949,1,2 +256,224,1174100,1,0 +184,184,1174252,1,0 +227,112,1174403,2,0,B|252:88|252:88|280:60|316:48|348:68,1,133.333333333333,8|0 +452,192,1174858,5,4 +256,356,1175161,1,2 +60,192,1175464,1,2 +256,28,1175767,1,4 +256,196,1176070,6,0,B|292:136,1,66.6666666666667,0|8 +256,196,1176373,2,0,B|220:136,1,66.6666666666667 +174,68,1176676,2,0,B|99:68|51:153|99:239|174:239,1,266.666666666667,4|2 +338,67,1177585,2,0,B|412:67|461:152|412:239|338:239,1,266.666666666667,4|2 +192,152,1178494,2,0,B|228:184|256:152|284:120|320:152,2,133.333333333333,4|2|2 +80,281,1179403,6,0,B|136:352|256:396|376:352|441:272,1,400,4|2 +448,188,1180464,1,0 +368,164,1180616,1,0 +356,248,1180767,2,0,B|332:272|292:276,1,66.6666666666667,8|0 +156,248,1181070,6,0,B|180:272|218:275,1,66.6666666666667,8|4 +212,192,1181373,2,0,B|188:168|150:165,1,66.6666666666667,0|0 +68,148,1181676,1,8 +84,64,1181828,1,8 +168,80,1181979,1,8 +256,106,1182131,6,0,B|256:36,1,66.6666666666667 +344,80,1182434,1,0 +428,64,1182585,1,8 +444,148,1182737,1,8 +362,164,1182888,2,0,B|324:168|300:192,1,66.6666666666667,0|4 +68,292,1183494,5,8 +40,212,1183646,2,0,B|84:192|140:220|148:268,2,133.333333333333,0|2|0 +32,128,1184403,1,8 +116,136,1184555,2,0,B|188:152|216:228,1,133.333333333333,0|4 +395,136,1185161,6,0,B|324:152|296:225,1,133.333333333333,0|0 +408,352,1185767,2,0,B|479:336|507:262,1,133.333333333333,2|0 +396,136,1186373,1,0 +104,352,1186676,6,0,B|32:336|4:262,1,133.333333333333,4|0 +80,220,1187131,1,8 +164,204,1187282,2,0,B|148:136,1,66.6666666666667 +192,69,1187585,2,0,B|256:87|256:87|319:69,1,133.333333333333,2|0 +364,135,1188040,2,0,B|348:204,1,66.6666666666667,8|0 +256,344,1188494,5,4 +140,120,1188797,1,2 +332,284,1189100,1,2 +256,44,1189403,1,4 +180,284,1189706,1,2 +372,120,1190009,1,2 +256,344,1190312,1,4 +488,244,1190767,6,0,B|436:40,1,200,8|2 +300,140,1191525,2,0,B|364:164,1,66.6666666666667,0|8 +212,140,1191979,2,0,B|148:164,1,66.6666666666667,8|2 +75,40,1192585,2,0,B|24:244,1,200,8|2 +204,268,1193343,5,0 +228,280,1193494,1,8 +256,284,1193646,1,8 +288,280,1193797,1,0 +316,268,1193949,1,4 +80,203,1194403,6,0,B|141:127|256:85|370:127|431:203,1,400,8|10 +212,312,1195767,2,0,B|180:252,1,66.6666666666667 +300,312,1196222,2,0,B|332:248,1,66.6666666666667,8|0 +212,144,1196676,5,8 +208,108,1196828,1,0 +224,76,1196979,1,0 +256,64,1197131,1,8 +288,76,1197282,1,0 +304,108,1197434,1,0 +300,144,1197585,1,12 +392,264,1197888,5,2 +392,264,1198040,1,2 +256,344,1198343,1,2 +256,344,1198494,1,0 +120,264,1198797,1,2 +176,104,1199100,1,2 +332,104,1199403,1,0 +256,216,1199706,5,0 +256,200,1199858,1,8 +256,184,1200009,1,0 +256,168,1200161,1,0 +256,152,1200312,1,2 +304,284,1200616,1,0 +284,304,1200767,1,8 +256,312,1200919,1,0 +228,304,1201070,1,0 +208,284,1201222,1,2 +84,192,1201525,6,0,B|52:280|52:280,1,66.6666666666667,0|8 +32,108,1201979,2,0,B|64:32|64:32,1,66.6666666666667,0|2 +201,101,1202434,2,0,B|219:71|252:59|293:64|315:108,1,133.333333333333 +313,250,1203040,2,0,B|296:278|260:291|216:285|192:238,1,133.333333333333,2|0 +155,317,1203494,6,0,B|182:349|233:356,1,66.6666666666667,8|0 +298,353,1203797,2,0,B|332:345|357:317,1,66.6666666666667,0|2 +256,188,1204252,1,0 +256,168,1204403,1,8 +256,148,1204555,1,0 +256,128,1204706,1,0 +256,104,1204858,1,4 +428,192,1205161,6,0,B|460:280|460:280,1,66.6666666666667,0|8 +480,108,1205616,2,0,B|448:32|448:32,1,66.6666666666667,0|2 +311,57,1206070,2,0,B|292:30|265:30|254:19|254:19|246:30|220:30|203:55,1,133.333333333333 +121,176,1206676,2,0,B|130:226|215:249|256:199|256:199|288:247|388:235|392:162,1,333.333333333333,2|0 +464,232,1207585,1,2 +337,345,1207888,5,0 +294,354,1208040,1,8 +256,336,1208191,1,0 +217,354,1208343,1,0 +178,345,1208494,1,2 +48,232,1208797,1,0 +48,232,1208949,1,8 +224,165,1209252,6,0,B|256:176|256:176|290:164,1,66.6666666666667,0|2 +197,56,1209706,2,0,B|255:28|255:28|317:55,2,133.333333333333,0|0|2 +116,184,1210616,1,0 +147,197,1210767,1,8 +169,224,1210919,1,0 +181,256,1211070,1,0 +180,292,1211222,1,2 +332,292,1211525,1,8 +331,256,1211676,1,8 +343,224,1211828,1,8 +365,197,1211979,1,0 +396,184,1212131,1,4 +336,44,1212434,6,0,B|336:77|336:77|314:106,1,66.6666666666667,0|8 +176,44,1212888,2,0,B|175:77|175:77|197:106,1,66.6666666666667,0|2 +200,244,1213343,2,0,B|217:272|253:285|297:279|321:232,1,133.333333333333 +99,267,1213949,2,0,B|131:363|263:412|385:368|423:243,1,400,2|2 +180,145,1215312,6,0,B|195:97|255:86|255:86|311:94|333:148,1,200,8|4 +124,44,1216222,5,8 +256,168,1216525,1,0 +256,168,1216676,1,2 +388,44,1216979,1,0 +435,226,1217282,1,2 +353,350,1217585,2,0,B|284:340|117:251|74:123|147:-32|400:-9|466:163|336:289|227:339|160:351,1,800,2|4 +77,224,1219706,1,0 +77,224,1219858,5,8 +120,48,1220161,1,2 +120,48,1220312,1,2 +256,120,1220616,1,0 +392,48,1220919,1,0 +400,200,1221222,2,0,B|382:282|318:334|255:334|166:330|116:273|107:181|107:181,2,400,2|2|4 +256,40,1223494,5,8 +256,184,1223797,1,2 +256,184,1223949,1,2 +319,332,1224252,2,0,B|300:360|264:373|220:367|196:320,1,133.333333333333,0|0 +96,200,1224858,1,2 +184,72,1225161,5,0 +256,40,1225312,1,8 +328,72,1225464,1,0 +416,200,1225767,1,0 +296,356,1226070,1,8 +320,280,1226222,1,8 +256,232,1226373,1,0 +192,280,1226525,1,0 +216,356,1226676,1,4 +336,111,1227131,6,0,B|352:47|288:15|256:15|223:15|159:47|175:111,2,274.000001469851,2|2|8 +256,304,1228343,1,0 +193,277,1228494,2,0,B|181:298|174:343|209:397|268:399|316:376|345:340|324:276|318:268,1,274.000001469851,2|8 +496,128,1229403,1,0 +256,32,1229706,5,0 +216,156,1229858,1,8 +320,80,1230009,1,8 +192,80,1230161,1,8 +296,156,1230312,1,4 +16,128,1230767,5,2 +175,288,1231222,2,0,B|159:352|223:384|256:384|288:384|352:352|336:288,1,274.000001469851,2|8 +438,116,1231979,1,0 +361,51,1232131,2,0,B|334:77|294:90|255:51|255:24|255:24|255:51|215:90|175:77|149:51,1,274.000001469851,2|8 +64,336,1233040,1,2 +256,224,1233343,5,0 +296,356,1233494,1,8 +192,276,1233646,1,8 +320,276,1233797,1,0 +216,356,1233949,1,4 +362,100,1234403,6,0,B|338:31|253:0|175:28|151:108,1,274.000001469851,2|2 +448,336,1235312,1,8 +256,212,1235616,1,0 +203,281,1235767,2,0,B|184:332|184:332|220:332|256:368|256:368|292:332|328:332|328:332|308:279,1,274.000001469851,2|8 +64,337,1236676,1,2 +180,88,1237131,6,0,B|203:42|256:31|310:43|333:90,1,182.666667646567,8|0 +362,187,1237585,2,0,B|324:295|164:293|148:177|148:177,3,274.000001469851,4|8|2|8 +40,360,1239252,1,8 +127,312,1239403,2,0,B|166:350|217:355,1,91.3333338232835,2|0 +305,353,1239706,2,0,B|346:350|385:312,1,91.3333338232835,0|8 +472,360,1240009,1,2 +474,357,1240085,1,0 +476,354,1240161,5,8 +488,248,1240312,1,0 +408,208,1240464,1,0 +320,144,1240616,1,0 +256,64,1240767,1,8 +192,144,1240919,1,0 +112,208,1241070,1,0 +24,248,1241222,1,4 +328,340,1241676,6,0,B|320:312|296:280|256:268|216:280|192:312|184:340,1,196.000001869202,8|0 +120,252,1242131,2,0,B|180:208|256:180|332:208|392:252,1,294.000002803803,2|8 +472,96,1242888,1,0 +392,36,1243040,6,0,B|332:80|256:108|180:80|120:36,1,294.000002803803,4|8 +16,68,1243646,2,0,B|8:168,1,98.0000009346008 +112,140,1243949,2,0,B|196:196|204:308,1,196.000001869202,2|0 +308,305,1244403,2,0,B|316:196|400:140,1,196.000001869202,8|2 +368,36,1244858,6,0,B|304:60|256:128|256:128|208:60|144:36,2,294.000002803803,4|8|2 +503,165,1246070,2,0,B|496:68,1,98.0000009346008,0|8 +424,148,1246373,2,0,B|431:245,1,98.0000009346008,0|0 +340,300,1246676,6,0,B|340:224|292:192|256:192|220:192|172:160|172:84,1,294.000002803803,4|8 +339,85,1247585,2,0,B|340:160|292:192|256:192|220:192|172:224|171:299,1,294.000002803803,2|8 +80,356,1248191,2,0,B|68:304|76:260,1,98.0000009346008,8|0 +136,168,1248494,6,0,B|212:168|228:256|304:256,1,196.000001869202,4|0 +412,248,1248949,2,0,B|480:252|496:180|496:180|512:104,1,196.000001869202,8|0 +424,40,1249403,2,0,B|356:36|340:108|340:108|324:184,1,196.000001869202,2|0 +324,184,1249858,1,8 +100,248,1250161,5,0 +100,248,1250312,2,0,B|32:252|16:180|16:180|0:104,1,196.000001869202,4|0 +88,40,1250767,2,0,B|156:36|172:108|172:108|188:184,1,196.000001869202,8|0 +292,212,1251222,2,0,B|384:220|384:220|396:164|372:120,1,196.000001869202,2|0 +324,60,1251676,1,8 +256,28,1251828,1,0 +188,60,1251979,1,0 +140,120,1252131,6,0,B|116:164|128:220|128:220|220:212,1,196.000001869202,4|0 +328,204,1252585,2,0,B|384:200|384:200|440:196|472:248|452:308|392:312|392:312|340:316,2,294.000002803803,8|2|8 +328,204,1253646,1,0 +174,316,1253949,2,0,B|120:312|120:312|60:308|40:248|72:196|128:200|128:200|184:204,1,294.000002803803,4|8 +192,96,1254555,2,0,B|96:88,2,98.0000009346008,0|8|4 +418,87,1255161,6,0,B|320:96,1,98.0000009346008,0|8 +280,184,1255464,2,0,B|378:175,1,98.0000009346008,8|0 +376,272,1255767,6,0,B|280:280|280:280|224:284|204:336,1,196.000001869202,4|0 +308,336,1256222,2,0,B|288:284|232:280|232:280|136:272,1,196.000001869202,8|0 +40,264,1256676,2,0,B|52:180|140:176|140:176|228:172|240:88,1,294.000002803803,2|8 +144,80,1257282,1,0 +136,272,1257585,5,4 +256,116,1257888,1,0 +256,116,1258040,1,8 +376,272,1258343,1,0 +376,272,1258494,2,0,B|424:252|460:200|440:136|416:108,1,196.000001869202,2|0 +332,60,1258949,2,0,B|280:60|256:8|256:8|232:60|180:60,1,196.000001869202,8|0 +96,108,1259403,2,0,B|71:136|51:200|87:252|135:272,1,196.000001869202,4|0 +180,360,1259858,2,0,B|232:360|256:308|256:308|280:360|332:360,1,196.000001869202,8|0 +424,320,1260312,2,0,B|368:276|336:192|368:108|424:64,2,294.000002803803,2|8|4 +256,176,1261676,5,8 +87,320,1262131,2,0,B|144:276|176:192|144:108|88:64,1,294.000002803803,2|8 +32,144,1262737,1,2 +32,240,1262888,1,0 +132,236,1263040,6,0,B|328:228,1,196.000001869202,4|0 +380,148,1263494,2,0,B|184:156,1,196.000001869202,8|0 +184,156,1263949,1,2 +332,60,1264252,2,0,B|429:55,1,98.0000009346008,0|8 +436,232,1264706,2,0,B|338:236,1,98.0000009346008,0|4 +82,329,1265161,6,0,B|180:324,1,98.0000009346008,0|8 +173,148,1265616,2,0,B|76:152,1,98.0000009346008,0|2 +132,236,1266070,1,0 +132,236,1266222,2,0,B|328:228,1,196.000001869202,8|0 +432,192,1266676,5,4 +256,128,1266979,1,0 +256,128,1267131,1,8 +80,192,1267434,1,0 +80,192,1267585,1,2 +352,240,1267888,1,0 +352,240,1268040,1,8 +160,240,1268343,1,0 +160,240,1268494,1,2 +316,372,1268949,5,8 +256,380,1269100,1,8 +196,372,1269252,1,2 +168,288,1269403,5,8 +256,276,1269555,1,0 +344,284,1269706,1,2 +372,200,1269858,5,8 +256,176,1270009,1,0 +140,200,1270161,1,2 +256,100,1270312,5,4 +384,280,1270767,6,0,B|436:280|488:252|512:192|488:132|436:104|384:104,1,294.000002803803,8|2 +300,126,1271373,2,0,B|300:224,1,98.0000009346008,0|2 +256,296,1271676,1,8 +212,224,1271828,2,0,B|212:126,1,98.0000009346008,0|2 +128,103,1272131,2,0,B|76:104|24:132|0:192|24:252|76:280|128:280,3,294.000002803803,4|2|0|2 +340,76,1273949,6,0,B|384:108|412:184|384:260|332:308|256:328|180:308|128:260|100:184|128:108|172:76,2,588.000005607605,4|2|4 +48,40,1276222,1,8 +36,136,1276373,1,0 +72,228,1276525,1,0 +140,296,1276676,2,0,B|220:304|256:224|256:224|292:304|372:296,1,294.000002803803,2|8 +440,228,1277282,1,0 +476,136,1277434,1,0 +464,40,1277585,1,4 +256,248,1278040,5,8 +256,64,1278494,1,2 +160,164,1278646,5,0 +160,260,1278797,1,0 +256,288,1278949,1,8 +352,260,1279100,1,0 +352,164,1279252,1,2 +256,136,1279403,1,4 +456,56,1279858,6,0,B|456:350,1,294.000002803803,8|2 +56,350,1280767,2,0,B|56:56,1,294.000002803803,8|4 +360,88,1281676,2,0,B|360:212|360:212|360:284|328:324|256:352|184:324|152:284|152:212|152:212|152:88,1,588.000005607605,8|8 +20,284,1283040,5,4 +8,208,1283191,1,0 +16,128,1283343,1,2 +80,80,1283494,1,8 +160,80,1283646,1,0 +228,120,1283797,1,2 +256,192,1283949,1,8 +284,264,1284100,1,0 +352,304,1284252,1,0 +432,304,1284403,1,8 +496,256,1284555,1,8 +504,176,1284706,1,0 +492,100,1284858,1,4 +208,192,1291222,5,0 +148,112,1291373,1,0 +148,112,1291449,1,0 +148,112,1291525,1,0 +52,132,1291676,1,0 +32,228,1291828,1,0 +100,292,1291979,1,0 +184,281,1292131,6,0,B|205:317|263:349|322:311|334:277,1,178.666658215332,4|2 +309,192,1292585,2,0,B|301:140|257:124|257:124|205:104|209:48,1,183.333327869574,8|0 +305,56,1293040,2,0,B|309:104|257:124|257:124|213:140|201:196,2,183.333327869574,2|0|0 +392,40,1293797,1,0 +464,96,1293949,1,2 +392,264,1294252,5,0 +336,328,1294403,1,8 +256,352,1294555,1,0 +176,328,1294706,1,0 +120,264,1294858,1,2 +120,120,1295161,1,0 +176,56,1295312,1,8 +256,32,1295464,1,0 +336,56,1295616,1,0 +392,120,1295767,1,2 +256,200,1296070,5,0 +256,200,1296222,1,8 +256,24,1296525,5,0 +256,24,1296676,1,2 +201,169,1296979,1,0 +331,76,1297282,1,2 +175,76,1297585,1,0 +297,171,1297888,1,0 +300,259,1298040,6,0,B|255:244|255:244|212:259,1,91.6666639347872,8|0 +212,349,1298343,2,0,B|256:363|256:363|299:349,1,91.6666639347872 +392,184,1298797,1,8 +346,101,1298949,1,8 +256,67,1299100,1,0 +165,101,1299252,1,8 +119,184,1299403,1,4 +256,276,1299706,5,0 +182,318,1299858,2,0,B|202:359|257:382|312:360|331:316,1,183.333327869574,2|0 +332,233,1300312,2,0,B|310:192|258:168|200:192|183:234,2,183.333327869574,2|0|0 +422,128,1301222,2,0,B|352:92|336:12|336:12|256:108|256:108|180:8|180:8|156:92|94:128,2,549.999983608723,2|2|4 +188,308,1303494,6,0,B|201:351|256:361|256:361|307:354|327:304,1,183.333327869574,8|0 +256,256,1303949,1,2 +360,80,1304252,1,0 +152,80,1304555,1,2 +68,233,1304858,2,0,B|52:304|140:352|191:289|191:289|209:334|255:347|302:334|320:291|320:291|370:351|463:307|443:225,2,549.999983608723,0|2|4 +256,68,1306979,5,0 +256,68,1307131,1,8 +256,252,1307434,1,0 +182,199,1307585,2,0,B|203:199|203:199|228:176|228:176|256:152|256:152|284:176|284:176|308:199|308:199|328:199,2,183.333327869574,2|0|0 +46,322,1308494,2,0,B|68:284|182:252|208:368|160:384|164:318|240:304|256:251|256:251|272:304|352:320|352:384|304:368|333:281|364:284|455:262|475:337|475:337,2,549.999983608723,2|2|4 +256,384,1310767,5,8 +332,219,1311070,1,0 +332,219,1311222,1,2 +179,217,1311525,1,0 +230,40,1311828,2,0,B|216:49|207:74|216:97|232:112|256:118|280:112|296:97|304:74|296:49|282:40,1,183.333327869574,2|0 +448,74,1312434,6,0,B|489:156,1,91.6666639347872,2|8 +444,238,1312737,2,0,B|416:326,1,91.6666639347872,0|8 +324,366,1313040,2,0,B|310:324|256:313|256:313|206:321|186:370,1,183.333327869574,8|0 +95,325,1313494,2,0,B|68:238,1,91.6666639347872,8|0 +23,156,1313797,2,0,B|64:74,1,91.6666639347872,8|4 +336,47,1314403,6,0,B|296:135|336:224,1,183.333327869574,8|0 +376,304,1314858,2,0,B|296:308|256:361|256:361|211:308|135:304,1,274.999991804362,2|8 +43,288,1315464,2,0,B|51:240|83:208,1,91.6666639347872,2|8 +174,224,1315767,6,0,B|215:135|175:47,1,183.333327869574,4|0 +83,51,1316222,2,0,B|139:107|127:200|43:240|-24:204,1,274.999991804362,8|2 +68,360,1316979,6,0,B|144:308,1,91.6666639347872,0|8 +256,372,1317282,2,0,B|256:280,1,91.6666639347872,8|0 +256,188,1317585,1,4 +444,360,1317888,6,0,B|368:308,1,91.6666639347872,0|8 +209,116,1318343,2,0,B|254:100|297:116,1,91.6666639347872 +344,43,1318646,2,0,B|256:2|167:43,1,183.333327869574,0|8 +44,176,1319252,1,0 +116,120,1319403,2,0,B|180:176|168:288,1,183.333327869574,2|0 +256,316,1319858,2,0,B|256:135,1,183.333327869574,8|0 +396,120,1320312,2,0,B|332:176|344:288,1,183.333327869574,2|0 +428,324,1320767,6,0,B|420:280|424:232,1,91.6666639347872,8|8 +464,84,1321070,2,0,B|472:128|468:176,1,91.6666639347872,0|4 +320,336,1321525,6,0,B|324:292|308:244,1,91.6666639347872,0|8 +256,172,1321828,1,0 +210,102,1321979,2,0,B|255:86|298:102,1,91.6666639347872 +191,339,1322434,6,0,B|187:295|202:249,1,91.6666639347872,0|8 +256,172,1322737,1,0 +312,100,1322888,1,0 +348,14,1323040,2,0,B|401:10|401:10|457:6|485:38|489:83,1,183.333327869574,2|0 +404,123,1323494,2,0,B|320:171|304:268,1,183.333327869574,8|0 +207,268,1323949,2,0,B|191:171|107:123,1,183.333327869574,2|0 +107,123,1324403,1,8 +192,92,1324555,5,0 +256,28,1324706,1,0 +320,92,1324858,1,4 +256,192,1325009,12,4,1326676 +60,192,1327131,5,0 +60,192,1327282,1,0 +160,136,1327434,1,0 +160,124,1327509,1,0 +160,112,1327585,5,2 +256,28,1327737,1,0 +352,112,1327888,1,0 +452,192,1328040,1,8 +352,272,1328191,1,0 +256,356,1328343,1,0 +160,272,1328494,1,4 +40,166,1328797,6,0,B|40:120|64:80,1,91.3333338232835,0|8 +255,146,1329252,2,0,B|268:176|244:208|256:236,1,91.3333338232835,0|2 +471,166,1329706,2,0,B|472:120|448:80,1,91.3333338232835,0|8 +364,312,1330161,5,0 +364,312,1330312,2,0,B|336:380|256:408|175:380|147:312,1,274.000001469851,4|8 +192,232,1330919,1,0 +256,168,1331070,1,0 +320,232,1331222,2,0,B|364:232|408:208|424:163|416:107,1,182.666667646567,2|0 +340,64,1331676,2,0,B|296:96|256:64|256:64|216:32|172:64,1,182.666667646567,8|2 +96,107,1332131,6,0,B|88:164|104:208|148:232|192:232,1,182.666667646567,4|0 +284,232,1332585,2,0,B|332:92|470:44,1,274.000001469851,8|2 +227,151,1333494,2,0,B|178:290|40:338,1,274.000001469851,8|4 +40,156,1334252,6,0,B|84:168|84:168|132:168,1,91.3333338232835,0|8 +179,91,1334555,2,0,B|203:55|256:27|308:55|332:91,1,182.666667646567,0|2 +360,180,1335009,1,0 +336,268,1335161,1,0 +256,308,1335312,1,8 +176,268,1335464,1,8 +152,180,1335616,1,0 +148,88,1335767,6,0,B|208:56|208:56|256:84|316:88,1,182.666667646567,4|0 +408,84,1336222,2,0,B|376:144|376:144|404:192|408:252,1,182.666667646567,8|0 +364,344,1336676,2,0,B|304:312|304:312|256:340|196:344,1,182.666667646567,2|0 +104,300,1337131,2,0,B|136:240|136:240|108:192|104:132,1,182.666667646567,8|0 +27,183,1337585,6,0,B|75:244|175:236|215:147|179:83,1,274.000001469851,4|8 +256,32,1338191,2,0,B|256:216,1,182.666667646567,0|2 +332,84,1338797,1,0 +332,83,1338949,2,0,B|296:148|336:236|436:244|484:183,1,274.000001469851,8|4 +256,192,1339555,12,6,1342131 +112,112,1342282,5,0 +168,40,1342434,1,0 +256,12,1342585,1,8 +344,40,1342737,1,0 +400,112,1342888,1,0 +332,170,1343040,6,0,B|312:129|257:106|202:128|183:172,1,182.666667646567,6|0 +181,260,1343494,2,0,B|201:301|256:324|311:302|330:258,1,182.666667646567,10|0 +256,216,1343949,1,0 +208,384,1344252,2,0,B|304:384|304:384,1,91.3333338232835,0|8 +256,216,1344706,1,0 +124,38,1345161,2,0,B|138:78|197:93|226:63|226:19|190:5|160:49|208:93|256:93|256:93|303:93|351:49|321:5|285:19|285:63|318:93|387:71|395:34,1,421.333338858287,2|0 +440,216,1346070,5,2 +388,304,1346222,1,10 +256,140,1346525,1,0 +204,212,1346676,2,0,B|212:264|256:280|256:280|308:300|304:356,1,182.666667646567 +208,348,1347131,2,0,B|204:300|256:280|256:280|300:264|312:208,1,182.666667646567,8|0 +256,140,1347585,1,0 +72,216,1347888,1,2 +124,304,1348040,1,10 +160,156,1348343,6,0,B|213:103|186:3|123:-2|81:55|123:108|202:81|257:14|257:14|310:81|390:108|432:55|390:-2|326:3|299:103|352:156,1,639.333336762985,0|2 +344,236,1349555,6,0,B|388:316,1,91.3333338232835,0|0 +256,364,1349858,2,0,B|256:252,1,91.3333338232835,8|0 +124,315,1350161,2,0,B|168:236,1,91.3333338232835,0|4 +44,44,1350767,1,8 +335,282,1351222,2,0,B|376:257|405:184|376:114|328:68|258:49|185:68|135:114|111:184|135:257|178:284,1,548.000002939701,2|2 +468,44,1352585,1,8 +357,277,1353040,6,0,B|339:348|254:387|171:346|154:277,1,274.000001469851,4|8 +22,192,1353797,2,0,B|5:-6|238:-24|305:41|372:108|388:158|354:192|256:441|156:192|122:158|138:108|205:41|272:-24|505:-6|483:194,1,1096.0000058794,0|0 +377,321,1355767,2,0,B|319:381|256:336|256:336|187:384|131:316,1,274.000001469851,2|2 +200,268,1356373,1,0 +140,212,1356525,1,0 +132,132,1356676,1,4 +180,64,1356828,1,0 +256,40,1356979,1,0 +332,64,1357131,1,6 +380,132,1357282,1,0 +372,212,1357434,1,0 +312,268,1357585,1,4 +52,80,1358494,6,0,B|52:37|113:29|132:69|132:69|150:110|197:110|214:69|214:69|229:29|279:29|296:69|296:69|312:110|360:110|376:69|376:69|397:29|458:37|458:81,2,548.000002939701,8|0|8 +256,192,1360767,1,0 +52,302,1361222,2,0,B|52:345|113:353|132:313|132:313|150:272|197:272|214:313|214:313|229:353|279:353|296:313|296:313|312:272|360:272|376:313|376:313|397:353|458:345|458:301,2,548.000002939701,0|8|0 +256,44,1363494,5,0 +244,104,1363949,1,8 +264,152,1364403,1,0 +244,208,1364858,1,4 +256,356,1365767,1,8 +256,356,1366373,5,0 +256,356,1366525,1,0 +256,356,1366676,1,0 +308,196,1367131,1,0 +176,288,1367585,1,8 +336,288,1368040,1,0 +204,196,1368494,1,0 +361,51,1369403,6,0,B|334:77|294:90|255:51|255:24|255:24|255:51|215:90|175:77|149:51,1,274.000001469851,8|0 +140,60,1370009,1,0 +127,69,1370161,1,0 +117,79,1370312,1,0 +256,192,1370767,1,0 +344,296,1371222,1,8 +320,324,1371373,1,0 +292,340,1371525,1,0 +260,344,1371676,1,8 +220,340,1371828,1,0 +192,324,1371979,1,0 +168,296,1372131,1,4 +256,192,1383040,12,0,1386676 +256,48,1387131,5,4 +256,216,1387585,1,0 +256,216,1388040,1,8 +176,236,1388191,1,0 +96,256,1388343,1,0 +40,200,1388494,6,0,B|20:156|40:112,1,91.3333338232835 +164,88,1388797,2,0,B|144:128|144:128|108:156,1,91.3333338232835,0|4 +210,327,1389403,6,0,B|256:344|300:328,1,91.3333338232835,0|0 +208,192,1389706,2,0,B|254:175|298:191,1,91.3333338232835,0|4 +472,200,1390161,5,0 +472,200,1390312,2,0,B|492:156|472:112,1,91.3333338232835 +348,88,1390616,2,0,B|368:128|368:128|404:156,1,91.3333338232835,0|4 +256,216,1391222,5,0 +256,216,1391676,1,8 +336,236,1391828,1,0 +416,256,1391979,1,0 +384,332,1392131,6,0,B|296:308,1,91.3333338232835 +128,332,1392434,2,0,B|216:308,1,91.3333338232835,0|4 +384,128,1393040,6,0,B|296:152,1,91.3333338232835 +128,128,1393343,2,0,B|216:152,1,91.3333338232835,0|4 +408,232,1393797,5,0 +408,232,1393949,2,0,B|316:232,1,91.3333338232835 +104,232,1394252,2,0,B|195:232,1,91.3333338232835,0|4 +195,232,1394858,1,0 +302,40,1395312,6,0,B|210:40,1,91.3333338232835,8|0 +296,116,1395616,2,0,B|380:152,1,91.3333338232835 +300,220,1395919,2,0,B|256:228|256:228|212:220,1,91.3333338232835 +216,116,1396222,2,0,B|48:188,1,182.666667646567,4|0 +80,312,1396676,5,8 +164,260,1396828,1,0 +256,300,1396979,1,0 +256,300,1397131,1,4 +395,232,1397282,6,0,B|353:313,1,91.3333338232835,0|0 +256,300,1397585,1,8 +159,313,1397737,2,0,B|117:232,1,91.3333338232835,0|0 +256,116,1398040,1,4 +256,116,1398494,1,0 +356,336,1398949,6,0,B|356:244,1,91.3333338232835,8|0 +256,348,1399252,2,0,B|256:256,1,91.3333338232835 +156,336,1399555,2,0,B|156:244,1,91.3333338232835 +256,116,1399858,1,4 +280,32,1400009,2,0,B|208:32,2,45.6666669116418 +356,84,1400312,1,8 +376,180,1400464,1,0 +348,276,1400616,1,0 +256,316,1400767,1,8 +164,276,1400919,1,0 +136,180,1401070,1,0 +152,88,1401222,6,0,B|112:24,2,45.6666669116418 +208,152,1401525,1,0 +256,72,1401676,2,0,B|256:24,2,45.6666669116418,8|0|0 +304,148,1401979,1,0 +360,88,1402131,2,0,B|400:24,2,45.6666669116418 +304,148,1402434,1,0 +256,216,1402585,2,0,B|256:308,1,91.3333338232835,8|0 +256,384,1402888,1,0 +176,352,1403040,5,2 +156,316,1403116,1,0 +136,280,1403191,1,0 +176,208,1403343,1,0 +184,128,1403494,2,0,B|204:84|256:60|308:84|328:128,1,182.666667646567,8|0 +336,208,1403949,1,8 +376,280,1404100,1,2 +356,316,1404176,1,0 +336,352,1404252,1,0 +256,384,1404403,5,8 +196,268,1404555,1,2 +316,268,1404706,1,0 +416,368,1404858,6,0,B|476:344|492:280|492:280|508:216,1,182.666667646567,4|0 +500,136,1405312,2,0,B|404:172|328:104,1,182.666667646567,8|0 +344,23,1405767,2,0,B|256:-16|167:23,1,182.666667646567,4|2 +11,135,1406373,6,0,B|107:171|180:105,1,182.666667646567,0|2 +330,277,1406979,2,0,B|404:212|500:248,1,182.666667646567,8|0 +180,277,1407585,2,0,B|107:212|11:247,1,182.666667646567,10|2 +120,332,1408040,5,8 +256,248,1408191,1,8 +392,332,1408343,1,0 +384,147,1408494,6,0,B|360:95|304:55|239:63|183:135|195:192|256:232|316:192|328:135|272:63|207:55|151:95|127:147,1,464.000007743836,4|2 +80,208,1409555,2,0,B|104:244|96:292,1,76.1333349488259 +12,180,1409858,2,0,B|12:136|40:100,1,76.1333349488259,8|0 +473,282,1410312,6,0,B|500:248|500:204,1,76.1333349488259,2|0 +415,95,1410616,2,0,B|408:140|432:176,1,76.1333349488259,0|8 +364,268,1410919,2,0,B|280:252,1,76.1333349488259,2|0 +148,116,1411222,2,0,B|232:132,1,76.1333349488259,2|0 +144,304,1411525,6,0,B|116:272|112:228,1,76.1333349488259,0|8 +368,80,1411828,2,0,B|396:112|400:156,1,76.1333349488259,2|8 +256,192,1412131,5,4 +256,192,1412282,12,8,1413494 +84,108,1413949,6,0,B|20:160,1,76.1333349488259,4|0 +84,251,1414252,2,0,B|128:180,1,76.1333349488259,8|2 +216,125,1414555,1,2 +216,125,1414631,1,0 +216,125,1414706,2,0,B|200:209,1,76.1333349488259,0|8 +312,208,1415009,2,0,B|296:125,1,76.1333349488259,0|2 +384,180,1415312,2,0,B|428:252,1,76.1333349488259,2|0 +493,160,1415616,2,0,B|428:108,1,76.1333349488259,0|4 +336,272,1416222,6,0,B|352:336|288:368|256:368|223:368|159:336|175:272,2,274.000001469851,2|2|8 +256,80,1417434,1,0 +193,107,1417585,2,0,B|181:86|174:41|209:-13|268:-15|316:8|345:44|324:108|313:114,1,274.000001469851,2|8 +496,256,1418494,1,2 +256,352,1418797,5,0 +216,228,1418949,1,8 +320,304,1419100,1,8 +192,304,1419252,1,8 +296,228,1419403,1,4 +16,256,1419858,5,2 +175,95,1420312,2,0,B|159:31|223:0|256:0|288:0|352:31|336:95,1,274.000001469851,2|8 +438,268,1421070,1,0 +361,333,1421222,2,0,B|334:307|294:294|255:333|255:360|255:360|255:333|215:294|175:307|149:333,1,274.000001469851,2|8 +80,288,1421828,2,0,B|108:248|160:236,1,91.3333338232835 +112,168,1422131,2,0,B|160:160|188:120,1,91.3333338232835,8|0 +256,76,1422434,1,0 +324,120,1422585,2,0,B|352:160|400:168,1,91.3333338232835,8|0 +357,237,1422888,2,0,B|400:248|432:288,1,91.3333338232835,0|4 +150,100,1423494,6,0,B|174:31|259:0|337:28|361:108,1,274.000001469851,2|2 +64,336,1424403,1,8 +256,212,1424706,1,0 +309,281,1424858,2,0,B|328:332|328:332|292:332|256:368|256:368|220:332|184:332|184:332|204:279,1,274.000001469851,2|8 +448,337,1425767,1,2 +180,88,1426222,6,0,B|203:42|256:31|310:43|333:90,1,182.666667646567,8|0 +362,187,1426676,2,0,B|324:295|164:293|148:177|148:177,3,274.000001469851,4|8|2|8 +40,360,1428494,1,2 +127,312,1428646,2,0,B|166:350|217:355,1,91.3333338232835,2|0 +305,353,1428949,2,0,B|346:350|385:312,1,91.3333338232835,8|8 +476,354,1429252,1,8 +488,248,1429403,5,8 +408,208,1429555,1,0 +320,144,1429706,1,0 +256,64,1429858,1,8 +192,144,1430009,1,0 +112,208,1430161,1,0 +24,248,1430312,1,4 +337,289,1430767,6,0,B|321:338|256:371|190:338|174:289,1,210.666669429143,2|0 +256,248,1431222,1,2 +256,56,1431525,1,0 +175,87,1431676,2,0,B|191:127|256:151|256:151|313:129|336:87,1,210.666669429143,8|0 +416,144,1432131,1,2 +416,336,1432434,2,0,B|368:312|368:312|344:264,1,105.333334714572,0|8 +166,266,1432888,2,0,B|144:312|144:312|96:336,1,105.333334714572,0|2 +96,144,1433343,5,0 +174,91,1433494,2,0,B|229:91|256:35|256:35|282:91|337:91,1,210.666669429143,8|0 +400,184,1433949,2,0,B|430:234|430:234|457:284|446:343|379:351|379:351,1,210.666669429143,2|0 +294,306,1434403,2,0,B|299:294|311:265|305:238|281:222|254:214|225:221|205:241|201:269|207:289|220:306,1,210.666669429143,8|0 +132,351,1434858,2,0,B|65:343|54:284|81:234|81:234|112:184,1,210.666669429143,2|0 +136,96,1435312,5,8 +215,45,1435464,2,0,B|222:20|255:3|288:20|296:45,1,105.333334714572,2|0 +376,96,1435767,1,2 +440,276,1436070,2,0,B|412:308|412:308|376:312|376:312|360:336,1,105.333334714572,0|8 +308,256,1436373,2,0,B|320:220|320:220|352:208|352:208|364:172,1,105.333334714572,2|0 +256,160,1436676,2,0,B|264:136|264:136|240:96|240:96|256:68|256:68,2,105.333334714572,8|0|0 +149,176,1437131,2,0,B|160:208|160:208|192:220|192:220|204:256,1,105.333334714572,8|0 +150,333,1437434,2,0,B|136:312|136:312|100:308|100:308|72:276,1,105.333334714572,0|4 +256,124,1437888,5,0 +176,92,1438040,2,0,B|192:43|257:10|323:43|339:92,1,210.666669429143,8|0 +360,192,1438494,2,0,B|136:192,1,210.666669429143,2|0 +176,292,1438949,2,0,B|192:341|257:374|323:341|339:292,1,210.666669429143,8|0 +416,348,1439403,5,2 +256,252,1439706,1,0 +256,252,1439858,1,8 +96,348,1440161,1,0 +96,348,1440312,1,2 +112,160,1440616,1,0 +164,80,1440767,1,8 +256,52,1440919,1,0 +348,80,1441070,1,0 +392,156,1441222,1,6 +256,192,1441373,12,2,1443040 +256,344,1443191,5,0 +344,312,1443343,1,10 +404,240,1443494,1,0 +404,144,1443646,1,8 +344,72,1443797,1,0 +256,40,1443949,1,8 +168,72,1444100,1,0 +108,144,1444252,1,8 +108,240,1444403,1,8 +168,312,1444555,5,8 +256,344,1444706,1,8 +344,312,1444858,1,4 +412,136,1445161,1,2 +452,52,1445312,1,8 +256,84,1445616,1,2 +256,176,1445767,1,0 +100,136,1446070,1,2 +60,52,1446222,1,8 +134,257,1446525,22,0,B|160:337|259:373|350:340|378:247,1,316.000004143715,2|2 +432,331,1447131,2,0,B|504:216|466:84|466:84,1,210.666669429143,8|0 +402,67,1447585,1,2 +256,188,1447888,1,0 +350,175,1448040,2,0,B|363:214|334:293|255:300|213:278,1,210.666669429143,8|0 +161,208,1448494,2,0,B|148:169|177:90|256:83|298:105,1,210.666669429143,2|0 +256,188,1448949,1,8 +112,68,1449252,1,0 +35,130,1449403,2,0,B|28:248|84:336,1,210.666669429143,2|0 +172,356,1449858,1,8 +300,236,1450161,38,0,B|323:218|338:177|323:136|295:111|254:100|213:111|185:136|170:177|185:218|209:236,1,316.000004143715,2|0 +104,228,1450767,1,8 +108,132,1450919,1,8 +164,56,1451070,1,0 +256,28,1451222,1,8 +348,56,1451373,1,8 +404,132,1451525,1,0 +408,228,1451676,1,8 +344,300,1451828,1,0 +256,332,1451979,1,8 +168,300,1452131,1,4 +44,44,1452585,21,2 +256,232,1453040,1,2 +312,60,1453343,1,0 +168,160,1453646,1,2 +348,160,1453949,1,2 +204,60,1454252,1,2 +256,136,1454403,1,8 +468,44,1454858,1,2 +448,232,1455161,5,0 +448,232,1455312,1,8 +296,352,1455616,1,0 +218,297,1455767,2,0,B|189:364|93:358|82:299|67:262|90:207|157:188|201:214|200:251,1,316.000004143715,2|8 +294,87,1456676,2,0,B|323:20|418:25|429:84|444:121|422:177|354:195|311:170|311:132,1,316.000004143715,2|8 +436,286,1457434,21,2 +350,317,1457585,1,8 +256,302,1457737,1,2 +185,247,1457888,1,2 +161,160,1458040,1,8 +177,66,1458191,1,0 +256,26,1458343,1,2 +334,66,1458494,1,10 +350,160,1458646,1,8 +326,247,1458797,1,0 +256,302,1458949,1,8 +161,317,1459100,1,8 +75,286,1459252,1,0 +40,200,1459403,38,0,B|8:160|16:88|64:48|136:56,1,210.666669429143,4|2 +200,112,1459858,1,8 +256,184,1460009,1,0 +312,112,1460161,1,2 +388,55,1460312,2,0,B|448:48|496:88|504:160|472:200,1,210.666669429143,0|0 +392,248,1460767,1,8 +296,288,1460919,2,0,B|289:263|256:246|223:263|215:288,1,105.333334714572,2|0 +128,240,1461222,1,0 +256,360,1461525,21,0 +256,360,1461676,1,8 +216,176,1461979,2,0,B|223:201|256:218|289:201|297:176,1,105.333334714572,2|0 +120,112,1462434,1,0 +168,32,1462585,1,8 +256,8,1462737,1,0 +344,32,1462888,1,0 +392,112,1463040,1,4 +256,192,1463191,12,2,1464858 +278,319,1465312,6,0,B|239:286|239:286|175:289|175:289,1,105.333334714572,8|0 +360,268,1465616,2,0,B|348:219|348:219|378:162|378:162,1,105.333334714572,2|8 +233,64,1465919,2,0,B|272:97|272:97|336:94|336:94,1,105.333334714572,0|8 +151,115,1466222,2,0,B|163:164|163:164|133:221|133:221,1,105.333334714572,8|0 +94,295,1466525,5,8 +194,352,1466676,2,0,B|203:291|254:272|254:272|315:249|310:184,1,210.666669429143,4|0 +328,96,1467131,1,8 +256,40,1467282,1,0 +184,96,1467434,1,0 +201,192,1467585,2,0,B|196:249|257:272|257:272|308:291|318:352,1,210.666669429143,2|0 +418,295,1468040,5,8 +472,216,1468191,2,0,B|416:192|424:128|424:128,1,105.333334714572 +344,80,1468494,2,0,B|304:96|264:80|256:48|256:48|248:80|208:96|168:80,1,210.666669429143,2|0 +168,176,1468949,2,0,B|216:208|216:208|256:184|256:184|296:208|296:208|344:176,1,210.666669429143,8|0 +256,280,1469403,5,2 +40,216,1469706,2,0,B|97:187|88:128|88:128,1,105.333334714572,0|8 +159,47,1470009,1,0 +257,24,1470161,1,0 +355,49,1470312,2,0,B|483:105|483:330|316:388|254:334|254:334|168:248|196:161|312:161|339:248|254:334|254:334|168:392|24:307|24:105|173:40,1,1264.00001657486,2|8 +264,76,1472282,5,8 +264,76,1472434,1,0 +264,76,1472585,1,8 +264,76,1472737,1,0 +264,76,1472888,1,8 +264,76,1473040,1,4 +400,320,1473494,1,6 +112,320,1473949,1,4 +256,192,1474100,12,0,1476676 +256,44,1505977,5,4 +172,96,1506172,1,4 +256,148,1506367,2,2,B|256:364,1,200,4|6 +100,332,1507536,6,0,B|80:216|132:128,1,200,0|8 +300,36,1508315,2,0,B|372:104|488:120,1,200 +472,220,1508899,1,0 +376,188,1509094,1,0 +216,308,1509484,2,0,B|112:308|16:376,1,200,8|0 +68,172,1510263,5,4 +220,44,1510652,1,0 +228,144,1510847,1,0 +308,204,1511042,1,8 +428,44,1511432,1,0 +488,236,1511821,1,0 +440,324,1512016,1,0 +348,284,1512211,1,0 +160,356,1512600,2,0,B|192:256|164:156,1,200,8|0 +348,76,1513380,5,6 +152,44,1513769,2,0,B|108:60|96:128,2,100,0|0|8 +256,216,1514549,1,0 +256,216,1514938,2,0,B|368:216,2,100 +64,164,1515717,2,0,B|124:72|224:52,1,200,8|0 +420,84,1516497,5,4 +384,280,1516886,1,0 +192,332,1517276,1,8 +68,176,1517665,1,0 +268,200,1518055,2,0,B|320:224|364:192,2,100 +116,104,1518834,5,8 +120,204,1519029,1,0 +220,188,1519224,1,0 +216,88,1519419,2,2,B|316:60|428:92,1,200 +364,176,1520003,1,0 +428,252,1520198,1,2 +260,364,1520587,5,0 +252,264,1520782,1,0 +156,288,1520977,2,2,B|116:188|180:88,1,200 +256,36,1521562,1,0 +396,176,1521951,5,8 +304,132,1522146,1,0 +204,124,1522341,1,0 +120,180,1522536,2,2,B|100:296|212:356,1,200 +256,268,1523120,1,0 +316,348,1523315,2,2,B|415:295|395:179,1,200 +296,168,1523899,1,0 +268,72,1524094,2,2,B|180:120|56:68,1,200 +32,164,1524678,1,0 +172,304,1525068,1,8 +216,216,1525263,5,0 +316,224,1525458,1,0 +332,124,1525652,2,2,B|460:112|492:216,1,200 +420,280,1526237,1,0 +336,336,1526432,2,2,B|240:352|128:336,1,200 +56,280,1527016,1,0 +68,180,1527211,2,2,B|172:116|204:20,1,200 +256,116,1527795,1,0 +432,212,1528185,1,8 +336,244,1528380,5,0 +408,316,1528574,1,0 +316,356,1528769,2,2,B|112:356,1,200 +16,356,1529354,1,0 +32,156,1529743,6,0,B|16:108|32:52,1,100,8|0 +104,128,1530133,2,0,B|120:180|176:208,1,100 +200,108,1530523,2,0,B|222:195|310:225|393:202|416:96,1,300,4|0 +476,184,1531302,1,8 +452,320,1531497,5,0 +360,360,1531691,1,0 +276,308,1531886,2,2,B|180:348|80:256,1,200 +32,184,1532471,1,0 +32,184,1532665,2,2,B|60:52|176:52,1,200 +260,64,1533250,1,0 +260,64,1533445,2,2,B|344:148|260:248,1,200 +196,316,1534029,2,0,B|80:316,2,100,0|0|8 +336,316,1534613,5,0 +432,296,1534808,1,0 +436,196,1535003,2,2,B|428:84|300:32,1,200 +256,116,1535587,1,0 +188,44,1535782,2,2,B|83:85|75:197,1,200 +176,184,1536367,2,0,B|184:240|135:282,1,100,0|2 +200,356,1536756,1,4 +256,164,1537146,1,0 +320,352,1537536,1,8 +448,292,1537730,6,0,B|412:244|444:184,2,100,0|0|2 +484,96,1538510,1,0 +392,64,1538704,1,0 +312,124,1538899,1,2 +216,300,1539289,1,0 +124,340,1539484,1,0 +108,240,1539678,1,2 +188,180,1539873,2,0,B|156:80|44:40,2,200,0|0|8 +280,72,1540847,5,2 +380,84,1541042,1,0 +424,172,1541237,1,2 +440,272,1541432,1,0 +372,344,1541626,2,2,B|264:384|188:292,1,200,2|0 +256,220,1542211,6,0,B|144:220,1,100,8|0 +168,120,1542600,2,0,B|56:120,1,100 +40,216,1542990,2,0,B|104:304|216:320,1,200,4|0 +256,232,1543574,1,0 +256,232,1543769,1,8 +388,272,1543964,5,0 +404,172,1544159,1,0 +364,80,1544354,2,2,B|160:80,1,200 +72,124,1544938,1,0 +160,168,1545133,2,2,B|108:268|192:360,1,200 +260,288,1545717,1,0 +336,352,1545912,1,2 +388,160,1546302,1,0 +484,184,1546497,1,0 +464,88,1546691,2,2,B|364:48|248:88,1,200 +256,180,1547276,1,0 +256,192,1547471,12,6,1549224 +408,32,1550782,5,6 +104,132,1551172,1,0 +408,228,1551562,1,8 +100,312,1551951,1,2 +256,272,1552341,5,0 +256,172,1552536,1,0 +256,272,1552730,1,0 +256,72,1553120,1,8 +56,72,1553510,6,2,B|84:164|20:264,1,200,2|6 +160,120,1554289,2,2,B|256:80|356:124,1,200,2|10 +492,268,1555068,2,2,B|429:169|457:77,1,200 +356,80,1555652,1,0 +260,60,1555847,1,2 +256,220,1556237,1,8 +256,220,1556626,1,0 +224,316,1556821,1,0 +124,308,1557016,5,6 +256,60,1557406,1,0 +380,312,1557795,1,8 +256,60,1558185,2,2,B|256:264,1,200,2|0 +256,260,1558769,1,0 +256,260,1558964,1,0 +256,192,1559354,12,0,1561302 +68,116,1561691,5,0 +168,116,1561886,1,8 +216,136,1561984,1,8 +260,116,1562081,1,8 +360,116,1562276,1,8 +324,208,1562471,1,8 +424,192,1562665,1,0 +360,116,1562860,1,0 +432,280,1563055,6,0,B|384:300|320:292,1,100,0|6 +184,160,1563639,2,0,B|128:160|104:108,2,100,0|0|8 +368,80,1564419,2,2,B|360:196|276:256,1,200 +228,168,1565003,1,0 +280,252,1565198,1,0 +100,336,1565587,6,2,B|32:272|32:136,1,200,10|2 +84,64,1566172,2,0,B|140:64|180:96,1,100,0|4 +256,276,1566756,1,2 +368,108,1567146,1,8 +488,268,1567536,2,2,B|440:348|304:328,1,200 +212,348,1568120,1,0 +200,248,1568315,2,2,B|136:164|12:176,1,200,2|10 +168,40,1569094,1,0 +256,84,1569289,2,0,B|276:28,2,50,0|0|4 +472,192,1569873,5,0 +256,336,1570263,1,8 +40,192,1570652,2,2,B|248:192,1,200,2|0 +240,192,1571237,1,0 +240,192,1571432,1,0 +256,192,1571821,12,0,1573769 +392,292,1574159,5,0 +360,156,1574354,1,8 +236,92,1574549,1,0 +128,180,1574743,1,0 +112,320,1574938,1,8 +240,264,1575133,1,0 +128,180,1575328,1,0 +284,152,1575523,5,0 +300,200,1575620,1,0 +316,248,1575717,1,4 +68,48,1585068,5,2 +132,280,1585652,1,2 +192,48,1586237,1,2 +432,192,1586626,5,2 +192,192,1587211,1,2 +316,88,1587600,5,0 +416,72,1587795,1,0 +316,88,1587990,2,2,B|344:196|288:288,1,200,2|2 +220,352,1588574,1,0 +200,256,1588769,2,2,B|124:192|12:168,1,200 +64,80,1589354,1,0 +64,80,1589549,1,2 +260,44,1589938,2,2,B|412:44,1,150,0|8 +488,104,1590717,5,0 +472,204,1590912,1,0 +376,236,1591107,1,2 +204,340,1591497,1,0 +248,252,1591691,1,0 +148,260,1591886,1,2 +28,100,1592276,1,0 +128,104,1592471,1,0 +208,44,1592665,2,2,B|324:32|380:132,1,200 +428,216,1593250,1,0 +484,24,1593639,1,8 +452,120,1593834,5,0 +428,216,1594029,1,0 +340,164,1594224,1,2 +256,344,1594613,1,0 +256,244,1594808,1,0 +256,344,1595003,1,2 +60,300,1595393,1,0 +156,276,1595587,1,0 +132,180,1595782,2,2,B|108:72|20:8,1,200 +20,316,1596756,1,8 +160,328,1596951,5,0 +260,348,1597146,1,0 +328,276,1597341,1,2 +300,180,1597536,1,0 +204,164,1597730,1,2 +204,164,1598315,1,8 +28,260,1598704,5,0 +80,172,1598899,1,0 +156,240,1599094,1,0 +320,168,1599484,1,0 +280,76,1599678,1,0 +380,84,1599873,1,8 +404,180,1600068,6,0,B|428:284,2,100,0|8|10 +256,44,1600847,1,0 +256,144,1601042,1,0 +256,44,1601237,1,2 +56,68,1601626,2,0,B|88:120|56:168,1,100 +52,264,1602016,2,2,B|96:364|232:352,1,200 +312,328,1602600,1,0 +152,208,1602990,1,8 +208,80,1603185,5,2 +304,100,1603380,1,0 +400,80,1603574,1,2 +464,268,1603964,1,0 +404,348,1604159,1,0 +304,352,1604354,1,2 +128,256,1604743,1,0 +224,280,1604938,1,0 +316,236,1605133,2,2,B|440:236|500:136,2,200,2|0|2 +224,280,1606107,1,8 +256,144,1606302,5,0 +160,120,1606497,1,0 +96,196,1606691,1,2 +292,232,1607081,1,0 +348,316,1607276,1,0 +444,292,1607471,1,2 +248,328,1607860,1,0 +248,328,1608055,2,2,B|148:292|108:176,1,200,2|0 +116,88,1608639,1,2 +200,144,1608834,2,0,B|252:164|312:144,2,100,0|0|8 +252,60,1609419,6,0,B|300:40|356:64,1,100,2|0 +440,100,1609808,2,0,B|420:148|456:216,1,100,2|0 +408,288,1610198,1,2 +124,192,1610782,5,8 +252,344,1611172,1,0 +156,316,1611367,1,0 +60,348,1611562,1,0 +44,148,1611951,2,0,B|112:68|224:64,1,200,0|8 +356,36,1612536,5,0 +328,132,1612730,1,0 +428,140,1612925,2,2,B|448:256|344:324,1,200 +276,256,1613510,1,0 +204,324,1613704,2,2,B|100:324|64:188,1,200 +36,104,1614289,1,0 +116,44,1614484,2,2,B|324:44,1,200 +416,52,1615068,1,0 +480,128,1615263,2,2,B|472:232|352:284,1,200 +356,180,1615847,2,2,B|296:172|272:244,2,100 +132,352,1616626,5,8 +60,232,1616821,1,8 +120,104,1617016,1,8 +240,32,1617211,1,8 +376,72,1617406,1,8 +416,208,1617600,1,0 +236,204,1617795,6,2,B|310:134|424:135,1,200,2|0 +472,328,1618574,1,8 +388,276,1618769,1,0 +476,228,1618964,1,0 +472,328,1619159,1,0 +324,340,1619354,6,0,B|220:364|124:320,1,200,6|0 +44,140,1620133,1,8 +132,188,1620328,1,0 +204,116,1620523,2,2,B|312:116|396:36,1,200 +456,120,1621107,1,0 +364,156,1621302,1,2 +468,328,1621691,1,8 +284,248,1622081,2,2,B|212:188|212:188|192:64,1,200,2|6 +28,192,1622860,5,2 +184,316,1623250,1,8 +248,124,1623639,2,2,B|352:60|458:182|384:292,1,300,2|0 +389,283,1624419,1,2 +200,216,1624808,1,8 +44,340,1625198,1,0 +44,340,1625393,5,0 +44,340,1625490,1,0 +44,340,1625587,2,0,B|88:136,1,200,6|0 +276,80,1626367,2,0,B|372:52|476:88,2,200,8|2|0 +184,124,1627341,1,0 +256,192,1627536,1,0 +256,192,1627925,12,0,1629873 +256,36,1630263,5,0 +292,56,1630458,1,8 +312,88,1630652,1,0 +316,128,1630847,1,0 +308,168,1631042,1,8 +296,208,1631237,1,0 +272,240,1631432,1,0 +244,268,1631626,1,0 +204,276,1631821,6,2,B|91:252|43:156,1,200,6|2 +304,48,1632600,2,0,B|428:72|444:204,2,200,8|2|0 +304,48,1633574,1,0 +304,48,1633769,1,2 +456,284,1634159,2,0,B|372:344|264:304,2,200,8|2|4 +240,104,1635328,6,2,B|140:108|72:204,1,200,2|8 +340,108,1636107,2,2,B|304:212|172:196,1,200 +180,196,1636691,1,0 +180,196,1636886,2,2,B|196:324|328:324,1,200,2|10 +452,84,1637665,1,0 +452,84,1637860,5,8 +452,84,1637958,1,8 +452,84,1638055,2,0,B|348:116|244:68,1,200,6|0 +64,124,1638834,1,8 +64,124,1639224,2,2,B|64:228|152:308,1,200 +244,316,1639808,1,0 +256,216,1640003,1,0 +256,192,1640393,12,8,1641951 +416,192,1642536,5,0 +416,192,1642730,2,8,B|432:116,2,66.6666666666667,0|8|8 +352,272,1643120,2,0,B|368:356,2,66.6666666666667,8|8|0 +292,192,1643510,2,0,B|272:120,2,66.6666666666667,0|8|8 +232,272,1643899,2,0,B|204:348,2,66.6666666666667,8|0|0 +132,296,1644289,1,4 +104,96,1644678,5,0 +196,136,1644873,1,0 +288,96,1645068,1,8 +456,208,1645458,1,0 +356,192,1645652,1,0 +264,228,1645847,2,2,B|152:228|60:324,2,200,10|2|10 +432,116,1647016,1,6 +264,228,1647406,5,8 +344,172,1647600,2,0,B|364:124,2,50 +248,152,1647990,1,0 +176,80,1648185,1,8 +76,96,1648380,1,0 +32,188,1648574,1,0 +84,272,1648769,1,0 +132,260,1648867,1,0 +176,280,1648964,6,2,B|248:344|368:312,1,200,10|2 +248,152,1649743,1,8 +424,56,1650133,2,2,B|320:28|224:56,1,200,2|10 +256,252,1650912,2,2,B|368:252|432:364,1,200,2|10 +220,344,1651691,5,2 +120,328,1651886,1,0 +128,228,1652081,1,8 +36,48,1652471,2,2,B|244:48,1,200,2|10 +436,60,1653250,2,2,B|420:160|468:268,1,200,2|10 +376,304,1653834,5,0 +292,192,1654029,1,0 +268,236,1654126,1,0 +220,248,1654224,1,0 +172,236,1654321,1,0 +148,192,1654419,1,8 +84,68,1654613,1,0 +32,196,1654808,5,0 +32,196,1655003,1,0 +32,196,1655198,1,10 +256,348,1655587,1,2 +476,192,1655977,1,10 +256,40,1656367,2,0,B|256:152,2,100,2|0|6 +160,192,1657146,5,0 +256,220,1657341,1,0 +340,164,1657536,1,8 +156,92,1657925,1,0 +80,156,1658120,1,0 +92,256,1658315,1,10 +276,176,1658704,6,2,B|312:288|196:344,2,200,2|10|2 +212,100,1659678,1,0 +308,68,1659873,1,8 +472,184,1660263,2,0,B|472:244|424:280,2,100,0|0|8 +376,360,1661042,1,0 +324,272,1661237,1,0 +324,272,1661334,1,0 +324,272,1661432,6,0,B|216:248|128:328,1,200,8|0 +52,268,1662016,1,0 +36,168,1662211,2,0,B|84:68|196:64,1,200,2|2 +256,144,1662795,1,0 +256,192,1662990,12,0,1666107 +256,192,1677016,12,4,1678574 +256,180,1678964,5,0 +256,180,1679159,1,0 +256,180,1679354,1,2 +160,308,1679743,1,0 +100,252,1679938,1,0 +56,184,1680133,2,0,B|140:92,1,100,2|0 +196,76,1680523,2,0,B|308:76,3,100,0|0|2|0 +376,76,1681302,2,0,B|412:124|396:176,1,100 +364,244,1681691,5,4 +208,272,1682081,2,0,B|208:392,2,100,0|0|2 +68,192,1682860,1,0 +140,156,1683055,1,0 +152,76,1683250,1,2 +256,200,1683639,1,0 +364,80,1684029,1,2 +428,128,1684224,1,0 +440,208,1684419,1,0 +392,272,1684613,1,0 +392,272,1684808,6,0,B|304:264|180:304,1,200,4|0 +256,152,1685587,1,2 +256,152,1685782,1,0 +256,152,1685977,1,0 +100,188,1686367,1,2 +256,228,1686756,1,0 +412,188,1687146,1,2 +364,124,1687341,1,0 +292,92,1687536,1,0 +220,124,1687730,1,0 +172,188,1687925,1,2 +472,312,1688315,5,0 +400,348,1688510,1,0 +300,348,1688704,1,8 +184,312,1688899,1,8 +136,180,1689094,1,8 +248,68,1689289,1,8 +400,164,1689484,1,6 +56,68,1690263,5,0 +32,132,1690393,1,0 +36,200,1690523,1,8 +68,256,1690652,1,8 +124,296,1690782,1,8 +192,300,1690912,1,0 +252,272,1691042,6,2,B|360:300|428:200,1,200,6|2 +300,48,1691821,1,8 +156,188,1692211,1,2 +284,240,1692406,1,0 +396,172,1692600,2,0,B|452:160|492:200,2,100,0|0|2 +256,316,1693380,1,8 +220,120,1693769,6,2,B|128:48|32:120,1,200,2|6 +56,316,1694549,2,2,B|260:316,1,200,2|10 +452,280,1695328,1,2 +424,184,1695523,1,0 +444,88,1695717,1,0 +348,120,1695912,1,0 +248,128,1696107,1,2 +256,328,1696497,1,8 +92,212,1696886,1,0 +92,212,1697081,5,0 +92,212,1697178,1,0 +92,212,1697276,2,2,B|191:234|304:212,2,200,6|2|10 +200,44,1698445,2,2,B|292:20|416:52,1,200 +444,136,1699029,1,0 +408,232,1699224,1,0 +256,192,1699613,12,0,1701562 +428,192,1701951,5,4 +376,192,1702049,1,0 +328,192,1702146,1,0 +280,192,1702243,1,0 +228,192,1702341,6,0,B|240:260,2,66.6666666666667,0|0|0 +132,228,1702730,2,0,B|100:300,2,66.6666666666667,0|0|0 +100,132,1703120,2,0,B|28:152,2,66.6666666666667 +192,88,1703510,6,2,B|284:44|404:92,1,200,6|2 +420,284,1704289,2,2,B|332:360|228:284,1,200,10|2 +156,352,1704873,1,0 +156,252,1705068,1,0 +60,280,1705263,1,0 +52,180,1705458,2,2,B|148:132|192:32,1,200,2|10 +360,284,1706237,6,2,B|448:204|384:92,2,200,2|6|2 +256,112,1707406,1,8 +184,300,1707795,2,2,B|96:268|56:136,1,200 +32,56,1708380,1,0 +132,56,1708574,2,2,B|352:56,1,200,2|10 +480,188,1709354,5,8 +460,288,1709549,1,8 +412,280,1709646,1,8 +380,240,1709743,1,6 +200,328,1710133,2,0,B|160:236|196:120,2,200,0|8|2 +100,152,1711302,1,0 +28,220,1711497,1,0 +16,120,1711691,1,8 +96,60,1711886,1,0 +196,56,1712081,2,2,B|308:32|400:88,1,200 +356,176,1712665,1,0 +308,264,1712860,1,4 +256,192,1712958,12,0,1714419 +256,308,1748243,6,0,B|256:364,2,54.9999983608723 +256,252,1749012,2,0,B|244:216|268:192|256:144,1,109.999996721745,0|0 +284,36,1750038,1,0 +228,36,1750294,1,0 +347,99,1750807,6,0,B|392:128|424:192|392:260|348:284,1,219.999993443489 +256,192,1752602,1,0 +164,100,1753115,2,0,B|120:124|88:192|120:256|164:284,1,219.999993443489 +332,292,1755166,54,0,B|320:352|256:392|192:352|180:292,1,219.999993443489 +176,236,1756448,1,0 +228,216,1756704,1,0 +284,216,1756961,1,0 +336,236,1757217,1,0 +436,188,1757730,1,0 +348,124,1758243,5,0 +308,84,1758499,2,0,B|256:68|256:68|204:84,1,109.999996721745,0|0 +204,140,1759268,2,0,B|200:184|256:220|312:184|308:140,1,164.999995082617,0|0 +356,332,1760807,6,0,B|324:360|288:364|256:336|256:336|224:364|188:360|156:332,1,219.999993443489,0|0 +204,272,1762345,2,0,B|256:300|308:272,1,109.999996721745,2|0 +336,188,1763371,2,0,B|304:168|256:188|256:188|208:208|176:196,1,165.99999386549,4|8 +100,164,1764140,6,0,B|76:132|74:87,1,82.9999969327451,0|8 +140,32,1764653,2,0,B|220:56,1,82.9999969327451,0|8 +300,76,1765166,1,0 +324,156,1765422,2,0,B|304:188|256:220|208:188|186:154,1,165.99999386549,2|8 +212,76,1766192,1,0 +292,55,1766448,2,0,B|372:32,1,82.9999969327451,2|0 +436,86,1766961,2,0,B|436:132|412:164,1,82.9999969327451,8|0 +336,236,1767474,2,0,B|256:196|176:236,2,165.99999386549,4|8|2 +416,252,1768756,5,0 +432,172,1769012,1,8 +348,156,1769268,2,0,B|260:155|212:76,1,165.99999386549,2|0 +299,76,1770038,2,0,B|251:155|163:155,1,165.99999386549,2|8 +80,144,1770807,1,0 +132,80,1771063,1,2 +52,68,1771320,1,0 +16,196,1771576,2,0,B|36:360,1,165.99999386549,4|8 +116,340,1772345,2,0,B|108:280|108:280|100:220|144:188,1,165.99999386549,2|0 +224,168,1773115,5,8 +288,216,1773371,1,0 +367,196,1773627,2,0,B|412:164|404:104|404:104|396:44,2,165.99999386549,2|8|8 +320,128,1774909,1,0 +256,72,1775166,1,2 +196,128,1775422,1,0 +180,208,1775679,6,0,B|200:284|272:284|272:284|308:284,1,165.99999386549,4|8 +392,288,1776448,2,0,B|372:364|300:364|300:364|264:364,1,165.99999386549,2|0 +180,360,1777217,2,0,B|156:272|64:256,1,165.99999386549,2|8 +40,176,1777986,5,0 +96,116,1778243,1,8 +176,100,1778499,1,0 +256,112,1778756,1,2 +344,192,1779012,1,0 +256,272,1779268,1,8 +168,192,1779525,1,0 +256,112,1779781,1,4 +324,44,1780038,54,0,B|408:32,1,82.9999969327451,0|8 +500,96,1780551,2,0,B|416:108,1,82.9999969327451,0|2 +364,192,1781063,2,0,B|388:272,1,82.9999969327451,0|8 +336,347,1781576,2,0,B|256:314|170:348,1,165.99999386549,4|0 +148,192,1782345,2,0,B|124:272,1,82.9999969327451,2|0 +64,216,1782858,5,8 +88,136,1783115,2,0,B|112:56,1,82.9999969327451,2|0 +196,52,1783627,2,0,B|236:76|256:108|256:108|276:76|316:52,1,165.99999386549,4|0 +364,120,1784397,5,2 +256,176,1784653,1,0 +148,120,1784909,1,2 +336,224,1785166,1,0 +176,224,1785422,1,2 +256,360,1785679,1,0 +256,276,1785935,1,8 +256,192,1786192,1,0 +344,136,1786448,6,0,B|360:52,1,82.9999969327451,8|0 +256,1,1786961,2,0,B|256:84,1,82.9999969327451,2|0 +168,136,1787474,2,0,B|152:52,1,82.9999969327451,8|0 +44,176,1787986,2,0,B|24:340,1,165.99999386549,4|8 +112,296,1788756,2,0,B|116:212,1,82.9999969327451,0|2 +204,81,1789268,2,0,B|204:164,1,82.9999969327451,0|8 +280,244,1789781,5,0 +468,208,1790038,2,0,B|488:44,1,165.99999386549,4|8 +400,88,1790807,2,0,B|396:172,1,82.9999969327451,0|2 +309,302,1791320,2,0,B|308:220,1,82.9999969327451,0|8 +256,136,1791833,1,0 +184,56,1792089,2,0,B|208:24|256:8|300:24|330:57,1,165.99999386549,4|8 +328,156,1792858,5,0 +256,224,1793115,2,0,B|176:276|208:368,1,165.99999386549,2|8 +305,366,1793884,2,0,B|338:275|254:224,1,165.99999386549,2|8 +256,124,1794653,1,8 +256,48,1795166,5,0 +256,244,1795422,1,8 +184,124,1795679,1,8 +328,124,1795935,1,8 +400,244,1796192,1,4 +340,336,1796448,6,2,B|316:280|256:248|196:280|171:338,1,219.999993443489,2|0 +64,352,1797217,2,0,B|40:244,1,109.999996721745,2|0 +92,148,1797730,1,8 +184,84,1797986,2,0,B|268:100|316:156|332:228,1,219.999993443489,4|0 +256,308,1798756,1,8 +180,228,1799012,2,0,B|197:155|245:99|329:83,1,219.999993443489,2|0 +432,120,1799781,1,8 +456,336,1800038,6,0,B|348:288|348:160,1,219.999993443489,4|0 +312,56,1800807,1,8 +200,56,1801063,1,0 +256,216,1801320,1,2 +256,104,1801576,1,0 +164,160,1801833,1,8 +108,68,1802089,1,0 +165,160,1802345,2,0,B|164:288|56:336,1,219.999993443489,4|8 +12,236,1803115,5,0 +64,216,1803243,2,0,B|144:236|200:304,1,164.999995082617,2|0 +308,276,1803884,1,8 +232,196,1804140,1,2 +96,132,1804397,2,0,B|72:75|124:3|204:35|212:103,1,219.999993443489,4|8 +300,36,1805166,1,0 +356,36,1805294,2,0,B|388:32|408:16|408:16|424:40|448:52,1,109.999996721745,2|0 +500,72,1805679,5,2 +492,180,1805935,1,8 +388,148,1806192,1,0 +416,252,1806448,2,0,B|440:309|388:381|308:349|300:281,1,219.999993443489,4|8 +208,220,1807217,2,0,B|199:152|119:120|67:192|91:249,1,219.999993443489,2|0 +176,320,1807986,1,8 +280,352,1808243,1,0 +404,276,1808499,5,4 +404,276,1808756,2,0,B|336:192,1,109.999996721745,2|8 +108,107,1809268,2,0,B|178:193,1,109.999996721745,2|0 +328,100,1809781,2,0,B|360:48|408:28,2,109.999996721745,0|8|2 +185,283,1810551,2,0,B|152:336|104:356,2,109.999996721745,0|2|8 +296,228,1811320,6,0,B|260:212|252:172|216:156,2,109.999996721745,0|2|8 +368,144,1812089,5,8 +308,52,1812345,1,8 +256,36,1812474,1,0 +204,52,1812602,1,4 +144,144,1812858,1,2 +92,240,1813115,1,8 +148,336,1813371,1,0 +256,344,1813627,2,0,B|308:324|324:264,1,109.999996721745,2|0 +268,168,1814140,5,8 +204,256,1814397,2,0,B|292:332|408:316,1,219.999993443489,4|0 +484,236,1815166,1,8 +492,124,1815422,2,0,B|464:52|368:32|312:100,1,219.999993443489,2|0 +216,156,1816192,1,8 +56,48,1816448,6,0,B|8:168|92:252,1,219.999993443489,4|0 +200,256,1817217,2,0,B|312:256,1,109.999996721745,8|0 +420,240,1817730,2,0,B|360:332,1,109.999996721745,2|0 +312,360,1818115,1,2 +200,360,1818371,1,0 +152,332,1818499,2,0,B|92:240,1,109.999996721745,2|4 +256,252,1819012,5,0 +208,100,1819268,1,8 +332,196,1819525,1,0 +180,196,1819781,1,2 +304,100,1820038,5,0 +256,168,1820294,1,8 +400,108,1820551,1,0 +420,160,1820679,1,0 +440,212,1820807,1,4 +356,284,1821063,2,0,B|304:288|256:244|256:244|208:288|156:284,1,219.999993443489,2|0 +52,320,1821833,1,2 +72,212,1822089,5,0 +92,160,1822217,1,0 +112,108,1822345,1,8 +156,8,1822602,2,0,B|207:4|255:48|255:48|303:4|354:7,1,219.999993443489,4|0 +352,120,1823371,1,8 +256,172,1823627,1,2 +160,120,1823884,1,0 +192,224,1824140,5,8 +180,276,1824268,1,0 +204,324,1824397,1,8 +256,344,1824525,1,0 +308,324,1824653,1,2 +332,276,1824781,1,0 +320,224,1824909,1,4 +152,140,1830294,6,0,B|232:111,1,83.5000010451675,0|8 +360,244,1830807,2,0,B|280:272,1,83.5000010451675,0|2 +124,240,1831320,2,0,B|204:212,1,83.5000010451675,0|8 +388,144,1831833,2,0,B|308:172,1,83.5000010451675,0|2 +208,60,1832345,2,0,B|236:140,1,83.5000010451675,0|8 +304,324,1832858,2,0,B|276:244,1,83.5000010451675,0|4 +440,232,1833627,5,8 +428,152,1833884,1,0 +360,200,1834140,1,2 +504,180,1834397,5,0 +492,100,1834653,1,8 +416,72,1834909,1,0 +332,68,1835166,2,0,B|292:68|292:68|256:44|256:44|220:68|220:68|180:68,1,167.000002090335,2|8 +96,72,1835935,1,0 +20,100,1836192,1,2 +8,180,1836448,1,0 +84,148,1836704,1,8 +176,284,1837217,6,0,B|343:284,2,167.000002090335,0|8|0 +100,164,1838499,6,0,B|180:192,1,83.5000010451675,2|8 +412,164,1839012,2,0,B|332:192,1,83.5000010451675,0|2 +76,72,1839525,2,0,B|156:100,1,83.5000010451675,0|8 +436,72,1840038,2,0,B|356:100,1,83.5000010451675,0|2 +256,52,1840551,1,0 +256,136,1840807,1,8 +256,176,1840935,1,0 +256,216,1841063,1,8 +256,300,1841320,1,4 +92,312,1841833,6,0,B|48:304|28:264,1,83.5000010451675,8|0 +104,232,1842345,1,2 +168,180,1842602,1,0 +192,100,1842858,1,8 +196,16,1843115,1,0 +116,36,1843371,2,0,B|120:124|42:176,2,167.000002090335,4|8|2 +176,152,1844653,6,4,B|256:136|256:136|338:152,1,167.000002090335,4|0 +395,36,1845422,2,0,B|392:124|468:178,1,167.000002090335,4|8 +492,96,1846192,2,0,B|368:205,1,167.000002090335,2|2 +292,172,1846961,1,8 +152,104,1847217,6,0,B|116:188|17:185,1,167.000002090335,2|0 +8,268,1847986,2,0,B|85:296,1,83.5000010451675,8|0 +221,264,1848499,2,0,B|143:235,1,83.5000010451675,2|0 +220,344,1849012,2,0,B|299:374,1,83.5000010451675,8|0 +432,356,1849525,5,4 +508,328,1849781,2,0,B|488:288|445:276,1,83.5000010451675,0|8 +364,268,1850294,2,0,B|358:176|289:122,1,167.000002090335 +352,68,1851063,2,0,B|296:8,1,83.5000010451675,8|0 +216,7,1851576,2,0,B|160:68,1,83.5000010451675,2|0 +80,88,1852089,2,0,B|44:168,1,83.5000010451675,8|0 +16,240,1852602,1,2 +32,312,1852858,2,0,B|104:332|124:260|189:280,1,167.000002090335 +323,280,1853627,6,0,B|388:260|408:332|481:311,1,167.000002090335,4|8 +456,240,1854397,2,0,B|388:260|408:332|340:352,1,167.000002090335,0|2 +256,280,1855166,1,8 +148,324,1855422,1,0 +104,220,1855679,1,2 +212,176,1855935,1,0 +256,280,1856192,5,8 +104,220,1856448,1,0 +164,64,1856704,1,2 +316,124,1856961,1,0 +316,124,1857089,1,8 +316,124,1857217,1,8 +420,252,1857474,1,8 +420,252,1857602,1,8 +420,252,1857730,5,4 +476,192,1857986,1,0 +500,272,1858243,2,0,B|496:332|424:344|424:344|372:352,1,167.000002090335,8|2 +300,312,1859012,1,0 +256,240,1859268,1,8 +212,312,1859525,1,0 +137,351,1859781,2,0,B|87:344|87:344|15:332|10:271,1,167.000002090335,4|8 +96,264,1860551,2,0,B|176:244,1,83.5000010451675,0|2 +124,180,1861063,2,0,B|200:148,2,83.5000010451675,0|8|0 +120,96,1861833,6,0,B|176:28|271:47,1,167.000002090335,4|8 +292,160,1862602,1,0 +256,264,1862858,1,2 +220,160,1863115,1,0 +312,224,1863371,1,8 +200,224,1863627,1,0 +243,48,1863884,6,0,B|336:28|393:97,1,167.000002090335,4|8 +460,168,1864653,1,0 +408,252,1864909,1,2 +424,348,1865166,1,0 +324,336,1865422,1,8 +244,280,1865679,1,8 +224,316,1865807,1,8 +188,336,1865935,5,4 +168,256,1866192,2,0,B|212:188|306:172,1,167.000002090335,2|0 +336,96,1866961,2,0,B|376:112|384:160,1,83.5000010451675,2|0 +424,232,1867474,1,8 +344,256,1867730,2,0,B|300:188|206:170,1,167.000002090335,4|0 +128,158,1868499,2,0,B|136:112|176:96,1,83.5000010451675,8|0 +120,12,1869012,2,0,B|112:58|72:74,1,83.5000010451675,2|0 +0,116,1869525,1,8 +40,188,1869781,1,0 +112,148,1870038,1,4 +256,64,1870551,6,0,B|288:132|224:236|256:310,2,250.500003135502,8|2|8 +256,64,1872217,1,0 +380,64,1872474,2,0,B|420:80,1,41.7500005225837 +440,192,1872858,2,0,B|376:164|376:164,1,41.7500005225837 +240,168,1873371,5,8 +204,216,1873499,1,8 +144,224,1873627,1,8 +92,188,1873756,1,0 +88,128,1873884,1,8 +124,76,1874012,1,8 +184,68,1874140,5,4 +292,76,1874397,2,0,B|364:88|360:168|360:168|356:260,1,219.999993443489,2|0 +324,364,1875166,1,2 +256,276,1875422,1,0 +188,364,1875679,1,8 +156,260,1875935,2,0,B|152:168|152:168|148:88|220:76,1,219.999993443489,2|0 +324,104,1876704,1,8 +256,192,1876961,2,0,B|184:104|72:80,1,219.999993443489,2|0 +168,24,1877730,1,8 +256,192,1877986,6,0,B|328:280|440:304,1,219.999993443489,4|0 +352,372,1878756,1,8 +252,328,1879012,2,0,B|216:280|160:276,1,109.999996721745,0|2 +28,300,1879525,2,0,B|64:348|120:352,1,109.999996721745,0|8 +76,224,1880038,1,0 +36,120,1880294,6,0,B|32:76|104:40|120:84|136:128|208:92|196:48,1,219.999993443489,4|8 +204,156,1881063,1,0 +216,208,1881192,2,0,B|228:244|256:244|284:244|296:208,1,109.999996721745,2|0 +308,156,1881576,1,2 +360,24,1881833,1,8 +452,132,1882089,1,2 +476,272,1882345,6,0,B|480:316|408:352|392:308|376:264|304:300|316:344,1,219.999993443489,4|8 +256,252,1883115,1,0 +200,344,1883371,1,2 +108,284,1883627,2,0,B|84:176,1,109.999996721745,0|8 +164,100,1884140,2,0,B|176:208,1,109.999996721745,0|2 +256,132,1884653,2,0,B|256:20,1,109.999996721745,0|8 +348,100,1885166,2,0,B|336:208,1,109.999996721745,0|2 +404,284,1885679,2,0,B|428:176,1,109.999996721745,0|8 +452,68,1886192,1,0 +256,40,1886448,5,4 +152,80,1886704,1,0 +256,196,1886961,1,8 +360,304,1887217,1,2 +256,344,1887474,1,0 +256,196,1887730,1,0 +104,192,1887986,5,8 +144,296,1888243,1,0 +256,196,1888499,1,0 +368,88,1888756,1,2 +408,192,1889012,1,8 +256,196,1889268,1,0 +104,192,1889525,1,2 +144,88,1889781,5,0 +256,40,1890038,1,8 +368,88,1890294,1,8 +396,136,1890422,1,0 +420,184,1890551,1,4 +416,296,1890807,2,0,B|368:312|316:288|316:288|256:256|196:288|196:288|144:312|96:296,1,329.999990165234,2|0 +148,200,1891833,1,0 +256,176,1892089,1,8 +403,79,1892345,6,0,B|456:100|456:100|432:152|456:204|456:204|403:224,1,219.999993443489,4|0 +256,256,1893115,1,8 +109,224,1893371,2,0,B|56:204|56:204|80:152|56:100|56:100|108:80,1,219.999993443489,2|0 +256,48,1894140,1,8 +344,196,1894397,6,0,B|300:264|204:264|160:196,1,219.999993443489,4|0 +152,84,1895166,1,8 +256,48,1895422,1,0 +360,84,1895679,1,2 +440,160,1895935,2,0,B|456:212,1,54.9999983608723,0|2 +412,312,1896320,2,0,B|396:260,1,54.9999983608723,0|2 +256,176,1896704,5,4 +208,328,1896961,1,0 +332,232,1897217,1,8 +180,232,1897474,1,0 +304,328,1897730,1,2 +256,256,1897986,1,0 +116,308,1898243,5,8 +80,264,1898371,1,0 +72,208,1898499,1,2 +84,156,1898627,1,0 +116,112,1898756,1,4 +312,12,1899268,5,8 +412,52,1899525,1,0 +324,120,1899781,1,2 +428,156,1900038,1,0 +428,336,1900294,5,8 +360,248,1900551,2,0,B|292:204|220:316|152:268,1,219.999993443489,4|0 +80,184,1901320,1,8 +188,160,1901576,1,0 +192,104,1901704,1,8 +196,48,1901833,1,8 +316,48,1902089,5,8 +320,104,1902217,1,8 +324,160,1902345,1,0 +340,212,1902474,1,8 +376,256,1902602,1,8 +424,280,1902730,1,0 +480,288,1902858,1,4 +256,132,1917730,5,0 +316,192,1917986,1,0 +256,252,1918243,1,8 +196,192,1918499,1,0 +256,92,1918756,5,2 +360,272,1919012,1,0 +152,272,1919268,1,4 +80,232,1919525,6,0,B|93:151,1,82.9999969327451,0|2 +56,47,1920038,2,0,B|16:120,2,82.9999969327451,0|8|0 +136,32,1920807,1,2 +208,68,1921063,1,0 +352,100,1921320,6,0,B|388:112|432:92|432:92|420:140|436:176,1,165.99999386549,4|2 +424,256,1922089,2,0,B|452:288|496:292,2,82.9999969327451,0|8|0 +360,204,1922858,2,0,B|312:272,1,82.9999969327451,2|0 +208,360,1923371,6,0,B|147:316|111:364|49:325,1,165.99999386549,4|2 +60,240,1924140,2,0,B|108:240|132:208,1,82.9999969327451,0|8 +148,88,1924653,2,0,B|152:132|193:153,1,82.9999969327451,0|2 +212,232,1925166,2,0,B|180:308,1,82.9999969327451 +256,336,1925679,1,0 +332,308,1925935,6,0,B|299:231,1,82.9999969327451,0|0 +312,148,1926448,1,8 +404,60,1926704,1,0 +376,180,1926961,1,2 +328,68,1927217,1,0 +436,132,1927474,1,4 +136,180,1927986,5,2 +108,60,1928243,1,0 +200,140,1928499,1,8 +76,132,1928756,1,0 +184,68,1929012,1,2 +136,180,1929268,1,0 +176,296,1929525,6,0,B|340:296,1,165.99999386549,4|2 +400,236,1930294,2,0,B|330:191,1,82.9999969327451,0|8 +256,152,1930807,1,0 +181,191,1931063,2,0,B|112:236,1,82.9999969327451,2|0 +80,128,1931576,6,0,B|112:48|112:48|188:24,1,165.99999386549,4|2 +256,100,1932345,1,0 +324,24,1932602,2,0,B|400:48|400:48|432:128,1,165.99999386549,8|2 +408,204,1933371,1,0 +388,240,1933499,1,0 +356,268,1933627,1,0 +308,200,1933884,1,0 +256,264,1934140,1,0 +204,200,1934397,1,0 +256,136,1934653,1,8 +104,204,1934909,5,0 +124,240,1935038,1,0 +156,268,1935166,1,0 +256,264,1935422,1,0 +256,280,1935679,1,0 +136,128,1950038,6,0,B|134:99|134:99,5,27.6666656442484 +208,128,1950551,2,0,B|208:95|208:95,5,27.6666656442484 +280,128,1951063,2,0,B|280:97|280:97,5,27.6666656442484 +352,128,1951576,2,0,B|352:99|352:99,5,27.6666656442484 +404,184,1952089,6,0,B|384:244|304:256|304:256|216:268,1,219.999993443489,4|8 +104,280,1952858,1,0 +128,328,1952986,2,0,B|188:328|228:364,1,109.999996721745,2|0 +287,368,1953371,2,0,B|328:332|388:332,1,109.999996721745,2|8 +356,228,1953884,6,0,B|384:184|356:124|356:124|384:68|356:16,1,219.999993443489,4|0 +256,60,1954653,1,8 +155,16,1954909,2,0,B|128:68|156:124|156:124|128:184|156:228,1,219.999993443489,2|0 +256,184,1955679,1,8 +448,128,1955935,6,0,B|468:208|416:288|348:296,1,219.999993443489,4|0 +176,200,1956704,1,8 +256,52,1956961,1,0 +336,200,1957217,1,2 +176,104,1957474,1,0 +336,104,1957730,1,8 +256,248,1957986,1,0 +64,127,1958243,6,0,B|44:208|96:288|164:296,1,219.999993443489,4|8 +208,196,1959012,1,2 +256,168,1959140,1,0 +304,196,1959268,1,2 +388,80,1959525,1,0 +256,20,1959781,1,8 +124,80,1960038,1,2 +76,204,1960294,5,4 +84,336,1960551,2,0,B|112:288,1,54.9999983608723,2|0 +160,244,1960807,1,10 +256,152,1961063,2,0,B|256:208,1,54.9999983608723,2|0 +256,272,1961320,1,2 +428,336,1961576,2,0,B|400:288,1,54.9999983608723,2|0 +352,244,1961833,1,10 +256,332,1962089,1,0 +160,244,1962345,5,2 +216,244,1962474,1,0 +272,232,1962602,1,0 +320,204,1962730,1,0 +344,156,1962858,1,8 +348,100,1962986,1,0 +328,48,1963115,1,0 +284,16,1963243,1,0 +228,16,1963371,5,2 +184,48,1963499,1,0 +164,100,1963627,1,0 +168,156,1963756,1,0 +192,204,1963884,1,8 +240,232,1964012,1,0 +296,244,1964140,1,0 +352,244,1964268,1,0 +408,236,1964397,5,4 +408,124,1964653,1,0 +256,148,1964909,1,8 +316,44,1965166,1,2 +196,44,1965422,1,0 +108,208,1965679,5,2 +256,312,1965935,1,8 +404,208,1966192,1,4 +256,192,1966448,12,4,1968499 +76,64,1969012,5,8 +180,104,1969268,1,0 +140,208,1969525,2,0,B|112:260|56:272,2,109.999996721745,2|0|8 +40,160,1970294,6,0,B|72:276|180:320,1,219.999993443489,4|0 +256,192,1971063,1,8 +332,64,1971320,2,0,B|440:108|472:224,1,219.999993443489,2|0 +256,288,1972089,1,8 +40,223,1972345,6,0,B|72:108|180:64,1,219.999993443489,4|0 +200,172,1973115,2,0,B|312:172,2,109.999996721745,8|0|2 +148,268,1973884,1,0 +204,272,1974012,2,0,B|256:288|256:288|308:272,1,109.999996721745,2|0 +364,268,1974397,1,2 +190,203,1974653,6,0,B|116:168|116:64|192:28,1,219.999993443489,4|8 +256,116,1975422,1,0 +320,28,1975679,2,0,B|396:64|396:168|320:204,1,219.999993443489,4|8 +256,292,1976448,1,0 +168,360,1976704,6,0,B|204:284|308:284|344:360,2,219.999993443489,4|8|2 +144,252,1977986,1,0 +40,216,1978243,1,8 +56,324,1978499,1,4 +256,44,1979012,1,0 +456,324,1979525,1,2 +192,244,1980038,5,8 +180,192,1980166,1,0 +204,144,1980294,1,8 +256,124,1980422,1,0 +308,144,1980551,1,2 +332,192,1980679,1,0 +320,244,1980807,1,4 +256,64,1994397,5,2 +336,320,1994825,1,0 +128,160,1995254,1,0 +384,160,1995682,1,0 +176,320,1996111,1,0 +256,192,1996539,1,0 +336,320,1996968,1,2 +336,144,1997397,6,0,B|320:101|256:69|192:101|176:149,1,200 +384,32,1998254,1,2 +256,192,1998682,1,0 +128,32,1999111,1,0 +176,240,1999539,2,0,B|192:283|256:315|320:283|336:235,1,200,2|0 +128,352,2000397,5,0 +256,192,2000825,1,0 +384,352,2001254,1,0 +472,200,2001682,2,0,B|456:96|456:96|384:32,1,200,0|2 +213,100,2002539,2,0,B|192:128|208:176|255:196|304:176|320:128|296:95,1,200 +126,33,2003397,2,0,B|56:96|56:96|40:200,1,200,2|0 +176,352,2004254,6,0,B|200:312|256:296|256:296|312:312|336:352,1,200,0|2 +301,182,2005111,1,0 +213,182,2005325,1,0 +304,24,2005754,2,0,B|349:50|349:50|368:96,1,100,0|2 +208,24,2006397,2,0,B|163:50|163:50|144:96,1,100 +339,233,2007254,6,0,B|380:288|348:384|255:424|157:384|125:288|173:223,1,400,2|0 +86,73,2008539,2,0,B|108:33|161:17|214:22|256:77|256:77|299:21|352:13|416:31|429:79|429:79,1,400,2|0 +336,248,2009825,2,0,B|320:202|256:170|192:202|176:245,1,200,2|0 +176,336,2010468,2,0,B|191:381|255:413|319:381|335:338,1,200 +256,296,2011111,5,2 +336,136,2011539,1,0 +176,136,2011968,1,0 +256,176,2012182,1,0 +336,136,2012397,2,0,B|368:80|336:32|304:16|304:16|256:52|256:52|208:16|208:16|176:32|136:80|180:144,1,400,2|0 +94,276,2013682,2,0,B|134:359|222:383|262:386|300:380|377:360|420:275,1,400,2|0 +256,192,2014968,5,2 +104,112,2015397,1,0 +184,64,2015611,2,0,B|199:18|263:-13|327:18|343:61,1,200 +408,112,2016254,1,2 +256,192,2016682,5,0 +168,360,2017111,1,0 +256,320,2017325,1,0 +340,360,2017539,2,0,B|395:298|408:225|358:155|311:129|254:113|210:125|154:141|108:209|110:255|111:328|188:373,1,600,2|2 +32,240,2019254,2,0,B|32:140,1,100 +104,84,2019682,1,0 +176,248,2020111,2,0,B|200:288|256:304|256:304|312:288|336:248,1,200,2|0 +336,156,2020754,2,0,B|312:116|256:100|256:100|200:116|176:156,1,200 +256,200,2021397,5,2 +356,348,2021825,1,0 +480,240,2022254,2,0,B|480:140,1,100,2|0 +408,84,2022682,1,0 +300,228,2023111,6,0,B|321:256|305:304|258:324|209:304|193:256|217:223,1,200,0|2 +256,148,2023754,1,0 +256,60,2023968,1,0 +100,84,2024397,1,2 +100,84,2024611,1,0 +100,84,2024825,1,0 +175,247,2025254,2,0,B|190:293|254:324|318:293|334:250,2,200,2|0|0 +342,361,2026539,5,2 +256,200,2026968,1,0 +256,200,2027182,1,0 +169,361,2027611,1,0 +169,361,2027825,1,2 +64,203,2028254,6,0,B|92:107|92:107|168:43,1,200,0|2 +343,42,2029111,2,0,B|420:107|420:107|448:203,1,200 +336,339,2029968,1,2 +256,312,2030182,1,0 +176,340,2030397,2,0,B|160:282|194:232|256:224|256:224|296:208|328:160|296:112|256:104|216:112|176:160|216:208|256:224|256:224|320:232|355:286|334:348,1,600,0|2 +440,192,2032111,5,0 +344,40,2032539,1,0 +256,16,2032754,1,0 +168,40,2032968,1,2 +72,192,2033397,1,0 +211,312,2033825,2,0,B|190:340|206:388|253:408|302:388|318:340|294:307,1,200,0|2 +208,156,2034682,5,0 +256,24,2034897,1,0 +304,156,2035111,1,2 +184,72,2035325,1,0 +324,76,2035539,1,0 +408,236,2035968,5,2 +256,340,2036397,1,0 +104,236,2036825,1,2 +172,68,2037254,1,0 +172,68,2037468,1,0 +340,68,2037897,1,0 +340,68,2038111,1,0 +256,200,2038539,5,2 +336,360,2038968,2,0,B|312:320|256:304|256:304|200:320|176:360,1,200,0|2 +104,196,2039825,1,0 +256,100,2040254,1,2 +408,200,2040682,1,0 +256,192,2040897,12,0,2043254 +256,24,2044325,5,2 +301,102,2044539,2,0,B|322:130|306:178|259:198|210:178|194:130|218:97,1,200 +340,232,2045397,1,2 +256,260,2045611,1,0 +172,232,2045825,1,4 +76,360,2046254,1,0 +436,360,2047111,1,2 +334,144,2047539,6,0,B|320:183|265:230|188:199|179:142|179:142,1,200,0|2 +212,52,2048182,2,0,B|224:38|241:23|296:26|305:57|305:57,1,100 +64,336,2049682,5,2 +173,204,2050111,2,0,B|187:236|247:285|320:257|341:200|341:200,1,200,0|2 +374,109,2050754,2,0,B|347:44|270:-14|156:19|137:117|137:117,1,300 +448,336,2052254,1,2 +256,192,2052682,5,0 +192,250,2052897,2,0,B|157:294|184:334|233:346|256:312|256:312|282:348|328:336|364:292|309:241,2,300,0|2|0 +56,324,2054611,1,0 +56,324,2054825,5,2 +176,96,2055254,2,0,B|200:56|256:40|256:40|312:56|336:96,1,200,0|2 +256,144,2055897,1,0 +336,188,2056111,2,0,B|312:228|256:244|256:244|200:228|176:188,1,200 +344,356,2057397,2,0,B|312:320|276:336|256:356|256:356|236:332|192:320|160:368,1,200,2|0 +256,264,2058039,1,0 +359,34,2058682,6,0,B|413:71|379:165|309:209|236:120|188:73|200:24|245:-2|264:-12|283:-2|302:16|321:73|283:120|231:211|109:185|106:73|123:44|171:20,1,600,2|2 +256,208,2060397,1,0 +212,372,2060825,1,2 +300,372,2061039,1,0 +136,168,2061682,6,0,B|163:233|240:291|354:258|373:160|373:160,1,300,0|0 +337,73,2062539,2,0,B|323:41|263:-8|190:20|169:77|169:77,1,200,2|0 +254,129,2063182,1,0 +176,352,2063825,1,2 +256,316,2064039,1,0 +336,352,2064254,1,0 +256,192,2064468,12,0,2065968 +46,270,2066397,6,0,B|106:194|106:194|46:110,1,200,2|0 +299,34,2067254,2,0,B|320:62|304:110|257:130|208:110|192:62|216:29,1,200,2|0 +454,270,2068111,2,0,B|394:194|394:194|454:110,1,200,2|0 +298,350,2068968,2,0,B|319:322|303:274|256:254|207:274|191:322|215:355,1,200,4|0 +480,60,2070254,6,0,B|480:107|412:116|391:71|391:71|372:26|320:26|301:71|301:71|284:116|230:116|211:71|211:71|194:26|140:26|123:71|123:71|99:116|33:107|33:58,2,600 +256,200,2073254,5,0 +168,360,2073682,1,0 +340,360,2074111,2,0,B|395:298|408:225|358:155|311:129|254:113|210:125|154:141|108:209|110:255|111:328|188:373,2,600,8|8|8 +472,200,2077325,6,0,B|472:100,1,100,8|8 +392,56,2077754,1,0 +336,128,2077968,2,0,B|312:168|256:184|256:184|200:168|176:128,1,200,8|0 +40,200,2078825,2,0,B|40:100,1,100,8|0 +116,52,2079254,1,4 +177,271,2079682,6,0,B|201:231|257:215|257:215|313:231|337:271,1,200 +299,355,2080325,2,0,B|283:372|256:377|256:377|227:372|213:354,1,100,0|8 +144,90,2080968,6,0,B|153:55|199:44|221:77|199:100|209:146|242:133|255:48|255:48|265:133|298:146|310:100|288:77|310:44|364:50|366:88,1,400,0|8 +340,268,2082254,1,0 +256,304,2082468,1,8 +172,268,2082682,1,0 +328,360,2083111,5,8 +256,196,2083539,1,0 +184,360,2083968,1,0 +112,194,2084397,2,0,B|172:135|127:69|127:69|216:94|257:0|257:0|292:94|382:69|382:69|339:136|399:194,2,600,8|8|8 +206,348,2087397,6,0,B|310:348,1,100,8|8 +355,271,2087825,2,0,B|154:271,1,200,8|8 +208,40,2088682,6,0,B|312:40,1,100,8|8 +357,117,2089111,2,0,B|156:117,1,200,8|4 +52,260,2089968,1,0 +212,344,2090397,2,0,B|224:358|241:373|296:370|305:339|305:339,1,100,0|2 +256,268,2090825,1,8 +460,260,2091254,1,0 +416,84,2091682,5,2 +352,148,2091897,1,0 +328,60,2092111,1,8 +160,148,2092539,1,0 +96,84,2092754,1,8 +184,60,2092968,1,0 +129,290,2093397,6,0,B|157:341|243:400|353:360|384:290|384:290,1,300,8|0 +300,228,2094254,2,0,B|288:242|271:257|216:254|207:223|207:223,1,100,2|0 +256,144,2094682,1,8 +148,44,2095111,6,0,B|72:112|72:112|56:208,1,200 +80,288,2095754,1,0 +168,324,2095968,2,0,B|192:360|232:360|256:344|256:344|276:360|320:360|344:324,1,200,8|0 +456,208,2096825,2,0,B|440:112|440:112|364:44,1,200,2|8 +256,192,2097682,1,0 +301,268,2097897,2,0,B|256:288|256:288|210:268,1,100,8|0 +48,344,2098539,5,8 +192,48,2099182,2,0,B|160:89|184:161|254:190|327:161|351:89|315:40,1,300,2|8 +464,344,2100468,1,0 +256,272,2100897,5,2 +256,360,2101111,1,8 +172,208,2101539,2,0,B|186:176|246:127|319:155|340:212|340:212,1,200,0|0 +123,97,2102397,2,0,B|158:52|257:5|353:49|389:100,1,300,8|8 +388,99,2103254,1,0 +332,296,2103682,1,8 +256,340,2103897,1,0 +180,296,2104111,1,0 +176,208,2104325,1,0 +256,160,2104539,1,0 +336,208,2104754,1,0 +256,248,2104968,5,8 +256,36,2105611,1,0 +256,248,2106039,5,2 +176,304,2106254,2,0,B|200:344|256:360|256:360|312:344|336:304,1,200,8|0 +411,139,2107111,2,0,B|370:42,1,100,2|0 +299,99,2107539,2,0,B|320:127|304:175|257:195|208:175|192:127|216:94,1,200,8|0 +139,46,2108182,2,0,B|101:139,1,100,8|0 +128,288,2108825,2,0,B|256:368|256:368|384:288,1,300,8|8 +300,232,2109682,2,0,B|256:256|256:256|212:232,1,100,8|0 +256,152,2110111,1,4 +108,52,2110539,5,2 +204,204,2110968,2,0,B|210:255|210:255|254:287|302:255|302:255|306:203,1,200,0|8 +412,60,2111825,1,2 +412,60,2112039,1,0 +440,224,2112468,1,0 +440,224,2112682,2,0,B|416:324|416:324|328:368|328:368,1,200,8|2 +184,368,2113539,2,0,B|97:324|97:324|73:224,1,200,0|8 +176,76,2114397,2,0,B|200:116|256:132|256:132|312:116|336:76,1,200,2|8 +256,32,2115039,1,0 +256,32,2115254,5,4 +432,192,2115682,2,0,B|404:171|356:187|336:234|356:283|404:299|437:275,1,200,2|0 +256,360,2116539,1,8 +80,276,2116968,2,0,B|108:297|156:281|176:234|156:185|108:169|75:193,1,200,2|0 +176,40,2117825,5,8 +336,40,2118254,1,0 +256,96,2118468,1,8 +176,40,2118682,1,0 +256,200,2119111,1,8 +208,348,2119539,5,8 +176,260,2119754,1,8 +256,200,2119968,1,8 +336,260,2120182,1,0 +304,348,2120397,1,12 +348,72,2120825,6,0,B|288:72|288:72|256:48|256:48|224:72|224:72|164:72,1,200,2|0 +160,352,2121682,6,0,B|128:338|79:278|107:205|164:184|164:184,1,200,8|2 +256,172,2122325,2,0,B|256:372,1,200,0|2 +352,352,2122968,2,0,B|384:338|433:278|405:205|348:184|348:184,1,200,8|0 +256,32,2123825,5,2 +96,152,2124254,1,8 +164,336,2124682,1,2 +348,336,2125111,1,0 +416,152,2125539,1,0 +256,192,2125647,12,0,2127682 +348,80,2127897,6,0,B|288:80|288:80|256:56|256:56|224:80|224:80|164:80,1,200,2|0 +172,288,2128754,2,0,B|186:256|246:207|319:235|340:292|340:292,1,200,0|0 +256,344,2129397,1,8 +192,152,2129825,2,0,B|156:56,1,100,8|0 +256,68,2130254,1,8 +320,152,2130468,2,0,B|356:56,1,100,0|4 +426,311,2131111,6,0,B|404:351|351:367|298:362|256:307|256:307|213:363|160:371|96:353|83:305|83:305,1,400,0|8 +256,192,2132397,5,0 +340,32,2132825,1,2 +256,64,2133039,1,0 +172,32,2133254,1,8 +256,284,2133897,1,8 +182,323,2134111,2,0,B|256:387|256:387|336:323,1,200,0|8 +320,152,2134968,2,0,B|292:208|292:208|256:188|220:208|220:208|196:152,1,200 +144,76,2135611,2,0,B|196:64|232:20|232:20|256:56|256:56|276:20|276:20|320:64|368:76,1,300 +404,252,2136682,5,0 +256,356,2137111,1,8 +108,252,2137539,1,0 +164,172,2137754,2,0,B|224:140|256:172|304:220|288:268|224:268|208:220|256:172|288:140|348:172,2,300,0|2|0 +256,28,2139468,5,0 +256,28,2139682,1,8 +396,140,2140111,1,8 +344,216,2140325,1,8 +256,240,2140539,1,0 +168,216,2140754,1,8 +116,140,2140968,1,12 +113,306,2141397,2,0,B|128:352|192:368|224:336|224:288|184:272|152:320|204:368|256:368|256:368|308:368|360:320|328:272|288:288|288:336|324:368|400:344|403:296,1,456.000004348755,0|8 +256,144,2142682,1,0 +256,56,2142897,1,0 +344,360,2143539,6,0,B|294:310|319:215|378:210|418:265|378:315|304:290|254:225|254:225|204:290|129:315|89:265|129:210|189:215|214:310|164:360,1,600,0|8 +172,68,2145254,2,0,B|186:36|246:-13|319:15|340:72|340:72,1,200,0|2 +373,163,2145897,2,0,B|346:228|269:286|155:253|136:155|136:155,2,300,0|0|2 +440,224,2147397,5,8 +213,335,2147825,2,0,B|236:352|256:360|256:360|277:351|304:331,1,100,0|2 +76,228,2148682,1,8 +256,192,2148789,12,2,2151254 +60,85,2151682,6,0,B|32:134|31:182,1,100,2|8 +120,156,2152111,2,0,B|98:269|152:358,1,200,0|8 +451,298,2152968,6,0,B|479:249|480:201,1,100,8|8 +391,227,2153397,2,0,B|413:114|359:25,1,200,8|4 +256,192,2154254,5,0 +33,334,2155111,6,0,B|33:287|101:278|122:323|122:323|141:368|193:368|212:323|212:323|229:278|283:278|302:323|302:323|319:368|373:368|390:323|390:323|414:278|480:287|480:336,1,600,8|8 +256,152,2157039,1,8 +176,108,2157254,2,0,B|192:65|256:33|320:65|336:113,2,200,8|8|8 +256,264,2158539,1,8 +80,336,2158968,6,0,B|132:368|160:336|176:320|176:320|192:336|208:352|232:344|232:344|256:368|280:344|280:344|304:352|320:336|336:320|336:320|352:336|380:368|432:336,1,400,8|0 +340,172,2160254,2,0,B|381:116|349:21|256:-18|159:21|127:116|175:181,1,400,8|0 +157,353,2161539,2,0,B|358:353,1,200,8|0 +306,276,2162182,2,0,B|202:276,1,100,8|0 +56,176,2162825,5,8 +157,31,2163254,2,0,B|358:31,1,200,0|8 +306,108,2163897,2,0,B|202:108,1,100,0|4 +256,280,2164539,1,0 +456,176,2164968,5,0 +380,228,2165182,1,0 +464,268,2165397,1,8 +300,364,2165825,2,0,B|321:336|305:288|258:268|209:288|193:336|217:369,1,200 +256,192,2166682,1,8 +56,176,2167111,1,0 +132,228,2167325,1,8 +48,264,2167539,1,0 +256,192,2167968,5,8 +300,20,2168397,2,0,B|321:48|305:96|258:116|209:96|193:48|217:15,1,200 +97,157,2169254,2,0,B|128:223|176:255|256:301|335:255|383:223|415:160,1,400,8|0 +437,320,2170539,2,0,B|368:384|256:416|139:386|72:316,1,400,8|0 +165,176,2171825,2,0,B|195:207|256:237|316:207|346:176,1,200,8|0 +352,88,2172468,2,0,B|296:0,1,100,8|0 +213,5,2172897,2,0,B|159:89,1,100,8|8 +48,232,2173539,5,8 +24,320,2173754,1,0 +104,360,2173968,1,8 +176,304,2174182,1,0 +136,224,2174397,1,4 +76,56,2174825,2,0,B|128:20|112:100|207:51|191:51|191:51|223:83|255:50|255:50|287:83|330:51|314:51|314:51|384:100|384:20|442:59,1,400,0|8 +464,232,2176111,5,8 +488,320,2176325,1,0 +408,360,2176539,1,8 +336,304,2176754,1,0 +376,224,2176968,1,8 +312,56,2177397,2,0,B|416:104|416:104,1,100 +200,56,2178039,2,0,B|96:104|96:104,1,100,0|8 +176,264,2178682,2,0,B|232:272|256:216|256:216|280:272|336:264,1,200 +344,360,2179325,1,0 +344,360,2179539,2,0,B|312:396|276:380|256:360|256:360|236:384|192:396|160:348,2,200,4|0|0 +367,36,2180825,6,0,B|398:21|475:23|512:92|491:149|491:149,1,200,8|2 +456,240,2181468,2,0,B|392:271|296:264|232:164|282:78|282:78,1,300,0|2 +256,336,2182754,1,0 +256,336,2182968,1,0 +256,152,2183397,1,8 +145,36,2183825,2,0,B|114:21|37:23|0:92|21:149|21:149,1,200,8|2 +56,240,2184468,2,0,B|120:271|216:264|280:164|230:78|230:78,1,300,0|2 +388,164,2185539,5,0 +256,360,2185968,1,8 +124,164,2186397,1,2 +180,308,2186825,1,0 +256,272,2187039,1,0 +332,308,2187254,1,8 +256,24,2187897,5,8 +256,216,2188325,1,0 +336,172,2188539,2,0,B|312:132|256:116|256:116|200:132|176:172,2,200,8|0|0 +428,337,2189825,2,0,B|397:384|334:368|272:337|319:306|319:259|303:243|256:228|209:243|194:259|194:306|241:337|178:368|116:384|85:337,1,456.000004348755,4|0 +16,176,2191111,2,0,B|59:186|103:161|113:118|113:118|114:83|115:49|81:30|46:46|28:80|44:116|78:117|113:118|113:118|157:111|184:69|177:25,1,456.000004348755,8|0 +334,24,2192397,2,0,B|327:69|354:111|398:118|398:118|433:117|467:116|483:80|465:46|430:30|396:49|397:83|398:118|398:118|408:161|452:186|496:176,1,456.000004348755,8|0 +464,254,2193468,1,0 +404,328,2193682,5,8 +256,192,2194111,1,0 +176,124,2194325,1,8 +208,36,2194539,1,8 +304,36,2194754,1,0 +336,124,2194968,1,12 +96,226,2195397,2,0,B|112:308|179:376|252:395|355:368|404:296|422:226,1,456.000004348755,0|8 +256,104,2196682,5,0 +44,48,2197111,1,0 +104,116,2197325,1,0 +176,56,2197539,2,0,B|192:13|256:-19|320:13|336:61,1,200,8|0 +336,148,2198182,2,0,B|320:191|256:223|192:191|176:143,1,200,8|0 +256,104,2198825,5,8 +164,300,2199254,1,0 +348,300,2199682,1,0 +256,192,2200111,12,8,2201397 +256,192,2201504,12,8,2202682 +256,192,2202789,12,4,2205254 +384,80,2225825,5,4 +128,80,2226468,1,2 +132,308,2227111,1,8 +384,308,2227754,1,2 +256,192,2228182,5,0 +336,148,2228397,1,8 +336,60,2228611,1,0 +256,24,2228825,1,2 +176,60,2229039,1,0 +176,148,2229254,1,0 +256,192,2229468,1,0 +320,256,2229682,2,0,B|351:297|327:368|257:398|185:368|161:297|196:248,1,300,8|2 +108,228,2230539,5,0 +72,208,2230682,1,0 +52,168,2230825,1,0 +56,128,2230968,2,0,B|64:76|112:28|176:36|212:76|212:76,1,200,8|0 +288,120,2231611,2,0,B|348:140|388:104|388:104,1,100,2|0 +468,96,2232039,1,0 +440,180,2232254,2,0,B|395:224|395:268|395:313|440:357,1,200,8|2 +256,364,2233111,2,0,B|256:156,1,200,0|8 +72,180,2233968,2,0,B|116:224|116:268|116:313|72:357,2,200,2|0|8 +48,136,2234968,1,0 +56,88,2235111,1,0 +88,60,2235254,2,0,B|112:32|148:32|172:68|172:68|196:100|236:104|260:72,1,200,2|0 +344,48,2235897,5,0 +428,80,2236111,2,0,B|496:88|508:160|492:220|440:240|372:224|372:224,1,200,4|0 +452,308,2236754,2,0,B|404:328|344:296|328:244|328:204|356:176|356:176,1,200,2|0 +336,100,2237397,2,0,B|312:60|256:44|256:44|200:60|176:100,1,200,8|0 +164,188,2238039,2,0,B|156:176|184:204|184:244|168:296|108:328|60:308,1,200,2|0 +76,220,2238682,1,8 +88,132,2238897,1,0 +172,100,2239111,5,2 +212,109,2239218,1,0 +245,142,2239325,1,0 +304,208,2239539,1,0 +388,172,2239754,1,0 +468,212,2239968,2,0,B|500:248|500:304|468:364|388:344|388:344,1,200,8|2 +368,328,2240539,1,0 +345,310,2240682,1,0 +314,311,2240825,1,0 +285,326,2240968,1,0 +252,331,2241111,1,0 +230,317,2241254,2,0,B|193:288|193:230|252:200|252:200|310:171|310:113|252:80,1,300,4|2 +176,48,2242111,6,0,B|136:92|80:76|80:76,1,100,0|0 +80,156,2242539,1,8 +168,324,2242968,5,2 +344,324,2243397,1,0 +432,156,2243825,1,4 +256,32,2244254,1,2 +176,76,2244468,2,0,B|192:119|256:151|320:119|336:71,1,200,8|0 +407,131,2245111,5,0 +388,154,2245218,1,0 +366,175,2245325,1,0 +341,192,2245432,1,0 +313,202,2245539,1,0 +283,210,2245647,1,0 +256,212,2245754,1,0 +229,210,2245861,1,0 +199,202,2245968,1,0 +171,192,2246075,1,0 +146,175,2246182,1,0 +124,154,2246289,1,0 +105,131,2246397,1,4 +52,240,2246825,5,2 +140,320,2247254,1,0 +256,348,2247682,1,8 +372,320,2248111,1,2 +460,240,2248539,1,0 +488,156,2248754,1,0 +404,172,2248968,6,0,B|320:128|320:128|304:20,1,200,8|2 +207,23,2249611,1,0 +207,23,2249825,2,0,B|192:128|192:128|108:172,1,200,0|8 +336,292,2250682,6,0,B|322:324|262:373|189:345|168:288|168:288,1,200,2|0 +135,197,2251325,2,0,B|162:132|239:74|353:107|372:205|372:205,1,300,2|0 +152,36,2252397,1,2 +360,36,2252825,1,8 +256,192,2253254,5,0 +192,250,2253468,2,0,B|157:294|184:334|233:346|256:312|256:312|282:348|328:336|364:292|309:241,2,300,2|8|0 +56,324,2255182,5,2 +56,324,2255397,1,8 +176,96,2255825,2,0,B|200:56|256:40|256:40|312:56|336:96,1,200,2|0 +256,144,2256468,1,0 +336,188,2256682,2,0,B|312:228|256:244|256:244|200:228|176:188,1,200,4|0 +456,324,2257539,1,0 +256,364,2257968,1,8 +56,324,2258397,1,2 +92,232,2258611,6,0,B|140:232|152:194|150:166|150:166|182:167|220:143|206:87,1,200,0|0 +303,101,2259254,2,0,B|298:142|329:167|361:166|361:166|359:194|371:232|420:232,1,200,2|0 +376,312,2259897,2,0,B|324:324|324:324|300:372,1,100,8|0 +208,365,2260325,2,0,B|188:324|188:324|136:312,1,100,0|8 +56,128,2260968,5,2 +256,104,2261397,1,0 +304,20,2261611,1,0 +208,20,2261825,1,8 +372,132,2262254,2,0,B|345:197|268:255|154:222|135:124|135:124,1,300,2|0 +56,188,2263111,2,0,B|76:240|144:300|220:308,1,200,8|0 +304,306,2263754,2,0,B|372:294|436:240|456:188,1,200,2|0 +456,187,2264397,1,2 +256,192,2264504,12,8,2265682 +256,192,2265789,12,10,2266968 +184,124,2267397,5,8 +256,76,2267611,1,8 +328,124,2267825,1,8 +304,212,2268039,1,0 +212,212,2268254,1,8 +256,352,2268682,5,8 +80,68,2269111,1,8 +432,64,2269539,1,12 +466,303,2269968,2,0,B|466:182|332:145|256:220|256:220|142:315|199:391|256:411|313:391|370:315|256:220|256:220|180:145|9:172|46:321|46:321,1,1000,0|8 +256,32,2272754,1,8 +176,76,2272968,2,0,B|192:119|256:151|320:119|336:71,1,200,8|8 +256,200,2273825,5,0 +168,360,2274254,1,0 +340,360,2274682,2,0,B|395:298|408:225|358:155|311:129|254:113|210:125|154:141|108:209|110:255|111:328|188:373,2,600,8|8|8 +472,200,2277897,6,0,B|472:100,1,100,8|8 +392,56,2278325,1,8 +336,128,2278539,2,0,B|312:168|256:184|256:184|200:168|176:128,1,200,4|0 +40,200,2279397,2,0,B|40:100,1,100,2|0 +116,52,2279825,1,4 +177,271,2280254,6,0,B|201:231|257:215|257:215|313:231|337:271,1,200 +299,355,2280897,2,0,B|283:372|256:377|256:377|227:372|213:354,1,100,0|8 +144,90,2281539,6,0,B|153:55|199:44|221:77|199:100|209:146|242:133|255:48|255:48|265:133|298:146|310:100|288:77|310:44|364:50|366:88,1,400,0|8 +340,268,2282825,5,0 +256,304,2283039,1,8 +172,268,2283254,1,0 +328,360,2283682,5,8 +256,196,2284111,1,0 +184,360,2284539,1,0 +256,196,2284968,5,4 +256,192,2285075,12,0,2286254 +256,192,2286361,12,0,2287539 +256,192,2287647,12,0,2290111 +192,144,2308992,6,0,B|160:96|96:80,2,100,2|0|0 +256,112,2309663,2,0,B|256:0,2,100,2|0|0 +320,144,2310335,2,0,B|352:96|416:80,2,100,2|0|0 +256,192,2311006,1,0 +176,304,2311678,2,0,B|208:352|256:368|256:368|304:352|336:304,1,200,4|4 +416,128,2312574,6,0,B|416:64|352:48,2,100,2|0|0 +256,144,2313245,2,0,B|256:32,2,100,2|0|0 +96,128,2313917,2,0,B|96:64|160:48,2,100,2|0|0 +256,144,2314589,1,0 +164,336,2315260,2,0,B|208:305|256:345|256:345|304:305|348:335|348:335,1,200,4|4 +256,256,2316156,5,0 +208,176,2316380,1,0 +112,192,2316603,1,2 +64,112,2316827,2,0,B|112:96|144:48,2,100,0|8|0 +192,112,2317499,2,0,B|256:32|384:48,1,200,2|0 +352,128,2318171,1,0 +336,208,2318394,2,0,B|336:272|400:304,1,100,2|0 +464,304,2318842,2,0,B|464:240|400:208,1,100,8|0 +352,128,2319290,5,2 +208,80,2319514,1,0 +112,192,2319738,2,0,B|64:224|80:288,1,100 +256,256,2320186,2,0,B|208:240|144:256,1,100,2|0 +112,192,2320633,1,8 +80,112,2320857,1,0 +160,80,2321081,2,0,B|256:128|352:80,1,200,2|0 +400,160,2321753,5,0 +352,240,2321977,2,0,B|351:240|307:270|259:230|259:230|211:270|167:239,1,200,2|8 +96,176,2322648,1,0 +64,256,2322872,2,0,B|64:304|80:368|176:368|208:352,1,200,2|4 +192,272,2323544,5,0 +256,208,2323768,1,2 +320,272,2323991,1,0 +311,354,2324215,2,0,B|336:368|432:368|448:304|448:256,1,200,8|0 +416,176,2324887,2,0,B|384:112|416:48,2,100,0|0|0 +320,192,2325559,1,2 +224,192,2325783,2,0,B|224:256|176:288,1,100,0|8 +160,128,2326230,2,0,B|160:64|112:32,1,100,0|2 +224,192,2326678,1,0 +160,128,2326902,1,4 +64,128,2327126,5,0 +192,48,2327350,1,2 +224,192,2327574,1,0 +304,112,2327797,2,0,B|400:48|512:80,1,200,8|2 +464,160,2328469,2,0,B|432:208|432:272,2,100,0|0|0 +464,336,2329141,1,2 +384,304,2329365,1,0 +304,256,2329589,2,0,B|256:288|208:256,1,100,8|0 +124,304,2330036,2,0,B|188:96,1,200,2|4 +156,16,2330708,6,0,B|188:128,1,100,0|2 +272,128,2331156,1,0 +352,176,2331380,2,0,B|304:288|368:384,1,200,8|0 +153,368,2332051,2,0,B|208:288|160:176,1,200 +64,176,2332723,2,0,B|96:224|96:272,1,100,2|0 +192,84,2333171,2,0,B|160:132|160:180,1,100,8|0 +256,192,2333618,1,2 +160,336,2334066,6,0,B|256:384|352:336,2,200,4|0|8 +160,256,2335186,1,2 +160,256,2335409,2,0,B|256:320|352:256,1,200,4|0 +344,168,2336081,6,0,B|360:116|332:72,1,100,0|4 +256,144,2336529,1,0 +256,144,2336641,1,0 +256,144,2336753,1,12 +192,80,2336977,1,0 +128,144,2337200,2,0,B|160:192|128:240,1,100,8|0 +240,336,2337648,6,0,B|192:240|256:144,1,200,4|2 +320,96,2338320,2,0,B|368:64|416:64,2,100,0|8|0 +380,164,2338991,1,0 +380,164,2339215,2,0,B|300:248|180:204,1,200,2|2 +284,108,2339887,1,8 +284,108,2340111,2,0,B|304:220|244:304,1,200,8|2 +160,236,2340783,1,2 +64,288,2341006,6,0,B|48:240|64:176,1,100,0|4 +48,16,2341454,2,0,B|64:64|48:128,1,100,0|2 +128,144,2341902,2,0,B|240:112,1,100,0|8 +304,128,2342350,1,0 +256,304,2342797,6,0,B|336:384|464:352,2,200,0|0|0 +381,253,2343917,2,0,B|381:189|333:157,1,100,8|0 +253,205,2344365,2,0,B|269:253|253:317,1,100,2|0 +173,253,2344812,5,4 +32,128,2345036,2,0,B|32:64|80:32,1,100,0|2 +160,80,2345484,2,0,B|144:128|160:192,1,100,0|8 +240,192,2345932,1,0 +288,112,2346156,1,2 +368,272,2346380,6,0,B|384:208|336:176,1,100,0|0 +288,256,2346827,2,0,B|272:320|320:352,1,100,0|2 +288,256,2347275,1,0 +352,176,2347499,1,8 +392,80,2347723,2,0,B|320:80|256:32|256:32|192:80|104:80,1,300,0|4 +80,160,2348618,5,0 +64,256,2348842,2,0,B|192:240,1,100,2|0 +224,320,2349290,2,0,B|96:336,1,100,8|0 +346,300,2349738,2,0,B|273:227|161:243,1,200,2|0 +176,144,2350409,1,0 +224,64,2350633,5,2 +400,48,2350857,1,0 +336,192,2351081,1,0 +256,80,2351305,5,0 +352,64,2351529,1,0 +320,160,2351753,1,0 +240,256,2351977,6,0,B|144:176|208:48,1,224.999993294478,4|2 +140,112,2352872,2,0,B|120:204|27:226,1,149.999995529652,8|0 +48,220,2353544,1,0 +88,300,2353768,1,2 +168,344,2353991,1,8 +256,364,2354215,2,0,B|336:348,1,74.9999977648259,0|0 +420,344,2354663,6,0,B|356:280|404:200,1,149.999995529652,8|2 +464,144,2355335,1,0 +384,108,2355559,2,0,B|316:68|240:120,1,150.000005722046,0|2 +260,208,2356230,1,0 +260,208,2356454,2,0,B|276:112|212:48|132:32|68:80,1,299.999991059304,10|0 +132,144,2357574,6,0,B|168:140|184:188,2,75.0000028610231,8|2|8 +140,328,2358245,2,0,B|140:232|252:200,1,149.999995529652,8|2 +216,212,2358917,1,8 +372,328,2359141,2,0,B|372:232|260:200,1,149.999995529652,4|2 +256,132,2359812,1,0 +184,80,2360036,2,0,B|256:48|256:48|328:80,2,149.999995529652,8|2|0 +108,128,2361156,1,8 +96,216,2361380,6,0,B|224:312,1,149.999995529652,2|8 +256,224,2362051,1,2 +416,216,2362275,2,0,B|288:312,2,149.999995529652,0|4|2 +420,128,2363394,1,8 +336,92,2363618,2,0,B|288:44|224:28|144:44|96:92|80:156,2,299.999991059304,8|0|8 +288,176,2365633,5,0 +160,256,2365857,1,4 +304,320,2366081,1,0 +288,176,2366305,5,6 +224,80,2366529,2,0,B|160:112|96:96,1,100,2|0 +48,48,2366977,2,2,B|16:96|48:160,1,100,2|0 +128,176,2367424,2,2,B|144:240|112:272,1,100,0|2 +160,368,2367872,2,2,B|240:288|224:176,1,200 +128,176,2368544,5,0 +227,187,2368768,2,2,B|259:139|307:123,1,100 +464,48,2369215,2,0,B|432:80|368:96,1,100,2|0 +368,192,2369663,2,2,B|480:224|480:352,1,200,6|2 +384,320,2370335,5,0 +288,336,2370559,1,2 +192,352,2370783,1,0 +96,352,2371006,2,0,B|128:304|96:256,1,100,2|0 +97,258,2371454,2,2,B|0:192|48:64,1,200 +144,80,2372126,1,0 +240,112,2372350,5,0 +336,80,2372574,1,2 +416,128,2372797,1,0 +416,32,2373021,1,2 +416,128,2373245,2,2,B|320:192|304:288,1,200,4|0 +384,320,2373917,2,0,B|288:256|160:304,1,200,2|0 +112,336,2374589,1,0 +80,256,2374812,1,0 +80,256,2375036,2,2,B|48:128|144:80,1,200,2|2 +208,144,2375708,6,2,B|256:160|320:144,1,100,0|2 +432,80,2376156,2,2,B|381:66|333:82,1,100 +240,64,2376603,1,0 +144,64,2376827,2,2,B|64:128|80:272,1,200,6|0 +32,176,2377499,1,0 +32,176,2377723,2,2,B|112:256|32:384,1,200,6|0 +120,296,2378394,2,2,B|196:196|325:267,1,200,0|4 +480,296,2379066,2,0,B|428:304|380:276,1,100 +432,96,2379514,5,0 +336,192,2379738,1,4 +472,220,2379962,1,0 +428,112,2380186,1,4 +352,184,2380409,1,0 +456,208,2380633,1,4 +256,192,2381081,6,2,B|160:112,1,100 +96,112,2381529,1,2 +96,112,2381753,1,0 +48,192,2381977,1,2 +48,192,2382200,2,2,B|204:316,1,200 +288,320,2382872,2,0,B|352:304|352:240,2,100,0|0|2 +288,320,2383544,1,0 +256,144,2383768,6,0,B|256:192|288:256,2,100,2|0|4 +192,64,2384439,2,2,B|184:121|126:149,1,100,2|2 +32,144,2384887,2,0,B|80:192|64:272,1,100,2|0 +128,320,2385335,1,2 +32,320,2385559,1,0 +128,320,2385783,6,2,B|176:224|304:256,1,200,6|0 +416,240,2386454,2,0,B|360:136|240:176,1,200,0|0 +188,92,2387126,1,4 +288,48,2387350,1,0 +368,112,2387574,1,0 +264,168,2387797,5,6 +368,112,2388021,2,2,B|432:96|480:32,2,100,0|2|2 +331,208,2388693,2,2,B|224:272|203:384,1,200,0|2 +208,358,2389365,1,0 +304,360,2389589,2,2,B|277:248|186:198,1,200,6|2 +128,128,2390260,1,0 +164,48,2390484,2,0,B|208:17|256:57|256:57|304:17|348:47|348:47,1,200,2|0 +384,128,2391156,1,2 +128,128,2391603,1,4 +256,192,2391827,12,0,2394066 +256,48,2401678,5,0 +256,48,2401790,1,0 +256,48,2401902,1,0 +256,48,2402014,1,0 +256,48,2402126,1,4 +208,112,2402350,6,0,B|256:144|304:112,1,100,0|2 +344,176,2402797,1,0 +344,176,2403021,2,0,B|312:208|256:224|192:208|152:168,1,200,8|0 +64,160,2403693,1,2 +32,240,2403917,1,0 +160,176,2404141,2,0,B|224:176|256:128,1,100,0|2 +160,96,2404589,2,0,B|128:48|160:-16,1,100,0|8 +240,32,2405036,2,0,B|309:113|453:97,1,200 +432,192,2405708,1,4 +384,272,2405932,5,0 +336,352,2406156,1,2 +256,304,2406380,2,0,B|256:192,1,100,0|8 +176,176,2406827,1,0 +176,176,2407051,2,0,B|192:48|64:32,2,200,2|0|2 +256,144,2408171,1,2 +256,144,2408394,2,0,B|272:32|400:32,1,200,8|2 +448,208,2409066,1,0 +448,208,2409290,6,0,B|432:144|448:96,1,100,4|0 +352,144,2409738,2,0,B|368:192|352:256,1,100,2|0 +272,288,2410186,2,0,B|256:224|272:176,1,100,8|0 +176,224,2410633,2,0,B|192:272|176:336,1,100,2|0 +96,320,2411081,5,0 +64,224,2411305,1,0 +80,128,2411529,2,0,B|176:64,1,100,2|0 +256,96,2411977,1,8 +353,76,2412200,2,0,B|449:12,1,100,2|0 +416,144,2412648,1,2 +416,144,2412872,6,0,B|464:240|416:352,2,200,8|0|8 +336,176,2413991,1,0 +240,176,2414215,1,2 +288,256,2414439,1,0 +240,176,2414663,1,0 +144,176,2414887,1,0 +192,256,2415111,1,10 +240,176,2415335,5,0 +240,176,2415447,1,0 +240,176,2415559,1,12 +144,48,2415783,1,0 +336,48,2416006,1,8 +240,176,2416230,1,0 +240,176,2416454,1,4 +304,240,2416678,5,0 +352,320,2416902,2,0,B|384:272|448:256,1,100,2|0 +432,176,2417350,2,0,B|320:144|320:16,1,200,8|2 +240,48,2418021,2,0,B|208:160|64:160,1,200,0|2 +48,256,2418693,1,2 +96,352,2418917,1,0 +96,352,2419141,2,0,B|144:240|256:240,2,200,8|0|4 +208,352,2420260,5,0 +304,352,2420484,1,2 +400,352,2420708,1,0 +400,352,2420932,2,0,B|352:240|240:240,1,200,8|0 +176,192,2421603,5,0 +144,112,2421827,1,2 +240,128,2422051,1,0 +240,128,2422275,2,0,B|352:128|416:16,1,200,0|8 +464,144,2422947,1,0 +416,272,2423171,1,2 +256,352,2423618,5,4 +160,336,2423842,2,0,B|112:240|176:144,1,200 +112,96,2424514,2,0,B|160:64|208:64,2,100,8|0|2 +288,80,2425186,1,0 +368,128,2425409,1,0 +352,224,2425633,1,0 +432,352,2425857,6,0,B|416:304|448:256,1,100,2|0 +256,208,2426305,2,0,B|256:320,1,100,8|0 +80,352,2426753,2,0,B|96:304|64:256,1,100,2|0 +64,160,2427200,1,4 +144,112,2427424,2,0,B|272:80,2,100,0|2|0 +192,192,2428096,2,0,B|208:320,1,100,8|0 +307,291,2428544,2,0,B|320:192,1,100,2|0 +256,96,2428991,5,0 +208,176,2429215,1,8 +304,176,2429439,1,0 +256,64,2429663,1,0 +176,176,2429887,1,4 +336,176,2430111,1,0 +388,272,2430335,1,0 +256,304,2430559,1,0 +128,272,2430783,6,0,B|128:144|48:64,1,224.999993294478,4|0 +168,88,2431678,2,0,B|252:100|312:40,1,150.000005722046,8|0 +396,40,2432350,1,8 +452,108,2432574,1,0 +416,192,2432797,1,0 +328,176,2433021,1,8 +320,88,2433245,1,0 +416,192,2433469,6,0,B|467:195|491:221,1,74.9999977648259,8|0 +420,280,2433917,2,0,B|384:364|288:344,1,150.000005722046,0|4 +324,260,2434589,1,0 +324,260,2434812,2,0,B|332:180|402:139,2,149.999995529652,0|8|0 +300,348,2435932,1,8 +220,200,2436156,1,0 +400,140,2436380,6,0,B|352:140|320:108,2,74.9999977648259,8|8|0 +348,32,2437051,2,0,B|348:120|260:144,1,150.000005722046,8|0 +260,232,2437723,1,0 +260,60,2437947,2,0,B|163:69|157:170,1,149.999995529652,4|0 +156,244,2438618,1,0 +256,336,2438842,2,0,B|352:336|360:248,2,150.000005722046,8|0|0 +256,336,2439962,1,8 +268,248,2440186,6,0,B|168:124,1,150.000005722046,0|8 +120,204,2440857,1,0 +80,124,2441081,2,0,B|168:112|196:40,2,150.000005722046,0|4|0 +120,204,2442200,1,8 +168,280,2442424,2,0,B|216:328|280:344|360:328|408:280|424:216,2,299.999991059304,8|0|0 +224,208,2444439,5,0 +352,128,2444663,1,0 +224,64,2444887,1,0 +128,80,2445111,6,2,B|80:112|96:192,1,100,6|2 +48,256,2445559,1,0 +96,336,2445783,2,0,B|160:320|224:368,1,100,0|2 +288,352,2446230,1,0 +368,320,2446454,1,2 +288,352,2446678,2,2,B|240:256|288:160,1,200 +288,64,2447350,2,0,B|176:48,1,100 +352,128,2447797,2,2,B|464:144,1,100,2|0 +400,224,2448245,5,2 +400,320,2448469,2,2,B|304:272|192:320,1,200,6|0 +128,352,2449141,2,2,B|144:288|128:240,1,100,2|0 +80,64,2449589,2,2,B|64:128|80:176,1,100,2|2 +176,192,2450036,1,0 +176,192,2450260,2,2,B|64:224|48:352,1,200 +128,256,2450932,6,0,B|240:304,1,100 +288,368,2451380,1,2 +384,320,2451603,2,0,B|475:280,1,100 +464,176,2452051,6,2,B|352:176|288:48,1,200,6|0 +302,73,2452723,1,2 +180,56,2452947,1,0 +152,180,2453171,1,2 +276,204,2453394,1,0 +152,180,2453618,1,2 +32,256,2453842,2,2,B|80:368|224:352,1,200,0|2 +256,288,2454514,1,0 +320,352,2454738,6,2,B|384:336|400:256,2,100,0|2|2 +256,288,2455409,1,0 +320,224,2455633,2,2,B|384:112|512:144,1,200,4|0 +400,128,2456305,1,0 +400,128,2456529,2,2,B|272:112|256:0,1,200,2|0 +176,32,2457200,2,2,B|192:160|64:208,1,200,0|2 +64,288,2457872,1,0 +64,288,2458096,6,0,B|128:288|176:336,1,100 +352,348,2458544,1,4 +240,352,2458768,1,0 +288,272,2458991,1,0 +304,256,2459103,1,0 +320,240,2459215,1,0 +336,224,2459327,1,0 +352,208,2459439,1,4 +256,48,2459887,6,0,B|176:128,2,100,0|2|2 +320,112,2460559,2,2,B|240:192,1,100 +384,176,2461006,2,2,B|240:320,1,200 +160,336,2461678,1,0 +80,288,2461902,1,0 +64,192,2462126,6,0,B|48:144|64:80,1,100,2|0 +128,144,2462574,2,2,B|144:192|128:256,1,100,2|0 +208,208,2463021,2,0,B|224:80|352:64,1,200,2|0 +416,96,2463693,1,0 +384,176,2463917,2,0,B|432:384,2,200,2|2|0 +304,224,2465036,1,0 +304,224,2465260,6,0,B|336:336,1,100 +192,240,2465708,2,0,B|160:128,1,100 +32,112,2466156,1,0 +144,32,2466380,1,0 +144,32,2466603,6,2,B|192:64|240:48,2,100,6|0|0 +144,128,2467275,2,2,B|224:192|208:320,1,200 +304,304,2467947,1,0 +304,304,2468171,2,2,B|289:188|369:124,1,200 +416,48,2468842,5,4 +256,32,2469066,1,0 +96,48,2469290,1,4 +192,128,2469514,1,0 +320,128,2469738,1,0 +256,240,2469962,1,0 +256,240,2470409,1,0 +256,192,2470633,12,0,2472872 +256,64,2487424,5,0 +256,64,2487648,1,0 +432,192,2488096,5,4 +368,256,2488320,2,0,B|368:368,2,100,0|0|8 +336,176,2488991,2,0,B|240:112,2,100,0|0|8 +256,224,2489663,2,0,B|160:160,2,100,0|0|8 +176,272,2490335,2,0,B|112:272|80:336,2,100,0|0|8 +336,272,2491006,2,0,B|400:272|432:336,2,100,0|0|8 +384,192,2491678,5,4 +416,112,2491902,1,0 +384,32,2492126,1,0 +256,32,2492350,5,8 +256,128,2492574,1,0 +256,224,2492797,1,0 +128,192,2493021,5,8 +96,112,2493245,1,0 +128,32,2493469,1,0 +256,32,2493693,6,0,B|256:160,3,100,8|0|0|8 +352,128,2494589,1,0 +432,176,2494812,2,0,B|384:208|400:288,1,100,8|0 +448,336,2495260,6,0,B|456:296|440:264|380:264|380:264|296:264,1,200,4|8 +124,256,2495932,2,0,B|116:216|132:184|192:184|192:184|276:184,1,200,0|8 +416,176,2496603,2,0,B|424:136|408:104|348:104|348:104|264:104,1,200,0|8 +164,104,2497275,2,0,B|100:24,2,100,0|0|8 +100,184,2497947,2,0,B|4:104,2,100,0|0|8 +256,192,2498618,1,0 +256,192,2498842,12,4,2500633 +384,48,2500857,6,0,B|368:112|384:160,1,100 +336,272,2501305,1,0 +336,272,2501529,2,0,B|272:64,1,200,4|0 +176,64,2502200,2,0,B|64:80,1,100,0|4 +64,176,2502648,6,0,B|32:304,1,100,8|0 +144,192,2503096,2,0,B|112:304,1,100,0|8 +224,208,2503544,2,0,B|192:320,1,100,0|8 +384,240,2503991,6,0,B|416:112,1,100 +304,224,2504439,2,0,B|336:112,1,100,8|0 +224,208,2504887,2,0,B|256:95,1,100,0|8 +176,48,2505335,5,0 +80,80,2505559,1,8 +48,176,2505783,1,0 +64,272,2506006,5,4 +256,352,2506454,1,0 +448,272,2506902,1,4 +352,96,2507350,1,0 +160,96,2507797,1,4 +256,272,2508245,2,0,B|292:185|228:158|260:74,2,200,0|4|0 +256,192,2509589,12,4,2513171 +336,48,2526380,5,0 +304,80,2526603,1,0 +272,112,2526827,1,0 +240,144,2527051,1,0 +208,176,2527275,1,0 +128,240,2527499,5,6 +48,304,2527723,2,2,B|144:336,1,100,2|0 +304,320,2528171,2,2,B|208:288,1,100,2|0 +304,224,2528618,1,2 +336,144,2528842,1,0 +304,224,2529066,2,2,B|496:288,1,200 +464,192,2529738,6,0,B|432:144|464:80,1,100 +256,64,2530186,2,2,B|368:80,1,100 +176,32,2530633,1,0 +176,32,2530857,2,2,B|176:160|16:192,1,200,6|0 +32,352,2531529,6,2,B|80:240,1,100,2|0 +208,304,2531977,1,2 +160,208,2532200,1,0 +71,261,2532424,1,0 +208,304,2532648,2,2,B|272:304|272:304|320:296|320:296|408:296,1,200,2|2 +448,204,2533320,6,0,B|320:204,1,100 +256,56,2533768,2,0,B|300:160,1,100,2|0 +220,216,2534215,1,0 +220,216,2534439,2,2,B|132:216|132:216|84:224|84:224|20:224,1,200,6|0 +80,308,2535111,1,2 +80,308,2535335,1,0 +80,308,2535559,2,2,B|132:276|148:216|120:164|72:152,1,200,2|0 +71,152,2536230,2,2,B|84:104|140:76|204:92|228:144,1,200,2|0 +380,136,2536902,5,0 +228,144,2537126,1,0 +308,208,2537350,1,2 +404,304,2537574,2,0,B|280:332,1,100,0|2 +116,256,2538021,2,2,B|192:232|192:232|248:232|248:232|324:204,1,200,6|0 +224,156,2538693,1,0 +224,156,2538917,2,2,B|300:132|300:132|356:132|356:132|432:104,1,200,6|0 +352,36,2539589,6,0,B|256:28|256:28|152:40,2,200 +312,164,2540708,1,0 +176,128,2540932,1,4 +56,156,2541156,5,0 +88,296,2541380,1,4 +220,204,2541603,1,0 +220,204,2541827,1,4 +420,224,2542275,5,0 +420,224,2542499,2,2,B|408:84,1,100,2|0 +328,68,2542947,1,2 +228,72,2543171,1,0 +328,68,2543394,2,2,B|344:272,1,200 +264,332,2544066,2,0,B|208:340|160:308,1,100 +72,336,2544514,6,2,B|192:316|180:184,1,200,2|0 +80,208,2545186,2,2,B|68:86|188:66,1,200,6|0 +284,48,2545857,2,0,B|384:40,2,100,0|2|0 +304,148,2546529,1,2 +208,116,2546753,1,0 +176,212,2546977,6,2,B|-8:316,1,200,2|0 +100,336,2547648,2,2,B|284:232,1,200,2|0 +376,248,2548320,2,0,B|436:248|460:200,2,100 +384,148,2548991,5,6 +364,48,2549215,1,0 +264,56,2549439,1,2 +192,124,2549663,2,2,B|144:228|208:320,1,200,0|2 +315,314,2550335,1,0 +315,314,2550559,2,2,B|376:228|328:124,1,200 +396,52,2551230,6,0,B|508:108,1,100 +328,124,2551678,2,0,B|240:80,1,100 +96,132,2552126,2,0,B|208:188,1,100 +256,292,2552574,1,4 +256,292,2552797,1,0 +256,192,2553021,12,4,2555708 +357,168,2579508,5,4 +232,96,2579732,1,2 +152,234,2579956,1,0 +280,300,2580179,1,0 +280,300,2580851,5,4 +152,234,2581075,1,2 +232,96,2581299,1,0 +357,168,2581523,1,0 +256,192,2582194,5,2 +256,192,2582418,1,0 +256,192,2582642,1,2 +208,364,2583090,6,0,B|224:378|256:394|288:378|304:362,1,100,4|0 +256,296,2583538,1,2 +200,232,2583762,2,0,B|163:179|192:112|255:92|304:104|346:153|336:200|312:232|312:232,1,300,0|4 +368,301,2584657,2,0,B|411:263|413:197,1,100,0|2 +405,123,2585105,1,0 +144,301,2585777,2,0,B|101:263|99:197,1,100,4|0 +107,123,2586224,1,4 +256,192,2586672,5,0 +256,192,2586784,1,0 +256,192,2586896,1,0 +256,192,2587120,1,0 +256,280,2587344,1,0 +451,140,2588015,6,0,B|465:124|481:92|465:60|449:44,1,100 +362,48,2588463,2,0,B|349:59|333:91|349:123|363:139,1,100 +336,328,2589359,1,0 +256,368,2589582,1,0 +176,328,2589806,1,0 +148,140,2590254,2,0,B|162:124|178:92|162:60|146:44,1,100 +59,48,2590702,2,0,B|46:59|30:91|46:123|60:139,1,100 +209,344,2591597,6,0,B|255:362|255:362|302:344,1,100 +301,243,2592045,2,0,B|254:225|254:225|207:244,1,100 +332,76,2592941,5,0 +256,20,2593165,1,0 +180,76,2593388,1,0 +212,156,2593612,1,0 +300,156,2593836,1,0 +300,156,2593948,1,0 +300,156,2594060,1,0 +376,204,2594284,5,0 +468,196,2594508,1,0 +504,276,2594732,1,0 +440,344,2594956,1,0 +360,296,2595179,1,0 +304,373,2595403,2,0,B|288:387|256:403|224:387|208:371,1,100,0|0 +152,296,2595851,1,0 +72,344,2596075,1,0 +8,276,2596299,1,0 +44,196,2596523,1,0 +136,204,2596747,1,0 +176,124,2596971,5,0 +208,92,2597082,1,0 +252,76,2597194,1,0 +296,92,2597306,1,0 +324,124,2597418,1,0 +256,184,2597642,1,0 +340,240,2597866,2,0,B|368:280|368:280|420:296|420:296,2,100 +256,284,2598538,2,0,B|256:388|256:388,2,100 +172,240,2599209,2,0,B|144:280|144:280|92:296|92:296,2,100 +256,180,2599881,1,0 +360,256,2600105,5,0 +360,256,2600217,1,0 +360,256,2600329,1,0 +360,256,2600441,1,0 +360,256,2600553,1,0 +360,256,2600665,1,0 +360,256,2600777,1,0 +360,256,2600888,1,0 +360,257,2601000,6,0,B|347:343|241:378,2,150,4|0|0 +400,240,2601784,1,0 +448,226,2601896,1,0 +277,64,2602344,1,0 +229,78,2602456,1,0 +181,92,2602568,1,0 +157,188,2602791,6,0,B|71:175|36:69,2,150 +145,237,2603575,1,0 +127,283,2603687,1,0 +284,159,2604135,1,0 +302,113,2604247,1,0 +314,65,2604359,1,0 +397,119,2604582,6,0,B|420:34|505:13,2,150 +444,136,2605366,1,0 +491,152,2605478,1,0 +346,290,2605926,1,0 +299,272,2606038,1,0 +252,252,2606150,1,0 +221,156,2606374,6,0,B|246:79|180:5,2,150 +179,163,2607157,1,0 +129,170,2607269,1,0 +17,336,2607717,1,0 +66,331,2607829,1,0 +115,323,2607941,1,0 +196,265,2608165,6,0,B|289:271|311:373,2,150 +205,215,2608948,1,0 +214,165,2609060,1,0 +401,233,2609508,1,0 +413,184,2609620,1,0 +426,135,2609732,1,0 +415,36,2609956,6,0,B|290:22|248:130,2,200 +216,8,2611299,1,0 +35,94,2611747,5,0 +58,137,2611859,1,0 +78,182,2611971,2,0,B|141:186|158:255,1,100 +99,323,2612418,1,0 +183,376,2612642,1,0 +183,376,2612866,1,0 +249,301,2613090,6,0,B|388:315,1,100 +429,251,2613538,1,0 +429,251,2613762,1,0 +375,167,2613985,1,0 +388,67,2614209,1,0 +196,65,2614433,6,0,B|171:20,7,50,0|0|0|0|0|0|0|0 +218,111,2615329,2,0,B|163:231|296:295,1,200,4|0 +347,216,2616000,1,0 +438,257,2616224,1,0 +414,354,2616448,5,0 +414,354,2616560,1,0 +414,354,2616672,2,0,B|175:368,1,200 +214,365,2617232,1,0 +214,365,2617344,1,0 +118,336,2617568,1,0 +161,246,2617791,1,0 +80,186,2618015,2,0,B|68:67|191:31,1,200 +180,34,2618575,1,0 +180,34,2618687,1,0 +230,121,2618911,5,0 +230,121,2619023,1,0 +230,121,2619135,2,0,B|363:104,1,100 +321,208,2619582,1,0 +321,208,2619694,1,0 +321,208,2619806,2,0,B|454:191,1,100 +482,274,2620254,6,0,B|281:299,1,200 +283,299,2620814,1,0 +283,299,2620926,1,0 +208,365,2621150,1,0 +122,312,2621374,1,0 +195,244,2621597,1,0 +195,244,2621709,1,0 +195,244,2621821,2,0,B|209:139,1,100 +148,63,2622269,1,0 +75,131,2622493,5,0 +75,131,2622605,1,0 +75,131,2622717,2,0,B|61:236,1,100 +87,327,2623165,1,0 +175,372,2623388,2,0,B|301:374|320:255,1,200 +409,218,2624060,1,0 +409,218,2624284,5,0 +103,218,2624732,1,0 +409,218,2625179,1,0 +103,218,2625627,1,0 +256,48,2626075,5,0 +256,48,2626187,1,0 +256,48,2626299,2,0,B|281:167,1,100 +186,191,2626747,1,0 +234,278,2626971,2,0,B|218:342|129:338,1,100 +88,268,2627418,1,0 +88,268,2627642,1,0 +43,178,2627866,5,0 +43,178,2627978,1,0 +43,178,2628090,2,0,B|66:72,1,100 +179,45,2628538,2,0,B|156:151,1,100 +240,255,2628985,2,0,B|263:149,1,100 +420,100,2629433,1,0 +420,100,2629545,1,0 +420,100,2629657,1,4 +340,310,2630105,6,0,B|316:352|256:374|204:357|173:311,1,200,0|0 +172,74,2631000,2,0,B|196:32|256:10|308:27|339:73,1,200,0|0 +339,73,2631560,1,0 +339,73,2631672,1,0 +43,206,2632120,6,0,B|66:312,1,100 +179,339,2632568,2,0,B|156:233,1,100 +240,129,2633015,2,0,B|263:235,1,100,0|4 +398,343,2633687,2,0,B|433:355|475:325|475:280|454:238|395:234|371:270,1,200 +393,60,2634582,2,0,B|357:47|315:77|315:122|336:164|395:168|419:132,1,200 +414,138,2635142,1,0 +414,138,2635254,1,0 +242,86,2635702,6,0,B|220:38|220:38|166:28|166:28,1,100 +119,101,2636150,1,0 +36,64,2636374,2,0,B|-24:160|36:252,1,200,0|4 +336,356,2637269,2,0,B|312:312|256:300|256:300|200:312|176:356,1,200 +476,251,2638165,2,0,B|536:160|476:64,1,200 +476,64,2638724,1,0 +476,64,2638836,1,0 +256,116,2639284,5,0 +328,172,2639508,1,0 +300,256,2639732,1,0 +212,256,2639956,1,0 +184,172,2640179,1,0 +108,128,2640403,6,0,B|80:64|80:64,2,50,0|0|0 +176,296,2640851,2,0,B|148:360|148:360,2,50 +256,96,2641299,2,0,B|256:48|256:48,2,50 +336,296,2641747,2,0,B|364:360|364:360,2,50 +404,128,2642194,2,0,B|432:64|432:64,2,50 +296,208,2642642,22,0,B|288:232|256:240|224:232|216:208,1,100 +256,120,2643090,1,0 +140,268,2643314,1,0 +172,296,2643426,1,0 +212,316,2643538,1,0 +256,324,2643650,1,0 +300,316,2643762,1,0 +340,296,2643874,1,0 +372,268,2643985,1,4 +152,152,2644433,6,0,B|130:104|130:104|76:94|76:94,1,100 +256,100,2644881,2,0,B|256:-8,1,100 +360,152,2645329,2,0,B|382:104|382:104|436:94|436:94,1,100 +209,344,2646224,6,0,B|255:362|255:362|302:344,1,100 +303,243,2646672,2,0,B|256:225|256:225|209:244,1,100 +40,50,2647344,22,0,B|61:104|116:123|179:104|196:45,1,200 +296,160,2648015,2,0,B|288:136|256:128|224:136|216:160,1,100 +317,50,2648463,2,0,B|333:104|396:123|451:104|472:50,1,200,0|0 +296,160,2649135,2,0,B|328:216|328:216|280:232|257:262|257:262|232:232|185:214|185:214|222:152,1,300 +304,348,2650030,6,0,B|256:376|204:348,1,100 +424,192,2650478,1,0 +257,53,2650702,1,0 +88,192,2650926,1,0 +88,192,2651038,1,0 +88,192,2651150,1,4 +297,350,2651597,6,0,B|297:302|297:302|337:262,1,100 +217,350,2652045,2,0,B|217:302|217:302|177:262,1,100 +417,115,2652717,22,0,B|367:16|260:-22|138:16|95:118,1,400,0|0 +172,238,2653836,2,0,B|198:283|257:300|314:282|339:237,1,200,0|0 +256,152,2654508,1,0 +256,192,2654732,12,0,2656299 +114,110,2656971,6,0,B|231:63,1,100 +398,274,2657418,2,0,B|281:321,1,100 +257,327,2657754,1,0 +207,329,2657866,1,0 +160,311,2657978,1,0 +136,266,2658090,1,0 +143,216,2658202,1,0 +179,181,2658314,2,0,B|280:89|156:-1,1,200,4|0 +376,255,2658985,6,0,B|367:325|432:349,1,100 +450,247,2659433,2,0,B|459:177|394:153,1,100 +312,172,2659881,2,0,B|259:272|112:233,1,200 +243,9,2660553,6,0,B|234:79|299:103,1,100 +367,44,2661000,1,0 +451,98,2661224,2,0,B|460:168|395:192,1,100 +454,275,2661672,2,0,B|225:269,1,200 +122,144,2662344,6,0,B|222:146,1,100 +220,311,2662791,2,0,B|420:317,1,200 +291,72,2663463,2,0,B|92:67,1,200 +96,233,2664135,5,0 +69,321,2664359,1,0 +155,346,2664582,1,0 +182,261,2664806,1,0 +96,234,2665030,1,0 +182,262,2665254,2,0,B|398:231,1,200 +506,369,2665926,6,0,B|497:299|449:257,1,100 +500,182,2666374,1,0 +427,113,2666597,2,0,B|436:43|492:10,1,100 +372,3,2667045,2,0,B|267:26|234:157,1,200 +385,212,2667717,6,0,B|381:273|324:303,1,100 +399,33,2668165,2,0,B|294:56|261:187,1,200 +79,197,2668836,2,0,B|184:174|217:43,1,200 +302,18,2669508,5,0 +376,85,2669732,2,0,B|427:96|465:165,2,100 +305,156,2670403,2,0,B|347:255|469:286,1,200 +231,107,2671075,6,0,B|145:108|111:163,2,100 +248,8,2671747,2,0,B|132:2|44:73,1,200 +22,95,2672306,1,0 +11,143,2672418,1,0 +35,186,2672530,1,0 +84,195,2672642,6,0,B|148:201|156:271,1,100,4|0 +252,240,2673090,1,0 +235,338,2673314,2,0,B|358:357|418:242,1,200 +175,277,2673985,6,0,B|110:267|73:328,1,100 +0,256,2674433,1,0 +82,199,2674657,2,0,B|47:88|92:-9,1,200 +216,125,2675329,6,0,B|294:191,1,100 +338,100,2675777,2,0,B|494:232,1,200 +463,325,2676448,1,0 +463,325,2676672,2,0,B|422:365|353:347,1,100 +275,25,2677568,5,0 +275,25,2677791,1,0 +275,25,2678015,2,0,B|303:70|297:135,1,100 +44,299,2678911,6,0,B|108:297|155:246,1,100 +47,322,2679359,2,0,B|111:320|158:269,1,100 +237,272,2679806,5,0 +237,272,2679918,1,0 +237,272,2680030,2,0,B|352:306,1,100 +370,207,2680478,1,0 +444,273,2680702,2,0,B|493:237|487:181,2,100 +425,371,2681374,6,0,B|214:354,1,200 +133,262,2682045,2,0,B|332:278,1,200 +358,196,2682717,2,0,B|252:187,1,100 +208,183,2683053,1,0 +158,178,2683165,1,0 +108,173,2683277,1,0 +58,166,2683388,2,0,B|20:124|41:55,1,100 +108,2,2683836,2,0,B|146:44|125:113,1,100 +222,57,2684284,6,0,B|433:40,1,200,0|0 +492,111,2684956,2,0,B|293:127,1,200 +235,209,2685627,2,0,B|341:200,1,100 +263,129,2686075,1,0 +213,134,2686187,1,0 +163,141,2686299,2,0,B|125:183|146:252,1,100 +256,30,2697717,5,0 +110,125,2697941,1,0 +133,290,2698165,1,0 +299,333,2698388,1,0 +421,211,2698612,1,0 +342,54,2698836,5,0 +169,54,2699060,1,0 +90,211,2699284,1,0 +212,333,2699508,1,0 +378,290,2699732,1,0 +401,125,2699956,1,0 +256,30,2700179,1,0 +256,192,2700403,5,0 +256,192,2700515,1,0 +256,192,2700627,1,0 +256,192,2700739,1,0 +256,192,2700851,1,0 +256,192,2700963,1,0 +256,192,2701075,1,0 +256,192,2701187,1,0 +256,192,2701299,1,4 +326,324,2701635,6,0,B|306:358|256:377|213:363|187:324,1,164.999995082617,0|0 +60,280,2702194,1,0 +76,148,2702418,2,0,B|88:92|88:92|132:52,1,109.999996721745 +209,147,2702866,2,0,B|219:123|254:115|289:122|302:146,1,109.999996721745 +256,188,2703202,1,0 +256,240,2703314,1,0 +384,56,2703538,2,0,B|424:92|424:92|436:148,1,109.999996721745 +326,311,2703985,2,0,B|306:345|256:364|213:350|187:311,2,164.999995082617 +256,192,2704881,5,0 +256,144,2704993,1,0 +256,96,2705105,1,0 +130,80,2705329,2,0,B|119:56|84:48|50:55|37:79,1,109.999996721745 +209,259,2705777,2,0,B|219:282|254:290|289:284|302:260,1,109.999996721745 +475,79,2706224,2,0,B|462:55|427:48|392:56|382:80,1,109.999996721745 +408,296,2706672,6,0,B|464:264,2,54.9999983608723 +300,336,2707120,2,0,B|286:360|256:366|256:366|225:360|212:336,1,109.999996721745 +192,228,2707568,2,0,B|211:192|257:182|257:182|303:192|322:228,2,164.999995082617 +104,296,2708463,2,0,B|48:264,2,54.9999983608723 +136,108,2708911,5,0 +256,32,2709135,1,0 +376,108,2709359,1,0 +336,260,2709582,1,0 +176,260,2709806,1,0 +256,152,2710030,1,0 +256,152,2710254,5,0 +404,348,2710702,1,0 +108,348,2711150,1,0 +175,131,2711597,6,0,B|192:71|257:48|320:72|338:134,1,219.999993443489,0|0 +256,156,2712157,2,0,B|256:232,1,54.9999983608723 +356,280,2712493,2,0,B|372:332|372:332|436:360|436:360,2,109.999996721745 +256,364,2713165,1,0 +156,280,2713388,2,0,B|140:332|140:332|76:360|76:360,2,109.999996721745 +156,280,2713948,1,0 +156,280,2714060,1,0 +209,160,2714284,2,0,B|219:136|254:128|289:135|302:159,1,109.999996721745 +95,106,2714732,5,0 +124,65,2714844,1,0 +161,33,2714956,1,0 +206,15,2715068,1,0 +256,8,2715179,1,0 +306,15,2715291,1,0 +351,33,2715403,1,0 +388,65,2715515,1,0 +417,106,2715627,1,4 +340,310,2716075,6,0,B|316:352|256:374|204:357|173:311,1,200,0|0 +340,129,2716971,2,0,B|316:87|256:65|204:82|173:128,1,200,0|0 +256,176,2717530,2,0,B|256:232|256:232,1,50 +400,336,2718090,6,0,B|440:224,1,100 +256,176,2718538,2,0,B|256:276,1,100 +112,336,2718985,2,0,B|72:224,1,100,0|4 +176,88,2719657,6,0,B|200:44|256:32|256:32|312:44|336:88,1,200 +336,296,2720553,2,0,B|312:340|256:352|256:352|200:340|176:296,1,200 +256,252,2721112,2,0,B|256:184|256:184,1,50 +160,48,2721672,5,0 +216,120,2721896,2,0,B|224:96|256:88|288:96|296:120,1,100 +352,48,2722344,1,0 +256,204,2722791,5,4 +160,356,2723239,1,0 +352,356,2723687,1,0 +340,157,2724135,2,0,B|316:115|256:93|204:110|173:156,1,200,0|0 +256,204,2724694,2,0,B|256:260|256:260,1,50 +416,92,2725254,5,0 +348,28,2725478,1,0 +256,8,2725702,1,0 +164,28,2725926,1,0 +96,92,2726150,1,0 +160,164,2726374,5,0 +144,212,2726485,1,0 +104,244,2726597,1,0 +208,316,2726821,2,0,B|190:336|190:336|180:360,2,50 +304,316,2727269,2,0,B|322:336|322:336|332:360,2,50 +408,244,2727717,1,0 +368,212,2727829,1,0 +352,164,2727941,1,0 +184,80,2728165,5,0 +80,104,2728388,1,0 +328,80,2728612,5,0 +432,104,2728836,1,0 +256,32,2729060,5,0 +256,104,2729284,1,0 +270,190,2729508,1,0 +270,190,2729620,1,0 +270,190,2729732,1,0 +270,190,2729844,1,0 +270,190,2729956,6,0,B|271:312|126:334,1,200,4|0 +344,248,2730627,2,0,B|402:270|419:337,2,100 +409,169,2731299,1,0 +310,151,2731523,2,0,B|325:32|457:27,1,200 +297,226,2732194,6,0,B|286:279|226:297,2,100 +204,186,2732866,1,0 +131,117,2733090,1,0 +208,53,2733314,2,0,B|432:48,1,200 +226,288,2733985,6,0,B|160:280|141:204,1,100 +276,358,2734433,2,0,B|393:349|414:209,1,200 +236,26,2735105,2,0,B|119:35|98:175,1,200 +166,229,2735777,5,0 +84,285,2736000,2,0,B|65:344|-6:353,2,100 +48,190,2736672,1,0 +118,118,2736896,1,0 +118,118,2737008,1,0 +118,118,2737120,2,0,B|326:103,1,200,4|0 +455,238,2737791,6,0,B|393:233|379:150,2,100 +476,139,2738463,1,0 +458,301,2738687,2,0,B|338:294|324:163,1,200 +476,139,2739359,1,0 +476,139,2739582,1,0 +416,356,2739806,6,0,B|295:340|272:206,1,200 +96,28,2740478,2,0,B|216:43|240:178,1,200 +145,200,2741150,1,0 +218,268,2741374,2,0,B|330:261,2,100 +169,355,2742045,6,0,B|389:363,1,200 +419,366,2742605,1,0 +468,367,2742717,1,0 +500,272,2742941,1,0 +448,186,2743165,1,0 +397,184,2743277,1,0 +347,181,2743388,1,0 +369,83,2743612,5,0 +318,82,2743724,1,0 +268,78,2743836,1,0 +217,77,2743948,1,0 +166,75,2744060,1,0 +116,71,2744172,1,0 +66,68,2744284,6,0,B|22:166|85:277,1,200,4|0 +174,237,2744956,1,0 +152,334,2745179,1,0 +152,334,2745403,2,0,B|259:358,1,100 +316,280,2745851,2,0,B|435:312|488:212,1,200 +194,111,2746523,5,0 +274,50,2746747,1,0 +194,111,2746971,1,0 +194,111,2747194,1,0 +261,185,2747418,1,0 +206,269,2747642,2,0,B|236:385|393:359,1,200 +438,298,2748314,6,0,B|440:198,1,100 +330,214,2748762,2,0,B|336:14,1,200 +209,285,2749433,2,0,B|214:86,1,200 +445,24,2750105,5,0 +345,30,2750329,1,0 +245,36,2750553,1,0 +145,41,2750777,1,0 +150,140,2751000,1,0 +50,153,2751224,2,0,B|21:275|129:337,1,200 +444,267,2751896,5,0 +345,254,2752120,1,0 +345,254,2752344,1,0 +444,267,2752568,1,0 +345,254,2752791,1,0 +285,335,2753015,2,0,B|161:325|165:199,1,200 +80,150,2753687,6,0,B|40:183|33:247,1,100 +139,102,2754135,2,0,B|234:49|359:83,1,200 +373,282,2754806,2,0,B|278:335|153:301,1,200 +147,211,2755478,5,0 +78,284,2755702,2,0,B|4:294|-11:364,2,100 +20,201,2756374,2,0,B|62:102|17:-2,1,200 +207,276,2757045,6,0,B|272:283|323:217,2,100 +156,362,2757717,2,0,B|249:393|381:350,1,200 +401,346,2758277,1,0 +443,319,2758388,1,0 +467,275,2758500,1,4 +480,228,2758612,5,4 +304,57,2759060,2,0,B|335:101|310:159|256:176|213:166|177:124|184:84|207:56|207:56,1,259.999995350838,0|0 +32,228,2759956,1,0 +298,356,2760403,2,0,B|312:296|312:296|256:256|256:256|199:296|199:296|215:357|215:357,1,259.999995350838 +368,112,2761299,5,0 +256,48,2761523,1,0 +144,112,2761747,1,0 +223,233,2761971,2,0,B|232:217|256:211|282:220|290:232,1,74.9999977648259 +256,304,2762194,1,0 +474,73,2762642,6,0,B|430:90|431:171|489:190|489:190|430:215|427:293|489:319,1,299.999991059304 +37,311,2763538,6,0,B|80:288|82:215|23:190|23:190|81:171|82:90|38:73,1,299.999991059304 +256,296,2764433,5,0 +256,24,2764881,1,0 +308,169,2765105,1,0 +184,88,2765329,1,0 +336,88,2765553,1,0 +336,88,2765665,1,0 +336,88,2765777,1,0 +212,168,2766000,1,0 +80,224,2766224,5,0 +144,328,2766448,1,0 +256,368,2766672,1,0 +368,328,2766896,1,0 +432,224,2767120,1,0 +298,192,2767344,2,0,B|302:215|288:248|259:253|233:252|210:230|206:209|215:190|215:190,1,149.999995529652,0|0 +192,82,2767791,2,0,B|256:42|256:42|320:82,1,149.999995529652 +397,162,2768239,6,0,B|465:191|465:191|484:274,1,149.999995529652 +440,362,2768687,1,0 +344,312,2768911,1,0 +308,348,2769023,1,0 +256,360,2769135,1,0 +204,348,2769247,1,0 +168,312,2769359,1,0 +72,364,2769582,1,0 +30,265,2769807,2,0,B|47:191|47:191|115:162,1,149.999995529652 +96,60,2770254,5,0 +196,96,2770478,2,0,B|205:120|244:118|256:89|256:89|265:118|306:118|315:97,1,149.999995529652 +420,60,2770926,1,0 +404,164,2771150,1,0 +318,240,2771374,2,0,B|299:208|254:191|215:204|191:239,1,149.999995529652,0|0 +208,340,2771821,1,0 +256,316,2771933,1,0 +304,340,2772045,1,0 +388,168,2772269,5,0 +356,128,2772381,1,0 +308,100,2772493,1,0 +256,88,2772605,1,0 +204,100,2772717,1,0 +156,128,2772829,1,0 +124,168,2772941,1,4 +256,296,2773165,5,0 +256,296,2773277,1,0 +256,296,2773388,1,0 +120,360,2773612,1,0 +28,240,2773836,1,0 +112,116,2774060,1,0 +256,152,2774284,1,0 +256,296,2774508,5,0 +256,296,2774620,1,0 +256,296,2774731,1,0 +392,360,2774955,1,0 +484,240,2775179,1,0 +400,116,2775403,1,0 +320,16,2775627,6,0,B|301:48|256:65|217:52|193:17,1,149.999995529652,0|0 +112,120,2776075,1,0 +204,240,2776299,1,0 +256,220,2776411,1,0 +304,240,2776523,1,4 +196,344,2776747,2,0,B|213:376|255:385|255:385|297:376|315:344,1,149.999995529652 +436,252,2777194,5,0 +396,108,2777418,1,0 +256,56,2777642,1,0 +116,108,2777866,1,0 +76,252,2778090,1,0 +76,252,2778202,1,0 +76,252,2778314,1,0 +208,348,2778538,5,0 +256,208,2778762,1,0 +304,348,2778985,1,0 +180,264,2779209,1,0 +332,264,2779433,1,0 +348,124,2779657,1,0 +312,80,2779769,1,0 +256,60,2779881,1,0 +200,80,2779993,1,0 +164,124,2780105,1,4 +76,240,2780329,5,0 +256,160,2780553,1,0 +436,244,2780777,1,0 +192,368,2781000,2,0,B|211:336|256:319|295:332|319:367,2,149.999995529652 +192,192,2781672,1,0 +256,192,2781784,1,0 +320,192,2781896,1,0 +320,16,2782120,6,0,B|301:48|256:65|217:52|193:17,2,149.999995529652 +424,120,2782791,1,0 +256,192,2783015,1,0 +96,120,2783239,1,0 +256,352,2783463,1,0 +256,192,2783687,6,0,B|252:203|238:234|285:241|301:236|315:230|336:212|323:182|328:171|332:161|326:145|310:125|295:132|283:107|277:112|244:105|219:108|204:131|189:147|180:169|180:169|169:197|172:220|178:254|191:280|206:310|255:317|286:330|322:338|357:307|381:282|403:250|408:216|414:197|422:176|425:150|406:108|386:57|353:37|305:22|251:26|214:22|174:41|139:77|121:113|107:146|107:146|97:176|87:233|95:284|124:325|166:371|200:383|250:410|330:406|384:383|417:348|445:311|483:242|479:162,1,1799.99994635582 +478,147,2786485,1,0 +472,126,2786597,1,0 +466,104,2786709,1,0 +457,83,2786821,1,0 +444,64,2786933,1,0 +432,44,2787045,1,0 +415,28,2787157,1,0 +397,14,2787269,1,4 +256,80,2801597,5,4 +256,192,2801709,12,0,2804284 +366,72,2804508,5,0 +422,120,2804732,1,0 +422,192,2804956,1,0 +366,239,2805179,2,0,B|253:192|145:240,1,224.999993294478,4|0 +113,306,2806075,2,0,B|258:390|408:299,1,300 +494,192,2807418,1,0 +398,79,2807866,2,0,B|258:-6|114:78,1,299.999991059304,4|4 +256,192,2808874,12,0,2811896 +64,152,2812120,5,0 +64,232,2812344,1,4 +256,192,2812456,12,0,2814135 +424,116,2814359,5,0 +426,153,2814471,1,0 +411,187,2814582,1,0 +380,208,2814694,1,0 +342,205,2814806,1,0 +309,186,2814918,1,0 +272,177,2815030,1,0 +234,178,2815142,1,0 +199,192,2815254,1,0 +177,222,2815366,1,0 +167,258,2815478,1,0 +171,293,2815590,1,0 +195,321,2815702,1,0 +227,339,2815814,1,0 +264,339,2815926,6,0,B|306:298|375:323,1,100 +441,263,2816374,1,0 +362,201,2816597,2,0,B|347:124|383:92,2,100 +272,248,2817269,1,0 +201,177,2817493,5,0 +201,177,2817605,1,0 +201,177,2817717,2,0,B|93:194,2,100 +289,129,2818388,1,0 +312,32,2818612,5,0 +410,30,2818836,1,0 +204,32,2819060,1,0 +106,30,2819284,1,0 +29,94,2819508,6,0,B|14:141|65:193,1,100 +57,184,2819844,1,0 +57,184,2819956,1,0 +52,284,2820179,5,0 +52,284,2820291,1,0 +52,284,2820403,2,0,B|170:273,1,100 +151,274,2820739,1,0 +151,274,2820851,1,0 +232,333,2821075,5,0 +232,333,2821187,1,0 +232,333,2821299,2,0,B|298:328|314:249,1,100 +306,275,2821635,1,0 +306,275,2821747,1,0 +401,305,2821971,5,0 +401,305,2822082,1,0 +401,305,2822194,2,0,B|382:81,1,200 +349,69,2822754,1,0 +303,47,2822866,1,0 +254,60,2822978,1,0 +232,105,2823090,6,0,B|234:166|174:188,1,100 +147,220,2823426,1,0 +111,255,2823538,1,0 +204,291,2823762,5,0 +239,326,2823874,1,0 +274,361,2823985,2,0,B|398:345,1,100 +421,363,2824321,1,0 +468,379,2824433,1,0 +462,279,2824657,5,0 +437,235,2824769,1,0 +392,211,2824881,2,0,B|379:150|437:120,1,100 +471,99,2825217,1,0 +480,49,2825329,1,0 +387,10,2825553,5,0 +337,16,2825665,1,0 +288,27,2825777,2,0,B|282:137|177:182,1,200 +235,263,2826448,1,0 +134,263,2826672,2,0,B|109:321|132:372,1,100,4|0 +127,360,2827008,1,0 +127,360,2827120,1,0 +225,343,2827344,5,0 +321,367,2827568,1,0 +338,268,2827791,1,0 +338,268,2827903,1,0 +338,268,2828015,2,0,B|479:251,1,100 +373,124,2828463,6,0,B|273:135,1,100 +189,80,2828911,1,0 +149,111,2829023,1,0 +139,160,2829135,1,0 +157,206,2829247,1,0 +196,236,2829359,1,0 +245,243,2829471,1,0 +290,262,2829582,1,0 +316,304,2829694,1,0 +307,353,2829806,1,0 +263,377,2829918,1,0 +213,381,2830030,1,0 +166,361,2830142,1,0 +116,366,2830254,1,4 +48,296,2830478,5,0 +17,256,2830590,1,0 +19,206,2830702,1,0 +54,168,2830814,1,0 +100,160,2830926,1,0 +145,180,2831038,1,0 +194,188,2831150,1,0 +243,181,2831262,1,0 +285,154,2831374,1,0 +302,107,2831485,1,0 +291,58,2831597,1,0 +255,22,2831709,1,0 +205,14,2831821,1,0 +160,36,2831933,1,0 +136,80,2832045,1,0 +194,188,2832269,5,0 +226,222,2832381,1,0 +232,273,2832493,1,0 +204,314,2832605,1,0 +155,328,2832717,1,0 +101,243,2832941,1,0 +53,227,2833053,1,0 +28,183,2833165,1,0 +112,132,2833388,1,0 +130,87,2833500,1,0 +176,62,2833612,1,0 +224,71,2833724,1,0 +255,111,2833836,1,0 +340,144,2834060,5,0 +390,145,2834172,1,0 +434,121,2834284,1,0 +492,202,2834508,2,0,B|456:227|438:286|453:314,1,100 +360,348,2834956,1,0 +360,348,2835068,1,0 +360,348,2835180,1,0 +296,288,2835403,2,0,B|288:312|256:320|224:312|216:288,1,100 +152,348,2835851,1,0 +152,348,2835963,1,0 +152,348,2836075,1,0 +256,208,2836299,5,0 +170,101,2836523,2,0,B|203:58|256:44|312:56|344:104,3,200,0|0|4|0 +404,192,2838090,5,0 +384,200,2838202,1,0 +368,212,2838314,1,0 +356,228,2838426,1,0 +348,248,2838538,1,0 +344,268,2838650,1,0 +348,288,2838762,1,0 +356,308,2838874,1,0 +368,324,2838985,1,0 +384,336,2839097,1,0 +404,344,2839209,1,0 +256,196,2839657,5,0 +108,192,2839881,5,0 +128,200,2839993,1,0 +144,212,2840105,1,0 +156,228,2840217,1,0 +164,248,2840329,1,0 +168,268,2840441,1,0 +164,288,2840553,1,0 +156,308,2840665,1,0 +144,324,2840776,1,0 +128,336,2840888,1,0 +108,344,2841000,1,0 +216,124,2841448,6,0,B|224:148|256:156|288:148|296:124,1,100 +296,123,2841784,1,0 +296,123,2841896,1,0 +256,36,2842120,1,0 +216,260,2842344,6,0,B|224:236|256:228|288:236|296:260,1,100 +256,348,2842791,1,0 +256,192,2842847,12,4,2843687 +256,192,2843799,12,0,2844582 +176,104,2845030,5,0 +256,48,2845254,1,0 +336,104,2845478,1,0 +308,200,2845702,1,0 +204,200,2845926,1,0 +183,297,2846150,2,0,B|198:352|258:373|316:351|333:294,1,200,0|0 +424,344,2846821,6,0,B|448:296|448:296|496:280,1,100 +424,208,2847269,1,0 +456,112,2847493,1,0 +372,48,2847717,1,0 +293,106,2847941,2,0,B|316:139|297:184|256:197|223:189|195:157|201:126|218:105|218:105,1,200,0|0 +140,48,2848612,1,0 +56,112,2848836,1,0 +88,208,2849060,1,0 +256,352,2849508,1,0 +338,300,2849732,2,0,B|310:254|257:240|202:251|172:305,1,200 +120,216,2850403,5,0 +208,168,2850627,1,0 +256,156,2850739,1,0 +304,168,2850851,1,0 +392,216,2851075,1,0 +396,116,2851299,1,0 +304,56,2851523,1,0 +256,44,2851635,1,0 +208,56,2851747,1,4 +116,116,2851971,1,0 +120,216,2852194,5,0 +208,268,2852418,2,0,B|184:276|176:308|184:340|208:348,1,100 +303,348,2852866,2,0,B|328:340|336:308|328:276|304:268,1,100 +392,216,2853314,6,0,B|336:188|332:132|332:132|384:121|408:60,1,200 +308,32,2853985,1,0 +204,32,2854209,1,0 +111,75,2854433,2,0,B|134:120|180:132|180:132|176:188|120:216,1,200 +216,280,2855105,2,0,B|227:258|255:252|255:252|283:258|295:280,1,100 +256,192,2855385,12,0,2856224 +256,192,2856280,12,0,2857120 +333,71,2857568,6,0,B|328:134|394:164,1,100 +179,313,2858015,2,0,B|184:250|118:220,1,100 +96,197,2858351,1,0 +74,151,2858463,1,0 +87,102,2858575,1,0 +129,75,2858687,1,0 +178,79,2858799,1,0 +218,108,2858911,2,0,B|298:184|412:151,1,200,4|0 +163,154,2859582,6,0,B|192:206|164:266,2,100 +93,81,2860254,1,0 +23,153,2860478,2,0,B|-22:249|34:367,1,200 +308,324,2861150,6,0,B|210:318,2,100 +353,234,2861821,2,0,B|362:164|297:140,1,100 +247,222,2862269,2,0,B|41:209,1,200 +126,25,2862941,6,0,B|102:71|96:129,1,100 +278,101,2863388,2,0,B|293:199|248:304,1,200 +428,259,2864060,2,0,B|404:145|420:45,1,200 +243,29,2864732,6,0,B|369:47,2,100 +143,15,2865403,1,0 +107,50,2865515,1,0 +105,100,2865627,1,0 +138,137,2865739,1,0 +184,155,2865851,1,0 +216,193,2865963,1,0 +227,241,2866075,2,0,B|261:337|415:331,1,200,4|0 +359,235,2866747,2,0,B|395:120,1,100 +474,190,2867194,2,0,B|510:75,1,100 +269,128,2867642,2,0,B|202:341,1,200 +460,196,2868314,6,0,B|496:81,1,100 +255,134,2868762,2,0,B|188:347,1,200 +195,324,2869433,1,0 +256,192,2869545,12,0,2873239 +256,96,2873463,5,0 +256,96,2873575,1,0 +256,96,2873687,1,0 +256,96,2873911,1,0 +256,96,2874135,1,0 +256,288,2874359,5,0 +256,288,2874471,1,0 +256,288,2874582,1,0 +256,288,2874806,1,0 +256,288,2875030,1,0 +352,192,2875254,5,0 +352,192,2875366,1,0 +352,192,2875478,1,0 +352,192,2875702,1,0 +352,192,2875926,1,0 +160,192,2876150,5,0 +160,192,2876262,1,0 +160,192,2876374,1,0 +160,192,2876597,1,0 +160,192,2876821,1,0 +296,56,2877045,5,0 +304,56,2877157,1,0 +312,56,2877269,1,0 +216,56,2877493,1,0 +200,56,2877717,1,0 +216,328,2877941,5,0 +208,328,2878053,1,0 +200,328,2878165,1,0 +296,328,2878389,1,0 +312,328,2878613,1,0 +256,192,2878724,12,0,2880403 +392,128,2880627,5,0 +392,128,2880739,1,0 +392,128,2880851,1,0 +392,248,2881075,1,0 +392,128,2881299,1,0 +120,256,2881523,5,0 +120,256,2881635,1,0 +120,256,2881747,1,0 +120,136,2881971,1,0 +120,256,2882194,1,0 +320,328,2882418,5,0 +320,328,2882530,1,0 +320,328,2882642,1,0 +200,328,2882866,1,0 +320,328,2883090,1,0 +192,56,2883314,5,0 +192,56,2883426,1,0 +192,56,2883538,1,0 +312,56,2883762,1,0 +192,56,2883985,1,0 +256,192,2884209,5,0 +256,192,2884321,1,0 +256,192,2884433,1,0 +256,192,2884657,1,0 +256,192,2884881,1,0 +256,192,2885105,5,0 +256,192,2885217,1,0 +256,192,2885329,1,0 +256,192,2885553,1,0 +256,192,2885777,1,0 +64,344,2886224,5,0 +96,344,2886336,1,0 +128,344,2886448,1,0 +160,344,2886560,1,0 +192,344,2886672,1,0 +224,344,2886784,1,0 +256,344,2886896,1,0 +288,344,2887008,1,0 +320,344,2887120,1,0 +352,344,2887232,1,0 +384,344,2887344,1,0 +416,344,2887456,1,0 +448,344,2887568,1,0 +256,192,2887679,12,0,2889359 +176,192,2901769,6,0,B|196:288|272:340|364:360,1,240.000005722046 +332,84,2903251,1,0 +428,136,2903621,1,2 +336,192,2903991,1,0 +428,252,2904362,1,2 +336,192,2904732,6,0,B|316:288|240:340|148:360,1,240.000005722046 +180,84,2906214,1,0 +84,136,2906584,1,2 +176,192,2906954,1,0 +84,252,2907325,1,2 +176,192,2907695,6,0,B|196:96|272:44|364:24,1,240.000005722046 +332,300,2909176,1,0 +428,248,2909547,1,2 +336,192,2909917,1,0 +428,132,2910288,1,2 +336,192,2910658,6,0,B|316:96|240:44|148:24,1,240.000005722046 +180,324,2912139,1,0 +332,324,2912510,1,2 +176,192,2912880,1,0 +204,236,2913065,1,0 +256,248,2913251,1,2 +308,236,2913436,1,0 +336,192,2913621,5,0 +76,324,2914362,1,0 +236,96,2915102,1,0 +340,128,2915473,2,0,B|308:164|304:200|352:248,1,120.000002861023,2|0 +240,276,2916214,1,2 +176,192,2916584,5,0 +436,324,2917325,1,0 +276,96,2918065,1,0 +172,128,2918436,2,0,B|204:164|208:200|160:248,1,120.000002861023,2|0 +272,276,2919176,1,2 +336,192,2919547,5,0 +76,60,2920288,1,0 +236,288,2921028,1,0 +340,256,2921399,2,0,B|308:220|304:184|352:136,1,120.000002861023,2|0 +240,108,2922139,1,2 +176,192,2922510,5,0 +436,60,2923251,1,0 +316,312,2923991,1,0 +228,296,2924362,2,0,B|228:280|228:280|228:208|280:208|280:120|280:120|280:104,1,200 +196,88,2925473,1,0 +174,95,2940288,6,0,B|194:52|255:27|316:48|338:97,2,200,2|8|2 +256,144,2942139,1,0 +208,224,2942510,1,8 +304,224,2942880,1,0 +347,302,2943251,2,0,B|308:333|270:317|255:302|255:302|240:317|199:333|164:302,1,200,2|8 +88,155,2944732,5,2 +68,67,2945102,1,0 +149,28,2945473,1,8 +210,93,2945843,1,0 +181,184,2946214,2,0,B|191:220|255:244|255:244|319:220|333:183,1,200,2|8 +424,229,2947695,5,2 +444,317,2948065,1,0 +363,356,2948436,1,8 +302,291,2948806,1,0 +331,200,2949176,2,0,B|321:164|257:140|257:140|194:160|181:202,1,200,2|8 +352,88,2950658,1,2 +256,48,2951028,1,0 +152,88,2951399,1,8 +44,56,2951769,21,8 +44,56,2951954,1,0 +44,56,2952139,1,4 +160,348,2952880,1,8 +36,172,2953436,1,0 +36,172,2953621,1,0 +192,140,2953991,1,0 +320,244,2954362,1,8 +476,212,2954732,1,0 +476,212,2954917,2,0,B|424:8|112:76|168:296,1,500,0|8 +320,244,2956214,1,0 +476,212,2956584,5,0 +320,244,2956954,1,0 +192,140,2957325,1,8 +36,172,2957695,1,0 +36,172,2957880,2,0,B|88:376|400:308|344:88,1,500,0|8 +192,140,2959176,1,0 +112,276,2959547,5,0 +256,344,2959917,1,0 +400,276,2960288,1,8 +340,136,2960658,2,0,B|364:66|291:34|256:69|256:69|221:34|148:66|172:136,2,299.999991059304 +460,270,2962510,1,0 +421,325,2962695,1,0 +360,300,2962880,1,0 +256,256,2963251,1,8 +152,300,2963621,1,0 +91,325,2963806,1,0 +52,270,2963991,5,0 +352,56,2964732,1,8 +116,92,2965288,1,0 +116,92,2965473,1,0 +176,240,2965843,1,0 +336,240,2966214,1,8 +396,92,2966584,1,0 +396,92,2966769,2,0,B|492:128|532:196|532:304|448:392|348:384|260:320,1,500,0|8 +396,92,2968065,5,0 +396,92,2968251,1,0 +396,92,2968436,1,0 +336,240,2968806,1,0 +176,240,2969176,1,8 +116,92,2969547,1,0 +116,92,2969732,2,0,B|20:128|-20:196|-20:304|64:392|164:384|252:320,1,500,0|8 +256,36,2971399,5,0 +176,172,2971769,1,0 +336,172,2972139,1,8 +432,300,2972510,2,0,B|356:399|257:327|257:327|158:399|83:300,1,400 +256,236,2973621,1,8 +432,172,2973991,2,0,B|356:73|257:144|257:144|158:73|83:172,1,400 +256,236,2975102,1,8 +256,60,2975473,1,8 +256,60,2975658,1,0 +256,60,2975843,5,4 +378,372,2976584,2,0,B|348:306|260:264|172:297|136:371,1,300,8|0 +156,204,2977325,2,0,B|372:204,1,200,8|8 +296,32,2978065,2,0,B|314:70|296:101|268:115|240:115|212:101|194:70|212:32,1,200,8|0 +126,127,2978621,2,0,B|174:192|256:213|337:192|385:127,1,300 +432,304,2979547,5,8 +256,352,2979917,1,0 +80,304,2980288,1,8 +181,159,2980658,2,0,B|191:195|255:219|255:219|319:195|333:158,1,200,0|8 +127,79,2981399,2,0,B|143:14|207:-1|272:14|304:46|288:95|256:111|223:95|207:46|239:14|304:-1|368:14|384:79,1,400 +480,224,2982510,5,8 +360,322,2982880,2,0,B|325:339|290:339|256:322|221:304|204:252|221:201|256:183|290:201|308:252|290:304|256:322|221:339|187:339|152:322,1,400 +32,224,2983991,1,8 +173,146,2984362,2,0,B|181:115|213:90|254:84|254:84|281:74|303:41|281:9|257:3|229:9|201:41|227:74|254:84|254:84|297:90|324:111|338:152,1,400 +448,288,2985473,1,8 +256,368,2985843,5,8 +184,312,2986028,1,8 +208,224,2986214,1,0 +304,224,2986399,1,8 +328,312,2986584,1,8 +334,99,2986954,2,0,B|317:52|255:28|199:50|176:101,1,200,4|0 +256,136,2987510,1,0 +256,136,2987695,5,4 +256,352,2988436,1,8 +412,108,2988991,1,0 +412,194,2989176,2,0,B|362:199|313:154|308:94|344:51,1,200,8|0 +167,51,2989917,2,0,B|203:94|198:154|149:199|100:194,1,200,8|0 +100,108,2990473,1,0 +256,204,2990843,1,0 +330,254,2991028,2,0,B|320:290|256:314|256:314|192:290|178:253,1,200,0|8 +364,344,2991769,5,0 +420,140,2992139,1,0 +256,48,2992510,1,0 +92,140,2992880,1,8 +148,344,2993251,1,0 +256,48,2993991,5,0 +432,336,2994732,1,0 +80,332,2995473,1,0 +256,304,2995843,1,8 +172,152,2996214,2,0,B|136:76|172:14|227:-12|283:-12|338:14|374:76|338:152,1,400 +472,276,2997325,1,8 +311,381,2997695,2,0,B|311:325|255:307|255:307|200:288|200:233,1,200,0|8 +256,168,2998251,1,8 +311,232,2998436,2,0,B|311:288|256:307|256:307|201:325|201:381,1,200,8|8 +39,276,2999176,1,8 +39,276,2999362,1,8 +39,276,2999547,1,4 +256,192,2999639,12,8,3001769 +256,192,3002510,5,4 +468,56,3008436,5,4 +352,348,3009176,1,8 +476,172,3009732,1,0 +476,172,3009917,1,0 +320,140,3010288,1,0 +192,244,3010658,1,8 +36,212,3011028,1,0 +36,212,3011214,2,0,B|88:8|400:76|344:296,1,500,0|8 +36,212,3012880,5,0 +192,244,3013251,1,0 +320,140,3013621,1,8 +476,172,3013991,1,0 +476,172,3014176,2,0,B|424:376|112:308|168:88,1,500,0|8 +320,140,3015473,1,0 +400,276,3015843,5,0 +256,344,3016214,1,0 +112,276,3016584,1,8 +172,136,3016954,2,0,B|148:66|221:34|256:69|256:69|291:34|364:66|340:136,2,299.999991059304 +256,272,3018806,1,0 +412,300,3019176,1,0 +256,272,3019547,1,8 +100,300,3019917,1,0 +100,300,3020102,1,0 +100,300,3020288,5,0 +376,99,3021028,2,0,B|349:30|255:-8|170:25|135:103,1,300,8|0 +176,180,3021769,2,0,B|193:227|255:251|311:229|334:178,1,200,0|0 +488,264,3022510,1,8 +336,348,3022880,1,0 +256,372,3023065,1,0 +176,348,3023251,1,0 +256,52,3023991,5,8 +24,264,3024547,1,0 +24,264,3024732,1,0 +120,112,3025102,1,0 +256,228,3025473,1,8 +392,112,3025843,1,0 +336,180,3026028,2,0,B|308:136|239:99|166:123|80:208|151:317|208:352|279:356|344:292|344:245,1,500,0|8 +448,352,3027325,5,0 +255,229,3027695,1,0 +64,352,3028065,1,0 +32,128,3028436,5,8 +173,13,3028806,2,0,B|137:89|173:151|228:177|284:177|339:151|375:89|339:13,1,400 +480,128,3029917,1,8 +352,288,3030288,5,0 +160,288,3030658,1,0 +336,184,3031028,1,8 +256,216,3031214,1,0 +176,184,3031399,1,8 +304,96,3031769,21,8 +208,96,3031954,1,0 +256,32,3032139,1,4 +256,32,3032880,37,8 +48,280,3033436,1,0 +48,280,3033621,1,0 +192,212,3033991,1,0 +328,292,3034362,1,8 +464,216,3034732,1,0 +464,216,3034917,2,0,B|397:316|291:313|235:285|185:249|132:157|191:49,1,500,0|8 +320,48,3036214,1,0 +256,196,3036584,5,0 +320,336,3036954,1,0 +416,208,3037325,1,8 +256,195,3037695,2,0,B|122:154|122:154|189:218|155:337|25:311,2,400 +256,196,3039917,1,0 +256,36,3040288,1,8 +256,195,3040658,2,0,B|389:154|389:154|322:218|356:337|486:311,1,400 +476,152,3041769,1,8 +352,52,3042139,5,0 +316,108,3042325,1,0 +256,136,3042510,1,0 +196,108,3042695,1,8 +160,52,3042880,1,0 +256,232,3043251,1,8 +256,40,3043621,1,0 +256,40,3043806,1,0 +256,40,3043991,5,4 +256,40,3044732,1,8 +464,280,3045288,1,0 +464,280,3045473,1,0 +320,212,3045843,1,0 +184,292,3046214,1,8 +48,216,3046584,1,0 +48,216,3046769,2,0,B|114:316|220:313|276:285|326:249|379:157|320:49,1,500,0|8 +192,48,3048065,1,0 +256,196,3048436,5,0 +192,336,3048806,1,0 +96,208,3049176,1,8 +256,196,3049547,2,0,B|389:236|389:236|322:173|356:54|486:80,2,400 +256,196,3051769,1,0 +256,355,3052139,1,8 +256,196,3052510,2,0,B|122:236|122:236|189:173|155:54|25:80,1,400 +36,239,3053621,1,8 +160,339,3053991,5,0 +196,283,3054176,1,0 +256,255,3054362,1,0 +316,283,3054547,1,8 +352,339,3054732,1,0 +256,159,3055102,1,8 +256,351,3055473,1,0 +256,351,3055658,1,0 +256,351,3055843,5,4 +256,36,3056584,1,8 +256,260,3057139,1,0 +256,260,3057325,2,0,B|256:112,1,132.00000125885 +312,96,3057880,1,0 +316,160,3058065,1,0 +256,188,3058251,1,0 +196,160,3058436,1,0 +200,96,3058621,1,0 +256,64,3058806,5,4 +332,348,3059547,2,0,B|289:366|256:333|256:308|256:308|256:333|222:366|181:348,1,200,8|0 +80,192,3060288,1,8 +256,88,3060658,1,0 +432,192,3061028,1,8 +340,39,3061399,2,0,B|376:115|340:177|285:203|229:203|174:177|138:115|174:39,2,400 +432,192,3063251,5,8 +256,296,3063621,1,0 +80,192,3063991,1,8 +172,345,3064362,2,0,B|136:269|172:207|227:181|283:181|338:207|374:269|338:345,2,400 +356,48,3066584,6,0,B|156:48,1,200,0|8 +52,196,3067325,1,0 +174,338,3067695,2,0,B|321:183|321:183|256:126|256:126|190:183|190:183|337:338,1,600,8|0 +464,192,3069176,1,8 +464,192,3069362,1,8 +464,192,3069547,1,0 +341,61,3069917,6,0,B|309:102|257:126|200:102|170:59,1,200,8|0 +19,154,3070658,2,0,B|49:231|123:301|196:315|255:330|314:315|392:300|461:231|492:152,1,600,4|0 +480,336,3072139,5,8 +384,80,3072510,1,0 +256,288,3072880,1,8 +128,80,3073251,1,0 +32,336,3073621,1,8 +97,274,3073806,1,0 +171,219,3073991,2,0,B|202:175|257:161|311:175|342:219,1,200,0|8 +344,39,3074732,6,0,B|311:82|258:96|203:82|171:39,1,200,0|8 +160,224,3075473,1,0 +352,224,3075843,1,8 +256,352,3076214,1,0 +256,352,3076954,5,0 +256,192,3077325,1,8 +120,76,3077695,2,0,B|147:143|226:120|256:102|256:37|256:37|256:102|292:120|368:144|400:65,1,400 +376,248,3078806,5,8 +256,344,3079176,1,0 +256,140,3079547,1,0 +136,248,3079917,1,0 +256,44,3080288,1,8 +376,248,3080658,1,0 +340,172,3080843,1,8 +256,140,3081028,1,8 +172,172,3081214,1,8 +136,248,3081399,1,8 +256,344,3081769,21,8 +488,104,3082510,2,0,B|500:97|521:64|516:9|478:-2|456:-23|369:-26|316:12|357:88|357:122|390:190|423:190|491:190|495:255|495:288|495:288|496:323|465:380|423:389|358:386|328:339|323:322|323:289|325:257|345:218|345:218|56:190|256:-177|457:190|157:221|157:221|189:250|198:289|190:322|190:338|156:389|90:389|51:373|21:337|19:289|19:289|20:240|33:208|90:190|123:190|156:122|156:88|169:17|140:-9|52:-29|18:-4|-9:55|4:88|27:110,1,2200,4|0 +72,192,3103251,5,0 +168,332,3103621,1,0 +344,332,3103991,1,0 +440,192,3104362,1,0 +256,148,3104732,1,0 +256,148,3105102,1,0 +168,296,3105473,5,0 +200,348,3105658,1,0 +256,364,3105843,1,0 +312,348,3106028,1,0 +344,296,3106214,2,0,B|272:208|348:88|472:128,1,264.0000025177 +500,268,3107510,1,0 +500,268,3107695,1,0 +400,236,3108065,1,0 +300,204,3108436,1,0 +300,100,3108806,1,0 +168,88,3109176,6,0,B|240:176|164:296|40:256,1,264.0000025177 +12,116,3110473,1,0 +12,116,3110658,1,0 +112,148,3111028,1,0 +212,180,3111399,1,0 +212,284,3111769,1,0 +344,288,3112139,6,0,B|410:277|421:196|403:192|403:192|421:189|410:108|344:97,2,264.0000025177 +256,192,3113991,1,0 +168,96,3114362,2,0,B|101:106|90:187|108:191|108:191|90:194|101:275|168:286,1,264.0000025177 +344,284,3115473,1,0 +256,192,3115843,1,0 +168,100,3116214,1,0 +196,44,3116399,1,0 +256,20,3116584,1,0 +316,44,3116769,1,0 +344,100,3116954,1,0 +256,192,3117325,1,0 +168,300,3117695,1,0 +168,300,3117880,1,0 +168,300,3118065,6,0,B|208:344|312:364|448:344|444:164|432:108|372:56|288:-28|144:4|64:152|140:248,2,800,4|8|8 +256,192,3121121,12,8,3122510 +256,192,3122602,12,8,3123991 +256,192,3124084,12,8,3126214 +108,240,3126584,5,0 +168,72,3126954,1,0 +348,72,3127325,1,0 +404,240,3127695,1,8 +256,360,3128065,1,8 +192,312,3128251,1,8 +212,232,3128436,1,8 +300,232,3128621,1,0 +320,312,3128806,1,8 +344,56,3129176,6,0,B|340:104|340:104|288:136,1,100,8|0 +216,131,3129547,2,0,B|171:103|171:103|167:55,1,100,8|0 +256,44,3129917,5,4 +256,44,3130658,1,8 +464,280,3131214,1,0 +464,280,3131399,1,0 +320,212,3131769,1,0 +184,292,3132139,1,8 +48,216,3132510,1,0 +48,216,3132695,2,0,B|115:316|221:313|277:285|327:249|380:157|321:49,1,500,0|8 +192,48,3133991,1,0 +256,196,3134362,5,0 +192,336,3134732,1,0 +96,208,3135102,1,8 +256,195,3135473,2,0,B|390:154|390:154|323:218|357:337|487:311,2,400 +256,196,3137695,5,0 +256,36,3138065,1,8 +256,195,3138436,2,0,B|123:154|123:154|190:218|156:337|26:311,1,400 +36,152,3139547,1,8 +160,52,3139917,1,0 +196,108,3140102,1,0 +256,136,3140288,1,0 +316,108,3140473,1,8 +352,52,3140658,1,0 +256,232,3141028,5,8 +256,40,3141399,1,0 +256,40,3141584,1,0 +256,40,3141769,1,4 +378,372,3142510,6,0,B|348:306|260:264|172:297|136:371,1,300,8|0 +156,204,3143251,2,0,B|372:204,1,200,8|8 +296,32,3143991,2,0,B|314:70|296:101|268:115|240:115|212:101|194:70|212:32,1,200,8|0 +126,127,3144547,2,0,B|174:192|256:213|337:192|385:127,1,300 +428,304,3145473,5,8 +256,364,3145843,1,0 +84,304,3146214,1,0 +332,212,3146584,6,0,B|322:176|258:152|258:152|192:172|180:213,1,200,0|8 +104,72,3147325,2,0,B|189:109|256:42|256:-7|256:-7|256:42|322:109|406:72,1,400 +480,224,3148436,1,8 +360,322,3148806,2,0,B|325:339|290:339|256:322|221:304|204:252|221:201|256:183|290:201|308:252|290:304|256:322|221:339|187:339|152:322,1,400 +32,224,3149917,5,8 +173,146,3150288,2,0,B|181:115|213:90|254:84|254:84|281:74|303:41|281:9|257:3|229:9|201:41|227:74|254:84|254:84|297:90|324:111|338:152,1,400 +492,232,3151399,1,8 +352,344,3151769,2,0,B|312:312|312:312|304:264,1,100,8|0 +392,256,3152139,2,0,B|384:208|384:208|344:176,1,100,8|0 +328,88,3152510,1,8 +256,144,3152695,1,0 +184,88,3152880,1,8 +168,176,3153065,2,0,B|128:208|128:208|120:256,1,100,0|8 +208,264,3153436,2,0,B|200:312|200:312|160:344,1,100,0|4 +160,56,3154362,5,8 +396,92,3154917,1,0 +396,92,3155102,1,0 +336,240,3155473,1,0 +176,240,3155843,1,8 +116,91,3156214,2,0,B|51:116|28:160|20:208|72:284|148:287|204:212,1,300 +176,240,3156954,1,0 +288,116,3157325,1,8 +116,92,3157695,5,0 +116,92,3157880,1,0 +116,92,3158065,1,0 +176,240,3158436,1,0 +336,240,3158806,1,8 +396,91,3159176,2,0,B|460:116|484:160|492:208|440:284|363:287|308:212,1,300 +336,240,3159917,2,0,B|372:288|288:332|256:256|256:256|224:332|140:288|176:240,1,300 +175,240,3160658,1,0 +256,80,3161028,5,0 +388,320,3161399,1,0 +124,320,3161769,1,8 +96,104,3162139,2,0,B|132:10|259:-40|374:4|421:109,1,400 +256,192,3163251,1,8 +96,280,3163621,2,0,B|132:373|259:424|374:379|421:274,1,400 +366,112,3164732,6,0,B|320:92|320:92|300:48,1,100,8|0 +212,46,3165102,2,0,B|192:92|192:92|146:112,1,100,8|0 +207,184,3165473,2,0,B|146:207|146:207|67:176|67:176|99:348|99:348|177:317|177:317|224:348|224:348|256:333|256:333|287:348|287:348|334:317|334:317|412:348|412:348|444:176|444:176|365:207|365:207|303:184,1,1000,4|0 +256,24,3167695,5,8 +396,91,3168065,2,0,B|461:116|484:160|492:208|440:284|364:287|308:212,1,300 +336,240,3168806,1,0 +224,116,3169176,1,8 +396,92,3169547,5,0 +396,92,3169732,1,0 +396,92,3169917,1,0 +336,240,3170288,1,0 +176,240,3170658,1,8 +116,91,3171028,2,0,B|52:116|28:160|20:208|72:284|149:287|204:212,1,300 +176,240,3171769,2,0,B|140:288|224:332|256:256|256:256|288:332|372:288|336:240,1,300 +337,240,3172510,1,0 +256,80,3172880,5,0 +124,320,3173251,1,0 +388,320,3173621,1,8 +416,104,3173991,2,0,B|380:10|253:-40|138:4|91:109,1,400 +256,192,3175102,1,8 +104,304,3175473,2,0,B|189:267|256:334|256:383|256:383|256:334|322:267|406:304,1,400,8|0 +386,195,3176460,5,0 +309,126,3176583,2,0,B|341:62,2,66.6666666666667,8|0|8 +203,126,3176955,2,0,B|171:62,2,66.6666666666667,8|0|8 +126,195,3177325,1,4 diff --git a/osu.Game.Tests/osu.Game.Tests.csproj b/osu.Game.Tests/osu.Game.Tests.csproj index 60ce67c7f6..3a15b5e6b1 100644 --- a/osu.Game.Tests/osu.Game.Tests.csproj +++ b/osu.Game.Tests/osu.Game.Tests.csproj @@ -30,6 +30,9 @@ false + + $(SolutionDir)\packages\DeepEqual.1.6.0.0\lib\net40\DeepEqual.dll + $(SolutionDir)\packages\NUnit.3.8.1\lib\net45\nunit.framework.dll True @@ -147,6 +150,7 @@ + \ No newline at end of file diff --git a/osu.Game.Tests/packages.config b/osu.Game.Tests/packages.config index ecc44f0c70..e09f2a07ba 100644 --- a/osu.Game.Tests/packages.config +++ b/osu.Game.Tests/packages.config @@ -4,6 +4,7 @@ Copyright (c) 2007-2017 ppy Pty Ltd . Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE --> + From 851c20aff0be3c55fc84c47d8b137de3cbc59222 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 7 Dec 2017 11:17:32 +0900 Subject: [PATCH 1011/1263] Add a few comments --- osu.Game/Audio/SampleInfo.cs | 4 ++++ osu.Game/IO/Serialization/IJsonSerializable.cs | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/osu.Game/Audio/SampleInfo.cs b/osu.Game/Audio/SampleInfo.cs index f8b5bf33d9..3c3a64dbb2 100644 --- a/osu.Game/Audio/SampleInfo.cs +++ b/osu.Game/Audio/SampleInfo.cs @@ -15,6 +15,10 @@ namespace osu.Game.Audio public const string HIT_NORMAL = @"hitnormal"; public const string HIT_CLAP = @"hitclap"; + /// + /// The that is used for and + /// if the values have not already been provided by the hitobject. + /// [JsonIgnore] public SoundControlPoint ControlPoint; diff --git a/osu.Game/IO/Serialization/IJsonSerializable.cs b/osu.Game/IO/Serialization/IJsonSerializable.cs index 8d10f0b291..38e7f47656 100644 --- a/osu.Game/IO/Serialization/IJsonSerializable.cs +++ b/osu.Game/IO/Serialization/IJsonSerializable.cs @@ -20,6 +20,10 @@ namespace osu.Game.IO.Serialization public static T DeepClone(this T obj) where T : IJsonSerializable => Deserialize(Serialize(obj)); + /// + /// Creates the default that should be used for all s. + /// + /// public static JsonSerializerSettings CreateGlobalSettings() => new JsonSerializerSettings { ReferenceLoopHandling = ReferenceLoopHandling.Ignore, From b0684cb194c11a24e6293e38bee98d3f4fc94191 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 7 Dec 2017 12:02:34 +0900 Subject: [PATCH 1012/1263] Add storyboard test case but disable for now --- .../Beatmaps/Formats/OsuJsonDecoderTest.cs | 23 +- ...ow - Rengetsu Ouka (_Kiva) [Yuki YukI].osu | 1231 +++++++++++++++++ osu.Game.Tests/osu.Game.Tests.csproj | 1 + 3 files changed, 1245 insertions(+), 10 deletions(-) create mode 100644 osu.Game.Tests/Resources/Kozato snow - Rengetsu Ouka (_Kiva) [Yuki YukI].osu diff --git a/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs index c3ebcb9e7c..5a66a7047d 100644 --- a/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs @@ -19,13 +19,14 @@ namespace osu.Game.Tests.Beatmaps.Formats [TestFixture] public class OsuJsonDecoderTest { - private const string beatmap_1 = "Soleily - Renatus (Gamu) [Insane].osu"; - private const string beatmap_2 = "Within Temptation - The Unforgiving (Armin) [Marathon].osu"; + private const string normal = "Soleily - Renatus (Gamu) [Insane].osu"; + private const string marathon = "Within Temptation - The Unforgiving (Armin) [Marathon].osu"; + private const string with_sb = "Kozato snow - Rengetsu Ouka (_Kiva) [Yuki YukI].osu"; [Test] public void TestDecodeMetadata() { - var beatmap = decodeAsJson(beatmap_1); + var beatmap = decodeAsJson(normal); var meta = beatmap.BeatmapInfo.Metadata; Assert.AreEqual(241526, meta.OnlineBeatmapSetID); Assert.AreEqual("Soleily", meta.Artist); @@ -43,7 +44,7 @@ namespace osu.Game.Tests.Beatmaps.Formats [Test] public void TestDecodeGeneral() { - var beatmap = decodeAsJson(beatmap_1); + var beatmap = decodeAsJson(normal); var beatmapInfo = beatmap.BeatmapInfo; Assert.AreEqual(0, beatmapInfo.AudioLeadIn); Assert.AreEqual(false, beatmapInfo.Countdown); @@ -57,7 +58,7 @@ namespace osu.Game.Tests.Beatmaps.Formats [Test] public void TestDecodeEditor() { - var beatmap = decodeAsJson(beatmap_1); + var beatmap = decodeAsJson(normal); var beatmapInfo = beatmap.BeatmapInfo; int[] expectedBookmarks = @@ -78,7 +79,7 @@ namespace osu.Game.Tests.Beatmaps.Formats [Test] public void TestDecodeDifficulty() { - var beatmap = decodeAsJson(beatmap_1); + var beatmap = decodeAsJson(normal); var difficulty = beatmap.BeatmapInfo.BaseDifficulty; Assert.AreEqual(6.5f, difficulty.DrainRate); Assert.AreEqual(4, difficulty.CircleSize); @@ -91,7 +92,7 @@ namespace osu.Game.Tests.Beatmaps.Formats [Test] public void TestDecodeColors() { - var beatmap = decodeAsJson(beatmap_1); + var beatmap = decodeAsJson(normal); Color4[] expected = { new Color4(142, 199, 255, 255), @@ -109,7 +110,7 @@ namespace osu.Game.Tests.Beatmaps.Formats [Test] public void TestDecodeHitObjects() { - var beatmap = decodeAsJson(beatmap_1); + var beatmap = decodeAsJson(normal); var curveData = beatmap.HitObjects[0] as IHasCurve; var positionData = beatmap.HitObjects[0] as IHasPosition; @@ -128,8 +129,10 @@ namespace osu.Game.Tests.Beatmaps.Formats Assert.IsTrue(beatmap.HitObjects[1].Samples.Any(s => s.Name == SampleInfo.HIT_CLAP)); } - [TestCase(beatmap_1)] - [TestCase(beatmap_2)] + [TestCase(normal)] + [TestCase(marathon)] + // Currently fails: + // [TestCase(with_sb)] public void TestParity(string beatmap) { var beatmaps = decode(beatmap); diff --git a/osu.Game.Tests/Resources/Kozato snow - Rengetsu Ouka (_Kiva) [Yuki YukI].osu b/osu.Game.Tests/Resources/Kozato snow - Rengetsu Ouka (_Kiva) [Yuki YukI].osu new file mode 100644 index 0000000000..38db42fddc --- /dev/null +++ b/osu.Game.Tests/Resources/Kozato snow - Rengetsu Ouka (_Kiva) [Yuki YukI].osu @@ -0,0 +1,1231 @@ +osu file format v9 + +[General] +AudioFilename: Kozato snow.mp3 +AudioLeadIn: 1000 +PreviewTime: 173263 +Countdown: 0 +SampleSet: Soft +StackLeniency: 0.5 +Mode: 0 +LetterboxInBreaks: 0 + +[Editor] +Bookmarks: 14893,27933,40766,54427,67053,80300,94167,107414,120247,133919,147166,160424,173673,187336,200172 +DistanceSpacing: 0.5 +BeatDivisor: 4 +GridSize: 8 + +[Metadata] +Title:Rengetsu Ouka +Artist:Kozato snow +Creator:_Kiva +Version:Yuki YukI +Source: +Tags:Kiva Snowy Dream Yumeko Yuki HakuNoKaemi wmfchris aabc271 + +[Difficulty] +HPDrainRate:8 +CircleSize:4 +OverallDifficulty:7 +ApproachRate:8 +SliderMultiplier:1.8 +SliderTickRate:0.5 + +[Events] +//Background and Video events +0,0,"BG_example.JPG" +//Break Periods +2,54644,66322 +2,67893,79572 +2,107641,119526 +2,160627,172513 +//Storyboard Layer 0 (Background) +Sprite,Background,Centre,"SB\bg2.png",320,240 + S,0,26288,26495,1,1.04096 + F,0,26288,27530,1,0 + S,0,26495,27530,1.04096,1.26624 +Sprite,Background,Centre,"SB\C32.png",320,240 + M,0,41193,54436,259,283,320,240 + F,0,41193,54436,1 + S,0,41193,54436,1.2048,1.13312 + R,0,41193,54436,0,0.1023999 + F,0,54436,55264,1,0 + S,0,54436,55264,1.13312,1.29696 +Sprite,Background,Centre,"SB\bg1.png",320,240 + F,0,27944,,1 + S,0,27944,41193,1,1.327681 + S,0,41193,,1.327681 +Sprite,Background,Centre,"SB\bg3.png",320,240 + F,0,160427,162083,0,1 + S,0,160427,162083,1 + S,0,162083,166829,1,1.035869 + F,0,162083,173677,1,0.9987923 + S,0,166829,173677,1.035869,1.11264 + F,0,173677,173780,0.9987923,0.8605523 +//Storyboard Layer 1 (Fail) +//Storyboard Layer 2 (Pass) +//Storyboard Layer 3 (Foreground) +Sprite,Foreground,Centre,"SB\bg2.png",320,240 + F,0,1445,2687,0.8,0 + S,0,1445,2687,1,1.16 +Sprite,Foreground,Centre,"SB\Mini Light.png",320,240 + M,0,24631,,140,147 + S,0,24631,24838,0.19104,0.488 + F,0,24631,25045,1,0 + S,0,24838,25045,0.488,0.5903998 +Sprite,Foreground,Centre,"SB\MINI SNOW.png",320,240 + M,0,25045,,472,224 + S,0,25045,25252,0.32416,0.5392001 + F,0,25045,25459,1,0 + S,0,25252,25459,0.5392001,0.6518402 +Sprite,Foreground,Centre,"SB\black.png",320,240 + F,0,26702,27944,0,1 + F,0,27944,28358,1,0.55296 + F,0,28358,28772,0.55296,0.005119934 +Sprite,Foreground,Centre,"SB\OP effect.png",320,240 + M,0,25459,,193,293 + F,0,25459,25666,1,0 + S,0,25459,25666,0.61088,1.24576 +Sprite,Foreground,Centre,"SB\OP effect.png",320,240 + M,0,25666,,387,373 + P,0,25666,,H + V,0,25666,,1.06144,1 + V,0,25666,,1.06144,1 + F,0,25666,25873,1,0 + S,0,25666,25873,0.6313599,1.4096 +Sprite,Foreground,Centre,"SB\OP effect.png",320,240 + M,0,25873,,417,134 + M,0,25873,,417,134 + P,0,25873,,V + F,0,25873,26080,1,0 + S,0,25873,26080,1,1.52224 +Sprite,Foreground,Centre,"SB\OP effect.png",320,240 + F,0,26080,26288,1,0 + S,0,26080,26288,1,1.54272 +Sprite,Foreground,Centre,"SB\sakura_b.png",320,240 + S,0,26288,26391,0.3,0.7 + F,0,26288,27116,1 + S,0,26391,27530,0.7,0.9 + F,0,27116,27530,1,0 +Sprite,Foreground,Centre,"SB\sakura_b.png",320,240 + M,0,26288,,529,377 + P,0,26288,,H + S,0,26288,26391,0.4,0.55 + F,0,26288,26702,1,0 + S,0,26391,26702,0.55,0.9 +Sprite,Foreground,Centre,"SB\sakura_b.png",320,240 + M,0,26288,,202,210 + P,0,26288,,H + P,0,26288,,V + S,0,26288,26391,0.4,0.64 + F,0,26288,26702,1,0 + S,0,26391,26702,0.64,0.7 +Sprite,Foreground,Centre,"SB\azure.png",320,240 + F,0,40779,41193,0,1 + F,0,41193,41814,1,0 +Sprite,Foreground,Centre,"SB\sakura_b",320,240 + F,0,54436,55264,0,1 + R,0,54436,61060,0.2252804,0 + S,0,54443,,1.5625 + M,0,54443,61060,378,177,304,342 + F,0,55264,59404,1 + F,0,59404,61060,1,0 +Sprite,Foreground,Centre,"SB\bg2.png",320,240 + F,0,61060,61267,0,0.7122133 + S,0,61060,62302,1,1.1024 + F,0,61267,62302,0.7122133,0 +Sprite,Foreground,Centre,"SB\bg2.png",320,240 + F,0,67685,67892,0,0.8333333 + S,0,67685,68927,1,1.13312 + F,0,67892,68927,0.8333333,0 +Sprite,Foreground,Centre,"SB\wakka.png",320,240 + M,0,80935,,305,116 + F,0,80935,81038,1,0.9206253 + S,0,80935,81038,0.3548797,0.7181275 + S,0,81038,,0.7181275 + F,0,81038,81349,0.9206253,0.6809599 + S,0,81038,81556,0.7181275,0.8000475 + F,0,81349,81556,0.6809599,0 +Sprite,Foreground,Centre,"SB\wakka.png",320,240 + F,0,14694,14901,0,0.8333333 + S,0,14694,14901,0.7337599,1.41984 + S,0,14901,15108,1.41984,1.6144 + F,0,14901,15936,0.8333333,0 + S,0,15108,15522,1.6144,1.80896 + S,0,15522,15936,1.80896,1.94208 +Animation,Foreground,Centre,"SB\am2\am2.png",320,240,5,500,LoopForever + S,0,67685,,1 + R,0,67685,,0 + F,0,67685,68513,0,0.7696 + M,0,67685,74310,102,25,93,434 + F,0,68513,69341,0.7696,1 + F,0,69341,70169,1,0.7696 + F,0,70169,70998,0.7696,1 + F,0,70998,71826,1,0.8771199 + F,0,71826,72654,0.8771199,1 + F,0,72654,73482,1,0.73888 + F,0,73482,74310,0.73888,0 +Animation,Foreground,Centre,"SB\am2\am2.png",320,240,5,500,LoopForever + S,0,67685,,1 + R,0,67685,,0 + F,0,67685,68513,0,0.7696 + M,0,67685,74310,411,130,387,308 + F,0,68513,69341,0.7696,1 + F,0,69341,70169,1,0.7696 + F,0,70169,70998,0.7696,1 + F,0,70998,71826,1,0.8771199 + F,0,71826,72654,0.8771199,1 + F,0,72654,73482,1,0.73888 + F,0,73482,74310,0.73888,0 +Animation,Foreground,Centre,"SB\am2\am2.png",320,240,5,500,LoopForever + S,0,67685,,1 + R,0,67685,,0 + F,0,67685,68513,0,0.7696 + M,0,67685,74310,102,25,93,434 + F,0,68513,69341,0.7696,1 + F,0,69341,70169,1,0.7696 + F,0,70169,70998,0.7696,1 + F,0,70998,71826,1,0.8771199 + F,0,71826,72654,0.8771199,1 + F,0,72654,73482,1,0.73888 + F,0,73482,74310,0.73888,0 +Animation,Foreground,Centre,"SB\am2\am2.png",320,240,5,500,LoopForever + S,0,67685,,1 + R,0,67685,,0 + F,0,67685,68513,0,0.7696 + M,0,67685,74310,179,179,203,467 + F,0,68513,69341,0.7696,1 + F,0,69341,70169,1,0.7696 + F,0,70169,70998,0.7696,1 + F,0,70998,71826,1,0.8771199 + F,0,71826,72654,0.8771199,1 + F,0,72654,73482,1,0.73888 + F,0,73482,74310,0.73888,0 +Animation,Foreground,Centre,"SB\am2\am2.png",320,240,5,500,LoopForever + S,0,67685,,1 + R,0,67685,,0 + F,0,67685,68513,0,0.7696 + M,0,67685,74310,237,361,274,534 + F,0,68513,69341,0.7696,1 + F,0,69341,70169,1,0.7696 + F,0,70169,70998,0.7696,1 + F,0,70998,71826,1,0.8771199 + F,0,71826,72654,0.8771199,1 + F,0,72654,73482,1,0.73888 + F,0,73482,74310,0.73888,0 +Animation,Foreground,Centre,"SB\am2\am2.png",320,240,5,500,LoopForever + S,0,67685,,0.63136 + R,0,67685,,0 + F,0,67685,68513,0,0.7696 + M,0,67685,74310,227,175,267,525 + F,0,68513,69341,0.7696,1 + F,0,69341,70169,1,0.7696 + F,0,70169,70998,0.7696,1 + F,0,70998,71826,1,0.8771199 + F,0,71826,72654,0.8771199,1 + F,0,72654,73482,1,0.73888 + F,0,73482,74310,0.73888,0 +Animation,Foreground,Centre,"SB\am2\am2.png",320,240,5,500,LoopForever + S,0,67685,,0.41632 + R,0,67685,,0 + F,0,67685,68513,0,0.7696 + M,0,67685,74310,564,-67,619,531 + F,0,68513,69341,0.7696,1 + F,0,69341,70169,1,0.7696 + F,0,70169,70998,0.7696,1 + F,0,70998,71826,1,0.8771199 + F,0,71826,72654,0.8771199,1 + F,0,72654,73482,1,0.73888 + F,0,73482,74310,0.73888,0 +Sprite,Foreground,Centre,"SB\SNOW.png",320,240 + S,0,67685,,2.35168 + F,0,67685,70998,0,1 + M,0,67685,80314,320,-211,317,693 + F,0,68513,80314,1,0 + F,0,70998,79279,1 + F,0,79279,80314,1,0 +Animation,Foreground,Centre,"SB\am2\am2.png",320,240,5,500,LoopForever + F,0,70998,71826,0,1 + M,0,70998,74299,257,66,263,208 + F,0,71826,72654,1,0.7132799 + F,0,72654,73689,0.7132799,1 + F,0,73689,74310,1,0 +Animation,Foreground,Centre,"SB\am2\am2.png",320,240,5,500,LoopForever + S,0,70998,,0.7030401 + F,0,70998,71826,0,1 + M,0,70998,74310,431,109,422,223 + F,0,71826,72654,1,0.7132799 + F,0,72654,73689,0.7132799,1 + F,0,73689,74310,1,0 +Animation,Foreground,Centre,"SB\am2\am2.png",320,240,5,500,LoopForever + F,0,70998,71826,0,1 + M,0,70998,74299,73,-34,66,270 + F,0,71826,72654,1,0.7132799 + F,0,72654,73689,0.7132799,1 + F,0,73689,74310,1,0 +Animation,Foreground,Centre,"SB\am2\am2.png",320,240,5,500,LoopForever + S,0,70998,,0.6825599 + F,0,70998,71826,0,1 + M,0,70998,74299,390,75,370,115 + F,0,71826,72654,1,0.7132799 + F,0,72654,73689,0.7132799,1 + F,0,73689,74310,1,0 +Sprite,Foreground,Centre,"SB\wakka.png",320,240 + M,0,81763,,249,251 + S,0,81763,81866,0.39584,0.6620799 + F,0,81763,82384,1,0 + S,0,81866,82384,0.6620799,0.8975999 +Sprite,Foreground,Centre,"SB\wakka.png",320,240 + M,0,82591,,152,394 + S,0,82591,82694,0.3651201,0.7952 + F,0,82591,83212,1,0 + S,0,82694,83212,0.7952,1.01024 +Sprite,Foreground,Centre,"SB\wakka.png",320,240 + M,0,83419,,456,324 + S,0,83419,83523,0.3856,0.744 + F,0,83419,84040,1,0 + S,0,83523,84040,0.744,1.02048 +Sprite,Foreground,Centre,"SB\wakka.png",320,240 + M,0,85075,,321,197 + S,0,85075,85179,0.37536,0.80544 + F,0,85075,85696,0.9948799,0 + S,0,85179,85696,0.80544,1.12288 +Sprite,Foreground,Centre,"SB\wakka.png",320,240 + M,0,85903,,248,284 + S,0,85903,86007,0.3344,0.8464 + F,0,85903,86524,1,0 + S,0,86007,86524,0.8464,1.2048 +Sprite,Foreground,Centre,"SB\wakka.png",320,240 + M,0,86731,,207,101 + S,0,86731,86835,0.37536,0.8 + F,0,86731,87352,1,0 + S,0,86835,87352,0.8463999,1.22528 +Sprite,Foreground,Centre,"SB\wakka.png",320,240 + M,0,87560,,472,229 + S,0,87560,87663,0.3,0.8 + F,0,87560,88180,1,0 + S,0,87663,88180,0.8,1.12 +Sprite,Foreground,Centre,"SB\wakka.png",320,240 + M,0,88388,,408,373 + S,0,88388,88491,0.3,0.8 + F,0,88388,88905,1,0 + S,0,88491,88905,0.8,1.12 +Sprite,Foreground,Centre,"SB\wakka.png",320,240 + M,0,89216,,321,136 + S,0,89216,89319,0.3,0.8 + F,0,89216,89733,1,0 + S,0,89319,89733,0.8,1.12 +Sprite,Foreground,Centre,"SB\wakka.png",320,240 + M,0,90044,,257,252 + S,0,90044,90147,0.3,0.8 + F,0,90044,90561,1,0 + S,0,90147,90561,0.8,1.12 +Sprite,Foreground,Centre,"SB\wakka.png",320,240 + M,0,90872,,265,292 + S,0,90872,90975,0.3,0.8 + F,0,90872,91389,1,0 + S,0,90975,91389,0.8,1.12 +Sprite,Foreground,Centre,"SB\wakka.png",320,240 + M,0,91700,,265,132 + S,0,91700,91804,0.3,0.8 + F,0,91700,92217,1,0 + S,0,91804,92217,0.8,1.12 +Sprite,Foreground,Centre,"SB\wakka.png",320,240 + M,0,92528,,521,252 + S,0,92528,92632,0.3,0.8 + F,0,92528,93045,1,0 + S,0,92632,93045,0.8,1.12 +Sprite,Foreground,Centre,"SB\wakka.png",320,240 + M,0,93356,,304,309 + S,0,93356,93460,0.3,0.8 + F,0,93356,93873,1,0 + S,0,93460,93873,0.8,1.12 +Sprite,Foreground,Centre,"SB\wakka.png",320,240 + M,0,84247,,495,122 + S,0,84247,84351,0.3855998,0.7849598 + F,0,84247,84868,1,0 + S,0,84351,84868,0.7849598,1.13312 +Sprite,Foreground,Centre,"SB\bg2.png",320,240 + M,0,94184,,320,240 + S,0,94184,94391,1,1.05632 + F,0,94184,95012,1,0 + S,0,94391,95012,1.05632,1.19456 +Sprite,Foreground,Centre,"SB\azure.png",320,240 + F,0,100809,102051,0.38048,0 +Sprite,Foreground,Centre,"SB\azure.png",320,240 + R,0,120276,,0 + F,0,120276,120690,0,1 + F,0,120690,121518,1,0 +Sprite,Foreground,Centre,"SB\bg4.png",320,240 + F,0,107441,133112,1 + S,0,107441,133112,1.3,1 + R,0,107441,133112,0.2,0 +Sprite,Foreground,Centre,"SB\azure.png",320,240 + F,0,107020,107434,0,1 + F,0,107434,108269,1,0 +Sprite,Foreground,Centre,"SB\C32.png",320,240 + F,0,173682,190322,1 + M,0,173682,200181,228,268,320,240 + S,0,173682,200181,1.70656,1 + R,0,173682,200181,0.3072,0 + F,0,190322,192412,1 + F,0,192412,200181,1 + F,0,200181,201009,1,0 +Sprite,Foreground,Centre,"SB\sakura_b.png",320,240 + F,0,173677,173682,0.69792,0.3702399 + S,0,173682,180306,1,1.43008 + R,0,173682,180306,0.04096008,2.7648 + F,0,173682,186103,0.3702399 + S,0,180306,186931,1.43008,1.64512 + R,0,180306,186931,2.7648,4.68992 + F,0,186103,186931,0.3702399,0 +Sprite,Foreground,Centre,"SB\MINI SNOW.png",320,240 + F,0,186931,187759,0,1 + S,0,186931,200181,1,1.53248 + R,0,186931,200181,1.92512,0 + F,0,187759,199353,1 + F,0,199353,200181,1,0 +Sprite,Foreground,Centre,"SB\sakura_b.png",320,240 + F,0,186931,188173,0,0.3503307 + S,0,186931,199353,1,1.28672 + R,0,186931,199353,-3.23584,-1.76128 + F,0,188173,198110,0.3503307,0.19104 + F,0,198110,199353,0.19104,0.005120086 + F,0,199353,200724,0.005120086,0 +Animation,Foreground,Centre,"SB\am1\am1.jpg",320,240,5,500,LoopForever + M,0,74310,,313,234 + F,0,74310,74724,0.05792008,1 + F,0,74724,75345,1,0.8813094 + F,0,75345,75966,0.8813094,0.9981386 + F,0,75966,76794,0.9981386,0.8279376 + F,0,76794,77622,0.8279376,0.9956568 + F,0,77622,78450,0.9956568,0.7588959 + F,0,78450,79279,0.7588959,0.9931734 + F,0,79279,80107,0.9931734,0.01013343 +Sprite,Foreground,Centre,"SB\wakka.png",320,240 + M,0,74310,,313,232 + S,0,74310,74413,0.3139198,0.6415999 + F,0,74310,75138,1,0 + S,0,74413,75138,0.6415999,0.7961942 +Sprite,Foreground,Centre,"SB\bg2.png",320,240 + F,0,133112,133940,0,1 + F,0,133940,147178,1 + S,0,133940,147178,1,1.16384 + F,0,147178,147592,1,0 + S,0,147178,147592,1.16384,1.33792 +Sprite,Foreground,Centre,"SB\sakura_b.png",320,240 + M,0,120690,,320,240 + S,0,120690,120794,1,1.29696 + F,0,120690,121104,1 + S,0,120794,121932,1.29696,1.44032 + F,0,121104,121932,1,0.002415478 +Sprite,Foreground,Centre,"SB\wakka.png",320,240 + S,0,160427,160531,0.7337601,1.4608 + F,0,160427,162083,1,0 + S,0,160531,161255,1.4608,1.77824 + S,0,161255,162083,1.77824,2.03615 +Sprite,Foreground,Centre,"SB\azure.png",320,240 + R,0,132284,,0 + F,0,132284,133112,0,1 + F,0,133112,133940,1,0 +Sprite,Foreground,Centre,"SB\wakka.png",320,240 + S,0,133940,134043,1,1.38912 + F,0,133940,134457,1,0.80544 + S,0,134043,134975,1.38912,1.89088 + F,0,134457,134975,0.80544,0 +Sprite,Foreground,Centre,"SB\SNOW.png",320,240 + S,0,108269,,2.37216 + F,0,108269,109097,0,1 + M,0,108269,120173,314,-250,315,229 + F,0,109097,112409,1 + F,0,112409,112823,1,0.80032 + F,0,112823,113237,0.80032,1 + F,0,113237,119344,1 + F,0,119344,120173,1,0 +Sprite,Foreground,Centre,"SB\black.png",320,240 + S,0,173263,,1 + F,0,173263,173682,0,1 + F,0,173682,174510,1,0 + F,0,173682,174510,1,0.004830897 +Sprite,Foreground,Centre,"SB\White Effect.png",320,240 + M,0,173677,,217,128 + F,0,173677,174510,1,0 + S,0,173677,174510,0.2115199,1.09216 +//Storyboard Sound Samples +//Background Colour Transformations +3,100,163,162,255 + +[TimingPoints] +1445,414.050100062108,4,2,1,70,1,0 +13659,-100,4,2,1,40,0,0 +13762,-100,4,2,1,45,0,0 +13866,-100,4,2,1,50,0,0 +13970,-100,4,2,1,55,0,0 +14073,-100,4,2,1,50,0,0 +14177,-100,4,2,1,55,0,0 +14280,-100,4,2,1,60,0,0 +14384,-100,4,2,1,75,0,0 +14487,-100,4,2,1,80,0,0 +14591,-100,4,2,1,85,0,0 +14694,-100,4,2,1,60,0,0 +14901,-100,4,2,0,45,0,0 +15005,-100,4,2,1,60,0,0 +15315,-100,4,2,0,45,0,0 +15419,-100,4,2,1,60,0,0 +15626,-100,4,2,0,45,0,0 +15833,-100,4,2,1,60,0,0 +16040,-100,4,2,0,45,0,0 +16247,-100,4,2,1,60,0,0 +16454,-100,4,2,0,45,0,0 +16764,-100,4,2,1,60,0,0 +16868,-100,4,2,0,45,0,0 +17178,-100,4,2,1,60,0,0 +17282,-100,4,2,0,45,0,0 +17489,-100,4,2,1,60,0,0 +17696,-100,4,2,0,45,0,0 +17903,-100,4,2,1,60,0,0 +18110,-100,4,2,0,45,0,0 +18317,-100,4,2,1,60,0,0 +18628,-100,4,2,0,45,0,0 +18731,-100,4,2,1,60,0,0 +18938,-100,4,2,0,45,0,0 +19145,-100,4,2,1,60,0,0 +19352,-100,4,2,0,45,0,0 +19559,-100,4,2,1,60,0,0 +19766,-100,4,2,0,45,0,0 +19973,-100,4,2,1,60,0,0 +20180,-100,4,2,0,45,0,0 +20387,-100,4,2,1,60,0,0 +20594,-100,4,2,0,45,0,0 +20801,-100,4,2,1,60,0,0 +21112,-100,4,2,0,45,0,0 +21215,-100,4,2,1,60,0,0 +21422,-100,4,2,0,45,0,0 +21629,-100,4,2,1,60,0,0 +21836,-100,4,2,0,45,0,0 +22043,-100,4,2,1,60,0,0 +22354,-100,4,2,0,45,0,0 +22458,-100,4,2,1,60,0,0 +22768,-100,4,2,0,45,0,0 +22872,-100,4,2,1,60,0,0 +23079,-100,4,2,0,45,0,0 +23286,-100,4,2,1,60,0,0 +23596,-100,4,2,0,45,0,0 +23700,-100,4,2,1,60,0,0 +23907,-100,4,2,0,45,0,0 +24114,-100,4,2,1,60,0,0 +24321,-100,4,2,0,45,0,0 +24528,-100,4,1,1,60,0,0 +27323,-100,4,2,1,60,0,0 +27530,-100,4,2,1,60,0,0 +27944,-100,4,2,1,60,0,0 +29082,-100,4,2,1,65,0,0 +39951,-100,4,2,1,80,0,0 +40158,-100,4,2,1,85,0,0 +40766,-100,4,2,1,30,0,0 +41193,-100,4,2,1,85,0,0 +41814,-100,4,2,1,85,0,0 +43471,-100,4,2,1,75,0,0 +44092,-100,4,2,1,65,0,0 +44299,-100,4,2,1,55,0,0 +44506,-100,4,2,1,45,0,0 +44920,-100,4,2,1,50,0,0 +45437,-100,4,2,1,55,0,0 +46162,-100,4,2,1,60,0,0 +47094,-100,4,2,1,65,0,0 +47818,-100,4,2,1,55,0,0 +48750,-100,4,2,1,60,0,0 +50095,-100,4,2,1,65,0,0 +54444,414.050100062108,4,2,1,70,1,0 +67383,-100,4,2,1,50,0,0 +67590,-100,4,2,1,70,0,0 +102680,-200,4,2,1,70,0,0 +105993,-100,4,2,1,70,0,0 +107441,414.050100062108,4,2,1,70,1,0 +107648,-100,4,2,1,70,0,0 +120380,-100,4,2,1,75,0,0 +132905,-100,4,2,1,35,0,0 +133008,-100,4,2,1,40,0,0 +133112,-100,4,2,1,45,0,0 +133215,-100,4,2,1,45,0,0 +133319,-100,4,2,1,50,0,0 +133422,-100,4,2,1,55,0,0 +133526,-100,4,2,1,60,0,0 +133629,-100,4,2,1,65,0,0 +133733,-100,4,2,1,70,0,0 +133836,-100,4,2,1,75,0,0 +133940,-100,4,2,1,80,0,1 +136217,-100,4,2,1,60,0,1 +137045,-100,4,2,1,80,0,1 +147174,-100,4,2,1,80,0,0 +147178,414.050100062108,4,2,1,70,1,0 +173263,-100,4,2,1,60,0,0 +173682,414.050100062108,4,2,1,70,1,0 +174303,-100,4,2,1,40,0,0 +174406,-100,4,2,1,45,0,0 +174510,-100,4,2,1,50,0,0 +174613,-100,4,2,1,55,0,0 +174717,-100,4,2,1,60,0,0 +174820,-100,4,2,1,65,0,0 +174924,-100,4,2,1,70,0,0 +175027,-100,4,2,1,75,0,0 +175131,-100,4,2,1,80,0,0 +186517,-100,4,2,1,30,0,0 +186931,-100,4,2,1,80,0,1 +187035,-100,4,2,1,80,0,1 +196247,-100,4,2,1,70,0,1 +196454,-100,4,2,1,60,0,1 +196661,-100,4,2,1,50,0,1 +196868,-100,4,2,1,80,0,1 +200181,-100,4,2,1,80,0,0 + +[Colours] +Combo1 : 152,48,207 +Combo2 : 254,75,169 +Combo3 : 226,5,221 +SliderBorder : 224,224,224 + +[HitObjects] +112,96,1030,1,0 +144,108,1134,1,0 +176,92,1237,1,0 +208,108,1341,1,0 +240,96,1445,1,0 +408,272,2894,5,0 +408,272,2997,1,0 +408,272,3101,2,0,B|360:280|312:272,1,90 +104,276,3515,2,0,B|152:268|200:276,1,90 +216,184,3929,1,0 +168,88,4136,1,0 +256,144,4343,1,0 +208,48,4550,1,0 +312,64,4757,5,0 +416,64,4964,1,0 +416,64,5067,2,0,B|448:104|464:144|464:200,1,135 +463,187,5481,1,0 +463,187,5585,1,0 +437,289,5792,1,0 +337,262,5999,1,0 +364,162,6206,1,0 +464,188,6413,1,0 +464,88,6620,6,0,B|424:64|368:56,1,90 +280,56,7034,2,0,B|184:56,1,90 +190,56,7448,1,0 +128,136,7655,1,0 +120,168,7759,1,0 +128,200,7862,1,0 +136,232,7966,1,0 +128,264,8069,1,0 +192,336,8276,5,0 +192,336,8380,2,0,B|240:336|288:328|336:312,1,135 +324,315,8794,1,0 +324,315,8897,1,0 +336,216,9104,1,0 +440,200,9311,1,0 +480,104,9518,1,0 +392,40,9726,6,0,B|288:40,1,90 +224,88,10140,1,0 +216,104,10243,1,0 +208,120,10347,1,0 +200,136,10450,1,0 +192,152,10554,1,0 +256,296,10761,1,0 +256,152,10968,1,0 +256,296,11175,1,0 +168,344,11382,5,0 +168,248,11589,1,0 +168,248,11692,1,0 +128,112,12003,1,0 +128,112,12106,1,0 +128,112,12210,2,0,B|144:160|128:208,1,90 +48,248,12624,2,0,B|32:200|48:152,1,90 +48,64,13038,5,0 +48,64,13245,2,0,B|96:64,2,45 +208,64,13659,1,0 +240,64,13762,1,0 +272,72,13866,1,0 +304,88,13970,1,0 +328,112,14073,1,8 +344,144,14177,1,8 +352,176,14280,1,8 +352,208,14384,5,0 +344,240,14487,1,0 +328,272,14591,1,0 +304,296,14694,2,0,B|264:320|216:328,1,90,0|2 +104,280,15108,2,0,B|144:256|192:248,1,90,0|2 +280,224,15522,1,0 +296,120,15729,1,2 +192,96,15936,1,0 +168,192,16143,5,2 +168,192,16247,1,0 +168,192,16350,1,0 +144,288,16557,2,0,B|208:288|208:288|232:264,1,90,2|0 +168,192,16971,2,0,B|104:192|104:192|80:216,1,90,2|0 +144,288,17385,1,2 +256,352,17592,1,0 +368,288,17799,1,2 +256,104,18007,5,0 +256,104,18214,1,2 +256,104,18317,2,0,B|256:240,1,135,0|2 +256,239,18731,1,0 +256,239,18835,1,0 +168,296,19042,1,2 +256,352,19249,1,0 +168,296,19456,1,2 +256,239,19663,1,0 +344,296,19870,1,2 +256,239,20077,1,0 +136,152,20284,5,2 +256,96,20491,1,0 +376,152,20698,1,2 +424,264,20905,1,0 +416,264,21008,1,0 +408,264,21112,1,2 +400,264,21215,1,0 +392,264,21319,1,0 +288,264,21526,1,2 +288,264,21629,1,0 +136,208,21940,5,2 +136,208,22043,1,0 +136,208,22147,2,0,B|136:144|136:144|160:128,1,90,0|2 +248,104,22561,2,0,B|248:168|248:168|224:184,1,90,0|2 +136,104,22975,1,0 +248,56,23182,1,2 +360,104,23389,1,0 +376,120,23493,1,0 +392,136,23596,1,2 +408,152,23700,1,0 +424,168,23803,1,0 +432,280,24010,5,2 +256,328,24217,1,0 +80,280,24424,1,2 +256,192,24631,12,0,27116 +256,192,27323,5,0 +256,192,27426,1,0 +256,192,27530,1,4 +72,136,27944,5,0 +161,84,28151,1,0 +158,182,28358,1,0 +96,80,28565,1,0 +192,32,28772,5,0 +224,32,28875,1,0 +256,32,28979,1,0 +288,32,29082,1,0 +320,32,29186,2,0,B|368:32,4,45 +272,112,29807,6,0,B|248:160|272:200,1,90 +360,160,30221,1,0 +368,168,30324,1,0 +376,176,30428,1,0 +384,184,30532,1,0 +392,192,30635,2,0,B|448:192,4,45 +328,280,31256,5,0 +224,296,31463,1,0 +128,248,31670,2,0,B|96:216|104:160,1,90 +176,88,32084,2,0,B|208:120|200:176,1,90 +128,248,32498,2,0,B|96:280,2,45 +216,192,32912,2,0,B|256:168|304:192,1,90 +264,288,33326,2,0,B|304:312|352:288,1,90 +408,208,33740,1,0 +424,104,33947,1,0 +336,40,34154,6,0,B|288:40,4,45,0|0|0|0|8 +336,136,34776,1,0 +176,136,34983,1,0 +256,72,35190,1,0 +256,112,35293,1,0 +256,160,35397,1,0 +88,264,35604,2,0,B|128:240|176:240,1,90 +424,264,36018,2,0,B|384:240|336:240,1,90 +208,320,36432,6,0,B|208:232,1,90 +304,320,36846,2,0,B|304:232,1,90 +256,144,37260,1,0 +256,144,37467,1,0 +256,144,37570,1,0 +256,144,37674,1,0 +336,80,37881,1,0 +424,136,38088,1,0 +424,136,38191,1,0 +424,136,38295,2,0,B|424:232,1,90 +344,272,38709,5,0 +344,176,38916,1,0 +256,328,39123,1,0 +256,120,39330,1,0 +176,224,39537,5,0 +176,224,39744,1,0 +176,224,39848,1,0 +176,224,39951,1,0 +120,128,40158,1,0 +120,128,40262,1,0 +120,128,40365,1,0 +224,128,40572,1,0 +224,128,40676,1,0 +224,128,40779,6,0,B|224:96,7,22.5 +224,105,41193,6,0,B|312:104,1,90,4|0 +400,152,41607,1,0 +400,256,41814,2,0,B|432:288,4,45 +304,312,42435,1,0 +208,256,42642,1,0 +208,256,42746,1,0 +208,256,42850,2,0,B|208:168,1,90 +168,80,43264,6,0,B|208:56|256:80,1,90 +272,112,43574,1,0 +288,144,43678,2,0,B|312:184|368:192,1,90 +368,96,44092,1,0 +368,288,44299,1,0 +280,336,44506,6,0,B|240:368,4,45 +232,248,45127,1,0 +232,248,45230,1,0 +128,248,45437,1,0 +120,248,45541,1,0 +112,248,45644,1,0 +104,248,45748,1,0 +48,168,45955,1,0 +104,80,46162,5,0 +120,80,46265,1,0 +136,80,46369,1,0 +152,80,46472,1,0 +168,80,46576,1,0 +272,80,46783,1,0 +272,80,46886,1,0 +376,80,47094,1,0 +400,80,47197,1,0 +424,80,47301,1,0 +448,80,47404,1,0 +456,176,47611,5,0 +400,256,47818,1,8 +368,256,47922,1,0 +336,256,48025,1,0 +304,256,48129,1,0 +272,256,48232,1,0 +176,256,48439,1,0 +176,256,48543,1,0 +80,256,48750,5,0 +80,256,48853,1,0 +80,256,48957,1,0 +80,256,49060,1,0 +128,168,49267,1,0 +32,168,49474,1,0 +32,168,49578,1,0 +32,168,49681,1,0 +32,168,49785,1,0 +32,168,49888,1,0 +80,80,50095,5,0 +96,72,50199,1,0 +200,40,50406,1,0 +224,40,50509,1,0 +248,40,50613,1,0 +272,40,50716,1,0 +360,96,50923,1,0 +415,175,51131,5,0 +336,230,51338,1,0 +281,151,51545,1,0 +360,96,51752,1,0 +360,96,51855,1,0 +360,96,51959,1,0 +442,214,52166,1,0 +323,297,52373,1,0 +241,178,52580,1,0 +241,178,52683,1,0 +241,178,52787,1,0 +256,192,52890,12,4,54444 +168,112,67072,5,0 +168,112,67176,1,0 +168,112,67279,1,0 +168,112,67486,1,8 +168,112,67693,1,4 +144,96,80322,5,0 +144,96,80425,1,0 +144,96,80529,1,0 +144,96,80736,1,0 +240,56,80943,1,12 +280,152,81150,1,0 +280,152,81253,1,0 +280,152,81357,1,0 +184,192,81564,1,0 +184,192,81771,1,4 +88,232,81978,5,0 +88,232,82185,1,0 +88,232,82392,1,0 +88,336,82599,2,8,B|184:336,1,90,8|0 +208,336,82909,1,0 +240,336,83013,2,0,B|328:336,1,90 +392,264,83427,1,4 +464,168,83634,1,0 +392,264,83841,1,0 +464,168,84048,1,0 +432,64,84255,6,8,B|336:64,1,90,8|0 +80,64,84669,2,8,B|176:64,1,90,0|0 +256,136,85083,1,4 +256,304,85290,1,0 +256,136,85497,1,0 +256,304,85704,1,0 +184,224,85911,5,8 +88,224,86118,1,0 +80,216,86222,1,0 +72,208,86325,1,0 +72,112,86532,1,0 +144,40,86739,2,0,B|240:40,1,90,4|0 +224,128,87153,2,0,B|312:128,1,90 +408,168,87568,6,0,B|432:208|416:256,1,90,8|0 +416,254,87878,1,0 +416,254,87982,1,0 +344,312,88189,1,0 +344,312,88396,1,4 +168,256,88603,1,0 +344,200,88810,1,0 +168,144,89017,1,0 +256,76,89224,5,8 +256,160,89431,1,0 +256,192,89534,1,0 +256,224,89638,1,0 +256,307,89845,1,0 +192,192,90052,1,4 +256,76,90259,1,0 +320,192,90466,1,0 +256,307,90673,1,0 +200,232,90880,5,8 +312,232,91087,1,0 +152,152,91294,1,0 +360,152,91501,1,0 +200,72,91708,5,4 +312,72,91915,1,0 +152,152,92122,1,0 +360,152,92329,1,0 +456,192,92536,5,8 +416,288,92743,1,0 +384,288,92847,1,0 +352,288,92950,1,0 +264,336,93157,2,0,B|240:296|240:240,1,90,0|4 +240,160,93571,1,0 +208,64,93778,1,0 +176,72,93882,1,0 +152,96,93985,1,0 +136,128,94089,1,0 +136,160,94192,5,8 +72,240,94399,2,0,B|16:256,2,45 +136,312,94813,1,0 +192,232,95020,2,0,B|240:152,1,90 +376,112,95434,2,0,B|328:192,1,90 +464,112,96056,5,0 +496,192,96263,1,0 +464,272,96470,1,0 +48,272,96884,1,0 +16,192,97091,1,0 +48,112,97298,1,0 +152,64,97505,5,0 +224,136,97712,1,0 +152,64,97919,1,0 +248,40,98126,1,0 +344,72,98333,2,0,B|392:88|416:144,1,90 +392,224,98747,2,0,B|344:208|320:152,1,90 +224,136,99161,5,0 +152,208,99368,1,0 +144,240,99471,1,0 +152,272,99575,1,0 +248,222,99782,1,0 +248,312,99989,2,0,B|248:216,1,90 +328,112,100403,2,0,B|328:216,1,90 +360,288,100817,5,2 +432,216,101024,1,0 +432,184,101128,1,0 +432,152,101231,1,0 +400,64,101438,1,0 +304,40,101645,2,0,B|256:40|216:72,1,90 +200,168,102059,2,0,B|248:168|288:136,1,90 +176,280,102680,6,0,B|176:336,2,45 +336,104,103508,2,0,B|336:48,2,45 +336,104,104130,5,0 +416,192,104337,1,0 +336,280,104544,1,0 +256,192,104751,1,0 +176,280,104958,1,0 +96,192,105165,1,0 +176,104,105372,1,0 +256,192,105579,1,0 +256,192,105786,5,0 +256,192,105993,2,0,B|256:136,2,45 +256,192,106407,1,0 +256,288,106614,1,0 +256,288,106821,2,0,B|160:288,1,90 +144,288,107131,1,0 +128,288,107235,1,0 +112,288,107338,1,0 +96,288,107441,1,4 +256,56,120276,5,0 +248,88,120380,1,0 +256,120,120483,1,0 +264,152,120587,1,0 +256,184,120690,5,4 +160,208,120897,2,0,B|176:256|224:280,1,90 +296,208,121311,1,0 +312,192,121415,1,0 +336,184,121518,5,0 +360,184,121622,1,0 +376,192,121725,1,0 +392,208,121829,1,0 +400,232,121932,1,0 +376,336,122139,1,0 +376,336,122243,1,0 +376,336,122346,6,0,B|336:360|288:360,1,90 +192,336,122760,2,0,B|168:296|168:248,1,90 +272,208,123174,1,0 +216,104,123381,1,0 +336,88,123588,2,0,B|304:120|304:176,2,90 +416,168,124210,1,0 +416,168,124313,2,0,B|472:192|472:256|424:280,1,135 +432,275,124727,1,0 +432,275,124831,1,0 +344,224,125038,1,0 +240,208,125245,2,0,B|248:160|304:136,1,90 +360,80,125659,6,0,B|328:40|272:56,1,90 +216,144,126073,1,0 +104,136,126280,1,0 +104,136,126383,1,0 +104,136,126487,2,0,B|64:168|64:224,1,90 +136,296,126901,5,0 +160,320,127004,1,0 +192,328,127108,1,0 +224,320,127211,1,0 +248,296,127315,2,0,B|280:264|296:216,1,90 +294,219,127625,1,0 +408,80,127936,5,0 +368,80,128039,1,0 +328,80,128143,1,0 +224,80,128350,1,0 +72,40,128557,1,0 +104,192,128764,1,0 +272,144,128971,5,0 +120,104,129178,1,0 +152,256,129385,1,0 +152,256,129489,1,0 +152,256,129592,1,0 +152,256,129696,1,0 +152,256,129799,2,0,B|200:280|240:256,1,90 +328,128,130213,2,0,B|280:104|240:128,1,90 +240,224,130627,5,0 +336,256,130834,1,0 +320,288,130938,1,0 +296,312,131041,2,0,B|256:344|208:352,1,90 +184,352,131352,1,0 +152,352,131455,1,0 +64,264,131662,1,0 +160,264,131869,1,0 +32,248,132076,1,0 +192,248,132284,1,0 +96,160,132491,1,0 +120,136,132594,1,0 +152,128,132698,1,0 +248,128,132905,5,0 +280,120,133008,1,0 +312,120,133112,1,0 +344,128,133215,1,0 +372,144,133319,1,0 +392,176,133422,1,0 +400,208,133526,1,0 +400,240,133629,1,0 +392,272,133733,1,0 +376,304,133836,1,0 +344,320,133940,6,0,B|304:344|256:344,1,90,4|0 +192,280,134354,1,0 +92,264,134561,1,0 +80,232,134664,1,0 +76,196,134768,1,0 +80,160,134871,1,0 +88,128,134975,2,0,B|104:88|144:56,1,90 +232,104,135389,6,0,B|256:152,2,45,0|0|8 +232,104,135803,1,0 +380,49,136010,1,0 +289,185,136217,1,0 +283,14,136424,1,0 +389,149,136631,1,0 +232,104,136838,1,0 +380,49,137045,1,0 +289,185,137252,5,4 +289,185,137459,1,0 +289,185,137563,1,0 +112,256,137873,1,0 +112,256,137977,1,0 +112,256,138080,2,0,B|160:272|208:256,1,90 +400,256,138494,2,0,B|352:240|304:256,1,90 +256,184,138908,5,8 +288,72,139115,1,0 +232,152,139322,1,0 +264,40,139529,1,0 +168,72,139736,1,0 +168,72,139943,1,0 +100,160,140150,1,0 +88,192,140254,1,0 +84,224,140357,1,0 +88,256,140461,1,0 +96,288,140565,6,0,B|128:328|184:336,1,90,4|0 +208,336,140875,1,0 +248,336,140979,2,0,B|336:336,1,90 +376,336,141289,1,0 +408,336,141393,1,0 +455,255,141600,1,0 +460,82,141807,1,0 +351,217,142014,1,0 +512,172,142221,5,8 +361,117,142428,1,0 +256,116,142635,2,0,B|208:116,3,45 +184,132,143049,2,0,B|144:160|144:216,1,90 +256,280,143463,2,0,B|296:252|296:196,1,90 +256,192,143877,12,4,147178 +152,120,148627,6,0,B|184:88,2,45 +152,232,149041,1,0 +264,232,149248,2,0,B|264:280|224:320,1,90 +152,232,149662,2,0,B|152:184|192:144,1,90 +288,128,150076,5,0 +416,64,150283,1,0 +288,128,150490,1,8 +392,184,150697,1,0 +392,184,150800,2,0,B|408:232|408:280|352:320,1,135 +367,307,151214,1,0 +367,307,151318,5,0 +256,344,151525,1,0 +98,316,151732,1,0 +126,158,151939,1,0 +283,186,152146,1,0 +194,290,152353,1,0 +36,262,152560,1,0 +64,104,152767,1,0 +221,132,152974,5,0 +194,290,153181,1,0 +128,192,153388,1,0 +144,192,153492,1,0 +160,192,153595,1,0 +176,192,153699,1,0 +192,192,153802,2,0,B|320:192,1,90,4|0 +280,192,154113,1,0 +472,152,154423,5,0 +480,192,154527,1,0 +472,232,154630,1,0 +336,192,154837,1,0 +456,112,155044,1,0 +456,272,155251,1,0 +360,328,155459,5,0 +152,328,155666,1,0 +256,272,155873,1,0 +256,240,155976,1,0 +256,208,156080,1,0 +256,176,156183,1,0 +256,144,156287,1,0 +320,64,156494,2,0,B|376:64|392:112,2,90,0|0|0 +216,64,157115,5,8 +216,64,157322,1,0 +216,64,157425,1,0 +88,104,157736,1,0 +88,104,157839,1,0 +88,104,157943,2,0,B|88:200,1,90 +184,256,158357,2,0,B|184:160,1,90 +88,228,158771,2,0,B|88:324,1,90 +88,318,159081,1,0 +88,318,159185,1,0 +192,320,159392,5,0 +208,320,159495,1,0 +224,320,159599,1,0 +240,320,159703,1,0 +256,320,159806,1,0 +272,320,159910,1,0 +288,320,160013,1,0 +304,320,160117,1,0 +320,320,160220,1,0 +336,320,160324,1,0 +352,320,160427,1,4 +152,72,173263,6,0,B|152:128,4,45,0|0|0|0|8 +248,48,173889,2,0,B|336:48,1,90,0|0 +408,120,174303,2,0,B|456:120,2,45,0|0|0 +376,152,174613,2,0,B|328:152,2,45 +408,184,174924,2,0,B|464:184,2,45 +376,216,175234,1,0 +344,240,175338,6,0,B|240:240,1,90,0|0 +184,184,175752,1,0 +144,296,175959,1,0 +152,160,176166,1,0 +112,272,176373,1,0 +32,216,176580,1,0 +32,112,176787,2,0,B|48:72|96:48,1,90,0|0 +200,48,177201,5,0 +200,48,177304,2,0,B|344:48,1,135 +368,48,177718,1,0 +400,48,177822,1,0 +448,144,178029,1,0 +424,256,178236,2,0,B|376:240|352:192,1,90,0|0 +344,160,178547,1,0 +336,120,178650,2,0,B|288:128|248:168,1,90,0|0 +160,224,179064,6,0,B|256:248,1,90 +352,160,179478,2,0,B|256:136,1,90 +176,88,179892,1,0 +144,72,179996,1,0 +112,88,180099,1,0 +80,72,180203,1,0 +56,88,180306,5,0 +56,176,180513,1,0 +56,176,180617,2,0,B|56:312,1,135 +56,311,181031,1,0 +56,311,181134,1,0 +168,312,181341,1,0 +256,256,181548,1,0 +344,312,181755,1,0 +440,280,181963,2,0,B|472:240|464:192,1,90,0|0 +440,96,182377,5,0 +432,80,182480,1,0 +424,64,182584,1,0 +416,48,182687,1,0 +408,32,182791,2,0,B|344:32|344:32|328:56,1,90 +288,136,183205,2,0,B|200:136,1,90 +128,64,183619,2,0,B|120:32|120:32|56:32,1,90 +32,32,183929,2,0,B|32:168,1,135 +32,200,184343,1,0 +32,232,184447,5,0 +128,272,184654,2,0,B|216:320,1,90 +328,272,185068,2,0,B|240:224,1,90 +168,160,185482,1,0 +176,120,185585,1,0 +208,96,185689,1,0 +320,80,185896,5,0 +352,88,185999,1,0 +376,112,186103,1,0 +384,152,186207,1,0 +376,184,186310,1,0 +344,208,186414,1,0 +312,208,186517,2,0,B|280:192,8,22.5,0|0|0|0|0|0|0|0|4 +256,192,187035,12,0,188173 +256,96,188380,5,0 +256,96,188484,1,0 +256,96,188587,1,8 +376,96,188794,1,0 +448,184,189001,2,0,B|360:216,1,90 +424,304,189415,2,0,B|336:336,1,90 +216,336,189829,1,0 +144,232,190036,1,0 +216,336,190244,1,4 +280,232,190451,5,0 +280,232,190554,2,0,B|280:96,1,135 +280,64,190968,1,0 +280,32,191072,1,0 +176,64,191279,1,0 +121,179,191486,1,0 +237,233,191693,1,0 +291,117,191900,2,0,B|360:184,1,90,8|0 +400,264,192314,6,0,B|352:256|304:264,1,90 +112,264,192728,2,0,B|160:256|208:264,1,90 +256,168,193142,2,0,B|280:128,4,45,0|0|0|0|4 +160,112,193763,1,0 +160,112,193866,2,0,B|104:112|64:144|64:208,1,135 +64,224,194280,1,0 +64,256,194384,1,0 +128,352,194591,5,0 +192,256,194798,1,0 +256,352,195005,1,0 +368,352,195212,2,0,B|416:340|420:280,1,90,8|0 +416,184,195626,1,0 +408,168,195730,1,0 +400,152,195833,1,0 +392,136,195937,1,0 +384,120,196040,5,0 +184,64,196247,1,0 +128,264,196454,1,0 +328,320,196661,1,0 +256,192,196868,12,8,199767 +256,192,200181,5,4 diff --git a/osu.Game.Tests/osu.Game.Tests.csproj b/osu.Game.Tests/osu.Game.Tests.csproj index 3a15b5e6b1..df22aede95 100644 --- a/osu.Game.Tests/osu.Game.Tests.csproj +++ b/osu.Game.Tests/osu.Game.Tests.csproj @@ -151,6 +151,7 @@ + \ No newline at end of file From fcfdbc8e07cf19ee234e2bff03eb0105272c9410 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 7 Dec 2017 12:02:48 +0900 Subject: [PATCH 1013/1263] Don't show the migrate button on deployed builds for now --- .../Sections/Maintenance/GeneralSettings.cs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs index f0f5b434cd..2b40ade895 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs @@ -20,7 +20,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance protected override string Header => "General"; [BackgroundDependencyLoader] - private void load(BeatmapManager beatmaps) + private void load(OsuGameBase osuGame, BeatmapManager beatmaps) { Children = new Drawable[] { @@ -55,8 +55,12 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance beatmaps.Restore(b); }).ContinueWith(t => Schedule(() => restoreButton.Enabled.Value = true)); } - }, - migrateButton = new SettingsButton + } + }; + + if (!osuGame.IsDeployedBuild) + { + Add(migrateButton = new SettingsButton { Text = "Migrate all beatmaps to the new format", Action = () => @@ -64,8 +68,8 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance migrateButton.Enabled.Value = false; Task.Factory.StartNew(beatmaps.MigrateAllToNewFormat).ContinueWith(t => Schedule(() => migrateButton.Enabled.Value = true), TaskContinuationOptions.LongRunning); } - } - }; + }); + } } } } From feef4b1890daa1bb609c995d3bd6a90d8c84b580 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 7 Dec 2017 12:18:00 +0900 Subject: [PATCH 1014/1263] Add license header --- osu.Game/IO/Serialization/Converters/TypedListConverter.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/IO/Serialization/Converters/TypedListConverter.cs b/osu.Game/IO/Serialization/Converters/TypedListConverter.cs index f8897a4e9d..36b53e1137 100644 --- a/osu.Game/IO/Serialization/Converters/TypedListConverter.cs +++ b/osu.Game/IO/Serialization/Converters/TypedListConverter.cs @@ -1,3 +1,6 @@ +// 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 Newtonsoft.Json; From f1dbcc4f1aab9d0b5540a9dfabeabea29858bc00 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 7 Dec 2017 12:23:53 +0900 Subject: [PATCH 1015/1263] Remove misleading comments --- osu.Game/Beatmaps/BeatmapManager.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 6b547afe5d..8d20a3dcfb 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -548,12 +548,10 @@ namespace osu.Game.Beatmaps public void UpdateContent(BeatmapInfo beatmapInfo, Stream newData) { - // let's only allow one concurrent update at a time for now. var context = createContext(); using (var transaction = context.BeginTransaction()) { - // create local stores so we can isolate and thread safely, and share a context/transaction. var setInfo = beatmapInfo.BeatmapSet; var existingSetFileInfo = setInfo.Files.First(f => f.FileInfo.Hash == beatmapInfo.Hash); var existingFileInfo = existingSetFileInfo.FileInfo; From 9e51480aa392935b9d06b29869cd9b24439d9d6a Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 7 Dec 2017 12:27:30 +0900 Subject: [PATCH 1016/1263] Cleanup TypedListConverter a bit --- osu.Game/IO/Serialization/Converters/TypedListConverter.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/osu.Game/IO/Serialization/Converters/TypedListConverter.cs b/osu.Game/IO/Serialization/Converters/TypedListConverter.cs index 36b53e1137..c3d5869035 100644 --- a/osu.Game/IO/Serialization/Converters/TypedListConverter.cs +++ b/osu.Game/IO/Serialization/Converters/TypedListConverter.cs @@ -69,10 +69,7 @@ namespace osu.Game.IO.Serialization.Converters serializer.Serialize(writer, lookupTable); writer.WritePropertyName("Items"); - writer.WriteStartArray(); - foreach (var item in objects) - item.WriteTo(writer); - writer.WriteEndArray(); + serializer.Serialize(writer, objects); writer.WriteEndObject(); } From d026587a915ad17d1ab9b3871fa0144ef1b6e095 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 7 Dec 2017 12:49:16 +0900 Subject: [PATCH 1017/1263] Add flag to explicitly serialize the type version --- .../Converters/TypedListConverter.cs | 31 +++++++++++++++++-- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/osu.Game/IO/Serialization/Converters/TypedListConverter.cs b/osu.Game/IO/Serialization/Converters/TypedListConverter.cs index c3d5869035..32b7772092 100644 --- a/osu.Game/IO/Serialization/Converters/TypedListConverter.cs +++ b/osu.Game/IO/Serialization/Converters/TypedListConverter.cs @@ -16,6 +16,26 @@ namespace osu.Game.IO.Serialization.Converters /// The type of objects contained in the this attribute is attached to. public class TypedListConverter : JsonConverter { + private readonly bool requiresTypeVersion; + + /// + /// Constructs a new . + /// + // ReSharper disable once UnusedMember.Global + public TypedListConverter() + { + } + + /// + /// Constructs a new . + /// + /// Whether the version of the type should be serialized. + // ReSharper disable once UnusedMember.Global (Used in Beatmap) + public TypedListConverter(bool requiresTypeVersion) + { + this.requiresTypeVersion = requiresTypeVersion; + } + public override bool CanConvert(Type objectType) => objectType == typeof(List); public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) @@ -49,12 +69,17 @@ namespace osu.Game.IO.Serialization.Converters var objects = new List(); foreach (var item in list) { - var type = item.GetType().AssemblyQualifiedName; + var type = item.GetType(); + var assemblyName = type.Assembly.GetName(); - int typeId = lookupTable.IndexOf(type); + var typeString = $"{type.FullName}, {assemblyName.Name}"; + if (requiresTypeVersion) + typeString += $", {assemblyName.Version}"; + + int typeId = lookupTable.IndexOf(typeString); if (typeId == -1) { - lookupTable.Add(type); + lookupTable.Add(typeString); typeId = lookupTable.Count - 1; } From a78441bc5a511d5f780cd949d2d21cc2218c8be9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 6 Dec 2017 23:03:31 +0900 Subject: [PATCH 1018/1263] Apply changes in line with framework input adjustments --- osu.Game.Rulesets.Osu/OsuInputManager.cs | 3 +++ .../DatabasedKeyBindingInputManager.cs | 4 +-- osu.Game/Input/KeyBindingStore.cs | 2 +- .../KeyBinding/GlobalKeyBindingsSection.cs | 4 +-- osu.Game/Rulesets/UI/RulesetInputManager.cs | 25 +++++++++++++++---- 5 files changed, 28 insertions(+), 10 deletions(-) diff --git a/osu.Game.Rulesets.Osu/OsuInputManager.cs b/osu.Game.Rulesets.Osu/OsuInputManager.cs index a65d28cec0..56990d1351 100644 --- a/osu.Game.Rulesets.Osu/OsuInputManager.cs +++ b/osu.Game.Rulesets.Osu/OsuInputManager.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 System.ComponentModel; using osu.Framework.Input.Bindings; using osu.Game.Rulesets.UI; @@ -9,6 +10,8 @@ namespace osu.Game.Rulesets.Osu { public class OsuInputManager : RulesetInputManager { + public IEnumerable PressedActions => KeyBindingContainer.PressedActions; + public OsuInputManager(RulesetInfo ruleset) : base(ruleset, 0, SimultaneousBindingMode.Unique) { } diff --git a/osu.Game/Input/Bindings/DatabasedKeyBindingInputManager.cs b/osu.Game/Input/Bindings/DatabasedKeyBindingInputManager.cs index bae14fc1dc..784e6462f2 100644 --- a/osu.Game/Input/Bindings/DatabasedKeyBindingInputManager.cs +++ b/osu.Game/Input/Bindings/DatabasedKeyBindingInputManager.cs @@ -14,7 +14,7 @@ namespace osu.Game.Input.Bindings /// A KeyBindingInputManager with a database backing for custom overrides. /// /// The type of the custom action. - public abstract class DatabasedKeyBindingInputManager : KeyBindingInputManager + public class DatabasedKeyBindingInputManager : KeyBindingContainer where T : struct { private readonly RulesetInfo ruleset; @@ -31,7 +31,7 @@ namespace osu.Game.Input.Bindings /// A reference to identify the current . Used to lookup mappings. Null for global mappings. /// An optional variant for the specified . Used when a ruleset has more than one possible keyboard layouts. /// Specify how to deal with multiple matches of s and s. - protected DatabasedKeyBindingInputManager(RulesetInfo ruleset = null, int? variant = null, SimultaneousBindingMode simultaneousMode = SimultaneousBindingMode.None) + public DatabasedKeyBindingInputManager(RulesetInfo ruleset = null, int? variant = null, SimultaneousBindingMode simultaneousMode = SimultaneousBindingMode.None) : base(simultaneousMode) { this.ruleset = ruleset; diff --git a/osu.Game/Input/KeyBindingStore.cs b/osu.Game/Input/KeyBindingStore.cs index 95791391f0..9e2988417a 100644 --- a/osu.Game/Input/KeyBindingStore.cs +++ b/osu.Game/Input/KeyBindingStore.cs @@ -27,7 +27,7 @@ namespace osu.Game.Input } } - public void Register(KeyBindingInputManager manager) => insertDefaults(manager.DefaultKeyBindings); + public void Register(KeyBindingContainer manager) => insertDefaults(manager.DefaultKeyBindings); private void insertDefaults(IEnumerable defaults, int? rulesetId = null, int? variant = null) { diff --git a/osu.Game/Overlays/KeyBinding/GlobalKeyBindingsSection.cs b/osu.Game/Overlays/KeyBinding/GlobalKeyBindingsSection.cs index 8ebd4ac545..4a7e4f4e6e 100644 --- a/osu.Game/Overlays/KeyBinding/GlobalKeyBindingsSection.cs +++ b/osu.Game/Overlays/KeyBinding/GlobalKeyBindingsSection.cs @@ -12,7 +12,7 @@ namespace osu.Game.Overlays.KeyBinding public override FontAwesome Icon => FontAwesome.fa_osu_hot; public override string Header => "Global"; - public GlobalKeyBindingsSection(KeyBindingInputManager manager) + public GlobalKeyBindingsSection(KeyBindingContainer manager) { Add(new DefaultBindingsSubsection(manager)); } @@ -21,7 +21,7 @@ namespace osu.Game.Overlays.KeyBinding { protected override string Header => string.Empty; - public DefaultBindingsSubsection(KeyBindingInputManager manager) + public DefaultBindingsSubsection(KeyBindingContainer manager) : base(null) { Defaults = manager.DefaultKeyBindings; diff --git a/osu.Game/Rulesets/UI/RulesetInputManager.cs b/osu.Game/Rulesets/UI/RulesetInputManager.cs index 8c4d6de1fe..5cd79cff29 100644 --- a/osu.Game/Rulesets/UI/RulesetInputManager.cs +++ b/osu.Game/Rulesets/UI/RulesetInputManager.cs @@ -5,6 +5,8 @@ using System.Collections.Generic; using System.Linq; using osu.Framework.Allocation; using osu.Framework.Configuration; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; using osu.Framework.Input; using osu.Framework.Input.Bindings; using osu.Framework.Timing; @@ -16,11 +18,24 @@ using OpenTK.Input; namespace osu.Game.Rulesets.UI { - public abstract class RulesetInputManager : DatabasedKeyBindingInputManager, ICanAttachKeyCounter, IHasReplayHandler + public abstract class RulesetInputManager : PassThroughInputManager, ICanAttachKeyCounter, IHasReplayHandler where T : struct { - protected RulesetInputManager(RulesetInfo ruleset, int variant, SimultaneousBindingMode unique) : base(ruleset, variant, unique) + public class RulesetKeyBindingContainer : DatabasedKeyBindingInputManager { + public RulesetKeyBindingContainer(RulesetInfo ruleset, int variant, SimultaneousBindingMode unique) + : base(ruleset, variant, unique) + { + } + } + + protected readonly KeyBindingContainer KeyBindingContainer; + + protected override Container Content => KeyBindingContainer; + + protected RulesetInputManager(RulesetInfo ruleset, int variant, SimultaneousBindingMode unique) + { + InternalChild = KeyBindingContainer = new RulesetKeyBindingContainer(ruleset, variant, unique); } #region Action mapping (for replays) @@ -41,10 +56,10 @@ namespace osu.Game.Rulesets.UI List newActions = replayState.PressedActions; foreach (var released in lastPressedActions.Except(newActions)) - PropagateReleased(KeyBindingInputQueue, released); + KeyBindingContainer.TriggerReleased(released); foreach (var pressed in newActions.Except(lastPressedActions)) - PropagatePressed(KeyBindingInputQueue, pressed); + KeyBindingContainer.TriggerPressed(pressed); lastPressedActions = newActions; } @@ -203,7 +218,7 @@ namespace osu.Game.Rulesets.UI Add(receptor); keyCounter.SetReceptor(receptor); - keyCounter.AddRange(DefaultKeyBindings.Select(b => b.GetAction()).Distinct().Select(b => new KeyCounterAction(b))); + keyCounter.AddRange(KeyBindingContainer.DefaultKeyBindings.Select(b => b.GetAction()).Distinct().Select(b => new KeyCounterAction(b))); } public class ActionReceptor : KeyCounterCollection.Receptor, IKeyBindingHandler From 245b5f759ff4a2cc00e4ca89a5b553bccbca0ade Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 7 Dec 2017 14:36:32 +0900 Subject: [PATCH 1019/1263] Underscore + lowercase all keys --- .../Converters/TypedListConverter.cs | 12 ++++++------ .../Serialization/Converters/Vector2Converter.cs | 6 +++--- osu.Game/IO/Serialization/IJsonSerializable.cs | 3 ++- osu.Game/IO/Serialization/KeyContractResolver.cs | 16 ++++++++++++++++ osu.Game/osu.Game.csproj | 1 + 5 files changed, 28 insertions(+), 10 deletions(-) create mode 100644 osu.Game/IO/Serialization/KeyContractResolver.cs diff --git a/osu.Game/IO/Serialization/Converters/TypedListConverter.cs b/osu.Game/IO/Serialization/Converters/TypedListConverter.cs index 32b7772092..7147f9110e 100644 --- a/osu.Game/IO/Serialization/Converters/TypedListConverter.cs +++ b/osu.Game/IO/Serialization/Converters/TypedListConverter.cs @@ -45,13 +45,13 @@ namespace osu.Game.IO.Serialization.Converters var obj = JObject.Load(reader); var lookupTable = new List(); - serializer.Populate(obj["LookupTable"].CreateReader(), lookupTable); + serializer.Populate(obj["lookup_table"].CreateReader(), lookupTable); - foreach (var tok in obj["Items"]) + foreach (var tok in obj["items"]) { var itemReader = tok.CreateReader(); - var typeName = lookupTable[(int)tok["Type"]]; + var typeName = lookupTable[(int)tok["type"]]; var instance = (T)Activator.CreateInstance(Type.GetType(typeName)); serializer.Populate(itemReader, instance); @@ -84,16 +84,16 @@ namespace osu.Game.IO.Serialization.Converters } var itemObject = JObject.FromObject(item, serializer); - itemObject.AddFirst(new JProperty("Type", typeId)); + itemObject.AddFirst(new JProperty("type", typeId)); objects.Add(itemObject); } writer.WriteStartObject(); - writer.WritePropertyName("LookupTable"); + writer.WritePropertyName("lookup_table"); serializer.Serialize(writer, lookupTable); - writer.WritePropertyName("Items"); + writer.WritePropertyName("items"); serializer.Serialize(writer, objects); writer.WriteEndObject(); diff --git a/osu.Game/IO/Serialization/Converters/Vector2Converter.cs b/osu.Game/IO/Serialization/Converters/Vector2Converter.cs index 5f21018fd5..87fbd31d21 100644 --- a/osu.Game/IO/Serialization/Converters/Vector2Converter.cs +++ b/osu.Game/IO/Serialization/Converters/Vector2Converter.cs @@ -18,7 +18,7 @@ namespace osu.Game.IO.Serialization.Converters public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { var obj = JObject.Load(reader); - return new Vector2((float)obj["X"], (float)obj["Y"]); + return new Vector2((float)obj["x"], (float)obj["y"]); } public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) @@ -27,9 +27,9 @@ namespace osu.Game.IO.Serialization.Converters writer.WriteStartObject(); - writer.WritePropertyName("X"); + writer.WritePropertyName("x"); writer.WriteValue(vector.X); - writer.WritePropertyName("Y"); + writer.WritePropertyName("y"); writer.WriteValue(vector.Y); writer.WriteEndObject(); diff --git a/osu.Game/IO/Serialization/IJsonSerializable.cs b/osu.Game/IO/Serialization/IJsonSerializable.cs index 38e7f47656..892c266fe3 100644 --- a/osu.Game/IO/Serialization/IJsonSerializable.cs +++ b/osu.Game/IO/Serialization/IJsonSerializable.cs @@ -30,7 +30,8 @@ namespace osu.Game.IO.Serialization Formatting = Formatting.Indented, ObjectCreationHandling = ObjectCreationHandling.Replace, DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate, - Converters = new JsonConverter[] { new Vector2Converter() } + Converters = new JsonConverter[] { new Vector2Converter() }, + ContractResolver = new KeyContractResolver() }; } } diff --git a/osu.Game/IO/Serialization/KeyContractResolver.cs b/osu.Game/IO/Serialization/KeyContractResolver.cs new file mode 100644 index 0000000000..10375646ce --- /dev/null +++ b/osu.Game/IO/Serialization/KeyContractResolver.cs @@ -0,0 +1,16 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using Humanizer; +using Newtonsoft.Json.Serialization; + +namespace osu.Game.IO.Serialization +{ + public class KeyContractResolver : DefaultContractResolver + { + protected override string ResolvePropertyName(string propertyName) + { + return propertyName.Underscore(); + } + } +} diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 9e5d4291ce..a2d4a00110 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -272,6 +272,7 @@ + 20171019041408_InitialCreate.cs From f5f7658e906125fca54bc57532971d8d3cb74b36 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 7 Dec 2017 14:40:28 +0900 Subject: [PATCH 1020/1263] Don't serialize TotalBreakTime --- osu.Game/Beatmaps/Beatmap.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Beatmaps/Beatmap.cs b/osu.Game/Beatmaps/Beatmap.cs index c331872dda..e9342584cc 100644 --- a/osu.Game/Beatmaps/Beatmap.cs +++ b/osu.Game/Beatmaps/Beatmap.cs @@ -34,15 +34,16 @@ namespace osu.Game.Beatmaps [JsonIgnore] public BeatmapMetadata Metadata => BeatmapInfo?.Metadata ?? BeatmapInfo?.BeatmapSet?.Metadata; - [JsonConverter(typeof(TypedListConverter))] /// /// The HitObjects this Beatmap contains. /// + [JsonConverter(typeof(TypedListConverter))] public List HitObjects = new List(); /// /// Total amount of break time in the beatmap. /// + [JsonIgnore] public double TotalBreakTime => Breaks.Sum(b => b.Duration); /// From e573db04d43361caf21e14b5c7a601ec0df4ebd5 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 7 Dec 2017 14:42:36 +0900 Subject: [PATCH 1021/1263] Don't serialize HitObject.Kiai --- osu.Game/Rulesets/Objects/HitObject.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Objects/HitObject.cs b/osu.Game/Rulesets/Objects/HitObject.cs index 92220ff8bd..0772e7707e 100644 --- a/osu.Game/Rulesets/Objects/HitObject.cs +++ b/osu.Game/Rulesets/Objects/HitObject.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 Newtonsoft.Json; using osu.Game.Audio; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; @@ -33,6 +34,7 @@ namespace osu.Game.Rulesets.Objects /// /// Whether this is in Kiai time. /// + [JsonIgnore] public bool Kiai { get; private set; } /// @@ -45,7 +47,7 @@ namespace osu.Game.Rulesets.Objects SoundControlPoint soundPoint = controlPointInfo.SoundPointAt(StartTime); EffectControlPoint effectPoint = controlPointInfo.EffectPointAt(StartTime); - Kiai |= effectPoint.KiaiMode; + Kiai = effectPoint.KiaiMode; // Initialize first sample Samples.ForEach(s => s.ControlPoint = soundPoint); From 0ba8988580a266343c1ab9ad42f0f5a85a7662d1 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 7 Dec 2017 15:32:39 +0900 Subject: [PATCH 1022/1263] Don't serialize Author + add SerializableAttributes --- osu.Game/Beatmaps/BeatmapInfo.cs | 1 + osu.Game/Beatmaps/BeatmapMetadata.cs | 3 +++ 2 files changed, 4 insertions(+) diff --git a/osu.Game/Beatmaps/BeatmapInfo.cs b/osu.Game/Beatmaps/BeatmapInfo.cs index 9450022a01..dd66812ea5 100644 --- a/osu.Game/Beatmaps/BeatmapInfo.cs +++ b/osu.Game/Beatmaps/BeatmapInfo.cs @@ -12,6 +12,7 @@ using osu.Game.Rulesets; namespace osu.Game.Beatmaps { + [Serializable] public class BeatmapInfo : IEquatable, IJsonSerializable, IHasPrimaryKey { [DatabaseGenerated(DatabaseGeneratedOption.Identity)] diff --git a/osu.Game/Beatmaps/BeatmapMetadata.cs b/osu.Game/Beatmaps/BeatmapMetadata.cs index 2efbcd4f15..67d6de49cd 100644 --- a/osu.Game/Beatmaps/BeatmapMetadata.cs +++ b/osu.Game/Beatmaps/BeatmapMetadata.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.ComponentModel.DataAnnotations.Schema; using System.Linq; @@ -9,6 +10,7 @@ using osu.Game.Users; namespace osu.Game.Beatmaps { + [Serializable] public class BeatmapMetadata { [DatabaseGenerated(DatabaseGeneratedOption.Identity)] @@ -51,6 +53,7 @@ namespace osu.Game.Beatmaps /// The author of the beatmaps in this set. /// public User Author; + public bool ShouldSerializeAuthor() => false; public string Source { get; set; } From 09f54b06ace0c82a3e500d18acd81e3737b475ff Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 7 Dec 2017 15:55:22 +0900 Subject: [PATCH 1023/1263] Just don't serialize Author altogether for now --- osu.Game/Beatmaps/BeatmapMetadata.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Beatmaps/BeatmapMetadata.cs b/osu.Game/Beatmaps/BeatmapMetadata.cs index 67d6de49cd..a9488ce0e2 100644 --- a/osu.Game/Beatmaps/BeatmapMetadata.cs +++ b/osu.Game/Beatmaps/BeatmapMetadata.cs @@ -52,8 +52,8 @@ namespace osu.Game.Beatmaps /// /// The author of the beatmaps in this set. /// + [JsonIgnore] public User Author; - public bool ShouldSerializeAuthor() => false; public string Source { get; set; } From bdf283a4e1b3d3a913beb6dfeb54e78d050d13de Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 7 Dec 2017 15:55:38 +0900 Subject: [PATCH 1024/1263] A bit more cleanup --- osu.Game/IO/Serialization/Converters/TypedListConverter.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/osu.Game/IO/Serialization/Converters/TypedListConverter.cs b/osu.Game/IO/Serialization/Converters/TypedListConverter.cs index 7147f9110e..b218f76b53 100644 --- a/osu.Game/IO/Serialization/Converters/TypedListConverter.cs +++ b/osu.Game/IO/Serialization/Converters/TypedListConverter.cs @@ -43,9 +43,7 @@ namespace osu.Game.IO.Serialization.Converters var list = new List(); var obj = JObject.Load(reader); - - var lookupTable = new List(); - serializer.Populate(obj["lookup_table"].CreateReader(), lookupTable); + var lookupTable = serializer.Deserialize>(obj["lookup_table"].CreateReader()); foreach (var tok in obj["items"]) { From 2a1a9b9f1f8454a595daeb89b012410541b9661c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 7 Dec 2017 17:26:39 +0900 Subject: [PATCH 1025/1263] Fix post-merge issue --- osu.Game/Beatmaps/WorkingBeatmap.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Beatmaps/WorkingBeatmap.cs b/osu.Game/Beatmaps/WorkingBeatmap.cs index c451460a78..736cc2a0b0 100644 --- a/osu.Game/Beatmaps/WorkingBeatmap.cs +++ b/osu.Game/Beatmaps/WorkingBeatmap.cs @@ -87,7 +87,7 @@ namespace osu.Game.Beatmaps private Waveform populateWaveform() => GetWaveform(); - public bool StoryboardLoaded => storyboard.IsValueCreated; + public bool StoryboardLoaded => storyboard.IsResultAvailable; public Storyboard Storyboard => storyboard.Value.Result; public async Task GetStoryboardAsync() => await storyboard.Value; private readonly AsyncLazy storyboard; From 13d0524542bed68cc93a559b64d45103c29bb6ac Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 7 Dec 2017 18:36:49 +0900 Subject: [PATCH 1026/1263] Update framework --- osu-framework | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu-framework b/osu-framework index 9cd6968a8c..797a351db2 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit 9cd6968a8c4d27415808f5e770d24fec5a44485f +Subproject commit 797a351db2e852fef5296453641ffbf6b2f6dc11 From 8c89354b36638a36def5a25ea70e6f96ac738c96 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 7 Dec 2017 20:44:38 +0900 Subject: [PATCH 1027/1263] Remove extra whitespace --- osu.Game/Overlays/BeatmapSet/HeaderButton.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game/Overlays/BeatmapSet/HeaderButton.cs b/osu.Game/Overlays/BeatmapSet/HeaderButton.cs index cddc05c554..ac5683de00 100644 --- a/osu.Game/Overlays/BeatmapSet/HeaderButton.cs +++ b/osu.Game/Overlays/BeatmapSet/HeaderButton.cs @@ -10,7 +10,6 @@ namespace osu.Game.Overlays.BeatmapSet { public class HeaderButton : TriangleButton { - public HeaderButton() { Height = 0; @@ -25,6 +24,5 @@ namespace osu.Game.Overlays.BeatmapSet Triangles.ColourDark = OsuColour.FromHex(@"094c5f"); Triangles.TriangleScale = 1.5f; } - } } From 24b3b10942bca6ef24e531e4e1a12adbc57be3c9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 7 Dec 2017 20:44:55 +0900 Subject: [PATCH 1028/1263] Move drawable assignment to load, remove depth overrides --- osu.Game/Overlays/BeatmapSet/FavouriteButton.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/osu.Game/Overlays/BeatmapSet/FavouriteButton.cs b/osu.Game/Overlays/BeatmapSet/FavouriteButton.cs index 77be4da5f8..1b22853656 100644 --- a/osu.Game/Overlays/BeatmapSet/FavouriteButton.cs +++ b/osu.Game/Overlays/BeatmapSet/FavouriteButton.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 osu.Framework.Allocation; using osu.Framework.Configuration; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -15,16 +16,15 @@ namespace osu.Game.Overlays.BeatmapSet { public readonly Bindable Favourited = new Bindable(); - public FavouriteButton() + [BackgroundDependencyLoader] + private void load() { - Container pink; SpriteIcon icon; AddRange(new Drawable[] { pink = new Container { - Depth = -1, RelativeSizeAxes = Axes.Both, Alpha = 0f, Children = new Drawable[] @@ -45,7 +45,6 @@ namespace osu.Game.Overlays.BeatmapSet }, icon = new SpriteIcon { - Depth = -1, Anchor = Anchor.Centre, Origin = Anchor.Centre, Icon = FontAwesome.fa_heart_o, From d52b84df46ee3e5662a058cc8de2a8d4414ff554 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 7 Dec 2017 20:53:28 +0900 Subject: [PATCH 1029/1263] Move KeyboardStep assignment to ctor --- osu.Game/Overlays/Settings/Sections/Input/MouseSettings.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/Input/MouseSettings.cs b/osu.Game/Overlays/Settings/Sections/Input/MouseSettings.cs index 53704ec72d..392bc6f1bd 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/MouseSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/MouseSettings.cs @@ -80,8 +80,6 @@ namespace osu.Game.Overlays.Settings.Sections.Input set { - KeyboardStep = 0.01f; - BindableDouble doubleValue = (BindableDouble)value; // create a second layer of bindable so we can only handle state changes when not being dragged. @@ -99,6 +97,11 @@ namespace osu.Game.Overlays.Settings.Sections.Input doubleValue.ValueChanged += newValue => base.Bindable.Value = newValue; } } + + public SensitivitySetting() + { + KeyboardStep = 0.01f; + } } private class SensitivitySlider : OsuSliderBar From 76c09ae59ef513cf899f0ca0310252d3d0e2e8b5 Mon Sep 17 00:00:00 2001 From: Aergwyn Date: Thu, 7 Dec 2017 13:44:47 +0100 Subject: [PATCH 1030/1263] added comments for local context checking --- osu.Game/Beatmaps/BeatmapStore.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapStore.cs b/osu.Game/Beatmaps/BeatmapStore.cs index 352f793aac..b23f093786 100644 --- a/osu.Game/Beatmaps/BeatmapStore.cs +++ b/osu.Game/Beatmaps/BeatmapStore.cs @@ -34,11 +34,12 @@ namespace osu.Game.Beatmaps foreach (var beatmap in beatmapSet.Beatmaps.Where(b => b.Metadata != null)) { + // check local context for metadata so we can reuse duplicates from the same set var contextMetadata = context.Set().Local.SingleOrDefault(e => e.Equals(beatmap.Metadata)); if (contextMetadata != null) - beatmap.Metadata = contextMetadata; + beatmap.Metadata = contextMetadata; // reuse existing else - context.BeatmapMetadata.Attach(beatmap.Metadata); + context.BeatmapMetadata.Attach(beatmap.Metadata); // adding new to context } context.BeatmapSetInfo.Attach(beatmapSet); From 1dcbfab18e97a3c39a01ceeeb42bb1096519269e Mon Sep 17 00:00:00 2001 From: Aergwyn Date: Thu, 7 Dec 2017 13:56:37 +0100 Subject: [PATCH 1031/1263] removed redundant comment --- osu.Game/Beatmaps/BeatmapStore.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Beatmaps/BeatmapStore.cs b/osu.Game/Beatmaps/BeatmapStore.cs index b23f093786..ac40b3378a 100644 --- a/osu.Game/Beatmaps/BeatmapStore.cs +++ b/osu.Game/Beatmaps/BeatmapStore.cs @@ -37,7 +37,7 @@ namespace osu.Game.Beatmaps // check local context for metadata so we can reuse duplicates from the same set var contextMetadata = context.Set().Local.SingleOrDefault(e => e.Equals(beatmap.Metadata)); if (contextMetadata != null) - beatmap.Metadata = contextMetadata; // reuse existing + beatmap.Metadata = contextMetadata; else context.BeatmapMetadata.Attach(beatmap.Metadata); // adding new to context } From 95955d68eff35ed128d90aab1ec1ca532bb4e3a1 Mon Sep 17 00:00:00 2001 From: Aergwyn Date: Thu, 7 Dec 2017 14:14:50 +0100 Subject: [PATCH 1032/1263] rephrased description of local context checking --- osu.Game/Beatmaps/BeatmapStore.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapStore.cs b/osu.Game/Beatmaps/BeatmapStore.cs index ac40b3378a..fb45c17454 100644 --- a/osu.Game/Beatmaps/BeatmapStore.cs +++ b/osu.Game/Beatmaps/BeatmapStore.cs @@ -34,12 +34,14 @@ namespace osu.Game.Beatmaps foreach (var beatmap in beatmapSet.Beatmaps.Where(b => b.Metadata != null)) { - // check local context for metadata so we can reuse duplicates from the same set + // If we detect a new metadata object it'll be attached to the current context so it can be reused + // to prevent duplicate entries when persisting. To accomplish this we look in the cache (.Local) + // of the corresponding table (.Set()) for matching entries to our criteria. var contextMetadata = context.Set().Local.SingleOrDefault(e => e.Equals(beatmap.Metadata)); if (contextMetadata != null) beatmap.Metadata = contextMetadata; else - context.BeatmapMetadata.Attach(beatmap.Metadata); // adding new to context + context.BeatmapMetadata.Attach(beatmap.Metadata); } context.BeatmapSetInfo.Attach(beatmapSet); From 43c270ea49559e2a8515d91dfbccddcf5d3f6a18 Mon Sep 17 00:00:00 2001 From: FreezyLemon Date: Thu, 7 Dec 2017 21:18:51 +0100 Subject: [PATCH 1033/1263] Rolled back the bad earlier implementation --- .../Objects/Drawables/DrawableHitStrong.cs | 11 ----- .../Drawables/DrawableTaikoHitObject.cs | 2 - .../UI/TaikoRulesetContainer.cs | 48 +------------------ .../Objects/Drawables/DrawableHitObject.cs | 4 +- 4 files changed, 2 insertions(+), 63 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHitStrong.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHitStrong.cs index eced24a8da..c07eaf4d8b 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHitStrong.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHitStrong.cs @@ -16,8 +16,6 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables /// private const double second_hit_window = 30; - protected override bool PlaysSamples => true; - private double firstHitTime; private bool firstKeyHeld; private TaikoAction firstHitAction; @@ -55,15 +53,6 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables return base.OnReleased(action); } - protected override void LoadComplete() - { - base.LoadComplete(); - - if (Samples.Count > 1) - // Removes the "normal" hitsound, leaving only the hitfinish one - Samples.RemoveAt(0); - } - public override bool OnPressed(TaikoAction action) { if (AllJudged) diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs index 8ebfaaea38..7976cbbbc1 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs @@ -14,8 +14,6 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables { public override Vector2 OriginPosition => new Vector2(DrawHeight / 2); - protected override bool PlaysSamples => false; - protected readonly Vector2 BaseSize; protected readonly TaikoPiece MainPiece; diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoRulesetContainer.cs b/osu.Game.Rulesets.Taiko/UI/TaikoRulesetContainer.cs index f72d253a73..48ee0a5b42 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoRulesetContainer.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoRulesetContainer.cs @@ -2,11 +2,8 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using osu.Framework.Allocation; -using osu.Framework.Audio; using osu.Framework.Graphics; -using osu.Framework.Input.Bindings; using osu.Game.Beatmaps; -using osu.Game.Input; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Replays; @@ -18,45 +15,21 @@ using osu.Game.Rulesets.Taiko.Scoring; using osu.Game.Rulesets.UI; using osu.Game.Rulesets.Taiko.Replays; using OpenTK; -using OpenTK.Input; using System.Linq; using osu.Framework.Input; -using System.Collections.Generic; namespace osu.Game.Rulesets.Taiko.UI { public class TaikoRulesetContainer : ScrollingRulesetContainer { - private readonly HashSet centreKeys = new HashSet(); - private readonly HashSet rimKeys = new HashSet(); - private AudioManager audio; - private IEnumerable keyBindings; - public TaikoRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap, bool isForCurrentRuleset) : base(ruleset, beatmap, isForCurrentRuleset) { } [BackgroundDependencyLoader] - private void load(AudioManager audio, KeyBindingStore store) + private void load() { - keyBindings = store.Query(Ruleset.RulesetInfo.ID, Ruleset.AvailableVariants?.First() ?? 0).Cast(); - if (keyBindings.Count() == 0) - keyBindings = Ruleset.GetDefaultKeyBindings(); - - foreach (var kb in keyBindings) - { - var key = (Key)(kb.KeyCombination.Keys as InputKey[]).First(); - var action = kb.GetAction(); - - if (action == TaikoAction.LeftCentre || action == TaikoAction.RightCentre) - centreKeys.Add(key); - - if (action == TaikoAction.LeftRim || action == TaikoAction.RightRim) - rimKeys.Add(key); - } - - this.audio = audio; loadBarLines(); } @@ -104,25 +77,6 @@ namespace osu.Game.Rulesets.Taiko.UI } } - protected override bool OnKeyDown(InputState state, KeyDownEventArgs args) - { - if (!args.Repeat) - { - var sampleBank = Beatmap.ControlPointInfo.SoundPointAt(WorkingBeatmap.Track.CurrentTime).SampleBank ?? "normal"; - string sampleName = ""; - - if (centreKeys.Contains(args.Key)) - sampleName = "hitnormal"; - - else if (rimKeys.Contains(args.Key)) - sampleName = "hitclap"; - - audio.Sample.Get($"Gameplay/{sampleBank}-{sampleName}")?.Play(); - } - - return base.OnKeyDown(state, args); - } - protected override Vector2 GetPlayfieldAspectAdjust() { const float default_relative_height = TaikoPlayfield.DEFAULT_HEIGHT / 768; diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index 12f4fc4f31..0a9de15586 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -59,8 +59,6 @@ namespace osu.Game.Rulesets.Objects.Drawables private readonly List judgements = new List(); public IReadOnlyList Judgements => judgements; - // Override in inheriting classes to prevent from playing samples on hit - protected virtual bool PlaysSamples => true; protected List Samples = new List(); @@ -95,7 +93,7 @@ namespace osu.Game.Rulesets.Objects.Drawables { UpdateState(state); - if (State == ArmedState.Hit && PlaysSamples) + if (State == ArmedState.Hit) PlaySamples(); }; From 105d01d85b9616f9d8be3ea9ea69893df8f882a1 Mon Sep 17 00:00:00 2001 From: Aergwyn Date: Thu, 7 Dec 2017 22:02:53 +0100 Subject: [PATCH 1034/1263] fix crash when restoring from any non-SongSelect-screen removed unwanted refresh --- osu.Game/Screens/Select/BeatmapCarousel.cs | 29 ++++++++-------------- osu.Game/Screens/Select/SongSelect.cs | 13 ++++++++-- 2 files changed, 22 insertions(+), 20 deletions(-) diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index fe981f1f2a..cbeefcdda5 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -112,29 +112,26 @@ namespace osu.Game.Screens.Select Schedule(() => removeGroup(groups.Find(b => b.BeatmapSet.ID == beatmapSet.ID))); } - public void UpdateBeatmap(BeatmapInfo beatmap) + public void UpdateBeatmapSet(BeatmapSetInfo beatmapSet) { - // todo: this method should not run more than once for the same BeatmapSetInfo. - var set = manager.QueryBeatmapSet(s => s.ID == beatmap.BeatmapSetInfoID); - // todo: this method should be smarter as to not recreate panels that haven't changed, etc. - var group = groups.Find(b => b.BeatmapSet.ID == set.ID); + var oldGroup = groups.Find(b => b.BeatmapSet.ID == beatmapSet.ID); - int i = groups.IndexOf(group); - if (i >= 0) - groups.RemoveAt(i); + var newGroup = createGroup(beatmapSet); - var newGroup = createGroup(set); + int index = groups.IndexOf(oldGroup); + if (index >= 0) + groups.RemoveAt(index); if (newGroup != null) { - if (i >= 0) - groups.Insert(i, newGroup); + if (index >= 0) + groups.Insert(index, newGroup); else addGroup(newGroup); } - bool hadSelection = selectedGroup == group; + bool hadSelection = selectedGroup == oldGroup; if (hadSelection && newGroup == null) selectedGroup = null; @@ -147,8 +144,8 @@ namespace osu.Game.Screens.Select var newSelection = newGroup.BeatmapPanels.Find(p => p.Beatmap.ID == selectedPanel?.Beatmap.ID); - if(newSelection == null && group != null && selectedPanel != null) - newSelection = newGroup.BeatmapPanels[Math.Min(newGroup.BeatmapPanels.Count - 1, group.BeatmapPanels.IndexOf(selectedPanel))]; + if(newSelection == null && oldGroup != null && selectedPanel != null) + newSelection = newGroup.BeatmapPanels[Math.Min(newGroup.BeatmapPanels.Count - 1, oldGroup.BeatmapPanels.IndexOf(selectedPanel))]; selectGroup(newGroup, newSelection); } @@ -306,8 +303,6 @@ namespace osu.Game.Screens.Select if (newCriteria != null) criteria = newCriteria; - if (!IsLoaded) return; - Action perform = delegate { filterTask = null; @@ -348,8 +343,6 @@ namespace osu.Game.Screens.Select private BeatmapGroup createGroup(BeatmapSetInfo beatmapSet) { - beatmapSet = manager.Refresh(beatmapSet); - if (beatmapSet.Beatmaps.All(b => b.Hidden)) return null; diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 0f72e3fd95..ee231ff5f4 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -203,8 +203,17 @@ namespace osu.Game.Screens.Select Push(new Editor()); } - private void onBeatmapRestored(BeatmapInfo b) => Schedule(() => carousel.UpdateBeatmap(b)); - private void onBeatmapHidden(BeatmapInfo b) => Schedule(() => carousel.UpdateBeatmap(b)); + private void onBeatmapRestored(BeatmapInfo beatmap) + { + var beatmapSet = beatmaps.QueryBeatmapSet(s => s.ID == beatmap.BeatmapSetInfoID); + Schedule(() => carousel.UpdateBeatmapSet(beatmapSet)); + } + + private void onBeatmapHidden(BeatmapInfo beatmap) + { + var beatmapSet = beatmaps.QueryBeatmapSet(s => s.ID == beatmap.BeatmapSetInfoID); + Schedule(() => carousel.UpdateBeatmapSet(beatmapSet)); + } private void carouselBeatmapsLoaded() { From d2f3d5a80769eeae5932b2c4e42039430253e468 Mon Sep 17 00:00:00 2001 From: FreezyLemon Date: Thu, 7 Dec 2017 23:09:51 +0100 Subject: [PATCH 1035/1263] Added basic SampleInfo.FromSoundPoint and GetChannel methods --- osu.Game/Audio/SampleInfo.cs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/osu.Game/Audio/SampleInfo.cs b/osu.Game/Audio/SampleInfo.cs index 171a1bdf75..4a5d836c53 100644 --- a/osu.Game/Audio/SampleInfo.cs +++ b/osu.Game/Audio/SampleInfo.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 osu.Framework.Audio; +using osu.Framework.Audio.Sample; +using osu.Framework.Configuration; +using osu.Game.Beatmaps.ControlPoints; + namespace osu.Game.Audio { public class SampleInfo @@ -10,6 +15,24 @@ namespace osu.Game.Audio public const string HIT_NORMAL = @"hitnormal"; public const string HIT_CLAP = @"hitclap"; + public static SampleInfo FromSoundPoint(SoundControlPoint soundPoint, string sampleName = SampleInfo.HIT_NORMAL) + { + return new SampleInfo() + { + Bank = soundPoint.SampleBank, + Name = sampleName, + Volume = soundPoint.SampleVolume, + }; + } + + public SampleChannel GetChannel(SampleManager manager) + { + var channel = manager.Get($"{Bank}-{Name}"); + + channel.AddAdjustment(AdjustableProperty.Volume, new BindableDouble(Volume / 100.0)); + return channel; + } + /// /// The bank to load the sample from. /// From 229c9b5b4ea4a2524b1fc4285bf86ce5d78ef2c5 Mon Sep 17 00:00:00 2001 From: FreezyLemon Date: Thu, 7 Dec 2017 23:11:34 +0100 Subject: [PATCH 1036/1263] First basic implementation of IKeyBindingHandler for the playfield so it can handle taiko hitsounds --- osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs | 33 +++++++++++++++++-- .../UI/TaikoRulesetContainer.cs | 2 +- 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs index ac3796f5b8..c4210dd261 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs @@ -16,10 +16,16 @@ 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 osu.Framework.Audio.Sample; +using System.Collections.Generic; +using osu.Game.Audio; namespace osu.Game.Rulesets.Taiko.UI { - public class TaikoPlayfield : ScrollingPlayfield + public class TaikoPlayfield : ScrollingPlayfield, IKeyBindingHandler { /// /// Default height of a when inside a . @@ -54,9 +60,14 @@ namespace osu.Game.Rulesets.Taiko.UI private readonly Box overlayBackground; private readonly Box background; - public TaikoPlayfield() + private ControlPointInfo controlPointInfo; + private IEnumerable allSamples; + private AudioManager audio; + + public TaikoPlayfield(ControlPointInfo controlPointInfo) : base(Axes.X) { + this.controlPointInfo = controlPointInfo; AddRangeInternal(new Drawable[] { backgroundContainer = new Container @@ -194,8 +205,15 @@ namespace osu.Game.Rulesets.Taiko.UI } [BackgroundDependencyLoader] - private void load(OsuColour colours) + private void load(OsuColour colours, AudioManager audio) { + this.audio = audio; + + foreach (var soundPoint in controlPointInfo.SoundPoints) + { + SampleInfo.FromSoundPoint(soundPoint).GetChannel(audio.Sample); + } + overlayBackgroundContainer.BorderColour = colours.Gray0; overlayBackground.Colour = colours.Gray1; @@ -258,5 +276,14 @@ namespace osu.Game.Rulesets.Taiko.UI kiaiExplosionContainer.Add(new KiaiHitExplosion(judgedObject, isRim)); } } + + public bool OnPressed(TaikoAction action) + { + var soundPoint = controlPointInfo.SoundPointAt(Time.Current); + + return true; + } + + public bool OnReleased(TaikoAction action) => false; } } diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoRulesetContainer.cs b/osu.Game.Rulesets.Taiko/UI/TaikoRulesetContainer.cs index 48ee0a5b42..614b446181 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoRulesetContainer.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoRulesetContainer.cs @@ -93,7 +93,7 @@ namespace osu.Game.Rulesets.Taiko.UI public override PassThroughInputManager CreateInputManager() => new TaikoInputManager(Ruleset.RulesetInfo); - protected override Playfield CreatePlayfield() => new TaikoPlayfield + protected override Playfield CreatePlayfield() => new TaikoPlayfield(Beatmap.ControlPointInfo) { Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft From 2e1dfa16a28c3bbcae530d8308aec726374cd052 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 8 Dec 2017 14:59:32 +0900 Subject: [PATCH 1037/1263] Fix checks disallowing import of older beatmaps with no embedded online IDs --- osu.Game/Beatmaps/BeatmapManager.cs | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index edbda1a685..6d6b1cb3f4 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -497,15 +497,21 @@ namespace osu.Game.Beatmaps using (var stream = new StreamReader(reader.GetStream(mapName))) metadata = Decoder.GetDecoder(stream).DecodeBeatmap(stream).Metadata; + // check if a set already exists with the same online id. - beatmapSet = beatmaps.BeatmapSets.FirstOrDefault(b => b.OnlineBeatmapSetID == metadata.OnlineBeatmapSetID) ?? new BeatmapSetInfo - { - OnlineBeatmapSetID = metadata.OnlineBeatmapSetID, - Beatmaps = new List(), - Hash = hash, - Files = fileInfos, - Metadata = metadata - }; + if (metadata.OnlineBeatmapSetID != null) + beatmapSet = beatmaps.BeatmapSets.FirstOrDefault(b => b.OnlineBeatmapSetID == metadata.OnlineBeatmapSetID); + + if (beatmapSet == null) + beatmapSet = new BeatmapSetInfo + { + OnlineBeatmapSetID = metadata.OnlineBeatmapSetID, + Beatmaps = new List(), + Hash = hash, + Files = fileInfos, + Metadata = metadata + }; + var mapNames = reader.Filenames.Where(f => f.EndsWith(".osu")); @@ -525,7 +531,7 @@ namespace osu.Game.Beatmaps beatmap.BeatmapInfo.Hash = ms.ComputeSHA2Hash(); beatmap.BeatmapInfo.MD5Hash = ms.ComputeMD5Hash(); - var existing = beatmaps.Beatmaps.FirstOrDefault(b => b.Hash == beatmap.BeatmapInfo.Hash || b.OnlineBeatmapID == beatmap.BeatmapInfo.OnlineBeatmapID); + var existing = beatmaps.Beatmaps.FirstOrDefault(b => b.Hash == beatmap.BeatmapInfo.Hash || (beatmap.BeatmapInfo.OnlineBeatmapID != null && b.OnlineBeatmapID == beatmap.BeatmapInfo.OnlineBeatmapID)); if (existing == null) { From 31884a951aada0914546c5bd4505038da70d640c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 8 Dec 2017 15:53:59 +0900 Subject: [PATCH 1038/1263] Remove "redundant" parenthesis --- osu.Game/Beatmaps/BeatmapManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 6d6b1cb3f4..f599e8a108 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -531,7 +531,7 @@ namespace osu.Game.Beatmaps beatmap.BeatmapInfo.Hash = ms.ComputeSHA2Hash(); beatmap.BeatmapInfo.MD5Hash = ms.ComputeMD5Hash(); - var existing = beatmaps.Beatmaps.FirstOrDefault(b => b.Hash == beatmap.BeatmapInfo.Hash || (beatmap.BeatmapInfo.OnlineBeatmapID != null && b.OnlineBeatmapID == beatmap.BeatmapInfo.OnlineBeatmapID)); + var existing = beatmaps.Beatmaps.FirstOrDefault(b => b.Hash == beatmap.BeatmapInfo.Hash || beatmap.BeatmapInfo.OnlineBeatmapID != null && b.OnlineBeatmapID == beatmap.BeatmapInfo.OnlineBeatmapID); if (existing == null) { From 40e750f309eb8d9f61d4ee16d44c8d5fa5131931 Mon Sep 17 00:00:00 2001 From: FreezyLemon Date: Fri, 8 Dec 2017 08:32:16 +0100 Subject: [PATCH 1039/1263] Added sample preloading and playing --- osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs index c4210dd261..eda5c75906 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs @@ -22,6 +22,7 @@ using osu.Framework.Audio; using osu.Framework.Audio.Sample; using System.Collections.Generic; using osu.Game.Audio; +using System; namespace osu.Game.Rulesets.Taiko.UI { @@ -61,7 +62,7 @@ namespace osu.Game.Rulesets.Taiko.UI private readonly Box background; private ControlPointInfo controlPointInfo; - private IEnumerable allSamples; + private SortedDictionary> allSamples; private AudioManager audio; public TaikoPlayfield(ControlPointInfo controlPointInfo) @@ -211,7 +212,9 @@ namespace osu.Game.Rulesets.Taiko.UI foreach (var soundPoint in controlPointInfo.SoundPoints) { - SampleInfo.FromSoundPoint(soundPoint).GetChannel(audio.Sample); + var normalSample = SampleInfo.FromSoundPoint(soundPoint).GetChannel(audio.Sample); + var clapSample = SampleInfo.FromSoundPoint(soundPoint, SampleInfo.HIT_CLAP).GetChannel(audio.Sample); + allSamples.Add(soundPoint.Time, new Tuple(normalSample, clapSample)); } overlayBackgroundContainer.BorderColour = colours.Gray0; @@ -279,7 +282,13 @@ namespace osu.Game.Rulesets.Taiko.UI public bool OnPressed(TaikoAction action) { - var soundPoint = controlPointInfo.SoundPointAt(Time.Current); + if (!allSamples.TryGetValue(controlPointInfo.SoundPointAt(Clock.CurrentTime).Time, out Tuple samples)) + throw new InvalidOperationException("Current sample set not found."); + + if (action == TaikoAction.LeftCentre || action == TaikoAction.RightCentre) + samples.Item1.Play(); + else + samples.Item2.Play(); return true; } From faa921ba05790c42ee9d6df15f360bb032023bab Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 8 Dec 2017 17:41:10 +0900 Subject: [PATCH 1040/1263] Fix up post-merge issues --- osu-framework | 2 +- ...layfieldOverlay.cs => TestCaseEditorSelectionLayer.cs} | 8 ++++---- osu.Game.Tests/osu.Game.Tests.csproj | 2 +- .../Edit/{PlayfieldOverlay.cs => SelectionLayer.cs} | 4 ++-- osu.Game/osu.Game.csproj | 1 + 5 files changed, 9 insertions(+), 8 deletions(-) rename osu.Game.Tests/Visual/{TestCaseEditorPlayfieldOverlay.cs => TestCaseEditorSelectionLayer.cs} (87%) rename osu.Game/Rulesets/Edit/{PlayfieldOverlay.cs => SelectionLayer.cs} (94%) diff --git a/osu-framework b/osu-framework index d231ca9f79..797a351db2 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit d231ca9f79936f3a7f3cff0c7721587755ae168c +Subproject commit 797a351db2e852fef5296453641ffbf6b2f6dc11 diff --git a/osu.Game.Tests/Visual/TestCaseEditorPlayfieldOverlay.cs b/osu.Game.Tests/Visual/TestCaseEditorSelectionLayer.cs similarity index 87% rename from osu.Game.Tests/Visual/TestCaseEditorPlayfieldOverlay.cs rename to osu.Game.Tests/Visual/TestCaseEditorSelectionLayer.cs index f0da23955d..79f3e4f1d3 100644 --- a/osu.Game.Tests/Visual/TestCaseEditorPlayfieldOverlay.cs +++ b/osu.Game.Tests/Visual/TestCaseEditorSelectionLayer.cs @@ -16,11 +16,11 @@ using osu.Game.Rulesets.Osu.UI; namespace osu.Game.Tests.Visual { - public class TestCaseEditorPlayfieldOverlay : OsuTestCase + public class TestCaseEditorSelectionLayer : OsuTestCase { - public override IReadOnlyList RequiredTypes => new[] { typeof(PlayfieldOverlay) }; + public override IReadOnlyList RequiredTypes => new[] { typeof(SelectionLayer) }; - public TestCaseEditorPlayfieldOverlay() + public TestCaseEditorSelectionLayer() { var playfield = new OsuEditPlayfield(); playfield.Add(new DrawableHitCircle(new HitCircle { Position = new Vector2(256, 192), Scale = 0.5f })); @@ -47,7 +47,7 @@ namespace osu.Game.Tests.Visual Clock = new FramedClock(new StopwatchClock()), Child = playfield }, - new PlayfieldOverlay(playfield) + new SelectionLayer(playfield) }; } } diff --git a/osu.Game.Tests/osu.Game.Tests.csproj b/osu.Game.Tests/osu.Game.Tests.csproj index b7536112e3..1596e7e961 100644 --- a/osu.Game.Tests/osu.Game.Tests.csproj +++ b/osu.Game.Tests/osu.Game.Tests.csproj @@ -108,7 +108,7 @@ - + diff --git a/osu.Game/Rulesets/Edit/PlayfieldOverlay.cs b/osu.Game/Rulesets/Edit/SelectionLayer.cs similarity index 94% rename from osu.Game/Rulesets/Edit/PlayfieldOverlay.cs rename to osu.Game/Rulesets/Edit/SelectionLayer.cs index 98b3bce265..cfe5f8ae5e 100644 --- a/osu.Game/Rulesets/Edit/PlayfieldOverlay.cs +++ b/osu.Game/Rulesets/Edit/SelectionLayer.cs @@ -17,7 +17,7 @@ using osu.Game.Graphics; namespace osu.Game.Rulesets.Edit { - public class PlayfieldOverlay : CompositeDrawable + public class SelectionLayer : CompositeDrawable { private readonly static Color4 selection_normal_colour = Color4.White; private readonly static Color4 selection_attached_colour = OsuColour.FromHex("eeaa00"); @@ -26,7 +26,7 @@ namespace osu.Game.Rulesets.Edit private readonly Playfield playfield; - public PlayfieldOverlay(Playfield playfield) + public SelectionLayer(Playfield playfield) { this.playfield = playfield; diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 660d7cb5e6..d74774e403 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -565,6 +565,7 @@ + From 61a6a2919ef47d50ee0087d92618cd9da27c3a35 Mon Sep 17 00:00:00 2001 From: FreezyLemon Date: Fri, 8 Dec 2017 09:41:13 +0100 Subject: [PATCH 1041/1263] Fixed multiple critical bugs and changed allSamples to a normal Dictionary for faster access --- osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs | 8 ++++++-- osu.Game/Audio/SampleInfo.cs | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs index eda5c75906..394b683531 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs @@ -62,7 +62,7 @@ namespace osu.Game.Rulesets.Taiko.UI private readonly Box background; private ControlPointInfo controlPointInfo; - private SortedDictionary> allSamples; + private Dictionary> allSamples; private AudioManager audio; public TaikoPlayfield(ControlPointInfo controlPointInfo) @@ -210,6 +210,7 @@ namespace osu.Game.Rulesets.Taiko.UI { this.audio = audio; + allSamples = new Dictionary>(); foreach (var soundPoint in controlPointInfo.SoundPoints) { var normalSample = SampleInfo.FromSoundPoint(soundPoint).GetChannel(audio.Sample); @@ -282,7 +283,10 @@ namespace osu.Game.Rulesets.Taiko.UI public bool OnPressed(TaikoAction action) { - if (!allSamples.TryGetValue(controlPointInfo.SoundPointAt(Clock.CurrentTime).Time, out Tuple samples)) + var currentTime = Clock.CurrentTime; + var soundPoint = currentTime < controlPointInfo.SoundPoints[0].Time ? controlPointInfo.SoundPoints[0] : controlPointInfo.SoundPointAt(currentTime); + + if (!allSamples.TryGetValue(soundPoint.Time, out Tuple samples)) throw new InvalidOperationException("Current sample set not found."); if (action == TaikoAction.LeftCentre || action == TaikoAction.RightCentre) diff --git a/osu.Game/Audio/SampleInfo.cs b/osu.Game/Audio/SampleInfo.cs index 4a5d836c53..6ee8a7f296 100644 --- a/osu.Game/Audio/SampleInfo.cs +++ b/osu.Game/Audio/SampleInfo.cs @@ -27,7 +27,7 @@ namespace osu.Game.Audio public SampleChannel GetChannel(SampleManager manager) { - var channel = manager.Get($"{Bank}-{Name}"); + var channel = manager.Get($"Gameplay/{Bank}-{Name}"); channel.AddAdjustment(AdjustableProperty.Volume, new BindableDouble(Volume / 100.0)); return channel; From 9d3d9bcdc8efab16d62946dbb658416b555f3b02 Mon Sep 17 00:00:00 2001 From: FreezyLemon Date: Fri, 8 Dec 2017 09:42:10 +0100 Subject: [PATCH 1042/1263] Corrected the return values for taiko DrawableHit and DrawableHitStrong (OnPressed == true if new Judgement occurs and is a hit) --- osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs | 3 ++- osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHitStrong.cs | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs index 489eacf386..9d797b77b5 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs @@ -67,7 +67,8 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables { validKeyPressed = HitActions.Contains(action); - return UpdateJudgement(true); + // Only count this as handled if the new judgement is a hit + return UpdateJudgement(true) && Judgements.Last().IsHit; } 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 c07eaf4d8b..a6575df6d7 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); + return firstKeyHeld && Judgements.Last().IsHit; } } } From 5341e791029201976bbf401f8cf4615c1086e4c6 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 8 Dec 2017 17:51:15 +0900 Subject: [PATCH 1043/1263] Remove SelectionDragger for now --- osu.Game/Rulesets/Edit/SelectionDragger.cs | 12 ------------ osu.Game/osu.Game.csproj | 1 - 2 files changed, 13 deletions(-) delete mode 100644 osu.Game/Rulesets/Edit/SelectionDragger.cs diff --git a/osu.Game/Rulesets/Edit/SelectionDragger.cs b/osu.Game/Rulesets/Edit/SelectionDragger.cs deleted file mode 100644 index 35ea3a375e..0000000000 --- a/osu.Game/Rulesets/Edit/SelectionDragger.cs +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) 2007-2017 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using osu.Framework.Graphics.Containers; - -namespace osu.Game.Rulesets.Edit -{ - public class SelectionDragger : CompositeDrawable - { - - } -} diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index d74774e403..99156e6658 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -564,7 +564,6 @@ - From 4b3cf0773d0bffcc503755bccbca1a652491c8e1 Mon Sep 17 00:00:00 2001 From: FreezyLemon Date: Fri, 8 Dec 2017 09:52:58 +0100 Subject: [PATCH 1044/1263] Various CI adjustments --- osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs | 5 +---- osu.Game/Audio/SampleInfo.cs | 4 ++-- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs index 394b683531..549c59cba1 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs @@ -61,9 +61,8 @@ namespace osu.Game.Rulesets.Taiko.UI private readonly Box overlayBackground; private readonly Box background; - private ControlPointInfo controlPointInfo; + private readonly ControlPointInfo controlPointInfo; private Dictionary> allSamples; - private AudioManager audio; public TaikoPlayfield(ControlPointInfo controlPointInfo) : base(Axes.X) @@ -208,8 +207,6 @@ namespace osu.Game.Rulesets.Taiko.UI [BackgroundDependencyLoader] private void load(OsuColour colours, AudioManager audio) { - this.audio = audio; - allSamples = new Dictionary>(); foreach (var soundPoint in controlPointInfo.SoundPoints) { diff --git a/osu.Game/Audio/SampleInfo.cs b/osu.Game/Audio/SampleInfo.cs index 6ee8a7f296..d3fc1d4932 100644 --- a/osu.Game/Audio/SampleInfo.cs +++ b/osu.Game/Audio/SampleInfo.cs @@ -15,9 +15,9 @@ namespace osu.Game.Audio public const string HIT_NORMAL = @"hitnormal"; public const string HIT_CLAP = @"hitclap"; - public static SampleInfo FromSoundPoint(SoundControlPoint soundPoint, string sampleName = SampleInfo.HIT_NORMAL) + public static SampleInfo FromSoundPoint(SoundControlPoint soundPoint, string sampleName = HIT_NORMAL) { - return new SampleInfo() + return new SampleInfo { Bank = soundPoint.SampleBank, Name = sampleName, From 51dc66df12ee244544757498c8a144f4d53352a1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 8 Dec 2017 18:45:06 +0900 Subject: [PATCH 1045/1263] Add support for relevance based search results in osu!direct --- osu.Game/Overlays/Direct/FilterControl.cs | 1 + osu.Game/Overlays/DirectOverlay.cs | 26 +++++++++++++++++++---- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/osu.Game/Overlays/Direct/FilterControl.cs b/osu.Game/Overlays/Direct/FilterControl.cs index 9b52cfd367..46ba000a28 100644 --- a/osu.Game/Overlays/Direct/FilterControl.cs +++ b/osu.Game/Overlays/Direct/FilterControl.cs @@ -105,6 +105,7 @@ namespace osu.Game.Overlays.Direct public enum DirectSortCriteria { + Relevance, Title, Artist, Creator, diff --git a/osu.Game/Overlays/DirectOverlay.cs b/osu.Game/Overlays/DirectOverlay.cs index 0b7a30797d..7994483043 100644 --- a/osu.Game/Overlays/DirectOverlay.cs +++ b/osu.Game/Overlays/DirectOverlay.cs @@ -43,6 +43,7 @@ namespace osu.Game.Overlays protected override SearchableListFilterControl CreateFilterControl() => new FilterControl(); private IEnumerable beatmapSets; + public IEnumerable BeatmapSets { get { return beatmapSets; } @@ -69,6 +70,7 @@ namespace osu.Game.Overlays } private ResultCounts resultAmounts; + public ResultCounts ResultAmounts { get { return resultAmounts; } @@ -115,7 +117,23 @@ namespace osu.Game.Overlays }, }; - Filter.Search.Current.ValueChanged += text => { if (text != string.Empty) Header.Tabs.Current.Value = DirectTab.Search; }; + Filter.Search.Current.ValueChanged += text => + { + if (text != string.Empty) + { + Header.Tabs.Current.Value = DirectTab.Search; + + if (Filter.Tabs.Current.Value == DirectSortCriteria.Ranked) + Filter.Tabs.Current.Value = DirectSortCriteria.Relevance; + } + else + { + Header.Tabs.Current.Value = DirectTab.NewestMaps; + + if (Filter.Tabs.Current.Value == DirectSortCriteria.Relevance) + Filter.Tabs.Current.Value = DirectSortCriteria.Ranked; + } + }; ((FilterControl)Filter).Ruleset.ValueChanged += ruleset => Scheduler.AddOnce(updateSearch); Filter.DisplayStyleControl.DisplayStyle.ValueChanged += recreatePanels; Filter.DisplayStyleControl.Dropdown.Current.ValueChanged += rankStatus => Scheduler.AddOnce(updateSearch); @@ -271,9 +289,9 @@ namespace osu.Game.Overlays if (Header.Tabs.Current.Value == DirectTab.Search && (Filter.Search.Text == string.Empty || currentQuery == string.Empty)) return; getSetsRequest = new SearchBeatmapSetsRequest(currentQuery.Value ?? string.Empty, - ((FilterControl)Filter).Ruleset.Value, - Filter.DisplayStyleControl.Dropdown.Current.Value, - Filter.Tabs.Current.Value); //todo: sort direction (?) + ((FilterControl)Filter).Ruleset.Value, + Filter.DisplayStyleControl.Dropdown.Current.Value, + Filter.Tabs.Current.Value); //todo: sort direction (?) getSetsRequest.Success += response => { From 679134c0306c5c74d7f1776d335ca075eecd836a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 8 Dec 2017 18:55:25 +0900 Subject: [PATCH 1046/1263] Add ShortName to rulesets --- osu.Game.Rulesets.Catch/CatchRuleset.cs | 2 ++ osu.Game.Rulesets.Mania/ManiaRuleset.cs | 2 ++ osu.Game.Rulesets.Osu/OsuRuleset.cs | 2 ++ osu.Game.Rulesets.Taiko/TaikoRuleset.cs | 2 ++ osu.Game/Beatmaps/DummyWorkingBeatmap.cs | 2 ++ osu.Game/Rulesets/Ruleset.cs | 19 ++++++++++++------- 6 files changed, 22 insertions(+), 7 deletions(-) diff --git a/osu.Game.Rulesets.Catch/CatchRuleset.cs b/osu.Game.Rulesets.Catch/CatchRuleset.cs index 1d5fc0545e..cb46c75583 100644 --- a/osu.Game.Rulesets.Catch/CatchRuleset.cs +++ b/osu.Game.Rulesets.Catch/CatchRuleset.cs @@ -93,6 +93,8 @@ namespace osu.Game.Rulesets.Catch public override string Description => "osu!catch"; + public override string ShortName => "fruits"; + public override Drawable CreateIcon() => new SpriteIcon { Icon = FontAwesome.fa_osu_fruits_o }; public override DifficultyCalculator CreateDifficultyCalculator(Beatmap beatmap, Mod[] mods = null) => new CatchDifficultyCalculator(beatmap); diff --git a/osu.Game.Rulesets.Mania/ManiaRuleset.cs b/osu.Game.Rulesets.Mania/ManiaRuleset.cs index 4eea884891..070c7b09d1 100644 --- a/osu.Game.Rulesets.Mania/ManiaRuleset.cs +++ b/osu.Game.Rulesets.Mania/ManiaRuleset.cs @@ -105,6 +105,8 @@ namespace osu.Game.Rulesets.Mania public override string Description => "osu!mania"; + public override string ShortName => "mania"; + public override Drawable CreateIcon() => new SpriteIcon { Icon = FontAwesome.fa_osu_mania_o }; public override DifficultyCalculator CreateDifficultyCalculator(Beatmap beatmap, Mod[] mods = null) => new ManiaDifficultyCalculator(beatmap); diff --git a/osu.Game.Rulesets.Osu/OsuRuleset.cs b/osu.Game.Rulesets.Osu/OsuRuleset.cs index 0d2343a33e..bb5700976d 100644 --- a/osu.Game.Rulesets.Osu/OsuRuleset.cs +++ b/osu.Game.Rulesets.Osu/OsuRuleset.cs @@ -124,6 +124,8 @@ namespace osu.Game.Rulesets.Osu public override string Description => "osu!"; + public override string ShortName => "osu"; + public override SettingsSubsection CreateSettings() => new OsuSettings(); public override int LegacyID => 0; diff --git a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs index 99ae36967a..4de9ba0ce7 100644 --- a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs +++ b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs @@ -95,6 +95,8 @@ namespace osu.Game.Rulesets.Taiko public override string Description => "osu!taiko"; + public override string ShortName => "taiko"; + public override Drawable CreateIcon() => new SpriteIcon { Icon = FontAwesome.fa_osu_taiko_o }; public override DifficultyCalculator CreateDifficultyCalculator(Beatmap beatmap, Mod[] mods = null) => new TaikoDifficultyCalculator(beatmap); diff --git a/osu.Game/Beatmaps/DummyWorkingBeatmap.cs b/osu.Game/Beatmaps/DummyWorkingBeatmap.cs index c187aa592a..1434943da0 100644 --- a/osu.Game/Beatmaps/DummyWorkingBeatmap.cs +++ b/osu.Game/Beatmaps/DummyWorkingBeatmap.cs @@ -63,6 +63,8 @@ namespace osu.Game.Beatmaps public override string Description => "dummy"; + public override string ShortName => "dummy"; + public DummyRuleset(RulesetInfo rulesetInfo) : base(rulesetInfo) { diff --git a/osu.Game/Rulesets/Ruleset.cs b/osu.Game/Rulesets/Ruleset.cs index df5e12a24f..642647ec69 100644 --- a/osu.Game/Rulesets/Ruleset.cs +++ b/osu.Game/Rulesets/Ruleset.cs @@ -23,13 +23,13 @@ namespace osu.Game.Rulesets public virtual IEnumerable GetBeatmapStatistics(WorkingBeatmap beatmap) => new BeatmapStatistic[] { }; public IEnumerable GetAllMods() => Enum.GetValues(typeof(ModType)).Cast() - // Get all mod types as an IEnumerable - .SelectMany(GetModsFor) - // Confine all mods of each mod type into a single IEnumerable - .Where(mod => mod != null) - // Filter out all null mods - .SelectMany(mod => (mod as MultiMod)?.Mods ?? new[] { mod }); - // Resolve MultiMods as their .Mods property + // Get all mod types as an IEnumerable + .SelectMany(GetModsFor) + // Confine all mods of each mod type into a single IEnumerable + .Where(mod => mod != null) + // Filter out all null mods + .SelectMany(mod => (mod as MultiMod)?.Mods ?? new[] { mod }); + // Resolve MultiMods as their .Mods property public abstract IEnumerable GetModsFor(ModType type); @@ -66,6 +66,11 @@ namespace osu.Game.Rulesets /// public virtual int LegacyID => -1; + /// + /// A unique short name to reference this ruleset in online requests. + /// + public abstract string ShortName { get; } + /// /// A list of available variant ids. /// From 4a723f738290cea4cf593cd30762ebeec1dc3976 Mon Sep 17 00:00:00 2001 From: FreezyLemon Date: Fri, 8 Dec 2017 11:05:00 +0100 Subject: [PATCH 1047/1263] Added the "Service Include" tag that is used by Visual Studio's test explorer to the .csproj files --- osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj | 3 +++ osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj | 3 +++ osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj | 4 +++- osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj | 3 +++ osu.Game/osu.Game.csproj | 3 +++ 5 files changed, 15 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj b/osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj index 969ee702e3..b03c8d2eea 100644 --- a/osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj +++ b/osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj @@ -90,6 +90,9 @@ True + + +

B|Y!(m@c!^JqGsmK0?R;3Kj7o^o-3dhd;XPE_l|aLy(^c5h@yRJP{$UeLMfoVa>!Kb~ot=Xx9)1&{gZ0Akrz$dw6kpBs z@@@u>mHc%!@wpz%&sBR9i^%Ml3H8*{grPmwqU@&|(6H%K*!P}>$`cYM2dn$+oK(o- zZ#F-adq>7nIu1eM2T;+PxO+8pohr8~^Xab!6TXgAsjJj+wfk3w=z}|jlV%LYKg%i<9R#o{w zUkJ;raouAhP-*}BZnW<^h4OnYfhMx|p!Z}W+Me7YZ1g;gB&R++a zotCdIgL#o;*5qqG`st^iUOIpN{1cD>0CLU%95rgxE2OIDOZy3+^Nmj--+Hp&jXzSE zd2 z%LoK6?Fj;b7CSngdLOR+)o|0o2u&`;*gJa`3wf(rQ1|#|XmzhYfj;NvUncMYUj( zLMR)=%pWfdJ`hFwJ*ZdDK;e~=d-F2?w46M7@`}lmC%=zgj=*>$P}J4cT~kt0@@E>L zR>}`>_ur1c?ST4Fb6f{t6n$e~2PDS(v)$i6)70%B@CmcPMe4bFOaV$)%|p?mDNq>` zNI7>TfrzB7zph=_>s{tRmnN{NhdIEXYbR;$K2Z-le6W&4FIhdeORBS};UN&<9)0n) z92~xWz)5CeE;{dUykjJ_Yj5I}7Hk=R>YjcTIr(bUjWI^M}r~ z!J^SaOHx}w%&wU?7WxZkK*^!Kek5R*gYWH6;Xc9+KDki!IRmk`gD+Vc4oyT85f=t| zMw?Lf%{6`cMD|DAA*iFH3lFPqtBClW;yh_)PoYsWEoIvm0r z5S3vU&*=jK-jhv`X_Zj%Za-PhbLX^S*C%J7KYL8KU!aTm!;;^u(nFs|>i*J6(4RXM zih}rg5@82lt0*C62cN>`6{)*=m0FU6FX{V{BVj=%l`6URVWLl@Du}|nFHR~FKz#PX z0}niK^ZobV-(zFR-oGq+_St6(ue$20m(*(YGRY_3R|W6WAHpC{uKyn+aR+Gu!5py3 z27`hkqc9+L0%i~piA1FqlwLFk#pld`+G2>$AR>XN0ges(L{W>~gfSEw(B`A-w`>y0pz7Ghj83+l-w@$J=!gRhAleD56qn!*k~R`-R;Ang3?09m3s zkin#=Lr^M-cH!*nNirqatvrymwIx? zwxbBWb|9s#zd1RG>jXZN#NKeRw^mO{6BPLaK~do)5{XD{=l=ZVYvv<=_JkhxeUI<) zhMe1v!uIYVbT+oa!J5FDxfpZxvYu(fLqPU34LJEnmi(>AD=k9a%9$`Moea4-zT=Tg zblcd$w|SrF2&9)Og@Z4g!Pk$2Po;oNtq2!ZrD-|lQdp1$VL)Qin}`IE;K={-aulta zlgw`%+`4t^B^O?JVI>j(fPC-Xy)$RbnDH8+(rBqCx4r%;6x&Xbx~5KAQR5rHzJOfK z`b(L(q38wEpe(h*d$2|n0x<(ei-Ds40gm^(0v-VbK9x*_>ex|eo?OwhG`MTRf}%vY zWBp#?h*K{bk5Mo)cto2pG$NPoI%}NABl8m z9h9QJfJ=utb+>mC8Alal1$rpP6+$_+MED=v&+h?T>8}^A@9^b-Ly&pEL#D8laYQ2l zrYq)R)Q#sR^Ba{PfBf-f3l}cjk3;~lfB*ia)2C18EBSN!5V;Q5iVZuIdD7EDvqju4%zdUAS{iS>&>q(d*iP0H0+64nF>mz)V(Xgkl0Q{ge_YDy)#1G$L1k=gt1e7NDjxBVK`AsT1&eJdz!g zo`4_PbEk*~u?dUNVu*7AjvhUF1@U%|T!7x+R-8V4dd=w3qn{xFFiJTwCzWu+3N8YY z5(12S4o(;$Eg%?joZ z1Kb6en4tKAvr)2QCbYau@DOgVmhxPP65STmz4Iwrb{vAd(*uKA2dmyF;`xe5OE~W5 zCoeHWF|i1W$;D8VTOi{krQQpiGywbaA0n{xbVmFGxe^u>&1&QH&4@=_6QG5Y;=m)`h0rFA{6qAaeB&O#EpQ7e}0LFIjIRp38yP?RC z`JO9bLD37tGw{wu916tbB24)H)lldpcL#FU)z#fnQBm<6VyXgr&$P0kq2Zs4ii#d0 zRF=fe0XwN=k8Xvo#Vh*6r%IotuwZ~@&UoWu7#B|pBlJLmiow9`745^gaVPr>ywz>+ zI-KFKVWcCGar!8fuU&vVva^TU>6h^O=~|k09Ts-Jm&_e4lp=LktER(Z6yYlstM(-A z<;A9OH(v?ToV5wwb;@(B0q$o$fXba2VUa6gLD8(1*8f0`Ne%@DD$JPh!)yBN5z!yf zwFR1*n(kuZj+kVi-m|Wv4}GVgpy0oy_5lpEIpBDdG=NTj+M9qd60<3g3!d3@h#PJ? zOmc)OEHF*05DqsOugqySf*w# z(I;Kv8i7MUe*y9)2Mk)B$OX`iD~5JPx!7V&QDh2t8X6E7Lj)#1p-DKan_)Xf^KqsL z$~HGFUPapb491cO3$hk4#HN5~Ry)AH6$}8pXXE%EegPVZ$v^}Eq1M*ceJlpq6G~v2HX7#fWuiDpc;Uzie)?&qY;~`wl^l3b3}5ux&RpyqD&u!y)PzI*H+J$Lrv#Z55lN z$O9qK(umM2vFeXGNXpnx_sd`uuLcIfDm3|HRiO_FX6TONek+9!dce}+eu>hqs;Kl@V7dM z;RC{P%#6;t0IG?%*s}+TBU#KrI#Kx7z|&OdQ#_+S~NZM*6;%WmaZ`^t3+;8mh3-aTlTt< zVeKHiJs6M09{~gg0$sNvTMWyzQ7D{01-c}9!Vfh$Yg*?hqa3;=6NQS-$vGk`ulJ*; z`!%PaioSjP$lZMTk(rvG^JjP?)aYX1-5Kn3I-j}z`s;7aECB4QM9af(LlYQ20KiP9J%1|lZa61?qE1v32=#m& zivEvZb51`qbmTF-l{YhZV{K^_s9$#L)h2xXsg3jp?4q4oD~3ji1{3zJ>#r>qi}Wzyu{t#W`Yot^ z!zT}5&;cOS^GPV)dy%FgQJ+F6;%5j&{0yx5EA`rhdko|v1tY$Y5y~7z0YIbELaCBo zfqN1XEr2+sKYBc=vO{h9O!v+Av9&22z<8zCws@@dN&5`%%*2=F$vPzum6tV3P zBFrEAes}!4@9#uo;(gD>s-1${VHq@#=NSl{O|YySUSU86Ob@LO1_16H?IU5~Z?uKG zAu-^l+t@DwMYAt^|Ag3_R+ah&okLB$zFb@~Y}H`$e_jt=nY7Kj7yw#YT7I%%!GfQh zIddj{Dln0zuCDGoB_$<4kqQ8u;U#vIZE+170N{nk-FH~}3t`-A*pW1qxXEb!WjpYD zoZ=hmQ_3vs@et=P;j=2ZD~=ips~*Y{vuFasI|}hGItq(k)XWbz`@aXV+Dh6L_eJy* zC~zkvZjBab=oIgXFc+sj5REU#9eiAj_BIl9yh#s8jStH)k*CQ(9qCu zFKPL|qL=ZDfr!+Vm6f-T8a3)yQX7K!J6!?*YHDh}IcCh5Khn$i<-kPhW5oc8}Qf)L-2OADIo@7$w;15KU5g zw^xsQ8U|ts8-R*!x|8sr=Msr@@o`p^-E)cLmSD6tJ*Q8fzHQ>fiO-_Hh9E?$0|yRV zGIi?IzbO<7NlC_>w%YLU+X(KjO}it|aHTGLGeX?Tns>obmRO(~oi9{*ey+$PRi18` zR8?Ly3U#>QYG@Z_vmJ-3U>skHF_$mNd2^s?=Rq8OWIdF0y}B{n`(UhShN3U0xnK=P zg7g&*SQ0RS76$?Z1iS~Lzp70DM38_Yo@0^kgVc^vVuQ|M=n!NdmTXozO76HYaleHa z;-;WSj~@Nv^y$;zM1q!J%AGrRE?>BC;fn+SlFH6FG|}|L7Wj9b`dk8l2>r!$l41XX zdTJR8ZaGib^Wp|c)r=xxM0cwVwo~;&g4&MNz}IYp%;ghO%Q9~wCf#|-(Cr2!@j9Bf zA41~`@54{b%1u#xA!17Ij8tlcdFm*!L8@_V3Dj0Y;zlU3#8DSA4cJ8R9&do-l~07m z(DmmC5KHaq!yuH(2AxAqoXW0RIst`WIahKX3xQ(mo;`ckEnd8M2ND2)V#9_Fb5^cg z`7%w6w5D@3*DWvZhI_+-w3>nrS7NVhti%yD|0PD0|J&tI6_^J8exzRBQQM4;!&Sue zRiZl%FLG{y#bvYHOw(9i2+Q(mFfW|~bwTcT1Y+s!t!jmR%ON;EIt`D_0dK%3dfIb! zV^BrRN7rGTPzvkJu`o|8mu4zN$bGmLZ4bW#xyU~W6RZBoc9T*N01UUVAQy&dSIYjwu6JQGZd zC&PUHbf~%i+b~OAX79fDcq1I|9)kN&Eqrc|D0hyQI`iR|2O&3UMSCj?w@I7EZPM6O z=%^tB2&ht8*Zi&>BJ3cyvw#T+W6&ya3mGy|7-p z2&Gpn3b(=X`Qd4^!Cu*j_QRFvI8p<5ZFqMeMMxIzd#6x!^}pj5SW1Hq`Z;4^x?l#> z;|t?&u9<_xU>J{?*oo)eUoCbz=9~bY6Vcr^(gej50R)zAAsqog25&Hp>$*CV|^2$TVyZt;E=8Tj49jDW|ic!kuHyH7Nr`8RK6tWW!Jps2UG&-*+d0WV}T%TRFXd~}|y z6>7cXbOZctcF4Q>-i3SKsYHXz@Sb>_d?eS<;-6Ly&vH=qwt#-LpwowQdnna=Rdyo zwXgltQ%^nBjzqfy&zLd8uyyO!U*zZK-yu~k@-=p%@xeEtXd6DsK+C-H#gYK?KJ~{&Mk*T0C>0r#aK;7tqQLYwQndwOXC=Hjepy(-?uSfBBRzoR0 z2?%X%Z4VP~f48Bb!HGlwFly8&?fdV)|DE#k@*mN{lmv+ZhX;+nS`VCQ`&{G#^bY&= znGf#mE*7m%Ft?EMvT%3XKAmmJrdO3&p+9#j^ou4!VbR5v=tsOZ(TSE6_+l8VN_9EZ#7GQ&IojEJp#|( zDuf)}U2vm46N3T}0$rv8gDW$uQK=D|(Z(~wQl;S#7UX$RPA);-*H=O=eOs_#U0vM| zDk>^C3$Vx5Tk*J6bMWB7>!(hgDmfX5bH1DY_$~q;Ri?c;NX}Cv<1dlK33m+(cL46U zl{M$2=Nq6uXA%s{r$AX`?zcUetEmGu8$J|!>?s|7m~{piOA3&8!xHF8Tga7+HV#*I zJo`QzpH{-@;f+x|kQEzIwsrxEm(37Py}0wmj>4l2aJ_pNK6(^s!F}d5yq!8bS$Q@U zks>O|*_RS%I5-5^55m1H^*1h(oC`t%%YE$Fv45U6Z5rbrz4QTGZ|?uh=K}N&`=vs{<2`SjQ1>|_u)iD0<-=@KSG}?mp3_ax%hY0z zJwsUm3T|2k?X1yVpuzbAY;JH1@xk&5aDRVx=4lHoT`P%`bUI($1LvMoqH!e`T)9Yf zH=aEPqc2|q)5NlVua|d0^6m{g3jI~B2{ZphwO1)qB@4WXAlLaWw8RzrLXP9yuQ5Uo58Hr(>?{#)C9-h(56>?e++cTuTpaW$DQMtG@NUglsf=AO&UPG z`d$_p%ndrwA1wsk{(LZ3H+rlIKt^l|(edZ;9fes7pe7(WpUGRQcmTkO$|8jnxN`=A za9}#?^twg^CCFq0MPsM@O|F%&p+Sk<(FSxBa_L-u)RoA;dQ88x)pdj zb4YH$aB<5>z#QaDL_$Y`N5U5o2EdhgcQzRtbx^tYER=6LN=ItTaHKY|cWGWgN({u# z8wC<4$&Yq)<<8Skwq`F_wFX*A*z=j$bf8EiVQ5f8{s$XComT;}zUk0)@l7C3igEni zqS8U*x|7g!sDL&{X)+sa+JMyv;vStK?beahtIze8%8HJ{Di!GVT><^EB6>c?b;UN{ zKUjn_EXcI&3UvfI`aKj11z6-l5G))4{B+jJIfelDzVgZ|cfS4h+b$tMgeO|%4j3>X zYR8Tp%i`kV?q+)tQ@w^p0=U=JK}P~`q41;kGaa=pK=bkgl{iGzMHOE*F$bhWvWV(0 z@%mMC@+tGmpyY=GbO@-}!UefNOdVb5JQSo5$$vLd`+KK4RD8Ur8loYTuG$G=tp$X9 z0Z7L7fKKzr0$1q7WUSWE%mO4hoq-l1IW!A$%Ese`P_<$w9qTS0lnGt#odTk`=Ilqz zb5O4*OyFPv4OwDXPiHcKnlJ*Bln?Radqd}&hJYk7+UxycdvsHAjV*uRTsdWO;RyTr zLpZ{Mcsw@kq(Y7S8;5)ZYd%UO5|B!zU`QZ)V$o>eMoU;9+tARkGB-DO$?@aIi8|$< z0pRbXB_$=#q@|_3!Zs3sj+^Swc7XXzMNp9dTqJx*Tr^|=p>WIa108>6uVFto5b2DS ze$p{LsFM%9^OP;#r)$Zl#6Q}V_%XC|ssM_= z*bZW)$u=#wQ!KUVn~ZQ4*s7}}%x*7ZiH z`|1ER9JmZBlMZAfx1|VkQYLo0HgXlrx~O6h#h?b6>caLQTk&f#ndwaMDvCP zQUqivD=T{`Gcyw-0N4r0<>KC+PDHrH?L-q;K^}lz!7*;g^(R2L=?w57aL$RG5^Wp= za!G7^++MT*e_=ldu$@=56ePp5K{h^zhWC7>?xN$a_GCVkt~*Ffs4D8@lL~C%EuMXP z4v(B8c0Lk+XO~fC4VTNH;FC=tsMSHNL;(Vk5EOR|rP_wWJRoXx`NktqedIFq{o@=5 zVQR{2py_%8$TN~a6yF?6HmY@WjF&;Bg}A<1j_)^|D~7!HegIkb&d~FTTYxWbmOhx( zSNpFWpsA_@6(Q*83B4h6?l>1_gIR!@&1b2XpHM%2ub9rNGa9IGKu_pCW_Win2N z5_}c7;FxgTiL0RAc@d0$9EG7GlsW-C&Qr^76l{TLlE_GiDGp+>m@-ex#I7L9?Zvu@ z1=+irGiT1+H)znH_2AS9#BqKv#|ggu_S?a?-FDk|gp08&3L?;+yb2AU?*?9g%o({Y zBmEhm7GUr)9kn&V*71jlJK_Q9Aj8z%EZ?cSNSInege5;6hPs0nX$GZ?sQVJ0kY)uk z8WcY*ma6@t9w{yw1Xc=O`E(=AyNDLaKq3-@xNjQ7EE)$~c{AZPRo26m_trsFuQbS5 zFqwMa@i~gV-U-*X9w&r4ff5~qy3>VldD(jESIAj%8+9fkjKsVvd3QZ%D(j&0qREgj zs(AzAch!WrRX?4ip+8K3io0n5q|YAhk_2SY89}qpw~+I@L6sVEYihl6zp;`fpGJ(&=={(6Jn-h|da1mrwXDE-Mf zaXcLF&cVR%-HG+R5QbB_VZ(;s5u604DnQ4*dO42w?6c3Nz4qE`tBKt)iuJ{=H9+-0 zw*ar9iR~d2$lU}jvanFkqZ{6mvK)T?<=Bob!%4+o)s z^J&PqKNq4$+EjOQlMxF4xgN9^%AnKy@sM=$AjdJPv&B&S!A5G%CH{USbRw!b-Voa1 zHUHTQ^?NRWwQD?NKRL@q%{LPUQUBR4&=*{%j=n~Y5t42l2B|ZKxil|9lR>lX0_e7$ zx6NGyrahY(noLGV$WSpL6Vh%OK}V(gigi=JOhp5zcM-Dy9fe9Agd4$x1yN-e_{b_` z>kveuN7Wyh3H2c;1Rz{A61a)}t4tYS4FI9zd2hY-RynkY0MKiAIgUC4w{6?@UVMD~ zLbm+@Eo5_5f3yv(c~z_(fw;gZ{XJa*7YX~Hw-vnQ`_qNvb3wo&b=Pq&!bFr;%Atg) z`;Dirg2=+Ph4!e_=en$yH{x%qRYCs0e}<-0C4~5;wn{icAhO)P5IbkMi(RNKt%0KV z*MpeDhxBJ}0ioS5puet!lDF3bw_ZmRiQ;nmJC4y1+xq&_EtELqWOziJHWXPP;Xa+;!bx`lP08M909p?=T?6y2xEx?!b zciva1-TD)5XcEiia=R0etWTF15Zyh(uaI%N4mJW^k(-TWi%`DMQC zF)PqY!18S;pz@cKz$My|j7WS5A%20q2*`QW1(^vDLu`Ig*CZF>#~OhAFMk2`!90lK z*_?#vpXH~=Lc(KHL698n_%22iN>}d&&Gw5BJFp8RKQfih6+kpzD21wJTWIBG%-y3Q zdR#BZak_#kqQPwjPLmmoDN;y(?p6>)+ax`9_N^h>ou*a^ri^Ilx`Z&5*k-~+>8||x z5HuYrq!OKWT^3m(Z60A3V%y&HH&|27UT7IHaX+!fU& z)B;-DA?W7#W1G6`1RVB(b~Q@L8cvqC-$g zOabiSXCxcE(VzpJj0@=tCPBjRo-WQkBu=ad)ND8nR*kD~3Vj1~c7r`+s26h}VSFD* zn>Ng6$k29TvhI!Ky2p!X4+3L(Ls%SzZ0ZD@!+vaF@DUcokRN^+7|Er1^N9VQ!+tOf zId{#TJ$vq)Jb5x^0D9y$zV4L&_rL!=`{}2j{x6Zz1KD2GRIQ?t0&28APmYU)(w~i& z6&XOQh6PdeH#dj{Vyc#-(@-(IdC-Wyq{imM(GXRfsN=Esj)Azby&Y@Pu;C}TkI8z>Xdf<9URnfK)qZ6w=;IIxC9cc6eUfm2{@bT##; zHef+*zyKq662HwJg zOxTY(7ghg>NhDk}3b?WCf^rB#Hz(hI`|Y_ezx;9$cyIvH=kjqpci6CDv70w$mIL8P2F_{O6%(fEpam)Z5>Z_%X$|eDg7=_;x?Y&3tM)AOoR?#YiFk(J3JA?kW+K=Zm5Aqs<^U5C)r` z00~QO27Zif)0l{4EPd}M5R^57mCuFP`^STPNVelxobrSk0AFpSnR~*CJ)qNF&3)%| z7s{dG)19;vw2Ei}F?S4wPBVtNNOp7xHhi`l%tbXekGI7HD#8Rz2@>eC_$G+%mF^qjG3nfy__HkU77xydE?=FH)_*(ipr? z$yZp=pX1N#ere$lbPoGD_5nts`X+(s_k+oW*fAJfdt(2unlNF)(-$sWz#ae|iO1LK z(S)Fj7cVaA(WA$^L}Igky2jlXLA~Y(aJ|qgE+Rf)AemOkDKRt{Y0$7AHeKwN1d80g zAnKFKs_YUsnyR1zO4c6))rmq7nYol;#e8=spYsX}yC)Mho)AB#cD5jl%H3z6f=_=2%jpVG2*n^C-3{W1Nx^(aS5gfX?`;H$ z)=C>~#62_-WCOCA*BGZfz4tQ+lm?o$XX+XU8B1n5T2EuPXYB`D!Fo+eopnt~V#t2_ z77!;p^^dhX1RMWzfQTRy-Mm;9tt94vrLzLEAGn!%_nnu6GJ)g8p!wlASn3^vYYD?Q zgURS2WN0=3FC_|6XN`cAF@0DiIAIc!{z?_7w_gA~VPtgfK!ETT7G&f2^R?fc9fEis zg+1)Yz{Ifv=axPo7@o!YyySd_D_5>OlarJ41$amRa@@P0^N7~2T|08ttXXRacVlgQ z7|QDCM&ZzLVear0_G9rtbR<%^YQMdKrkN6E8GY9%h?>-!mBR(I?XK-OMPuundL5Pc zRO)ki)KTZ{3|6$^iQ2Ci)5DecvD5OAOK^3?FCbQ%X=Wfc5@DDKze@sD?fEU5j@BN{ zqph-{tU?e=BoKA?D3Fh7&fIG_oCmebcY~B802ARQ@sH<%w0CowhoMSIhrA#Ipw74` zKBWC|7KrQwj^V(%ReQmBxQPB;Y1BdVErX!*?IT@El99NS-y8(}(W|y`Y4-jIN}>sH zvf?NcaH~}y&y2-GC^*n3zzkY(&c0+OI$_5p%p`2$k@qyH3uN3jnl=?>Qyyy}+6!Js z`M<+KX#<|>1cH_R3>Ynd_BkMCn{xsYQmsi&&cARZa8uYd06~!RUE8>EF-dvSCaVRo4L!ZkO^hl_;_Aeah8_)sc;cU!3bJ0!3;^r-anLKj&gOL0a7>W&*i?w>*W7SKy)O?Mzc~aPGa*r|e5c8$c%^)dmP7fH<;-(*{H5$%8-`?SGtw>R18P6Gn*F2^gpaphM8k@B(%G zdE0jevhRe1iJTVg%=hqUAoj`{NM37e$K;x%2)wc7X`TjU?T?S>^^8JHNuVm(;N1_ZA!G!&AbD@nJd+QKL|J@jO z$%0P4%6cfz2zO%U5Z3mWq);L0bqQEO2` z3H2Q?#BU`(uo*<$f^onVyB7Og-*+A=KHm-stL+~6y;30M$!QMr#bPi**@s(zbFqr{ zBQy#)knrSGkaTa(Dl^tGa~^Gy5u2OJXAg#?8G{|n#!y-dbxVH%PNSYmV-?W?tL@kP~GUqa