From 5c3b7ac12ca35da401f06f981ff814791be0b97b Mon Sep 17 00:00:00 2001 From: Kelvin <2yangk23@gmail.com> Date: Mon, 28 Aug 2017 00:22:18 -0700 Subject: [PATCH 01/47] Allow rearranging playlist tracks --- osu.Game/Overlays/Music/PlaylistItem.cs | 43 ++++++++++++++++++++++++- osu.Game/Overlays/Music/PlaylistList.cs | 7 ++-- 2 files changed, 47 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/Music/PlaylistItem.cs b/osu.Game/Overlays/Music/PlaylistItem.cs index 4145a8d1f0..6c38755e72 100644 --- a/osu.Game/Overlays/Music/PlaylistItem.cs +++ b/osu.Game/Overlays/Music/PlaylistItem.cs @@ -8,6 +8,7 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; +using osu.Framework.Input; using osu.Framework.Localisation; using osu.Game.Beatmaps; using osu.Game.Graphics; @@ -28,6 +29,7 @@ namespace osu.Game.Overlays.Music private IEnumerable titleSprites; private UnicodeBindableString titleBind; private UnicodeBindableString artistBind; + private FillFlowContainer Playlist; public readonly BeatmapSetInfo BeatmapSetInfo; @@ -48,8 +50,9 @@ namespace osu.Game.Overlays.Music } } - public PlaylistItem(BeatmapSetInfo setInfo) + public PlaylistItem(FillFlowContainer playlist, BeatmapSetInfo setInfo) { + Playlist = playlist; BeatmapSetInfo = setInfo; RelativeSizeAxes = Axes.X; @@ -132,6 +135,44 @@ namespace osu.Game.Overlays.Music return true; } + protected override bool OnDragStart(InputState state) + { + return true; + } + + // Maybe render some ghost text + protected override bool OnDrag(InputState state) + { + return true; + } + + private int clamp(int value, int min, int max) + { + return (value <= min) ? min : (value >= max) ? max : value; + } + + protected override bool OnDragEnd(InputState state) + { + int src = (int) Depth; + int dst = clamp((int) ((state.Mouse.Position.Y - Parent.DrawPosition.Y) / Height), 0, Playlist.Count - 1); + + if (src == dst) + return true; + + if (src < dst) + { + for (int i = src + 1; i <= dst; i++) + Playlist.ChangeChildDepth(Playlist[i], i - 1); + } + else + { + for (int i = dst; i < src; i++) + Playlist.ChangeChildDepth(Playlist[i], i + 1); + } + Playlist.ChangeChildDepth(this, dst); + return true; + } + public string[] FilterTerms { get; private set; } private bool matching = true; diff --git a/osu.Game/Overlays/Music/PlaylistList.cs b/osu.Game/Overlays/Music/PlaylistList.cs index 3dd514edeb..3cbef8c22e 100644 --- a/osu.Game/Overlays/Music/PlaylistList.cs +++ b/osu.Game/Overlays/Music/PlaylistList.cs @@ -19,7 +19,7 @@ namespace osu.Game.Overlays.Music { set { - items.Children = value.Select(item => new PlaylistItem(item) { OnSelect = itemSelected }).ToList(); + items.Children = value.Select((item, index) => new PlaylistItem(items, item) { OnSelect = itemSelected, Depth = index }).ToList(); } } @@ -75,7 +75,7 @@ namespace osu.Game.Overlays.Music public void AddBeatmapSet(BeatmapSetInfo beatmapSet) { - items.Add(new PlaylistItem(beatmapSet) { OnSelect = itemSelected }); + items.Add(new PlaylistItem(items, beatmapSet) { OnSelect = itemSelected, Depth = items.Count }); } public void RemoveBeatmapSet(BeatmapSetInfo beatmapSet) @@ -96,6 +96,9 @@ namespace osu.Game.Overlays.Music } } + // Compare with reversed ChildID and Depth + protected override int Compare(Drawable x, Drawable y) => base.Compare(y, x); + public IEnumerable FilterableChildren => Children; public ItemSearchContainer() From 97ebf382883210c1828a276b9a2685c2f5e071f5 Mon Sep 17 00:00:00 2001 From: Kelvin <2yangk23@gmail.com> Date: Mon, 28 Aug 2017 00:56:03 -0700 Subject: [PATCH 02/47] Use PlaylistList to manage Prev/Next tracks --- osu.Game/Overlays/Music/PlaylistItem.cs | 2 +- osu.Game/Overlays/Music/PlaylistList.cs | 18 ++++++++++++++++++ osu.Game/Overlays/Music/PlaylistOverlay.cs | 16 ++++++++-------- 3 files changed, 27 insertions(+), 9 deletions(-) diff --git a/osu.Game/Overlays/Music/PlaylistItem.cs b/osu.Game/Overlays/Music/PlaylistItem.cs index 6c38755e72..f6ba78c897 100644 --- a/osu.Game/Overlays/Music/PlaylistItem.cs +++ b/osu.Game/Overlays/Music/PlaylistItem.cs @@ -29,8 +29,8 @@ namespace osu.Game.Overlays.Music private IEnumerable titleSprites; private UnicodeBindableString titleBind; private UnicodeBindableString artistBind; - private FillFlowContainer Playlist; + private readonly FillFlowContainer Playlist; public readonly BeatmapSetInfo BeatmapSetInfo; public Action OnSelect; diff --git a/osu.Game/Overlays/Music/PlaylistList.cs b/osu.Game/Overlays/Music/PlaylistList.cs index 3cbef8c22e..019049eb96 100644 --- a/osu.Game/Overlays/Music/PlaylistList.cs +++ b/osu.Game/Overlays/Music/PlaylistList.cs @@ -46,6 +46,24 @@ namespace osu.Game.Overlays.Music } } + public BeatmapSetInfo NextItem + { + get + { + var available = items.Children; + return (available.SkipWhile(i => !i.Selected).Skip(1).FirstOrDefault() ?? available.FirstOrDefault())?.BeatmapSetInfo; + } + } + + public BeatmapSetInfo PreviousItem + { + get + { + var available = items.Children.Reverse(); + return (available.SkipWhile(i => !i.Selected).Skip(1).FirstOrDefault() ?? available.FirstOrDefault())?.BeatmapSetInfo; + } + } + public PlaylistList() { Children = new Drawable[] diff --git a/osu.Game/Overlays/Music/PlaylistOverlay.cs b/osu.Game/Overlays/Music/PlaylistOverlay.cs index 83e92c5554..e987e7a5c1 100644 --- a/osu.Game/Overlays/Music/PlaylistOverlay.cs +++ b/osu.Game/Overlays/Music/PlaylistOverlay.cs @@ -126,24 +126,24 @@ namespace osu.Game.Overlays.Music public void PlayPrevious() { - var currentID = beatmapBacking.Value?.BeatmapSetInfo.ID ?? -1; - var available = BeatmapSets.Reverse(); - - var playable = available.SkipWhile(b => b.ID != currentID).Skip(1).FirstOrDefault() ?? available.FirstOrDefault(); + var playable = list.PreviousItem; if (playable != null) + { playSpecified(playable.Beatmaps[0]); + list.SelectedItem = playable; + } } public void PlayNext() { - var currentID = beatmapBacking.Value?.BeatmapSetInfo.ID ?? -1; - var available = BeatmapSets; - - var playable = available.SkipWhile(b => b.ID != currentID).Skip(1).FirstOrDefault() ?? available.FirstOrDefault(); + var playable = list.NextItem; if (playable != null) + { playSpecified(playable.Beatmaps[0]); + list.SelectedItem = playable; + } } private void playSpecified(BeatmapInfo info) From 2f5d8a7f884a365b0302f8f0d863146d1c1e34a9 Mon Sep 17 00:00:00 2001 From: Kelvin <2yangk23@gmail.com> Date: Mon, 28 Aug 2017 01:08:51 -0700 Subject: [PATCH 03/47] Fixed code style errors --- osu.Game/Overlays/Music/PlaylistItem.cs | 28 ++++++++++++------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/osu.Game/Overlays/Music/PlaylistItem.cs b/osu.Game/Overlays/Music/PlaylistItem.cs index f6ba78c897..85c8cd0c93 100644 --- a/osu.Game/Overlays/Music/PlaylistItem.cs +++ b/osu.Game/Overlays/Music/PlaylistItem.cs @@ -30,7 +30,7 @@ namespace osu.Game.Overlays.Music private UnicodeBindableString titleBind; private UnicodeBindableString artistBind; - private readonly FillFlowContainer Playlist; + private readonly FillFlowContainer playlist; public readonly BeatmapSetInfo BeatmapSetInfo; public Action OnSelect; @@ -52,7 +52,7 @@ namespace osu.Game.Overlays.Music public PlaylistItem(FillFlowContainer playlist, BeatmapSetInfo setInfo) { - Playlist = playlist; + this.playlist = playlist; BeatmapSetInfo = setInfo; RelativeSizeAxes = Axes.X; @@ -117,19 +117,19 @@ namespace osu.Game.Overlays.Music }); } - protected override bool OnHover(Framework.Input.InputState state) + protected override bool OnHover(InputState state) { handle.FadeIn(fade_duration); return base.OnHover(state); } - protected override void OnHoverLost(Framework.Input.InputState state) + protected override void OnHoverLost(InputState state) { handle.FadeOut(fade_duration); } - protected override bool OnClick(Framework.Input.InputState state) + protected override bool OnClick(InputState state) { OnSelect?.Invoke(BeatmapSetInfo); return true; @@ -146,15 +146,10 @@ namespace osu.Game.Overlays.Music return true; } - private int clamp(int value, int min, int max) - { - return (value <= min) ? min : (value >= max) ? max : value; - } - protected override bool OnDragEnd(InputState state) { int src = (int) Depth; - int dst = clamp((int) ((state.Mouse.Position.Y - Parent.DrawPosition.Y) / Height), 0, Playlist.Count - 1); + int dst = clamp((int) ((state.Mouse.Position.Y - Parent.DrawPosition.Y) / Height), 0, playlist.Count - 1); if (src == dst) return true; @@ -162,17 +157,22 @@ namespace osu.Game.Overlays.Music if (src < dst) { for (int i = src + 1; i <= dst; i++) - Playlist.ChangeChildDepth(Playlist[i], i - 1); + playlist.ChangeChildDepth(playlist[i], i - 1); } else { for (int i = dst; i < src; i++) - Playlist.ChangeChildDepth(Playlist[i], i + 1); + playlist.ChangeChildDepth(playlist[i], i + 1); } - Playlist.ChangeChildDepth(this, dst); + playlist.ChangeChildDepth(this, dst); return true; } + private int clamp(int value, int min, int max) + { + return value <= min ? min : value >= max ? max : value; + } + public string[] FilterTerms { get; private set; } private bool matching = true; From 12be5b417d58b0a02773888472a40eb2e90847f6 Mon Sep 17 00:00:00 2001 From: Kelvin <2yangk23@gmail.com> Date: Mon, 28 Aug 2017 22:51:26 -0700 Subject: [PATCH 04/47] Use MathHelper.Clamp - Fix formatting --- osu.Game/Overlays/Music/PlaylistItem.cs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/osu.Game/Overlays/Music/PlaylistItem.cs b/osu.Game/Overlays/Music/PlaylistItem.cs index 85c8cd0c93..a86cca117a 100644 --- a/osu.Game/Overlays/Music/PlaylistItem.cs +++ b/osu.Game/Overlays/Music/PlaylistItem.cs @@ -148,8 +148,8 @@ namespace osu.Game.Overlays.Music protected override bool OnDragEnd(InputState state) { - int src = (int) Depth; - int dst = clamp((int) ((state.Mouse.Position.Y - Parent.DrawPosition.Y) / Height), 0, playlist.Count - 1); + int src = (int)Depth; + int dst = MathHelper.Clamp((int)(state.Mouse.Position.Y / Height), 0, playlist.Count - 1); if (src == dst) return true; @@ -164,15 +164,11 @@ namespace osu.Game.Overlays.Music for (int i = dst; i < src; i++) playlist.ChangeChildDepth(playlist[i], i + 1); } + playlist.ChangeChildDepth(this, dst); return true; } - private int clamp(int value, int min, int max) - { - return value <= min ? min : value >= max ? max : value; - } - public string[] FilterTerms { get; private set; } private bool matching = true; From 636492b9cf8297347e416776a89868bbc43d5b0b Mon Sep 17 00:00:00 2001 From: Kelvin <2yangk23@gmail.com> Date: Mon, 28 Aug 2017 22:59:28 -0700 Subject: [PATCH 05/47] Rearrange tracks in OnDrag --- osu.Game/Overlays/Music/PlaylistItem.cs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/osu.Game/Overlays/Music/PlaylistItem.cs b/osu.Game/Overlays/Music/PlaylistItem.cs index a86cca117a..6c7e590a88 100644 --- a/osu.Game/Overlays/Music/PlaylistItem.cs +++ b/osu.Game/Overlays/Music/PlaylistItem.cs @@ -140,13 +140,7 @@ namespace osu.Game.Overlays.Music return true; } - // Maybe render some ghost text protected override bool OnDrag(InputState state) - { - return true; - } - - protected override bool OnDragEnd(InputState state) { int src = (int)Depth; int dst = MathHelper.Clamp((int)(state.Mouse.Position.Y / Height), 0, playlist.Count - 1); From 458c3a355fd0c6d20d656a68aaac7e73c5c9cd04 Mon Sep 17 00:00:00 2001 From: Kelvin <2yangk23@gmail.com> Date: Mon, 28 Aug 2017 23:28:58 -0700 Subject: [PATCH 06/47] Rearrange dragging using cheeseburger icon only --- osu.Game/Overlays/Music/PlaylistItem.cs | 77 ++++++++++++++----------- 1 file changed, 42 insertions(+), 35 deletions(-) diff --git a/osu.Game/Overlays/Music/PlaylistItem.cs b/osu.Game/Overlays/Music/PlaylistItem.cs index 6c7e590a88..876ad4f767 100644 --- a/osu.Game/Overlays/Music/PlaylistItem.cs +++ b/osu.Game/Overlays/Music/PlaylistItem.cs @@ -71,15 +71,9 @@ namespace osu.Game.Overlays.Music Children = new Drawable[] { - handle = new SpriteIcon + handle = new PlaylistItemHandle(playlist) { - Anchor = Anchor.TopLeft, - Origin = Anchor.TopLeft, - Size = new Vector2(12), Colour = colours.Gray5, - Icon = FontAwesome.fa_bars, - Alpha = 0f, - Margin = new MarginPadding { Left = 5, Top = 2 }, }, text = new OsuTextFlowContainer { @@ -135,34 +129,6 @@ namespace osu.Game.Overlays.Music return true; } - protected override bool OnDragStart(InputState state) - { - return true; - } - - protected override bool OnDrag(InputState state) - { - int src = (int)Depth; - int dst = MathHelper.Clamp((int)(state.Mouse.Position.Y / Height), 0, playlist.Count - 1); - - if (src == dst) - return true; - - if (src < dst) - { - for (int i = src + 1; i <= dst; i++) - playlist.ChangeChildDepth(playlist[i], i - 1); - } - else - { - for (int i = dst; i < src; i++) - playlist.ChangeChildDepth(playlist[i], i + 1); - } - - playlist.ChangeChildDepth(this, dst); - return true; - } - public string[] FilterTerms { get; private set; } private bool matching = true; @@ -179,5 +145,46 @@ namespace osu.Game.Overlays.Music this.FadeTo(matching ? 1 : 0, 200); } } + + private class PlaylistItemHandle : SpriteIcon + { + private readonly FillFlowContainer playlist; + + public PlaylistItemHandle(FillFlowContainer playlist) + { + this.playlist = playlist; + Anchor = Anchor.TopLeft; + Origin = Anchor.TopLeft; + Size = new Vector2(12); + Icon = FontAwesome.fa_bars; + Alpha = 0f; + Margin = new MarginPadding { Left = 5, Top = 2 }; + } + + protected override bool OnDragStart(InputState state) => true; + + protected override bool OnDrag(InputState state) + { + int src = (int)Parent.Depth; + int dst = MathHelper.Clamp((int)((state.Mouse.Position.Y + Parent.Position.Y) / Parent.Height), 0, playlist.Count - 1); + + if (src == dst) + return true; + + if (src < dst) + { + for (int i = src + 1; i <= dst; i++) + playlist.ChangeChildDepth(playlist[i], i - 1); + } + else + { + for (int i = dst; i < src; i++) + playlist.ChangeChildDepth(playlist[i], i + 1); + } + + playlist.ChangeChildDepth(Parent as PlaylistItem, dst); + return true; + } + } } } From 1eb31afd146305e5204d016a95f2ea43599737b9 Mon Sep 17 00:00:00 2001 From: Kelvin <2yangk23@gmail.com> Date: Tue, 29 Aug 2017 00:39:17 -0700 Subject: [PATCH 07/47] Get destination index using binarysearch --- osu.Game/Overlays/Music/PlaylistItem.cs | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Music/PlaylistItem.cs b/osu.Game/Overlays/Music/PlaylistItem.cs index 876ad4f767..941b858364 100644 --- a/osu.Game/Overlays/Music/PlaylistItem.cs +++ b/osu.Game/Overlays/Music/PlaylistItem.cs @@ -166,7 +166,7 @@ namespace osu.Game.Overlays.Music protected override bool OnDrag(InputState state) { int src = (int)Parent.Depth; - int dst = MathHelper.Clamp((int)((state.Mouse.Position.Y + Parent.Position.Y) / Parent.Height), 0, playlist.Count - 1); + int dst = getIndex(state.Mouse.Position.Y + Parent.Position.Y); if (src == dst) return true; @@ -185,6 +185,24 @@ namespace osu.Game.Overlays.Music playlist.ChangeChildDepth(Parent as PlaylistItem, dst); return true; } + + private int getIndex(float position) { + IReadOnlyList items = playlist.Children; + + // Binary Search without matching exact + int min = 0; + int max = items.Count - 1; + while (min <= max) + { + int m = (min + max) / 2; + if (items[m].Y < position) + min = m + 1; + else if (items[m].Y > position) + max = m - 1; + } + + return (int)items[min - 1].Depth; + } } } } From e5bf3f6a6af29f753b3b619293a8b9de6ff477c2 Mon Sep 17 00:00:00 2001 From: Kelvin <2yangk23@gmail.com> Date: Tue, 29 Aug 2017 00:46:11 -0700 Subject: [PATCH 08/47] Fix out of bounds --- osu.Game/Overlays/Music/PlaylistItem.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Music/PlaylistItem.cs b/osu.Game/Overlays/Music/PlaylistItem.cs index 941b858364..1491d7d0dd 100644 --- a/osu.Game/Overlays/Music/PlaylistItem.cs +++ b/osu.Game/Overlays/Music/PlaylistItem.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using OpenTK.Graphics; using osu.Framework.Allocation; using osu.Framework.Graphics; @@ -201,7 +202,7 @@ namespace osu.Game.Overlays.Music max = m - 1; } - return (int)items[min - 1].Depth; + return (int)items[Math.Max(0, min - 1)].Depth; } } } From 0e363fce1e05118e929e3d598f10fef75f0c1ce3 Mon Sep 17 00:00:00 2001 From: Kelvin <2yangk23@gmail.com> Date: Tue, 29 Aug 2017 22:25:04 -0700 Subject: [PATCH 09/47] Try to fix stuttering behavior --- osu.Game/Overlays/Music/PlaylistItem.cs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Music/PlaylistItem.cs b/osu.Game/Overlays/Music/PlaylistItem.cs index 1491d7d0dd..9df15bfd04 100644 --- a/osu.Game/Overlays/Music/PlaylistItem.cs +++ b/osu.Game/Overlays/Music/PlaylistItem.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using OpenTK.Graphics; using osu.Framework.Allocation; using osu.Framework.Graphics; @@ -151,6 +150,9 @@ namespace osu.Game.Overlays.Music { private readonly FillFlowContainer playlist; + private const int line_height = 22; + private const int rearrange_buffer = 3; + public PlaylistItemHandle(FillFlowContainer playlist) { this.playlist = playlist; @@ -202,7 +204,12 @@ namespace osu.Game.Overlays.Music max = m - 1; } - return (int)items[Math.Max(0, min - 1)].Depth; + int index = Math.Max(0, min - 1); + // Only move if mouse falls within buffer + if (position - items[index].Y > rearrange_buffer && position - items[index].Y < line_height - rearrange_buffer) { + return (int)items[index].Depth; + } + return (int)Parent.Depth; } } } From 07da29ea1ce6e4c4fb6551f16efcbcf002fdfcd0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 30 Aug 2017 20:41:41 +0900 Subject: [PATCH 10/47] Add context menu to beatmap set header --- osu.Game/Beatmaps/Drawables/BeatmapGroup.cs | 3 +++ .../Beatmaps/Drawables/BeatmapSetHeader.cs | 23 ++++++++++++++++++- osu.Game/Screens/Select/BeatmapCarousel.cs | 3 +++ osu.Game/Screens/Select/SongSelect.cs | 14 +++++++---- 4 files changed, 37 insertions(+), 6 deletions(-) diff --git a/osu.Game/Beatmaps/Drawables/BeatmapGroup.cs b/osu.Game/Beatmaps/Drawables/BeatmapGroup.cs index ad9a0a787b..dc68c9a49e 100644 --- a/osu.Game/Beatmaps/Drawables/BeatmapGroup.cs +++ b/osu.Game/Beatmaps/Drawables/BeatmapGroup.cs @@ -23,6 +23,8 @@ namespace osu.Game.Beatmaps.Drawables /// public Action StartRequested; + public Action DeleteRequested; + public BeatmapSetHeader Header; private BeatmapGroupState state; @@ -66,6 +68,7 @@ namespace osu.Game.Beatmaps.Drawables Header = new BeatmapSetHeader(beatmap) { GainedSelection = headerGainedSelection, + DeleteRequested = b => DeleteRequested(b), RelativeSizeAxes = Axes.X, }; diff --git a/osu.Game/Beatmaps/Drawables/BeatmapSetHeader.cs b/osu.Game/Beatmaps/Drawables/BeatmapSetHeader.cs index a2457ba78e..6510f92547 100644 --- a/osu.Game/Beatmaps/Drawables/BeatmapSetHeader.cs +++ b/osu.Game/Beatmaps/Drawables/BeatmapSetHeader.cs @@ -9,16 +9,22 @@ using osu.Framework.Allocation; 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; +using osu.Framework.Graphics.UserInterface; +using osu.Game.Graphics.UserInterface; namespace osu.Game.Beatmaps.Drawables { - public class BeatmapSetHeader : Panel + public class BeatmapSetHeader : Panel, IHasContextMenu { public Action GainedSelection; + + public Action DeleteRequested; + private readonly SpriteText title; private readonly SpriteText artist; @@ -148,5 +154,20 @@ namespace osu.Game.Beatmaps.Drawables foreach (var p in panels) difficultyIcons.Add(new DifficultyIcon(p.Beatmap)); } + + public MenuItem[] ContextMenuItems + { + get + { + List items = new List(); + + if (State == PanelSelectedState.NotSelected) + items.Add(new OsuMenuItem("Expand", MenuItemType.Highlighted, () => State = PanelSelectedState.Selected)); + + items.Add(new OsuMenuItem("Delete", MenuItemType.Destructive, () => DeleteRequested?.Invoke(beatmap))); + + return items.ToArray(); + } + } } } \ No newline at end of file diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index 264636b258..448f5395b6 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -140,6 +140,8 @@ namespace osu.Game.Screens.Select public Action StartRequested; + public Action DeleteRequested; + public void SelectNext(int direction = 1, bool skipDifficulties = true) { if (groups.All(g => g.State == BeatmapGroupState.Hidden)) @@ -305,6 +307,7 @@ namespace osu.Game.Screens.Select { SelectionChanged = (g, p) => selectGroup(g, p), StartRequested = b => StartRequested?.Invoke(), + DeleteRequested = b => DeleteRequested?.Invoke(b), State = BeatmapGroupState.Collapsed }; } diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 6c149c3f30..4eb6da4f88 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -106,6 +106,7 @@ namespace osu.Game.Screens.Select Origin = Anchor.CentreRight, SelectionChanged = carouselSelectionChanged, BeatmapsChanged = carouselBeatmapsLoaded, + DeleteRequested = b => promptDelete(b), StartRequested = () => carouselRaisedStart(), }); Add(FilterControl = new FilterControl @@ -163,7 +164,7 @@ namespace osu.Game.Screens.Select Footer.AddButton(@"random", colours.Green, triggerRandom, Key.F2); Footer.AddButton(@"options", colours.Blue, BeatmapOptions.ToggleVisibility, Key.F3); - BeatmapOptions.AddButton(@"Delete", @"Beatmap", FontAwesome.fa_trash, colours.Pink, promptDelete, Key.Number4, float.MaxValue); + BeatmapOptions.AddButton(@"Delete", @"Beatmap", FontAwesome.fa_trash, colours.Pink, () => promptDelete(Beatmap), Key.Number4, float.MaxValue); } if (manager == null) @@ -389,10 +390,12 @@ namespace osu.Game.Screens.Select Beatmap.SetDefault(); } - private void promptDelete() + private void promptDelete(WorkingBeatmap beatmap) { - if (Beatmap != null && !Beatmap.IsDefault) - dialogOverlay?.Push(new BeatmapDeleteDialog(Beatmap)); + if (beatmap == null) + return; + + dialogOverlay?.Push(new BeatmapDeleteDialog(beatmap)); } protected override bool OnKeyDown(InputState state, KeyDownEventArgs args) @@ -408,7 +411,8 @@ namespace osu.Game.Screens.Select case Key.Delete: if (state.Keyboard.ShiftPressed) { - promptDelete(); + if (!Beatmap.IsDefault) + promptDelete(Beatmap); return true; } break; From 8619f28ced14952e50aa9a1f96adb60ae5734f05 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 30 Aug 2017 20:41:53 +0900 Subject: [PATCH 11/47] Add context menu to beatmap difficulty (wip) --- osu.Game/Beatmaps/Drawables/BeatmapPanel.cs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/osu.Game/Beatmaps/Drawables/BeatmapPanel.cs b/osu.Game/Beatmaps/Drawables/BeatmapPanel.cs index 429ecaf416..f963931c7c 100644 --- a/osu.Game/Beatmaps/Drawables/BeatmapPanel.cs +++ b/osu.Game/Beatmaps/Drawables/BeatmapPanel.cs @@ -5,6 +5,7 @@ using System; 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.Game.Graphics; using osu.Game.Graphics.Backgrounds; @@ -14,16 +15,19 @@ using OpenTK.Graphics; using osu.Framework.Input; using osu.Game.Graphics.Sprites; using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.UserInterface; namespace osu.Game.Beatmaps.Drawables { - public class BeatmapPanel : Panel + public class BeatmapPanel : Panel, IHasContextMenu { public BeatmapInfo Beatmap; private readonly Sprite background; public Action GainedSelection; public Action StartRequested; + public Action DeleteRequested; + private readonly Triangles triangles; private readonly StarCounter starCounter; @@ -148,5 +152,12 @@ namespace osu.Game.Beatmaps.Drawables } }; } + + public MenuItem[] ContextMenuItems => new MenuItem[] + { + new OsuMenuItem("Play", MenuItemType.Highlighted), + new OsuMenuItem("Edit"), + new OsuMenuItem("Delete", MenuItemType.Destructive), + }; } } From 2fb4126ffc07eb84c9428009f8a8917f25313655 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 30 Aug 2017 20:53:33 +0900 Subject: [PATCH 12/47] Use BeatmapSetInfo instead of WorkingBeatmap --- osu.Game/Beatmaps/Drawables/BeatmapGroup.cs | 2 +- osu.Game/Beatmaps/Drawables/BeatmapPanel.cs | 2 +- osu.Game/Beatmaps/Drawables/BeatmapSetHeader.cs | 4 ++-- osu.Game/Screens/Select/SongSelect.cs | 7 ++++--- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/osu.Game/Beatmaps/Drawables/BeatmapGroup.cs b/osu.Game/Beatmaps/Drawables/BeatmapGroup.cs index dc68c9a49e..a4c7da71d8 100644 --- a/osu.Game/Beatmaps/Drawables/BeatmapGroup.cs +++ b/osu.Game/Beatmaps/Drawables/BeatmapGroup.cs @@ -23,7 +23,7 @@ namespace osu.Game.Beatmaps.Drawables /// public Action StartRequested; - public Action DeleteRequested; + public Action DeleteRequested; public BeatmapSetHeader Header; diff --git a/osu.Game/Beatmaps/Drawables/BeatmapPanel.cs b/osu.Game/Beatmaps/Drawables/BeatmapPanel.cs index f963931c7c..235c98b43c 100644 --- a/osu.Game/Beatmaps/Drawables/BeatmapPanel.cs +++ b/osu.Game/Beatmaps/Drawables/BeatmapPanel.cs @@ -157,7 +157,7 @@ namespace osu.Game.Beatmaps.Drawables { new OsuMenuItem("Play", MenuItemType.Highlighted), new OsuMenuItem("Edit"), - new OsuMenuItem("Delete", MenuItemType.Destructive), + new OsuMenuItem("Delete", MenuItemType.Destructive, () => DeleteRequested?.Invoke(Beatmap)), }; } } diff --git a/osu.Game/Beatmaps/Drawables/BeatmapSetHeader.cs b/osu.Game/Beatmaps/Drawables/BeatmapSetHeader.cs index 6510f92547..b475a23ffd 100644 --- a/osu.Game/Beatmaps/Drawables/BeatmapSetHeader.cs +++ b/osu.Game/Beatmaps/Drawables/BeatmapSetHeader.cs @@ -23,7 +23,7 @@ namespace osu.Game.Beatmaps.Drawables { public Action GainedSelection; - public Action DeleteRequested; + public Action DeleteRequested; private readonly SpriteText title; private readonly SpriteText artist; @@ -164,7 +164,7 @@ namespace osu.Game.Beatmaps.Drawables if (State == PanelSelectedState.NotSelected) items.Add(new OsuMenuItem("Expand", MenuItemType.Highlighted, () => State = PanelSelectedState.Selected)); - items.Add(new OsuMenuItem("Delete", MenuItemType.Destructive, () => DeleteRequested?.Invoke(beatmap))); + items.Add(new OsuMenuItem("Delete", MenuItemType.Destructive, () => DeleteRequested?.Invoke(beatmap.BeatmapSetInfo))); return items.ToArray(); } diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 4eb6da4f88..6cd47aa9f6 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -249,7 +249,8 @@ namespace osu.Game.Screens.Select if (beatmap == null) { - performLoad(); + if (!Beatmap.IsDefault) + performLoad(); } else { @@ -390,7 +391,7 @@ namespace osu.Game.Screens.Select Beatmap.SetDefault(); } - private void promptDelete(WorkingBeatmap beatmap) + private void promptDelete(BeatmapSetInfo beatmap) { if (beatmap == null) return; @@ -412,7 +413,7 @@ namespace osu.Game.Screens.Select if (state.Keyboard.ShiftPressed) { if (!Beatmap.IsDefault) - promptDelete(Beatmap); + promptDelete(Beatmap.Value.BeatmapSetInfo); return true; } break; From 3b4b4b669bb88d4f3a35d54542399499a771fec9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 30 Aug 2017 21:12:46 +0900 Subject: [PATCH 13/47] Add framework for deleting difficulties --- osu.Game/Beatmaps/BeatmapManager.cs | 12 +++++++++- osu.Game/Beatmaps/Drawables/BeatmapGroup.cs | 3 +++ osu.Game/Screens/Select/BeatmapCarousel.cs | 5 +++- .../Screens/Select/BeatmapDeleteDialog.cs | 23 ++++++++++++------- osu.Game/Screens/Select/SongSelect.cs | 11 ++++++++- 5 files changed, 43 insertions(+), 11 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 1dcab6cb5d..c52576fb9f 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -170,7 +170,7 @@ namespace osu.Game.Beatmaps /// Delete a beatmap from the manager. /// Is a no-op for already deleted beatmaps. /// - /// The beatmap to delete. + /// The beatmap set to delete. public void Delete(BeatmapSetInfo beatmapSet) { lock (beatmaps) @@ -180,6 +180,16 @@ namespace osu.Game.Beatmaps files.Dereference(beatmapSet.Files.Select(f => f.FileInfo).ToArray()); } + /// + /// Delete a beatmap from the manager. + /// Is a no-op for already deleted beatmaps. + /// + /// The beatmap difficulty to delete. + public void Delete(BeatmapInfo beatmap) + { + //todo: implement + } + /// /// Returns a to a usable state if it has previously been deleted but not yet purged. /// Is a no-op for already usable beatmaps. diff --git a/osu.Game/Beatmaps/Drawables/BeatmapGroup.cs b/osu.Game/Beatmaps/Drawables/BeatmapGroup.cs index a4c7da71d8..b47210620d 100644 --- a/osu.Game/Beatmaps/Drawables/BeatmapGroup.cs +++ b/osu.Game/Beatmaps/Drawables/BeatmapGroup.cs @@ -25,6 +25,8 @@ namespace osu.Game.Beatmaps.Drawables public Action DeleteRequested; + public Action DeleteDifficultyRequested; + public BeatmapSetHeader Header; private BeatmapGroupState state; @@ -77,6 +79,7 @@ namespace osu.Game.Beatmaps.Drawables { Alpha = 0, GainedSelection = panelGainedSelection, + DeleteRequested = p => DeleteDifficultyRequested?.Invoke(p), StartRequested = p => { StartRequested?.Invoke(p.Beatmap); }, RelativeSizeAxes = Axes.X, }).ToList(); diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index 448f5395b6..a1c7f64188 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -140,7 +140,9 @@ namespace osu.Game.Screens.Select public Action StartRequested; - public Action DeleteRequested; + public Action DeleteRequested; + + public Action DeleteDifficultyRequested; public void SelectNext(int direction = 1, bool skipDifficulties = true) { @@ -308,6 +310,7 @@ namespace osu.Game.Screens.Select SelectionChanged = (g, p) => selectGroup(g, p), StartRequested = b => StartRequested?.Invoke(), DeleteRequested = b => DeleteRequested?.Invoke(b), + DeleteDifficultyRequested = b => DeleteDifficultyRequested?.Invoke(b), State = BeatmapGroupState.Collapsed }; } diff --git a/osu.Game/Screens/Select/BeatmapDeleteDialog.cs b/osu.Game/Screens/Select/BeatmapDeleteDialog.cs index 96caf2f236..15ec84a7d8 100644 --- a/osu.Game/Screens/Select/BeatmapDeleteDialog.cs +++ b/osu.Game/Screens/Select/BeatmapDeleteDialog.cs @@ -13,29 +13,36 @@ namespace osu.Game.Screens.Select { private BeatmapManager manager; + private readonly Action deleteAction; + [BackgroundDependencyLoader] private void load(BeatmapManager beatmapManager) { manager = beatmapManager; } - public BeatmapDeleteDialog(WorkingBeatmap beatmap) + public BeatmapDeleteDialog(BeatmapSetInfo beatmap) : this() { - if (beatmap == null) throw new ArgumentNullException(nameof(beatmap)); + BodyText = $@"{beatmap.Metadata?.Artist} - {beatmap.Metadata?.Title} (ALL DIFFICULTIES)"; + deleteAction = () => manager.Delete(beatmap); + } + public BeatmapDeleteDialog(BeatmapInfo beatmap) : this() + { + BodyText = $@"{beatmap.Metadata?.Artist} - {beatmap.Metadata?.Title} [{beatmap.Version}]"; + deleteAction = () => manager.Delete(beatmap); + } + + public BeatmapDeleteDialog() + { Icon = FontAwesome.fa_trash_o; HeaderText = @"Confirm deletion of"; - BodyText = $@"{beatmap.Metadata?.Artist} - {beatmap.Metadata?.Title}"; Buttons = new PopupDialogButton[] { new PopupDialogOkButton { Text = @"Yes. Totally. Delete it.", - Action = () => - { - beatmap.Dispose(); - manager.Delete(beatmap.BeatmapSetInfo); - }, + Action = () => deleteAction(), }, new PopupDialogCancelButton { diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 6cd47aa9f6..b3ee33e7c6 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -107,6 +107,7 @@ namespace osu.Game.Screens.Select SelectionChanged = carouselSelectionChanged, BeatmapsChanged = carouselBeatmapsLoaded, DeleteRequested = b => promptDelete(b), + DeleteDifficultyRequested = b => promptDelete(b), StartRequested = () => carouselRaisedStart(), }); Add(FilterControl = new FilterControl @@ -164,7 +165,7 @@ namespace osu.Game.Screens.Select Footer.AddButton(@"random", colours.Green, triggerRandom, Key.F2); Footer.AddButton(@"options", colours.Blue, BeatmapOptions.ToggleVisibility, Key.F3); - BeatmapOptions.AddButton(@"Delete", @"Beatmap", FontAwesome.fa_trash, colours.Pink, () => promptDelete(Beatmap), Key.Number4, float.MaxValue); + BeatmapOptions.AddButton(@"Delete", @"Beatmap", FontAwesome.fa_trash, colours.Pink, () => promptDelete(Beatmap.Value.BeatmapSetInfo), Key.Number4, float.MaxValue); } if (manager == null) @@ -399,6 +400,14 @@ namespace osu.Game.Screens.Select dialogOverlay?.Push(new BeatmapDeleteDialog(beatmap)); } + private void promptDelete(BeatmapInfo beatmap) + { + if (beatmap == null) + return; + + dialogOverlay?.Push(new BeatmapDeleteDialog(beatmap)); + } + protected override bool OnKeyDown(InputState state, KeyDownEventArgs args) { if (args.Repeat) return false; From 5a58489adf72eacb03c182b419381d24a6c2a954 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 30 Aug 2017 21:12:58 +0900 Subject: [PATCH 14/47] Hook up play and edit (kinda) --- osu.Game/Beatmaps/Drawables/BeatmapPanel.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/osu.Game/Beatmaps/Drawables/BeatmapPanel.cs b/osu.Game/Beatmaps/Drawables/BeatmapPanel.cs index 235c98b43c..1006380a2b 100644 --- a/osu.Game/Beatmaps/Drawables/BeatmapPanel.cs +++ b/osu.Game/Beatmaps/Drawables/BeatmapPanel.cs @@ -26,6 +26,7 @@ namespace osu.Game.Beatmaps.Drawables public Action GainedSelection; public Action StartRequested; + public Action EditRequested; public Action DeleteRequested; private readonly Triangles triangles; @@ -155,8 +156,8 @@ namespace osu.Game.Beatmaps.Drawables public MenuItem[] ContextMenuItems => new MenuItem[] { - new OsuMenuItem("Play", MenuItemType.Highlighted), - new OsuMenuItem("Edit"), + new OsuMenuItem("Play", MenuItemType.Highlighted, () => StartRequested?.Invoke(this)), + new OsuMenuItem("Edit", MenuItemType.Standard, () => EditRequested?.Invoke(this)), new OsuMenuItem("Delete", MenuItemType.Destructive, () => DeleteRequested?.Invoke(Beatmap)), }; } From d252af8ab45f4048525da834bbc6f2450b3b5454 Mon Sep 17 00:00:00 2001 From: Akash Mozumdar Date: Thu, 31 Aug 2017 02:36:25 -0400 Subject: [PATCH 15/47] basic implementation of hp --- .../Scoring/OsuScoreProcessor.cs | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs b/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs index 856ca0c98d..df97e06118 100644 --- a/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs +++ b/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs @@ -27,7 +27,7 @@ namespace osu.Game.Rulesets.Osu.Scoring { base.Reset(); - Health.Value = 1; + Health.Value = 0.5; Accuracy.Value = 1; scoreResultCounts.Clear(); @@ -56,13 +56,21 @@ namespace osu.Game.Rulesets.Osu.Scoring scoreResultCounts[judgement.Score] = scoreResultCounts.GetOrDefault(judgement.Score) + 1; comboResultCounts[judgement.Combo] = comboResultCounts.GetOrDefault(judgement.Combo) + 1; } - - switch (judgement.Result) + switch (judgement.Score) { - case HitResult.Hit: - Health.Value += 0.1f; + case OsuScoreResult.Hit300: + Health.Value += 0.01f; break; - case HitResult.Miss: + + case OsuScoreResult.Hit100: + Health.Value -= 0.01f; + break; + + case OsuScoreResult.Hit50: + Health.Value -= 0.05f; + break; + + case OsuScoreResult.Miss: Health.Value -= 0.2f; break; } From cbc35e0cf3040caff865a33b5a64c3e018951b0d Mon Sep 17 00:00:00 2001 From: Akash Mozumdar Date: Thu, 31 Aug 2017 04:31:48 -0400 Subject: [PATCH 16/47] implemented hp --- .../Scoring/OsuScoreProcessor.cs | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs b/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs index df97e06118..3a06ef2260 100644 --- a/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs +++ b/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs @@ -23,6 +23,14 @@ namespace osu.Game.Rulesets.Osu.Scoring { } + + float beatmapHp = 0; + + protected override void ComputeTargets(Game.Beatmaps.Beatmap beatmap) + { + beatmapHp = beatmap.BeatmapInfo.Difficulty.DrainRate; + } + protected override void Reset() { base.Reset(); @@ -59,19 +67,19 @@ namespace osu.Game.Rulesets.Osu.Scoring switch (judgement.Score) { case OsuScoreResult.Hit300: - Health.Value += 0.01f; + Health.Value += (10.2 - beatmapHp) * 0.02; break; case OsuScoreResult.Hit100: - Health.Value -= 0.01f; + Health.Value += (8 - beatmapHp) * 0.02; break; case OsuScoreResult.Hit50: - Health.Value -= 0.05f; + Health.Value += (4 - beatmapHp) * 0.02; break; case OsuScoreResult.Miss: - Health.Value -= 0.2f; + Health.Value -= beatmapHp * 0.04; break; } } From af2f45a98058f175b52b89703478c10cd0fb8d34 Mon Sep 17 00:00:00 2001 From: Akash Mozumdar Date: Thu, 31 Aug 2017 04:44:00 -0400 Subject: [PATCH 17/47] slight edits --- osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs b/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs index 3a06ef2260..a0662ab51d 100644 --- a/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs +++ b/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs @@ -24,7 +24,7 @@ namespace osu.Game.Rulesets.Osu.Scoring } - float beatmapHp = 0; + float beatmapHp; protected override void ComputeTargets(Game.Beatmaps.Beatmap beatmap) { @@ -78,6 +78,10 @@ namespace osu.Game.Rulesets.Osu.Scoring Health.Value += (4 - beatmapHp) * 0.02; break; + case OsuScoreResult.SliderTick: + Health.Value += System.Math.Max(7 - beatmapHp, 0) * 0.01; + break; + case OsuScoreResult.Miss: Health.Value -= beatmapHp * 0.04; break; From 04596fee6122886b6488b0dc547b0a65bde61350 Mon Sep 17 00:00:00 2001 From: Akash Mozumdar Date: Thu, 31 Aug 2017 08:26:06 -0400 Subject: [PATCH 18/47] Update OsuScoreProcessor.cs --- osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs b/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs index a0662ab51d..7760e773d3 100644 --- a/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs +++ b/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs @@ -35,7 +35,7 @@ namespace osu.Game.Rulesets.Osu.Scoring { base.Reset(); - Health.Value = 0.5; + Health.Value = 1; Accuracy.Value = 1; scoreResultCounts.Clear(); From 472710e5db861b3065bbcc7554ad92eb4d1371e4 Mon Sep 17 00:00:00 2001 From: Akash Mozumdar Date: Thu, 31 Aug 2017 21:35:30 -0400 Subject: [PATCH 19/47] trim whitespace --- osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs b/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs index a0662ab51d..a079eb4c80 100644 --- a/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs +++ b/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs @@ -23,7 +23,6 @@ namespace osu.Game.Rulesets.Osu.Scoring { } - float beatmapHp; protected override void ComputeTargets(Game.Beatmaps.Beatmap beatmap) From 1f646e6d548a988fba0fbc102a09e02574a35c85 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 31 Aug 2017 15:49:56 +0900 Subject: [PATCH 20/47] Add hiding support for beatmap difficulties --- osu-framework | 2 +- osu.Game/Beatmaps/BeatmapInfo.cs | 2 + osu.Game/Beatmaps/BeatmapManager.cs | 57 ++++++++++++------- osu.Game/Beatmaps/BeatmapStore.cs | 43 +++++++++++++- osu.Game/Beatmaps/Drawables/BeatmapGroup.cs | 5 +- osu.Game/Beatmaps/Drawables/BeatmapPanel.cs | 2 +- .../Beatmaps/Drawables/BeatmapSetHeader.cs | 6 ++ osu.Game/Screens/Select/BeatmapCarousel.cs | 38 +++++++++++-- .../Screens/Select/BeatmapDeleteDialog.cs | 19 +------ osu.Game/Screens/Select/SongSelect.cs | 21 +++---- 10 files changed, 136 insertions(+), 59 deletions(-) diff --git a/osu-framework b/osu-framework index 167d5cda8f..2804e052ca 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit 167d5cda8f3ddae702ffc8d8d22dac67e48b509c +Subproject commit 2804e052ca2ce068f015771d28170d18573687e1 diff --git a/osu.Game/Beatmaps/BeatmapInfo.cs b/osu.Game/Beatmaps/BeatmapInfo.cs index ebf77bf9df..c962201fe3 100644 --- a/osu.Game/Beatmaps/BeatmapInfo.cs +++ b/osu.Game/Beatmaps/BeatmapInfo.cs @@ -52,6 +52,8 @@ namespace osu.Game.Beatmaps [JsonProperty("file_sha2")] public string Hash { get; set; } + public bool Hidden { get; set; } + /// /// MD5 is kept for legacy support (matching against replays, osu-web-10 etc.). /// diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index c52576fb9f..551612330b 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -33,11 +33,21 @@ namespace osu.Game.Beatmaps /// public event Action BeatmapSetAdded; + /// + /// Fired when a single difficulty has been hidden. + /// + public event Action BeatmapHidden; + /// /// Fired when a is removed from the database. /// public event Action BeatmapSetRemoved; + /// + /// Fired when a single difficulty has been restored. + /// + public event Action BeatmapRestored; + /// /// A default representation of a WorkingBeatmap to use when no beatmap is available. /// @@ -71,6 +81,8 @@ namespace osu.Game.Beatmaps beatmaps = new BeatmapStore(connection); beatmaps.BeatmapSetAdded += s => BeatmapSetAdded?.Invoke(s); beatmaps.BeatmapSetRemoved += s => BeatmapSetRemoved?.Invoke(s); + beatmaps.BeatmapHidden += b => BeatmapHidden?.Invoke(b); + beatmaps.BeatmapRestored += b => BeatmapRestored?.Invoke(b); this.storage = storage; this.files = files; @@ -162,8 +174,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); } /// @@ -173,22 +184,23 @@ 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()); } /// - /// Delete a beatmap from the manager. - /// Is a no-op for already deleted beatmaps. + /// Delete a beatmap difficulty. /// - /// The beatmap difficulty to delete. - public void Delete(BeatmapInfo beatmap) - { - //todo: implement - } + /// The beatmap difficulty to hide. + public void Hide(BeatmapInfo beatmap) => beatmaps.Hide(beatmap); + + /// + /// Restore a beatmap difficulty. + /// + /// The beatmap difficulty to restore. + public void Restore(BeatmapInfo beatmap) => beatmaps.Restore(beatmap); /// /// Returns a to a usable state if it has previously been deleted but not yet purged. @@ -197,8 +209,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()); @@ -258,6 +269,13 @@ namespace osu.Game.Beatmaps } } + /// + /// Refresh an existing instance of a from the store. + /// + /// A stale instance. + /// A fresh instance. + public BeatmapSetInfo Refresh(BeatmapSetInfo beatmapSet) => QueryBeatmapSet(s => s.ID == beatmapSet.ID); + /// /// Perform a lookup query on available s. /// @@ -265,7 +283,7 @@ namespace osu.Game.Beatmaps /// Results from the provided query. public List QueryBeatmapSets(Expression> query) { - lock (beatmaps) return beatmaps.QueryAndPopulate(query); + return beatmaps.QueryAndPopulate(query); } /// @@ -275,15 +293,12 @@ 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().FirstOrDefault(query); + BeatmapInfo set = beatmaps.Query().FirstOrDefault(query); - if (set != null) - beatmaps.Populate(set); + if (set != null) + beatmaps.Populate(set); - return set; - } + return set; } /// diff --git a/osu.Game/Beatmaps/BeatmapStore.cs b/osu.Game/Beatmaps/BeatmapStore.cs index 8212712bf9..0f2d8cffa6 100644 --- a/osu.Game/Beatmaps/BeatmapStore.cs +++ b/osu.Game/Beatmaps/BeatmapStore.cs @@ -16,11 +16,14 @@ namespace osu.Game.Beatmaps public event Action BeatmapSetAdded; public event Action BeatmapSetRemoved; + 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 => 3; + protected override int StoreVersion => 4; public BeatmapStore(SQLiteConnection connection) : base(connection) @@ -81,6 +84,10 @@ namespace osu.Game.Beatmaps // Added MD5Hash column to BeatmapInfo Connection.MigrateTable(); break; + case 4: + // Added Hidden column to BeatmapInfo + Connection.MigrateTable(); + break; } } } @@ -100,7 +107,7 @@ namespace osu.Game.Beatmaps } /// - /// Delete a to the database. + /// Delete a from the database. /// /// The beatmap to delete. /// Whether the beatmap's was changed. @@ -131,6 +138,38 @@ namespace osu.Game.Beatmaps return true; } + /// + /// Hide a in the database. + /// + /// The beatmap to hide. + /// Whether the beatmap's was changed. + public bool Hide(BeatmapInfo beatmap) + { + if (beatmap.Hidden) return false; + + beatmap.Hidden = true; + Connection.Update(beatmap); + + BeatmapHidden?.Invoke(beatmap); + return true; + } + + /// + /// Restore a previously hidden . + /// + /// The beatmap to restore. + /// Whether the beatmap's was changed. + public bool Restore(BeatmapInfo beatmap) + { + if (!beatmap.Hidden) return false; + + beatmap.Hidden = false; + Connection.Update(beatmap); + + BeatmapRestored?.Invoke(beatmap); + return true; + } + private void cleanupPendingDeletions() { Connection.RunInTransaction(() => diff --git a/osu.Game/Beatmaps/Drawables/BeatmapGroup.cs b/osu.Game/Beatmaps/Drawables/BeatmapGroup.cs index b47210620d..19dfc22506 100644 --- a/osu.Game/Beatmaps/Drawables/BeatmapGroup.cs +++ b/osu.Game/Beatmaps/Drawables/BeatmapGroup.cs @@ -25,6 +25,8 @@ namespace osu.Game.Beatmaps.Drawables public Action DeleteRequested; + public Action RestoreHiddenRequested; + public Action DeleteDifficultyRequested; public BeatmapSetHeader Header; @@ -71,10 +73,11 @@ namespace osu.Game.Beatmaps.Drawables { GainedSelection = headerGainedSelection, DeleteRequested = b => DeleteRequested(b), + RestoreHiddenRequested = b => RestoreHiddenRequested(b), RelativeSizeAxes = Axes.X, }; - BeatmapSet.Beatmaps = BeatmapSet.Beatmaps.OrderBy(b => b.StarDifficulty).ToList(); + BeatmapSet.Beatmaps = BeatmapSet.Beatmaps.Where(b => !b.Hidden).OrderBy(b => b.StarDifficulty).ToList(); BeatmapPanels = BeatmapSet.Beatmaps.Select(b => new BeatmapPanel(b) { Alpha = 0, diff --git a/osu.Game/Beatmaps/Drawables/BeatmapPanel.cs b/osu.Game/Beatmaps/Drawables/BeatmapPanel.cs index 1006380a2b..6b17b3bb8b 100644 --- a/osu.Game/Beatmaps/Drawables/BeatmapPanel.cs +++ b/osu.Game/Beatmaps/Drawables/BeatmapPanel.cs @@ -158,7 +158,7 @@ namespace osu.Game.Beatmaps.Drawables { new OsuMenuItem("Play", MenuItemType.Highlighted, () => StartRequested?.Invoke(this)), new OsuMenuItem("Edit", MenuItemType.Standard, () => EditRequested?.Invoke(this)), - new OsuMenuItem("Delete", MenuItemType.Destructive, () => DeleteRequested?.Invoke(Beatmap)), + new OsuMenuItem("Hide", MenuItemType.Destructive, () => DeleteRequested?.Invoke(Beatmap)), }; } } diff --git a/osu.Game/Beatmaps/Drawables/BeatmapSetHeader.cs b/osu.Game/Beatmaps/Drawables/BeatmapSetHeader.cs index b475a23ffd..ee75b77747 100644 --- a/osu.Game/Beatmaps/Drawables/BeatmapSetHeader.cs +++ b/osu.Game/Beatmaps/Drawables/BeatmapSetHeader.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Linq; using OpenTK; using OpenTK.Graphics; using osu.Framework.Allocation; @@ -25,6 +26,8 @@ namespace osu.Game.Beatmaps.Drawables public Action DeleteRequested; + public Action RestoreHiddenRequested; + private readonly SpriteText title; private readonly SpriteText artist; @@ -164,6 +167,9 @@ namespace osu.Game.Beatmaps.Drawables if (State == PanelSelectedState.NotSelected) items.Add(new OsuMenuItem("Expand", MenuItemType.Highlighted, () => State = PanelSelectedState.Selected)); + if (beatmap.BeatmapSetInfo.Beatmaps.Any(b => b.Hidden)) + items.Add(new OsuMenuItem("Restore all hidden", MenuItemType.Standard, () => RestoreHiddenRequested?.Invoke(beatmap.BeatmapSetInfo))); + items.Add(new OsuMenuItem("Delete", MenuItemType.Destructive, () => DeleteRequested?.Invoke(beatmap.BeatmapSetInfo))); return items.ToArray(); diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index a1c7f64188..5d495a61f0 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -107,12 +107,39 @@ namespace osu.Game.Screens.Select }); } - public void RemoveBeatmap(BeatmapSetInfo beatmapSet) + public void RemoveBeatmap(BeatmapSetInfo beatmapSet) => removeGroup(groups.Find(b => b.BeatmapSet.ID == beatmapSet.ID)); + + internal void UpdateBeatmap(BeatmapInfo beatmap) { - Schedule(delegate + // todo: this method should not run more than once for the same BeatmapSetInfo. + var set = manager.Refresh(beatmap.BeatmapSet); + + // 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); + + 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) + selectedGroup = null; + + Filter(null, false); + + //check if we can/need to maintain our current selection. + if (selectedGroup == group && newGroup.BeatmapPanels.Count > 0) { - removeGroup(groups.Find(b => b.BeatmapSet.ID == beatmapSet.ID)); - }); + var newSelection = + 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); + } } public void SelectBeatmap(BeatmapInfo beatmap, bool animated = true) @@ -142,6 +169,8 @@ namespace osu.Game.Screens.Select public Action DeleteRequested; + public Action RestoreRequested; + public Action DeleteDifficultyRequested; public void SelectNext(int direction = 1, bool skipDifficulties = true) @@ -310,6 +339,7 @@ namespace osu.Game.Screens.Select SelectionChanged = (g, p) => selectGroup(g, p), StartRequested = b => StartRequested?.Invoke(), DeleteRequested = b => DeleteRequested?.Invoke(b), + RestoreHiddenRequested = s => RestoreRequested?.Invoke(s), DeleteDifficultyRequested = b => DeleteDifficultyRequested?.Invoke(b), State = BeatmapGroupState.Collapsed }; diff --git a/osu.Game/Screens/Select/BeatmapDeleteDialog.cs b/osu.Game/Screens/Select/BeatmapDeleteDialog.cs index 15ec84a7d8..aa37705cdf 100644 --- a/osu.Game/Screens/Select/BeatmapDeleteDialog.cs +++ b/osu.Game/Screens/Select/BeatmapDeleteDialog.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.Game.Beatmaps; using osu.Game.Graphics; @@ -13,28 +12,16 @@ namespace osu.Game.Screens.Select { private BeatmapManager manager; - private readonly Action deleteAction; - [BackgroundDependencyLoader] private void load(BeatmapManager beatmapManager) { manager = beatmapManager; } - public BeatmapDeleteDialog(BeatmapSetInfo beatmap) : this() + public BeatmapDeleteDialog(BeatmapSetInfo beatmap) { - BodyText = $@"{beatmap.Metadata?.Artist} - {beatmap.Metadata?.Title} (ALL DIFFICULTIES)"; - deleteAction = () => manager.Delete(beatmap); - } + BodyText = $@"{beatmap.Metadata?.Artist} - {beatmap.Metadata?.Title}"; - public BeatmapDeleteDialog(BeatmapInfo beatmap) : this() - { - BodyText = $@"{beatmap.Metadata?.Artist} - {beatmap.Metadata?.Title} [{beatmap.Version}]"; - deleteAction = () => manager.Delete(beatmap); - } - - public BeatmapDeleteDialog() - { Icon = FontAwesome.fa_trash_o; HeaderText = @"Confirm deletion of"; Buttons = new PopupDialogButton[] @@ -42,7 +29,7 @@ namespace osu.Game.Screens.Select new PopupDialogOkButton { Text = @"Yes. Totally. Delete it.", - Action = () => deleteAction(), + Action = () => manager.Delete(beatmap), }, new PopupDialogCancelButton { diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index b3ee33e7c6..b743af5351 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -107,7 +107,8 @@ namespace osu.Game.Screens.Select SelectionChanged = carouselSelectionChanged, BeatmapsChanged = carouselBeatmapsLoaded, DeleteRequested = b => promptDelete(b), - DeleteDifficultyRequested = b => promptDelete(b), + RestoreRequested = s => { foreach (var b in s.Beatmaps) manager.Restore(b); }, + DeleteDifficultyRequested = b => manager.Hide(b), StartRequested = () => carouselRaisedStart(), }); Add(FilterControl = new FilterControl @@ -176,6 +177,8 @@ namespace osu.Game.Screens.Select manager.BeatmapSetAdded += onBeatmapSetAdded; manager.BeatmapSetRemoved += onBeatmapSetRemoved; + manager.BeatmapHidden += onBeatmapHidden; + manager.BeatmapRestored += onBeatmapRestored; dialogOverlay = dialog; @@ -192,6 +195,9 @@ namespace osu.Game.Screens.Select carousel.AllowSelection = !Beatmap.Disabled; } + private void onBeatmapRestored(BeatmapInfo b) => carousel.UpdateBeatmap(b); + private void onBeatmapHidden(BeatmapInfo b) => carousel.UpdateBeatmap(b); + private void carouselBeatmapsLoaded() { if (Beatmap.Value.BeatmapSetInfo?.DeletePending == false) @@ -380,10 +386,7 @@ namespace osu.Game.Screens.Select } } - private void addBeatmapSet(BeatmapSetInfo beatmapSet) - { - carousel.AddBeatmap(beatmapSet); - } + private void addBeatmapSet(BeatmapSetInfo beatmapSet) => carousel.AddBeatmap(beatmapSet); private void removeBeatmapSet(BeatmapSetInfo beatmapSet) { @@ -400,14 +403,6 @@ namespace osu.Game.Screens.Select dialogOverlay?.Push(new BeatmapDeleteDialog(beatmap)); } - private void promptDelete(BeatmapInfo beatmap) - { - if (beatmap == null) - return; - - dialogOverlay?.Push(new BeatmapDeleteDialog(beatmap)); - } - protected override bool OnKeyDown(InputState state, KeyDownEventArgs args) { if (args.Repeat) return false; From f9d02afb007870f8bf9d778f99fd4de9d047af46 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 1 Sep 2017 18:13:21 +0900 Subject: [PATCH 21/47] Don't allow selection of a hidden beatmap --- osu.Game/Screens/Select/BeatmapCarousel.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index 5d495a61f0..8cdfcf1db0 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -144,7 +144,7 @@ namespace osu.Game.Screens.Select public void SelectBeatmap(BeatmapInfo beatmap, bool animated = true) { - if (beatmap == null) + if (beatmap == null || beatmap.Hidden) { SelectNext(); return; From 3d61cde266f3aac7149e9f18893bff6a8ecfd211 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 1 Sep 2017 18:22:38 +0900 Subject: [PATCH 22/47] Correctly delay loading of PlaySongSelect-specific components --- osu.Game/Screens/Select/PlaySongSelect.cs | 6 ++---- osu.Game/Screens/Select/SongSelect.cs | 11 ++++++++--- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/osu.Game/Screens/Select/PlaySongSelect.cs b/osu.Game/Screens/Select/PlaySongSelect.cs index 662e1d55a2..7e03707d18 100644 --- a/osu.Game/Screens/Select/PlaySongSelect.cs +++ b/osu.Game/Screens/Select/PlaySongSelect.cs @@ -54,13 +54,11 @@ namespace osu.Game.Screens.Select ValidForResume = false; Push(new Editor()); }, Key.Number3); - - Beatmap.ValueChanged += beatmap_ValueChanged; } - private void beatmap_ValueChanged(WorkingBeatmap beatmap) + protected override void UpdateBeatmap(WorkingBeatmap beatmap) { - if (!IsCurrentScreen) return; + base.UpdateBeatmap(beatmap); beatmap.Mods.BindTo(modSelect.SelectedMods); diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index b743af5351..e0e27e069d 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -244,7 +244,7 @@ namespace osu.Game.Screens.Select ensurePlayingSelected(preview); } - changeBackground(Beatmap.Value); + UpdateBeatmap(Beatmap.Value); }; selectionChangedDebounce?.Cancel(); @@ -312,7 +312,7 @@ namespace osu.Game.Screens.Select { if (Beatmap != null && !Beatmap.Value.BeatmapSetInfo.DeletePending) { - changeBackground(Beatmap); + UpdateBeatmap(Beatmap); ensurePlayingSelected(); } @@ -358,7 +358,12 @@ namespace osu.Game.Screens.Select initialAddSetsTask?.Cancel(); } - private void changeBackground(WorkingBeatmap beatmap) + /// + /// Allow components in SongSelect to update their loaded beatmap details. + /// This is a debounced call (unlike directly binding to WorkingBeatmap.ValueChanged). + /// + /// The working beatmap. + protected virtual void UpdateBeatmap(WorkingBeatmap beatmap) { var backgroundModeBeatmap = Background as BackgroundScreenBeatmap; if (backgroundModeBeatmap != null) From 8e0d18d36f73ddca1d66ef44e3707f900e6c0d8d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 1 Sep 2017 18:26:01 +0900 Subject: [PATCH 23/47] Add a button to restore all hidden difficulties --- .../Sections/Maintenance/GeneralSettings.cs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs index 9d13a2ae2f..233ca7be60 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs @@ -13,6 +13,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance { private OsuButton importButton; private OsuButton deleteButton; + private OsuButton restoreButton; protected override string Header => "General"; @@ -41,6 +42,20 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance Task.Run(() => beatmaps.DeleteAll()).ContinueWith(t => Schedule(() => deleteButton.Enabled.Value = true)); } }, + restoreButton = new OsuButton + { + RelativeSizeAxes = Axes.X, + Text = "Restore all hidden difficulties", + Action = () => + { + restoreButton.Enabled.Value = false; + Task.Run(() => + { + foreach (var b in beatmaps.QueryBeatmaps(b => b.Hidden)) + beatmaps.Restore(b); + }).ContinueWith(t => Schedule(() => restoreButton.Enabled.Value = true)); + } + }, }; } } From b19ae7c44ed3c9df5d1fb7200c11a53d59b84651 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 1 Sep 2017 18:37:46 +0900 Subject: [PATCH 24/47] Update framework --- osu-framework | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu-framework b/osu-framework index 2804e052ca..2bd341b29d 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit 2804e052ca2ce068f015771d28170d18573687e1 +Subproject commit 2bd341b29d6a7ed864aa9c1c5fad4668dafe03a4 From 3ede685ee9985065c079e2099dd2cf0a4706bb2a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 1 Sep 2017 18:44:51 +0900 Subject: [PATCH 25/47] Fix crash on random selection from a previously null selection --- osu.Game/Screens/Select/BeatmapCarousel.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index 264636b258..556ba68e95 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -191,7 +191,8 @@ namespace osu.Game.Screens.Select if (!visibleGroups.Any()) return; - randomSelectedBeatmaps.Push(new KeyValuePair(selectedGroup, selectedGroup.SelectedPanel)); + if (selectedGroup != null) + randomSelectedBeatmaps.Push(new KeyValuePair(selectedGroup, selectedGroup.SelectedPanel)); BeatmapGroup group; From c6b226b017f7a9212a195164983202ddbcf0bf42 Mon Sep 17 00:00:00 2001 From: Akash Mozumdar Date: Fri, 1 Sep 2017 15:32:03 -0400 Subject: [PATCH 26/47] refactor --- osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs b/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs index db39629d45..a66ac3298f 100644 --- a/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs +++ b/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs @@ -23,7 +23,7 @@ namespace osu.Game.Rulesets.Osu.Scoring { } - float beatmapHp; + private float beatmapHp; protected override void ComputeTargets(Game.Beatmaps.Beatmap beatmap) { From dd26c80837edb47bb5287c740e1d67b3e5338cb7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 4 Sep 2017 07:59:32 +0900 Subject: [PATCH 27/47] Delete -> Hide --- osu.Game/Beatmaps/Drawables/BeatmapGroup.cs | 4 ++-- osu.Game/Beatmaps/Drawables/BeatmapPanel.cs | 4 ++-- osu.Game/Screens/Select/BeatmapCarousel.cs | 4 ++-- osu.Game/Screens/Select/SongSelect.cs | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/osu.Game/Beatmaps/Drawables/BeatmapGroup.cs b/osu.Game/Beatmaps/Drawables/BeatmapGroup.cs index 19dfc22506..4a389101e2 100644 --- a/osu.Game/Beatmaps/Drawables/BeatmapGroup.cs +++ b/osu.Game/Beatmaps/Drawables/BeatmapGroup.cs @@ -27,7 +27,7 @@ namespace osu.Game.Beatmaps.Drawables public Action RestoreHiddenRequested; - public Action DeleteDifficultyRequested; + public Action HideDifficultyRequested; public BeatmapSetHeader Header; @@ -82,7 +82,7 @@ namespace osu.Game.Beatmaps.Drawables { Alpha = 0, GainedSelection = panelGainedSelection, - DeleteRequested = p => DeleteDifficultyRequested?.Invoke(p), + HideRequested = p => HideDifficultyRequested?.Invoke(p), StartRequested = p => { StartRequested?.Invoke(p.Beatmap); }, RelativeSizeAxes = Axes.X, }).ToList(); diff --git a/osu.Game/Beatmaps/Drawables/BeatmapPanel.cs b/osu.Game/Beatmaps/Drawables/BeatmapPanel.cs index 6b17b3bb8b..e216f1b83e 100644 --- a/osu.Game/Beatmaps/Drawables/BeatmapPanel.cs +++ b/osu.Game/Beatmaps/Drawables/BeatmapPanel.cs @@ -27,7 +27,7 @@ namespace osu.Game.Beatmaps.Drawables public Action GainedSelection; public Action StartRequested; public Action EditRequested; - public Action DeleteRequested; + public Action HideRequested; private readonly Triangles triangles; private readonly StarCounter starCounter; @@ -158,7 +158,7 @@ namespace osu.Game.Beatmaps.Drawables { new OsuMenuItem("Play", MenuItemType.Highlighted, () => StartRequested?.Invoke(this)), new OsuMenuItem("Edit", MenuItemType.Standard, () => EditRequested?.Invoke(this)), - new OsuMenuItem("Hide", MenuItemType.Destructive, () => DeleteRequested?.Invoke(Beatmap)), + new OsuMenuItem("Hide", MenuItemType.Destructive, () => HideRequested?.Invoke(Beatmap)), }; } } diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index 7044447508..94ae740c74 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -171,7 +171,7 @@ namespace osu.Game.Screens.Select public Action RestoreRequested; - public Action DeleteDifficultyRequested; + public Action HideDifficultyRequested; public void SelectNext(int direction = 1, bool skipDifficulties = true) { @@ -341,7 +341,7 @@ namespace osu.Game.Screens.Select StartRequested = b => StartRequested?.Invoke(), DeleteRequested = b => DeleteRequested?.Invoke(b), RestoreHiddenRequested = s => RestoreRequested?.Invoke(s), - DeleteDifficultyRequested = b => DeleteDifficultyRequested?.Invoke(b), + HideDifficultyRequested = b => HideDifficultyRequested?.Invoke(b), State = BeatmapGroupState.Collapsed }; } diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index e0e27e069d..8925732128 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -108,7 +108,7 @@ namespace osu.Game.Screens.Select BeatmapsChanged = carouselBeatmapsLoaded, DeleteRequested = b => promptDelete(b), RestoreRequested = s => { foreach (var b in s.Beatmaps) manager.Restore(b); }, - DeleteDifficultyRequested = b => manager.Hide(b), + HideDifficultyRequested = b => manager.Hide(b), StartRequested = () => carouselRaisedStart(), }); Add(FilterControl = new FilterControl From 543a71efcc7a8dfff9c5c40d5f99bef42509e0b8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 4 Sep 2017 08:21:07 +0900 Subject: [PATCH 28/47] Fix ObjectDisposal exceptions due to lingering event binds --- osu.Game/Screens/Select/SongSelect.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 8925732128..f97c4fe420 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -353,6 +353,8 @@ namespace osu.Game.Screens.Select { manager.BeatmapSetAdded -= onBeatmapSetAdded; manager.BeatmapSetRemoved -= onBeatmapSetRemoved; + manager.BeatmapHidden -= onBeatmapHidden; + manager.BeatmapRestored -= onBeatmapRestored; } initialAddSetsTask?.Cancel(); From 57678a13d9d3faf49fe0f422b8716893a73bf7f8 Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Mon, 4 Sep 2017 09:10:04 +0900 Subject: [PATCH 29/47] Update in-line with framework changes. --- osu-framework | 2 +- osu.Game/Beatmaps/Drawables/BeatmapGroup.cs | 9 ++++++++- osu.Game/Beatmaps/Drawables/Panel.cs | 9 ++++++++- .../Containers/OsuFocusedOverlayContainer.cs | 6 +++--- .../Graphics/UserInterface/BreadcrumbControl.cs | 6 ++++++ .../Graphics/UserInterface/OsuContextMenu.cs | 9 +++++---- osu.Game/Graphics/UserInterface/OsuDropdown.cs | 14 +++++--------- osu.Game/Graphics/UserInterface/OsuMenu.cs | 16 +++++++--------- osu.Game/OsuGame.cs | 4 ++-- osu.Game/Overlays/ChatOverlay.cs | 2 +- osu.Game/Overlays/DialogOverlay.cs | 2 +- osu.Game/Overlays/MainSettings.cs | 2 +- osu.Game/Overlays/MedalSplash/DrawableMedal.cs | 5 +++++ osu.Game/Overlays/MusicController.cs | 2 +- .../Settings/Sections/General/LoginSettings.cs | 4 ++-- osu.Game/Overlays/Settings/Sidebar.cs | 6 ++++++ .../Toolbar/ToolbarOverlayToggleButton.cs | 2 +- osu.Game/Overlays/WaveOverlayContainer.cs | 5 +++++ osu.Game/Screens/Menu/Button.cs | 4 ++++ osu.Game/Screens/Menu/ButtonSystem.cs | 4 ++++ osu.Game/Screens/Play/SkipButton.cs | 8 +++++++- osu.Game/Screens/Play/SquareGraph.cs | 6 ++++++ .../Select/Leaderboards/LeaderboardScore.cs | 8 ++++++++ 23 files changed, 97 insertions(+), 38 deletions(-) diff --git a/osu-framework b/osu-framework index 2bd341b29d..5c0e50379e 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit 2bd341b29d6a7ed864aa9c1c5fad4668dafe03a4 +Subproject commit 5c0e50379e47a3805097dbc36a713decc64f49ce diff --git a/osu.Game/Beatmaps/Drawables/BeatmapGroup.cs b/osu.Game/Beatmaps/Drawables/BeatmapGroup.cs index 4a389101e2..c66bf637e2 100644 --- a/osu.Game/Beatmaps/Drawables/BeatmapGroup.cs +++ b/osu.Game/Beatmaps/Drawables/BeatmapGroup.cs @@ -11,6 +11,8 @@ namespace osu.Game.Beatmaps.Drawables { public class BeatmapGroup : IStateful { + public event Action StateChanged; + public BeatmapPanel SelectedPanel; /// @@ -42,6 +44,10 @@ namespace osu.Game.Beatmaps.Drawables get { return state; } set { + if (state == value) + return; + state = value; + switch (value) { case BeatmapGroupState.Expanded: @@ -60,7 +66,8 @@ namespace osu.Game.Beatmaps.Drawables panel.State = PanelSelectedState.Hidden; break; } - state = value; + + StateChanged?.Invoke(state); } } diff --git a/osu.Game/Beatmaps/Drawables/Panel.cs b/osu.Game/Beatmaps/Drawables/Panel.cs index d07be88392..d6ed306b39 100644 --- a/osu.Game/Beatmaps/Drawables/Panel.cs +++ b/osu.Game/Beatmaps/Drawables/Panel.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; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -15,6 +16,8 @@ namespace osu.Game.Beatmaps.Drawables { public const float MAX_HEIGHT = 80; + public event Action StateChanged; + public override bool RemoveWhenNotAlive => false; private readonly Container nestedContainer; @@ -77,11 +80,15 @@ namespace osu.Game.Beatmaps.Drawables set { - if (state == value) return; + if (state == value) + return; var last = state; state = value; + ApplyState(last); + + StateChanged?.Invoke(State); } } diff --git a/osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs b/osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs index 0713fa1a52..4ea4f4cdc3 100644 --- a/osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs +++ b/osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs @@ -19,12 +19,12 @@ namespace osu.Game.Graphics.Containers samplePopIn = audio.Sample.Get(@"UI/melodic-5"); samplePopOut = audio.Sample.Get(@"UI/melodic-4"); - StateChanged += OsuFocusedOverlayContainer_StateChanged; + StateChanged += onStateChanged; } - private void OsuFocusedOverlayContainer_StateChanged(VisibilityContainer arg1, Visibility arg2) + private void onStateChanged(Visibility visibility) { - switch (arg2) + switch (visibility) { case Visibility.Visible: samplePopIn?.Play(); diff --git a/osu.Game/Graphics/UserInterface/BreadcrumbControl.cs b/osu.Game/Graphics/UserInterface/BreadcrumbControl.cs index b3e53280fb..65ece51a70 100644 --- a/osu.Game/Graphics/UserInterface/BreadcrumbControl.cs +++ b/osu.Game/Graphics/UserInterface/BreadcrumbControl.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 osu.Framework; using osu.Framework.Graphics; @@ -35,6 +36,8 @@ namespace osu.Game.Graphics.UserInterface private class BreadcrumbTabItem : OsuTabItem, IStateful { + public event Action StateChanged; + public readonly SpriteIcon Chevron; //don't allow clicking between transitions and don't make the chevron clickable @@ -42,6 +45,7 @@ namespace osu.Game.Graphics.UserInterface public override bool HandleInput => State == Visibility.Visible; private Visibility state; + public Visibility State { get { return state; } @@ -62,6 +66,8 @@ namespace osu.Game.Graphics.UserInterface this.FadeOut(transition_duration, Easing.OutQuint); this.ScaleTo(new Vector2(0.8f, 1f), transition_duration, Easing.OutQuint); } + + StateChanged?.Invoke(State); } } diff --git a/osu.Game/Graphics/UserInterface/OsuContextMenu.cs b/osu.Game/Graphics/UserInterface/OsuContextMenu.cs index 808c72ee5d..4ce6c98744 100644 --- a/osu.Game/Graphics/UserInterface/OsuContextMenu.cs +++ b/osu.Game/Graphics/UserInterface/OsuContextMenu.cs @@ -14,14 +14,17 @@ namespace osu.Game.Graphics.UserInterface private const int fade_duration = 250; public OsuContextMenu() + : base(Direction.Vertical) { - CornerRadius = 5; - EdgeEffect = new EdgeEffectParameters + MaskingContainer.CornerRadius = 5; + MaskingContainer.EdgeEffect = new EdgeEffectParameters { Type = EdgeEffectType.Shadow, Colour = Color4.Black.Opacity(0.1f), Radius = 4, }; + + ItemsContainer.Padding = new MarginPadding { Vertical = DrawableOsuMenuItem.MARGIN_VERTICAL }; } [BackgroundDependencyLoader] @@ -32,7 +35,5 @@ namespace osu.Game.Graphics.UserInterface protected override void AnimateOpen() => this.FadeIn(fade_duration, Easing.OutQuint); protected override void AnimateClose() => this.FadeOut(fade_duration, Easing.OutQuint); - - protected override MarginPadding ItemFlowContainerPadding => new MarginPadding { Vertical = DrawableOsuMenuItem.MARGIN_VERTICAL }; } } \ No newline at end of file diff --git a/osu.Game/Graphics/UserInterface/OsuDropdown.cs b/osu.Game/Graphics/UserInterface/OsuDropdown.cs index dde154bb61..275cc2ab64 100644 --- a/osu.Game/Graphics/UserInterface/OsuDropdown.cs +++ b/osu.Game/Graphics/UserInterface/OsuDropdown.cs @@ -57,6 +57,9 @@ namespace osu.Game.Graphics.UserInterface { CornerRadius = 4; BackgroundColour = Color4.Black.Opacity(0.5f); + + // todo: this uses the same styling as OsuMenu. hopefully we can just use OsuMenu in the future with some refactoring + ItemsContainer.Padding = new MarginPadding(5); } // todo: this uses the same styling as OsuMenu. hopefully we can just use OsuMenu in the future with some refactoring @@ -64,14 +67,7 @@ namespace osu.Game.Graphics.UserInterface protected override void AnimateClose() => this.FadeOut(300, Easing.OutQuint); // todo: this uses the same styling as OsuMenu. hopefully we can just use OsuMenu in the future with some refactoring - protected override MarginPadding ItemFlowContainerPadding => new MarginPadding(5); - - // todo: this uses the same styling as OsuMenu. hopefully we can just use OsuMenu in the future with some refactoring - protected override void UpdateMenuHeight() - { - var actualHeight = (RelativeSizeAxes & Axes.Y) > 0 ? 1 : ContentHeight; - this.ResizeHeightTo(State == MenuState.Opened ? actualHeight : 0, 300, Easing.OutQuint); - } + protected override void UpdateSize(Vector2 newSize) => this.ResizeTo(newSize, 300, Easing.OutQuint); private Color4 accentColour; public Color4 AccentColour @@ -141,7 +137,7 @@ namespace osu.Game.Graphics.UserInterface protected override Drawable CreateContent() => new Content(); - protected class Content : FillFlowContainer, IHasText + protected new class Content : FillFlowContainer, IHasText { public string Text { diff --git a/osu.Game/Graphics/UserInterface/OsuMenu.cs b/osu.Game/Graphics/UserInterface/OsuMenu.cs index ab37fd2c90..a8cb8cafbb 100644 --- a/osu.Game/Graphics/UserInterface/OsuMenu.cs +++ b/osu.Game/Graphics/UserInterface/OsuMenu.cs @@ -12,27 +12,25 @@ using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.UserInterface; using osu.Framework.Input; using osu.Game.Graphics.Sprites; +using OpenTK; namespace osu.Game.Graphics.UserInterface { public class OsuMenu : Menu { - public OsuMenu() + public OsuMenu(Direction direction) + : base(direction) { - CornerRadius = 4; BackgroundColour = Color4.Black.Opacity(0.5f); + + MaskingContainer.CornerRadius = 4; + ItemsContainer.Padding = new MarginPadding(5); } protected override void AnimateOpen() => this.FadeIn(300, Easing.OutQuint); protected override void AnimateClose() => this.FadeOut(300, Easing.OutQuint); - protected override void UpdateMenuHeight() - { - var actualHeight = (RelativeSizeAxes & Axes.Y) > 0 ? 1 : ContentHeight; - this.ResizeHeightTo(State == MenuState.Opened ? actualHeight : 0, 300, Easing.OutQuint); - } - - protected override MarginPadding ItemFlowContainerPadding => new MarginPadding(5); + protected override void UpdateSize(Vector2 newSize) => this.ResizeTo(newSize, 300, Easing.OutQuint); protected override DrawableMenuItem CreateDrawableMenuItem(MenuItem item) => new DrawableOsuMenuItem(item); diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 30bc09d50f..c020675881 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -230,13 +230,13 @@ namespace osu.Game var singleDisplayOverlays = new OverlayContainer[] { chat, social, direct }; foreach (var overlay in singleDisplayOverlays) { - overlay.StateChanged += (container, state) => + overlay.StateChanged += state => { if (state == Visibility.Hidden) return; foreach (var c in singleDisplayOverlays) { - if (c == container) continue; + if (c == overlay) continue; c.State = Visibility.Hidden; } }; diff --git a/osu.Game/Overlays/ChatOverlay.cs b/osu.Game/Overlays/ChatOverlay.cs index 6dd5425fd1..b5bb1a2d9f 100644 --- a/osu.Game/Overlays/ChatOverlay.cs +++ b/osu.Game/Overlays/ChatOverlay.cs @@ -169,7 +169,7 @@ namespace osu.Game.Overlays channelTabs.Current.ValueChanged += newChannel => CurrentChannel = newChannel; channelTabs.ChannelSelectorActive.ValueChanged += value => channelSelection.State = value ? Visibility.Visible : Visibility.Hidden; - channelSelection.StateChanged += (overlay, state) => + channelSelection.StateChanged += state => { channelTabs.ChannelSelectorActive.Value = state == Visibility.Visible; diff --git a/osu.Game/Overlays/DialogOverlay.cs b/osu.Game/Overlays/DialogOverlay.cs index 012e93f10d..7853eefd2c 100644 --- a/osu.Game/Overlays/DialogOverlay.cs +++ b/osu.Game/Overlays/DialogOverlay.cs @@ -26,7 +26,7 @@ namespace osu.Game.Overlays dialogContainer.Add(currentDialog); currentDialog.Show(); - currentDialog.StateChanged += onDialogOnStateChanged; + currentDialog.StateChanged += state => onDialogOnStateChanged(dialog, state); State = Visibility.Visible; } diff --git a/osu.Game/Overlays/MainSettings.cs b/osu.Game/Overlays/MainSettings.cs index b4d9cac045..4fe86d62fd 100644 --- a/osu.Game/Overlays/MainSettings.cs +++ b/osu.Game/Overlays/MainSettings.cs @@ -53,7 +53,7 @@ namespace osu.Game.Overlays private const float hidden_width = 120; - private void keyBindingOverlay_StateChanged(VisibilityContainer container, Visibility visibility) + private void keyBindingOverlay_StateChanged(Visibility visibility) { switch (visibility) { diff --git a/osu.Game/Overlays/MedalSplash/DrawableMedal.cs b/osu.Game/Overlays/MedalSplash/DrawableMedal.cs index 56b26e7176..3ac8af7b2b 100644 --- a/osu.Game/Overlays/MedalSplash/DrawableMedal.cs +++ b/osu.Game/Overlays/MedalSplash/DrawableMedal.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; using OpenTK; using osu.Framework.Allocation; @@ -19,6 +20,8 @@ namespace osu.Game.Overlays.MedalSplash private const float scale_when_unlocked = 0.76f; private const float scale_when_full = 0.6f; + public event Action StateChanged; + private readonly Medal medal; private readonly Container medalContainer; private readonly Sprite medalSprite, medalGlow; @@ -132,6 +135,8 @@ namespace osu.Game.Overlays.MedalSplash state = value; updateState(); + + StateChanged?.Invoke(State); } } diff --git a/osu.Game/Overlays/MusicController.cs b/osu.Game/Overlays/MusicController.cs index cb4628825e..0a06439c3e 100644 --- a/osu.Game/Overlays/MusicController.cs +++ b/osu.Game/Overlays/MusicController.cs @@ -204,7 +204,7 @@ namespace osu.Game.Overlays beatmapBacking.BindTo(game.Beatmap); - playlist.StateChanged += (c, s) => playlistButton.FadeColour(s == Visibility.Visible ? colours.Yellow : Color4.White, 200, Easing.OutQuint); + playlist.StateChanged += s => playlistButton.FadeColour(s == Visibility.Visible ? colours.Yellow : Color4.White, 200, Easing.OutQuint); } protected override void LoadComplete() diff --git a/osu.Game/Overlays/Settings/Sections/General/LoginSettings.cs b/osu.Game/Overlays/Settings/Sections/General/LoginSettings.cs index a816fa56c1..e62050fae1 100644 --- a/osu.Game/Overlays/Settings/Sections/General/LoginSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/General/LoginSettings.cs @@ -292,6 +292,8 @@ namespace osu.Game.Overlays.Settings.Sections.General Colour = Color4.Black.Opacity(0.25f), Radius = 4, }; + + ItemsContainer.Padding = new MarginPadding(); } [BackgroundDependencyLoader] @@ -300,8 +302,6 @@ namespace osu.Game.Overlays.Settings.Sections.General BackgroundColour = colours.Gray3; } - protected override MarginPadding ItemFlowContainerPadding => new MarginPadding(); - protected override DrawableMenuItem CreateDrawableMenuItem(MenuItem item) => new DrawableUserDropdownMenuItem(item); private class DrawableUserDropdownMenuItem : DrawableOsuDropdownMenuItem diff --git a/osu.Game/Overlays/Settings/Sidebar.cs b/osu.Game/Overlays/Settings/Sidebar.cs index b22a5ab126..55167188a3 100644 --- a/osu.Game/Overlays/Settings/Sidebar.cs +++ b/osu.Game/Overlays/Settings/Sidebar.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; using OpenTK; @@ -19,6 +20,9 @@ namespace osu.Game.Overlays.Settings private readonly FillFlowContainer content; internal const float DEFAULT_WIDTH = ToolbarButton.WIDTH; internal const int EXPANDED_WIDTH = 200; + + public event Action StateChanged; + protected override Container Content => content; public Sidebar() @@ -102,6 +106,8 @@ namespace osu.Game.Overlays.Settings this.ResizeTo(new Vector2(EXPANDED_WIDTH, Height), 500, Easing.OutQuint); break; } + + StateChanged?.Invoke(State); } } diff --git a/osu.Game/Overlays/Toolbar/ToolbarOverlayToggleButton.cs b/osu.Game/Overlays/Toolbar/ToolbarOverlayToggleButton.cs index 6d61a096b2..c530e8d7ff 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarOverlayToggleButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarOverlayToggleButton.cs @@ -45,7 +45,7 @@ namespace osu.Game.Overlays.Toolbar stateContainer.StateChanged -= stateChanged; } - private void stateChanged(VisibilityContainer c, Visibility state) + private void stateChanged(Visibility state) { switch (state) { diff --git a/osu.Game/Overlays/WaveOverlayContainer.cs b/osu.Game/Overlays/WaveOverlayContainer.cs index fd89dcfbc4..4f9783a762 100644 --- a/osu.Game/Overlays/WaveOverlayContainer.cs +++ b/osu.Game/Overlays/WaveOverlayContainer.cs @@ -167,6 +167,8 @@ namespace osu.Game.Overlays private class Wave : Container, IStateful { + public event Action StateChanged; + public float FinalPosition; public Wave() @@ -200,6 +202,7 @@ namespace osu.Game.Overlays } private Visibility state; + public Visibility State { get { return state; } @@ -216,6 +219,8 @@ namespace osu.Game.Overlays this.MoveToY(FinalPosition, APPEAR_DURATION, easing_show); break; } + + StateChanged?.Invoke(State); } } } diff --git a/osu.Game/Screens/Menu/Button.cs b/osu.Game/Screens/Menu/Button.cs index 0898c079ce..aca169c3dc 100644 --- a/osu.Game/Screens/Menu/Button.cs +++ b/osu.Game/Screens/Menu/Button.cs @@ -28,6 +28,8 @@ namespace osu.Game.Screens.Menu /// public class Button : BeatSyncedContainer, IStateful { + public event Action StateChanged; + private readonly Container iconText; private readonly Container box; private readonly Box boxHoverLayer; @@ -266,6 +268,8 @@ namespace osu.Game.Screens.Menu this.FadeOut(explode_duration / 4f * 3); break; } + + StateChanged?.Invoke(State); } } } diff --git a/osu.Game/Screens/Menu/ButtonSystem.cs b/osu.Game/Screens/Menu/ButtonSystem.cs index 71f2a16c09..e4dbe00a80 100644 --- a/osu.Game/Screens/Menu/ButtonSystem.cs +++ b/osu.Game/Screens/Menu/ButtonSystem.cs @@ -22,6 +22,8 @@ namespace osu.Game.Screens.Menu { public class ButtonSystem : Container, IStateful { + public event Action StateChanged; + public Action OnEdit; public Action OnExit; public Action OnDirect; @@ -294,6 +296,8 @@ namespace osu.Game.Screens.Menu backButton.State = state == MenuState.Play ? ButtonState.Expanded : ButtonState.Contracted; settingsButton.State = state == MenuState.TopLevel ? ButtonState.Expanded : ButtonState.Contracted; } + + StateChanged?.Invoke(State); } } diff --git a/osu.Game/Screens/Play/SkipButton.cs b/osu.Game/Screens/Play/SkipButton.cs index 3cf371f1e1..6519a8db36 100644 --- a/osu.Game/Screens/Play/SkipButton.cs +++ b/osu.Game/Screens/Play/SkipButton.cs @@ -133,6 +133,8 @@ namespace osu.Game.Screens.Play private class FadeContainer : Container, IStateful { + public event Action StateChanged; + private Visibility state; private ScheduledDelegate scheduledHide; @@ -144,8 +146,10 @@ namespace osu.Game.Screens.Play } set { - var lastState = state; + if (state == value) + return; + var lastState = state; state = value; scheduledHide?.Cancel(); @@ -164,6 +168,8 @@ namespace osu.Game.Screens.Play this.FadeOut(1000, Easing.OutExpo); break; } + + StateChanged?.Invoke(State); } } diff --git a/osu.Game/Screens/Play/SquareGraph.cs b/osu.Game/Screens/Play/SquareGraph.cs index f3bb523611..81dbf3eca4 100644 --- a/osu.Game/Screens/Play/SquareGraph.cs +++ b/osu.Game/Screens/Play/SquareGraph.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; @@ -170,6 +171,8 @@ namespace osu.Game.Screens.Play private const float padding = 2; public const float WIDTH = cube_size + padding; + public event Action StateChanged; + private readonly List drawableRows = new List(); private float filled; @@ -186,6 +189,7 @@ namespace osu.Game.Screens.Play } private ColumnState state; + public ColumnState State { get { return state; } @@ -196,6 +200,8 @@ namespace osu.Game.Screens.Play if (IsLoaded) fillActive(); + + StateChanged?.Invoke(State); } } diff --git a/osu.Game/Screens/Select/Leaderboards/LeaderboardScore.cs b/osu.Game/Screens/Select/Leaderboards/LeaderboardScore.cs index d7c85fff90..2987f4476c 100644 --- a/osu.Game/Screens/Select/Leaderboards/LeaderboardScore.cs +++ b/osu.Game/Screens/Select/Leaderboards/LeaderboardScore.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.Graphics; @@ -21,6 +22,8 @@ namespace osu.Game.Screens.Select.Leaderboards { public static readonly float HEIGHT = 60; + public event Action StateChanged; + public readonly int RankPosition; public readonly Score Score; @@ -41,11 +44,14 @@ namespace osu.Game.Screens.Select.Leaderboards private readonly FillFlowContainer modsContainer; private Visibility state; + public Visibility State { get { return state; } set { + if (state == value) + return; state = value; switch (state) @@ -88,6 +94,8 @@ namespace osu.Game.Screens.Select.Leaderboards break; } + + StateChanged?.Invoke(State); } } From 2a64bcda85aaa686fbefee7e22fb0a0dca9bd928 Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Mon, 4 Sep 2017 09:32:44 +0900 Subject: [PATCH 30/47] Fix resizing bug(?). --- osu.Game/Graphics/UserInterface/OsuDropdown.cs | 14 +++++++++++++- osu.Game/Graphics/UserInterface/OsuMenu.cs | 14 +++++++++++++- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/OsuDropdown.cs b/osu.Game/Graphics/UserInterface/OsuDropdown.cs index 275cc2ab64..b69186e8b0 100644 --- a/osu.Game/Graphics/UserInterface/OsuDropdown.cs +++ b/osu.Game/Graphics/UserInterface/OsuDropdown.cs @@ -67,7 +67,19 @@ namespace osu.Game.Graphics.UserInterface protected override void AnimateClose() => this.FadeOut(300, Easing.OutQuint); // todo: this uses the same styling as OsuMenu. hopefully we can just use OsuMenu in the future with some refactoring - protected override void UpdateSize(Vector2 newSize) => this.ResizeTo(newSize, 300, Easing.OutQuint); + protected override void UpdateSize(Vector2 newSize) + { + if (Direction == Direction.Vertical) + { + Width = newSize.X; + this.ResizeHeightTo(newSize.Y, 300, Easing.OutQuint); + } + else + { + Height = newSize.Y; + this.ResizeWidthTo(newSize.X, 300, Easing.OutQuint); + } + } private Color4 accentColour; public Color4 AccentColour diff --git a/osu.Game/Graphics/UserInterface/OsuMenu.cs b/osu.Game/Graphics/UserInterface/OsuMenu.cs index a8cb8cafbb..103155dd1f 100644 --- a/osu.Game/Graphics/UserInterface/OsuMenu.cs +++ b/osu.Game/Graphics/UserInterface/OsuMenu.cs @@ -30,7 +30,19 @@ namespace osu.Game.Graphics.UserInterface protected override void AnimateOpen() => this.FadeIn(300, Easing.OutQuint); protected override void AnimateClose() => this.FadeOut(300, Easing.OutQuint); - protected override void UpdateSize(Vector2 newSize) => this.ResizeTo(newSize, 300, Easing.OutQuint); + protected override void UpdateSize(Vector2 newSize) + { + if (Direction == Direction.Vertical) + { + Width = newSize.X; + this.ResizeHeightTo(newSize.Y, 300, Easing.OutQuint); + } + else + { + Height = newSize.Y; + this.ResizeWidthTo(newSize.X, 300, Easing.OutQuint); + } + } protected override DrawableMenuItem CreateDrawableMenuItem(MenuItem item) => new DrawableOsuMenuItem(item); From 9078444a6292fce1bd4e8a4ec6019c5c487a2f9f Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Mon, 4 Sep 2017 11:03:04 +0900 Subject: [PATCH 31/47] Fix items jumping between two indices in the edge case, use a linear search for now. --- osu.Game/Overlays/Music/PlaylistItem.cs | 45 ++++++++++--------------- 1 file changed, 18 insertions(+), 27 deletions(-) diff --git a/osu.Game/Overlays/Music/PlaylistItem.cs b/osu.Game/Overlays/Music/PlaylistItem.cs index 9df15bfd04..44bb2687f7 100644 --- a/osu.Game/Overlays/Music/PlaylistItem.cs +++ b/osu.Game/Overlays/Music/PlaylistItem.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Linq; using OpenTK.Graphics; using osu.Framework.Allocation; using osu.Framework.Graphics; @@ -150,9 +151,6 @@ namespace osu.Game.Overlays.Music { private readonly FillFlowContainer playlist; - private const int line_height = 22; - private const int rearrange_buffer = 3; - public PlaylistItemHandle(FillFlowContainer playlist) { this.playlist = playlist; @@ -169,7 +167,23 @@ namespace osu.Game.Overlays.Music protected override bool OnDrag(InputState state) { int src = (int)Parent.Depth; - int dst = getIndex(state.Mouse.Position.Y + Parent.Position.Y); + + var matchingItem = playlist.Children.LastOrDefault(c => c.Position.Y < state.Mouse.Position.Y + Parent.Position.Y); + if (matchingItem == null) + return true; + + int dst = (int)matchingItem.Depth; + + // Due to the position predicate above, there is an edge case to consider when an item is moved upwards: + // At the point where the two items cross there will be two items sharing the same condition, and the items will jump back + // and forth between the two positions because of this. This is accentuated if the items span differing line heights. + // The easiest way to avoid this is to ensure the movement direction matches the expected mouse delta + + if (state.Mouse.Delta.Y <= 0 && dst > src) + return true; + + if (state.Mouse.Delta.Y >= 0 && dst < src) + return true; if (src == dst) return true; @@ -188,29 +202,6 @@ namespace osu.Game.Overlays.Music playlist.ChangeChildDepth(Parent as PlaylistItem, dst); return true; } - - private int getIndex(float position) { - IReadOnlyList items = playlist.Children; - - // Binary Search without matching exact - int min = 0; - int max = items.Count - 1; - while (min <= max) - { - int m = (min + max) / 2; - if (items[m].Y < position) - min = m + 1; - else if (items[m].Y > position) - max = m - 1; - } - - int index = Math.Max(0, min - 1); - // Only move if mouse falls within buffer - if (position - items[index].Y > rearrange_buffer && position - items[index].Y < line_height - rearrange_buffer) { - return (int)items[index].Depth; - } - return (int)Parent.Depth; - } } } } From 9b0309e6835a61f7d314e2cfbe6cc97bb4d456ec Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Mon, 4 Sep 2017 11:28:15 +0900 Subject: [PATCH 32/47] Use TakeWhile instead of reversing the list. --- osu.Game/Overlays/Music/PlaylistList.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Music/PlaylistList.cs b/osu.Game/Overlays/Music/PlaylistList.cs index 019049eb96..f463d382b0 100644 --- a/osu.Game/Overlays/Music/PlaylistList.cs +++ b/osu.Game/Overlays/Music/PlaylistList.cs @@ -59,8 +59,8 @@ namespace osu.Game.Overlays.Music { get { - var available = items.Children.Reverse(); - return (available.SkipWhile(i => !i.Selected).Skip(1).FirstOrDefault() ?? available.FirstOrDefault())?.BeatmapSetInfo; + var available = items.Children; + return (available.TakeWhile(i => !i.Selected).LastOrDefault() ?? available.LastOrDefault())?.BeatmapSetInfo; } } From 3b575444bedcfe4db9906abcd8ef7bafb4bd4d65 Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Mon, 4 Sep 2017 13:12:12 +0900 Subject: [PATCH 33/47] Rewrite PlaylistList as CompositeDrawable and remove all backwards PlaylistList references Now handles drag at a PlaylistList.ItemsScrollContainer level (private class), and PlaylistList itself is no longer a Container so it only supports adding BeatmapSets. Sorry for the rewrite x.x. --- osu.Game/Overlays/Music/PlaylistItem.cs | 66 ++---- osu.Game/Overlays/Music/PlaylistList.cs | 256 ++++++++++++++------- osu.Game/Overlays/Music/PlaylistOverlay.cs | 10 +- 3 files changed, 188 insertions(+), 144 deletions(-) diff --git a/osu.Game/Overlays/Music/PlaylistItem.cs b/osu.Game/Overlays/Music/PlaylistItem.cs index 44bb2687f7..2aaa182685 100644 --- a/osu.Game/Overlays/Music/PlaylistItem.cs +++ b/osu.Game/Overlays/Music/PlaylistItem.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using System.Linq; using OpenTK.Graphics; using osu.Framework.Allocation; using osu.Framework.Graphics; @@ -18,7 +17,7 @@ using OpenTK; namespace osu.Game.Overlays.Music { - internal class PlaylistItem : Container, IFilterable + internal class PlaylistItem : Container, IFilterable, IDraggable { private const float fade_duration = 100; @@ -31,11 +30,12 @@ namespace osu.Game.Overlays.Music private UnicodeBindableString titleBind; private UnicodeBindableString artistBind; - private readonly FillFlowContainer playlist; public readonly BeatmapSetInfo BeatmapSetInfo; public Action OnSelect; + public bool IsDraggable => handle.IsHovered; + private bool selected; public bool Selected { @@ -51,9 +51,8 @@ namespace osu.Game.Overlays.Music } } - public PlaylistItem(FillFlowContainer playlist, BeatmapSetInfo setInfo) + public PlaylistItem(BeatmapSetInfo setInfo) { - this.playlist = playlist; BeatmapSetInfo = setInfo; RelativeSizeAxes = Axes.X; @@ -72,9 +71,9 @@ namespace osu.Game.Overlays.Music Children = new Drawable[] { - handle = new PlaylistItemHandle(playlist) + handle = new PlaylistItemHandle { - Colour = colours.Gray5, + Colour = colours.Gray5 }, text = new OsuTextFlowContainer { @@ -149,11 +148,9 @@ namespace osu.Game.Overlays.Music private class PlaylistItemHandle : SpriteIcon { - private readonly FillFlowContainer playlist; - public PlaylistItemHandle(FillFlowContainer playlist) + public PlaylistItemHandle() { - this.playlist = playlist; Anchor = Anchor.TopLeft; Origin = Anchor.TopLeft; Size = new Vector2(12); @@ -161,47 +158,14 @@ namespace osu.Game.Overlays.Music Alpha = 0f; Margin = new MarginPadding { Left = 5, Top = 2 }; } - - protected override bool OnDragStart(InputState state) => true; - - protected override bool OnDrag(InputState state) - { - int src = (int)Parent.Depth; - - var matchingItem = playlist.Children.LastOrDefault(c => c.Position.Y < state.Mouse.Position.Y + Parent.Position.Y); - if (matchingItem == null) - return true; - - int dst = (int)matchingItem.Depth; - - // Due to the position predicate above, there is an edge case to consider when an item is moved upwards: - // At the point where the two items cross there will be two items sharing the same condition, and the items will jump back - // and forth between the two positions because of this. This is accentuated if the items span differing line heights. - // The easiest way to avoid this is to ensure the movement direction matches the expected mouse delta - - if (state.Mouse.Delta.Y <= 0 && dst > src) - return true; - - if (state.Mouse.Delta.Y >= 0 && dst < src) - return true; - - if (src == dst) - return true; - - if (src < dst) - { - for (int i = src + 1; i <= dst; i++) - playlist.ChangeChildDepth(playlist[i], i - 1); - } - else - { - for (int i = dst; i < src; i++) - playlist.ChangeChildDepth(playlist[i], i + 1); - } - - playlist.ChangeChildDepth(Parent as PlaylistItem, dst); - return true; - } } } + + public interface IDraggable : IDrawable + { + /// + /// Whether this can be dragged in its current state. + /// + bool IsDraggable { get; } + } } diff --git a/osu.Game/Overlays/Music/PlaylistList.cs b/osu.Game/Overlays/Music/PlaylistList.cs index f463d382b0..a4550f7f52 100644 --- a/osu.Game/Overlays/Music/PlaylistList.cs +++ b/osu.Game/Overlays/Music/PlaylistList.cs @@ -4,125 +4,205 @@ using System; using System.Collections.Generic; using System.Linq; +using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Input; using osu.Game.Beatmaps; using osu.Game.Graphics.Containers; +using OpenTK; namespace osu.Game.Overlays.Music { - internal class PlaylistList : Container + internal class PlaylistList : CompositeDrawable { - private readonly FillFlowContainer items; - - public IEnumerable BeatmapSets - { - set - { - items.Children = value.Select((item, index) => new PlaylistItem(items, item) { OnSelect = itemSelected, Depth = index }).ToList(); - } - } - - public BeatmapSetInfo FirstVisibleSet => items.Children.FirstOrDefault(i => i.MatchingFilter)?.BeatmapSetInfo; - - private void itemSelected(BeatmapSetInfo b) - { - OnSelect?.Invoke(b); - } - public Action OnSelect; - private readonly SearchContainer search; - - public void Filter(string searchTerm) => search.SearchTerm = searchTerm; - - public BeatmapSetInfo SelectedItem - { - get { return items.Children.FirstOrDefault(i => i.Selected)?.BeatmapSetInfo; } - set - { - foreach (PlaylistItem s in items.Children) - s.Selected = s.BeatmapSetInfo.ID == value?.ID; - } - } - - public BeatmapSetInfo NextItem - { - get - { - var available = items.Children; - return (available.SkipWhile(i => !i.Selected).Skip(1).FirstOrDefault() ?? available.FirstOrDefault())?.BeatmapSetInfo; - } - } - - public BeatmapSetInfo PreviousItem - { - get - { - var available = items.Children; - return (available.TakeWhile(i => !i.Selected).LastOrDefault() ?? available.LastOrDefault())?.BeatmapSetInfo; - } - } + private readonly ItemsScrollContainer items; public PlaylistList() { - Children = new Drawable[] + InternalChild = items = new ItemsScrollContainer { - new OsuScrollContainer - { - RelativeSizeAxes = Axes.Both, - Children = new Drawable[] - { - search = new SearchContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Children = new Drawable[] - { - items = new ItemSearchContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - }, - } - } - }, - }, + RelativeSizeAxes = Axes.Both, + OnSelect = set => OnSelect?.Invoke(set) }; } - public void AddBeatmapSet(BeatmapSetInfo beatmapSet) + public new MarginPadding Padding { - items.Add(new PlaylistItem(items, beatmapSet) { OnSelect = itemSelected, Depth = items.Count }); + get { return base.Padding; } + set { base.Padding = value; } } - public void RemoveBeatmapSet(BeatmapSetInfo beatmapSet) + public IEnumerable BeatmapSets { set { items.Sets = value; } } + + public BeatmapSetInfo FirstVisibleSet => items.FirstVisibleSet; + public BeatmapSetInfo NextSet => items.NextSet; + public BeatmapSetInfo PreviousSet => items.PreviousSet; + + public BeatmapSetInfo SelectedSet { - PlaylistItem itemToRemove = items.Children.FirstOrDefault(item => item.BeatmapSetInfo.ID == beatmapSet.ID); - if (itemToRemove != null) items.Remove(itemToRemove); + get { return items.SelectedSet; } + set { items.SelectedSet = value; } } - private class ItemSearchContainer : FillFlowContainer, IHasFilterableChildren + public void AddBeatmapSet(BeatmapSetInfo beatmapSet) => items.AddBeatmapSet(beatmapSet); + public bool RemoveBeatmapSet(BeatmapSetInfo beatmapSet) => items.RemoveBeatmapSet(beatmapSet); + + public void Filter(string searchTerm) => items.SearchTerm = searchTerm; + + private class ItemsScrollContainer : OsuScrollContainer { - public string[] FilterTerms => new string[] { }; - public bool MatchingFilter + public Action OnSelect; + + private readonly SearchContainer search; + private readonly FillFlowContainer items; + + private PlaylistItem draggedItem; + + public ItemsScrollContainer() + { + Children = new Drawable[] + { + search = new SearchContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Children = new Drawable[] + { + items = new ItemSearchContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + }, + } + } + }; + } + + public IEnumerable Sets { set { - if (value) - InvalidateLayout(); + items.Clear(); + value.ForEach(AddBeatmapSet); } } - // Compare with reversed ChildID and Depth - protected override int Compare(Drawable x, Drawable y) => base.Compare(y, x); - - public IEnumerable FilterableChildren => Children; - - public ItemSearchContainer() + public string SearchTerm { - LayoutDuration = 200; - LayoutEasing = Easing.OutQuint; + get { return search.SearchTerm; } + set { search.SearchTerm = value; } + } + + public void AddBeatmapSet(BeatmapSetInfo beatmapSet) + { + items.Add(new PlaylistItem(beatmapSet) + { + OnSelect = set => OnSelect?.Invoke(set), + Depth = items.Count + }); + } + + public bool RemoveBeatmapSet(BeatmapSetInfo beatmapSet) + { + var itemToRemove = items.FirstOrDefault(i => i.BeatmapSetInfo.ID == beatmapSet.ID); + if (itemToRemove == null) + return false; + return items.Remove(itemToRemove); + } + + public BeatmapSetInfo SelectedSet + { + get { return items.FirstOrDefault(i => i.Selected)?.BeatmapSetInfo; } + set + { + foreach (PlaylistItem s in items.Children) + s.Selected = s.BeatmapSetInfo.ID == value?.ID; + } + } + + public BeatmapSetInfo FirstVisibleSet => items.FirstOrDefault(i => i.MatchingFilter)?.BeatmapSetInfo; + public BeatmapSetInfo NextSet => (items.SkipWhile(i => !i.Selected).Skip(1).FirstOrDefault() ?? items.FirstOrDefault())?.BeatmapSetInfo; + public BeatmapSetInfo PreviousSet => (items.TakeWhile(i => !i.Selected).LastOrDefault() ?? items.LastOrDefault())?.BeatmapSetInfo; + + protected override bool OnDragStart(InputState state) + { + draggedItem = items.FirstOrDefault(d => d.IsDraggable); + return draggedItem != null || base.OnDragStart(state); + } + + protected override bool OnDrag(InputState state) + { + if (draggedItem == null) + return base.OnDrag(state); + + // Mouse position in the position space of the items container + Vector2 itemsPos = items.ToLocalSpace(state.Mouse.NativeState.Position); + + int src = (int)draggedItem.Depth; + + var matchingItem = items.LastOrDefault(c => c.Position.Y < itemsPos.Y); + if (matchingItem == null) + return true; + + int dst = (int)matchingItem.Depth; + + // Due to the position predicate above, there is an edge case to consider when an item is moved upwards: + // At the point where the two items cross there will be two items sharing the same condition, and the items will jump back + // and forth between the two positions because of this. This is accentuated if the items span differing line heights. + // The easiest way to avoid this is to ensure the movement direction matches the expected mouse delta + + if (state.Mouse.Delta.Y <= 0 && dst > src) + return true; + + if (state.Mouse.Delta.Y >= 0 && dst < src) + return true; + + if (src == dst) + return true; + + if (src < dst) + { + for (int i = src + 1; i <= dst; i++) + items.ChangeChildDepth(items[i], i - 1); + } + else + { + for (int i = dst; i < src; i++) + items.ChangeChildDepth(items[i], i + 1); + } + + items.ChangeChildDepth(draggedItem, dst); + + return true; + } + + protected override bool OnDragEnd(InputState state) => draggedItem != null || base.OnDragEnd(state); + + private class ItemSearchContainer : FillFlowContainer, IHasFilterableChildren + { + public string[] FilterTerms => new string[] { }; + public bool MatchingFilter + { + set + { + if (value) + InvalidateLayout(); + } + } + + // Compare with reversed ChildID and Depth + protected override int Compare(Drawable x, Drawable y) => base.Compare(y, x); + + public IEnumerable FilterableChildren => Children; + + public ItemSearchContainer() + { + LayoutDuration = 200; + LayoutEasing = Easing.OutQuint; + } } } } diff --git a/osu.Game/Overlays/Music/PlaylistOverlay.cs b/osu.Game/Overlays/Music/PlaylistOverlay.cs index e987e7a5c1..d05ad85726 100644 --- a/osu.Game/Overlays/Music/PlaylistOverlay.cs +++ b/osu.Game/Overlays/Music/PlaylistOverlay.cs @@ -92,7 +92,7 @@ namespace osu.Game.Overlays.Music protected override void LoadComplete() { base.LoadComplete(); - beatmapBacking.ValueChanged += b => list.SelectedItem = b?.BeatmapSetInfo; + beatmapBacking.ValueChanged += b => list.SelectedSet = b?.BeatmapSetInfo; beatmapBacking.TriggerChange(); } @@ -126,23 +126,23 @@ namespace osu.Game.Overlays.Music public void PlayPrevious() { - var playable = list.PreviousItem; + var playable = list.PreviousSet; if (playable != null) { playSpecified(playable.Beatmaps[0]); - list.SelectedItem = playable; + list.SelectedSet = playable; } } public void PlayNext() { - var playable = list.NextItem; + var playable = list.NextSet; if (playable != null) { playSpecified(playable.Beatmaps[0]); - list.SelectedItem = playable; + list.SelectedSet = playable; } } From 2ed20f5a6f6ba54b498971d15fb1299aa5ab15e2 Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Mon, 4 Sep 2017 14:20:40 +0900 Subject: [PATCH 34/47] Add better fix for items swapping erratically. --- osu.Game/Overlays/Music/PlaylistList.cs | 27 +++++++++++-------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/osu.Game/Overlays/Music/PlaylistList.cs b/osu.Game/Overlays/Music/PlaylistList.cs index a4550f7f52..8af8943ded 100644 --- a/osu.Game/Overlays/Music/PlaylistList.cs +++ b/osu.Game/Overlays/Music/PlaylistList.cs @@ -143,22 +143,19 @@ namespace osu.Game.Overlays.Music int src = (int)draggedItem.Depth; - var matchingItem = items.LastOrDefault(c => c.Position.Y < itemsPos.Y); - if (matchingItem == null) - return true; + // Find the last item with position < mouse position. Note we can't directly use + // the item positions as they are being transformed + float heightAccumulator = 0; + int dst = 0; + for (; dst < items.Count; dst++) + { + // Using BoundingBox here takes care of scale, paddings, etc... + heightAccumulator += items[dst].BoundingBox.Height; + if (heightAccumulator > itemsPos.Y) + break; + } - int dst = (int)matchingItem.Depth; - - // Due to the position predicate above, there is an edge case to consider when an item is moved upwards: - // At the point where the two items cross there will be two items sharing the same condition, and the items will jump back - // and forth between the two positions because of this. This is accentuated if the items span differing line heights. - // The easiest way to avoid this is to ensure the movement direction matches the expected mouse delta - - if (state.Mouse.Delta.Y <= 0 && dst > src) - return true; - - if (state.Mouse.Delta.Y >= 0 && dst < src) - return true; + dst = MathHelper.Clamp(dst, 0, items.Count - 1); if (src == dst) return true; From 04c3801fcc19c0a21064ee82dceff414f635dc20 Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Mon, 4 Sep 2017 14:58:28 +0900 Subject: [PATCH 35/47] Add scrolling points so items can be dragged beyond the list. --- osu.Game/Overlays/Music/PlaylistList.cs | 73 +++++++++++++++++++------ 1 file changed, 57 insertions(+), 16 deletions(-) diff --git a/osu.Game/Overlays/Music/PlaylistList.cs b/osu.Game/Overlays/Music/PlaylistList.cs index 8af8943ded..ad964f7458 100644 --- a/osu.Game/Overlays/Music/PlaylistList.cs +++ b/osu.Game/Overlays/Music/PlaylistList.cs @@ -137,46 +137,87 @@ namespace osu.Game.Overlays.Music { if (draggedItem == null) return base.OnDrag(state); + return true; + } - // Mouse position in the position space of the items container - Vector2 itemsPos = items.ToLocalSpace(state.Mouse.NativeState.Position); + protected override bool OnDragEnd(InputState state) + { + var handled = draggedItem != null || base.OnDragEnd(state); + draggedItem = null; - int src = (int)draggedItem.Depth; + return handled; + } + + protected override void Update() + { + base.Update(); + + if (draggedItem == null) + return; + + var mouseState = GetContainingInputManager().CurrentState.Mouse; + + updateScrollPosition(mouseState); + updateDragPosition(mouseState); + } + + private void updateScrollPosition(IMouseState mouseState) + { + const float start_offset = 10; + const double max_power = 50; + const double exp_base = 1.05; + + var localPos = ToLocalSpace(mouseState.Position); + + if (localPos.Y < start_offset) + { + var power = Math.Min(max_power, Math.Abs(start_offset - localPos.Y)); + ScrollBy(-(float)Math.Pow(exp_base, power)); + } + else if (localPos.Y > DrawHeight - start_offset) + { + var power = Math.Min(max_power, Math.Abs(DrawHeight - start_offset - localPos.Y)); + ScrollBy((float)Math.Pow(exp_base, power)); + } + } + + private void updateDragPosition(IMouseState mouseState) + { + var itemsPos = items.ToLocalSpace(mouseState.Position); + + int srcIndex = (int)draggedItem.Depth; // Find the last item with position < mouse position. Note we can't directly use // the item positions as they are being transformed float heightAccumulator = 0; - int dst = 0; - for (; dst < items.Count; dst++) + int dstIndex = 0; + for (; dstIndex < items.Count; dstIndex++) { // Using BoundingBox here takes care of scale, paddings, etc... - heightAccumulator += items[dst].BoundingBox.Height; + heightAccumulator += items[dstIndex].BoundingBox.Height; if (heightAccumulator > itemsPos.Y) break; } - dst = MathHelper.Clamp(dst, 0, items.Count - 1); + dstIndex = MathHelper.Clamp(dstIndex, 0, items.Count - 1); - if (src == dst) - return true; + if (srcIndex == dstIndex) + return; - if (src < dst) + if (srcIndex < dstIndex) { - for (int i = src + 1; i <= dst; i++) + for (int i = srcIndex + 1; i <= dstIndex; i++) items.ChangeChildDepth(items[i], i - 1); } else { - for (int i = dst; i < src; i++) + for (int i = dstIndex; i < srcIndex; i++) items.ChangeChildDepth(items[i], i + 1); } - items.ChangeChildDepth(draggedItem, dst); - - return true; + items.ChangeChildDepth(draggedItem, dstIndex); } - protected override bool OnDragEnd(InputState state) => draggedItem != null || base.OnDragEnd(state); private class ItemSearchContainer : FillFlowContainer, IHasFilterableChildren { From 722b7419d634e4627cf5eed409ee6acc45be702f Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Mon, 4 Sep 2017 15:06:21 +0900 Subject: [PATCH 36/47] Clamp at the end points. --- osu.Game/Overlays/Music/PlaylistList.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/osu.Game/Overlays/Music/PlaylistList.cs b/osu.Game/Overlays/Music/PlaylistList.cs index ad964f7458..6c8fb61ef2 100644 --- a/osu.Game/Overlays/Music/PlaylistList.cs +++ b/osu.Game/Overlays/Music/PlaylistList.cs @@ -8,6 +8,7 @@ using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Input; +using osu.Framework.MathUtils; using osu.Game.Beatmaps; using osu.Game.Graphics.Containers; using OpenTK; @@ -171,11 +172,17 @@ namespace osu.Game.Overlays.Music if (localPos.Y < start_offset) { + if (Current <= 0) + return; + var power = Math.Min(max_power, Math.Abs(start_offset - localPos.Y)); ScrollBy(-(float)Math.Pow(exp_base, power)); } else if (localPos.Y > DrawHeight - start_offset) { + if (IsScrolledToEnd()) + return; + var power = Math.Min(max_power, Math.Abs(DrawHeight - start_offset - localPos.Y)); ScrollBy((float)Math.Pow(exp_base, power)); } From ad966f41f5cc559f60681cac7e64a745c99b30f9 Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Mon, 4 Sep 2017 15:08:41 +0900 Subject: [PATCH 37/47] Fix CI error. --- osu.Game/Overlays/Music/PlaylistList.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Overlays/Music/PlaylistList.cs b/osu.Game/Overlays/Music/PlaylistList.cs index 6c8fb61ef2..e98fc45915 100644 --- a/osu.Game/Overlays/Music/PlaylistList.cs +++ b/osu.Game/Overlays/Music/PlaylistList.cs @@ -8,7 +8,6 @@ using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Input; -using osu.Framework.MathUtils; using osu.Game.Beatmaps; using osu.Game.Graphics.Containers; using OpenTK; From ed0f2a654baccd5425c7a4b0ff8629cd32e8dae2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 4 Sep 2017 18:51:50 +0900 Subject: [PATCH 38/47] Rename variable --- osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs b/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs index a66ac3298f..8ba92a8d30 100644 --- a/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs +++ b/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs @@ -23,11 +23,11 @@ namespace osu.Game.Rulesets.Osu.Scoring { } - private float beatmapHp; + private float hpDrainRate; protected override void ComputeTargets(Game.Beatmaps.Beatmap beatmap) { - beatmapHp = beatmap.BeatmapInfo.Difficulty.DrainRate; + hpDrainRate = beatmap.BeatmapInfo.Difficulty.DrainRate; } protected override void Reset() @@ -66,23 +66,23 @@ namespace osu.Game.Rulesets.Osu.Scoring switch (judgement.Score) { case OsuScoreResult.Hit300: - Health.Value += (10.2 - beatmapHp) * 0.02; + Health.Value += (10.2 - hpDrainRate) * 0.02; break; case OsuScoreResult.Hit100: - Health.Value += (8 - beatmapHp) * 0.02; + Health.Value += (8 - hpDrainRate) * 0.02; break; case OsuScoreResult.Hit50: - Health.Value += (4 - beatmapHp) * 0.02; + Health.Value += (4 - hpDrainRate) * 0.02; break; case OsuScoreResult.SliderTick: - Health.Value += System.Math.Max(7 - beatmapHp, 0) * 0.01; + Health.Value += System.Math.Max(7 - hpDrainRate, 0) * 0.01; break; case OsuScoreResult.Miss: - Health.Value -= beatmapHp * 0.04; + Health.Value -= hpDrainRate * 0.04; break; } } From e9f076244065fa732782bac35293bb7c9027cf1c Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Tue, 5 Sep 2017 10:29:51 +0900 Subject: [PATCH 39/47] Don't query GetContainingInputManager every Update. --- osu.Game/Overlays/Music/PlaylistList.cs | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/osu.Game/Overlays/Music/PlaylistList.cs b/osu.Game/Overlays/Music/PlaylistList.cs index e98fc45915..ff1a8dd0dc 100644 --- a/osu.Game/Overlays/Music/PlaylistList.cs +++ b/osu.Game/Overlays/Music/PlaylistList.cs @@ -59,8 +59,6 @@ namespace osu.Game.Overlays.Music private readonly SearchContainer search; private readonly FillFlowContainer items; - private PlaylistItem draggedItem; - public ItemsScrollContainer() { Children = new Drawable[] @@ -127,14 +125,19 @@ namespace osu.Game.Overlays.Music public BeatmapSetInfo NextSet => (items.SkipWhile(i => !i.Selected).Skip(1).FirstOrDefault() ?? items.FirstOrDefault())?.BeatmapSetInfo; public BeatmapSetInfo PreviousSet => (items.TakeWhile(i => !i.Selected).LastOrDefault() ?? items.LastOrDefault())?.BeatmapSetInfo; + private InputState dragInputState; + private PlaylistItem draggedItem; + protected override bool OnDragStart(InputState state) { + dragInputState = state; draggedItem = items.FirstOrDefault(d => d.IsDraggable); return draggedItem != null || base.OnDragStart(state); } protected override bool OnDrag(InputState state) { + dragInputState = state; if (draggedItem == null) return base.OnDrag(state); return true; @@ -142,6 +145,7 @@ namespace osu.Game.Overlays.Music protected override bool OnDragEnd(InputState state) { + dragInputState = state; var handled = draggedItem != null || base.OnDragEnd(state); draggedItem = null; @@ -155,19 +159,17 @@ namespace osu.Game.Overlays.Music if (draggedItem == null) return; - var mouseState = GetContainingInputManager().CurrentState.Mouse; - - updateScrollPosition(mouseState); - updateDragPosition(mouseState); + updateScrollPosition(); + updateDragPosition(); } - private void updateScrollPosition(IMouseState mouseState) + private void updateScrollPosition() { const float start_offset = 10; const double max_power = 50; const double exp_base = 1.05; - var localPos = ToLocalSpace(mouseState.Position); + var localPos = ToLocalSpace(dragInputState.Mouse.NativeState.Position); if (localPos.Y < start_offset) { @@ -187,9 +189,9 @@ namespace osu.Game.Overlays.Music } } - private void updateDragPosition(IMouseState mouseState) + private void updateDragPosition() { - var itemsPos = items.ToLocalSpace(mouseState.Position); + var itemsPos = items.ToLocalSpace(dragInputState.Mouse.NativeState.Position); int srcIndex = (int)draggedItem.Depth; @@ -250,4 +252,4 @@ namespace osu.Game.Overlays.Music } } } -} \ No newline at end of file +} From 1904b5edfe93bbffdd153a20b4803314c9655234 Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Tue, 5 Sep 2017 10:37:49 +0900 Subject: [PATCH 40/47] Only store native position instead of input state. --- osu.Game/Overlays/Music/PlaylistList.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/osu.Game/Overlays/Music/PlaylistList.cs b/osu.Game/Overlays/Music/PlaylistList.cs index ff1a8dd0dc..360e2ad843 100644 --- a/osu.Game/Overlays/Music/PlaylistList.cs +++ b/osu.Game/Overlays/Music/PlaylistList.cs @@ -125,19 +125,19 @@ namespace osu.Game.Overlays.Music public BeatmapSetInfo NextSet => (items.SkipWhile(i => !i.Selected).Skip(1).FirstOrDefault() ?? items.FirstOrDefault())?.BeatmapSetInfo; public BeatmapSetInfo PreviousSet => (items.TakeWhile(i => !i.Selected).LastOrDefault() ?? items.LastOrDefault())?.BeatmapSetInfo; - private InputState dragInputState; + private Vector2 nativeDragPosition; private PlaylistItem draggedItem; protected override bool OnDragStart(InputState state) { - dragInputState = state; + nativeDragPosition = state.Mouse.NativeState.Position; draggedItem = items.FirstOrDefault(d => d.IsDraggable); return draggedItem != null || base.OnDragStart(state); } protected override bool OnDrag(InputState state) { - dragInputState = state; + nativeDragPosition = state.Mouse.NativeState.Position; if (draggedItem == null) return base.OnDrag(state); return true; @@ -145,7 +145,7 @@ namespace osu.Game.Overlays.Music protected override bool OnDragEnd(InputState state) { - dragInputState = state; + nativeDragPosition = state.Mouse.NativeState.Position; var handled = draggedItem != null || base.OnDragEnd(state); draggedItem = null; @@ -169,7 +169,7 @@ namespace osu.Game.Overlays.Music const double max_power = 50; const double exp_base = 1.05; - var localPos = ToLocalSpace(dragInputState.Mouse.NativeState.Position); + var localPos = ToLocalSpace(nativeDragPosition); if (localPos.Y < start_offset) { @@ -191,7 +191,7 @@ namespace osu.Game.Overlays.Music private void updateDragPosition() { - var itemsPos = items.ToLocalSpace(dragInputState.Mouse.NativeState.Position); + var itemsPos = items.ToLocalSpace(nativeDragPosition); int srcIndex = (int)draggedItem.Depth; From d69b8d7784f1eb2d8b63b5c62d52ad750e5af958 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 5 Sep 2017 17:09:58 +0900 Subject: [PATCH 41/47] Add basic combo score factor to osu! ruleset --- .../Scoring/OsuScoreProcessor.cs | 80 ++++++++++++++++--- 1 file changed, 69 insertions(+), 11 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs b/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs index 8ba92a8d30..8432c5b26a 100644 --- a/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs +++ b/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.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 System; using System.Collections.Generic; +using osu.Framework.Configuration; using osu.Framework.Extensions; +using osu.Game.Beatmaps; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Osu.Judgements; using osu.Game.Rulesets.Osu.Objects; @@ -14,6 +17,8 @@ namespace osu.Game.Rulesets.Osu.Scoring { internal class OsuScoreProcessor : ScoreProcessor { + public readonly Bindable Mode = new Bindable(ScoringMode.Exponential); + public OsuScoreProcessor() { } @@ -25,9 +30,28 @@ namespace osu.Game.Rulesets.Osu.Scoring private float hpDrainRate; - protected override void ComputeTargets(Game.Beatmaps.Beatmap beatmap) + private int totalAccurateJudgements; + + private readonly Dictionary scoreResultCounts = new Dictionary(); + private readonly Dictionary comboResultCounts = new Dictionary(); + + private double comboMaxScore; + + protected override void ComputeTargets(Beatmap beatmap) { hpDrainRate = beatmap.BeatmapInfo.Difficulty.DrainRate; + totalAccurateJudgements = beatmap.HitObjects.Count; + + foreach (var h in beatmap.HitObjects) + { + // TODO: add support for other object types. + AddJudgement(new OsuJudgement + { + MaxScore = OsuScoreResult.Hit300, + Score = OsuScoreResult.Hit300, + Result = HitResult.Hit + }); + } } protected override void Reset() @@ -41,9 +65,6 @@ namespace osu.Game.Rulesets.Osu.Scoring comboResultCounts.Clear(); } - private readonly Dictionary scoreResultCounts = new Dictionary(); - private readonly Dictionary comboResultCounts = new Dictionary(); - public override void PopulateScore(Score score) { base.PopulateScore(score); @@ -63,6 +84,7 @@ namespace osu.Game.Rulesets.Osu.Scoring scoreResultCounts[judgement.Score] = scoreResultCounts.GetOrDefault(judgement.Score) + 1; comboResultCounts[judgement.Combo] = comboResultCounts.GetOrDefault(judgement.Combo) + 1; } + switch (judgement.Score) { case OsuScoreResult.Hit300: @@ -78,7 +100,7 @@ namespace osu.Game.Rulesets.Osu.Scoring break; case OsuScoreResult.SliderTick: - Health.Value += System.Math.Max(7 - hpDrainRate, 0) * 0.01; + Health.Value += Math.Max(7 - hpDrainRate, 0) * 0.01; break; case OsuScoreResult.Miss: @@ -87,17 +109,53 @@ namespace osu.Game.Rulesets.Osu.Scoring } } - int score = 0; - int maxScore = 0; + calculateScore(); + + calculateScore(); + } + + private void calculateScore() + { + int baseScore = 0; + double comboScore = 0; + + int baseMaxScore = 0; foreach (var j in Judgements) { - score += j.ScoreValue; - maxScore += j.MaxScoreValue; + baseScore += j.ScoreValue; + baseMaxScore += j.MaxScoreValue; + + comboScore += j.ScoreValue * (1 + Combo.Value / 10d); } - TotalScore.Value = score; - Accuracy.Value = (double)score / maxScore; + Accuracy.Value = (double)baseScore / baseMaxScore; + + if (comboScore > comboMaxScore) + comboMaxScore = comboScore; + + if (baseScore == 0) + TotalScore.Value = 0; + else + { + // temporary to make scoring feel more like score v1 without being score v1. + float exponentialFactor = Mode.Value == ScoringMode.Exponential ? (float)Judgements.Count / 100 : 1; + + TotalScore.Value = + (int) + ( + exponentialFactor * + 700000 * comboScore / comboMaxScore + + 300000 * Math.Pow(Accuracy.Value, 10) * ((double)Judgements.Count / totalAccurateJudgements) + + 0 /* bonusScore */ + ); + } + } + + public enum ScoringMode + { + Standardised, + Exponential } } } From 24f7fbe1e5d7ad1d0b4637a1b750c25bc787ccf0 Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Tue, 5 Sep 2017 19:14:37 +0900 Subject: [PATCH 42/47] Update framework. --- osu-framework | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu-framework b/osu-framework index 5c0e50379e..3edf658577 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit 5c0e50379e47a3805097dbc36a713decc64f49ce +Subproject commit 3edf65857759f32d5a6d07ed523a2892b09c3c6a From b871323ed8091577a151cd3285152408db0e6643 Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Tue, 5 Sep 2017 19:26:28 +0900 Subject: [PATCH 43/47] Fix BeatmapGroup initialization not correctly setting panels to Hidden. --- osu.Game/Beatmaps/Drawables/BeatmapGroup.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/osu.Game/Beatmaps/Drawables/BeatmapGroup.cs b/osu.Game/Beatmaps/Drawables/BeatmapGroup.cs index c66bf637e2..9c62289bfa 100644 --- a/osu.Game/Beatmaps/Drawables/BeatmapGroup.cs +++ b/osu.Game/Beatmaps/Drawables/BeatmapGroup.cs @@ -33,19 +33,16 @@ namespace osu.Game.Beatmaps.Drawables public BeatmapSetHeader Header; - private BeatmapGroupState state; - public List BeatmapPanels; public BeatmapSetInfo BeatmapSet; + private BeatmapGroupState state; public BeatmapGroupState State { get { return state; } set { - if (state == value) - return; state = value; switch (value) @@ -97,6 +94,7 @@ namespace osu.Game.Beatmaps.Drawables Header.AddDifficultyIcons(BeatmapPanels); } + private void headerGainedSelection(BeatmapSetHeader panel) { State = BeatmapGroupState.Expanded; From 0fc2e49ce6b12f2003f043135189293653ea2247 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 5 Sep 2017 19:33:20 +0900 Subject: [PATCH 44/47] Remove second calculateScore call --- osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs b/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs index 8432c5b26a..41e0dbff41 100644 --- a/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs +++ b/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs @@ -110,8 +110,6 @@ namespace osu.Game.Rulesets.Osu.Scoring } calculateScore(); - - calculateScore(); } private void calculateScore() From 05f5dfba81c5dd0d2cdf52c8cf933d921f3515db Mon Sep 17 00:00:00 2001 From: Tom Date: Tue, 5 Sep 2017 13:57:30 +0200 Subject: [PATCH 45/47] Change difficulty colors and add ExpertPlus ExpertPlus is for beatmaps above 6.75* --- .../Drawables/DifficultyColouredContainer.cs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/osu.Game/Beatmaps/Drawables/DifficultyColouredContainer.cs b/osu.Game/Beatmaps/Drawables/DifficultyColouredContainer.cs index 2614baa116..41b77f6584 100644 --- a/osu.Game/Beatmaps/Drawables/DifficultyColouredContainer.cs +++ b/osu.Game/Beatmaps/Drawables/DifficultyColouredContainer.cs @@ -33,7 +33,8 @@ namespace osu.Game.Beatmaps.Drawables Normal, Hard, Insane, - Expert + Expert, + ExpertPlus } private DifficultyRating getDifficultyRating(BeatmapInfo beatmap) @@ -44,7 +45,8 @@ namespace osu.Game.Beatmaps.Drawables if (rating < 2.25) return DifficultyRating.Normal; if (rating < 3.75) return DifficultyRating.Hard; if (rating < 5.25) return DifficultyRating.Insane; - return DifficultyRating.Expert; + if (rating < 6.75) return DifficultyRating.Expert; + return DifficultyRating.ExpertPlus; } private Color4 getColour(BeatmapInfo beatmap) @@ -55,12 +57,14 @@ namespace osu.Game.Beatmaps.Drawables return palette.Green; default: case DifficultyRating.Normal: - return palette.Yellow; + return palette.Blue; case DifficultyRating.Hard: - return palette.Pink; + return palette.Yellow; case DifficultyRating.Insane: - return palette.Purple; + return palette.Pink; case DifficultyRating.Expert: + return palette.Purple; + case DifficultyRating.ExpertPlus: return palette.Gray0; } } From 081b98ef39c3678ce7c5960505e86fe41627a711 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 5 Sep 2017 21:30:14 +0900 Subject: [PATCH 46/47] "Use" the hitobject Obviously temporary. --- .../Scoring/OsuScoreProcessor.cs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs b/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs index 41e0dbff41..3ee8f56665 100644 --- a/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs +++ b/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs @@ -44,13 +44,16 @@ namespace osu.Game.Rulesets.Osu.Scoring foreach (var h in beatmap.HitObjects) { - // TODO: add support for other object types. - AddJudgement(new OsuJudgement + if (h != null) { - MaxScore = OsuScoreResult.Hit300, - Score = OsuScoreResult.Hit300, - Result = HitResult.Hit - }); + // TODO: add support for other object types. + AddJudgement(new OsuJudgement + { + MaxScore = OsuScoreResult.Hit300, + Score = OsuScoreResult.Hit300, + Result = HitResult.Hit + }); + } } } From 1e10d977f9c3e7e166a1a4cdecdd1c7837c61073 Mon Sep 17 00:00:00 2001 From: Tom Date: Tue, 5 Sep 2017 15:39:27 +0200 Subject: [PATCH 47/47] Accuracy starts at 100% instead of 0% --- osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs b/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs index 647a1381c6..83203f5a7e 100644 --- a/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs +++ b/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs @@ -268,6 +268,7 @@ namespace osu.Game.Rulesets.Taiko.Scoring base.Reset(); Health.Value = 0; + Accuracy.Value = 1; bonusScore = 0; comboPortion = 0;